mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-28 06:09:40 +00:00
Merge pull request #2481 from Capostrophic/nitristrips
Handle NiTriStrips (feature #5121)
This commit is contained in:
commit
9355881abc
10 changed files with 233 additions and 77 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
ShapeData::read(nif);
|
||||
|
|
|
@ -53,6 +53,15 @@ public:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -54,6 +54,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
|
|||
newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode ));
|
||||
newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode ));
|
||||
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("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
|
||||
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("NiFloatData", &construct <NiFloatData> , RC_NiFloatData ));
|
||||
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("NiColorData", &construct <NiColorData> , RC_NiColorData ));
|
||||
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 Camera
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<NiFloatData> NiFloatDataPtr;
|
|||
typedef RecordPtrT<NiColorData> NiColorDataPtr;
|
||||
typedef RecordPtrT<NiKeyframeData> NiKeyframeDataPtr;
|
||||
typedef RecordPtrT<NiTriShapeData> NiTriShapeDataPtr;
|
||||
typedef RecordPtrT<NiTriStripsData> NiTriStripsDataPtr;
|
||||
typedef RecordPtrT<NiSkinInstance> NiSkinInstancePtr;
|
||||
typedef RecordPtrT<NiSourceTexture> NiSourceTexturePtr;
|
||||
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!
|
||||
// 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<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)
|
||||
{
|
||||
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<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)
|
||||
{
|
||||
|
@ -290,13 +346,13 @@ void BulletNifLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags,
|
|||
|
||||
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));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<btCompoundShape> mCompoundShape;
|
||||
|
||||
|
|
|
@ -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<const Nif::NiTriShape*>(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<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
|
||||
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<osg::MatrixTransform*>(node.get()), animflags);
|
||||
|
||||
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);
|
||||
}
|
||||
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<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 (!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<int>::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<int>& boundTextures, int animflags)
|
||||
{
|
||||
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())
|
||||
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:
|
||||
// - 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<const Nif::Property*> 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<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;
|
||||
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))
|
||||
continue;
|
||||
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(
|
||||
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr())->data.getPtr());
|
||||
|
@ -1089,25 +1139,11 @@ namespace NifOsg
|
|||
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<osg::Geometry> sourceGeometry (new osg::Geometry);
|
||||
triShapeToGeometry(triShape, sourceGeometry, parentNode, composite, boundTextures, animflags);
|
||||
morphGeom->setSourceGeometry(sourceGeometry);
|
||||
|
||||
const std::vector<Nif::NiMorphData::MorphData>& 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<int>& boundTextures, int animflags)
|
||||
{
|
||||
assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
|
||||
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);
|
||||
rig->setSourceGeometry(geometry);
|
||||
rig->setName(triShape->name);
|
||||
|
||||
const Nif::NiSkinInstance *skin = triShape->skin.getPtr();
|
||||
rig->setName(nifNode->name);
|
||||
|
||||
// Assign bone weights
|
||||
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::NodeList &bones = skin->bones;
|
||||
for(size_t i = 0;i < bones.length();i++)
|
||||
|
|
Loading…
Reference in a new issue