mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 14:56:38 +00:00 
			
		
		
		
	Load NiTriShapes into Ogre meshes
This commit is contained in:
		
							parent
							
								
									3029c221ef
								
							
						
					
					
						commit
						441a5c2da2
					
				
					 1 changed files with 172 additions and 1 deletions
				
			
		|  | @ -490,11 +490,182 @@ class NIFMeshLoader : Ogre::ManualResourceLoader | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // Convert NiTriShape to Ogre::SubMesh
 | ||||
|     void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) | ||||
|     { | ||||
|         const Nif::NiTriShapeData *data = shape->data.getPtr(); | ||||
|         const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); | ||||
|         std::vector<Ogre::Vector3> srcVerts = data->vertices; | ||||
|         std::vector<Ogre::Vector3> srcNorms = data->normals; | ||||
|         if(skin != NULL) | ||||
|         { | ||||
| #if 0 | ||||
|             // Convert vertices and normals back to bone space
 | ||||
|             std::vector<Vector3> newVerts(srcVerts.size(), Vector3(0,0,0)); | ||||
|             std::vector<Vector3> newNorms(srcNorms.size(), Vector3(0,0,0)); | ||||
| 
 | ||||
|             NiSkinDataRef data = skin->GetSkinData(); | ||||
|             const std::vector<NiNodeRef> &bones = skin->GetBones(); | ||||
|             for(size_t b = 0;b < bones.size();b++) | ||||
|             { | ||||
|                 Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform(); | ||||
| 
 | ||||
|                 const std::vector<SkinWeight> &weights = data->GetBoneWeights(b); | ||||
|                 for(size_t i = 0;i < weights.size();i++) | ||||
|                 { | ||||
|                     size_t index = weights[i].index; | ||||
|                     float weight = weights[i].weight; | ||||
| 
 | ||||
|                     newVerts.at(index) += (mat*srcVerts[index]) * weight; | ||||
|                     if(newNorms.size() > index) | ||||
|                     { | ||||
|                         for(size_t j = 0;j < 3;j++) | ||||
|                         { | ||||
|                             newNorms[index][j] += mat[0][j]*srcNorms[index][0] * weight; | ||||
|                             newNorms[index][j] += mat[1][j]*srcNorms[index][1] * weight; | ||||
|                             newNorms[index][j] += mat[2][j]*srcNorms[index][2] * weight; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             srcVerts = newVerts; | ||||
|             srcNorms = newNorms; | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|         // Set the bounding box first
 | ||||
|         BoundsFinder bounds; | ||||
|         bounds.add(&srcVerts[0][0], srcVerts.size()); | ||||
|         mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), | ||||
|                                                 bounds.maxX(), bounds.maxY(), bounds.maxZ())); | ||||
|         mesh->_setBoundingSphereRadius(bounds.getRadius()); | ||||
| 
 | ||||
|         // This function is just one long stream of Ogre-barf, but it works
 | ||||
|         // great.
 | ||||
|         Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); | ||||
|         Ogre::HardwareVertexBufferSharedPtr vbuf; | ||||
|         Ogre::HardwareIndexBufferSharedPtr ibuf; | ||||
|         Ogre::VertexBufferBinding *bind; | ||||
|         Ogre::VertexDeclaration *decl; | ||||
|         int nextBuf = 0; | ||||
| 
 | ||||
|         Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); | ||||
| 
 | ||||
|         // Add vertices
 | ||||
|         sub->useSharedVertices = false; | ||||
|         sub->vertexData = new Ogre::VertexData(); | ||||
|         sub->vertexData->vertexStart = 0; | ||||
|         sub->vertexData->vertexCount = srcVerts.size(); | ||||
| 
 | ||||
|         decl = sub->vertexData->vertexDeclaration; | ||||
|         bind = sub->vertexData->vertexBufferBinding; | ||||
|         if(srcVerts.size()) | ||||
|         { | ||||
|             vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), | ||||
|                                                 srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, | ||||
|                                                 true); | ||||
|             vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); | ||||
| 
 | ||||
|             decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); | ||||
|             bind->setBinding(nextBuf++, vbuf); | ||||
|         } | ||||
| 
 | ||||
|         // Vertex normals
 | ||||
|         if(srcNorms.size()) | ||||
|         { | ||||
|             vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), | ||||
|                                                 srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, | ||||
|                                                 true); | ||||
|             vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); | ||||
| 
 | ||||
|             decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); | ||||
|             bind->setBinding(nextBuf++, vbuf); | ||||
|         } | ||||
| 
 | ||||
|         // Vertex colors
 | ||||
|         const std::vector<Ogre::Vector4> &colors = data->colors; | ||||
|         if(colors.size()) | ||||
|         { | ||||
|             Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); | ||||
|             std::vector<Ogre::RGBA> colorsRGB(colors.size()); | ||||
|             for(size_t i = 0;i < colorsRGB.size();i++) | ||||
|             { | ||||
|                 Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); | ||||
|                 rs->convertColourValue(clr, &colorsRGB[i]); | ||||
|             } | ||||
|             vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), | ||||
|                                                 colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, | ||||
|                                                 true); | ||||
|             vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); | ||||
|             decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); | ||||
|             bind->setBinding(nextBuf++, vbuf); | ||||
|         } | ||||
| 
 | ||||
|         // Texture UV coordinates
 | ||||
|         size_t numUVs = data->uvlist.size(); | ||||
|         if(numUVs) | ||||
|         { | ||||
|             size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); | ||||
|             vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, | ||||
|                                                 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); | ||||
|             for(size_t i = 0;i < numUVs;i++) | ||||
|             { | ||||
|                 const std::vector<Ogre::Vector2> &uvlist = data->uvlist[i]; | ||||
|                 vbuf->writeData(i*srcVerts.size()*elemSize, elemSize*srcVerts.size(), &uvlist[0], true); | ||||
|                 decl->addElement(nextBuf, i*srcVerts.size()*elemSize, Ogre::VET_FLOAT2, | ||||
|                                  Ogre::VES_TEXTURE_COORDINATES, i); | ||||
|             } | ||||
|             bind->setBinding(nextBuf++, vbuf); | ||||
|         } | ||||
| 
 | ||||
|         // Triangle faces
 | ||||
|         const std::vector<short> &srcIdx = data->triangles; | ||||
|         if(srcIdx.size()) | ||||
|         { | ||||
|             ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), | ||||
|                                                Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); | ||||
|             ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); | ||||
|             sub->indexData->indexBuffer = ibuf; | ||||
|             sub->indexData->indexCount = srcIdx.size(); | ||||
|             sub->indexData->indexStart = 0; | ||||
|         } | ||||
| 
 | ||||
|         // Assign bone weights for this TriShape
 | ||||
| #if 0 | ||||
|         if(skin != NULL) | ||||
|         { | ||||
|             // Get the skeleton resource, so weights can be applied
 | ||||
|             Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); | ||||
|             Ogre::SkeletonPtr skel = skelMgr->getByName(mesh->getSkeletonName()); | ||||
| 
 | ||||
|             NiSkinDataRef data = skin->GetSkinData(); | ||||
|             const std::vector<NiNodeRef> &bones = skin->GetBones(); | ||||
|             for(size_t i = 0;i < bones.size();i++) | ||||
|             { | ||||
|                 Ogre::VertexBoneAssignment boneInf; | ||||
|                 boneInf.boneIndex = skel->getBone(bones[i]->GetName())->getHandle(); | ||||
| 
 | ||||
|                 const std::vector<SkinWeight> &weights = data->GetBoneWeights(i); | ||||
|                 for(size_t j = 0;j < weights.size();j++) | ||||
|                 { | ||||
|                     boneInf.vertexIndex = weights[j].index; | ||||
|                     boneInf.weight = weights[j].weight; | ||||
|                     sub->addBoneAssignment(boneInf); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
|         if(mMaterialName.length() > 0) | ||||
|             sub->setMaterialName(mMaterialName); | ||||
|     } | ||||
| 
 | ||||
|     bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) | ||||
|     { | ||||
|         if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) | ||||
|         { | ||||
|             warn("Not loading shape \""+mShapeName+"\" in "+mName); | ||||
|             handleNiTriShape(mesh, dynamic_cast<Nif::NiTriShape*>(node)); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue