From d619dd60576a9300f1986c156dd98dad1b4c0c93 Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 20 Aug 2006 00:34:05 +0000 Subject: [PATCH] 1. Fix issue with exporting with user version specified. Oblivion CS will crash if not set correctly. 2. Fix issues with nif export in general around bhk ordering (ported over from gundalfs changes) 3. Civ4 Shader support for max 4. Numerous bug fixes to max. --- MaxNifPlugins_Readme.txt | 10 +- MaxNifTools.ini | 44 ++-- NifCommon/AppSettings.cpp | 18 ++ NifCommon/AppSettings.h | 3 + NifCommon/IniSection.h | 124 +++++++++++ NifCommon/NifCommon_VC80.vcproj | 8 + NifCommon/niutils.cpp | 89 +++++++- NifCommon/niutils.h | 10 +- NifCommon/objectParams.h | 5 +- NifExport/Coll.cpp | 29 +-- NifExport/Config.cpp | 7 + NifExport/Exporter.cpp | 15 +- NifExport/Exporter.h | 9 +- NifExport/Mesh.cpp | 7 +- NifExport/MtlTex.cpp | 334 ++++++++++++++++++++++++++-- NifExport/NifExport.cpp | 105 ++++++++- NifExport/NifExport.rc | 122 +++++++---- NifExport/NifExport_VC80.vcproj | 12 +- NifExport/Util.cpp | 10 +- NifExport/pch.h | 3 +- NifExport/resource.h | 10 +- NifImport/ImportMeshAndSkin.cpp | 2 +- NifImport/ImportMtlAndTex.cpp | 213 +++++++++++++++++- NifImport/ImportSkeleton.cpp | 5 +- NifImport/MaxNifImport.cpp | 38 ---- NifImport/MaxNifImport.rc | 40 +++- NifImport/MaxNifImport_VC80.vcproj | 8 +- NifImport/NIFImport.cpp | 119 ++++++---- NifImport/NIFImporter.h | 10 +- NifImport/NifDialog.cpp | 187 ++++++++++++++++ NifImport/objectParams.h | 339 ----------------------------- NifImport/resource.h | 22 +- NifPlugins_VC80.sln | 1 + 33 files changed, 1380 insertions(+), 578 deletions(-) create mode 100644 NifCommon/IniSection.h create mode 100644 NifImport/NifDialog.cpp delete mode 100644 NifImport/objectParams.h diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 902dc78..971f29c 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -34,11 +34,15 @@ - Added Vertex Color modifier support - Fixed issue with static animation import - Fixed issue with skin vertex weight count import + - Added support for more material/texture properties + - Added support for Civilization IV Shader, if installed + o holds much of the material data in nif compatible form 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). + - Dropped Official Max6 support because I do not have Max 6 to compile it + o Try editing the MaxNifTools.ini and setting the MaxSDKVersion to 0x17700d00 - 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. @@ -46,6 +50,10 @@ - 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 + - Added support for more material/texture properties + - Added support for Civilization IV Shader, if installed + o holds much of the material data in nif compatible form + - Fixed issue with UV map needing to be flipped o NifProps Utility - Mass, Restitution(Ellasticity), and Friction now share values with Reactor(Havok) diff --git a/MaxNifTools.ini b/MaxNifTools.ini index c7b2529..74969fd 100644 --- a/MaxNifTools.ini +++ b/MaxNifTools.ini @@ -6,7 +6,7 @@ ShortDescription=Netimmerse/Gamebryo ; KnownApplications - Used to indicate which sections in the ini file point ; to "Applications" which have their own settings in a section below. -KnownApplications=Oblivion;Morrowind;Civ4;DAoC +KnownApplications=Oblivion;Morrowind;Civilization 4;Dark Age of Camelot;User ; Reparse the Applications (and therefore Texture directory cache) on every import/export Reparse=0 @@ -24,14 +24,14 @@ GenerateStrips=1 FurnatureMarkers=1 ; Use Lights if present. Default:0 Lights=0 -; Include Hidden Nodes if present. Default:0 -IncludeHidden=0 +; Include Hidden Nodes if present. Default:1 +IncludeHidden=1 ; Export Collision meshes if present. Default:1 ExportCollision=1 ; Export Vertext Colors. Default:1 VertexColors=1 -; Remap Indices. Default:1 -RemapIndices=1 +; Remap Indices. Default:0 +RemapIndices=0 ; Texture Prefix if texture not found in AppSettings directory. Default:textures TexturePrefix=textures ; Add Export additional NiNodes for Meshes. Default: 0 @@ -40,14 +40,14 @@ ExportExtraNodes=0 ExportSkin=1 ; Export UserPropBuffer. Default: 0 UserPropBuffer=0 -; Flatten Node Hierarchy. Default: 0 -FlattenHierarchy=0 -; Remove Unreferenced Bones. Default: 0 -RemoveUnreferencedBones=0 +; Flatten Node Hierarchy. Default: 1 +FlattenHierarchy=1 +; Remove Unreferenced Bones. Default: 1 +RemoveUnreferencedBones=1 [MaxNifImport] ; Max SDK Plugin Version (0 - AutoSelect; 0x17700d00 - Max6, 0x1f401100 - Max8) Default: 0 -MaxSDKVersion=0x17700d00 +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 @@ -64,7 +64,7 @@ EnableAutoSmooth=1 ; AutoSmooth angle. Default: 30 AutoSmoothAngle=30.0 ; Remove Double/Illegal faces on meshes on import. Default:1 -RemoveDoubleFaces=1 +RemoveDegenerateFaces=1 RemoveIllegalFaces=1 ; EnableSkinSupport attempt to skin the mesh if bones are available. Default:1 EnableSkinSupport=1 @@ -92,8 +92,6 @@ MaxBoneWidth=0.1 BoneWidthToLengthRatio=0.01 ; Force nub to point back to parent at expense of loss of rotation data. Default: 1 ForceRotation=0 -; Browse for skeleton on import. Default: 1 -BrowseForSkeleton=1 ; DefaultName for Skeletons (use if in same directory as imported nif) DefaultSkeletonName=skeleton.nif @@ -121,6 +119,8 @@ ApplyOverallTransformToSkinAndBones=1 bhkScaleFactor=7.0 ; [Applications] +; NiVersion - Version of Nif use by game +; NiUserVersion - User Version of Nif used by game ; RootPaths - Semicolon separated list of base directories to use when determining which app the imported file is from ; ; TextureRootPaths - Semicolon separated list of base directories to look for texturefiles @@ -132,6 +132,8 @@ bhkScaleFactor=7.0 ; GoToSkeletonBindPosition - Morrowind trishape data is not in the correct bind position for import. Default: 1 [Oblivion] +NiVersion=20.0.0.5 +NiUserVersion=11 ; Installation Folder InstallPath=[HKLM\SOFTWARE\Bethesda Softworks\Oblivion]=@"Installed Path" ExtractFolder=E:\Nifs\Oblivion @@ -148,6 +150,8 @@ TextureSearchPaths=${RootPath}\Textures;${TextureRootPath}\Textures\Characters;$ GoToSkeletonBindPosition=1 [Morrowind] +NiVersion=4.0.0.2 +NiUserVersion=0 InstallPath=[HKLM\SOFTWARE\Bethesda Softworks\Morrowind]=@"Installed Path" RootPath=${InstallPath}\Data Files ExtractFolder=E:\Nifs\Morrowind\Data Files @@ -157,7 +161,9 @@ TextureExtensions=.tga; TextureSearchPaths=${RootPath}\Textures GoToSkeletonBindPosition=1 -[Civ4] +[Civilization 4] +NiVersion=20.0.0.4 +NiUserVersion=0 InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Firaxis Games\Sid Meier's Civilization 4]=@"INSTALLDIR" RootPath= ExtractFolder=C:\Projects\Main\Civilization4\assets @@ -168,7 +174,9 @@ TextureSearchPaths= GoToSkeletonBindPosition=1 DummyNodeMatches=MD;Bip;Bip??;* NonAccum;Effect*;Sound*;Dummy* -[DAoC] +[Dark Age of Camelot] +NiVersion=10.1.0.0 +NiUserVersion=0 Isles_InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Dark Age of Camelot - Shrouded Isles_is1]=@"InstallLocation" RootPath= ExtractFolder= @@ -177,4 +185,8 @@ TextureRootPaths=$(ExtractFolder) TextureExtensions=.dds;.bmp;.tga TextureSearchPaths= GoToSkeletonBindPosition=1 -ApplyOverallTransformToSkinAndBones=0 \ No newline at end of file +ApplyOverallTransformToSkinAndBones=0 + +[User] +NiVersion=20.0.0.5 +NiUserVersion=0 diff --git a/NifCommon/AppSettings.cpp b/NifCommon/AppSettings.cpp index 59cbb30..efb8b9c 100644 --- a/NifCommon/AppSettings.cpp +++ b/NifCommon/AppSettings.cpp @@ -2,6 +2,7 @@ #include <string.h> #include <tchar.h> #include "AppSettings.h" +#include "IniSection.h" AppSettingsMap TheAppSettings; @@ -18,6 +19,7 @@ void AppSettings::Initialize(Interface *gi) string Applications = GetIniValue<string>("System", "KnownApplications", "", iniName); stringlist apps = TokenizeString(Applications.c_str(), ";"); + apps.push_back(string("User")); // always ensure that user is present for (stringlist::iterator appstr=apps.begin(); appstr != apps.end(); ++appstr){ AppSettings* setting = FindAppSetting(*appstr); if (NULL == setting){ @@ -46,6 +48,9 @@ void AppSettings::ReadSettings(string iniFile) std::swap(Environment, settings); + NiVersion = GetSetting<string>("NiVersion", "20.0.0.5"); + NiUserVersion = GetSetting<int>("NiUserVersion", 0); + rootPath = GetSetting<string>("RootPath"); rootPaths = TokenizeString(GetSetting<string>("RootPaths").c_str(), ";"); searchPaths = TokenizeString(GetSetting<string>("TextureSearchPaths").c_str(), ";"); @@ -61,6 +66,19 @@ void AppSettings::ReadSettings(string iniFile) dummyNodeMatches = TokenizeString(GetSetting<string>("DummyNodeMatches").c_str(), ";"); } +void AppSettings::WriteSettings(Interface *gi) +{ + TCHAR iniName[MAX_PATH]; + LPCTSTR pluginDir = gi->GetDir(APP_PLUGCFG_DIR); + PathCombine(iniName, pluginDir, "MaxNifTools.ini"); + if (-1 != _taccess(iniName, 0)) + { + SetIniValue(Name.c_str(), "NiVersion", NiVersion.c_str(), iniName); + SetIniValue(Name.c_str(), "NiUserVersion", FormatString("%d", NiUserVersion).c_str(), iniName); + } +} + + string AppSettings::FindImage(const string& fname){ TCHAR buffer[MAX_PATH]; diff --git a/NifCommon/AppSettings.h b/NifCommon/AppSettings.h index 0d7cfec..3e009ee 100644 --- a/NifCommon/AppSettings.h +++ b/NifCommon/AppSettings.h @@ -42,9 +42,12 @@ public: NameValueCollection imgTable; stringlist dummyNodeMatches; int applyOverallTransformToSkinAndBones; + std::string NiVersion; + int NiUserVersion; static void Initialize(Interface *gi); void ReadSettings(std::string iniFile); + void WriteSettings(Interface *gi); std::string FindImage(const std::string& fname); // Check whether the given file is a child of the root paths diff --git a/NifCommon/IniSection.h b/NifCommon/IniSection.h new file mode 100644 index 0000000..e42f6a8 --- /dev/null +++ b/NifCommon/IniSection.h @@ -0,0 +1,124 @@ +#pragma once + +#include <string> +#include <list> +enum INIDEFTYPE +{ + IDT_STRING, + IDT_INT, + IDT_FLOAT, + IDT_BOOL, + IDT_FILENAME, + IDT_UNKNOWN, +}; + +struct INIDEF +{ + INIDEF() : ShortName(NULL), IniName(NULL), MemberAddr(0), Description(NULL), DefaultValue(NULL), ValueSize(0) { + } + + ~INIDEF() { + if (ValueSize && DefaultValue) { + delete DefaultValue; + DefaultValue = NULL; + ValueSize = 0; + } + } + + template<typename U> + INIDEF(LPCTSTR sName, LPCTSTR iName, const U& member, U default, LPCTSTR desc, INIDEFTYPE type) + : ShortName(sName), IniName(iName), MemberAddr(NULL), Description(NULL), MemberType(type) { + SetDefault(default); + } + + template<> + INIDEF(LPCTSTR sName, LPCTSTR iName, const std::string& member, std::string default, LPCTSTR desc, INIDEFTYPE type) + : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { + MemberType = type==IDT_UNKNOWN?IDT_STRING:type; + SetDefault(default); + } + + template<> + INIDEF(LPCTSTR sName, LPCTSTR iName, const int& member, int default, LPCTSTR desc, INIDEFTYPE type) + : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { + MemberType = type==IDT_UNKNOWN?IDT_INT:type; + SetDefault(default); + } + + template<> + INIDEF(LPCTSTR sName, LPCTSTR iName, const float& member, float default, LPCTSTR desc, INIDEFTYPE type) + : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { + MemberType = type==IDT_UNKNOWN?IDT_FLOAT:type; + SetDefault(default); + } + + template<> + INIDEF(LPCTSTR sName, LPCTSTR iName, const bool& member, bool default, LPCTSTR desc, INIDEFTYPE type) + : ShortName(sName), IniName(iName), MemberAddr((DWORD)&member), Description(NULL) { + MemberType = type==IDT_UNKNOWN?IDT_BOOL:type; + SetDefault(default); + } + + template<typename U> + void SetDefault(U default) { + ValueSize = sizeof(U); + DefaultValue = new U(default); + } + + template <typename U> + const U& GetDefault() const { + return *(U*)DefaultValue; + } + + LPCTSTR ShortName; + LPCTSTR IniName; + DWORD MemberAddr; + INIDEFTYPE MemberType; + LPCTSTR Description; + LPVOID DefaultValue; + DWORD ValueSize; +}; + +#define BEGIN_INI_MAP(name) \ + virtual void *GetMember(const INIDEF* memptr) const { return (void*)(((char*)this) + memptr->MemberAddr); } \ + virtual const INIDEF* GetInfDefmap() const { return InternalGetInfDefmap(); } \ + static INIDEF* InternalGetInfDefmap() { \ + const name* pThis = 0; \ + static INIDEF map[] = { \ + +#define BEGIN_INI_MAP_WITH_BASE(name, base) \ + virtual void *GetMember(const INIDEF* memptr) const { return (void*)(((char*)this) + memptr->MemberAddr); } \ + virtual const INIDEF* GetInfDefmap() const { return InternalGetInfDefmap(); } \ + static INIDEF* InternalGetInfDefmap() { \ + const name* pThis = 0; \ + static INIDEF map[] = { \ + +#define END_INI_MAP() \ + INIDEF() };\ + return map;\ +} + +#define ADDITEM(sName, iName, member, desc) \ + INIDEF(sName, iName, pThis->member, desc, IDT_UNKNOWN), \ + +#define ADDITEMEX(sName, iName, member, type, desc) \ + INIDEF(sName, iName, pThis->member, desc, type), \ + +struct IniFileSection +{ + virtual LPCTSTR GetName() const = 0; + virtual const INIDEF* GetInfDefmap() const = 0; + virtual void *GetMember(const INIDEF* memptr) const = 0; +}; + +typedef std::list<IniFileSection*> IniFileSectionList; + +inline int GetIniDefSectionSize(IniFileSection *section) { + int len = 0; + + for (const INIDEF *inidef = section->GetInfDefmap() + ; inidef != NULL && inidef->ShortName + ; ++inidef) + ++len; + return len; +} \ No newline at end of file diff --git a/NifCommon/NifCommon_VC80.vcproj b/NifCommon/NifCommon_VC80.vcproj index 0f75d8f..d8d7fc7 100644 --- a/NifCommon/NifCommon_VC80.vcproj +++ b/NifCommon/NifCommon_VC80.vcproj @@ -504,6 +504,10 @@ RelativePath=".\AppSettings.h" > </File> + <File + RelativePath=".\IniSection.h" + > + </File> <File RelativePath=".\NifGui.h" > @@ -516,6 +520,10 @@ RelativePath=".\niutils.h" > </File> + <File + RelativePath=".\objectParams.h" + > + </File> <File RelativePath=".\pch.h" > diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp index 3f2190a..f6e0b75 100644 --- a/NifCommon/niutils.cpp +++ b/NifCommon/niutils.cpp @@ -70,12 +70,12 @@ std::string FormatString(const TCHAR* format,...) } // Tokenize a string using strtok and return it as a stringlist -stringlist TokenizeString(LPCTSTR str, LPCTSTR delims) +stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim) { stringlist values; LPTSTR buf = STRDUPA(str); for (LPTSTR p = _tcstok(buf, delims); p && *p; p = _tcstok(NULL, delims)){ - values.push_back(string(p)); + values.push_back(string((trim) ? Trim(p) : p)); } return values; } @@ -583,6 +583,22 @@ TriObject* GetTriObject(Object *o) } // Get or Create the Skin Modifier +Modifier *GetOrCreateSkin(INode *node) +{ + Modifier *skinMod = GetSkin(node); + if (skinMod) + return skinMod; + + IDerivedObject *dobj = CreateDerivedObject(node->GetObjectRef()); + //create a skin modifier and add it + 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; +} + Modifier *GetSkin(INode *node) { Object* pObj = node->GetObjectRef(); @@ -604,14 +620,65 @@ Modifier *GetSkin(INode *node) } pObj = pDerObj->GetObjRef(); } + return NULL; +} - 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; -} +TSTR GetFileVersion(const char *fileName) +{ + TSTR retval; + char fileVersion[MAX_PATH]; + if (fileName == NULL) + { + GetModuleFileName(hInstance, fileVersion, MAX_PATH); + fileName = fileVersion; + } + HMODULE ver = GetModuleHandle("version.dll"); + if (!ver) ver = LoadLibrary("version.dll"); + if (ver != NULL) + { + DWORD (APIENTRY *GetFileVersionInfoSize)(LPCTSTR, LPDWORD) = NULL; + BOOL (APIENTRY *GetFileVersionInfo)(LPCTSTR, DWORD, DWORD, LPVOID) = NULL; + BOOL (APIENTRY *VerQueryValue)(const LPVOID, LPTSTR, LPVOID *, PUINT) = NULL; + *(FARPROC*)&GetFileVersionInfoSize = GetProcAddress(ver, "GetFileVersionInfoSizeA"); + *(FARPROC*)&GetFileVersionInfo = GetProcAddress(ver, "GetFileVersionInfoA"); + *(FARPROC*)&VerQueryValue = GetProcAddress(ver, "VerQueryValueA"); + if (GetFileVersionInfoSize && GetFileVersionInfo && VerQueryValue) + { + DWORD vLen = 0; + DWORD vSize = GetFileVersionInfoSize(fileName,&vLen); + if (vSize) + { + LPVOID versionInfo = malloc(vSize+1); + if (GetFileVersionInfo(fileName,vLen,vSize,versionInfo)) + { + LPVOID version=NULL; + if (VerQueryValue(versionInfo,"\\VarFileInfo\\Translation",&version,(UINT *)&vLen) && vLen==4) + { + DWORD langD = *(DWORD*)version; + sprintf(fileVersion, "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion", + (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24, (langD & 0xff0000)>>16); + } + else + { + sprintf(fileVersion, "\\StringFileInfo\\%04X04B0\\ProductVersion", GetUserDefaultLangID()); + } + LPCTSTR value = NULL; + if (VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen)) + value = LPCTSTR(version); + else if (VerQueryValue(versionInfo,"\\StringFileInfo\\040904B0\\ProductVersion",&version,(UINT *)&vLen)) + value = LPCTSTR(version); + if (value != NULL) + { + stringlist val = TokenizeString(value, ",", true); + if (val.size() >= 4){ + retval = FormatText("%s.%s.%s.%s", val[0].c_str(), val[1].c_str(), val[2].c_str(), val[3].c_str()); + } + } + free(versionInfo); + } + } + } + } + return retval; +} \ No newline at end of file diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index 1a8cf8f..11aaec2 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -121,7 +121,7 @@ struct NumericStringEquivalence // Common collections that I use typedef std::map<std::string, std::string, ltstr> NameValueCollection; typedef std::pair<std::string, std::string> KeyValuePair; -typedef std::list<std::string> stringlist; +typedef std::vector<std::string> stringlist; extern int wildcmp(const TCHAR *wild, const TCHAR *string); extern int wildcmpi(const TCHAR *wild, const TCHAR *string); @@ -209,7 +209,7 @@ inline void SetIniValue<TSTR>(LPCTSTR Section, LPCTSTR Setting, TSTR value, LPCT extern TSTR FormatText(const TCHAR* format,...); extern std::string FormatString(const TCHAR* format,...); -extern stringlist TokenizeString(LPCTSTR str, LPCTSTR delims); +extern stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim=false); extern string GetIndirectValue(LPCSTR path); extern NameValueCollection ReadIniSection(LPCTSTR Section, LPCTSTR iniFileName ); extern string ExpandQualifiers(const string& src, const NameValueCollection& map); @@ -271,6 +271,9 @@ static inline Color TOCOLOR(const Niflib::Color3& c3) { return Color(c3.r, c3.g, c3.b); } +static inline Niflib::Color3 TOCOLOR3(const Color& c3) { + return Niflib::Color3(c3.r, c3.g, c3.b); +} static inline Point3 TOPOINT3(const Niflib::Vector3& v){ return Point3(v.x, v.y, v.z); @@ -334,7 +337,10 @@ inline Niflib::Ref<U> SelectFirstObjectOfType( list<Niflib::Ref<T> > const & obj TSTR PrintMatrix3(Matrix3& m); TSTR PrintMatrix44(Niflib::Matrix44& m); +extern Modifier *GetOrCreateSkin(INode *node); extern Modifier *GetSkin(INode *node); extern TriObject* GetTriObject(Object *o); +extern TSTR GetFileVersion(const char *fileName); + #endif // _NIUTILS_H_ \ No newline at end of file diff --git a/NifCommon/objectParams.h b/NifCommon/objectParams.h index 23a45f4..9773e3e 100644 --- a/NifCommon/objectParams.h +++ b/NifCommon/objectParams.h @@ -32,7 +32,7 @@ inline Value* make_maxscript_value(const Color& rgb); inline Value* make_maxscript_value(LPCTSTR str); inline Value* make_maxscript_value(ReferenceTarget* rtarg); -#if VERSION_3DSMAX <= ((MAX_RELEASE_R7<<16)+(15<<8)+0) +#if VERSION_3DSMAX <= ((7000<<16)+(15<<8)+0) // Version 7 inline void clear_error_source_data() {} #endif @@ -317,7 +317,8 @@ inline float ConvertMAXScriptToC<float>::cvt(Value* val) inline Color ConvertMAXScriptToC<Color>::cvt(Value* val) { - return val->to_point3(); + Point3 pt3 = val->to_point3(); + return Color(pt3.x/255.0f, pt3.y/255.0f, pt3.z/255.0f); } inline LPTSTR ConvertMAXScriptToC<LPTSTR>::cvt(Value* val) diff --git a/NifExport/Coll.cpp b/NifExport/Coll.cpp index 20a7ab6..5c8f30f 100755 --- a/NifExport/Coll.cpp +++ b/NifExport/Coll.cpp @@ -252,6 +252,9 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node) // marked as collision? bool coll = npIsCollision(node); + bool local = !mFlattenHierarchy; + NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent; + NiNodeRef newParent; if (coll) { @@ -275,7 +278,7 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node) body->SetRotation(q); body->SetTranslation(Vector3(trans.x/7, trans.y/7, trans.z/7)); */ - newParent = makeNode(parent, node); + newParent = nodeParent; // always have collision one level up? bhkSphereRepShapeRef shape = makeCollisionShape(node); bhkRigidBodyRef body = makeCollisionBody(node); @@ -283,18 +286,17 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node) bhkCollisionObjectRef co = DynamicCast<bhkCollisionObject>(CreateBlock("bhkCollisionObject")); co->SetBody(DynamicCast<NiObject>(body)); + co->SetParent(newParent); // link newParent->SetCollisionObject(DynamicCast<NiCollisionObject>(co)); - } else - if (isCollisionGroup(node)) - { - newParent = makeNode(parent, node); - } else - newParent = parent; - + } else if (isCollisionGroup(node) && !mFlattenHierarchy) { + newParent = makeNode(nodeParent, node); + } else { + newParent = nodeParent; + } for (int i=0; i<node->NumberOfChildren(); i++) { Result result = exportCollision(newParent, node->GetChildNode(i)); @@ -315,13 +317,13 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node) // Handle compatibility npGetProp(node, NP_HVK_MASS_OLD, mass, NP_DEFAULT_HVK_EMPTY); - if (mass != NP_DEFAULT_HVK_EMPTY) + if (mass == NP_DEFAULT_HVK_EMPTY) npGetProp(node, NP_HVK_MASS, mass, NP_DEFAULT_HVK_MASS); npGetProp(node, NP_HVK_FRICTION_OLD, frict, NP_DEFAULT_HVK_EMPTY); - if (frict != NP_DEFAULT_HVK_EMPTY) + if (frict == NP_DEFAULT_HVK_EMPTY) npGetProp(node, NP_HVK_FRICTION, frict, NP_DEFAULT_HVK_FRICTION); npGetProp(node, NP_HVK_RESTITUTION_OLD, resti, NP_DEFAULT_HVK_EMPTY); - if (resti != NP_DEFAULT_HVK_EMPTY) + if (resti == NP_DEFAULT_HVK_EMPTY) npGetProp(node, NP_HVK_RESTITUTION, resti, NP_DEFAULT_HVK_RESTITUTION); npGetProp(node, NP_HVK_LAYER, lyr, NP_DEFAULT_HVK_LAYER); @@ -336,7 +338,7 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node) npGetProp(node, NP_HVK_CENTER, center); // setup body - bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBody")); + bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBodyT")); body->SetLayer(lyr); body->SetLayerCopy(lyr); @@ -351,6 +353,8 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node) body->SetMaxAngularVelocity(maxangvel); body->SetPenetrationDepth(pendepth); body->SetCenter(center); + QuaternionXYZW q; q.x = q.y = q.z = 0; q.w = 1.0f; + body->SetRotation(q); return body; } @@ -490,7 +494,6 @@ bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node) shape->SetUnknownInts1(unknownInts1); */ - ASSERT(!"TODO: Need to support this"); /* Still not handled vector<uint> unknownInts2; unknownInts2.resize(1); diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp index 5c4937c..f9ab730 100755 --- a/NifExport/Config.cpp +++ b/NifExport/Config.cpp @@ -57,6 +57,13 @@ void Exporter::writeConfig(Interface *i) SetIniValue(NifExportSection, "TexturePrefix", mTexPrefix, iniName); SetIniValue(NifExportSection, "ExportCollision", mExportCollision, iniName); SetIniValue(NifExportSection, "RemapIndices", mRemapIndices, iniName); + + SetIniValue(NifExportSection, "ExportExtraNodes", mExportExtraNodes, iniName); + SetIniValue(NifExportSection, "ExportSkin", mExportSkin, iniName); + SetIniValue(NifExportSection, "UserPropBuffer", mUserPropBuffer, iniName); + SetIniValue(NifExportSection, "FlattenHierarchy", mFlattenHierarchy, iniName); + SetIniValue(NifExportSection, "RemoveUnreferencedBones", mRemoveUnreferencedBones, iniName); + SetIniValue(NifExportSection, "SortNodesToEnd", mSortNodesToEnd, iniName); } } diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index a38bfe3..57c2e09 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -20,6 +20,9 @@ bool Exporter::mUserPropBuffer=false; bool Exporter::mFlattenHierarchy=false; bool Exporter::mRemoveUnreferencedBones=false; bool Exporter::mSortNodesToEnd=false; +string Exporter::mGameName = "User"; +string Exporter::mNifVersion = "20.0.0.5"; +int Exporter::mNifUserVersion = 0; Exporter::Exporter(Interface *i, AppSettings *appSettings) : mI(i), mAppSettings(appSettings) @@ -28,11 +31,21 @@ Exporter::Exporter(Interface *i, AppSettings *appSettings) Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) { + //root->SetName("Scene Root"); + BSXFlagsRef bsx = CreateNiObject<BSXFlags>(); bsx->SetName("BSX"); bsx->SetFlags(0x00000002); root->AddExtraData(DynamicCast<NiExtraData>(bsx)); - exportUPB(root, node); + bool ok = exportUPB(root, node); + + if (!ok && Exporter::mExportCollision) + { + NiStringExtraDataRef strings = DynamicCast<NiStringExtraData>(CreateBlock("NiStringExtraData")); + strings->SetName("UPB"); + strings->SetData("Ellasticity = 0.300000\r\nFriction = 0.300000\r\nUnyielding = 0\r\nProxy_Geometry = <None>\r\nUse_Display_Proxy = 0\r\nDisplay_Children = 1\r\nDisable_Collisions = 0\r\nInactive = 0\r\nDisplay_Proxy = <None>\r\nMass = 0.000000\r\nSimulation_Geometry = 2\r\nCollision_Groups = 589825\r\n"); + root->AddExtraData(DynamicCast<NiExtraData>(strings)); + } mNiRoot = root; diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index a931c1b..e73a5a4 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -5,6 +5,7 @@ using namespace Niflib; class BitmapTex; class AppSettings; +class StdMat2; class Exporter { @@ -49,6 +50,9 @@ public: static bool mFlattenHierarchy; static bool mRemoveUnreferencedBones; static bool mSortNodesToEnd; + static string mGameName; + static string mNifVersion; + static int mNifUserVersion; Exporter(Interface *i, AppSettings *appSettings); @@ -108,7 +112,8 @@ private: void nodeTransform(QuaternionXYZW &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true); Point3 getVertexNormal(Mesh* mesh, int faceNo, RVertex* rv); bool equal(const Vector3 &a, const Point3 &b, float thresh); - BitmapTex *getTexture(Mtl *mtl); + BitmapTex *getTexture(Mtl *mtl); + BitmapTex *getTexture(Mtl *mtl, int i); void getTextureMatrix(Matrix3 &mat, Mtl *mtl); NiNodeRef makeNode(NiNodeRef &parent, INode *maxNode, bool local=true); NiNodeRef getNode(const string& name); @@ -138,8 +143,10 @@ private: /* texture & material */ // creates NiTexturingProperty + NiSourceTexture void makeTexture(NiAVObjectRef &parent, Mtl *mtl); + bool makeTextureDesc(BitmapTex *bmTex, Niflib::TexDesc &td); // creates a NiMaterialProperty void makeMaterial(NiAVObjectRef &parent, Mtl *mtl); + bool exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl); /* havok & collision */ int addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm); diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index 2ec3cb8..8c29ba4 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -251,7 +251,6 @@ NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp NiAVObjectRef av(DynamicCast<NiAVObject>(shape)); makeMaterial(av, mtl); - makeTexture(av, mtl); parent->AddChild(DynamicCast<NiAVObject>(shape)); @@ -265,8 +264,10 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr Point3 norm = getVertexNormal(mesh, face, mesh->getRVertPtr(vidx)); Point3 uv; - if (mesh->tVerts && mesh->tvFace) + if (mesh->tVerts && mesh->tvFace) { uv = mesh->tVerts[ mesh->tvFace[ face ].t[ vi ]] * texm; + uv.y += 1.0f; + } Color4 col(1.0f, 1.0f, 1.0f); if (mVertexColors && !vertColors.empty()){ @@ -282,7 +283,7 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr if (equal(grp.verts[i], pt, mWeldThresh) && equal(grp.vnorms[i], norm, 0)) { - if (mesh->tvFace && (grp.uvs[i].u!=uv.x || grp.uvs[i].v!=uv.y)) + if (mesh->tVerts && mesh->tvFace && (grp.uvs[i].u!=uv.x || grp.uvs[i].v!=uv.y)) continue; if (mVertexColors && !vertColors.empty() && diff --git a/NifExport/MtlTex.cpp b/NifExport/MtlTex.cpp index a18a2b2..75b4089 100755 --- a/NifExport/MtlTex.cpp +++ b/NifExport/MtlTex.cpp @@ -1,20 +1,76 @@ #include "pch.h" #include "stdmat.h" +#include "shaders.h" #include "AppSettings.h" +#include "obj/NiWireframeProperty.h" +#include "obj/NiAlphaProperty.h" +#include "obj/NiStencilProperty.h" +#include "obj/NiShadeProperty.h" +#include "obj/NiVertexColorProperty.h" +#include "obj/NiDitherProperty.h" +#include "obj/NiSpecularProperty.h" void Exporter::makeTexture(NiAVObjectRef &parent, Mtl *mtl) { - BitmapTex *bmTex = getTexture(mtl); - + BitmapTex *bmTex = getTexture(mtl); if (!bmTex) - return; + return; - NiTexturingPropertyRef texProp(DynamicCast<NiTexturingProperty>(CreateBlock("NiTexturingProperty"))); + NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>(); texProp->SetApplyMode(APPLY_MODULATE); texProp->SetTextureCount(7); TexDesc td; - td.source = DynamicCast<NiSourceTexture>(CreateBlock("NiSourceTexture")); + if (makeTextureDesc(bmTex, td)) + texProp->SetTexture(BASE_MAP, td); + + NiPropertyRef prop = DynamicCast<NiProperty>(texProp); + parent->AddProperty(prop); +} + +bool Exporter::makeTextureDesc(BitmapTex *bmTex, TexDesc& td) +{ + td.source = CreateNiObject<NiSourceTexture>(); + + // Filtering + switch (bmTex->GetFilterType()) + { + case FILTER_PYR: td.filterMode = FILTER_TRILERP; break; + case FILTER_SAT: td.filterMode = FILTER_BILERP; break; + case FILTER_NADA: td.filterMode = FILTER_NEAREST; break; + } + + td.clampMode = TexClampMode(); + switch (bmTex->GetTextureTiling()) + { + case 3: td.clampMode = WRAP_S_WRAP_T; break; + case 1: td.clampMode = WRAP_S_CLAMP_T; break; + case 2: td.clampMode = CLAMP_S_WRAP_T; break; + case 0: td.clampMode = CLAMP_S_CLAMP_T; break; + } + + if (UVGen *uvGen = bmTex->GetTheUVGen()){ + if (RefTargetHandle ref = uvGen->GetReference(0)){ + TexCoord trans, tiling; + float wangle; + bool ok = true; + if(ok) ok &= getMAXScriptValue(ref, "U_Offset", 0, trans.u); + if(ok) ok &= getMAXScriptValue(ref, "V_Offset", 0, trans.v); + if(ok) ok &= getMAXScriptValue(ref, "U_Tiling", 0, tiling.u); + if(ok) ok &= getMAXScriptValue(ref, "V_Tiling", 0, tiling.v); + if(ok) ok &= getMAXScriptValue(ref, "W_Angle", 0, wangle); + if (ok) { + if (trans.u != 0.0f || trans.v != 0.0f || tiling.u != 1.0f || tiling.v != 1.0f || wangle != 0.0f) { + td.hasTextureTransform = true; + td.translation = trans; + td.tiling = tiling; + td.wRotation = TORAD(wangle); + td.transformType_ = 1; + td.centerOffset = TexCoord(0.5, 0.5); + } + } + } + } // Get file name and check if it matches the "app" settings in the ini file TSTR mapPath; @@ -31,23 +87,25 @@ void Exporter::makeTexture(NiAVObjectRef &parent, Mtl *mtl) { TSTR p, f; SplitPathFile(mapPath, &p, &f); - TSTR newPath; - if (mTexPrefix != "") - newPath = TSTR(mTexPrefix.c_str()) + _T("\\") + f; - else - newPath = f; - + TSTR newPath; + if (mTexPrefix != "") + newPath = TSTR(mTexPrefix.c_str()) + _T("\\") + f; + else + newPath = f; + NiObjectRef unk_link(NULL); - td.source->SetExternalTexture(newPath.data(), unk_link); + td.source->SetExternalTexture(newPath.data(), unk_link); } - texProp->SetTexture(BASE_MAP, td); - - NiPropertyRef prop = DynamicCast<NiProperty>(texProp); - parent->AddProperty(prop); + return true; } void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl) { + // Fill-in using the Civ4 Shader if available + bool done = exportCiv4Shader(parent, mtl); + if (done) + return; + string name; NiMaterialPropertyRef mtlProp(DynamicCast<NiMaterialProperty>(CreateBlock("NiMaterialProperty"))); if (mtl) @@ -74,6 +132,29 @@ void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl) { StdMat2 * smtl = (StdMat2*)mtl; mtlProp->SetTransparency(smtl->GetOpacity(0)); + + if (smtl->SupportsShaders()) { + if (Shader *s = smtl->GetShader()) { + if (smtl->GetWire()){ + NiWireframePropertyRef wireProp = CreateNiObject<NiWireframeProperty>(); + wireProp->SetFlags(1); + parent->AddProperty(wireProp); + } + if (smtl->GetTwoSided()){ + NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>(); + stencil->SetStencilFunction(4); + stencil->SetStencilEnabled(false); + stencil->SetPassAction(3); + stencil->SetDrawMode(3); + parent->AddProperty(stencil); + } + if (smtl->IsFaceted()) { + NiShadePropertyRef shade = CreateNiObject<NiShadeProperty>(); + shade->SetFlags(0); + parent->AddProperty(shade); + } + } + } } } else { @@ -90,6 +171,8 @@ void Exporter::makeMaterial(NiAVObjectRef &parent, Mtl *mtl) NiPropertyRef prop = DynamicCast<NiProperty>(mtlProp); parent->AddProperty(prop); + + makeTexture(parent, mtl); } @@ -133,6 +216,21 @@ BitmapTex *Exporter::getTexture(Mtl *mtl) return bmTex; } +BitmapTex *Exporter::getTexture(Mtl *mtl, int i) +{ + if (mtl) { + int texMaps = mtl->NumSubTexmaps(); + if (i < texMaps) { + if (Texmap *texMap = mtl->GetSubTexmap(i)) { + if (texMap->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { + return (BitmapTex*)texMap; + } + } + } + } + return NULL; +} + void Exporter::getTextureMatrix(Matrix3 &mat, Mtl *mtl) { BitmapTex *tex = getTexture(mtl); @@ -141,3 +239,207 @@ void Exporter::getTextureMatrix(Matrix3 &mat, Mtl *mtl) else mat.IdentityMatrix(); } + + +bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) +{ + if (!mtl) + return false; + + RefTargetHandle ref = mtl->GetReference(2/*shader*/); + if (!ref) + return false; + + TSTR shaderByName; + if(mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0) ) + { + StdMat2 * smtl = (StdMat2*)mtl; + if (smtl->SupportsShaders()) { + if (Shader *s = smtl->GetShader()) { + s->GetClassName(shaderByName); + } + } + } + if (shaderByName != TSTR("CivilizationIV Shader")) + return false; + + //if (Shader *s = mtl->GetShader()) { + // TSTR className; + // s->GetClassName(className); + // if (className != TSTR("CivilizationIV Shader")) + // return false; + + Color ambient = Color(0.0f,0.0f,0.0f), diffuse = Color(0.0f,0.0f,0.0f), specular = Color(0.0f,0.0f,0.0f), emittance = Color(0.0f,0.0f,0.0f); + float shininess = 0.0f, alpha = 0.0f, Magnitude = 0.0f, LumaScale = 0.0f, LumaOffset = 0.0f; + int TestRef = 0, srcBlend = 0, destBlend = 0, TestMode = 0; + bool AlphaTestEnable = false; + int ApplyMode = 0, SrcVertexMode = 0, LightingMode = 0; + bool VertexColorsEnable = false, SpecularEnable = false, NoSorter = false, Dither = false; + int alphaMode = 0, BaseTextureExport=0, DarkTextureExport=0, DetailTextureExport=0; + int Decal1TextureExport=0, Decal2TextureExport=0, GlossTextureExport=0, GlowTextureExport=0; + LPTSTR CustomShader = NULL; + int ShaderViewerTechnique=0, ShaderExportTechnique=0; + bool UseNormalMaps = false; + int NormalMapTechnique=0; + + bool ok = true; + + if(ok) ok &= getMAXScriptValue(ref, "ambient", 0, ambient ); + if(ok) ok &= getMAXScriptValue(ref, "diffuse", 0, diffuse ); + if(ok) ok &= getMAXScriptValue(ref, "specular", 0, specular ); + if(ok) ok &= getMAXScriptValue(ref, "emittance", 0, emittance ); + if(ok) ok &= getMAXScriptValue(ref, "shininess", 0, shininess ); + if(ok) ok &= getMAXScriptValue(ref, "alpha", 0, alpha ); + if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Magnitude", 0, Magnitude); + if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Luma_Scale", 0, LumaScale); + if(ok) ok &= getMAXScriptValue(ref, "Bump_Map_Luma_offset", 0, LumaOffset); + if(ok) ok &= getMAXScriptValue(ref, "TestRef", 0, TestRef ); + if(ok) ok &= getMAXScriptValue(ref, "AlphaTestEnable", 0, AlphaTestEnable ); + if(ok) ok &= getMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable); + if(ok) ok &= getMAXScriptValue(ref, "SpecularEnable", 0, SpecularEnable); + if(ok) ok &= getMAXScriptValue(ref, "NoSorter", 0, NoSorter); + if(ok) ok &= getMAXScriptValue(ref, "Dither", 0, Dither ); + if(ok) ok &= getMAXScriptValue(ref, "UseNormalMaps", 0, UseNormalMaps ); + if(ok) ok &= getMAXScriptValue(ref, "srcBlend", 0, srcBlend); + if(ok) ok &= getMAXScriptValue(ref, "destBlend", 0, destBlend); + if(ok) ok &= getMAXScriptValue(ref, "TestMode", 0, TestMode ); + if(ok) ok &= getMAXScriptValue(ref, "ApplyMode", 0, ApplyMode); + if(ok) ok &= getMAXScriptValue(ref, "SourceVertexMode", 0, SrcVertexMode); + if(ok) ok &= getMAXScriptValue(ref, "LightingMode", 0, LightingMode); + if(ok) ok &= getMAXScriptValue(ref, "alphaMode", 0, alphaMode); + if(ok) ok &= getMAXScriptValue(ref, "BaseTextureExport", 0, BaseTextureExport); + if(ok) ok &= getMAXScriptValue(ref, "DarkTextureExport", 0, DarkTextureExport); + if(ok) ok &= getMAXScriptValue(ref, "DetailTextureExport", 0, DetailTextureExport); + if(ok) ok &= getMAXScriptValue(ref, "Decal1TextureExport", 0, Decal1TextureExport); + if(ok) ok &= getMAXScriptValue(ref, "Decal2TextureExport", 0, Decal2TextureExport); + if(ok) ok &= getMAXScriptValue(ref, "GlossTextureExport", 0, GlossTextureExport); + if(ok) ok &= getMAXScriptValue(ref, "GlowTextureExport", 0, GlowTextureExport); + if(ok) ok &= getMAXScriptValue(ref, "CustomShader", 0, CustomShader ); + if(ok) ok &= getMAXScriptValue(ref, "ShaderViewerTechnique", 0, ShaderViewerTechnique); + if(ok) ok &= getMAXScriptValue(ref, "ShaderExportTechnique", 0, ShaderExportTechnique); + if(ok) ok &= getMAXScriptValue(ref, "NormalMapTechnique", 0, NormalMapTechnique ); + + if (ok) // civ4 shader + { + NiMaterialPropertyRef mtlProp = CreateNiObject<NiMaterialProperty>(); + parent->AddProperty(mtlProp); + + mtlProp->SetName((char*)mtl->GetName()); + mtlProp->SetAmbientColor(TOCOLOR3(ambient)); + mtlProp->SetDiffuseColor(TOCOLOR3(diffuse)); + mtlProp->SetSpecularColor(TOCOLOR3(specular)); + mtlProp->SetEmissiveColor(TOCOLOR3(emittance)); + mtlProp->SetGlossiness(shininess); + mtlProp->SetTransparency(alpha/100.0f); + if(mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0) ) + { + StdMat2 * smtl = (StdMat2*)mtl; + if (smtl->SupportsShaders()) { + if (Shader *s = smtl->GetShader()) { + if (smtl->GetWire()){ + NiWireframePropertyRef wireProp = CreateNiObject<NiWireframeProperty>(); + wireProp->SetFlags(1); + parent->AddProperty(wireProp); + } + if (smtl->GetTwoSided()){ + NiStencilPropertyRef stencil = CreateNiObject<NiStencilProperty>(); + stencil->SetStencilFunction(4); + stencil->SetStencilEnabled(false); + stencil->SetPassAction(3); + stencil->SetDrawMode(3); + parent->AddProperty(stencil); + } + if (smtl->IsFaceted()) { + NiShadePropertyRef shade = CreateNiObject<NiShadeProperty>(); + shade->SetFlags(0); + parent->AddProperty(shade); + } + } + } + } + if (VertexColorsEnable && (SrcVertexMode != 2 || LightingMode != 1)) { + NiVertexColorPropertyRef vertexColor = CreateNiObject<NiVertexColorProperty>(); + parent->AddProperty(vertexColor); + vertexColor->SetVertexMode(VertMode(SrcVertexMode)); + vertexColor->SetLightingMode(LightMode(LightingMode)); + vertexColor->SetFlags(LightingMode + (SrcVertexMode << 3)); + } + if (SpecularEnable) { + NiSpecularPropertyRef prop = CreateNiObject<NiSpecularProperty>(); + parent->AddProperty(prop); + prop->SetFlags(1); + + } + if (Dither) { + NiDitherPropertyRef prop = CreateNiObject<NiDitherProperty>(); + parent->AddProperty(prop); + prop->SetFlags(1); + } + if (alphaMode != 0 || AlphaTestEnable) { + // always add alpha ??? + NiAlphaPropertyRef alphaProp = CreateNiObject<NiAlphaProperty>(); + parent->AddProperty(alphaProp); + alphaProp->SetAlphaBlend(true); + if (alphaMode == 0) { // automatic + alphaProp->SetSourceBlendMode(NiAlphaProperty::BlendMode(srcBlend)); + alphaProp->SetDestBlendMode(NiAlphaProperty::BlendMode(destBlend)); + } else if (alphaMode == 1) { // None + alphaProp->SetAlphaBlend(false); + alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_SRC_ALPHA); + alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA); + } else if (alphaMode == 2) { // Standard + alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_SRC_ALPHA); + alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA); + } else if (alphaMode == 3) { // Additive + alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_ONE); + alphaProp->SetDestBlendMode(NiAlphaProperty::BM_ONE); + } else if (alphaMode == 4) { // Multiplicative + alphaProp->SetSourceBlendMode(NiAlphaProperty::BM_ZERO); + alphaProp->SetDestBlendMode(NiAlphaProperty::BM_SRC_COLOR); + } else { // Advanced + alphaProp->SetSourceBlendMode(NiAlphaProperty::BlendMode(srcBlend)); + alphaProp->SetDestBlendMode(NiAlphaProperty::BlendMode(destBlend)); + } + alphaProp->SetTestMode(NiAlphaProperty::TestMode(TestMode)); + alphaProp->SetAlphaSort(!NoSorter); + alphaProp->SetAlphaTestThreshold(TestRef); + alphaProp->SetAlphaTest(AlphaTestEnable); + } + + int ntex = mtl->NumSubTexmaps(); + if (ntex > 0) + { + ntex = min(ntex, 7); + TexType texmap[] = {BASE_MAP, DARK_MAP, DETAIL_MAP, DECAL_0_MAP, BUMP_MAP, GLOSS_MAP, GLOW_MAP, DECAL_1_MAP}; + NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>(); + texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode)); + texProp->SetTextureCount(7); + for (int i = 0; i < ntex; ++i) { + + BitmapTex *bmTex = getTexture(mtl, i); + if (!bmTex) + continue; + + TexDesc td; + if (makeTextureDesc(bmTex, td)) { + TexType textype = texmap[i]; + texProp->SetTexture(textype, td); + if (textype == BUMP_MAP) { + td.source->SetPixelLayout(PIX_LAY_BUMPMAP); + texProp->SetLumaOffset(LumaOffset); + texProp->SetLumaScale(LumaScale); + + Matrix22 m2; + m2[0][0] = m2[1][1] = Magnitude; + m2[0][1] = m2[1][0] = 0.0f; + texProp->SetBumpMapMatrix(m2); + } + } + } + + parent->AddProperty(texProp); + } + return true; + } + return false; +} diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index 4095a3a..2605160 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -66,6 +66,16 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA { case WM_INITDIALOG: { + // Append file version to dialog + TSTR fileVersion = GetFileVersion(NULL); + if (!fileVersion.isNull()) { + char buffer[256]; + GetWindowText(hWnd, buffer, _countof(buffer)); + _tcscat(buffer, TEXT(" ")); + _tcscat(buffer, fileVersion); + SetWindowText(hWnd, buffer); + } + imp = (NifExport *)lParam; CenterWindow(hWnd,GetParent(hWnd)); CheckDlgButton(hWnd, IDC_CHK_STRIPS, Exporter::mTriStrips); @@ -75,7 +85,23 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA CheckDlgButton(hWnd, IDC_CHK_VCOLORS, Exporter::mVertexColors); SetDlgItemText(hWnd, IDC_ED_TEXPREFIX, Exporter::mTexPrefix.c_str()); CheckDlgButton(hWnd, IDC_CHK_COLL, Exporter::mExportCollision); - CheckDlgButton(hWnd, IDC_CHK_REMAP, Exporter::mRemapIndices); + CheckDlgButton(hWnd, IDC_CHK_REMAP, Exporter::mRemapIndices); + + CheckDlgButton(hWnd, IDC_CHK_EXTRA, Exporter::mExportExtraNodes); + CheckDlgButton(hWnd, IDC_CHK_SKIN, Exporter::mExportSkin); + CheckDlgButton(hWnd, IDC_CHK_UPB, Exporter::mUserPropBuffer); + CheckDlgButton(hWnd, IDC_CHK_HIER, Exporter::mFlattenHierarchy); + CheckDlgButton(hWnd, IDC_CHK_REM_BONES, Exporter::mRemoveUnreferencedBones); + CheckDlgButton(hWnd, IDC_CHK_SORTNODES, Exporter::mSortNodesToEnd); + + string selection = Exporter::mGameName; + string version = Exporter::mNifVersion; + string userVer = FormatString("%d", Exporter::mNifUserVersion); + for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr) + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_ADDSTRING, 0, LPARAM(itr->Name.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_SELECTSTRING, WPARAM(-1), LPARAM(selection.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str())); TSTR tmp; tmp.printf("%.4f", Exporter::mWeldThresh); @@ -92,11 +118,23 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA case WM_COMMAND: if (HIWORD(wParam) == BN_CLICKED) { - char tmp[MAX_PATH]; + char tmp[MAX_PATH], *end; bool close = false; switch (LOWORD(wParam)) { case IDOK: + // Validity Check + GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH); + if (tmp[0] != 0) + { + int nifVersion = GetVersion(tmp); + if (!IsVersionSupported(nifVersion)) + { + MessageBox(hWnd, FormatString("Version '%s' is not a supported version.", tmp).c_str(), "NifExport", MB_OK|MB_ICONSTOP); + return FALSE; + } + } + Exporter::mTriStrips = IsDlgButtonChecked(hWnd, IDC_CHK_STRIPS); Exporter::mExportHidden = IsDlgButtonChecked(hWnd, IDC_CHK_HIDDEN); Exporter::mExportFurn = IsDlgButtonChecked(hWnd, IDC_CHK_FURN); @@ -104,6 +142,13 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA Exporter::mVertexColors = IsDlgButtonChecked(hWnd, IDC_CHK_VCOLORS); Exporter::mExportCollision = IsDlgButtonChecked(hWnd, IDC_CHK_COLL); Exporter::mRemapIndices = IsDlgButtonChecked(hWnd, IDC_CHK_REMAP); + + Exporter::mExportExtraNodes = IsDlgButtonChecked(hWnd, IDC_CHK_EXTRA); + Exporter::mExportSkin = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN); + Exporter::mUserPropBuffer = IsDlgButtonChecked(hWnd, IDC_CHK_UPB); + Exporter::mFlattenHierarchy = IsDlgButtonChecked(hWnd, IDC_CHK_HIER); + Exporter::mRemoveUnreferencedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES); + Exporter::mSortNodesToEnd = IsDlgButtonChecked(hWnd, IDC_CHK_SORTNODES); GetDlgItemText(hWnd, IDC_ED_TEXPREFIX, tmp, MAX_PATH); Exporter::mTexPrefix = tmp; @@ -111,6 +156,16 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA GetDlgItemText(hWnd, IDC_ED_WELDTHRESH, tmp, MAX_PATH); Exporter::mWeldThresh = atof(tmp); + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) + { + Exporter::mGameName = appSettings->Name; + GetDlgItemText(hWnd, IDC_CB_VERSION, tmp, MAX_PATH); + Exporter::mNifVersion = tmp; + GetDlgItemText(hWnd, IDC_CB_USER_VERSION, tmp, MAX_PATH); + Exporter::mNifUserVersion = strtol(tmp, &end, 0); + } + EndDialog(hWnd, imp->mDlgResult=IDOK); close = true; break; @@ -124,8 +179,7 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA if (close) SendMessage(hWnd, WM_CLOSE, 0, 0); } - - if (HIWORD(wParam) == STN_CLICKED) + else if (HIWORD(wParam) == STN_CLICKED) { if (LOWORD(wParam) == IDC_LBL_LINK) { @@ -133,7 +187,21 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA NULL, NULL, SW_SHOWDEFAULT); } } - + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + if (LOWORD(wParam) == IDC_CB_GAME) + { + char tmp[MAX_PATH]; + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) + { + string version = appSettings->NiVersion; + string userVer = FormatString("%d", appSettings->NiUserVersion); + SendDlgItemMessage(hWnd, IDC_CB_VERSION, WM_SETTEXT, 0, LPARAM(version.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_USER_VERSION, WM_SETTEXT, 0, LPARAM(userVer.c_str())); + } + } + } break; } return FALSE; @@ -243,12 +311,15 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL appSettings = FindAppSetting(curapp); } } - if (appSettings == NULL && !TheAppSettings.empty()){ + if (appSettings == NULL && !TheAppSettings.empty()) appSettings = &TheAppSettings.front(); - } if(!suppressPrompts) { + Exporter::mGameName = appSettings->Name; + Exporter::mNifVersion = appSettings->NiVersion; + Exporter::mNifUserVersion = appSettings->NiUserVersion; + if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), NifExportOptionsDlgProc, (LPARAM)this) != IDOK) return true; @@ -256,10 +327,28 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL Exporter::writeConfig(i); // write config to root node Exporter::writeConfig(i->GetRootNode()); + + // Update the current app version + appSettings = FindAppSetting(Exporter::mGameName); + if (appSettings == NULL && !TheAppSettings.empty()) + appSettings = &TheAppSettings.front(); + appSettings->NiVersion = Exporter::mNifVersion; + appSettings->NiUserVersion = Exporter::mNifUserVersion; + appSettings->WriteSettings(i); } try { + int nifVersion = VER_20_0_0_5; + int nifUserVer = Exporter::mNifUserVersion; + + if (!Exporter::mNifVersion.empty()) + { + nifVersion = GetVersion(Exporter::mNifVersion); + if (!IsVersionSupported(nifVersion)) + throw exception(FormatString("Version '%s' is not a supported version.").c_str()); + } + Exporter::mSelectedOnly = (options&SCENE_EXPORT_SELECTED) != 0; Exporter exp(i, appSettings); @@ -269,7 +358,7 @@ int NifExport::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL if (result!=Exporter::Ok) throw exception("Unknown error."); - WriteNifTree(name, NiObjectRef(root), VER_20_0_0_5, 11); + WriteNifTree(name, NiObjectRef(root), nifVersion, nifUserVer); } catch (exception &e) diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc index 0386678..efbb97a 100755 --- a/NifExport/NifExport.rc +++ b/NifExport/NifExport.rc @@ -13,7 +13,7 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Deutsch (Deutschland) resources +// German (Germany) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) #ifdef _WIN32 @@ -35,12 +35,12 @@ END #endif // APSTUDIO_INVOKED -#endif // Deutsch (Deutschland) resources +#endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -// Englisch (USA) resources +// English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 @@ -73,48 +73,43 @@ END // Dialog // -IDD_PANEL DIALOGEX 0, 0, 200, 137 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU +IDD_PANEL DIALOGEX 0, 0, 207, 187 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOOLWINDOW CAPTION "Export Nif" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - CONTROL "",IDC_EDIT,"CustEdit",NOT WS_VISIBLE | WS_TABSTOP,148,8, - 35,10 - CONTROL "",IDC_SPIN,"SpinnerControl",NOT WS_VISIBLE,186,7,7,10 - PUSHBUTTON "&Export",IDOK,5,115,34,14 - PUSHBUTTON "&Cancel",IDCANCEL,45,115,33,14 - CONTROL "Include &Hidden",IDC_CHK_HIDDEN,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,80,5,64,10 - CONTROL "Generate &Strips",IDC_CHK_STRIPS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,5,5,65,10 - CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button", - BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,5,15,71,10 - EDITTEXT IDC_ED_TEXPREFIX,5,60,190,12,ES_AUTOHSCROLL - LTEXT "Texture &Prefix",IDC_STATIC,5,50,44,8 - CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | - WS_DISABLED | WS_TABSTOP,5,25,35,10 - EDITTEXT IDC_ED_WELDTHRESH,163,22,35,12,ES_AUTOHSCROLL | NOT - WS_VISIBLE | WS_DISABLED - LTEXT "Auto-&Weld",IDC_LBL_WELDTHRESH,160,30,34,8,NOT - WS_VISIBLE | WS_DISABLED - CONTROL "Export Co&llision",IDC_CHK_COLL,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,80,15,68,10 - CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,80,25,68,10 - LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,98,114,95, - 14,SS_NOTIFY | SS_CENTERIMAGE - CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,80,35,68,10 - COMBOBOX IDC_CB_GAME,5,90,105,70,CBS_DROPDOWN | CBS_SORT | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - LTEXT "Game",IDC_STATIC,5,79,66,8,WS_DISABLED - EDITTEXT IDC_CB_VERSION,115,90,45,12,ES_AUTOHSCROLL | WS_DISABLED - LTEXT "Version",IDC_STATIC,115,79,39,8,WS_DISABLED - EDITTEXT IDC_CB_USER_VERSION,165,90,30,12,ES_AUTOHSCROLL | - WS_DISABLED - LTEXT "User",IDC_STATIC,165,79,25,8,WS_DISABLED + GROUPBOX "Export:",IDC_STATIC,7,7,81,97 + CONTROL "&Hidden Nodes",IDC_CHK_HIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,17,67,10 + CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,29,67,10 + CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,41,67,10 + CONTROL "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,53,67,10 + CONTROL "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,65,67,10 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,77,67,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,89,67,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,97 + CONTROL "Generate &Strips",IDC_CHK_STRIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,17,88,10 + CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,29,88,10 + CONTROL "Extra Nodes on Mesh",IDC_CHK_EXTRA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,41,88,11 + CONTROL "Add User Prop Buffer",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,53,88,11 + CONTROL "Flatten Hierarchy",IDC_CHK_HIER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,65,88,10 + CONTROL "Remove Extra Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,77,88,10 + CONTROL "Sort Nodes",IDC_CHK_SORTNODES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,89,88,10 + CONTROL "",IDC_SPIN,"SpinnerControl",NOT WS_VISIBLE,193,7,7,10 + CONTROL "",IDC_EDIT,"CustEdit",NOT WS_VISIBLE | WS_TABSTOP,194,18,6,10 + EDITTEXT IDC_ED_WELDTHRESH,189,30,11,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED + LTEXT "Auto-&Weld",IDC_LBL_WELDTHRESH,192,42,8,8,NOT WS_VISIBLE | WS_DISABLED + LTEXT "Default Texture &Prefix:",IDC_STATIC,7,111,71,8 + EDITTEXT IDC_ED_TEXPREFIX,7,122,190,12,ES_AUTOHSCROLL + LTEXT "Game",IDC_STATIC,7,138,66,8 + COMBOBOX IDC_CB_GAME,7,149,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Version",IDC_STATIC,117,138,39,8 + EDITTEXT IDC_CB_VERSION,117,149,45,12,ES_AUTOHSCROLL + LTEXT "User",IDC_STATIC,167,138,25,8 + EDITTEXT IDC_CB_USER_VERSION,167,149,30,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "&Export",IDOK,5,166,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,166,33,14 + LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,105,166,95,14,SS_NOTIFY | SS_CENTERIMAGE END @@ -129,14 +124,53 @@ BEGIN IDD_PANEL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 193 + RIGHTMARGIN, 200 TOPMARGIN, 7 - BOTTOMMARGIN, 130 + BOTTOMMARGIN, 180 END END #endif // APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,2,0,0 + PRODUCTVERSION 0,2,0,0 + FILEFLAGSMASK 0x37L +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "3ds Max Nif Exporter" + VALUE "FileVersion", "0, 2, 0, 0" + VALUE "InternalName", "NifExport.dle" + VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." + VALUE "OriginalFilename", "NifExport.dle" + VALUE "ProductName", "3ds Max Nif Exporter" + VALUE "ProductVersion", "0, 2, 0, 0" + VALUE "SpecialBuild", "Alpha" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + ///////////////////////////////////////////////////////////////////////////// // // String Table @@ -149,7 +183,7 @@ BEGIN IDS_SPIN "Spin" END -#endif // Englisch (USA) resources +#endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/NifExport/NifExport_VC80.vcproj b/NifExport/NifExport_VC80.vcproj index fc8e25e..dda568d 100644 --- a/NifExport/NifExport_VC80.vcproj +++ b/NifExport/NifExport_VC80.vcproj @@ -47,7 +47,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="2" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" @@ -153,7 +153,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include;..\..\niflib;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" @@ -250,7 +250,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax6\maxsdk\include;..\..\niflib;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" @@ -349,7 +349,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="2" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" @@ -457,7 +457,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="2" InlineFunctionExpansion="2" EnableIntrinsicFunctions="true" @@ -563,7 +563,7 @@ /> <Tool Name="VCCLCompilerTool" - AdditionalOptions="/LD /FI"$(ProjectDir)pch.h"" + AdditionalOptions="/LD /FI"$(ProjectDir)pch.h" /Zm200" Optimization="0" AdditionalIncludeDirectories="C:\3dsmax7\maxsdk\include;..\..\niflib;..\NifCommon" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS" diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index c714c70..b310bc0 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -234,12 +234,16 @@ struct SortNodeEquivalence if (!rhs) return true; string ltype = lhs->GetType().GetTypeName(); string rtype = rhs->GetType().GetTypeName(); - if (ltype == "NiNode") + if (ltype == rtype) return false; - if (rtype == "NiNode") + if (ltype == "bhkCollisionObject") return true; - if (ltype == rtype) + if (rtype == "bhkCollisionObject") return false; + if (ltype == "NiNode") + return false; + else if (rtype == "NiNode") + return true; return (ltype < rtype); } }; diff --git a/NifExport/pch.h b/NifExport/pch.h index f916d52..34cf26c 100755 --- a/NifExport/pch.h +++ b/NifExport/pch.h @@ -13,7 +13,8 @@ #include "istdplug.h" #include "iparamb2.h" #include "iparamm2.h" - +#include "objectParams.h" +#undef ALPHA_NONE // niflib/Ref.h' header guard caused havok! // near & far diff --git a/NifExport/resource.h b/NifExport/resource.h index 520d8a8..26b1288 100755 --- a/NifExport/resource.h +++ b/NifExport/resource.h @@ -25,6 +25,14 @@ #define IDC_CB_VERSION 1015 #define IDC_CB_VERSION2 1016 #define IDC_CB_USER_VERSION 1016 +#define IDC_CHK_SKIN 1017 +#define IDC_CHK_ANIMATION 1018 +#define IDC_CHK_EXTRA 1019 +#define IDC_CHK_UPB 1020 +#define IDC_CHK_HIER 1021 +#define IDC_CHK_REM_BONES 1022 +#define IDC_CHECK7 1023 +#define IDC_CHK_SORTNODES 1023 #define IDC_COLOR 1456 #define IDC_EDIT 1490 #define IDC_SPIN 1496 @@ -35,7 +43,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1016 +#define _APS_NEXT_CONTROL_VALUE 1024 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/NifImport/ImportMeshAndSkin.cpp b/NifImport/ImportMeshAndSkin.cpp index 4cfdc3f..846be26 100644 --- a/NifImport/ImportMeshAndSkin.cpp +++ b/NifImport/ImportMeshAndSkin.cpp @@ -365,7 +365,7 @@ bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom) vector<NiNodeRef> nifBones = nifSkin->GetBones(); //create a skin modifier and add it - Modifier *skinMod = GetSkin(tnode); + Modifier *skinMod = GetOrCreateSkin(tnode); TriObject *triObject = GetTriObject(tnode->GetObjectRef()); Mesh& m = triObject->GetMesh(); diff --git a/NifImport/ImportMtlAndTex.cpp b/NifImport/ImportMtlAndTex.cpp index 838ba00..d99faf6 100644 --- a/NifImport/ImportMtlAndTex.cpp +++ b/NifImport/ImportMtlAndTex.cpp @@ -16,6 +16,10 @@ HISTORY: #include "obj/NiWireframeProperty.h" #include "obj/NiAlphaProperty.h" #include "obj/NiStencilProperty.h" +#include "obj/NiShadeProperty.h" +#include "obj/NiVertexColorProperty.h" +#include "obj/NiDitherProperty.h" +#include "obj/NiSpecularProperty.h" #include "objectParams.h" using namespace Niflib; @@ -26,10 +30,50 @@ Texmap* NifImporter::CreateTexture(TexDesc& desc) string filename = texSrc->GetExternalFileName(); if (bmpMgr->CanImport(filename.c_str())){ BitmapTex *bmpTex = NewDefaultBitmapTex(); - bmpTex->SetName(texSrc->GetName().c_str()); + string name = texSrc->GetName(); + if (name.empty()) { + TCHAR buffer[MAX_PATH]; + _tcscpy(buffer, PathFindFileName(filename.c_str())); + PathRemoveExtension(buffer); + name = buffer; + } + bmpTex->SetName(name.c_str()); bmpTex->SetMapName(const_cast<TCHAR*>(FindImage(filename).c_str())); bmpTex->SetAlphaAsMono(TRUE); - bmpTex->SetAlphaSource(ALPHA_NONE); + bmpTex->SetAlphaSource(ALPHA_DEFAULT); + + switch (desc.filterMode) + { + case FILTER_TRILERP: bmpTex->SetFilterType(FILTER_PYR); break; + case FILTER_BILERP: bmpTex->SetFilterType(FILTER_SAT); break; + case FILTER_NEAREST: bmpTex->SetFilterType(FILTER_NADA); break; + } + + if (UVGen *uvGen = bmpTex->GetTheUVGen()){ + + switch (desc.clampMode) + { + case WRAP_S_WRAP_T : uvGen->SetTextureTiling(3); break; + case WRAP_S_CLAMP_T: uvGen->SetTextureTiling(1); break; + case CLAMP_S_WRAP_T: uvGen->SetTextureTiling(2); break; + case CLAMP_S_CLAMP_T:uvGen->SetTextureTiling(0); break; + } + + if (desc.hasTextureTransform) { + if (RefTargetHandle ref = uvGen->GetReference(0)){ + TexCoord trans = desc.translation; + TexCoord tiling = desc.tiling; + float wangle = TODEG(desc.wRotation); + + setMAXScriptValue(ref, "U_Offset", 0, trans.u); + setMAXScriptValue(ref, "V_Offset", 0, trans.v); + setMAXScriptValue(ref, "U_Tiling", 0, tiling.u); + setMAXScriptValue(ref, "V_Tiling", 0, tiling.v); + setMAXScriptValue(ref, "W_Angle", 0, wangle); + } + } + } + return bmpTex; } } @@ -45,6 +89,7 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec NiWireframePropertyRef wireRef = SelectFirstObjectOfType<NiWireframeProperty>(props); NiAlphaPropertyRef alphaRef = SelectFirstObjectOfType<NiAlphaProperty>(props); NiStencilPropertyRef stencilRef = SelectFirstObjectOfType<NiStencilProperty>(props); + NiShadePropertyRef shadeRef = SelectFirstObjectOfType<NiShadeProperty>(props); bool hasTexture = (texRef && matRef); if (matRef != NULL){ @@ -52,6 +97,13 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec m->SetName(matRef->GetName().c_str()); if (showTextures) m->SetMtlFlag(MTL_DISPLAY_ENABLE_FLAGS, TRUE); + + // try the civ4 shader first then default back to normal shaders + if (ImportCiv4Shader(node, avObject, m)) { + gi->GetMaterialLibrary().Add(m); + node->GetINode()->SetMtl(m); + return true; + } m->SetAmbient(TOCOLOR(matRef->GetAmbientColor()),0); m->SetDiffuse(TOCOLOR(matRef->GetDiffuseColor()),0); m->SetSpecular(TOCOLOR(matRef->GetSpecularColor()),0); @@ -64,19 +116,24 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec m->SetShininess(matRef->GetGlossiness()/100.0,0); m->SetOpacity(matRef->GetTransparency(),0); - bool hasShaderAttributes = (wireRef != NULL) || (stencilRef != NULL); + bool hasShaderAttributes = (wireRef != NULL) || (stencilRef != NULL) || (shadeRef != NULL); if (m->SupportsShaders() && hasShaderAttributes) { if (Shader *s = m->GetShader()) { if (wireRef != NULL && (wireRef->GetFlags() & 1)) { BOOL value = TRUE; - setMAXScriptValue(s->GetReference(0), "wire", 0, value); + m->SetWire(value); } if (stencilRef != NULL) { - + if (stencilRef->GetDrawMode() == 3 /*DRAW_BOTH*/) { + BOOL value = TRUE; + m->SetTwoSided(value); + } + } + if (shadeRef != NULL && shadeRef->GetFlags() & 1) { + m->SetFaceted(TRUE); } } } - if (NULL != texRef) { @@ -115,12 +172,150 @@ bool NifImporter::ImportMaterialAndTextures(ImpNode *node, NiAVObjectRef avObjec return hasTexture; } +bool NifImporter::ImportCiv4Shader(ImpNode *node, NiAVObjectRef avObject, StdMat2 *mtl) +{ + if (!useCiv4Shader || !mtl || !mtl->SupportsShaders()) + return false; + + Class_ID civ4Shader(0x670a77d0,0x23ab5c7f); + if (!mtl->SwitchShader(civ4Shader)) + return false; + + TSTR shaderByName; + if (Shader *s = mtl->GetShader()) + s->GetClassName(shaderByName); + if (shaderByName != TSTR("CivilizationIV Shader")) + return false; + + RefTargetHandle ref = mtl->GetReference(2/*shader*/); + if (!ref) + return false; + + vector<NiPropertyRef> props = avObject->GetProperties(); + + if (NiMaterialPropertyRef matRef = SelectFirstObjectOfType<NiMaterialProperty>(props)){ + Color ambient = TOCOLOR(matRef->GetAmbientColor()); + Color diffuse = TOCOLOR(matRef->GetDiffuseColor()); + Color specular = TOCOLOR(matRef->GetSpecularColor()); + Color emittance = TOCOLOR(matRef->GetEmissiveColor()); + float shininess = matRef->GetGlossiness(); + float alpha = matRef->GetTransparency() * 100.0f; + + mtl->SetShinStr(0.0,0); + mtl->SetShininess(shininess/100.0,0); + mtl->SetOpacity(alpha*100.0f,0); + + setMAXScriptValue(ref, "ambient", 0, ambient ); + setMAXScriptValue(ref, "diffuse", 0, diffuse ); + setMAXScriptValue(ref, "specular", 0, specular ); + setMAXScriptValue(ref, "emittance", 0, emittance ); + setMAXScriptValue(ref, "shininess", 0, shininess ); + setMAXScriptValue(ref, "alpha", 0, alpha ); + } + if (NiShadePropertyRef shadeRef = SelectFirstObjectOfType<NiShadeProperty>(props)) { + if (shadeRef->GetFlags() & 1){ + mtl->SetFaceted(TRUE); + } + } + if (NiWireframePropertyRef wireRef = SelectFirstObjectOfType<NiWireframeProperty>(props)) { + if (wireRef->GetFlags() & 1){ + mtl->SetWire(TRUE); + } + } + if (NiStencilPropertyRef stencilRef = SelectFirstObjectOfType<NiStencilProperty>(props)) { + mtl->SetTwoSided(TRUE); + } + bool Dither = false; + bool SpecularEnable = false; + if (NiDitherPropertyRef ditherRef = SelectFirstObjectOfType<NiDitherProperty>(props)) { + Dither = (ditherRef->GetFlags() & 1) ? true : false; + } + if (NiSpecularPropertyRef specRef = SelectFirstObjectOfType<NiSpecularProperty>(props)) { + SpecularEnable = (specRef->GetFlags() & 1) ? true : false; + } + setMAXScriptValue(ref, "Dither", 0, Dither ); + setMAXScriptValue(ref, "SpecularEnable", 0, SpecularEnable); + + if (NiVertexColorPropertyRef vertexColor = SelectFirstObjectOfType<NiVertexColorProperty>(props)) { + int SrcVertexMode = vertexColor->GetVertexMode(); + int LightingMode = vertexColor->GetLightingMode(); + bool VertexColorsEnable = true; + setMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable); + setMAXScriptValue(ref, "SourceVertexMode", 0, SrcVertexMode); + setMAXScriptValue(ref, "LightingMode", 0, LightingMode); + } else { + bool VertexColorsEnable = false; + setMAXScriptValue(ref, "Vertex_Color_Enable", 0, VertexColorsEnable); + } + if (NiAlphaPropertyRef alphaRef = SelectFirstObjectOfType<NiAlphaProperty>(props)) { + int TestRef = alphaRef->GetAlphaTestThreshold(); + int srcBlend = alphaRef->GetSourceBlendMode(); + int destBlend = alphaRef->GetDestBlendMode(); + int TestMode = alphaRef->GetTestMode(); + bool AlphaTestEnable = alphaRef->GetAlphaTest(); + bool NoSorter = !alphaRef->GetAlphaSort(); + bool alphaBlend = alphaRef->GetAlphaBlend(); + int alphaMode = 1; + + if (!alphaBlend) { + alphaMode = 1; // none + } else if (srcBlend == NiAlphaProperty::BM_SRC_ALPHA && destBlend == NiAlphaProperty::BM_ONE_MINUS_SRC_ALPHA) { + alphaMode = 0; // standard or automatic? + } else if (srcBlend == NiAlphaProperty::BM_ONE && destBlend == NiAlphaProperty::BM_ONE) { + alphaMode = 3; + } else if (srcBlend == NiAlphaProperty::BM_ZERO && destBlend == NiAlphaProperty::BM_SRC_COLOR) { + alphaMode = 4; + } else { + alphaMode = 5; + } + setMAXScriptValue(ref, "AlphaTestEnable", 0, AlphaTestEnable ); + setMAXScriptValue(ref, "alphaMode", 0, alphaMode); + setMAXScriptValue(ref, "srcBlend", 0, srcBlend); + setMAXScriptValue(ref, "destBlend", 0, destBlend); + setMAXScriptValue(ref, "NoSorter", 0, NoSorter); + setMAXScriptValue(ref, "TestRef", 0, TestRef ); + setMAXScriptValue(ref, "TestMode", 0, TestMode ); + } + if (NiTexturingPropertyRef texRef = SelectFirstObjectOfType<NiTexturingProperty>(props)) { + Matrix22 m2 = texRef->GetBumpMapMatrix(); + float Magnitude = (m2[0][0] + m2[1][1]) / 2.0f; + float LumaScale = texRef->GetLumaScale(); + float LumaOffset = texRef->GetLumaOffset(); + int ApplyMode = texRef->GetApplyMode(); + + setMAXScriptValue(ref, "Bump_Map_Magnitude", 0, Magnitude); + setMAXScriptValue(ref, "Bump_Map_Luma_Scale", 0, LumaScale); + setMAXScriptValue(ref, "Bump_Map_Luma_offset", 0, LumaOffset); + setMAXScriptValue(ref, "ApplyMode", 0, ApplyMode); + + int ntex = mtl->NumSubTexmaps(); + if (ntex > 0) + { + ntex = min(ntex, 7); + TexType texmap[] = {BASE_MAP, DARK_MAP, DETAIL_MAP, DECAL_0_MAP, BUMP_MAP, GLOSS_MAP, GLOW_MAP, DECAL_1_MAP}; + NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>(); + texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode)); + texProp->SetTextureCount(7); + for (int i = 0; i < ntex; ++i) { + TexType textype = texmap[i]; + if (texRef->HasTexture(textype)){ + if (Texmap* tex = CreateTexture(texRef->GetTexture(textype))) { + mtl->SetSubTexmap(i, tex); + } + } + } + } + } + return true; +} + + string NifImporter::FindImage(const string& name) { TCHAR buffer[MAX_PATH]; // Simply check for fully qualified path - if (PathIsRoot(name.c_str())) { + if (!PathIsRelative(name.c_str())) { if (-1 != _taccess(name.c_str(), 0)) return string(buffer); } @@ -138,4 +333,6 @@ string NifImporter::FindImage(const string& name) return appSettings->FindImage(name); } return name; -} \ No newline at end of file +} + + diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index 885d930..dfc2eb0 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -611,10 +611,7 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) else if (bone = CreateBone(name, p, pp, zAxis)) { PosRotScaleNode(bone, p, q, scale, prs); - if (isDummy) - bone->Hide(TRUE); - else - bone->Hide(node->GetHidden() ? TRUE : FALSE); + bone->Hide(node->GetHidden() ? TRUE : FALSE); } if (bone) { diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp index 40f861f..9af93ff 100644 --- a/NifImport/MaxNifImport.cpp +++ b/NifImport/MaxNifImport.cpp @@ -64,44 +64,6 @@ class MaxNifImportClassDesc : public ClassDesc2 { static MaxNifImportClassDesc MaxNifImportDesc; ClassDesc2* GetMaxNifImportDesc() { return &MaxNifImportDesc; } -BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { - static NifImporter *imp = NULL; - - switch(message) { - case WM_INITDIALOG: - { - imp = (NifImporter *)lParam; - CenterWindow(hWnd,GetParent(hWnd)); - - char buffer[33] = {0}; - sprintf(buffer, "%f", imp->bipedHeight); - SetWindowText(GetDlgItem(hWnd, IDC_EDITHEIGHT), buffer); - } - return TRUE; - - case WM_CLOSE: - { - char buffer[33] = {0}, *end = NULL; - GetWindowText(GetDlgItem(hWnd, IDC_EDITHEIGHT), buffer, 33); - imp->bipedHeight = strtod(buffer, &end); - EndDialog(hWnd, 0); - } - return TRUE; - - case WM_COMMAND : - { - switch (wParam) - { - case IDCLOSE : - SendMessage(hWnd, WM_CLOSE, 0, 0); - return TRUE; - } - } - break; - } - return FALSE; -} - //--- MaxNifImport ------------------------------------------------------- MaxNifImport::MaxNifImport() diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index 06f8df2..639490e 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -26,14 +26,34 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_PANEL DIALOGEX 0, 0, 142, 59 +IDD_PANEL DIALOGEX 0, 0, 206, 158 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Import Nif" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - EDITTEXT IDC_EDITHEIGHT,68,15,62,14,ES_AUTOHSCROLL - LTEXT "&Height:",IDC_STATIC,16,18,49,8 - PUSHBUTTON "&Close",IDCLOSE,44,38,50,14 + GROUPBOX "Import:",IDC_STATIC,7,6,81,81 + CONTROL "&Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,16,67,10 + CONTROL "Skin Modifier",IDC_CHK_SKIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,27,67,10 + CONTROL "&Vertex Colors",IDC_CHK_VCOLORS,"Button",BS_AUTO3STATE | WS_TABSTOP,14,38,67,10 + CONTROL "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,62,67,10 + CONTROL "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,50,67,10 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,73,67,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,81 + CONTROL "Flip UV",IDC_CHK_FLIP_UV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,16,88,10 + CONTROL "&Render Textures in View",IDC_CHK_SHOW_TEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,27,88,10 + CONTROL "&Auto Smooth Mesh",IDC_CHK_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,38,88,11 + CONTROL "Remove Illegal Faces",IDC_CHK_ILLEGAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,50,88,11 + CONTROL "Remove Unused Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,62,88,10 + CONTROL "&Use Biped",IDC_CHK_BIPED,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,102,73,87,10 + LTEXT "Skeleton:",IDC_STC_SKELETON,7,107,31,8 + EDITTEXT IDC_ED_SKELETON,7,119,171,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BTN_BROWSE,180,119,19,13 + LTEXT "Game:",IDC_STATIC,7,93,31,8 + COMBOBOX IDC_CB_GAME,47,91,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "&Import",IDOK,5,137,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,137,33,14 + LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,93,137,95,14,SS_NOTIFY | SS_CENTERIMAGE END @@ -48,9 +68,9 @@ BEGIN IDD_PANEL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 135 + RIGHTMARGIN, 199 TOPMARGIN, 7 - BOTTOMMARGIN, 52 + BOTTOMMARGIN, 151 END END #endif // APSTUDIO_INVOKED @@ -88,8 +108,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,6,8 - PRODUCTVERSION 0,1,6,0 + FILEVERSION 0,2,0,0 + PRODUCTVERSION 0,2,0,0 FILEFLAGSMASK 0x37L #ifdef _DEBUG FILEFLAGS 0x21L @@ -105,12 +125,12 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "3ds Max Nif Importer" - VALUE "FileVersion", "0, 1, 6, 8" + VALUE "FileVersion", "0, 2, 0, 0" VALUE "InternalName", "MaxNifImport.dli" VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved." VALUE "OriginalFilename", "MaxNifImport.dli" VALUE "ProductName", "3ds Max Nif Importer" - VALUE "ProductVersion", "0, 1, 6, 0" + VALUE "ProductVersion", "0, 2, 0, 0" VALUE "SpecialBuild", "Alpha" END END diff --git a/NifImport/MaxNifImport_VC80.vcproj b/NifImport/MaxNifImport_VC80.vcproj index d05d46e..245bcbb 100644 --- a/NifImport/MaxNifImport_VC80.vcproj +++ b/NifImport/MaxNifImport_VC80.vcproj @@ -695,10 +695,6 @@ RelativePath=".\KFImporter.h" > </File> - <File - RelativePath=".\objectParams.h" - > - </File> <File RelativePath=".\resource.h" > @@ -788,6 +784,10 @@ RelativePath=".\MaxNifImport.h" > </File> + <File + RelativePath=".\NifDialog.cpp" + > + </File> <File RelativePath=".\NIFImport.cpp" > diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index b8f9dc9..c728fed 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -72,7 +72,7 @@ void NifImporter::Initialize() hasSkeleton = HasSkeleton(); isBiped = IsBiped(); - skeleton = (appSettings != NULL) ? appSettings->Skeleton : ""; + skeleton = GetSkeleton(appSettings); importSkeleton = (appSettings != NULL) ? appSettings->useSkeleton : false; importSkeleton &= hasSkeleton; @@ -89,6 +89,22 @@ void NifImporter::Initialize() } } +string NifImporter::GetSkeleton(AppSettings *appSettings) +{ + string skeleton = (appSettings != NULL) ? appSettings->Skeleton : ""; + // Guess that the skeleton is the same one in the current directory + if (importSkeleton && !defaultSkeletonName.empty()) { + TCHAR buffer[MAX_PATH]; + GetFullPathName(name.c_str(), _countof(buffer), buffer, NULL); + PathRemoveFileSpec(buffer); + PathAddBackslash(buffer); + PathAppend(buffer, defaultSkeletonName.c_str()); + if (-1 != _taccess(buffer, 0)) + skeleton = buffer; + } + return skeleton; +} + void NifImporter::LoadIniSettings() { TCHAR iniName[MAX_PATH]; @@ -127,6 +143,7 @@ void NifImporter::LoadIniSettings() enableSkinSupport = GetIniValue(NifImportSection, "EnableSkinSupport", true); enableCollision = GetIniValue(NifImportSection, "EnableCollision", true); vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1); + useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true); // Biped importBones = GetIniValue(BipedImportSection, "ImportBones", true); @@ -154,7 +171,10 @@ void NifImporter::LoadIniSettings() // Collision bhkScaleFactor = GetIniValue<float>(CollisionSection, "bhkScaleFactor", 7.0f); - + ApplyAppSettings(); +} +void NifImporter::ApplyAppSettings() +{ goToSkeletonBindPosition = false; // Override specific settings if (appSettings) { @@ -170,14 +190,22 @@ void NifImporter::LoadIniSettings() void NifImporter::SaveIniSettings() { - //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); + SetIniValue(NifImportSection, "UseBiped", useBiped); + SetIniValue(NifImportSection, "EnableSkinSupport", enableSkinSupport); + SetIniValue(NifImportSection, "VertexColorMode", vertexColorMode); + SetIniValue(NifImportSection, "EnableCollision", enableCollision); + //SetIniValue(NifImportSection, "EnableFurniture", enableAnimations); + + SetIniValue(NifImportSection, "FlipUVTextures", flipUVTextures); + SetIniValue(NifImportSection, "ShowTextures", showTextures); + SetIniValue(NifImportSection, "EnableAutoSmooth", enableAutoSmooth); + SetIniValue(NifImportSection, "RemoveIllegalFaces", removeIllegalFaces); + SetIniValue(NifImportSection, "RemoveDegenerateFaces", removeDegenerateFaces); + + SetIniValue(BipedImportSection, "ImportBones", importBones); + SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); + + SetIniValue(AnimImportSection, "EnableAnimations", enableAnimations); } INode *NifImporter::GetNode(Niflib::NiNodeRef node) @@ -190,39 +218,48 @@ INode *NifImporter::GetNode(Niflib::NiNodeRef node) bool NifImporter::DoImport() { bool ok = true; + if (!suppressPrompts) + { + if (!ShowDialog()) + return true; + + ApplyAppSettings(); + SaveIniSettings(); + } + vector<string> importedBones; if (!isBiped && importSkeleton && importBones) { - if (browseForSkeleton) - { - TCHAR filter[64], *pfilter=filter; - pfilter = _tcscpy(filter, shortDescription.c_str()); - pfilter = _tcscat(pfilter, " (*.NIF)"); - pfilter += strlen(pfilter); - *pfilter++ = '\0'; - _tcscpy(pfilter, "*.NIF"); - pfilter += strlen(pfilter); - *pfilter++ = '\0'; - *pfilter++ = '\0'; - - TCHAR filename[MAX_PATH]; - GetFullPathName(skeleton.c_str(), _countof(filename), filename, NULL); - - OPENFILENAME ofn; - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = gi->GetMAXHWnd(); - ofn.lpstrFilter = filter; - ofn.lpstrFile = filename; - ofn.nMaxFile = _countof(filename); - ofn.lpstrTitle = TEXT("Browse for Skeleton NIF..."); - ofn.lpstrDefExt = TEXT("NIF"); - ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST; - importSkeleton = GetOpenFileName(&ofn) ? true : false; - if (importSkeleton) { - skeleton = filename; - } - } + //if (browseForSkeleton) + //{ + // TCHAR filter[64], *pfilter=filter; + // pfilter = _tcscpy(filter, shortDescription.c_str()); + // pfilter = _tcscat(pfilter, " (*.NIF)"); + // pfilter += strlen(pfilter); + // *pfilter++ = '\0'; + // _tcscpy(pfilter, "*.NIF"); + // pfilter += strlen(pfilter); + // *pfilter++ = '\0'; + // *pfilter++ = '\0'; + + // TCHAR filename[MAX_PATH]; + // GetFullPathName(skeleton.c_str(), _countof(filename), filename, NULL); + + // OPENFILENAME ofn; + // memset(&ofn, 0, sizeof(ofn)); + // ofn.lStructSize = sizeof(ofn); + // ofn.hwndOwner = gi->GetMAXHWnd(); + // ofn.lpstrFilter = filter; + // ofn.lpstrFile = filename; + // ofn.nMaxFile = _countof(filename); + // ofn.lpstrTitle = TEXT("Browse for Skeleton NIF..."); + // ofn.lpstrDefExt = TEXT("NIF"); + // ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST; + // importSkeleton = GetOpenFileName(&ofn) ? true : false; + // if (importSkeleton) { + // skeleton = filename; + // } + //} if (importSkeleton && !skeleton.empty()) { NifImporter skelImport(skeleton.c_str(), i, gi, suppressPrompts); if (skelImport.isValid()) @@ -233,7 +270,7 @@ bool NifImporter::DoImport() // Disable undesirable skeleton items skelImport.enableCollision = false; skelImport.enableAnimations = false; - + skelImport.suppressPrompts = true; skelImport.DoImport(); if (!skelImport.useBiped && removeUnusedImportedBones) importedBones = GetNamesOfNodes(skelImport.nodes); diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index c15cbf1..4f61b1d 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -15,8 +15,10 @@ HISTORY: #define __NIFIMPORTER_H__ #include "BaseImporter.h" +#include "IniSection.h" + // NIF Importer -class NifImporter : public BaseImporter +class NifImporter : public BaseImporter//, public IniFileSection { public: // Ini settings @@ -30,6 +32,7 @@ public: bool goToSkeletonBindPosition; bool enableCollision; int vertexColorMode; + bool useCiv4Shader; // Biped/Bones related settings bool importBones; @@ -77,6 +80,8 @@ public: void LoadIniSettings(); void SaveIniSettings(); + void ApplyAppSettings(); + bool HasSkeleton(); bool IsBiped(); void ImportBones(vector<Niflib::NiNodeRef>& bones); @@ -92,6 +97,7 @@ public: bool ImportMesh(Niflib::NiTriShapeRef triShape); bool ImportMesh(Niflib::NiTriStripsRef triStrips); bool ImportMaterialAndTextures(ImpNode *node, Niflib::NiAVObjectRef avObject); + bool ImportCiv4Shader(ImpNode *node, Niflib::NiAVObjectRef avObject, StdMat2 *m); bool ImportTransform(ImpNode *node, Niflib::NiAVObjectRef avObject); 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); @@ -105,7 +111,9 @@ public: bool ImportCollision(Niflib::NiNodeRef node); INode *GetNode(Niflib::NiNodeRef node); + string GetSkeleton(AppSettings *appSettings); + bool ShowDialog(); virtual bool DoImport(); // Animation Helpers diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp new file mode 100644 index 0000000..8294625 --- /dev/null +++ b/NifImport/NifDialog.cpp @@ -0,0 +1,187 @@ +/********************************************************************** +*< +FILE: ImporterCore.cpp + +DESCRIPTION: Core Import helper routines + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#include "stdafx.h" +#include "MaxNifImport.h" +#include "resource.h" +#include "shellapi.h" + +using namespace Niflib; + +BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { + static NifImporter *imp = NULL; + static DWORD dlgRes = IDCANCEL; + + switch(message) { + case WM_INITDIALOG: + { + dlgRes = IDCANCEL; + + // Append file version to dialog + TSTR version = GetFileVersion(NULL); + if (!version.isNull()) { + char buffer[256]; + GetWindowText(hWnd, buffer, _countof(buffer)); + _tcscat(buffer, TEXT(" ")); + _tcscat(buffer, version); + SetWindowText(hWnd, buffer); + } + + imp = (NifImporter *)lParam; + CenterWindow(hWnd,GetParent(hWnd)); + + CheckDlgButton(hWnd, IDC_CHK_BONES, imp->importBones); + CheckDlgButton(hWnd, IDC_CHK_SKIN, imp->enableSkinSupport); + CheckDlgButton(hWnd, IDC_CHK_VCOLORS, imp->vertexColorMode); + CheckDlgButton(hWnd, IDC_CHK_COLL, imp->enableCollision); + CheckDlgButton(hWnd, IDC_CHK_ANIMATION, imp->enableAnimations); + //CheckDlgButton(hWnd, IDC_CHK_FURN, imp->); + + CheckDlgButton(hWnd, IDC_CHK_FLIP_UV, imp->flipUVTextures); + CheckDlgButton(hWnd, IDC_CHK_SHOW_TEX, imp->showTextures); + CheckDlgButton(hWnd, IDC_CHK_AUTOSMOOTH, imp->enableAutoSmooth); + CheckDlgButton(hWnd, IDC_CHK_ILLEGAL, imp->removeIllegalFaces); + CheckDlgButton(hWnd, IDC_CHK_REM_BONES, imp->removeUnusedImportedBones); + CheckDlgButton(hWnd, IDC_CHK_BIPED, imp->useBiped); + + string selection = (imp->appSettings) ? imp->appSettings->Name : "User"; + for (AppSettingsMap::iterator itr = TheAppSettings.begin(), end = TheAppSettings.end(); itr != end; ++itr) + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_ADDSTRING, 0, LPARAM(itr->Name.c_str())); + SendDlgItemMessage(hWnd, IDC_CB_GAME, CB_SELECTSTRING, WPARAM(-1), LPARAM(selection.c_str())); + + SHAutoComplete(GetDlgItem(hWnd, IDC_ED_SKELETON), SHACF_FILESYSTEM); + if (imp->HasSkeleton() && imp->appSettings && imp->importSkeleton) { + SetDlgItemText(hWnd, IDC_ED_SKELETON, imp->skeleton.c_str()); + } else { + EnableWindow(GetDlgItem(hWnd, IDC_STC_SKELETON), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_ED_SKELETON), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_BTN_BROWSE), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_CHK_BIPED), FALSE); + EnableWindow(GetDlgItem(hWnd, IDC_CHK_REM_BONES), FALSE); + } + } + return TRUE; + + case WM_CLOSE: + { + EndDialog(hWnd, dlgRes); + } + return TRUE; + + case WM_COMMAND : + { + if (HIWORD(wParam) == BN_CLICKED) + { + char tmp[MAX_PATH]; + switch (LOWORD(wParam)) + { + case IDOK: + + imp->importBones = IsDlgButtonChecked(hWnd, IDC_CHK_BONES) ? true : false; + imp->enableSkinSupport = IsDlgButtonChecked(hWnd, IDC_CHK_SKIN) ? true : false; + imp->vertexColorMode = (int)IsDlgButtonChecked(hWnd, IDC_CHK_VCOLORS); + imp->enableCollision = IsDlgButtonChecked(hWnd, IDC_CHK_COLL) ? true : false; + imp->enableAnimations = IsDlgButtonChecked(hWnd, IDC_CHK_ANIMATION) ? true : false; + //IsDlgButtonChecked(hWnd, IDC_CHK_FURN, imp->); + + imp->flipUVTextures = IsDlgButtonChecked(hWnd, IDC_CHK_FLIP_UV) ? true : false; + imp->showTextures = IsDlgButtonChecked(hWnd, IDC_CHK_SHOW_TEX) ? true : false; + imp->enableAutoSmooth = IsDlgButtonChecked(hWnd, IDC_CHK_AUTOSMOOTH) ? true : false; + imp->removeDegenerateFaces = + imp->removeIllegalFaces = IsDlgButtonChecked(hWnd, IDC_CHK_ILLEGAL) ? true : false; + imp->removeUnusedImportedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES) ? true : false; + imp->useBiped = IsDlgButtonChecked(hWnd, IDC_CHK_BIPED) ? true : false; + + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) { + imp->appSettings = appSettings; + } + + GetDlgItemText(hWnd, IDC_ED_SKELETON, tmp, MAX_PATH); + imp->skeleton = tmp; + + EndDialog(hWnd, dlgRes=IDOK); + return TRUE; + + case IDCANCEL: + EndDialog(hWnd, dlgRes=IDCANCEL); + return TRUE; + + case IDC_BTN_BROWSE: + { + TCHAR filter[64], *pfilter=filter; + pfilter = _tcscpy(filter, shortDescription.c_str()); + pfilter = _tcscat(pfilter, " (*.NIF)"); + pfilter += strlen(pfilter); + *pfilter++ = '\0'; + _tcscpy(pfilter, "*.NIF"); + pfilter += strlen(pfilter); + *pfilter++ = '\0'; + *pfilter++ = '\0'; + + GetDlgItemText(hWnd, IDC_ED_SKELETON, tmp, MAX_PATH); + GetLongPathName(tmp, tmp, _countof(tmp)); + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = imp->gi->GetMAXHWnd(); + ofn.lpstrFilter = filter; + ofn.lpstrFile = tmp; + ofn.nMaxFile = _countof(tmp); + ofn.lpstrTitle = TEXT("Browse for Skeleton NIF..."); + ofn.lpstrDefExt = TEXT("NIF"); + ofn.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_NOCHANGEDIR|OFN_PATHMUSTEXIST; + if (GetOpenFileName(&ofn)) { + SetDlgItemText(hWnd, IDC_ED_SKELETON, tmp); + } + } + break; + } + } + else if (HIWORD(wParam) == STN_CLICKED) + { + if (LOWORD(wParam) == IDC_LBL_LINK) + { + ShellExecute(hWnd, "open", "http://niftools.sourceforge.net", + NULL, NULL, SW_SHOWDEFAULT); + } + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + if (LOWORD(wParam) == IDC_CB_GAME) + { + char tmp[MAX_PATH]; + GetDlgItemText(hWnd, IDC_CB_GAME, tmp, MAX_PATH); + if (AppSettings *appSettings = FindAppSetting(tmp)) + { + string skeleton = imp->GetSkeleton(appSettings); + BOOL enable = imp->HasSkeleton() ? TRUE : FALSE; + if (enable) { + SetDlgItemText(hWnd, IDC_ED_SKELETON, skeleton.c_str()); + } + EnableWindow(GetDlgItem(hWnd, IDC_STC_SKELETON), enable); + EnableWindow(GetDlgItem(hWnd, IDC_ED_SKELETON), enable); + EnableWindow(GetDlgItem(hWnd, IDC_BTN_BROWSE), enable); + } + } + } + } + break; + } + return FALSE; +} + +bool NifImporter::ShowDialog() +{ + return (IDOK == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), MaxNifImportOptionsDlgProc, (LPARAM)this)); +} \ No newline at end of file diff --git a/NifImport/objectParams.h b/NifImport/objectParams.h deleted file mode 100644 index 23a45f4..0000000 --- a/NifImport/objectParams.h +++ /dev/null @@ -1,339 +0,0 @@ -/*===========================================================================*\ - | - | FILE: objectParams.h - | Skeleton project and code for a Utility - | 3D Studio MAX R3.0 - | - | AUTH: Cleve Ard - | Render Group - | Copyright(c) Discreet 2000 - | - | HIST: Started 9-8-00 - | -\*===========================================================================*/ - -#ifndef _OBJECTPARAMS_H_ -#define _OBJECTPARAMS_H_ - -#include "maxscrpt/maxscrpt.h" -#include "maxscrpt/Numbers.h" -#include "maxscrpt/Name.h" -#include "maxscrpt/ColorVal.h" -#include "maxscrpt/MAXObj.h" -#include "assert1.h" - -template <class T> -class ConvertMAXScriptToC; -inline Value* make_maxscript_value(bool v); -inline Value* make_maxscript_value(int v); -inline Value* make_maxscript_value(float v); -inline Value* make_maxscript_value(COLORREF rgb); -inline Value* make_maxscript_value(const Color& rgb); -inline Value* make_maxscript_value(LPCTSTR str); -inline Value* make_maxscript_value(ReferenceTarget* rtarg); - -#if VERSION_3DSMAX <= ((MAX_RELEASE_R7<<16)+(15<<8)+0) -inline void clear_error_source_data() {} -#endif - -// Not all of the paramters for materials and shaders -// are published in the interfaces. ObjectParams class -// is used to access the properties of objects the same -// way the scriptor does, so you can get to properties. - -// Set the array parameter named name to the value at time t. -template<class T> -bool setMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T value, int tabIndex) -{ - bool rval = false; // Return false if fails - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - two_value_locals(prop, result); // Keep two local variables - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name of the parameter and then retrieve - // the array holding the value we want to set. - vl.prop = Name::intern(name); - vl.result = MAXWrapper::get_property(obj, vl.prop, NULL); - - // Make sure it is the right type. - if (vl.result != NULL && vl.result->tag == class_tag(MAXPB2ArrayParam)) { - // OK. Now we make sure the tabIndex is within the array bounds. - MAXPB2ArrayParam* array = static_cast<MAXPB2ArrayParam*>(vl.result); - if (array->pblock != NULL && array->pdef != NULL - && tabIndex >= 0 && tabIndex < array->pblock->Count(array->pdef->ID)) { - // Set the value in the array. - array->pblock->SetValue(array->pdef->ID, 0, value, tabIndex); - rval = true; // Succeeded - } - } - } catch ( ... ) { - // Failed. - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// Set the parameter. Cannot be an array entry -template<class T> -bool setMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value) -{ - bool rval = false; // return false if fails - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - two_value_locals(prop, val); // Keep two local variables - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name and value to set - vl.prop = Name::intern(name); - vl.val = make_maxscript_value(value); - - // Set the value. - Value* val = MAXWrapper::set_property(obj, vl.prop, vl.val); - if (val != NULL) - rval = true; // Succeeded - } catch ( ... ) { - // Failed. - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// Get the parameter from an array -template<class T> -bool getMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value, int tabIndex) -{ - bool rval = false; // Return false if fails - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - two_value_locals(prop, result); // Keep two local variables - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name and the array holding the roperty. - vl.prop = Name::intern(name); - vl.result = MAXWrapper::get_property(obj, vl.prop, NULL); - - // Make sure it is they right type. - if (vl.result != NULL && is_tab_param(vl.result)) { - // OK. Now we make sure the tabIndex is within the array bounds. - MAXPB2ArrayParam* array = static_cast<MAXPB2ArrayParam*>(vl.result); - if (array->pblock != NULL && array->pdef != NULL - && tabIndex >= 0 && tabIndex < array->pblock->Count(array->pdef->ID)) { - // Good. Get the value - array->pblock->GetValue(array->pdef->ID, 0, value, Interval(0,0), tabIndex); - rval = true; // Succeeded - } - } - } catch ( ... ) { - // Failed. - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// Get the parameter -template<class T> -bool getMAXScriptValue(ReferenceTarget* obj, LPTSTR name, TimeValue t, T& value) -{ - bool rval = false; // Return false if fails - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - two_value_locals(prop, result); // Keep two local varaibles - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name and the parameter value - vl.prop = Name::intern(name); - vl.result = MAXWrapper::get_property(obj, vl.prop, NULL); - - // Make sure it is valid. - if (vl.result != NULL && vl.result != &undefined && vl.result != &unsupplied) { - // Convert to C++ type. - value = ConvertMAXScriptToC<T>::cvt(vl.result); - rval = true; // Succeeded - } - } catch ( ... ) { - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// Get the parameter controller -inline Control* getMAXScriptController(ReferenceTarget* obj, LPTSTR name, ParamDimension*& dim) -{ - Control* rval = NULL; - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - one_value_local(prop); // Keep one local varaibles - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name and the parameter value - vl.prop = Name::intern(name); - rval = MAXWrapper::get_max_prop_controller(obj, vl.prop, &dim); - } catch ( ... ) { - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// Set the parameter controller -inline bool setMAXScriptController(ReferenceTarget* obj, LPTSTR name, Control* control, ParamDimension* dim) -{ - bool rval = false; - assert(obj != NULL); - init_thread_locals(); - push_alloc_frame(); - two_value_locals(prop, maxControl); // Keep two local varaibles - save_current_frames(); - trace_back_active = FALSE; - - try { - // Get the name and the parameter value - vl.prop = Name::intern(name); - vl.maxControl = MAXControl::intern(control, dim); - rval = MAXWrapper::set_max_prop_controller(obj, vl.prop, - static_cast<MAXControl*>(vl.maxControl)) != 0; - } catch ( ... ) { - clear_error_source_data(); - restore_current_frames(); - MAXScript_signals = 0; - if (progress_bar_up) - MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; - } - pop_value_locals(); - pop_alloc_frame(); - return rval; -} - -// These helpers are used to convert C++ values to -// their MAXScript value. Maxscript uses different -// methods to handle the conversion, and these helpers -// allow the conversion to be templated. You may need -// to add more converter, if you need to access other -// parameter types. -inline Value* make_maxscript_value(bool v) -{ - return_protected(v ? &true_value : &false_value); -} - -inline Value* make_maxscript_value(int v) -{ - return_protected(Integer::intern(v)); -} - -inline Value* make_maxscript_value(float v) -{ - return_protected(Float::intern(v)); -} - -inline Value* make_maxscript_value(COLORREF rgb) -{ - return new ColorValue(rgb); -} - -inline Value* make_maxscript_value(const Color& rgb) -{ - return new ColorValue(rgb); -} - -inline Value* make_maxscript_value(LPCTSTR str) -{ - return Name::intern(const_cast<LPTSTR>(str)); -} - -inline Value* make_maxscript_value(ReferenceTarget* rtarg) -{ - return MAXClass::make_wrapper_for(rtarg); -} - -// These helpers convert MAXScript values to C++ values. -// MAXScript uses different methods for this conversion, -// and these helpers template the conversion. You will -// need to add more converters if you need more types. -template <class T> -class ConvertMAXScriptToC { -public: - static T cvt(Value* val); -}; - -inline bool ConvertMAXScriptToC<bool>::cvt(Value* val) -{ - return val->to_bool() != 0; -} - -inline int ConvertMAXScriptToC<int>::cvt(Value* val) -{ - return val->to_int(); -} - -inline float ConvertMAXScriptToC<float>::cvt(Value* val) -{ - return val->to_float(); -} - -inline Color ConvertMAXScriptToC<Color>::cvt(Value* val) -{ - return val->to_point3(); -} - -inline LPTSTR ConvertMAXScriptToC<LPTSTR>::cvt(Value* val) -{ - return val->to_string(); -} - -inline Texmap* ConvertMAXScriptToC<Texmap*>::cvt(Value* val) -{ - return val->to_texmap(); -} - -inline ReferenceTarget* ConvertMAXScriptToC<ReferenceTarget*>::cvt(Value* val) -{ - return val->to_reftarg(); -} - - -#endif diff --git a/NifImport/resource.h b/NifImport/resource.h index 01805df..6c53f31 100644 --- a/NifImport/resource.h +++ b/NifImport/resource.h @@ -12,9 +12,25 @@ #define IDC_DOSTUFF 1000 #define IDC_EDITHEIGHT 1001 #define IDC_BUTTON1 1002 -#define IDC_COLOR 1456 -#define IDC_EDIT 1490 -#define IDC_SPIN 1496 +#define IDC_BTN_BROWSE 1002 +#define IDC_CHK_BONES 1003 +#define IDC_CHK_FLIP_UV 1004 +#define IDC_CHK_FURN 1005 +#define IDC_ED_SKELETON 1006 +#define IDC_CHK_BIPED 1007 +#define IDC_CHK_COLL 1010 +#define IDC_LBL_LINK 1011 +#define IDC_CHK_VCOLORS 1012 +#define IDC_CHK_SHOW_TEX 1013 +#define IDC_CB_GAME 1014 +#define IDC_CB_USER_VERSION 1016 +#define IDC_CHK_SKIN 1017 +#define IDC_CHK_ANIMATION 1018 +#define IDC_CHK_AUTOSMOOTH 1019 +#define IDC_CHK_ILLEGAL 1020 +#define IDC_STC_SKELETON 1021 +#define IDC_CHK_REM_BONES 1022 + // Next default values for new objects // diff --git a/NifPlugins_VC80.sln b/NifPlugins_VC80.sln index b3f9085..b1ec78f 100644 --- a/NifPlugins_VC80.sln +++ b/NifPlugins_VC80.sln @@ -30,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject MaxNifPlugins_Readme.txt = MaxNifPlugins_Readme.txt MaxNifTools.ini = MaxNifTools.ini + ..\docsys\nif.xml = ..\docsys\nif.xml NifPlugins_Development_Readme.txt = NifPlugins_Development_Readme.txt EndProjectSection EndProject -- GitLab