Handle NiLines (feature #5445)

pull/2883/head
Capostrophic 4 years ago
parent 505a5e9ca6
commit 7aca18f92b

@ -21,6 +21,7 @@
Bug #5427: GetDistance unknown ID error is misleading
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 #5445: Handle NiLines
0.46.0
------

@ -110,6 +110,32 @@ void NiTriStripsData::read(NIFStream *nif)
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)
{
NiGeometryData::read(nif);

@ -62,6 +62,14 @@ public:
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
{
public:

@ -54,6 +54,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
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("NiLines", &construct <NiLines> , RC_NiLines ));
newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles ));
newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
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("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData ));
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("NiColorData", &construct <NiColorData> , RC_NiColorData ));
newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData ));

@ -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
{

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

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

@ -612,7 +612,9 @@ namespace NifOsg
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);
static const std::string markerName = "tri editormarker";
@ -624,9 +626,9 @@ namespace NifOsg
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->skin;
if (skin.empty())
handleTriShape(nifNode, node, composite, boundTextures, animflags);
handleGeometry(nifNode, node, composite, boundTextures, animflags);
else
handleSkinnedTriShape(nifNode, node, composite, boundTextures, animflags);
handleSkinnedGeometry(nifNode, node, composite, boundTextures, animflags);
if (!nifNode->controller.empty())
handleMeshControllers(nifNode, node, composite, boundTextures, animflags);
@ -1099,8 +1101,11 @@ namespace NifOsg
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())
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
if (!normals.empty())
@ -1108,6 +1113,7 @@ namespace NifOsg
if (!colors.empty())
geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
const auto& uvlist = data->uvlist;
int textureStage = 0;
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)
{
const Nif::NiTriShape* triShape = static_cast<const Nif::NiTriShape*>(nifNode);
if (!triShape->data.empty())
{
const Nif::NiTriShapeData* data = triShape->data.getPtr();
vertexColorsPresent = !data->colors.empty();
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name);
niGeometryData = static_cast<const Nif::NiGeometryData*>(data);
if (!data->triangles.empty())
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(),
(unsigned short*)data->triangles.data()));
}
}
else
else if (nifNode->recType == Nif::RC_NiTriStrips)
{
const Nif::NiTriStrips* triStrips = static_cast<const Nif::NiTriStrips*>(nifNode);
if (!triStrips->data.empty())
{
const Nif::NiTriStripsData* data = triStrips->data.getPtr();
vertexColorsPresent = !data->colors.empty();
triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name);
niGeometryData = static_cast<const Nif::NiGeometryData*>(data);
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)
continue;
geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(),
(unsigned short*)strip.data()));
if (strip.size() >= 3)
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:
// - if there are no vertex colors, we need to disable colorMode.
@ -1168,15 +1184,15 @@ namespace NifOsg
// above the actual renderable would be tedious.
std::vector<const Nif::Property*> 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::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)
{
if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active))
@ -1215,12 +1231,12 @@ namespace NifOsg
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)
{
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);
triShapeToGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags);
handleNiGeometry(nifNode, geometry, parentNode, composite, boundTextures, animflags);
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
rig->setSourceGeometry(geometry);
rig->setName(nifNode->name);

Loading…
Cancel
Save