#include "SM_Engine3DPCH.h"
#include "SM_D3DGeometry.h"
#include "SM_Mesh.h"
#include "NvTriStripObjects.h"

using namespace std;


#define VBTHRESHOLD 32768
#define OPTIMIZEIB  0

void OptimizeIndexList(unsigned short* usDest, unsigned short* usSource, unsigned short usIndices)
{
  unsigned i,j;
  NvStripifier Stripifier;

  WordVec Indices;
  
  for (i=0 ; i<usIndices ; i++)
  {
    Indices.push_back(usSource[i]);
  }

  NvStripInfoVec Strips;
  NvFaceInfoVec  Faces;

  Stripifier.Stripify(Indices, 10, 0, Strips, Faces);

  unsigned uOffset=0;

  for(i=0; i <Strips.size(); i++)
	{
	  for(j=0; j<Strips[i]->m_faces.size(); j++)
	  {
      usDest[uOffset++]=Strips[i]->m_faces[j]->m_v0;
      usDest[uOffset++]=Strips[i]->m_faces[j]->m_v1;
      usDest[uOffset++]=Strips[i]->m_faces[j]->m_v2;		  
	  }				
  }
			
  //now, make a VB for the leftOver faces
	for(i = 0; i < Faces.size(); i++)
	{
		usDest[uOffset++]=Faces[i]->m_v0;		
		usDest[uOffset++]=Faces[i]->m_v1;		
		usDest[uOffset++]=Faces[i]->m_v2;		
	}	

  assert(uOffset==usIndices);
}


D3DGeometry::D3DGeometry()
{
  m_pcName       =0;
  m_iVertexBuffer=-1;
  m_iIndexBuffer =-1;
  m_pVertices    =0;
  m_pIndices     =0;
}

D3DGeometry::~D3DGeometry()
{
  Shutdown();
}

int D3DGeometry::Init(RenderMesh* pRenderMesh)
{
  #ifdef USESTATICBUFFERS 
  IDirect3DVertexBuffer8*   pVertexBuffer=0; 
  FVF_PosNormalDiffuseTex1* pVertices=0;
  IDirect3DIndexBuffer8*    pIndexBuffer=0; 
  unsigned short*           pIndices=0;    
  #endif

  assert(m_iVertexBuffer==-1);
  assert(m_iIndexBuffer ==-1);

  unsigned uVertex,uIndex;

  assert(pRenderMesh->m_pcName);

  m_pcName=new char[strlen(pRenderMesh->m_pcName)+1];
  strcpy(m_pcName, pRenderMesh->m_pcName);

  m_uMeshElements=pRenderMesh->m_uElements;  
  if (!m_uMeshElements)
  {
    assert(!"D3DGeometry::Init() passing an empty mesh");
    return (-1);
  }

  m_pMeshElements=new MeshElement[m_uMeshElements];
  if (!m_pMeshElements)
  {
    return (-1);
  }

  unsigned i,j;
  unsigned uVertices=0;
  unsigned uIndices =0;
  

  // Count vertices and indices
  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    uVertices+=pRenderMesh->m_pElements[i].m_uVertices;
    uIndices +=pRenderMesh->m_pElements[i].m_uIndices;
  }

  bool bUseVBIB=uVertices*sizeof(FVF_PosNormalDiffuseTex1)>=VBTHRESHOLD;

  // Create VB/IB
  #ifdef USESTATICBUFFERS
  if (bUseVBIB)
  {
    m_iVertexBuffer=ResourceManager::CreateVertexBuffer(
            uVertices*sizeof(FVF_PosNormalDiffuseTex1), 
            D3DUSAGE_WRITEONLY, 
            FVF_POSNORMALDIFFUSETEX1, 
            D3DPOOL_MANAGED);

    m_iIndexBuffer=ResourceManager::CreateIndexBuffer(
              uIndices*sizeof(unsigned short), 
              D3DUSAGE_WRITEONLY , 
              D3DFMT_INDEX16, 
              D3DPOOL_MANAGED);

    if (m_iVertexBuffer==-1 || m_iIndexBuffer==-1)
    {
      goto HASERROR;
    }
  }
  #endif


  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    #ifdef USESTATICBUFFERS
    if (bUseVBIB)
    {
      m_pMeshElements[i].m_iIB=m_iIndexBuffer;
      m_pMeshElements[i].m_iVB=m_iVertexBuffer;    
    }
    else
    {
      m_pMeshElements[i].m_iIB=-1;
      m_pMeshElements[i].m_iVB=-1;    
    }
    #else
    m_pMeshElements[i].m_iIB=-1;
    m_pMeshElements[i].m_iVB=-1;
    #endif
    m_pMeshElements[i].m_iShader=pRenderMesh->m_pElements[i].m_iMaterial;
  }

  // Fill VB/IB
  #ifdef USESTATICBUFFERS  
  if (bUseVBIB)
  {
    
    pVertexBuffer=ResourceManager::GetVertexBufferFromID(m_iVertexBuffer);
    pVertexBuffer->Lock(0, sizeof(FVF_PosNormalDiffuseTex1)*uVertices, (BYTE**) &pVertices, 0);
  }
  #endif


  uVertex=0;
  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    uVertex+=pRenderMesh->m_pElements[i].m_uVertices;
  }

  m_pVertices=new FVF_PosNormalDiffuseTex1[uVertex];
  if (!m_pVertices)
  {
    goto HASERROR;
  }

  uVertex=0;
  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    m_pMeshElements[i].m_uStartVertex=uVertex;
    m_pMeshElements[i].m_uVertices=pRenderMesh->m_pElements[i].m_uVertices;
    m_pMeshElements[i].m_pVertices=m_pVertices+uVertex;               

    for (j=0 ; j<pRenderMesh->m_pElements[i].m_uVertices ; j++)
    {
      #ifdef USESTATICBUFFERS
      if (bUseVBIB)
      {
        pVertices[uVertex].x=pRenderMesh->m_pElements[i].m_pRenderVertices[j].x;
        pVertices[uVertex].y=pRenderMesh->m_pElements[i].m_pRenderVertices[j].y;
        pVertices[uVertex].z=pRenderMesh->m_pElements[i].m_pRenderVertices[j].z;
        pVertices[uVertex].diffuse=pRenderMesh->m_pElements[i].m_pRenderVertices[j].diffuse;
        pVertices[uVertex].u=pRenderMesh->m_pElements[i].m_pRenderVertices[j].u;
        pVertices[uVertex].v=-pRenderMesh->m_pElements[i].m_pRenderVertices[j].v;
        pVertices[uVertex].nx=pRenderMesh->m_pElements[i].m_pRenderVertices[j].nx;
        pVertices[uVertex].ny=pRenderMesh->m_pElements[i].m_pRenderVertices[j].ny;
        pVertices[uVertex].nz=pRenderMesh->m_pElements[i].m_pRenderVertices[j].nz;
      }
      #endif

      m_pVertices[uVertex].x=pRenderMesh->m_pElements[i].m_pRenderVertices[j].x;
      m_pVertices[uVertex].y=pRenderMesh->m_pElements[i].m_pRenderVertices[j].y;
      m_pVertices[uVertex].z=pRenderMesh->m_pElements[i].m_pRenderVertices[j].z;
      m_pVertices[uVertex].diffuse=pRenderMesh->m_pElements[i].m_pRenderVertices[j].diffuse;
      m_pVertices[uVertex].u=pRenderMesh->m_pElements[i].m_pRenderVertices[j].u;
      m_pVertices[uVertex].v=-pRenderMesh->m_pElements[i].m_pRenderVertices[j].v;
      m_pVertices[uVertex].nx=pRenderMesh->m_pElements[i].m_pRenderVertices[j].nx;
      m_pVertices[uVertex].ny=pRenderMesh->m_pElements[i].m_pRenderVertices[j].ny;
      m_pVertices[uVertex].nz=pRenderMesh->m_pElements[i].m_pRenderVertices[j].nz;
      

      uVertex++;
    }     
    #ifdef USESTATICBUFFERS      
    if (bUseVBIB)
    {
      assert( memcmp(m_pMeshElements[i].m_pVertices, pVertices, sizeof(FVF_PosNormalDiffuseTex1)*pRenderMesh->m_pElements[i].m_uVertices)==0);
    }
    #endif
  }
  assert(uVertex==uVertices);

  #ifdef USESTATICBUFFERS 
  if (bUseVBIB)
  {
    pVertexBuffer->Unlock();
  }
  #endif  



  #ifdef USESTATICBUFFERS  
  if (bUseVBIB)
  {  
  pIndexBuffer=ResourceManager::GetIndexBufferFromID(m_iIndexBuffer);
  pIndexBuffer->Lock(0, sizeof(unsigned short)*uIndices, (BYTE**) &pIndices, 0);
  }
  #endif

  m_pIndices=new unsigned short[uIndices];
  if (!m_pIndices)
  {
    return -1;
  }



  uIndex=0;
  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    m_pMeshElements[i].m_uStartIndex=uIndex;
    m_pMeshElements[i].m_uPrimitives=pRenderMesh->m_pElements[i].m_uIndices/3;
    m_pMeshElements[i].m_pIndices   =m_pIndices+m_pMeshElements[i].m_uStartIndex;
    

    #if OPTIMIZEIB
    OptimizeIndexList(m_pIndices+uIndex, pRenderMesh->m_pElements[i].m_pusIndices, pRenderMesh->m_pElements[i].m_uIndices);
    if (bUseVBIB)
    {
      memcpy(pIndices+uIndex, m_pIndices+uIndex, sizeof(short)*pRenderMesh->m_pElements[i].m_uIndices);
    }
    uIndex+=pRenderMesh->m_pElements[i].m_uIndices;    
    #else            
    for (j=0 ; j<pRenderMesh->m_pElements[i].m_uIndices ; j++)
    {
      #ifdef USESTATICBUFFERS  
      if (bUseVBIB)
      {
        pIndices[uIndex]=pRenderMesh->m_pElements[i].m_pusIndices[j];
      }
      #endif

      m_pIndices[uIndex]=pRenderMesh->m_pElements[i].m_pusIndices[j];
      uIndex++;
    }
    #endif
    ///

    #ifdef USESTATICBUFFERS    
    if (bUseVBIB)
    {
      assert( memcmp(m_pMeshElements[i].m_pIndices, pIndices, sizeof(unsigned short)*pRenderMesh->m_pElements[i].m_uIndices)==0);
    }
    #endif
  }  

  assert(uIndex==uIndices);

  #ifdef USESTATICBUFFERS        
  if (bUseVBIB)
  {
    pIndexBuffer->Unlock();
  }
  #endif

  // Radius
  m_fRadius=0;
  for (i=0 ; i<pRenderMesh->m_uElements ; i++)
  {
    for (j=0 ; j<pRenderMesh->m_pElements[i].m_uVertices ; j++)
    {
      Vector3D v=Vector3D(pRenderMesh->m_pElements[i].m_pRenderVertices[j].x,
                          pRenderMesh->m_pElements[i].m_pRenderVertices[j].y,
                          pRenderMesh->m_pElements[i].m_pRenderVertices[j].z);

      m_fRadius=max(v.Length(), m_fRadius);
      
      uVertex++;
    } 
  }

  return (0);

HASERROR:
  return (-1);

  
}

int D3DGeometry::Shutdown()
{
  if (m_pcName)            { delete[] m_pcName; m_pcName=0; }
  if (m_iVertexBuffer!=-1) { ResourceManager::ReleaseVertexBuffer(m_iVertexBuffer); m_iVertexBuffer=-1; }
  if (m_iIndexBuffer !=-1) { ResourceManager::ReleaseIndexBuffer(m_iIndexBuffer ); m_iIndexBuffer =-1; }  
  if (m_pVertices)     delete[] m_pVertices; m_pVertices=0;
  if (m_pIndices)      delete[] m_pIndices; m_pIndices=0;

  ClearCache();
  if (m_pMeshElements) delete[] m_pMeshElements; m_pMeshElements=0;  

  return (0);
}


void D3DGeometry::PreTransform  (Vector3D* pv3d, Quaternion* pq)
{
  unsigned i,j;

  Matrix4X4 m;
  ToTransform(&m, pv3d, pq);            

  for (j=0 ; j<m_uMeshElements ; j++)
  {
    for (i=0 ; i<m_pMeshElements[j].m_uVertices ; i++)
    {
      Vector3D v(m_pMeshElements[j].m_pVertices[i].x,
                 m_pMeshElements[j].m_pVertices[i].y,
                 m_pMeshElements[j].m_pVertices[i].z);

      Vector3D vt;

      m.Transform(&vt, &v, 1);

      m_pMeshElements[j].m_pVertices[i].x=vt.x;
      m_pMeshElements[j].m_pVertices[i].y=vt.y;
      m_pMeshElements[j].m_pVertices[i].z=vt.z;
    }
    
  }
}


void D3DGeometry::AABB(AABox* pAABB)
{
  unsigned i,j;
  pAABB->m_v3dMax=Vector3D(FLT_MIN, FLT_MIN, FLT_MIN);
  pAABB->m_v3dMin=Vector3D(FLT_MAX, FLT_MAX, FLT_MAX);

  for (j=0 ; j<m_uMeshElements ; j++)
  {
    for (i=0 ; i<m_pMeshElements[j].m_uVertices ; i++)
    {
      Vector3D v(m_pMeshElements[j].m_pVertices[i].x,
                 m_pMeshElements[j].m_pVertices[i].y,
                 m_pMeshElements[j].m_pVertices[i].z);

      *pAABB|=v;
    }
    
  }
}

void D3DGeometry::ClearCache()
{
  int i;
  for (i=0 ; i<m_uMeshElements ; i++)
  {
    m_pMeshElements[i].ClearCache();
  }
}

void D3DGeometry::PreCache      ()
{
  int i;
  for (i=0 ; i<m_uMeshElements ; i++)
  {
    m_pMeshElements[i].PreCache();
  }
}


int D3DGeometry::GenerateShadowVolume ()
{
  int i;
  for (i=0 ; i<m_uMeshElements ; i++)
  {
    if (GenerateShadowVolume(&m_pMeshElements[i]) != 0)
    {
      return -1;
    }
  }

  return 0;
}

struct D3DGeometryEdge
{
  void     Init()
  {
    m_iFaces[0] = m_iFaces[1] = m_iEdge[0] = m_iEdge[1] = -1;
  }

  void     AddVertices(Vector3D& vA, Vector3D& vB)
  {
    if (memcmp(&vA, &vB, sizeof(Vector3D))<0)
    {
      m_v3dVertices[0] = vA;
      m_v3dVertices[1] = vB;
    }
    else
    {
      m_v3dVertices[0] = vB;
      m_v3dVertices[1] = vA;
    }
  }
  
  void     AddFace(int iFace, int iEdge)
  {
    if (m_iFaces[0] == -1)
    {
      m_iFaces[0] = iFace;
      m_iEdge[0] = iEdge;
    }
    else
    {
      //assert(m_iFaces[1] == -1);
      if (m_iFaces[1] == -1)
      {
        m_iFaces[1] = iFace;
        m_iEdge[1] = iEdge;
      }
    }
  }

  Vector3D m_v3dVertices[2];
  int      m_iFaces[2];
  int      m_iEdge[2];
};

bool operator==(const D3DGeometryEdge& a, const D3DGeometryEdge& b) 
{
  return (memcmp(a.m_v3dVertices, b.m_v3dVertices, 2*sizeof(Vector3D))==0);
}

bool operator<(const D3DGeometryEdge& a, const D3DGeometryEdge& b) 
{
  return (memcmp(a.m_v3dVertices, b.m_v3dVertices, 2*sizeof(Vector3D))<0);
}


int D3DGeometry::GenerateShadowVolume (MeshElement* pMeshElement)
{
  unsigned i,j;
  
  unsigned uFaces = pMeshElement->m_uPrimitives;

  ShadowVolumeData* pVolumeData;
  pVolumeData = new ShadowVolumeData();
  if (!pVolumeData)
  {
    return -1;
  }

  // Generate vertices 
  unsigned uVertices = pMeshElement->m_uPrimitives * 3;
  pVolumeData->m_pVertices = new FVF_PosNormal[uVertices];
  pVolumeData->m_uVertices = uVertices;
  if (!pVolumeData->m_pVertices)
  {
    return -1;
  }

  map<D3DGeometryEdge, D3DGeometryEdge> Edges;
  
  for ( i = 0 ; i < uFaces ; i++)
  {
    // Calculate Normal
    Vector3D vA = Vector3D(pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3]].x,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3]].y,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3]].z);

    Vector3D vB = Vector3D(pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+1]].x,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+1]].y,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+1]].z);

    Vector3D vC = Vector3D(pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+2]].x,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+2]].y,
                           pMeshElement->m_pVertices[pMeshElement->m_pIndices[i*3+2]].z);

    Vector3D vNormal = Vector3D::Cross(vC-vA, vB-vA).Normalize();

    pVolumeData->m_pVertices[i*3+0].x  =vA.x;
    pVolumeData->m_pVertices[i*3+0].y  =vA.y;
    pVolumeData->m_pVertices[i*3+0].z  =vA.z;
    pVolumeData->m_pVertices[i*3+0].nx =vNormal.x;
    pVolumeData->m_pVertices[i*3+0].ny =vNormal.y;
    pVolumeData->m_pVertices[i*3+0].nz =vNormal.z;

    pVolumeData->m_pVertices[i*3+1].x  =vB.x;
    pVolumeData->m_pVertices[i*3+1].y  =vB.y;
    pVolumeData->m_pVertices[i*3+1].z  =vB.z;
    pVolumeData->m_pVertices[i*3+1].nx =vNormal.x;
    pVolumeData->m_pVertices[i*3+1].ny =vNormal.y;
    pVolumeData->m_pVertices[i*3+1].nz =vNormal.z;

    pVolumeData->m_pVertices[i*3+2].x  =vC.x;
    pVolumeData->m_pVertices[i*3+2].y  =vC.y;
    pVolumeData->m_pVertices[i*3+2].z  =vC.z;
    pVolumeData->m_pVertices[i*3+2].nx =vNormal.x;
    pVolumeData->m_pVertices[i*3+2].ny =vNormal.y;
    pVolumeData->m_pVertices[i*3+2].nz =vNormal.z; 

    D3DGeometryEdge Edge[3];

    Edge[0].AddVertices(vA, vB);
    Edge[1].AddVertices(vB, vC);
    Edge[2].AddVertices(vC, vA);
    

    for (j = 0 ; j < 3 ; j++)
    {
      if ( Edges.find(Edge[j]) == Edges.end() )
      {
        Edge[j].Init();
        Edge[j].AddFace(i, j);
        Edges.insert(std::pair<D3DGeometryEdge, D3DGeometryEdge>(Edge[j], Edge[j]));
      }
      else
      {
        Edges[Edge[j]].AddFace(i, j);
      }
    }      
  }

  map<D3DGeometryEdge, D3DGeometryEdge>::iterator Iter;
  unsigned uNewFaces = Edges.size()*2;

  
  pVolumeData->m_pIndices = new unsigned short[Edges.size()*6 + uFaces*3];
  if (!pVolumeData->m_pIndices)
  {
    return -1;
  }
  

  unsigned uOffset = 0;
  for (Iter = Edges.begin() ; Iter != Edges.end() ; Iter++)
  {

    /*SM_Main::OutputDebug("%i %i : %i %i (%f, %f, %f) (%f, %f, %f)\n", 
      Iter->second.m_iFaces[0], Iter->second.m_iEdge[0],
      Iter->second.m_iFaces[1], Iter->second.m_iEdge[1],
      Iter->second.m_v3dVertices[0].x, Iter->second.m_v3dVertices[0].y, Iter->second.m_v3dVertices[0].z,
      Iter->second.m_v3dVertices[1].x, Iter->second.m_v3dVertices[1].y, Iter->second.m_v3dVertices[1].z);    */

    D3DGeometryEdge* pEdge = &Iter->second;

    int iOffset[3][2]=
    {
      { 0, 1 },
      { 1, 2 },
      { 2, 0 },
    };
    
    if (pEdge->m_iFaces[1] == -1)
    {
      // degenerate tris
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      pVolumeData->m_pIndices[uOffset++] = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];      
    }
    else
    {
      int iA, iB, iC, iD;

      iA = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][0];
      iB = pEdge->m_iFaces[0]*3+iOffset[pEdge->m_iEdge[0]][1];
      iC = pEdge->m_iFaces[1]*3+iOffset[pEdge->m_iEdge[1]][0];
      iD = pEdge->m_iFaces[1]*3+iOffset[pEdge->m_iEdge[1]][1];

      Vector3D vA = Vector3D(pVolumeData->m_pVertices[iA].x,
                             pVolumeData->m_pVertices[iA].y,
                             pVolumeData->m_pVertices[iA].z);

      
      Vector3D vC = Vector3D(pVolumeData->m_pVertices[iC].x,
                             pVolumeData->m_pVertices[iC].y,
                             pVolumeData->m_pVertices[iC].z);

      if (memcmp(&vA, &vC, sizeof(Vector3D)) != 0)
      {
        int iTemp = iC;
        iC = iD;
        iD = iTemp;

#ifdef _DEBUG
        Vector3D vAA = Vector3D(pVolumeData->m_pVertices[iA].x,
                                pVolumeData->m_pVertices[iA].y,
                                pVolumeData->m_pVertices[iA].z);

        Vector3D vBB = Vector3D(pVolumeData->m_pVertices[iB].x,
                                pVolumeData->m_pVertices[iB].y,
                                pVolumeData->m_pVertices[iB].z);
      
        Vector3D vCC = Vector3D(pVolumeData->m_pVertices[iC].x,
                                pVolumeData->m_pVertices[iC].y,
                                pVolumeData->m_pVertices[iC].z);

        Vector3D vDD = Vector3D(pVolumeData->m_pVertices[iD].x,
                                pVolumeData->m_pVertices[iD].y,
                                pVolumeData->m_pVertices[iD].z);

        assert(memcmp(&vAA, &vCC, sizeof(Vector3D)) == 0);
        assert(memcmp(&vBB, &vDD, sizeof(Vector3D)) == 0);

#endif
      }

      // A++++B
      //  |  |
      // C++++D
     
      pVolumeData->m_pIndices[uOffset++] = iA;
      pVolumeData->m_pIndices[uOffset++] = iB;
      pVolumeData->m_pIndices[uOffset++] = iC;
      pVolumeData->m_pIndices[uOffset++] = iB;
      pVolumeData->m_pIndices[uOffset++] = iD;
      pVolumeData->m_pIndices[uOffset++] = iC;      
    }    
  }

  pVolumeData->m_uBorderFaces = uOffset / 3;

  for (i = 0 ; i < uFaces ; i++)
  {
    pVolumeData->m_pIndices[uOffset++] = i*3;
    pVolumeData->m_pIndices[uOffset++] = i*3+2;
    pVolumeData->m_pIndices[uOffset++] = i*3+1;
  }

  pVolumeData->m_uFaces = uOffset / 3;
  assert(uOffset == Edges.size()*6 + uFaces*3);

  
  pMeshElement->m_pShadowVolumeData = pVolumeData;

  return 0;
}
  