1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-03 17:19:39 +00:00

Reduce code duplication further

This commit is contained in:
capostrophic 2019-08-08 19:26:50 +03:00
parent 91efdf18a9
commit 7fc3153f62
3 changed files with 68 additions and 151 deletions

View file

@ -96,7 +96,6 @@ void NiTriStripsData::read(NIFStream *nif)
// Every strip with n points defines n-2 triangles, so this should be unnecessary. // Every strip with n points defines n-2 triangles, so this should be unnecessary.
/*int tris =*/ nif->getUShort(); /*int tris =*/ nif->getUShort();
// Number of triangle strips // Number of triangle strips
int numStrips = nif->getUShort(); int numStrips = nif->getUShort();
// Number of points in each strip // Number of points in each strip

View file

@ -58,28 +58,17 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD
{ {
const std::vector<osg::Vec3f> &vertices = data.vertices; const std::vector<osg::Vec3f> &vertices = data.vertices;
const std::vector<std::vector<unsigned short>> &strips = data.strips; const std::vector<std::vector<unsigned short>> &strips = data.strips;
if (vertices.empty() || strips.empty()) // Can't make a triangle from less than three vertices. All strips have the same size.
if (vertices.empty() || strips.empty() || strips[0].size() < 3)
return; return;
// Assume every strip has the same size
const int singleStripSize = static_cast<int>(strips[0].size());
// Can't make a triangle from less than three vertices.
if (singleStripSize < 3)
return;
mesh.preallocateVertices(static_cast<int>(data.vertices.size())); mesh.preallocateVertices(static_cast<int>(data.vertices.size()));
// There are N+2*M vertex indices in sum in all strips // There are N+2*M vertex indices overall, so we must substract 2*M (N triangles, M strips)
// where N is the number of triangles and M is the number of strips mesh.preallocateIndices(static_cast<int>((strips.size()-2) * strips[0].size()));
mesh.preallocateIndices(static_cast<int>((strips.size()-2) * singleStripSize));
// It's triangulation time. Totally not a NifSkope spell ripoff. // It's triangulation time. Totally not a NifSkope spell ripoff.
for (const std::vector<unsigned short>& strip : strips) for (const std::vector<unsigned short>& strip : strips)
{ {
unsigned short a = strip[0]; unsigned short a = strip[0], b = strip[0], c = strip[1];
unsigned short b = strip[0];
unsigned short c = strip[1];
bool flip = false;
for (int i = 2; i < static_cast<int>(strip.size()); i++) for (int i = 2; i < static_cast<int>(strip.size()); i++)
{ {
a = b; a = b;
@ -87,24 +76,26 @@ void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::NiTriStripsD
c = strip[i]; c = strip[i];
if (a != b && b != c && a != c) if (a != b && b != c && a != c)
{ {
if (!flip) if (i%2==0)
mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[b]), getbtVector(vertices[c])); mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[b]), getbtVector(vertices[c]));
else else
mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[c]), getbtVector(vertices[b])); mesh.addTriangle(getbtVector(vertices[a]), getbtVector(vertices[c]), getbtVector(vertices[b]));
} }
flip = !flip;
} }
} }
} }
void fillTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriShapeData& data) void fillTriangleMeshWithTransform(btTriangleMesh& mesh, const Nif::Node* nifNode, const osg::Matrixf &transform)
{ {
fillTriangleMeshWithTransform(mesh, data, osg::Matrixf()); 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::NiTriStripsData& data) void fillTriangleMesh(btTriangleMesh& mesh, const Nif::Node* node)
{ {
fillTriangleMeshWithTransform(mesh, data, osg::Matrixf()); fillTriangleMeshWithTransform(mesh, node, osg::Matrixf());
} }
} }
@ -326,9 +317,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons
const Nif::NiTriShape* shape = static_cast<const Nif::NiTriShape*>(nifNode); 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()) if (shape->data.empty() || shape->data->triangles.empty())
return;
if (shape->data->triangles.empty())
return; return;
} }
else else
@ -336,9 +325,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons
const Nif::NiTriStrips* shape = static_cast<const Nif::NiTriStrips*>(nifNode); const Nif::NiTriStrips* shape = static_cast<const Nif::NiTriStrips*>(nifNode);
if (!shape->skin.empty()) if (!shape->skin.empty())
isAnimated = false; isAnimated = false;
if (shape->data.empty()) if (shape->data.empty() || shape->data->strips.empty())
return;
if (shape->data->strips.empty())
return; return;
} }
@ -350,10 +337,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons
std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh); std::unique_ptr<btTriangleMesh> childMesh(new btTriangleMesh);
if (nifNode->recType == Nif::RC_NiTriShape) fillTriangleMesh(*childMesh, nifNode);
fillTriangleMesh(*childMesh, static_cast<const Nif::NiTriShape*>(nifNode)->data.get());
else
fillTriangleMesh(*childMesh, static_cast<const Nif::NiTriStrips*>(nifNode)->data.get());
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();
@ -381,16 +365,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons
if (!mAvoidStaticMesh) if (!mAvoidStaticMesh)
mAvoidStaticMesh.reset(new btTriangleMesh(false)); mAvoidStaticMesh.reset(new btTriangleMesh(false));
if (nifNode->recType == Nif::RC_NiTriShape) fillTriangleMeshWithTransform(*mAvoidStaticMesh, nifNode, transform);
{
const Nif::NiTriShape* shape = static_cast<const Nif::NiTriShape*>(nifNode);
fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform);
}
else
{
const Nif::NiTriStrips* shape = static_cast<const Nif::NiTriStrips*>(nifNode);
fillTriangleMeshWithTransform(*mAvoidStaticMesh, shape->data.get(), transform);
}
} }
else else
{ {
@ -398,17 +373,7 @@ void BulletNifLoader::handleNiTriShape(const Nif::Node *nifNode, int flags, cons
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, nifNode, transform);
if (nifNode->recType == Nif::RC_NiTriShape)
{
const Nif::NiTriShape* shape = static_cast<const Nif::NiTriShape*>(nifNode);
fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform);
}
else
{
const Nif::NiTriStrips* shape = static_cast<const Nif::NiTriStrips*>(nifNode);
fillTriangleMeshWithTransform(*mStaticMesh, shape->data.get(), transform);
}
} }
} }

View file

@ -576,8 +576,7 @@ namespace NifOsg
node->setDataVariance(osg::Object::DYNAMIC); node->setDataVariance(osg::Object::DYNAMIC);
} }
// Same thing for animated shapes if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) // Same thing for animated shapes
if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated)
{ {
node->setDataVariance(osg::Object::DYNAMIC); node->setDataVariance(osg::Object::DYNAMIC);
} }
@ -1038,85 +1037,55 @@ 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;
for (std::vector<int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage)
{
int uvSet = *it;
if (uvSet >= (int)data->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);
continue;
}
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(data->uvlist[uvSet].size(), data->uvlist[uvSet].data()), osg::Array::BIND_PER_VERTEX);
}
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()));
// 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);
}
void triStripsToGeometry(const Nif::NiTriStrips *triStrips, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{
const Nif::NiTriStripsData* data = triStrips->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);
int textureStage = 0; int textureStage = 0;
for (const int uvSet : boundTextures) for (const int uvSet : boundTextures)
{ {
if (uvSet >= (int)data->uvlist.size()) if (uvSet >= (int)uvlist.size())
{ {
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on TriStrips \"" << triStrips->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++; 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->strips.empty()) if (nifNode->recType == Nif::RC_NiTriShape)
{ {
for (const std::vector<unsigned short>& strip : data->strips) const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
{ const Nif::NiTriShapeData* data = triShape->data.getPtr();
// Can't make a triangle from less than three vertices. vertexColorsPresent = !data->colors.empty();
// All strips have the same size. triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
if (strip.size() < 3) if (!data->triangles.empty())
break; geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, (unsigned short*)data->triangles.data()));
strip.size(), (unsigned short*)strip.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);
// Can't make a triangle from less than three vertices. All strips have the same size.
if (!data->strips.empty() && data->strips[0].size() < 3)
for (const std::vector<unsigned short>& strip : data->strips)
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:
@ -1124,34 +1093,26 @@ namespace NifOsg
// - 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(triStrips, drawableProps); collectDrawableProperties(nifNode, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, !data->colors.empty(), animflags, false); applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags, false);
} }
void handleTriShape(const Nif::Node* nifNode, 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); assert(nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips);
osg::ref_ptr<osg::Drawable> drawable; osg::ref_ptr<osg::Drawable> drawable;
osg::ref_ptr<osg::Geometry> geom (new osg::Geometry); 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) if (nifNode->recType == Nif::RC_NiTriShape)
{ ctrl = static_cast<const Nif::NiTriShape*>(nifNode)->controller;
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
triShapeToGeometry(triShape, geom, parentNode, composite, boundTextures, animflags);
handleMorphController(triShape->controller, drawable, geom, parentNode, composite, boundTextures, animflags);
}
else else
{ ctrl = static_cast<const Nif::NiTriStrips*>(nifNode)->controller;
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode); handleMorphController(ctrl, drawable, geom, parentNode, composite, boundTextures, animflags);
triStripsToGeometry(triStrips, geom, parentNode, composite, boundTextures, animflags);
handleMorphController(triStrips->controller, drawable, geom, parentNode, composite, boundTextures, animflags);
}
if (!drawable.get()) if (!drawable.get())
drawable = geom; drawable = geom;
drawable->setName(nifNode->name); drawable->setName(nifNode->name);
parentNode->addChild(drawable); parentNode->addChild(drawable);
} }
@ -1193,21 +1154,8 @@ namespace NifOsg
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); 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);
Nif::NiSkinInstancePtr skinPtr; triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags);
if (nifNode->recType == Nif::RC_NiTriShape)
{
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
triShapeToGeometry(triShape, geometry, parentNode, composite, boundTextures, animflags);
skinPtr = triShape->skin;
}
else
{
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
triStripsToGeometry(triStrips, geometry, parentNode, composite, boundTextures, animflags);
skinPtr = triStrips->skin;
}
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(nifNode->name); rig->setName(nifNode->name);
@ -1215,6 +1163,11 @@ namespace NifOsg
// 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::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;