Files
Leviathan/Library/External/build/SpeedTreeRT/SourceCode/LeafGeometry.cpp
T
2026-06-01 12:46:52 +02:00

623 lines
25 KiB
C++

///////////////////////////////////////////////////////////////////////
// Name: LeafGeometry.cpp
//
// *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
//
// Copyright (c) 2001-2004 IDV, Inc.
// All Rights Reserved.
//
// IDV, Inc.
// 1233 Washington St. Suite 610
// Columbia, SC 29201
// Voice: (803) 799-1699
// Fax: (803) 931-0320
// Web: http://www.idvinc.com
//
// This software is supplied under the terms of a license agreement or
// nondisclosure agreement with Interactive Data Visualization and may not
// be copied or disclosed except in accordance with the terms of that
// agreement.
#include "Debug.h"
#include "SpeedTreeRT.h"
#include "BillboardLeaf.h"
#include "LeafGeometry.h"
#include "WindEngine.h"
#include "UpVector.h"
#include "Endian.h"
// In an effort to keep all of the leaves from facing the same direction,
// small rotations are added to the billboarding matrix in an order to
// fight depth buffer conflict. This table contains a series of values
// used as the rotation angles (in degrees)
const int c_nLeafOffsetCount = 30;
const float c_fLeafOffsetScalar = 1.0f;
static float afLeafOffsets[c_nLeafOffsetCount] =
{
c_fLeafOffsetScalar * 6.0f, c_fLeafOffsetScalar * -10.0f, c_fLeafOffsetScalar * 16.0f,
c_fLeafOffsetScalar * -8.0f, c_fLeafOffsetScalar * 2.0f, c_fLeafOffsetScalar * -18.0f,
c_fLeafOffsetScalar * -14.0f, c_fLeafOffsetScalar * 0.0f, c_fLeafOffsetScalar * -4.0f,
c_fLeafOffsetScalar * 10.0f, c_fLeafOffsetScalar * -6.0f, c_fLeafOffsetScalar * 8.0f,
c_fLeafOffsetScalar * 4.0f, c_fLeafOffsetScalar * -2.0f, c_fLeafOffsetScalar * 14.0f,
c_fLeafOffsetScalar * -12.0f, c_fLeafOffsetScalar * 14.0f, c_fLeafOffsetScalar * -16.0f,
c_fLeafOffsetScalar * 4.0f, c_fLeafOffsetScalar * -18.0f, c_fLeafOffsetScalar * 13.0f,
c_fLeafOffsetScalar * 9.0f, c_fLeafOffsetScalar * 17.0f, c_fLeafOffsetScalar * -9.0f,
c_fLeafOffsetScalar * 3.0f, c_fLeafOffsetScalar * -7.0f, c_fLeafOffsetScalar * -15.0f,
c_fLeafOffsetScalar * 7.0f, c_fLeafOffsetScalar * -5.0f, c_fLeafOffsetScalar * 15.0f
};
///////////////////////////////////////////////////////////////////////
// SLodGeometry::SLodGeometry definition
CLeafGeometry::SLodGeometry::SLodGeometry( ) :
m_bValid(false),
m_pOrigCenterCoords(NULL)
{
}
///////////////////////////////////////////////////////////////////////
// SLodGeometry::~SLodGeometry definition
CLeafGeometry::SLodGeometry::~SLodGeometry( )
{
// delete variables inherited from CSpeedTreeRT::SGeometry::SLeaf
delete[] const_cast<unsigned char*>(m_pLeafMapIndices);
delete[] const_cast<unsigned char*>(m_pLeafClusterIndices);
delete[] const_cast<float*>(m_pCenterCoords);
delete[] const_cast<unsigned long*>(m_pColors);
delete[] const_cast<float*>(m_pNormals);
delete[] const_cast<float*>(m_pBinormals);
delete[] const_cast<float*>(m_pTangents);
delete[] const_cast<float**>(m_pLeafMapTexCoords);
delete[] const_cast<float**>(m_pLeafMapCoords);
delete[] const_cast<float*>(m_pWindWeights);
delete[] const_cast<unsigned char*>(m_pWindMatrixIndices);
m_pLeafMapIndices = NULL;
m_pLeafClusterIndices = NULL;
m_pCenterCoords = NULL;
m_pColors = NULL;
m_pNormals = NULL;
m_pBinormals = NULL;
m_pTangents = NULL;
m_pLeafMapTexCoords = NULL;
m_pLeafMapCoords = NULL;
m_pWindWeights = NULL;
m_pWindMatrixIndices = NULL;
// delete variable declared in SLodGeometry
delete[] m_pOrigCenterCoords;
m_pOrigCenterCoords = NULL;
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::CLeafGeometry definition
CLeafGeometry::CLeafGeometry(CWindEngine* pWindEngine) :
m_bManualLighting(false),
m_bVertexWeighting(false),
// wind
m_pWindEngine(pWindEngine),
// compute tables
m_usNumRockingGroups(3),
m_pTimeOffsets(NULL),
m_pLeafVertexes(NULL),
m_pLeafTexCoords(NULL),
m_pVertexProgramTable(NULL),
// texture information
m_usNumTextures(0),
m_pLeafDimensions(NULL),
m_pLeafOrigins(NULL),
// LODs
m_usNumLods(0),
m_pLods(NULL)
{
st_assert(pWindEngine);
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::~CLeafGeometry definition
CLeafGeometry::~CLeafGeometry( )
{
delete[] m_pLeafDimensions;
delete[] m_pLeafOrigins;
delete[] m_pLods;
delete[] m_pVertexProgramTable;
m_pTimeOffsets = NULL;
m_pLeafTexCoords = NULL;
m_pLeafDimensions = NULL;
m_pLeafOrigins = NULL;
m_pLods = NULL;
m_pVertexProgramTable = NULL;
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::Invalidate definition
void CLeafGeometry::Invalidate(void)
{
if (m_pLods)
for (int i = 0; i < m_usNumLods; ++i)
m_pLods[i].Invalidate( );
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::GetLeafBillboardTable definition
const float* CLeafGeometry::GetLeafBillboardTable(unsigned int& nEntryCount) const
{
// copy the leaf map position coordinates
float* pTable = m_pVertexProgramTable;
int nLodSize = m_usNumTextures * m_usNumRockingGroups * 2 * 4 * 4; // 2 for mirrored, 4 corners per leaf, 4 floats per vertex
if (pTable && m_pLeafVertexes && m_pLeafVertexes[0] && m_pVertexProgramTable)
{
memcpy(pTable, m_pLeafVertexes[0], nLodSize * sizeof(float));
pTable += nLodSize;
// calculate total floats in table
nEntryCount = pTable - m_pVertexProgramTable;
}
return m_pVertexProgramTable;
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::ComputeExtents definition
//
// Because the leaf clusters rock backand forth, taking their
// contribution to the tree's overall bounding box is not
// very straightforward.
//
// Each leaf has a position, a size, and a leafmap origin. The
// longest diagonal from the origin the four corner is computed
// for each leaf map type. Those are then added to the leaf
// positions throughout the tree in all six orthographic
// directions.
void CLeafGeometry::ComputeExtents(CRegion& cExtents) const
{
if (m_pLeafOrigins &&
m_pLeafDimensions &&
m_pLods)
{
// for each basec leafmap type (determined by how many leaf texture
// maps were specified in CAD, determine the longest diagonals.
vector<float> vLongestDiagonal;
for (int i = 0; i < m_usNumTextures; ++i)
{
const CVec3 cScaledOrigin(m_pLeafOrigins[i][0] * m_pLeafDimensions[i][0],
m_pLeafOrigins[i][1] * m_pLeafDimensions[i][1]);
float fLongest = 0.0f;
if (cScaledOrigin.Distance(CVec3(0.0f, 0.0f)) > fLongest)
fLongest = cScaledOrigin.Distance(CVec3(0.0f, 0.0f));
if (cScaledOrigin.Distance(CVec3(m_pLeafDimensions[i][0], 0.0f)) > fLongest)
fLongest = cScaledOrigin.Distance(CVec3(m_pLeafDimensions[i][0], 0.0f));
if (cScaledOrigin.Distance(CVec3(m_pLeafDimensions[i][0], m_pLeafDimensions[i][1])) > fLongest)
fLongest = cScaledOrigin.Distance(CVec3(m_pLeafDimensions[i][0], m_pLeafDimensions[i][1]));
if (cScaledOrigin.Distance(CVec3(0.0f, m_pLeafDimensions[i][1])) > fLongest)
fLongest = cScaledOrigin.Distance(CVec3(0.0f, m_pLeafDimensions[i][1]));
vLongestDiagonal.push_back(fLongest);
}
// for each leaf in all leaf LODs, determine maximum space taken
// in all six orthographic directions.
for (int nLod = 0; nLod < m_usNumLods; ++nLod)
{
SLodGeometry* pLod = m_pLods + nLod;
for (unsigned int j = 0; j < pLod->m_usLeafCount; ++j)
{
CRegion cLeafSwingExtents;
const float* pPos = pLod->m_pCenterCoords + j * 3;
const CVec3 cCenter(pPos[0], pPos[1], pPos[2]);
const float fLongestSide = vLongestDiagonal[pLod->m_pLeafMapIndices[j] / 2];
// the CRegion operator^ expands the region to include the right-hand
// CVec3 object.
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0] + fLongestSide, cCenter[1], cCenter[2]);
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0] - fLongestSide, cCenter[1], cCenter[2]);
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0], cCenter[1] + fLongestSide, cCenter[2]);
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0], cCenter[1] - fLongestSide, cCenter[2]);
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0], cCenter[1], cCenter[2] + fLongestSide);
cLeafSwingExtents = cLeafSwingExtents ^ CVec3(cCenter[0], cCenter[1], cCenter[2] - fLongestSide);
cExtents = cExtents + cLeafSwingExtents;
}
}
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::Transform definition
void CLeafGeometry::Transform(const CTransform& cTransform)
{
if (m_pLods &&
m_pLeafDimensions)
{
for (int nLod = 0; nLod < m_usNumLods; ++nLod)
{
SLodGeometry* pLod = m_pLods + nLod;
// transform the base positions of the leaves
for (int i = 0; i < pLod->m_usLeafCount; ++i)
{
// transform positions
float* pCoord = const_cast<float*>(pLod->m_pCenterCoords + i * 3);
CVec3 cCoord(pCoord[0], pCoord[1], pCoord[2]);
cCoord = cCoord * cTransform;
memcpy(pCoord, cCoord.m_afData, 3 * sizeof(float));
// m_pOrigPositions is used as a basis for wind computations,
// need to transform those too, if they are being used
if (m_bVertexWeighting)
{
float* pOrigCoord = pLod->m_pOrigCenterCoords + i * 3;
CVec3 cOrigCoord(pOrigCoord[0], pOrigCoord[1], pOrigCoord[2]);
cOrigCoord = cOrigCoord * cTransform;
memcpy(pOrigCoord, cOrigCoord.m_afData, 3 * sizeof(float));
}
}
}
// scale the leaves up by x-scale factor (arbitrary)
float fScalar = cTransform.m_afData[0][0];
for (int j = 0; j < m_usNumTextures; ++j)
m_pLeafDimensions[j] *= fScalar;
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::Init definition
void CLeafGeometry::Init(unsigned short usNumLeafLods, const vector<CBillboardLeaf*>* pvLeafLods, const SIdvLeafInfo& sLeafInfo)
{
// set table info
m_usNumRockingGroups = static_cast<unsigned short>(sLeafInfo.m_nNumRockingGroups);
// deletion of these three pointers in still handled in the
// SIdvLeafInfo destructor
m_pTimeOffsets = sLeafInfo.m_pTimeOffsets;
m_pLeafVertexes = sLeafInfo.m_pLeafVertexes;
m_pLeafTexCoords = sLeafInfo.m_pLeafTexCoords;
// set texture info
m_usNumTextures = static_cast<unsigned short>(sLeafInfo.m_vLeafTextures.size( ));
m_pLeafDimensions = new CVec3[m_usNumTextures];
m_pLeafOrigins = new CVec3[m_usNumTextures];
for (int i = 0; i < m_usNumTextures; ++i)
{
m_pLeafDimensions[i] = sLeafInfo.m_vLeafTextures[i].m_cSizeUsed;
m_pLeafOrigins[i] = sLeafInfo.m_vLeafTextures[i].m_cOrigin;
}
// new leaf vertex shader table
int nSize = m_usNumTextures * m_usNumRockingGroups * 2 * 4 * 4; // 2 for mirrored, 4 corners per leaf, 4 floats per vertex
m_pVertexProgramTable = new float[nSize];
InitLods(usNumLeafLods, pvLeafLods);
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::SetTextureCoords definition
//
// When composite leaf maps are used, this function allows CSpeedTreeRT to
// pass in user-specified texture coordinates for each leaf map.
void CLeafGeometry::SetTextureCoords(unsigned int nLeafMapIndex, const float* pTexCoords)
{
if (m_pLeafTexCoords &&
pTexCoords)
{
float fSign = CSpeedTreeRT::GetTextureFlip( ) ? -1.0f : 1.0f;
// one leaf map is setup just like the user specified
float* pEntry = m_pLeafTexCoords + (nLeafMapIndex * 2) * (2 * 4);
*pEntry++ = pTexCoords[0];
*pEntry++ = fSign * pTexCoords[1];
*pEntry++ = pTexCoords[2];
*pEntry++ = fSign * pTexCoords[3];
*pEntry++ = pTexCoords[4];
*pEntry++ = fSign * pTexCoords[5];
*pEntry++ = pTexCoords[6];
*pEntry++ = fSign * pTexCoords[7];
// another is mirrored (by swapping S coordinates) for a more interesting effect
pEntry = m_pLeafTexCoords + (nLeafMapIndex * 2 + 1) * (2 * 4);
*pEntry++ = pTexCoords[2];
*pEntry++ = fSign * pTexCoords[1];
*pEntry++ = pTexCoords[0];
*pEntry++ = fSign * pTexCoords[3];
*pEntry++ = pTexCoords[6];
*pEntry++ = fSign * pTexCoords[5];
*pEntry++ = pTexCoords[4];
*pEntry++ = fSign * pTexCoords[7];
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::Update definition
//
// Update is generally called once per frame per tree. It advances the leaf rocking
// groups by setting up and applying the billboard and rocking computations. Part of
// the optimization scheme is have a small number of template leaves that are billboarded
// and rocked and the rest of the leaves are offset from them.
void CLeafGeometry::Update(CSpeedTreeRT::SGeometry::SLeaf& sGeometry, unsigned short usLodLevel, float fAzimuth, float fPitch, float fSizeIncreaseFactor)
{
if (m_pLods &&
usLodLevel < m_usNumLods &&
m_pLeafVertexes &&
m_pLeafOrigins &&
m_pLeafDimensions &&
m_pWindEngine &&
m_pTimeOffsets)
{
SLodGeometry* pLod = m_pLods + usLodLevel;
st_assert(pLod);
if (!pLod->IsValid( ))
{
if (m_pWindEngine->GetLeafWindMethod( ) == CSpeedTreeRT::WIND_CPU)
(void) ComputeWindEffect(usLodLevel);
// determines how much larger the lower LODs get relative to the original leaves
float fSizeMultiplier = 1.0f;
if (usLodLevel > 0)
fSizeMultiplier = 1.0f + fSizeIncreaseFactor * float(usLodLevel);
CVec3 acRawCorners[4];
CVec3 acBillboardedCorners[4];
for (int i = 0; i < m_usNumTextures * 2; ++i) // X 2 for mirrored textures
{
// determine origin and size
CVec3 cOrigin = m_pLeafOrigins[i / 2];
if (!(i % 2)) // if this is a mirrored leaf, flip x-value of origin
cOrigin[0] = 1.0f - cOrigin[0];
const CVec3& cSize = m_pLeafDimensions[i / 2];
// layout the coordinates for the simple, non-billboarded leaf
float afP1[3] = { 0.0f, fSizeMultiplier * (1.0f - cOrigin[0]) * cSize[0], fSizeMultiplier * (1.0f - cOrigin[1]) * cSize[1] };
float afP2[3] = { 0.0f, fSizeMultiplier * -(cOrigin[0] * cSize[0]), afP1[2] };
float afP3[3] = { 0.0f, afP2[1], fSizeMultiplier * -(cOrigin[1] * cSize[1]) };
float afP4[3] = { 0.0f, afP1[1], afP3[2] };
// adjust the coordinates for alternate coordinate system
Assign3d(acRawCorners[0].m_afData, afP1);
Assign3d(acRawCorners[1].m_afData, afP2);
Assign3d(acRawCorners[2].m_afData, afP3);
Assign3d(acRawCorners[3].m_afData, afP4);
// each leaf texture has m_nNumRockingGroups number of leaf groups
for (int j = 0; j < m_usNumRockingGroups; ++j)
{
// determine how much the leaves are rocked
float fWindAngle = m_pWindEngine->RockLeaf((i + 1) * m_pTimeOffsets[j]);
// setup the billboarding/rocking leaf transform
int nOffsetIndex = (i * m_usNumRockingGroups) + j;
CRotTransform cTrans;
#ifdef UPVECTOR_POS_Z
cTrans.RotateZ(fAzimuth + afLeafOffsets[nOffsetIndex]);
cTrans.RotateY(fPitch + afLeafOffsets[c_nLeafOffsetCount - nOffsetIndex - 1]);
cTrans.RotateX(fWindAngle);
#endif
#ifdef UPVECTOR_NEG_Z
cTrans.RotateZ(-(fAzimuth + afLeafOffsets[nOffsetIndex]));
cTrans.RotateY(fPitch + afLeafOffsets[c_nLeafOffsetCount - nOffsetIndex - 1]);
cTrans.RotateX(fWindAngle);
#endif
#ifdef UPVECTOR_POS_Y
cTrans.RotateY(fAzimuth + afLeafOffsets[nOffsetIndex]);
cTrans.RotateZ(fPitch + afLeafOffsets[c_nLeafOffsetCount - nOffsetIndex - 1]);
cTrans.RotateX(-fWindAngle);
#endif
#ifdef UPVECTOR_DIRECTX_RIGHT_HANDED_COORDINATE_SYSTEM
cTrans.RotateZ(-(fAzimuth + afLeafOffsets[nOffsetIndex]));
cTrans.RotateX(-(fPitch + afLeafOffsets[c_nLeafOffsetCount - nOffsetIndex - 1]));
cTrans.RotateY(fWindAngle);
#endif
// transform the straight quad into a billboarded/rocking leaf
acBillboardedCorners[0] = acRawCorners[0] * cTrans;
acBillboardedCorners[1] = acRawCorners[1] * cTrans;
acBillboardedCorners[2] = acRawCorners[2] * cTrans;
acBillboardedCorners[3] = acRawCorners[3] * cTrans;
// copy data into array for use by client application
float* pBillboard = m_pLeafVertexes[usLodLevel] + i * (m_usNumRockingGroups * 16) + j * 16;
memcpy(pBillboard, acBillboardedCorners[0], 3 * sizeof(float)); pBillboard += 4;
memcpy(pBillboard, acBillboardedCorners[1], 3 * sizeof(float)); pBillboard += 4;
memcpy(pBillboard, acBillboardedCorners[2], 3 * sizeof(float)); pBillboard += 4;
memcpy(pBillboard, acBillboardedCorners[3], 3 * sizeof(float)); pBillboard += 4;
}
}
pLod->Validate( );
}
// update the appropriate pointers and variables of the resulting computations
sGeometry = *pLod;
sGeometry.m_bIsActive = true;
sGeometry.m_nDiscreteLodLevel = usLodLevel;
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::ComputeWindEffect definition
//
// This is the code for the CPU leaf wind solution. It takes two
// points: the original leaf position, and the leaf position multiplied
// times the appropriate wind matrix, and then interpolates between them
// based on the wind weight value (0.0 to 1.0).
void CLeafGeometry::ComputeWindEffect(unsigned short nLodLevel)
{
if (m_pWindEngine &&
nLodLevel < m_usNumLods &&
m_bVertexWeighting &&
m_pLods)
{
SLodGeometry* pLod = m_pLods + nLodLevel;
if (pLod &&
pLod->m_pOrigCenterCoords &&
pLod->m_pCenterCoords)
{
CVec3 cFullWindEffect, cInterpWindEffect;
for (int i = 0; i < pLod->m_usLeafCount; ++i)
{
float fWeight = pLod->m_pWindWeights[i];
float* pOrigCoord = pLod->m_pOrigCenterCoords + i * 3;
cFullWindEffect.Set(pOrigCoord[0], pOrigCoord[1], pOrigCoord[2]);
unsigned char ucWindGroup = pLod->m_pWindMatrixIndices[i];
cFullWindEffect = cFullWindEffect * m_pWindEngine->GetWindMatrix(ucWindGroup);
cInterpWindEffect.Set(VecInterpolate(pOrigCoord[0], cFullWindEffect[0], fWeight),
VecInterpolate(pOrigCoord[1], cFullWindEffect[1], fWeight),
VecInterpolate(pOrigCoord[2], cFullWindEffect[2], fWeight));
memcpy(const_cast<float*>(pLod->m_pCenterCoords + i * 3), cInterpWindEffect.m_afData, 12);
}
}
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::InitLods definition
//
// This is where the bulk of the work is done in transfering the leaf data computed
// by CIdvBranch and CTreeEngine. The code changes depending on the API/engine
// defined during compilation as well as the coordinate system.
void CLeafGeometry::InitLods(unsigned short usNumLeafLods, const vector<CBillboardLeaf*>* pvLeafLods)
{
if (pvLeafLods &&
m_pLeafVertexes &&
m_pWindEngine &&
m_pLeafTexCoords)
{
m_usNumLods = usNumLeafLods;
m_pLods = new SLodGeometry[usNumLeafLods];
int i, j;
for (unsigned short usLod = 0; usLod < usNumLeafLods; ++usLod)
{
SLodGeometry* pLod = m_pLods + usLod;
pLod->m_usLeafCount = static_cast<unsigned short>(pvLeafLods[usLod].size( ));
// coords
pLod->m_pLeafMapCoords = const_cast<const float**>(new float*[pLod->m_usLeafCount]);
for (j = 0; j < pLod->m_usLeafCount; ++j)
pLod->m_pLeafMapCoords[j] = m_pLeafVertexes[usLod] + pvLeafLods[usLod][j]->GetAltTextureIndex( ) * (m_usNumRockingGroups * 16) + pvLeafLods[usLod][j]->GetAngle( ) * 16;
// wind related
if (m_bVertexWeighting)
{
// orig positions (basis for wind)
pLod->m_pOrigCenterCoords = new float[pLod->m_usLeafCount * 3];
for (i = 0; i < pLod->m_usLeafCount; ++i)
Assign3d(pLod->m_pOrigCenterCoords + i * 3, pvLeafLods[usLod][i]->GetPosition( ).m_afData);
// wind weights
pLod->m_pWindWeights = new float[pLod->m_usLeafCount];
for (i = 0; i < pLod->m_usLeafCount; ++i)
(const_cast<float*>(pLod->m_pWindWeights))[i] = 1.0f - pvLeafLods[usLod][i]->GetWeight( );
// wind groups
pLod->m_pWindMatrixIndices = new unsigned char[pLod->m_usLeafCount];
for (i = 0; i < pLod->m_usLeafCount; ++i)
{
unsigned char ucGroup = pvLeafLods[usLod][i]->GetWindGroup( );
// chGroup spans a wide range of matrices, mod it down to size
unsigned int nStartingMatrix = 0, nMatrixSpan = 1;
m_pWindEngine->GetLocalMatrices(nStartingMatrix, nMatrixSpan);
ucGroup = static_cast<unsigned char>(nStartingMatrix) + ucGroup % static_cast<unsigned char>(nMatrixSpan);
(const_cast<unsigned char*>(pLod->m_pWindMatrixIndices))[i] = ucGroup;
}
}
// positions
pLod->m_pCenterCoords = new float[pLod->m_usLeafCount * 3];
for (i = 0; i < pLod->m_usLeafCount; ++i)
Assign3d(const_cast<float*>(pLod->m_pCenterCoords + i * 3), pvLeafLods[usLod][i]->GetPosition( ).m_afData);
// texture indexes
pLod->m_pLeafMapIndices = new unsigned char[pLod->m_usLeafCount];
for (i = 0; i < pLod->m_usLeafCount; ++i)
(const_cast<unsigned char*>(pLod->m_pLeafMapIndices))[i] = static_cast<unsigned char>(pvLeafLods[usLod][i]->GetAltTextureIndex( ));
// cluster indices, used for vertex shaders mostly
pLod->m_pLeafClusterIndices = new unsigned char[pLod->m_usLeafCount];
for (i = 0; i < pLod->m_usLeafCount; ++i)
(const_cast<unsigned char*>(pLod->m_pLeafClusterIndices))[i] = static_cast<unsigned char>(pvLeafLods[usLod][i]->GetAltTextureIndex( ) *
m_usNumRockingGroups + pvLeafLods[usLod][i]->GetAngle( ));
// texcoords
pLod->m_pLeafMapTexCoords = const_cast<const float**>(new float*[pLod->m_usLeafCount]);
for (i = 0; i < pLod->m_usLeafCount; ++i)
pLod->m_pLeafMapTexCoords[i] = m_pLeafTexCoords + pvLeafLods[usLod][i]->GetAltTextureIndex( ) * 8;
// colors
pLod->m_pColors = new unsigned long[pLod->m_usLeafCount];
for (i = 0; i < pLod->m_usLeafCount; ++i)
(const_cast<unsigned long*>(pLod->m_pColors))[i] = EndianSwap32(pvLeafLods[usLod][i]->GetColorLong( ));
// normals
if (!m_bManualLighting)
{
pLod->m_pNormals = new float[pLod->m_usLeafCount * 3];
for (i = 0; i < pLod->m_usLeafCount; ++i)
Assign3d(const_cast<float*>(pLod->m_pNormals + i * 3), pvLeafLods[usLod][i]->GetNormal( ).m_afData);
}
// bump mapping
if (!m_bManualLighting)
{
pLod->m_pTangents = new float[pLod->m_usLeafCount * 3];
pLod->m_pBinormals = new float[pLod->m_usLeafCount * 3];
for (i = 0; i < pLod->m_usLeafCount; ++i)
{
Assign3d(const_cast<float*>(pLod->m_pTangents + i * 3), pvLeafLods[usLod][i]->GetTangent( ).m_afData);
Assign3d(const_cast<float*>(pLod->m_pBinormals + i * 3), pvLeafLods[usLod][i]->GetBinormal( ).m_afData);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////
// CLeafGeometry::GetTextureCoords definition
void CLeafGeometry::GetTextureCoords(unsigned int nLeafMapIndex, float* pTexCoords) const
{
if (m_pLeafTexCoords &&
pTexCoords)
{
float* pEntry = m_pLeafTexCoords + (nLeafMapIndex * 2) * (2 * 4);
memcpy(pTexCoords, pEntry, 8 * sizeof(float));
}
}