1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-23 15:40:42 +00:00

Cleanup RecordPtrT

This moves the index resolution into a separate post method instead of always
checking when access. As a result, it reduces the size of it down to the size
of a pointer, as opposed to 2 pointers + 1 int. The appropriate methods are
added to the various node types to make sure they're resolved.
This commit is contained in:
Chris Robinson 2012-07-02 21:41:21 -07:00
parent efb95e2f83
commit 046e9686f9
11 changed files with 1364 additions and 1283 deletions

View File

@ -25,6 +25,7 @@
#define _NIF_CONTROLLED_H_ #define _NIF_CONTROLLED_H_
#include "extra.hpp" #include "extra.hpp"
#include "controller.hpp"
namespace Nif namespace Nif
{ {
@ -33,92 +34,104 @@ namespace Nif
class Controlled : public Extra class Controlled : public Extra
{ {
public: public:
ControllerPtr controller; ControllerPtr controller;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Extra::read(nif); Extra::read(nif);
controller.read(nif); controller.read(nif);
} }
void post(NIFFile *nif)
{
Extra::post(nif);
controller.post(nif);
}
}; };
/// Has name, extra-data and controller /// Has name, extra-data and controller
class Named : public Controlled class Named : public Controlled
{ {
public: public:
Misc::SString name; Misc::SString name;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
name = nif->getString(); name = nif->getString();
Controlled::read(nif); Controlled::read(nif);
} }
}; };
typedef Named NiSequenceStreamHelper; typedef Named NiSequenceStreamHelper;
class NiParticleGrowFade : public Controlled class NiParticleGrowFade : public Controlled
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controlled::read(nif); Controlled::read(nif);
// Two floats. // Two floats.
nif->skip(8); nif->skip(8);
} }
}; };
class NiParticleColorModifier : public Controlled class NiParticleColorModifier : public Controlled
{ {
public: public:
NiColorDataPtr data; NiColorDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controlled::read(nif); Controlled::read(nif);
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controlled::post(nif);
data.post(nif);
}
}; };
class NiGravity : public Controlled class NiGravity : public Controlled
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controlled::read(nif); Controlled::read(nif);
// two floats, one int, six floats // two floats, one int, six floats
nif->skip(9*4); nif->skip(9*4);
} }
}; };
// NiPinaColada // NiPinaColada
class NiPlanarCollider : public Controlled class NiPlanarCollider : public Controlled
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controlled::read(nif); Controlled::read(nif);
// (I think) 4 floats + 4 vectors // (I think) 4 floats + 4 vectors
nif->skip(4*16); nif->skip(4*16);
} }
}; };
class NiParticleRotation : public Controlled class NiParticleRotation : public Controlled
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controlled::read(nif); Controlled::read(nif);
/* /*
byte (0 or 1) byte (0 or 1)
float (1) float (1)
float*3 float*3
*/ */
nif->skip(17); nif->skip(17);
} }
}; };
} // Namespace } // Namespace

View File

@ -34,136 +34,187 @@ namespace Nif
class Controller : public Record class Controller : public Record
{ {
public: public:
ControllerPtr next; ControllerPtr next;
int flags; int flags;
float frequency, phase; float frequency, phase;
float timeStart, timeStop; float timeStart, timeStop;
ControlledPtr target; ControlledPtr target;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
next.read(nif); next.read(nif);
flags = nif->getShort(); flags = nif->getShort();
frequency = nif->getFloat(); frequency = nif->getFloat();
phase = nif->getFloat(); phase = nif->getFloat();
timeStart = nif->getFloat(); timeStart = nif->getFloat();
timeStop = nif->getFloat(); timeStop = nif->getFloat();
target.read(nif); target.read(nif);
} }
void post(NIFFile *nif)
{
Record::post(nif);
next.post(nif);
target.post(nif);
}
}; };
class NiBSPArrayController : public Controller class NiBSPArrayController : public Controller
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
// At the moment, just skip it all // At the moment, just skip it all
nif->skip(111); nif->skip(111);
int s = nif->getShort(); int s = nif->getShort();
nif->skip(15 + s*40); nif->skip(15 + s*40);
} }
}; };
typedef NiBSPArrayController NiParticleSystemController; typedef NiBSPArrayController NiParticleSystemController;
class NiMaterialColorController : public Controller class NiMaterialColorController : public Controller
{ {
public: public:
NiPosDataPtr data; NiPosDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
class NiPathController : public Controller class NiPathController : public Controller
{ {
public: public:
NiPosDataPtr posData; NiPosDataPtr posData;
NiFloatDataPtr floatData; NiFloatDataPtr floatData;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
/* /*
int = 1 int = 1
2xfloat 2xfloat
short = 0 or 1 short = 0 or 1
*/ */
nif->skip(14); nif->skip(14);
posData.read(nif); posData.read(nif);
floatData.read(nif); floatData.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
posData.post(nif);
floatData.post(nif);
}
}; };
class NiUVController : public Controller class NiUVController : public Controller
{ {
public: public:
NiUVDataPtr data; NiUVDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
nif->getShort(); // always 0 nif->getShort(); // always 0
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
class NiKeyframeController : public Controller class NiKeyframeController : public Controller
{ {
public: public:
NiKeyframeDataPtr data; NiKeyframeDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
class NiAlphaController : public Controller class NiAlphaController : public Controller
{ {
public: public:
NiFloatDataPtr data; NiFloatDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
class NiGeomMorpherController : public Controller class NiGeomMorpherController : public Controller
{ {
public: public:
NiMorphDataPtr data; NiMorphDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
data.read(nif); data.read(nif);
nif->getByte(); // always 0 nif->getByte(); // always 0
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
class NiVisController : public Controller class NiVisController : public Controller
{ {
public: public:
NiVisDataPtr data; NiVisDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Controller::read(nif); Controller::read(nif);
data.read(nif); data.read(nif);
} }
void post(NIFFile *nif)
{
Controller::post(nif);
data.post(nif);
}
}; };
} // Namespace } // Namespace

File diff suppressed because it is too large Load Diff

View File

@ -35,57 +35,62 @@ typedef Node Effect;
// NiPointLight and NiSpotLight? // NiPointLight and NiSpotLight?
struct NiLight : Effect struct NiLight : Effect
{ {
struct SLight struct SLight
{ {
float dimmer; float dimmer;
Vector ambient; Vector ambient;
Vector diffuse; Vector diffuse;
Vector specular; Vector specular;
}; };
const SLight *light;
const SLight *light; void read(NIFFile *nif)
{
Effect::read(nif);
void read(NIFFile *nif) nif->getInt(); // 1
{ nif->getInt(); // 1?
Effect::read(nif); light = nif->getPtr<SLight>();
}
nif->getInt(); // 1
nif->getInt(); // 1?
light = nif->getPtr<SLight>();
}
}; };
struct NiTextureEffect : Effect struct NiTextureEffect : Effect
{ {
NiSourceTexturePtr texture; NiSourceTexturePtr texture;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Effect::read(nif); Effect::read(nif);
int tmp = nif->getInt(); int tmp = nif->getInt();
if(tmp) nif->getInt(); // always 1? if(tmp) nif->getInt(); // always 1?
/* /*
3 x Vector4 = [1,0,0,0] 3 x Vector4 = [1,0,0,0]
int = 2 int = 2
int = 0 or 3 int = 0 or 3
int = 2 int = 2
int = 2 int = 2
*/ */
nif->skip(16*4); nif->skip(16*4);
texture.read(nif); texture.read(nif);
/* /*
byte = 0 byte = 0
vector4 = [1,0,0,0] vector4 = [1,0,0,0]
short = 0 short = 0
short = -75 short = -75
short = 0 short = 0
*/ */
nif->skip(23); nif->skip(23);
} }
void post(NIFFile *nif)
{
Effect::post(nif);
texture.post(nif);
}
}; };
} // Namespace } // Namespace

View File

@ -38,70 +38,70 @@ namespace Nif
class Extra : public Record class Extra : public Record
{ {
public: public:
ExtraPtr extra; ExtraPtr extra;
void read(NIFFile *nif) { extra.read(nif); } void read(NIFFile *nif) { extra.read(nif); }
void post(NIFFile *nif) { extra.post(nif); }
}; };
class NiVertWeightsExtraData : public Extra class NiVertWeightsExtraData : public Extra
{ {
public: public:
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Extra::read(nif); Extra::read(nif);
// We should have s*4+2 == i, for some reason. Might simply be the // We should have s*4+2 == i, for some reason. Might simply be the
// size of the rest of the record, unhelpful as that may be. // size of the rest of the record, unhelpful as that may be.
/*int i =*/ nif->getInt(); /*int i =*/ nif->getInt();
int s = nif->getShort(); // number of vertices int s = nif->getShort(); // number of vertices
nif->getFloatLen(s); // vertex weights I guess nif->getFloatLen(s); // vertex weights I guess
} }
}; };
class NiTextKeyExtraData : public Extra class NiTextKeyExtraData : public Extra
{ {
public: public:
struct TextKey struct TextKey
{ {
float time; float time;
Misc::SString text; Misc::SString text;
}; };
std::vector<TextKey> list;
std::vector<TextKey> list; void read(NIFFile *nif)
{
Extra::read(nif);
void read(NIFFile *nif) nif->getInt(); // 0
{
Extra::read(nif);
nif->getInt(); // 0 int keynum = nif->getInt();
list.resize(keynum);
int keynum = nif->getInt(); for(int i=0; i<keynum; i++)
list.resize(keynum); {
for(int i=0; i<keynum; i++) list[i].time = nif->getFloat();
{ list[i].text = nif->getString();
list[i].time = nif->getFloat(); }
list[i].text = nif->getString(); }
}
}
}; };
class NiStringExtraData : public Extra class NiStringExtraData : public Extra
{ {
public: public:
/* Two known meanings: /* Two known meanings:
"MRK" - marker, only visible in the editor, not rendered in-game "MRK" - marker, only visible in the editor, not rendered in-game
"NCO" - no collision "NCO" - no collision
*/ */
Misc::SString string; Misc::SString string;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Extra::read(nif); Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful... nif->getInt(); // size of string + 4. Really useful...
string = nif->getString(); string = nif->getString();
} }
}; };
} // Namespace } // Namespace

View File

@ -190,17 +190,23 @@ void NIFFile::parse()
void NiSkinInstance::post(NIFFile *nif) void NiSkinInstance::post(NIFFile *nif)
{ {
int bnum = bones.length(); data.post(nif);
if(bnum != static_cast<int> (data->bones.size())) root.post(nif);
nif->fail("Mismatch in NiSkinData bone count"); bones.post(nif);
root->makeRootBone(data->trafo); if(data.empty() || root.empty())
nif->fail("NiSkinInstance missing root or data");
for(int i=0; i<bnum; i++) size_t bnum = bones.length();
if(bnum != data->bones.size())
nif->fail("Mismatch in NiSkinData bone count");
root->makeRootBone(data->trafo);
for(int i=0; i<bnum; i++)
{ {
if(!bones.has(i)) if(!bones.has(i))
nif->fail("Oops: Missing bone! Don't know how to handle this."); nif->fail("Oops: Missing bone! Don't know how to handle this.");
bones[i].makeBone(i, data->bones[i]);
bones[i].makeBone(i, data->bones[i]);
} }
} }

View File

@ -43,113 +43,107 @@ namespace Nif
class NIFFile class NIFFile
{ {
enum NIFVersion enum NIFVersion {
{ VER_MW = 0x04000002 // Morrowind NIFs
VER_MW = 0x04000002 // Morrowind NIFs
}; };
/// Nif file version /// Nif file version
int ver; int ver;
/// Input stream /// Input stream
StreamPtr inp; StreamPtr inp;
/// File name, used for error messages /// File name, used for error messages
std::string filename; std::string filename;
/// Record list /// Record list
std::vector<Record*> records; std::vector<Record*> records;
/// Parse the file /// Parse the file
void parse(); void parse();
public: public:
/// Used for error handling /// Used for error handling
void fail(const std::string &msg) void fail(const std::string &msg)
{ {
std::string err = "NIFFile Error: " + msg; std::string err = "NIFFile Error: " + msg;
err += "\nFile: " + filename; err += "\nFile: " + filename;
throw std::runtime_error(err); throw std::runtime_error(err);
} }
/// Open a NIF stream. The name is used for error messages. /// Open a NIF stream. The name is used for error messages.
NIFFile(StreamPtr nif, const std::string &name) NIFFile(StreamPtr nif, const std::string &name)
: filename(name) : filename(name)
{ {
/* Load the entire file into memory. This allows us to use /* Load the entire file into memory. This allows us to use
direct pointers to the data arrays in the NIF, instead of direct pointers to the data arrays in the NIF, instead of
individually allocating and copying each one. individually allocating and copying each one.
The NIF data is only stored temporarily in memory, since once The NIF data is only stored temporarily in memory, since once
the mesh data is loaded it is siphoned into OGRE and the mesh data is loaded it is siphoned into OGRE and
deleted. For that reason, we might improve this further and deleted. For that reason, we might improve this further and
use a shared region/pool based allocation scheme in the use a shared region/pool based allocation scheme in the
future, especially since only one NIFFile will ever be loaded future, especially since only one NIFFile will ever be loaded
at any given time. at any given time.
*/ */
inp = StreamPtr(new BufferStream(nif)); inp = StreamPtr(new BufferStream(nif));
parse(); parse();
} }
~NIFFile() ~NIFFile()
{ {
for(std::size_t i=0; i<records.size(); i++) for(std::size_t i=0; i<records.size(); i++)
{ delete records[i];
delete records[i];
}
} }
/// Get a given record /// Get a given record
Record *getRecord(int index) Record *getRecord(size_t index)
{ {
assert(index >= 0 && index < static_cast<int> (records.size())); Record *res = records.at(index);
Record *res = records[index]; assert(res != NULL);
assert(res != NULL); return res;
return res; }
}
/// Number of records /// Number of records
int numRecords() { return records.size(); } int numRecords() { return records.size(); }
/* ************************************************
/*************************************************
Parser functions Parser functions
****************************************************/
****************************************************/ void skip(size_t size) { inp->getPtr(size); }
void skip(size_t size) { inp->getPtr(size); } template<class X> const X* getPtr() { return (const X*)inp->getPtr(sizeof(X)); }
template<class X> X getType() { return *getPtr<X>(); }
unsigned short getShort() { return getType<unsigned short>(); }
int getInt() { return getType<int>(); }
float getFloat() { return getType<float>(); }
char getByte() { return getType<char>(); }
template<class X> const X* getPtr() { return (const X*)inp->getPtr(sizeof(X)); } template<class X>
template<class X> X getType() { return *getPtr<X>(); } Misc::SliceArray<X> getArrayLen(int num)
unsigned short getShort() { return getType<unsigned short>(); }
int getInt() { return getType<int>(); }
float getFloat() { return getType<float>(); }
char getByte() { return getType<char>(); }
template<class X>
Misc::SliceArray<X> getArrayLen(int num)
{ return Misc::SliceArray<X>((const X*)inp->getPtr(num*sizeof(X)),num); } { return Misc::SliceArray<X>((const X*)inp->getPtr(num*sizeof(X)),num); }
template<class X> template<class X>
Misc::SliceArray<X> getArray() Misc::SliceArray<X> getArray()
{ {
int len = getInt(); int len = getInt();
return getArrayLen<X>(len); return getArrayLen<X>(len);
} }
Misc::SString getString() { return getArray<char>(); } Misc::SString getString() { return getArray<char>(); }
const Vector *getVector() { return getPtr<Vector>(); } const Vector *getVector() { return getPtr<Vector>(); }
const Matrix *getMatrix() { return getPtr<Matrix>(); } const Matrix *getMatrix() { return getPtr<Matrix>(); }
const Transformation *getTrafo() { return getPtr<Transformation>(); } const Transformation *getTrafo() { return getPtr<Transformation>(); }
const Vector4 *getVector4() { return getPtr<Vector4>(); } const Vector4 *getVector4() { return getPtr<Vector4>(); }
Misc::FloatArray getFloatLen(int num) Misc::FloatArray getFloatLen(int num)
{ return getArrayLen<float>(num); } { return getArrayLen<float>(num); }
// For fixed-size strings where you already know the size // For fixed-size strings where you already know the size
const char *getString(int size) const char *getString(int size)
{ return (const char*)inp->getPtr(size); } { return (const char*)inp->getPtr(size); }
}; };

View File

@ -26,6 +26,7 @@
#include "controlled.hpp" #include "controlled.hpp"
#include "data.hpp" #include "data.hpp"
#include "property.hpp"
namespace Nif namespace Nif
{ {
@ -37,191 +38,220 @@ namespace Nif
class Node : public Named class Node : public Named
{ {
public: public:
// Node flags. Interpretation depends somewhat on the type of node. // Node flags. Interpretation depends somewhat on the type of node.
int flags; int flags;
const Transformation *trafo; const Transformation *trafo;
PropertyList props; PropertyList props;
// Bounding box info // Bounding box info
bool hasBounds; bool hasBounds;
const Vector *boundPos; const Vector *boundPos;
const Matrix *boundRot; const Matrix *boundRot;
const Vector *boundXYZ; // Box size const Vector *boundXYZ; // Box size
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Named::read(nif); Named::read(nif);
flags = nif->getShort(); flags = nif->getShort();
trafo = nif->getTrafo(); trafo = nif->getTrafo();
props.read(nif); props.read(nif);
hasBounds = !!nif->getInt(); hasBounds = !!nif->getInt();
if(hasBounds) if(hasBounds)
{ {
nif->getInt(); // always 1 nif->getInt(); // always 1
boundPos = nif->getVector(); boundPos = nif->getVector();
boundRot = nif->getMatrix(); boundRot = nif->getMatrix();
boundXYZ = nif->getVector(); boundXYZ = nif->getVector();
} }
boneTrafo = NULL; boneTrafo = NULL;
boneIndex = -1; boneIndex = -1;
} }
// Bone transformation. If set, node is a part of a skeleton. void post(NIFFile *nif)
const NiSkinData::BoneTrafo *boneTrafo; {
Named::post(nif);
props.post(nif);
}
// Bone weight info, from NiSkinData // Bone transformation. If set, node is a part of a skeleton.
const NiSkinData::BoneInfo *boneInfo; const NiSkinData::BoneTrafo *boneTrafo;
// Bone index. If -1, this node is either not a bone, or if // Bone weight info, from NiSkinData
// boneTrafo is set it is the root bone in the skeleton. const NiSkinData::BoneInfo *boneInfo;
short boneIndex;
void makeRootBone(const NiSkinData::BoneTrafo *tr) // Bone index. If -1, this node is either not a bone, or if
{ // boneTrafo is set it is the root bone in the skeleton.
boneTrafo = tr; short boneIndex;
boneIndex = -1;
}
void makeBone(short ind, const NiSkinData::BoneInfo &bi) void makeRootBone(const NiSkinData::BoneTrafo *tr)
{ {
boneInfo = &bi; boneTrafo = tr;
boneTrafo = bi.trafo; boneIndex = -1;
boneIndex = ind; }
}
void makeBone(short ind, const NiSkinData::BoneInfo &bi)
{
boneInfo = &bi;
boneTrafo = bi.trafo;
boneIndex = ind;
}
}; };
struct NiTriShapeCopy struct NiTriShapeCopy
{ {
std::string sname; std::string sname;
std::vector<std::string> boneSequence; std::vector<std::string> boneSequence;
Nif::NiSkinData::BoneTrafoCopy trafo; Nif::NiSkinData::BoneTrafoCopy trafo;
//Ogre::Quaternion initialBoneRotation; //Ogre::Quaternion initialBoneRotation;
//Ogre::Vector3 initialBoneTranslation; //Ogre::Vector3 initialBoneTranslation;
std::vector<Ogre::Vector3> vertices; std::vector<Ogre::Vector3> vertices;
std::vector<Ogre::Vector3> normals; std::vector<Ogre::Vector3> normals;
std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfo; std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfo;
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> > vertsToWeights; std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> > vertsToWeights;
Nif::NiMorphData morph; Nif::NiMorphData morph;
}; };
struct NiNode : Node struct NiNode : Node
{ {
NodeList children; NodeList children;
NodeList effects; NodeList effects;
/* Known NiNode flags: /* Known NiNode flags:
0x01 hidden
0x02 use mesh for collision
0x04 use bounding box for collision (?)
0x08 unknown, but common
0x20, 0x40, 0x80 unknown
*/
0x01 hidden void read(NIFFile *nif)
0x02 use mesh for collision {
0x04 use bounding box for collision (?) Node::read(nif);
0x08 unknown, but common children.read(nif);
0x20, 0x40, 0x80 unknown effects.read(nif);
*/ }
void read(NIFFile *nif) void post(NIFFile *nif)
{ {
Node::read(nif); Node::post(nif);
children.read(nif); children.post(nif);
effects.read(nif); effects.post(nif);
} }
}; };
struct NiTriShape : Node struct NiTriShape : Node
{ {
/* Possible flags: /* Possible flags:
0x40 - mesh has no vertex normals ? 0x40 - mesh has no vertex normals ?
Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have
been observed so far. been observed so far.
*/ */
NiTriShapeDataPtr data; NiTriShapeDataPtr data;
NiSkinInstancePtr skin; NiSkinInstancePtr skin;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Node::read(nif); Node::read(nif);
data.read(nif); data.read(nif);
skin.read(nif); skin.read(nif);
} }
NiTriShapeCopy clone(){ void post(NIFFile *nif)
NiTriShapeCopy copy; {
copy.sname = name.toString(); Node::post(nif);
float *ptr = (float*)data->vertices.ptr; data.post(nif);
float *ptrNormals = (float*)data->normals.ptr; skin.post(nif);
int numVerts = data->vertices.length / 3; }
for(int i = 0; i < numVerts; i++)
{
float *current = (float*) (ptr + i * 3);
copy.vertices.push_back(Ogre::Vector3(*current, *(current + 1), *(current + 2)));
if(ptrNormals){ NiTriShapeCopy clone()
float *currentNormals = (float*) (ptrNormals + i * 3); {
copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2))); NiTriShapeCopy copy;
} copy.sname = name.toString();
} float *ptr = (float*)data->vertices.ptr;
float *ptrNormals = (float*)data->normals.ptr;
int numVerts = data->vertices.length / 3;
for(int i = 0; i < numVerts; i++)
{
float *current = (float*) (ptr + i * 3);
copy.vertices.push_back(Ogre::Vector3(*current, *(current + 1), *(current + 2)));
if(ptrNormals)
{
float *currentNormals = (float*) (ptrNormals + i * 3);
copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2)));
}
}
return copy; return copy;
} }
}; };
struct NiCamera : Node struct NiCamera : Node
{ {
struct Camera struct Camera
{ {
// Camera frustrum // Camera frustrum
float left, right, top, bottom, nearDist, farDist; float left, right, top, bottom, nearDist, farDist;
// Viewport // Viewport
float vleft, vright, vtop, vbottom; float vleft, vright, vtop, vbottom;
// Level of detail modifier // Level of detail modifier
float LOD; float LOD;
}; };
const Camera *cam;
const Camera *cam; void read(NIFFile *nif)
{
Node::read(nif);
void read(NIFFile *nif) nif->getPtr<Camera>();
{
Node::read(nif);
nif->getPtr<Camera>(); nif->getInt(); // -1
nif->getInt(); // 0
nif->getInt(); // -1 }
nif->getInt(); // 0
}
}; };
struct NiAutoNormalParticles : Node struct NiAutoNormalParticles : Node
{ {
NiAutoNormalParticlesDataPtr data; NiAutoNormalParticlesDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Node::read(nif); Node::read(nif);
data.read(nif); data.read(nif);
nif->getInt(); // -1 nif->getInt(); // -1
} }
void post(NIFFile *nif)
{
Node::post(nif);
data.post(nif);
}
}; };
struct NiRotatingParticles : Node struct NiRotatingParticles : Node
{ {
NiRotatingParticlesDataPtr data; NiRotatingParticlesDataPtr data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Node::read(nif); Node::read(nif);
data.read(nif); data.read(nif);
nif->getInt(); // -1 nif->getInt(); // -1
} }
void post(NIFFile *nif)
{
Node::post(nif);
data.post(nif);
}
}; };
} // Namespace } // Namespace
#endif #endif

View File

@ -32,104 +32,116 @@ namespace Nif
class Property : public Named class Property : public Named
{ {
public: public:
// The meaning of these depends on the actual property type. // The meaning of these depends on the actual property type.
int flags; int flags;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Named::read(nif); Named::read(nif);
flags = nif->getShort(); flags = nif->getShort();
} }
}; };
class NiTexturingProperty : public Property class NiTexturingProperty : public Property
{ {
public: public:
// A sub-texture // A sub-texture
struct Texture struct Texture
{ {
/* Clamp mode /* Clamp mode
0 - clampS clampT 0 - clampS clampT
1 - clampS wrapT 1 - clampS wrapT
2 - wrapS clampT 2 - wrapS clampT
3 - wrapS wrapT 3 - wrapS wrapT
*/ */
/* Filter: /* Filter:
0 - nearest 0 - nearest
1 - bilinear 1 - bilinear
2 - trilinear 2 - trilinear
3, 4, 5 - who knows 3, 4, 5 - who knows
*/ */
bool inUse; bool inUse;
NiSourceTexturePtr texture; NiSourceTexturePtr texture;
int clamp, set, filter; int clamp, set, filter;
short unknown2; short unknown2;
void read(NIFFile *nif)
{
inUse = !!nif->getInt();
if(!inUse) return;
texture.read(nif);
clamp = nif->getInt();
filter = nif->getInt();
set = nif->getInt();
// I have no idea, but I think these are actually two
// PS2-specific shorts (ps2L and ps2K), followed by an unknown
// short.
nif->skip(6);
}
void post(NIFFile *nif)
{
texture.post(nif);
}
};
/* Apply mode:
0 - replace
1 - decal
2 - modulate
3 - hilight // These two are for PS2 only?
4 - hilight2
*/
int apply;
/*
* The textures in this list are as follows:
*
* 0 - Base texture
* 1 - Dark texture
* 2 - Detail texture
* 3 - Gloss texture (never used?)
* 4 - Glow texture
* 5 - Bump map texture
* 6 - Decal texture
*/
Texture textures[7];
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
inUse = !!nif->getInt(); Property::read(nif);
if(!inUse) return; apply = nif->getInt();
texture.read(nif); // Unknown, always 7. Probably the number of textures to read
clamp = nif->getInt(); // below
filter = nif->getInt(); nif->getInt();
set = nif->getInt();
// I have no idea, but I think these are actually two textures[0].read(nif); // Base
// PS2-specific shorts (ps2L and ps2K), followed by an unknown textures[1].read(nif); // Dark
// short. textures[2].read(nif); // Detail
nif->skip(6); textures[3].read(nif); // Gloss (never present)
textures[4].read(nif); // Glow
textures[5].read(nif); // Bump map
if(textures[5].inUse)
{
// Ignore these at the moment
/*float lumaScale =*/ nif->getFloat();
/*float lumaOffset =*/ nif->getFloat();
/*const Vector4 *lumaMatrix =*/ nif->getVector4();
}
textures[6].read(nif); // Decal
} }
};
/* Apply mode: void post(NIFFile *nif)
0 - replace {
1 - decal Property::post(nif);
2 - modulate for(int i = 0;i < 7;i++)
3 - hilight // These two are for PS2 only? textures[i].post(nif);
4 - hilight2 }
*/
int apply;
/*
* The textures in this list are as follows:
*
* 0 - Base texture
* 1 - Dark texture
* 2 - Detail texture
* 3 - Gloss texture (never used?)
* 4 - Glow texture
* 5 - Bump map texture
* 6 - Decal texture
*/
Texture textures[7];
void read(NIFFile *nif)
{
Property::read(nif);
apply = nif->getInt();
// Unknown, always 7. Probably the number of textures to read
// below
nif->getInt();
textures[0].read(nif); // Base
textures[1].read(nif); // Dark
textures[2].read(nif); // Detail
textures[3].read(nif); // Gloss (never present)
textures[4].read(nif); // Glow
textures[5].read(nif); // Bump map
if(textures[5].inUse)
{
// Ignore these at the moment
/*float lumaScale =*/ nif->getFloat();
/*float lumaOffset =*/ nif->getFloat();
/*const Vector4 *lumaMatrix =*/ nif->getVector4();
}
textures[6].read(nif); // Decal
}
}; };
// These contain no other data than the 'flags' field in Property // These contain no other data than the 'flags' field in Property
@ -140,88 +152,88 @@ typedef Property NiSpecularProperty;
typedef Property NiWireframeProperty; typedef Property NiWireframeProperty;
// The rest are all struct-based // The rest are all struct-based
template <typename Struct> template <typename T>
struct StructPropT : Property struct StructPropT : Property
{ {
const Struct* data; const T* data;
void read(NIFFile *nif) void read(NIFFile *nif)
{ {
Property::read(nif); Property::read(nif);
data = nif->getPtr<Struct>(); data = nif->getPtr<T>();
} }
}; };
struct S_MaterialProperty struct S_MaterialProperty
{ {
// The vector components are R,G,B // The vector components are R,G,B
Vector ambient, diffuse, specular, emissive; Vector ambient, diffuse, specular, emissive;
float glossiness, alpha; float glossiness, alpha;
}; };
struct S_VertexColorProperty struct S_VertexColorProperty
{ {
/* Vertex mode: /* Vertex mode:
0 - source ignore 0 - source ignore
1 - source emmisive 1 - source emmisive
2 - source amb diff 2 - source amb diff
Lighting mode Lighting mode
0 - lighting emmisive 0 - lighting emmisive
1 - lighting emmisive ambient/diffuse 1 - lighting emmisive ambient/diffuse
*/ */
int vertmode, lightmode; int vertmode, lightmode;
}; };
struct S_AlphaProperty struct S_AlphaProperty
{ {
/* /*
In NiAlphaProperty, the flags have the following meaning: In NiAlphaProperty, the flags have the following meaning:
Bit 0 : alpha blending enable Bit 0 : alpha blending enable
Bits 1-4 : source blend mode Bits 1-4 : source blend mode
Bits 5-8 : destination blend mode Bits 5-8 : destination blend mode
Bit 9 : alpha test enable Bit 9 : alpha test enable
Bit 10-12 : alpha test mode Bit 10-12 : alpha test mode
Bit 13 : no sorter flag ( disables triangle sorting ) Bit 13 : no sorter flag ( disables triangle sorting )
blend modes (glBlendFunc): blend modes (glBlendFunc):
0000 GL_ONE 0000 GL_ONE
0001 GL_ZERO 0001 GL_ZERO
0010 GL_SRC_COLOR 0010 GL_SRC_COLOR
0011 GL_ONE_MINUS_SRC_COLOR 0011 GL_ONE_MINUS_SRC_COLOR
0100 GL_DST_COLOR 0100 GL_DST_COLOR
0101 GL_ONE_MINUS_DST_COLOR 0101 GL_ONE_MINUS_DST_COLOR
0110 GL_SRC_ALPHA 0110 GL_SRC_ALPHA
0111 GL_ONE_MINUS_SRC_ALPHA 0111 GL_ONE_MINUS_SRC_ALPHA
1000 GL_DST_ALPHA 1000 GL_DST_ALPHA
1001 GL_ONE_MINUS_DST_ALPHA 1001 GL_ONE_MINUS_DST_ALPHA
1010 GL_SRC_ALPHA_SATURATE 1010 GL_SRC_ALPHA_SATURATE
test modes (glAlphaFunc): test modes (glAlphaFunc):
000 GL_ALWAYS 000 GL_ALWAYS
001 GL_LESS 001 GL_LESS
010 GL_EQUAL 010 GL_EQUAL
011 GL_LEQUAL 011 GL_LEQUAL
100 GL_GREATER 100 GL_GREATER
101 GL_NOTEQUAL 101 GL_NOTEQUAL
110 GL_GEQUAL 110 GL_GEQUAL
111 GL_NEVER 111 GL_NEVER
Taken from: Taken from:
http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html
Right now we only use standard alpha blending (see the Ogre code Right now we only use standard alpha blending (see the Ogre code
that sets it up) and it appears that this is the only blending that sets it up) and it appears that this is the only blending
used in the original game. Bloodmoon (along with several mods) do used in the original game. Bloodmoon (along with several mods) do
however use other settings, such as discarding pixel values with however use other settings, such as discarding pixel values with
alpha < 1.0. This is faster because we don't have to mess with the alpha < 1.0. This is faster because we don't have to mess with the
depth stuff like we did for blending. And OGRE has settings for depth stuff like we did for blending. And OGRE has settings for
this too. this too.
*/ */
// Tested against when certain flags are set (see above.) // Tested against when certain flags are set (see above.)
unsigned char threshold; unsigned char threshold;
}; };
typedef StructPropT<S_AlphaProperty> NiAlphaProperty; typedef StructPropT<S_AlphaProperty> NiAlphaProperty;

View File

@ -88,26 +88,25 @@ enum RecordType
/// Base class for all records /// Base class for all records
struct Record struct Record
{ {
// Record type and type name // Record type and type name
int recType; int recType;
Misc::SString recName; Misc::SString recName;
Record() : recType(RC_MISSING) {} Record() : recType(RC_MISSING) {}
/// Parses the record from file /// Parses the record from file
virtual void read(NIFFile *nif) = 0; virtual void read(NIFFile *nif) = 0;
/// Does post-processing, after the entire tree is loaded /// Does post-processing, after the entire tree is loaded
virtual void post(NIFFile *nif) {} virtual void post(NIFFile *nif) {}
virtual ~Record() {} virtual ~Record() {}
/* /*
Use these later if you want custom allocation of all NIF objects Use these later if you want custom allocation of all NIF objects
static void* operator new(size_t size);
static void* operator new(size_t size); static void operator delete(void *p);
static void operator delete(void *p); */
*/
}; };
} // Namespace } // Namespace

View File

@ -37,61 +37,51 @@ namespace Nif
template <class X> template <class X>
class RecordPtrT class RecordPtrT
{ {
int index; union {
X* ptr; intptr_t index;
NIFFile *nif; X* ptr;
};
public: public:
RecordPtrT() : index(-2) {}
RecordPtrT() : index(-2), ptr(NULL) {} /// Read the index from the nif
void read(NIFFile *nif)
{
// Can only read the index once
assert(index == -2);
/// Read the index from the nif // Store the index for later
void read(NIFFile *_nif) index = nif->getInt();
{ }
// Can only read the index once
assert(index == -2);
// Store the NIFFile pointer for later /// Resolve index to pointer
nif = _nif; void post(NIFFile *nif)
{
if(index < 0)
ptr = NULL;
else
{
Record *r = nif->getRecord(index);
// And cast it
ptr = dynamic_cast<X*>(r);
assert(ptr != NULL);
}
}
// And the index, of course /// Look up the actual object from the index
index = nif->getInt(); X* getPtr()
} {
/** Set the pointer explicitly. May be used when you are pointing to
records in another file, eg. when you have a .nif / .kf pair.
*/
void set(X *p)
{
ptr = p;
index = -1;
}
/// Look up the actual object from the index
X* getPtr()
{
// Have we found the pointer already?
if(ptr == NULL)
{
// Get the record
assert(index >= 0);
Record *r = nif->getRecord(index);
// And cast it
ptr = dynamic_cast<X*>(r);
assert(ptr != NULL); assert(ptr != NULL);
} return ptr;
return ptr; }
} X& get() { return *getPtr(); }
/// Syntactic sugar /// Syntactic sugar
X* operator->() { return getPtr(); } X* operator->() { return getPtr(); }
X& get() { return *getPtr(); }
/// Pointers are allowed to be empty /// Pointers are allowed to be empty
bool empty() { return index == -1 && ptr == NULL; } bool empty() { return ptr == NULL; }
int getIndex() { return index; }
}; };
/** A list of references to other records. These are read as a list, /** A list of references to other records. These are read as a list,
@ -101,40 +91,38 @@ class RecordPtrT
template <class X> template <class X>
class RecordListT class RecordListT
{ {
typedef RecordPtrT<X> Ptr; typedef RecordPtrT<X> Ptr;
std::vector<Ptr> list; std::vector<Ptr> list;
public: public:
void read(NIFFile *nif)
void read(NIFFile *nif)
{
int len = nif->getInt();
list.resize(len);
assert(len >= 0 && len < 1000);
for(int i=0;i<len;i++)
list[i].read(nif);
}
X& operator[](int index)
{ {
assert(index >= 0 && index < static_cast<int> (list.size())); int len = nif->getInt();
return list[index].get(); list.resize(len);
for(size_t i=0;i < list.size();i++)
list[i].read(nif);
} }
bool has(int index) void post(NIFFile *nif)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return !list[index].empty();
}
int getIndex(int index)
{ {
if(has(index)) return list[index].getIndex(); for(size_t i=0;i < list.size();i++)
else return -1; list[i].post(nif);
} }
int length() { return list.size(); } X& operator[](size_t index)
{
return list.at(index).get();
}
bool has(size_t index)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return !list.at(index).empty();
}
int length()
{ return list.size(); }
}; };