All-In-Wonder-cg        
All_In_Wonder.cg
//TITLE: 
    //
    //	FAST_MONSTER_SHADER
 
 
 
    //DESCRIPTION:
    //	lots of tuneable params, in 1-pass, less accurate (see PURE THEORY)
 
 
 
    //TODO:
    //
    //	Alpha testing, specular level in diffuse alpha, environment lookup, ambient occlusion map, 
    //	2-texture using cheap and nice detail texturing (even for offset-maps), etc. could be still
    //	added, happy tweaking pioneers out there.
    //	Though less fast, multipass solution would allow for more instructions in 1 pass, if all
    //	the goodies listed above won't fit into 64 instuction limit of ps2.0 .
 
 
 
    //WARNING: PURE THEORY :)
    //
    //	This version has 1 defect, which is precision:
    //	Non-linear interpolation of per-vertex lightdir and eyedir(->halfangle) in vertex
    //  shader causes distortions when light is about poly-size distance from a large poly (or closer)
    //	but this is unperceptible when cam is farther (eg. in most cases).
    //	When cam approaches surface that close, shader switching is the optimal solution
    //  though that other shader being nice and accurate, is quite costy, and cannot be realized
    //  for 3 lights in 1 pass, because far more calculations (lightdir and eyedir) are in 
    //  fragment shader, and instruction count is limited to 64 in ps2.0
    //
    //	Remaining options: 
    //		- not use this precise one (aka. never let cam that close to a poly)
    //		- use a second shader like this monster, but only for 1 light, and make it
    //		  multipass (a bit slower) 
    //		  (I will try if 2 lights can be pushed below instruction count limit though
    //		   'cause there might be cases when 2 lights would be enought)
    //		- never use more than 1(maybe 2 if I can do it) lights that close, thus monster remains
    //		  an 1-pass shader, though still quite costy (about -10..-15 FPS max.)
    //
    //  (Also note that distance for attenuation is calculated at per-vertex level - attenuation
    //   can't be because it is non-linear, so remains to the frag shader, but as always, I will
    //	 try how it looks, and if you are fine with just linear attenuation, who knows? Might work
    //	 as well, and fast :)
    //
    //  (thanks for all this info on distorsion Sinbad!)
 
 
 
    //BUGS(?) AND FLAWS:
    //
    //	Ogre log complains about not being able to hand the shader all uniforms and custom
    //	parameters when running the shader with reduced parameter count
    //  - hardly effects performance or quality :) - but if you put comments ('//') into
    //	material parser before those unused params, all is perfect
    //
    //	Please report any bugs, performance bottlenecks, possible optimizations. See CONTACT.
 
 
 
    //HOW I COMPUTE THINGS (just to be consistent with techicals)
    //
    //	For this shader, I put performance over quality.
    //	This means: - NdotL, pow((NdotH),exponent))	-> no reflection vector
    //				- less accuracy when light is close to surface (see PURE THEORY on this)
    //				- attenuation has just linear component varying(k1), and is calculated in
    //				  vertex shader, and interpolated to frag shader automatically
    //				- specular exponents are the same for the 3 lights, change it if u wish
    //
    //	ALSO NOTE WELL:
    //				- I use no material light reflection coefficients, they are doing (1,1,1) to
    //				  all kinds of lights (diff, amb, spec)
    //				- diffuse texture is modulating diffuse light component only
    //				- there in no such thing as ambient light component here, just big global ambient
    //				  colour as a general environment lighting imitation
    //				- I attenuate diffuse and specular both, and only them
    //
    //				- at maximum-complexity, it does perpixel offset-mapping with modulative 
    //				  diffuse texturing, and with ambient, diffuse, and specular components,
    //				  also attenuation
    //				  Expect extensions later.
    //
    //				- Since I have only 7 texcoords in vs2.0/ps2.0, and for attenuation, I need
    //				  to pass distance to frag shader, and not calculate it there, to be fast, 
    //				  I need an 8th.
    //				  To have attenuation, I decided that it will use the slot of halfvector of
    //				  light3.
    //				  IF YOU USE ATTENUATION, YOU WON'T GET SPECULAR OF THE 3RD LIGHT!
    //				  To add, this version suffers from the precision bug (mentioned in THEORY),
    //				  so expect proper attenuation only when perpixel is proper, too.
    //				  (You might change this to let it have specular, IF it does not have diffuse,
    //				   if wish, but I believe this way is more common.
    //				   Or, do you know a situation when specular of 3rd light is needed with atten?)
    //
    //	As you see, this shader is quite efficient (mainly being 1-pass), supports 3 lights,
    //	but techniques used are quite simple.
 
 
 
    //CONTACT:
    //
    //	the name is guilderstein, email: forgamedev@yahoo.com, insert OGRE into subject please
 
 
 
    //USAGE SUGGESTIONS:
    //	
    //	PLEASE AVOID OBSCURE/ESOTERIC USAGE PARAMETERS
    //	(like OFFSET on, but ANY_TEXTURE off)
    //	I guess you will try it just to make it sweat, anyway :)
    //
    //	REQUIREMENTS: (VERY IMPORTANT FOR EFFICIENCY AND CORRECT RESULTS)
    //		1. Can be used with no lights just DIFFUSE_TEXTURE, but turn off OFFSET/NORMAL-mapping,
    //		   ATTENUATION, DIFFUSE, and SPECULAR!
    //		2. When doing OFFSET/NORMAL-mapping, leave ANY_TEXTURE and at least LIGHT0
    //		   AND DIFFUSE or SPECULAR on !
    //		3. DIFFUSE_TEXTURE needs ANY_TEXTURE on. LIGHTx needs at least DIFFUSE or SPECULAR.
    //		   DIFFUSE and SPECULAR needs LIGHTx.
    //		4. When using with fewer than 3 lights, turn off lights in this order: 2,1,0 !
    //		5. Use ATTENUATION with AT_LEAST light0 AND diffuse OR specular on !
    //		6. Due to technical constraints, using ATTENUATION means no specular from light2 !
    //		7. Try to use it with healty parameter-combos, at all time !
    //
    //
    //
    //	YOU'VE BEEN WARNED :D
    //
    //
    //
    //Tried working configs: full, full with just offset 0, full but just perpixel,
    //						 any above with less lights (not 0, see above!),
    //						 many combos with diffuse, specular, and ambient with above ones
    //						 zero lights with just texturing (good for debugging, etc.)
    //
    //						 Attenuation might have issues. No guarantee for that. Yet.
    //
    //	So shall be workin' if you keep yourself to the 6 rules above.
    //
    //	If you want to look at the code/know what happens when you turn sg. on/off, I suggest
    //	using MSVC8. Though cannot compile, and you get syntax highlighting only for C parts,
    //	it grays out unused code for you - real-time, during you write it. 
    //	Quite handy if you ask me :).
 
 
 
    //LIMITATIONS, PROS, CONTRAS, FUTURE
    //
    // The good:
    //
    //	- VERY fast, thanks to being 1 pass
    //		(in fact, when run with the same options, faster than every other shader I wrote :)
    //	- Compile time tuneable options, 1 fast shader for LOTS of scenarios.
    //	  Just reload the shader after changing some 0s to 1s in first few lines with a key
    //	  binding or anything in Ogre.
    //
    // The bad:
    //
    //	- Limited to 3 lights, and with attenuation, you mush make other restrictions, due to its
    //	  massive instruction count (read on about this)
    //	- Not exact in when lights are close to surfaces which have very few, very large polys
    //	  (though this is rare case, and you can switch it that situation to another shader)
    //
    // And the ugly:
    //
    //	- Anytime you add another feature, either new limitations arise, to keep it below instruction
    //	  count, being a ps2.0 shader (64 is way_not_enough), or
    //	- Another ugly thing: this beast needs LOTS of data to traverse between vert and frag
    //	  shaders, and bingding semantics are limited, again way_tooo_much 
    //	  (8 texcoords, 1 pos, 1 normal, few worthless extras like color)
    //	  
    // So, it can run full speed, full feature wo. attenuation. Thats the deal.
    // With atten on, you much cut it somewhere. Either set offset and ambient to 0 
    // (you can still have normal-mapping though), or use only 2 lights.
    // AND apart from that, I need another binding semantic, but I do not have any left, so light2's
    // specular is the sacrifice.
    // (again, in major number of environments, the 3rd closest lights specular contrib can be
    //  omitted, given attenuation is more important, at least I think so)
    //
    //
    // In closing, about future: more features, and 2 more versions: 1 slow but featurefull multipass
    // one, and 1 slow VERY accurate one, which you can use in front of players looking at 1 poly
    // walls.
 
 
 
    //TWEAK HERE
    //
    //	#define PER_VERTEX 1				-> TODO /?/
    //	#define SPOT_LIGHTS 1				-> TODO
    //	#define DETAIL_BUMP_TEXTURE 1		-> TODO (bump means normal map, height in alpha optional)
    //	#define DETAIL_DIFFUSE_TEXTURE 1	-> TODO
    //	#define SPECULAR_POWER_TEXTURE 1	-> TODO (stored in diffuse texture's alpha)
    //	#define ENVIRONMENT_MAPPING 1		-> TODO
    //	#define AMBIENT_OCCLUSION 1			-> TODO (modulates envir. lighting aka. ambient)
    //	#define OPACITY_TEXTURE 1			-> TODO (offset-mapped decals, for.ex)
    //
    //	Other suggestions?
 
    #define ATTENUATION 1
 
    #define ANY_TEXTURE 1
    #define DIFFUSE_TEXTURE 1
 
    #define AT_LEAST_PERPIXEL 1
    #define AT_LEAST_NORMAL_MAPPING 1
    #define OFFSET_MAPPING 1
 
    #define AMBIENT 1
    #define DIFFUSE 1
    #define SPECULAR 1
 
    #define LIGHT0 1
    #define LIGHT1 1
    #define LIGHT2 0
 
    // Helper: Expand a range-compressed vector
    float3 expand(float3 v)
    {
        return (v - 0.5) * 2;
    }
 
 
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //									VERT COMES
    /////////////////////////////////////////////////////////////////////////////////////////////////
 
 
    //quite chaotic form, maybe more logical arrangement possible
    void WonderShader_Lim3_Fast_Vert
    (
             float4 position	: POSITION,
             float3 normal		: NORMAL,
             out float4 oPosition	: POSITION,
 
        #if ANY_TEXTURE
             float2 uv		: TEXCOORD0,
             out float2 oUv		: TEXCOORD0,
             uniform float scale,
        #endif
 
        #if AT_LEAST_NORMAL_MAPPING
             float3 tangent     	: TEXCOORD1,
        #elif AT_LEAST_PERPIXEL  //just normal perpixel, use texcoord7 to transmit to frag (holds eyedir in offset case)
             out float3 oNorm	: TEXCOORD7,
        #endif
             
 
    // Still in frag shader!	
    //	#if AMBIENT
    //		uniform float4 ambient,
    //		out float4 oColor	: COLOR,
    //	#endif
 
 
        #if LIGHT0
             uniform float4 lightPosition0, // object space
          #if DIFFUSE
             out float3 oLightDir0  : TEXCOORD1,
          #endif
          #if SPECULAR
             out float3 oHalfAngle0	: TEXCOORD4,
          #endif
        #endif
 
        #if LIGHT1
             uniform float4 lightPosition1, // object space
          #if DIFFUSE
             out float3 oLightDir1  : TEXCOORD2,
          #endif
          #if SPECULAR
             out float3 oHalfAngle1	: TEXCOORD5,
          #endif
        #endif
 
        #if LIGHT2
             uniform float4 lightPosition2, // object space
          #if DIFFUSE
             out float3 oLightDir2	: TEXCOORD3,
          #endif
        #endif
 
        #if ATTENUATION
          out float4 dist	: TEXCOORD6, // .x, .y, and .z is used for light distances
        #elif SPECULAR
          out float3 oHalfAngle2	: TEXCOORD6,
        #endif 
 
        #if OFFSET_MAPPING  //needs eye no matter specular
             uniform float3 eyePosition,   // object space
             out float3 oEyeDir     : TEXCOORD7,
        #elif SPECULAR	//no need to output eye, even if normal-mapping is on
             uniform float3 eyePosition,   // object space
        #endif
             
             uniform float4x4 worldviewproj 
    )
    {
        oPosition = mul(worldviewproj , position);
 
    #if ANY_TEXTURE
        oUv = uv * scale;
    #endif
 
 
    #if AT_LEAST_NORMAL_MAPPING	
        float3 binormal = cross(tangent, normal);
        float3x3 rotation = float3x3(tangent, binormal, normal);
    #elif AT_LEAST_PERPIXEL
        oNorm = normal;
    #endif
 
 
    #if OFFSET_MAPPING	//no matter specular, I need eye for offsetting
        float3 eyeDir = eyePosition - position.xyz;
        eyeDir = normalize(mul(rotation, eyeDir));
        oEyeDir = eyeDir;
    #elif SPECULAR	//I need eye only if specular other than offset, plus no eye output now
        float3 eyeDir = normalize(eyePosition - position.xyz);
      #if AT_LEAST_NORMAL_MAPPING  //eye needs adjustment if normal-mapping
        eyeDir = normalize(mul(rotation, eyeDir));
      #endif
    #endif
 
    //if DIFFUSE is commented out, we only need temp_lightDirX for oHalfAngle
    //and if both DIFFUSE and SPECULAR is out, we shall not calculate any lighting
    #if LIGHT0
      #if ATTENUATION
        float3 temp_lightDir0 = lightPosition0.xyz -  (position * lightPosition0.w);
        dist.x = length(temp_lightDir0);
        temp_lightDir0 = temp_lightDir0 / dist.x; //normalize it this way
 
    //	oatten.x = 1/(atten.y + dist0*atten.z + dist0*dist0*atten.w);
            //some attenuation calc, could be faster with some approximation
            //I think at least leaving only kl component
      #else
        float3 temp_lightDir0 = normalize(lightPosition0.xyz -  (position * lightPosition0.w));
      #endif
      #if AT_LEAST_NORMAL_MAPPING
        temp_lightDir0 = normalize(mul(rotation, temp_lightDir0));
        #if DIFFUSE
          oLightDir0 = temp_lightDir0;
        #endif
      #elif DIFFUSE //just normal perpixel
        oLightDir0 = temp_lightDir0;
      #endif
 
      #if SPECULAR
        oHalfAngle0 = normalize(eyeDir + temp_lightDir0);
      #endif
 
    #endif
 
    #if LIGHT1
      #if ATTENUATION
        float3 temp_lightDir1 = lightPosition1.xyz -  (position * lightPosition1.w);
        dist.y = length(temp_lightDir1);
        temp_lightDir1 = temp_lightDir1 / dist.y; //normalize it this way
 
    //	oatten.y = 1/(atten.y + dist1*atten.z + dist1*dist1*atten.w);
            //some attenuation calc, could be faster with some approximation
            //I think at least leaving only kl component
      #else
        float3 temp_lightDir1 = normalize(lightPosition1.xyz -  (position * lightPosition1.w));
      #endif
      #if AT_LEAST_NORMAL_MAPPING
        temp_lightDir1 = normalize(mul(rotation, temp_lightDir1));
        #if DIFFUSE
          oLightDir1 = temp_lightDir1;
        #endif
      #elif DIFFUSE //just normal perpixel
        oLightDir1 = temp_lightDir1;
      #endif
 
      #if SPECULAR
        oHalfAngle1 = normalize(eyeDir + temp_lightDir1);
      #endif
 
    #endif
 
    #if LIGHT2
      #if ATTENUATION
        float3 temp_lightDir2 = lightPosition2.xyz -  (position * lightPosition2.w);
        dist.z = length(temp_lightDir2);
        temp_lightDir2 = temp_lightDir2 / dist.z; //normalize it this way
 
    //	oatten.z = 1/(atten.y + dist2*atten.z + dist2*dist2*atten.w);
            //some attenuation calc, could be faster with some approximation
            //I think at least leaving only kl component
      #else
        float3 temp_lightDir2 = normalize(lightPosition2.xyz -  (position * lightPosition2.w));
        #if SPECULAR
          oHalfAngle2 = normalize(eyeDir + temp_lightDir2);
        #endif
      #endif
      #if AT_LEAST_NORMAL_MAPPING
        temp_lightDir2 = normalize(mul(rotation, temp_lightDir2));
        #if DIFFUSE
          oLightDir2 = temp_lightDir2;
        #endif
      #elif DIFFUSE //just normal perpixel
        oLightDir2 = temp_lightDir2;
      #endif
    #endif
 
    }






    /////////////////////////////////////////////////////////////////////////////////////////////////
    //									FRAG COMES
    /////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
    void WonderShader_Lim3_Fast_Frag(
 
        #if DIFFUSE_TEXTURE
              uniform sampler2D diffuseMap : register(s1),
              float2 uv		: TEXCOORD0,
        #elif ANY_TEXTURE
             float2 uv		: TEXCOORD0,
        #endif
 
        #if LIGHT0
          #if DIFFUSE
             float3 LightDir0  	: TEXCOORD1,
             uniform float4 lightDiffuse0,
          #endif
          #if SPECULAR
             float3 HalfAngle0	: TEXCOORD4,
             uniform float4 lightSpecular0,
          #endif
        #endif
 
        #if LIGHT1
          #if DIFFUSE
             float3 LightDir1  	: TEXCOORD2,
             uniform float4 lightDiffuse1,
          #endif
          #if SPECULAR
             float3 HalfAngle1	: TEXCOORD5,
             uniform float4 lightSpecular1,
          #endif
        #endif
 
        #if LIGHT2
          #if DIFFUSE
             float3 LightDir2	: TEXCOORD3,
             uniform float4 lightDiffuse2,
          #endif
        #endif
             
        #if OFFSET_MAPPING
             float3 EyeDir     	: TEXCOORD7,
             uniform float4 scaleBias,
             uniform sampler2D   normalHeightMap : register(s0),
        #elif AT_LEAST_NORMAL_MAPPING
              uniform sampler2D   normalHeightMap : register(s0),
        #elif AT_LEAST_PERPIXEL	//no normal-mapping, use standard normal, in eyedir's place
             float3 normalvec		: TEXCOORD7,
        #endif
 
        #if SPECULAR
            uniform float exponent0,
    //		uniform float exponent1,
    //		uniform float exponent2,
        #endif
 
        #if AMBIENT
            uniform float4 ambient,
        #endif
 
        #if ATTENUATION	//if on, supposed to have light0 on as well!
            float4 dist		: TEXCOORD6,
            uniform float4 atten0,
          #if LIGHT1
            uniform float4 atten1,
          #endif
          #if LIGHT2
            uniform float4 atten2,
          #endif
        #elif SPECULAR
          #if LIGHT2
             float3 HalfAngle2	: TEXCOORD6,
             uniform float4 lightSpecular2,
          #endif
        #endif
 
            out float4 oColor	: COLOR
        )
    {
    #if OFFSET_MAPPING
        float height = tex2D(normalHeightMap, uv).a;
        float scale = scaleBias.x;
        float bias = scaleBias.y;
        float displacement = (height * scale) + bias;
        float3 uv2 = float3(uv, 1); 
        float2 newTexCoord = ((EyeDir * displacement) + uv2).xy;
        float3 bumpVec = expand(tex2D(normalHeightMap, newTexCoord ).xyz);
        float3 N = normalize(bumpVec);
      #if DIFFUSE_TEXTURE
        float3 diffusetex = tex2D(diffuseMap, newTexCoord).xyz; 
      #endif
    #elif AT_LEAST_NORMAL_MAPPING
        float3 bumpVec = expand(tex2D(normalHeightMap, uv).xyz);
        float3 N = normalize(bumpVec);
      #if DIFFUSE_TEXTURE
        float3 diffusetex = tex2D(diffuseMap, uv).xyz;
      #endif
    #elif AT_LEAST_PERPIXEL
        float3 N = normalize(normalvec);
      #if DIFFUSE_TEXTURE
        float3 diffusetex = tex2D(diffuseMap, uv).xyz;
      #endif
    #elif DIFFUSE_TEXTURE
        float3 diffusetex = tex2D(diffuseMap, uv).xyz;
    #endif	
 
 
    //If different exponents for different specular-lights, change 3 places here!
 
    #if LIGHT0
      #if DIFFUSE
        float NdotL0 = dot(normalize(LightDir0), N);
        #if SPECULAR //both
          float NdotH0 = dot(normalize(HalfAngle0), N);
          float4 Lit0 = lit(NdotL0,NdotH0,exponent0);
        #else //just diffuse
          float4 Lit0;
          Lit0.y = saturate(NdotL0);
        #endif
      #elif SPECULAR //just specular
        float NdotH0 = dot(normalize(HalfAngle0), N);
        float4 Lit0;
        Lit0.z = pow(saturate(NdotH0),exponent0);
      #endif
    #endif
 
    #if LIGHT1
      #if DIFFUSE
        float NdotL1 = dot(normalize(LightDir1), N);
        #if SPECULAR //both
          float NdotH1 = dot(normalize(HalfAngle1), N);
          float4 Lit1 = lit(NdotL1,NdotH1,exponent0);
        #else //just diffuse
          float4 Lit1;
          Lit1.y = saturate(NdotL1);
        #endif
      #elif SPECULAR //just specular
        float NdotH1 = dot(normalize(HalfAngle1), N);
        float4 Lit1;
        Lit1.z = pow(saturate(NdotH1),exponent0);
      #endif
    #endif
 
    #if LIGHT2
      #if DIFFUSE
        float NdotL2 = dot(normalize(LightDir2), N);
        #if SPECULAR //both
          #if !ATTENUATION
            float NdotH2 = dot(normalize(HalfAngle2), N);
            float4 Lit2 = lit(NdotL2,NdotH2,exponent0);
          #else
            float4 Lit2;
            Lit2.y = saturate(NdotL2);
          #endif
        #else //just diffuse
          float4 Lit2;
          Lit2.y = saturate(NdotL2);
        #endif
      #elif SPECULAR //just specular
        #if !ATTENUATION
          float NdotH2 = dot(normalize(HalfAngle2), N);
          float4 Lit2;
          Lit2.z = pow(saturate(NdotH2),exponent0);
        #else
          float4 Lit2;
          Lit2 = float4(1,0,0,1);
        #endif
      #endif
    #endif
 
        oColor = 
 
    #if ATTENUATION //since usage rules specify it, we have at least light0 on with at least either
                    //diffuse or specular also on !
                    // - if you want no lighting, just textures, turn attenuation off!
                    //But yes, you can have diffusetex with just specular :)
                    //Note that you can't have specular of light2 with attenuation on. See docs.
 
    // Final color formula with atten
    // oColor = atten0 * (diffusetex * lightDiffuse0 * Lit0.y + lightSpecular0 * Lit0.z)
    //		    atten1 * (diffusetex * lightDiffuse1 * Lit1.y + lightSpecular1 * Lit1.z)
    //		    atten2 * (diffusetex * lightDiffuse2 * Lit2.y + lightSpecular2 * Lit2.z)
    //		    + ambient;
 
      #if !DIFFUSE	//we start with the no diffuse just diffusetex case, here only spec is attenuated
        #if DIFFUSE_TEXTURE
          float4(diffusetex,1) +
        #endif
      #endif
 
      1/(atten0.y + atten0.z*dist.x + atten0.w*dist.x*dist.x)* (
        //we always have light0 on here, and spec0 or diffuse0 with it
      #if SPECULAR
        lightSpecular0 * Lit0.z
        #if DIFFUSE
          +
        #else //light0 has only spec, light0 done
          )
        #endif
      #endif
      #if DIFFUSE
        lightDiffuse0 * Lit0.y	//without + sign, we are good at no specular case as well
        #if DIFFUSE_TEXTURE
          * float4(diffusetex,1)) //light0 done
        #else
          ) //light0 done
        #endif
      #endif
 
      #if LIGHT1	//optional, but if we have it, we have either diff1 or spec1, difftex can be 0/1
        + 1/(atten1.y + atten1.z*dist.y + atten1.w*dist.y*dist.y) * (
        #if SPECULAR
          lightSpecular1 * Lit1.z
          #if DIFFUSE
            +
          #else //light1 has only spec, light1 done
            )
          #endif
        #endif
 
        #if DIFFUSE
          lightDiffuse1 * Lit1.y	//without + sign here, we are good at no specular case as well
          #if DIFFUSE_TEXTURE
            * float4(diffusetex,1)) //light1 done
          #else
            ) //light1 done
          #endif
        #endif
      #endif
 
      #if LIGHT2	//ditto goes for diff2, and difftex (no specular here)
        + 1/(atten2.y + atten2.z*dist.z + atten2.w*dist.z*dist.z) * (
        #if DIFFUSE
          lightDiffuse2 * Lit2.y	//without + sign here, we are good at no specular case as well
          #if DIFFUSE_TEXTURE
            * float4(diffusetex,1)) //light2 done
          #else
            ) //light2 done
          #endif
        #endif
      #endif
 
    #else
 
    // And wo. atten
    // oColor = diffusetex 
    //		    * (lightDiffuse0 * Lit0.y + lightDiffuse1 * Lit1.y + lightDiffuse2 * Lit2.y)
    //		    + lightSpecular0 * Lit0.z + lightSpecular1 * Lit1.z + lightSpecular2 * Lit2.z
    //		    + ambient;
 
      float4(0,0,0,0)	//this is needed to simplify preprocessor stuff, no FPS cost :)
 
      #if DIFFUSE_TEXTURE //at least diffuse texture, no lighting yet
          + float4(diffusetex,1)
        #if DIFFUSE //modulate texture with lighting
          *(
          #if LIGHT0
            lightDiffuse0 * Lit0.y
          #endif
          #if LIGHT1
            + lightDiffuse1 * Lit1.y
          #endif
          #if LIGHT2
            + lightDiffuse2 * Lit2.y
          #endif
          )
        #endif
      #elif DIFFUSE //just diffuse lighting, no modulation
          #if LIGHT0
            + lightDiffuse0 * Lit0.y
          #endif
          #if LIGHT1
            + lightDiffuse1 * Lit1.y
          #endif
          #if LIGHT2
            + lightDiffuse2 * Lit2.y
          #endif
      #endif
        
      #if SPECULAR
        #if LIGHT0
          + lightSpecular0 * Lit0.z
        #endif
        #if LIGHT1
          + lightSpecular1 * Lit1.z
        #endif
        #if LIGHT2  
          + lightSpecular2 * Lit2.z
        #endif
      #endif
    #endif
 
    #if AMBIENT
        + ambient
    #endif
        ;
 
 
    }