#include "intrin.h" #include "OBJMesh.h" #include "BinMeshData.h" #ifdef EXTRACODE #include "StringHelper.h" #include "TextFileReader.h" #include #include #include #include #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 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 ]; }*/