//**************************************************************************/
// Copyright (c) 2011 Autodesk, Inc.
// All rights reserved.
// 
// These coded instructions, statements, and computer programs contain
// unpublished proprietary information written by Autodesk, Inc., and are
// protected by Federal copyright law. They may not be disclosed to third
// parties or copied or duplicated in any form, in whole or in part, without
// the prior written consent of Autodesk, Inc.
//**************************************************************************/
// DESCRIPTION: PointCloud Stylization effect.
// AUTHOR: Danny Chen
// CREATED: April 2012
//**************************************************************************/


// Macros for test:
//#define LIMITBOX_ENABLE 1
//#define LIGHTING_ENABLE 0
//#define TWOSIDEDLIGHTING_ENABLE 0
//#define HIGHLIGHT_LIMITBOX_ENABLE 0
//#define HIGHLIGHT_EDGE_ENABLE 0
//#define HIGHLIGHT_REGION_ENABLE 1
//#define HIGHLIGHT_SCAN_ENABLE 1
//#define LIDAR_FORMAT_ENABLE 1
//#define HIGHLIGHTBOX_ENABLE 1




// Macros
//#define LIMITBOX_PLANES                  6      // Limit Box (Clipping Box) has 6 planes.
//#define HIGHLIGHTBOX_PLANES              6
#define MAX_LAYERS                       64     // 64 layers with different color.

// OGS internal constants
float4x4 gNormalMatrix : WorldInverseTranspose < string UIWidget = "None"; >; // the matrix to transform normal
float4x4 gWVPXf : WorldViewProjection < string UIWidget = "None"; >; // transform matrix   
float4x4 gVPXf : ViewProjection < string UIWidget = "None"; >; // view-projection transform matrix   
float4x4 gWXf: World < string UIWidget = "None"; >; // world
float3 gViewDirection : ViewDirection < string UIWidget = "None"; >;
float2 gScreenSize: ViewportPixelSize  < string UIWidget = "None"; >;

// locale position
float3 gLocale;

// the original world/normal transformation if we apply locale 
// in OGS transformations.
bool gUseOriginWorld;
float4x4 gOriginWXf;
float4x4 gOriginNormalMatrix;


//planes for the limit box                                                                                   
float4                                  gLimitBoxPlanes[LIMITBOX_PLANES];  //a box with 6 planes.  
float                                   gLimitBoxBorders[LIMITBOX_PLANES];
bool                                    gHighLightIntersect; // highlight intersect point
bool                                    gInvertLimitBox;
bool                                    gLimitBoxShowOut;
float4                                  gLimitBoxColor;
int                                     gLimitPlaneCount;

#if HIGHLIGHTBOX_ENABLE
//planes for the highlight box                                                                                   
float4                                  gHighlightBoxPlanes[HIGHLIGHTBOX_PLANES];
int                                     gHighlightPlaneCount;
float4                                  gHighlightBoxColor;
#endif

// point single color.
float4	gPointColor; 

// scan transform and high light.
float4x4 gScanMatrix;
float4  gScanColor;
bool gScanHighLight; 



// point size
float gRootRadius;          //size of root bbox, used to compute point size : PER_SCAN
int   gMaxPointSize;        //in pixels, used to compute point size                              
int   gMinPointSize;        //used to compute point size  
int   gPointSize;            //default point size, decide if we need to adjust point size  
float4 gNearPlane;			// PER_PROJ 

// LOD
int gMaxDepth;  // PER_SCAN

// parameters for gradient texture
float gGradientMaxValue;
float gGradientMinValue;
float gGradientScale;
float2 gThreshold;
bool  gFilterGradient;
int   gGradientOption;
float4 gMaxGradientColor;
float4 gMinGradientColor;

// color ramp texture( should be relatively slow on pre gf8xxx hardware )   
texture gGradientTex;
bool gForceTrueColor; 

sampler1D GradientSamplerLinear = 
sampler_state
{
    Texture = <gGradientTex>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
	AddressU = CLAMP;
};   

sampler1D GradientSamplerPoint= 
sampler_state
{
    Texture = <gGradientTex>;
    MipFilter = POINT;
    MinFilter = POINT;
    MagFilter = POINT;
	AddressU = CLAMP;
};   

// parameters for region texture
int gRegionCount;
float gRegionScale;
float gRegionFactor;
int gGlobalRegionIndex;

texture gRegionTex;
sampler1D RegionSamplerPoint= 
sampler_state
{
    Texture = <gRegionTex>;
    MipFilter = POINT;
    MinFilter = POINT;
    MagFilter = POINT;
	AddressU = CLAMP;
}; 

// lighting parameter
#define LIGHT_COUNT 3

struct Light
{
    // light color
    float3 Color;

    // light ambient color
    float3 AmbColor;

    // light specular color
    float3 SpecColor;

    // light direction
    float3 Dir;

    // these for are reserved for future extension
    float3 Pos;
    float4 Atten;
    float2 Cone;
};

// light set
Light gLightList[LIGHT_COUNT]: LightArray;

// light count
int gNumDirectionalLights : DirLightCount;

// specular power
float gGlossiness: SpecularPower;

bool gSpecularEnable;
float4 gEdgeColor;



void ComputeDirectionalLight(Light light, 
    float3 Nw, float3 Vw, float3 Pw, float exp,
    out float3 amb,out float3 diff, out float3 spec)
{
	float3 Lw = -normalize(light.Dir);
    float NdotL = dot(Nw,Lw);

    float3 Hw = normalize(Vw + Lw);
    float  NdotH = dot(Nw, Hw);
    float  NdotV = dot(Nw,Vw);

#if TWOSIDEDLIGHTING_ENABLE
    NdotV = abs(NdotV);
    NdotL = abs(NdotL);
    NdotH = abs(NdotH);
#else
    NdotV = saturate(NdotV);
    NdotH = saturate(NdotH);
    NdotH = NdotL<0?0:NdotH;

    NdotL = saturate(NdotL);
#endif

    amb  = light.AmbColor;
    diff = light.Color * NdotL;
    spec = light.SpecColor*pow(NdotH,exp);
}


void ComputeLighting(
    float3 Nw, float3 Vw, float3 Pw, float exp,
    out float3 amb, out float3 diff, out float3 spec)
{
    amb  = float3(0.0f,0.0f,0.0f);
    diff = float3(0.0f,0.0f,0.0f);
    spec = float3(0.0f,0.0f,0.0f);

    float3 tempAmb = float3(0.0f,0.0f,0.0f);
    float3 tempDiff = float3(0.0f,0.0f,0.0f);
    float3 tempSpec = float3(0.0f,0.0f,0.0f);

    if (gNumDirectionalLights >1)
    {
        ComputeDirectionalLight(gLightList[1],Nw,Vw,Pw,exp,
                tempAmb,tempDiff,tempSpec);
        amb  += tempAmb;
        diff += tempDiff;
        spec += tempSpec;
    }
    if (gNumDirectionalLights >2)
    {
         tempAmb = float3(0.0f,0.0f,0.0f);
         tempDiff = float3(0.0f,0.0f,0.0f);
         tempSpec = float3(0.0f,0.0f,0.0f);

         ComputeDirectionalLight(gLightList[2],Nw,Vw,Pw,exp,
                tempAmb,tempDiff,tempSpec);
        amb  += tempAmb;
        diff += tempDiff;
        spec += tempSpec;
    }

    if (!gSpecularEnable)
        spec = float3(0.0f,0.0f,0.0f);
    
}


// 
struct VS_INPUT
{
    float3 Pos  : POSITION;	
	float3 Normal : NORMAL;
	float4 Color   : COLOR;
	float2 Layer : TEXCOORD0;
}; 

struct VS_TO_PS
{
    float4 HPos       : POSITION;	
	float  pointSize  : PSIZE;
	float3 Property	  : TEXCOORD0; // x: discard, y: gradient, z: region
    float4 Color      : TEXCOORD1;
	float3 Normal 	  : TEXCOORD2;
    float3 WPos       : TEXCOORD3;
};


#define DISCARD_PROP Property.x
#define GTEXCRD Property.y
#define RTEXCRD Property.z

//retrieves normal z coordinate                 
float getNormalZ( float2 xyCoord )             
{                                                                    
    float dp = dot( xyCoord, xyCoord );      
    if( dp > 1.0 )  dp = 1.0;                
    return sqrt( 1.0 -  dp );                
}  

//  
float3 ComputeNormal(float3 normal_value)
{
    float3 normalParam = normalize(normal_value);

    float3 normal_result = gUseOriginWorld?
        mul(normalParam, (float3x3)gOriginNormalMatrix):
        mul(normalParam, (float3x3)gNormalMatrix);

    normal_result = mul(normal_result, (float3x3)gScanMatrix);
         
    return normalize(normal_result);
}

// compute tranformed position in world space
float4 ComputeTransformedVec(float4 wPos)
{
     return gUseOriginWorld?
                mul(wPos, gOriginWXf):
                mul(wPos, gWXf);
}
//calculates distance to plane                                       
float planeDistance(float4 planeEq, float3 pos )    
{                                                                                        
       float dotProd = dot( planeEq.xyz, pos.xyz );        
       return ( dotProd + planeEq.w );                               
} 

float ComputePointSize()
{
	// compute point size                                                                                                                                                      
    //if( gPointSize == 0)//dynamic point size                                                                                         
    //{                                                                                                                                                             
        //extract octree depth of current vertex                                                                            
    //    float childRadius = gRootRadius * ( 1.0 / pow( 2.0, voxLevel ) );                                       
              
		//calculate voxel size                                                                                                                   
    //    float dist = planeDistance( gNearPlane, pos );                                      
    //    float pSize =  (childRadius / dist * gScreenSize.x) * 0.5 ;                                                             
        //if( dist > 25.0 )                                                                                                                      
        //            pSize = -1.5;                                                                                                              
	//	return max( min( pSize, (float)gMaxPointSize), (float)gMinPointSize );                                                                                                                                                                                                    
    //}                                                                                                                                                             
    //else                                                                                                                                                   
    //{                                                                                                                                                             
        return gPointSize == 0? 1.0f:gPointSize;                                                                                                
    //}   
	
}

//check if point inside limit box
int pointInsideLimitBox( float3 pnt )                                        
{                     
    bool onEdge = false;                                                                                        
    for( int i = 0; i < gLimitPlaneCount; i++ )                                                      
    {    
        float dist = planeDistance( gLimitBoxPlanes[i],  pnt );                                                                                                  
        if(dist  <  0.0 )       
            return 2;          //outside       
        else if (dist < gLimitBoxBorders[i])
            onEdge = true;                                        
    }                                                                                                      
    return onEdge?1:0;                                                                                     
}      

float GetLayer(float val)
{
   return (gGlobalRegionIndex == -1)?val:gGlobalRegionIndex;
}

float ComputeRegionProp(float val)
{	
    val = GetLayer(val);
	return (float) (val+0.5f)/(float)gRegionCount*gRegionScale;
}


float ComputeLimitBox(float3 pos)
{
#if LIMITBOX_ENABLE
	int val = pointInsideLimitBox( pos );

    val = gInvertLimitBox?2-val:val;   
    
    if (gLimitBoxShowOut)
    {
        val = val>=1?1:val;
    }                
    return (float)val;                                               
#else
	return 0.0f;
#endif
}

#if HIGHLIGHTBOX_ENABLE
bool ComputeHighlightBox(float3 pos)
{
   if(gHighlightPlaneCount == 0)
      return false;

   for(int index = 0;index < gHighlightPlaneCount;index++)
   {
      float dist = planeDistance(gHighlightBoxPlanes[index], pos);
      if(dist  >  0.0)
         return false; //outside
   }
   
   return true;
}
#endif


VS_TO_PS PointCloud_VS(VS_INPUT In)
{
	   VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
	   float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);

	   output.Color = In.Color;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	     
     #if HIGHLIGHTBOX_ENABLE
     if (ComputeHighlightBox(transformedVec.xyz))
         output.Color = gHighlightBoxColor;
     #endif
     
	   return output;
}
VS_TO_PS PointCloudSingleColor_VS(VS_INPUT In)
{
	   VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);

	   output.Color = gPointColor;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	   
     #if HIGHLIGHTBOX_ENABLE
     if (ComputeHighlightBox(transformedVec.xyz))
         output.Color = gHighlightBoxColor;
     #endif
	     
	   return output;
}
VS_TO_PS PointCloudNormalRamp_VS(VS_INPUT In)
{
	   VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);
	   output.Color = float4(output.Normal*0.5f+0.5f,1.0f);;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	     
     #if HIGHLIGHTBOX_ENABLE
     if (ComputeHighlightBox(transformedVec.xyz))
         output.Color = gHighlightBoxColor;
     #endif
     
	   return output;
}
float ComputeGradProp(float val)
{
    val = (gGlobalRegionIndex == -1)?val:gGlobalRegionIndex;
	return (val-gGradientMinValue)/(gGradientMaxValue - gGradientMinValue)*gGradientScale;
}

VS_TO_PS PointCloudHeightRamp_VS(VS_INPUT In)
{
	   VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);
	   
	   output.GTEXCRD = ComputeGradProp(transformedVec.z);

	   output.Color = In.Color;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz+gLocale.z);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;

    #if HIGHLIGHTBOX_ENABLE
    if (ComputeHighlightBox(transformedVec.xyz))
    {
       output.Color = gHighlightBoxColor;
       output.GTEXCRD = 1.1f; // This is to force non-use of the gradient color
    }
    #endif
	     
	   return output;
}

VS_TO_PS PointCloudLODRamp_VS(VS_INPUT In)
{
	   VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);
	   
	   output.GTEXCRD = ComputeGradProp(In.Layer.y);

	   output.Color = In.Color;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	   
    #if HIGHLIGHTBOX_ENABLE
    if (ComputeHighlightBox(transformedVec.xyz))
    {
       output.Color = gHighlightBoxColor;
       output.GTEXCRD = 1.1f; // This is to force non-use of the gradient color
    }
    #endif
	     
	   return output;
}

VS_TO_PS PointCloudIntensityRamp_VS(VS_INPUT In)
{
	  VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);
	   
	   output.GTEXCRD = ComputeGradProp(In.Color.a);

	   output.Color = In.Color;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	
    #if HIGHLIGHTBOX_ENABLE
    if (ComputeHighlightBox(transformedVec.xyz))
    {
       output.Color = gHighlightBoxColor;
       output.GTEXCRD = 1.1f; // This is to force non-use of the gradient color
    }
    #endif	
	   return output;
}


VS_TO_PS PointCloudClassificationRamp_VS(VS_INPUT In)
{
	  VS_TO_PS output;
		
	   float discardVertex = 0.0;      
	   output.Property = float3(0.0f,0.0f,0.0f);
	   
       float4 wPos = mul(float4(In.Pos,1.0f),gScanMatrix);
       output.HPos = mul(wPos,gWVPXf); // compute transformed position   
	   float4 transformedVec = ComputeTransformedVec(wPos);
       output.WPos = transformedVec.xyz;
	   
	   // compute normal  
	   output.RTEXCRD  =  ComputeRegionProp(In.Layer.x);    
	   output.Normal = ComputeNormal(In.Normal.xyz);
	   
	   output.GTEXCRD = ComputeGradProp(In.Layer.y+0.5f);

	   output.Color = In.Color;
	   output.pointSize = ComputePointSize();
       output.DISCARD_PROP = ComputeLimitBox(transformedVec.xyz);  //if higher then 1.0 discard vertex    

       if (abs(GetLayer(In.Layer.x) - 61.0f) < 0.000001f)
           output.DISCARD_PROP = 2.0f;
	   
    #if HIGHLIGHTBOX_ENABLE
    if (ComputeHighlightBox(transformedVec.xyz))
    {
       output.Color = gHighlightBoxColor;
       output.GTEXCRD = 1.1f; // This is to force non-use of the gradient color
    }
    #endif
	     
	   return output;
}

float3 ComputeLightingColor(VS_TO_PS In, float3 color)
{
#if LIGHTING_ENABLE
    float3 amb;
    float3 diff;
    float3 spec;

    float3 Nw = normalize(In.Normal);
    float3 Vw = -normalize(gViewDirection);

    //
    ComputeLighting(Nw,Vw,In.WPos,gGlossiness,
        amb,diff,spec);

    // combine lighting result.
    color.xyz = color.xyz*0.2f + color.xyz*0.4f*amb + color.xyz*1.0f*diff + color.xyz*0.6f*spec; 

#if HIGHLIGHT_EDGE_ENABLE
    float NdotV = abs(dot(Nw,Vw));

    if (NdotV <0.2f)
    {
        color.xyz = color.xyz + gEdgeColor.xyz*gEdgeColor.a;
    }
#endif
    
#endif

    return color;
    
}


float4 PointCloud_PS(VS_TO_PS In): COLOR
{
	if (In.DISCARD_PROP > 1.2f)
		discard;
		
	float4 color = float4(In.Color.xyz,1.0f);

    if ((gHighLightIntersect||gLimitBoxShowOut)&&(In.DISCARD_PROP > 0.5f))
    {
        color = gLimitBoxColor;
    }
	
#if HIGHLIGHT_SCAN_ENABLE
	if (gScanHighLight)
		color.xyz = lerp(color.xyz,gScanColor.xyz,gScanColor.w);
#endif

#if HIGHLIGHT_REGION_ENABLE
	float4 RegionInfo = tex1D(RegionSamplerPoint,In.RTEXCRD);
	 if (RegionInfo.w < 0.25f)
        discard;
    else if (RegionInfo.w < 0.75f)
	    color.xyz = lerp(color.xyz,RegionInfo.xyz,gRegionFactor);
#endif	

    color.xyz = ComputeLightingColor(In,color.xyz);
	return color;
}

float4 PointCloudTexLinear_PS(VS_TO_PS In): COLOR
{
    if (In.DISCARD_PROP > 1.2f)
		discard;

	bool upBorder = (In.GTEXCRD >= 1.0f);
    bool downBorder = (In.GTEXCRD <= 0.0f);
    bool outBorder = upBorder||downBorder;

    if ((gGradientOption == 1)&&(outBorder))
            discard;

    float4 color  = tex1D(GradientSamplerLinear,In.GTEXCRD);
    
    
    // to do: can be optimized by macro.
    color = (gGradientOption == 2)?
                (upBorder?
                     gMaxGradientColor:
                 downBorder?
                     gMinGradientColor: color):
                (outBorder? 
                     float4(In.Color.rgb,1.0f):color);

    if ((gFilterGradient)&&(color.a<0.5f))
        discard;

    if (gForceTrueColor)
       color = float4(In.Color.rgb,1.0f);

    if ((gHighLightIntersect||gLimitBoxShowOut)&&(In.DISCARD_PROP > 0.5f))
    {
        color = gLimitBoxColor;
    }
	
#if HIGHLIGHT_SCAN_ENABLE
	if (gScanHighLight)
		color.xyz = lerp(color.xyz,gScanColor.xyz,gScanColor.w);
#endif

#if HIGHLIGHT_REGION_ENABLE
	float4 RegionInfo = tex1D(RegionSamplerPoint,In.RTEXCRD);
	 if (RegionInfo.w < 0.25f)
        discard;
    else if (RegionInfo.w < 0.75f)
	    color.xyz = lerp(color.xyz,RegionInfo.xyz,gRegionFactor);
#endif	

    color.xyz = ComputeLightingColor(In,color.xyz);

	return color;
}

float4 PointCloudTexPoint_PS(VS_TO_PS In): COLOR
{
    if (In.DISCARD_PROP > 1.2f)
		discard;

    bool upBorder = (In.GTEXCRD >= 1.0f);
    bool downBorder = (In.GTEXCRD <= 0.0f);
    bool outBorder = upBorder||downBorder;

    if ((gGradientOption == 1)&&(outBorder))
            discard;

    float4 color  = tex1D(GradientSamplerPoint,In.GTEXCRD);
    
    
    // to do: can be optimized by macro.
    color = (gGradientOption == 2)?
                (upBorder?
                     gMaxGradientColor:
                 downBorder?
                     gMinGradientColor: color):
                (outBorder? 
                     float4(In.Color.rgb,1.0f):color);

	
	
    if ((gFilterGradient)&&(color.a<0.5f))
        discard;

    if (gForceTrueColor)
       color = float4(In.Color.rgb,1.0f);

    if ((gHighLightIntersect||gLimitBoxShowOut)&&(In.DISCARD_PROP > 0.5f))
    {
        color = gLimitBoxColor;
    }

   
	
#if HIGHLIGHT_SCAN_ENABLE
	if (gScanHighLight)
		color.xyz = lerp(color.xyz,gScanColor.xyz,gScanColor.w);
#endif

#if HIGHLIGHT_REGION_ENABLE
	float4 RegionInfo = tex1D(RegionSamplerPoint,In.RTEXCRD);
	 if (RegionInfo.w < 0.25f)
        discard;
    else if (RegionInfo.w < 0.75f)
	    color.xyz = lerp(color.xyz,RegionInfo.xyz,gRegionFactor);
#endif	
    
    color.xyz = ComputeLightingColor(In,color.xyz);

	return color;
}

// Simply output point color.
RasterizerState DisableCulling
{
	CullMode = NONE;
    ScissorEnable = TRUE;
};
technique RenderTrueColor
{
    pass P0
    {          
        VertexShader = compile glslv PointCloud_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}
technique RenderTrueColorNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloud_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}

technique RenderSingleColor
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudSingleColor_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}
technique RenderSingleColorNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudSingleColor_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}

technique RenderNormalRamp
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudNormalRamp_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}
technique RenderNormalRampNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudNormalRamp_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
    }
}

technique RenderHeightRamp
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudHeightRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}
technique RenderHeightRampNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudHeightRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}

technique RenderElevationRamp
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudHeightRamp_VS();
        PixelShader  = compile glslf PointCloudTexPoint_PS(); 
    }
}
technique RenderElevationRampNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudHeightRamp_VS();
        PixelShader  = compile glslf PointCloudTexPoint_PS(); 
    }
}

technique RenderLODRamp
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudLODRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}
technique RenderLODRampNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudLODRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}

technique RenderIntensityRamp
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudIntensityRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}
technique RenderIntensityRampNoGS
{
    pass P0
    {          
        VertexShader = compile glslv PointCloudIntensityRamp_VS();
        PixelShader  = compile glslf PointCloudTexLinear_PS(); 
    }
}

technique RenderClassificationRamp
{
    pass P0
    {   
#if LIDAR_FORMAT_ENABLE       
        VertexShader = compile glslv PointCloudClassificationRamp_VS();
        PixelShader  = compile glslf PointCloudTexPoint_PS(); 
#else
        VertexShader = compile glslv PointCloud_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
#endif
    }
}
technique RenderClassificationRampNoGS
{
    pass P0
    {    
#if LIDAR_FORMAT_ENABLE          
        VertexShader = compile glslv PointCloudClassificationRamp_VS();
        PixelShader  = compile glslf PointCloudTexPoint_PS(); 
#else
        VertexShader = compile glslv PointCloud_VS();
        PixelShader  = compile glslf PointCloud_PS(); 
#endif
    }
}


//todo: for classification ramp
