diff --git a/CHANGELOG.md b/CHANGELOG.md index 773d4eeb5d..fa9d987962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -161,6 +161,7 @@ Feature #5051: Provide a separate textures for scrollbars Feature #5094: Unix like console hotkeys Feature #5098: Allow user controller bindings + Feature #5121: Handle NiTriStrips and NiTriStripsData Feature #5122: Use magic glow for enchanted arrows Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4695: Optimize Distant Terrain memory consumption diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 0860219305..4a9266239c 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -90,6 +90,26 @@ void NiTriShapeData::read(NIFStream *nif) } } +void NiTriStripsData::read(NIFStream *nif) +{ + ShapeData::read(nif); + + // Every strip with n points defines n-2 triangles, so this should be unnecessary. + /*int tris =*/ nif->getUShort(); + // Number of triangle strips + int numStrips = nif->getUShort(); + + std::vector lengths; + nif->getUShorts(lengths, numStrips); + + for (int i = 0; i < numStrips; i++) + { + std::vector strip; + nif->getUShorts(strip, lengths[i]); + strips.emplace_back(strip); + } +} + void NiAutoNormalParticlesData::read(NIFStream *nif) { ShapeData::read(nif); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 6b7aa579bc..fb1199cff9 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -53,6 +53,15 @@ public: void read(NIFStream *nif); }; +class NiTriStripsData : public ShapeData +{ +public: + // Triangle strips, series of vertex indices. + std::vector> strips; + + void read(NIFStream *nif); +}; + class NiAutoNormalParticlesData : public ShapeData { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 6675fef08e..4b3760ba22 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -54,6 +54,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiBSAnimationNode", &construct , RC_NiBSAnimationNode )); newFactory.insert(makeEntry("NiBillboardNode", &construct , RC_NiBillboardNode )); newFactory.insert(makeEntry("NiTriShape", &construct , RC_NiTriShape )); + newFactory.insert(makeEntry("NiTriStrips", &construct , RC_NiTriStrips )); newFactory.insert(makeEntry("NiRotatingParticles", &construct , RC_NiRotatingParticles )); newFactory.insert(makeEntry("NiAutoNormalParticles", &construct , RC_NiAutoNormalParticles )); newFactory.insert(makeEntry("NiCamera", &construct , RC_NiCamera )); @@ -96,6 +97,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiParticleRotation", &construct , RC_NiParticleRotation )); newFactory.insert(makeEntry("NiFloatData", &construct , RC_NiFloatData )); newFactory.insert(makeEntry("NiTriShapeData", &construct , RC_NiTriShapeData )); + newFactory.insert(makeEntry("NiTriStripsData", &construct , RC_NiTriStripsData )); newFactory.insert(makeEntry("NiVisData", &construct , RC_NiVisData )); newFactory.insert(makeEntry("NiColorData", &construct , RC_NiColorData )); newFactory.insert(makeEntry("NiPixelData", &construct , RC_NiPixelData )); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index cc1871d83a..5e5f445cf4 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -156,6 +156,29 @@ struct NiTriShape : Node } }; +struct NiTriStrips : Node +{ + NiTriStripsDataPtr data; + NiSkinInstancePtr skin; + + void read(NIFStream *nif) + { + Node::read(nif); + data.read(nif); + skin.read(nif); + } + + void post(NIFFile *nif) + { + Node::post(nif); + data.post(nif); + skin.post(nif); + if (!skin.empty()) + nif->setUseSkinning(true); + } +}; + + struct NiCamera : Node { struct Camera diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 4a044ac471..909c268bbe 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -41,6 +41,7 @@ enum RecordType RC_NiBillboardNode, RC_AvoidNode, RC_NiTriShape, + RC_NiTriStrips, RC_NiRotatingParticles, RC_NiAutoNormalParticles, RC_NiBSParticleNode, @@ -80,6 +81,7 @@ enum RecordType RC_NiParticleRotation, RC_NiFloatData, RC_NiTriShapeData, + RC_NiTriStripsData, RC_NiVisData, RC_NiColorData, RC_NiPixelData, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index e8aa8cb5b5..9779735171 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -135,6 +135,7 @@ class NiPixelData; class NiColorData; struct NiKeyframeData; class NiTriShapeData; +class NiTriStripsData; class NiSkinInstance; class NiSourceTexture; class NiRotatingParticlesData; @@ -154,6 +155,7 @@ typedef RecordPtrT NiFloatDataPtr; typedef RecordPtrT NiColorDataPtr; typedef RecordPtrT NiKeyframeDataPtr; typedef RecordPtrT NiTriShapeDataPtr; +typedef RecordPtrT NiTriStripsDataPtr; typedef RecordPtrT NiSkinInstancePtr; typedef RecordPtrT NiSourceTexturePtr; typedef RecordPtrT NiRotatingParticlesDataPtr; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 8f98174ab7..2f24a40674 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -54,9 +54,57 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriShapeDa } } -void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data) +void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsData& data, const osg::Matrixf &transform) { - fillTriangleMeshWithTransform(mesh, data, osg::Matrixf()); + const std::vector &vertices = data.vertices; + const std::vector> &strips = data.strips; + if (vertices.empty() || strips.empty()) + return; + mesh.preallocateVertices(static_cast(data.vertices.size())); + int numTriangles = 0; + for (const std::vector& strip : strips) + { + // Each strip with N points contains information about N-2 triangles. + if (strip.size() >= 3) + numTriangles += static_cast(strip.size()-2); + } + mesh.preallocateIndices(static_cast(numTriangles)); + + // It's triangulation time. Totally not a NifSkope spell ripoff. + for (const std::vector& strip : strips) + { + // Can't make a triangle from less than 3 points. + if (strip.size() < 3) + continue; + + unsigned short a = strip[0], b = strip[0], c = strip[1]; + for (int i = 2; i < static_cast(strip.size()); i++) + { + a = b; + b = c; + c = strip[i]; + if (a != b && b != c && a != c) + { + if (i%2==0) + mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[b]), getbtVector(vertices[c])); + else + mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[c]), getbtVector(vertices[b])); + } + } + } +} + +void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::Node* nifNode, const osg::Matrixf &transform) +{ + if (nifNode->recType == Nif::RC_NiTriShape) + fillTriangleMeshWithTransform(mesh, static_cast(nifNode)->data.get(), transform); + else // if (nifNode->recType == Nif::RC_NiTriStrips) + fillTriangleMeshWithTransform(mesh, static_cast(nifNode)->data.get(), transform); +} + +void fillTriangleMesh(btTriangleMesh& mesh, const Nif::Node* node) +{ + fillTriangleMeshWithTransform(mesh, node, osg::Matrixf()); } } @@ -244,9 +292,9 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape! // It must be ignored completely. // (occurs in tr_ex_imp_wall_arch_04.nif) - if(!node->hasBounds && node->recType == Nif::RC_NiTriShape) + if(!node->hasBounds && (node->recType == Nif::RC_NiTriShape || node->recType == Nif::RC_NiTriStrips)) { - handleNiTriShape(static_cast(node), flags, getWorldTransform(node), isAnimated, avoid); + handleNiTriShape(node, flags, getWorldTransform(node), isAnimated, avoid); } } @@ -263,25 +311,33 @@ void BulletNifLoader::handleNode(const std::string& fileName, const Nif::Node *n } } -void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf &transform, +void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, const osg::Matrixf &transform, bool isAnimated, bool avoid) { - assert(shape != nullptr); + assert(nifNode != nullptr); // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. if ((flags & 0x800)) - { return; + + if (nifNode->recType == Nif::RC_NiTriShape) + { + const Nif::NiTriShape* shape = static_cast(nifNode); + if (!shape->skin.empty()) + isAnimated = false; + if (shape->data.empty() || shape->data->triangles.empty()) + return; + } + else + { + const Nif::NiTriStrips* shape = static_cast(nifNode); + if (!shape->skin.empty()) + isAnimated = false; + if (shape->data.empty() || shape->data->strips.empty()) + return; } - if (!shape->skin.empty()) - isAnimated = false; - - if (shape->data.empty()) - return; - if (shape->data->triangles.empty()) - return; if (isAnimated) { @@ -290,13 +346,13 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, std::unique_ptr childMesh(new btTriangleMesh); - fillTriangleMesh(*childMesh, shape->data.get()); + fillTriangleMesh(*childMesh, nifNode); std::unique_ptr childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); childMesh.release(); - float scale = shape->trafo.scale; - const Nif::Node* parent = shape; + float scale = nifNode->trafo.scale; + const Nif::Node* parent = nifNode; while (parent->parent) { parent = parent->parent; @@ -308,7 +364,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, btTransform trans(btQuaternion(q.x(), q.y(), q.z(), q.w()), btVector3(v.x(), v.y(), v.z())); - mShape->mAnimatedShapes.insert(std::make_pair(shape->recIndex, mCompoundShape->getNumChildShapes())); + mShape->mAnimatedShapes.emplace(nifNode->recIndex, mCompoundShape->getNumChildShapes()); mCompoundShape->addChildShape(trans, childShape.get()); childShape.release(); @@ -318,7 +374,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, if (!mAvoidStaticMesh) mAvoidStaticMesh.reset(new btTriangleMesh(false)); - fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform); + fillTriangleMeshWithTransform(*mAvoidStaticMesh, nifNode, transform); } else { @@ -326,7 +382,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, mStaticMesh.reset(new btTriangleMesh(false)); // Static shape, just transform all vertices into position - fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform); + fillTriangleMeshWithTransform(*mStaticMesh, nifNode, transform); } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index de7e6bdcdd..e423e51496 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -26,6 +26,7 @@ namespace Nif class Node; struct Transformation; struct NiTriShape; + struct NiTriStrips; } namespace NifBullet @@ -58,7 +59,7 @@ private: bool hasAutoGeneratedCollision(const Nif::Node *rootNode); - void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const osg::Matrixf& transform, bool isAnimated, bool avoid); + void handleNiTriShape(const Nif::Node *nifNode, int flags, const osg::Matrixf& transform, bool isAnimated, bool avoid); std::unique_ptr mCompoundShape; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 69840117d1..60644c758f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -452,6 +452,7 @@ namespace NifOsg break; } case Nif::RC_NiTriShape: + case Nif::RC_NiTriStrips: case Nif::RC_NiAutoNormalParticles: case Nif::RC_NiRotatingParticles: // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. @@ -575,7 +576,7 @@ namespace NifOsg node->setDataVariance(osg::Object::DYNAMIC); } - if (nifNode->recType == Nif::RC_NiTriShape && isAnimated) // the same thing for animated NiTriShapes + if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) // Same thing for animated shapes { node->setDataVariance(osg::Object::DYNAMIC); } @@ -584,20 +585,25 @@ namespace NifOsg applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); - if (nifNode->recType == Nif::RC_NiTriShape && !skipMeshes) + if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && !skipMeshes) { - const Nif::NiTriShape* triShape = static_cast(nifNode); - const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name); + const std::string nodeName = Misc::StringUtils::lowerCase(nifNode->name); static const std::string markerName = "tri editormarker"; static const std::string shadowName = "shadow"; static const std::string shadowName2 = "tri shadow"; const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName); if (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2)) { - if (triShape->skin.empty()) - handleTriShape(triShape, node, composite, boundTextures, animflags); + Nif::NiSkinInstancePtr skin; + if (nifNode->recType == Nif::RC_NiTriShape) + skin = static_cast(nifNode)->skin; + else // if (nifNode->recType == Nif::RC_NiTriStrips) + skin = static_cast(nifNode)->skin; + + if (skin.empty()) + handleTriShape(nifNode, node, composite, boundTextures, animflags); else - handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); + handleSkinnedTriShape(nifNode, node, composite, boundTextures, animflags); if (!nifNode->controller.empty()) handleMeshControllers(nifNode, node, composite, boundTextures, animflags); @@ -612,7 +618,8 @@ namespace NifOsg // Note: NiTriShapes are not allowed to have KeyframeControllers (the vanilla engine just crashes when there is one). // We can take advantage of this constraint for optimizations later. - if (nifNode->recType != Nif::RC_NiTriShape && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) + if (nifNode->recType != Nif::RC_NiTriShape && nifNode->recType != Nif::RC_NiTriStrips + && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); const Nif::NiNode *ninode = dynamic_cast(nifNode); @@ -673,7 +680,7 @@ namespace NifOsg handleVisController(static_cast(ctrl.getPtr()), node, animflags); } else if(ctrl->recType == Nif::RC_NiGeomMorpherController) - {} // handled in handleTriShape + {} // handled in handleMorphController else Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } @@ -1030,57 +1037,100 @@ namespace NifOsg } } - void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + void triCommonToGeometry(osg::Geometry *geometry, const std::vector& vertices, const std::vector& normals, const std::vector>& uvlist, const std::vector& colors, const std::vector& boundTextures, const std::string& name) { - const Nif::NiTriShapeData* data = triShape->data.getPtr(); - - if (!data->vertices.empty()) - geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), data->vertices.data())); - if (!data->normals.empty()) - geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), data->normals.data()), osg::Array::BIND_PER_VERTEX); + if (!vertices.empty()) + geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data())); + if (!normals.empty()) + geometry->setNormalArray(new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX); + if (!colors.empty()) + geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX); int textureStage = 0; - for (std::vector::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) + for (const int uvSet : boundTextures) { - int uvSet = *it; - if (uvSet >= (int)data->uvlist.size()) + if (uvSet >= (int)uvlist.size()) { - Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename; - if (!data->uvlist.empty()) - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[0].size(), data->uvlist[0].data()), osg::Array::BIND_PER_VERTEX); + Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; + if (!uvlist.empty()) + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[0].size(), uvlist[0].data()), osg::Array::BIND_PER_VERTEX); continue; } - geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), data->uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[uvSet].size(), uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX); + textureStage++; } + } - if (!data->colors.empty()) - geometry->setColorArray(new osg::Vec4Array(data->colors.size(), data->colors.data()), osg::Array::BIND_PER_VERTEX); - - if (!data->triangles.empty()) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, - data->triangles.size(), - (unsigned short*)data->triangles.data())); + void triShapeToGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + { + bool vertexColorsPresent = false; + if (nifNode->recType == Nif::RC_NiTriShape) + { + const Nif::NiTriShape* triShape = static_cast(nifNode); + const Nif::NiTriShapeData* data = triShape->data.getPtr(); + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name); + if (!data->triangles.empty()) + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), + (unsigned short*)data->triangles.data())); + } + else + { + const Nif::NiTriStrips* triStrips = static_cast(nifNode); + const Nif::NiTriStripsData* data = triStrips->data.getPtr(); + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name); + if (!data->strips.empty()) + { + for (const std::vector& strip : data->strips) + { + // Can't make a triangle from less than three vertices. + if (strip.size() < 3) + continue; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), + (unsigned short*)strip.data())); + } + } + } // osg::Material properties are handled here for two reasons: // - if there are no vertex colors, we need to disable colorMode. // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them // above the actual renderable would be tedious. std::vector drawableProps; - collectDrawableProperties(triShape, drawableProps); - applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false); + collectDrawableProperties(nifNode, drawableProps); + applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags, false); } - void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + void handleTriShape(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { + assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips); osg::ref_ptr drawable; - for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) + osg::ref_ptr geom (new osg::Geometry); + triShapeToGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags); + Nif::ControllerPtr ctrl; + if (nifNode->recType == Nif::RC_NiTriShape) + ctrl = static_cast(nifNode)->controller; + else + ctrl = static_cast(nifNode)->controller; + handleMorphController(ctrl, drawable, geom, parentNode, composite, boundTextures, animflags); + + if (!drawable.get()) + drawable = geom; + drawable->setName(nifNode->name); + parentNode->addChild(drawable); + } + + void handleMorphController(Nif::ControllerPtr ctrl, osg::Drawable *drawable, osg::ref_ptr geom, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + { + for (; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) continue; if(ctrl->recType == Nif::RC_NiGeomMorpherController) { - drawable = handleMorphGeometry(static_cast(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); + drawable = handleMorphGeometry(static_cast(ctrl.getPtr()), geom, parentNode, composite, boundTextures, animflags); osg::ref_ptr morphctrl = new GeomMorpherController( static_cast(ctrl.getPtr())->data.getPtr()); @@ -1089,25 +1139,11 @@ namespace NifOsg break; } } - - if (!drawable.get()) - { - osg::ref_ptr geom (new osg::Geometry); - drawable = geom; - triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags); - } - - drawable->setName(triShape->name); - - parentNode->addChild(drawable); } - osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) + osg::ref_ptr handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, osg::ref_ptr sourceGeometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { osg::ref_ptr morphGeom = new SceneUtil::MorphGeometry; - - osg::ref_ptr sourceGeometry (new osg::Geometry); - triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags); morphGeom->setSourceGeometry(sourceGeometry); const std::vector& morphs = morpher->data.getPtr()->mMorphs; @@ -1120,21 +1156,25 @@ namespace NifOsg return morphGeom; } - void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, + void handleSkinnedTriShape(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector& boundTextures, int animflags) { + assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); - + triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags); osg::ref_ptr rig(new SceneUtil::RigGeometry); rig->setSourceGeometry(geometry); - rig->setName(triShape->name); - - const Nif::NiSkinInstance *skin = triShape->skin.getPtr(); + rig->setName(nifNode->name); // Assign bone weights osg::ref_ptr map (new SceneUtil::RigGeometry::InfluenceMap); + Nif::NiSkinInstancePtr skinPtr; + if (nifNode->recType == Nif::RC_NiTriShape) + skinPtr = static_cast(nifNode)->skin; + else + skinPtr = static_cast(nifNode)->skin; + const Nif::NiSkinInstance *skin = skinPtr.getPtr(); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++)