Merge pull request #2481 from Capostrophic/nitristrips

Handle NiTriStrips (feature #5121)
pull/541/head
Andrei Kortunov 5 years ago committed by GitHub
commit 9355881abc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -161,6 +161,7 @@
Feature #5051: Provide a separate textures for scrollbars Feature #5051: Provide a separate textures for scrollbars
Feature #5094: Unix like console hotkeys Feature #5094: Unix like console hotkeys
Feature #5098: Allow user controller bindings Feature #5098: Allow user controller bindings
Feature #5121: Handle NiTriStrips and NiTriStripsData
Feature #5122: Use magic glow for enchanted arrows Feature #5122: Use magic glow for enchanted arrows
Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption Task #4695: Optimize Distant Terrain memory consumption

@ -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<unsigned short> lengths;
nif->getUShorts(lengths, numStrips);
for (int i = 0; i < numStrips; i++)
{
std::vector<unsigned short> strip;
nif->getUShorts(strip, lengths[i]);
strips.emplace_back(strip);
}
}
void NiAutoNormalParticlesData::read(NIFStream *nif) void NiAutoNormalParticlesData::read(NIFStream *nif)
{ {
ShapeData::read(nif); ShapeData::read(nif);

@ -53,6 +53,15 @@ public:
void read(NIFStream *nif); void read(NIFStream *nif);
}; };
class NiTriStripsData : public ShapeData
{
public:
// Triangle strips, series of vertex indices.
std::vector<std::vector<unsigned short>> strips;
void read(NIFStream *nif);
};
class NiAutoNormalParticlesData : public ShapeData class NiAutoNormalParticlesData : public ShapeData
{ {
public: public:

@ -54,6 +54,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode )); newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode ));
newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode )); newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode ));
newFactory.insert(makeEntry("NiTriShape", &construct <NiTriShape> , RC_NiTriShape )); newFactory.insert(makeEntry("NiTriShape", &construct <NiTriShape> , RC_NiTriShape ));
newFactory.insert(makeEntry("NiTriStrips", &construct <NiTriStrips> , RC_NiTriStrips ));
newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles )); newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles ));
newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles )); newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera )); newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera ));
@ -96,6 +97,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation )); newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
newFactory.insert(makeEntry("NiFloatData", &construct <NiFloatData> , RC_NiFloatData )); newFactory.insert(makeEntry("NiFloatData", &construct <NiFloatData> , RC_NiFloatData ));
newFactory.insert(makeEntry("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData )); newFactory.insert(makeEntry("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData ));
newFactory.insert(makeEntry("NiTriStripsData", &construct <NiTriStripsData> , RC_NiTriStripsData ));
newFactory.insert(makeEntry("NiVisData", &construct <NiVisData> , RC_NiVisData )); newFactory.insert(makeEntry("NiVisData", &construct <NiVisData> , RC_NiVisData ));
newFactory.insert(makeEntry("NiColorData", &construct <NiColorData> , RC_NiColorData )); newFactory.insert(makeEntry("NiColorData", &construct <NiColorData> , RC_NiColorData ));
newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData )); newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData ));

@ -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 NiCamera : Node
{ {
struct Camera struct Camera

@ -41,6 +41,7 @@ enum RecordType
RC_NiBillboardNode, RC_NiBillboardNode,
RC_AvoidNode, RC_AvoidNode,
RC_NiTriShape, RC_NiTriShape,
RC_NiTriStrips,
RC_NiRotatingParticles, RC_NiRotatingParticles,
RC_NiAutoNormalParticles, RC_NiAutoNormalParticles,
RC_NiBSParticleNode, RC_NiBSParticleNode,
@ -80,6 +81,7 @@ enum RecordType
RC_NiParticleRotation, RC_NiParticleRotation,
RC_NiFloatData, RC_NiFloatData,
RC_NiTriShapeData, RC_NiTriShapeData,
RC_NiTriStripsData,
RC_NiVisData, RC_NiVisData,
RC_NiColorData, RC_NiColorData,
RC_NiPixelData, RC_NiPixelData,

@ -135,6 +135,7 @@ class NiPixelData;
class NiColorData; class NiColorData;
struct NiKeyframeData; struct NiKeyframeData;
class NiTriShapeData; class NiTriShapeData;
class NiTriStripsData;
class NiSkinInstance; class NiSkinInstance;
class NiSourceTexture; class NiSourceTexture;
class NiRotatingParticlesData; class NiRotatingParticlesData;
@ -154,6 +155,7 @@ typedef RecordPtrT<NiFloatData> NiFloatDataPtr;
typedef RecordPtrT<NiColorData> NiColorDataPtr; typedef RecordPtrT<NiColorData> NiColorDataPtr;
typedef RecordPtrT<NiKeyframeData> NiKeyframeDataPtr; typedef RecordPtrT<NiKeyframeData> NiKeyframeDataPtr;
typedef RecordPtrT<NiTriShapeData> NiTriShapeDataPtr; typedef RecordPtrT<NiTriShapeData> NiTriShapeDataPtr;
typedef RecordPtrT<NiTriStripsData> NiTriStripsDataPtr;
typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr; typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr;
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr; typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr; typedef RecordPtrT<NiRotatingParticlesData> NiRotatingParticlesDataPtr;

@ -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<osg::Vec3f> &vertices = data.vertices;
const std::vector<std::vector<unsigned short>> &strips = data.strips;
if (vertices.empty() || strips.empty())
return;
mesh.preallocateVertices(static_cast<int>(data.vertices.size()));
int numTriangles = 0;
for (const std::vector<unsigned short>& strip : strips)
{
// Each strip with N points contains information about N-2 triangles.
if (strip.size() >= 3)
numTriangles += static_cast<int>(strip.size()-2);
}
mesh.preallocateIndices(static_cast<int>(numTriangles));
// It's triangulation time. Totally not a NifSkope spell ripoff.
for (const std::vector<unsigned short>& 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<int>(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<const Nif::NiTriShape*>(nifNode)->data.get(), transform);
else // if (nifNode->recType == Nif::RC_NiTriStrips)
fillTriangleMeshWithTransform(mesh, static_cast<const Nif::NiTriStrips*>(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! // NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
// It must be ignored completely. // It must be ignored completely.
// (occurs in tr_ex_imp_wall_arch_04.nif) // (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<const Nif::NiTriShape*>(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) bool isAnimated, bool avoid)
{ {
assert(shape != nullptr); assert(nifNode != nullptr);
// If the object was marked "NCO" earlier, it shouldn't collide with // If the object was marked "NCO" earlier, it shouldn't collide with
// anything. So don't do anything. // anything. So don't do anything.
if ((flags & 0x800)) if ((flags & 0x800))
{
return; return;
}
if (nifNode->recType == Nif::RC_NiTriShape)
{
const Nif::NiTriShape* shape = static_cast<const Nif::NiTriShape*>(nifNode);
if (!shape->skin.empty()) if (!shape->skin.empty())
isAnimated = false; isAnimated = false;
if (shape->data.empty() || shape->data->triangles.empty())
if (shape->data.empty())
return; return;
if (shape->data->triangles.empty()) }
else
{
const Nif::NiTriStrips* shape = static_cast<const Nif::NiTriStrips*>(nifNode);
if (!shape->skin.empty())
isAnimated = false;
if (shape->data.empty() || shape->data->strips.empty())
return; return;
}
if (isAnimated) if (isAnimated)
{ {
@ -290,13 +346,13 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh); std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh);
fillTriangleMesh(*childMesh, shape->data.get()); fillTriangleMesh(*childMesh, nifNode);
std::unique_ptr<Resource::TriangleMeshShape> childShape(new Resource::TriangleMeshShape(childMesh.get(), true)); std::unique_ptr<Resource::TriangleMeshShape> childShape(new Resource::TriangleMeshShape(childMesh.get(), true));
childMesh.release(); childMesh.release();
float scale = shape->trafo.scale; float scale = nifNode->trafo.scale;
const Nif::Node* parent = shape; const Nif::Node* parent = nifNode;
while (parent->parent) while (parent->parent)
{ {
parent = 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())); 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()); mCompoundShape->addChildShape(trans, childShape.get());
childShape.release(); childShape.release();
@ -318,7 +374,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
if (!mAvoidStaticMesh) if (!mAvoidStaticMesh)
mAvoidStaticMesh.reset(new btTriangleMesh(false)); mAvoidStaticMesh.reset(new btTriangleMesh(false));
fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform); fillTriangleMeshWithTransform(*mAvoidStaticMesh, nifNode, transform);
} }
else else
{ {
@ -326,7 +382,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
mStaticMesh.reset(new btTriangleMesh(false)); mStaticMesh.reset(new btTriangleMesh(false));
// Static shape, just transform all vertices into position // Static shape, just transform all vertices into position
fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform); fillTriangleMeshWithTransform(*mStaticMesh, nifNode, transform);
} }
} }

@ -26,6 +26,7 @@ namespace Nif
class Node; class Node;
struct Transformation; struct Transformation;
struct NiTriShape; struct NiTriShape;
struct NiTriStrips;
} }
namespace NifBullet namespace NifBullet
@ -58,7 +59,7 @@ private:
bool hasAutoGeneratedCollision(const Nif::Node *rootNode); 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<btCompoundShape> mCompoundShape; std::unique_ptr<btCompoundShape> mCompoundShape;

@ -452,6 +452,7 @@ namespace NifOsg
break; break;
} }
case Nif::RC_NiTriShape: case Nif::RC_NiTriShape:
case Nif::RC_NiTriStrips:
case Nif::RC_NiAutoNormalParticles: case Nif::RC_NiAutoNormalParticles:
case Nif::RC_NiRotatingParticles: case Nif::RC_NiRotatingParticles:
// Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. // 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); 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); node->setDataVariance(osg::Object::DYNAMIC);
} }
@ -584,20 +585,25 @@ namespace NifOsg
applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); 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<const Nif::NiTriShape*>(nifNode); const std::string nodeName = Misc::StringUtils::lowerCase(nifNode->name);
const std::string nodeName = Misc::StringUtils::lowerCase(triShape->name);
static const std::string markerName = "tri editormarker"; static const std::string markerName = "tri editormarker";
static const std::string shadowName = "shadow"; static const std::string shadowName = "shadow";
static const std::string shadowName2 = "tri shadow"; static const std::string shadowName2 = "tri shadow";
const bool isMarker = hasMarkers && !nodeName.compare(0, markerName.size(), markerName); 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 (!isMarker && nodeName.compare(0, shadowName.size(), shadowName) && nodeName.compare(0, shadowName2.size(), shadowName2))
{ {
if (triShape->skin.empty()) Nif::NiSkinInstancePtr skin;
handleTriShape(triShape, node, composite, boundTextures, animflags); if (nifNode->recType == Nif::RC_NiTriShape)
skin = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
else // if (nifNode->recType == Nif::RC_NiTriStrips)
skin = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
if (skin.empty())
handleTriShape(nifNode, node, composite, boundTextures, animflags);
else else
handleSkinnedTriShape(triShape, node, composite, boundTextures, animflags); handleSkinnedTriShape(nifNode, node, composite, boundTextures, animflags);
if (!nifNode->controller.empty()) if (!nifNode->controller.empty())
handleMeshControllers(nifNode, node, composite, boundTextures, animflags); 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). // 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. // 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<osg::MatrixTransform*>(node.get()), animflags); handleNodeControllers(nifNode, static_cast<osg::MatrixTransform*>(node.get()), animflags);
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode); const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
@ -673,7 +680,7 @@ namespace NifOsg
handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags); handleVisController(static_cast<const Nif::NiVisController*>(ctrl.getPtr()), node, animflags);
} }
else if(ctrl->recType == Nif::RC_NiGeomMorpherController) else if(ctrl->recType == Nif::RC_NiGeomMorpherController)
{} // handled in handleTriShape {} // handled in handleMorphController
else else
Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; 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<int>& boundTextures, int animflags) void triCommonToGeometry(osg::Geometry *geometry, const std::vector<osg::Vec3f>& vertices, const std::vector<osg::Vec3f>& normals, const std::vector<std::vector<osg::Vec2f>>& uvlist, const std::vector<osg::Vec4f>& colors, const std::vector<int>& boundTextures, const std::string& name)
{ {
const Nif::NiTriShapeData* data = triShape->data.getPtr(); if (!vertices.empty())
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
if (!data->vertices.empty()) if (!normals.empty())
geometry->setVertexArray(new osg::Vec3Array(data->vertices.size(), data->vertices.data())); geometry->setNormalArray(new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX);
if (!data->normals.empty()) if (!colors.empty())
geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), data->normals.data()), osg::Array::BIND_PER_VERTEX); geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
int textureStage = 0; int textureStage = 0;
for (std::vector<int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage) for (const int uvSet : boundTextures)
{ {
int uvSet = *it; if (uvSet >= (int)uvlist.size())
if (uvSet >= (int)data->uvlist.size())
{ {
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriShape \"" << triShape->name << "\" in " << mFilename; Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename;
if (!data->uvlist.empty()) if (!uvlist.empty())
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[0].size(), data->uvlist[0].data()), osg::Array::BIND_PER_VERTEX); geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[0].size(), uvlist[0].data()), osg::Array::BIND_PER_VERTEX);
continue; 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()) void triShapeToGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
geometry->setColorArray(new osg::Vec4Array(data->colors.size(), data->colors.data()), osg::Array::BIND_PER_VERTEX); {
bool vertexColorsPresent = false;
if (nifNode->recType == Nif::RC_NiTriShape)
{
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(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()) if (!data->triangles.empty())
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
data->triangles.size(),
(unsigned short*)data->triangles.data())); (unsigned short*)data->triangles.data()));
}
else
{
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(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<unsigned short>& 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: // osg::Material properties are handled here for two reasons:
// - if there are no vertex colors, we need to disable colorMode. // - 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 // - there are 3 "overlapping" nif properties that all affect the osg::Material, handling them
// above the actual renderable would be tedious. // above the actual renderable would be tedious.
std::vector<const Nif::Property*> drawableProps; std::vector<const Nif::Property*> drawableProps;
collectDrawableProperties(triShape, drawableProps); collectDrawableProperties(nifNode, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false); applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags, false);
} }
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags) void handleTriShape(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{ {
assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
osg::ref_ptr<osg::Drawable> drawable; osg::ref_ptr<osg::Drawable> drawable;
for (Nif::ControllerPtr ctrl = triShape->controller; !ctrl.empty(); ctrl = ctrl->next) osg::ref_ptr<osg::Geometry> geom (new osg::Geometry);
triShapeToGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags);
Nif::ControllerPtr ctrl;
if (nifNode->recType == Nif::RC_NiTriShape)
ctrl = static_cast<const Nif::NiTriShape*>(nifNode)->controller;
else
ctrl = static_cast<const Nif::NiTriStrips*>(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<osg::Geometry> geom, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{
for (; !ctrl.empty(); ctrl = ctrl->next)
{ {
if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
continue; continue;
if(ctrl->recType == Nif::RC_NiGeomMorpherController) if(ctrl->recType == Nif::RC_NiGeomMorpherController)
{ {
drawable = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), triShape, parentNode, composite, boundTextures, animflags); drawable = handleMorphGeometry(static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr()), geom, parentNode, composite, boundTextures, animflags);
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController( osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr()); static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr());
@ -1089,25 +1139,11 @@ namespace NifOsg
break; break;
} }
} }
if (!drawable.get())
{
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry);
drawable = geom;
triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags);
}
drawable->setName(triShape->name);
parentNode->addChild(drawable);
} }
osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, const Nif::NiTriShape *triShape, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags) osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher, osg::ref_ptr<osg::Geometry> sourceGeometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{ {
osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry; osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry;
osg::ref_ptr<osg::Geometry> sourceGeometry (new osg::Geometry);
triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags);
morphGeom->setSourceGeometry(sourceGeometry); morphGeom->setSourceGeometry(sourceGeometry);
const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->data.getPtr()->mMorphs; const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->data.getPtr()->mMorphs;
@ -1120,21 +1156,25 @@ namespace NifOsg
return morphGeom; 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<int>& boundTextures, int animflags) const std::vector<int>& boundTextures, int animflags)
{ {
assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry); osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags); triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags);
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry); osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
rig->setSourceGeometry(geometry); rig->setSourceGeometry(geometry);
rig->setName(triShape->name); rig->setName(nifNode->name);
const Nif::NiSkinInstance *skin = triShape->skin.getPtr();
// Assign bone weights // Assign bone weights
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map (new SceneUtil::RigGeometry::InfluenceMap); osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map (new SceneUtil::RigGeometry::InfluenceMap);
Nif::NiSkinInstancePtr skinPtr;
if (nifNode->recType == Nif::RC_NiTriShape)
skinPtr = static_cast<const Nif::NiTriShape*>(nifNode)->skin;
else
skinPtr = static_cast<const Nif::NiTriStrips*>(nifNode)->skin;
const Nif::NiSkinInstance *skin = skinPtr.getPtr();
const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NiSkinData *data = skin->data.getPtr();
const Nif::NodeList &bones = skin->bones; const Nif::NodeList &bones = skin->bones;
for(size_t i = 0;i < bones.length();i++) for(size_t i = 0;i < bones.length();i++)

Loading…
Cancel
Save