mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-10 15:45:37 +00:00
Merge pull request #2481 from Capostrophic/nitristrips
Handle NiTriStrips (feature #5121)
This commit is contained in:
commit
9355881abc
@ -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())
|
||||||
|
isAnimated = false;
|
||||||
|
if (shape->data.empty() || shape->data->triangles.empty())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!shape->skin.empty())
|
|
||||||
isAnimated = false;
|
|
||||||
|
|
||||||
if (shape->data.empty())
|
|
||||||
return;
|
|
||||||
if (shape->data->triangles.empty())
|
|
||||||
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 (!data->triangles.empty())
|
if (nifNode->recType == Nif::RC_NiTriShape)
|
||||||
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
{
|
||||||
data->triangles.size(),
|
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
|
||||||
(unsigned short*)data->triangles.data()));
|
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<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…
x
Reference in New Issue
Block a user