!!ARBfp1.0

#textures:
#texture[0], 2D		- normal map with water noise normals
#texture[1], 2D		- reflection texture from pass 1
#texture[2], 2D		- foam texture
#texture[3], 2D		- amount of foam

OPTION	ARB_fog_linear;	# define this or ARB_fog_exp, ARB_fog_exp2 for using fog, fixme test if it works
	# this just adds 2-3 commands to the shader doing the simple fog calculations.
	# see fragment_program.txt, we can do it on owr own...

ATTRIB	noisetexc = fragment.texcoord[0];	# texcoords for noisemap
ATTRIB	reflectiontexc = fragment.texcoord[1];	# texcoords for reflection texture
ATTRIB	viewerdir = fragment.texcoord[2];	# vector to viewer (E)
ATTRIB	halfangle = fragment.texcoord[3]; 	# half angle vector (H=L*E)
ATTRIB	upwellingcolor = fragment.color;
# we also need special (modified) reflectiontexc for the foam (x,y,w). These values are coded in
# noisetexc.zw and reflectiontexc.z

PARAM	lightcolor = state.light[0].diffuse;
PARAM	matshininess = state.material.shininess;

OUTPUT	outputcolor = result.color;			# fragment color output

TEMP	E;		# direction to viewer (normalized)
TEMP	H;		# halfangle (normalized)
TEMP	N;		# normal, from normal map (normalized)
TEMP	fresnel;
TEMP	speccol;
TEMP	tmp;
TEMP	reflectioncol;
TEMP	tmp2;
TEMP	tmp3;

# fixme: new idea: compute perlin noise in fragment program. from a lower res map
# a high detailed noise can be computed with some texture lookups. so normal map
# could be computed on the fly, maybe leading to higher precision normals
# avoiding the quantization effect with specular mapping


# 1. get and normalize normal vector from texmap
TEX	N, noisetexc, texture[0], 2D;	# get
MAD	N, N, 2, -1;			# expand
DP3	N.w, N, N;			# normalize
RSQ	N.w, N.w;
MUL	N.xyz, N.w, N;
# fixme: the resulting normals are not very smooth across pixels, leading to ugly effects.
#MOV N.x,0;
#MOV N.y,0;
#MOV N.z,1;


# 2. get and normalize halfangle
DP3	H.w, halfangle, halfangle;
RSQ	H.w, H.w;
MUL	H.xyz, H.w, halfangle;


# 3. get and normalize vector to viewer
DP3	E.w, viewerdir, viewerdir;
RSQ	E.w, E.w;
MUL	E.xyz, E.w, viewerdir;


# 4. compute fresnel term
# 4.1. compute E*N, we need to saturate because the product because it
#      could be negative when the angle between face normal
#      and viewer is nearly perpendicular
##DP3_SAT	fresnel.x, E, N;
DP3	fresnel.x, E, N;
ABS_SAT	fresnel.x, fresnel.x;

#fixme: this computation causes large(r) areas where the fresnel term is near zero
# maybe because of this saturation... yes, it seems so.
#MAD	fresnel.x, fresnel.x, 0.8, 0.2;
#but taking the absolute value or something the like doesn't seem to help
#absolute value would map negative values back to positive area.
#that looks like rings of mirror areas etc. ugly
#ABS	fresnel.x, fresnel.x;

# 4.2. compute fresnel term approximation 1/((1+x)^8) for x in [0...1]
#      fixme: maybe one POW is faster than three MULs...
# fixme 2: maybe this is not very accurate, better use a lookup texture? No, doesn't look better.
# fixme 3: do pow first and then rcp or other way round? which is more accurate?
ADD	fresnel.x, fresnel.x, 1;
##RCP	fresnel.x, fresnel.x;
MUL	fresnel.y, fresnel.x, fresnel.x;
MUL	fresnel.z, fresnel.y, fresnel.y;
MUL	fresnel.x, fresnel.z, fresnel.z;
RCP	fresnel.x, fresnel.x;

MUL	fresnel.x, fresnel.x, 0.8;	# test, never use full reflectivity, at most 0.8
# that multiplication greatly increases the realism of the appearance!


# 5. compute specular light brightness (blinn-phong shading)
#    spec = (H.N)^shininess
DP3_SAT	tmp, H, N;
MOV tmp.w,160;
POW	tmp.x, tmp.x, tmp.w; # matshininess.x;	# fixme: could be read from a 1D map if that is faster
	#fixme: maybe a 1D lookup map is more precise?
	#no it seems not faster or not much faster and NOT more precise.
	#the problem is the texture mapping. either the coordinates are not
	#interpolated smooth enough or the texture lookup is not precise enough.
	#the problem is the normal lookup from the texture map. with constant normal the effect vanishes.
	#it seems that the variables/registers in fragment programs are not precise enough.
	#fixme: shininess is not set in program yet
MUL	speccol, lightcolor, tmp.x;


# 6. get reflection color
# fixme: tweak texture coordinates with normal and real position...
TXP	reflectioncol, reflectiontexc, texture[1], 2D;


# 7. result is interpolation between texture1 (reflection) and upwelling color
#   (interpolated with fresnel term)
#   (get upwelling color from fragment color)
LRP	tmp, fresnel.x, reflectioncol, upwellingcolor;
ADD	tmp, tmp, speccol;


# 8. foam
# 8.1. fetch amount of foam from map 3 with modified reflectiontexc
MOV	tmp2.x, noisetexc.z;
MOV	tmp2.y, noisetexc.w;
MOV	tmp2.w, reflectiontexc.z;
TXP	tmp2, tmp2, texture[3], 2D;

# 8.2. fetch foam texture from map 2 with noisetexc
TEX	tmp3, noisetexc, texture[2], 2D;
#MUL	tmp2.x, tmp2.x, tmp3.w;	# also use foam texture's alpha value
MUL	tmp2.x, tmp2.x, tmp3.x;	# use foam luminance for mixing
MOV	tmp3.xyz, 1;		# fixme: retrieve foam base color from local parameter (foam is darker at night!)

# 8.3. interpolate between foam color and water color with amount
LRP	outputcolor, tmp2.x, tmp3, tmp;
# do not set outputcolor.w, we have no alpha here...
# outputcolor.w is fetched from inputcolor.w, which is set to upwelling color,
# which is computed from the values given by the C++ program, and thus w=1 here.
#MOV	outputcolor.w, 1;	# fixme: get rid of this


#ADD	outputcolor, tmp, speccol;

#test hacks.
#MOV	outputcolor.xyz, fresnel.x;
#DP3	tmp, E, N;	# hier kommt in der ferne 0 raus, obwohl N variiert. fehlende tangentx?
#MAD	outputcolor.xyz, tmp.x, 0.5, 0.5;
#MAD	outputcolor.xyz, E, 0.5, 0.5;
#MOV	outputcolor, tmp;
#MOV	outputcolor, reflectioncol;
#MOV	outputcolor, upwellingcolor;
#MOV	outputcolor, speccol;
#	MOV outputcolor.xyz, tmp2;
#MOV	outputcolor.xyz, halfangle;


# fixme
# fp does: compute N, compute H.N^shininess =: specular, E.N -> =: fresnel
# compute reflection (with distorsion)
# [fresnel = E.N] , color = lininterpol(fresnel, upwelling(local!), reflection) + specular

END
