1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-29 08:15:35 +00:00
openmw/components/nif/node.hpp

497 lines
13 KiB
C++
Raw Normal View History

#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP
#define OPENMW_COMPONENTS_NIF_NODE_HPP
2010-01-06 11:28:37 +00:00
2022-06-17 11:35:33 +00:00
#include <osg/Plane>
#include "controlled.hpp"
#include "extra.hpp"
#include "data.hpp"
#include "property.hpp"
#include "niftypes.hpp"
#include "controller.hpp"
#include "base.hpp"
#include "physics.hpp"
2010-01-06 11:28:37 +00:00
#include <components/misc/stringops.hpp>
2010-01-06 11:28:37 +00:00
namespace Nif
{
struct NiNode;
2012-07-03 05:49:44 +00:00
struct NiBoundingVolume
{
enum Type
{
2022-06-17 11:35:33 +00:00
BASE_BV = 0xFFFFFFFF,
SPHERE_BV = 0,
BOX_BV = 1,
CAPSULE_BV = 2,
LOZENGE_BV = 3,
UNION_BV = 4,
HALFSPACE_BV = 5
};
struct NiSphereBV
{
osg::Vec3f center;
float radius{0.f};
};
struct NiBoxBV
{
osg::Vec3f center;
2022-06-17 11:35:33 +00:00
Matrix3 axes;
osg::Vec3f extents;
};
struct NiCapsuleBV
{
osg::Vec3f center, axis;
float extent{0.f}, radius{0.f};
};
struct NiLozengeBV
{
float radius{0.f}, extent0{0.f}, extent1{0.f};
osg::Vec3f center, axis0, axis1;
};
struct NiHalfSpaceBV
{
2022-06-17 11:35:33 +00:00
osg::Plane plane;
osg::Vec3f origin;
};
unsigned int type;
NiSphereBV sphere;
NiBoxBV box;
NiCapsuleBV capsule;
NiLozengeBV lozenge;
std::vector<NiBoundingVolume> children;
2022-06-17 11:35:33 +00:00
NiHalfSpaceBV halfSpace;
void read(NIFStream* nif)
{
type = nif->getUInt();
switch (type)
{
2022-06-17 11:35:33 +00:00
case BASE_BV:
break;
case SPHERE_BV:
{
sphere.center = nif->getVector3();
sphere.radius = nif->getFloat();
break;
}
case BOX_BV:
{
box.center = nif->getVector3();
2022-06-17 11:35:33 +00:00
box.axes = nif->getMatrix3();
box.extents = nif->getVector3();
break;
}
case CAPSULE_BV:
{
capsule.center = nif->getVector3();
capsule.axis = nif->getVector3();
capsule.extent = nif->getFloat();
capsule.radius = nif->getFloat();
break;
}
case LOZENGE_BV:
{
lozenge.radius = nif->getFloat();
2022-06-17 11:35:33 +00:00
if (nif->getVersion() >= NIFStream::generateVersion(4,2,1,0))
{
lozenge.extent0 = nif->getFloat();
lozenge.extent1 = nif->getFloat();
}
lozenge.center = nif->getVector3();
lozenge.axis0 = nif->getVector3();
lozenge.axis1 = nif->getVector3();
break;
}
case UNION_BV:
{
unsigned int numChildren = nif->getUInt();
if (numChildren == 0)
break;
children.resize(numChildren);
for (NiBoundingVolume& child : children)
child.read(nif);
break;
}
case HALFSPACE_BV:
{
2022-06-17 11:35:33 +00:00
halfSpace.plane = osg::Plane(nif->getVector4());
if (nif->getVersion() >= NIFStream::generateVersion(4,2,1,0))
halfSpace.origin = nif->getVector3();
break;
}
default:
{
nif->file->fail("Unhandled NiBoundingVolume type: " + std::to_string(type));
}
}
}
};
2010-01-06 11:28:37 +00:00
/** A Node is an object that's part of the main NIF tree. It has
parent node (unless it's the root), and transformation (location
and rotation) relative to it's parent.
*/
2020-12-15 22:06:05 +00:00
struct Node : public Named
2010-01-06 11:28:37 +00:00
{
2022-06-21 21:43:16 +00:00
enum Flags {
Flag_Hidden = 0x0001,
Flag_MeshCollision = 0x0002,
Flag_BBoxCollision = 0x0004,
Flag_ActiveCollision = 0x0020
};
// Node flags. Interpretation depends somewhat on the type of node.
unsigned int flags;
2022-06-21 21:43:16 +00:00
2012-07-10 04:35:36 +00:00
Transformation trafo;
2015-02-17 16:08:55 +00:00
osg::Vec3f velocity; // Unused? Might be a run-time game state
PropertyList props;
// Bounding box info
bool hasBounds{false};
NiBoundingVolume bounds;
// Collision object info
NiCollisionObjectPtr collision;
void read(NIFStream *nif) override
{
Named::read(nif);
flags = nif->getBethVersion() <= 26 ? nif->getUShort() : nif->getUInt();
trafo = nif->getTrafo();
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
velocity = nif->getVector3();
if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3)
props.read(nif);
if (nif->getVersion() <= NIFStream::generateVersion(4,2,2,0))
hasBounds = nif->getBoolean();
if (hasBounds)
bounds.read(nif);
// Reference to the collision object in Gamebryo files.
if (nif->getVersion() >= NIFStream::generateVersion(10,0,1,0))
collision.read(nif);
parents.clear();
2012-07-03 05:49:44 +00:00
isBone = false;
}
void post(NIFFile *nif) override
{
Named::post(nif);
props.post(nif);
collision.post(nif);
}
2018-10-09 06:21:12 +00:00
// Parent node, or nullptr for the root node. As far as I'm aware, only
2012-07-03 05:49:44 +00:00
// NiNodes (or types derived from NiNodes) can be parents.
std::vector<NiNode*> parents;
2012-07-03 05:49:44 +00:00
2021-01-09 10:21:57 +00:00
bool isBone{false};
void setBone()
{
isBone = true;
}
2022-06-21 21:43:16 +00:00
bool isHidden() const { return flags & Flag_Hidden; }
bool hasMeshCollision() const { return flags & Flag_MeshCollision; }
bool hasBBoxCollision() const { return flags & Flag_BBoxCollision; }
bool collisionActive() const { return flags & Flag_ActiveCollision; }
2010-01-06 14:00:08 +00:00
};
struct NiNode : Node
{
NodeList children;
NodeList effects;
enum BSAnimFlags {
AnimFlag_AutoPlay = 0x0020
};
enum BSParticleFlags {
ParticleFlag_AutoPlay = 0x0020,
ParticleFlag_LocalSpace = 0x0080
};
void read(NIFStream *nif) override
{
Node::read(nif);
children.read(nif);
if (nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO4)
effects.read(nif);
// Discard transformations for the root node, otherwise some meshes
// occasionally get wrong orientation. Only for NiNode-s for now, but
// can be expanded if needed.
// FIXME: if node 0 is *not* the only root node, this must not happen.
if (0 == recIndex && !Misc::StringUtils::ciEqual(name, "bip01"))
{
trafo = Nif::Transformation::getIdentity();
}
}
void post(NIFFile *nif) override
{
Node::post(nif);
children.post(nif);
effects.post(nif);
2012-07-03 05:49:44 +00:00
for(size_t i = 0;i < children.length();i++)
{
// Why would a unique list of children contain empty refs?
if(!children[i].empty())
children[i]->parents.push_back(this);
}
}
2010-01-06 14:00:08 +00:00
};
2020-05-14 07:52:27 +00:00
struct NiGeometry : Node
{
/* Possible flags:
0x40 - mesh has no vertex normals ?
Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have
been observed so far.
*/
struct MaterialData
{
std::vector<std::string> names;
std::vector<int> extra;
unsigned int active{0};
bool needsUpdate{false};
void read(NIFStream *nif)
{
if (nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
return;
unsigned int num = 0;
if (nif->getVersion() <= NIFStream::generateVersion(20,1,0,3))
num = nif->getBoolean(); // Has Shader
else if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5))
num = nif->getUInt();
if (num)
{
nif->getStrings(names, num);
nif->getInts(extra, num);
}
if (nif->getVersion() >= NIFStream::generateVersion(20,2,0,5))
active = nif->getUInt();
if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS)
needsUpdate = nif->getBoolean();
}
};
NiGeometryDataPtr data;
2020-05-14 07:52:27 +00:00
NiSkinInstancePtr skin;
MaterialData material;
BSShaderPropertyPtr shaderprop;
NiAlphaPropertyPtr alphaprop;
void read(NIFStream *nif) override
{
Node::read(nif);
data.read(nif);
skin.read(nif);
material.read(nif);
if (nif->getVersion() == NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO3)
{
shaderprop.read(nif);
alphaprop.read(nif);
}
}
void post(NIFFile *nif) override
{
Node::post(nif);
data.post(nif);
skin.post(nif);
shaderprop.post(nif);
alphaprop.post(nif);
if (recType != RC_NiParticles && !skin.empty())
nif->setUseSkinning(true);
}
};
struct NiTriShape : NiGeometry {};
struct BSLODTriShape : NiTriShape
{
unsigned int lod0, lod1, lod2;
void read(NIFStream *nif) override
{
NiTriShape::read(nif);
lod0 = nif->getUInt();
lod1 = nif->getUInt();
lod2 = nif->getUInt();
}
};
struct NiTriStrips : NiGeometry {};
struct NiLines : NiGeometry {};
struct NiParticles : NiGeometry { };
2010-01-07 18:11:03 +00:00
struct NiCamera : Node
{
struct Camera
{
unsigned short cameraFlags{0};
// Camera frustrum
float left, right, top, bottom, nearDist, farDist;
2010-01-07 18:11:03 +00:00
// Viewport
float vleft, vright, vtop, vbottom;
2010-01-07 18:11:03 +00:00
// Level of detail modifier
float LOD;
2012-07-10 07:27:13 +00:00
// Orthographic projection usage flag
bool orthographic{false};
void read(NIFStream *nif)
2012-07-10 07:27:13 +00:00
{
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
cameraFlags = nif->getUShort();
left = nif->getFloat();
right = nif->getFloat();
top = nif->getFloat();
bottom = nif->getFloat();
nearDist = nif->getFloat();
farDist = nif->getFloat();
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
orthographic = nif->getBoolean();
vleft = nif->getFloat();
vright = nif->getFloat();
vtop = nif->getFloat();
vbottom = nif->getFloat();
LOD = nif->getFloat();
2012-07-10 07:27:13 +00:00
}
};
2012-07-10 04:35:36 +00:00
Camera cam;
2010-01-07 18:11:03 +00:00
void read(NIFStream *nif) override
{
Node::read(nif);
2010-01-07 18:11:03 +00:00
2012-07-10 07:27:13 +00:00
cam.read(nif);
2010-01-07 18:11:03 +00:00
nif->getInt(); // -1
nif->getInt(); // 0
if (nif->getVersion() >= NIFStream::generateVersion(4,2,1,0))
nif->getInt(); // 0
}
2010-01-07 18:11:03 +00:00
};
2015-11-12 18:40:31 +00:00
// A node used as the base to switch between child nodes, such as for LOD levels.
struct NiSwitchNode : public NiNode
{
unsigned int switchFlags{0};
2021-01-09 10:21:57 +00:00
unsigned int initialIndex{0};
2019-06-08 22:58:02 +00:00
void read(NIFStream *nif) override
2015-11-12 18:40:31 +00:00
{
NiNode::read(nif);
if (nif->getVersion() >= NIFStream::generateVersion(10,1,0,0))
switchFlags = nif->getUShort();
2019-06-08 22:58:02 +00:00
initialIndex = nif->getUInt();
2015-11-12 18:40:31 +00:00
}
};
struct NiLODNode : public NiSwitchNode
{
osg::Vec3f lodCenter;
struct LODRange
{
float minRange;
float maxRange;
};
std::vector<LODRange> lodLevels;
void read(NIFStream *nif) override
2015-11-12 18:40:31 +00:00
{
NiSwitchNode::read(nif);
if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW && nif->getVersion() <= NIFStream::generateVersion(10,0,1,0))
2020-02-02 14:08:17 +00:00
lodCenter = nif->getVector3();
else if (nif->getVersion() > NIFStream::generateVersion(10,0,1,0))
{
nif->skip(4); // NiLODData, unsupported at the moment
return;
}
2015-11-12 18:40:31 +00:00
unsigned int numLodLevels = nif->getUInt();
for (unsigned int i=0; i<numLodLevels; ++i)
{
LODRange r;
r.minRange = nif->getFloat();
r.maxRange = nif->getFloat();
lodLevels.push_back(r);
}
}
};
2022-03-29 19:47:37 +00:00
struct NiFltAnimationNode : public NiSwitchNode
{
2022-04-06 22:49:08 +00:00
float mDuration;
enum Flags
{
2022-04-06 22:49:08 +00:00
Flag_Swing = 0x40
};
2022-03-29 19:47:37 +00:00
void read(NIFStream *nif) override
{
NiSwitchNode::read(nif);
2022-04-06 22:49:08 +00:00
mDuration = nif->getFloat();
2022-03-29 19:47:37 +00:00
}
2022-06-21 21:43:16 +00:00
bool swing() const { return flags & Flag_Swing; }
2022-03-29 19:47:37 +00:00
};
// Abstract
struct NiAccumulator : Record
{
void read(NIFStream *nif) override {}
};
// Node children sorters
struct NiClusterAccumulator : NiAccumulator {};
struct NiAlphaAccumulator : NiClusterAccumulator {};
struct NiSortAdjustNode : NiNode
{
enum SortingMode
{
SortingMode_Inherit,
SortingMode_Off,
SortingMode_Subsort
};
int mMode;
NiAccumulatorPtr mSubSorter;
void read(NIFStream *nif) override
{
NiNode::read(nif);
mMode = nif->getInt();
if (nif->getVersion() <= NIFStream::generateVersion(20,0,0,3))
mSubSorter.read(nif);
}
void post(NIFFile *nif) override
{
2022-02-09 10:55:32 +00:00
NiNode::post(nif);
mSubSorter.post(nif);
}
};
2010-01-06 11:28:37 +00:00
} // Namespace
#endif