From 441a5c2da20f595da6fd5d8ad0b98c2f6c4b9f07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jul 2012 14:12:12 -0700 Subject: [PATCH] Load NiTriShapes into Ogre meshes --- components/nifogre/ogre_nif_loader.cpp | 173 ++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b0e92d82f..884d8f64e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -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 srcVerts = data->vertices; + std::vector srcNorms = data->normals; + if(skin != NULL) + { +#if 0 + // Convert vertices and normals back to bone space + std::vector newVerts(srcVerts.size(), Vector3(0,0,0)); + std::vector newNorms(srcNorms.size(), Vector3(0,0,0)); + + NiSkinDataRef data = skin->GetSkinData(); + const std::vector &bones = skin->GetBones(); + for(size_t b = 0;b < bones.size();b++) + { + Matrix44 mat = data->GetBoneTransform(b) * bones[b]->GetWorldTransform(); + + const std::vector &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 &colors = data->colors; + if(colors.size()) + { + Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); + std::vector 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 &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 &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 &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 &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(node)); return true; }