/*****************************************************************************************
 *                                                                                       *
 * OpenSpace                                                                             *
 *                                                                                       *
 * Copyright (c) 2014                                                                    *
 *                                                                                       *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                       *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                       *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#ifndef TEXTURETILE_HGLSL
#define TEXTURETILE_HGLSL

// Must match the values in tiledataset.cpp
// (could be set as shader preprocessing data so that multiple definitions
// are not needed)
#define TILE_PIXEL_START_OFFSET ivec2(-2)
#define TILE_PIXEL_SIZE_DIFFERENCE ivec2(4)

vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) {
	vec2 uvOffset = uv - vec2(0.5);
	float thres = 0.5 - borderSize/2;
	bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres;
	vec3 color = isBorder ? borderColor : vec3(0);
	return vec4(color, 0);
}


/////////////////////////////////////////////////////////////////////
//                       ChunkTile Depth Transform                      //
/////////////////////////////////////////////////////////////////////

struct TileDepthTransform {
    float depthScale;
    float depthOffset;
};

float getTransformedTexVal(const TileDepthTransform transform, const float val){
	return transform.depthOffset + transform.depthScale * val;
}

vec4 getTransformedTexVal(const TileDepthTransform transform, const vec4 val){
	return transform.depthOffset + transform.depthScale * val;
}

/////////////////////////////////////////////////////////////////////
//                        ChunkTile UV Transform                        //
/////////////////////////////////////////////////////////////////////

struct TileUvTransform {
    vec2 uvOffset;
    vec2 uvScale;
};


/////////////////////////////////////////////////////////////////////
//                              ChunkTile                               //
/////////////////////////////////////////////////////////////////////
struct ChunkTile {
	sampler2D textureSampler;
	TileUvTransform uvTransform;
};

vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, const ChunkTile chunkTile, vec2 tileUV){
	ivec2 resolution = textureSize(chunkTile.textureSampler, 0);

	vec2 sourceSize = vec2(resolution) + sizeDiff;
	vec2 currentSize = vec2(resolution);
	vec2 sourceToCurrentSize = currentSize / sourceSize;
	tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize);
	return tileUV;
}

vec2 TileUVToTextureSamplePosition(const ChunkTile chunkTile, vec2 tileUV){
	vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV;
	uv = compensateSourceTextureSampling(vec2(-2), vec2(4), chunkTile, uv);
	return uv;
}

vec4 getTexVal(const ChunkTile chunkTile, vec2 tileUV){
	vec2 samplePosition = TileUVToTextureSamplePosition(chunkTile, tileUV);
	vec4 texVal = texture(chunkTile.textureSampler, samplePosition);
	return texVal;
}



/////////////////////////////////////////////////////////////////////
//                         Chunk Tile Pile                         //
/////////////////////////////////////////////////////////////////////
struct ChunkTilePile {
	ChunkTile chunkTile0;
	ChunkTile chunkTile1;
	ChunkTile chunkTile2;
};

struct LayerSettings {
	float opacity;
	float gamma;
	float multiplier;
};

struct Layer {
	ChunkTilePile pile;
	TileDepthTransform depthTransform;
	LayerSettings settings;
};

struct LevelWeights {
	float w1;
	float w2;
	float w3;
};

float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor, float distToVertexOnEllipsoid){
	float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid;
	float desiredLevel = log2(projectedScaleFactor);
	return chunkLevel - desiredLevel;
}

LevelWeights getLevelWeights(float levelInterpolationParameter){
	LevelWeights levelWeights;
	levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1);
	levelWeights.w2 = (clamp(levelInterpolationParameter, 0 , 1) - clamp(levelInterpolationParameter - 1, 0 , 1));
	levelWeights.w3 = clamp(levelInterpolationParameter - 1, 0 , 1);
	return levelWeights;
}

LevelWeights getDefaultLevelWeights(){
	LevelWeights levelWeights;
	levelWeights.w1 = 1;
	levelWeights.w2 = 0;
	levelWeights.w3 = 0;
	return levelWeights;
}


vec4 getTexVal(const ChunkTilePile chunkTilePile, const LevelWeights w, const vec2 uv){
	return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) + 
		w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) + 
		w.w3 * getTexVal(chunkTilePile.chunkTile2, uv);
}


#endif // TEXTURETILE_HGLSL