//----------------------------------------------------------------------- void MeshInformer::getEntityTriangles(const Entity* entity, std::vector<Vector3>& vertices, std::vector<size_t>& indices, std::vector<size_t>* indexOffsets) { size_t numVertices = 0, numIndices = 0; getEntityStatistics(entity, numVertices, numIndices); size_t vertex_offset = vertices.size(); size_t index_offset = indices.size(); vertices.resize(vertex_offset + numVertices); indices.resize(index_offset + numIndices); // Software blended vertex data available only if animation enabled, and software animation are // used by internally engine, or user requested software animation. bool useBlended = entity->_isAnimated() && (!entity->isHardwareAnimationEnabled() || entity->getSoftwareAnimationRequests() > 0); // Use skinned vertex data only if blended data available and skeleton animation enabled. bool useSkinned = useBlended && entity->_isSkeletonAnimated(); Vector3* pVertices = &vertices[0]; size_t* pIndices = &indices[0]; size_t shared_vertex_offset = vertex_offset; bool added_shared_vertex = false; size_t numSubEntities = entity->getNumSubEntities(); for (size_t i = 0; i < numSubEntities; ++i) { SubEntity* subEntity = entity->getSubEntity(i); if (!subEntity->isVisible()) { // Skip non-visible sub-entity continue; } SubMesh* subMesh = subEntity->getSubMesh(); if (indexOffsets) { indexOffsets->push_back(index_offset); } if (subMesh->operationType == RenderOperation::OT_TRIANGLE_LIST || subMesh->operationType == RenderOperation::OT_TRIANGLE_STRIP || subMesh->operationType == RenderOperation::OT_TRIANGLE_FAN) { size_t current_vertex_offset; if (subMesh->useSharedVertices) { if (!added_shared_vertex) { size_t vertexCount = getVertices(pVertices + vertex_offset, useSkinned ? entity->_getSkelAnimVertexData() : useBlended && subMesh->parent->getSharedVertexDataAnimationType() != VAT_NONE ? entity->_getSoftwareVertexAnimVertexData() : subMesh->parent->sharedVertexData); shared_vertex_offset = vertex_offset; vertex_offset += vertexCount; added_shared_vertex = true; } current_vertex_offset = shared_vertex_offset; } else { size_t vertexCount = getVertices(pVertices + vertex_offset, useSkinned ? subEntity->_getSkelAnimVertexData() : useBlended && subMesh->getVertexAnimationType() != VAT_NONE ? subEntity->_getSoftwareVertexAnimVertexData() : subMesh->vertexData); current_vertex_offset = vertex_offset; vertex_offset += vertexCount; } size_t index_count = getTriangles(pIndices + index_offset, subMesh->indexData, current_vertex_offset, subMesh->operationType); index_offset += index_count; } } }
void MeshSerializerTests::assertMeshClone(Mesh* a, Mesh* b, MeshVersion version /*= MESH_VERSION_LATEST*/) { // TODO: Compare skeleton // TODO: Compare animations // TODO: Compare pose animations // CPPUNIT_ASSERT(a->getGroup() == b->getGroup()); // CPPUNIT_ASSERT(a->getName() == b->getName()); #ifndef OGRE_TEST_XMLSERIALIZER // XML serializer fails on these! CPPUNIT_ASSERT(isEqual(a->getBoundingSphereRadius(), b->getBoundingSphereRadius())); CPPUNIT_ASSERT(isEqual(a->getBounds().getMinimum(), b->getBounds().getMinimum())); CPPUNIT_ASSERT(isEqual(a->getBounds().getMaximum(), b->getBounds().getMaximum())); #else StringStream str; Real val1 = a->getBoundingSphereRadius(); Real val2 = b->getBoundingSphereRadius(); Real diff = (val1 > val2) ? (val1 / val2) : (val2 / val1); if (diff > 1.1) { str << "bound sphere diff: " << diff << std::endl; } val1 = a->getBounds().getMinimum().length(); val2 = b->getBounds().getMinimum().length(); diff = (val1 > val2) ? (val1 / val2) : (val2 / val1); if (diff > 1.1) { str << "bound min diff: " << diff << std::endl; } val1 = a->getBounds().getMaximum().length(); val2 = b->getBounds().getMaximum().length(); diff = (val1 > val2) ? (val1 / val2) : (val2 / val1); if (diff > 1.1) { str << "bound max diff: " << diff << std::endl; } if (!str.str().empty()) { StringStream str2; str2 << std::endl << "Mesh name: " << b->getName() << std::endl; str2 << str.str(); std::cout << str2.str(); // OutputDebugStringA(str2.str().c_str()); } #endif /* ifndef OGRE_TEST_XMLSERIALIZER */ // AutobuildEdgeLists is not saved to mesh file. You need to set it after loading a mesh! // CPPUNIT_ASSERT(a->getAutoBuildEdgeLists() == b->getAutoBuildEdgeLists()); CPPUNIT_ASSERT(isHashMapClone(a->getSubMeshNameMap(), b->getSubMeshNameMap())); assertVertexDataClone(a->sharedVertexData, b->sharedVertexData); CPPUNIT_ASSERT(a->getCreator() == b->getCreator()); CPPUNIT_ASSERT(a->getIndexBufferUsage() == b->getIndexBufferUsage()); CPPUNIT_ASSERT(a->getSharedVertexDataAnimationIncludesNormals() == b->getSharedVertexDataAnimationIncludesNormals()); CPPUNIT_ASSERT(a->getSharedVertexDataAnimationType() == b->getSharedVertexDataAnimationType()); CPPUNIT_ASSERT(a->getVertexBufferUsage() == b->getVertexBufferUsage()); CPPUNIT_ASSERT(a->hasVertexAnimation() == b->hasVertexAnimation()); #ifndef OGRE_TEST_XMLSERIALIZER CPPUNIT_ASSERT(a->isEdgeListBuilt() == b->isEdgeListBuilt()); // <== OgreXMLSerializer is doing post processing to generate edgelists! #endif // !OGRE_TEST_XMLSERIALIZER if ((a->getNumLodLevels() > 1 || b->getNumLodLevels() > 1) && ((version < MESH_VERSION_1_8 || (!isLodMixed(a) && !isLodMixed(b))) && // mixed lod only supported in v1.10+ (version < MESH_VERSION_1_4 || (a->getLodStrategy() == DistanceLodStrategy::getSingletonPtr() && b->getLodStrategy() == DistanceLodStrategy::getSingletonPtr())))) { // Lod Strategy only supported in v1.41+ CPPUNIT_ASSERT(a->getNumLodLevels() == b->getNumLodLevels()); CPPUNIT_ASSERT(a->hasManualLodLevel() == b->hasManualLodLevel()); CPPUNIT_ASSERT(a->getLodStrategy() == b->getLodStrategy()); int numLods = a->getNumLodLevels(); for (int i = 0; i < numLods; i++) { if (version != MESH_VERSION_1_0 && a->getAutoBuildEdgeLists() == b->getAutoBuildEdgeLists()) { assertEdgeDataClone(a->getEdgeList(i), b->getEdgeList(i)); } else if (a->getLodLevel(i).edgeData != NULL && b->getLodLevel(i).edgeData != NULL) { assertEdgeDataClone(a->getLodLevel(i).edgeData, b->getLodLevel(i).edgeData); } assertLodUsageClone(a->getLodLevel(i), b->getLodLevel(i)); } } CPPUNIT_ASSERT(a->getNumSubMeshes() == b->getNumSubMeshes()); int numLods = std::min(a->getNumLodLevels(), b->getNumLodLevels()); int numSubmeshes = a->getNumSubMeshes(); for (int i = 0; i < numSubmeshes; i++) { SubMesh* aSubmesh = a->getSubMesh(i); SubMesh* bSubmesh = b->getSubMesh(i); CPPUNIT_ASSERT(aSubmesh->getMaterialName() == bSubmesh->getMaterialName()); CPPUNIT_ASSERT(aSubmesh->isMatInitialised() == bSubmesh->isMatInitialised()); CPPUNIT_ASSERT(aSubmesh->useSharedVertices == bSubmesh->useSharedVertices); CPPUNIT_ASSERT(aSubmesh->getVertexAnimationIncludesNormals() == bSubmesh->getVertexAnimationIncludesNormals()); CPPUNIT_ASSERT(aSubmesh->getVertexAnimationType() == bSubmesh->getVertexAnimationType()); CPPUNIT_ASSERT(aSubmesh->getTextureAliasCount() == bSubmesh->getTextureAliasCount()); CPPUNIT_ASSERT(isContainerClone(aSubmesh->blendIndexToBoneIndexMap, bSubmesh->blendIndexToBoneIndexMap)); // TODO: Compare getBoneAssignments and getTextureAliases for (int n = 0; n < numLods; n++) { if (a->_isManualLodLevel(n)) { continue; } RenderOperation aop, bop; aSubmesh->_getRenderOperation(aop, n); bSubmesh->_getRenderOperation(bop, n); assertIndexDataClone(aop.indexData, bop.indexData); assertVertexDataClone(aop.vertexData, bop.vertexData); CPPUNIT_ASSERT(aop.operationType == bop.operationType); CPPUNIT_ASSERT(aop.useIndexes == bop.useIndexes); } } }
void XMLToBinary(XmlOptions opts) { // Read root element and decide from there what type String response; TiXmlDocument* doc = new TiXmlDocument(opts.source); // Some double-parsing here but never mind if (!doc->LoadFile()) { cout << "Unable to open file " << opts.source << " - fatal error." << endl; delete doc; exit (1); } TiXmlElement* root = doc->RootElement(); if (!stricmp(root->Value(), "mesh")) { delete doc; MeshPtr newMesh = MeshManager::getSingleton().createManual("conversion", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); VertexElementType colourElementType; if (opts.d3d) colourElementType = VET_COLOUR_ARGB; else colourElementType = VET_COLOUR_ABGR; xmlMeshSerializer->importMesh(opts.source, colourElementType, newMesh.getPointer()); // Re-jig the buffers? // Make sure animation types are up to date first newMesh->_determineAnimationTypes(); if (opts.reorganiseBuffers) { logMgr->logMessage("Reorganising vertex buffers to automatic layout..."); // Shared geometry if (newMesh->sharedVertexData) { // Automatic VertexDeclaration* newDcl = newMesh->sharedVertexData->vertexDeclaration->getAutoOrganisedDeclaration( newMesh->hasSkeleton(), newMesh->hasVertexAnimation(), newMesh->getSharedVertexDataAnimationIncludesNormals()); if (*newDcl != *(newMesh->sharedVertexData->vertexDeclaration)) { // Usages don't matter here since we're onlly exporting BufferUsageList bufferUsages; for (size_t u = 0; u <= newDcl->getMaxSource(); ++u) bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY); newMesh->sharedVertexData->reorganiseBuffers(newDcl, bufferUsages); } } // Dedicated geometry Mesh::SubMeshIterator smIt = newMesh->getSubMeshIterator(); while (smIt.hasMoreElements()) { SubMesh* sm = smIt.getNext(); if (!sm->useSharedVertices) { const bool hasVertexAnim = sm->getVertexAnimationType() != Ogre::VAT_NONE; // Automatic VertexDeclaration* newDcl = sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration( newMesh->hasSkeleton(), hasVertexAnim, sm->getVertexAnimationIncludesNormals()); if (*newDcl != *(sm->vertexData->vertexDeclaration)) { // Usages don't matter here since we're onlly exporting BufferUsageList bufferUsages; for (size_t u = 0; u <= newDcl->getMaxSource(); ++u) bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY); sm->vertexData->reorganiseBuffers(newDcl, bufferUsages); } } } } if( opts.mergeTexcoordResult != opts.mergeTexcoordToDestroy ) { newMesh->mergeAdjacentTexcoords( uint16(opts.mergeTexcoordResult), uint16(opts.mergeTexcoordToDestroy) ); } if (opts.nuextremityPoints) { Mesh::SubMeshIterator smIt = newMesh->getSubMeshIterator(); while (smIt.hasMoreElements()) { SubMesh* sm = smIt.getNext(); sm->generateExtremes (opts.nuextremityPoints); } } meshSerializer->exportMesh(newMesh.getPointer(), opts.dest, opts.endian); // Clean up the conversion mesh MeshManager::getSingleton().remove("conversion"); } else if (!stricmp(root->Value(), "skeleton")) { delete doc; SkeletonPtr newSkel = SkeletonManager::getSingleton().create("conversion", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); xmlSkeletonSerializer->importSkeleton(opts.source, newSkel.getPointer()); if (opts.optimiseAnimations) { newSkel->optimiseAllAnimations(); } skeletonSerializer->exportSkeleton(newSkel.getPointer(), opts.dest, SKELETON_VERSION_LATEST, opts.endian); // Clean up the conversion skeleton SkeletonManager::getSingleton().remove("conversion"); } else { delete doc; } }