mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 17:56:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			205 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
	
		
			12 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();
 | |
| 
 | |
| /// Get the file's version in a human readable form
 | |
| std::string NIFFile::printVersion(unsigned int version)
 | |
| {
 | |
|     union ver_quad
 | |
|     {
 | |
|         uint32_t full;
 | |
|         uint8_t quad[4];
 | |
|     } version_out;
 | |
| 
 | |
|     version_out.full = version;
 | |
| 
 | |
|     return Ogre::StringConverter::toString(version_out.quad[3])
 | |
|     +"." + Ogre::StringConverter::toString(version_out.quad[2])
 | |
|     +"." + Ogre::StringConverter::toString(version_out.quad[1])
 | |
|     +"." + Ogre::StringConverter::toString(version_out.quad[0]);
 | |
| }
 | |
| 
 | |
| 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.getUInt();
 | |
|   if(ver != VER_MW)
 | |
|     fail("Unsupported NIF version: " + printVersion(ver));
 | |
|   // 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);
 | |
| }
 | |
| 
 | |
| }
 |