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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -38,70 +38,70 @@ namespace Nif
class Extra : public Record
{
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
{
public:
void read(NIFFile *nif)
{
Extra::read(nif);
void read(NIFFile *nif)
{
Extra::read(nif);
// 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.
/*int i =*/ nif->getInt();
int s = nif->getShort(); // number of vertices
// 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.
/*int i =*/ nif->getInt();
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
{
public:
struct TextKey
{
float time;
Misc::SString text;
};
struct TextKey
{
float time;
Misc::SString text;
};
std::vector<TextKey> list;
std::vector<TextKey> list;
void read(NIFFile *nif)
{
Extra::read(nif);
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // 0
nif->getInt(); // 0
int keynum = nif->getInt();
list.resize(keynum);
for(int i=0; i<keynum; i++)
{
list[i].time = nif->getFloat();
list[i].text = nif->getString();
}
}
int keynum = nif->getInt();
list.resize(keynum);
for(int i=0; i<keynum; i++)
{
list[i].time = nif->getFloat();
list[i].text = nif->getString();
}
}
};
class NiStringExtraData : public Extra
{
public:
/* Two known meanings:
"MRK" - marker, only visible in the editor, not rendered in-game
"NCO" - no collision
*/
Misc::SString string;
/* Two known meanings:
"MRK" - marker, only visible in the editor, not rendered in-game
"NCO" - no collision
*/
Misc::SString string;
void read(NIFFile *nif)
{
Extra::read(nif);
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
};
} // Namespace

View file

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

View file

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

View file

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

View file

@ -32,104 +32,116 @@ namespace Nif
class Property : public Named
{
public:
// The meaning of these depends on the actual property type.
int flags;
// The meaning of these depends on the actual property type.
int flags;
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getShort();
}
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getShort();
}
};
class NiTexturingProperty : public Property
{
public:
// A sub-texture
struct Texture
{
/* Clamp mode
0 - clampS clampT
1 - clampS wrapT
2 - wrapS clampT
3 - wrapS wrapT
*/
// A sub-texture
struct Texture
{
/* Clamp mode
0 - clampS clampT
1 - clampS wrapT
2 - wrapS clampT
3 - wrapS wrapT
*/
/* Filter:
0 - nearest
1 - bilinear
2 - trilinear
3, 4, 5 - who knows
*/
bool inUse;
NiSourceTexturePtr texture;
/* Filter:
0 - nearest
1 - bilinear
2 - trilinear
3, 4, 5 - who knows
*/
bool inUse;
NiSourceTexturePtr texture;
int clamp, set, filter;
short unknown2;
int clamp, set, filter;
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)
{
inUse = !!nif->getInt();
if(!inUse) return;
Property::read(nif);
apply = nif->getInt();
texture.read(nif);
clamp = nif->getInt();
filter = nif->getInt();
set = nif->getInt();
// Unknown, always 7. Probably the number of textures to read
// below
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);
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
}
};
/* 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)
{
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
}
void post(NIFFile *nif)
{
Property::post(nif);
for(int i = 0;i < 7;i++)
textures[i].post(nif);
}
};
// These contain no other data than the 'flags' field in Property
@ -140,88 +152,88 @@ typedef Property NiSpecularProperty;
typedef Property NiWireframeProperty;
// The rest are all struct-based
template <typename Struct>
template <typename T>
struct StructPropT : Property
{
const Struct* data;
const T* data;
void read(NIFFile *nif)
{
Property::read(nif);
data = nif->getPtr<Struct>();
}
void read(NIFFile *nif)
{
Property::read(nif);
data = nif->getPtr<T>();
}
};
struct S_MaterialProperty
{
// The vector components are R,G,B
Vector ambient, diffuse, specular, emissive;
float glossiness, alpha;
// The vector components are R,G,B
Vector ambient, diffuse, specular, emissive;
float glossiness, alpha;
};
struct S_VertexColorProperty
{
/* Vertex mode:
0 - source ignore
1 - source emmisive
2 - source amb diff
/* Vertex mode:
0 - source ignore
1 - source emmisive
2 - source amb diff
Lighting mode
0 - lighting emmisive
1 - lighting emmisive ambient/diffuse
*/
int vertmode, lightmode;
Lighting mode
0 - lighting emmisive
1 - lighting emmisive ambient/diffuse
*/
int vertmode, lightmode;
};
struct S_AlphaProperty
{
/*
In NiAlphaProperty, the flags have the following meaning:
/*
In NiAlphaProperty, the flags have the following meaning:
Bit 0 : alpha blending enable
Bits 1-4 : source blend mode
Bits 5-8 : destination blend mode
Bit 9 : alpha test enable
Bit 10-12 : alpha test mode
Bit 13 : no sorter flag ( disables triangle sorting )
Bit 0 : alpha blending enable
Bits 1-4 : source blend mode
Bits 5-8 : destination blend mode
Bit 9 : alpha test enable
Bit 10-12 : alpha test mode
Bit 13 : no sorter flag ( disables triangle sorting )
blend modes (glBlendFunc):
0000 GL_ONE
0001 GL_ZERO
0010 GL_SRC_COLOR
0011 GL_ONE_MINUS_SRC_COLOR
0100 GL_DST_COLOR
0101 GL_ONE_MINUS_DST_COLOR
0110 GL_SRC_ALPHA
0111 GL_ONE_MINUS_SRC_ALPHA
1000 GL_DST_ALPHA
1001 GL_ONE_MINUS_DST_ALPHA
1010 GL_SRC_ALPHA_SATURATE
blend modes (glBlendFunc):
0000 GL_ONE
0001 GL_ZERO
0010 GL_SRC_COLOR
0011 GL_ONE_MINUS_SRC_COLOR
0100 GL_DST_COLOR
0101 GL_ONE_MINUS_DST_COLOR
0110 GL_SRC_ALPHA
0111 GL_ONE_MINUS_SRC_ALPHA
1000 GL_DST_ALPHA
1001 GL_ONE_MINUS_DST_ALPHA
1010 GL_SRC_ALPHA_SATURATE
test modes (glAlphaFunc):
000 GL_ALWAYS
001 GL_LESS
010 GL_EQUAL
011 GL_LEQUAL
100 GL_GREATER
101 GL_NOTEQUAL
110 GL_GEQUAL
111 GL_NEVER
test modes (glAlphaFunc):
000 GL_ALWAYS
001 GL_LESS
010 GL_EQUAL
011 GL_LEQUAL
100 GL_GREATER
101 GL_NOTEQUAL
110 GL_GEQUAL
111 GL_NEVER
Taken from:
http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html
Taken from:
http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html
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
used in the original game. Bloodmoon (along with several mods) do
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
depth stuff like we did for blending. And OGRE has settings for
this too.
*/
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
used in the original game. Bloodmoon (along with several mods) do
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
depth stuff like we did for blending. And OGRE has settings for
this too.
*/
// Tested against when certain flags are set (see above.)
unsigned char threshold;
// Tested against when certain flags are set (see above.)
unsigned char threshold;
};
typedef StructPropT<S_AlphaProperty> NiAlphaProperty;

View file

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

View file

@ -37,61 +37,51 @@ namespace Nif
template <class X>
class RecordPtrT
{
int index;
X* ptr;
NIFFile *nif;
union {
intptr_t index;
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
void read(NIFFile *_nif)
{
// Can only read the index once
assert(index == -2);
// Store the index for later
index = nif->getInt();
}
// Store the NIFFile pointer for later
nif = _nif;
/// Resolve index to pointer
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
index = nif->getInt();
}
/** 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);
/// Look up the actual object from the index
X* getPtr()
{
assert(ptr != NULL);
}
return ptr;
}
return ptr;
}
X& get() { return *getPtr(); }
/// Syntactic sugar
X* operator->() { return getPtr(); }
X& get() { return *getPtr(); }
/// Syntactic sugar
X* operator->() { return getPtr(); }
/// Pointers are allowed to be empty
bool empty() { return index == -1 && ptr == NULL; }
int getIndex() { return index; }
/// Pointers are allowed to be empty
bool empty() { return ptr == NULL; }
};
/** A list of references to other records. These are read as a list,
@ -101,40 +91,38 @@ class RecordPtrT
template <class X>
class RecordListT
{
typedef RecordPtrT<X> Ptr;
std::vector<Ptr> list;
typedef RecordPtrT<X> Ptr;
std::vector<Ptr> list;
public:
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)
public:
void read(NIFFile *nif)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return list[index].get();
int len = nif->getInt();
list.resize(len);
for(size_t i=0;i < list.size();i++)
list[i].read(nif);
}
bool has(int index)
{
assert(index >= 0 && index < static_cast<int> (list.size()));
return !list[index].empty();
}
int getIndex(int index)
void post(NIFFile *nif)
{
if(has(index)) return list[index].getIndex();
else return -1;
for(size_t i=0;i < list.size();i++)
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(); }
};