// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#version 410 core

layout (std140) uniform lighting
{
  vec4 DiffuseColor_FogStart;
  vec4 AmbientColor_FogEnd;
  vec4 FogColor_FogOn;
  vec4 LightDir_FogRate;
  vec4 OceanColorLight;
  vec4 OceanColorDark;
  vec4 RiverColorLight;
  vec4 RiverColorDark;
};

layout (std140) uniform overlay_params
{
  int draw_shadows;
  int draw_lines;
  int draw_hole_lines;
  int draw_areaid_overlay;
  int draw_terrain_height_contour;
  int draw_wireframe;
  int wireframe_type;
  float wireframe_radius;
  float wireframe_width;
  int draw_impass_overlay;
  int draw_paintability_overlay;
  int draw_selection_overlay;
  vec4 wireframe_color;
  int draw_impassible_climb;
  int climb_use_output_angle;
  int climb_use_smooth_interpolation;
  float climb_value;
  int draw_vertex_color;
  int draw_groundeffectid_overlay;
  int draw_groundeffect_layerid_overlay;
  int draw_noeffectdoodad_overlay;
  int draw_only_normals;
  int point_normals_up;
};

struct ChunkInstanceData
{
  ivec4 ChunkTextureSamplers;
  ivec4 ChunkTextureArrayIDs;
  ivec4 ChunkHoles_DrawImpass_TexLayerCount_CantPaint;
  ivec4 ChunkTexDoAnim;
  ivec4 ChunkTexAnimSpeed;
  ivec4 AreaIDColor_Pad2_DrawSelection;
  ivec4 ChunkXZ_TileXZ;
  ivec4 ChunkTexAnimDir;

  // Mists Heightmapping

  ivec4 ChunkHeightTextureSamplers;
  ivec4 ChunkTextureUVScale;
  vec4 ChunkTextureHeightScale;
  vec4 ChunkTextureHeightOffset;

  vec4 ChunkGroundEffectColor;
  // pack 8x8 bools in two ints. Simplified ChunksLayerEnabled to a bool instead of 2 bits id.
  // If those modes are mutually exclusive, we can do it in ChunkGroundEffectColor for now.
  ivec4 ChunkDoodadsEnabled2_ChunksLayerEnabled2;
};

layout (std140) uniform chunk_instances
{
  ChunkInstanceData instances[256];
};

uniform sampler2DArray shadowmap;
uniform sampler2DArray alphamap;
uniform sampler2D stamp_brush;
uniform sampler2DArray textures[11];
uniform vec3 camera;

uniform int draw_cursor_circle;
uniform vec3 cursor_position;
uniform float cursorRotation;
uniform float outer_cursor_radius;
uniform float inner_cursor_ratio;
uniform vec4 cursor_color;
uniform bool enable_mists_heightmapping;

in vec3 vary_position;
in vec2 vary_texcoord;
in vec2 vary_t0_uv;
in vec2 vary_t1_uv;
in vec2 vary_t2_uv;
in vec2 vary_t3_uv;
in vec3 vary_normal;
in vec3 vary_mccv;
flat in int instanceID;
flat in vec3 triangle_normal;

out vec4 out_color;

const float TILESIZE  = 533.33333;
const float CHUNKSIZE = TILESIZE / 16.0;
const float HOLESIZE  = CHUNKSIZE * 0.25;
const float UNITSIZE = HOLESIZE * 0.5;
const float PI = 3.14159265358979323846;

vec3 random_color(float areaID)
{
  float r = fract(sin(dot(vec2(areaID), vec2(12.9898, 78.233))) * 43758.5453);
  float g = fract(sin(dot(vec2(areaID), vec2(11.5591, 70.233))) * 43569.5451);
  float b = fract(sin(dot(vec2(areaID), vec2(13.1234, 76.234))) * 43765.5452);

  return vec3(r, g, b);
}

vec4 get_tex_color(vec2 tex_coord, int tex_sampler, int array_index)
{
  if (tex_sampler == 0)
  {
    return texture(textures[0], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 1)
  {
    return texture(textures[1], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 2)
  {
    return texture(textures[2], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 3)
  {
    return texture(textures[3], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 4)
  {
    return texture(textures[4], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 5)
  {
    return texture(textures[5], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 6)
  {
    return texture(textures[6], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 7)
  {
    return texture(textures[7], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 8)
  {
    return texture(textures[8], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 9)
  {
    return texture(textures[9], vec3(tex_coord, array_index)).rgba;
  }
  else if (tex_sampler == 10)
  {
    return texture(textures[10], vec3(tex_coord, array_index)).rgba;
  }

  return vec4(0);


  /*
  // This should be more compliant to the GLSL standard, but seems to be slower :(
  vec2 uvDx = dFdx(tex_coord);
  vec2 uvDy = dFdy(tex_coord);
  vec3 uv = vec3(tex_coord, array_index);
  
  switch(tex_sampler) 
  {
    case 0:
      return textureGrad(textures[0], uv, uvDx, uvDy);
    case 1:
      return textureGrad(textures[1], uv, uvDx, uvDy);
    case 2:
      return textureGrad(textures[2], uv, uvDx, uvDy);
    case 3:
      return textureGrad(textures[3], uv, uvDx, uvDy);
    case 4:
      return textureGrad(textures[4], uv, uvDx, uvDy);
    case 5:
      return textureGrad(textures[5], uv, uvDx, uvDy);
    case 6:
      return textureGrad(textures[6], uv, uvDx, uvDy);
    case 7:
      return textureGrad(textures[7], uv, uvDx, uvDy);
    case 8:
      return textureGrad(textures[8], uv, uvDx, uvDy);
    case 9:
      return textureGrad(textures[9], uv, uvDx, uvDy);
    case 10:
      return textureGrad(textures[10], uv, uvDx, uvDy);
    default:
      return vec4(0.0);
  }

  */

}

const int numChunks = 16;
const int numTiles = 64;

vec2 getAdjustedUV(vec2 uv, int textureScale) {
    vec2 worldOffset = (numChunks * instances[instanceID].ChunkXZ_TileXZ.zw) + instances[instanceID].ChunkXZ_TileXZ.xy;

    // Scale the UV coordinates. Wow Interprets texture scaling this way.
    vec2 combinedUV = fract((uv + worldOffset) / ((1 << textureScale) / 8.0f));

    return combinedUV;
}

vec4 mists_texture_blend()
{
  vec3 alpha = texture(alphamap, vec3(vary_texcoord / 8.0, instanceID)).rgb;

  int layer_count = instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b;

  alpha.r = mix(alpha.r, 0.0, float(layer_count < 2));
  alpha.g = mix(alpha.g, 0.0, float(layer_count < 3));
  alpha.b = mix(alpha.b, 0.0, float(layer_count < 4));


  vec2 worldScaled_vary_t0_uv = getAdjustedUV(vary_t0_uv/8.0, instances[instanceID].ChunkTextureUVScale.x);
  vec2 worldScaled_vary_t1_uv = getAdjustedUV(vary_t1_uv/8.0, instances[instanceID].ChunkTextureUVScale.y);
  vec2 worldScaled_vary_t2_uv = getAdjustedUV(vary_t2_uv/8.0, instances[instanceID].ChunkTextureUVScale.z);
  vec2 worldScaled_vary_t3_uv = getAdjustedUV(vary_t3_uv/8.0, instances[instanceID].ChunkTextureUVScale.w);

  // Mists HeightMapping: Multi Layer Blending.
  vec4 layer_weights = vec4(1.0 - clamp(dot(vec3(1.0),alpha), 0, 1), alpha);

  vec4 t0h = get_tex_color(worldScaled_vary_t0_uv, instances[instanceID].ChunkHeightTextureSamplers.x, abs(instances[instanceID].ChunkTextureArrayIDs.x));
  vec4 t1h = get_tex_color(worldScaled_vary_t1_uv, instances[instanceID].ChunkHeightTextureSamplers.y, abs(instances[instanceID].ChunkTextureArrayIDs.y));
  vec4 t2h = get_tex_color(worldScaled_vary_t2_uv, instances[instanceID].ChunkHeightTextureSamplers.z, abs(instances[instanceID].ChunkTextureArrayIDs.z));
  vec4 t3h = get_tex_color(worldScaled_vary_t3_uv, instances[instanceID].ChunkHeightTextureSamplers.w, abs(instances[instanceID].ChunkTextureArrayIDs.w));

  vec4 layer_pct = vec4 ( layer_weights.x * ( t0h.a * instances[instanceID].ChunkTextureHeightScale.x + instances[instanceID].ChunkTextureHeightOffset.x)
					 , layer_weights.y * ( t1h.a * instances[instanceID].ChunkTextureHeightScale.y + instances[instanceID].ChunkTextureHeightOffset.y)
					 , layer_weights.z * ( t2h.a * instances[instanceID].ChunkTextureHeightScale.z + instances[instanceID].ChunkTextureHeightOffset.z)
					 , layer_weights.w * ( t3h.a * instances[instanceID].ChunkTextureHeightScale.w + instances[instanceID].ChunkTextureHeightOffset.w)
					 );
  vec4 layer_pct_max = vec4( max( max(layer_pct.x, layer_pct.y) , max(layer_pct.z, layer_pct.w) ) );
  layer_pct = layer_pct * (vec4(1.0) - clamp(layer_pct_max - layer_pct, 0, 1));
  layer_pct = layer_pct / vec4( dot(vec4(1.0),layer_pct) );    

  vec4 t0 = get_tex_color(worldScaled_vary_t0_uv, instances[instanceID].ChunkTextureSamplers.x, 
                          abs(instances[instanceID].ChunkTextureArrayIDs.x)) * layer_pct.x;
  t0.a = mix(t0.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.x < 0));

  vec4 t1 = get_tex_color(worldScaled_vary_t1_uv, instances[instanceID].ChunkTextureSamplers.y, 
                        abs(instances[instanceID].ChunkTextureArrayIDs.y)) * layer_pct.y;
  //vec4 t1 = get_tex_color(vary_t1_uv / 5 , instances[instanceID].ChunkTextureSamplers.y, abs(instances[instanceID].ChunkTextureArrayIDs.y));
  t1.a = mix(t1.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.y < 0));

  vec4 t2 = get_tex_color(worldScaled_vary_t2_uv, instances[instanceID].ChunkTextureSamplers.z, 
                        abs(instances[instanceID].ChunkTextureArrayIDs.z)) * layer_pct.z;
  t2.a = mix(t2.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.z < 0));

  vec4 t3 =get_tex_color(worldScaled_vary_t3_uv, instances[instanceID].ChunkTextureSamplers.w,
                         abs(instances[instanceID].ChunkTextureArrayIDs.w)) * layer_pct.w;
  t3.a = mix(t3.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.w < 0));

  return vec4 (t0 + t1 + t2 + t3);//(t0 * (1.0 - (a0 + a1 + a2)) + t1 * a0 + t2 * a1 + t3 * a2);
}

vec4 texture_blend()
{
  vec3 alpha = texture(alphamap, vec3(vary_texcoord / 8.0, instanceID)).rgb;

  int layer_count = instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b;

  alpha.r = mix(alpha.r, 0.0, float(layer_count < 2));
  alpha.g = mix(alpha.g, 0.0, float(layer_count < 3));
  alpha.b = mix(alpha.b, 0.0, float(layer_count < 4));

  float a0 = alpha.r;
  float a1 = alpha.g;
  float a2 = alpha.b;

  vec4 t0 = get_tex_color(vary_t0_uv, instances[instanceID].ChunkTextureSamplers.x, abs(instances[instanceID].ChunkTextureArrayIDs.x));
  t0.a = mix(t0.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.x < 0));

  vec4 t1 = get_tex_color(vary_t1_uv, instances[instanceID].ChunkTextureSamplers.y, abs(instances[instanceID].ChunkTextureArrayIDs.y));
  t1.a = mix(t1.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.y < 0));

  vec4 t2 = get_tex_color(vary_t2_uv, instances[instanceID].ChunkTextureSamplers.z, abs(instances[instanceID].ChunkTextureArrayIDs.z));
  t2.a = mix(t2.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.z < 0));

  vec4 t3 = get_tex_color(vary_t3_uv, instances[instanceID].ChunkTextureSamplers.w, abs(instances[instanceID].ChunkTextureArrayIDs.w));
  t3.a = mix(t3.a, 0.f, int(instances[instanceID].ChunkTextureArrayIDs.w < 0));

  return vec4 (t0 * (1.0 - (a0 + a1 + a2)) + t1 * a0 + t2 * a1 + t3 * a2);
}

float contour_alpha(float unit_size, float pos, float line_width)
{
  float f = abs(fract((pos + unit_size*0.5) / unit_size) - 0.5);
  float df = abs(line_width / unit_size);
  return smoothstep(0.0, df, f);
}

float contour_alpha(float unit_size, vec2 pos, vec2 line_width)
{
  return 1.0 - min( contour_alpha(unit_size, pos.x, line_width.x)
                  , contour_alpha(unit_size, pos.y, line_width.y)
                  );
}

void main()
{
  float dist_from_camera = distance(camera, vary_position);

  vec3 fw = fwidth(vary_position.xyz);

  // calc world lighting
  vec3 currColor;
  vec3 lDiffuse = vec3(0.0, 0.0, 0.0);
  // vec3 accumlatedLight = vec3(1.0, 1.0, 1.0);

  vec3 normalized_normal = normalize(vary_normal);
  if(point_normals_up == 1)
  {
    normalized_normal = vec3(0, 1, 0);
  }
  float nDotL = clamp(dot(normalized_normal, -normalize(LightDir_FogRate.xyz)), 0.0, 1.0); // default LightDir = -0.6

  vec3 skyColor = (AmbientColor_FogEnd.xyz * 1.10000002);
  vec3 groundColor = (AmbientColor_FogEnd.xyz * 0.699999988);

  currColor = mix(groundColor, skyColor, 0.5 + (0.5 * nDotL));
  lDiffuse = DiffuseColor_FogStart.xyz * nDotL;

  vec3 reflection = normalize(normalized_normal - (-LightDir_FogRate.xyz));
  float specularFactor = max(dot(reflection, normalize(camera - vary_position)), 0.0);

  // blend textures
  if(enable_mists_heightmapping)
  {
	  out_color = mix(vec4(1.0, 1.0, 1.0, 0.0), mists_texture_blend(), int(instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b > 0));
  }
  else
  {
	  out_color = mix(vec4(1.0, 1.0, 1.0, 0.0), texture_blend(), int(instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.b > 0));
  }

  vec3 spc = out_color.a * out_color.rgb * pow(specularFactor, 8);
  out_color.a = 1.0;

  // apply vertex color
  if (draw_vertex_color != 0)
  {
    out_color.rgb *= vary_mccv;
  }

  // apply world lighting
  out_color.rgb = clamp(out_color.rgb * (currColor + lDiffuse + spc), 0.0, 1.0);

  // apply overlays
  if(draw_paintability_overlay != 0 && instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.a != 0)
  {
    out_color *= vec4(1.0, 0.0, 0.0, 1.0);
  }

  if(draw_areaid_overlay != 0)
  {
    out_color.rgb = out_color.rgb * 0.3 + random_color(instances[instanceID].AreaIDColor_Pad2_DrawSelection.r);
  }



  if(draw_groundeffectid_overlay != 0)
  {
    out_color.rgb = out_color.rgb * 0.3 + instances[instanceID].ChunkGroundEffectColor.rgb;
  }

  if(draw_groundeffect_layerid_overlay != 0)
  {
    // if chuck does not have our texture it is set as black color
    if (instances[instanceID].ChunkGroundEffectColor.rgb == vec3(0.0, 0.0, 0.0))
    {
      out_color.rgb = out_color.rgb * 0.3 + instances[instanceID].ChunkGroundEffectColor.rgb;
    }
    else
    {
      uint is_active = 0;

      uvec2 tile_index = uvec2(uint(floor(vary_position.x / TILESIZE)), uint(floor(vary_position.z / TILESIZE)));
      vec2 tile_base_pos = vec2(float(tile_index.x * TILESIZE), float(tile_index.y * TILESIZE));
      uvec2 chunk_index = uvec2(uint(floor(instanceID / 16)), uint(floor(instanceID % 16)));
      vec2 chunk_base_pos = vec2(float(chunk_index.x * CHUNKSIZE), float(chunk_index.y * CHUNKSIZE));
      uint unit_x = uint(floor((vary_position.x - (tile_base_pos.x + chunk_base_pos.x)) / UNITSIZE));
      uint unit_z = uint(floor((vary_position.z - (tile_base_pos.y + chunk_base_pos.y)) / UNITSIZE));

      // x and y aren't swapped because getDoodadActiveLayerIdAt() already does it in code
      if (unit_x < 4)
      {
        is_active =  uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.b) & (1 << ((unit_x * 8) + unit_z) );
      }
      else
      {
        is_active =  uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.a) & (1 << ((unit_x * 8) + unit_z) - 32 ); // (unit_x-4) * 8 + unit_z)
      }

      if (is_active != 0)
      {
        // if set, draw chunk in green
        out_color.rgb = mix(vec3(0.0, 1.0, 0.0), out_color.rgb, 0.7);
      }
      else
      {
        // else, draw in red
        out_color.rgb = mix(vec3(1.0, 0.0, 0.0), out_color.rgb, 0.7);
      }
    }
  }

  // render mode for ge doodads enabled on chunk unit. no_render set = white
  if(draw_noeffectdoodad_overlay != 0)
  {
    uint no_doodad = 0;
  
    uvec2 tile_index = uvec2(uint(floor(vary_position.x / TILESIZE)), uint(floor(vary_position.z / TILESIZE)));
    vec2 tile_base_pos = vec2(float(tile_index.x * TILESIZE), float(tile_index.y * TILESIZE));
    uvec2 chunk_index = uvec2(uint(floor(instanceID / 16)), uint(floor(instanceID % 16)));
    // uint chunk_x = uint(floor( (vary_position.x - tile_base_pos.x) / CHUNKSIZE));
    // uint chunk_y = uint(floor( (vary_position.z - tile_base_pos.y) / CHUNKSIZE));
    vec2 chunk_base_pos = vec2(float(chunk_index.x * CHUNKSIZE), float(chunk_index.y * CHUNKSIZE));
    uint unit_x = uint(floor((vary_position.x - (tile_base_pos.x + chunk_base_pos.x)) / UNITSIZE));
    uint unit_z = uint(floor((vary_position.z - (tile_base_pos.y + chunk_base_pos.y)) / UNITSIZE));
  
    // swapped x and y order, the data is wrongly ordered when loaded
    if (unit_z < 4)
    {
      no_doodad =  uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.r) & (1 << ((unit_z * 8) + unit_x) );
    }
    else
    {
      no_doodad =  uint(instances[instanceID].ChunkDoodadsEnabled2_ChunksLayerEnabled2.g) & (1 << ((unit_z * 8) + unit_x) - 32 ); // (unit_x-4) * 8 + unit_z)
    }
  
    if (no_doodad != 0)
    {
      // if set, draw chunk in white
      out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
    }
    else
    {
      // else, draw in black(default)
      out_color.rgb = mix(vec3(0.0), out_color.rgb, 0.5);
    }
  }

  if(draw_impass_overlay != 0 && instances[instanceID].ChunkHoles_DrawImpass_TexLayerCount_CantPaint.g != 0)
  {
    out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
  }

  if(draw_selection_overlay != 0 && instances[instanceID].AreaIDColor_Pad2_DrawSelection.a != 0)
  {
   out_color.rgb = mix(vec3(1.0), out_color.rgb, 0.5);
  }

  if (draw_shadows != 0)
  {
    float shadow_alpha = texture(shadowmap, vec3(vary_texcoord / 8.0, instanceID)).r;
    out_color = vec4 (out_color.rgb * (1.0 - shadow_alpha), 1.0);
  }

  if (draw_terrain_height_contour != 0)
  {
    out_color = vec4(out_color.rgb * contour_alpha(4.0, vary_position.y+0.1, fw.y), 1.0);
  }

  bool lines_drawn = false;
  if(draw_lines != 0)
  {
    vec4 color = vec4(0.0, 0.0, 0.0, 0.0);

    color.a = contour_alpha(TILESIZE, vary_position.xz, fw.xz * 1.5);
    color.g = color.a > 0.0 ? 0.8 : 0.0;

    if(color.a == 0.0)
    {
      color.a = contour_alpha(CHUNKSIZE, vary_position.xz, fw.xz);
      color.r = color.a > 0.0 ? 0.8 : 0.0;
    }
    if(draw_hole_lines != 0 && color.a == 0.0)
    {
      color.a = contour_alpha(HOLESIZE, vary_position.xz, fw.xz * 0.75);
      color.b = 0.8;
    }

    lines_drawn = color.a > 0.0;
    out_color.rgb = mix(out_color.rgb, color.rgb, color.a);
  }


  if(FogColor_FogOn.w != 0)
  {
    float start = AmbientColor_FogEnd.w * DiffuseColor_FogStart.w; // 0

    vec3 fogParams;
    fogParams.x = -(1.0 / (AmbientColor_FogEnd.w - start)); // - 1 / 338
    fogParams.y = (1.0 / (AmbientColor_FogEnd.w - start)) * AmbientColor_FogEnd.w; // 1 / 338 * 338
    fogParams.z = LightDir_FogRate.w; // 2.7

    float f1 = (dist_from_camera * fogParams.x) + fogParams.y; // 1.0029
    float f2 = max(f1, 0.0);
    float f3 = pow(f2, fogParams.z);
    float f4 = min(f3, 1.0);

    float fogFactor = 1.0 - f4;

    float alpha = clamp((dist_from_camera - start) / (AmbientColor_FogEnd.w - start), 0.0, 1.0);

    out_color.rgb = mix(out_color.rgb, FogColor_FogOn.rgb, fogFactor);
  }

  if(draw_wireframe != 0 && !lines_drawn)
  {
    // true by default => type 0
	  bool draw_wire = true;
      float real_wireframe_radius = max(outer_cursor_radius * wireframe_radius, 2.0 * UNITSIZE);

	  if(wireframe_type == 1)
	  {
		  draw_wire = (length(vary_position.xz - cursor_position.xz) < real_wireframe_radius);
	  }

	  if(draw_wire)
	  {
		  float alpha = contour_alpha(UNITSIZE, vary_position.xz, fw.xz * wireframe_width);
		  float xmod = mod(vary_position.x, UNITSIZE);
		  float zmod = mod(vary_position.z, UNITSIZE);
		  float d = length(fw.xz) * wireframe_width;
		  float diff = min( min(abs(xmod - zmod), abs(xmod - UNITSIZE + zmod))
                      , min(abs(zmod - xmod), abs(zmod + UNITSIZE - zmod))
                      );

		  alpha = max(alpha, 1.0 - smoothstep(0.0, d, diff));
          out_color.rgb = mix(out_color.rgb, wireframe_color.rgb, wireframe_color.a *alpha);
	  }
  }

  if (draw_impassible_climb != 0)
  {
      vec4 color = vec4(out_color.r, out_color.g, out_color.b, 0.5);
      vec3 use_normal;

      if (climb_use_smooth_interpolation != 0)
      {
          use_normal = vary_normal;
      }
      else
      {
          use_normal = triangle_normal;
      }

      float d1 = use_normal.y;
      float d2 = sqrt(use_normal.x * use_normal.x +
                      use_normal.y * use_normal.y +
                      use_normal.z * use_normal.z);

      if (d2 > 0.0)
      {
          float normal_angle = acos(d1/d2);

          if (climb_use_output_angle != 0)
          {
              color.r = normal_angle;
          }
          else
          {
              if (normal_angle > climb_value)
              {
                  color.r = 1.0;
              }
          }
      }


      out_color.rgb = mix(out_color.rgb, color.rgb, color.a);
  }

  if(draw_cursor_circle == 1)
  {
    float diff = length(vary_position.xz - cursor_position.xz);
    diff = min(abs(diff - outer_cursor_radius), abs(diff - outer_cursor_radius * inner_cursor_ratio));
    float alpha = smoothstep(0.0, length(fw.xz), diff);

    out_color.rgb = mix(cursor_color.rgb, out_color.rgb, alpha);
  }
  else if(draw_cursor_circle == 2)
  {
    float angle = cursorRotation * 2.0 * PI;
    vec2 topleft = cursor_position.xz;
    topleft.x -= outer_cursor_radius;
    topleft.y -= outer_cursor_radius;
    vec2 texcoord = (vary_position.xz - topleft) / outer_cursor_radius * 0.5 - 0.5;
    vec2 rotatedTexcoord;
    rotatedTexcoord.x = texcoord.x * cos(angle) + texcoord.y * sin(angle) + 0.5;
    rotatedTexcoord.y = texcoord.y * cos(angle) - texcoord.x * sin(angle) + 0.5;
    /*out_color.rgb = mix(out_color.rgb, texture(stampBrush, rotatedTexcoord).rgb
    , 1.0 * (int(length(vary_position.xz - cursor_position.xz) / outer_cursor_radius < 1.0))
    * (1.0 - length(vary_position.xz - cursor_position.xz) / outer_cursor_radius));*/
    out_color.rgb = mix(out_color.rgb, cursor_color.rgb, texture(stamp_brush, rotatedTexcoord).r
    * int(abs(vary_position.x - cursor_position.x) <= outer_cursor_radius
    && abs(vary_position.z - cursor_position.z) <= outer_cursor_radius));
    /*vec2 posRel = vary_position.xz - cursor_position.xz;
    float pos_x = posRel.x * sin(angle) - posRel.y * cos(angle);
    float pos_z = posRel.y * sin(angle) + posRel.x * cos(angle);
    float diff_x = abs(pos_x);
    float diff_z = abs(pos_z);
    float inner_radius = outer_cursor_radius * inner_cursor_ratio;
    float d = length(fw);
    float alpha = 1.0 * (1 - int((diff_x < outer_cursor_radius && diff_z < outer_cursor_radius
    && (outer_cursor_radius - diff_x <= d || outer_cursor_radius - diff_z <= d)) || (diff_x < inner_radius
    && diff_z < inner_radius && (inner_radius - diff_x <= d || inner_radius - diff_z <= d))));
    out_color.rgb = mix(cursor_color.rgb, out_color.rgb, alpha);*/
  }

  if(draw_only_normals != 0)
  {
    out_color.rgb = vec3(vary_normal.z * -1, vary_normal.y, vary_normal.x * -1) * 0.5 + 0.5;
  }

}
