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.
actorid
Chris Robinson 13 years ago
parent efb95e2f83
commit 046e9686f9

@ -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;
void read(NIFFile *nif)
{
Extra::read(nif);
controller.read(nif);
}
ControllerPtr controller;
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;
void read(NIFFile *nif)
{
Controlled::read(nif);
data.read(nif);
}
NiColorDataPtr data;
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);
/*
byte (0 or 1)
float (1)
float*3
*/
nif->skip(17);
}
void read(NIFFile *nif)
{
Controlled::read(nif);
/*
byte (0 or 1)
float (1)
float*3
*/
nif->skip(17);
}
};
} // Namespace

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

@ -35,57 +35,62 @@ typedef Node Effect;
// NiPointLight and NiSpotLight?
struct NiLight : Effect
{
struct SLight
{
float dimmer;
Vector ambient;
Vector diffuse;
Vector specular;
};
const SLight *light;
void read(NIFFile *nif)
{
Effect::read(nif);
nif->getInt(); // 1
nif->getInt(); // 1?
light = nif->getPtr<SLight>();
}
struct SLight
{
float dimmer;
Vector ambient;
Vector diffuse;
Vector specular;
};
const SLight *light;
void read(NIFFile *nif)
{
Effect::read(nif);
nif->getInt(); // 1
nif->getInt(); // 1?
light = nif->getPtr<SLight>();
}
};
struct NiTextureEffect : Effect
{
NiSourceTexturePtr texture;
void read(NIFFile *nif)
{
Effect::read(nif);
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);
texture.read(nif);
/*
byte = 0
vector4 = [1,0,0,0]
short = 0
short = -75
short = 0
*/
nif->skip(23);
}
NiSourceTexturePtr texture;
void read(NIFFile *nif)
{
Effect::read(nif);
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);
texture.read(nif);
/*
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

@ -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;
};
std::vector<TextKey> list;
void read(NIFFile *nif)
{
Extra::read(nif);
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();
}
}
struct TextKey
{
float time;
Misc::SString text;
};
std::vector<TextKey> list;
void read(NIFFile *nif)
{
Extra::read(nif);
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();
}
}
};
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;
void read(NIFFile *nif)
{
Extra::read(nif);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
/* 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);
nif->getInt(); // size of string + 4. Really useful...
string = nif->getString();
}
};
} // Namespace

@ -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++)
{
if(!bones.has(i))
nif->fail("Oops: Missing bone! Don't know how to handle this.");
size_t bnum = bones.length();
if(bnum != data->bones.size())
nif->fail("Mismatch in NiSkinData bone count");
root->makeRootBone(data->trafo);
bones[i].makeBone(i, data->bones[i]);
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]);
}
}

@ -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.
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();
/* 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));
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;
}
/// Number of records
int numRecords() { return records.size(); }
/// 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(); }
/*************************************************
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); }
};

@ -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;
// Bounding box info
bool hasBounds;
const Vector *boundPos;
const Matrix *boundRot;
const Vector *boundXYZ; // Box size
void read(NIFFile *nif)
{
Named::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();
}
boneTrafo = NULL;
boneIndex = -1;
}
// Bone transformation. If set, node is a part of a skeleton.
const NiSkinData::BoneTrafo *boneTrafo;
// Bone weight info, from NiSkinData
const NiSkinData::BoneInfo *boneInfo;
// 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 makeRootBone(const NiSkinData::BoneTrafo *tr)
{
boneTrafo = tr;
boneIndex = -1;
}
void makeBone(short ind, const NiSkinData::BoneInfo &bi)
{
boneInfo = &bi;
boneTrafo = bi.trafo;
boneIndex = ind;
}
// 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
void read(NIFFile *nif)
{
Named::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();
}
boneTrafo = NULL;
boneIndex = -1;
}
void post(NIFFile *nif)
{
Named::post(nif);
props.post(nif);
}
// Bone transformation. If set, node is a part of a skeleton.
const NiSkinData::BoneTrafo *boneTrafo;
// Bone weight info, from NiSkinData
const NiSkinData::BoneInfo *boneInfo;
// 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 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;
/* Known NiNode flags:
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);
}
NodeList children;
NodeList effects;
/* Known NiNode flags:
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 post(NIFFile *nif)
{
Node::post(nif);
children.post(nif);
effects.post(nif);
}
};
struct NiTriShape : 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.
*/
NiTriShapeDataPtr data;
NiSkinInstancePtr skin;
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)));
if(ptrNormals){
float *currentNormals = (float*) (ptrNormals + i * 3);
copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2)));
}
}
return copy;
}
/* Possible flags:
0x40 - mesh has no vertex normals ?
Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have
been observed so far.
*/
NiTriShapeDataPtr data;
NiSkinInstancePtr skin;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
skin.read(nif);
}
void post(NIFFile *nif)
{
Node::post(nif);
data.post(nif);
skin.post(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)));
if(ptrNormals)
{
float *currentNormals = (float*) (ptrNormals + i * 3);
copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2)));
}
}
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;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
NiAutoNormalParticlesDataPtr data;
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;
void read(NIFFile *nif)
{
Node::read(nif);
data.read(nif);
nif->getInt(); // -1
}
NiRotatingParticlesDataPtr data;
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

@ -32,104 +32,116 @@ namespace Nif
class Property : public Named
{
public:
// The meaning of these depends on the actual property type.
int flags;
void read(NIFFile *nif)
{
Named::read(nif);
flags = nif->getShort();
}
// The meaning of these depends on the actual property type.
int flags;
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
*/
/* Filter:
0 - nearest
1 - bilinear
2 - trilinear
3, 4, 5 - who knows
// 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;
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
*/
bool inUse;
NiSourceTexturePtr texture;
int clamp, set, filter;
short unknown2;
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;
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);
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);
}
};
/* 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
}
};
// 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
Lighting mode
0 - lighting emmisive
1 - lighting emmisive ambient/diffuse
*/
int vertmode, lightmode;
/* 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;
};
struct S_AlphaProperty
{
/*
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 )
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
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.
*/
// Tested against when certain flags are set (see above.)
unsigned char threshold;
/*
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 )
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
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.
*/
// Tested against when certain flags are set (see above.)
unsigned char threshold;
};
typedef StructPropT<S_AlphaProperty> NiAlphaProperty;

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

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

Loading…
Cancel
Save