int CalCoreModel::loadCoreMesh(const std::string& strFilename, const char* pbyBuffer, unsigned long nBufferSize) { // the core skeleton has to be loaded already if(m_pCoreSkeleton == 0) { CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__); return -1; } // load a new core mesh CalLoader loader; CalCoreMesh *pCoreMesh; pCoreMesh = loader.loadCoreMesh(strFilename, pbyBuffer, nBufferSize); if(pCoreMesh == 0) return -1; // add core mesh to this core model int meshId; meshId = addCoreMesh(pCoreMesh); if(meshId == -1) { pCoreMesh->release(); return -1; } return meshId; }
void CalCoreBone::calculateBoundingBox(CalCoreModel * pCoreModel) { int boneId = m_pCoreSkeleton->getCoreBoneId(m_strName); bool bBoundsComputed = false; initBoundingBox(); int meshId; for(meshId=0; meshId < pCoreModel->getCoreMeshCount(); ++meshId) { CalCoreMesh * pCoreMesh = pCoreModel->getCoreMesh(meshId); int submeshId; for(submeshId=0;submeshId<pCoreMesh->getCoreSubmeshCount();submeshId++) { CalCoreSubmesh *pCoreSubmesh = pCoreMesh->getCoreSubmesh(submeshId); if(pCoreSubmesh->getSpringCount()==0) { std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex(); for(size_t vertexId=0;vertexId <vectorVertex.size(); ++vertexId) { for(size_t influenceId=0;influenceId<vectorVertex[vertexId].vectorInfluence.size();++influenceId) { CalCoreSubmesh::Influence &influence = vectorVertex[vertexId].vectorInfluence[influenceId]; if(influence.boneId == boneId && influence.weight > 0.5f) { const bool updated = updateBoundingBox(vectorVertex[vertexId].position); bBoundsComputed = bBoundsComputed || updated; } } } } } } // To handle bones with no vertices assigned (do not "optimize" this code away!) if(!bBoundsComputed) { for(int planeId = 0; planeId < 6; ++planeId) { m_boundingBox.plane[planeId].setPosition(m_translation); m_boundingPosition[planeId] = m_translation; } } m_boundingBoxPrecomputed = true; }
CalCoreModel* osgCal::loadCoreModel( const std::string& cfgFileName, float& scale, bool ignoreMeshes ) throw (std::runtime_error) { // -- Initial loading of model -- scale = 1.0f; bool bScale = false; FILE* f = fopen( cfgFileName.c_str(), "r" ); if( !f ) { throw std::runtime_error( "Can't open " + cfgFileName ); } FileCloser closer( f ); std::auto_ptr< CalCoreModel > calCoreModel( new CalCoreModel( "dummy" ) ); // Extract path from fileName std::string dir = osgDB::getFilePath( cfgFileName ); static const int LINE_BUFFER_SIZE = 4096; char buffer[LINE_BUFFER_SIZE]; while ( fgets( buffer, LINE_BUFFER_SIZE,f ) ) { // Ignore comments or empty lines if ( *buffer == '#' || *buffer == 0 ) continue; char* equal = strchr( buffer, '=' ); if ( equal ) { // Terminates first token *equal++ = 0; // Removes ending newline ( CR & LF ) { int last = strlen( equal ) - 1; if ( equal[last] == '\n' ) equal[last] = 0; if ( last > 0 && equal[last-1] == '\r' ) equal[last-1] = 0; } // extract file name. all animations, meshes and materials names // are taken from file name without extension std::string nameToLoad; char* point = strrchr( equal, '.' ); if ( point ) { nameToLoad = std::string( equal, point ); } else { nameToLoad = equal; } std::string fullpath = dir + "/" + std::string( equal ); // process .cfg parameters if ( !strcmp( buffer, "scale" ) ) { bScale = true; std::istringstream equal_stream(equal); equal_stream.imbue(std::locale::classic()); equal_stream >> scale; continue; } if ( !strcmp( buffer, "skeleton" ) ) { if( !calCoreModel->loadCoreSkeleton( fullpath ) ) { throw std::runtime_error( "Can't load skeleton: " + CalError::getLastErrorDescription() ); } } else if ( !strcmp( buffer, "animation" ) ) { int animationId = calCoreModel->loadCoreAnimation( fullpath ); if( animationId < 0 ) { throw std::runtime_error( "Can't load animation " + nameToLoad + ": " + CalError::getLastErrorDescription() ); } calCoreModel->getCoreAnimation(animationId) ->setName( nameToLoad ); } else if ( !strcmp( buffer, "mesh" ) ) { if ( ignoreMeshes ) { // we don't need meshes since VBO data is already loaded // from cache continue; } int meshId = calCoreModel->loadCoreMesh( fullpath ); if( meshId < 0 ) { throw std::runtime_error( "Can't load mesh " + nameToLoad + ": " + CalError::getLastErrorDescription() ); } calCoreModel->getCoreMesh( meshId )->setName( nameToLoad ); // -- Remove zero influence vertices -- // warning: this is a temporary workaround and subject to // remove! (this actually must be fixed in blender exporter) CalCoreMesh* cm = calCoreModel->getCoreMesh( meshId ); for ( int i = 0; i < cm->getCoreSubmeshCount(); i++ ) { CalCoreSubmesh* sm = cm->getCoreSubmesh( i ); std::vector< CalCoreSubmesh::Vertex >& v = sm->getVectorVertex(); for ( size_t j = 0; j < v.size(); j++ ) { std::vector< CalCoreSubmesh::Influence >& infl = v[j].vectorInfluence; std::vector< CalCoreSubmesh::Influence >::iterator it = infl.begin(); for ( ;it != infl.end(); ) { if ( it->weight <= 0.0001 ) it = infl.erase( it ); else ++it; } std::sort( infl.begin(), infl.end(), DataCmp<CalCoreSubmesh::Influence,float> (FIELD_OFFSET(CalCoreSubmesh::Influence,weight)) ); } } } else if ( !strcmp( buffer, "material" ) ) { int materialId = calCoreModel->loadCoreMaterial( fullpath ); if( materialId < 0 ) { throw std::runtime_error( "Can't load material " + nameToLoad + ": " + CalError::getLastErrorDescription() ); } else { calCoreModel->createCoreMaterialThread( materialId ); calCoreModel->setCoreMaterialId( materialId, 0, materialId ); CalCoreMaterial* material = calCoreModel->getCoreMaterial( materialId ); material->setName( nameToLoad ); } } } }
void loadMeshes( CalCoreModel* calCoreModel, MeshesVector& meshes ) throw (std::runtime_error) { const int maxVertices = Constants::MAX_VERTEX_PER_MODEL; const int maxFaces = Constants::MAX_VERTEX_PER_MODEL * 3; std::auto_ptr< CalHardwareModel > calHardwareModel( new CalHardwareModel( calCoreModel ) ); osg::ref_ptr< VertexBuffer > vertexBuffer( new VertexBuffer( maxVertices ) ); osg::ref_ptr< WeightBuffer > weightBuffer( new WeightBuffer( maxVertices ) ); osg::ref_ptr< MatrixIndexBuffer > matrixIndexBuffer( new MatrixIndexBuffer( maxVertices ) ); osg::ref_ptr< NormalBuffer > normalBuffer( new NormalBuffer( maxVertices ) ); osg::ref_ptr< NormalBuffer > tangentBuffer( new NormalBuffer( maxVertices ) ); osg::ref_ptr< NormalBuffer > binormalBuffer( new NormalBuffer( maxVertices ) ); osg::ref_ptr< TexCoordBuffer > texCoordBuffer( new TexCoordBuffer( maxVertices ) ); std::vector< CalIndex > indexBuffer( maxFaces*3 ); std::vector< float > floatMatrixIndexBuffer( maxVertices*4 ); calHardwareModel->setVertexBuffer((char*)vertexBuffer->getDataPointer(), 3*sizeof(float)); #ifdef OSG_CAL_BYTE_BUFFERS std::vector< float > floatNormalBuffer( getVertexCount()*3 ); calHardwareModel->setNormalBuffer((char*)&floatNormalBuffer.begin(), 3*sizeof(float)); #else calHardwareModel->setNormalBuffer((char*)normalBuffer->getDataPointer(), 3*sizeof(float)); #endif calHardwareModel->setWeightBuffer((char*)weightBuffer->getDataPointer(), 4*sizeof(float)); calHardwareModel->setMatrixIndexBuffer((char*)&floatMatrixIndexBuffer.front(), 4*sizeof(float)); calHardwareModel->setTextureCoordNum( 1 ); calHardwareModel->setTextureCoordBuffer(0, // texture stage # (char*)texCoordBuffer->getDataPointer(), 2*sizeof(float)); calHardwareModel->setIndexBuffer( &indexBuffer.front() ); // calHardwareModel->setCoreMeshIds(_activeMeshes); // if ids not set all meshes will be used at load() time //std::cout << "calHardwareModel->load" << std::endl; calHardwareModel->load( 0, 0, Constants::MAX_BONES_PER_MESH ); //std::cout << "calHardwareModel->load ok" << std::endl; int vertexCount = calHardwareModel->getTotalVertexCount(); // int faceCount = calHardwareModel->getTotalFaceCount(); // std::cout << "vertexCount = " << vertexCount << "; faceCount = " << faceCount << std::endl; GLubyte* matrixIndexBufferData = (GLubyte*) matrixIndexBuffer->getDataPointer(); for ( int i = 0; i < vertexCount*4; i++ ) { matrixIndexBufferData[i] = static_cast< GLubyte >( floatMatrixIndexBuffer[i] ); } #ifdef OSG_CAL_BYTE_BUFFERS GLbyte* normals = (GLbyte*) normalBuffer->getDataPointer(); for ( int i = 0; i < vertexCount*3; i++ ) { normals[i] = static_cast< GLbyte >( floatNormalBuffer[i]*127.0 ); } #endif // invert UVs for OpenGL (textures are inverted otherwise - for example, see abdulla/klinok) GLfloat* texCoordBufferData = (GLfloat*) texCoordBuffer->getDataPointer(); for ( float* tcy = texCoordBufferData + 1; tcy < texCoordBufferData + 2*vertexCount; tcy += 2 ) { *tcy = 1.0f - *tcy; } // -- And now create meshes data -- int unriggedBoneIndex = calCoreModel->getCoreSkeleton()->getVectorCoreBone().size(); // we add empty bone in ModelData to handle unrigged vertices; for( int hardwareMeshId = 0; hardwareMeshId < calHardwareModel->getHardwareMeshCount(); hardwareMeshId++ ) { calHardwareModel->selectHardwareMesh(hardwareMeshId); int faceCount = calHardwareModel->getFaceCount(); if ( faceCount == 0 ) { continue; // we ignore empty meshes } CalHardwareModel::CalHardwareMesh* hardwareMesh = &calHardwareModel->getVectorHardwareMesh()[ hardwareMeshId ]; osg::ref_ptr< MeshData > m( new MeshData ); m->name = calCoreModel->getCoreMesh( hardwareMesh->meshId )->getName(); m->coreMaterial = hardwareMesh->pCoreMaterial; if ( m->coreMaterial == NULL ) { CalCoreMesh* coreMesh = calCoreModel->getCoreMesh( hardwareMesh->meshId ); CalCoreSubmesh* coreSubmesh = coreMesh->getCoreSubmesh( hardwareMesh->submeshId ); // hardwareMesh->pCoreMaterial = // coreModel->getCoreMaterial( coreSubmesh->getCoreMaterialThreadId() ); char buf[ 1024 ]; snprintf( buf, 1024, "pCoreMaterial == NULL for mesh '%s' (mesh material id = %d), verify your mesh file data", m->name.c_str(), coreSubmesh->getCoreMaterialThreadId() ); throw std::runtime_error( buf ); } // -- Create index buffer -- int indexesCount = faceCount * 3; int startIndex = calHardwareModel->getStartIndex(); if ( indexesCount <= 0x100 ) { m->indexBuffer = new osg::DrawElementsUByte( osg::PrimitiveSet::TRIANGLES, indexesCount ); GLubyte* data = (GLubyte*)m->indexBuffer->getDataPointer(); const CalIndex* i = &indexBuffer[ startIndex ]; const CalIndex* iEnd = &indexBuffer[ startIndex + indexesCount ]; while ( i < iEnd ) { *data++ = (GLubyte)*i++; } } else if ( indexesCount <= 0x10000 ) { m->indexBuffer = new osg::DrawElementsUShort( osg::PrimitiveSet::TRIANGLES, indexesCount ); GLushort* data = (GLushort*)m->indexBuffer->getDataPointer(); const CalIndex* i = &indexBuffer[ startIndex ]; const CalIndex* iEnd = &indexBuffer[ startIndex + indexesCount ]; while ( i < iEnd ) { *data++ = (GLushort)*i++; } } else { m->indexBuffer = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, indexesCount ); GLuint* data = (GLuint*)m->indexBuffer->getDataPointer(); const CalIndex* i = &indexBuffer[ startIndex ]; const CalIndex* iEnd = &indexBuffer[ startIndex + indexesCount ]; while ( i < iEnd ) { *data++ = (GLuint)*i++; } } // -- Create other buffers -- int vertexCount = calHardwareModel->getVertexCount(); int baseVertexIndex = calHardwareModel->getBaseVertexIndex(); #define SUB_BUFFER( _type, _name ) \ new _type( _name->begin() + baseVertexIndex, \ _name->begin() + baseVertexIndex + vertexCount ) m->vertexBuffer = SUB_BUFFER( VertexBuffer, vertexBuffer ); m->weightBuffer = SUB_BUFFER( WeightBuffer, weightBuffer ); m->matrixIndexBuffer = SUB_BUFFER( MatrixIndexBuffer, matrixIndexBuffer ); m->normalBuffer = SUB_BUFFER( NormalBuffer, normalBuffer ); m->texCoordBuffer = SUB_BUFFER( TexCoordBuffer, texCoordBuffer ); // -- Parameters and buffers setup -- m->boundingBox = calculateBoundingBox( m->vertexBuffer.get() ); m->bonesIndices = hardwareMesh->m_vectorBonesIndices; checkRigidness( m.get(), unriggedBoneIndex ); checkForEmptyTexCoord( m.get() ); generateTangentAndHandednessBuffer( m.get(), &indexBuffer[ startIndex ] ); meshes.push_back( m.get() ); } }
bool CalHardwareModel::load(int baseVertexIndex, int startIndex,int maxBonesPerMesh) { if(m_pVertexBuffer==NULL || m_pNormalBuffer ==NULL|| m_pWeightBuffer ==NULL || m_pMatrixIndexBuffer ==NULL) { CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__); return false; } int mapId; for(mapId = 0; mapId < m_textureCoordNum; mapId++) { if(m_pTextureCoordBuffer[mapId]==NULL) { CalError::setLastError(CalError::INVALID_HANDLE, __FILE__, __LINE__); return false; } } m_vectorVertexIndiceUsed.resize(50000); int vertexCount=baseVertexIndex; int faceIndexCount = startIndex; // unused. //CalCoreSkeleton * pCoreSkeleton = m_pCoreModel->getCoreSkeleton(); //std::vector< CalCoreBone *>& vectorBone = pCoreSkeleton->getVectorCoreBone(); // if unspecified, fill with all core mesh ids if(m_coreMeshIds.empty()) { for(int coreMeshId = 0; coreMeshId < m_pCoreModel->getCoreMeshCount(); coreMeshId++) m_coreMeshIds.push_back(coreMeshId); } for(std::vector<int>::iterator meshIdIt = m_coreMeshIds.begin();meshIdIt != m_coreMeshIds.end(); meshIdIt++) { int meshId = *meshIdIt; CalCoreMesh *pCoreMesh = m_pCoreModel->getCoreMesh(meshId); int submeshCount= pCoreMesh->getCoreSubmeshCount(); int submeshId; for(submeshId = 0 ;submeshId < submeshCount ; submeshId++) { CalCoreSubmesh *pCoreSubmesh = pCoreMesh->getCoreSubmesh(submeshId); std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex(); std::vector<CalCoreSubmesh::Face>& vectorFace = pCoreSubmesh->getVectorFace(); // unused. //std::vector< std::vector<CalCoreSubmesh::TextureCoordinate> >& vectorTex = pCoreSubmesh->getVectorVectorTextureCoordinate(); CalHardwareMesh hardwareMesh; hardwareMesh.meshId = meshId; hardwareMesh.submeshId = submeshId; hardwareMesh.baseVertexIndex=vertexCount; hardwareMesh.startIndex=faceIndexCount; hardwareMesh.m_vectorBonesIndices.clear(); hardwareMesh.vertexCount=0; hardwareMesh.faceCount=0; int startIndex=hardwareMesh.startIndex; int faceId; for( faceId =0 ;faceId<pCoreSubmesh->getFaceCount();faceId++) { if(canAddFace(hardwareMesh,vectorFace[faceId],vectorVertex,maxBonesPerMesh)) { m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[0],pCoreSubmesh,maxBonesPerMesh); m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3+1]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[1],pCoreSubmesh,maxBonesPerMesh); m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3+2]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[2],pCoreSubmesh,maxBonesPerMesh); hardwareMesh.faceCount++; } else { vertexCount+=hardwareMesh.vertexCount; faceIndexCount+=hardwareMesh.faceCount*3; hardwareMesh.pCoreMaterial= m_pCoreModel->getCoreMaterial(pCoreSubmesh->getCoreMaterialThreadId()); m_vectorHardwareMesh.push_back(hardwareMesh); hardwareMesh.baseVertexIndex=vertexCount; hardwareMesh.startIndex=faceIndexCount; hardwareMesh.m_vectorBonesIndices.clear(); hardwareMesh.vertexCount=0; hardwareMesh.faceCount=0; startIndex=hardwareMesh.startIndex; m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[0],pCoreSubmesh,maxBonesPerMesh); m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3+1]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[1],pCoreSubmesh,maxBonesPerMesh); m_pIndexBuffer[startIndex+hardwareMesh.faceCount*3+2]= addVertex(hardwareMesh,vectorFace[faceId].vertexId[2],pCoreSubmesh,maxBonesPerMesh); hardwareMesh.faceCount++; } } vertexCount+=hardwareMesh.vertexCount; faceIndexCount+=hardwareMesh.faceCount*3; hardwareMesh.pCoreMaterial= m_pCoreModel->getCoreMaterial(pCoreSubmesh->getCoreMaterialThreadId()); m_vectorHardwareMesh.push_back(hardwareMesh); } } m_vectorVertexIndiceUsed.clear(); m_totalFaceCount=0; m_totalVertexCount=0; for(size_t hardwareMeshId = 0; hardwareMeshId < m_vectorHardwareMesh.size(); hardwareMeshId++) { m_totalFaceCount+=m_vectorHardwareMesh[hardwareMeshId].faceCount; m_totalVertexCount+=m_vectorHardwareMesh[hardwareMeshId].vertexCount; } return true; }
void CalCoreBone::calculateBoundingBox(CalCoreModel * pCoreModel) { int boneId = m_pCoreSkeleton->getCoreBoneId(m_strName); bool bBoundsComputed=false; int planeId; CalQuaternion rot; rot=m_rotationBoneSpace; rot.invert(); CalVector dir = CalVector(1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[0].setNormal(dir); dir = CalVector(-1.0f,0.0f,0.0f); dir*=rot; m_boundingBox.plane[1].setNormal(dir); dir = CalVector(0.0f,1.0f,0.0f); dir*=rot; m_boundingBox.plane[2].setNormal(dir); dir = CalVector(0.0f,-1.0f,0.0f); dir*=rot; m_boundingBox.plane[3].setNormal(dir); dir = CalVector(0.0f,0.0f,1.0f); dir*=rot; m_boundingBox.plane[4].setNormal(dir); dir = CalVector(0.0f,0.0f,-1.0f); dir*=rot; m_boundingBox.plane[5].setNormal(dir); int meshId; for(meshId=0; meshId < pCoreModel->getCoreMeshCount(); ++meshId) { CalCoreMesh * pCoreMesh = pCoreModel->getCoreMesh(meshId); int submeshId; for(submeshId=0;submeshId<pCoreMesh->getCoreSubmeshCount();submeshId++) { CalCoreSubmesh *pCoreSubmesh = pCoreMesh->getCoreSubmesh(submeshId); if(pCoreSubmesh->getSpringCount()==0) { std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex(); for(size_t vertexId=0;vertexId <vectorVertex.size(); ++vertexId) { for(size_t influenceId=0;influenceId<vectorVertex[vertexId].vectorInfluence.size();++influenceId) { if(vectorVertex[vertexId].vectorInfluence[influenceId].boneId == boneId && vectorVertex[vertexId].vectorInfluence[influenceId].weight > 0.5f) { for(planeId = 0; planeId < 6; ++planeId) { if(m_boundingBox.plane[planeId].eval(vectorVertex[vertexId].position) < 0.0f) { m_boundingBox.plane[planeId].setPosition(vectorVertex[vertexId].position); m_boundingPosition[planeId]=vectorVertex[vertexId].position; bBoundsComputed=true; } } } } } } } } // To handle bones with no vertices assigned if(!bBoundsComputed) { for(planeId = 0; planeId < 6; ++planeId) { m_boundingBox.plane[planeId].setPosition(m_translation); m_boundingPosition[planeId] = m_translation; } } m_boundingBoxPrecomputed = true; }
void CalCoreSkeleton::calculateBoundingBoxes(CalCoreModel *pCoreModel) { size_t boneId; // First, find out whether all the bounding boxes have already been precomputed. // If so, we can bail out early. bool alreadyComputed = true; for(boneId=0;boneId<m_vectorCoreBone.size();++boneId) { if (! m_vectorCoreBone[boneId]->isBoundingBoxPrecomputed()) { alreadyComputed = false; break; } } if (alreadyComputed) { return; } // Initialize all bounding boxes empty. for(boneId=0;boneId<m_vectorCoreBone.size();++boneId) { m_vectorCoreBone[boneId]->initBoundingBox(); } // Loop over all vertices updating bounding boxes. for(int meshId=0; meshId < pCoreModel->getCoreMeshCount(); ++meshId) { CalCoreMesh * pCoreMesh = pCoreModel->getCoreMesh(meshId); for(int submeshId=0;submeshId<pCoreMesh->getCoreSubmeshCount();submeshId++) { CalCoreSubmesh *pCoreSubmesh = pCoreMesh->getCoreSubmesh(submeshId); if(pCoreSubmesh->getSpringCount()==0) { std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex(); for(size_t vertexId=0;vertexId <vectorVertex.size(); ++vertexId) { for(size_t influenceId=0; influenceId < vectorVertex[vertexId].vectorInfluence.size(); ++influenceId) { if (vectorVertex[vertexId].vectorInfluence[influenceId].weight > 0.5f) { boneId = vectorVertex[vertexId].vectorInfluence[influenceId].boneId; m_vectorCoreBone[boneId]->updateBoundingBox( vectorVertex[vertexId].position ); break; // there can be at most one bone with majority influence } } } } } } // Mark bounding boxes as computed. for(boneId=0;boneId<m_vectorCoreBone.size();++boneId) { m_vectorCoreBone[boneId]->setBoundingBoxPrecomputed( true ); } }