/****************************************************************************** libx42make - skinned vertex animation library (exporter utilities) Copyright (C) 2007 HermitWorks Entertainment Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA. ******************************************************************************/ #include "local.h" namespace x42 { namespace make { /***** Group */ std::vector< index > Group::InternalGetTriangleIndices( void ) const { uint numElems = indices.size() ? (uint)indices.size() : (uint)verts.size(); uint numPrims; switch( primType ) { case PrimType::TriangleList: case PrimType::TriangleStrip: case PrimType::TriangleFan: numPrims = PrimType::ElemsToPrims( primType, numElems ); break; default: numPrims = 0; //can't handle these break; } std::vector< index > ret( numPrims * 3 ); if( numPrims ) { if( primType == PrimType::TriangleStrip && indices.size() ) { assert( indices.size() == ret.size(), "Odd index count." ); std::copy( indices.begin(), indices.end(), ret.begin() ); } else { uint iOut = 0; GroupPrimitiveIterator iter( this ); while( iter.Next() ) { ret[iOut++] = iter.Current( 0 ); ret[iOut++] = iter.Current( 1 ); ret[iOut++] = iter.Current( 2 ); } } } return ret; } void Group::OptimizeMesh( bool makeStrip ) { switch( primType ) { case PrimType::TriangleList: case PrimType::TriangleStrip: case PrimType::TriangleFan: break; default: //can't handle these types return; } if( !indices.size() ) //already optimal return; nv::DisableRestart(); nv::SetCacheSize( nv::CACHESIZE_GEFORCE3 ); //GEFORCE 3 and up - reorder on load if detected different if( makeStrip ) { nv::SetListsOnly( false ); nv::SetStitchStrips( true ); } else { nv::SetListsOnly( true ); } ushort numPrimGroups; nv::PrimitiveGroup *pgStrip, *pgRemap; std::vector< index > triIndices = InternalGetTriangleIndices(); nv::GenerateStrips( &triIndices[0], (uint)triIndices.size(), &pgStrip, &numPrimGroups ); auto_array< nv::PrimitiveGroup > delStrips( pgStrip ); nv::RemapIndices( pgStrip, numPrimGroups, (ushort)verts.size(), &pgRemap ); auto_array< nv::PrimitiveGroup > delRemap( pgRemap ); if( makeStrip ) { if( numPrimGroups != 1 ) { warn( 0, "Failed to stitch strips." ); OptimizeMesh( false ); //try again in plain triangle mode return; } else primType = PrimType::TriangleStrip; } else primType = PrimType::TriangleList; //clear the group indices.clear(); //dump everything back into the group std::vector< Vertex > newVerts( verts.size() ); std::vector< bool > newVertSet( verts.size(), false ); for( nv::PrimitiveGroup *pg = pgStrip, *rpg = pgRemap; numPrimGroups--; pg++, rpg++ ) { if( !makeStrip ) demand( pg->type == nv::PT_LIST, "NVTriStrip produced non-list." ); for( uint i = 0; i < pg->numIndices; i++ ) { ushort dstIdx = rpg->indices[i]; //index where we'll put the vert if( !newVertSet[dstIdx] ) { uint srcIdx = pg->indices[i]; //index from the source array newVerts[dstIdx] = verts[srcIdx]; newVertSet[dstIdx] = true; } indices.push_back( dstIdx ); } } std::copy( newVerts.begin(), newVerts.end(), verts.begin() ); } /***** Lod */ void Lod::OptimizeMeshes( bool makeStrips ) { for( uint i = 0; i < groups.size(); i++ ) groups[i]->OptimizeMesh( makeStrips ); } /***** ModelData */ void ModelData::OptimizeMeshes( bool makeStrips ) { for( uint i = 0; i < lods.size(); i++ ) lods[i]->OptimizeMeshes( makeStrips ); } }; };