port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

View File

@@ -0,0 +1,646 @@
#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 ];
}*/