Posted: 10th Nov 2013 17:01
NEW!!! V 1.1

All code written for V1 will work for V1.1 without modification!

I've now added per-object Alpha to the CSM System! Check it out!

[DOWNLOAD IN NEXT POST]

With CSM you can add cubic shadow mapping to your games with just 4 commands!
+ Code Snippet
//During game init.
CSM_Start(ShadowQuality)
//Before or during your Loop, after object and textures have been
//loaded (called once per object to recieve shadows):
CSM_ObjectTexture(ObjectID, DiffTexID, NormalTexID)
//Called before or during your Loop:
mylight=CSM_LightAdd(X,Y,Z,Range)
//Called at the end of your Loop:
CSM_Update()

//And that's it! :-)


I've written a fully commented example to go with it so it's easy to understand how to use it.

Current Features (new Features in bold):
->Shadow & Normal mapping
->Light flashes
->Pulsating lights (colour and/or range)
->Lights can be dynamically added/deleted
->Debugging functionalliy
->Per Object Alpha
->Optimisation (+2%FPS for me, your milage may vary )

New functions (also explained in example code!):
->CSM_ObjectAlphaEnable(ObjectID as integer, Enable as boolean) ->Enable or disable Alpha for an object
->CSM_ObjectAlphaSet(ObjectID as integer, Alpha as float)
->CSM_Flush() ->Reset the CSM system


Current limitations:
->6 lights max

Next to do (Need help with this):
->Packing shadow maps into colour chanels (allowing upto 18 lights)

Here's the shader code (same as V1):
+ Code Snippet
//====================================================
// Cubic Shadow Mapping
//====================================================
// By EVOLVED, adapted for multiple lights by Bruce Browning
// www.evolved-software.com
//====================================================

//--------------
// un-tweaks
//--------------
   matrix WorldVP:WorldViewProjection; 
   matrix World:World;    
   matrix ViewInv:ViewInverse;       

//--------------
// Tweaks
//--------------
   float3 Ambient={0.01f,0.01f, 0.01f};    
   float4 FogColor={0.8f,0.8f,0.8f,1.0f};
   float FogRange=2500.0f;
   float Alpha=1.0f;
//L0
   float4 LPos_0={150.0f,150.0f,0.0f,1.0f};    
   float3 LCol_0={1.0f,1.0f,1.0f};
   float  LRng_0=350.0f; 
//L1
   float4 LPos_1={-150.0f,150.0f,0.0f,1.0f};
   float3 LCol_1={1.0f,1.0f,1.0f};
   float  LRng_1=350.0f;
//L2
   float4 LPos_2={-150.0f,150.0f,0.0f,1.0f};    
   float3 LCol_2={1.0f,1.0f,1.0f};
   float  LRng_2=350.0f;
//L3
   float4 LPos_3={-150.0f,150.0f,0.0f,1.0f};    
   float3 LCol_3={1.0f,1.0f,1.0f};
   float  LRng_3=350.0f;
//L4
   float4 LPos_4={-150.0f,150.0f,0.0f,1.0f};    
   float3 LCol_4={1.0f,1.0f,1.0f};
   float  LRng_4=350.0f;
//L5
   float4 LPos_5={-150.0f,150.0f,0.0f,1.0f};    
   float3 LCol_5={1.0f,1.0f,1.0f};
   float  LRng_5=350.0f;

//--------------
// Textures
//--------------
   texture BaseTX <string Name=\"\";>;	
   sampler2D Base = sampler_state 
      {
     	texture = <BaseTX>;
      };
   texture NormalTX <string Name=\"\";>;	
   sampler2D Normal = sampler_state 
      {
 	texture = <NormalTX>;
      };
   texture DepthMapTX_0 <string Name=\"\";>;
   sampler DepthMap_0 = sampler_state
      {
	texture = <DepthMapTX_0>;
      };
   texture DepthMapTX_1 <string Name=\"\";>;
   sampler DepthMap_1 = sampler_state
      {
	texture = <DepthMapTX_1>;
      };
   texture DepthMapTX_2 <string Name=\"\";>;
   sampler DepthMap_2 = sampler_state
      {
	texture = <DepthMapTX_2>;
      };
   texture DepthMapTX_3 <string Name=\"\";>;
   sampler DepthMap_3 = sampler_state
      {
	texture = <DepthMapTX_3>;
      };
   texture DepthMapTX_4 <string Name=\"\";>;
   sampler DepthMap_4 = sampler_state
      {
	texture = <DepthMapTX_4>;
      };
   texture DepthMapTX_5 <string Name=\"\";>;
   sampler DepthMap_5 = sampler_state
      {
	texture = <DepthMapTX_5>;
      };

//--------------
// structs 
//--------------
   struct IN_Depth
     {
 	float4 Pos:POSITION; 
     };
   struct OUT_Depth
     {
 	float4 OPos:POSITION; 
 	float3 Depth:TEXCOORD1; 
     };
   struct IN_NormalMap
     {
 	float4 Pos:POSITION; 
 	float2 UV:TEXCOORD; 
	float3 Normal:NORMAL;
 	float3 Tangent:TANGENT;
 	float3 Binormal:BINORMAL;
     };
   struct OUT_NormalMap
     {
	float4 OPos:POSITION; 
 	float2 Tex:TEXCOORD0; 
  	float3 LightVec:TEXCOORD1; 
	float3 Attenuation:TEXCOORD2;
	float3 ViewVec:TEXCOORD3; 
 	float3 ShadowMap:TEXCOORD4; 
	float Fog:FOG;
     };

//--------------
// vertex shaders
//--------------
//--Depth--
   OUT_Depth VS_L0(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_0-WPos; 
        OUT.Depth=-(LightPos/LRng_0); 
        return OUT;
     }
   OUT_Depth VS_L1(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_1-WPos; 
        OUT.Depth=-(LightPos/LRng_1); 
        return OUT;
     }
   OUT_Depth VS_L2(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_2-WPos; 
        OUT.Depth=-(LightPos/LRng_2); 
        return OUT;
     }
   OUT_Depth VS_L3(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_3-WPos; 
        OUT.Depth=-(LightPos/LRng_3); 
        return OUT;
     }
   OUT_Depth VS_L4(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_4-WPos; 
        OUT.Depth=-(LightPos/LRng_4); 
        return OUT;
     }
   OUT_Depth VS_L5(IN_Depth IN)
     {
        OUT_Depth OUT;
        OUT.OPos = mul(IN.Pos,WorldVP); 
        float3 WPos=mul(IN.Pos,World);  
	    float3 LightPos=LPos_5-WPos; 
        OUT.Depth=-(LightPos/LRng_5); 
        return OUT;
     }

//--Mapping--
   OUT_NormalMap VS_NormalMap_L0(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_0-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_0); 
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }
   OUT_NormalMap VS_NormalMap_L1(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_1-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_1);
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }
   OUT_NormalMap VS_NormalMap_L2(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_2-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_2);
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }
   OUT_NormalMap VS_NormalMap_L3(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_3-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_3);
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }
   OUT_NormalMap VS_NormalMap_L4(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_4-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_4);
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }
   OUT_NormalMap VS_NormalMap_L5(IN_NormalMap IN) 
     {
 	OUT_NormalMap OUT;
	OUT.OPos=mul(IN.Pos,WorldVP);
    	OUT.Tex=IN.UV;
	float3x3 TBN={IN.Tangent,IN.Binormal,IN.Normal};
	TBN=transpose(mul(TBN,World));
	float3 WPos=mul(IN.Pos,World);  
	float3 LightPos=LPos_5-WPos; 
	float3 ViewPos=ViewInv[3].xyz-WPos;
	OUT.LightVec=mul(LightPos,TBN);
	OUT.Attenuation=-(LightPos/LRng_5);
 	OUT.ViewVec=mul(ViewPos,TBN);
	OUT.ShadowMap=-LightPos;
	OUT.Fog=1-saturate(dot(ViewPos/FogRange,ViewPos/FogRange));	
	return OUT;
     }


//--------------
// pixel shaders
//--------------
//--Depth--
   float4 PS_L0(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }
   float4 PS_L1(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }
   float4 PS_L2(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }
   float4 PS_L3(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }
   float4 PS_L4(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }
   float4 PS_L5(OUT_Depth IN) : COLOR
     {
	return float4(length(IN.Depth)+0.011f,0,0,1);
     }


//--Mapping--
// L0
   float4 PS_NormalMap_L0(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex); 
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_0*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_0,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_0,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)+Ambient),Texture.w*Alpha);
     }
// L1
   float4 PS_NormalMap_L1(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex);
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_1*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_1,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_1,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)),Texture.w*Alpha);
     }
// L2
   float4 PS_NormalMap_L2(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex);
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_2*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_2,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_2,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)),Texture.w*Alpha);
     }
// L3
   float4 PS_NormalMap_L3(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex);
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_3*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_3,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_3,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)),Texture.w*Alpha);
     }
// L4
   float4 PS_NormalMap_L4(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex);
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_4*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_4,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_4,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)),Texture.w*Alpha);
     }
// L5
   float4 PS_NormalMap_L5(OUT_NormalMap IN)  : COLOR
     {
	float4 Texture=tex2D(Base,IN.Tex);
	float3 NormalMap=tex2D(Normal,IN.Tex)*2-1;
	float3 LightV=normalize(IN.LightVec);  	
	float3 ViewV=normalize(IN.ViewVec);
	NormalMap=normalize(NormalMap);
	float Normal=saturate(dot(reflect(-ViewV,NormalMap),LightV));
	Normal=pow(Normal,16)+saturate(dot(NormalMap,LightV)); 
	float3 Light=LCol_5*(1-dot(IN.Attenuation,IN.Attenuation));
	float Depth=length(IN.Attenuation);
    float shadowmap=1-(texCUBE(DepthMap_5,IN.ShadowMap+float3(-0.8f,-0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.0f,-0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.8f,-0.8f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(-0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
     	shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.0f,0.0f,0.0f)) < Depth ? 0.111f:0.0f);
      	shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.8f,0.0f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(-0.8f,0.8f,0.0f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.0f,0.8f,0.8f)) < Depth ? 0.111f:0.0f);
        shadowmap=shadowmap-(texCUBE(DepthMap_5,IN.ShadowMap+float3(0.8f,0.8f,-0.8f)) < Depth ? 0.111f:0.0f);
	return float4(Texture*((Normal*Light*shadowmap)),Texture.w*Alpha);
     }


//--------------
// techniques   
//--------------
//--Depthmap--
// L0
    technique DepthMap_L0
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L0(); 
 	PixelShader  = compile ps_2_0 PS_L0(); 		
      }
      }
// L1
	technique DepthMap_L1
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L1(); 
 	PixelShader  = compile ps_2_0 PS_L1();
      }
      }
// L2
	technique DepthMap_L2
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L2(); 
 	PixelShader  = compile ps_2_0 PS_L2();
      }
      }
// L3
	technique DepthMap_L3
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L3(); 
 	PixelShader  = compile ps_2_0 PS_L3();
      }
      }
// L4
	technique DepthMap_L4
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L4(); 
 	PixelShader  = compile ps_2_0 PS_L4();
      }
      }
// L5
	technique DepthMap_L5
      {
 	pass p1
      {		
 	VertexShader = compile vs_2_0 VS_L5(); 
 	PixelShader  = compile ps_2_0 PS_L5();
      }
      }

//--Mapping---
   technique ShadowMapping_L0
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;
      }
      }
   technique ShadowMapping_L1
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
      }
	pass p2
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L1(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L1();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;	
      }
      }
   technique ShadowMapping_L2
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
      }
	pass p2
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L1(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L1();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p3
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L2(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L2();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;	
      }
      }
   technique ShadowMapping_L3
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
      }
	pass p2
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L1(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L1();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p3
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L2(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L2();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p4
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L3(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L3();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;	
      }
      }
   technique ShadowMapping_L4
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
      }
	pass p2
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L1(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L1();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p3
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L2(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L2();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p4
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L3(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L3();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p5
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L4(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L4();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;	
      }
      }
   technique ShadowMapping_L5
      {
 	pass p1
      {		
 	vertexShader = compile vs_2_0 VS_NormalMap_L0(); 
 	pixelShader  = compile ps_2_0 PS_NormalMap_L0();
      }
	pass p2
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L1(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L1();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p3
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L2(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L2();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p4
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L3(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L3();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p5
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L4(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L4();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
      }
	pass p6
      {
	vertexShader = compile vs_2_0 VS_NormalMap_L5(); 
	pixelShader  = compile ps_2_0 PS_NormalMap_L5();
	AlphaBlendEnable = True;
 	SrcBlend = ONE;
 	DestBlend = One;
	FOGCOLOR=(FogColor); 
	FOGENABLE=TRUE;	
      }
      }
Posted: 10th Nov 2013 17:01
[Continued message]

And the code for the V1.1 CSM System:
+ Code Snippet
//==========================================================
// Cubic Shadow Mapping -> CSM_ DBP code
//==========================================================
// CSM system by Bruce for use with the adapted shader
// from EVOLVED 'Cubic_Shadow_Mapping_For_CSM.fx'
//==========================================================

//Constants
//Tweakables
#constant CSM_EffectPath "FX/Cubic_Shadow_Mapping_For_CSM.fx"
#constant CSM_Vector4ID 1
#constant CSM_CameraMaskOnFunctionExit %0001
#constant CSM_DebugMessageBufferLength 9

//Untweakables
#constant CSM_MaxCubemaps 5


//Types
type CSM_XYZFloatType
    X as float
    Y as float
    Z as float
endtype
type CSM_RGBType
    R as byte 
    G as byte
    B as byte
endtype
type CSM_LightType
    LightID as integer
    Pos as CSM_XYZFloatType
    Range as float
    Colour as CSM_RGBType
    Active as boolean
    CameraID as integer
    ShadowImage as integer
    LinkedObjectID as integer
    LinkedObjectCameraToPointAtID as integer
    RemoveAfterTime as integer
    LightIsFlash as boolean
    LightPulseTime as integer
    LightPulsePhase as float
    LightPulseSpeed as float
    LightPulseColour1 as CSM_RGBType
    LightPulseColour2 as CSM_RGBType
    LightPulseRange1 as float
    LightPulseRange2 as float
    LightPulseLast as integer
    LightPulseDoNotUpdateRange as boolean
    LightPulseDoNotUpdateColour as boolean    
endtype
type CSM_ObjectType
    ObjectID as integer
    DiffuseTexID as integer
    NormalTexID as integer
    EffectID as integer
endtype


//Globals
global CSM_EffectID as integer
global CSM_LightCount as integer
global CSM_LightActiveCount as integer
global CSM_LightArrayLength as integer
global CSM_ObjectCount as integer
global CSM_ShadowQuality as integer
global CSM_DebugOn as boolean


//Functions

/////////////////////
//   Init system   //
/////////////////////
//Start CSM
function CSM_Start(iShadowQuality as integer)
    local i as integer
    //Get fresh IDs
    CSM_EffectID=CSM_GetFreeEffectID()
    CSM_ShadowQuality=iShadowQuality
    //Load effect    
    load effect CSM_EffectPath,CSM_EffectID,0
    //Set var defaults
    CSM_LightCount=-1 : CSM_LightActiveCount=-1
    //Make array for lights
    dim CSM_Lights() as CSM_LightType : CSM_LightArrayLength=-1    
    //Make array for objects
    dim CSM_Objects() as CSM_ObjectType : CSM_ObjectCount=-1
    //Make vector
    null=make vector4(CSM_Vector4ID)
    //Pre-calc sin func
    dim CSM_Sin(360) as float
        for i=0 to 360 : CSM_Sin(i)=0.5*(1+sin(i)) : Next i
    //Debug setup
    dim CSM_DebugMessages(CSM_DebugMessageBufferLength) as string
Endfunction


////////////////////////////
//   Flush/reset system   //
////////////////////////////
function CSM_Flush()
    local i as integer
    //Remove all the lights
    for i=0 to CSM_LightArrayLength
        CSM_LightRemove(CSM_Lights(0).LightID)         
    Next i
    //Reset light array length var
    CSM_LightArrayLength=-1
    //Objects should be automatiacally taken care of when they are deleted
    CSM_Update()
Endfunction


//////////////////////
//     Objects      //
//////////////////////

//Add object textures & set up for shadows
function CSM_ObjectTexture(ObjectID as integer, DiffuseTextureID as integer, NormalTextureID as integer)
    if CSM_DebugOn>0
        if object exist(ObjectID)=0
            CSM_DebugAddMessage(get time$()+ ": CSM_ObjectTexture -> ERROR: Object does not exist, ObjectID="+str$(ObjectID))
            exitfunction
        endif
        if image exist(DiffuseTextureID)=0 then CSM_DebugAddMessage(get time$()+ ": CSM_ObjectTexture -> ERROR: Diffuse texture does not exist, TextureID="+str$(DiffuseTextureID))        
        if image exist(NormalTextureID)=0 then CSM_DebugAddMessage(get time$()+ ": CSM_ObjectTexture -> ERROR: Normal texture does not exist, TextureID="+str$(NormalTextureID))
    endif
    //Add object data
    add to queue CSM_Objects() : inc CSM_ObjectCount,1
    CSM_Objects().ObjectID=ObjectID : CSM_Objects().DiffuseTexID=DiffuseTextureID : CSM_Objects().NormalTexID=NormalTextureID
    CSM_Objects().EffectID=CSM_EffectID
    //Apply diffuse and normal textures
    if DiffuseTextureID>0 then texture object ObjectID,0,DiffuseTextureID
    if NormalTextureID>0 then texture object ObjectID,1,NormalTextureID
    //Apply cubemaps
    for i=0 to CSM_LightArrayLength
        Apply Cube Map To Object ObjectID,2+i,1+i
    next i
    //Set effect
    set object effect ObjectID,CSM_EffectID
Endfunction


//Remove object
function CSM_ObjectRemove(ObjectID as integer)
    local i as integer
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).ObjectID=ObjectID
            if object exist(ObjectID)=1 then set object mask ObjectID,%0001
            array delete element CSM_Objects(),i
            dec CSM_ObjectCount,1            
            exitfunction
        Endif
    next i    
Endfunction


//Set object transparency
function CSM_ObjectAlphaEnable(ObjectID as integer, AlphaEnabled as boolean)
    local i as integer
    if CSM_DebugOn>0
        if object exist(ObjectID)=0
            CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaEnable -> ERROR: Object does not exist, ObjectID="+str$(ObjectID))
            exitfunction
        endif
    endif
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).ObjectID=ObjectID
            if AlphaEnabled=1
                if CSM_Objects(i).EffectID=CSM_EffectID
                    CSM_Objects(i).EffectID=CSM_GetFreeEffectID()
                    load effect CSM_EffectPath,CSM_Objects(i).EffectID,0
                else
                    CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaEnable -> WARNING: Object already alpha enabled!, ObjectID="+str$(ObjectID))                    
                endif
                set object transparency ObjectID,2
            else
                if CSM_Objects(i).EffectID<>CSM_EffectID then delete effect CSM_Objects(i).EffectID
                CSM_Objects(i).EffectID=CSM_EffectID
                set object transparency ObjectID,1
            endif
            set object effect ObjectID,CSM_Objects(i).EffectID            
            exitfunction
        Endif
    Next i
Endfunction


//Set the alpha value of the obejct
function CSM_ObjectAlphaSet(ObjectID as integer, Alpha as float)
    local i as integer
    if CSM_DebugOn>0
        if object exist(ObjectID)=0
            CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaSet -> ERROR: Object does not exist, ObjectID="+str$(ObjectID))
            exitfunction
        endif
        if Alpha>1.0 OR Alpha<0.0
            CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaSet -> ERROR: Alpha value must be a float in the range 0.0 to 1.0, Alpha="+str$(Alpha))
            if Alpha>1.0 then Alpha=1.0
            if Alpha<0.0 then Alpha=0.0
            CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaSet -> WARNING: Alpha value capped in valid range, Alpha="+str$(Alpha))
        endif
    endif
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).ObjectID=ObjectID
            if CSM_Objects(i).EffectID=CSM_EffectID
                if CSM_DebugOn>0 then CSM_DebugAddMessage(get time$()+ ": CSM_ObjectAlphaSet -> ERROR: Object using default CSM effect, probable cause: object alpha not enabled.")
                exitfunction
            endif
            set effect constant float CSM_Objects(i).EffectID,"Alpha",Alpha
        endif
    Next i
Endfunction


//////////////////////
//      Lights      //
//////////////////////

//Add a light to the system
function CSM_LightAdd(PosX as float,PosY as float,PosZ as float, Range as float)
    local rLightID as integer
    if CSM_DebugOn>0
        if CSM_LightArrayLength+1>CSM_MaxCubemaps
            CSM_DebugAddMessage(get time$()+ ": CSM_LightAdd -> ERROR: No more lights can be created (MAX="+str$(CSM_MaxCubemaps+1)+")")
            exitfunction -1
        else
            CSM_DebugAddMessage(get time$()+ ": CSM_LightAdd -> Light created, LightID="+str$(CSM_LightCount+1))        
        endif
    endif
    //Add to queue and inc vals
    add to queue CSM_Lights() : CSM_LightArrayLength=array count(CSM_Lights())
    inc CSM_LightCount,1 : CSM_Lights().LightID=CSM_LightCount : rLightID=CSM_LightCount
    //Save data
    CSM_Lights().Pos.X=PosX : CSM_Lights().Pos.Y=PosY : CSM_Lights().Pos.Z=PosZ : CSM_Lights().Range=Range
    //Set default vals
    CSM_Lights().Active=1 : inc CSM_LightActiveCount,1 : CSM_Lights().LinkedObjectCameraToPointAtID=-1
    CSM_Lights().Colour.R=255.0 : CSM_Lights().Colour.G=255.0 : CSM_Lights().Colour.B=255.0
    //Make camera, cubemap & image
    CSM_Lights().CameraID=CSM_GetFreeCameraID() : CSM_Lights().ShadowImage=CSM_GetFreeImageID()
    make camera CSM_Lights().CameraID : set camera to image CSM_Lights().CameraID,CSM_Lights().ShadowImage,CSM_ShadowQuality,CSM_ShadowQuality : color backdrop CSM_Lights().CameraID,rgb(255,255,255)
    Make Dynamic Cube Map CSM_LightArrayLength+1,CSM_ShadowQuality
    //Add cubemap to objects
    CSM_LightAddCubemapToObjects(CSM_Lights().LightID)
endfunction rLightID


//Remove a light from the system
function CSM_LightRemove(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightRemove -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    dec CSM_LightArrayLength,1
    if CSM_Lights(QueueIndex).Active>0 then dec CSM_LightActiveCount,1
    delete dynamic cube map QueueIndex+1
    delete camera CSM_Lights(QueueIndex).CameraID
    delete image CSM_Lights(QueueIndex).ShadowImage
    array delete element CSM_Lights(),QueueIndex
Endfunction


//Add a flash to the system
function CSM_LightFlashAdd(PosX as float,PosY as float,PosZ as float, Range as float, FlashDuration as integer)
    local rLightID as integer : rLightID=CSM_LightAdd(PosX,PosY,PosZ, Range)
    if CSM_DebugOn>0
        if rLightID<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightFlashAdd -> ERROR: Light creation failed.")
            exitfunction -1
        endif
    endif
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(rLightID)
    CSM_Lights(QueueIndex).RemoveAfterTime=timer()+FlashDuration
    CSM_Lights(QueueIndex).LightIsFlash=1
Endfunction rLightID


///////////////////////////////////
//   Apply cubemaps to objects   //
///////////////////////////////////

//Apply a new light's cubemap to previously added objects
function CSM_LightAddCubemapToObjects(LightID as integer)
    local i as integer
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightAddCubemapToObjects -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    for i=0 to CSM_ObjectCount
        if object exist(CSM_Objects(i).ObjectID)=0
            if CSM_DebugOn>0
                CSM_DebugAddMessage(get time$()+ ": CSM_LightAddCubemapToObjects -> ERROR: Object does not exist, ObjectID="+str$(CSM_Objects(i).ObjectID)+")")
            endif
        else
            Apply Cube Map To Object CSM_Objects(i).ObjectID,2+QueueIndex,QueueIndex+1
        endif
    Next i
endfunction


//Re-apply all cubemaps to all objects
function CSM_ObjectCubemapsRefresh()
    local i as integer : local j as integer
    for i=0 to CSM_ObjectCount
        for j=0 to CSM_LightArrayLength
            if CSM_DebugOn>0
                if object exist(CSM_Objects(i).ObjectID)=0 then CSM_DebugAddMessage(get time$()+ ": CSM_LightAddCubemapToObjects -> ERROR: Object does not exist, ObjectID="+str$(CSM_Objects(i).ObjectID)+")")
            endif
            Apply Cube Map To Object CSM_Objects(i).ObjectID,2+j,j+1
        next j
    Next i
endfunction


//////////////////////////////
//   Set light properties   //
//////////////////////////////
//Set light active
function CSM_LightSetActive(LightID as integer, Active as boolean)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetActive -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    if CSM_Lights(QueueIndex).Active=0 and Active=1 then inc CSM_LightActiveCount,1
    if CSM_Lights(QueueIndex).Active=1 and Active=0 then dec CSM_LightActiveCount,1
    CSM_Lights(QueueIndex).Active=Active
endfunction

//Set light range
function CSM_LightSetRange(LightID as integer, Range as float)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetRange -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
        if Range<5 then CSM_DebugAddMessage(get time$()+ ": CSM_LightSetRange -> WARNING: Light range is small; a light which doesn't effect objects may give lighting artifacts.")
    endif
    CSM_Lights(QueueIndex).Range=Range
endfunction

//Set light position
function CSM_LightSetPosition(LightID as integer, PosX as float,PosY as float,PosZ as float)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetPosition -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    CSM_Lights(QueueIndex).Pos.X=PosX : CSM_Lights(QueueIndex).Pos.Y=PosY : CSM_Lights(QueueIndex).Pos.Z=PosZ
endfunction

//Set light colour
function CSM_LightSetColour(LightID as integer, R as byte, G as byte, B as byte)
    local fR as float : local fG as float : local fB as float
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetColour -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    CSM_Lights(QueueIndex).Colour.R=R : CSM_Lights(QueueIndex).Colour.G=G : CSM_Lights(QueueIndex).Colour.B=B
endfunction

//Set linked object
function CSM_LightSetLinkedObject(LightID as integer, ObjectID as integer, CameraToPointAtID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetLinkedObject -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
        if object exist(ObjectID)=0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetLinkedObject -> ERROR: Object does not exist. (ObjectID="+str$(ObjectID)+")")
            exitfunction
        endif
        if camera exist(CameraToPointAtID)=0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetLinkedObject -> ERROR: Camera does not exist. (CameraID="+str$(CameraToPointAtID)+")")
            exitfunction
        endif
    endif
    CSM_Lights(QueueIndex).LinkedObjectID=ObjectID
    if CameraToPointAtID>-1 then CSM_Lights(QueueIndex).LinkedObjectCameraToPointAtID=CameraToPointAtID
endfunction

//Set light pulse
function CSM_LightSetPulse(LightID as integer, PulseTime as float, PulsePhase as integer, Range1 as float, Range2 as float, ColourR1 as byte, ColourG1 as byte, ColourB1 as byte, ColourR2 as byte, ColourG2 as byte, ColourB2 as byte)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightSetPulse -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
        if Range<5 then CSM_DebugAddMessage(get time$()+ ": CSM_LightSetPulse -> WARNING: Light range is small; a light which doesn't effect objects may create lighting artifacts.")
    endif
    CSM_Lights(QueueIndex).LightPulseSpeed     =360.0/PulseTime //deg/ms
    CSM_Lights(QueueIndex).LightPulsePhase     =PulsePhase
    CSM_Lights(QueueIndex).LightPulseLast      =timer()
    if ColourR1=ColourR2 and ColourG1=ColourG2 and ColourB1=ColourB2
        CSM_Lights(QueueIndex).LightPulseDoNotUpdateColour =1
    else
        CSM_Lights(QueueIndex).LightPulseColour1.R =ColourR1
        CSM_Lights(QueueIndex).LightPulseColour1.G =ColourG1
        CSM_Lights(QueueIndex).LightPulseColour1.B =ColourB1
        CSM_Lights(QueueIndex).LightPulseColour2.R =ColourR2
        CSM_Lights(QueueIndex).LightPulseColour2.G =ColourG2
        CSM_Lights(QueueIndex).LightPulseColour2.B =ColourB2
    endif   
    if Range1=Range2
        CSM_Lights(QueueIndex).LightPulseDoNotUpdateRange =1
    else
        CSM_Lights(QueueIndex).LightPulseRange1 =Range1
        CSM_Lights(QueueIndex).LightPulseRange2 =Range2
    endif    
Endfunction


//////////////////////////////
//   Get light properties   //
//////////////////////////////

//Get light exist
function CSM_LightExist(LightID as integer)
    if CSM_LightGetArrayIndexByID(LightID)>-1 then exitfunction 1
Endfunction 0

//Get light range
function CSM_LightGetRange(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetRange -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as float : rValue=CSM_Lights(QueueIndex).Range
endfunction rValue

//Get light position
function CSM_LightGetPositionX(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetPositionX -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as float : rValue=CSM_Lights(QueueIndex).Pos.X
endfunction rValue
function CSM_LightGetPositionY(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetPositionY -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as float : rValue=CSM_Lights(QueueIndex).Pos.Y
endfunction rValue
function CSM_LightGetPositionZ(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetPositionZ -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as float : rValue=CSM_Lights(QueueIndex).Pos.Z
endfunction rValue

//Get light colour
function CSM_LightGetColourR(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetColourR -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as byte : rValue=CSM_Lights(QueueIndex).Colour.R
endfunction rValue
function CSM_LightGetColourG(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetColourG -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as byte : rValue=CSM_Lights(QueueIndex).Colour.G
endfunction rValue
function CSM_LightGetColourB(LightID as integer)
    local QueueIndex as integer : QueueIndex=CSM_LightGetArrayIndexByID(LightID)
    if CSM_DebugOn>0
        if QueueIndex<0
            CSM_DebugAddMessage(get time$()+ ": CSM_LightGetColourB -> ERROR: LightID not found. (LightID="+str$(LightID)+")")
            exitfunction
        endif
    endif
    local rValue as byte : rValue=CSM_Lights(QueueIndex).Colour.B
endfunction rValue


//////////////////////////////
//   Set fog properties     //
//////////////////////////////
//Set fog colour
function CSM_FogSetColour(R as byte, G as byte, B as byte)
    local fR as float : local fG as float : local fB as float
    fR=(R*1.0)/255.0 : fG=(G*1.0)/255.0 : fB=(B*1.0)/255.0    
    set vector4 CSM_Vector4ID,fR,fG,fB,0.0 : set effect constant vector CSM_EffectID,"FogColor",CSM_Vector4ID
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).EffectID<>CSM_EffectID then set effect constant vector CSM_Objects(i).EffectID,"FogColor",CSM_Vector4ID
    Next i 
endfunction

//Set fog range
function CSM_FogSetRange(Range as float)
    set effect constant float CSM_EffectID,"FogRange",Range
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).EffectID<>CSM_EffectID then set effect constant float CSM_Objects(i).EffectID,"FogRange",Range        
    Next i
endfunction


///////////////////////
//   Update system   //
///////////////////////
//Update the system
function CSM_Update()
    local i as integer
    local CurrentTime as integer : CurrentTime=timer()
    //Check for object deletion
    CSM_ObjectUpdate()
    //Handle pulse lights
    CSM_LightPulseUpdate()
    //Sort array
    CSM_LightUpdateArray()
    //Place linked objects
    for i=0 to CSM_LightArrayLength
        if CSM_Lights(i).Active>0
            //Update linked object
            if CSM_Lights(i).LinkedObjectID>0
                position object CSM_Lights(i).LinkedObjectID,CSM_Lights(i).Pos.X,CSM_Lights(i).Pos.Y,CSM_Lights(i).Pos.Z
                if CSM_Lights(i).LinkedObjectCameraToPointAtID>-1
                    point object CSM_Lights(i).LinkedObjectID,camera position x(CSM_Lights(i).LinkedObjectCameraToPointAtID),camera position y(CSM_Lights(i).LinkedObjectCameraToPointAtID),camera position z(CSM_Lights(i).LinkedObjectCameraToPointAtID)
                endif
            endif 
        endif
    Next i
    //Render lighting -> Same cubemaps are used for all instances of the CSM shader
    for i=0 to CSM_LightArrayLength
        if CSM_Lights(i).Active>0
            //Render depth map to cube map
            set effect technique CSM_EffectID,"DepthMap_L"+str$(i)
            Render Dynamic Cube Map i+1,CSM_Lights(i).CameraID,CSM_Lights(i).Pos.X,CSM_Lights(i).Pos.Y,CSM_Lights(i).Pos.Z
            
        endif
    Next i
    //Set effect technique for default CSM shader and object shaders
    set effect technique CSM_EffectID,"ShadowMapping_L"+str$(CSM_LightActiveCount)
    for i=0 to CSM_ObjectCount
        if CSM_Objects(i).EffectID<>CSM_EffectID
            set effect technique CSM_Objects(i).EffectID,"ShadowMapping_L"+str$(CSM_LightActiveCount)
        endif
    Next i 
    //Set sync mask ready for exit
    sync mask CSM_CameraMaskOnFunctionExit
    //Delete on render
    for i=0 to CSM_LightArrayLength
        if CSM_Lights(i).LightIsFlash>0
            if CurrentTime>CSM_Lights(i).RemoveAfterTime then CSM_LightRemove(CSM_Lights(i).LightID)
        endif
    Next i  
    //Print debugging data to screen
    if CSM_DebugOn>0 then CSM_DebugPrint()
Endfunction


//Update objects
function CSM_ObjectUpdate()
    local i as integer
    for i=0 to CSM_ObjectCount
        if object exist(CSM_Objects(i).ObjectID)=0
            if CSM_DebugOn>0
                CSM_DebugAddMessage(get time$()+ ": CSM_ObjectUpdate -> Object does not exist, removed from CSM system, ObjectID="+str$(CSM_Objects(i).ObjectID)+")")
            endif
            CSM_ObjectRemove(CSM_Objects(i).ObjectID)
            dec i,1
        endif
    Next i
Endfunction


///////////////////////////////////////
//     Light handling functions      //
///////////////////////////////////////

//Sort array by active
function CSM_LightUpdateArray()
    local i as integer
    local Swapped as boolean
    local tSwap as CSM_LightType
    //Do a bubble sort by active
    repeat
        Swapped=0
        for i=1 to CSM_LightArrayLength
            if CSM_Lights(i-1).Active<CSM_Lights(i).Active
                tSwap           = CSM_Lights(i-1)
                CSM_Lights(i-1) = CSM_Lights(i)
                CSM_Lights(i)   = tSwap
                Swapped=1
            endif            
        Next i
    until Swapped=0
    //Update shader data
     CSM_LightUpdateShaderData()
Endfunction


//Update shader with newest data
function CSM_LightUpdateShaderData()
    local i as integer : local j as integer
    for i=0 to CSM_LightArrayLength
        //Update colour data
        local fR as float : local fG as float : local fB as float
        fR=(CSM_Lights(i).Colour.R*1.0)/255.0 : fG=(CSM_Lights(i).Colour.G*1.0)/255.0 : fB=(CSM_Lights(i).Colour.B*1.0)/255.0
        if fR>255.0 then fR=255.0 : if fG>255.0 then fG=255.0 : if fB>255.0 then fB=255.0   
        set vector4 CSM_Vector4ID,fR,fG,fB,0.0 : set effect constant vector CSM_EffectID,"LCol_"+str$(i),CSM_Vector4ID
        //Update pos data
        set vector4 CSM_Vector4ID,CSM_Lights(i).Pos.X,CSM_Lights(i).Pos.Y,CSM_Lights(i).Pos.Z,0 : set effect constant vector CSM_EffectID,"LPos_"+str$(i),CSM_Vector4ID
        //Update range data
        set effect constant float CSM_EffectID,"LRng_"+str$(i),CSM_Lights(i).Range        
    Next i
    //Update other shader instances
    for j=0 to CSM_ObjectCount
        if CSM_Objects(j).EffectID<>CSM_EffectID
            for i=0 to CSM_LightArrayLength
                //Update colour data
                local fR as float : local fG as float : local fB as float
                fR=(CSM_Lights(i).Colour.R*1.0)/255.0 : fG=(CSM_Lights(i).Colour.G*1.0)/255.0 : fB=(CSM_Lights(i).Colour.B*1.0)/255.0
                if fR>255.0 then fR=255.0 : if fG>255.0 then fG=255.0 : if fB>255.0 then fB=255.0   
                set vector4 CSM_Vector4ID,fR,fG,fB,0.0 : set effect constant vector CSM_Objects(j).EffectID,"LCol_"+str$(i),CSM_Vector4ID
                //Update pos data
                set vector4 CSM_Vector4ID,CSM_Lights(i).Pos.X,CSM_Lights(i).Pos.Y,CSM_Lights(i).Pos.Z,0 : set effect constant vector CSM_Objects(j).EffectID,"LPos_"+str$(i),CSM_Vector4ID
                //Update range data
                set effect constant float CSM_Objects(j).EffectID,"LRng_"+str$(i),CSM_Lights(i).Range        
            Next i            
        endif
    Next j
Endfunction dist


//Update light properties for pulse lights
function CSM_LightPulseUpdate()
    local i as integer : local InterpolatePercent as float
    local CurrentTime as integer : CurrentTime=timer()
    for i=0 to CSM_LightArrayLength
        if CSM_Lights(i).LightPulseSpeed>0.0
            inc CSM_Lights(i).LightPulsePhase, CSM_Lights(i).LightPulseSpeed*(CurrentTime-CSM_Lights(i).LightPulseLast)
            if CSM_Lights(i).LightPulsePhase>360.0 then CSM_Lights(i).LightPulsePhase=0.0
            InterpolatePercent = CSM_Sin(int(CSM_Lights(i).LightPulsePhase))
            if CSM_Lights(QueueIndex).LightPulseDoNotUpdateColour=0
                CSM_Lights(i).Colour.R = CSM_InterpolateByte(CSM_Lights(i).LightPulseColour1.R,CSM_Lights(i).LightPulseColour2.R,InterpolatePercent)
                CSM_Lights(i).Colour.G = CSM_InterpolateByte(CSM_Lights(i).LightPulseColour1.G,CSM_Lights(i).LightPulseColour2.G,InterpolatePercent)
                CSM_Lights(i).Colour.B = CSM_InterpolateByte(CSM_Lights(i).LightPulseColour1.B,CSM_Lights(i).LightPulseColour2.B,InterpolatePercent)
            endif
            if CSM_Lights(QueueIndex).LightPulseDoNotUpdateRange=0 then CSM_Lights(i).Range=CSM_InterpolateByte(CSM_Lights(i).LightPulseRange1,CSM_Lights(i).LightPulseRange2,InterpolatePercent)
            CSM_Lights(i).LightPulseLast =CurrentTime
        endif
    next i
Endfunction


//Interpolate between two values given a percentage
function CSM_InterpolateFloat(Value1 as float, Value2 as float, Percentage as float)
    local rOutput as float
    rOutput=Value1+((Value2-Value1)*Percentage)
Endfunction rOutput
function CSM_InterpolateByte(Value1 as integer, Value2 as integer, Percentage as float)
    local rOutput as integer
    rOutput=Value1+((Value2-Value1)*Percentage)
    if rOutput<0 then rOutput=0
    if rOutput>255 then rOutput=255
Endfunction rOutput


///////////////////////////////
// Get queue index function  //
///////////////////////////////
function CSM_LightGetArrayIndexByID(LightID as integer)
    local i as integer
    //Search lights array
    for i=CSM_LightArrayLength to 0 step -1
        if CSM_Lights(i).LightID=LightID
            exitfunction i
        endif
    Next i    
Endfunction -1


///////////////////////////////
//      Debug functions      //
///////////////////////////////
//Add a message to the debug message buffer
function CSM_DebugAddMessage(MessageString as string)
    local i as integer
    //Check message is not current
    for i=0 to CSM_DebugMessageBufferLength 
        if CSM_DebugMessages(i)=MessageString then exitfunction
    Next i
    //Add message to queue
    for i=0 to CSM_DebugMessageBufferLength-1
        CSM_DebugMessages(i)=CSM_DebugMessages(i+1)
    Next i
    CSM_DebugMessages(CSM_DebugMessageBufferLength)=MessageString
Endfunction


//Print debug messages to screen
function CSM_DebugPrint()
    local TextHeight as integer : TextHeight=(text height("A")+2)
    local x as integer : local y as integer
    local tablex as integer
    local x1 as integer : local x2 as integer : local y1 as integer : local y2 as integer
    //Print basic info at top of screen
    x=20 : y=50
    text x,y,"CSM debug data:": inc y,TextHeight
    text x,y,"Active light count="+str$(CSM_LightActiveCount) : inc y,TextHeight
    //Print light table next
    local ColumnWidth as integer : ColumnWidth=125
    inc y,TextHeight
    tablex=20+(0.5*(text width("Shader light ID"))) : x=tablex
    center text x,y,"Shader light ID": inc x,ColumnWidth : center text x,y,"CSM light ID" : inc x,ColumnWidth : center text x,y,"Position": inc x,ColumnWidth : center text x,y,"Colour": inc x,ColumnWidth : center text x,y,"Range": inc x,ColumnWidth : center text x,y,"Pulse speed": inc x,ColumnWidth : center text x,y,"Pulse phase": inc x,ColumnWidth : center text x,y,"Remove time": inc x,ColumnWidth
    for i=0 to CSM_LightArrayLength
        x=tablex : inc y,TextHeight
        center text x,y,str$(i) : inc x,ColumnWidth
        center text x,y,str$(CSM_Lights(i).LightID) : inc x,ColumnWidth
        center text x,y,str$(int(CSM_Lights(i).Pos.X))+","+str$(int(CSM_Lights(i).Pos.Y))+","+str$(int(CSM_Lights(i).Pos.Z)) : inc x,ColumnWidth
        center text x,y,str$(int(CSM_Lights(i).Colour.R))+","+str$(int(CSM_Lights(i).Colour.G))+","+str$(int(CSM_Lights(i).Colour.B)) : inc x,ColumnWidth
        center text x,y,str$(CSM_Lights(i).Range) : inc x,ColumnWidth
        center text x,y,left$(str$(CSM_Lights(i).LightPulseSpeed),7) : inc x,ColumnWidth
        center text x,y,left$(str$(CSM_Lights(i).LightPulsePhase),7) : inc x,ColumnWidth
        center text x,y,str$(CSM_Lights(i).RemoveAfterTime) : inc x,ColumnWidth   
    Next i
    //Print debug messages at bottom of screen
    y1=screen height()-((CSM_DebugMessageBufferLength+1)*TextHeight)-40 : x1=20
    y2=screen height()-20 : x2 = screen width()-20
    line x1,y1,x2,y1 : line x2,y1,x2,y2 : line x2,y2,x1,y2 : line x1,y2,x1,y1
    x=x1+10 : y=y1+10
    for i=CSM_DebugMessageBufferLength to 0 step -1
        text x,y,CSM_DebugMessages(i)   : inc y,TextHeight
    Next i
Endfunction

//Set debugging on/off
function CSM_SetDebugOn(DebugState as boolean)
    CSM_DebugOn=DebugState
Endfunction


///////////////////////////////
//   Get free... functions   //
///////////////////////////////

//Get a free ID
function CSM_GetFreeCameraID()
    local i as integer
    repeat : inc i : until camera exist(i)=0
Endfunction i
function CSM_GetFreeImageID()
    local i as integer
    repeat : inc i : until image exist(i)=0
Endfunction i
function CSM_GetFreeEffectID()
    local i as integer
    repeat : inc i : until effect exist(i)=0
Endfunction i
function CSM_GetFreeCubemapID()
    local i as integer
    repeat : inc i : until dynamic cube map exist(i)=0
Endfunction i


And here is the example's code:
+ Code Snippet
//==========================================================
// Cubic Shadow Mapping
//==========================================================
// Shader By EVOLVED adapted for multiple lights by Bruce
// DBP code/CSM system by Bruce
//==========================================================

//Include the CSM source file or add it to your project
#include "Functions_CSM_V1_1.dba"

//This is CSM's set debug on function, with it you can turn debugging on or off (by setting 1 for on or 0 for off).
//This get explained a bit more later.
CSM_SetDebugOn(1)

   //Setup Display -> set display to desktop screen resolution
      load dll "user32.dll",1
         Sw=call dll(1,"GetSystemMetrics",0)
         Sh=call dll(1,"GetSystemMetrics",1)
      delete dll 1
      set display mode Sw,Sh,32,1 : set window off
      sync on : sync rate 0
      hide mouse
      
   //Set Text
      set text font "Verdana"
      set text size 15
      set text to bold
      ink rgb(200,200,0),0

   //Setup Camera -> Standard camera setup
      backdrop on
      color backdrop rgb(128,128,128)
      autocam off
      position camera 0,0,-150
      set camera fov 85
      xrotate camera 30
      CamDis#=-100
      
    //CSM start the Cubic Shadow Mapping functions.
     CSM_Start(512)
    //The number called with this function is the shadow quality (the resolution of the shadow maps).
    //The higher the number, the better the shadows will look but the slower the shadow shader will run.
    //Works with any number but powers of 2 are best, 256 is low quality, 512 is my preference and 1024+ is high quality

   //Load Textures to apply to our objects
   //-> the textures with '_n' after the name are normalmaps, you'll need them for the shader to work.
   //If you don't know what a normal map is, google for it, there's loads of info on the web!
      load image "Media/rockwall.dds",1
      load image "Media/rockwall_n.dds",2
      load image "Media/Floor.dds",4
      load image "Media/Floor_n.dds",5
      

   //Create Object -> Load and scale a teapot object
      load object "Media/t-pot.x",1
      scale object 1,4500,4500,4500
      scale object texture 1,0,4,3
    //When we apply our textures to our object, they have to be applied in a specific way, but the next command does all that for us!
    //We call this command like this: CSM_ObjectTexture(Object_ID, Diffuse_Texture_ID, Normalmap_Texture_ID)
    //and that's it! Our object is all set up for shadows and normal mapping! The textures must already be loaded and the object
    //must exist, otherwise the command will fail.
      CSM_ObjectTexture(1,1,2)
    //NEW!! We can now call this function with negative numbers for the texture IDs (Diffuse, Normal, or both) to tell CSM not to
    //apply that texture; if this is done we can apply the textures to the object ourselves.
    
   
    ////////////////////////////////////////////
    /////                ALPHA              ////
    ////////////////////////////////////////////
    //Before we can set an object's alpha value we must first enable it. We can enable or disable alpha with this function:      
      //CSM_ObjectAlphaEnable(1,1)
    //Which is called like this: CSM_ObjectAlphaEnable(ObjectID as integer, AlphaEnabled as boolean)
    //Now that alpha has been enabled we can set an alpha value. Alpha values are float values between 0.0 and 1.0 NOT 0 and 255!!
    //That means to get 75% alpha we simply use an alpha value of 0.75. Let's set the teapot to 50% transparency:
      //CSM_ObjectAlphaSet(1,0.5)
    //This function is called like this: CSM_ObjectAlphaSet(ObjectID as integer, AlphaValue as float)   
    

   //Create floor -> make a floor object so we can see the shadows
    make object box 2,500,1,500
    scale object texture 2,0,5,5
    position object 2,0,-65,0      
    //CSM -> Called like before
    CSM_ObjectTexture(2,4,5)
    

    //Make some random objects to cast shadows
    for i=1 to 50
        obj=3+i
        prim=rnd(2)
        if prim=0 then make object sphere obj,25
        if prim=1 then make object cube obj,25
        if prim=2 then make object cone obj,25
        position object obj,rnd(500)-250,-50,rnd(500)-250
        //Apply textures as before
        CSM_ObjectTexture(obj,1,2)
        //Objects made and not added to the CSM system using 'CSM_ObjectTexture' will still cast shadows. If you want an object NOT to
        //cast a shadow then set the object mask so only camera 0 renders the object:
        //set object mask ObjectID,%0001
        //'%0001' are binary (all binary numbers start with '%' followed by the bits, which are read from right to left) flags
        //for camera rendering. The '1' on the far right is for camera 0, the '0' to the left of the '1' is the flag for camera
        //1, the next '0' for camera 2 and so on upto camera 32 (but you don't need to put in all the zeros!).
        //With this line we are telling DBP that this obejct can only be seen by camera 0.
    Next      


   //Light Flares -> These are objects simply to show us where the lights are!
   //We'll use them later.
      load image "Media/Flare.JPG",998
      make object plain 998,50,50
      texture object 998,998
      ghost object on 998
      set object ambient 998,0
        Clone Object 999,998
        Clone Object 1000,998
        Clone Object 1001,998
        Clone Object 1002,998
        Clone Object 1003,998

    //OK, so now we're going to add a light. We'll use the command 'CSM_LightAdd'
    //the inputs are like so: CSM_LightAdd(Position sdX , Position Y , Position Z , Light Range)
    mylight=CSM_LightAdd(0,75,50,200) 
    //the 'CSM_LightAdd' returns an integer, this is the light's ID which can be used to set, change or get
    //the light's properties.
    //We're going to set a property now:
    CSM_LightSetLinkedObject(mylight,998,PFX_BloomCameraID)
    //Often, you'll want to position an object at the light's source and point this object at a camera (e.g. lens flares).
    //This function allows the system to automatically update the position of the object and point it at the camera ID we give.
    //The inputs are so: CSM_LightSetLinkedObject(Light ID , Object ID , Camera to point at ID) the light, object and camera
    //must exist or the command will fail (with debugging on).
    
    //Let's make some other lights and link the objects we made earlier.
    mylight=CSM_LightAdd(0,75,50,250) 
    CSM_LightSetLinkedObject(mylight,999,PFX_BloomCameraID)
    
    mylight=CSM_LightAdd(-250,50,-250,150)
     CSM_LightSetLinkedObject(mylight,1000,PFX_BloomCameraID)
    //OK, now lights are cool but white is a bit boring. This next command allows us to change the colour of the light
    //it is called like this: CSM_LightSetColour(Light ID , Red component as byte , Green component as byte , Blue component as byte)
    //Here I'll set a random colour.
     CSM_LightSetColour(mylight,rnd(255),rnd(255),rnd(255))
     
    mylight=CSM_LightAdd(250,50,-250,150)
     CSM_LightSetColour(mylight,rnd(255),rnd(255),rnd(255))
     CSM_LightSetLinkedObject(mylight,1001,0)

    mylight=CSM_LightAdd(-250,50,250,150)
     CSM_LightSetLinkedObject(mylight,1002,PFX_BloomCameraID)
    //One more thing we can do is make a pulsating light, we can vary the range or the colour or both, the system will handle interpolation and updating
    //automatically, this one function is all we need:
    //CSM_LightSetPulse(Light ID , Pulse duration in milliseconds , Starting phase angle, Range 1 , Range 2, R1 , G1 , B1 , R2 , G2 , B2)
     CSM_LightSetPulse(mylight,5000.0,0, 75.0,250.0, rnd(255),rnd(255),rnd(255), rnd(255),rnd(255),rnd(255))
     //The pulse function uses a sin-wave to interpolate the values. The starting phase angle is used to start the light a certain way through the pulse
     //e.g. if we wanted a light with a very long duration, say 10 or 20 mins, and wanted it to start bright but then get darker (to simulate
     //a day/night cycle for example) then we would set the phase time appropriately:
     //CSM_LightSetPulse(mylight,500000.0, 90, 10.0,1000.0, 255,255,255, 255,255,255)
     //The pahse angle here is 90 degrees so the pulse will start at the brightest point of the pulse. 180 degrees is the darkest point of the pulse.
    
    //This is an important function. It resets all the cubemaps on all the objects associated with the CSM system.
    //This should be the first thing you try when debugging CSM lights, put this command in after all the objects are set up but before your
    //main loop. It is called without inputs. There shouldn't be any problems here so we won't call it now.
    //CSM_ObjectCubemapsRefresh()



   `Start loop
      do
          
   `Control Camera
      position camera PFX_BloomCameraID,0,0,0
         if mouseclick()=0
            xrotate camera PFX_BloomCameraID,camera angle x(PFX_BloomCameraID)-mousemovey()*0.25
            yrotate camera PFX_BloomCameraID,camera angle y(PFX_BloomCameraID)+mousemovex()*0.25
            if camera angle x(PFX_BloomCameraID)>80 then xrotate camera PFX_BloomCameraID,80
            if camera angle x(PFX_BloomCameraID)<-60 then xrotate camera PFX_BloomCameraID,-60
         endif
         if mouseclick()>0 then CamDis#=CamDis#-mousemovey()*0.25
         CamDis#=CamDis#+mousemovez()*0.25
         if CamDis#>-20 then CamDis#=-20
         if CamDis#<-300 then CamDis#=-300
         move camera PFX_BloomCameraID,CamDis#
         if camera position y(PFX_BloomCameraID)<-60 then position camera PFX_BloomCameraID,camera position x(PFX_BloomCameraID),-60,camera position z(PFX_BloomCameraID)
      mousemovex()=0
      mousemovey()=0

   `Rotate object
      if KEYSTATE(19)=1 and rotate=1 and nopress=0 then rotate=0:nopress=1
      if KEYSTATE(19)=1 and rotate=0 and nopress=0 then rotate=1:nopress=1
      if rotate=1
         rotate object 1,0,object angle y(1)+0.5,0
      endif

   `Move Light(s)
      if KEYSTATE(38)=1 and MoveLight=1 and nopress=0 then MoveLight=0:nopress=1
      if KEYSTATE(38)=1 and MoveLight=0 and nopress=0 then MoveLight=1:nopress=1
         if MoveLight=0
            ang#=wrapvalue(ang#+0.25)
            ang2#=wrapvalue(ang#+120)
            
            //CSM
            //Here we will set a new position for lights 0 and 1 (the first and second lights), this function
            //is called so: CSM_LightSetPosition(Light ID, Position X , Position Y , Position Z) there's 
            //not much more to say about it.
            CSM_LightSetPosition(0,cos(ang#)*90,80,sin(ang#)*90)
            CSM_LightSetPosition(1,cos(ang2#)*90,80,sin(ang2#)*90)
            
         endif

   `Change Texture
      if KEYSTATE(20)=1 and nopress=0
         delete image 1:delete image 2
            inc image
               if image>4 then image=1
               if image=1 then load image "Media/rockwall.dds",1 :load image "Media/rockwall_n.dds",2
               if image=2 then load image "Media/wall1.dds",1:load image "Media/wall1_n.dds",2
               if image=3 then load image "Media/oldwall3.dds",1:load image "Media/oldwall3_n.dds",2
               if image=4 then load image "Media/rock4_1.dds",1 :load image "Media/rock4_1_n.dds",2
                //Retexture objects
                for i=1 to 100
                    if object exist(i)=1 and i<>2 then  CSM_ObjectTexture(i,1,2)   
                Next i             
         nopress=1
      endif

   `Change Object
      if Spacekey()=1 and nopress=0
         delete object 1
             inc object
               if object>5 then object=1
               if object=1 then load object "Media/t-pot.x",1:scale object 1,4500,4500,4500:scale object texture 1,0,4,3
               if object=2 then load object "Media/Tosus.x",1:scale object texture 1,0,1.5,1
               if object=3 then make object box 1,75,75,75
               if object=4 then make object sphere 1,75,40,40:scale object texture 1,0,2,1
               if object=5 then make object cylinder 1,75:scale object texture 1,0,3,1
               CSM_ObjectTexture(1,1,2)
            set object effect 1,1
         nopress=1
      endif      

   `Text
      center text sw/2,15,"T - Change Texture      Space - Change Object      R - Rotate Object      L - Move Light"
      center text sw/2,30,"Return - Flashlight      Arrowkeys - Turn lights on/off      Control - Debug text"
      center text sw/2,45,"FPS  "+str$(screen fps())+"   @   "+str$(sw)+"x"+str$(sh)

    //Here we can turn lights on and off, we can do that with the 'CSM_LightSetActive' function
    //it is called like this: CSM_LightSetActive(Light ID , Active) where 'Active' is 0 for off
    //and 1 for on. This will not remove a light from the system and should be used to temporarily
    //turn lights off or on. To remove a light permanently, the function 'CSM_LightRemove(Light ID)'
    //Should be used. 
    CSM_LightSetActive(0,1-upkey())
    CSM_LightSetActive(1,1-downkey())
    CSM_LightSetActive(3,1-leftkey())
    CSM_LightSetActive(2,1-rightkey())
    
    //Make light flash when return is pressed
    if returnkey()>0 and nopress=0
    //Here is a useful function (e.g. for weapon muzzle flashes). Here we will create a light flash. This is a light which
    //will automatically be removed after a certain amount of time. It is called like this:
    //Light ID = CSM_LightFlashAdd(Position X , Position Y , Position Z , Range , Duration in milliseconds)
    //When the time is over the light will be automatically deleted (it must be made again, you cannot turn it back on with
    //'CSM_LightSetActive'). The settings for this type of light can be set just like a normal light.
    mylight=CSM_LightFlashAdd(250,50,250,150,500)
     CSM_LightSetColour(mylight,rnd(255),rnd(255),rnd(255))
     CSM_LightSetLinkedObject(mylight,1003,0)
    // CSM_LightSetPulse(mylight,500.0,0, 75.0,250.0, rnd(255),rnd(255),rnd(255), rnd(255),rnd(255),rnd(255))
    //We could use the rem'd-out line above to make a pulsating light flash. Try it and see.
        nopress=1
    Endif
    
    //Unlock keys on lift
    if (KEYSTATE(19)+KEYSTATE(38)+KEYSTATE(20)+spacekey()+returnkey())=0 then nopress=0
    
    //This is an example of two functions which weren't used in this demo:
    //     if CSM_LightExist(mylight)=1
    //         CSM_LightRemove(mylight)
    //     endif
    //The 'CSM_LightExist' function is called with a light ID and returns a boolean (1 for light does exist and 0 for light
    //doesn't exist) and the 'CSM_LightRemove' function is called with a light ID and permanently deletes the light (it must
    //be made again, you cannot turn it back on with 'CSM_LightSetActive').
    
    //And one more function we didn't use:
    //CSM_ObjectRemove( ObjectID as integer )
    //This function DOES NOT DELETE THE OBJECT, only removes it from the CSM system so that it is no longer affected by the
    //shader and will not cast shadows.
    
    //And a new function:
    //CSM_Flush()
    //This function is called without arguments. This function returns the CSM system to the state it was in when first started.
    //Basically this is an easy way to reset the system eg. between levels.
    
    //This function MUST be called in your loop after you have positioned, coloured, etc. all your lights & objects
    //but BEFORE the sync function.
    CSM_Update()
    //Here we are again, the CSM_SetDebugOn function. This function just sets debugging on or off, the CSM_Update function prints
    //debug data to the screen. Turning debugging on will reduce performance, turning debugging off will skip error catching/handling.
    CSM_SetDebugOn(controlkey())

    //Sync the screen and loop back to the top.
     sync mask %01 : sync
  loop


All these and the DBP project file are in the download along with a compiled .exe of the example (7MB total).

Comments welcome!

Thanks,
Bruce
Posted: 10th Nov 2013 17:08
Screen shot #1
Posted: 10th Nov 2013 17:08
Screenshot #2
Posted: 10th Nov 2013 17:09
Screenshot #3
Posted: 10th Nov 2013 19:43
Screenshot #4 - on-screen debug text
Posted: 11th Nov 2013 0:17
This is pretty awesome! The only downside (correct me if I'm wrong) is that this shader doesn't support animation. I also always wanted the shadow area to be bigger when I used the original shader.

EDIT I was wrong about it not shadowing boned and animated models, just tried it out and works wonderfully. Thanks for donating this, I think I may have a use for it soon.
Posted: 11th Nov 2013 13:25
This is pretty awesome! The only downside (correct me if I'm wrong) is that this shader doesn't support animation. I also always wanted the shadow area to be bigger when I used the original shader.


You had me worried for a minute!

I think I may have a use for it soon


Glad I could help!

FYI I plan to come back to this after my current project and add more lights (upto 18, this is almost done already) and spotlights too!

Thanks for the feedback!
Posted: 11th Nov 2013 17:59
Nicely Done.

Excellent coding style. So many people write great code examples
except the poor coding style prevents reusing the code with out a rewrite.

FYI I plan to come back to this after my current project and add more lights (up to 18, this is almost done already) and spotlights too!


Would adding that many lights slow down the FPS too much to make it useable in a project?

Thanks for posting.


">
Posted: 12th Nov 2013 17:09
Excellent coding style. So many people write great code examples
except the poor coding style prevents reusing the code with out a rewrite.


Thanks!

Would adding that many lights slow down the FPS too much to make it useable in a project?


Yes and no. It depends on how many lights you use: the light-for-light performance should be the same (if you use 6 lights with this shader you'll get the same performance when you use 6 lights with the next one) but with the advantage of being able to use more lights!

Thanks,
Bruce
Posted: 14th Nov 2013 0:28
I would like to add this to my website if I may.
Posted: 14th Nov 2013 9:23
I would like to add this to my website if I may.


Please do! Remember to check back later for the next Version too!

Thanks,
Bruce
Posted: 28th Nov 2013 19:17
Looks like a good program; will have an observation some time soon.
Posted: 4th Dec 2013 5:37
Very nice will come in handy hopefully you will get more lights going.
Posted: 4th Dec 2013 9:44
Thanks for the comments!

hopefully you will get more lights going.


Yeah, I'm working on another project at the moment and will probably focus on getting alpha working first, no doubt I'll make a new thread asking for help with this shader at some point!

Take care,
Bruce
Posted: 8th Jan 2014 23:35
Bump for the new Version!

Check out the example for advice on how to use the new functions!


Take care,
Bruce