mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 06:53:52 +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