1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 23:23:52 +00:00

Merge pull request #2883 from Capostrophic/nilines

Handle NiLines (feature #5445)
This commit is contained in:
Bret Curtis 2020-06-01 01:23:10 +02:00 committed by GitHub
commit f5e2e53bcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 101 additions and 24 deletions

View file

@ -23,6 +23,7 @@
Bug #5435: Enemies can't hurt the player when collision is off Bug #5435: Enemies can't hurt the player when collision is off
Bug #5441: Enemies can't push a player character when in critical strike stance Bug #5441: Enemies can't push a player character when in critical strike stance
Feature #5362: Show the soul gems' trapped soul in count dialog Feature #5362: Show the soul gems' trapped soul in count dialog
Feature #5445: Handle NiLines
0.46.0 0.46.0
------ ------

View file

@ -110,6 +110,32 @@ void NiTriStripsData::read(NIFStream *nif)
nif->getUShorts(strips[i], lengths[i]); nif->getUShorts(strips[i], lengths[i]);
} }
void NiLinesData::read(NIFStream *nif)
{
NiGeometryData::read(nif);
size_t num = vertices.size();
std::vector<char> flags;
nif->getChars(flags, num);
// Can't construct a line from a single vertex.
if (num < 2)
return;
// Convert connectivity flags into usable geometry. The last element needs special handling.
for (size_t i = 0; i < num-1; ++i)
{
if (flags[i] & 1)
{
lines.emplace_back(i);
lines.emplace_back(i+1);
}
}
// If there are just two vertices, they can be connected twice. Probably isn't critical.
if (flags[num-1] & 1)
{
lines.emplace_back(num-1);
lines.emplace_back(0);
}
}
void NiAutoNormalParticlesData::read(NIFStream *nif) void NiAutoNormalParticlesData::read(NIFStream *nif)
{ {
NiGeometryData::read(nif); NiGeometryData::read(nif);

View file

@ -62,6 +62,14 @@ public:
void read(NIFStream *nif); void read(NIFStream *nif);
}; };
struct NiLinesData : public NiGeometryData
{
// Lines, series of indices that correspond to connected vertices.
std::vector<unsigned short> lines;
void read(NIFStream *nif);
};
class NiAutoNormalParticlesData : public NiGeometryData class NiAutoNormalParticlesData : public NiGeometryData
{ {
public: public:

View file

@ -54,6 +54,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
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("NiTriStrips", &construct <NiTriStrips> , RC_NiTriStrips ));
newFactory.insert(makeEntry("NiLines", &construct <NiLines> , RC_NiLines ));
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 ));
@ -97,6 +98,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
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("NiTriStripsData", &construct <NiTriStripsData> , RC_NiTriStripsData ));
newFactory.insert(makeEntry("NiLinesData", &construct <NiLinesData> , RC_NiLinesData ));
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 ));

View file

@ -182,6 +182,26 @@ struct NiTriStrips : NiGeometry
} }
}; };
struct NiLines : NiGeometry
{
NiLinesDataPtr data;
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
{ {

View file

@ -43,6 +43,7 @@ enum RecordType
RC_NiCollisionSwitch, RC_NiCollisionSwitch,
RC_NiTriShape, RC_NiTriShape,
RC_NiTriStrips, RC_NiTriStrips,
RC_NiLines,
RC_NiRotatingParticles, RC_NiRotatingParticles,
RC_NiAutoNormalParticles, RC_NiAutoNormalParticles,
RC_NiBSParticleNode, RC_NiBSParticleNode,
@ -83,6 +84,7 @@ enum RecordType
RC_NiFloatData, RC_NiFloatData,
RC_NiTriShapeData, RC_NiTriShapeData,
RC_NiTriStripsData, RC_NiTriStripsData,
RC_NiLinesData,
RC_NiVisData, RC_NiVisData,
RC_NiColorData, RC_NiColorData,
RC_NiPixelData, RC_NiPixelData,

View file

@ -142,6 +142,7 @@ class NiRotatingParticlesData;
class NiAutoNormalParticlesData; class NiAutoNormalParticlesData;
class NiPalette; class NiPalette;
struct NiParticleModifier; struct NiParticleModifier;
struct NiLinesData;
using NodePtr = RecordPtrT<Node>; using NodePtr = RecordPtrT<Node>;
using ExtraPtr = RecordPtrT<Extra>; using ExtraPtr = RecordPtrT<Extra>;
@ -158,6 +159,7 @@ using NiColorDataPtr = RecordPtrT<NiColorData>;
using NiKeyframeDataPtr = RecordPtrT<NiKeyframeData>; using NiKeyframeDataPtr = RecordPtrT<NiKeyframeData>;
using NiTriShapeDataPtr = RecordPtrT<NiTriShapeData>; using NiTriShapeDataPtr = RecordPtrT<NiTriShapeData>;
using NiTriStripsDataPtr = RecordPtrT<NiTriStripsData>; using NiTriStripsDataPtr = RecordPtrT<NiTriStripsData>;
using NiLinesDataPtr = RecordPtrT<NiLinesData>;
using NiSkinInstancePtr = RecordPtrT<NiSkinInstance>; using NiSkinInstancePtr = RecordPtrT<NiSkinInstance>;
using NiSourceTexturePtr = RecordPtrT<NiSourceTexture>; using NiSourceTexturePtr = RecordPtrT<NiSourceTexture>;
using NiRotatingParticlesDataPtr = RecordPtrT<NiRotatingParticlesData>; using NiRotatingParticlesDataPtr = RecordPtrT<NiRotatingParticlesData>;

View file

@ -612,7 +612,9 @@ namespace NifOsg
applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags);
if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && !skipMeshes) const bool isGeometry = nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips || nifNode->recType == Nif::RC_NiLines;
if (isGeometry && !skipMeshes)
{ {
const std::string nodeName = Misc::StringUtils::lowerCase(nifNode->name); const std::string nodeName = Misc::StringUtils::lowerCase(nifNode->name);
static const std::string markerName = "tri editormarker"; static const std::string markerName = "tri editormarker";
@ -624,9 +626,9 @@ namespace NifOsg
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin; Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
if (skin.empty()) if (skin.empty())
handleTriShape(nifNode, node, composite, boundTextures, animflags); handleGeometry(nifNode, node, composite, boundTextures, animflags);
else else
handleSkinnedTriShape(nifNode, node, composite, boundTextures, animflags); handleSkinnedGeometry(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);
@ -1099,8 +1101,11 @@ namespace NifOsg
partsys->getOrCreateStateSet(); partsys->getOrCreateStateSet();
} }
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<unsigned int>& boundTextures, const std::string& name) void handleNiGeometryData(osg::Geometry *geometry, const Nif::NiGeometryData* data, const std::vector<unsigned int>& boundTextures, const std::string& name)
{ {
const auto& vertices = data->vertices;
const auto& normals = data->normals;
const auto& colors = data->colors;
if (!vertices.empty()) if (!vertices.empty())
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data())); geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
if (!normals.empty()) if (!normals.empty())
@ -1108,6 +1113,7 @@ namespace NifOsg
if (!colors.empty()) if (!colors.empty())
geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX); geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
const auto& uvlist = data->uvlist;
int textureStage = 0; int textureStage = 0;
for (const unsigned int uvSet : boundTextures) for (const unsigned int uvSet : boundTextures)
{ {
@ -1124,43 +1130,53 @@ namespace NifOsg
} }
} }
void triShapeToGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures, int animflags) void handleNiGeometry(const Nif::Node *nifNode, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures, int animflags)
{ {
bool vertexColorsPresent = false; const Nif::NiGeometryData* niGeometryData = nullptr;
if (nifNode->recType == Nif::RC_NiTriShape) if (nifNode->recType == Nif::RC_NiTriShape)
{ {
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode); const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
if (!triShape->data.empty()) if (!triShape->data.empty())
{ {
const Nif::NiTriShapeData* data = triShape->data.getPtr(); const Nif::NiTriShapeData* data = triShape->data.getPtr();
vertexColorsPresent = !data->colors.empty(); niGeometryData = static_cast<const Nif::NiGeometryData*>(data);
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, data->triangles.size(), geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
(unsigned short*)data->triangles.data())); (unsigned short*)data->triangles.data()));
} }
} }
else else if (nifNode->recType == Nif::RC_NiTriStrips)
{ {
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode); const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
if (!triStrips->data.empty()) if (!triStrips->data.empty())
{ {
const Nif::NiTriStripsData* data = triStrips->data.getPtr(); const Nif::NiTriStripsData* data = triStrips->data.getPtr();
vertexColorsPresent = !data->colors.empty(); niGeometryData = static_cast<const Nif::NiGeometryData*>(data);
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
if (!data->strips.empty()) if (!data->strips.empty())
{ {
for (const std::vector<unsigned short>& strip : data->strips) for (const auto& strip : data->strips)
{ {
// Can't make a triangle from less than three vertices. if (strip.size() >= 3)
if (strip.size() < 3) geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
continue; (unsigned short*)strip.data()));
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
(unsigned short*)strip.data()));
} }
} }
} }
} }
else if (nifNode->recType == Nif::RC_NiLines)
{
const Nif::NiLines* lines = static_cast<const Nif::NiLines*>(nifNode);
if (!lines->data.empty())
{
const Nif::NiLinesData* data = lines->data.getPtr();
niGeometryData = static_cast<const Nif::NiGeometryData*>(data);
const auto& line = data->lines;
if (!line.empty())
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), (unsigned short*)line.data()));
}
}
if (niGeometryData)
handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->name);
// 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.
@ -1168,15 +1184,15 @@ namespace NifOsg
// 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(nifNode, drawableProps); collectDrawableProperties(nifNode, drawableProps);
applyDrawableProperties(parentNode, drawableProps, composite, vertexColorsPresent, animflags); applyDrawableProperties(parentNode, drawableProps, composite, niGeometryData && !niGeometryData->colors.empty(), animflags);
} }
void handleTriShape(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures, int animflags) void handleGeometry(const Nif::Node* nifNode, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned 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 || nifNode->recType == Nif::RC_NiLines);
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); handleNiGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags);
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
@ -1215,12 +1231,12 @@ namespace NifOsg
return morphGeom; return morphGeom;
} }
void handleSkinnedTriShape(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, void handleSkinnedGeometry(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
const std::vector<unsigned int>& boundTextures, int animflags) const std::vector<unsigned 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 || nifNode->recType == Nif::RC_NiLines);
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry); osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry);
triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags); handleNiGeometry(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(nifNode->name); rig->setName(nifNode->name);