You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
11 KiB
C++
190 lines
11 KiB
C++
#include "niffile.hpp"
|
|
#include "effect.hpp"
|
|
|
|
#include <map>
|
|
|
|
#include <OgreResourceGroupManager.h>
|
|
|
|
namespace Nif
|
|
{
|
|
|
|
/// Open a NIF stream. The name is used for error messages.
|
|
NIFFile::NIFFile(const std::string &name)
|
|
: ver(0)
|
|
, filename(name)
|
|
{
|
|
parse();
|
|
}
|
|
|
|
NIFFile::~NIFFile()
|
|
{
|
|
for (std::vector<Record*>::iterator it = records.begin() ; it != records.end(); ++it)
|
|
{
|
|
delete *it;
|
|
}
|
|
}
|
|
|
|
template <typename NodeType> static Record* construct() { return new NodeType; }
|
|
|
|
struct RecordFactoryEntry {
|
|
|
|
typedef Record* (*create_t) ();
|
|
|
|
create_t mCreate;
|
|
RecordType mType;
|
|
|
|
};
|
|
|
|
///Helper function for adding records to the factory map
|
|
static std::pair<std::string,RecordFactoryEntry> makeEntry(std::string recName, Record* (*create_t) (), RecordType type)
|
|
{
|
|
RecordFactoryEntry anEntry = {create_t,type};
|
|
return std::make_pair(recName, anEntry);
|
|
}
|
|
|
|
///These are all the record types we know how to read.
|
|
static std::map<std::string,RecordFactoryEntry> makeFactory()
|
|
{
|
|
std::map<std::string,RecordFactoryEntry> newFactory;
|
|
newFactory.insert(makeEntry("NiNode", &construct <NiNode> , RC_NiNode ));
|
|
newFactory.insert(makeEntry("AvoidNode", &construct <NiNode> , RC_AvoidNode ));
|
|
newFactory.insert(makeEntry("NiBSParticleNode", &construct <NiNode> , RC_NiBSParticleNode ));
|
|
newFactory.insert(makeEntry("NiBSAnimationNode", &construct <NiNode> , RC_NiBSAnimationNode ));
|
|
newFactory.insert(makeEntry("NiBillboardNode", &construct <NiNode> , RC_NiBillboardNode ));
|
|
newFactory.insert(makeEntry("NiTriShape", &construct <NiTriShape> , RC_NiTriShape ));
|
|
newFactory.insert(makeEntry("NiRotatingParticles", &construct <NiRotatingParticles> , RC_NiRotatingParticles ));
|
|
newFactory.insert(makeEntry("NiAutoNormalParticles", &construct <NiAutoNormalParticles> , RC_NiAutoNormalParticles ));
|
|
newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera ));
|
|
newFactory.insert(makeEntry("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode ));
|
|
newFactory.insert(makeEntry("NiTexturingProperty", &construct <NiTexturingProperty> , RC_NiTexturingProperty ));
|
|
newFactory.insert(makeEntry("NiMaterialProperty", &construct <NiMaterialProperty> , RC_NiMaterialProperty ));
|
|
newFactory.insert(makeEntry("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty ));
|
|
newFactory.insert(makeEntry("NiAlphaProperty", &construct <NiAlphaProperty> , RC_NiAlphaProperty ));
|
|
newFactory.insert(makeEntry("NiVertexColorProperty", &construct <NiVertexColorProperty> , RC_NiVertexColorProperty ));
|
|
newFactory.insert(makeEntry("NiShadeProperty", &construct <NiShadeProperty> , RC_NiShadeProperty ));
|
|
newFactory.insert(makeEntry("NiDitherProperty", &construct <NiDitherProperty> , RC_NiDitherProperty ));
|
|
newFactory.insert(makeEntry("NiWireframeProperty", &construct <NiWireframeProperty> , RC_NiWireframeProperty ));
|
|
newFactory.insert(makeEntry("NiSpecularProperty", &construct <NiSpecularProperty> , RC_NiSpecularProperty ));
|
|
newFactory.insert(makeEntry("NiStencilProperty", &construct <NiStencilProperty> , RC_NiStencilProperty ));
|
|
newFactory.insert(makeEntry("NiVisController", &construct <NiVisController> , RC_NiVisController ));
|
|
newFactory.insert(makeEntry("NiGeomMorpherController", &construct <NiGeomMorpherController> , RC_NiGeomMorpherController ));
|
|
newFactory.insert(makeEntry("NiKeyframeController", &construct <NiKeyframeController> , RC_NiKeyframeController ));
|
|
newFactory.insert(makeEntry("NiAlphaController", &construct <NiAlphaController> , RC_NiAlphaController ));
|
|
newFactory.insert(makeEntry("NiUVController", &construct <NiUVController> , RC_NiUVController ));
|
|
newFactory.insert(makeEntry("NiPathController", &construct <NiPathController> , RC_NiPathController ));
|
|
newFactory.insert(makeEntry("NiMaterialColorController", &construct <NiMaterialColorController> , RC_NiMaterialColorController ));
|
|
newFactory.insert(makeEntry("NiBSPArrayController", &construct <NiBSPArrayController> , RC_NiBSPArrayController ));
|
|
newFactory.insert(makeEntry("NiParticleSystemController", &construct <NiParticleSystemController> , RC_NiParticleSystemController ));
|
|
newFactory.insert(makeEntry("NiFlipController", &construct <NiFlipController> , RC_NiFlipController ));
|
|
newFactory.insert(makeEntry("NiAmbientLight", &construct <NiLight> , RC_NiLight ));
|
|
newFactory.insert(makeEntry("NiDirectionalLight", &construct <NiLight> , RC_NiLight ));
|
|
newFactory.insert(makeEntry("NiTextureEffect", &construct <NiTextureEffect> , RC_NiTextureEffect ));
|
|
newFactory.insert(makeEntry("NiVertWeightsExtraData", &construct <NiVertWeightsExtraData> , RC_NiVertWeightsExtraData ));
|
|
newFactory.insert(makeEntry("NiTextKeyExtraData", &construct <NiTextKeyExtraData> , RC_NiTextKeyExtraData ));
|
|
newFactory.insert(makeEntry("NiStringExtraData", &construct <NiStringExtraData> , RC_NiStringExtraData ));
|
|
newFactory.insert(makeEntry("NiGravity", &construct <NiGravity> , RC_NiGravity ));
|
|
newFactory.insert(makeEntry("NiPlanarCollider", &construct <NiPlanarCollider> , RC_NiPlanarCollider ));
|
|
newFactory.insert(makeEntry("NiParticleGrowFade", &construct <NiParticleGrowFade> , RC_NiParticleGrowFade ));
|
|
newFactory.insert(makeEntry("NiParticleColorModifier", &construct <NiParticleColorModifier> , RC_NiParticleColorModifier ));
|
|
newFactory.insert(makeEntry("NiParticleRotation", &construct <NiParticleRotation> , RC_NiParticleRotation ));
|
|
newFactory.insert(makeEntry("NiFloatData", &construct <NiFloatData> , RC_NiFloatData ));
|
|
newFactory.insert(makeEntry("NiTriShapeData", &construct <NiTriShapeData> , RC_NiTriShapeData ));
|
|
newFactory.insert(makeEntry("NiVisData", &construct <NiVisData> , RC_NiVisData ));
|
|
newFactory.insert(makeEntry("NiColorData", &construct <NiColorData> , RC_NiColorData ));
|
|
newFactory.insert(makeEntry("NiPixelData", &construct <NiPixelData> , RC_NiPixelData ));
|
|
newFactory.insert(makeEntry("NiMorphData", &construct <NiMorphData> , RC_NiMorphData ));
|
|
newFactory.insert(makeEntry("NiKeyframeData", &construct <NiKeyframeData> , RC_NiKeyframeData ));
|
|
newFactory.insert(makeEntry("NiSkinData", &construct <NiSkinData> , RC_NiSkinData ));
|
|
newFactory.insert(makeEntry("NiUVData", &construct <NiUVData> , RC_NiUVData ));
|
|
newFactory.insert(makeEntry("NiPosData", &construct <NiPosData> , RC_NiPosData ));
|
|
newFactory.insert(makeEntry("NiRotatingParticlesData", &construct <NiRotatingParticlesData> , RC_NiRotatingParticlesData ));
|
|
newFactory.insert(makeEntry("NiAutoNormalParticlesData", &construct <NiAutoNormalParticlesData> , RC_NiAutoNormalParticlesData ));
|
|
newFactory.insert(makeEntry("NiSequenceStreamHelper", &construct <NiSequenceStreamHelper> , RC_NiSequenceStreamHelper ));
|
|
newFactory.insert(makeEntry("NiSourceTexture", &construct <NiSourceTexture> , RC_NiSourceTexture ));
|
|
newFactory.insert(makeEntry("NiSkinInstance", &construct <NiSkinInstance> , RC_NiSkinInstance ));
|
|
return newFactory;
|
|
}
|
|
|
|
|
|
///Make the factory map used for parsing the file
|
|
static const std::map<std::string,RecordFactoryEntry> factories = makeFactory();
|
|
|
|
void NIFFile::parse()
|
|
{
|
|
NIFStream nif (this, Ogre::ResourceGroupManager::getSingleton().openResource(filename));
|
|
|
|
// Check the header string
|
|
std::string head = nif.getString(40);
|
|
if(head.compare(0, 22, "NetImmerse File Format") != 0)
|
|
fail("Invalid NIF header");
|
|
|
|
// Get BCD version
|
|
ver = nif.getInt();
|
|
if(ver != VER_MW)
|
|
fail("Unsupported NIF version");
|
|
|
|
// Number of records
|
|
size_t recNum = nif.getInt();
|
|
records.resize(recNum);
|
|
|
|
/* The format for 10.0.1.0 seems to be a bit different. After the
|
|
header, it contains the number of records, r (int), just like
|
|
4.0.0.2, but following that it contains a short x, followed by x
|
|
strings. Then again by r shorts, one for each record, giving
|
|
which of the above strings to use to identify the record. After
|
|
this follows two ints (zero?) and then the record data. However
|
|
we do not support or plan to support other versions yet.
|
|
*/
|
|
|
|
for(size_t i = 0;i < recNum;i++)
|
|
{
|
|
Record *r = NULL;
|
|
|
|
std::string rec = nif.getString();
|
|
if(rec.empty())
|
|
fail("Record number " + Ogre::StringConverter::toString(i) + " out of " + Ogre::StringConverter::toString(recNum) + " is blank.");
|
|
|
|
|
|
std::map<std::string,RecordFactoryEntry>::const_iterator entry = factories.find(rec);
|
|
|
|
if (entry != factories.end())
|
|
{
|
|
r = entry->second.mCreate ();
|
|
r->recType = entry->second.mType;
|
|
}
|
|
else
|
|
fail("Unknown record type " + rec);
|
|
|
|
assert(r != NULL);
|
|
assert(r->recType != RC_MISSING);
|
|
r->recName = rec;
|
|
r->recIndex = i;
|
|
records[i] = r;
|
|
r->read(&nif);
|
|
}
|
|
|
|
size_t rootNum = nif.getUInt();
|
|
roots.resize(rootNum);
|
|
|
|
//Determine which records are roots
|
|
for(size_t i = 0;i < rootNum;i++)
|
|
{
|
|
int idx = nif.getInt();
|
|
if (idx >= 0)
|
|
{
|
|
roots[i] = records.at(idx);
|
|
}
|
|
else
|
|
{
|
|
roots[i] = NULL;
|
|
warn("Null Root found");
|
|
}
|
|
}
|
|
|
|
// Once parsing is done, do post-processing.
|
|
for(size_t i=0; i<recNum; i++)
|
|
records[i]->post(this);
|
|
}
|
|
|
|
}
|