void EMDOgre::createOgreMesh(EMDSubmesh *submesh, string mesh_name) { string ogre_mesh_name = mesh_name + "_" + submesh->getMaterialName(); Ogre::MeshPtr ogre_mesh = Ogre::MeshManager::getSingleton().createManual(ogre_mesh_name, XENOVIEWER_RESOURCE_GROUP); LibXenoverse::AABB mesh_aabb; mesh_aabb.reset(); if (skeleton) { ogre_mesh->setSkeletonName(skeleton->getName()); } // Create Vertex Pool vector<EMDVertex> submesh_vertices = submesh->getVertices(); const size_t nVertices = submesh_vertices.size(); const size_t nVertCount = 8; const size_t vbufCount = nVertCount*nVertices; float *vertices = (float *)malloc(sizeof(float)*vbufCount); for (size_t i = 0; i < nVertices; i++) { vertices[i*nVertCount] = submesh_vertices[i].x; vertices[i*nVertCount + 1] = submesh_vertices[i].y; vertices[i*nVertCount + 2] = submesh_vertices[i].z; vertices[i*nVertCount + 3] = submesh_vertices[i].nx; vertices[i*nVertCount + 4] = submesh_vertices[i].ny; vertices[i*nVertCount + 5] = submesh_vertices[i].nz; vertices[i*nVertCount + 6] = submesh_vertices[i].u; vertices[i*nVertCount + 7] = submesh_vertices[i].v; mesh_aabb.addPoint(submesh_vertices[i].x, submesh_vertices[i].y, submesh_vertices[i].z); } // Create Submeshes for each Triangle List vector<EMDTriangles> submesh_triangles = submesh->getTriangles(); for (size_t i = 0; i < submesh_triangles.size(); i++) { Ogre::SubMesh *sub = createOgreSubmesh(&submesh_triangles[i], ogre_mesh); } // Create Shared Vertex Data for all submeshes Ogre::VertexData *vertex_data = new Ogre::VertexData(); ogre_mesh->sharedVertexData = vertex_data; vertex_data->vertexCount = nVertices; Ogre::VertexDeclaration* decl = vertex_data->vertexDeclaration; size_t offset = 0; decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); decl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); Ogre::HardwareVertexBufferSharedPtr vbuf = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(offset, nVertices, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true); Ogre::VertexBufferBinding* bind = vertex_data->vertexBufferBinding; bind->setBinding(0, vbuf); // Create Bone Assignments if Skeleton name exists if (skeleton) { Ogre::Skeleton *ogre_skeleton = skeleton->getOgreSkeleton(); if (ogre_skeleton) { for (size_t i = 0; i < submesh_triangles.size(); i++) { EMDTriangles *triangles = &submesh_triangles[i]; vector<unsigned int> vertex_indices; size_t face_count = triangles->faces.size(); // Make a list of all vertex indices being used in the submesh vertex_indices.reserve(face_count); for (size_t j = 0; j < face_count; j++) { bool found = false; for (size_t k = 0; k < vertex_indices.size(); k++) { if (vertex_indices[k] == triangles->faces[j]) { found = true; break; } } if (!found) vertex_indices.push_back(triangles->faces[j]); } // Build Bone Mapping Table vector<unsigned short> bone_table; bone_table.resize(triangles->bone_names.size()); for (size_t j = 0; j < bone_table.size(); j++) { string bone_name = triangles->bone_names[j]; LOG_DEBUG("Bone Skin Table %d: %s\n", j, bone_name.c_str()); if (ogre_skeleton->hasBone(bone_name)) { Ogre::Bone *mBone = ogre_skeleton->getBone(bone_name); bone_table[j] = mBone->getHandle(); } else { LOG_DEBUG("Couldn't find %s in ogre skeleton!\n", bone_name.c_str()); } } // Add bone assignments to all the vertices that were found for (size_t j = 0; j < vertex_indices.size(); j++) { Ogre::VertexBoneAssignment vba; vba.vertexIndex = vertex_indices[j]; EMDVertex *vertex = &submesh_vertices[vba.vertexIndex]; for (size_t k = 0; k < 4; k++) { unsigned char bone_index = vertex->bone[3 - k]; float bone_weight = vertex->bone_weight[k]; if (bone_weight > 0.0f) { vba.boneIndex = bone_table[bone_index]; vba.weight = bone_weight; ogre_mesh->addBoneAssignment(vba); } } } } // Apply changes, build the buffer ogre_mesh->_compileBoneAssignments(); ogre_mesh->sharedVertexData->reorganiseBuffers(decl->getAutoOrganisedDeclaration(true, false, false)); } } //ogre_mesh->_setBounds(Ogre::AxisAlignedBox(mesh_aabb.start_x, mesh_aabb.start_y, mesh_aabb.start_z, mesh_aabb.end_x, mesh_aabb.end_y, mesh_aabb.end_z)); ogre_mesh->_setBounds(Ogre::AxisAlignedBox(-1000, -1000, -1000, 1000, 1000, 1000)); ogre_mesh->_setBoundingSphereRadius(mesh_aabb.sizeMax()); ogre_mesh->load(); free(vertices); created_meshes.push_back(ogre_mesh_name); }
// Write submesh data to an Ogre compatible mesh bool Submesh::createOgreSubmesh(Ogre::MeshPtr pMesh,const ParamList& params) { size_t i,j; bool stat; // Create a new submesh Ogre::SubMesh* pSubmesh; if (m_name != "") pSubmesh = pMesh->createSubMesh(m_name.c_str()); else pSubmesh = pMesh->createSubMesh(); // Set material pSubmesh->setMaterialName(m_pMaterial->name().c_str()); // Set use shared geometry flag pSubmesh->useSharedVertices = params.useSharedGeom; // Create vertex data for current submesh pSubmesh->vertexData = new Ogre::VertexData(); // Set number of indexes pSubmesh->indexData->indexCount = 3*m_faces.size(); pSubmesh->vertexData->vertexCount = m_vertices.size(); // Check if we need to use 32 bit indexes bool use32BitIndexes = false; if (m_vertices.size() > 65536 || params.useSharedGeom) { use32BitIndexes = true; } // Create a new index buffer pSubmesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer( use32BitIndexes ? Ogre::HardwareIndexBuffer::IT_32BIT : Ogre::HardwareIndexBuffer::IT_16BIT, pSubmesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); // Fill the index buffer with faces data if (use32BitIndexes) { Ogre::uint32* pIdx = static_cast<Ogre::uint32*>( pSubmesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD)); for (i=0; i<m_faces.size(); i++) { *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[0]); *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[1]); *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[2]); } pSubmesh->indexData->indexBuffer->unlock(); } else { Ogre::uint16* pIdx = static_cast<Ogre::uint16*>( pSubmesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD)); for (i=0; i<m_faces.size(); i++) { *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[0]); *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[1]); *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[2]); } pSubmesh->indexData->indexBuffer->unlock(); } // Define vertex declaration (only if we're not using shared geometry) if(!params.useSharedGeom) { Ogre::VertexDeclaration* pDecl = pSubmesh->vertexData->vertexDeclaration; unsigned buf = 0; size_t offset = 0; // Add vertex position pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); // Add vertex normal if (params.exportVertNorm) { pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3); } // Add vertex colour if(params.exportVertCol) { pDecl->addElement(buf, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR); } // Add texture coordinates for (i=0; i<m_vertices[0].texcoords.size(); i++) { Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, 2); pDecl->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, static_cast<unsigned short>(i)); offset += Ogre::VertexElement::getTypeSize(uvType); } Ogre::VertexDeclaration* pOptimalDecl = pDecl->getAutoOrganisedDeclaration( params.exportVBA, params.exportBlendShapes || params.exportVertAnims, false); // Fill the vertex buffer using the newly created vertex declaration stat = createOgreVertexBuffer(pSubmesh,pDecl,m_vertices); // Write vertex bone assignements list if (params.exportVBA) { // Create a new vertex bone assignements list Ogre::SubMesh::VertexBoneAssignmentList vbas; // Scan list of shared geometry vertices for (i=0; i<m_vertices.size(); i++) { vertex v = m_vertices[i]; // Add all bone assignemnts for every vertex to the bone assignements list for (j=0; j<v.vbas.size(); j++) { Ogre::VertexBoneAssignment vba; vba.vertexIndex = static_cast<unsigned int>(i); vba.boneIndex = v.vbas[j].jointIdx; vba.weight = v.vbas[j].weight; vbas.insert(Ogre::SubMesh::VertexBoneAssignmentList::value_type(i, vba)); } } // Rationalise the bone assignements list pSubmesh->parent->_rationaliseBoneAssignments(pSubmesh->vertexData->vertexCount,vbas); // Add bone assignements to the submesh for (Ogre::SubMesh::VertexBoneAssignmentList::iterator bi = vbas.begin(); bi != vbas.end(); bi++) { pSubmesh->addBoneAssignment(bi->second); } pSubmesh->_compileBoneAssignments(); } pSubmesh->vertexData->reorganiseBuffers(pOptimalDecl); } return true; }