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:
parent
efb95e2f83
commit
046e9686f9
@ -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
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user