!!ARBvp1.0 OPTION ARB_position_invariant ;

# SteveL #3879: Do not distort where the sampled texel would come from a surface closer than
# the water surface. Fix for water distorting player weapon etc. Amendments to frag prog.
# SteveL #4306: Output the "depth" of water between the player and the background into the alpha
# channel, so that subsequent material stages can use it to blend correctly between their own colour and 
# the background color, giving the impression of murky water containing sediment. 
#
#
# input:
# 
# texcoord[0] TEX0	texcoords
#
# local[0]	scroll
# local[1]	deform magnitude (1.0 is reasonable, 2.0 is twice as wavy, 0.5 is half as wavy, etc)
# local[2]  depth of this material needed to completely hide the background. #4306
#
# output:
# 
# texCoord[1] is the model surface texture coords
# texCoord[2] is the copied deform magnitude
# vertex color is used to pass the depth from local[2] to the fragment shader #4306

TEMP	R0, R1, R2;

# texture 1 takes the texture coordinates and adds a scroll
ADD		result.texcoord[1], vertex.texcoord[0], program.local[0];

# texture 2 takes the deform magnitude and scales it by the projection distance
PARAM	vec = { 1, 0, 0, 1 };

MOV		R0, vec;
DP4		R0.z, vertex.position, state.matrix.modelview.row[2];

DP4		R1, R0, state.matrix.projection.row[0];
DP4		R2, R0, state.matrix.projection.row[3];

# don't let the recip get near zero for polygons that cross the view plane
MAX		R2, R2, 1;

RCP		R2, R2.w;
MUL		R1, R1, R2;

# clamp the distance so the the deformations don't get too wacky near the view
MIN		R1, R1, 0.02;

MUL		result.texcoord[2], R1, program.local[1];
MOV     result.color, program.local[2];
END

#======================================================================

!!ARBfp1.0 
OPTION ARB_precision_hint_fastest;

# texture 0 is _currentRender
# texture 1 is a normal map that we will use to deform texture 0
# texture 2 is _currentDepth
#
# env[0] is the 1.0 to _currentRender conversion
# env[1] is the fragment.position to 0.0 - 1.0 conversion
#
# Hard-coded constants
#    depth_consts allows us to recover the original depth in Doom units of anything in the depth 
#    buffer. TDM's projection matrix differs slightly from the classic projection matrix as it 
#    implements a "nearly-infinite" zFar. The matrix is hard-coded in the engine, so we use hard-coded 
#    constants here for efficiency. depth_consts is derived from the numbers in that matrix.
#

TEMP	localNormal, R0;

PARAM	subOne = { -1, -1, -1, -1 };
PARAM	scaleTwo = { 2, 2, 2, 2 };

# load the filtered normal map and convert to -1 to 1 range
TEX		localNormal, fragment.texcoord[1], texture[1], 2D;
MOV		localNormal.x, localNormal.a;
MAD		localNormal, localNormal, scaleTwo, subOne;

# calculate the screen texcoord in the 0.0 to 1.0 range
MUL		R0, fragment.position, program.env[1];

# offset by the scaled localNormal and clamp it to 0.0 - 1.0
MAD_SAT	R0, localNormal, fragment.texcoord[2], R0;

# scale by the screen non-power-of-two-adjust
MUL		R0, R0, program.env[0];

# Get the displaced color
TEMP 	displacedColor;
TEX		displacedColor, R0, texture[0], 2D;

# Fix foreground object distortion. Get another sample from the opposite direction, 
# to use if the sample came from the foreground. 
TEMP  	altCoord, altColor, origCoord, chosenColor;
MUL		origCoord, program.env[0], program.env[1];		# Screen space to 
MUL		origCoord, origCoord, fragment.position.xyxy;	# tex coord conversion
SUB	  	altCoord.xy, R0, origCoord; 	# Diff between original coord and distorted coord
ADD   	altCoord, origCoord, -altCoord;	# Now distorted in the opposite direction
TEX   	altColor, altCoord, texture[0], 2D;

# Test whether the samples came from the foreground, rejecting them if so.
# Start with the original undistorted color. We'll use this if both samples came 
# from the foreground.
TEX		chosenColor, origCoord, texture[0], 2D;

# Next 4 lines are needed for #4306 -- alpha depth
# #4306 In each case record the depth of the sample in the alpha channel w
TEMP	depth;
MUL     origCoord.xy, origCoord, program.env[4].zwzw; # zw holds the ratio of _currentRender size to _currentDepth size
TEX     depth, origCoord, texture[2], 2D;
MOV     chosenColor.w, depth.x;

# Test whether the alt color came from the background, and use it in preference if so
MUL     altCoord.xy, altCoord, program.env[4].zwzw; # zw holds the ratio of _currentRender size to _currentDepth size
TEX		depth, altCoord, texture[2], 2D;
MOV     altColor.w, depth.x;  #4306
SUB		depth, depth.x, fragment.position.z;
CMP		chosenColor, depth, chosenColor, altColor;

# Test whether the displaced color came from the background, and use it in preference if so
MUL     R0.xy, R0, program.env[4].zwzw;
TEX		depth, R0, texture[2], 2D;
MOV     displacedColor.w, depth.x;  #4306
SUB		depth, depth.x, fragment.position.z;
CMP		chosenColor, depth, chosenColor, displacedColor;

# #4306 Calculate the opacity of the material using the depth difference between the 
# transparent surface and the solid background

PARAM   depth_consts = { 0.33333333, -0.33316667, 0.0, 0.0 }; 
TEMP    scene_depth, surface_depth, final_rgba;

# Calculate original depth in doom units from the nonlinear depth buffer values we captured earlier
MIN	  chosenColor.w, chosenColor.w, 0.9994;	# Required by TDM projection matrix. Equates to max recoverable 
                                            # depth of 30k units, which is enough. 0.9995 is infinite depth. This
                                            # is needed only if there is caulk sky on show (which writes no depth, 
                                            # so leaves 1 in the depth texture).
MAD   scene_depth, chosenColor.w, depth_consts.x, depth_consts.y;
RCP   scene_depth, scene_depth.x;

# Find the depth of the transparent surface in doom units too
MAD   surface_depth, fragment.position.z, depth_consts.x, depth_consts.y;
RCP   surface_depth, surface_depth.x;

# Calculate the depth diff, divide by the opaque threshold and clamp
# NB depths are negative. We use -tmp in the division to give a positive 
# value where the surface is visible in front of the solid background
ADD       final_rgba, scene_depth, -surface_depth;
MUL_SAT   final_rgba.a, -final_rgba.r, fragment.color.r;   
MOV       final_rgba.rgb, chosenColor;
MOV       result.color, final_rgba;

END

