diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index db4fa85f2c157698262f2df209eedb363990ae4b..902dc78cfc998d967e3d5e31b4c4edac2bff90d8 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -27,6 +27,28 @@ Change log ---------- + + 0.2 + ----- + o Importer + - Added Vertex Color modifier support + - Fixed issue with static animation import + - Fixed issue with skin vertex weight count import + + o Exporter + - Upgraded to Visual Studio 2005 + - Dropped registry support in favor of INI file. + - Dropped Official Max6 support because I do not have SDK to compile it with (try the max 7 files). + - Fixed issue with importing glossiness setting on textures. + - Fixed issues with export of vertex color. Alpha map is now exported as part of the normal color map. + - No longer exports meshes associated with bone or biped nodes. + - No longer exports extra NiNode when exporting NiTriGeom-based objects (can be reset in ini file) + - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok) + - Modified UPB export to actually export the values in the UserPropBuffer not just a fixed list. + - Added Skin Modifier export + + o NifProps Utility + - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok) 0.1.5 ----- diff --git a/MaxNifTools.ini b/MaxNifTools.ini index 13800f9c7d798749280a9a2d4fa110b4bdb2a0f7..c7b2529df4b160dd7e4ce3bba87ac4db452b4627 100644 --- a/MaxNifTools.ini +++ b/MaxNifTools.ini @@ -11,6 +11,8 @@ KnownApplications=Oblivion;Morrowind;Civ4;DAoC Reparse=0 [MaxNifExport] +; Max SDK Plugin Version (0 - AutoSelect; 0x17700d00 - Max6, 0x1f401100 - Max8) Default: 0 +MaxSDKVersion=0 ; Current Application to get setting/directory information from. Should match KnownApps above or Auto. ; Auto will check the import file against the known root paths use that app if a directory match is found. CurrentApp=Auto @@ -32,10 +34,20 @@ VertexColors=1 RemapIndices=1 ; Texture Prefix if texture not found in AppSettings directory. Default:textures TexturePrefix=textures -; Version to tell 3ds Max that we are for compatibility. Default:013 -Version=013 +; Add Export additional NiNodes for Meshes. Default: 0 +ExportExtraNodes=0 +; Export Skin Modifier when attached to bones. Default: 1 +ExportSkin=1 +; Export UserPropBuffer. Default: 0 +UserPropBuffer=0 +; Flatten Node Hierarchy. Default: 0 +FlattenHierarchy=0 +; Remove Unreferenced Bones. Default: 0 +RemoveUnreferencedBones=0 [MaxNifImport] +; Max SDK Plugin Version (0 - AutoSelect; 0x17700d00 - Max6, 0x1f401100 - Max8) Default: 0 +MaxSDKVersion=0x17700d00 ; Current Application to get setting/directory information from. Should match KnownApps above or Auto. ; Auto will check the import file against the known root paths use that app if a directory match is found. CurrentApp=Auto @@ -51,13 +63,15 @@ ShowTextures=1 EnableAutoSmooth=1 ; AutoSmooth angle. Default: 30 AutoSmoothAngle=30.0 -; Remove Double/Illegal faces on meshes on import +; Remove Double/Illegal faces on meshes on import. Default:1 RemoveDoubleFaces=1 RemoveIllegalFaces=1 -; EnableSkinSupport attempt to skin the mesh if bones are available +; EnableSkinSupport attempt to skin the mesh if bones are available. Default:1 EnableSkinSupport=1 -; Enable Havok Collision Support +; Enable Havok Collision Support. Default:1 EnableCollision=1 +; Vertex Color Support mode. (0-Disable; 1-Bake into mesh; 2-Use VertexPaint Modifier) Default:1 +VertexColorMode=1 [BipedImport] ; Top level bone import setting. Default:1 diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp index 9296d470d5ff329b1552990d1e1be2649ab241c5..3f2190afafdf38b239afd0220d83afe5d2fa0793 100644 --- a/NifCommon/niutils.cpp +++ b/NifCommon/niutils.cpp @@ -558,3 +558,60 @@ INode* FindINode(Interface *i, NiObjectNETRef node) } return NULL; } + +Matrix3 GetNodeLocalTM(INode *n, TimeValue t) +{ + Matrix3 m3 = n->GetNodeTM(t); + Matrix3 m3p = n->GetParentTM(t); + m3p.Invert(); + return m3 * m3p; +} + +// Locate a TriObject in an Object if it exists +TriObject* GetTriObject(Object *o) +{ + if (o && o->CanConvertToType(triObjectClassID)) + return (TriObject *)o->ConvertToType(0, triObjectClassID); + while (o->SuperClassID() == GEN_DERIVOB_CLASS_ID && o) + { + IDerivedObject* dobj = (IDerivedObject *)(o); + o = dobj->GetObjRef(); + if (o && o->CanConvertToType(triObjectClassID)) + return (TriObject *)o->ConvertToType(0, triObjectClassID); + } + return NULL; +} + +// Get or Create the Skin Modifier +Modifier *GetSkin(INode *node) +{ + Object* pObj = node->GetObjectRef(); + if (!pObj) return NULL; + while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) + { + IDerivedObject* pDerObj = (IDerivedObject *)(pObj); + int Idx = 0; + while (Idx < pDerObj->NumModifiers()) + { + // Get the modifier. + Modifier* mod = pDerObj->GetModifier(Idx); + if (mod->ClassID() == SKIN_CLASSID) + { + // is this the correct Physique Modifier based on index? + return mod; + } + Idx++; + } + pObj = pDerObj->GetObjRef(); + } + + IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef()); + + //create a skin modifier and add it + Modifier *skinMod = (Modifier*) CreateInstance(OSM_CLASS_ID, SKIN_CLASSID); + dobj->SetAFlag(A_LOCK_TARGET); + dobj->AddModifier(skinMod); + dobj->ClearAFlag(A_LOCK_TARGET); + node->SetObjectRef(dobj); + return skinMod; +} diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index c3ebf85bfa4760228dd0856a1ac43e5b0ef5b9e8..1a8cf8f0ef58eda64eee8555d53fd0b4ef37c198 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -58,19 +58,20 @@ inline TCHAR *Trim(TCHAR*&p) { // Case insensitive string equivalence test for collections struct ltstr { - bool operator()(const TCHAR* s1, const TCHAR* s2) const + bool operator()(const char* s1, const char* s2) const { return _tcsicmp(s1, s2) < 0; } - bool operator()(const std::string& s1, const std::string& s2) const - { return s1.compare(s2) < 0; } + bool operator()(const string& s1, const string& s2) const + { return _tcsicmp(s1.c_str(), s2.c_str()) < 0; } - bool operator()(const std::string& s1, const TCHAR * s2) const - { return s1.compare(s2) < 0; } + bool operator()(const string& s1, const char * s2) const + { return _tcsicmp(s1.c_str(), s2) < 0; } - bool operator()(const TCHAR * s1, const std::string& s2) const - { return s2.compare(s1) >= 0; } + bool operator()(const char * s1, const string& s2) const + { return _tcsicmp(s1, s2.c_str()) >= 0; } }; + // Case insensitive string equivalence but numbers are sorted together struct NumericStringEquivalence { @@ -228,6 +229,7 @@ enum PosRotScale extern void PosRotScaleNode(INode *n, Point3 p, Quat& q, float s, PosRotScale prs = prsDefault, TimeValue t = 0); extern void PosRotScaleNode(Control *c, Point3 p, Quat& q, float s, PosRotScale prs = prsDefault, TimeValue t = 0); extern void PosRotScaleNode(INode *n, Matrix3& m3, PosRotScale prs = prsDefault, TimeValue t = 0); +extern Matrix3 GetNodeLocalTM(INode *n, TimeValue t = 0); extern Niflib::NiNodeRef FindNodeByName( const vector<Niflib::NiNodeRef>& blocks, const string& name ); extern std::vector<Niflib::NiNodeRef> SelectNodesByName( const vector<Niflib::NiNodeRef>& blocks, LPCTSTR match); @@ -269,20 +271,15 @@ static inline Color TOCOLOR(const Niflib::Color3& c3) { return Color(c3.r, c3.g, c3.b); } -static inline Matrix3 TOMATRIX3(const Niflib::Matrix44 &tm, bool invert = false){ - Niflib::Vector3 pos; Niflib::Matrix33 rot; float scale; - tm.Decompose(pos, rot, scale); - Matrix3 m(rot.rows[0].data, rot.rows[1].data, rot.rows[2].data, Point3()); - if (invert) m.Invert(); - m.SetTrans(Point3(pos.x, pos.y, pos.z)); - return m; -} - static inline Point3 TOPOINT3(const Niflib::Vector3& v){ return Point3(v.x, v.y, v.z); } +static inline Niflib::Vector3 TOVECTOR3(const Point3& v){ + return Niflib::Vector3(v.x, v.y, v.z); +} + static inline Quat TOQUAT(const Niflib::Quaternion& q, bool inverse = false){ Quat qt(q.x, q.y, q.z, q.w); return (inverse) ? qt.Inverse() : qt; @@ -299,6 +296,22 @@ static inline AngAxis TOANGAXIS(const Niflib::Quaternion& q, bool inverse = fals return AngAxis(q.x, q.y, q.z, q.w); } +static inline Matrix3 TOMATRIX3(const Niflib::Matrix44 &tm, bool invert = false){ + Niflib::Vector3 pos; Niflib::Matrix33 rot; float scale; + tm.Decompose(pos, rot, scale); + Matrix3 m(rot.rows[0].data, rot.rows[1].data, rot.rows[2].data, Point3()); + if (invert) m.Invert(); + m.SetTrans(Point3(pos.x, pos.y, pos.z)); + return m; +} + +static inline Niflib::Matrix44 TOMATRIX4(const Matrix3 &tm, bool invert = false){ + Niflib::Matrix33 m3(tm.GetRow(0)[0], tm.GetRow(0)[1], tm.GetRow(0)[2], + tm.GetRow(1)[0], tm.GetRow(1)[1], tm.GetRow(1)[2], + tm.GetRow(2)[0], tm.GetRow(2)[1], tm.GetRow(2)[2]); + Niflib::Matrix44 m4(TOVECTOR3(tm.GetTrans()), m3, 1.0f); + return m4; +} template <typename U, typename T> inline Niflib::Ref<U> SelectFirstObjectOfType( vector<Niflib::Ref<T> > const & objs ) { @@ -321,4 +334,7 @@ inline Niflib::Ref<U> SelectFirstObjectOfType( list<Niflib::Ref<T> > const & obj TSTR PrintMatrix3(Matrix3& m); TSTR PrintMatrix44(Niflib::Matrix44& m); +extern Modifier *GetSkin(INode *node); +extern TriObject* GetTriObject(Object *o); + #endif // _NIUTILS_H_ \ No newline at end of file diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp index 659d7b07610fbf54d2579b65210f4f1fe32f982f..5c4937cadb20e65d8f923e8f922cad1db6c0e984 100755 --- a/NifExport/Config.cpp +++ b/NifExport/Config.cpp @@ -48,7 +48,6 @@ void Exporter::writeConfig(Interface *i) LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); PathCombine(iniName, pluginDir, "MaxNifTools.ini"); - SetIniValue(NifExportSection, "Version", mVersion, iniName); SetIniValue(NifExportSection, "GenerateStrips", mTriStrips, iniName); SetIniValue(NifExportSection, "IncludeHidden", mExportHidden, iniName); SetIniValue(NifExportSection, "FurnatureMarkers", mExportFurn, iniName); @@ -92,7 +91,7 @@ void Exporter::readConfig(Interface *i) LPCTSTR pluginDir = i->GetDir(APP_PLUGCFG_DIR); PathCombine(iniName, pluginDir, "MaxNifTools.ini"); - mVersion = GetIniValue<int>(NifExportSection, "Version", 013, iniName); + //mVersion = GetIniValue<int>(NifExportSection, "Version", 013, iniName); mTriStrips = GetIniValue<bool>(NifExportSection, "GenerateStrips", true, iniName); mExportHidden = GetIniValue<bool>(NifExportSection, "IncludeHidden", false, iniName); mExportFurn = GetIniValue<bool>(NifExportSection, "FurnatureMarkers", true, iniName); @@ -102,6 +101,13 @@ void Exporter::readConfig(Interface *i) mTexPrefix = GetIniValue<string>(NifExportSection, "TexturePrefix", "textures", iniName); mExportCollision = GetIniValue<bool>(NifExportSection, "ExportCollision", true, iniName); mRemapIndices = GetIniValue(NifExportSection, "RemapIndices", true, iniName); + + mExportExtraNodes = GetIniValue(NifExportSection, "ExportExtraNodes", false, iniName); + mExportSkin = GetIniValue(NifExportSection, "ExportSkin", false, iniName); + mUserPropBuffer = GetIniValue(NifExportSection, "UserPropBuffer", false, iniName); + mFlattenHierarchy = GetIniValue(NifExportSection, "FlattenHierarchy", false, iniName); + mRemoveUnreferencedBones = GetIniValue(NifExportSection, "RemoveUnreferencedBones", false, iniName); + mSortNodesToEnd = GetIniValue(NifExportSection, "SortNodesToEnd", false, iniName); } } diff --git a/NifExport/DllEntry.cpp b/NifExport/DllEntry.cpp index 6fdd5ac3362c37472c5e0e98040ebd64eae453c9..3d0f8fad0569996db48f4cec1a1b8d941defcd5f 100755 --- a/NifExport/DllEntry.cpp +++ b/NifExport/DllEntry.cpp @@ -1,9 +1,12 @@ #include "pch.h" +#include "niutils.h" extern ClassDesc2* GetNifExportDesc(); +static void InitializeLibSettings(); HINSTANCE hInstance; int controlsInit = FALSE; +int libVersion = VERSION_3DSMAX; // This function is called by Windows when the DLL is loaded. This // function may also be called many times during time critical operations @@ -20,10 +23,31 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) InitCustomControls(hInstance); // Initialize MAX's custom controls InitCommonControls(); // Initialize Win95 controls } - + if (fdwReason == DLL_PROCESS_ATTACH) + InitializeLibSettings(); return (TRUE); } +void InitializeLibSettings() +{ + Interface *gi = GetCOREInterface(); + TCHAR iniName[MAX_PATH]; + if (gi) { + LPCTSTR pluginDir = gi->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + } else { + GetModuleFileName(NULL, iniName, _countof(iniName)); + if (LPTSTR fname = PathFindFileName(iniName)) + fname = NULL; + PathAddBackslash(iniName); + PathAppend(iniName, "plugcfg"); + PathAppend(iniName, "MaxNifTools.ini"); + } + libVersion = GetIniValue("MaxNifExport", "MaxSDKVersion", libVersion, iniName); + if (libVersion == 0) + libVersion = VERSION_3DSMAX; +} + // This function returns a string that describes the DLL and where the user // could purchase the DLL if they don't have it. __declspec( dllexport ) const TCHAR* LibDescription() @@ -52,7 +76,7 @@ __declspec( dllexport ) ClassDesc* LibClassDesc(int i) // to catch obsolete DLLs. __declspec( dllexport ) ULONG LibVersion() { - return VERSION_3DSMAX; + return libVersion; } TCHAR *GetString(int id) diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index 05eaed77d3bd5e1ba58cad5167290667817b30c3..a38bfe331892fd4a3c5d67ff83de4f2c477aad17 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -14,6 +14,12 @@ string Exporter::mTexPrefix="textures"; bool Exporter::mExportCollision=true; bool Exporter::mRemapIndices=true; bool Exporter::mUseRegistry=false; +bool Exporter::mExportExtraNodes=false; +bool Exporter::mExportSkin=false; +bool Exporter::mUserPropBuffer=false; +bool Exporter::mFlattenHierarchy=false; +bool Exporter::mRemoveUnreferencedBones=false; +bool Exporter::mSortNodesToEnd=false; Exporter::Exporter(Interface *i, AppSettings *appSettings) : mI(i), mAppSettings(appSettings) @@ -22,32 +28,11 @@ Exporter::Exporter(Interface *i, AppSettings *appSettings) Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) { - BSXFlagsRef bsx = DynamicCast<BSXFlags>(CreateBlock("BSXFlags")); + BSXFlagsRef bsx = CreateNiObject<BSXFlags>(); bsx->SetName("BSX"); bsx->SetFlags(0x00000002); root->AddExtraData(DynamicCast<NiExtraData>(bsx)); - - // Write the actual UPB sans any np_ prefixed strings - TSTR upb; - node->GetUserPropBuffer(upb); - if (!upb.isNull()) - { - string line; - istringstream istr(string(upb), ios_base::out); - ostringstream ostr; - while (!istr.eof()) { - std::getline(istr, line); - if (!line.empty() && 0 != line.compare(0, 3, "np_")) - ostr << line << endl; - } - if (!ostr.str().empty()) - { - NiStringExtraDataRef strings = DynamicCast<NiStringExtraData>(CreateBlock("NiStringExtraData")); - strings->SetName("UPB"); - strings->SetData(ostr.str()); - root->AddExtraData(DynamicCast<NiExtraData>(strings)); - } - } + exportUPB(root, node); mNiRoot = root; @@ -58,11 +43,22 @@ Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) if (mExportCollision) { - result = exportCollision(root, node); if (result != Ok) return result; } + // handle post export callbacks (like skin) + for (CallbackList::iterator cb = mPostExportCallbacks.begin(); cb != mPostExportCallbacks.end(); cb = mPostExportCallbacks.erase(cb)) + { + (*cb)->execute(); + delete (*cb); + } + // Remove unreferenced Bones + if (mRemoveUnreferencedBones) + removeUnreferencedBones(mNiRoot); + if (mSortNodesToEnd) + sortNodes(mNiRoot); + return Ok; } diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index 01a991ba2fe40bd00f867d01c8cb891331b72233..a931c1be48718980b30b77c6e6906be033f09872 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -19,6 +19,15 @@ public: Skip }; + // Callback for post-processing instructions + struct NiCallback + { + NiCallback() {}; + virtual ~NiCallback() {}; + virtual Result execute() = 0; + }; + + /* exporter version */ static int mVersion; @@ -33,7 +42,13 @@ public: static bool mVertexColors; static float mWeldThresh; static bool mExportCollision; - static bool mRemapIndices; + static bool mRemapIndices; + static bool mExportExtraNodes; + static bool mExportSkin; + static bool mUserPropBuffer; + static bool mFlattenHierarchy; + static bool mRemoveUnreferencedBones; + static bool mSortNodesToEnd; Exporter(Interface *i, AppSettings *appSettings); @@ -67,14 +82,20 @@ private: Triangles faces; vector<TexCoord> uvs; vector<Color4> vcolors; + vector<int> vidx; + TriStrips strips; }; // maps face groups to material ID typedef std::map<int, FaceGroup> FaceGroups; - + typedef std::map<string, NiNodeRef> NodeMap; + typedef std::list<NiCallback*> CallbackList; + Interface *mI; NiNodeRef mNiRoot; AppSettings *mAppSettings; + NodeMap mNodeMap; + CallbackList mPostExportCallbacks; Result exportCollision(NiNodeRef &root, INode *node); Result exportMeshes(NiNodeRef &root, INode *node); @@ -89,7 +110,8 @@ private: bool equal(const Vector3 &a, const Point3 &b, float thresh); BitmapTex *getTexture(Mtl *mtl); void getTextureMatrix(Matrix3 &mat, Mtl *mtl); - NiNodeRef makeNode(NiNodeRef &parent, INode *maxNode, bool local=true); + NiNodeRef makeNode(NiNodeRef &parent, INode *maxNode, bool local=true); + NiNodeRef getNode(const string& name); // returns true if the node contains collision objects bool isCollisionGroup(INode *maxNode, bool root=true); // returns true if the node contains meshes @@ -97,19 +119,19 @@ private: /* tristrips */ void strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vector3> &norms, const Triangles &tris); - void strippify(TriStrips &strips, FaceGroup &grp); + void strippify(FaceGroup &grp); NiTriStripsDataRef makeTriStripsData(const TriStrips &strips); /* mesh export */ // adds a vertex to a face group if it doesn't exist yet. returns new or previous index into the // vertex array. - int addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm); + int addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm, vector<Color4>& vertColors); // adds a face to a face group - void addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm); + void addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm, vector<Color4>& vertColors); // creates face groups from faces with same sub material id - bool splitMesh(INode *node, Mesh *, FaceGroups &grps, TimeValue t); + bool splitMesh(INode *node, Mesh *, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors); // creates a NiTriStrips or NiTriShape hierarchy from a face group - bool makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp); + NiTriBasedGeomRef makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp, bool exportStrips); // splits mesh and converts it into nif blocks Result exportMesh(NiNodeRef &parent, INode *node, TimeValue t); @@ -134,6 +156,15 @@ private: bhkSphereRepShapeRef makeBoxShape(Object *obj); bhkSphereRepShapeRef makeSphereShape(Object *obj); bhkSphereRepShapeRef makeCapsuleShape(Object *obj); + + /* skin export */ + bool makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t); + bool exportSkin(); + + /* misc export */ + bool exportUPB(NiNodeRef &root, INode *node); + bool removeUnreferencedBones(NiNodeRef node); + void sortNodes(NiNodeRef node); }; #endif diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index 54e9fb973a149de5f86c598f2f2dab29a381de6f..2ec3cb8d42e6eafd40293523d2efb49b427ccf48 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -1,5 +1,12 @@ #include "pch.h" - +#include "niutils.h" +#include "iskin.h" +#ifdef USE_BIPED +# include <cs/BipedApi.h> +#endif +#include "obj/NiSkinInstance.h" +#include "obj/NiSkinData.h" +#include "obj/NiSkinPartition.h" /* void FPUtility::GetAlphaVal(void) @@ -46,24 +53,51 @@ Exporter::Result Exporter::exportMeshes(NiNodeRef &parent, INode *node) if (coll || (node->IsHidden() && !mExportHidden && !coll) || (mSelectedOnly && !node->Selected())) return Skip; + bool local = !mFlattenHierarchy; + NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent; + NiNodeRef newParent; TimeValue t = 0; ObjectState os = node->EvalWorldState(t); - if (os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) - { - newParent = makeNode(parent, node); - Result result; - result = exportMesh(newParent, node, t); - if (result != Ok) - return result; - - } else - if (isMeshGroup(node)) + // Always skip bones and bipeds + SClass_ID scid = node->SuperClassID(); + Class_ID ncid = node->ClassID(); + TSTR nodeName = node->GetName(); + TSTR nodeClass; node->GetClassName(nodeClass); + + // For some unusual reason, bones named Helper are converted to Meshes and + // lose their Bone properties except a new node named Bone seem to show up + if (node->IsBoneShowing() || strmatch(nodeName, "Bone")) + newParent = makeNode(nodeParent, node, local); + else if (os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) + { + TSTR objClass; + os.obj->GetClassName(objClass); + SClass_ID oscid = os.obj->SuperClassID(); + Class_ID oncid = os.obj->ClassID(); + if (os.obj && (os.obj->ClassID() == BONE_OBJ_CLASSID || os.obj->ClassID() == Class_ID(BONE_CLASS_ID,0))) + newParent = makeNode(nodeParent, node, local); +#ifdef USE_BIPED + else if (os.obj && os.obj->node->ClassID() == BIPED_CLASS_ID) + newParent = makeNode(nodeParent, node, local); +#endif + else + { + newParent = (mExportExtraNodes) ? makeNode(nodeParent, node, local) : nodeParent; + + Result result; + result = exportMesh(newParent, node, t); + if (result != Ok) + return result; + } + } + else if (isMeshGroup(node) && local) // only create node if local { - newParent = makeNode(parent, node); + newParent = makeNode(parent, node, local); - } else + } + else newParent = parent; for (int i=0; i<node->NumberOfChildren(); i++) @@ -81,31 +115,93 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue { ObjectState os = node->EvalWorldState(t); + bool local = !mFlattenHierarchy; + TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0)); if (!tri) return Error; Mesh *mesh = &tri->GetMesh(); + + // Note that calling setVCDisplayData will clear things like normals so we set this up first + vector<Color4> vertColors; + if (mVertexColors) + { + bool hasvc = false; + if (mesh->mapSupport(MAP_ALPHA)) + { + mesh->setVCDisplayData(MAP_ALPHA); + int n = mesh->getNumVertCol(); + if (n > vertColors.size()) + vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); + VertColor *vertCol = mesh->vertColArray; + if (vertCol) { + for (int i=0; i<n; ++i) { + VertColor c = vertCol[ i ]; + float a = (c.x + c.y + c.z) / 3.0f; + vertColors[i].a = a; + hasvc |= (a != 1.0f); + } + } + } + if (mesh->mapSupport(0)) + { + mesh->setVCDisplayData(0); + VertColor *vertCol = mesh->vertColArray; + int n = mesh->getNumVertCol(); + if (n > vertColors.size()) + vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); + if (vertCol) { + for (int i=0; i<n; ++i) { + VertColor col = vertCol[ i ]; + vertColors[i] = Color4(col.x, col.y, col.z, vertColors[i].a); + hasvc |= (col.x != 1.0f || col.y != 1.0f || col.z != 1.0f); + } + } + } + if (!hasvc) vertColors.clear(); + } + mesh->buildNormals(); Result result = Ok; while (1) { FaceGroups grps; - if (!splitMesh(node, mesh, grps, t)) + if (!splitMesh(node, mesh, grps, t, vertColors)) { result = Error; break; } + bool exportStrips = mTriStrips; + + // Disable strips if exporting skin nodes, for now + //if (exportStrips && mExportSkin && GetSkin(node) != NULL) + // exportStrips = false; + + Matrix33 rot; Vector3 trans; + nodeTransform(rot, trans, node, t, local); + Matrix44 tm(trans, rot, 1.0f); + + TSTR basename = node->NodeName(); + TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s"; + + int i=1; FaceGroups::iterator grp; - for (grp=grps.begin(); grp!=grps.end(); ++grp) + for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i) { - if (!makeMesh(ninode, getMaterial(node, grp->first), grp->second)) + string name = FormatString(basename, basename.data(), i); + NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips); + if (shape == NULL) { result = Error; break; } + + shape->SetName(name); + shape->SetLocalTransform(tm); + makeSkin(shape, node, grp->second, t); } break; @@ -117,28 +213,25 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue return result; } -bool Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp) +NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp, bool exportStrips) { NiTriBasedGeomRef shape; NiTriBasedGeomDataRef data; - if (mTriStrips) + if (exportStrips) { - NiTriStripsRef stripsShape = DynamicCast<NiTriStrips>(CreateBlock("NiTriStrips")); + NiTriStripsRef stripsShape = CreateNiObject<NiTriStrips>(); shape = DynamicCast<NiTriBasedGeom>(stripsShape); - - TriStrips strips; - strippify(strips, grp); - NiTriStripsDataRef stripData = makeTriStripsData(strips); + strippify(grp); + NiTriStripsDataRef stripData = makeTriStripsData(grp.strips); data = DynamicCast<NiTriBasedGeomData>(stripData); } else { - NiTriShapeRef tris = DynamicCast<NiTriShape>(CreateBlock("NiTriShape")); - NiTriShapeDataRef triData = DynamicCast<NiTriShapeData>(CreateBlock("NiTriShapeData")); + NiTriShapeRef tris = CreateNiObject<NiTriShape>(); + NiTriShapeDataRef triData = CreateNiObject<NiTriShapeData>(); data = DynamicCast<NiTriBasedGeomData>(triData); shape = DynamicCast<NiTriBasedGeom>(tris); - triData->SetTriangles(grp.faces); } @@ -162,21 +255,27 @@ bool Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp) parent->AddChild(DynamicCast<NiAVObject>(shape)); - return true; + return shape; } -int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm) +int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matrix3 &texm, vector<Color4>& vertColors) { - Point3 pt = mesh->verts[ mesh->faces[ face ].v[ vi ] ]; - Point3 norm = getVertexNormal(mesh, face, mesh->getRVertPtr(mesh->faces[ face ].v[ vi ])); + int vidx = mesh->faces[ face ].v[ vi ]; + Point3 pt = mesh->verts[ vidx ]; + Point3 norm = getVertexNormal(mesh, face, mesh->getRVertPtr(vidx)); Point3 uv; - if (mesh->tvFace) + if (mesh->tVerts && mesh->tvFace) uv = mesh->tVerts[ mesh->tvFace[ face ].t[ vi ]] * texm; - VertColor col; - if (mVertexColors && mesh->vertCol) - col = mesh->vertCol[ mesh->vcFace[ face ].t[ vi ] ]; + Color4 col(1.0f, 1.0f, 1.0f); + if (mVertexColors && !vertColors.empty()){ + TVFace *vcFace = mesh->vcFaceData ? mesh->vcFaceData : mesh->vcFace; + if (vcFace) { + int vidx = vcFace[ face ].t[ vi ]; + col = vertColors[vidx]; + } + } for (int i=0; i<grp.verts.size(); i++) { @@ -186,38 +285,40 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr if (mesh->tvFace && (grp.uvs[i].u!=uv.x || grp.uvs[i].v!=uv.y)) continue; - if (mVertexColors && mesh->vertCol && - (grp.vcolors[i].r!=col.x || - grp.vcolors[i].g!=col.y || - grp.vcolors[i].b!=col.z)) + if (mVertexColors && !vertColors.empty() && + (grp.vcolors[i].r!=col.r || + grp.vcolors[i].g!=col.g || + grp.vcolors[i].b!=col.b)) continue; return i; } } + grp.vidx.push_back(vidx); grp.verts.push_back(Vector3(pt.x, pt.y, pt.z)); grp.vnorms.push_back(Vector3(norm.x, norm.y, norm.z)); if (mesh->tvFace) grp.uvs.push_back(TexCoord(uv.x, uv.y)); - if (mVertexColors && mesh->vertCol) - grp.vcolors.push_back(Color4(col.x, col.y, col.z, 1)); + if (mVertexColors && !vertColors.empty()){ + grp.vcolors.push_back(col); + } return grp.verts.size()-1; } -void Exporter::addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm) +void Exporter::addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, const Matrix3 &texm, vector<Color4>& vertColors) { Triangle tri; for (int i=0; i<3; i++) - tri[i] = addVertex(grp, face, vi[i], mesh, texm); + tri[i] = addVertex(grp, face, vi[i], mesh, texm, vertColors); grp.faces.push_back(tri); } -bool Exporter::splitMesh(INode *node, Mesh *mesh, FaceGroups &grps, TimeValue t) +bool Exporter::splitMesh(INode *node, Mesh *mesh, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors) { Mtl* nodeMtl = node->GetMtl(); Matrix3 tm = node->GetObjTMAfterWSM(t); @@ -251,8 +352,162 @@ bool Exporter::splitMesh(INode *node, Mesh *mesh, FaceGroups &grps, TimeValue t) texm *= flip; - addFace(grps[mtlID], i, vi, mesh, texm); + addFace(grps[mtlID], i, vi, mesh, texm, vertColors); } return true; } + +// Callback interface to register a Skin after entire structure is built due to contraints +// in the nif library +struct SkinInstance : public Exporter::NiCallback +{ + 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; + + + Exporter *owner; + // Common Data + NiTriBasedGeomRef shape; + vector<NiNodeRef> boneList; + + // Bone to weight map + BoneWeightList boneWeights; + + // Partition + int nWeightsPerVertex; + vector<WeightList> vertexWeights; + BoneList boneMap; + vector<ushort> vertexMap; + Strips strips; + vector<BoneList> boneIndexList; + Triangles triangles; + + SkinInstance(Exporter *Owner) : owner(Owner) {} + virtual ~SkinInstance() {} + virtual Exporter::Result execute(); +}; + + +bool Exporter::makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t) +{ + if (!mExportSkin) + return false; + + if (grp.verts.empty()) + return false; + + //get the skin modifier + Modifier *mod = GetSkin(node); + if (!mod) + return false; + + ISkin *skin = (ISkin *) mod->GetInterface(I_SKIN); + if (!skin) + return false; + + ISkinContextData *skinData = skin->GetContextInterface(node); + if (!skinData) + return false; + + if (grp.strips.empty()) + strippify(grp); + + // Create new call back to finish export + SkinInstance* si = new SkinInstance(this); + mPostExportCallbacks.push_back(si); + + si->shape = shape; + for (TriStrips::iterator strip = grp.strips.begin(); strip != grp.strips.end(); ++strip) + si->strips.push_back(*strip); + + // Get number of weights per vertex + int nWeightsPerVertex = 4; + Interval ivalid; + IParamBlock2 *params = mod->GetParamBlockByID(2/*advanced*/); + params->GetValue(0x7/*bone_Limit*/, 0, nWeightsPerVertex, ivalid); + si->nWeightsPerVertex = nWeightsPerVertex; + + // Get bone references (may not actually exist in proper structure at this time) + int totalBones = skin->GetNumBones(); + si->boneWeights.resize(totalBones); + si->boneList.resize(totalBones); + si->boneMap.resize(totalBones); + for (int i=0; i<totalBones; ++i) { + string name = skin->GetBoneName(i); + si->boneList[i] = getNode(name); + si->boneMap[i] = i; + } + + vector<int>& vidx = grp.vidx; + vector<Vector3>& verts = grp.verts; + int nv = vidx.size(); + si->vertexMap.resize(nv); + si->vertexWeights.resize(nv); + si->boneIndexList.resize(nv); + + for (int i=0; i<nv; ++i) + { + SkinInstance::WeightList& vertexWeights = si->vertexWeights[i]; + SkinInstance::BoneList& boneIndexList = si->boneIndexList[i]; + vertexWeights.assign(nWeightsPerVertex, 0.0f); + boneIndexList.resize(nWeightsPerVertex, 0); + si->vertexMap[i] = i; + + int vi = vidx[i]; + Vector3& vert = verts[i]; + int nbones = skinData->GetNumAssignedBones(vi); + for (int j=0; j<nbones; ++j) + { + SkinWeight sw; + sw.index = i; + sw.weight = skinData->GetBoneWeight(vi,j); + int boneIndex = skinData->GetAssignedBone(vi,j); + + SkinInstance::SkinWeightList& weights = si->boneWeights[boneIndex]; + weights.push_back(sw); + + boneIndexList[j] = boneIndex; + vertexWeights[j] = sw.weight; + } + } + return true; +} + +Exporter::Result SkinInstance::execute() +{ + shape->BindSkin(boneList); + uint bone = 0; + for (BoneWeightList::iterator bitr = boneWeights.begin(); bitr != boneWeights.end(); ++bitr, ++bone) + shape->SetBoneWeights(bone, (*bitr)); + + NiSkinInstanceRef skin = shape->GetSkinInstance(); + NiSkinPartitionRef partition = CreateNiObject<NiSkinPartition>(); + partition->SetNumPartitions(1); + partition->SetWeightsPerVertex(0, nWeightsPerVertex); + partition->SetBoneMap(0, boneMap); + partition->SetNumVertices(0, ushort(vertexMap.size()) ); + partition->SetVertexMap(0, vertexMap); + partition->EnableVertexWeights(0, true); + for (int i=0; i<vertexWeights.size(); ++i) { + partition->SetVertexWeights(0, i, vertexWeights[i]); + } + //partition->SetTriangles() + partition->SetStripCount(0, ushort(strips.size()) ); + for (int i=0; i<strips.size(); ++i) { + partition->SetStrip(0, i, strips[i]); + } + partition->EnableVertexBoneIndices(0, true); + for (int i=0; i<boneIndexList.size(); ++i) { + partition->SetVertexBoneIndices(0, i, boneIndexList[i]); + } + + skin->SetSkinPartition(partition); + + return Exporter::Ok; +} diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj index f26a65a4a35a47778d2a073f6d79715570ba76fa..fc8e25e2ef0100924b32526d640dbcbc0fd0b6c3 100644 --- a/NifExport/NifExport_VC80.vcproj +++ b/NifExport/NifExport_VC80.vcproj @@ -54,7 +54,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" RuntimeLibrary="0" @@ -156,7 +156,7 @@ AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" ExceptionHandling="2" @@ -253,7 +253,7 @@ AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" ExceptionHandling="2" @@ -356,7 +356,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" RuntimeLibrary="0" @@ -464,7 +464,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" ExceptionHandling="2" RuntimeLibrary="0" @@ -566,7 +566,7 @@ AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" StringPooling="true" MinimalRebuild="true" ExceptionHandling="2" diff --git a/NifExport/Strips.cpp b/NifExport/Strips.cpp index 2294710d7249029a500e5649b3a5e5a36eeba07a..8443bb7d7a049f1467b4a70e0b0eaa257131ff40 100755 --- a/NifExport/Strips.cpp +++ b/NifExport/Strips.cpp @@ -70,8 +70,10 @@ void Exporter::strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vecto } } -void Exporter::strippify(TriStrips &strips, FaceGroup &grp) +void Exporter::strippify(FaceGroup &grp) { + TriStrips &strips = grp.strips; + strips.clear(); unsigned short *data = (unsigned short *)malloc(grp.faces.size() * 3 * 2); int i; diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index 930b0ca58c211383b3c3e0309a4fb0fd7be433b3..c714c707df901670b79a70dac5346865aa847a5a 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -88,10 +88,22 @@ bool Exporter::equal(const Vector3 &a, const Point3 &b, float thresh) (fabsf(a.z-b.z) <= thresh); } +NiNodeRef Exporter::getNode(const string& name) +{ + NodeMap::iterator itr = mNodeMap.find(name); + if (itr != mNodeMap.end()) + return (*itr).second; + NiNodeRef node = CreateNiObject<NiNode>(); + node->SetName(name); + mNodeMap[name] = node; + return node; +} + NiNodeRef Exporter::makeNode(NiNodeRef &parent, INode *maxNode, bool local) { - NiNodeRef node = DynamicCast<NiNode>(CreateBlock("NiNode")); - + string name = (char*)maxNode->GetName(); + NiNodeRef node = getNode(name); + Matrix33 rot; Vector3 trans; TimeValue t = 0; @@ -99,8 +111,8 @@ NiNodeRef Exporter::makeNode(NiNodeRef &parent, INode *maxNode, bool local) node->SetLocalRotation(rot); node->SetLocalTranslation(trans); - string name = (char*)maxNode->GetName(); - node->SetName(name); + + exportUPB(node, maxNode); parent->AddChild(DynamicCast<NiAVObject>(node)); return node; @@ -152,3 +164,91 @@ bool Exporter::isMeshGroup(INode *maxNode, bool root) return false; } + +bool Exporter::exportUPB(NiNodeRef &root, INode *node) +{ + bool ok = false; + if (!mUserPropBuffer) + return ok; + + // Write the actual UPB sans any np_ prefixed strings + TSTR upb; + node->GetUserPropBuffer(upb); + if (!upb.isNull()) + { + string line; + istringstream istr(string(upb), ios_base::out); + ostringstream ostr; + while (!istr.eof()) { + std::getline(istr, line); + if (!line.empty() && 0 != line.compare(0, 3, "np_")) + ostr << line << endl; + } + if (!ostr.str().empty()) + { + NiStringExtraDataRef strings = CreateNiObject<NiStringExtraData>(); + strings->SetName("UPB"); + strings->SetData(ostr.str()); + root->AddExtraData(DynamicCast<NiExtraData>(strings)); + ok = true; + } + } + return ok; +} + + +bool Exporter::removeUnreferencedBones(NiNodeRef node) +{ + NiNodeRef parent = node->GetParent(); + bool remove = (NULL != parent) && !node->IsSkinInfluence(); + Matrix44 ntm = node->GetLocalTransform(); + vector<NiAVObjectRef> children = node->GetChildren(); + for (vector<NiAVObjectRef>::iterator itr = children.begin(); itr != children.end(); ++itr) + { + NiAVObjectRef& child = (*itr); + bool childRemove = false; + if (child->IsDerivedType(NiNode::TypeConst())) + { + childRemove = removeUnreferencedBones(StaticCast<NiNode>(child)); + } + if (childRemove) + { + node->RemoveChild(child); + } + else if (remove) // Reparent abandoned nodes to root + { + Matrix44 tm = child->GetLocalTransform(); + child->SetLocalTransform( ntm * tm ); + node->RemoveChild(child); + mNiRoot->AddChild(child); + } + } + return remove; +} + +struct SortNodeEquivalence +{ + inline bool operator()(const NiAVObjectRef& lhs, const NiAVObjectRef& rhs) const + { + if (!lhs) return !rhs; + if (!rhs) return true; + string ltype = lhs->GetType().GetTypeName(); + string rtype = rhs->GetType().GetTypeName(); + if (ltype == "NiNode") + return false; + if (rtype == "NiNode") + return true; + if (ltype == rtype) + return false; + return (ltype < rtype); + } +}; + +void Exporter::sortNodes(NiNodeRef node) +{ + node->SortChildren(SortNodeEquivalence()); + + vector<NiNodeRef> children = DynamicCast<NiNode>(node->GetChildren()); + for (vector<NiNodeRef>::iterator itr = children.begin(); itr != children.end(); ++itr) + sortNodes(*itr); +} \ No newline at end of file diff --git a/NifImport/DllEntry.cpp b/NifImport/DllEntry.cpp index 436e5afcd8c994c68a7df75ce9743d574eb2d14d..5647fa4c9fced0a99ffc31ed01cc28358f4a336b 100644 --- a/NifImport/DllEntry.cpp +++ b/NifImport/DllEntry.cpp @@ -14,9 +14,11 @@ #include "MaxNifImport.h" extern ClassDesc2* GetMaxNifImportDesc(); +static void InitializeLibSettings(); HINSTANCE hInstance; int controlsInit = FALSE; +int libVersion = VERSION_3DSMAX; // This function is called by Windows when the DLL is loaded. This // function may also be called many times during time critical operations @@ -33,10 +35,33 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) InitCustomControls(hInstance); // Initialize MAX's custom controls InitCommonControls(); // Initialize Win95 controls } + if (fdwReason == DLL_PROCESS_ATTACH) + InitializeLibSettings(); return (TRUE); } +void InitializeLibSettings() +{ + Interface *gi = GetCOREInterface(); + TCHAR iniName[MAX_PATH]; + if (gi) { + LPCTSTR pluginDir = gi->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + } else { + GetModuleFileName(NULL, iniName, _countof(iniName)); + if (LPTSTR fname = PathFindFileName(iniName)) + fname = NULL; + PathAddBackslash(iniName); + PathAppend(iniName, "plugcfg"); + PathAppend(iniName, "MaxNifTools.ini"); + } + libVersion = GetIniValue("MaxNifImport", "MaxSDKVersion", libVersion, iniName); + if (libVersion == 0) + libVersion = VERSION_3DSMAX; + +} + // This function returns a string that describes the DLL and where the user // could purchase the DLL if they don't have it. __declspec( dllexport ) const TCHAR* LibDescription() @@ -60,14 +85,6 @@ __declspec( dllexport ) ClassDesc* LibClassDesc(int i) } } -// This function returns a pre-defined constant indicating the version of -// the system under which it was compiled. It is used to allow the system -// to catch obsolete DLLs. -__declspec( dllexport ) ULONG LibVersion() -{ - return VERSION_3DSMAX; -} - TCHAR *GetString(int id) { static TCHAR buf[256]; @@ -77,3 +94,10 @@ TCHAR *GetString(int id) return NULL; } +// This function returns a pre-defined constant indicating the version of +// the system under which it was compiled. It is used to allow the system +// to catch obsolete DLLs. +__declspec( dllexport ) ULONG LibVersion() +{ + return ULONG(libVersion); +} diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index c126177aae030b3551ac3a03b6712db9ab690ca7..9307e84af31e007e901db9da469638c18d7e2250 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -310,7 +310,7 @@ bool KFMImporter::ImportAnimation() // Set initial conditions Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation()); + Quat q = TOQUAT(interp->GetRotation(), true); float s = interp->GetScale(); PosRotScaleNode(c, p, q, s, prsDefault, 0); @@ -326,7 +326,7 @@ bool KFMImporter::ImportAnimation() // Set initial conditions Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation()); + Quat q = TOQUAT(interp->GetRotation(), true); float s = interp->GetScale(); PosRotScaleNode(c, p, q, s, prsDefault, 0); @@ -349,7 +349,7 @@ bool KFMImporter::ImportAnimation() if (NiTransformInterpolatorRef interp = tc->GetInterpolator()) { // Set initial conditions Point3 p = TOPOINT3(interp->GetTranslation()); - Quat q = TOQUAT(interp->GetRotation()); + Quat q = TOQUAT(interp->GetRotation(), true); float s = interp->GetScale(); PosRotScaleNode(c, p, q, s, prsDefault, 0); diff --git a/NifImport/ImportCollision.cpp b/NifImport/ImportCollision.cpp index 64552101b0a50b635e77b084921501ccd1f22cfd..7d4b307c7d961929b3860fe303224454d896c039 100644 --- a/NifImport/ImportCollision.cpp +++ b/NifImport/ImportCollision.cpp @@ -18,6 +18,7 @@ HISTORY: #include "obj\bhkShape.h" #include "obj\bhkSphereShape.h" #include "obj\bhkCapsuleShape.h" +#include "obj\bhkConvexVerticesShape.h" #include "NifPlugins.h" using namespace Niflib; @@ -39,8 +40,9 @@ struct CollisionImport bool ImportRigidBody(bhkRigidBodyRef rb, INode* node); bool ImportShape(bhkRigidBodyRef body, bhkShapeRef shape, INode* parent); - bool ImportSphere(bhkRigidBodyRef body, bhkSphereShapeRef shape, INode *parent); - bool ImportCapsule(bhkRigidBodyRef body, bhkCapsuleShapeRef shape, INode *parent); + INode* ImportSphere(bhkRigidBodyRef body, bhkSphereShapeRef shape, INode *parent); + INode* ImportCapsule(bhkRigidBodyRef body, bhkCapsuleShapeRef shape, INode *parent); + INode* ImportConvexVertices(bhkRigidBodyRef body, bhkConvexVerticesShapeRef shape, INode *parent); }; bool NifImporter::ImportCollision(NiNodeRef node) @@ -108,22 +110,46 @@ bool CollisionImport::ImportRigidBody(bhkRigidBodyRef body, INode* node) return true; } -bool CollisionImport::ImportShape(bhkRigidBodyRef body, bhkShapeRef shape, INode* node) +bool CollisionImport::ImportShape(bhkRigidBodyRef body, bhkShapeRef shape, INode* parent) { + INode *shapeNode = NULL; if (shape->IsDerivedType(bhkCapsuleShape::TypeConst())) { - return ImportCapsule(body, bhkCapsuleShapeRef(shape), node); + shapeNode = ImportCapsule(body, bhkCapsuleShapeRef(shape), parent); } else if (shape->IsDerivedType(bhkSphereShape::TypeConst())) { - return ImportSphere(body, bhkSphereShapeRef(shape), node); + shapeNode = ImportSphere(body, bhkSphereShapeRef(shape), parent); + } + else if (shape->IsDerivedType(bhkConvexVerticesShape::TypeConst())) + { + shapeNode = ImportConvexVertices(body, bhkConvexVerticesShapeRef(shape), parent); + } + + // Now do common post processing for the node + if (shapeNode != NULL) + { + TSTR name = "bhk"; + name.Append(parent->GetName()); + shapeNode->SetName(name); + + Point3 pos = TOPOINT3(body->GetTranslation()) * ni.bhkScaleFactor; + Quat rot = TOQUAT(body->GetRotation()); + PosRotScaleNode(shapeNode, pos, rot, ni.bhkScaleFactor, prsDefault); + + shapeNode->SetPrimaryVisibility(FALSE); + shapeNode->SetSecondaryVisibility(FALSE); + shapeNode->BoneAsLine(TRUE); + shapeNode->SetRenderable(FALSE); + shapeNode->XRayMtl(TRUE); + parent->AttachChild(shapeNode); + return true; } return false; } -bool CollisionImport::ImportSphere(bhkRigidBodyRef body, bhkSphereShapeRef shape, INode *parent) +INode* CollisionImport::ImportSphere(bhkRigidBodyRef body, bhkSphereShapeRef shape, INode *parent) { - bool ok = false; if (SimpleObject *ob = (SimpleObject *)ni.gi->CreateInstance(GEOMOBJECT_CLASS_ID, Class_ID(SPHERE_CLASS_ID, 0))) { float radius = shape->GetRadius(); @@ -131,34 +157,16 @@ bool CollisionImport::ImportSphere(bhkRigidBodyRef body, bhkSphereShapeRef shape setMAXScriptValue(t, "radius", 0, radius); if (INode *n = ni.gi->CreateObjectNode(ob)) { - TSTR name = "bhk"; - name.Append(parent->GetName()); - n->SetName(name); - // Need to "Affect Pivot Only" and "Center to Object" first n->CenterPivot(0, FALSE); - - Point3 pos = TOPOINT3(body->GetTranslation()) * ni.bhkScaleFactor; - Point3 center = TOPOINT3(body->GetCenter()); - Quat rot = TOQUAT(body->GetRotation()); - PosRotScaleNode(n, pos, rot, ni.bhkScaleFactor, prsDefault); - - n->SetPrimaryVisibility(FALSE); - n->SetSecondaryVisibility(FALSE); - n->BoneAsLine(TRUE); - n->SetRenderable(FALSE); - n->XRayMtl(TRUE); - - parent->AttachChild(n); - ok = true; + return n; } } - return ok; + return NULL; } -bool CollisionImport::ImportCapsule(bhkRigidBodyRef body, bhkCapsuleShapeRef shape, INode *parent) +INode* CollisionImport::ImportCapsule(bhkRigidBodyRef body, bhkCapsuleShapeRef shape, INode *parent) { - bool ok = false; if (SimpleObject *ob = (SimpleObject *)ni.gi->CreateInstance(GEOMOBJECT_CLASS_ID, SCUBA_CLASS_ID)) { float radius = shape->GetRadius(); float radius1 = shape->GetRadius1(); @@ -169,42 +177,24 @@ bool CollisionImport::ImportCapsule(bhkRigidBodyRef body, bhkCapsuleShapeRef sha int heighttype = 1; RefTargetHandle t = ob->GetReference(0); - IParamArray *params = ob->GetParamBlock(); params->SetValue(ob->GetParamBlockIndex(CAPSULE_RADIUS), 0, radius); params->SetValue(ob->GetParamBlockIndex(CAPSULE_HEIGHT), 0, height); params->SetValue(ob->GetParamBlockIndex(CAPSULE_CENTERS), 0, heighttype); - //setMAXScriptValue(t, "radius", 0, radius); - //setMAXScriptValue(t, "height", 0, height); - //setMAXScriptValue(t, "heighttype", 0, heighttype); - if (INode *n = ni.gi->CreateObjectNode(ob)) { - TSTR name = "bhk"; - name.Append(parent->GetName()); - n->SetName(name); - // Need to "Affect Pivot Only" and "Center to Object" first //n->CenterPivot(0, FALSE); - Point3 pos = TOPOINT3(body->GetTranslation()) * ni.bhkScaleFactor; - Point3 center = TOPOINT3(body->GetCenter()); - Quat rot = TOQUAT(body->GetRotation()); - float ang[] = { 0.0f, TORAD(-90.0f), TORAD(180.0f) }; - Quat q; EulerToQuat(ang, q); - rot *= q; - - PosRotScaleNode(n, pos, rot, ni.bhkScaleFactor, prsDefault); + // Need to reposition the Capsule so that caps are rotated correctly for pts given - n->SetPrimaryVisibility(FALSE); - n->SetSecondaryVisibility(FALSE); - n->BoneAsLine(TRUE); - n->SetRenderable(FALSE); - n->XRayMtl(TRUE); - - parent->AttachChild(n); - ok = true; + return n; } } - return ok; + return NULL; +} + +INode* CollisionImport::ImportConvexVertices(bhkRigidBodyRef body, bhkConvexVerticesShapeRef shape, INode *parent) +{ + return NULL; } \ No newline at end of file diff --git a/NifImport/ImportMeshAndSkin.cpp b/NifImport/ImportMeshAndSkin.cpp index 6ed67028aec1652d746fdcb800b47d9051915916..4cfdc3f3d44b7c48092a1a4ede2cab63b641f06b 100644 --- a/NifImport/ImportMeshAndSkin.cpp +++ b/NifImport/ImportMeshAndSkin.cpp @@ -12,58 +12,10 @@ HISTORY: **********************************************************************/ #include "stdafx.h" #include "MaxNifImport.h" +#include "istdplug.h" using namespace Niflib; -// Locate a TriObject in an Object if it exists -TriObject* GetTriObject(Object *o) -{ - if (o && o->CanConvertToType(triObjectClassID)) - return (TriObject *)o->ConvertToType(0, triObjectClassID); - while (o->SuperClassID() == GEN_DERIVOB_CLASS_ID && o) - { - IDerivedObject* dobj = (IDerivedObject *)(o); - o = dobj->GetObjRef(); - if (o && o->CanConvertToType(triObjectClassID)) - return (TriObject *)o->ConvertToType(0, triObjectClassID); - } - return NULL; -} - -// Get or Create the Skin Modifier -Modifier *GetSkin(INode *node) -{ - Object* pObj = node->GetObjectRef(); - if (!pObj) return NULL; - while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) - { - IDerivedObject* pDerObj = (IDerivedObject *)(pObj); - int Idx = 0; - while (Idx < pDerObj->NumModifiers()) - { - // Get the modifier. - Modifier* mod = pDerObj->GetModifier(Idx); - if (mod->ClassID() == SKIN_CLASSID) - { - // is this the correct Physique Modifier based on index? - return mod; - } - Idx++; - } - pObj = pDerObj->GetObjRef(); - } - - IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef()); - - //create a skin modifier and add it - Modifier *skinMod = (Modifier*) CreateInstance(OSM_CLASS_ID, SKIN_CLASSID); - dobj->SetAFlag(A_LOCK_TARGET); - dobj->AddModifier(skinMod); - dobj->ClearAFlag(A_LOCK_TARGET); - node->SetObjectRef(dobj); - return skinMod; -} - bool NifImporter::ImportTransform(ImpNode *node, NiAVObjectRef avObject) { node->SetTransform(0,TOMATRIX3(avObject->GetWorldTransform())); @@ -101,7 +53,7 @@ bool NifImporter::ImportMeshes(NiNodeRef node) return ok; } -bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triGeom, NiTriBasedGeomDataRef triGeomData, bool hasTexture) +bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triGeom, NiTriBasedGeomDataRef triGeomData, vector<Triangle>& tris) { Mesh& mesh = o->GetMesh(); @@ -148,36 +100,48 @@ bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triG mesh.setNormal(i, Point3(v.x, v.y, v.z)); } } - // vertex coloring - { - bool hasAlpha = false; - vector<Color4> cv = triGeomData->GetColors(); - mesh.setNumVertCol(cv.size()); - for (int i=0; i<cv.size(); i++){ - Color4& c = cv[i]; - mesh.vertCol[i].Set(c.r, c.g, c.b); - hasAlpha |= (c.a != 0.0); - } + + // Triangles and texture vertices + SetTrangles(mesh, tris); + + ImportVertexColor(node, o, triGeom, triGeomData, tris); + + ImportMaterialAndTextures(node, triGeom); + + if (enableSkinSupport) + ImportSkin(node, triGeom); + + i->AddNodeToScene(node); + + INode *inode = node->GetINode(); + inode->EvalWorldState(0); + + // attach child + if (INode *parent = GetNode(triGeom->GetParent())) + parent->AttachChild(inode, 1); + + inode->Hide(triGeom->GetHidden() ? TRUE : FALSE); + + if (enableAutoSmooth){ + mesh.AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE); } + return true; } -void NifImporter::SetTrangles(Mesh& mesh, vector<Triangle>& v, bool hasTexture) +void NifImporter::SetTrangles(Mesh& mesh, vector<Triangle>& v) { int n = v.size(); mesh.setNumFaces(n); - //if (hasTexture) - mesh.setNumTVFaces(n); + mesh.setNumTVFaces(n); for (int i=0; i<n; ++i) { Triangle& t = v[i]; Face& f = mesh.faces[i]; f.setVerts(t.v1, t.v2, t.v3); f.Show(); f.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS); - //if (hasTexture) { - TVFace& tf = mesh.tvFace[i]; - tf.setTVerts(t.v1, t.v2, t.v3); - //} + TVFace& tf = mesh.tvFace[i]; + tf.setTVerts(t.v1, t.v2, t.v3); } } @@ -195,37 +159,13 @@ bool NifImporter::ImportMesh(NiTriShapeRef triShape) INode *inode = node->GetINode(); // Texture - bool hasTexture = ImportMaterialAndTextures(node, triShape); Mesh& mesh = triObject->GetMesh(); NiTriShapeDataRef triShapeData = DynamicCast<NiTriShapeData>(triShape->GetData()); if (triShapeData == NULL) return false; - ok |= ImportMesh(node, triObject, triShape, triShapeData, hasTexture); - - // Triangles and texture vertices - if (ok) - { - vector<Triangle> v = triShapeData->GetTriangles(); - SetTrangles(mesh, v, hasTexture); - } - if (enableSkinSupport) - ImportSkin(node, triShape); - - i->AddNodeToScene(node); - - // attach child - if (INode *parent = GetNode(triShape->GetParent())) - parent->AttachChild(inode, 1); - - inode->Hide(triShape->GetHidden() ? TRUE : FALSE); - - if (enableAutoSmooth){ - if (TriObject *tri = GetTriObject(inode->GetObjectRef())){ - tri->GetMesh().AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE); - } - } - + vector<Triangle> tris = triShapeData->GetTriangles(); + ok |= ImportMesh(node, triObject, triShape, triShapeData, tris); return ok; } @@ -242,43 +182,164 @@ bool NifImporter::ImportMesh(NiTriStripsRef triStrips) node->SetName(name.c_str()); // Texture - bool hasTexture = ImportMaterialAndTextures(node, triStrips); - Mesh& mesh = triObject->GetMesh(); NiTriStripsDataRef triStripsData = DynamicCast<NiTriStripsData>(triStrips->GetData()); if (triStripsData == NULL) return false; - ok |= ImportMesh(node, triObject, triStrips, triStripsData, hasTexture); + vector<Triangle> tris = triStripsData->GetTriangles(); + ok |= ImportMesh(node, triObject, triStrips, triStripsData, tris); + return ok; +} - // Triangles and texture vertices - if (ok) +// vertex coloring +bool NifImporter::ImportVertexColor(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, vector<Triangle>& tris) +{ + bool hasAlpha = false; + bool hasColor = false; + Mesh& mesh = o->GetMesh(); + + if (vertexColorMode == 1) // Bake into mesh (no Modifier) { - vector<Triangle> v = triStripsData->GetTriangles(); - SetTrangles(mesh, v, hasTexture); - } - if (enableSkinSupport) - ImportSkin(node, triStrips); + vector<Color4> cv = triGeomData->GetColors(); + int n = cv.size(); + if (n > 0) + { + INode *tnode = node->GetINode(); + + vector<TVFace> vcFace; + int nt = tris.size(); + vcFace.resize(nt); + mesh.setNumVCFaces(nt); + for (int i=0; i<nt; ++i) { + Triangle& t = tris[i]; + TVFace& vcf = vcFace[i]; + vcf.setTVerts(t.v1, t.v2, t.v3); + mesh.vcFace[i].setTVerts(t.v1, t.v2, t.v3); + } - i->AddNodeToScene(node); + vector<VertColor> vertColors, vertAlpha; + vertColors.resize(n); + vertAlpha.resize(n); + mesh.setNumVertCol(cv.size()); + + for (int i=0; i<n; i++){ + Color4& c = cv[i]; + hasColor |= (c.r != 1.0f && c.g != 1.0f && c.b != 1.0f); + vertColors[i] = Color(c.r,c.g,c.b); + + hasAlpha |= (c.a != 1.0f); + vertAlpha[i] = Color(c.a,c.a,c.a); + } - // attach child - if (INode *parent = GetNode(triStrips->GetParent())) { - parent->AttachChild(inode, 0); + // Add the Vertex Paint Alpha modifier now + if (hasAlpha) + { + mesh.setMapSupport(MAP_ALPHA, TRUE); + mesh.setNumMapVerts(MAP_ALPHA, n, FALSE); + mesh.setNumMapFaces(MAP_ALPHA, nt, FALSE); + mesh.setVCDisplayData(MAP_ALPHA, 0, 0); + for (int i=0; i<nt; ++i) + mesh.vcFaceData[i] = vcFace[i]; + for (int i=0; i<n; ++i) + mesh.vertColArray[i] = vertAlpha[i]; + } + // Add the Vertex Paint Color modifier now + if (hasAlpha || hasColor) + { + mesh.setMapSupport(0, TRUE); + mesh.setNumMapVerts(0, n, TRUE); + mesh.setNumMapFaces(0, nt, FALSE); + mesh.setVCDisplayData(0, NULL, NULL); + for (int i=0; i<nt; ++i) + mesh.vcFaceData[i] = vcFace[i]; + for (int i=0; i<n; ++i) + mesh.vertColArray[i] = vertColors[i]; + } + } } + else if (vertexColorMode == 2) + { + vector<Color4> cv = triGeomData->GetColors(); + int n = cv.size(); + if (n > 0) + { - inode->Hide(triStrips->GetHidden() ? TRUE : FALSE); + INode *tnode = node->GetINode(); - // apply autosmooth after object creation for it to take hold - if (enableAutoSmooth){ - if (TriObject *tri = GetTriObject(inode->GetObjectRef())){ - tri->GetMesh().AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE); + vector<Color> colorMap, alphaMap; + IVertexPaint::VertColorTab vertColors, vertAlpha; + vertColors.SetCount(n, TRUE); + vertAlpha.SetCount(n, TRUE); + colorMap.resize(n); + alphaMap.resize(n); + mesh.setNumVertCol(cv.size()); + + for (int i=0; i<n; i++){ + Color4& c = cv[i]; + mesh.vertCol[i].Set(c.r, c.g, c.b); + + hasColor |= (c.r != 1.0f && c.g != 1.0f && c.b != 1.0f); + colorMap[i] = Color(c.r,c.g,c.b); + vertColors[i] = &colorMap[i]; + + hasAlpha |= (c.a != 1.0f); + alphaMap[i] = Color(c.a,c.a,c.a); + vertAlpha[i] = &alphaMap[i]; + } + // Civ4 assumes that vcFace is filled in even if only alpha is given via color modifier + if (hasColor || hasAlpha) + { + int n = tris.size(); + mesh.setNumVCFaces(n); + for (int i=0; i<n; ++i) { + Triangle& t = tris[i]; + TVFace& vcf = mesh.vcFace[i]; + vcf.setTVerts(t.v1, t.v2, t.v3); + } + } + // Add the Vertex Paint Color modifier now + if (hasColor) + { + IDerivedObject *dobj = CreateDerivedObject(tnode->GetObjectRef()); + Modifier * mod = (Modifier*)CreateInstance(OSM_CLASS_ID, PAINTLAYERMOD_CLASS_ID); + dobj->AddModifier(mod); + tnode->SetObjectRef(dobj); + IVertexPaint* ivertexPaint = (IVertexPaint*)mod->GetInterface(IVERTEXPAINT_INTERFACE_ID); + ObjectState os = tnode->EvalWorldState(0); + IAssignVertexColors::Options o; + ivertexPaint->GetOptions(o); + o.mapChannel = 0; + o.mixVertColors = true; + ivertexPaint->SetOptions(o); + ivertexPaint->SetColors(tnode, vertColors); + //mod->DisableModInViews(); + //mod->EnableModInViews(); + } + // Add the Vertex Paint Alpha modifier now + if (hasAlpha) + { + IDerivedObject *dobj = CreateDerivedObject(tnode->GetObjectRef()); + Modifier * mod = (Modifier*)CreateInstance(OSM_CLASS_ID, PAINTLAYERMOD_CLASS_ID); + dobj->AddModifier(mod); + tnode->SetObjectRef(dobj); + IVertexPaint* ivertexPaint = (IVertexPaint*)mod->GetInterface(IVERTEXPAINT_INTERFACE_ID); + ObjectState os = tnode->EvalWorldState(0); + IAssignVertexColors::Options o; + ivertexPaint->GetOptions(o); + o.mapChannel = -2; + o.mixVertColors = true; + ivertexPaint->SetOptions(o); + ivertexPaint->SetColors(tnode, vertAlpha); + //mod->DisableModInViews(); + //mod->EnableModInViews(); + } } } - - return ok; + return (hasAlpha || hasColor); } + struct VertexHolder { VertexHolder() : vertIndex(0), count(0) {} diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index 69038d7c47da7c42e814c2cc48e744d0a53afa9a..885d9307f21f757fe5c7491ac6dfe76bc6b1a99a 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -12,7 +12,9 @@ HISTORY: **********************************************************************/ #include "stdafx.h" #include "MaxNifImport.h" +#ifdef USE_BIPED #include <cs/BipedApi.h> +#endif #include <obj/NiTriBasedGeom.h> #include <obj/NiTriBasedGeomData.h> #include <obj/NiTimeController.h> @@ -486,6 +488,7 @@ INode *NifImporter::CreateBone(const string& name, Point3 startPos, Point3 endPo setMAXScriptValue(o->GetReference(0), "width", 0, width); setMAXScriptValue(o->GetReference(0), "height", 0, width); } + n->BoneAsLine(1); n->ShowBone(2); } return result.n; diff --git a/NifImport/MaxNifImport_VC80.vcproj b/NifImport/MaxNifImport_VC80.vcproj index 204c390433eda2e6a4621b0f44e44eefe845fa1b..d05d46e9cfaefeadbf4298674f94c3230d2a2f02 100644 --- a/NifImport/MaxNifImport_VC80.vcproj +++ b/NifImport/MaxNifImport_VC80.vcproj @@ -797,10 +797,6 @@ > </File> </Filter> - <File - RelativePath="..\MaxNifPlugins_Readme.txt" - > - </File> </Files> <Globals> </Globals> diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index f02484a96bd5e64b62047ea0c1425b273f52d7fa..b8f9dc9f34800d879348115b1076b5c9f19c17b2 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -116,40 +116,41 @@ void NifImporter::LoadIniSettings() } // General System level - useBiped = GetIniValue<bool>(NifImportSection, "UseBiped", false); + useBiped = GetIniValue(NifImportSection, "UseBiped", false); skeletonCheck = GetIniValue<string>(NifImportSection, "SkeletonCheck", "Bip*"); - showTextures = GetIniValue<bool>(NifImportSection, "ShowTextures", true); - removeIllegalFaces = GetIniValue<bool>(NifImportSection, "RemoveIllegalFaces", true); - removeDegenerateFaces = GetIniValue<bool>(NifImportSection, "RemoveDegenerateFaces", true); - enableAutoSmooth = GetIniValue<bool>(NifImportSection, "EnableAutoSmooth", true); - autoSmoothAngle = GetIniValue<float>(NifImportSection, "AutoSmoothAngle", 30.0f); - flipUVTextures = GetIniValue<bool>(NifImportSection, "FlipUVTextures", true); - enableSkinSupport = GetIniValue<bool>(NifImportSection, "EnableSkinSupport", true); - enableCollision = GetIniValue<bool>(NifImportSection, "EnableCollision", true); + showTextures = GetIniValue(NifImportSection, "ShowTextures", true); + removeIllegalFaces = GetIniValue(NifImportSection, "RemoveIllegalFaces", true); + removeDegenerateFaces = GetIniValue(NifImportSection, "RemoveDegenerateFaces", true); + enableAutoSmooth = GetIniValue(NifImportSection, "EnableAutoSmooth", true); + autoSmoothAngle = GetIniValue(NifImportSection, "AutoSmoothAngle", 30.0f); + flipUVTextures = GetIniValue(NifImportSection, "FlipUVTextures", true); + enableSkinSupport = GetIniValue(NifImportSection, "EnableSkinSupport", true); + enableCollision = GetIniValue(NifImportSection, "EnableCollision", true); + vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1); // Biped - importBones = GetIniValue<bool>(BipedImportSection, "ImportBones", true); - bipedHeight = GetIniValue<float>(BipedImportSection, "BipedHeight", 131.90f); - bipedAngle = GetIniValue<float>(BipedImportSection, "BipedAngle", 90.0f); - bipedAnkleAttach = GetIniValue<float>(BipedImportSection, "BipedAnkleAttach", 0.2f); - bipedTrianglePelvis = GetIniValue<bool>(BipedImportSection, "BipedTrianglePelvis", false); - removeUnusedImportedBones = GetIniValue<bool>(BipedImportSection, "RemoveUnusedImportedBones", false); - forceRotation = GetIniValue<bool>(BipedImportSection, "ForceRotation", true); - browseForSkeleton = GetIniValue<bool>(BipedImportSection, "BrowseForSkeleton", true); + importBones = GetIniValue(BipedImportSection, "ImportBones", true); + bipedHeight = GetIniValue(BipedImportSection, "BipedHeight", 131.90f); + bipedAngle = GetIniValue(BipedImportSection, "BipedAngle", 90.0f); + bipedAnkleAttach = GetIniValue(BipedImportSection, "BipedAnkleAttach", 0.2f); + bipedTrianglePelvis = GetIniValue(BipedImportSection, "BipedTrianglePelvis", false); + removeUnusedImportedBones = GetIniValue(BipedImportSection, "RemoveUnusedImportedBones", false); + forceRotation = GetIniValue(BipedImportSection, "ForceRotation", true); + browseForSkeleton = GetIniValue(BipedImportSection, "BrowseForSkeleton", true); defaultSkeletonName = GetIniValue<string>(BipedImportSection, "DefaultSkeletonName", "Skeleton.Nif"); - minBoneWidth = GetIniValue<float>(BipedImportSection, "MinBoneWidth", 0.5f); - maxBoneWidth = GetIniValue<float>(BipedImportSection, "MaxBoneWidth", 3.0f); - boneWidthToLengthRatio = GetIniValue<float>(BipedImportSection, "BoneWidthToLengthRatio", 0.25f); - createNubsForBones = GetIniValue<bool>(BipedImportSection, "CreateNubsForBones", true); + minBoneWidth = GetIniValue(BipedImportSection, "MinBoneWidth", 0.5f); + maxBoneWidth = GetIniValue(BipedImportSection, "MaxBoneWidth", 3.0f); + boneWidthToLengthRatio = GetIniValue(BipedImportSection, "BoneWidthToLengthRatio", 0.25f); + createNubsForBones = GetIniValue(BipedImportSection, "CreateNubsForBones", true); dummyNodeMatches = TokenizeString(GetIniValue<string>(BipedImportSection, "DummyNodeMatches", "").c_str(), ";"); - convertBillboardsToDummyNodes = GetIniValue<bool>(BipedImportSection, "ConvertBillboardsToDummyNodes", true); - uncontrolledDummies = GetIniValue<bool>(BipedImportSection, "UncontrolledDummies", true); + convertBillboardsToDummyNodes = GetIniValue(BipedImportSection, "ConvertBillboardsToDummyNodes", true); + uncontrolledDummies = GetIniValue(BipedImportSection, "UncontrolledDummies", true); // Animation - replaceTCBRotationWithBezier = GetIniValue<bool>(AnimImportSection, "ReplaceTCBRotationWithBezier", true); - enableAnimations = GetIniValue<bool>(AnimImportSection, "EnableAnimations", true); - requireMultipleKeys = GetIniValue<bool>(AnimImportSection, "RequireMultipleKeys", true); - applyOverallTransformToSkinAndBones = GetIniValue<bool>(AnimImportSection, "ApplyOverallTransformToSkinAndBones", true); + replaceTCBRotationWithBezier = GetIniValue(AnimImportSection, "ReplaceTCBRotationWithBezier", true); + enableAnimations = GetIniValue(AnimImportSection, "EnableAnimations", true); + requireMultipleKeys = GetIniValue(AnimImportSection, "RequireMultipleKeys", true); + applyOverallTransformToSkinAndBones = GetIniValue(AnimImportSection, "ApplyOverallTransformToSkinAndBones", true); // Collision bhkScaleFactor = GetIniValue<float>(CollisionSection, "bhkScaleFactor", 7.0f); @@ -169,14 +170,14 @@ void NifImporter::LoadIniSettings() void NifImporter::SaveIniSettings() { - SetIniValue<bool>(NifImportSection, "UseBiped", useBiped); - SetIniValue<string>(NifImportSection, "Skeleton", skeleton); - SetIniValue<string>(NifImportSection, "SkeletonCheck", skeletonCheck); - - SetIniValue<float>(BipedImportSection, "BipedHeight", bipedHeight); - SetIniValue<float>(BipedImportSection, "BipedAngle", bipedAngle); - SetIniValue<float>(BipedImportSection, "BipedAnkleAttach", bipedAnkleAttach); - SetIniValue<bool>(BipedImportSection, "BipedTrianglePelvis", bipedTrianglePelvis); + //SetIniValue(NifImportSection, "UseBiped", useBiped); + //SetIniValue<string>(NifImportSection, "Skeleton", skeleton); + //SetIniValue<string>(NifImportSection, "SkeletonCheck", skeletonCheck); + + //SetIniValue<float>(BipedImportSection, "BipedHeight", bipedHeight); + //SetIniValue<float>(BipedImportSection, "BipedAngle", bipedAngle); + //SetIniValue<float>(BipedImportSection, "BipedAnkleAttach", bipedAnkleAttach); + //SetIniValue(BipedImportSection, "BipedTrianglePelvis", bipedTrianglePelvis); } INode *NifImporter::GetNode(Niflib::NiNodeRef node) diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index 4f543ed198395d5597f17b50f420bc5f95e93293..c15cbf1d72103962de741a3174e6e1ba589f41d5 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -29,6 +29,7 @@ public: bool enableSkinSupport; bool goToSkeletonBindPosition; bool enableCollision; + int vertexColorMode; // Biped/Bones related settings bool importBones; @@ -87,12 +88,13 @@ public: bool ImportUPB(INode *node, Niflib::NiNodeRef block); - void SetTrangles(Mesh& mesh, vector<Niflib::Triangle>& v, bool hasTexture); + void SetTrangles(Mesh& mesh, vector<Niflib::Triangle>& v); bool ImportMesh(Niflib::NiTriShapeRef triShape); bool ImportMesh(Niflib::NiTriStripsRef triStrips); bool ImportMaterialAndTextures(ImpNode *node, Niflib::NiAVObjectRef avObject); bool ImportTransform(ImpNode *node, Niflib::NiAVObjectRef avObject); - bool ImportMesh(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, bool hasTexture); + bool ImportMesh(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, vector<Niflib::Triangle>& tris); + bool ImportVertexColor(ImpNode *node, TriObject *o, Niflib::NiTriBasedGeomRef triGeom, Niflib::NiTriBasedGeomDataRef triGeomData, vector<Niflib::Triangle>& tris); bool ImportSkin(ImpNode *node, Niflib::NiTriBasedGeomRef triGeom); Texmap* CreateTexture(Niflib::TexDesc& desc);