diff --git a/include/gen/obj_defines.h b/include/gen/obj_defines.h index cadeace828e8718bb3c339f8c5d641ba08779b04..728411a8613e4d3e78cdba59508f2bd461a7e283 100644 --- a/include/gen/obj_defines.h +++ b/include/gen/obj_defines.h @@ -533,18 +533,17 @@ InternalFixLinks( objects, link_stack, version, user_version ); \ return InternalGetRefs(); \ #define NI_DYNAMIC_EFFECT_MEMBERS \ -bool hasAffectedNodeList_; \ -uint affectedNodeList_; \ bool switchState; \ mutable uint numAffectedNodes; \ vector<Ref<NiAVObject > > affectedNodes; \ +vector<uint > affectedNodeListPointers; \ #define NI_DYNAMIC_EFFECT_INCLUDE "NiAVObject.h" \ #define NI_DYNAMIC_EFFECT_PARENT NiAVObject \ #define NI_DYNAMIC_EFFECT_CONSTRUCT \ - : hasAffectedNodeList_(false), affectedNodeList_((uint)0), switchState(false), numAffectedNodes((uint)0) \ + : switchState(false), numAffectedNodes((uint)0) \ #define NI_DYNAMIC_EFFECT_READ \ InternalRead( in, link_stack, version, user_version ); \ @@ -3364,14 +3363,14 @@ Vector3 lodCenter; \ mutable uint numLodLevels; \ vector<LODRange > lodLevels; \ ushort unknownShort; \ -Ref<NiLODData > rangeData; \ +Ref<NiLODData > lodLevelData; \ #define NI_L_O_D_NODE_INCLUDE "NiNode.h" \ #define NI_L_O_D_NODE_PARENT NiNode \ #define NI_L_O_D_NODE_CONSTRUCT \ - : numLodLevels((uint)0), unknownShort((ushort)0), rangeData(NULL) \ + : numLodLevels((uint)0), unknownShort((ushort)0), lodLevelData(NULL) \ #define NI_L_O_D_NODE_READ \ InternalRead( in, link_stack, version, user_version ); \ @@ -4849,7 +4848,7 @@ float boundRadius; \ Vector3 worldCenter; \ float worldRadius; \ mutable uint proportionCount; \ -vector<float > proportion; \ +vector<float > proportionLevels; \ #define NI_SCREEN_L_O_D_DATA_INCLUDE "NiLODData.h" \ @@ -5597,6 +5596,57 @@ InternalFixLinks( objects, link_stack, version, user_version ); \ #define NI_TRI_STRIPS_DATA_GETREFS \ return InternalGetRefs(); \ +#define NI_CLOD_MEMBERS \ + +#define NI_CLOD_INCLUDE "NiTriBasedGeom.h" \ + +#define NI_CLOD_PARENT NiTriBasedGeom \ + +#define NI_CLOD_CONSTRUCT \ + +#define NI_CLOD_READ \ +InternalRead( in, link_stack, version, user_version ); \ + +#define NI_CLOD_WRITE \ +InternalWrite( out, link_map, version, user_version ); \ + +#define NI_CLOD_STRING \ +return InternalAsString( verbose ); \ + +#define NI_CLOD_FIXLINKS \ +InternalFixLinks( objects, link_stack, version, user_version ); \ + +#define NI_CLOD_GETREFS \ +return InternalGetRefs(); \ + +#define NI_CLOD_DATA_MEMBERS \ +array<ushort,5> unknown5Shorts; \ +float unknownFloat; \ +uint unknownInt; \ +array<ushort,44> unknownClodShorts; \ + +#define NI_CLOD_DATA_INCLUDE "NiTriBasedGeomData.h" \ + +#define NI_CLOD_DATA_PARENT NiTriBasedGeomData \ + +#define NI_CLOD_DATA_CONSTRUCT \ + : unknownFloat(0.0f), unknownInt((uint)0) \ + +#define NI_CLOD_DATA_READ \ +InternalRead( in, link_stack, version, user_version ); \ + +#define NI_CLOD_DATA_WRITE \ +InternalWrite( out, link_map, version, user_version ); \ + +#define NI_CLOD_DATA_STRING \ +return InternalAsString( verbose ); \ + +#define NI_CLOD_DATA_FIXLINKS \ +InternalFixLinks( objects, link_stack, version, user_version ); \ + +#define NI_CLOD_DATA_GETREFS \ +return InternalGetRefs(); \ + #define NI_U_V_CONTROLLER_MEMBERS \ ushort unknownShort; \ Ref<NiUVData > data; \ diff --git a/include/obj/NiClod.h b/include/obj/NiClod.h new file mode 100644 index 0000000000000000000000000000000000000000..98b05419d676688a129ec148853390f90daf7f41 --- /dev/null +++ b/include/obj/NiClod.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#ifndef _NICLOD_H_ +#define _NICLOD_H_ + +#include "NiTriBasedGeom.h" +namespace Niflib { + + +#include "../gen/obj_defines.h" + +class NiClod; +typedef Ref<NiClod> NiClodRef; + +/*! + * NiClod - A shape node that refers to singular triangle data. + */ + +class NIFLIB_API NiClod : public NI_CLOD_PARENT { +public: + NiClod(); + ~NiClod(); + //Run-Time Type Information + static const Type & TypeConst() { return TYPE; } +private: + static const Type TYPE; +public: + virtual void Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ); + virtual void Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const; + virtual string asString( bool verbose = false ) const; + virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ); + virtual list<NiObjectRef> GetRefs() const; + virtual const Type & GetType() const; + +protected: + NI_CLOD_MEMBERS + STANDARD_INTERNAL_METHODS +}; + +} +#endif diff --git a/include/obj/NiClodData.h b/include/obj/NiClodData.h new file mode 100644 index 0000000000000000000000000000000000000000..d78146eebe416ce7d24077d1628700de0eaba489 --- /dev/null +++ b/include/obj/NiClodData.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#ifndef _NICLODDATA_H_ +#define _NICLODDATA_H_ + +#include "NiTriBasedGeomData.h" +namespace Niflib { + + +#include "../gen/obj_defines.h" + +class NiClodData; +typedef Ref<NiClodData> NiClodDataRef; + +/*! + * NiClodData - A shape node that refers to singular triangle data. + */ + +class NIFLIB_API NiClodData : public NI_CLOD_DATA_PARENT { +public: + NiClodData(); + ~NiClodData(); + //Run-Time Type Information + static const Type & TypeConst() { return TYPE; } +private: + static const Type TYPE; +public: + virtual void Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ); + virtual void Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const; + virtual string asString( bool verbose = false ) const; + virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ); + virtual list<NiObjectRef> GetRefs() const; + virtual const Type & GetType() const; + +protected: + NI_CLOD_DATA_MEMBERS + STANDARD_INTERNAL_METHODS +}; + +} +#endif diff --git a/include/obj/NiControllerManager.h b/include/obj/NiControllerManager.h index 1fb91e6400fa6ecfab9cd070b26fec0c9c23c6e7..9fa69342d1877eb21b4b115d78610c172413c205 100644 --- a/include/obj/NiControllerManager.h +++ b/include/obj/NiControllerManager.h @@ -39,7 +39,24 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; - //TODO: This is not a priority but needs to be implemented eventually + /*! + * Designates whether animation sequences are cumulative? + */ + bool GetCumulative() const; + void SetCumulative( bool value ); + + /*! + * Refers to a list of NiControllerSequence object. + */ + vector<Ref<NiControllerSequence > > GetControllerSequences() const; + void SetControllerSequences( const vector<Ref<NiControllerSequence > >& value ); + + /*! + * Refers to a NiDefaultAVObjectPalette. + */ + Ref<NiDefaultAVObjectPalette > GetObjectPalette() const; + void SetObjectPalette( Ref<NiDefaultAVObjectPalette > value ); + protected: NI_CONTROLLER_MANAGER_MEMBERS STANDARD_INTERNAL_METHODS diff --git a/include/obj/NiDefaultAVObjectPalette.h b/include/obj/NiDefaultAVObjectPalette.h index 1d72351d9ddb5ce372715e3daa29428ad1e9e439..5381a6a45d2fc16c5bba6d8a5417a7fa7dc8ff77 100644 --- a/include/obj/NiDefaultAVObjectPalette.h +++ b/include/obj/NiDefaultAVObjectPalette.h @@ -37,6 +37,12 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; + /*! + * The objects. + */ + vector<Ref<NiAVObject> > GetObjs() const; + void SetObjs( const vector<Ref<NiAVObject> >& value ); + protected: NI_DEFAULT_A_V_OBJECT_PALETTE_MEMBERS STANDARD_INTERNAL_METHODS diff --git a/include/obj/NiDynamicEffect.h b/include/obj/NiDynamicEffect.h index 67f8513a9ce054a8f17190b2323c5572737de30d..a9af02e29d18c508094639309c1c9beafac40dba 100644 --- a/include/obj/NiDynamicEffect.h +++ b/include/obj/NiDynamicEffect.h @@ -38,21 +38,6 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; - /*! - * Determines whether or not an unknown integer follows. - */ - bool GetHasAffectedNodeList_() const; - void SetHasAffectedNodeList_( bool value ); - - /*! - * This is probably the list of affected nodes. For some reason i do not - * know the max exporter seems to write pointers instead of links. But it - * doesn't matter because at least in version 4.0.0.2 the list is - * automagically updated by the engine during the load stage. - */ - uint GetAffectedNodeList_() const; - void SetAffectedNodeList_( uint value ); - /*! * Turns effect on and off? Switches list to list of unaffected nodes? */ @@ -65,6 +50,15 @@ public: vector<Ref<NiAVObject > > GetAffectedNodes() const; void SetAffectedNodes( const vector<Ref<NiAVObject > >& value ); + /*! + * This is probably the list of affected nodes. For some reason i do not + * know the max exporter seems to write pointers instead of links. But it + * doesn't matter because at least in version 4.0.0.2 the list is + * automagically updated by the engine during the load stage. + */ + vector<uint > GetAffectedNodeListPointers() const; + void SetAffectedNodeListPointers( const vector<uint >& value ); + protected: NI_DYNAMIC_EFFECT_MEMBERS STANDARD_INTERNAL_METHODS diff --git a/include/obj/NiSkinPartition.h b/include/obj/NiSkinPartition.h index b9656349ac3710355a7510e0ddf8bb5af3337407..df04b7d056b3735e4987e8ccb64f22c711bce8c8 100644 --- a/include/obj/NiSkinPartition.h +++ b/include/obj/NiSkinPartition.h @@ -74,6 +74,7 @@ public: protected: friend class NiTriBasedGeom; NiSkinPartition(Ref<NiTriBasedGeom> shape); + NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex); void SetNumPartitions( int value ); void SetWeightsPerVertex( int partition, ushort value ); diff --git a/include/obj/NiTriBasedGeom.h b/include/obj/NiTriBasedGeom.h index 5ad3c35ed4e93823fc6c0cc88855549d293a56ec..7c6f56f15df16839ea26e1da5b15dccdd73b50e4 100644 --- a/include/obj/NiTriBasedGeom.h +++ b/include/obj/NiTriBasedGeom.h @@ -56,7 +56,7 @@ public: */ void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ); - void GenHardwareSkinInfo( int max_bones_per_partition = 4 ); + void GenHardwareSkinInfo( int max_bones_per_partition = 4, int max_bones_per_vertex = 4 ); Ref<NiSkinInstance> GetSkinInstance() const; diff --git a/include/obj/NiTriShapeData.h b/include/obj/NiTriShapeData.h index f4b576e6cddbfbd5cee5fba78198ae15f0772754..87d7b9735cce9c8b0a5bf547335541cd2bad76e9 100644 --- a/include/obj/NiTriShapeData.h +++ b/include/obj/NiTriShapeData.h @@ -35,6 +35,8 @@ public: virtual const Type & GetType() const; public: + NiTriShapeData(const vector<Triangle>& verts); + //--Match Detection--// //Re-implemented only to casue match detection data to be cleared diff --git a/include/obj/NiTriStripsData.h b/include/obj/NiTriStripsData.h index 5893de6f1a8359e5b134c44eec530bbe29a80cd5..1c9a315fc1be4bb20b8c4d4441d54ff6bcc88067 100644 --- a/include/obj/NiTriStripsData.h +++ b/include/obj/NiTriStripsData.h @@ -32,6 +32,9 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; + + NiTriStripsData(const vector<Triangle> &tris, bool nvtristrips = true); + //--Counts--// /*! Used to get the number of triangle strips that this mesh is divided into. @@ -77,6 +80,8 @@ public: virtual void SetTriangles( const vector<Triangle> & in ); private: + void SetNvTriangles( const vector<Triangle> & in ); + void SetTSTriangles( const vector<Triangle> & in ); ushort CalcTriangleCount() const; protected: diff --git a/niflib.vcproj b/niflib.vcproj index d43e9283b2bc22f86a5952840f8059c713d06edc..36174843a60089b43aceb61e8ee5b5d171af7c00 100644 --- a/niflib.vcproj +++ b/niflib.vcproj @@ -17,8 +17,8 @@ <Configurations> <Configuration Name="Debug|Win32" - OutputDirectory="$(ProjectDir)../Debug" - IntermediateDirectory="$(ProjectDir)../Debug" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" ConfigurationType="4" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" @@ -41,6 +41,7 @@ <Tool Name="VCCLCompilerTool" Optimization="0" + AdditionalIncludeDirectories="$(ProjectDir)" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" @@ -81,8 +82,8 @@ </Configuration> <Configuration Name="Release|Win32" - OutputDirectory="$(ProjectDir)..\Release" - IntermediateDirectory="$(ProjectDir)..\Release" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" ConfigurationType="4" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" @@ -107,6 +108,7 @@ Name="VCCLCompilerTool" Optimization="0" WholeProgramOptimization="false" + AdditionalIncludeDirectories="$(ProjectDir)" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" UsePrecompiledHeader="0" @@ -145,8 +147,8 @@ </Configuration> <Configuration Name="PyNiflib|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" ConfigurationType="4" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" @@ -168,6 +170,7 @@ /> <Tool Name="VCCLCompilerTool" + AdditionalIncludeDirectories="$(ProjectDir)" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="0" UsePrecompiledHeader="0" @@ -205,8 +208,8 @@ </Configuration> <Configuration Name="Release - DLL|Win32" - OutputDirectory="$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" @@ -231,6 +234,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/FI"pch.h"" Optimization="3" + AdditionalIncludeDirectories="$(ProjectDir)" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BUILDING_NIFLIB_DLL;USE_NIFLIB_DLL" RuntimeLibrary="2" UsePrecompiledHeader="0" @@ -278,8 +282,8 @@ </Configuration> <Configuration Name="Debug - PCH|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" ConfigurationType="4" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" @@ -301,16 +305,83 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/FI"$(ProjectDir)pch.h"" + AdditionalOptions="/FI"$(ProjectDir)include\pch.h"" Optimization="0" + AdditionalIncludeDirectories="$(ProjectDir)" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="1" - UsePrecompiledHeader="0" - PrecompiledHeaderThrough="" + UsePrecompiledHeader="2" + PrecompiledHeaderThrough="$(ProjectDir)include\pch.h" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLibrarianTool" + OutputFile="lib/niflib_debug.lib" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release - PCH|Win32" + OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)" + IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)" + ConfigurationType="4" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalOptions="/FI"$(ProjectDir)include\pch.h"" + Optimization="0" + WholeProgramOptimization="false" + AdditionalIncludeDirectories="$(ProjectDir)" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="0" + UsePrecompiledHeader="2" + PrecompiledHeaderThrough="$(ProjectDir)include\pch.h" WarningLevel="3" - DebugInformationFormat="4" + DebugInformationFormat="3" /> <Tool Name="VCManagedResourceCompilerTool" @@ -323,7 +394,7 @@ /> <Tool Name="VCLibrarianTool" - OutputFile="$(ProjectDir)../bin/niflibd.lib" + OutputFile="lib/niflib.lib" /> <Tool Name="VCALinkTool" @@ -426,6 +497,15 @@ PrecompiledHeaderThrough="$(ProjectDir)include/pch.h" /> </FileConfiguration> + <FileConfiguration + Name="Release - PCH|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="1" + PrecompiledHeaderThrough="$(ProjectDir)include\pch.h" + /> + </FileConfiguration> </File> <File RelativePath=".\src\Type.cpp" @@ -750,6 +830,14 @@ RelativePath=".\src\obj\NiCamera.cpp" > </File> + <File + RelativePath=".\src\obj\NiClod.cpp" + > + </File> + <File + RelativePath=".\src\obj\NiClodData.cpp" + > + </File> <File RelativePath=".\src\obj\NiCollisionData.cpp" > @@ -1824,6 +1912,14 @@ RelativePath=".\include\obj\NiCamera.h" > </File> + <File + RelativePath=".\include\obj\NiClod.h" + > + </File> + <File + RelativePath=".\include\obj\NiClodData.h" + > + </File> <File RelativePath=".\include\obj\NiCollisionData.h" > diff --git a/src/gen/obj_factories.cpp b/src/gen/obj_factories.cpp index 729c5c5aafe129c2ebe073dcc4c984f3b1b21f9a..bd1a7d9a3e26ea498a7e5c8727b433699bdd8dc8 100644 --- a/src/gen/obj_factories.cpp +++ b/src/gen/obj_factories.cpp @@ -349,6 +349,10 @@ NiObject * CreateNiTriShapeData() { return new NiTriShapeData; } NiObject * CreateNiTriStrips() { return new NiTriStrips; } #include "../../include/obj/NiTriStripsData.h" NiObject * CreateNiTriStripsData() { return new NiTriStripsData; } +#include "../../include/obj/NiClod.h" +NiObject * CreateNiClod() { return new NiClod; } +#include "../../include/obj/NiClodData.h" +NiObject * CreateNiClodData() { return new NiClodData; } #include "../../include/obj/NiUVController.h" NiObject * CreateNiUVController() { return new NiUVController; } #include "../../include/obj/NiUVData.h" @@ -543,6 +547,8 @@ void RegisterBlockFactories() { global_block_map["NiTriShapeData"] = CreateNiTriShapeData; global_block_map["NiTriStrips"] = CreateNiTriStrips; global_block_map["NiTriStripsData"] = CreateNiTriStripsData; + global_block_map["NiClod"] = CreateNiClod; + global_block_map["NiClodData"] = CreateNiClodData; global_block_map["NiUVController"] = CreateNiUVController; global_block_map["NiUVData"] = CreateNiUVData; global_block_map["NiVectorExtraData"] = CreateNiVectorExtraData; diff --git a/src/gen/obj_impl.cpp b/src/gen/obj_impl.cpp index e0df54b8f470f22b05be0db8cdf27c13ea33b029..86f2f94ba33b2d1188aa55b9ee89334a97c5a309 100644 --- a/src/gen/obj_impl.cpp +++ b/src/gen/obj_impl.cpp @@ -175,6 +175,8 @@ using namespace std; #include "../../include/obj/NiTriShapeData.h" #include "../../include/obj/NiTriStrips.h" #include "../../include/obj/NiTriStripsData.h" +#include "../../include/obj/NiClod.h" +#include "../../include/obj/NiClodData.h" #include "../../include/obj/NiUVController.h" #include "../../include/obj/NiUVData.h" #include "../../include/obj/NiVectorExtraData.h" @@ -1146,39 +1148,33 @@ std::list<NiObjectRef> NiAVObject::InternalGetRefs() const { void NiDynamicEffect::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { uint block_num; NiAVObject::Read( in, link_stack, version, user_version ); - if ( version <= 0x04000002 ) { - NifStream( hasAffectedNodeList_, in, version ); - if ( (hasAffectedNodeList_ != 0) ) { - NifStream( affectedNodeList_, in, version ); - }; - }; if ( version >= 0x0A020000 ) { NifStream( switchState, in, version ); }; - if ( version >= 0x0A010000 ) { NifStream( numAffectedNodes, in, version ); + if ( version >= 0x0A010000 ) { affectedNodes.resize(numAffectedNodes); for (uint i2 = 0; i2 < affectedNodes.size(); i2++) { NifStream( block_num, in, version ); link_stack.push_back( block_num ); }; }; + if ( version <= 0x0A000102 ) { + affectedNodeListPointers.resize(numAffectedNodes); + for (uint i2 = 0; i2 < affectedNodeListPointers.size(); i2++) { + NifStream( affectedNodeListPointers[i2], in, version ); + }; + }; } void NiDynamicEffect::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { NiAVObject::Write( out, link_map, version, user_version ); numAffectedNodes = uint(affectedNodes.size()); - if ( version <= 0x04000002 ) { - NifStream( hasAffectedNodeList_, out, version ); - if ( (hasAffectedNodeList_ != 0) ) { - NifStream( affectedNodeList_, out, version ); - }; - }; if ( version >= 0x0A020000 ) { NifStream( switchState, out, version ); }; - if ( version >= 0x0A010000 ) { NifStream( numAffectedNodes, out, version ); + if ( version >= 0x0A010000 ) { for (uint i2 = 0; i2 < affectedNodes.size(); i2++) { if ( affectedNodes[i2] != NULL ) NifStream( link_map[StaticCast<NiObject>(affectedNodes[i2])], out, version ); @@ -1186,16 +1182,17 @@ void NiDynamicEffect::InternalWrite( ostream& out, map<NiObjectRef,uint> link_ma NifStream( 0xffffffff, out, version ); }; }; + if ( version <= 0x0A000102 ) { + for (uint i2 = 0; i2 < affectedNodeListPointers.size(); i2++) { + NifStream( affectedNodeListPointers[i2], out, version ); + }; + }; } std::string NiDynamicEffect::InternalAsString( bool verbose ) const { stringstream out; out << NiAVObject::asString(); numAffectedNodes = uint(affectedNodes.size()); - out << " Has Affected Node List?: " << hasAffectedNodeList_ << endl; - if ( (hasAffectedNodeList_ != 0) ) { - out << " Affected Node List?: " << affectedNodeList_ << endl; - }; out << " Switch State: " << switchState << endl; out << " Num Affected Nodes: " << numAffectedNodes << endl; for (uint i1 = 0; i1 < affectedNodes.size(); i1++) { @@ -1205,6 +1202,13 @@ std::string NiDynamicEffect::InternalAsString( bool verbose ) const { }; out << " Affected Nodes[" << i1 << "]: " << affectedNodes[i1] << endl; }; + for (uint i1 = 0; i1 < affectedNodeListPointers.size(); i1++) { + if ( !verbose && ( i1 > MAXARRAYDUMP ) ) { + out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl; + break; + }; + out << " Affected Node List Pointers[" << i1 << "]: " << affectedNodeListPointers[i1] << endl; + }; return out.str(); } @@ -7486,8 +7490,8 @@ void NiLODNode::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, uns }; if ( version >= 0x0A010000 ) { NifStream( unknownShort, out, version ); - if ( rangeData != NULL ) - NifStream( link_map[StaticCast<NiObject>(rangeData)], out, version ); + if ( lodLevelData != NULL ) + NifStream( link_map[StaticCast<NiObject>(lodLevelData)], out, version ); else NifStream( 0xffffffff, out, version ); }; @@ -7511,7 +7515,7 @@ std::string NiLODNode::InternalAsString( bool verbose ) const { out << " Far Extent: " << lodLevels[i1].farExtent << endl; }; out << " Unknown Short: " << unknownShort << endl; - out << " Range Data: " << rangeData << endl; + out << " LOD Level Data: " << lodLevelData << endl; return out.str(); } @@ -7521,11 +7525,11 @@ void NiLODNode::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint if (link_stack.empty()) throw runtime_error("Trying to pop a link from empty stack. This is probably a bug."); if (link_stack.front() != 0xffffffff) { - rangeData = DynamicCast<NiLODData>(objects[link_stack.front()]); - if ( rangeData == NULL ) + lodLevelData = DynamicCast<NiLODData>(objects[link_stack.front()]); + if ( lodLevelData == NULL ) throw runtime_error("Link could not be cast to required type during file read. This NIF file may be invalid or improperly understood."); } else - rangeData = NULL; + lodLevelData = NULL; link_stack.pop_front(); }; } @@ -7533,8 +7537,8 @@ void NiLODNode::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint std::list<NiObjectRef> NiLODNode::InternalGetRefs() const { list<Ref<NiObject> > refs; refs = NiNode::GetRefs(); - if ( rangeData != NULL ) - refs.push_back(StaticCast<NiObject>(rangeData)); + if ( lodLevelData != NULL ) + refs.push_back(StaticCast<NiObject>(lodLevelData)); return refs; } @@ -10297,40 +10301,40 @@ void NiScreenLODData::InternalRead( istream& in, list<uint> & link_stack, unsign NifStream( worldCenter, in, version ); NifStream( worldRadius, in, version ); NifStream( proportionCount, in, version ); - proportion.resize(proportionCount); - for (uint i1 = 0; i1 < proportion.size(); i1++) { - NifStream( proportion[i1], in, version ); + proportionLevels.resize(proportionCount); + for (uint i1 = 0; i1 < proportionLevels.size(); i1++) { + NifStream( proportionLevels[i1], in, version ); }; } void NiScreenLODData::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { NiLODData::Write( out, link_map, version, user_version ); - proportionCount = uint(proportion.size()); + proportionCount = uint(proportionLevels.size()); NifStream( boundCenter, out, version ); NifStream( boundRadius, out, version ); NifStream( worldCenter, out, version ); NifStream( worldRadius, out, version ); NifStream( proportionCount, out, version ); - for (uint i1 = 0; i1 < proportion.size(); i1++) { - NifStream( proportion[i1], out, version ); + for (uint i1 = 0; i1 < proportionLevels.size(); i1++) { + NifStream( proportionLevels[i1], out, version ); }; } std::string NiScreenLODData::InternalAsString( bool verbose ) const { stringstream out; out << NiLODData::asString(); - proportionCount = uint(proportion.size()); + proportionCount = uint(proportionLevels.size()); out << " Bound Center: " << boundCenter << endl; out << " Bound Radius: " << boundRadius << endl; out << " World Center: " << worldCenter << endl; out << " World Radius: " << worldRadius << endl; out << " Proportion Count: " << proportionCount << endl; - for (uint i1 = 0; i1 < proportion.size(); i1++) { + for (uint i1 = 0; i1 < proportionLevels.size(); i1++) { if ( !verbose && ( i1 > MAXARRAYDUMP ) ) { out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl; break; }; - out << " Proportion[" << i1 << "]: " << proportion[i1] << endl; + out << " Proportion Levels[" << i1 << "]: " << proportionLevels[i1] << endl; }; return out.str(); } @@ -11734,7 +11738,6 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un if ( (textureCount == 8) ) { NifStream( hasDecal1Texture, in, version ); }; - if ( version >= 0x14000004 ) { if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) { NifStream( block_num, in, version ); link_stack.push_back( block_num ); @@ -11759,7 +11762,6 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un }; }; }; - }; if ( version >= 0x0A000100 ) { NifStream( numShaderTextures, in, version ); shaderTextures.resize(numShaderTextures); @@ -11997,7 +11999,6 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin if ( (textureCount == 8) ) { NifStream( hasDecal1Texture, out, version ); }; - if ( version >= 0x14000004 ) { if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) { if ( decal1Texture.source != NULL ) NifStream( link_map[StaticCast<NiObject>(decal1Texture.source)], out, version ); @@ -12024,7 +12025,6 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin }; }; }; - }; if ( version >= 0x0A000100 ) { NifStream( numShaderTextures, out, version ); for (uint i2 = 0; i2 < shaderTextures.size(); i2++) { @@ -12320,7 +12320,6 @@ void NiTexturingProperty::InternalFixLinks( const vector<NiObjectRef> & objects, decal0Texture.source = NULL; link_stack.pop_front(); }; - if ( version >= 0x14000004 ) { if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) { if (link_stack.empty()) throw runtime_error("Trying to pop a link from empty stack. This is probably a bug."); @@ -12332,7 +12331,6 @@ void NiTexturingProperty::InternalFixLinks( const vector<NiObjectRef> & objects, decal1Texture.source = NULL; link_stack.pop_front(); }; - }; if ( version >= 0x0A000100 ) { for (uint i2 = 0; i2 < shaderTextures.size(); i2++) { if ( (shaderTextures[i2].isUsed != 0) ) { @@ -12746,6 +12744,112 @@ std::list<NiObjectRef> NiTriStripsData::InternalGetRefs() const { return refs; } +void NiClod::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NiTriBasedGeom::Read( in, link_stack, version, user_version ); +} + +void NiClod::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { + NiTriBasedGeom::Write( out, link_map, version, user_version ); +} + +std::string NiClod::InternalAsString( bool verbose ) const { + stringstream out; + out << NiTriBasedGeom::asString(); + return out.str(); +} + +void NiClod::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NiTriBasedGeom::FixLinks( objects, link_stack, version, user_version ); +} + +std::list<NiObjectRef> NiClod::InternalGetRefs() const { + list<Ref<NiObject> > refs; + refs = NiTriBasedGeom::GetRefs(); + return refs; +} + +void NiClodData::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NiTriBasedGeomData::Read( in, link_stack, version, user_version ); + for (uint i1 = 0; i1 < 5; i1++) { + NifStream( unknown5Shorts[i1], in, version ); + }; + NifStream( unknownFloat, in, version ); + NifStream( unknownInt, in, version ); + if ( (unknownInt == 9) ) { + for (uint i2 = 0; i2 < 44; i2++) { + NifStream( unknownClodShorts[i2], in, version ); + }; + }; + if ( (unknownInt == 199) ) { + for (uint i2 = 0; i2 < 233; i2++) { + NifStream( unknownClodShorts[i2], in, version ); + }; + }; + if ( (unknownInt == 24) ) { + for (uint i2 = 0; i2 < 57; i2++) { + NifStream( unknownClodShorts[i2], in, version ); + }; + }; +} + +void NiClodData::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { + NiTriBasedGeomData::Write( out, link_map, version, user_version ); + for (uint i1 = 0; i1 < 5; i1++) { + NifStream( unknown5Shorts[i1], out, version ); + }; + NifStream( unknownFloat, out, version ); + NifStream( unknownInt, out, version ); + if ( (unknownInt == 9) ) { + for (uint i2 = 0; i2 < 44; i2++) { + NifStream( unknownClodShorts[i2], out, version ); + }; + }; + if ( (unknownInt == 199) ) { + for (uint i2 = 0; i2 < 233; i2++) { + NifStream( unknownClodShorts[i2], out, version ); + }; + }; + if ( (unknownInt == 24) ) { + for (uint i2 = 0; i2 < 57; i2++) { + NifStream( unknownClodShorts[i2], out, version ); + }; + }; +} + +std::string NiClodData::InternalAsString( bool verbose ) const { + stringstream out; + out << NiTriBasedGeomData::asString(); + for (uint i1 = 0; i1 < 5; i1++) { + if ( !verbose && ( i1 > MAXARRAYDUMP ) ) { + out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl; + break; + }; + out << " Unknown 5 Shorts[" << i1 << "]: " << unknown5Shorts[i1] << endl; + }; + out << " Unknown Float: " << unknownFloat << endl; + out << " Unknown Int: " << unknownInt << endl; + if ( (unknownInt == 9) ) { + for (uint i2 = 0; i2 < 44; i2++) { + if ( !verbose && ( i2 > MAXARRAYDUMP ) ) { + out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl; + break; + }; + out << " Unknown Clod Shorts[" << i2 << "]: " << unknownClodShorts[i2] << endl; + }; + }; + return out.str(); +} + +void NiClodData::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NiTriBasedGeomData::FixLinks( objects, link_stack, version, user_version ); +} + +std::list<NiObjectRef> NiClodData::InternalGetRefs() const { + list<Ref<NiObject> > refs; + refs = NiTriBasedGeomData::GetRefs(); + return refs; +} + void NiUVController::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { uint block_num; NiTimeController::Read( in, link_stack, version, user_version ); diff --git a/src/obj/NiClod.cpp b/src/obj/NiClod.cpp new file mode 100644 index 0000000000000000000000000000000000000000..536b1a98a98df8034077d879a3e1e136d33e7f9b --- /dev/null +++ b/src/obj/NiClod.cpp @@ -0,0 +1,37 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#include "../../include/obj/NiClod.h" +using namespace Niflib; + +//Definition of TYPE constant +const Type NiClod::TYPE("NiClod", &NI_CLOD_PARENT::TypeConst() ); + +NiClod::NiClod() NI_CLOD_CONSTRUCT {} + +NiClod::~NiClod() {} + +void NiClod::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_CLOD_READ +} + +void NiClod::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { + NI_CLOD_WRITE +} + +string NiClod::asString( bool verbose ) const { + NI_CLOD_STRING +} + +void NiClod::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_CLOD_FIXLINKS +} + +list<NiObjectRef> NiClod::GetRefs() const { + NI_CLOD_GETREFS +} + +const Type & NiClod::GetType() const { + return TYPE; +}; + diff --git a/src/obj/NiClodData.cpp b/src/obj/NiClodData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7af336893ce2eba64aeaf4a54d5395659549fd5 --- /dev/null +++ b/src/obj/NiClodData.cpp @@ -0,0 +1,37 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#include "../../include/obj/NiClodData.h" +using namespace Niflib; + +//Definition of TYPE constant +const Type NiClodData::TYPE("NiClodData", &NI_CLOD_DATA_PARENT::TypeConst() ); + +NiClodData::NiClodData() NI_CLOD_DATA_CONSTRUCT {} + +NiClodData::~NiClodData() {} + +void NiClodData::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_CLOD_DATA_READ +} + +void NiClodData::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { + NI_CLOD_DATA_WRITE +} + +string NiClodData::asString( bool verbose ) const { + NI_CLOD_DATA_STRING +} + +void NiClodData::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_CLOD_DATA_FIXLINKS +} + +list<NiObjectRef> NiClodData::GetRefs() const { + NI_CLOD_DATA_GETREFS +} + +const Type & NiClodData::GetType() const { + return TYPE; +}; + diff --git a/src/obj/NiControllerManager.cpp b/src/obj/NiControllerManager.cpp index b08e6f6329d691bc2cea6e1ddf432527f19cdbcd..7dfd00cd9dff960370110855b3f69674b0f50745 100644 --- a/src/obj/NiControllerManager.cpp +++ b/src/obj/NiControllerManager.cpp @@ -37,3 +37,27 @@ const Type & NiControllerManager::GetType() const { return TYPE; }; +bool NiControllerManager::GetCumulative() const { + return cumulative; +} + +void NiControllerManager::SetCumulative( bool value ) { + cumulative = value; +} + +vector<Ref<NiControllerSequence > > NiControllerManager::GetControllerSequences() const { + return controllerSequences; +} + +void NiControllerManager::SetControllerSequences( const vector<Ref<NiControllerSequence > >& value ) { + controllerSequences = value; +} + +Ref<NiDefaultAVObjectPalette > NiControllerManager::GetObjectPalette() const { + return objectPalette; +} + +void NiControllerManager::SetObjectPalette( Ref<NiDefaultAVObjectPalette > value ) { + objectPalette = value; +} + diff --git a/src/obj/NiDefaultAVObjectPalette.cpp b/src/obj/NiDefaultAVObjectPalette.cpp index 13696c3b4917438a201aa43ce9efef87e3050799..bfbf5b65b84a993574652d3705f94d14463a68dc 100644 --- a/src/obj/NiDefaultAVObjectPalette.cpp +++ b/src/obj/NiDefaultAVObjectPalette.cpp @@ -37,3 +37,21 @@ const Type & NiDefaultAVObjectPalette::GetType() const { return TYPE; }; +vector<Ref<NiAVObject> > NiDefaultAVObjectPalette::GetObjs() const { + vector<NiAVObjectRef> objRefs; + for (vector<AVObject>::const_iterator itr = objs.begin(); itr != objs.end(); ++itr) { + objRefs.push_back(itr->avObject); + } + return objRefs; +} + +void NiDefaultAVObjectPalette::SetObjs( const vector<Ref<NiAVObject> >& value ) { + objs.clear(); + for (vector<NiAVObjectRef>::const_iterator itr = value.begin(); itr != value.end(); ++itr) { + AVObject obj; + obj.name = (*itr)->GetName(); + obj.avObject = (*itr).Ptr(); + objs.push_back(obj); + } +} + diff --git a/src/obj/NiDynamicEffect.cpp b/src/obj/NiDynamicEffect.cpp index 88c1f15798d40edd16644be3d812e750c8a88746..945237ede3891617778a515170b48aae9f0aa9b9 100644 --- a/src/obj/NiDynamicEffect.cpp +++ b/src/obj/NiDynamicEffect.cpp @@ -36,22 +36,6 @@ const Type & NiDynamicEffect::GetType() const { return TYPE; }; -bool NiDynamicEffect::GetHasAffectedNodeList_() const { - return hasAffectedNodeList_; -} - -void NiDynamicEffect::SetHasAffectedNodeList_( bool value ) { - hasAffectedNodeList_ = value; -} - -uint NiDynamicEffect::GetAffectedNodeList_() const { - return affectedNodeList_; -} - -void NiDynamicEffect::SetAffectedNodeList_( uint value ) { - affectedNodeList_ = value; -} - bool NiDynamicEffect::GetSwitchState() const { return switchState; } @@ -68,3 +52,11 @@ void NiDynamicEffect::SetAffectedNodes( const vector<Ref<NiAVObject > >& value ) affectedNodes = value; } +vector<uint > NiDynamicEffect::GetAffectedNodeListPointers() const { + return affectedNodeListPointers; +} + +void NiDynamicEffect::SetAffectedNodeListPointers( const vector<uint >& value ) { + affectedNodeListPointers = value; +} + diff --git a/src/obj/NiLODNode.cpp b/src/obj/NiLODNode.cpp index d02c5ff2fa5e047fd4d0700ca6e660c8c134e9a1..f339e8467d25364cfd7bef5695797618f31c1857 100644 --- a/src/obj/NiLODNode.cpp +++ b/src/obj/NiLODNode.cpp @@ -54,10 +54,10 @@ void NiLODNode::SetLODLevels( const vector<LODRange >& value ) { } Ref<NiLODData > NiLODNode::GetLODLevelData() const { - return rangeData; + return lodLevelData; } void NiLODNode::SetLODLevelData( Ref<NiLODData > value ) { - rangeData = value; + lodLevelData = value; } diff --git a/src/obj/NiScreenLODData.cpp b/src/obj/NiScreenLODData.cpp index 9bcadfc6402d46a7ffbf289ea9e8b764a3cef74b..7c777080eb431ea6890bc1412f901e512edfae4f 100644 --- a/src/obj/NiScreenLODData.cpp +++ b/src/obj/NiScreenLODData.cpp @@ -68,10 +68,10 @@ void NiScreenLODData::SetWorldRadius( float value ) { } vector<float > NiScreenLODData::GetProportionLevels() const { - return proportion; + return proportionLevels; } void NiScreenLODData::SetProportionLevels( const vector<float >& value ) { - proportion = value; + proportionLevels = value; } diff --git a/src/obj/NiSkinPartition.cpp b/src/obj/NiSkinPartition.cpp index 2f1001c6a817aa89eabf7764bfc2cfd15c4759d1..d68fdf31c4bed85fdfca8850e945f0d0dc25c669 100644 --- a/src/obj/NiSkinPartition.cpp +++ b/src/obj/NiSkinPartition.cpp @@ -10,16 +10,20 @@ All rights reserved. Please see niflib.h for licence. */ #include "../../include/obj/NiTriStripsData.h" #include "../../include/gen/SkinWeight.h" #include "../../NvTriStrip/NvTriStrip.h" +#include <algorithm> using namespace Niflib; -typedef vector<SkinWeight> SkinWeightList; -typedef vector<SkinWeightList> BoneWeightList; typedef vector<float> WeightList; typedef vector<ushort> BoneList; typedef vector<ushort> Strip; typedef vector<Strip> Strips; typedef vector<Triangle> Triangles; +typedef pair<int,float> BoneWeight; +typedef vector<BoneWeight> BoneWeightList; +typedef SkinPartition Partition; +typedef vector<SkinPartition > PartitionList; + //Definition of TYPE constant const Type NiSkinPartition::TYPE("NiSkinPartition", &NI_SKIN_PARTITION_PARENT::TypeConst() ); @@ -228,7 +232,7 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) { throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." ); } - int nWeightsPerVertex = 0; + int nWeightsPerVertex = 4; vector<WeightList> vertexWeights; BoneList boneMap; vector<ushort> vertexMap; @@ -298,7 +302,8 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) { } } else { - SetTriangles(0, geomData->GetTriangles()); + Triangles triangles = geomData->GetTriangles(); + SetTriangles(0, triangles); unsigned short *data = new unsigned short[triangles.size() * 3 * 2]; for (size_t i=0; i< triangles.size(); i++) { @@ -331,4 +336,382 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) { } } -} \ No newline at end of file +} + + +//////////////////////////////////////////////// + +static void mergeBones( BoneList &a, BoneList& b ) { + for (size_t i=0; i<b.size(); ++i) { + int c = b[i]; + BoneList::iterator it = find(a.begin(), a.end(), c); + if ( a.end() == it ) { + a.push_back( c ); + } + } +} + +static bool containsBones( BoneList& a, BoneList& b ) { + for (size_t i=0; i<b.size(); ++i) { + int c = b[i]; + BoneList::iterator it = find(a.begin(), a.end(), c); + if ( a.end() == it ) { + return false; + } + } + return true; +} +template <typename I, typename V> +int indexOf(I begin, I end, const V& val) { + return std::distance(begin, std::find(begin, end, val)); +} + + +NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex ) { + NiSkinInstanceRef skinInst = shape->GetSkinInstance(); + if ( skinInst == NULL ) { + throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinInstance found." ); + } + NiSkinDataRef skinData = skinInst->GetSkinData(); + if ( skinData == NULL ) { + throw runtime_error( "You must bind a skin before setting generating skin partitions. No NiSkinData found." ); + } + NiTriBasedGeomDataRef geomData = shape->GetData(); + if ( geomData == NULL ) { + throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." ); + } + + // read in the weights from NiSkinData + vector<Vector3> verts = geomData->GetVertices(); + vector< BoneWeightList > weights; + if (verts.empty()){ + throw runtime_error( "Attempted to generate a skin partition on a mesh with no vertices." ); + } + + Triangles triangles = geomData->GetTriangles(); + if (triangles.empty()) { + throw runtime_error( "Attempted to generate a skin partition on a mesh with no triangles." ); + } + + weights.resize( verts.size() ); + int numBones = skinData->GetBoneCount(); + for ( int bone = 0; bone < numBones; bone++ ) + { + vector<SkinWeight> vertexWeights = skinData->GetBoneWeights(bone); + for (int r = 0; r < int(vertexWeights.size()); ++r ){ + int vertex = vertexWeights[r].index; + float weight = vertexWeights[r].weight; + if ( vertex >= int(weights.size()) ) + throw runtime_error( "bad NiSkinData - vertex count does not match" ); + weights[vertex].insert( weights[vertex].end(), BoneWeight(bone, weight) ); + } + } + + // count min and max bones per vertex + int minBones, maxBones; + minBones = maxBones = weights[0].size(); + for(vector< BoneWeightList >::iterator itr = weights.begin(); itr != weights.end(); ++itr ){ + int n = (*itr).size(); + minBones = min(n, minBones); + maxBones = max(n, maxBones); + } + + if ( minBones <= 0 ) + throw runtime_error( "bad NiSkinData - some vertices have no weights at all" ); + + // reduce vertex influences if necessary + if ( maxBones > maxBonesPerVertex ) + { + vector< BoneWeightList >::iterator it = weights.begin(); + int c = 0; + while ( it != weights.end() ) + { + BoneWeightList & lst = *it; + if ( int(lst.size()) > maxBonesPerVertex ) + c++; + + while ( int(lst.size()) > maxBonesPerVertex ) { + int j = 0; + float weight = lst.front().second; + for ( int i = 0; i < int(lst.size()); i++ ) + { + if ( lst[i].second < weight ) + j = i; + } + BoneWeightList::iterator jit = lst.begin() + j; + lst.erase( jit ); + } + + float totalWeight = 0; + for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) { + totalWeight += (*bw).second; + } + for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) { + (*bw).second /= totalWeight; + } + } + //qWarning() << "reduced" << c << "vertices to" << maxBonesPerVertex << "bone influences (maximum number of bones per vertex was" << maxBones << ")"; + } + + maxBones = maxBonesPerVertex; + + // reduces bone weights so that the triangles fit into the partitions + + typedef multimap<int,int> matchmap; + typedef pair<matchmap::iterator, matchmap::iterator> matchrange; + matchmap match; + bool doMatch = true; + + BoneList tribones; + int cnt = 0; + for (Triangles::iterator itr = triangles.begin(); itr != triangles.end(); ++itr) { + Triangle& tri = (*itr); + do + { + tribones.clear(); + for ( int c = 0; c < 3; c++ ) { + BoneWeightList& bwl = weights[tri[c]]; + for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) { + if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) ) + tribones.insert(tribones.end(), (*bw).first ); + } + } + + if ( int(tribones.size()) > maxBonesPerPartition ) + { + // sum up the weights for each bone + // bones with weight == 1 can't be removed + + map<int, float> sum; + vector<int> nono; + + for ( int t = 0; t < 3; t++ ) { + BoneWeightList& bwl = weights[tri[t]]; + if ( bwl.size() == 1 ) + nono.insert(nono.end(), bwl.front().first ); + + for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) { + sum[ (*bw).first ] += (*bw).second; + } + } + + // select the bone to remove + + float minWeight = 5.0; + int minBone = -1; + + for (map<int, float>::iterator sitr = sum.begin(); sitr != sum.end(); ++sitr) { + int b = (*sitr).first; + if ( (find(nono.begin(), nono.end(), b) == nono.end()) && sum[b] < minWeight) { + minWeight = sum[b]; + minBone = b; + } + } + + if ( minBone < 0 ) // this shouldn't never happen + throw runtime_error( "internal error 0x01" ); + + // do a vertex match detect + if ( doMatch ) { + for ( size_t a = 0; a < verts.size(); a++ ) { + match.insert(matchmap::value_type(a, a)); + for ( size_t b = a + 1; b < verts.size(); b++ ) { + if ( verts[a] == verts[b] && weights[a] == weights[b] ) { + match.insert(matchmap::value_type(a, b)); + match.insert(matchmap::value_type(b, a)); + } + } + } + } + + // now remove that bone from all vertices of this triangle and from all matching vertices too + for ( int t = 0; t < 3; t++ ) { + bool rem = false; + + matchrange range = match.equal_range(tri[t]); + for (matchmap::iterator itr = range.first; itr != range.second; ++itr) { + int v = (*itr).second; + + BoneWeightList & bws = weights[ v ]; + BoneWeightList::iterator it = bws.begin(); + while ( it != bws.end() ) { + BoneWeight & bw = *it; + if ( bw.first == minBone ) { + it = bws.erase(it); + rem = true; + } else { + ++it; + } + } + + float totalWeight = 0; + + for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { + totalWeight += (*bw).second; + } + + if ( totalWeight == 0 ) + throw runtime_error( "internal error 0x02" ); + + // normalize + for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { + (*bw).second /= totalWeight; + } + } + if ( rem ) + cnt++; + } + } + } while ( int(tribones.size()) > maxBonesPerPartition ); + } + //if ( cnt > 0 ) + // qWarning() << "removed" << cnt << "bone influences"; + + PartitionList& parts = skinPartitionBlocks; + // split the triangles into partitions + while ( ! triangles.empty() ) { + + SkinPartition part; + Triangles::iterator it = triangles.begin(); + while ( it != triangles.end() ) { + Triangle & tri = *it; + + BoneList tribones; + for ( int c = 0; c < 3; c++ ) { + BoneWeightList& bws = weights[tri[c]]; + for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) { + if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) ) + tribones.push_back( (*bw).first ); + } + } + + if ( part.bones.empty() || containsBones( part.bones, tribones ) ) { + mergeBones( part.bones, tribones ); + part.triangles.push_back( tri ); + it = triangles.erase(it); + } else { + ++it; + } + } + + parts.push_back( part ); + } + + //qWarning() << parts.size() << "small partitions"; + + // merge partitions + + bool merged; + do + { + merged = false; + // Working backwards through this list minimizes numbers of swaps + //for ( int p2 = int(parts.size()-1); p2 >= 0 && ! merged; --p2 ) + //{ + // Partition& part2 = parts[p2]; + // for ( int p1 = int(p2-1); p1 >= 0 && ! merged; --p1 ) + // { + // Partition& part1 = parts[p1]; + for ( int p1 = 0; p1 < int(parts.size()) && ! merged; p1++ ) + { + Partition& part1 = parts[p1]; + for ( int p2 = p1+1; p2 < int(parts.size()) && ! merged; p2++ ) + { + Partition& part2 = parts[p2]; + BoneList mergedBones = part1.bones; + mergeBones( mergedBones, part2.bones ); + if ( int(mergedBones.size()) <= maxBonesPerPartition ) + { + PartitionList::iterator p2i = parts.begin() + p2; + part1.bones = mergedBones; + part1.triangles.insert(part1.triangles.end(), (*p2i).triangles.begin(), (*p2i).triangles.end()); + parts.erase(p2i); + merged = true; + } + } + } + } + while ( merged ); + + //qWarning() << parts.size() << "partitions"; + + // start writing NiSkinPartition + + for ( int p = 0; p < int(parts.size()); p++ ) + { + Partition& part = parts[p]; + BoneList& bones = part.bones; + sort( bones.begin(), bones.end() ); + + Triangles& triangles = part.triangles; + + vector<ushort>& vertices = part.vertexMap; + for( Triangles::iterator tri = triangles.begin(); tri != triangles.end(); ++tri) { + for ( int t = 0; t < 3; t++ ) { + if ( vertices.end() == find(vertices.begin(), vertices.end(), (*tri)[t] ) ) + vertices.push_back( (*tri)[t] ); + } + } + sort( vertices.begin(), vertices.end() ); + part.numVertices = vertices.size(); + part.hasVertexMap = true; + + // map the vertices + + for ( int tri = 0; tri < int(triangles.size()); tri++ ) { + for ( int t = 0; t < 3; t++ ) { + triangles[tri][t] = indexOf(vertices.begin(), vertices.end(), triangles[tri][t]); + } + } + + SetWeightsPerVertex(p, maxBones); + EnableVertexWeights(p, true); + EnableVertexBoneIndices(p, true); + + // strippify the triangles + NiTriStripsDataRef data = new NiTriStripsData(triangles, true); + int nstrips = data->GetStripCount(); + SetStripCount( p, nstrips ); + for ( int i=0; i<nstrips; ++i ) { + SetStrip(p, i, data->GetStrip(i)); + } + + //// Special case for pre-stripped data + //unsigned short *data = new unsigned short[triangles.size() * 3 * 2]; + //for (size_t i=0; i< triangles.size(); i++) { + // data[i * 3 + 0] = triangles[i][0]; + // data[i * 3 + 1] = triangles[i][1]; + // data[i * 3 + 2] = triangles[i][2]; + //} + //PrimitiveGroup * groups = 0; + //unsigned short numGroups = 0; + + //// GF 3+ + //SetCacheSize(CACHESIZE_GEFORCE3); + //// don't generate hundreds of strips + //SetStitchStrips(true); + //GenerateStrips(data, triangles.size()*3, &groups, &numGroups); + //delete [] data; + //if (groups) { + // SetStripCount(p, numGroups); + // for (int g=0; g<numGroups; g++) { + // if (groups[g].type == PT_STRIP) { + // vector<Niflib::ushort> strip(groups[g].numIndices); + // for (size_t s=0; s<groups[g].numIndices; s++) + // strip[s] = groups[g].indices[s]; + // SetStrip(p, g, strip); + // } + // } + // delete [] groups; + //} + + // fill in vertex weights and bones + for (size_t v = 0; v < vertices.size(); ++v) { + BoneWeightList& bwl = weights[vertices[v]]; + for ( int b = 0; b < maxBones; b++ ) { + part.boneIndices[v][b] = (int(bwl.size()) > b) ? indexOf(bones.begin(), bones.end(), bwl[b].first) : 0 ; + part.vertexWeights[v][b] = (int(bwl.size()) > b ? bwl[b].second : 0.0f); + } + } + } +} diff --git a/src/obj/NiTriBasedGeom.cpp b/src/obj/NiTriBasedGeom.cpp index 242fae9385ea0bbf2dd3b5640efa7548372f6408..a35d9c2580c27077d431dcb731a2430c5b794526 100644 --- a/src/obj/NiTriBasedGeom.cpp +++ b/src/obj/NiTriBasedGeom.cpp @@ -358,8 +358,12 @@ void NiTriBasedGeom::SetBoneWeights( uint bone_index, const vector<SkinWeight> & skinData->SetBoneWeights( bone_index, n, center, radius ); } -void NiTriBasedGeom::GenHardwareSkinInfo( int max_bones_per_partition ) { - NiSkinPartitionRef skinPart = new NiSkinPartition( this ); +void NiTriBasedGeom::GenHardwareSkinInfo( int max_bones_per_partition /*= 4*/, int max_bones_per_vertex /*= INT_MAX*/ ) { + NiSkinPartitionRef skinPart; + if ( max_bones_per_partition == 0 ) //old method + skinPart = new NiSkinPartition( this ); + else + skinPart = new NiSkinPartition( this, max_bones_per_partition, max_bones_per_vertex ); // Set the partition info in both places and it will be handled when exported. NiSkinInstanceRef skinInst = GetSkinInstance(); diff --git a/src/obj/NiTriShapeData.cpp b/src/obj/NiTriShapeData.cpp index 090e9bbb48a730f7208eeca0ef747f9a2fb7bd98..4da709e637ccb95af293eedcf339e19f500a86a4 100644 --- a/src/obj/NiTriShapeData.cpp +++ b/src/obj/NiTriShapeData.cpp @@ -36,6 +36,10 @@ const Type & NiTriShapeData::GetType() const { return TYPE; }; +NiTriShapeData::NiTriShapeData(const vector<Triangle> &tris) { + SetTriangles(tris); +} + void NiTriShapeData::SetVertices( const vector<Vector3> & in ) { //Take normal action NiTriBasedGeomData::SetVertices( in ); diff --git a/src/obj/NiTriStripsData.cpp b/src/obj/NiTriStripsData.cpp index c20deffe461421975b5176fd1710004c213c38fe..f8dc1289a224166be7dbd6dbb2084a03f55df961 100644 --- a/src/obj/NiTriStripsData.cpp +++ b/src/obj/NiTriStripsData.cpp @@ -3,8 +3,15 @@ All rights reserved. Please see niflib.h for licence. */ #include "../../include/obj/NiTriStripsData.h" #include "../../NvTriStrip/NvTriStrip.h" +#include "../../TriStripper/tri_stripper.h" using namespace Niflib; +using namespace triangle_stripper; + +// Helper methods +typedef vector<unsigned short> TriStrip; +typedef list<TriStrip> TriStrips; + //Definition of TYPE constant const Type NiTriStripsData::TYPE("NiTriStripsData", &NI_TRI_STRIPS_DATA_PARENT::TypeConst() ); @@ -37,6 +44,13 @@ const Type & NiTriStripsData::GetType() const { return TYPE; }; +NiTriStripsData::NiTriStripsData(const vector<Triangle> &tris, bool nvtristrips) { + if (nvtristrips) + SetNvTriangles(tris); + else + SetTSTriangles(tris); +} + ushort NiTriStripsData::GetStripCount() const { return ushort(points.size()); } @@ -121,6 +135,10 @@ ushort NiTriStripsData::CalcTriangleCount() const { } void NiTriStripsData::SetTriangles( const vector<Triangle> & in ) { + SetNvTriangles(in); +} + +void NiTriStripsData::SetNvTriangles( const vector<Triangle> & in ) { if ( in.size() > 65535 || in.size() < 0 ) { throw runtime_error("Invalid Triangle Count: must be between 0 and 65535."); } @@ -163,3 +181,90 @@ void NiTriStripsData::SetTriangles( const vector<Triangle> & in ) { numTriangles = CalcTriangleCount(); } +void NiTriStripsData::SetTSTriangles( const vector<Triangle> & in ) { + if ( in.size() > 65535 || in.size() < 0 ) { + throw runtime_error("Invalid Triangle Count: must be between 0 and 65535."); + } + + points.clear(); + numTriangles = 0; + + TriStrips strips; + vector<unsigned int> idcs(in.size()*3); + size_t i, j; + for (i=0; i<in.size(); i++) + { + idcs[i * 3 + 0] = in[i][0]; + idcs[i * 3 + 1] = in[i][1]; + idcs[i * 3 + 2] = in[i][2]; + } + + tri_stripper stripper(idcs); + + primitive_vector groups; + stripper.Strip(&groups); + + // triangles left over + vector<Triangle> stris; + + for (i=0; i<groups.size(); i++) + { + if (groups[i].Type == TRIANGLE_STRIP) + { + strips.push_back(TriStrip(groups[i].Indices.size())); + TriStrip &strip = strips.back(); + + for (j=0; j<groups[i].Indices.size(); j++) + strip[j] = groups[i].Indices[j]; + } else + { + int size = stris.size(); + stris.resize(size + groups[i].Indices.size()/3); + for (j=(size>0)?(size-1):0; j<stris.size(); j++) + { + stris[j][0] = groups[i].Indices[j*3+0]; + stris[j][1] = groups[i].Indices[j*3+1]; + stris[j][2] = groups[i].Indices[j*3+2]; + } + } + } + + if (stris.size()) + { + // stitch em + TriStrip strip; + if (strips.size() > 0) + { + strip.push_back(strips.back()[strips.back().size()-1]); + strip.push_back(stris[0][0]); + } + for (i=0; i<stris.size(); i++) + { + if (i > 0) + { + strip.push_back(stris[i][0]); + strip.push_back(stris[i][0]); + } + + strip.push_back(stris[i][0]); + strip.push_back(stris[i][1]); + strip.push_back(stris[i][2]); + if (i < stris.size()-1) + strip.push_back(stris[i][2]); + } + strips.push_back(strip); + } + + if (strips.size() > 0) + { + SetStripCount(strips.size()); + + int i = 0; + TriStrips::const_iterator it; + for (it=strips.begin(); it!=strips.end(); ++it) + SetStrip(i++, *it); + } + + //Recalculate Triangle Count + numTriangles = CalcTriangleCount(); +}