//CTMPOMFIX by TIMETRAVELBEARD 2023-7-20: various fixes for ctm with pom, -and then some (for info and tutorial on resource pack formatting for compatibility check my discord or patreon, it will be public) 

//last revised 2023-9-5, v 1.3 (alpha B)


//I am providing this code FREE TO BE ENJOYED BY THE MINECRAFT COMMUNITY with the following stipulations:

//BASICALLY:
//  This is for your personal, non-commercial use. You can include it in your Minecraft shader as a standalone file if you ask for permission and I agree.
//  Do Not Redistribute. Share links not files.
//  Do not modify except as stated below.
//  Do not copy my code. 



//EXTENDED:

//ABOUT PORTING, USING, OR REDISTRIBUTING THIS CODE:

//ALL RIGHTS RESERVED, DO NOT MODIFY OR REDISTRIBUTE EXCEPT AS STATED BELOW. 

//MODIFICATIONS: Talk to me if there are things you'd like to be changed or added.  I want this to be STANDARDIZED so it's easier to work with and incorporate.

//YOU CAN MODIFY ONLY THE COMPATIBILITY ZONE MARKED BELOW, to make this work in your shader, and only either with my permission, or if you try to reach me at all 3 points of contact listed below, and I am both inactive on those platforms and don't respond in 30 days.

//IF YOU WANT THIS IN YOUR SHADER JUST ASK ME, I will most likely say yes and may even help port it. If you try to reach me at all 3 points of contact listed below, and I am both inactive on those platforms and don't respond in 30 days, then you can include this in your Minecraft shader provided that the shader is free and publically available, or is just for your personal use. 

//METHOD OF INCLUSION: If I agree that you can include this in your shader, you are putting this file in as a standalone file in the shader and using "#include" do not copy paste my code into other files.

//COMMERCIAL OR FOR PROFIT SHADERS OR PRODUCTS, REDISTRIBUTION: If your shader or product is not free to access and publically available, you definitely need my permision to include this code and distribute it in or with your product, and the 30 day contact window does not apply. If you use this code or any derivative in a commercial product without my explicit permission, be prepared for legal recourse. THIS IS PROVIDED BY ME FREE TO BE ENJOYED BY THE MINECRAFT COMMUNITY and while I am alive I want it to stay FREE for minecraft and to be STANDARDIZED. If you want to make money with it then I get some. If you want to use it in any projects, commercial or non-commercial, you need to ask.

//CREDIT
//I wrote this code, do not take credit for it. if you include this in your shader, credit me in whatever way you credit contributors to your project. Do not include it without my permission, as stated above.

//CHANGES: This license may change from time to time, ask me for the current version or check the newest release.

//CONTACT ME VIA:

//My Patreon https://www.patreon.com/timetravelbeard

//My YouTube https://youtube.com/@timetravelbeard3588

//My Discord Server https://discord.gg/S6F4r6K5yU

//*Discord is currently my prefered point of contact






//#####################
// COMPATIBILITY ZONE 
//#####################

// YOU CAN MODIFY ONLY THIS MARKED COMPATIBILITY ZONE BELOW AND ONLY TO ADD COMPATIBILITY FOR YOUR SHADER

//shader specific sdjustments
#define CPF_SHADER_STYLE 0

//phrasing style 0, default, ch
#if CPF_SHADER_STYLE == 0
uniform float near;
uniform float far;

#define ALBEDO_TEXTURE_CALL_FOR_FLAG_CHECK textureLod(texture,fract(coord) * vtexcoordam.pq + vtexcoordam.st,0)
#define ALBEDO_TEXTURE_CALL_PREFIX textureGrad(texture, 
#define ALBEDO_TEXTURE_CALL_SUFFIX * vtexcoordam.pq + vtexcoordam.st, dcdx, dcdy)
#define ALBEDO_TEXTURE_SET_UV_SUFFIX * vtexcoordam.pq+vtexcoordam.st

#define ALBEDO_TEXTURE_SAMPLER texture 
#define SPECULAR_TEXTURE_SAMPLER normals 
#define NORMAL_TEXTURE_SAMPLER normals 

#define NORMAL_TEXTURE_CALL_PREFIX texture2DGradARB(normals,
#define NORMAL_TEXTURE_CALL_SUFFIX *vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy)

#define TEXTURE_CALL_PREFIX texture2DGradARB(
#define TEXTURE_CALL_SUFFIX  *vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy)

#define QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq 
#define QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 
#define TEXTURE_CALL_GRADS , dcdx, dcdy

#define CPF_ADDS_DEPTH_WRITE 1
#define SHADER_NOISE_FUNCTION 0.0
#endif
//>

//phrasing style 1, bliss
#if CPF_SHADER_STYLE == 1 
#define ALBEDO_TEXTURE_CALL_FOR_FLAG_CHECK textureGrad(texture, fract(coord) * vtexcoordam.pq + vtexcoordam.st, dcdx, dcdy)
#define ALBEDO_TEXTURE_CALL_PREFIX textureGrad(texture, 
#define ALBEDO_TEXTURE_CALL_SUFFIX * vtexcoordam.pq + vtexcoordam.st, dcdx, dcdy)
#define ALBEDO_TEXTURE_SET_UV_SUFFIX * vtexcoordam.pq+vtexcoordam.st

#define ALBEDO_TEXTURE_SAMPLER texture
#define SPECULAR_TEXTURE_SAMPLER specular
#define NORMAL_TEXTURE_SAMPLER normals

#define NORMAL_TEXTURE_CALL_PREFIX texture2DGradARB(normals,
#define NORMAL_TEXTURE_CALL_SUFFIX *vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy)

#define TEXTURE_CALL_PREFIX texture2DGradARB(
#define TEXTURE_CALL_SUFFIX  *vtexcoordam.pq+vtexcoordam.st,dcdx,dcdy)

#define QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq 
#define QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 

#define CPF_ADDS_DEPTH_WRITE 0
#define SHADER_NOISE_FUNCTION 2* interleaved_gradientNoise()
#endif
//>

//phrasing style 2, Complimentary Reimagined
#if CPF_SHADER_STYLE == 2
#define ALBEDO_TEXTURE_CALL_FOR_FLAG_CHECK textureGrad(tex, fract(coord) * vTexCoordAM.pq + vTexCoordAM.st, dcdx, dcdy)
#define ALBEDO_TEXTURE_CALL_PREFIX textureGrad(tex, 
#define ALBEDO_TEXTURE_CALL_SUFFIX * vTexCoordAM.pq + vTexCoordAM.st, dcdx, dcdy)
#define ALBEDO_TEXTURE_SET_UV_SUFFIX * vTexCoordAM.pq + vTexCoordAM.st

#define ALBEDO_TEXTURE_SAMPLER tex
#define SPECULAR_TEXTURE_SAMPLER tex
#define NORMAL_TEXTURE_SAMPLER normals

#define NORMAL_TEXTURE_CALL_PREFIX textureGrad(normals,
#define NORMAL_TEXTURE_CALL_SUFFIX * vTexCoordAM.pq + vTexCoordAM.st, dcdx, dcdy)

#define TEXTURE_CALL_PREFIX textureGrad(
#define TEXTURE_CALL_SUFFIX  * vTexCoordAM.pq + vTexCoordAM.st, dcdx, dcdy)

#define QUAD_TEXTURE_SIZE_COMPONENT vTexCoordAM.pq 

#define CPF_ADDS_DEPTH_WRITE 1

#endif
//>



//see if these are faster for checking flags or pixels, try
//texelFetch()
//textureLod()


//*ADD YOUR SHADER COMPATIBILITY CODE HERE

// YOU CAN MODIFY ONLY THIS MARKED COMPATIBILITY ZONE ABOVE AND ONLY TO ADD COMPATIBILITY FOR YOUR SHADER

//#####################
//#####################




//DOCUMENTATION

//This is exhaustedly commented in an attempt to serve as documentation

//for additional help making compatible resource packs, come to my discord server listed above.




//SETTINGS

//some of these defines go in a settings toggle, at least CTMPOMFIX

#define CTMPOMFIX 0 // [0 1]  //CTMPOMFIX overhauls 3D textures (POM) with special features, including fixing seams on 3D Connected Textures in resource packs formatted for it. in many cases it vastly improves quality/performance . Turn on POM, turn off Video Settings/Quality/Better Grass 

#define INITIAL_POM_QUALITY_CPF 30 // [5 10 20 25 30 40 50 75 100 200 400 1000] //Initial POM Quality . This is EXPONENTIALLY INCREASED by the REFINE_POM Setting . Recommend 20+ but you don't need much more . 20 Initial with 5 Refine is like 1,000 Quality for the cost of 25

#define POM_DISTANCE_CPF 25 // [5 10 15 20 25 30 40 50 60 75 100 200] //How far out 3D textures (POM) will be 3D 

#define POM_DEPTH_CPF 0.25 //[0.1 0.25 0.5 0.75 1.0] //Depth of 3D Textures. 0.25 is the standard . Changing may break Seamlessness and look bad

#define FADE_IN_POM_CPF 5 // [0 1 2 3 4 5 6 7 8 9 10] //3D fade in for pom . how much of POM distance is used for fade . 0 is none, 10 is all . Recommend around 5 

#define DYNAMIC_QUALITY_CPF 0 // [0 1] //lower pom quality at a distance . might improve performance . might make it worse . requires fade_in

#define FAR_FIXES_CPF 1 // [0 1] //CTMPOMFIX OPTION: . just leave this on. hides buggy 3D overlays out of pom range and fixes UVs for textures using ctmpomfix mode 11 (some mods). also potentially improves performance in some cases

#define ENABLE_CTMPOMFIX_POM_SPACE 1 // [0 1] //CTMPOMFIX OPTION: . this is an alternate POM implementation with even more special features in the works

#define CPF_RELATIVE_SPACE 0 // [0 1] //CTMPOMFIX OPTION: 

#define INCREASE_QUALITY_AT_ANGLES_CPF 2 // [2 3 4 5 0]  // Increase the quality of POM at grazing angles . lower is better quality, but 0 is Off . this also limits the distance rays can go inside of blocks

#define DEPTH_WRITE_CPF 1 // [0 1] //for 3D transitions and edges to be seamless and display correctly . also screen space shadows . OFF BREAKS A LOT OF STUFF . leave on unless not using any of it

#define SMOOTHING_NOISE_CPF 0 //[0 1 2 3] //You can apply Noise to gently Smooth POM, it blurs it but reduces visible layers, especially at angles. Can also help de-flicker Pom Refinement if it's flickering, or cause it to flicker, or make 3D overlays to have seams.  0 - disable noise 1 - use noise . 2 - blur distance  3 - blur close to smooth

#define NOISE_FUNCTION_CPF 0 //[0 1 2 3 4] //Some shaders inject noise functions into POM, it helps hide layers but can blur . generally it's good . 0 - use a Shader Supplied noise function, if any . 1-x use other functions . 1+ may introduce some banding in pom until I find better alt noise functions

#define NOISE_STRENGTH_CPF 1.0 //[0.0 0.1 0.25 0.33 0.5 0.75 0.9 1.0 1.5 2.0 2.5 3.0] //Some shaders inject noise functions into POM, it helps hide layers but can blur . Adjust its strength . This can improve or worsen POM appearance . This may create or solve flickering

 #define REFINE_POM_CPF 10 //[0 1 2 3 4 5 6 7 10 20] //POM Refinement Steps . EXPONENTIAL QUALITY INCREASE FOR ALMOST FREE . 1 is ~4x quality at the cost of 1 quality . an extra 2x for every additional step . not great on very low quality for sharp stuff like grass, atleast 20 Initial Quality recommended . on some shaders low values may flicker

#define TEXTURE_FILTERING_CPF 0 //[0 1 2 3 4 5 6 7] //Filter Textures so they aren't pixelated when close up, performance may vary by mode . 0 - none . 1 - bilinear (mode 1) . bilinear (mode 2) . COMING SOON

#define TEXTURE_FILTERING_DISTANCE_CPF 2 //[0 1 2 5 10 20 30 50 100 200 500 10000] //Filter Textures so they aren't pixelated when close up . How far out to use this effect . very low is fine for high res packs

#define POM_STYLE_CPF 0 //[0 1 2] //0 - sharp voxel cubes. 1 - tesselate .  2 - smooth polygons

#define EXTEND_3D_SHADOWS_CPF 0 //[0 1 2] //Depth writing for 3D Shadows, ao, etc in Textures out of POM range . 0 - off . 1 and 2 look the same, but either may be faster on your machine

#define UPSCALE_RESOLUTION_CPF 1 //[1 2 4 8 16 32 64 1] // Multplier for Upscaling and Texture filtering . 1 is infinite . these all cost the same, it's just visual preference

#define TEXTURE_BLEND_SOFTNESS_CPF 1.0 //[0.0 0.05 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] //1 is Softer Texture Blending . lOWER will sharpen Adaptive Contrast to maintain high contrast areas even more, but in doing so limits softer blending.

#define TEXTURE_FILTER_FADE_CPF 0.2 // [0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0] //fade in for texture filtering

#define FAST_TEX_READS_CPF 0 // [0 0] //coming soon

#define ALPHA_CUTOFF_CPF 0.25 // [0.05 0.1 0.2 0.25 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.95] //Things more opaque than this will be solid in Texture Filtering . Thickens Grass at lower numbers



#define CTMPOMFIX_INFO 0 // [0 1]  //CTMPOMFIX is an enhanced alternative POM with special features and usually a vast quality/performance increase. TURN ON POM, TURN OFF BETTER GRASS .  please report bugs and incompatibilities to timetravelbeard on discord or patreon  . More features coming soon



//start of core code
#if CTMPOMFIX == 1


//UTILITIES


float capf(in float f,in float fmin,in float fmax)
{
return f< fmin?fmin:f>fmax?fmax:f;
}

int roundi(in float f)
{//round float to int
return  fract(f)<.5?int(f):int(f)+1; 
}

float fract_signed(in float f)
{
	return f-int(f);
}

float fract_signed_oct(in float f)
{
	f*=8;
	return (f-int(f))*.125;
}

float easy_noise_cpf()
{
#if NOISE_FUNCTION_CPF == 0
return NOISE_STRENGTH_CPF * SHADER_NOISE_FUNCTION;
#endif

#if NOISE_FUNCTION_CPF == 1
return NOISE_STRENGTH_CPF *  0.1 * fract(sin(frameTimeCounter*1.3147+17.5*gl_FragCoord.x+11.7*gl_FragCoord.y));
#endif

#if NOISE_FUNCTION_CPF == 2
return NOISE_STRENGTH_CPF *  0.1 * fract(sin(1*fract(frameTimeCounter*1.3147)+fract(1.37*gl_FragCoord.x)+fract(111.7*gl_FragCoord.y)));
#endif

#if NOISE_FUNCTION_CPF == 3
return NOISE_STRENGTH_CPF *  fract(sin(frameTimeCounter*1.3147+17.5*gl_FragCoord.x+11.7*gl_FragCoord.y));
#endif

#if NOISE_FUNCTION_CPF == 4
return NOISE_STRENGTH_CPF *  fract(sin(1*fract(frameTimeCounter*1.3147)+fract(1.37*gl_FragCoord.x)+fract(111.7*gl_FragCoord.y)));
#endif
}


#if CPF_ADDS_DEPTH_WRITE == 1



#endif



#if CPF_SHADER_STYLE == 0

	vec3 normal_tex_to_world_cpf(in vec3 bumpy)
	{
	//bumpy = gl_Normal.rgb;
 bumpy = (bumpy*2-1);
bumpy.b = 1-(abs(bumpy.g)+abs(bumpy.r));
vec3 normal = normalMat.xyz;
        vec3 tangent2 = normalize(cross(tangent.rgb,normal)*tangent.w);
		mat3 tbnMatrix = mat3(tangent.x, tangent2.x, normal.x,
								  tangent.y, tangent2.y, normal.y,
						     	  tangent.z, tangent2.z, normal.z);
return (bumpy * tbnMatrix)*mat3(gl_ModelViewMatrix);	  
}
	
vec3 normal_tex_to_view_cpf(in vec3 bumpy)
	{
	//bumpy = gl_Normal.rgb;
 bumpy = (bumpy*2-1);
bumpy.b = 1-(abs(bumpy.g)+abs(bumpy.r));
vec3 normal = normalMat.xyz;
        vec3 tangent2 = normalize(cross(tangent.rgb,normal)*tangent.w);
		mat3 tbnMatrix = mat3(tangent.x, tangent2.x, normal.x,
								  tangent.y, tangent2.y, normal.y,
						     	  tangent.z, tangent2.z, normal.z);
return (bumpy * tbnMatrix);//*mat3(gl_ModelViewMatrix);	  
}

vec3 normal_to_view_cpf(in vec3 bumpy)
	{
	//bumpy = gl_Normal.rgb;
 bumpy = (bumpy*2-1);
bumpy.b = 1-(abs(bumpy.g)+abs(bumpy.r));
vec3 normal = normalMat.xyz;
        vec3 tangent2 = normalize(cross(tangent.rgb,normal)*tangent.w);
		mat3 tbnMatrix = mat3(tangent.x, tangent2.x, normal.x,
								  tangent.y, tangent2.y, normal.y,
						     	  tangent.z, tangent2.z, normal.z);
return bumpy * tbnMatrix;//*mat3(gl_ModelViewMatrix);	    
}

      #endif


float linearize_depth_cpf(in float d)
{
    // from gl_FragCoord.z to world measurements
    return 2.0 * near  * far / (far + near - (2.0 * d - 1.0) * (far - near));

}



float delinearize_depth_cpf(in float dee)
{// from world measurements to gl_FragDepth
    return ( ( (far + near - 2.0 * near * far / dee) / (far - near) )  + 1.0) / 2.0;
}



void fast_depth_write_cpf(in float fee)
{
	  #if DEPTH_WRITE_CPF == 2
	  //gl_FragDepth = ((gl_FragCoord.z));
      gl_FragDepth = ((gl_FragCoord.z) + fee *0.000001); 
      #endif
	  #if DEPTH_WRITE_CPF == 1
      gl_FragDepth = delinearize_depth_cpf(linearize_depth_cpf(gl_FragCoord.z) + fee); 
      #endif
}



//VARIABLES


float Ctm_pom_fix_margin;
int Ctm_pom_fix_mode;

#if TEXTURE_FILTERING_CPF == 0 &&  POM_STYLE_CPF == 0
#else




//
//for: softness of texture filtering, fade
//sub_pixel_position = softness==0?sub_pixel_position*0:  (1+ (sub_pixel_position-1) / softness);


//for: adaptive_contrast_bilinear_filter_cpf



vec4 Normalize_rgba_cpf(in vec4 v)
{//get color profile
float t =(v.r+v.g+v.b);//*v.a;
//float it = t<=0 ? 0 : 1.0/t;
return t<= 0? v*0 : v/t;// vec4(v.r*it,v.g*it,v.b*it,v.a);
}



vec4 blend_with_alpha_cpf(in vec4 a, in vec4 b,in float bxy)
{//blend 2 rgb with alpha weight
 
    bxy = clamp(bxy,0.0,1.0);
	  float abxy = bxy;
	bxy=a.a<.5?1:b.a<.5?0:bxy;
	vec4 c=  (a* (1-bxy) + b * bxy );
	c.a= (a.a* (1-abxy) + b.a * abxy );
	return c;

}







vec4 adaptive_contrast_bilinear_filter_cpf(in vec4 a, in vec4 b, in vec4 c, in vec4 d, in vec2 sub_pixel_position)
{
	
	//get a,b,c,d etc
	//...
	
	
	//TODO: Optimizecwith dot instead of dist
	
	#if UPSCALE_RESOLUTION_CPF == 1
	#else
	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif
	
	
	
//blend with contrast by color profile

//a to b
//get pixel color similarity


	
float softness = 1- TEXTURE_BLEND_SOFTNESS_CPF * distance(Normalize_rgba_cpf(a).rgb,Normalize_rgba_cpf(b).rgb);

//apply that softness to sub_pixel_position
float xyp= softness<=0?0: (1+ (sub_pixel_position.x -1) / softness);
//blend a,b
vec4 y1 = blend_with_alpha_cpf(a,b,xyp);



//c to d
//get pixel color similarity
softness = 1- TEXTURE_BLEND_SOFTNESS_CPF * distance(Normalize_rgba_cpf(c).rgb,Normalize_rgba_cpf(d).rgb);
//apply that softness to sub_pixel_position
 xyp= softness<=0?0:  (1+ (sub_pixel_position.x -1) / softness);
//blend c,d
vec4 y2 = blend_with_alpha_cpf(c,d,xyp);

//y1 to y2
//get pixel color similarity
softness = 1- TEXTURE_BLEND_SOFTNESS_CPF * distance(Normalize_rgba_cpf(y1).rgb, Normalize_rgba_cpf(y2).rgb);
//apply that softness to sub_pixel_position
 xyp= softness<=0?0:  (1+ (sub_pixel_position.y -1) / softness);
//blend y1, y2
return blend_with_alpha_cpf(y1,y2,xyp);



	
return vec4(0.0,0.0,0.0,0.0);
}//func
//


//in frag per pixel for texture filtering
 ivec2  atlas_size;
uniform ivec2 atlasSize;
vec2 pixelsize;



//for texture filtering/blending

vec2 pixel_size_in_atlas_space = 1.0/atlasSize;
//vec2 pixel_size_in_local_space = pq/pixel_size_in_atlas_space;

vec2 local_to_atlas_pixel_space(vec4 uv_comp, vec2 uv_local)
{
 return (uv_comp.st+uv_comp.pq*uv_local)*atlasSize;
}

//QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq define QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.pq 


vec4 local_uv_to_bilinear_data(in vec2 uv)
{

//if(	textureQueryLod( ALBEDO_TEXTURE_SAMPLER,	coordinate).y >=1)
 return ALBEDO_TEXTURE_CALL_PREFIX uv ALBEDO_TEXTURE_CALL_SUFFIX;

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  QUAD_TEXTURE_POSITION_COMPONENT + QUAD_TEXTURE_SIZE_COMPONENT * uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;

//Get data
#if FAST_TEX_READS_CPF == 1

	//vec4 a = textureLod( ALBEDO_TEXTURE_SAMPLER , uv ,0);//* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 b = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + vec2( pixel_size_in_atlas_space.x, 0.0))* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 c = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + vec2( 0.0, pixel_size_in_atlas_space.y))* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 d = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + pixel_size_in_atlas_space) * QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);

	vec4 a = ALBEDO_TEXTURE_CALL_PREFIX uv ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 b = ALBEDO_TEXTURE_CALL_PREFIX uv + vec2( pixel_size_in_atlas_space.x, 0.0) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 c = ALBEDO_TEXTURE_CALL_PREFIX (uv + vec2( 0.0, pixel_size_in_atlas_space.y)) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 d = ALBEDO_TEXTURE_CALL_PREFIX (uv + pixel_size_in_atlas_space) ALBEDO_TEXTURE_CALL_SUFFIX;

#else
	vec4 a = ALBEDO_TEXTURE_CALL_PREFIX uv ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 b = ALBEDO_TEXTURE_CALL_PREFIX uv + vec2( pixel_size_in_atlas_space.x, 0.0) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 c = ALBEDO_TEXTURE_CALL_PREFIX (uv + vec2( 0.0, pixel_size_in_atlas_space.y)) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 d = ALBEDO_TEXTURE_CALL_PREFIX (uv + pixel_size_in_atlas_space) ALBEDO_TEXTURE_CALL_SUFFIX;
#endif

//Blend data, return
return mix( mix(a,b,sub_pixel_position.x), mix(c,d,sub_pixel_position.x), sub_pixel_position.y);

}//Func




vec4 atlas_uv_to_bilinear_data(in vec2 uv, in float dist)
{

if(	dist > TEXTURE_FILTERING_DISTANCE_CPF ) return  ALBEDO_TEXTURE_CALL_PREFIX uv TEXTURE_CALL_GRADS );

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;




 
//setup distance fade
float iTEXDIST=1.0/TEXTURE_FILTERING_DISTANCE_CPF;
float iTEXFADE=1.0/TEXTURE_FILTER_FADE_CPF;
//apply that softness to sub_pixel_position
vec2 sharpness = clamp((sub_pixel_position-(1-TEXTURE_BLEND_SOFTNESS_CPF))/(TEXTURE_BLEND_SOFTNESS_CPF),0,1);
//apply distance fade
float distfade = clamp((dist-(TEXTURE_FILTERING_DISTANCE_CPF-TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF))/(TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF),0,1);
sub_pixel_position*=(sharpness);//
sub_pixel_position=clamp(sub_pixel_position*(1-distfade)+distfade*0,0,1);
 
 

 
 	#if UPSCALE_RESOLUTION_CPF == 1
	#else
	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif


//cut off 
float bx = uv.x < QUAD_TEXTURE_POSITION_COMPONENT.x + QUAD_TEXTURE_SIZE_COMPONENT.x * (1+ Ctm_pom_fix_margin) -pixel_size_in_atlas_space.x?1.0:0.0;
float by = uv.y < QUAD_TEXTURE_POSITION_COMPONENT.y + QUAD_TEXTURE_SIZE_COMPONENT.y * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.y?1.0:0.0;

//Get data
#if FAST_TEX_READS_CPF == 1

	vec4 a = textureLod( ALBEDO_TEXTURE_SAMPLER , uv ,0);//* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 b = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + vec2( pixel_size_in_atlas_space.x, 0.0))* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 c = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + vec2( 0.0, pixel_size_in_atlas_space.y))* QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);
	//vec4 d = textureLod( ALBEDO_TEXTURE_SAMPLER , (uv + pixel_size_in_atlas_space) * QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,0);

	//vec4 a = ALBEDO_TEXTURE_CALL_PREFIX uv ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 b = ALBEDO_TEXTURE_CALL_PREFIX uv + vec2( pixel_size_in_atlas_space.x, 0.0) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 c = ALBEDO_TEXTURE_CALL_PREFIX (uv + vec2( 0.0, pixel_size_in_atlas_space.y)) ALBEDO_TEXTURE_CALL_SUFFIX;
	vec4 d = ALBEDO_TEXTURE_CALL_PREFIX (uv + pixel_size_in_atlas_space) ALBEDO_TEXTURE_CALL_SUFFIX;

#else
	vec4 a = ALBEDO_TEXTURE_CALL_PREFIX uv TEXTURE_CALL_GRADS );
	vec4 b = ALBEDO_TEXTURE_CALL_PREFIX uv + vec2( pixel_size_in_atlas_space.x * bx, 0.0) TEXTURE_CALL_GRADS );
	vec4 c = ALBEDO_TEXTURE_CALL_PREFIX (uv + vec2( 0.0, pixel_size_in_atlas_space.y * by))TEXTURE_CALL_GRADS  );
	vec4 d = ALBEDO_TEXTURE_CALL_PREFIX (uv + vec2( pixel_size_in_atlas_space.x * bx, pixel_size_in_atlas_space.y * by)) TEXTURE_CALL_GRADS );
#endif

#if TEXTURE_FILTERING_CPF == 1 
//Blend data, return
a= blend_with_alpha_cpf( blend_with_alpha_cpf(a,b,sub_pixel_position.x), blend_with_alpha_cpf(c,d,sub_pixel_position.x), sub_pixel_position.y);
a.a=a.a>= ALPHA_CUTOFF_CPF ?1:0;
return a;
#endif

#if TEXTURE_FILTERING_CPF == 2 
//Blend data, return
a= adaptive_contrast_bilinear_filter_cpf(a,b,c,d,sub_pixel_position);
a.a=a.a>= ALPHA_CUTOFF_CPF ?1:0;
return a;
#endif

}//Func

vec4 atlas_uv_to_bilinear_data_specular(in vec2 uv, in float dist)
{


if(	dist > TEXTURE_FILTERING_DISTANCE_CPF ) return   TEXTURE_CALL_PREFIX SPECULAR_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;

//setup distance fade
float iTEXDIST=1.0/TEXTURE_FILTERING_DISTANCE_CPF;
float iTEXFADE=1.0/TEXTURE_FILTER_FADE_CPF;
//apply that softness to sub_pixel_position
vec2 sharpness = clamp((sub_pixel_position-(1-TEXTURE_BLEND_SOFTNESS_CPF))/(TEXTURE_BLEND_SOFTNESS_CPF),0,1);
//apply distance fade
float distfade = clamp((dist-(TEXTURE_FILTERING_DISTANCE_CPF-TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF))/(TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF),0,1);
sub_pixel_position*=(sharpness);//
sub_pixel_position=clamp(sub_pixel_position*(1-distfade)+distfade*0,0,1);
 
 	#if UPSCALE_RESOLUTION_CPF == 1
	#else
	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif

//cut off QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq  QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 
float bx = uv.x < QUAD_TEXTURE_POSITION_COMPONENT.x + QUAD_TEXTURE_SIZE_COMPONENT.x * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.x?1.0:0.0;
float by = uv.y < QUAD_TEXTURE_POSITION_COMPONENT.y + QUAD_TEXTURE_SIZE_COMPONENT.y * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.y?1.0:0.0;

//Get data
vec4 a = TEXTURE_CALL_PREFIX SPECULAR_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );
vec4 b = TEXTURE_CALL_PREFIX SPECULAR_TEXTURE_SAMPLER ,  uv + vec2( pixel_size_in_atlas_space.x*bx, 0.0) TEXTURE_CALL_GRADS );
vec4 c = TEXTURE_CALL_PREFIX SPECULAR_TEXTURE_SAMPLER ,  (uv + vec2( 0.0, pixel_size_in_atlas_space.y*by))TEXTURE_CALL_GRADS  );
vec4 d = TEXTURE_CALL_PREFIX SPECULAR_TEXTURE_SAMPLER , (uv + vec2( pixel_size_in_atlas_space.x*bx,pixel_size_in_atlas_space.y*by)) TEXTURE_CALL_GRADS );

//Blend data, return
return mix( mix(a,b,sub_pixel_position.x), mix(c,d,sub_pixel_position.x), sub_pixel_position.y);

}//Func

vec4 atlas_uv_to_bilinear_data_normal(in vec2 uv, in float dist)
{

if(	dist > TEXTURE_FILTERING_DISTANCE_CPF ) return  TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
 
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;

//setup distance fade
float iTEXDIST=1.0/TEXTURE_FILTERING_DISTANCE_CPF;
float iTEXFADE=1.0/TEXTURE_FILTER_FADE_CPF;
//apply that softness to sub_pixel_position
vec2 sharpness = clamp((sub_pixel_position-(1-TEXTURE_BLEND_SOFTNESS_CPF))/(TEXTURE_BLEND_SOFTNESS_CPF),0,1);
//apply distance fade
float distfade = clamp((dist-(TEXTURE_FILTERING_DISTANCE_CPF-TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF))/(TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF),0,1);
sub_pixel_position*=(sharpness);//
sub_pixel_position=clamp(sub_pixel_position*(1-distfade)+distfade*0,0,1);

 	#if UPSCALE_RESOLUTION_CPF == 1
	#else
	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif

//cut off QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq  QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 
float bx = uv.x < QUAD_TEXTURE_POSITION_COMPONENT.x + QUAD_TEXTURE_SIZE_COMPONENT.x * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.x?1.0:0.0;
float by = uv.y < QUAD_TEXTURE_POSITION_COMPONENT.y + QUAD_TEXTURE_SIZE_COMPONENT.y * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.y?1.0:0.0;

//Get data
vec4 a = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );
vec4 b = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv + vec2( pixel_size_in_atlas_space.x*bx, 0.0) TEXTURE_CALL_GRADS );
vec4 c = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  (uv + vec2( 0.0, pixel_size_in_atlas_space.y*by))TEXTURE_CALL_GRADS  );
vec4 d = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER , (uv + vec2( pixel_size_in_atlas_space.x*bx,pixel_size_in_atlas_space.y*by)) TEXTURE_CALL_GRADS );

//Blend data, return
return mix( mix(a,b,sub_pixel_position.x), mix(c,d,sub_pixel_position.x), sub_pixel_position.y);

}//Func

float mixf(in float f, in float f2, in float f3)
{
return f*(1-f3)+f2*f3;
}

vec4 atlas_uv_to_bilinear_data_normal_2h(in vec2 uv, in float dist)
{

if(	dist > TEXTURE_FILTERING_DISTANCE_CPF ) return  TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
 
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;


 
 	#if UPSCALE_RESOLUTION_CPF == 1 ||  POM_STYLE_CPF == 2
	#else
	//setup distance fade
float iTEXDIST=1.0/TEXTURE_FILTERING_DISTANCE_CPF;
float iTEXFADE=1.0/TEXTURE_FILTER_FADE_CPF;
//apply that softness to sub_pixel_position
vec2 sharpness = clamp((sub_pixel_position-(1-TEXTURE_BLEND_SOFTNESS_CPF))/(TEXTURE_BLEND_SOFTNESS_CPF),0,1);
//apply distance fade
float distfade = clamp((dist-(TEXTURE_FILTERING_DISTANCE_CPF-TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF))/(TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF),0,1);
sub_pixel_position*=(sharpness);//
sub_pixel_position=clamp(sub_pixel_position*(1-distfade)+distfade*0,0,1);

	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif

//cut off QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq  QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 
float bx = uv.x < QUAD_TEXTURE_POSITION_COMPONENT.x + QUAD_TEXTURE_SIZE_COMPONENT.x * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.x?1.0:0.0;
float by = uv.y < QUAD_TEXTURE_POSITION_COMPONENT.y + QUAD_TEXTURE_SIZE_COMPONENT.y * (1+ Ctm_pom_fix_margin)  -pixel_size_in_atlas_space.y?1.0:0.0;

//Get data
vec4 a = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv TEXTURE_CALL_GRADS );
vec4 b = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  uv + vec2( pixel_size_in_atlas_space.x*bx, 0.0) TEXTURE_CALL_GRADS );
vec4 c = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER ,  (uv + vec2( 0.0, pixel_size_in_atlas_space.y*by))TEXTURE_CALL_GRADS  );
vec4 d = TEXTURE_CALL_PREFIX NORMAL_TEXTURE_SAMPLER , (uv + vec2( pixel_size_in_atlas_space.x*bx,pixel_size_in_atlas_space.y*by)) TEXTURE_CALL_GRADS );

//Blend data, return
return mix( mix(a,b,sub_pixel_position.x), mix(c,d,sub_pixel_position.x), sub_pixel_position.y);

}//Func

/*
float atlas_uv_to_bilinear_data_height(in vec2 uv)
{

//if(	textureQueryLod( ALBEDO_TEXTURE_SAMPLER,	coordinate).y >=1)
 //return ALBEDO_TEXTURE_CALL_PREFIX uv ALBEDO_TEXTURE_CALL_SUFFIX;

//Get position in pixel space and blend %
vec2 uv_in_pixel_space =  uv *atlasSize;
vec2 sub_pixel_position=fract(uv_in_pixel_space);
uv = floor(uv_in_pixel_space)* pixel_size_in_atlas_space;


//setup distance fade
float iTEXDIST=1.0/TEXTURE_FILTERING_DISTANCE_CPF;
float iTEXFADE=1.0/TEXTURE_FILTER_FADE_CPF;
//apply that softness to sub_pixel_position
vec2 sharpness = clamp((sub_pixel_position-(1-TEXTURE_BLEND_SOFTNESS_CPF))/(TEXTURE_BLEND_SOFTNESS_CPF),0,1);
//apply distance fade
float distfade = clamp((dist-(TEXTURE_FILTERING_DISTANCE_CPF-TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF))/(TEXTURE_FILTERING_DISTANCE_CPF*TEXTURE_FILTER_FADE_CPF),0,1);
sub_pixel_position*=(sharpness);//
sub_pixel_position=clamp(sub_pixel_position*(1-distfade)+distfade*0,0,1);
	

 
 	#if UPSCALE_RESOLUTION_CPF == 1
	#else
	//limit upscale resolution
	sub_pixel_position= floor(sub_pixel_position*UPSCALE_RESOLUTION_CPF )/ UPSCALE_RESOLUTION_CPF ;
	#endif


//cut off QUAD_TEXTURE_SIZE_COMPONENT vtexcoordam.pq  QUAD_TEXTURE_POSITION_COMPONENT vtexcoordam.st 
float bx = uv.x < QUAD_TEXTURE_POSITION_COMPONENT.x + QUAD_TEXTURE_SIZE_COMPONENT.x -pixel_size_in_atlas_space.x?1.0:0.0;
float by = uv.y < QUAD_TEXTURE_POSITION_COMPONENT.y + QUAD_TEXTURE_SIZE_COMPONENT.y -pixel_size_in_atlas_space.y?1.0:0.0;

//Get data
  vec4 aa  = 1;//textureGather(NORMAL_TEXTURE_SAMPLER, uv, 4);
float a = aa.r;
float b = aa.g;
float c = aa.b;
float d = aa.a;
//Blend data, return
//debug here
return mix( mix(a,b,sub_pixel_position.x), mix(c,d,sub_pixel_position.x), sub_pixel_position.y);

}//Func
*/

void bilinear_filter_setupc()
{
	atlas_size=atlasSize; //TextureSize( texture ,1);
    pixelsize = 1.0/atlas_size;

}

vec4 bilinear_interpolationc(vec4 a, vec4 b, vec4 c, vec4 d, float xp, float yp)
{
  return mix( mix(a, b, xp), mix(c, d, xp), yp);
 
}

//textureGather( 	gsampler2D sampler,  	vec2 P,  	[int comp]); //get 4 heights
 
// texelFetch( 	gsampler1D sampler,  	int P,	int lod);	//get 1 rgba
  	
  	//vec2 textureSize( 	gsampler2D sampler, int lod);}
//  	vec2 textureQueryLod( 	gsampler1D sampler,	float P); //x = mipmap, y = lod.


vec4 bilinear_filteringc(in vec2 coordinateb) 
{

#define TRHRHHR 0
#if TRHRHHR == 1
	//bail if in mipmap territory
//if(	textureQueryLod( texture_a,	coordinate).y >=1) return vec4(texture2D(texture_a, coordinate));
	
	//if(	textureQueryLod( 	texture_a,	coordinate).y >= 1) return TEXTURE_CALL_PREFIX texture_a, coordinate TEXTURE_CALL_SUFFIX ;

	
	//enter pixel int space
vec2 coord = coordinate * TEXTURE_CALL_SUFFIX * atlas_size;
	//get xp,yp
	vec2 xyp = fract(coord);	
	//re-center pixel sampling, .5 to avoid bleed
	coord = floor(coord);//+.5;


// try different sampling techniques
	
//get neighboring pixel coords (if not using gather texture fetch)
vec2 coord_x1 = coord+vec2(1.0, 0.0 );
vec2 coord_y2 = coord+vec2(0.0, 1.0);
vec2 coord_xy3 = coord+vec2(1.0, 1.0);

//switch from atlas pixel space to atlas 0-1 space and
//read texture data( try a few ways)
vec4 a = vec4(texelFetch(texture_a, coord*pixelsize),0);
vec4 b = vec4(texelFetch(texture_a, coord_x1*pixelsize ),0);
vec4 c = vec4(texelFetch(texture_a, coord_y2*pixelsize ),0);
vec4 d = vec4(texelFetch(texture_a, coord_xy3*pixelsize ),0);

//


//blend and return
return mix( mix(a, b, xyp.x), mix(c, d, xyp.x), xyp.y);
#endif
return vec4(0.0,0,0.0,0.0);

}


#endif
//>end if using texture filtering

//EXTRAS


//v1.3


//individual blades of grass

vec3 wavy_grass(in vec3 p) {
    //wavy grass
    float t = 0;//frameTimeCounter;
    vec3 bend;
    bend.x=(1-p.z)* .5*( sin(p.x+p.y*.5+t)+sin(t+.2) );
    bend.y=(1-p.z)* bend.x* sin(t);
    bend.z= 0;//-(abs(bend.x)+ abs(bend.y));
    return bend;
}
vec2 wavy_grass_test(in vec2 p) {
    //wavy grass
    float t = 0;//frameTimeCounter;
    vec2 bend;
    bend.x= .5*( sin(p.x+p.y*.5+t)+sin(t+.2) );
    bend.y= bend.x* sin(t);
    //bend.z= 0;//-(abs(bend.x)+ abs(bend.y));
    return bend;
}

//multilevel pom


//v1.4

//3D animated lava with variations

//diamond material


//v1.5

//3D cube map


//1.6

//full voxel models







//CTMPOMFIX FUNCTIONS
	
	
void checkForCtmPomFixFlag(in vec2 coord)
	{
		//this checks the albedo map for flagged pixel values, specifically in the alpha channel. these values change how POM is handled, similar to how metalness is handled in pbr_s textures
		
		//put local coord into texture space and check for flags
		// v1 Core CTMPOMFIX, flag mode 0:
		//defined extra redundant texture margin for pom ray march is an additional 1/16th of visible texture width * (255-a) with a in ranges 0 to 16
		Ctm_pom_fix_margin=15.9375*(1-( ALBEDO_TEXTURE_CALL_FOR_FLAG_CHECK).a);
		//v 1.2+ extra CTMPOMFIX flags and modes ((255-a) with a>16):
		Ctm_pom_fix_mode=roundi(Ctm_pom_fix_margin<1.05?0:(Ctm_pom_fix_margin-1)*16);
		//limit modes to those currently implemented, default to mode 0
		Ctm_pom_fix_mode=Ctm_pom_fix_mode>7?0:Ctm_pom_fix_mode;
		//disregard margin flags over 100%  in case Cutouts use ctmpomfix
		Ctm_pom_fix_margin=Ctm_pom_fix_margin>1?0:Ctm_pom_fix_margin;
	}//func
	
		vec4 checkForCtmPomFixFlag_return(in vec2 coord)
	{
		//this checks the albedo map for flagged pixel values, specifically in the alpha channel. these values change how POM is handled, similar to how metalness is handled in pbr_s textures
		
		//put local coord into texture space and check for flags
		// v1 Core CTMPOMFIX, flag mode 0:
		//defined extra redundant texture margin for pom ray march is an additional 1/16th of visible texture width * (255-a) with a in ranges 0 to 16
		vec4 albedo=ALBEDO_TEXTURE_CALL_FOR_FLAG_CHECK;
		Ctm_pom_fix_margin=15.9375*(1-albedo.a);
		//v 1.2+ extra CTMPOMFIX flags and modes ((255-a) with a>16):
		Ctm_pom_fix_mode=roundi(Ctm_pom_fix_margin<1.05?0:(Ctm_pom_fix_margin-1)*16);
		//limit modes to those currently implemented, default to mode 0
		Ctm_pom_fix_mode=Ctm_pom_fix_mode>7?0:Ctm_pom_fix_mode;
		//disregard margin flags over 100%  in case Cutouts use ctmpomfix
		Ctm_pom_fix_margin=Ctm_pom_fix_margin>1?0:Ctm_pom_fix_margin;
		return albedo;
	}//func
	
	
//the following function has 2 variations, to accomodate certain pom modes without branching

//for height checking normal maps in pom raymarch
vec2 fract_ctmpomfix_h(in vec2 v)
{
	//alternate pom tiling functiionalities to change pom raymarch behavior
	switch (Ctm_pom_fix_mode)
	{
case 0://ctmpomfix core
//this is a safely dynamically wider tiling for the pom raymarch
v.x= v.x<0-Ctm_pom_fix_margin?v.x+1+Ctm_pom_fix_margin*2:v.x>=1+Ctm_pom_fix_margin?v.x-(1+Ctm_pom_fix_margin*2):v.x;
v.y= v.y<0-Ctm_pom_fix_margin?v.y+1+Ctm_pom_fix_margin*2:v.y>=1+Ctm_pom_fix_margin?v.y-(1+Ctm_pom_fix_margin*2):v.y;

v.x= v.x<0-Ctm_pom_fix_margin?v.x+1+Ctm_pom_fix_margin*2:v.x>=1+Ctm_pom_fix_margin?v.x-(1+Ctm_pom_fix_margin*2):v.x;
v.y= v.y<0-Ctm_pom_fix_margin?v.y+1+Ctm_pom_fix_margin*2:v.y>=1+Ctm_pom_fix_margin?v.y-(1+Ctm_pom_fix_margin*2):v.y;

v.x= v.x<0-Ctm_pom_fix_margin?0-Ctm_pom_fix_margin:v.x>=1+Ctm_pom_fix_margin?1+Ctm_pom_fix_margin:v.x;
v.y= v.y<0-Ctm_pom_fix_margin?0-Ctm_pom_fix_margin:v.y>=1+Ctm_pom_fix_margin?1+Ctm_pom_fix_margin:v.y;
break;

//added for v1.2
case 1://tile quarter (half distance) twice, then clamp 238
v.x=v.x<0? .5+v.x:v.x>1?.5+(v.x-1):v.x;
v.x=v.x<0? .5+v.x:v.x>1?.5+(v.x-1):v.x;
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<0? .5+v.y:v.y>1?.5+(v.y-1):v.y;
v.y=v.y<0? .5+v.y:v.y>1?.5+(v.y-1):v.y;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 2://mirror once and clamp 237
v.x=v.x<=0? 0-v.x:v.x>=1?1-(v.x-1):v.x;
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<=0? 0-v.y:v.y>=1?1-(v.y-1):v.y;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 3://crop and extend (for overlay borders) 236
case 5://outward corners fix a, tile a 0.5, crop n 234
case 6://outward corners fix b, tile a 1.0, crop n 233
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 4://drop/discard (shaped/contoured edges) 235
if (v.x< 0||v.x>1||v.y<0||v.y>1) discard;
break;
case 7:// 1/8th tile, 232 ##### ALPHA, TELL ME IF YOU USE THIS OR IT MIGHT BE DELETED FROM FUTURE VERSIONS
v.x=v.x<0?0.125+fract_signed_oct(v.x):v.x>1?0.875+fract_signed_oct(v.x):v.x;
v.y=v.y<0?0.125+fract_signed_oct(v.y):v.y>1?0.875+fract_signed_oct(v.y):v.y;
break;
//230, 229 reserved as 90% opacity

//in the future:
//fade in pom? requires core vs patch function sets
//maybe single pixel flags instead of using pom_depth_writing for borders. would free albedo.a and allow more data encoding in a single invisible strip
//v1.3 multilevel pom and moving grass
//v1.4 specialty shader flags
//v1.5  cube mapped shapes with full depth
//v1.6 full voxel models in pom space as extra effective lod (dh van pom voxl)
	};//switch
return v;
}//func


//for reading albedo map (and normal map normals, and specular data)
vec2 fract_ctmpomfix_a(in vec2 v)
{
	//alternate pom tiling functiionalities to change pom raymarch behavior
	switch (Ctm_pom_fix_mode)
	{
case 0://ctmpomfix core
//this is a safely dynamically wider tiling for the pom raymarch
case 6://outward corners fix b, tile a 1.0, crop n 233
v.x= v.x<0-Ctm_pom_fix_margin?v.x+1+Ctm_pom_fix_margin*2:v.x>=1+Ctm_pom_fix_margin?v.x-(1+Ctm_pom_fix_margin*2):v.x;
v.y= v.y<0-Ctm_pom_fix_margin?v.y+1+Ctm_pom_fix_margin*2:v.y>=1+Ctm_pom_fix_margin?v.y-(1+Ctm_pom_fix_margin*2):v.y;

v.x= v.x<0-Ctm_pom_fix_margin?v.x+1+Ctm_pom_fix_margin*2:v.x>=1+Ctm_pom_fix_margin?v.x-(1+Ctm_pom_fix_margin*2):v.x;
v.y= v.y<0-Ctm_pom_fix_margin?v.y+1+Ctm_pom_fix_margin*2:v.y>=1+Ctm_pom_fix_margin?v.y-(1+Ctm_pom_fix_margin*2):v.y;

v.x= v.x<0-Ctm_pom_fix_margin?0-Ctm_pom_fix_margin:v.x>=1+Ctm_pom_fix_margin?1+Ctm_pom_fix_margin:v.x;
v.y= v.y<0-Ctm_pom_fix_margin?0-Ctm_pom_fix_margin:v.y>=1+Ctm_pom_fix_margin?1+Ctm_pom_fix_margin:v.y;
break;

//added for v1.2
case 1://tile quarter (half distance) twice, then clamp 238
case 5://outward corners fix a, tile a 0.5, crop n 234
v.x=v.x<0? .5+v.x:v.x>1?.5+(v.x-1):v.x;
v.x=v.x<0? .5+v.x:v.x>1?.5+(v.x-1):v.x;
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<0? .5+v.y:v.y>1?.5+(v.y-1):v.y;
v.y=v.y<0? .5+v.y:v.y>1?.5+(v.y-1):v.y;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 2://mirror once and clamp 237
v.x=v.x<=0? 0-v.x:v.x>=1?1-(v.x-1):v.x;
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<=0? 0-v.y:v.y>=1?1-(v.y-1):v.y;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 3://crop and extend (for overlay borders) 236
v.x=v.x<0?0:v.x>1?1:v.x;
v.y=v.y<0?0:v.y>1?1:v.y;
break;
case 4://drop/discard (shaped/contoured edges) 235
if (v.x< 0||v.x>1||v.y<0||v.y>1) discard;
break;
case 7:// 1/8th tile, 232 ##### ALPHA, TELL ME IF YOU USE THIS OR IT MIGHT BE DELETED FROM FUTURE VERSIONS
v.x=v.x<0?0.125+fract_signed_oct(v.x):v.x>1?0.875+fract_signed_oct(v.x):v.x;
v.y=v.y<0?0.125+fract_signed_oct(v.y):v.y>1?0.875+fract_signed_oct(v.y):v.y;
break;

//230, 229 reserved as 90% opacity


	};//switch
return v;
}//func


void do_FAR_FIXES_CPF()
{
    if(Ctm_pom_fix_mode!=0) discard;
}



//MODIFIED TEXTURE READ FUNCTIONS


    //for normal map
	vec4 readNormal_h(in vec2 coord,in float dist)
	{//for height map reads
	
	#if POM_STYLE_CPF == 0
		
		return NORMAL_TEXTURE_CALL_PREFIX fract_ctmpomfix_h(coord) NORMAL_TEXTURE_CALL_SUFFIX;
	#else
	
	//return  vec4(0.0 , 0.0, 0.0, atlas_uv_to_bilinear_data_height( fract_ctmpomfix_h(coord) * QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ));
//return vec4(0.0 , 0.0, 0.0,  atlas_uv_to_bilinear_data_height( fract_ctmpomfix_h(coord) * QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ) );



	return  atlas_uv_to_bilinear_data_normal_2h( fract_ctmpomfix_h(coord) * QUAD_TEXTURE_SIZE_COMPONENT + QUAD_TEXTURE_POSITION_COMPONENT ,dist);




		#endif
	}
	
	vec4 readNormal(in vec2 coord)
	{//for normals
		return NORMAL_TEXTURE_CALL_PREFIX fract_ctmpomfix_a(coord) NORMAL_TEXTURE_CALL_SUFFIX;
	}
	
	vec4 readNormal_basic(in vec2 coord)
	{//basic unmodified read at UVs
		return NORMAL_TEXTURE_CALL_PREFIX fract(coord) NORMAL_TEXTURE_CALL_SUFFIX;
	}
	
	vec4 readNormal_basic2(in vec2 coord,out vec4 ntex)
	{//basic unmodified read + double return to be sneaky in a multipart if statement
		ntex= NORMAL_TEXTURE_CALL_PREFIX fract(coord) NORMAL_TEXTURE_CALL_SUFFIX;
		return ntex;
	}
	
	//for albedo map
	vec4 readTexture(in vec2 coord)
	{//for albedo 
		return ALBEDO_TEXTURE_CALL_PREFIX fract_ctmpomfix_a(coord) ALBEDO_TEXTURE_CALL_SUFFIX;
	}
	
	vec4 readTexture_basic(in vec2 coord)
	{//for albedo 
		return ALBEDO_TEXTURE_CALL_PREFIX fract(coord) ALBEDO_TEXTURE_CALL_SUFFIX;
	}



#if FADE_IN_POM_CPF == 0
const float iFADE_IN_POM_CPF = 10.0 ;
#else
const float iFADE_IN_POM_CPF = 10.0 / FADE_IN_POM_CPF;
#endif
//variables
const float iPom_distance = 1.0/POM_DISTANCE_CPF;

#if ENABLE_CTMPOMFIX_POM_SPACE == 1
//a custom POM implementation with special features




#if CTMPOMFIX == 1

//functions
void Ctmpomfix_alt_pom_as_insert_for_coords(in float dist, in vec4 tex_coord, in vec3 view_vector, inout vec2 pom_target_coord, in float noise_in)
{

#if SMOOTHING_NOISE_CPF == 0
  noise_in = 0; //disable shader noise
 #else
 #if NOISE_FUNCTION_CPF == 0 
  noise_in = noise_in==0.0?easy_noise_cpf() : noise_in*NOISE_STRENGTH_CPF;
  #else
    noise_in=easy_noise_cpf();
   #endif
 #endif
 
//check if skip pom if not needed or invalid and check im pom range
 
  vec4 pixel_normal;//=readNormal_basic(tex_coord.st);


float fade_in=1.0-dist*iPom_distance;

	

 #if FAR_FIXES_CPF == 1  
 checkForCtmPomFixFlag(tex_coord.st);
 #endif

#if EXTEND_3D_SHADOWS_CPF == 2
				pixel_normal = readNormal_basic(tex_coord.st);
				float extended_shadow  = (1-pixel_normal.a )* POM_DEPTH_CPF;
				//fast_depth_write_cpf(extended_shadow );
			
			
	if(fade_in<=0||view_vector.z >= 0.0 ||pixel_normal.a== 1 ||  pixel_normal.a==0 ) 
	{//not doing pom
  
#else		
    

	if(fade_in<=0||view_vector.z >= 0.0 ||readNormal_basic2(tex_coord.st,pixel_normal).a== 1 ||  pixel_normal.a==0 ) 
	{//not doing pom
  
#endif
  
  
  #if FAR_FIXES_CPF == 1  
  //do_FAR_FIXES_CPF(); //fix things out of pom range
  #if EXTEND_3D_SHADOWS_CPF == 0
	if(fade_in<0&&Ctm_pom_fix_mode!=0) discard;
  #endif
	#endif
	

	
	
	//export, done
	pom_target_coord=tex_coord.st ALBEDO_TEXTURE_SET_UV_SUFFIX;



     //depth write pom    
      #if DEPTH_WRITE_CPF == 0
	  #else
		#if EXTEND_3D_SHADOWS_CPF == 0
			gl_FragDepth = gl_FragCoord.z;
		#else
		
		
			#if EXTEND_3D_SHADOWS_CPF == 1
				//vec3 bumpy = vec3(.5,.5,1);
				//bumpy = abs(normal_to_view_cpf(bumpy));
				//bumpy.b = 1;
				
				//extended_shadow=extended_shadow==1?0:extended_shadow;
				//extended_shadow= (1-normal_to_view_cpf(vec3(0.0,0.0,extended_shadow)).b ) *POM_DEPTH_CPF;
				
				float extended_shadow  = (1-readNormal_basic(tex_coord.st).a )* POM_DEPTH_CPF;
				//float extended_shadow  = (1-pixel_normal.a )* POM_DEPTH_CPF;
				fast_depth_write_cpf(extended_shadow );
			#endif
			#if EXTEND_3D_SHADOWS_CPF == 2
				//float extended_shadow  = (1-readNormal_basic(tex_coord.st).a )* POM_DEPTH_CPF;
				fast_depth_write_cpf(extended_shadow );
			#endif
		
		
		
		#endif
		
      #endif


	 

  }//did not do pom
  else
{//in range and valid, do pom


		

//check for flagged pixels
   // pixel_albedo =
    #if FAR_FIXES_CPF == 0
    checkForCtmPomFixFlag(tex_coord.st);
	#endif
	
	
	
	//better fade ins for POM
	float POM_DEPTH_CPF_faded=POM_DEPTH_CPF;
    #if FADE_IN_POM_CPF == 0 

		 fade_in=1.0;
		 POM_DEPTH_CPF_faded=POM_DEPTH_CPF;
		 const float pom_quality = INITIAL_POM_QUALITY_CPF;
		 const float ipom_quality = 1.0/pom_quality;
	#else
	
	

		  fade_in=capf(fade_in,0.0,1.0);
		  
		  #if SMOOTHING_NOISE_CPF == 2
			noise_in *= clamp(dist,0.0,1.0); //blur distance
			#endif
			#if SMOOTHING_NOISE_CPF == 3
			noise_in *= (1.0- clamp(dist,0.0,2.0)*.5); //blur close
			#endif
		  
		//pom height fade in from 100 - 50% range
		 //POM_DEPTH_CPF_faded =fade_in>.5?POM_DEPTH_CPF: POM_DEPTH_CPF * fade_in *2;
		 //POM_DEPTH_CPF_faded = capf(fade_in *iFADE_IN_POM_CPF,0.0,1.0);
		
		
	
        #if EXTEND_3D_SHADOWS_CPF == 0
			POM_DEPTH_CPF_faded = POM_DEPTH_CPF* capf(fade_in *iFADE_IN_POM_CPF,0.0,1.0);
			#if FAR_FIXES_CPF == 1  
				//transitions stay deep, this can potentially be animated for rain and stuff for erosion
				POM_DEPTH_CPF_faded=Ctm_pom_fix_mode==0?POM_DEPTH_CPF_faded: POM_DEPTH_CPF;
			#else
				//fade transitions and base pom down
				POM_DEPTH_CPF_faded=Ctm_pom_fix_mode!=0?POM_DEPTH_CPF_faded: POM_DEPTH_CPF;
			#endif
		#else
			POM_DEPTH_CPF_faded = POM_DEPTH_CPF* capf(fade_in *iFADE_IN_POM_CPF,0.0,1.0);
			float pom_fade_amont= POM_DEPTH_CPF_faded / POM_DEPTH_CPF;
		#endif
			 

		#if DYNAMIC_QUALITY_CPF == 1
		//dynamic pom quality based on distance, 10% - 100% at 25% - 100% distance
		 float pom_quality =fade_in>0.75?INITIAL_POM_QUALITY_CPF: INITIAL_POM_QUALITY_CPF*(0.1+fade_in*1.2);
		  float ipom_quality = 1.0/pom_quality;
		#else
		//no DYNAMIC_QUALITY_CPF == 0
		 const float pom_quality = INITIAL_POM_QUALITY_CPF;
		 const float ipom_quality = 1.0/pom_quality;
		#endif
		
		

	#endif	




  

		//set up pom ray march
     
	  
  

      #if INCREASE_QUALITY_AT_ANGLES_CPF == 0
	  
		 float ray_error = ipom_quality*POM_DEPTH_CPF_faded / -view_vector.z;
	  
	  #else
	   // const float fSHARPEN_GRAZING_ANGLES = 2;
	   float ray_error = ipom_quality*POM_DEPTH_CPF_faded / -view_vector.z;
       ray_error=ray_error> INCREASE_QUALITY_AT_ANGLES_CPF * ipom_quality ? INCREASE_QUALITY_AT_ANGLES_CPF * ipom_quality:ray_error;
	   
		#endif
		
		  		   
				

  vec3 rayvelocity = view_vector.xyz *ray_error;
  
 
  
      vec3 ray = vec3(tex_coord.st, 1.0);
      
				
	  
	  
	 //enter relative space
	  rayvelocity.z/=POM_DEPTH_CPF_faded;
	  
	   //start pom ray march
      ray += noise_in*rayvelocity;
     
	  
	       //loop pom raymarch using updated readNormal function and dynamic depth
	       int raysteps;
			for (raysteps = 0;
          (raysteps < pom_quality) && (readNormal_h(ray.st,dist).a  < ray.p);
          ++raysteps) {
               ray = ray+rayvelocity;
      }//>pom ray march
	  
	   // SUPER POM 1
	  

#if REFINE_POM_CPF == 0
#else
float  refined_rayv = 0.5;
float refined_ray_total= -0.5;
for (int i=0;i< REFINE_POM_CPF ;i++)
{
	refined_rayv*= 0.5;
	refined_ray_total=(readNormal_h(ray.xy+refined_ray_total*rayvelocity.xy,dist).a < ray.z+refined_ray_total*rayvelocity.z)? refined_ray_total + refined_rayv:refined_ray_total - refined_rayv;
}

      #endif
	  
	  
      //leave relative space
	  rayvelocity.z*=POM_DEPTH_CPF_faded;
	
	 	

     //no oob safety

			 //update albedo UV to pom target
			 #if REFINE_POM_CPF == 0
			 pom_target_coord = fract_ctmpomfix_a(ray.st) ALBEDO_TEXTURE_SET_UV_SUFFIX;
#else
			
				   pom_target_coord = fract_ctmpomfix_a(ray.st+refined_ray_total*rayvelocity.xy) ALBEDO_TEXTURE_SET_UV_SUFFIX;
				   
      #endif
				    
				   
   
     //depth write pom    
      #if DEPTH_WRITE_CPF == 0
	  #else
	  
		#if EXTEND_3D_SHADOWS_CPF == 0
			#if REFINE_POM_CPF == 0
			
				fast_depth_write_cpf( raysteps *ray_error);
			#else
				fast_depth_write_cpf( (raysteps+refined_ray_total) *ray_error);

			#endif
		#else
			#if EXTEND_3D_SHADOWS_CPF == 1
				float extended_shadow  = (1-pixel_normal.a )* POM_DEPTH_CPF;
			#endif
			#if REFINE_POM_CPF == 0
			
				fast_depth_write_cpf( raysteps *ray_error*pom_fade_amont + extended_shadow*(1-pom_fade_amont)  );
			#else
				fast_depth_write_cpf( (raysteps+refined_ray_total)*pom_fade_amont *ray_error  + extended_shadow*(1-pom_fade_amont));

			#endif
		#endif
		  
      #endif
	  
	  

		#define CDDDD 0
#if CDDDD == 1
 #endif
	//debug
	
	
    }//> do pom (passed checks)
	
	//vec4 pixel_albedo = texture2DGradARB(texture, pom_target_coord.xy,dcdx,dcdy);
	

	
	}//func
	
	
	

	
void Ctmpomfix_alt_pom_as_insert_for_texture_data(in float dist, in vec4 tex_coord, in vec3 view_vector, inout vec2 pom_target_coord, in float noise_in, inout vec4 albedo_target, inout vec4 normal_target,inout vec4 specular_target)
{
Ctmpomfix_alt_pom_as_insert_for_coords(dist, tex_coord, view_vector,pom_target_coord, noise_in);

#if TEXTURE_FILTERING_CPF == 1 
albedo_target = atlas_uv_to_bilinear_data(pom_target_coord,dist);
normal_target= atlas_uv_to_bilinear_data_normal(pom_target_coord,dist);
specular_target=atlas_uv_to_bilinear_data_specular(pom_target_coord,dist);
#endif

#if TEXTURE_FILTERING_CPF == 2 
albedo_target = atlas_uv_to_bilinear_data(pom_target_coord,dist);
normal_target= atlas_uv_to_bilinear_data_normal(pom_target_coord,dist);
specular_target=atlas_uv_to_bilinear_data_specular(pom_target_coord,dist);
#endif

#if TEXTURE_FILTERING_CPF == 3
albedo_target=vec4(1.0,1.0,1.0,1.0);
normal_target=vec4(0.5,0.5,1.0,1.0);
specular_target=vec4(0.0,0.0,0.0,1.0);
#endif

#if TEXTURE_FILTERING_CPF == 4
vec3 bumpy = atlas_uv_to_bilinear_data_normal(pom_target_coord,dist).rgb;
bumpy = normal_tex_to_view_cpf(bumpy);
bumpy= (bumpy+1)*.5;
albedo_target=vec4(bumpy.r,bumpy.g,bumpy.b,1.0);
normal_target= atlas_uv_to_bilinear_data_normal(pom_target_coord,dist);
specular_target=atlas_uv_to_bilinear_data_specular(pom_target_coord,dist);
#endif


#if TEXTURE_FILTERING_CPF == 5
vec3 bumpy = atlas_uv_to_bilinear_data_normal(pom_target_coord,dist).rgb;
bumpy = vec3(.5,.5,1);
bumpy = normal_to_view_cpf(bumpy);
bumpy= (bumpy+1)*.5;
bumpy.b=bumpy.b*2-1;
albedo_target=vec4(bumpy.b,bumpy.b,bumpy.b,1.0);
normal_target= atlas_uv_to_bilinear_data_normal(pom_target_coord,dist);
specular_target=atlas_uv_to_bilinear_data_specular(pom_target_coord,dist);
#endif
}

	
#endif
//end if ENABLE_CTMPOMFIX_POM_SPACE




#endif
#endif
//end if CTMPOMFIX == 1





// /> end of core CTMPOMFIX code, just inserts to function calls after this and optimizations