//========================================================================================
// EQUINOX-3D Cg fragment program
//
// This shader code was automatically generated by the EQUINOX-3D Cg shader framework
//
// Copyright (C) 1992-2017 by Gabor Nagy. All rights reserved.
//========================================================================================


//c ; cgc -noentry Voxels_frg.cg


typedef float   CgCoordinate;
typedef float3  CgCoord3;

#define CgHUGE	1e30

typedef struct
{
 float3  Origin, Direction;
} CgRay;


typedef struct
{
// E3dBBox    BBox;
 int3       GridCount;
// E3dVoxel*  Voxels;
 CgCoord3   VoxelSize, VoxelSizeInv;
} CgUniformGrid;


typedef struct
{
 int3		GridPosition;
 int3		GridStep,
		GridOut;
 CgCoord3	GridNext,
		GridDelta;
} CgRayGridState;

#define XToVoxel(px) 	( ((px) - LBBoxMinX) * PUniformGrid.VoxelSizeInv.x )
#define YToVoxel(py) 	( ((py) - LBBoxMinY) * PUniformGrid.VoxelSizeInv.y )
#define ZToVoxel(pz) 	( ((pz) - LBBoxMinZ) * PUniformGrid.VoxelSizeInv.z )

#define VoxelToX(px)	((px) * LVoxelXSize + LBBoxMinX)
#define VoxelToY(py)	((py) * LVoxelYSize + LBBoxMinY)
#define VoxelToZ(pz)	((pz) * LVoxelZSize + LBBoxMinZ)

#define EPSILON	0.000001

//================================================
// Initialize Voxel-traversal for a Ray
//================================================
void E3dCg_RayDDAInit(const in CgUniformGrid PUniformGrid, const in float3 PBBoxMin, const in float3 PBBoxMax, const int3 PGridCount, const in float3 PVoxelSize, const in CgRay PRay, inout CgRayGridState PState)
{
 const CgCoordinate	LBBoxMinX = PBBoxMin.x, LBBoxMinY = PBBoxMin.y, LBBoxMinZ = PBBoxMin.z,
			LRayX = PRay.Origin.x, LRayY = PRay.Origin.y, LRayZ = PRay.Origin.z,
			LDirX = PRay.Direction.x, LDirY = PRay.Direction.y, LDirZ = PRay.Direction.z,
			LVoxelXSize = PVoxelSize.x, LVoxelYSize = PVoxelSize.y, LVoxelZSize = PVoxelSize.z;


// Compute the Voxel of the ray origin
//
 PState.GridPosition.x = XToVoxel(LRayX);if(PState.GridPosition.x >= PGridCount.x) PState.GridPosition.x = PGridCount.x - 1;
 PState.GridPosition.y = YToVoxel(LRayY);if(PState.GridPosition.y >= PGridCount.y) PState.GridPosition.y = PGridCount.y - 1;
 PState.GridPosition.z = ZToVoxel(LRayZ);if(PState.GridPosition.z >= PGridCount.z) PState.GridPosition.z = PGridCount.z - 1;


// PState.GridDelta   - distance increment along the ray to the adjacent Voxel in the X direction.
// PState.GridNext    - the total distance from the ray origin to the next Voxel in the X direction.
// PState.GridStep.   - either +1 or -1 accroding to the ray X direction. 
// PState.GridOut.    - -1 or _GridXCount: the first X Voxel index outside the grid
//

// X
//
 if(abs(LDirX) > EPSILON)
 {
  const CgCoordinate	LInv = 1.0f / LDirX;
  if(LDirX > 0.0f)
  {
   PState.GridDelta.x = LVoxelXSize * LInv;
   PState.GridNext.x = (VoxelToX(PState.GridPosition.x + 1) - LRayX) * LInv;
   PState.GridStep.x = 1; PState.GridOut.x = PUniformGrid.GridCount.x;
  }
  else
  {
   PState.GridDelta.x = LVoxelXSize * -LInv;
   PState.GridNext.x = (VoxelToX(PState.GridPosition.x) - LRayX) * LInv;
   PState.GridStep.x = PState.GridOut.x = -1;
  }
 }
 else
 {
  PState.GridDelta.x = 0.0f;
  PState.GridNext.x = CgHUGE;
 }

// Y
//
 if(abs(LDirY) > EPSILON)
 {
  const CgCoordinate	LInv = 1.0f / LDirY;
  if(LDirY > 0.0f)
  {
   PState.GridDelta.y = LVoxelYSize * LInv;
   PState.GridNext.y = (VoxelToY(PState.GridPosition.y + 1) - LRayY) * LInv;
   PState.GridStep.y = 1; PState.GridOut.y = PUniformGrid.GridCount.y;
  }
  else
  {
   PState.GridDelta.y = LVoxelYSize * -LInv;
   PState.GridNext.y = (VoxelToY(PState.GridPosition.y) - LRayY) * LInv;
   PState.GridStep.y = PState.GridOut.y = -1;
  }
 }
 else
 {
  PState.GridDelta.y = 0.0f;
  PState.GridNext.y = CgHUGE;
 }

// Z
//
 if(abs(LDirZ) > EPSILON)
 {
  const CgCoordinate	LInv = 1.0f / LDirZ;
  if(LDirZ > 0.0f)
  {
   PState.GridDelta.z = LVoxelZSize * LInv;
   PState.GridNext.z = (VoxelToZ(PState.GridPosition.z + 1) - LRayZ) * LInv;
   PState.GridStep.z = 1; PState.GridOut.z = PUniformGrid.GridCount.z;
  }
  else
  {
   PState.GridDelta.z = LVoxelZSize * -LInv;
   PState.GridNext.z = (VoxelToZ(PState.GridPosition.z) - LRayZ) * LInv;
   PState.GridStep.z = PState.GridOut.z = -1;
  }
 }
 else
 {
  PState.GridDelta.z = 0.0f;
  PState.GridNext.z = CgHUGE;
 }
}



inline void Illuminate(const float3 LightPosition, const half4 LightColor,
	const float3 LPointToEye,
	const float3 Position,
	const in float3 BBoxMin, const in float3 BBoxMax, const in float3 BBoxSize,
	const in sampler3D Voxels,

	inout half4 LResultColor)
{
 LResultColor.rgb = float3(0.5, 0.0, 0.0);
}


inline void IlluminateWithShadow(const half4 ShadowColor, const float3 LightPosition, const half4 LightColor,
	const float3 LPointToEye,
	const float3 Position,
	const in float3 BBoxMin, const in float3 BBoxMax, const in float3 BBoxSize,
	const in int3 PGridCount,
	const in float3 PVoxelSize, const in float3 PVoxelSizeInv,
	const in sampler3D Voxels,

	inout half4 LResultColor)
{
 CgRay   LRay;LRay.Origin = Position;LRay.Direction = -LPointToEye;

 CgUniformGrid PUniformGrid;
 PUniformGrid.GridCount = PGridCount;
 PUniformGrid.VoxelSize = PVoxelSize;
 PUniformGrid.VoxelSizeInv = PVoxelSizeInv;

 float3  LTexCoords = float3(Position.x / BBoxSize.x + 0.5, Position.y / BBoxSize.y + 0.5, 0.5);
 float3  LColor = tex3D(Voxels, LTexCoords).rgb;
// float3  LColor = tex3D(Voxels, float3(0.25, 0.25, 0.5));


// LResultColor.rgb = float3(0.5, 0.0, 0.0);
 LResultColor.rgb = LColor * 100000.0;
}



/*
typedef float3	LightingFloat3_t;


// Vertex-Fragment interface
//
struct InterpolatedValues
{
 float4 HPosition		: POSITION;
 float4 Position		: TEXCOORD7;
};


void main(in InterpolatedValues IN,
    out float4 OutColor : COLOR,
    const uniform float3 EyeLocalPosition,
    uniform sampler3D Voxels)
{
 const float3            LLocalPosition = IN.Position.xyz;
 const LightingFloat3_t  LEyeRay = normalize(LLocalPosition - EyeLocalPosition);

 OutColor = float3(0.5, 0.0, 0.0);
}
*/
