mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-04 00:26:45 +00:00 
			
		
		
		
	Handle NiLines (feature #5445)
This commit is contained in:
		
							parent
							
								
									505a5e9ca6
								
							
						
					
					
						commit
						7aca18f92b
					
				
					 8 changed files with 101 additions and 24 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
		Reference in a new issue