From ba3074ad79b1146c7effcb13449ce6741c28800c Mon Sep 17 00:00:00 2001 From: Shon Ferguson <shonferg@users.sourceforge.net> Date: Sat, 12 Nov 2005 21:06:48 +0000 Subject: [PATCH] =?UTF-8?q?Finished=20basic=20version=20support=20?= =?UTF-8?q?=EF=BF=BD=20still=20need=20to=20implement=20new=20block=20readi?= =?UTF-8?q?ng=20scheme=20for=20version=205=20and=20up.=20Updated=20all=20b?= =?UTF-8?q?asic=20blocks=20with=20correctly=20versioned=20attributes=20fro?= =?UTF-8?q?m=20DocSys=20database.=20Updated=20all=20data=20blocks=20except?= =?UTF-8?q?=20for=20NiSkinPartition=20and=20NiControllerSequence=20to=20re?= =?UTF-8?q?act=20correctly=20to=20known=20version=20differences=20up=20to?= =?UTF-8?q?=2010.1.0.0.=20All=20blocks=20but=20the=20above=20now=20have=20?= =?UTF-8?q?both=20a=20Read=20and=20a=20Write=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NIF_Blocks.cpp | 1136 ++++++++++++++++++++++++------------ NIF_Blocks.h | 1506 ++++++++++++++++++++++++------------------------ NIF_IO.cpp | 20 + NIF_IO.h | 6 +- nif_attrs.h | 194 ++++--- niflib.cpp | 58 +- niflib.h | 43 +- 7 files changed, 1740 insertions(+), 1223 deletions(-) diff --git a/NIF_Blocks.cpp b/NIF_Blocks.cpp index 0877874e..1852a05f 100644 --- a/NIF_Blocks.cpp +++ b/NIF_Blocks.cpp @@ -48,7 +48,7 @@ extern string current_file; * ABlock methods **********************************************************/ -ABlock::ABlock() : _ref_count(0), _block_num(-1) { +ABlock::ABlock() : _ref_count(0), _block_num(-1), _namable(false), _first_named_ver(0) { //Temporary to test reference counting blocks_in_memory++; } @@ -67,55 +67,55 @@ ABlock::~ABlock() { void ABlock::AddAttr( string type, string name, unsigned int first_ver, unsigned int last_ver ) { IAttr * attr; if ( type == "int" ) { - attr = new IntAttr( name, this ); + attr = new IntAttr( name, this, first_ver, last_ver ); } else if ( type == "short" ) { - attr = new ShortAttr( name, this ); + attr = new ShortAttr( name, this, first_ver, last_ver ); } else if ( type == "byte" ) { - attr = new ByteAttr( name, this ); + attr = new ByteAttr( name, this, first_ver, last_ver ); } else if ( type == "float" ) { - attr = new FloatAttr( name, this ); + attr = new FloatAttr( name, this, first_ver, last_ver ); } else if ( type == "float3" ) { - attr = new Float3Attr( name, this ); + attr = new Float3Attr( name, this, first_ver, last_ver ); } else if ( type == "string" ) { - attr = new StringAttr( name, this ); + attr = new StringAttr( name, this, first_ver, last_ver ); } else if ( type == "link" ) { - attr = new LinkAttr( name, this ); + attr = new LinkAttr( name, this, first_ver, last_ver ); } else if ( type == "flags" ) { - attr = new FlagsAttr( name, this ); + attr = new FlagsAttr( name, this, first_ver, last_ver ); } else if ( type == "matrix33" ) { - attr = new MatrixAttr( name, this ); + attr = new MatrixAttr( name, this, first_ver, last_ver ); } else if ( type == "linkgroup" ) { - attr = new LinkGroupAttr( name, this ); + attr = new LinkGroupAttr( name, this, first_ver, last_ver ); } else if ( type == "bones" ) { - attr = new BoneAttr( name, this ); + attr = new BoneAttr( name, this, first_ver, last_ver ); } else if ( type == "bbox" ) { - attr = new BBoxAttr( name, this ); + attr = new BBoxAttr( name, this, first_ver, last_ver ); } else if ( type == "condint" ) { - attr = new CIntAttr( name, this ); + attr = new CIntAttr( name, this, first_ver, last_ver ); } else if ( type == "vertmode" ) { - attr = new VertModeAttr( name, this ); + attr = new VertModeAttr( name, this, first_ver, last_ver ); } else if ( type == "lightmode" ) { - attr = new LightModeAttr( name, this ); + attr = new LightModeAttr( name, this, first_ver, last_ver ); } else if ( type == "texture" ) { - attr = new TextureAttr( name, this ); + attr = new TextureAttr( name, this, first_ver, last_ver, false ); } else if ( type == "bumpmap" ) { - attr = new TextureAttr( name, this, true ); + attr = new TextureAttr( name, this, first_ver, last_ver, true ); } else if ( type == "applymode" ) { - attr = new ApplyModeAttr( name, this ); + attr = new ApplyModeAttr( name, this, first_ver, last_ver ); } else if ( type == "texsource" ) { - attr = new TexSourceAttr( name, this ); + attr = new TexSourceAttr( name, this, first_ver, last_ver ); } else if ( type == "pixellayout" ) { - attr = new PixelLayoutAttr( name, this ); + attr = new PixelLayoutAttr( name, this, first_ver, last_ver ); } else if ( type == "mipmapformat" ) { - attr = new MipMapFormatAttr( name, this ); + attr = new MipMapFormatAttr( name, this, first_ver, last_ver ); } else if ( type == "alphaformat" ) { - attr = new AlphaFormatAttr( name, this ); + attr = new AlphaFormatAttr( name, this, first_ver, last_ver ); } else if ( type == "nodeancestor" ) { - attr = new NodeAncestorAttr( name, this ); + attr = new NodeAncestorAttr( name, this, first_ver, last_ver ); } else if ( type == "skeletonroot" ) { - attr = new SkeletonRootAttr( name, this ); + attr = new SkeletonRootAttr( name, this, first_ver, last_ver ); } else if ( type == "particlegroup" ) { - attr = new ParticleGroupAttr( name, this ); + attr = new ParticleGroupAttr( name, this, first_ver, last_ver ); } else { cout << type << endl; throw runtime_error("Unknown attribute type requested."); @@ -123,7 +123,6 @@ void ABlock::AddAttr( string type, string name, unsigned int first_ver, unsigned _attr_map[name] = attr_ref(attr); _attr_vect.push_back(attr_ref(attr)); - _attr_vers.push_back( pair<unsigned int, unsigned int>(first_ver, last_ver) ); } attr_ref ABlock::GetAttr(string attr_name) { @@ -150,44 +149,52 @@ blk_ref ABlock::GetParent() { } void ABlock::Read( ifstream& in, unsigned int version ) { + //Read Name if there is one + if ( _namable == true && version >= _first_named_ver ) { + _name = ReadString( in ); + } + + //Read Attributes for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { - if ( version >= _attr_vers[i].first && version <= _attr_vers[i].second ) { - _attr_vect[i]->Read( in ); - //cout << " " << _attr_vect[i]->GetName() << ": " << _attr_vect[i]->asString() << endl; - } + _attr_vect[i]->Read( in, version ); + //cout << " " << _attr_vect[i]->GetName() << ": " << _attr_vect[i]->asString() << endl; } } void ABlock::Write( ofstream& out, unsigned int version ) { + //Write Name if there is one + if ( _namable == true && version >= _first_named_ver ) { + WriteString( _name, out ); + } + //Write Attributes for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { //cout << "Writing " << blk_ref(this) << " " << _attr_vect[i]->GetName() << endl; - _attr_vect[i]->Write( out ); + _attr_vect[i]->Write( out, version ); } } string ABlock::asString() { + // Create a stringstream and set the floating point format + // fixed notation with one decimal place stringstream out; out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out.setf(ios::fixed, ios::floatfield); - out << setprecision(1); - + //Output the first parent of this block out << "Parent: " << GetParent() << endl; + + //Output the name if there is one + if ( _namable == true ) { + out << "Name: " << _name << endl; + } + + //Output Attributes for (unsigned int i = 0; i < _attr_vect.size(); ++i ) { out << _attr_vect[i]->GetName() << ": " << _attr_vect[i]->asString() << endl; } - //if ( _parents.size() > 1 ) { - // cout << endl << "Parents:"; - // for (unsigned int i = 0; i < _parents.size(); ++i ) { - // cout << " " << _parents[i]->GetBlockType(); - // } - // cout << endl << "Node: " << GetBlockType() << "\a"; - // cin.get(); - //} - + //Return result as a string return out.str(); } @@ -548,16 +555,16 @@ string NiNode::asString() { } /*********************************************************** - * NiTriShapeData methods + * AShapeData methods **********************************************************/ /** - * NiTriShapeData::Read - Assumes block name has already been read from in + * AShapeData::Read - Assumes block name has already been read from in */ -void NiTriShapeData::Read( ifstream& in, unsigned int version ){ +void AShapeData::Read( ifstream& in, unsigned int version ){ short vert_count = ReadUShort( in ); - int hasVertices = ReadUInt( in ); + bool hasVertices = ReadBool( in, version );; if ( hasVertices != 0 ){ vertices.resize( vert_count ); for ( uint i = 0; i < vertices.size(); ++i ){ @@ -567,7 +574,13 @@ void NiTriShapeData::Read( ifstream& in, unsigned int version ){ } } - int hasNormals = ReadUInt( in ); + /// numTexSets up here up after from version 10.0.1.0 on + short numTexSets; + if ( version >= 0x0A000100 ) { + numTexSets = ReadUShort( in ); + } + + bool hasNormals = ReadBool( in, version );; if ( hasNormals != 0 ){ normals.resize( vert_count ); for ( uint i = 0; i < normals.size(); ++i ){ @@ -577,10 +590,10 @@ void NiTriShapeData::Read( ifstream& in, unsigned int version ){ } } - GetAttr("Center")->Read( in ); - GetAttr("Radius")->Read( in ); + GetAttr("Center")->Read( in, version ); + GetAttr("Radius")->Read( in, version ); - int hasVertexColors = ReadUInt( in ); + bool hasVertexColors = ReadBool( in, version );; if ( hasVertexColors != 0 ){ colors.resize( vert_count ); for ( uint i = 0; i < colors.size(); ++i ){ @@ -590,9 +603,15 @@ void NiTriShapeData::Read( ifstream& in, unsigned int version ){ colors[i].a = ReadFloat( in ); } } - - short numTexSets = ReadUShort( in ); - int hasUVs = ReadUInt( in ); + // numTexSets down here up to version 4.2.2.0 + if ( version <= 0x04020200 ) { + numTexSets = ReadUShort( in ); + } + // hasUVs does not exist after version 4.0.0.2 + bool hasUVs = true; + if ( version <= 0x04000002 ) { + hasUVs = ReadBool( in, version ); + } if ( numTexSets > 0 && hasUVs != 0 ){ uv_sets.resize( numTexSets ); //UVs = new fVector2[numVertices * numTexSets]; @@ -605,30 +624,14 @@ void NiTriShapeData::Read( ifstream& in, unsigned int version ){ } } - short numTriangles = ReadUShort( in ); - if (numTriangles > 0) { - int numVertexIndices = ReadUInt( in ); - triangles.resize( numTriangles ); - for ( int i = 0; i < numTriangles; ++i ){ - triangles[i].v1 = ReadUShort( in ); - triangles[i].v2 = ReadUShort( in ); - triangles[i].v3 = ReadUShort( in ); - } - } - - short matchGroupCount = ReadUShort( in ); - match_group_mode = ( matchGroupCount != 0 ); // Only record whether or not file prefers to have match data generated - - short sub_count; - for ( int i = 0; i < matchGroupCount; ++i ){ - sub_count = ReadUShort( in ); - for (ushort j = 0; j < sub_count; ++j) { - ReadUShort( in ); // Read data, but don't care what it is - } + // Unknown Short here from version 10.0.1.0 on + // Just read it and throw it away for now + if ( version >= 0x0A000100 ) { + ReadUShort( in ); } } -string NiTriShapeData::asString() { +string AShapeData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); out << setprecision(1); @@ -706,41 +709,20 @@ string NiTriShapeData::asString() { } out << endl; - out << "Triangles: " << uint(triangles.size()); - if (verbose) { - for ( uint i = 0; i < triangles.size(); ++i) { - if (i % 3 == 0) - out << endl << " "; - else - out << " "; - - out << "(" << setw(5) << triangles[i].v1 << ", " << setw(5) << triangles[i].v2 << ", " << setw(5) << triangles[i].v3 << " )"; - } - } else { - out << endl << "<<Data Not Shown>>"; - } - out << endl; - - out << "Match Detection: "; - if ( match_group_mode ) - out << "On" << endl; - else - out << "Off" << endl; - return out.str(); } /** - * NiTriShapeData::Write - Writes block name to out, in addition to data. + * AShapeData::Write */ -void NiTriShapeData::Write( ofstream& out, unsigned int version ){ +void AShapeData::Write( ofstream& out, unsigned int version ){ WriteUShort( short(vertices.size()), out ); if ( vertices.size() > 0 ) - WriteUInt( 1, out ); + WriteBool( true, out, version ); else - WriteUInt( 0, out ); + WriteBool( false, out, version ); for ( uint i = 0; i < vertices.size(); ++i ){ WriteFloat( vertices[i].x, out ); @@ -749,9 +731,9 @@ void NiTriShapeData::Write( ofstream& out, unsigned int version ){ } if ( normals.size() > 0 ) - WriteUInt( 1, out ); + WriteBool( true, out, version ); else - WriteUInt( 0, out ); + WriteBool( false, out, version ); for ( uint i = 0; i < normals.size(); ++i) { WriteFloat( normals[i].x, out ); @@ -759,13 +741,13 @@ void NiTriShapeData::Write( ofstream& out, unsigned int version ){ WriteFloat( normals[i].z, out ); } - GetAttr("Center")->Write( out ); - GetAttr("Radius")->Write( out ); + GetAttr("Center")->Write( out, version ); + GetAttr("Radius")->Write( out, version ); if ( colors.size() > 0 ) - WriteUInt( 1, out ); + WriteBool( true, out, version ); else - WriteUInt( 0, out ); + WriteBool( false, out, version ); for ( uint i = 0; i < colors.size(); ++i ){ WriteFloat( colors[i].r, out ); @@ -776,9 +758,9 @@ void NiTriShapeData::Write( ofstream& out, unsigned int version ){ WriteUShort( ushort(uv_sets.size()), out ); if ( uv_sets.size() > 0 && uv_sets[0].size() > 0 ) // hasUVs - WriteUInt( 1, out ); + WriteBool( true, out, version ); else - WriteUInt( 0, out ); + WriteBool( false, out, version ); for ( uint i = 0; i < uv_sets.size(); ++i) { for ( uint j = 0; j < uv_sets[i].size(); ++j) { @@ -786,6 +768,296 @@ void NiTriShapeData::Write( ofstream& out, unsigned int version ){ WriteFloat( uv_sets[i][j].v, out ); } } +} + +void * AShapeData::QueryInterface( int id ) { + // Contains ShapeData Interface + if ( id == ID_SHAPE_DATA ) { + return (void*)static_cast<IShapeData*>(this); + } else { + return AData::QueryInterface( id ); + } +} + +void AShapeData::SetVertexCount(int n) { + vertices.resize(n); + normals.resize(n); + colors.resize(n); + for (uint i = 0; i < uv_sets.size(); ++i) { + uv_sets[i].resize(n); + } +} + +void AShapeData::SetUVSetCount(int n) { + uv_sets.resize(n); +} + +//--Setters--// +void AShapeData::SetVertices( const vector<Vector3> & in ) { + if (in.size() != vertices.size()) + throw runtime_error("Input array size must equal Vertex Count. Call SetVertexCount() to resize."); + vertices = in; +} + +void AShapeData::SetNormals( const vector<Vector3> & in ) { + if (in.size() != vertices.size()) + throw runtime_error("Input array size must equal Vertex Count. Call SetVertexCount() to resize."); + normals = in; +} + +void AShapeData::SetColors( const vector<Color> & in ) { + if (in.size() != vertices.size()) + throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); + colors = in; +} + +void AShapeData::SetUVSet( int index, const vector<UVCoord> & in ) { + if (in.size() != vertices.size()) + throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); + uv_sets[index] = in; +} + +/*********************************************************** + * AParticlesData methods + **********************************************************/ + +void AParticlesData::Read( ifstream& in, unsigned int version ) { + AShapeData::Read( in, version ); + + //numActive exists up to version 4.0.0.2 + if ( version <= 0x04000002 ) { + numActive = ReadUShort( in ); + } + + GetAttr("Active Radius")->Read( in, version ); + + //numValid exists up to version 4.0.0.2 + if ( version <= 0x04000002 ) { + numValid = ReadUShort( in ); + } + + GetAttr("Unknown Short")->Read( in, version ); + + hasSizes = ReadBool( in, version ); + + if ( hasSizes ) { + sizes.resize( vertices.size() ); + for ( uint i = 0; i < sizes.size(); ++i ) { + sizes[i] = ReadFloat( in ); + } + } +} + +void AParticlesData::Write( ofstream& out, unsigned int version ) { + AShapeData::Write( out, version ); + + //numActive exists up to version 4.0.0.2 + if ( version <= 0x04000002 ) { + WriteUShort( numActive, out ); + } + + GetAttr("Active Radius")->Write( out, version ); + + //numValid exists up to version 4.0.0.2 + if ( version <= 0x04000002 ) { + WriteUShort( numValid, out ); + } + + + GetAttr("Unknown Short")->Write( out, version ); + + WriteBool( hasSizes, out, version ); + + if ( hasSizes ) { + for ( uint i = 0; i < sizes.size(); ++i ) { + WriteFloat( sizes[i], out ); + } + } +} + +string AParticlesData::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + out << AShapeData::asString(); + + out << "Num Active: " << numActive << endl + << "Active Radius: " << GetAttr("Active Radius")->asFloat() << endl + << "Num Valid: " << numValid << endl + << "Unknown Short: " << GetAttr("Unknown Short")->asInt() << endl + << "Sizes: "; + + if ( hasSizes ) { + if (verbose) { + for ( uint i = 0; i < sizes.size(); ++i) { + out << i << ": " << sizes[i] << endl; + } + } else { + out << endl << "<<Data Not Shown>>"; + } + } else { + out << "None" << endl; + } + + return out.str(); +} + +/*********************************************************** + * ARotatingParticlesData methods + **********************************************************/ + +void ARotatingParticlesData::Read( ifstream& in, unsigned int version ) { + AParticlesData::Read( in, version ); + + hasRotations = ReadBool( in, version ); + + if ( hasRotations ) { + rotations.resize( vertices.size() ); + for ( uint i = 0; i < rotations.size(); ++i ) { + rotations[i].w = ReadFloat( in ); + rotations[i].x = ReadFloat( in ); + rotations[i].y = ReadFloat( in ); + rotations[i].z = ReadFloat( in ); + } + } +} + +void ARotatingParticlesData::Write( ofstream& out, unsigned int version ) { + AParticlesData::Write( out, version ); + + WriteBool( hasRotations, out, version ); + + if ( hasRotations ) { + for ( uint i = 0; i < rotations.size(); ++i ) { + WriteFloat( rotations[i].w, out ); + WriteFloat( rotations[i].x, out ); + WriteFloat( rotations[i].y, out ); + WriteFloat( rotations[i].z, out ); + } + } +} + +string ARotatingParticlesData::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + out << AParticlesData::asString() + << "Rotations: "; + + if ( hasRotations ) { + if (verbose) { + for ( uint i = 0; i < rotations.size(); ++i) { + out << i << ": [" << rotations[i].w << " (" << rotations[i].x << ", " << rotations[i].y << ", " << rotations[1].z << ")]" << endl; + } + } else { + out << endl << "<<Data Not Shown>>"; + } + } else { + out << "None" << endl; + } + + return out.str(); +} + +/*********************************************************** + * NiParticleMeshesData methods + **********************************************************/ + +void NiParticleMeshesData::Read( ifstream& in, unsigned int version ) { + ARotatingParticlesData::Read( in, version ); + + GetAttr("Unknown Link")->Read( in, version ); +} + +void NiParticleMeshesData::Write( ofstream& out, unsigned int version ) { + ARotatingParticlesData::Write( out, version ); + + GetAttr("Unknown Link")->Write( out, version ); +} + +string NiParticleMeshesData::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + out << ARotatingParticlesData::asString() + << "Unknown Link: " << GetAttr("Unknown Link")->asString() << endl; + + return out.str(); +} + +/*********************************************************** + * NiTriShapeData methods + **********************************************************/ + +/** + * NiTriShapeData::Read - Assumes block name has already been read from in + */ +void NiTriShapeData::Read( ifstream& in, unsigned int version ){ + AShapeData::Read( in, version ); + + short numTriangles = ReadUShort( in ); + if (numTriangles > 0) { + int numVertexIndices = ReadUInt( in ); + triangles.resize( numTriangles ); + for ( int i = 0; i < numTriangles; ++i ){ + triangles[i].v1 = ReadUShort( in ); + triangles[i].v2 = ReadUShort( in ); + triangles[i].v3 = ReadUShort( in ); + } + } + + short matchGroupCount = ReadUShort( in ); + match_group_mode = ( matchGroupCount != 0 ); // Only record whether or not file prefers to have match data generated + + short sub_count; + for ( int i = 0; i < matchGroupCount; ++i ){ + sub_count = ReadUShort( in ); + for (ushort j = 0; j < sub_count; ++j) { + ReadUShort( in ); // Read data, but don't care what it is + } + } +} + +string NiTriShapeData::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + out << AShapeData::asString(); + + out << "Triangles: " << uint(triangles.size()); + if (verbose) { + for ( uint i = 0; i < triangles.size(); ++i) { + if (i % 3 == 0) + out << endl << " "; + else + out << " "; + + out << "(" << setw(5) << triangles[i].v1 << ", " << setw(5) << triangles[i].v2 << ", " << setw(5) << triangles[i].v3 << " )"; + } + } else { + out << endl << "<<Data Not Shown>>"; + } + out << endl; + + out << "Match Detection: "; + if ( match_group_mode ) + out << "On" << endl; + else + out << "Off" << endl; + + return out.str(); +} + +/** + * NiTriShapeData::Write - Writes block name to out, in addition to data. + */ +void NiTriShapeData::Write( ofstream& out, unsigned int version ){ + + AShapeData::Write( out, version ); WriteUShort( ushort(triangles.size()), out ); @@ -800,8 +1072,6 @@ void NiTriShapeData::Write( ofstream& out, unsigned int version ){ } } - - if ( match_group_mode ) { WriteUShort( ushort(vertices.size()), out ); //Match Group Count = Vertex Count @@ -832,56 +1102,105 @@ void * NiTriShapeData::QueryInterface( int id ) { if ( id == ID_TRI_SHAPE_DATA ) { return (void*)static_cast<ITriShapeData*>(this); } else { - return ABlock::QueryInterface( id ); - } -} - -void NiTriShapeData::SetVertexCount(int n) { - vertices.resize(n); - normals.resize(n); - colors.resize(n); - for (uint i = 0; i < uv_sets.size(); ++i) { - uv_sets[i].resize(n); + return AShapeData::QueryInterface( id ); } } -void NiTriShapeData::SetUVSetCount(int n) { - uv_sets.resize(n); -} - void NiTriShapeData::SetTriangleCount(int n) { triangles.resize(n); } //--Setters--// -void NiTriShapeData::SetVertices( const vector<Vector3> & in ) { - if (in.size() != vertices.size()) - throw runtime_error("Input array size must equal Vertex Count. Call SetVertexCount() to resize."); - vertices = in; -} -void NiTriShapeData::SetNormals( const vector<Vector3> & in ) { +void NiTriShapeData::SetTriangles( const vector<Triangle> & in ) { if (in.size() != vertices.size()) - throw runtime_error("Input array size must equal Vertex Count. Call SetVertexCount() to resize."); - normals = in; + throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); + triangles = in; } -void NiTriShapeData::SetColors( const vector<Color> & in ) { - if (in.size() != vertices.size()) - throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); - colors = in; +/*********************************************************** + * NiTriStripsData methods + **********************************************************/ + +void NiTriStripsData::Read( ifstream& in, unsigned int version ){ + AShapeData::Read( in, version ); + + //Read number of Triangles but discard it + ReadUShort( in ); + + //Initialize vectors to number and size of strips + short numStrips = ReadUShort( in ); + strips.resize( numStrips ); + for ( uint i = 0; i < strips.size(); ++i ) { + short stripSize = ReadUShort( in ); + strips[i].resize( stripSize ); + } + + //Read points + for ( uint i = 0; i < strips.size(); ++i ) { + for ( uint j = 0; j < strips[i].size(); ++j ) { + strips[i][j] = ReadUShort( in ); + } + } } -void NiTriShapeData::SetUVSet( int index, const vector<UVCoord> & in ) { - if (in.size() != vertices.size()) - throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); - uv_sets[index] = in; +void NiTriStripsData::Write( ofstream& out, unsigned int version ){ + + AShapeData::Write( out, version ); + + //Calculate number of triangles + //Sum of length of each strip - 2 + short numTriangles = 0; + for ( uint i = 0; i < strips.size(); ++i ) { + numTriangles += short(strips[i].size() - 2); + } + + //Write number of triangles and strips + WriteUShort( numTriangles, out ); + WriteUShort( ushort(strips.size()), out ); + + //Write Strip Sizes + for ( uint i = 0; i < strips.size(); ++i ) { + WriteUShort( ushort(strips[i].size()), out ); + } + + //Write points + for ( uint i = 0; i < strips.size(); ++i ) { + for ( uint j = 0; j < strips[i].size(); ++j ) { + WriteUShort( strips[i][j], out ); + } + } } -void NiTriShapeData::SetTriangles( const vector<Triangle> & in ) { - if (in.size() != vertices.size()) - throw runtime_error("Vector size must equal Vertex Count. Call SetVertexCount() to resize."); - triangles = in; +string NiTriStripsData::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + out << AShapeData::asString(); + + //Calculate number of triangles + //Sum of length of each strip - 2 + short numTriangles = 0; + for ( uint i = 0; i < strips.size(); ++i ) { + numTriangles += short(strips[i].size() - 2); + } + + out << "Triangles: " << numTriangles << endl + << "Strips: " << ushort(strips.size()) << endl; + + if (verbose) { + for ( uint i = 0; i < strips.size(); ++i ) { + out << " Strip " << i + 1 << endl; + for ( uint j = 0; j < strips[i].size(); ++j ) { + out << " " << strips[i][j] << endl; + } + } + } else { + out << endl << " <<Data Not Shown>>"; + } + + return out.str(); } /*********************************************************** @@ -898,7 +1217,11 @@ void NiSkinData::Read( ifstream& in, unsigned int version ) { ReadFVector3( translation, in ); scale = ReadFloat( in ); int boneCount = ReadUInt( in ); - unknown = ReadUInt( in ); + unknownInt = ReadUInt( in ); + //unknownByte exists from version 4.2.1.0 on + if ( version >= 0x04020100 ) { + unknownByte = ReadByte( in ); + } bones.resize(boneCount); for( int i = 0; i < boneCount; i++ ) { for (int c = 0; c < 3; ++c) { @@ -931,7 +1254,11 @@ void NiSkinData::Write( ofstream& out, unsigned int version ) { WriteFVector3( translation, out ); WriteFloat( scale, out ); WriteUInt(short(bone_map.size()), out); - WriteUInt(unknown, out); + WriteUInt(unknownInt, out); + //unknownByte exists from version 4.2.1.0 on + if ( version >= 0x04020100 ) { + WriteByte( unknownByte, out ); + } map<IBlock*, Bone>::iterator it; for( it = bone_map.begin(); it != bone_map.end(); ++it ) { @@ -1011,7 +1338,8 @@ string NiSkinData::asString() { << "Translate: " << translation << endl << "Scale: " << scale << endl << "Bone Count: " << uint(bone_map.size()) << endl - << "Unknown Index: " << unknown << endl + << "Unknown Index: " << unknownInt << endl + << "Unknown Byte: " << unknownByte << endl << "Bones:" << endl; map<IBlock*, Bone>::iterator it; @@ -1686,28 +2014,45 @@ string NiKeyframeData::asString() { **********************************************************/ void NiColorData::Read( ifstream& in, unsigned int version ) { - colorCount = ReadUInt( in ); + uint colorCount = ReadUInt( in ); keyType = ReadUInt( in ); if (keyType != 1) { - cout << "NiColorData is thought to only support keyType of 1, but this NIF has a keyType of " << keyType << ". Please report it to NIFLA. Aborting" << endl; - throw runtime_error("Abort"); + stringstream str; + str << "NiColorData is thought to only support keyType of 1, but this NIF has a keyType of " << keyType << "." << endl; + throw runtime_error( str.str() ); } - Key<fVector4> tmp; - for (uint i = 0; i < colorCount; i++) { - tmp.time = ReadFloat( in ); - ReadFVector4( tmp.data, in ); - keys.push_back(tmp); + keys.resize( colorCount ); + for (uint i = 0; i < keys.size(); i++) { + keys[i].time = ReadFloat( in ); + ReadFVector4( keys[i].data, in ); } } +void NiColorData::Write( ofstream& out, unsigned int version ) { + WriteUInt( uint(keys.size()), out ); + WriteUInt( keyType, out ); + + if (keyType != 1) { + stringstream str; + str << "NiColorData is thought to only support keyType of 1, but this NIF has a keyType of " << keyType << "." << endl; + throw runtime_error( str.str() ); + } + + for (uint i = 0; i < keys.size(); i++) { + WriteFloat( keys[i].time, out ); + WriteFVector4( keys[i].data, out ); + } +} + + string NiColorData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out << "Color Count: " << colorCount << endl + out << "Color Count: " << uint(keys.size()) << endl << "Key Type: " << keyType << endl; if (verbose) { @@ -1727,21 +2072,39 @@ string NiColorData::asString() { **********************************************************/ void NiFloatData::Read( ifstream& in, unsigned int version ) { - colorCount = ReadUInt( in ); + uint keyCount = ReadUInt( in ); keyType = ReadUInt( in ); if (keyType != 2) { - cout << "NiFloatata is thought to only support keyType of 2, but this NIF has a keyType of " << keyType << ". Please report it to NIFLA. Aborting" << endl; - throw runtime_error("Abort"); + stringstream str; + str << "NiFloatata is thought to only support keyType of 2, but this NIF has a keyType of " << keyType << "."; + throw runtime_error( str.str() ); + } + + keys.resize( keyCount ); + for (uint i = 0; i < keys.size(); i++) { + keys[i].time = ReadFloat( in ); + keys[i].data = ReadFloat( in ); + keys[i].forward_tangent = ReadFloat( in ); + keys[i].backward_tangent = ReadFloat( in ); + } +} + +void NiFloatData::Write( ofstream& out, unsigned int version ) { + WriteUInt( uint(keys.size()), out ); + WriteUInt( keyType, out ); + + if (keyType != 2) { + stringstream str; + str << "NiFloatata is thought to only support keyType of 2, but this NIF has a keyType of " << keyType << "."; + throw runtime_error( str.str() ); } - Key<float> tmp; - for (uint i = 0; i < colorCount; i++) { - tmp.time = ReadFloat( in ); - tmp.data = ReadFloat( in ); - tmp.forward_tangent = ReadFloat( in ); - tmp.backward_tangent = ReadFloat( in ); - keys.push_back(tmp); + for (uint i = 0; i < keys.size(); i++) { + WriteFloat( keys[i].time, out ); + WriteFloat( keys[i].data, out ); + WriteFloat( keys[i].forward_tangent, out ); + WriteFloat( keys[i].backward_tangent, out ); } } @@ -1750,7 +2113,7 @@ string NiFloatData::asString() { out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out << "Vector Count: " << colorCount << endl + out << "Key Count: " << uint(keys.size()) << endl << "Key Type: " << keyType << endl; if (verbose) { @@ -1770,24 +2133,38 @@ string NiFloatData::asString() { **********************************************************/ void NiStringExtraData::Read( ifstream& in, unsigned int version ) { - GetAttr("Next Extra Data")->Read( in ); + GetAttr("Next Extra Data")->Read( in, version ); + + //Read Name if there is one + if ( _namable == true && version >= _first_named_ver ) { + _name = ReadString( in ); + } - //Read Bytes Remaining but don't bother to store it - ReadUInt( in ); + //Up to version 4.2.2.0, read bytes remaining but don't bother to store it + if ( version <= 0x04020200 ) { + ReadUInt( in ); + } - GetAttr("String Data")->Read( in ); + GetAttr("String Data")->Read( in, version ); } void NiStringExtraData::Write( ofstream& out, unsigned int version ) { - GetAttr("Next Extra Data")->Write( out ); + //Write Name if there is one + if ( _namable == true && version >= _first_named_ver ) { + WriteString( _name, out ); + } + + GetAttr("Next Extra Data")->Write( out, version ); - //Write Bytes Remaining - length of string + 4 attr_ref string_data = GetAttr("String Data"); - - WriteUInt( uint(string_data->asString().length()) + 4, out ); - string_data->Write( out ); + //Up to version 4.2.2.0, Write Bytes Remaining - length of string + 4 + if ( version <= 0x04020200 ) { + WriteUInt( uint(string_data->asString().length()) + 4, out ); + } + + string_data->Write( out, version ); } string NiStringExtraData::asString() { @@ -1798,7 +2175,8 @@ string NiStringExtraData::asString() { attr_ref next_data = GetAttr("Next Extra Data"); attr_ref string_data = GetAttr("String Data"); - out << next_data->GetName() << ": " << next_data->asLink() << endl + out << "Name: " << _name << endl + << next_data->GetName() << ": " << next_data->asLink() << endl << "Bytes Remaining: " << uint(string_data->asString().length()) + 4 << endl << string_data->GetName() << ": " << string_data->asString() << endl; @@ -1813,24 +2191,37 @@ void NiMorphData::Read( ifstream& in, unsigned int version ) { uint morphCount = ReadUInt( in ); vertCount = ReadUInt( in ); - GetAttr("Unknown Byte")->Read( in ); + GetAttr("Unknown Byte")->Read( in, version ); morphs.resize(morphCount); for ( uint i = 0; i < morphs.size() ; ++i ) { uint timeCount = ReadUInt( in ); morphs[i].keyType = KeyType(ReadUInt( in )); - if (timeCount > 0 && morphs[i].keyType != 2) { - cout << "NiMorphData is thought to only support keyType of 2, but this NIF has a keyType of " << morphs[i].keyType << ". Please report it to NifTools. Aborting." << endl; - throw runtime_error("Abort"); + if (timeCount > 0 && (morphs[i].keyType < 1 || morphs[i].keyType > 3 ) ) { + stringstream s; + s << "NiMorphData is thought to only support keyType of 1, 2, or 3, but this NIF has a keyType of " << morphs[i].keyType << "."; + throw runtime_error(s.str()); } morphs[i].keys.resize( timeCount ); for (uint j = 0; j < morphs[i].keys.size(); ++j ) { + + //Always read the time and data morphs[i].keys[j].time = ReadFloat( in ); morphs[i].keys[j].data = ReadFloat( in ); - morphs[i].keys[j].forward_tangent = ReadFloat( in ); - morphs[i].keys[j].backward_tangent = ReadFloat( in ); + + if ( morphs[i].keyType == 2 ) { + //Uses Quadratic interpolation + morphs[i].keys[j].forward_tangent = ReadFloat( in ); + morphs[i].keys[j].backward_tangent = ReadFloat( in ); + } else if ( morphs[i].keyType == 3 ) { + //Uses TBC interpolation + morphs[i].keys[j].tension = ReadFloat( in ); + morphs[i].keys[j].bias = ReadFloat( in ); + morphs[i].keys[j].continuity = ReadFloat( in ); + + } } morphs[i].morph.resize( vertCount ); @@ -1846,22 +2237,35 @@ void NiMorphData::Write( ofstream& out, unsigned int version ) { WriteUInt( uint(morphs.size()), out ); WriteUInt( vertCount, out ); - GetAttr("Unknown Byte")->Write( out ); + GetAttr("Unknown Byte")->Write( out, version ); for ( uint i = 0; i < morphs.size() ; ++i ) { WriteUInt( uint(morphs[i].keys.size()), out ); WriteUInt( KeyType(morphs[i].keyType), out ); - if (morphs[i].keys.size() > 0 && morphs[i].keyType != 2) { - cout << "NiMorphData is thought to only support keyType of 2, but this NIF has a keyType of " << morphs[i].keyType << ". Please report it to NifTools. Aborting." << endl; - throw runtime_error("Abort"); + if ( morphs[i].keyType < 1 || morphs[i].keyType > 3 ) { + stringstream s; + s << "NiMorphData is thought to only support keyType of 1, 2, or 3, but this NIF has a keyType of " << morphs[i].keyType << "."; + throw runtime_error(s.str()); } for (uint j = 0; j < morphs[i].keys.size(); ++j ) { + + //Always write the time and data WriteFloat( morphs[i].keys[j].time, out ); WriteFloat( morphs[i].keys[j].data, out ); - WriteFloat( morphs[i].keys[j].forward_tangent, out ); - WriteFloat( morphs[i].keys[j].backward_tangent, out ); + + if ( morphs[i].keyType == 2 ) { + //Uses Quadratic interpolation + WriteFloat( morphs[i].keys[j].forward_tangent, out ); + WriteFloat( morphs[i].keys[j].backward_tangent, out ); + } else if ( morphs[i].keyType == 3 ) { + //Uses TBC interpolation + WriteFloat ( morphs[i].keys[j].tension, out ); + WriteFloat ( morphs[i].keys[j].bias, out ); + WriteFloat ( morphs[i].keys[j].continuity, out ); + + } } for (uint j = 0; j < vertCount ; ++j ) { @@ -1889,7 +2293,15 @@ string NiMorphData::asString() { if (verbose) { for (uint j = 0; j < morphs[i].keys.size(); ++j ) { - out << "Key Time: " << morphs[i].keys[j].time << " Influence?: " << morphs[i].keys[j].data << " F: " << morphs[i].keys[j].forward_tangent << " B: " << morphs[i].keys[j].backward_tangent << endl; + //Always show time and data + out << "Key Time: " << morphs[i].keys[j].time << ", Influence?: " << morphs[i].keys[j].data; + if ( morphs[i].keyType == 2 ) { + //Uses Quadratic interpolation + out << ", FT(" << morphs[i].keys[j].forward_tangent << ") BT(" << morphs[i].keys[j].backward_tangent << ")"; + } else if ( morphs[i].keyType == 3 ) { + out << ", T " << morphs[i].keys[j].tension << ", B " << morphs[i].keys[j].bias << ", C " << morphs[i].keys[j].continuity; + } + out << endl; } for (uint j = 0; j < vertCount ; ++j ) { @@ -1921,6 +2333,63 @@ void NiMorphData::SetMorphVerts( int n, const vector<Vector3> & in ) { morphs[n].morph = in; } +/*********************************************************** + * NiPalette methods + **********************************************************/ + +void NiPalette::Read( ifstream& in, unsigned int version ) { + //Read 5 unknown bytes + for (int i = 0; i < 5; ++i) { + unknownBytes[i] = ReadByte( in ); + } + + //Read Palette + for (int i = 0; i < 256; ++i) { + for (int j = 0; j < 4; ++j) { + palette[i][j] = ReadByte( in ); + } + } +} + +void NiPalette::Write( ofstream& out, unsigned int version ) { + //Write 5 unknown bytes + for (int i = 0; i < 5; ++i) { + WriteByte( unknownBytes[i], out ); + } + + //Read Palette + for (int i = 0; i < 256; ++i) { + for (int j = 0; j < 4; ++j) { + WriteByte( palette[i][j], out ); + } + } +} + + +string NiPalette::asString() { + stringstream out; + out.setf(ios::fixed, ios::floatfield); + out << setprecision(1); + + //Print 5 unknown bytes + for (int i = 0; i < 5; ++i) { + out << "Unknown Byte " << i + 1 << ": " << unknownBytes[i] << endl; + } + + //Print Palette + out << "Palette:" << endl; + if (verbose) { + for (int i = 0; i < 256; ++i) { + out << i + 1 << ": " << int(palette[i][0]) << ", " << int(palette[i][1]) << ", " << int(palette[i][2]) << ", " << int(palette[i][3]) << endl; + } + } else { + out << " <<Data Not Shown>>" << endl; + } + + return out.str(); +} + + /*********************************************************** * NiPixelData methods **********************************************************/ @@ -1937,17 +2406,16 @@ void NiPixelData::Read( ifstream& in, unsigned int version ) { unknown8Bytes[i] = ReadByte( in ); } - GetAttr("Unknown Index")->Read( in ); + GetAttr("Unknown Index")->Read( in, version ); - mipCount = ReadUInt( in ); + uint mipCount = ReadUInt( in ); bytesPerPixel = ReadUInt( in ); - MipMap temp; + mipmaps.resize( mipCount ); for ( uint i = 0; i < mipCount; ++i ) { - temp.width = ReadUInt( in ); - temp.height = ReadUInt( in ); - temp.offset = ReadUInt( in ); - mipmaps.push_back(temp); + mipmaps[i].width = ReadUInt( in ); + mipmaps[i].height = ReadUInt( in ); + mipmaps[i].offset = ReadUInt( in ); } dataSize = ReadUInt( in ); @@ -1955,6 +2423,33 @@ void NiPixelData::Read( ifstream& in, unsigned int version ) { in.read( (char *)data, dataSize); } +void NiPixelData::Write( ofstream& out, unsigned int version ) { + WriteUInt( unknownInt, out ); + WriteUInt( rMask, out ); + WriteUInt( gMask, out ); + WriteUInt( bMask, out ); + WriteUInt( aMask, out ); + WriteUInt( bpp, out ); + + for (int i = 0; i < 8; ++i) { + WriteByte( unknown8Bytes[i], out ); + } + + GetAttr("Unknown Index")->Write( out, version ); + + WriteUInt( uint(mipmaps.size()), out ); + WriteUInt( bytesPerPixel, out ); + + for ( uint i = 0; i < mipmaps.size(); ++i ) { + WriteUInt( mipmaps[i].width, out ); + WriteUInt( mipmaps[i].height, out ); + WriteUInt( mipmaps[i].offset, out ); + } + + WriteUInt( dataSize, out ); + out.write( (char *)data, dataSize); +} + string NiPixelData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -1977,7 +2472,7 @@ string NiPixelData::asString() { out << endl; out << "Unknown Index: " << GetAttr("Unknown Index")->asLink() << endl - << "Mipmap Count: " << mipCount << endl + << "Mipmap Count: " << uint(mipmaps.size()) << endl << "Bytes Per Pixel: " << bytesPerPixel << endl; for ( uint i = 0; i < mipmaps.size(); ++i ) { @@ -1997,10 +2492,10 @@ string NiPixelData::asString() { **********************************************************/ void NiPosData::Read( ifstream& in, unsigned int version ) { - posCount = ReadUInt( in ); + uint keyCount = ReadUInt( in ); keyType = ReadUInt( in ); - keys.resize(posCount); + keys.resize(keyCount); for (uint i = 0; i < keys.size(); i++) { keys[i].time = ReadFloat( in ); ReadFVector3( keys[i].data, in ); @@ -2011,8 +2506,30 @@ void NiPosData::Read( ifstream& in, unsigned int version ) { } if (keyType != 1 && keyType != 2) { - cout << "NiPosData is thought to only support keyTypes of 1 and 2, but this NIF has a keyType of " << keyType << ". Please report it to NIFLA. Aborting" << endl; - throw runtime_error("Abort"); + stringstream str; + str << "NiPosData is thought to only support keyTypes of 1 and 2, but this NIF has a keyType of " << keyType << "."; + throw runtime_error( str.str() ); + } + } +} + +void NiPosData::Write( ofstream& out, unsigned int version ) { + WriteUInt( uint(keys.size()), out ); + WriteUInt( keyType, out ); + + for (uint i = 0; i < keys.size(); i++) { + WriteFloat( keys[i].time, out ); + WriteFVector3( keys[i].data, out ); + + if (keyType == 2) { + WriteFVector3( keys[i].forward_tangent, out ); + WriteFVector3( keys[i].backward_tangent, out ); + } + + if (keyType != 1 && keyType != 2) { + stringstream str; + str << "NiPosData is thought to only support keyTypes of 1 and 2, but this NIF has a keyType of " << keyType << "."; + throw runtime_error( str.str() ); } } } @@ -2022,7 +2539,7 @@ string NiPosData::asString() { out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out << "Pos Count: " << posCount << endl + out << "Key Count: " << uint(keys.size()) << endl << "Key Type: " << keyType << endl; if (verbose) { @@ -2041,147 +2558,13 @@ string NiPosData::asString() { return out.str(); } -/*********************************************************** - * NiRotatingParticlesData methods - **********************************************************/ - -void NiRotatingParticlesData::Read( ifstream& in, unsigned int version ) { - - // short count1 - - // int b1 - // if(b1 != 0) - // foreach count1 - // float[3] unknown - - // int or float = 0 - // float[4] unknown - - // int b2 - // if(b2 != 0) - // foreach count1 - // float[4] unknown - - // int = 0 - // short unknown - // short count2 - always equal to count1 ? - // float unknown - // short unknown - - // int b3 - // if(b3 != 0) - // foreach count2 (or count1) - // float unknown - - // int b4 - // if(b4 != 0) - // foreach count2 (or count1) - // float[4] unknown - - ushort count1 = ReadUShort( in ); - uint b1 = ReadUInt( in ); - - cout << "Count 1: " << count1 << endl - << "Bool 1: " << b1 << endl; - - if (b1) { - fVector3 vect; - for (uint i = 0; i < count1; ++i) { - ReadFVector3( vect, in ); - cout << "Unknown 3 Floats: " << vect << endl; - } - } - - uint unknownInt = ReadUInt( in ); - - fVector4 unknown4Floats; - ReadFVector4( unknown4Floats, in ); - uint b2 = ReadUInt( in ); - - cout << "Unknown Int: " << unknownInt << endl - << "Unknown 4 Floats: " << unknown4Floats << endl - << "Bool 2: " << b2 << endl; - - if (b2) { - fVector4 unknown4Floats2; - for (uint i = 0; i < count1; ++i) { - ReadFVector4( unknown4Floats2, in ); - cout << "Unkown 4 Floats: " << unknown4Floats2 << endl; - } - } - - uint unknownInt2 = ReadUInt( in ); - ushort unknownShort = ReadUShort( in ); - ushort count2 = ReadUShort( in ); - float unknownFloat = ReadFloat( in ); - ushort unknownShort2 = ReadUShort( in ); - uint b3 = ReadUInt( in ); - - cout << "Unknown Int 2: " << unknownInt2 << endl - << "Unknown Short: " << unknownShort << endl - << "Count 2: " << count2 << endl - << "Unknown Float: " << unknownFloat << endl - << "Unknown Short 2: " << unknownShort2 << endl - << "Bool 3: " << b3 << endl; - - if (b3) { - float temp; - for (uint i = 0; i < count1; ++i) { - temp = ReadFloat( in ); - cout << "Unkown Float: " << temp << endl; - } - } - - uint b4 = ReadUInt( in ); - - cout << "Bool 4: " << b4 << endl; - - if (b4) { - fVector4 unknown4Floats3; - for (uint i = 0; i < count1; ++i) { - ReadFVector4( unknown4Floats3, in ); - cout << "Unkown 4 Floats: " << unknown4Floats3 << endl; - } - } - - //int len = BlockSearch(in); - - ////Create byte array and read in unknown block - //byte * data = new byte [len]; - //in.read((char*)data, len); - - //Display Data in Hex form - //cout << hex << setfill('0'); - //for (int j = 0; j < len; j++) { - // cout << uppercase << setw(2) << uint(data[j]); - // if (j % 16 == 15 || j == len - 1) - // cout << endl; - // else if (j % 16 == 7) - // cout << " "; - // else if (j % 8 == 3) - // cout << " "; - // else - // cout << " "; - //} - //cout << dec << setfill(' '); - - /*delete [] data;*/ - - //if (count1 != count2) { - // cout << "\a"; - // cin.get(); - //} -} - /*********************************************************** * NiTextKeyExtraData methods **********************************************************/ void NiTextKeyExtraData::Read( ifstream& in, unsigned int version ) { - - GetAttr("Next Extra Data")->Read( in ); - GetAttr("Unknown Int")->Read( in ); - + ABlock::Read( in, version ); + uint keyCount = ReadUInt( in ); _keys.resize(keyCount); @@ -2193,8 +2576,7 @@ void NiTextKeyExtraData::Read( ifstream& in, unsigned int version ) { void NiTextKeyExtraData::Write( ofstream& out, unsigned int version ) { - GetAttr("Next Extra Data")->Write( out ); - GetAttr("Unknown Int")->Write( out ); + ABlock::Write( out, version ); WriteUInt( uint(_keys.size()), out ); @@ -2231,12 +2613,12 @@ string NiTextKeyExtraData::asString() { void NiUVData::Read( ifstream& in, unsigned int version ) { for (uint i = 0; i < 4; ++i) { - groups[i].count = ReadUInt( in ); + uint count = ReadUInt( in ); - if ( groups[i].count > 0 ) { + if ( count > 0 ) { groups[i].keyType = ReadUInt( in ); - groups[i].keys.resize(groups[i].count); + groups[i].keys.resize(count); for (uint j = 0; j < groups[i].keys.size(); ++j) { groups[i].keys[j].time = ReadFloat( in ); groups[i].keys[j].data = ReadFloat( in ); @@ -2250,6 +2632,26 @@ void NiUVData::Read( ifstream& in, unsigned int version ) { } } +void NiUVData::Write( ofstream& out, unsigned int version ) { + for (uint i = 0; i < 4; ++i) { + WriteUInt( uint(groups[i].keys.size()), out ); + + if ( groups[i].keys.size() > 0 ) { + WriteUInt( groups[i].keyType, out ); + + for (uint j = 0; j < groups[i].keys.size(); ++j) { + WriteFloat( groups[i].keys[j].time, out ); + WriteFloat( groups[i].keys[j].data, out ); + + if ( groups[i].keyType == 2) { + WriteFloat( groups[i].keys[j].forward_tangent, out ); + WriteFloat( groups[i].keys[j].backward_tangent, out ); + } + } + } + } +} + string NiUVData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -2257,9 +2659,9 @@ string NiUVData::asString() { for (uint i = 0; i < 4; ++i) { out << "UV Group " << i + 1 << ":" << endl - << " Count: " << groups[i].count << endl; + << " Key Count: " << uint(groups[i].keys.size()) << endl; - if ( groups[i].count > 0 ) { + if ( groups[i].keys.size() > 0 ) { out << " Key Type: " << groups[i].keyType << endl; if (verbose) { @@ -2284,10 +2686,11 @@ string NiUVData::asString() { * NiVertWeightsExtraData methods **********************************************************/ -void NiVertWeightsExtraData ::Read( ifstream& in, unsigned int version ) { - GetAttr("Next Extra Data")->Read( in ); +void NiVertWeightsExtraData::Read( ifstream& in, unsigned int version ) { + ABlock::Read( in, version ); + bytes = ReadUInt( in ); - verts = ReadUShort( in ); + ushort verts = ReadUShort( in ); weights.resize( verts ); for (uint i = 0; i < weights.size(); ++i) { @@ -2295,14 +2698,26 @@ void NiVertWeightsExtraData ::Read( ifstream& in, unsigned int version ) { } } +void NiVertWeightsExtraData::Write( ofstream& out, unsigned int version ) { + ABlock::Write( out, version ); + + WriteUInt( bytes, out ); + WriteUShort( ushort(weights.size()), out ); + + for (uint i = 0; i < weights.size(); ++i) { + WriteFloat( weights[i], out ); + } +} + string NiVertWeightsExtraData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out << "Next Extra Data: " << GetAttr("Next Extra Data")->asLink() << endl - << "Bytes: " << bytes << endl - << "Verts: " << verts << endl; + out << ABlock::asString(); + + out << "Bytes: " << bytes << endl + << "Verts: " << uint(weights.size()) << endl; if (verbose) { for (uint i = 0; i < weights.size(); ++i) { @@ -2320,21 +2735,30 @@ string NiVertWeightsExtraData::asString() { **********************************************************/ void NiVisData ::Read( ifstream& in, unsigned int version ) { - visCount = ReadUInt( in ); + uint keyCount = ReadUInt( in ); - keys.resize( visCount ); + keys.resize( keyCount ); for (uint i = 0; i < keys.size(); ++i) { keys[i].time = ReadFloat( in ); keys[i].data = ReadByte( in ); // Is Visible? True/False } } +void NiVisData ::Write( ofstream& out, unsigned int version ) { + WriteUInt( uint(keys.size()), out ); + + for (uint i = 0; i < keys.size(); ++i) { + WriteFloat( keys[i].time, out ); + WriteByte( keys[i].data, out ); // Is Visible? True/False + } +} + string NiVisData::asString() { stringstream out; out.setf(ios::fixed, ios::floatfield); out << setprecision(1); - out << "Visibility Count: " << visCount << endl; + out << "Key Count: " << uint(keys.size()) << endl; if (verbose) { for (uint i = 0; i < keys.size(); ++i) { diff --git a/NIF_Blocks.h b/NIF_Blocks.h index 50e0b153..739dfdaa 100644 --- a/NIF_Blocks.h +++ b/NIF_Blocks.h @@ -102,6 +102,11 @@ public: } } + //Name Functions + virtual bool Namable() { return _namable; } + virtual void SetName( string & name ) { _name = name; } + virtual string GetName() { return _name; } + //--Internal Functions--// void AddParent( blk_ref parent); void RemoveParent( IBlock * match ); @@ -110,31 +115,29 @@ public: void Read( ifstream& in, unsigned int version ); void Write( ofstream& out, unsigned int version ); -private: +protected: map<string, attr_ref> _attr_map; vector<attr_ref> _attr_vect; - vector< pair< unsigned int, unsigned int > > _attr_vers; int _block_num; unsigned int _ref_count; vector<IBlock*> _parents; + bool _namable; + unsigned int _first_named_ver; + string _name; }; -class AExtraData : public ABlock { +class AControllable : public ABlock { public: - AExtraData() { - AddAttr( "link", "Next Extra Data" ); - } - ~AExtraData() {}; + AControllable(); + void Init() {} + ~AControllable() {} }; -class ANamed : public ABlock { +class ANamed : public AControllable { public: - ANamed(){ - AddAttr( "string", "Name" ); - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - } - ~ANamed(){} + ANamed(); + void Init() { _namable = true; } + ~ANamed() {} }; class INodeInternal { @@ -145,19 +148,10 @@ public: class ANode : public ANamed, public INode, public INodeInternal { public: - ANode(){ - AddAttr( "flags", "Flags" ); - AddAttr( "float3", "Translation" ); - AddAttr( "matrix33", "Rotation" ); - AddAttr( "float", "Scale" ); - AddAttr( "float3", "Velocity" ); - AddAttr( "linkgroup", "Properties" ); - AddAttr( "bbox", "Bounding Box", 0, VER_4_0_0_2 ); - AddAttr( "byte" , "Unknown Byte", VER_4_2_0_2 ); - - SetIdentity44(bindPosition); - } + ANode(); + void Init() { SetIdentity44(bindPosition); }; ~ANode(); + void InitAttrs(); void * QueryInterface( int id ); void Read( ifstream& in, unsigned int version ) { ABlock::Read( in, version ); @@ -184,53 +178,63 @@ protected: class AParentNode : public ANode { public: - AParentNode(){ - AddAttr( "linkgroup", "Children" ); - AddAttr( "linkgroup", "Effects" ); - } - ~AParentNode(){} + AParentNode(); + void Init() {} + ~AParentNode() {} +}; + +class AShape : public ANode { +public: + AShape(); + void Init() {} + ~AShape() {} }; class AProperty : public ANamed { public: - AProperty() { - AddAttr( "flags", "Flags" ); - } + AProperty(); + void Init() {} ~AProperty() {} }; class AController : public ABlock { public: - AController() { - AddAttr( "link", "Next Controller" ); - AddAttr( "flags", "Flags" ); - AddAttr( "float", "Frequency" ); - AddAttr( "float", "Phase" ); - AddAttr( "float", "Start Time" ); - AddAttr( "float", "Stop Time" ); - AddAttr( "nodeancestor", "Target Node" ); - } + AController(); + void Init() {} ~AController() {} }; -class ALight : public ANode { +class AData : public ABlock { public: - ALight (){ - //AddAttr( "int", "Unknown Int 1" ); - //AddAttr( "int", "Unknown Int 2" ); - AddAttr( "float", "Dimmer" ); - AddAttr( "float3", "Ambient Color" ); - AddAttr( "float3", "Diffuse Color" ); - AddAttr( "float3", "Specular Color" ); + AData() {} + void Init() {} + ~AData() {} +}; + +class AExtraData : public AData { +public: + AExtraData() { + _namable = true; + _first_named_ver = 0x10000100; + AddAttr( "link", "Next Extra Data", 0, 0x04020200 ); } - ~ALight (){} + ~AExtraData() {}; }; -// Used to move temporarily stored bone indicies into SkinInstanceData block to facilitate -// the illusion that these are stored together with the bone data -class ISkinInstance { + +class AParticleSystemController : public AController { +public: + AParticleSystemController(); + void Init() {} + ~AParticleSystemController() {} }; +class ALight : public ANode { +public: + ALight(); + void Init() {} + ~ALight() {} +}; /** * NiNode - Root of each model component. @@ -238,8 +242,9 @@ class ISkinInstance { class NiNode : public AParentNode { public: - NiNode(){} - ~NiNode(){} + NiNode(); + void Init() {} + ~NiNode() {} string GetBlockType() { return "NiNode"; } string asString(); }; @@ -248,148 +253,151 @@ public: * RootCollisionNode */ class RootCollisionNode : public AParentNode { +public: - public: - - RootCollisionNode(){} - ~RootCollisionNode(){} + RootCollisionNode(); + void Init() {} + ~RootCollisionNode() {} - string GetBlockType() { return "RootCollisionNode"; } + string GetBlockType() { return "RootCollisionNode"; } }; /** * AvoidNode */ class AvoidNode : public AParentNode { +public: - public: - - AvoidNode(){} - ~AvoidNode(){} + AvoidNode(); + void Init() {} + ~AvoidNode() {} - string GetBlockType() { return "AvoidNode"; } + string GetBlockType() { return "AvoidNode"; } }; /** * NiBillboardNode */ class NiBillboardNode : public AParentNode { +public: + NiBillboardNode(); + void Init() {} + ~NiBillboardNode() {} - public: + string GetBlockType() { return "NiBillboardNode"; } +}; - NiBillboardNode(){} - ~NiBillboardNode(){} +/** + * NiBSAnimationNode + */ +class NiBSAnimationNode : public AParentNode { +public: + NiBSAnimationNode(); + void Init() {} + ~NiBSAnimationNode() {} - string GetBlockType() { return "NiBillboardNode"; } + string GetBlockType() { return "NiBSAnimationNode"; } }; /** * NiBSParticleNode */ class NiBSParticleNode : public AParentNode { +public: + NiBSParticleNode(); + void Init() {} + ~NiBSParticleNode() {} - public: - - NiBSParticleNode(){} - ~NiBSParticleNode(){} - - string GetBlockType() { return "NiBSParticleNode"; } + string GetBlockType() { return "NiBSParticleNode"; } }; /** - * NiBSAnimationNode + * NiLODNode */ -class NiBSAnimationNode : public AParentNode { - - public: - - NiBSAnimationNode(){} - ~NiBSAnimationNode(){} +class NiLODNode : public AParentNode { +public: + NiLODNode(); + void Init() {} + ~NiLODNode() {} - string GetBlockType() { return "NiBSAnimationNode"; } + string GetBlockType() { return "NiLODNode"; } }; - /** * ZBuffer data. */ class NiZBufferProperty : public AProperty { +public: + NiZBufferProperty(); + void Init() {} + ~NiZBufferProperty() {} - public: - - NiZBufferProperty(){ - AddAttr( "int", "Unknown Int", VER_4_2_0_2 ); - } - ~NiZBufferProperty(){} - - string GetBlockType() { return "NiZBufferProperty"; } + string GetBlockType() { return "NiZBufferProperty"; } }; /** * NiShadeProperty */ class NiShadeProperty : public AProperty { +public: - public: - - NiShadeProperty(){} - ~NiShadeProperty(){} + NiShadeProperty(); + void Init() {} + ~NiShadeProperty() {} - string GetBlockType() { return "NiShadeProperty"; } + string GetBlockType() { return "NiShadeProperty"; } }; /** * ZBuffer data.NiWireframeProperty */ class NiWireframeProperty : public AProperty { +public: - public: - - NiWireframeProperty(){} - ~NiWireframeProperty(){} + NiWireframeProperty(); + void Init() {} + ~NiWireframeProperty() {} - string GetBlockType() { return "NiWireframeProperty"; } + string GetBlockType() { return "NiWireframeProperty"; } }; /** * NiDitherProperty */ class NiDitherProperty : public AProperty { +public: - public: - - NiDitherProperty(){} - ~NiDitherProperty(){} + NiDitherProperty(); + void Init() {} + ~NiDitherProperty() {} - string GetBlockType() { return "NiDitherProperty"; } + string GetBlockType() { return "NiDitherProperty"; } }; /** * NiSequenceStreamHelper */ class NiSequenceStreamHelper : public ANamed { +public: - public: - - NiSequenceStreamHelper (){} - ~NiSequenceStreamHelper (){} + NiSequenceStreamHelper (); + void Init() {} + ~NiSequenceStreamHelper () {} - string GetBlockType() { return "NiSequenceStreamHelper"; } + string GetBlockType() { return "NiSequenceStreamHelper"; } }; /** * NiVertexColorProperty - Vertex colour data. */ class NiVertexColorProperty : public AProperty{ - public: +public: - NiVertexColorProperty(){ - AddAttr( "vertmode", "Vertex Mode" ); - AddAttr( "lightmode", "Lighting Mode" ); - } - ~NiVertexColorProperty(){} + NiVertexColorProperty(); + void Init() {} + ~NiVertexColorProperty() {} - string GetBlockType() { return "NiVertexColorProperty"; } + string GetBlockType() { return "NiVertexColorProperty"; } }; @@ -397,66 +405,47 @@ class NiVertexColorProperty : public AProperty{ /** * NiTriShape - */ -class NiTriShape : public ANode { - public: - NiTriShape() { - AddAttr( "link", "Data" ); - AddAttr( "link", "Skin Instance" ); - } - ~NiTriShape(){} - string GetBlockType() { return "NiTriShape"; } +class NiTriShape : public AShape { +public: + NiTriShape(); + void Init() {} + ~NiTriShape() {} + + string GetBlockType() { return "NiTriShape"; } }; /** - * NiTexturingProperty - + * NiTriStrips - */ -class NiTexturingProperty : public AProperty { +class NiTriStrips : public AShape { +public: + NiTriStrips(); + void Init() {} + ~NiTriStrips() {} - public: - NiTexturingProperty( ) { - AddAttr( "applymode", "Apply Mode" ); - AddAttr( "int", "Texture Count?" ); - AddAttr( "texture", "Base Texture" ); - AddAttr( "texture", "Dark Texture" ); - AddAttr( "texture", "Detail Texture" ); - AddAttr( "texture", "Gloss Texture" ); - AddAttr( "texture", "Glow Texture" ); - AddAttr( "bumpmap", "Bump Map Texture" ); - AddAttr( "texture", "Decal 0 Texture" ); - } - ~NiTexturingProperty(){} - string GetBlockType() { return "NiTexturingProperty"; } + string GetBlockType() { return "NiTriStrips"; } }; - //byte useExternal - set to 0 or 1 - - //if(useExternal == 0) - // byte unknown = 1 - // int pixelIndex - index of NiPixelData record - //else - // string file - texture file name - - //int pixelLayout - //int mipmap - //int alpha - see the NIFLA spec - - //byte unknown = 1 +/** + * NiTexturingProperty - + */ +class NiTexturingProperty : public AProperty { +public: + NiTexturingProperty( ); + void Init() {} + ~NiTexturingProperty() {} + string GetBlockType() { return "NiTexturingProperty"; } +}; /** * NiSourceTexture - Data for the associated texture, included in nif or external. */ class NiSourceTexture : public ANamed{ - - public: - NiSourceTexture(){ - AddAttr( "texsource", "Texture Source" ); - AddAttr( "pixellayout", "Pixel Layout" ); - AddAttr( "mipmapformat", "Use Mipmaps" ); - AddAttr( "alphaformat", "Alpha Format" ); - AddAttr( "byte", "Unknown Byte" ); - } - ~NiSourceTexture(){} - string GetBlockType() { return "NiSourceTexture"; } +public: + NiSourceTexture(); + void Init() {} + ~NiSourceTexture() {} + string GetBlockType() { return "NiSourceTexture"; } }; @@ -464,167 +453,299 @@ class NiSourceTexture : public ANamed{ /** * NiPixelData - Texture data for an included texture. */ -class NiPixelData : public ABlock{ - - public: - NiPixelData(){ - AddAttr( "link", "Unknown Index" ); - data = NULL; } - ~NiPixelData(){ if (data != NULL) delete [] data; } - - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ){} - string asString(); - string GetBlockType() { return "NiPixelData"; } +class NiPixelData : public AData { +public: + NiPixelData() { + AddAttr( "link", "Unknown Index" ); + data = NULL; } + ~NiPixelData() { if (data != NULL) delete [] data; } - private: - struct MipMap { - uint width, height, offset; - }; - - uint unknownInt, rMask, gMask, bMask, aMask, bpp; - byte unknown8Bytes[8]; - uint mipCount, bytesPerPixel; - vector<MipMap> mipmaps; - uint dataSize; - byte * data; + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiPixelData"; } +private: + struct MipMap { + uint width, height, offset; + }; + + uint unknownInt, rMask, gMask, bMask, aMask, bpp; + byte unknown8Bytes[8]; + uint bytesPerPixel; + vector<MipMap> mipmaps; + uint dataSize; + byte * data; }; - - /** * NiMaterialProperty - material properties */ class NiMaterialProperty : public AProperty{ - public: - NiMaterialProperty(){ - AddAttr( "float3", "Ambient Color" ); - AddAttr( "float3", "Diffuse Color" ); - AddAttr( "float3", "Specular Color" ); - AddAttr( "float3", "Emissive Color" ); - AddAttr( "float", "Glossiness" ); - AddAttr( "float", "Alpha" ); - } - ~NiMaterialProperty(){} - string GetBlockType() { return "NiMaterialProperty"; }; +public: + NiMaterialProperty(); + void Init() {} + ~NiMaterialProperty() {} + string GetBlockType() { return "NiMaterialProperty"; }; }; /** * NiSpecularProperty - */ class NiSpecularProperty : public AProperty { - - public: - NiSpecularProperty() {} - ~NiSpecularProperty(){} - string GetBlockType() { return "NiSpecularProperty"; }; +public: + NiSpecularProperty(); + void Init() {} + ~NiSpecularProperty() {} + string GetBlockType() { return "NiSpecularProperty"; }; }; - +/** + * NiStencilProperty - + */ +class NiStencilProperty : public AProperty { +public: + NiStencilProperty(); + void Init() {} + ~NiStencilProperty() {} + string GetBlockType() { return "NiStencilProperty"; }; +}; /** * NiAlphaProperty - Does the mesh have alpha-blending enabled? */ class NiAlphaProperty : public AProperty { +public: + NiAlphaProperty(); + void Init() {} + ~NiAlphaProperty() {} + string GetBlockType() { return "NiAlphaProperty"; } +}; - public: +/** + * AShapeData - Mesh data: vertices, vertex normals, etc. + */ +class AShapeData : public AData, public IShapeData { +public: + AShapeData() { + AddAttr( "float3", "Center" ); + AddAttr( "float", "Radius" ); + } + ~AShapeData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); - NiAlphaProperty(){ - AddAttr( "byte", "Unknown Byte" ); - } - ~NiAlphaProperty(){} - string GetBlockType() { return "NiAlphaProperty"; } + void * QueryInterface( int id ); + + //--IShapeData--// + //Counts + short GetVertexCount() { return short(vertices.size()); } + short GetUVSetCount() { return short(uv_sets.size()); } + void SetVertexCount(int n); + void SetUVSetCount(int n); + //Getters + vector<Vector3> GetVertices() { return vertices; } + vector<Vector3> GetNormals() { return normals; } + vector<Color> GetColors() { return colors; } + vector<UVCoord> GetUVSet( int index ) { return uv_sets[index]; } + //Setters + void SetVertices( const vector<Vector3> & in ); + void SetNormals( const vector<Vector3> & in ); + void SetColors( const vector<Color> & in ); + void SetUVSet( int index, const vector<UVCoord> & in ); +protected: + vector<Vector3> vertices; + vector<Vector3> normals; + vector<Color> colors; + vector< vector<UVCoord> > uv_sets; }; +/** + * AParticlesData - Generic particle system data block. + */ +class AParticlesData : public AShapeData { +public: + AParticlesData() { + AddAttr( "float", "Active Radius" ); + AddAttr( "short", "Unknown Short", 0x0401000C ); + } + ~AParticlesData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); +protected: + bool hasSizes; + short numActive, numValid; + vector<float> sizes; +}; /** - * Contains the mesh data of a group. + * ARotatingParticlesData - Generic rotating particles data block. */ -class NiTriShapeData : public ABlock, public ITriShapeData { - public: +class ARotatingParticlesData : public AParticlesData { +public: + ARotatingParticlesData() {} + ~ARotatingParticlesData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); +protected: + bool hasRotations; + vector<Quaternion> rotations; +}; - NiTriShapeData() : match_group_mode(false) { - AddAttr( "float3", "Center" ); - AddAttr( "float", "Radius" ); - } - ~NiTriShapeData(){} +/** + * NiParticleMeshesData - Particle meshes data. + */ - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ); - string asString(); - string GetBlockType() { return "NiTriShapeData"; } - void * QueryInterface( int id ); +class NiParticleMeshesData : public ARotatingParticlesData { +public: + NiParticleMeshesData() { + AddAttr( "link", "Unknown Link" ); + } + ~NiParticleMeshesData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); - //--ITriShapeData--// - //Counts - short GetVertexCount() { return short(vertices.size()); } - short GetUVSetCount() { return short(uv_sets.size()); } - short GetTriangleCount() { return short(triangles.size()); } - void SetVertexCount(int n); - void SetUVSetCount(int n); - void SetTriangleCount(int n); - //Match Detection - void SetMatchDetectionMode(bool choice) { match_group_mode = choice; } - bool GetMatchDetectionMode() { return match_group_mode; } - //Getters - vector<Vector3> GetVertices() { return vertices; } - vector<Vector3> GetNormals() { return normals; } - vector<Color> GetColors() { return colors; } - vector<UVCoord> GetUVSet( int index ) { return uv_sets[index]; } - vector<Triangle> GetTriangles() { return triangles; } - //Setters - void SetVertices( const vector<Vector3> & in ); - void SetNormals( const vector<Vector3> & in ); - void SetColors( const vector<Color> & in ); - void SetUVSet( int index, const vector<UVCoord> & in ); - void SetTriangles( const vector<Triangle> & in ); + string GetBlockType() { return "NiParticleMeshesData"; } +protected: + +}; - private: - vector<Vector3> vertices; - vector<Vector3> normals; - vector<Color> colors; - vector< vector<UVCoord> > uv_sets; - vector<Triangle> triangles; - bool match_group_mode; - //short vert_count; +/** + * NiAutoNormalParticlesData - Particle system data block (emits particles along vertex normals?). + */ + +class NiAutoNormalParticlesData : public AParticlesData { +public: + NiAutoNormalParticlesData() {} + ~NiAutoNormalParticlesData() {} + string GetBlockType() { return "NiAutoNormalParticlesData"; } +}; + +/** + * NiTriShapeData - Holds mesh data using a list of singular triangles. + */ +class NiTriShapeData : public AShapeData, public ITriShapeData { +public: + NiTriShapeData() : match_group_mode(false) {} + ~NiTriShapeData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiTriShapeData"; } + void * QueryInterface( int id ); + + //--ITriShapeData--// + //Counts + short GetTriangleCount() { return short(triangles.size()); } + void SetTriangleCount(int n); + //Match Detection + void SetMatchDetectionMode(bool choice) { match_group_mode = choice; } + bool GetMatchDetectionMode() { return match_group_mode; } + //Getters + vector<Triangle> GetTriangles() { return triangles; } + //Setters + void SetTriangles( const vector<Triangle> & in ); + +private: + vector<Triangle> triangles; + bool match_group_mode; }; +/** + * NiTriStripsData - Holds mesh data using strips of triangles. + */ +class NiTriStripsData : public AShapeData { +public: + NiTriStripsData() {} + ~NiTriStripsData() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + + string GetBlockType() { return "NiTriStripsData"; } + +private: + vector< vector<short> > strips; +}; + +/** + * NiCollisionData - Collision box. + */ +class NiCollisionData : public AData { +public: + NiCollisionData() { + AddAttr( "int", "Unknown Int 1" ); + AddAttr( "int", "Unknown Int 2" ); + AddAttr( "byte", "Unknown Byte" ); + AddAttr( "int", "Unknown Int 3" ); + AddAttr( "int", "Unknown Int 4" ); + AddAttr( "float3", "Radius" ); + } + ~NiCollisionData() {} + + string GetBlockType() { return "NiCollisionData"; } +}; + + + /** * NiKeyframeController */ class NiKeyframeController : public AController { public: - NiKeyframeController(){ - AddAttr( "link", "Data" ); - } - ~NiKeyframeController(){} + NiKeyframeController(); + void Init() {} + ~NiKeyframeController() {} string GetBlockType() { return "NiKeyframeController"; } }; +/** + * NiKeyframeController + */ +class NiLookAtController : public AController { +public: + NiLookAtController(); + void Init() {} + ~NiLookAtController() {} + string GetBlockType() { return "NiLookAtController"; } +}; + /** * NiAlphaController */ class NiAlphaController : public AController { public: - NiAlphaController(){ - AddAttr( "link", "Data" ); - } - ~NiAlphaController(){} + NiAlphaController(); + void Init() {} + ~NiAlphaController() {} string GetBlockType() { return "NiAlphaController"; } }; +/** + * NiFlipController + */ +class NiFlipController : public AController { +public: + NiFlipController(); + void Init() {} + ~NiFlipController() {} + string GetBlockType() { return "NiFlipController"; } +}; + /** * NiVisController */ class NiVisController : public AController { public: - NiVisController(){ - AddAttr( "link", "Data" ); - } - ~NiVisController(){} + NiVisController(); + void Init() {} + ~NiVisController() {} string GetBlockType() { return "NiVisController"; } }; @@ -633,11 +754,9 @@ public: */ class NiMaterialColorController : public AController { public: - - NiMaterialColorController(){ - AddAttr( "link", "Data" ); - } - ~NiMaterialColorController(){} + NiMaterialColorController(); + void Init() {} + ~NiMaterialColorController() {} string GetBlockType() { return "NiMaterialColorController"; } }; @@ -646,11 +765,9 @@ public: */ class NiUVController : public AController { public: - NiUVController (){ - AddAttr( "link", "Data" ); - AddAttr( "short", "Unknown Short" ); - } - ~NiUVController (){} + NiUVController(); + void Init() {} + ~NiUVController() {} string GetBlockType() { return "NiUVController"; } }; @@ -660,15 +777,9 @@ public: class NiPathController : public AController { public: - NiPathController (){ - AddAttr( "int", "Unknown Int 1" ); - AddAttr( "int", "Unknown Int 2" ); - AddAttr( "int", "Unknown Int 3" ); - AddAttr( "short", "Unknown Short" ); - AddAttr( "link", "Pos Data" ); - AddAttr( "link", "Float Data" ); - } - ~NiPathController (){} + NiPathController(); + void Init() {} + ~NiPathController() {} string GetBlockType() { return "NiPathController"; } }; @@ -678,8 +789,9 @@ public: class NiAmbientLight : public ALight { public: - NiAmbientLight (){} - ~NiAmbientLight (){} + NiAmbientLight(); + void Init() {} + ~NiAmbientLight() {} string GetBlockType() { return "NiAmbientLight"; } }; @@ -689,8 +801,9 @@ public: class NiDirectionalLight : public ALight { public: - NiDirectionalLight (){} - ~NiDirectionalLight (){} + NiDirectionalLight(); + void Init() {} + ~NiDirectionalLight() {} string GetBlockType() { return "NiDirectionalLight"; } }; @@ -700,11 +813,9 @@ public: class NiAutoNormalParticles : public ANode { public: - NiAutoNormalParticles (){ - AddAttr( "link", "Data" ); - AddAttr( "link", "Unknown Index?" ); // Always -1 - } - ~NiAutoNormalParticles (){} + NiAutoNormalParticles(); + void Init() {} + ~NiAutoNormalParticles() {} string GetBlockType() { return "NiAutoNormalParticles"; } }; @@ -714,11 +825,9 @@ public: class NiRotatingParticles : public ANode { public: - NiRotatingParticles (){ - AddAttr( "link", "Data" ); - AddAttr( "link", "Unknown Index?" ); // Always -1 - } - ~NiRotatingParticles (){} + NiRotatingParticles(); + void Init() {} + ~NiRotatingParticles() {} string GetBlockType() { return "NiRotatingParticles"; } }; @@ -728,35 +837,9 @@ public: class NiTextureEffect : public ANode { public: - NiTextureEffect (){ - AddAttr( "condint", "Conditional Int" ); - AddAttr( "float", "Unknown Float 1" ); - AddAttr( "float", "Unknown Float 2" ); - AddAttr( "float", "Unknown Float 3" ); - AddAttr( "float", "Unknown Float 4" ); - AddAttr( "float", "Unknown Float 5" ); - AddAttr( "float", "Unknown Float 6" ); - AddAttr( "float", "Unknown Float 7" ); - AddAttr( "float", "Unknown Float 8" ); - AddAttr( "float", "Unknown Float 9" ); - AddAttr( "float", "Unknown Float 10" ); - AddAttr( "float", "Unknown Float 11" ); - AddAttr( "float", "Unknown Float 12" ); - AddAttr( "int", "Unknown Int 1" ); - AddAttr( "int", "Unknown Int 2" ); - AddAttr( "int", "Unknown Int 3" ); - AddAttr( "int", "Unknown Int 4" ); - AddAttr( "link", "Source Texture" ); - AddAttr( "byte", "Unknown Byte" ); - AddAttr( "float", "Unknown Float 13" ); - AddAttr( "float", "Unknown Float 14" ); - AddAttr( "float", "Unknown Float 15" ); - AddAttr( "float", "Unknown Float 16" ); - AddAttr( "short", "PS2 L?" ); - AddAttr( "short", "PS2 K?" ); - AddAttr( "short", "Unknown Short" ); - } - ~NiTextureEffect (){} + NiTextureEffect(); + void Init() {} + ~NiTextureEffect() {} string GetBlockType() { return "NiTextureEffect"; } }; @@ -766,106 +849,105 @@ public: class NiCamera : public ANode { public: - NiCamera (){ - AddAttr( "float", "Frustum Left" ); - AddAttr( "float", "Frustum Right" ); - AddAttr( "float", "Frustum Top" ); - AddAttr( "float", "Frustum Bottom" ); - AddAttr( "float", "Frustum Near" ); - AddAttr( "float", "Frustum Far" ); - AddAttr( "float", "Viewport Left" ); - AddAttr( "float", "Viewport Right" ); - AddAttr( "float", "Viewport Top" ); - AddAttr( "float", "Viewport Bottom" ); - AddAttr( "float", "LOLAdjust" ); - AddAttr( "link", "Unknown Index?" ); // Always -1 - AddAttr( "int", "Unknown Int" ); // Always 0 - } - ~NiCamera (){} + NiCamera(); + void Init() {} + ~NiCamera() {} string GetBlockType() { return "NiCamera"; } }; +/** + * NiParticleMeshes + */ + +class NiParticleMeshes : public ANode { +public: + NiParticleMeshes(); + void Init() {} + ~NiParticleMeshes() {} + string GetBlockType() { return "NiParticleMeshes"; } +}; + /** * NiGravity */ -class NiGravity : public ABlock { +class NiGravity : public AControllable { public: - NiGravity (){ - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - AddAttr( "float", "Unknown Float 1" ); - AddAttr( "float", "Unknown Float 2" ); - AddAttr( "int", "Unknown Int 1" ); - AddAttr( "float", "Unknown Float 3" ); - AddAttr( "float", "Unknown Float 4" ); - AddAttr( "float", "Unknown Float 5" ); - AddAttr( "float", "Unknown Float 6" ); - AddAttr( "float", "Unknown Float 7" ); - AddAttr( "float", "Unknown Float 8" ); - } - ~NiGravity (){} + NiGravity(); + void Init() {} + ~NiGravity() {} string GetBlockType() { return "NiGravity"; } }; +/** + * NiParticleBomb + */ + +class NiParticleBomb : public AControllable { +public: + NiParticleBomb(); + void Init() {} + ~NiParticleBomb() {} + string GetBlockType() { return "NiParticleBomb"; } +}; + /** * NiPlanarCollider */ -class NiPlanarCollider : public ABlock { -public: - NiPlanarCollider (){ - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - AddAttr( "float", "Unknown Float 1" ); - AddAttr( "float", "Unknown Float 2" ); - AddAttr( "float", "Unknown Float 3" ); - AddAttr( "float", "Unknown Float 4" ); - AddAttr( "float", "Unknown Float 5" ); - AddAttr( "float", "Unknown Float 6" ); - AddAttr( "float", "Unknown Float 7" ); - AddAttr( "float", "Unknown Float 8" ); - AddAttr( "float", "Unknown Float 9" ); - AddAttr( "float", "Unknown Float 10" ); - AddAttr( "float", "Unknown Float 11" ); - AddAttr( "float", "Unknown Float 12" ); - AddAttr( "float", "Unknown Float 13" ); - AddAttr( "float", "Unknown Float 14" ); - AddAttr( "float", "Unknown Float 15" ); - AddAttr( "float", "Unknown Float 16" ); - } - ~NiPlanarCollider (){} +class NiPlanarCollider : public AControllable { +public: + NiPlanarCollider(); + void Init() {} + ~NiPlanarCollider() {} string GetBlockType() { return "NiPlanarCollider"; } }; +/** + * NiPlanarCollider + */ + +class NiSphericalCollider : public AControllable { +public: + NiSphericalCollider(); + void Init() {} + ~NiSphericalCollider() {} + string GetBlockType() { return "NiSphericalCollider"; } +}; + /** * NiParticleGrowFade */ -class NiParticleGrowFade : public ABlock { +class NiParticleGrowFade : public AControllable { public: - NiParticleGrowFade (){ - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - AddAttr( "float", "Unknown Float 1" ); - AddAttr( "float", "Unknown Float 2" ); - } - ~NiParticleGrowFade (){} + NiParticleGrowFade(); + void Init() {} + ~NiParticleGrowFade() {} string GetBlockType() { return "NiParticleGrowFade"; } }; /** - * NiParticleGrowFade + * NiParticleMeshModifier */ -class NiParticleColorModifier : public ABlock { +class NiParticleMeshModifier : public AControllable { public: - NiParticleColorModifier (){ - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - AddAttr( "link", "Color Data" ); - } - ~NiParticleColorModifier (){} + NiParticleMeshModifier(); + void Init() {} + ~NiParticleMeshModifier() {} + string GetBlockType() { return "NiParticleMeshModifier"; } +}; + +/** + * NiParticleColorModifier + */ + +class NiParticleColorModifier : public AControllable { +public: + NiParticleColorModifier(); + void Init() {} + ~NiParticleColorModifier() {} string GetBlockType() { return "NiParticleColorModifier"; } }; @@ -873,54 +955,23 @@ public: * NiGravity */ -class NiParticleRotation : public ABlock { +class NiParticleRotation : public AControllable { public: - NiParticleRotation (){ - AddAttr( "link", "Extra Data" ); - AddAttr( "link", "Controller" ); - AddAttr( "byte", "Unknown Byte" ); - AddAttr( "float", "Unknown Float 1" ); - AddAttr( "float", "Unknown Float 2" ); - AddAttr( "float", "Unknown Float 3" ); - AddAttr( "float", "Unknown Float 4" ); - } - ~NiParticleRotation (){} + NiParticleRotation(); + void Init() {} + ~NiParticleRotation() {} string GetBlockType() { return "NiParticleRotation"; } }; -//NiGravity : Controlled -// -// float[2] unknown -// int unknown -// float[6] unknown -// -//NiPlanarCollider : Controlled -// -// float unknown[16] -// -//NiParticleGrowFade : Controlled -// -// float unknown[2] -// -//NiParticleColorModifier : Controlled -// -// int colorIndex - index to NiColorData record -// -//NiParticleRotation : Controlled -// -// byte unknown -// float unknown = 1 -// float unknown[3] - /** * NiKeyframeData - */ -class NiKeyframeData : public ABlock, public IKeyframeData { +class NiKeyframeData : public AData, public IKeyframeData { public: - NiKeyframeData(){} - ~NiKeyframeData(){} + NiKeyframeData() {} + ~NiKeyframeData() {} void Read( ifstream& in, unsigned int version ); void Write( ofstream& out, unsigned int version ); @@ -962,13 +1013,37 @@ class NiKeyframeData : public ABlock, public IKeyframeData { vector< Key<float> > scaleKeys; }; +/** + * NiPalette + */ + +class NiPalette : public AData { +public: + NiPalette() {} + void Init() {} + ~NiPalette() {} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + + string GetBlockType() { return "NiPalette"; } +private: + byte unknownBytes[5]; + byte palette[256][4]; +}; + +/** + * NiSkinPartition + */ -//-- Skin Stuff --// +class NiSkinPartition : public AData { +public: + NiSkinPartition(); + void Init() {} + ~NiSkinPartition() {} + string GetBlockType() { return "NiSkinPartition"; } +}; - //int data - NiSkinData index - //int root - Skeleton root NiNode index (?) - //int boneCount - //int bones[boneCount] - Index of bones (NiNode records) /** * NiSkinInstance @@ -981,37 +1056,35 @@ public: virtual void ReadBoneList( ifstream& in ) = 0; }; -class NiSkinInstance : public ABlock, public ISkinInstInternal { - - public: - - NiSkinInstance(){ - AddAttr( "link", "Data" ); - AddAttr( "skeletonroot", "Skeleton Root" ); - AddAttr( "bones", "Bones" ); - } - ~NiSkinInstance(){} - string GetBlockType() { return "NiSkinInstance"; } +class NiSkinInstance : public AData, public ISkinInstInternal { +public: + NiSkinInstance(){ + AddAttr( "link", "Data" ); + AddAttr( "skeletonroot", "Skeleton Root" ); + AddAttr( "bones", "Bones" ); + } + ~NiSkinInstance() {} + string GetBlockType() { return "NiSkinInstance"; } - void * QueryInterface( int id ) { - if ( id == SkinInstInternal ) { - return (void*)static_cast<ISkinInstInternal*>(this);; - } else { - return ABlock::QueryInterface( id ); - } + void * QueryInterface( int id ) { + if ( id == SkinInstInternal ) { + return (void*)static_cast<ISkinInstInternal*>(this);; + } else { + return ABlock::QueryInterface( id ); } + } - //ISkinInstInternal + //ISkinInstInternal - vector<int> GetBoneList() { return bones; } + vector<int> GetBoneList() { return bones; } - void ReadBoneList( ifstream& in ) { - int len = ReadUInt( in ); - bones.resize( len ); - for (int i = 0; i < len; ++i ) { - bones[i] = ReadUInt( in ); - } + void ReadBoneList( ifstream& in ) { + int len = ReadUInt( in ); + bones.resize( len ); + for (int i = 0; i < len; ++i ) { + bones[i] = ReadUInt( in ); } + } private: vector<int> bones; }; @@ -1024,17 +1097,18 @@ public: virtual void RemoveBoneByPtr( IBlock * bone ) = 0; }; -class NiSkinData : public ABlock, public ISkinData, public ISkinDataInternal { +class NiSkinData : public AData, public ISkinData, public ISkinDataInternal { public: - NiSkinData(){ + NiSkinData() { SetIdentity33(rotation); translation[0] = 0.0f; translation[1] = 0.0f; translation[2] = 0.0f; scale = 1.0f; - unknown = -1; + unknownInt = -1; + unknownByte = 1; } ~NiSkinData(); @@ -1068,7 +1142,8 @@ class NiSkinData : public ABlock, public ISkinData, public ISkinDataInternal { Matrix33 rotation; fVector3 translation; float scale; - int unknown; + int unknownInt; + byte unknownByte; map<IBlock*, Bone> bone_map; vector<Bone> bones; }; @@ -1076,233 +1151,232 @@ class NiSkinData : public ABlock, public ISkinData, public ISkinDataInternal { //-- New Nodes--// class NiGeomMorpherController : public AController{ +public: + NiGeomMorpherController(); + void Init() {} + ~NiGeomMorpherController() {} - public: - - NiGeomMorpherController(){ - AddAttr( "link", "Morph Data" ); - AddAttr( "byte", "Unknown Byte" ); - } - ~NiGeomMorpherController(){} - - string asString(); - string GetBlockType() { return "NiGeomMorpherController"; } + string asString(); + string GetBlockType() { return "NiGeomMorpherController"; } }; -class NiColorData : public ABlock{ - - public: - - NiColorData(){} - ~NiColorData(){} +class NiColorData : public AData { +public: + NiColorData() {} + ~NiColorData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiColorData"; }; + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiColorData"; }; - private: - uint colorCount, keyType; - vector<Key<fVector4> > keys; +private: + uint keyType; + vector< Key<fVector4> > keys; }; -class NiFloatData : public ABlock{ +/** + * NiControllerSequence - Root node in .kf files (version 10.0.1.0 and up). + */ +class NiControllerSequence : public AData { +public: + NiControllerSequence() { + _namable = true; + } + ~NiControllerSequence() {} - public: + string GetBlockType() { return "NiControllerSequence"; } +private: + vector< pair< string, blk_ref> > controllers; +}; - NiFloatData(){} - ~NiFloatData(){} +class NiFloatData : public AData { +public: + NiFloatData() {} + ~NiFloatData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiFloatData"; }; + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiFloatData"; }; - private: - uint colorCount, keyType; - vector<Key<float> > keys; +private: + uint keyType; + vector<Key<float> > keys; }; -class NiStringExtraData : public AExtraData{ - - public: +class NiStringExtraData : public AExtraData { +public: + NiStringExtraData() { + AddAttr( "string", "String Data" ); + } + ~NiStringExtraData() {} - NiStringExtraData(){ - AddAttr( "string", "String Data" ); - } - ~NiStringExtraData(){} + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiStringExtraData"; } +}; - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ); - string asString(); - string GetBlockType() { return "NiStringExtraData"; }; +class NiBooleanExtraData : public AExtraData { +public: + NiBooleanExtraData() { + AddAttr( "byte", "Boolean Data" ); + } + ~NiBooleanExtraData() {} - private: - string strData; + string GetBlockType() { return "NiBooleanExtraData"; }; }; -class NiMorphData : public ABlock, public IMorphData { +class NiIntegerExtraData : public AExtraData { +public: + NiIntegerExtraData() { + AddAttr( "int", "Integer Data" ); + } + ~NiIntegerExtraData() {} - public: + string GetBlockType() { return "NiIntegerExtraData"; }; +}; - NiMorphData(){ - AddAttr( "byte", "Unknown Byte" ); - } - ~NiMorphData(){} +class NiMorphData : public AData, public IMorphData { +public: + NiMorphData() { + AddAttr( "byte", "Unknown Byte" ); + } + ~NiMorphData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ); - string asString(); - string GetBlockType() { return "NiMorphData"; }; + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiMorphData"; }; - void * QueryInterface( int id ) { - if ( id == ID_MORPH_DATA ) { - return (void*)static_cast<IMorphData*>(this);; - } else { - return ABlock::QueryInterface( id ); - } + void * QueryInterface( int id ) { + if ( id == ID_MORPH_DATA ) { + return (void*)static_cast<IMorphData*>(this);; + } else { + return ABlock::QueryInterface( id ); } + } - //--IMorphData Functions --// - int GetVertexCount() { return vertCount; } - void SetVertexCount( int n ); - int GetMorphCount() { return int(morphs.size()); } - void SetMorphCount( int n ) { morphs.resize( n ); } - vector< Key<float> > GetMorphKeys( int n ) { return morphs[n].keys; } - void SetMorphKeys( int n, vector< Key<float> > & keys ) { morphs[n].keys = keys; } - vector<Vector3> GetMorphVerts( int n) { return morphs[n].morph; } - void SetMorphVerts( int n, const vector<Vector3> & in ); + //--IMorphData Functions --// + int GetVertexCount() { return vertCount; } + void SetVertexCount( int n ); + int GetMorphCount() { return int(morphs.size()); } + void SetMorphCount( int n ) { morphs.resize( n ); } + vector< Key<float> > GetMorphKeys( int n ) { return morphs[n].keys; } + void SetMorphKeys( int n, vector< Key<float> > & keys ) { morphs[n].keys = keys; } + vector<Vector3> GetMorphVerts( int n) { return morphs[n].morph; } + void SetMorphVerts( int n, const vector<Vector3> & in ); - private: - struct Morph { - Morph() : keyType(QUADRATIC_KEY) {} - ~Morph() {} - KeyType keyType; - vector< Key<float> > keys; - vector< Vector3 > morph; - }; - - uint vertCount; - vector<Morph> morphs; +private: + struct Morph { + Morph() : keyType(QUADRATIC_KEY) {} + ~Morph() {} + KeyType keyType; + vector< Key<float> > keys; + vector< Vector3 > morph; + }; + + uint vertCount; + vector<Morph> morphs; }; -class NiPosData : public ABlock{ - - public: - - NiPosData(){} - ~NiPosData(){} +class NiPosData : public AData { +public: + NiPosData() {} + ~NiPosData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiPosData"; } + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiPosData"; } - private: - uint posCount, keyType; - vector<Key<fVector3> > keys; +private: + uint keyType; + vector<Key<fVector3> > keys; }; -class NiRotatingParticlesData : public ABlock{ - - public: - - NiRotatingParticlesData(){} - ~NiRotatingParticlesData(){} - - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString() { return string(""); }; - string GetBlockType() { return "NiRotationparticlesData"; } - - private: +class NiRotatingParticlesData : public ARotatingParticlesData { +public: + NiRotatingParticlesData() {} + ~NiRotatingParticlesData() {} + string GetBlockType() { return "NiRotationparticlesData"; } }; class NiTextKeyExtraData : public AExtraData, public ITextKeyExtraData { +public: + NiTextKeyExtraData() { + AddAttr( "int", "Unknown Int", 0, 0x04020200 ); + } + ~NiTextKeyExtraData() {} - public: - - NiTextKeyExtraData(){ - AddAttr( "int", "Unknown Int" ); - } - ~NiTextKeyExtraData(){} - - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ); - string asString(); - string GetBlockType() { return "NiTextKeyExtraData"; } + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiTextKeyExtraData"; } - void * QueryInterface( int id ) { - if ( id == ID_TEXT_KEY_EXTRA_DATA ) { - return (void*)static_cast<ITextKeyExtraData*>(this);; - } else { - return AExtraData::QueryInterface( id ); - } + void * QueryInterface( int id ) { + if ( id == ID_TEXT_KEY_EXTRA_DATA ) { + return (void*)static_cast<ITextKeyExtraData*>(this);; + } else { + return AExtraData::QueryInterface( id ); } + } - //--ITextKeyExtraData Functions--// - virtual vector< Key<string> > GetRotateKeys() { return _keys; } - virtual void SetRotateKeys( vector< Key<string> > & keys ) { _keys = keys; } + //--ITextKeyExtraData Functions--// + virtual vector< Key<string> > GetRotateKeys() { return _keys; } + virtual void SetRotateKeys( vector< Key<string> > & keys ) { _keys = keys; } - private: - vector< Key<string> > _keys; +private: + vector< Key<string> > _keys; }; -class NiUVData : public ABlock{ - - public: - - NiUVData(){} - ~NiUVData(){} +class NiUVData : public AData { +public: + NiUVData() {} + ~NiUVData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiUVData"; } + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiUVData"; } - private: - struct UVGroup { - uint count; - uint keyType; - vector<Key<float> > keys; - }; - UVGroup groups[4]; +private: + struct UVGroup { + uint keyType; + vector<Key<float> > keys; + }; + UVGroup groups[4]; }; class NiVertWeightsExtraData : public AExtraData{ +public: + NiVertWeightsExtraData() {} + ~NiVertWeightsExtraData() {} - public: - - NiVertWeightsExtraData(){} - ~NiVertWeightsExtraData(){} - - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiVertWeightsExtraData"; } + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiVertWeightsExtraData"; } - private: - uint bytes; - ushort verts; - vector<float> weights; +private: + uint bytes; + vector<float> weights; }; -class NiVisData : public ABlock{ - - public: - - NiVisData(){} - ~NiVisData(){} +class NiVisData : public AData { +public: + NiVisData() {} + ~NiVisData() {} - void Read( ifstream& in, unsigned int version ); - void Write( ofstream& out, unsigned int version ) {} - string asString(); - string GetBlockType() { return "NiVisData"; } + void Read( ifstream& in, unsigned int version ); + void Write( ofstream& out, unsigned int version ); + string asString(); + string GetBlockType() { return "NiVisData"; } - private: - uint visCount; - vector<Key<byte> > keys; +private: + vector<Key<byte> > keys; }; class UnknownMixIn { @@ -1311,7 +1385,7 @@ public: data = NULL; _block_type = block_type; } - ~UnknownMixIn(){ if (data != NULL) delete [] data; } + ~UnknownMixIn() { if (data != NULL) delete [] data; } void Read( ifstream& in, unsigned int version ); void Write( ofstream& out, unsigned int version ); string asString(); @@ -1326,7 +1400,7 @@ private: class UnknownBlock : public ABlock, public UnknownMixIn { public: UnknownBlock( string block_type ) : UnknownMixIn(block_type) {} - ~UnknownBlock(){} + ~UnknownBlock() {} void Read( ifstream& in, unsigned int version ) { //cout << endl << "Unknown Block Type found: " << GetBlockType() << "\a" << endl; ABlock::Read( in, version ); @@ -1346,7 +1420,7 @@ public: class UnknownControllerBlock : public AController, public UnknownMixIn { public: UnknownControllerBlock( string block_type ) : UnknownMixIn(block_type) {} - ~UnknownControllerBlock(){} + ~UnknownControllerBlock() {} void Read( ifstream& in, unsigned int version ) { ABlock::Read( in, version ); UnknownMixIn::Read( in, version ); @@ -1371,7 +1445,7 @@ public: class UnknownPropertyBlock : public AProperty, public UnknownMixIn { public: UnknownPropertyBlock( string block_type ) : UnknownMixIn(block_type) {} - ~UnknownPropertyBlock(){} + ~UnknownPropertyBlock() {} void Read( ifstream& in, unsigned int version ) { ABlock::Read( in, version ); UnknownMixIn::Read( in, version ); @@ -1396,111 +1470,23 @@ public: /** * NiParticleSystemController */ -class NiParticleSystemController : public AController { -public: - NiParticleSystemController() { - AddAttr( "float", "Unknown 16 Floats[0]" ); - AddAttr( "float", "Unknown 16 Floats[1]" ); - AddAttr( "float", "Unknown 16 Floats[2]" ); - AddAttr( "float", "Unknown 16 Floats[3]" ); - AddAttr( "float", "Unknown 16 Floats[4]" ); - AddAttr( "float", "Unknown 16 Floats[5]" ); - AddAttr( "float", "Unknown 16 Floats[6]" ); - AddAttr( "float", "Unknown 16 Floats[7]" ); - AddAttr( "float", "Unknown 16 Floats[8]" ); - AddAttr( "float", "Unknown 16 Floats[9]" ); - AddAttr( "float", "Unknown 16 Floats[10]" ); - AddAttr( "float", "Unknown 16 Floats[11]" ); - AddAttr( "float", "Unknown 16 Floats[12]" ); - AddAttr( "float", "Unknown 16 Floats[13]" ); - AddAttr( "float", "Unknown 16 Floats[14]" ); - AddAttr( "float", "Unknown 16 Floats[15]" ); - AddAttr( "byte", "Unknown Byte" ); - AddAttr( "float3", "Unknown 3 Floats" ); - AddAttr( "short", "Unknown Short" ); - AddAttr( "float3", "Unknown 3 Floats 2" ); - AddAttr( "link", "Emitter" ); - AddAttr( "byte", "Unknown 16 Bytes[0]" ); - AddAttr( "byte", "Unknown 16 Bytes[1]" ); - AddAttr( "byte", "Unknown 16 Bytes[2]" ); - AddAttr( "byte", "Unknown 16 Bytes[3]" ); - AddAttr( "byte", "Unknown 16 Bytes[4]" ); - AddAttr( "byte", "Unknown 16 Bytes[5]" ); - AddAttr( "byte", "Unknown 16 Bytes[6]" ); - AddAttr( "byte", "Unknown 16 Bytes[7]" ); - AddAttr( "byte", "Unknown 16 Bytes[8]" ); - AddAttr( "byte", "Unknown 16 Bytes[9]" ); - AddAttr( "byte", "Unknown 16 Bytes[10]" ); - AddAttr( "byte", "Unknown 16 Bytes[11]" ); - AddAttr( "byte", "Unknown 16 Bytes[12]" ); - AddAttr( "byte", "Unknown 16 Bytes[13]" ); - AddAttr( "byte", "Unknown 16 Bytes[14]" ); - AddAttr( "byte", "Unknown 16 Bytes[15]" ); - AddAttr( "particlegroup", "Particles" ); - AddAttr( "link", "Unknown Link" ); - AddAttr( "link", "Particle Extra" ); - AddAttr( "link", "Unknown Link 2" ); - AddAttr( "byte", "Trailer" ); - - - } - - //void Read( ifstream& in, unsigned int version ) { - - // ABlock::Read( in, version ); - - // uint count = GetAttr("Num Particles")->asInt(); - - // //cout << "Count: " << count << endl; - - // //short num = 0; - // //short last_num = -1; - // //int n = 0; - // //IAttr * attr = new MatrixAttr( "" ); - // //cout << setprecision(3); - // for ( int i = 0; i < count; ++i ) { - // //attr->Read( in ); - // //attr->Print( cout ); - // ReadFloat( in ); ReadFloat( in ); ReadFloat( in ); - // ReadFloat( in ); ReadFloat( in ); ReadFloat( in ); - // ReadFloat( in ); ReadFloat( in ); ReadFloat( in ); - // ReadUShort( in ); - // ReadUShort( in ); - // //cout << " " << num << endl; - - // //if ( num != last_num + 1 ) - // // break; - - // //last_num = num; - // //++n; - - // } - - // //in.seekg( -40, ios::cur ); - - // //cout << "True Count: " << n << endl; - - // //if ( n != count ) { - // // cout << "\a"; - // // cin.get(); - // //} - - // - // UnknownMixIn::Read( in, version ); - - // - // //if (!b) { - // // cout << ReadFloat( in ) << endl - // // << ReadFloat( in ) << endl - // // << ReadFloat( in ) << endl - // // << ReadFloat( in ) << endl; - // //} - // - // - //} - - ~NiParticleSystemController(){} +class NiParticleSystemController : public AParticleSystemController { +public: + NiParticleSystemController(); + void Init() {} + ~NiParticleSystemController() {} string GetBlockType() { return "NiParticleSystemController"; } }; -#endif // TAH_NIF_LIB_NIF_BLOCKS_H +/** + * NiBSPArrayController + */ +class NiBSPArrayController : public AParticleSystemController { +public: + NiBSPArrayController(); + void Init() {} + ~NiBSPArrayController() {} + string GetBlockType() { return "NiBSPArrayController"; } +}; + +#endif diff --git a/NIF_IO.cpp b/NIF_IO.cpp index 974048d3..1a15b0a4 100644 --- a/NIF_IO.cpp +++ b/NIF_IO.cpp @@ -231,6 +231,16 @@ string ReadString( ifstream &in ) { return out; } +bool ReadBool( ifstream &in, unsigned int version ) { + if ( version < 0x04010001 ) { + //Bools are stored as integers before version 4.1.0.1 + return (ReadUInt( in ) != 0); + } else { + //And as bytes from 4.1.0.1 on + return (ReadByte( in ) != 0); + } +} + /** * Write utility functions. */ @@ -287,6 +297,16 @@ void WriteString( string val, ofstream& out ) { out.write( val.c_str(), std::streamsize(val.size()) ); } +void WriteBool( bool val, ofstream& out, unsigned int version ) { + if ( version < 0x04010001 ) { + //Bools are stored as integers before version 4.1.0.1 + WriteUInt(int(val), out ); + } else { + //And as bytes from 4.1.0.1 on + WriteByte(byte(val), out ); + } +} + void WriteBlockName( const char* name, uint nameLength, ofstream& out ){ WriteUInt( nameLength, out ); diff --git a/NIF_IO.h b/NIF_IO.h index 1860fefd..b70ba863 100644 --- a/NIF_IO.h +++ b/NIF_IO.h @@ -196,6 +196,8 @@ float ReadFloat( ifstream &in ); string ReadString( ifstream &in ); +bool ReadBool( ifstream &in, unsigned int version ); + void ReadUSVector3( usVector3& vec, ifstream& in ); void ReadFVector2( fVector2& fvec, ifstream& in ); @@ -219,6 +221,8 @@ void WriteFloat( float val, ofstream& out ); void WriteString( string val, ofstream& out ); +void WriteBool( bool val, ofstream& out, unsigned int version ); + void WriteFVector2( fVector2& fvec, ofstream& out ); void WriteFVector3( fVector3& fvec, ofstream& out ); @@ -251,4 +255,4 @@ private: -#endif // TAH_NIF_LIB_NIF_IO_H +#endif diff --git a/nif_attrs.h b/nif_attrs.h index 8b62ab6b..8033dd88 100644 --- a/nif_attrs.h +++ b/nif_attrs.h @@ -46,7 +46,7 @@ const char ATTRERR[] = "Attribute type Missmatch."; class AAttr : public IAttr { public: - AAttr( string name, IBlock * owner ) : _name(name), _owner(owner) {} + AAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : _name(name), _owner(owner), _first_ver(first_ver), _last_ver(last_ver) {} ~AAttr() {} string GetType() const { return "void"; } string GetName() const { return _name; } @@ -79,9 +79,25 @@ public: void ClearLinks() { cout << "ClearLinks" << endl; throw runtime_error(ATTRERR); } void RemoveLinks( blk_ref block ) { cout << "RemoveLinks" << endl; throw runtime_error(ATTRERR); } blk_ref FindLink( string block_type ) { cout << "FindLink" << endl; throw runtime_error(ATTRERR); } + //Read/WriteFunctions + void Read( ifstream& in, unsigned int version ) { + if ( version >= _first_ver && version <= _last_ver ) { + this->ReadAttr( in, version ); + } + } + void Write( ofstream& out, unsigned int version ) { + if ( version >= _first_ver && version <= _last_ver ) { + this->WriteAttr( out, version ); + } + } protected: + //Internal Read/Write Functions + virtual void ReadAttr( ifstream& in, unsigned int version ) = 0; + virtual void WriteAttr( ofstream& out, unsigned int version ) = 0; + string _name; IBlock * _owner; + unsigned int _first_ver, _last_ver; }; class lnk_ref : public blk_ref { @@ -161,11 +177,11 @@ private: class IntAttr : public AAttr { public: - IntAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + IntAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~IntAttr() {} string GetType() const { return "int"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -183,11 +199,11 @@ private: class ShortAttr : public AAttr { public: - ShortAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + ShortAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~ShortAttr() {} string GetType() const { return "short"; } - void Read( ifstream& in ) { data = ReadUShort( in ); } - void Write( ofstream& out ) { WriteUShort( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUShort( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUShort( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -205,11 +221,11 @@ private: class ByteAttr : public AAttr { public: - ByteAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + ByteAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~ByteAttr() {} string GetType() const { return "byte"; } - void Read( ifstream& in ) { data = ReadByte( in ); } - void Write( ofstream& out ) { WriteByte( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadByte( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteByte( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -227,11 +243,11 @@ private: class FloatAttr : public AAttr { public: - FloatAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0.0f) {} + FloatAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0.0f) {} ~FloatAttr() {} string GetType() const { return "float"; } - void Read( ifstream& in ) { data = ReadFloat( in ); } - void Write( ofstream& out ) { WriteFloat( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadFloat( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteFloat( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -249,19 +265,19 @@ private: class Float3Attr : public AAttr { public: - Float3Attr( string name, IBlock * owner) : AAttr(name, owner) { + Float3Attr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver) : AAttr(name, owner, first_ver, last_ver) { data[0] = 0.0f; data[1] = 0.0f; data[2] = 0.0f; } ~Float3Attr() {} string GetType() const { return "float3"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { data[0] = ReadFloat( in ); data[1] = ReadFloat( in ); data[2] = ReadFloat( in ); } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteFloat( data[0], out ); WriteFloat( data[1], out ); WriteFloat( data[2], out ); @@ -294,11 +310,11 @@ private: class StringAttr : public AAttr { public: - StringAttr( string name, IBlock * owner) : AAttr( name, owner ) {} + StringAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ) {} ~StringAttr() {} string GetType() const { return "string"; } - void Read( ifstream& in ) { data = ReadString( in ); } - void Write( ofstream& out ) { WriteString( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadString( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteString( data, out ); } string asString() const { return data; } void Set(string & n) { data = n; } private: @@ -307,10 +323,10 @@ private: class LinkAttr : public AAttr { public: - LinkAttr( string name, IBlock * owner ) : AAttr( name, owner ), link( owner ) {} + LinkAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), link( owner ) {} ~LinkAttr() {} string GetType() const { return "link"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { ////Remove all links beloning to this attribute //_owner->RemoveAttrLinks(this); @@ -323,7 +339,7 @@ public: //Set block index only link.set_index( ReadUInt( in ) ); } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( link.get_index(), out ); } string asString() const { @@ -357,11 +373,11 @@ private: class FlagsAttr : public AAttr { public: - FlagsAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + FlagsAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~FlagsAttr() {} string GetType() const { return "flags"; } - void Read( ifstream& in ) { data = ReadUShort( in ); } - void Write( ofstream& out ) { WriteUShort( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUShort( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUShort( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -386,21 +402,21 @@ private: class MatrixAttr : public AAttr { public: - MatrixAttr( string name, IBlock * owner) : AAttr( name, owner ) { + MatrixAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ) { data[0][0] = 1.0f; data[0][1] = 0.0f; data[0][2] = 0.0f; data[1][0] = 0.0f; data[1][1] = 1.0f; data[1][2] = 0.0f; data[2][0] = 0.0f; data[2][1] = 0.0f; data[2][2] = 1.0f; } ~MatrixAttr() {} string GetType() const { return "matrix33"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { for (int c = 0; c < 3; ++c) { for (int r = 0; r < 3; ++r) { data[r][c] = ReadFloat( in ); } } } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { for (int c = 0; c < 3; ++c) { for (int r = 0; r < 3; ++r) { WriteFloat( data[r][c], out ); @@ -456,9 +472,9 @@ private: class BoneAttr : public AAttr { public: - BoneAttr( string name, IBlock * owner ) : AAttr(name, owner) {} + BoneAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr(name, owner, first_ver, last_ver) {} ~BoneAttr() {} - void Read ( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { ISkinInstInternal * data = (ISkinInstInternal*)_owner->QueryInterface( SkinInstInternal ); if ( data != NULL ) { data->ReadBoneList( in ); @@ -466,7 +482,7 @@ public: throw runtime_error ("Attempted to use a bone list attribute on a block that doesn't support it."); } } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { ISkinInstInternal * data = (ISkinInstInternal*)_owner->QueryInterface( SkinInstInternal ); blk_ref data_blk = _owner->GetAttr("Data")->asLink(); if ( data_blk.is_null() == false ) { @@ -519,10 +535,10 @@ typedef LinkSetList::iterator LinkSetIt; class LinkGroupAttr : public AAttr { public: - LinkGroupAttr( string name, IBlock * owner ) : AAttr( name, owner ) {} + LinkGroupAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ) {} ~LinkGroupAttr() {} string GetType() const { return "linkgroup"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { int len = ReadUInt( in ); //cout << "Link Group Size: " << len << endl; @@ -536,7 +552,7 @@ public: AddLink( blk_ref( index ) ); } } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { //Write the number of links WriteUInt( uint(links.size()), out ); //cout << "Link Group Size: " << uint(links.size()) << endl; @@ -618,7 +634,7 @@ private: class BBoxAttr : public AAttr { public: - BBoxAttr( string name, IBlock * owner) : AAttr( name, owner ) { + BBoxAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ) { data.isUsed = false; data.unknownInt = 0; @@ -635,8 +651,8 @@ public: } ~BBoxAttr() {} string GetType() const { return "bbox"; } - void Read( ifstream& in ) { - data.isUsed = (ReadUInt( in ) != 0); + void ReadAttr( ifstream& in, unsigned int version ) { + data.isUsed = ReadBool( in, version ); if ( data.isUsed ){ data.unknownInt = ReadUInt( in ); data.translation.x = ReadFloat( in ); @@ -652,8 +668,8 @@ public: data.radius.z = ReadFloat( in ); } } - void Write( ofstream& out ) { - WriteUInt(int(data.isUsed), out ); + void WriteAttr( ofstream& out, unsigned int version ) { + WriteBool( data.isUsed, out, version ); if ( data.isUsed ){ WriteUInt( data.unknownInt, out ); WriteFloat( data.translation.x, out ); @@ -700,20 +716,20 @@ private: class CIntAttr : public AAttr { public: - CIntAttr( string name, IBlock * owner) : AAttr( name, owner ) { + CIntAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ) { data.isUsed = false; data.unknownInt = 0; } ~CIntAttr() {} string GetType() const { return "condint"; } - void Read( ifstream& in ) { - data.isUsed = ( ReadUInt( in ) != 0 ); + void ReadAttr( ifstream& in, unsigned int version ) { + data.isUsed = ReadBool( in, version ); if (data.isUsed) { data.unknownInt = ReadUInt( in ); } } - void Write( ofstream& out ) { - WriteUInt( int(data.isUsed), out ); + void WriteAttr( ofstream& out, unsigned int version ) { + WriteBool( data.isUsed, out, version ); if (data.isUsed) { WriteUInt( data.unknownInt, out ); } @@ -743,11 +759,11 @@ private: class VertModeAttr : public AAttr { public: - VertModeAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + VertModeAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~VertModeAttr() {} string GetType() const { return "vertmode"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -778,11 +794,11 @@ private: class LightModeAttr : public AAttr { public: - LightModeAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + LightModeAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~LightModeAttr() {} string GetType() const { return "lightmode"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -821,23 +837,28 @@ private: class TextureAttr : public LinkAttr { public: - TextureAttr( string name, IBlock * owner, bool isBumpMap = false ) : LinkAttr(name, owner), _isBumpMap(isBumpMap) { + TextureAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver, bool isBumpMap = false ) : LinkAttr(name, owner, first_ver, last_ver), _isBumpMap(isBumpMap) { memset( &data, 0, sizeof(data) ); } ~TextureAttr() {} string GetType() const { return "texture"; } - void Read( ifstream& in ) { - data.isUsed = ( ReadUInt( in ) != 0 ); + void ReadAttr( ifstream& in, unsigned int version ) { + data.isUsed = ReadBool( in, version ); if ( data.isUsed ) { //Read in link for TextureSource - LinkAttr::Read( in ); + LinkAttr::ReadAttr( in, version ); data.clampMode = TexClampMode( ReadUInt( in ) ); data.filterMode = TexFilterMode( ReadUInt( in ) ); data.textureSet = ReadUInt( in ); data.PS2_L = ReadUShort( in ); data.PS2_K = ReadUShort( in ); - data.unknownShort = ReadUShort( in ); + + //unknownShort exists up to version 4.1.0.12 + if ( version <= 0x0401000C ) { + data.unknownShort = ReadUShort( in ); + } + if ( _isBumpMap ) { data.bmLumaScale = ReadFloat( in ); data.bmLumaOffset = ReadFloat( in ); @@ -848,18 +869,21 @@ public: } } } - void Write( ofstream& out ) { - WriteUInt( uint(data.isUsed), out ); + void WriteAttr( ofstream& out, unsigned int version ) { + WriteBool( data.isUsed, out, version ); if ( data.isUsed ) { //Write link - LinkAttr::Write( out ); + LinkAttr::WriteAttr( out, version ); WriteUInt( data.clampMode, out ); WriteUInt( data.filterMode, out ); WriteUInt( data.textureSet, out ); WriteUShort( data.PS2_L, out ); WriteUShort( data.PS2_K, out ); - WriteUShort( data.unknownShort, out ); + //unknownShort exists up to version 4.1.0.12 + if ( version <= 0x0401000C ) { + WriteUShort( data.unknownShort, out ); + } if ( _isBumpMap ) { WriteFloat( data.bmLumaScale, out ); WriteFloat( data.bmLumaOffset, out ); @@ -981,11 +1005,11 @@ private: class ApplyModeAttr : public AAttr { public: - ApplyModeAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + ApplyModeAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~ApplyModeAttr() {} string GetType() const { return "applymode"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -1029,12 +1053,12 @@ private: class TexSourceAttr : public LinkAttr { public: - TexSourceAttr( string name, IBlock * owner ) : LinkAttr(name, owner) {} + TexSourceAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : LinkAttr(name, owner, first_ver, last_ver) {} ~TexSourceAttr() { memset(&data, 0, sizeof(data) ); } string GetType() const { return "texsource"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { data.useExternal = ( ReadByte( in ) != 0 ); if ( data.useExternal ) { data.fileName = ReadString( in ); @@ -1042,17 +1066,17 @@ public: data.unknownByte = ReadByte( in ); //Read link for Pixel Data - LinkAttr::Read( in ); + LinkAttr::ReadAttr( in, version ); } } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteByte( byte(data.useExternal), out ); if ( data.useExternal ) { WriteString( data.fileName, out ); } else { WriteByte ( data.unknownByte, out ); //Write link for Pixel Data - LinkAttr::Write( out ); + LinkAttr::WriteAttr( out, version ); } } string asString() const { @@ -1085,11 +1109,11 @@ private: class PixelLayoutAttr : public AAttr { public: - PixelLayoutAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + PixelLayoutAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~PixelLayoutAttr() {} string GetType() const { return "pixellayout"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -1138,11 +1162,11 @@ private: class MipMapFormatAttr : public AAttr { public: - MipMapFormatAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + MipMapFormatAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~MipMapFormatAttr() {} string GetType() const { return "mipmapformat"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -1179,11 +1203,11 @@ private: class AlphaFormatAttr : public AAttr { public: - AlphaFormatAttr( string name, IBlock * owner) : AAttr( name, owner ), data(0) {} + AlphaFormatAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr( name, owner, first_ver, last_ver ), data(0) {} ~AlphaFormatAttr() {} string GetType() const { return "alphaformat"; } - void Read( ifstream& in ) { data = ReadUInt( in ); } - void Write( ofstream& out ) { WriteUInt( data, out ); } + void ReadAttr( ifstream& in, unsigned int version ) { data = ReadUInt( in ); } + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( data, out ); } string asString() const { stringstream out; out.setf(ios::fixed, ios::floatfield); @@ -1217,13 +1241,13 @@ private: class NodeAncestorAttr : public AAttr { public: - NodeAncestorAttr( string name, IBlock * owner ) : AAttr(name, owner) {} + NodeAncestorAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr(name, owner, first_ver, last_ver) {} ~NodeAncestorAttr() {} string GetType() const { return "nodeancestor"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { ReadUInt(in); } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( _owner->GetParent()->GetBlockNum(), out ); } blk_ref FindNodeAncestor() const { @@ -1261,13 +1285,13 @@ public: class SkeletonRootAttr : public AAttr { public: - SkeletonRootAttr( string name, IBlock * owner ) : AAttr(name, owner) {} + SkeletonRootAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr(name, owner, first_ver, last_ver) {} ~SkeletonRootAttr() {} string GetType() const { return "skeletonroot"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { original_root = ReadUInt( in ); //Read data but do nothing with it } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteUInt( FindRoot().get_index(), out ); } blk_ref FindRoot() const { @@ -1317,11 +1341,11 @@ private: class ParticleGroupAttr : public AAttr { public: - ParticleGroupAttr( string name, IBlock * owner ) : AAttr(name, owner) {} + ParticleGroupAttr( string name, IBlock * owner, unsigned int first_ver, unsigned int last_ver ) : AAttr(name, owner, first_ver, last_ver) {} ~ParticleGroupAttr() {} string GetType() const { return "particlegroup"; } - void Read( ifstream& in ) { + void ReadAttr( ifstream& in, unsigned int version ) { num_particles = ReadUShort( in ); num_valid = ReadUShort( in ); @@ -1337,7 +1361,7 @@ public: } } - void Write( ofstream& out ) { + void WriteAttr( ofstream& out, unsigned int version ) { WriteUShort( num_particles, out ); WriteUShort( num_valid, out ); diff --git a/niflib.cpp b/niflib.cpp index 80234cee..45077ade 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -64,30 +64,48 @@ blk_ref CreateBlock( string block_type ) { block = new NiAmbientLight; } else if (block_type == "NiAutoNormalParticles") { block = new NiAutoNormalParticles; + } else if (block_type == "NiAutoNormalParticlesData") { + block = new NiAutoNormalParticlesData; } else if (block_type == "NiBillboardNode") { block = new NiBillboardNode; + } else if (block_type == "NiBooleanExtraData") { + block = new NiBooleanExtraData; } else if (block_type == "NiBSAnimationNode") { block = new NiBSAnimationNode; + } else if (block_type == "NiBSPArrayController") { + block = new NiBSPArrayController; } else if (block_type == "NiBSParticleNode") { block = new NiBSParticleNode; } else if (block_type == "NiCamera") { block = new NiCamera; + } else if (block_type == "NiCollisionData") { + block = new NiCollisionData; } else if (block_type == "NiColorData") { block = new NiColorData; + //} else if (block_type == "NiControllerSequence") { + // block = new NiControllerSequence; } else if (block_type == "NiDirectionalLight") { block = new NiDirectionalLight; } else if (block_type == "NiDitherProperty") { block = new NiDitherProperty; + } else if (block_type == "NiFlipController") { + block = new NiFlipController; } else if (block_type == "NiFloatData") { block = new NiFloatData; } else if (block_type == "NiGeomMorpherController") { block = new NiGeomMorpherController; } else if (block_type == "NiGravity") { block = new NiGravity; + } else if (block_type == "NiIntegerExtraData") { + block = new NiIntegerExtraData; } else if (block_type == "NiKeyframeController") { block = new NiKeyframeController; } else if (block_type == "NiKeyframeData") { block = new NiKeyframeData; + } else if (block_type == "NiLODNode") { + block = new NiLODNode; + } else if (block_type == "NiLookAtController") { + block = new NiLookAtController; } else if (block_type == "NiMaterialColorController") { block = new NiMaterialColorController; } else if (block_type == "NiMaterialProperty") { @@ -96,10 +114,20 @@ blk_ref CreateBlock( string block_type ) { block = new NiMorphData; } else if (block_type == "NiNode") { block = new NiNode; + } else if (block_type == "NiPalette") { + block = new NiPalette; + } else if (block_type == "NiParticleBomb") { + block = new NiParticleBomb; } else if (block_type == "NiParticleColorModifier") { block = new NiParticleColorModifier; } else if (block_type == "NiParticleGrowFade") { block = new NiParticleGrowFade; + } else if (block_type == "NiParticleMeshes") { + block = new NiParticleMeshes; + } else if (block_type == "NiParticleMeshesData") { + block = new NiParticleMeshesData; + } else if (block_type == "NiParticleMeshModifier") { + block = new NiParticleMeshModifier; } else if (block_type == "NiParticleRotation") { block = new NiParticleRotation; } else if (block_type == "NiParticleSystemController") { @@ -114,8 +142,8 @@ blk_ref CreateBlock( string block_type ) { block = new NiPosData; } else if (block_type == "NiRotatingParticles") { block = new NiRotatingParticles; - //} else if (block_type == "NiRotatingParticlesData") { - // block = new NiRotatingParticlesData; + } else if (block_type == "NiRotatingParticlesData") { + block = new NiRotatingParticlesData; } else if ( block_type == "NiSequenceStreamHelper") { block = new NiSequenceStreamHelper; } else if (block_type == "NiShadeProperty") { @@ -124,10 +152,16 @@ blk_ref CreateBlock( string block_type ) { block = new NiSkinData; } else if (block_type == "NiSkinInstance") { block = new NiSkinInstance; + //} else if (block_type == "NiSkinPartition") { + // block = new NiSkinPartition; } else if (block_type == "NiSourceTexture") { block = new NiSourceTexture; } else if (block_type == "NiSpecularProperty") { block = new NiSpecularProperty; + } else if (block_type == "NiSphericalCollider") { + block = new NiSphericalCollider; + } else if (block_type == "NiStencilProperty") { + block = new NiStencilProperty; } else if (block_type == "NiStringExtraData") { block = new NiStringExtraData; } else if (block_type == "NiTextKeyExtraData") { @@ -138,6 +172,8 @@ blk_ref CreateBlock( string block_type ) { block = new NiTexturingProperty; } else if (block_type == "NiTriShape") { block = new NiTriShape; + } else if (block_type == "NiTriStrips") { + block = new NiTriStrips; } else if (block_type == "NiTriShapeData") { block = new NiTriShapeData; } else if ( block_type == "NiUVController") { @@ -214,11 +250,11 @@ vector<blk_ref> ReadNifList( string file_name ) { uint numBlocks = ReadUInt( in ); //Output - //cout << endl - // << "====[ File Header ]====" << endl - // << "Header: " << header_string << endl - // << "Version: " << Hex(version) << endl - // << "Number of blocks: " << int(numBlocks) << endl; + cout << endl << endl + << "====[ " << file_name << " | File Header ]====" << endl + << "Header: " << header_string << endl + << "Version: " << Hex(version) << endl + << "Number of blocks: " << int(numBlocks) << endl; //vector<blk_ref> v; //return v; @@ -254,7 +290,7 @@ vector<blk_ref> ReadNifList( string file_name ) { throw runtime_error("Read failue - Bad block position"); } - //cout << endl << i << ": " << blockName << endl; + cout << endl << i << ": " << blockName; //Create Block of the type that was found blocks[i] = CreateBlock(blockName); @@ -279,6 +315,8 @@ vector<blk_ref> ReadNifList( string file_name ) { delete [] blockName; } + cout << endl; + //--Read Footer--// uint unknownInt = ReadUInt( in ); uint unknownInt2 = ReadUInt( in ); @@ -476,6 +514,10 @@ attr_ref::operator Texture() { return _attr->asTexture(); } //--Query Functions--// +IShapeData * QueryShapeData( blk_ref & block ) { + return (IShapeData*)block->QueryInterface( ID_SHAPE_DATA ); +} + ITriShapeData * QueryTriShapeData( blk_ref & block ) { return (ITriShapeData*)block->QueryInterface( ID_TRI_SHAPE_DATA ); } diff --git a/niflib.h b/niflib.h index 3d2cb886..931e6200 100644 --- a/niflib.h +++ b/niflib.h @@ -77,6 +77,7 @@ const int ID_NODE = 2; const int ID_KEYFRAME_DATA = 3; const int ID_TEXT_KEY_EXTRA_DATA = 4; const int ID_MORPH_DATA = 5; +const int ID_SHAPE_DATA = 6; //NIF Versions const int VER_4_0_0_2 = 0x04000002; @@ -362,6 +363,11 @@ public: //To check for specialized Interfaces virtual void * QueryInterface( int id ) = 0; + + //Name Functions + virtual bool Namable() = 0; + virtual void SetName( string & name ) = 0; + virtual string GetName() = 0; protected: friend class blk_ref; @@ -375,8 +381,8 @@ public: virtual ~IAttr() {} virtual string GetType() const = 0; virtual string GetName() const = 0; - virtual void Read( ifstream& in ) = 0; - virtual void Write( ofstream& out ) = 0; + virtual void Read( ifstream& in, unsigned int version ) = 0; + virtual void Write( ofstream& out, unsigned int version ) = 0; //Getters virtual int asInt() const = 0; virtual float asFloat() const = 0; @@ -422,31 +428,41 @@ public: virtual Matrix44 GetLocalBindPos() = 0; }; -class ITriShapeData { +class IShapeData { public: - ITriShapeData() {} - virtual ~ITriShapeData () {} + IShapeData() {} + virtual ~IShapeData() {} //Counts virtual short GetVertexCount() = 0; virtual short GetUVSetCount() = 0; - virtual short GetTriangleCount() = 0; virtual void SetVertexCount(int n) = 0; virtual void SetUVSetCount(int n) = 0; - virtual void SetTriangleCount(int n) = 0; - //Match Detection - virtual void SetMatchDetectionMode(bool choice) = 0; - virtual bool GetMatchDetectionMode() = 0; //Getters virtual vector<Vector3> GetVertices() = 0; virtual vector<Vector3> GetNormals() = 0; virtual vector<Color> GetColors() = 0; virtual vector<UVCoord> GetUVSet( int index ) = 0; - virtual vector<Triangle> GetTriangles() = 0; //Setters virtual void SetVertices( const vector<Vector3> & in ) = 0; virtual void SetNormals( const vector<Vector3> & in ) = 0; virtual void SetColors( const vector<Color> & in ) = 0; virtual void SetUVSet( int index, const vector<UVCoord> & in ) = 0; +}; + + +class ITriShapeData { +public: + ITriShapeData() {} + virtual ~ITriShapeData () {} + //Counts + virtual short GetTriangleCount() = 0; + virtual void SetTriangleCount(int n) = 0; + //Match Detection + virtual void SetMatchDetectionMode(bool choice) = 0; + virtual bool GetMatchDetectionMode() = 0; + //Getters + virtual vector<Triangle> GetTriangles() = 0; + //Setters virtual void SetTriangles( const vector<Triangle> & in ) = 0; }; @@ -857,9 +873,10 @@ public: friend ostream & operator<<(ostream & lh, const blk_ref & rh) { if (rh._block != NULL) { lh << rh._block->GetBlockType() << "(Block " << rh._block->GetBlockNum() << ")"; + attr_ref attr = rh._block->GetAttr("Name"); - if (attr.is_null() == false ) { - lh << " [" << attr->asString() << "]"; + if ( rh->Namable() == true ) { + lh << " [" << rh->GetName() << "]"; } } else { if (rh._index == -1) -- GitLab