646 lines
16 KiB
C++
646 lines
16 KiB
C++
#include "intrin.h"
|
|
#include "OBJMesh.h"
|
|
#include "BinMeshData.h"
|
|
|
|
#ifdef EXTRACODE
|
|
#include "StringHelper.h"
|
|
#include "TextFileReader.h"
|
|
|
|
#include <sstream>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <cmath>
|
|
#endif
|
|
|
|
ObjMesh g_objMesh;
|
|
|
|
#ifdef EXTRACODE
|
|
|
|
float ObjMesh::m_fMaxRoundError= 0.0f;
|
|
float ObjMesh::RoundFloat( float f, int iBits )
|
|
{
|
|
DWORD dw= *((DWORD*)&f);
|
|
int e= ( ( dw >> 23 ) & 0xff ) - 127;
|
|
if( e == - 127)
|
|
{
|
|
m_fMaxRoundError= max( fabs( f ), m_fMaxRoundError );
|
|
return 0.0f;
|
|
}
|
|
|
|
DWORD dwMask= 0xffffffff << ( 32 - iBits );
|
|
float Add= powf( 2.0f, (float)( e - iBits + 8 ) );
|
|
|
|
const int iTests= 7;
|
|
float fValues[ iTests ];
|
|
for( int i= 0; i < iTests; ++i )
|
|
{
|
|
fValues[ i ]= f + Add * (float)( i - iTests / 2 ) ;
|
|
((DWORD*)(fValues))[ i ]&= dwMask;
|
|
}
|
|
int iNearest= 0;
|
|
for( int i= 1; i < iTests; ++i )
|
|
{
|
|
if( fabs( f - fValues[ iNearest ] ) > fabs( f - fValues[ i ] ) )
|
|
{
|
|
iNearest= i;
|
|
}
|
|
}
|
|
|
|
m_fMaxRoundError= max( fabs( f - fValues[ iNearest ] ), m_fMaxRoundError );
|
|
return fValues[ iNearest ];
|
|
}
|
|
|
|
std::vector< unsigned char > TopologyRaw;
|
|
std::vector<BinVertex> VertexRaw;
|
|
|
|
|
|
bool ObjMesh::LoadMesh(
|
|
const char* pcFileName,
|
|
int FloatBits,
|
|
bool bFlatten,
|
|
BinMesh& bm,
|
|
int& IndexBytes,
|
|
int& VertexBytes )
|
|
{
|
|
std::map< VertexInfo, int > mapVertexData;
|
|
std::vector< Vertex > VertexData;
|
|
std::vector< int > Topology;
|
|
std::vector< Vertex > PrePos;
|
|
std::vector< Vertex > PreNormal;
|
|
|
|
Topology.reserve( 1000 );
|
|
PrePos.reserve( 1000 );
|
|
PreNormal.reserve( 1000 );
|
|
|
|
FrameWork::TextFileReader tfrData;
|
|
|
|
if( !tfrData.read( pcFileName ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_FaceCount= 0;
|
|
|
|
for( int i= 0; i < (int)tfrData.getFileLines().size(); ++i )
|
|
{
|
|
std::string strAct= tfrData.getFileLines()[ i ];
|
|
std::string strCommand;
|
|
if( FrameWork::StringHelper::splitAt( strAct, " ", strCommand ) )
|
|
{
|
|
FrameWork::StringHelper::trim(
|
|
strCommand,
|
|
FrameWork::StringHelper::getSpaceTab() );
|
|
FrameWork::StringHelper::toUpper( strCommand );
|
|
}
|
|
|
|
if( strCommand == "V" )
|
|
{
|
|
std::stringstream ss;
|
|
ss << strAct;
|
|
|
|
Vertex vxPos;
|
|
vxPos.position.x= 0;
|
|
vxPos.position.y= 0;
|
|
vxPos.position.z= 0;
|
|
|
|
ss >> vxPos.position.x;
|
|
ss >> vxPos.position.y;
|
|
ss >> vxPos.position.z;
|
|
|
|
PrePos.push_back( vxPos );
|
|
}
|
|
else if( strCommand == "VN" )
|
|
{
|
|
std::stringstream ss;
|
|
ss << strAct;
|
|
|
|
Vertex vxNorm;
|
|
vxNorm.normal.x= 0;
|
|
vxNorm.normal.y= 0;
|
|
vxNorm.normal.z= 0;
|
|
|
|
ss >> vxNorm.normal.x;
|
|
ss >> vxNorm.normal.y;
|
|
ss >> vxNorm.normal.z;
|
|
|
|
PreNormal.push_back( vxNorm );
|
|
}
|
|
else if( strCommand == "F" )
|
|
{
|
|
FrameWork::StringHelper::trim(
|
|
strAct,
|
|
FrameWork::StringHelper::getSpaceTab() );
|
|
|
|
std::vector< std::string > strVerts;
|
|
FrameWork::StringHelper::tokenize(
|
|
strAct, " ", strVerts );
|
|
|
|
std::vector< int > Read;
|
|
|
|
for( size_t j= 0; j < strVerts.size(); ++j )
|
|
{
|
|
std::vector< std::string > vecIndex;
|
|
std::string strIndex= strVerts[ j ];
|
|
FrameWork::StringHelper::trim(
|
|
strIndex,
|
|
FrameWork::StringHelper::getSpaceTab() );
|
|
|
|
FrameWork::StringHelper::tokenize(
|
|
strIndex, "/", vecIndex );
|
|
for( int jj= 0; jj < 3; ++jj )
|
|
{
|
|
std::stringstream ss;
|
|
if( jj < (int)vecIndex.size() )
|
|
{
|
|
ss << vecIndex[ jj ];
|
|
}
|
|
|
|
int iValue= -1;
|
|
ss >> iValue;
|
|
Read.push_back( iValue );
|
|
}
|
|
}
|
|
|
|
m_FaceCount++;
|
|
Topology.push_back( Read.size() / 3 );
|
|
for( int i=0; i < (int)Read.size(); i+= 3 )
|
|
{
|
|
int iIndex= i;
|
|
|
|
VertexInfo vInfo;
|
|
vInfo.m_iPos= Read[ iIndex ];
|
|
vInfo.m_iUV= Read[ iIndex + 1];
|
|
vInfo.m_iNormal= Read[ iIndex + 2];
|
|
|
|
int iMapIndex;
|
|
std::map< VertexInfo, int >::iterator it=
|
|
mapVertexData.find( vInfo );
|
|
if( it != mapVertexData.end() )
|
|
{
|
|
iMapIndex= it->second;
|
|
}
|
|
else
|
|
{
|
|
iMapIndex= (int)VertexData.size();
|
|
mapVertexData[ vInfo ]= iMapIndex;
|
|
Vertex vNew;
|
|
vNew.position= PrePos[ vInfo.m_iPos - 1 ].position;
|
|
if( (size_t)vInfo.m_iNormal - 1 >= PreNormal.size() )
|
|
{
|
|
// Normalen werden sowieso generiert
|
|
vNew.normal= D3DXVECTOR3(0, 0, 0 );
|
|
}
|
|
else
|
|
{
|
|
vNew.normal= PreNormal[ vInfo.m_iNormal - 1 ].normal;
|
|
}
|
|
VertexData.push_back( vNew );
|
|
}
|
|
Topology.push_back( iMapIndex );
|
|
}
|
|
}
|
|
}
|
|
|
|
//neuordnen der Topology koennte Speicherplatz sparen bei der Kompression
|
|
|
|
D3DXVECTOR3 PosPredictor( 0.0f, 0.0f, 0.0f );
|
|
int IndexPredictor= 0;
|
|
|
|
TopologyRaw.resize( 0 );
|
|
VertexRaw.resize( 0 );
|
|
std::map< int, int > IndexMapping;
|
|
|
|
bm.m_PrimitiveCount= 0;
|
|
|
|
for(size_t i= 0; i < Topology.size(); ++i )
|
|
{
|
|
int iCount= Topology[ i ];
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= Topology[ i + 1 + j ];
|
|
|
|
//Index schon gespeichert?
|
|
std::map< int, int >::iterator it= IndexMapping.find( iIndex );
|
|
if( it == IndexMapping.end() )
|
|
{
|
|
//Vertex ist neu
|
|
D3DXVECTOR3 PosData= VertexData[ iIndex ].position - PosPredictor;
|
|
IndexMapping[ iIndex ]= VertexRaw.size();
|
|
BinVertex v;
|
|
v.m_Pos[ 0 ]= PosData.x;
|
|
v.m_Pos[ 1 ]= PosData.y;
|
|
v.m_Pos[ 2 ]= PosData.z;
|
|
|
|
if( bFlatten )
|
|
{
|
|
v.m_Pos[ 2 ]= 0.0f;
|
|
}
|
|
|
|
//Positionswert hier runden macht Kompression besser
|
|
v.m_Pos[ 0 ]= RoundFloat( v.m_Pos[ 0 ], FloatBits );
|
|
v.m_Pos[ 1 ]= RoundFloat( v.m_Pos[ 1 ], FloatBits );
|
|
v.m_Pos[ 2 ]= RoundFloat( v.m_Pos[ 2 ], FloatBits );
|
|
|
|
VertexRaw.push_back( v );
|
|
//PosPredictor+= D3DXVECTOR3( v.m_Pos[ 0 ], v.m_Pos[ 1 ], v.m_Pos[ 2 ] );
|
|
|
|
TopologyRaw.push_back( 0 );
|
|
IndexPredictor++;
|
|
}
|
|
else
|
|
{
|
|
//Vertex schon vorhanden
|
|
int iIndexTransformed= IndexPredictor - it->second;
|
|
while( iIndexTransformed >= BinMesh::c_FarVertex )
|
|
{
|
|
iIndexTransformed-= BinMesh::c_FarVertex;
|
|
TopologyRaw.push_back( BinMesh::c_FarVertex );
|
|
}
|
|
TopologyRaw.push_back( iIndexTransformed );
|
|
}
|
|
}
|
|
TopologyRaw.push_back( BinMesh::c_FinishPoly );
|
|
bm.m_PrimitiveCount++;
|
|
i+= iCount;
|
|
}
|
|
|
|
bm.m_pTopology= &(TopologyRaw[ 0 ]);
|
|
bm.m_pVertex= &(VertexRaw[ 0 ]);
|
|
IndexBytes= TopologyRaw.size();
|
|
VertexBytes= VertexRaw.size() * sizeof(BinVertex);
|
|
return LoadMesh( &bm );
|
|
|
|
m_VertexCount= (unsigned int)VertexData.size();
|
|
m_IndexCount= (unsigned int)Topology.size();
|
|
|
|
for(size_t i= 0; i < VertexData.size(); ++i )
|
|
{
|
|
m_VertexBuffer[ i ]= VertexData[ i ];
|
|
}
|
|
for(size_t i= 0; i < Topology.size(); ++i )
|
|
{
|
|
m_IndexBuffer[ i ]= Topology[ i ];
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
bool ObjMesh::LoadMesh( BinMesh* pBinMesh )
|
|
{
|
|
m_IndexCount= 0;
|
|
m_FaceCount= 0;
|
|
m_VertexCount= 0;
|
|
|
|
int IndexPredictor= 0;
|
|
unsigned char* pData= pBinMesh->m_pTopology;
|
|
|
|
int iFaceType= 0;
|
|
int iVertex= IndexPredictor;
|
|
int New= 1;
|
|
while( m_FaceCount < pBinMesh->m_PrimitiveCount )
|
|
{
|
|
unsigned char c= *pData++;
|
|
switch( c )
|
|
{
|
|
case BinMesh::c_FinishPoly:
|
|
m_IndexBuffer[ m_IndexCount ]= iFaceType;
|
|
m_IndexCount+= iFaceType + 1;
|
|
m_FaceCount++;
|
|
iFaceType= 0;
|
|
break;
|
|
case BinMesh::c_FarVertex:
|
|
iVertex-= BinMesh::c_FarVertex;
|
|
New= 0;
|
|
break;
|
|
case 0:
|
|
IndexPredictor+= New;
|
|
m_VertexCount+= New;
|
|
default:
|
|
iFaceType++;
|
|
m_IndexBuffer[ m_IndexCount + iFaceType ]= iVertex - c;
|
|
iVertex= IndexPredictor;
|
|
New= 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
D3DXVECTOR3 PosPredictor( 0.0f, 0.0f, 0.0f );
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
D3DXVECTOR3 p(
|
|
pBinMesh->m_pVertex[ i ].m_Pos[ 0 ],
|
|
pBinMesh->m_pVertex[ i ].m_Pos[ 1 ],
|
|
pBinMesh->m_pVertex[ i ].m_Pos[ 2 ] );
|
|
PosPredictor= p;
|
|
m_VertexBuffer[ i ].position= PosPredictor;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ObjMesh::GenerateNormals()
|
|
{
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
m_VertexBuffer[ i ].normal= D3DXVECTOR3( 0, 0, 0);
|
|
}
|
|
|
|
for(int i= 0; i < m_IndexCount; )
|
|
{
|
|
int iCount= m_IndexBuffer[ i ];
|
|
++i;
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= m_IndexBuffer[ i + j ];
|
|
int iIndexPrev= m_IndexBuffer[ i + ( ( j + iCount - 1 ) % iCount ) ];
|
|
int iIndexNext= m_IndexBuffer[ i + ( ( j + 1 ) % iCount ) ];
|
|
D3DXVECTOR3 p1( m_VertexBuffer[ iIndexPrev ].position - m_VertexBuffer[ iIndex ].position );
|
|
D3DXVECTOR3 p2( m_VertexBuffer[ iIndexNext ].position - m_VertexBuffer[ iIndex ].position );
|
|
D3DXVec3Cross( &p1, &p2, &p1 );
|
|
m_VertexBuffer[ iIndex ].normal+= p1;
|
|
}
|
|
i+= iCount;
|
|
}
|
|
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
D3DXVec3Normalize( &( m_VertexBuffer[ i ].normal ), &( m_VertexBuffer[ i ].normal ) );
|
|
}
|
|
}
|
|
|
|
void ObjMesh::UnIndex()
|
|
{
|
|
m_OP.Reset();
|
|
m_OP.m_NextVertexCount= 0;
|
|
for(int i= 0; i < m_IndexCount; )
|
|
{
|
|
int iCount= m_IndexBuffer[ i ];
|
|
++i;
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= m_IndexBuffer[ i + j ];
|
|
m_OP.m_NextVB[ m_OP.m_NextVertexCount ]= m_VertexBuffer[ iIndex ];
|
|
m_IndexBuffer[ i + j ]= m_OP.m_NextVertexCount;
|
|
m_OP.m_NextVertexCount++;
|
|
}
|
|
i+= iCount;
|
|
}
|
|
|
|
//Klatteratatsch ins Mesh kopieren...
|
|
mymemcpy( m_VertexBuffer, m_OP.m_NextVB, sizeof( m_VertexBuffer ) );
|
|
m_VertexCount= m_OP.m_NextVertexCount;
|
|
}
|
|
|
|
|
|
void ObjMesh::CatmullClarkSubdivide()
|
|
{
|
|
if( m_IndexCount >= MaxIndexBuffer / 4 )
|
|
{
|
|
return;
|
|
}
|
|
if( m_VertexCount >= MaxVertexBuffer * 9 / 4 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// neuer VB ist so:
|
|
// alter VB bzw. verschobene Originalpunkte
|
|
// ein Vertex pro Face (FacePunkte)
|
|
// ein Vertex pro Edge (EdgePunkte)
|
|
|
|
//neuer IB ist so:
|
|
// 4 / alte Ecke0 / EdgePunkt / FaceFacePunkt / EdgePunkt
|
|
// 4 / alte Ecke1 / EdgePunkt / FaceFacePunkt / EdgePunkt
|
|
//...
|
|
// 4 / alte EckeN / EdgePunkt / FaceFacePunkt / EdgePunkt ( N== Vertexcount )
|
|
//beim kopieren dann ueberall noch 4
|
|
|
|
m_OP.Reset();
|
|
m_OP.m_NextVertexCount= m_VertexCount + m_FaceCount; //Basis Vertices sind die alte Ecken und die neuen FacePunkte
|
|
|
|
int iFace= 0;
|
|
for(int i= 0; i < m_IndexCount; )
|
|
{
|
|
int iCount= m_IndexBuffer[ i ];
|
|
++i;
|
|
D3DXVECTOR3& fp= m_OP.m_NextVB[ m_VertexCount + iFace ].position;
|
|
unsigned short int* pIB= m_OP.m_NextIB + m_OP.m_NextIndexCount;
|
|
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= m_IndexBuffer[ i + j ];
|
|
fp+= m_VertexBuffer[ iIndex ].position;
|
|
pIB[ j * 5 ]= 4;
|
|
pIB[ j * 5 + 1]= iIndex;
|
|
pIB[ j * 5 + 3 ]= m_VertexCount + iFace; // erste Haelfte IB fertig
|
|
}
|
|
fp/= (float)iCount; // jetzt ist der FacePunkt fertig
|
|
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= m_IndexBuffer[ i + j ];
|
|
int iIndexNext= m_IndexBuffer[ i + ( ( j + 1 ) % iCount ) ];
|
|
int Edge= m_OP.MakeEdgeID( iIndex, iIndexNext );
|
|
m_OP.m_NextVB[ m_OP.m_EdgeID[ Edge ] ].position+= fp; // Summe aller FacePunkte zu dieser Ecke sind hier
|
|
|
|
pIB[ j * 5 + 2 ]= m_OP.m_EdgeID[ Edge ];
|
|
pIB[ ( j * 5 + 9 ) % ( iCount * 5 ) ]= m_OP.m_EdgeID[ Edge ]; // IB fertig!
|
|
|
|
m_OP.m_NextVB[ iIndex ].position+= fp; //Summe aller FacePunkte die an diesen Originalpunkt grenzen
|
|
}
|
|
|
|
i+= iCount;
|
|
iFace++;
|
|
m_OP.m_NextIndexCount+= iCount * 5;
|
|
m_OP.m_NextFaceCount+= iCount;
|
|
}
|
|
|
|
// Originalpunkte verschieben
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
bool bOpenEdges= false; // gab es offene Kanten (d.h. einseitig benutze?)
|
|
D3DXVECTOR3 vEdges(0,0,0);
|
|
D3DXVECTOR3 vOpenEdges(0,0,0);
|
|
int iEdgeCount= 0;
|
|
int iOpenEdgeCount= 0;
|
|
|
|
for( int j=0; j < m_OP.m_iEdgeCount; ++j )
|
|
{
|
|
int V1= ( m_OP.m_EdgeConfiguration[ j ] & 0x0000ffff );
|
|
int V2= ( m_OP.m_EdgeConfiguration[ j ] & 0xffff0000 ) >> 16;
|
|
if( V1 == i || V2 == i )
|
|
{
|
|
D3DXVECTOR3 vMid= m_VertexBuffer[ V1 ].position + m_VertexBuffer[ V2 ].position;
|
|
if( m_OP.m_EdgeUsage[ j ] == 1 )
|
|
{
|
|
bOpenEdges= true;
|
|
iOpenEdgeCount++;
|
|
vOpenEdges+= vMid;
|
|
}
|
|
iEdgeCount++;
|
|
vEdges+= vMid;
|
|
}
|
|
}
|
|
|
|
if( bOpenEdges )
|
|
{
|
|
m_OP.m_NextVB[ i ].position= vOpenEdges / (float)( iOpenEdgeCount * 4 ) +
|
|
m_VertexBuffer[ i ].position * 0.5f;
|
|
}
|
|
else
|
|
{
|
|
m_OP.m_NextVB[ i ].position=
|
|
m_OP.m_NextVB[ i ].position / (float)iEdgeCount +
|
|
vEdges / (float)iEdgeCount +
|
|
m_VertexBuffer[ i ].position * (float)( iEdgeCount - 3 );
|
|
m_OP.m_NextVB[ i ].position/= (float)iEdgeCount;
|
|
}
|
|
}
|
|
|
|
//EdgePunkte anpassen
|
|
for( int j=0; j < m_OP.m_iEdgeCount; ++j )
|
|
{
|
|
int V1= ( m_OP.m_EdgeConfiguration[ j ] & 0x0000ffff );
|
|
int V2= ( m_OP.m_EdgeConfiguration[ j ] & 0xffff0000 ) >> 16;
|
|
if( m_OP.m_EdgeUsage[ j ] < 2 )
|
|
{
|
|
m_OP.m_NextVB[ m_OP.m_EdgeID[ j ] ].position= D3DXVECTOR3( 0,0,0 );
|
|
m_OP.m_EdgeUsage[ j ]= 0;
|
|
}
|
|
|
|
m_OP.m_NextVB[ m_OP.m_EdgeID[ j ] ].position+= m_VertexBuffer[ V1 ].position;
|
|
m_OP.m_NextVB[ m_OP.m_EdgeID[ j ] ].position+= m_VertexBuffer[ V2 ].position;
|
|
m_OP.m_NextVB[ m_OP.m_EdgeID[ j ] ].position/= (float)(m_OP.m_EdgeUsage[ j ] + 2 );
|
|
}
|
|
|
|
//Klatteratatsch ins Mesh kopieren...
|
|
mymemcpy( m_VertexBuffer, m_OP.m_NextVB, sizeof( m_VertexBuffer ) );
|
|
mymemcpy( m_IndexBuffer, m_OP.m_NextIB, sizeof( m_IndexBuffer ) );
|
|
m_VertexCount= m_OP.m_NextVertexCount;
|
|
m_IndexCount= m_OP.m_NextIndexCount;
|
|
m_FaceCount= m_OP.m_NextFaceCount;
|
|
}
|
|
|
|
void ObjMesh::Extrude( float fExtend )
|
|
{
|
|
m_OP.Reset();
|
|
|
|
for(int i= 0; i < m_IndexCount; )
|
|
{
|
|
int iCount= m_IndexBuffer[ i ];
|
|
m_IndexBuffer[ i + m_IndexCount ]= iCount;
|
|
++i;
|
|
|
|
for( int j= 0; j < iCount; ++j )
|
|
{
|
|
int iIndex= m_IndexBuffer[ i + j ];
|
|
int iIndexNext= m_IndexBuffer[ i + ( ( j + 1 ) % iCount ) ];
|
|
int ID= m_OP.MakeEdgeID( iIndex, iIndexNext );
|
|
if( iIndex > iIndexNext )
|
|
{
|
|
m_OP.m_EdgeUsage[ ID ]+= 0x80;
|
|
}
|
|
m_IndexBuffer[ i + m_IndexCount + iCount - j - 1 ]= iIndex + m_VertexCount;
|
|
}
|
|
i+= iCount;
|
|
}
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
m_VertexBuffer[ i + m_VertexCount].position= m_VertexBuffer[ i ].position;
|
|
m_VertexBuffer[ i ].position.z-= fExtend;
|
|
m_VertexBuffer[ i + m_VertexCount].position.z+= fExtend;
|
|
}
|
|
m_IndexCount*= 2;
|
|
m_FaceCount*= 2;
|
|
|
|
for( int i= 0; i < m_OP.m_iEdgeCount; ++i )
|
|
{
|
|
if( (m_OP.m_EdgeUsage[ i ] & 0x7f ) == 1 )
|
|
{
|
|
int iAdd= m_OP.m_EdgeUsage[ i ] == 1 ? 0 : m_VertexCount;
|
|
int V1= ( m_OP.m_EdgeConfiguration[ i ] & 0x0000ffff );
|
|
int V2= ( m_OP.m_EdgeConfiguration[ i ] & 0xffff0000 ) >> 16;
|
|
m_IndexBuffer[ m_IndexCount++ ]= 4;
|
|
m_IndexBuffer[ m_IndexCount++ ]= V1+ iAdd;
|
|
iAdd= m_VertexCount - iAdd;
|
|
m_IndexBuffer[ m_IndexCount++ ]= V1+ iAdd;
|
|
m_IndexBuffer[ m_IndexCount++ ]= V2+ iAdd;
|
|
iAdd= m_VertexCount - iAdd;
|
|
m_IndexBuffer[ m_IndexCount++ ]= V2+ iAdd;
|
|
m_FaceCount+= 1;
|
|
}
|
|
}
|
|
m_VertexCount*= 2;
|
|
|
|
}
|
|
|
|
void ObjMesh::SuperEllip( float fStrength )
|
|
{
|
|
if( m_VertexCount == 0 )
|
|
{
|
|
return;
|
|
}
|
|
float fMax= m_VertexBuffer[ 0 ].position.z;
|
|
float fMin= m_VertexBuffer[ 0 ].position.z;
|
|
for( int i= 1; i < m_VertexCount; ++i )
|
|
{
|
|
fMax= maximum( m_VertexBuffer[ i ].position.z, fMax );
|
|
fMin= minimum( m_VertexBuffer[ i ].position.z, fMin );
|
|
}
|
|
|
|
float fMid= ( fMax + fMin ) * 0.5f;
|
|
float fExt= ( fMax - fMin ) * 0.5f;
|
|
|
|
for( int i= 0; i < m_VertexCount; ++i )
|
|
{
|
|
float Pos= ( m_VertexBuffer[ i ].position.z - fMid ) / fExt;
|
|
Pos= signpow( Pos, fStrength );
|
|
m_VertexBuffer[ i ].position.z= fMid + Pos * fExt;
|
|
}
|
|
}
|
|
|
|
void ObjMesh::OpInfo::Reset()
|
|
{
|
|
mymemset( m_NextVB, 0, sizeof( m_NextVB ) );
|
|
mymemset( m_NextIB, 0, sizeof( m_NextIB ) );
|
|
mymemset( m_EdgeConfiguration, 0, sizeof( m_EdgeConfiguration ) );
|
|
mymemset( m_EdgeUsage, 0, sizeof( m_EdgeUsage ) );
|
|
mymemset( m_EdgeID, 0, sizeof( m_EdgeID ) );
|
|
|
|
m_NextVertexCount= 0;
|
|
m_NextIndexCount= 0;
|
|
m_NextFaceCount= 0;
|
|
|
|
m_iEdgeCount= 0;
|
|
}
|
|
|
|
int ObjMesh::OpInfo::MakeEdgeID( unsigned short VertexA, unsigned short VertexB )
|
|
{
|
|
unsigned int EdgeConfiguration= VertexA > VertexB ? ( VertexA << 16 | VertexB ) : ( VertexB << 16 | VertexA );
|
|
for( int i=0; i < m_iEdgeCount; ++i )
|
|
{
|
|
if( m_EdgeConfiguration[ i ] == EdgeConfiguration )
|
|
{
|
|
m_EdgeUsage[ i ]++;
|
|
return i;
|
|
}
|
|
}
|
|
m_EdgeConfiguration[ m_iEdgeCount ]= EdgeConfiguration;
|
|
m_EdgeUsage[ m_iEdgeCount ]++;
|
|
m_EdgeID[ m_iEdgeCount ]= m_NextVertexCount;
|
|
m_NextVertexCount++;
|
|
return m_iEdgeCount++;
|
|
}
|
|
|
|
/* Vertex m_NextVB[ ObjMesh::MaxVertexBuffer ];
|
|
unsigned short int m_NextIB[ ObjMesh::MaxIndexBuffer ];
|
|
int m_NextVertexCount;
|
|
int m_NextIndexCount;
|
|
int m_NextFaceCount;
|
|
|
|
int m_iEdgeCount;
|
|
unsigned int m_EdgeConfiguration[ ObjMesh::MaxIndexBuffer ];
|
|
unsigned char m_EdgeUsage[ ObjMesh::MaxIndexBuffer ];
|
|
|
|
unsigned short int m_EdgeID[ ObjMesh::MaxIndexBuffer ];
|
|
}*/ |