587 lines
19 KiB
C++
587 lines
19 KiB
C++
///////////////////////////////////////////////////////////////////////
|
|
// Name: IndexedGeometry.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.
|
|
|
|
#pragma warning (disable : 4786)
|
|
#include "Debug.h"
|
|
#include "WindEngine.h"
|
|
#include "IndexedGeometry.h"
|
|
#include "UpVector.h"
|
|
#include "Endian.h"
|
|
using namespace std;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::CIndexedGeometry definition
|
|
|
|
CIndexedGeometry::CIndexedGeometry(CWindEngine* pWindEngine, bool bRetainTexCoords) :
|
|
m_bRetainTexCoords(bRetainTexCoords),
|
|
m_bValid(true),
|
|
m_eWindMethod(CSpeedTreeRT::WIND_NONE),
|
|
m_pWindEngine(pWindEngine),
|
|
m_nNumLodLevels(0),
|
|
m_bVertexWeighting(false),
|
|
m_bManualLighting(false),
|
|
m_nVertexCounter(0),
|
|
m_nStripCounter(0),
|
|
m_nVertexSize(0),
|
|
m_pVertexWindComputed(NULL),
|
|
m_nVertexCounterLodLevel(0)
|
|
{
|
|
st_assert(pWindEngine);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::~CIndexedGeometry definition
|
|
|
|
CIndexedGeometry::~CIndexedGeometry( )
|
|
{
|
|
delete[] m_pVertexWindComputed;
|
|
m_pVertexWindComputed = NULL;
|
|
|
|
DeleteIndexData( );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::CombineStrips definition
|
|
|
|
void CIndexedGeometry::CombineStrips(void)
|
|
{
|
|
// no need to concat empty strips
|
|
if (GetVertexCount( ) > 0)
|
|
{
|
|
// these will replace the class member variables m_pNumStrips, m_pStripLengths, and m_pStrips
|
|
vector<vector<unsigned short> > vCompositeStripLengths(m_nNumLodLevels);
|
|
vector<vector<unsigned short*> > vCompositeStrips(m_nNumLodLevels);
|
|
vector<int> vCompositeTriangleCounts(m_nNumLodLevels);
|
|
|
|
// for each LOD level, concat the strips together as one
|
|
for (unsigned short usLod = 0; usLod < m_nNumLodLevels; ++usLod)
|
|
{
|
|
// how many indexes are there for this LOD?
|
|
int nCompositeLength = 0;
|
|
unsigned short usStrip;
|
|
for (usStrip = 0; usStrip < GetNumStrips(usLod); ++usStrip)
|
|
nCompositeLength += m_vStripLengths[usLod][usStrip];
|
|
|
|
// add four more indexes between each individual strip
|
|
int nNumStrips = GetNumStrips(usLod);
|
|
if (nNumStrips > 0)
|
|
nNumStrips--;
|
|
nCompositeLength += 4 * nNumStrips;
|
|
|
|
if (nCompositeLength > 0)
|
|
{
|
|
// make new composite strip
|
|
unsigned short* pCompositeStrip = new unsigned short[nCompositeLength];
|
|
unsigned short* pStripPointer = pCompositeStrip;
|
|
for (usStrip = 0; usStrip < GetNumStrips(usLod); ++usStrip)
|
|
{
|
|
// copy the strip
|
|
unsigned short usStripLength = m_vStripLengths[usLod][usStrip];
|
|
memcpy(pStripPointer, m_vStrips[usLod][usStrip], usStripLength * sizeof(unsigned short));
|
|
pStripPointer += usStripLength;
|
|
|
|
// don't bridge if this is the last strip
|
|
if (usStrip < GetNumStrips(usLod) - 1)
|
|
{
|
|
// add last vertex again
|
|
*pStripPointer++ = m_vStrips[usLod][usStrip][usStripLength - 1];
|
|
|
|
// add first vertex of next strip twice
|
|
unsigned short x = m_vStrips[usLod][usStrip + 1][0];
|
|
*pStripPointer++ = x;
|
|
x = m_vStrips[usLod][usStrip + 1][0];
|
|
*pStripPointer++ = x;
|
|
|
|
// add second vertex of next strip
|
|
st_assert(m_vStripLengths[usLod][usStrip + 1] > 1);
|
|
*pStripPointer++ = m_vStrips[usLod][usStrip + 1][1];
|
|
}
|
|
}
|
|
|
|
// force values to reflect single strip data
|
|
vCompositeStripLengths[usLod].push_back(static_cast<unsigned short>(nCompositeLength));
|
|
vCompositeStrips[usLod].push_back(pCompositeStrip);
|
|
vCompositeTriangleCounts[usLod] = nCompositeLength - 2;
|
|
}
|
|
else
|
|
{
|
|
vCompositeStripLengths[usLod].clear( );
|
|
vCompositeStrips[usLod].clear( );
|
|
vCompositeTriangleCounts[usLod] = 0;
|
|
}
|
|
}
|
|
|
|
// remove all of the old separate strips
|
|
DeleteIndexData( );
|
|
|
|
// replace member vars with new composite strip data
|
|
m_vStripLengths = vCompositeStripLengths;
|
|
m_vStrips = vCompositeStrips;
|
|
m_vTriangleCounts = vCompositeTriangleCounts;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::ComputeExtents definition
|
|
|
|
void CIndexedGeometry::ComputeExtents(CRegion& cExtents) const
|
|
{
|
|
unsigned short usVertexCount = GetVertexCount( );
|
|
for (int i = 0; i < usVertexCount; ++i)
|
|
{
|
|
const float* pCoord = GetVertexCoord(i);
|
|
CVec3 cCoord(pCoord[0], pCoord[1], pCoord[2]);
|
|
|
|
// operator^ expands cExtents to include cCoord
|
|
cExtents = cExtents ^ cCoord;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::SetNumLodLevels definition
|
|
|
|
void CIndexedGeometry::SetNumLodLevels(unsigned short nLevels)
|
|
{
|
|
m_vStripLengths.clear( );
|
|
m_vStrips.clear( );
|
|
m_vTriangleCounts.clear( );
|
|
|
|
m_nNumLodLevels = nLevels;
|
|
|
|
m_vStripLengths.resize(nLevels);
|
|
m_vStrips.resize(nLevels);
|
|
m_vTriangleCounts.resize(nLevels);
|
|
|
|
for (int i = 0; i < nLevels; ++i)
|
|
m_vTriangleCounts[i] = 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::Transform definition
|
|
|
|
void CIndexedGeometry::Transform(const CTransform& cTransform)
|
|
{
|
|
unsigned short usVertexCount = GetVertexCount( );
|
|
for (int i = 0; i < usVertexCount; ++i)
|
|
{
|
|
// transform coordinates
|
|
float* pCoord = const_cast<float*>(GetVertexCoord(i));
|
|
CVec3 cCoord(pCoord[0], pCoord[1], pCoord[2]);
|
|
cCoord = cCoord * cTransform;
|
|
memcpy(pCoord, cCoord.m_afData, 3 * sizeof(float));
|
|
|
|
// orig coordinates are used as a basis for wind computations,
|
|
// need to transform those too, if they are being used
|
|
if (m_bVertexWeighting &&
|
|
!m_vOrigCoords.empty( ))
|
|
{
|
|
float* pOrigCoord = const_cast<float*>(GetOrigVertexCoord(i));
|
|
cCoord.Set(pOrigCoord[0], pOrigCoord[1], pOrigCoord[2]);
|
|
cCoord = cCoord * cTransform;
|
|
memcpy(pOrigCoord, cCoord.m_afData, 3 * sizeof(float));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddStrip definition
|
|
|
|
void CIndexedGeometry::AddStrip(unsigned short nLodLevel, unsigned short* pStrip, unsigned short nStripLength)
|
|
{
|
|
st_assert(nLodLevel < m_nNumLodLevels);
|
|
st_assert(pStrip);
|
|
|
|
// record strip length
|
|
m_vStripLengths[nLodLevel].resize(m_nStripCounter + 1);
|
|
m_vStripLengths[nLodLevel][m_nStripCounter] = nStripLength;
|
|
|
|
// record strip pointer
|
|
m_vStrips[nLodLevel].resize(m_nStripCounter + 1);
|
|
m_vStrips[nLodLevel][m_nStripCounter] = pStrip;
|
|
|
|
// record triangle count
|
|
m_vTriangleCounts[nLodLevel] += nStripLength - 2;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexColor definition
|
|
|
|
void CIndexedGeometry::AddVertexColor(const float* pColor)
|
|
{
|
|
st_assert(pColor);
|
|
|
|
// convert the 4-float value into a single unsigned long
|
|
unsigned long ulColor = EndianSwap32(ColorFloatsToLong(pColor));
|
|
|
|
// store new color
|
|
m_vColors.push_back(ulColor);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexCoord definition
|
|
|
|
void CIndexedGeometry::AddVertexCoord(const float* pCoord)
|
|
{
|
|
st_assert(pCoord);
|
|
|
|
// adjust for current up vector
|
|
float afNewCoord[3];
|
|
Assign3d(afNewCoord, pCoord);
|
|
|
|
// store new coordinate
|
|
m_vCoords.push_back(afNewCoord[0]);
|
|
m_vCoords.push_back(afNewCoord[1]);
|
|
m_vCoords.push_back(afNewCoord[2]);
|
|
|
|
// if using CPU-based wind we need to have a copy of the coordinates that are
|
|
// unaffected by wind
|
|
if (m_bVertexWeighting &&
|
|
m_eWindMethod == CSpeedTreeRT::WIND_CPU)
|
|
{
|
|
m_vOrigCoords.push_back(afNewCoord[0]);
|
|
m_vOrigCoords.push_back(afNewCoord[1]);
|
|
m_vOrigCoords.push_back(afNewCoord[2]);
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexNormal definition
|
|
|
|
void CIndexedGeometry::AddVertexNormal(const float* pNormal)
|
|
{
|
|
st_assert(pNormal);
|
|
|
|
// store new normal
|
|
m_vNormals.push_back(pNormal[0]);
|
|
m_vNormals.push_back(pNormal[1]);
|
|
m_vNormals.push_back(pNormal[2]);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexTexCoord0 definition
|
|
|
|
void CIndexedGeometry::AddVertexTexCoord0(const float* pTexCoord, short sIndex)
|
|
{
|
|
st_assert(pTexCoord);
|
|
|
|
// texture coordinates are randomly accessed by the CFrondEngine class, so
|
|
// we put some code here to compensate
|
|
if (m_nVertexCounter == m_vTexCoords0.size( ) / 2)
|
|
{
|
|
m_vTexCoords0.resize(m_vTexCoords0.size( ) + 2);
|
|
if (sIndex > -1 &&
|
|
m_bRetainTexCoords)
|
|
{
|
|
m_vTexIndices0.resize(m_vTexIndices0.size( ) + 1);
|
|
m_vOrigTexCoords0.resize(m_vOrigTexCoords0.size( ) + 2);
|
|
}
|
|
}
|
|
|
|
// Copies of the texture coordinates and texture indices are used to facilitate functions
|
|
// that exist solely for use in SpeedTreeCAD, SpeedTreeMAX, and SpeedTreeMAYA. There's
|
|
// pretty much no reason the end user will need to access these.
|
|
if (sIndex > -1 &&
|
|
m_bRetainTexCoords)
|
|
{
|
|
m_vTexIndices0[m_nVertexCounter] = static_cast<unsigned char>(sIndex);
|
|
m_vOrigTexCoords0[m_nVertexCounter * 2] = pTexCoord[0];
|
|
m_vOrigTexCoords0[m_nVertexCounter * 2 + 1] = pTexCoord[1];
|
|
}
|
|
|
|
// store the new texture coords
|
|
m_vTexCoords0[m_nVertexCounter * 2] = pTexCoord[0];
|
|
m_vTexCoords0[m_nVertexCounter * 2 + 1] = CSpeedTreeRT::GetTextureFlip( ) ? -pTexCoord[1] : pTexCoord[1];
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexTexCoord1 definition
|
|
|
|
void CIndexedGeometry::AddVertexTexCoord1(const float* pTexCoord)
|
|
{
|
|
st_assert(pTexCoord);
|
|
|
|
// store the new texture coords
|
|
m_vTexCoords1.push_back(pTexCoord[0]);
|
|
if (CSpeedTreeRT::GetTextureFlip( ))
|
|
m_vTexCoords1.push_back(-pTexCoord[1]);
|
|
else
|
|
m_vTexCoords1.push_back(pTexCoord[1]);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexWind definition
|
|
|
|
void CIndexedGeometry::AddVertexWind(float fWindWeight, unsigned char ucWindMatrixIndex)
|
|
{
|
|
// computed values are opposite of those needed by the app
|
|
fWindWeight = 1.0f - fWindWeight;
|
|
|
|
// chWindMatrixIndex spans a wide range of matrices, mod it down to size
|
|
unsigned int nStartingMatrix = 0, nMatrixSpan = 1;
|
|
m_pWindEngine->GetLocalMatrices(nStartingMatrix, nMatrixSpan);
|
|
ucWindMatrixIndex = static_cast<unsigned char>(nStartingMatrix + ucWindMatrixIndex % nMatrixSpan);
|
|
|
|
// store the attributes
|
|
m_vWindWeights.push_back(fWindWeight);
|
|
m_vWindMatrixIndices.push_back(ucWindMatrixIndex);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexTangent definition
|
|
|
|
void CIndexedGeometry::AddVertexTangent(const float* pTangent)
|
|
{
|
|
st_assert(pTangent);
|
|
|
|
float afAdjustedTangent[3];
|
|
Assign3d(afAdjustedTangent, pTangent);
|
|
|
|
m_vTangents.push_back(afAdjustedTangent[0]);
|
|
m_vTangents.push_back(afAdjustedTangent[1]);
|
|
m_vTangents.push_back(afAdjustedTangent[2]);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::AddVertexBinormal definition
|
|
|
|
void CIndexedGeometry::AddVertexBinormal(const float* pBinormal)
|
|
{
|
|
st_assert(pBinormal);
|
|
|
|
float afAdjustedBinormal[3];
|
|
Assign3d(afAdjustedBinormal, pBinormal);
|
|
|
|
m_vBinormals.push_back(afAdjustedBinormal[0]);
|
|
m_vBinormals.push_back(afAdjustedBinormal[1]);
|
|
m_vBinormals.push_back(afAdjustedBinormal[2]);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::ResetStripCounter definition
|
|
|
|
void CIndexedGeometry::ResetStripCounter(unsigned short nLodLevel)
|
|
{
|
|
// st_assert(nLodLevel < m_nNumLodLevels);
|
|
|
|
m_nVertexCounterLodLevel = nLodLevel;
|
|
m_nStripCounter = 0;
|
|
m_vTriangleCounts[nLodLevel] = 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetStrip definition
|
|
|
|
unsigned short* CIndexedGeometry::GetStrip(unsigned short nLodLevel, unsigned short& nStripLength) const
|
|
{
|
|
st_assert(nLodLevel < m_nNumLodLevels);
|
|
st_assert(m_nStripCounter < GetNumStrips(nLodLevel));
|
|
|
|
nStripLength = m_vStripLengths[nLodLevel][m_nStripCounter];
|
|
|
|
return m_vStrips[nLodLevel][m_nStripCounter];
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetStripsPointer definition
|
|
|
|
unsigned short** CIndexedGeometry::GetStripsPointer(unsigned short nLodLevel) const
|
|
{
|
|
st_assert(nLodLevel < m_nNumLodLevels);
|
|
|
|
if( m_vStrips[nLodLevel].empty() ) return 0;
|
|
|
|
return const_cast<unsigned short**>(&(m_vStrips[nLodLevel][0]));
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetTriangleCount definition
|
|
|
|
unsigned int CIndexedGeometry::GetTriangleCount(unsigned short nLodLevel) const
|
|
{
|
|
st_assert(nLodLevel < m_nNumLodLevels);
|
|
|
|
return m_vTriangleCounts[nLodLevel];
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::ComputeWindEffect definition
|
|
//
|
|
// This is the code for the CPU branch wind solution. It takes two
|
|
// points per vertex: the original vertex, and that vertex multiplied
|
|
// times the appropriate wind matrix, and then interpolates between them
|
|
// based on the wind weight value (0.0 to 1.0).
|
|
|
|
bool CIndexedGeometry::ComputeWindEffect(unsigned short nLodLevel)
|
|
{
|
|
st_assert(m_bVertexWeighting);
|
|
st_assert(m_pWindEngine);
|
|
|
|
bool bGeometryUpdated = false;
|
|
if (!IsValid( ))
|
|
{
|
|
unsigned short usVertexCount = GetVertexCount( );
|
|
if (!m_pVertexWindComputed)
|
|
m_pVertexWindComputed = new bool[usVertexCount];
|
|
for (int i = 0; i < usVertexCount; ++i)
|
|
m_pVertexWindComputed[i] = false; // makes sure we don't recompute any vertex
|
|
|
|
CVec3 cFullWindEffect, cInterpWindEffect;
|
|
for (int nStrip = 0; nStrip < GetNumStrips(nLodLevel); ++nStrip)
|
|
{
|
|
for (int nVertex = 0; nVertex < m_vStripLengths[nLodLevel][nStrip]; ++nVertex)
|
|
{
|
|
unsigned short nIndex = m_vStrips[nLodLevel][nStrip][nVertex];
|
|
if (!m_pVertexWindComputed[nIndex])
|
|
{
|
|
float fWeight = m_vWindWeights[nIndex];
|
|
float* pOrigCoord = &(m_vOrigCoords[0]) + 3 * nIndex;
|
|
|
|
cFullWindEffect.Set(pOrigCoord[0], pOrigCoord[1], pOrigCoord[2]);
|
|
unsigned short usWindGroup = m_vWindMatrixIndices[nIndex];
|
|
cFullWindEffect = cFullWindEffect * m_pWindEngine->GetWindMatrix(usWindGroup);
|
|
cInterpWindEffect.Set(VecInterpolate(pOrigCoord[0], cFullWindEffect[0], fWeight),
|
|
VecInterpolate(pOrigCoord[1], cFullWindEffect[1], fWeight),
|
|
VecInterpolate(pOrigCoord[2], cFullWindEffect[2], fWeight));
|
|
|
|
memcpy(&(m_vCoords[0]) + nIndex * 3, cInterpWindEffect.m_afData, 3 * sizeof(float));
|
|
|
|
m_pVertexWindComputed[nIndex] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Validate( );
|
|
bGeometryUpdated = true;
|
|
}
|
|
|
|
return bGeometryUpdated;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::DeleteLodStrip definition
|
|
|
|
void CIndexedGeometry::DeleteLodStrip(unsigned short usLodLevel)
|
|
{
|
|
st_assert(usLodLevel < m_nNumLodLevels);
|
|
|
|
for (int i = 0; i < GetNumStrips(usLodLevel); ++i)
|
|
{
|
|
delete[] m_vStrips[usLodLevel][i];
|
|
m_vStrips[usLodLevel][i] = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::DeleteIndexData definition
|
|
|
|
void CIndexedGeometry::DeleteIndexData(void)
|
|
{
|
|
for (unsigned int i = 0; i < m_vStrips.size( ); ++i)
|
|
{
|
|
for (unsigned int j = 0; j < m_vStrips[i].size( ); ++j)
|
|
{
|
|
delete[] m_vStrips[i][j];
|
|
m_vStrips[i][j] = NULL;
|
|
}
|
|
m_vStrips[i].clear( );
|
|
}
|
|
m_vStrips.clear( );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetVertexCoord definition
|
|
|
|
const float* CIndexedGeometry::GetVertexCoord(unsigned int nVertexIndex) const
|
|
{
|
|
st_assert(nVertexIndex < m_vCoords.size( ) / 3);
|
|
|
|
return &(m_vCoords[0]) + nVertexIndex * 3;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetVertexTexCoord0 definition
|
|
|
|
const float* CIndexedGeometry::GetVertexTexCoord0(unsigned int nVertexIndex) const
|
|
{
|
|
st_assert(nVertexIndex < m_vTexCoords0.size( ) / 2);
|
|
|
|
return &(m_vTexCoords0[nVertexIndex * 2]);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::GetOrigVertexCoord definition
|
|
|
|
const float* CIndexedGeometry::GetOrigVertexCoord(unsigned int nVertexIndex) const
|
|
{
|
|
st_assert(nVertexIndex < m_vOrigCoords.size( ) / 3);
|
|
|
|
return &(m_vOrigCoords[0]) + nVertexIndex * 3;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// CIndexedGeometry::ChangeTexCoord definition
|
|
|
|
void CIndexedGeometry::ChangeTexCoord(unsigned char chChangedMapIndex, float* pNewTexCoords)
|
|
{
|
|
st_assert(m_bRetainTexCoords);
|
|
|
|
if (chChangedMapIndex == m_vTexIndices0[m_nVertexCounter])
|
|
{
|
|
float afTexCoords[2] =
|
|
{
|
|
VecInterpolate(pNewTexCoords[2], pNewTexCoords[0], m_vOrigTexCoords0[m_nVertexCounter * 2]),
|
|
VecInterpolate(pNewTexCoords[5], pNewTexCoords[1], m_vOrigTexCoords0[m_nVertexCounter * 2 + 1])
|
|
};
|
|
|
|
if (CSpeedTreeRT::GetTextureFlip( ))
|
|
afTexCoords[1] = -afTexCoords[1];
|
|
|
|
AddVertexTexCoord0(afTexCoords);
|
|
}
|
|
}
|
|
|