From 0cc5fc7fd512c5b5a371d06dc2ae3cc9bc8a897c Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 10 Sep 2006 00:58:34 +0000 Subject: [PATCH] 0.2.3 ----- o Exporter - Fix issue when exporting a mesh with a skin modifier that had bones that were not used. - Fix bug with normals introduced in 0.2.2 when fixing previous problem - Changed code to scale the mesh so that Reset XForm is not required - Added support for Bone LOD code. Works with Civ4 Bone LOD Manager. - Added support for Lights and Cameras o Importer - Alter code to create Camera nodes when name begins with Camera. - Initial pass at Lights - Fixed issues with skin modifier on Civ4 Units and Leaderheads - Added support for Bone LOD code. Works with Civ4 Bone LOD Manager. - Added support for Lights and Cameras - Fixed issues with Textures with muliple UV Sets --- MaxNifPlugins_Readme.txt | 11 +- MaxNifTools.ini | 4 + NifCommon/AnimKey.h | 2 +- NifCommon/AppSettings.cpp | 6 + NifCommon/AppSettings.h | 2 + NifCommon/MAX_Mem.h | 1010 ++++++++++++++++++++++++++++ NifCommon/MAX_MemDirect.h | 195 ++++++ NifCommon/NifCommon_VC80.vcproj | 8 + NifCommon/niutils.cpp | 261 ++++++- NifCommon/niutils.h | 18 +- NifCommon/objectParams.h | 1 + NifExport/Animation.cpp | 2 +- NifExport/Coll.cpp | 116 ++-- NifExport/Config.cpp | 8 + NifExport/Exporter.cpp | 235 +++---- NifExport/Exporter.h | 24 +- NifExport/KfExport.cpp | 6 +- NifExport/Mesh.cpp | 317 ++++++--- NifExport/NifExport.cpp | 14 +- NifExport/NifExport.rc | 49 +- NifExport/Util.cpp | 172 ++++- NifExport/resource.h | 7 +- NifImport/ImportAnimation.cpp | 227 ++++++- NifImport/ImportLights.cpp | 116 ++++ NifImport/ImportMeshAndSkin.cpp | 24 +- NifImport/ImportSkeleton.cpp | 25 +- NifImport/KFImporter.cpp | 8 +- NifImport/KFMImporter.cpp | 26 +- NifImport/KFMImporter.h | 2 + NifImport/KfDialog.cpp | 89 +++ NifImport/MaxNifImport.cpp | 4 - NifImport/MaxNifImport.h | 1 + NifImport/MaxNifImport.rc | 55 +- NifImport/MaxNifImport_VC80.vcproj | 16 +- NifImport/NIFImport.cpp | 51 +- NifImport/NIFImporter.h | 12 +- NifImport/NifDialog.cpp | 12 +- NifImport/resource.h | 6 + NifImport/stdafx.h | 1 + 39 files changed, 2682 insertions(+), 461 deletions(-) create mode 100644 NifCommon/MAX_Mem.h create mode 100644 NifCommon/MAX_MemDirect.h create mode 100644 NifImport/ImportLights.cpp create mode 100644 NifImport/KfDialog.cpp diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index dcf265b..810cd27 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -1,4 +1,4 @@ - MaxPlugins 0.2.2 + MaxPlugins 0.2.3 ================ @@ -32,9 +32,18 @@ o Exporter - Fix issue when exporting a mesh with a skin modifier that had bones that were not used. + - Fix bug with normals introduced in 0.2.2 when fixing previous problem + - Changed code to scale the mesh so that Reset XForm is not required + - Added support for Bone LOD code. Works with Civ4 Bone LOD Manager. + - Added support for Lights and Cameras o Importer - Alter code to create Camera nodes when name begins with Camera. + - Initial pass at Lights + - Fixed issues with skin modifier on Civ4 Units and Leaderheads + - Added support for Bone LOD code. Works with Civ4 Bone LOD Manager. + - Added support for Lights and Cameras + - Fixed issues with Textures with muliple UV Sets 0.2.2 ----- diff --git a/MaxNifTools.ini b/MaxNifTools.ini index e63efe1..f7d60de 100644 --- a/MaxNifTools.ini +++ b/MaxNifTools.ini @@ -74,6 +74,10 @@ EnableCollision=1 VertexColorMode=1 ; Merge NonAccum transforms into base node. Default: 1 MergeNonAccum=1 +; Import Lights. Default: 0 +Lights=0 +; Import Cameras. Default: 0 +Cameras=0 [BipedImport] ; Top level bone import setting. Default:1 diff --git a/NifCommon/AnimKey.h b/NifCommon/AnimKey.h index cc66775..1cb3462 100644 --- a/NifCommon/AnimKey.h +++ b/NifCommon/AnimKey.h @@ -33,7 +33,7 @@ inline float FrameToTime(TimeValue t) { typedef Key<float> FloatKey; typedef Key<Quaternion> QuatKey; typedef Key<Vector3> Vector3Key; - +typedef Key<string> StringKey; template<typename T, typename U> T MapKey(U& key, float time); diff --git a/NifCommon/AppSettings.cpp b/NifCommon/AppSettings.cpp index efb8b9c..17d4fbb 100644 --- a/NifCommon/AppSettings.cpp +++ b/NifCommon/AppSettings.cpp @@ -62,6 +62,7 @@ void AppSettings::ReadSettings(string iniFile) goToSkeletonBindPosition = GetSetting<bool>("GoToSkeletonBindPosition", goToSkeletonBindPosition); disableCreateNubsForBones = GetSetting<bool>("DisableCreateNubsForBones", disableCreateNubsForBones); applyOverallTransformToSkinAndBones = GetSetting<int>("ApplyOverallTransformToSkinAndBones", -1); + textureUseFullPath = GetSetting<bool>("TextureUseFullPath", textureUseFullPath); dummyNodeMatches = TokenizeString(GetSetting<string>("DummyNodeMatches").c_str(), ";"); } @@ -144,6 +145,11 @@ bool AppSettings::IsFileInRootPaths(const std::string& fname) std::string AppSettings::GetRelativeTexPath(const std::string& fname, const std::string& prefix) { TCHAR buffer[MAX_PATH]; + if (textureUseFullPath) + { + GetFullPathName(fname.c_str(), _countof(buffer), buffer, NULL); + return string(buffer); + } if (!PathIsRelative(fname.c_str())) { TCHAR root[MAX_PATH]; diff --git a/NifCommon/AppSettings.h b/NifCommon/AppSettings.h index 3e009ee..87d93ad 100644 --- a/NifCommon/AppSettings.h +++ b/NifCommon/AppSettings.h @@ -25,6 +25,7 @@ public: , useSkeleton(false) , goToSkeletonBindPosition(true) , disableCreateNubsForBones(false) + , textureUseFullPath(false) {} std::string Name; @@ -38,6 +39,7 @@ public: bool useSkeleton; bool goToSkeletonBindPosition; bool disableCreateNubsForBones; + bool textureUseFullPath; NameValueCollection Environment; NameValueCollection imgTable; stringlist dummyNodeMatches; diff --git a/NifCommon/MAX_Mem.h b/NifCommon/MAX_Mem.h new file mode 100644 index 0000000..6cfc773 --- /dev/null +++ b/NifCommon/MAX_Mem.h @@ -0,0 +1,1010 @@ +/********************************************************************** + *< + FILE: MAX_Mem.h + + DESCRIPTION: + + CREATED BY: Michaelson Britt + + HISTORY: + + *> Copyright (c) 2002, All Rights Reserved. + **********************************************************************/ + + +#ifndef __MAX_MEM_H +#define __MAX_MEM_H + +#if (_MSC_VER >= 1300) // Visual Studio .NET + + +#include <malloc.h> +#include <new.h> +//Notes: +//- No handling for new/delete "placement form" operators +//- The Microsoft documentation claims that the functions _heapadd(), _heapchk() etc. +// are supported only under WinNT + + +//FIXME? should we wrap the header files for these functions? + + +//CodeExport void *__cdecl MAX_new_placement(size_t,void*); +//CodeExport void __cdecl MAX_delete_placement(void*,void*); + +//__forceinline void* operator new(size_t size, void* _P) +//{ +// return MAX_new_placement(size,_P); +//} + +//__forceinline void operator delete(void* memblock, void* _P) +//{ +// MAX_delete_placement(memblock,_P); +//} + +//Allocate block of memory from heap +//_CRTIMP void * __cdecl malloc(size_t); +CoreExport void * (__cdecl *MAX_malloc)(size_t); +#define malloc(size) (*MAX_malloc)(size) + +//Allocate storage for array, initializing every byte in allocated block to 0 +//_CRTIMP void * __cdecl calloc(size_t, size_t); +CoreExport void * (__cdecl *MAX_calloc)(size_t, size_t); +#define calloc(num,size) (*MAX_calloc)(num,size) + +//Reallocate block to new size +//_CRTIMP void * __cdecl realloc(void *, size_t); +CoreExport void * (__cdecl *MAX_realloc)(void *, size_t); +#define realloc(memblock,size) (*MAX_realloc)(memblock,size) + +//Expand or shrink block of memory without moving it +//_CRTIMP void * __cdecl _expand(void *, size_t); +CoreExport void * (__cdecl *MAX_expand)(void *, size_t); +#define _expand(memblock,size) (*MAX_expand)(memblock,size) + +//Free allocated block +//_CRTIMP void __cdecl free(void *); +CoreExport void (__cdecl *MAX_free)(void *); +#define free(memblock) (*MAX_free)(memblock) + +//Return size of allocated block +//_CRTIMP size_t __cdecl _msize(void *); +CoreExport size_t (__cdecl *MAX_msize)(void *); +#define _msize(memblock) (*MAX_msize)(memblock) + +// Set hook function +//_CRTIMP _HEAPHOOK __cdecl _setheaphook(_HEAPHOOK); +//CoreExport _HEAPHOOK (__cdecl *MAX_setheaphook)(_HEAPHOOK); +//Warning! Disabled because HEAPHOOK does not seem to be enabled in practice +//#define MAX_setheaphook(_HEAPHOOK) (*MAX_setheaphook)(_HEAPHOOK) + +//Add memory to heap +//_CRTIMP int __cdecl _heapadd(void *, size_t); +CoreExport int (__cdecl *MAX_heapadd)(void *, size_t); +#define _heapadd(memblock,size) (*MAX_heapadd)(memblock,size) + +//Check heap for consistency +//_CRTIMP int __cdecl _heapchk(void); +CoreExport int (__cdecl *MAX_heapchk)(void); +#define _heapchk() (*MAX_heapchk)() + +//Release unused memory in heap +//_CRTIMP int __cdecl _heapmin(void); +CoreExport int (__cdecl *MAX_heapmin)(void); +#define _heapmin() (*MAX_heapmin)() + +//Fill free heap entries with specified value +//_CRTIMP int __cdecl _heapset(unsigned int); +CoreExport int (__cdecl *MAX_heapset)(unsigned int); +#define _heapset(fill) (*MAX_heapset)(fill) + +//Return information about each entry in heap +//_CRTIMP int __cdecl _heapwalk(_HEAPINFO *); +CoreExport int (__cdecl *MAX_heapwalk)(_HEAPINFO *); +#define _heapwalk(entryinfo) (*MAX_heapwalk)(entryinfo) + +//Return address of current new handler routine as set by _set_new_handler +//_CRTIMP _PNH __cdecl _query_new_handler( void ); +CoreExport _PNH (__cdecl *MAX_query_new_handler)( void ); +#define _query_new_handler() (*MAX_query_new_handler)() + +//Enable error-handling mechanism when new operator fails (to allocate memory) and enable compilation of Standard Template Libraries (STL) +//_CRTIMP _PNH __cdecl _set_new_handler( _PNH ); +CoreExport _PNH (__cdecl *MAX_set_new_handler)( _PNH ); +#define _set_new_handler(pNewHandler) (*MAX_set_new_handler)(pNewHandler) + +//Return integer indicating new handler mode set by _set_new_mode for malloc +//_CRTIMP int __cdecl _query_new_mode( void ); +CoreExport int (__cdecl *MAX_query_new_mode)( void ); +#define _query_new_mode() (*MAX_query_new_mode)() + +//Set new handler mode for malloc +//_CRTIMP int __cdecl _set_new_mode( int ); +CoreExport int (__cdecl *MAX_set_new_mode)( int ); +#define _set_new_mode(newhandlermode) (*MAX_set_new_mode)(newhandlermode) + +//Get/Set the upper limit for the size of a memory allocation that will be supported by the small-block heap +//_CRTIMP size_t __cdecl _get_sbh_threshold(void); +//_CRTIMP int __cdecl _set_sbh_threshold(size_t); +CoreExport size_t (__cdecl *MAX_get_sbh_threshold)(void); +#define _get_sbh_threshold() (*MAX_get_sbh_threshold)() + +CoreExport int (__cdecl *MAX_set_sbh_threshold)(size_t); +#define _set_sbh_threshold(size) (*MAX_set_sbh_threshold)(size) + + +//Allocate memory from stack +//NOTE: no implementation needed. Only heap allocation causes a problem +//void * __cdecl _alloca(size_t); +//CoreExport void * __cdecl MAX_alloca(size_t); +//#define _alloca(size) MAX_alloca(size) + + + +/*** +* +* MAX_Mem wrapper for Microsoft crtdbg.h geader file +* +****/ + + +/*** +*crtdbg.h - Supports debugging features of the C runtime library. +* +* Copyright (c) 1994-2001, Microsoft Corporation. All rights reserved. +* +*Purpose: +* Support CRT debugging features. +* +* [Public] +* +****/ + +//#if (_MSC_VER >= 1300) // Visual Studio .NET + + +//#if _MSC_VER > 1000 +//#pragma once +//#endif + +#if !defined(_WIN32) +#error ERROR: Only Win32 target supported! +#endif + + + +CoreExport void *__cdecl MAX_new(size_t size); +CoreExport void __cdecl MAX_delete(void* mem); + +__forceinline void* operator new(size_t size) +{ + return MAX_new(size); +} + +__forceinline void operator delete(void* memblock) +{ + MAX_delete(memblock); +} + + + + /**************************************************************************** + * + * CRTDBG.H Support + * + ***************************************************************************/ + + +#ifdef __cplusplus +//extern "C" { +#endif /* __cplusplus */ + + /**************************************************************************** + * + * Constants and types + * + ***************************************************************************/ + +#if !defined(_W64) +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +#define _W64 __w64 +#else +#define _W64 +#endif +#endif + +#ifndef _SIZE_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 size_t; +#else +typedef _W64 unsigned int size_t; +#endif +#define _SIZE_T_DEFINED +#endif + +/* Define NULL pointer value */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + + /**************************************************************************** + * + * Debug Reporting + * + ***************************************************************************/ + +typedef void *_HFILE; /* file handle pointer */ + +#define _CRT_WARN 0 +#define _CRT_ERROR 1 +#define _CRT_ASSERT 2 +#define _CRT_ERRCNT 3 + +#define _CRTDBG_MODE_FILE 0x1 +#define _CRTDBG_MODE_DEBUG 0x2 +#define _CRTDBG_MODE_WNDW 0x4 +#define _CRTDBG_REPORT_MODE -1 + +#define _CRTDBG_INVALID_HFILE ((_HFILE)-1) +#define _CRTDBG_HFILE_ERROR ((_HFILE)-2) +#define _CRTDBG_FILE_STDOUT ((_HFILE)-4) +#define _CRTDBG_FILE_STDERR ((_HFILE)-5) +#define _CRTDBG_REPORT_FILE ((_HFILE)-6) + +typedef int (__cdecl * _CRT_REPORT_HOOK)(int, char *, int *); + +#define _CRT_RPTHOOK_INSTALL 0 +#define _CRT_RPTHOOK_REMOVE 1 + + /**************************************************************************** + * + * Heap + * + ***************************************************************************/ + + + + /**************************************************************************** + * + * Heap + * + ***************************************************************************/ + + /**************************************************************************** + * + * Client-defined allocation hook + * + ***************************************************************************/ + +#define _HOOK_ALLOC 1 +#define _HOOK_REALLOC 2 +#define _HOOK_FREE 3 + +typedef int (__cdecl * _CRT_ALLOC_HOOK)(int, void *, size_t, int, long, const unsigned char *, int); + + /**************************************************************************** + * + * Memory management + * + ***************************************************************************/ + +/* + * Bit values for _crtDbgFlag flag: + * + * These bitflags control debug heap behavior. + */ + +#define _CRTDBG_ALLOC_MEM_DF 0x01 /* Turn on debug allocation */ +#define _CRTDBG_DELAY_FREE_MEM_DF 0x02 /* Don't actually free memory */ +#define _CRTDBG_CHECK_ALWAYS_DF 0x04 /* Check heap every alloc/dealloc */ +#define _CRTDBG_RESERVED_DF 0x08 /* Reserved - do not use */ +#define _CRTDBG_CHECK_CRT_DF 0x10 /* Leak check/diff CRT blocks */ +#define _CRTDBG_LEAK_CHECK_DF 0x20 /* Leak check at program exit */ + +/* + * Some bit values for _crtDbgFlag which correspond to frequencies for checking + * the the heap. + */ +#define _CRTDBG_CHECK_EVERY_16_DF 0x00100000 /* check heap every 16 heap ops */ +#define _CRTDBG_CHECK_EVERY_128_DF 0x00800000 /* check heap every 128 heap ops */ +#define _CRTDBG_CHECK_EVERY_1024_DF 0x04000000 /* check heap every 1024 heap ops */ +#define _CRTDBG_CHECK_DEFAULT_DF _CRTDBG_CHECK_EVERY_1024_DF + +#define _CRTDBG_REPORT_FLAG -1 /* Query bitflag status */ + +#define _BLOCK_TYPE(block) (block & 0xFFFF) +#define _BLOCK_SUBTYPE(block) (block >> 16 & 0xFFFF) + + + /**************************************************************************** + * + * Memory state + * + ***************************************************************************/ + +/* Memory block identification */ +#define _FREE_BLOCK 0 +#define _NORMAL_BLOCK 1 +#define _CRT_BLOCK 2 +#define _IGNORE_BLOCK 3 +#define _CLIENT_BLOCK 4 +#define _MAX_BLOCKS 5 + +typedef void (__cdecl * _CRT_DUMP_CLIENT)(void *, size_t); + +struct _CrtMemBlockHeader; +typedef struct _CrtMemState +{ + struct _CrtMemBlockHeader * pBlockHeader; + size_t lCounts[_MAX_BLOCKS]; + size_t lSizes[_MAX_BLOCKS]; + size_t lHighWaterCount; + size_t lTotalCount; +} _CrtMemState; + + + /**************************************************************************** + * + * Declarations, prototype and function-like macros + * + ***************************************************************************/ + + +#ifndef _DEBUG + + /**************************************************************************** + * + * Debug OFF + * Debug OFF + * Debug OFF + * + ***************************************************************************/ + +#define _ASSERT(expr) ((void)0) + +#define _ASSERTE(expr) ((void)0) + + +#define _RPT0(rptno, msg) + +#define _RPT1(rptno, msg, arg1) + +#define _RPT2(rptno, msg, arg1, arg2) + +#define _RPT3(rptno, msg, arg1, arg2, arg3) + +#define _RPT4(rptno, msg, arg1, arg2, arg3, arg4) + + +#define _RPTF0(rptno, msg) + +#define _RPTF1(rptno, msg, arg1) + +#define _RPTF2(rptno, msg, arg1, arg2) + +#define _RPTF3(rptno, msg, arg1, arg2, arg3) + +#define _RPTF4(rptno, msg, arg1, arg2, arg3, arg4) + +#define _malloc_dbg(s, t, f, l) MAX_malloc(s) +#define _calloc_dbg(c, s, t, f, l) MAX_calloc(c, s) +#define _realloc_dbg(p, s, t, f, l) MAX_realloc(p, s) +#define _expand_dbg(p, s, t, f, l) MAX_expand(p, s) +#define _free_dbg(p, t) MAX_free(p) +#define _msize_dbg(p, t) MAX_msize(p) + +/* WARNING! There are no VC6 equivalents for these +#define _aligned_malloc_dbg(s, a, f, l) _aligned_malloc(s, a) +#define _aligned_realloc_dbg(p, s, a, f, l) _aligned_realloc(p, s, a) +#define _aligned_free_dbg(p) _aligned_free(p) +#define _aligned_offset_malloc_dbg(s, a, o, f, l) _aligned_offset_malloc(s, a, o) +#define _aligned_offset_realloc_dbg(p, s, a, o, f, l) _aligned_offset_realloc(p, s, a, o) +*/ + +#define _CrtSetReportHook(f) ((_CRT_REPORT_HOOK)0) +#define _CrtSetReportHook2(t, f) ((int)0) +#define _CrtSetReportMode(t, f) ((int)0) +#define _CrtSetReportFile(t, f) ((_HFILE)0) + +#define _CrtDbgBreak() ((void)0) + +#define _CrtSetBreakAlloc(a) ((long)0) + +#define _CrtSetAllocHook(f) ((_CRT_ALLOC_HOOK)0) + +#define _CrtCheckMemory() ((int)1) +#define _CrtSetDbgFlag(f) ((int)0) +#define _CrtDoForAllClientObjects(f, c) ((void)0) +#define _CrtIsValidPointer(p, n, r) ((int)1) +#define _CrtIsValidHeapPointer(p) ((int)1) +#define _CrtIsMemoryBlock(p, t, r, f, l) ((int)1) +#define _CrtReportBlockType(p) ((int)-1) + +#define _CrtSetDumpClient(f) ((_CRT_DUMP_CLIENT)0) + +#define _CrtMemCheckpoint(s) ((void)0) +#define _CrtMemDifference(s1, s2, s3) ((int)0) +#define _CrtMemDumpAllObjectsSince(s) ((void)0) +#define _CrtMemDumpStatistics(s) ((void)0) +#define _CrtDumpMemoryLeaks() ((int)0) + + +#else /* _DEBUG */ + + + /**************************************************************************** + * + * Debug ON + * Debug ON + * Debug ON + * + ***************************************************************************/ + + +/* Define _CRTIMP */ + +#ifndef _CRTIMP +#ifdef _DLL +#define _CRTIMP __declspec(dllimport) +#else /* ndef _DLL */ +#define _CRTIMP +#endif /* _DLL */ +#endif /* _CRTIMP */ + + /**************************************************************************** + * + * Debug Reporting + * + ***************************************************************************/ + +//_CRTIMP extern long _crtAssertBusy; +CoreExport extern long& MAX_crtAssertBusy; +#define _crtAssertBusy (MAX_crtAssertBusy) + +//Install a client-defined reporting function by hooking it into the C run-time debug reporting process +//_CRTIMP _CRT_REPORT_HOOK __cdecl _CrtSetReportHook( +// _CRT_REPORT_HOOK +// ); +CoreExport _CRT_REPORT_HOOK (__cdecl *MAX_CrtSetReportHook)(_CRT_REPORT_HOOK); +#define _CrtSetReportHook(reportHook) (*MAX_CrtSetReportHook)(reportHook) + + + +/* WARNING! There is no VC6 equivalent +_CRTIMP int __cdecl _CrtSetReportHook2( + int, + _CRT_REPORT_HOOK + ); +*/ + +//Install a client-defined reporting function by hooking it into the C run-time debug reporting process +//_CRTIMP int __cdecl _CrtSetReportMode( +// int, +// int +// ); +CoreExport int (__cdecl *MAX_CrtSetReportMode)(int,int); +#define _CrtSetReportMode(reportType,reportMode) (*MAX_CrtSetReportMode)(reportType,reportMode) + + +//Identify the file or stream to be used as a destination for a specific report type by _CrtDbgReport +//_CRTIMP _HFILE __cdecl _CrtSetReportFile( +// int, +// _HFILE +// ); +CoreExport _HFILE (__cdecl *MAX_CrtSetReportFile)(int,_HFILE); +#define _CrtSetReportFile(reportType,reportFile) (*MAX_CrtSetReportFile)(reportType,reportFile) + +//Generate a debug report with a user message and send the report to three possible destinations +//_CRTIMP int __cdecl _CrtDbgReport( +// int, +// const char *, +// int, +// const char *, +// const char *, +// ...); +CoreExport int (__cdecl *MAX_CrtDbgReport)(int,const char *,int,const char *,const char *,...); +#define _CrtDbgReport (*MAX_CrtDbgReport) //NOTE: using a standard define, rather than a macro + + +/* Asserts */ + +#if _MSC_VER >= 1300 || !defined(_M_IX86) || defined(_CRT_PORTABLE) +#define _ASSERT_BASE(expr, msg) \ + (void) ((expr) || \ + (1 != MAX_CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, msg)) || \ + (MAX_CrtDbgBreak(), 0)) +#else +#define _ASSERT_BASE(expr, msg) \ + do { if (!(expr) && \ + (1 == MAX_CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, msg))) \ + MAX_CrtDbgBreak(); } while (0) +#endif + +#define _ASSERT(expr) _ASSERT_BASE((expr), NULL) + +#define _ASSERTE(expr) _ASSERT_BASE((expr), #expr) + +/* Reports with no file/line info */ + +#if _MSC_VER >= 1300 || !defined(_M_IX86) || defined(_CRT_PORTABLE) +#define _RPT_BASE(args) \ + (void) ((1 != MAX_CrtDbgReport args) || \ + (MAX_CrtDbgBreak(), 0)) +#else +#define _RPT_BASE(args) \ + do { if ((1 == MAX_CrtDbgReport args)) \ + MAX_CrtDbgBreak(); } while (0) +#endif + +#define _RPT0(rptno, msg) \ + _RPT_BASE((rptno, NULL, 0, NULL, "%s", msg)) + +#define _RPT1(rptno, msg, arg1) \ + _RPT_BASE((rptno, NULL, 0, NULL, msg, arg1)) + +#define _RPT2(rptno, msg, arg1, arg2) \ + _RPT_BASE((rptno, NULL, 0, NULL, msg, arg1, arg2)) + +#define _RPT3(rptno, msg, arg1, arg2, arg3) \ + _RPT_BASE((rptno, NULL, 0, NULL, msg, arg1, arg2, arg3)) + +#define _RPT4(rptno, msg, arg1, arg2, arg3, arg4) \ + _RPT_BASE((rptno, NULL, 0, NULL, msg, arg1, arg2, arg3, arg4)) + + +/* Reports with file/line info */ + +#define _RPTF0(rptno, msg) \ + _RPT_BASE((rptno, __FILE__, __LINE__, NULL, "%s", msg)) + +#define _RPTF1(rptno, msg, arg1) \ + _RPT_BASE((rptno, __FILE__, __LINE__, NULL, msg, arg1)) + +#define _RPTF2(rptno, msg, arg1, arg2) \ + _RPT_BASE((rptno, __FILE__, __LINE__, NULL, msg, arg1, arg2)) + +#define _RPTF3(rptno, msg, arg1, arg2, arg3) \ + _RPT_BASE((rptno, __FILE__, __LINE__, NULL, msg, arg1, arg2, arg3)) + +#define _RPTF4(rptno, msg, arg1, arg2, arg3, arg4) \ + _RPT_BASE((rptno, __FILE__, __LINE__, NULL, msg, arg1, arg2, arg3, arg4)) + + +//_CRTIMP void __cdecl _CrtDbgBreak(void); +CoreExport void __cdecl MAX_CrtDbgBreak(void); + +#define _CrtDbgBreak() MAX_CrtDbgBreak() + +/* +#if _MSC_VER >= 1300 && !defined(_CRT_PORTABLE) +#define _CrtDbgBreak() __debugbreak() +#elif defined(_M_IX86) && !defined(_CRT_PORTABLE) +#define _CrtDbgBreak() __asm { int 3 } +#elif defined(_M_ALPHA) && !defined(_CRT_PORTABLE) +void _BPT(); +#pragma intrinsic(_BPT) +#define _CrtDbgBreak() _BPT() +#elif defined(_M_IA64) && !defined(_CRT_PORTABLE) +void __break(int); +#pragma intrinsic (__break) +#define _CrtDbgBreak() __break(0x80016) +#else +_CRTIMP void __cdecl _CrtDbgBreak( + void + ); +#endif +*/ + + /**************************************************************************** + * + * Heap routines + * + ***************************************************************************/ + +#ifdef _CRTDBG_MAP_ALLOC + +#define malloc(s) MAX_malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define calloc(c, s) MAX_calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define realloc(p, s) MAX_realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define _expand(p, s) MAX_expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define free(p) MAX_free_dbg(p, _NORMAL_BLOCK) +#define _msize(p) MAX_msize_dbg(p, _NORMAL_BLOCK) +/* WARNING! No VC6 equivalent +#define _aligned_malloc(s, a) _aligned_malloc_dbg(s, a, __FILE__, __LINE__) +#define _aligned_realloc(p, s, a) _aligned_realloc_dbg(p, s, a, __FILE__, __LINE__) +#define _aligned_offset_malloc(s, a, o) _aligned_offset_malloc_dbg(s, a, o, __FILE__, __LINE__) +#define _aligned_offset_realloc(p, s, a, o) _aligned_offset_realloc_dbg(p, s, a, o, __FILE__, __LINE__) +#define _aligned_free(p) _aligned_free_dbg(p) +*/ +#endif /* _CRTDBG_MAP_ALLOC */ + +//_CRTIMP extern long _crtBreakAlloc; /* Break on this allocation */ +CoreExport extern long& MAX_crtBreakAlloc; +#define _crtBreakAlloc (MAX_crtBreakAlloc) + +//Set a breakpoint on a specified object allocation order number +//_CRTIMP long __cdecl _CrtSetBreakAlloc( +// long +// ); +CoreExport long (__cdecl *MAX_CrtSetBreakAlloc)(long); +#define _CrtSetBreakAlloc(lBreakAlloc) (*MAX_CrtSetBreakAlloc)(lBreakAlloc) + + +/* + * Prototypes for malloc, free, realloc, etc are in malloc.h + */ + +//Debug version of malloc; only available in the debug versions of the run-time libraries +//_CRTIMP void * __cdecl _malloc_dbg( +// size_t, +// int, +// const char *, +// int +// ); +CoreExport void * (__cdecl *MAX_malloc_dbg)(size_t,int,const char *,int); +#define _malloc_dbg(size,blockType,filename,lineNumber) (*MAX_malloc_dbg)(size,blockType,filename,lineNumber) + +//Debug version of calloc; only available in the debug versions of the run-time libraries +//_CRTIMP void * __cdecl _calloc_dbg( +// size_t, +// size_t, +// int, +// const char *, +// int +// ); +CoreExport void * (__cdecl *MAX_calloc_dbg)(size_t, size_t, int, const char *, int); +#define _calloc_dbg(num,size,blockType,filename,lineNumber) (*MAX_calloc_dbg)(num,size,blockType,filename,lineNumber) + +//Debug version of realloc; only available in the debug versions of the run-time libraries +//_CRTIMP void * __cdecl _realloc_dbg( +// void *, +// size_t, +// int, +// const char *, +// int +// ); +CoreExport void * (__cdecl *MAX_realloc_dbg)(void *, size_t, int, const char *, int); +#define _realloc_dbg(userData,newSize,blockType,filename,lineNumber) (*MAX_realloc_dbg)(userData,newSize,blockType,filename,lineNumber) + +//Debug version of _expand; only available in the debug versions of the run-time libraries +//_CRTIMP void * __cdecl _expand_dbg( +// void *, +// size_t, +// int, +// const char *, +// int +// ); +CoreExport void * (__cdecl *MAX_expand_dbg)(void *, size_t, int, const char *, int); +#define _expand_dbg(userData,newSize,blockType,filename,lineNumber) (*MAX_expand_dbg)(userData,newSize,blockType,filename,lineNumber) + +//Debug version of free; only available in the debug versions of the run-time libraries +//_CRTIMP void __cdecl _free_dbg( +// void *, +// int +// ); +CoreExport void (__cdecl *MAX_free_dbg)(void *, int); +#define _free_dbg(userData,blockType) (*MAX_free_dbg)(userData,blockType) + +//Debug version of _msize; only available in the debug versions of the run-time libraries +//_CRTIMP size_t __cdecl _msize_dbg ( +// void *, +// int +// ); +CoreExport size_t (__cdecl *MAX_msize_dbg)(void *, int); +#define _msize_dbg(userData,blockType) (*MAX_msize_dbg)(userData,blockType) + + +/* WARNING! No VC6 equivalent + +_CRTIMP void * __cdecl _aligned_malloc_dbg( + size_t, + size_t, + const char *, + int + ); + +_CRTIMP void * __cdecl _aligned_realloc_dbg( + void *, + size_t, + size_t, + const char *, + int + ); + +_CRTIMP void * __cdecl _aligned_offset_malloc_dbg( + size_t, + size_t, + size_t, + const char *, + int + ); + +_CRTIMP void * __cdecl _aligned_offset_realloc_dbg( + void *, + size_t, + size_t, + size_t, + const char *, + int + ); + +_CRTIMP void __cdecl _aligned_free_dbg( + void * + ); +*/ + + /**************************************************************************** + * + * Client-defined allocation hook + * + ***************************************************************************/ + +//Install a client-defined allocation function by hooking it into the C run-time debug memory allocation process +//_CRTIMP _CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook( +// _CRT_ALLOC_HOOK +// ); +CoreExport _CRT_ALLOC_HOOK (__cdecl *MAX_CrtSetAllocHook)(_CRT_ALLOC_HOOK); +#define _CrtSetAllocHook(allocHook) (*MAX_CrtSetAllocHook)(allocHook) + + + /**************************************************************************** + * + * Memory management + * + ***************************************************************************/ + +/* + * Bitfield flag that controls CRT heap behavior + * Default setting is _CRTDBG_ALLOC_MEM_DF + */ + +//_CRTIMP extern int _crtDbgFlag; +CoreExport extern int& MAX_crtDbgFlag; +#define _crtDbgFlag (MAX_crtDbgFlag) + +//Confirm the integrity of the memory blocks allocated on the debug heap +//_CRTIMP int __cdecl _CrtCheckMemory( +// void +// ); +CoreExport int (__cdecl *MAX_CrtCheckMemory)(void); +#define _CrtCheckMemory() (*MAX_CrtCheckMemory)() + +//Retrieve or modify the state of the _crtDbgFlag flag to control the allocation behavior of the debug heap manager +//_CRTIMP int __cdecl _CrtSetDbgFlag( +// int +// ); +CoreExport int (__cdecl *MAX_CrtSetDbgFlag)(int); +#define _CrtSetDbgFlag(newFlag) (*MAX_CrtSetDbgFlag)(newFlag) + +//Call an application-supplied function for all _CLIENT_BLOCK types on the heap +//_CRTIMP void __cdecl _CrtDoForAllClientObjects( +// void (*pfn)(void *, void *), +// void * +// ); +CoreExport void (__cdecl *MAX_CrtDoForAllClientObjects)(void (*pfn)(void *, void *),void *); +#define _CrtDoForAllClientObjects(pfn,context) (*MAX_CrtDoForAllClientObjects)(pfn,context) + +//Verify that a specified memory range is valid for reading and writing +//_CRTIMP int __cdecl _CrtIsValidPointer( +// const void *, +// unsigned int, +// int +// ); +CoreExport int (__cdecl *MAX_CrtIsValidPointer)(const void *,unsigned int,int); +#define _CrtIsValidPointer(address,size,access) (*MAX_CrtIsValidPointer)(address,size,access) + +//Verify that a specified pointer is in the local heap +//_CRTIMP int __cdecl _CrtIsValidHeapPointer( +// const void * +// ); +CoreExport int (__cdecl *MAX_CrtIsValidHeapPointer)(const void *); +#define _CrtIsValidHeapPointer(userData) (*MAX_CrtIsValidHeapPointer)(userData) + +//Verify that a specified memory block is located within the local heap and that it has a valid debug heap block type identifier +//_CRTIMP int __cdecl _CrtIsMemoryBlock( +// const void *, +// unsigned int, +// long *, +// char **, +// int * +// ); +CoreExport int (__cdecl *MAX_CrtIsMemoryBlock)(const void *,unsigned int,long *,char **,int *); +#define _CrtIsMemoryBlock(userData,size,requestNumber,filename,linenumber) (*MAX_CrtIsMemoryBlock)(userData,size,requestNumber,filename,linenumber) + + +/* WARNING! No VC6 equivalent +_CRTIMP int __cdecl _CrtReportBlockType( + const void * + ); +*/ + + + /**************************************************************************** + * + * Memory state + * + ***************************************************************************/ + +//Install an application-defined function that is called every time a debug dump function is called to dump _CLIENT_BLOCK type memory blocks +//_CRTIMP _CRT_DUMP_CLIENT __cdecl _CrtSetDumpClient( +// _CRT_DUMP_CLIENT +// ); +CoreExport _CRT_DUMP_CLIENT (__cdecl *MAX_CrtSetDumpClient)(_CRT_DUMP_CLIENT); +#define _CrtSetDumpClient(dumpClient) (*MAX_CrtSetDumpClient)(dumpClient) + +//Obtain the current state of the debug heap and store it in an application-supplied _CrtMemState structure +//_CRTIMP void __cdecl _CrtMemCheckpoint( +// _CrtMemState * +// ); +CoreExport void (__cdecl *MAX_CrtMemCheckpoint)(_CrtMemState *); +#define _CrtMemCheckpoint(state) (*MAX_CrtMemCheckpoint)(state) + +//Compare two memory states for significant differences and return the results +//_CRTIMP int __cdecl _CrtMemDifference( +// _CrtMemState *, +// const _CrtMemState *, +// const _CrtMemState * +// ); +CoreExport int (__cdecl *MAX_CrtMemDifference)(_CrtMemState *,const _CrtMemState *,const _CrtMemState *); +#define _CrtMemDifference(stateDiff,oldState,newState) (*MAX_CrtMemDifference)(stateDiff,oldState,newState) + +//Dump information about objects on the heap since a specified checkpoint was taken or from the start of program execution +//_CRTIMP void __cdecl _CrtMemDumpAllObjectsSince( +// const _CrtMemState * +// ); +CoreExport void (__cdecl *MAX_CrtMemDumpAllObjectsSince)(const _CrtMemState *); +#define _CrtMemDumpAllObjectsSince(state) (*MAX_CrtMemDumpAllObjectsSince)(state) + +//Dump the debug header information for a specified memory state in a user-readable form +//_CRTIMP void __cdecl _CrtMemDumpStatistics( +// const _CrtMemState * +// ); +CoreExport void (__cdecl *MAX_CrtMemDumpStatistics)(const _CrtMemState *); +#define _CrtMemDumpStatistics(state) (*MAX_CrtMemDumpStatistics)(state) + +//Dump all of the memory blocks on the debug heap when a significant memory leak has occurred +//_CRTIMP int __cdecl _CrtDumpMemoryLeaks( +// void +// ); +CoreExport int (__cdecl *MAX_CrtDumpMemoryLeaks)(void); +#define _CrtDumpMemoryLeaks() (*MAX_CrtDumpMemoryLeaks)() + + +#endif /* _DEBUG */ + +#ifdef __cplusplus +//} + +#ifndef _MFC_OVERRIDES_NEW + +//extern "C++" { + +#pragma warning(disable: 4507) /* Ignore faulty warning */ + +#ifndef _DEBUG + + /**************************************************************************** + * + * Debug OFF + * Debug OFF + * Debug OFF + * + ***************************************************************************/ + +CoreExport void *__cdecl MAX_new_array(size_t size); +CoreExport void __cdecl MAX_delete_array(void* mem); + +//void * __cdecl operator new[](size_t); +__forceinline void* _cdecl operator new[](size_t size) +{ + return MAX_new_array(size); +} + + +//FIXME: implement this +//inline void * __cdecl operator new(size_t s, int, const char *, int) +// { return ::operator new(s); } + +//FIXME: implement this +//inline void* __cdecl operator new[](size_t s, int, const char *, int) +// { return ::operator new[](s); } + +#if _MSC_VER >= 1200 + + +//void __cdecl operator delete[](void *); +__forceinline void _cdecl operator delete[](void* memblock) +{ + MAX_delete_array(memblock); +} + +//FIXME: implement this +//inline void __cdecl operator delete(void * _P, int, const char *, int) +// { ::operator delete(_P); } + +//FIXME: implement this +//inline void __cdecl operator delete[](void * _P, int, const char *, int) +// { ::operator delete[](_P); } +#endif +#else /* _DEBUG */ + + /**************************************************************************** + * + * Debug ON + * Debug ON + * Debug ON + * + ***************************************************************************/ + +CoreExport void *__cdecl MAX_new_array(size_t size); +CoreExport void __cdecl MAX_delete_array(void* mem); + +//void * __cdecl operator new[](size_t); +__forceinline void* _cdecl operator new[](size_t size) +{ + return MAX_new_array(size); +} + +//FIXME: implement this +//void * __cdecl operator new( +// size_t, +// int, +// const char *, +// int +// ); + +//FIXME: implement this +//void * __cdecl operator new[]( +// size_t, +// int, +// const char *, +// int +// ); + +#if _MSC_VER >= 1200 +//void __cdecl operator delete[](void *); +__forceinline void _cdecl operator delete[](void* memblock) +{ + MAX_delete_array(memblock); +} + +//FIXME: implement this +//inline void __cdecl operator delete(void * _P, int, const char *, int) +// { ::operator delete(_P); } + +//FIXME: implement this +//inline void __cdecl operator delete[](void * _P, int, const char *, int) +// { ::operator delete[](_P); } +#endif + +#ifdef _CRTDBG_MAP_ALLOC + +//FIXME: implement this +//inline void * __cdecl operator new(size_t s) +// { return ::operator new(s, _NORMAL_BLOCK, __FILE__, __LINE__); } + +//FIXME: implement this +//inline void* __cdecl operator new[](size_t s) +// { return ::operator new[](s, _NORMAL_BLOCK, __FILE__, __LINE__); } + +#endif /* _CRTDBG_MAP_ALLOC */ + +#endif /* _DEBUG */ + +//} + +#endif /* _MFC_OVERRIDES_NEW */ + +#endif /* __cplusplus */ + + + +#endif //_MSC_VER > 1300 + +#endif /* MAX_MEM */ + diff --git a/NifCommon/MAX_MemDirect.h b/NifCommon/MAX_MemDirect.h new file mode 100644 index 0000000..47340a5 --- /dev/null +++ b/NifCommon/MAX_MemDirect.h @@ -0,0 +1,195 @@ +/********************************************************************** + *< + FILE: MAX_Mem + + DESCRIPTION: Access to the memory routines used by Max + (Can be called from plug-ins compiled with different + memory handling) + + CREATED BY: Cleve Ard & Michaelson Britt + + HISTORY: Created, Oct. 2003 + + *> Copyright (c) 2003 Autodesk, Inc., All Rights Reserved. + **********************************************************************/ + +#ifndef __MAX_MEM_H +#define __MAX_MEM_H + +#include <crtdbg.h> +#include <malloc.h> +#include <new.h> + + + +// NOTE: For efficiency, most functions are declared as pointers which +// route into the corresponding function. This avoids passing through +// a "wrapper" layer. +// +// New and Delete were implemented with wrappers, so that the original +// MAX_Mem.h could use function overloads with them, since this is not +// possible with the preprocessor. +// int* x = new; +// There's no way to define 'new' as a preprocessor macro such that +// 'new int' is translated to 'MAX_new( sizeof(int) )' + + +CoreExport void *__cdecl MAX_new(size_t size); + +CoreExport void *__cdecl MAX_new_array(size_t size); + +// Disabled: Placement forms not supported +//CoreExport void *__cdecl MAX_new_placement(size_t size, void *_P); + +CoreExport void __cdecl MAX_delete(void* mem); + +CoreExport void __cdecl MAX_delete_array(void* mem); + +// Disabled: Placement forms not supported +//CoreExport void __cdecl MAX_delete_placement(void *memblock, void *_P); + +//Allocate block of memory from heap +CoreExport void * (__cdecl *MAX_malloc)(size_t size); + +//Allocate storage for array, initializing every byte in allocated block to 0 +CoreExport void * (__cdecl *MAX_calloc)(size_t num, size_t size); + +//Reallocate block to new size +CoreExport void * (__cdecl *MAX_realloc)(void *memblock, size_t size); + +//Expand or shrink block of memory without moving it +CoreExport void * (__cdecl *MAX_expand)(void * memblock, size_t size); + +//Free allocated block +CoreExport void (__cdecl *MAX_free)(void * memblock); + +//Return size of allocated block +CoreExport size_t (__cdecl *MAX_msize)(void *memblock); + +// Set hook function +// Disabled: because HEAPHOOK does not seem to be enabled in practice +//CoreExport _HEAPHOOK (__cdecl *MAX_setheaphook)(_HEAPHOOK); + +//Add memory to heap +CoreExport int (__cdecl *MAX_heapadd)(void * memblock, size_t size); + +//Check heap for consistency +CoreExport int (__cdecl *MAX_heapchk)(void); + +//Release unused memory in heap +CoreExport int (__cdecl *MAX_heapmin)(void); + +//Fill free heap entries with specified value +CoreExport int (__cdecl *MAX_heapset)(unsigned int fill); + +//Return information about each entry in heap +CoreExport int (__cdecl *MAX_heapwalk)(_HEAPINFO *entryinfo); + +//Return address of current new handler routine as set by _set_new_handler +CoreExport _PNH (__cdecl *MAX_query_new_handler)( void ); + +//Enable error-handling mechanism when new operator fails (to allocate memory) and enable compilation of Standard Template Libraries (STL) +CoreExport _PNH (__cdecl *MAX_set_new_handler)( _PNH pNewHandler ); + +//Return integer indicating new handler mode set by _set_new_mode for malloc +CoreExport int (__cdecl *MAX_query_new_mode)( void ); + +//Set new handler mode for malloc +CoreExport int (__cdecl *MAX_set_new_mode)( int newhandlermode ); + +//Get/Set the upper limit for the size of a memory allocation that will be supported by the small-block heap +CoreExport size_t (__cdecl *MAX_get_sbh_threshold)(void); +CoreExport int (__cdecl *MAX_set_sbh_threshold)(size_t size); + + +//----------------------------------------------------------------------------- +// The following debug functions are available only in a Sparks debug build + +#ifdef _DEBUG +#ifndef IS_HYBRID + +//Debug version of calloc; only available in the debug versions of the run-time libraries +CoreExport void * (__cdecl *MAX_calloc_dbg)(size_t num, size_t size, int blockType, const char * filename, int lineNumber); + +//Debug version of _expand; only available in the debug versions of the run-time libraries +CoreExport void * (__cdecl *MAX_expand_dbg)(void * userData, size_t newSize, int blockType, const char * filename, int lineNumber); + +//Debug version of malloc; only available in the debug versions of the run-time libraries +CoreExport void * (__cdecl *MAX_malloc_dbg)(size_t size,int blockType,const char *filename,int lineNumber); + +//Debug version of free; only available in the debug versions of the run-time libraries +CoreExport void (__cdecl *MAX_free_dbg)(void * userData, int blockType); + +//Debug version of _msize; only available in the debug versions of the run-time libraries +CoreExport size_t (__cdecl *MAX_msize_dbg)(void *userData, int blockType); + +//Debug version of realloc; only available in the debug versions of the run-time libraries +CoreExport void * (__cdecl *MAX_realloc_dbg)(void *userData, size_t newSize, int blockType, const char *filename, int lineNumber); + +CoreExport extern long& MAX_crtAssertBusy; + +//Install a client-defined reporting function by hooking it into the C run-time debug reporting process +CoreExport _CRT_REPORT_HOOK (__cdecl *MAX_CrtSetReportHook)(_CRT_REPORT_HOOK reportHook); + +//Install a client-defined reporting function by hooking it into the C run-time debug reporting process +CoreExport int (__cdecl *MAX_CrtSetReportMode)(int reportType,int reportMode); + +//Identify the file or stream to be used as a destination for a specific report type by _CrtDbgReport +CoreExport _HFILE (__cdecl *MAX_CrtSetReportFile)(int reportType,_HFILE reportFile); + +//Generate a debug report with a user message and send the report to three possible destinations +CoreExport int (__cdecl *MAX_CrtDbgReport)(int,const char *,int,const char *,const char *,...); + +CoreExport void __cdecl MAX_CrtDbgBreak(void); + +CoreExport extern long& MAX_crtBreakAlloc; /* Break on this allocation */ + +//Set a breakpoint on a specified object allocation order number +CoreExport long (__cdecl *MAX_CrtSetBreakAlloc)(long lBreakAlloc); + +//Install a client-defined allocation function by hooking it into the C run-time debug memory allocation process +CoreExport _CRT_ALLOC_HOOK (__cdecl *MAX_CrtSetAllocHook)(_CRT_ALLOC_HOOK allocHook); + +CoreExport extern int& MAX_crtDbgFlag; + +//Confirm the integrity of the memory blocks allocated on the debug heap +CoreExport int (__cdecl *MAX_CrtCheckMemory)(void); + +//Retrieve or modify the state of the _crtDbgFlag flag to control the allocation behavior of the debug heap manager +CoreExport int (__cdecl *MAX_CrtSetDbgFlag)(int newFlag); + +//Call an application-supplied function for all _CLIENT_BLOCK types on the heap +CoreExport void (__cdecl *MAX_CrtDoForAllClientObjects)(void (*pfn)(void *, void *),void *context); + +//Verify that a specified memory range is valid for reading and writing +CoreExport int (__cdecl *MAX_CrtIsValidPointer)(const void *address,unsigned int size,int access); + +//Verify that a specified pointer is in the local heap +CoreExport int (__cdecl *MAX_CrtIsValidHeapPointer)(const void *userData); + +//Verify that a specified memory block is located within the local heap and that it has a valid debug heap block type identifier +CoreExport int (__cdecl *MAX_CrtIsMemoryBlock)(const void *userData,unsigned int size,long *requestNumber,char **filename,int *linenumber); + +//Install an application-defined function that is called every time a debug dump function is called to dump _CLIENT_BLOCK type memory blocks +CoreExport _CRT_DUMP_CLIENT (__cdecl *MAX_CrtSetDumpClient)(_CRT_DUMP_CLIENT dumpClient); + +//Obtain the current state of the debug heap and store it in an application-supplied _CrtMemState structure +CoreExport void (__cdecl *MAX_CrtMemCheckpoint)(_CrtMemState *state); + +//Compare two memory states for significant differences and return the results +CoreExport int (__cdecl *MAX_CrtMemDifference)(_CrtMemState *stateDiff,const _CrtMemState *oldState,const _CrtMemState *newState); + +//Dump information about objects on the heap since a specified checkpoint was taken or from the start of program execution +CoreExport void (__cdecl *MAX_CrtMemDumpAllObjectsSince)(const _CrtMemState *state); + +//Dump the debug header information for a specified memory state in a user-readable form +CoreExport void (__cdecl *MAX_CrtMemDumpStatistics)(const _CrtMemState *state); + +//Dump all of the memory blocks on the debug heap when a significant memory leak has occurred +CoreExport int (__cdecl *MAX_CrtDumpMemoryLeaks)(void); + +#endif //IS_HYBRID +#endif //_DEBUG + + +#endif //__MAX_MEM_H diff --git a/NifCommon/NifCommon_VC80.vcproj b/NifCommon/NifCommon_VC80.vcproj index 6026cbc..62f60d5 100644 --- a/NifCommon/NifCommon_VC80.vcproj +++ b/NifCommon/NifCommon_VC80.vcproj @@ -516,6 +516,14 @@ RelativePath=".\IniSection.h" > </File> + <File + RelativePath=".\MAX_Mem.h" + > + </File> + <File + RelativePath=".\MAX_MemDirect.h" + > + </File> <File RelativePath=".\NifGui.h" > diff --git a/NifCommon/niutils.cpp b/NifCommon/niutils.cpp index 5164417..b46ca0d 100644 --- a/NifCommon/niutils.cpp +++ b/NifCommon/niutils.cpp @@ -69,6 +69,110 @@ std::string FormatString(const TCHAR* format,...) return text; } + +// routine for parsing white space separated lines. Handled like command line parameters w.r.t quotes. +static void parse_line ( + const char *start, + char **argv, + char *args, + int *numargs, + int *numchars + ) +{ + const char NULCHAR = '\0'; + const char SPACECHAR = ' '; + const char TABCHAR = '\t'; + const char RETURNCHAR = '\r'; + const char LINEFEEDCHAR = '\n'; + const char DQUOTECHAR = '\"'; + const char SLASHCHAR = '\\'; + const char *p; + int inquote; /* 1 = inside quotes */ + int copychar; /* 1 = copy char to *args */ + unsigned numslash; /* num of backslashes seen */ + + *numchars = 0; + *numargs = 0; /* the program name at least */ + + p = start; + + inquote = 0; + + /* loop on each argument */ + for(;;) + { + if ( *p ) { while (*p == SPACECHAR || *p == TABCHAR || *p == RETURNCHAR || *p == LINEFEEDCHAR) ++p; } + + if (*p == NULCHAR) break; /* end of args */ + + /* scan an argument */ + if (argv) + *argv++ = args; /* store ptr to arg */ + ++*numargs; + + /* loop through scanning one argument */ + for (;;) + { + copychar = 1; + /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote + 2N+1 backslashes + " ==> N backslashes + literal " + N backslashes ==> N backslashes */ + numslash = 0; + while (*p == SLASHCHAR) + { + /* count number of backslashes for use below */ + ++p; + ++numslash; + } + if (*p == DQUOTECHAR) + { + /* if 2N backslashes before, start/end quote, otherwise copy literally */ + if (numslash % 2 == 0) { + if (inquote) { + if (p[1] == DQUOTECHAR) + p++; /* Double quote inside quoted string */ + else /* skip first quote char and copy second */ + copychar = 0; + } else + copychar = 0; /* don't copy quote */ + + inquote = !inquote; + } + numslash /= 2; /* divide numslash by two */ + } + + /* copy slashes */ + while (numslash--) { + if (args) + *args++ = SLASHCHAR; + ++*numchars; + } + + /* if at end of arg, break loop */ + if (*p == NULCHAR || (!inquote && (*p == SPACECHAR || *p == TABCHAR || *p == RETURNCHAR || *p == LINEFEEDCHAR))) + break; + + /* copy character into argument */ + if (copychar) + { + if (args) + *args++ = *p; + ++*numchars; + } + ++p; + } + + /* null-terminate the argument */ + if (args) + *args++ = NULCHAR; /* terminate string */ + ++*numchars; + } + /* We put one last argument in -- a null ptr */ + if (argv) + *argv++ = NULL; + ++*numargs; +} + // Tokenize a string using strtok and return it as a stringlist stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim) { @@ -80,6 +184,32 @@ stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim) return values; } +// Tokenize a string using strtok and return it as a stringlist +stringlist TokenizeCommandLine(LPCTSTR str, bool trim) +{ + stringlist values; + int nargs = 0, nchars = 0; + parse_line( str, NULL, NULL, &nargs, &nchars); + char **largv = (char **)_alloca(nargs * sizeof(TCHAR *) + nchars * sizeof(TCHAR)); + parse_line( str, largv, ((TCHAR*)largv) + nargs * sizeof(TCHAR*), &nargs, &nchars); + for (int i=0; i<nargs; ++i) { + LPTSTR p = largv[i]; + if (p == NULL) continue; + values.push_back(string((trim) ? Trim(p) : p)); + } + return values; +} + +string JoinCommandLine(stringlist args) +{ + std::stringstream str; + for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { + if (itr != args.begin()) str << ' '; + str << (*itr); + } + return str.str(); +} + // Parse and ini file section and return the results as s NameValueCollection. NameValueCollection ReadIniSection(LPCTSTR Section, LPCTSTR iniFileName ) { @@ -302,6 +432,11 @@ int wildcmpi(const TCHAR *wild, const TCHAR *string) { return !*wild; } +bool wildmatch(const TCHAR* match, const TCHAR* value) +{ + return (wildcmpi(match, value)) ? true : false; +} + bool wildmatch(const string& match, const std::string& value) { return (wildcmpi(match.c_str(), value.c_str())) ? true : false; @@ -323,6 +458,58 @@ void RenameNode(Interface *gi, LPCTSTR SrcName, LPCTSTR DstName) if (node != NULL) node->SetName(const_cast<LPTSTR>(DstName)); } +Point3 TOEULER(const Matrix3 &m) +{ + Point3 rv(0.0f, 0.0f, 0.0f); + if ( m.GetRow(2)[0] < 1.0 ) + { + if ( m.GetRow(2)[0] > - 1.0 ) + { + rv[2] = atan2( - m.GetRow(1)[0], m.GetRow(0)[0] ); + rv[1] = asin( m.GetRow(2)[0] ); + rv[0] = atan2( - m.GetRow(2)[1], m.GetRow(2)[2] ); + } + else + { + rv[2] = - atan2( - m.GetRow(1)[2], m.GetRow(1)[1] ); + rv[1] = - PI / 2; + rv[0] = 0.0; + } + } + else + { + rv[2] = atan2( m.GetRow(1)[2], m.GetRow(1)[1] ); + rv[1] = PI / 2; + rv[0] = 0.0; + } + return rv; +} + +inline Point3 TODEG(const Point3& p){ + return Point3(TODEG(p[0]), TODEG(p[1]), TODEG(p[2])); +} + +inline Point3 TORAD(const Point3& p){ + return Point3(TORAD(p[0]), TORAD(p[1]), TORAD(p[2])); +} + +inline TSTR TOSTRING(const Point3& p) { + return FormatText("[%g,%g,%g]", p[0], p[1], p[2]); +} + +inline TSTR TOSTRING(float p) { + return FormatText("%g", p); +} + +inline TSTR TOSTRING(const Matrix3& m) { + return TOSTRING( TODEG( TOEULER(m) ) ); +} + +inline TSTR TOSTRING(const Quat& q) { + Matrix3 m; q.MakeMatrix(m); + return TOSTRING( m ); +} + void PosRotScaleNode(INode *n, Matrix3& m3, PosRotScale prs, TimeValue t) { Point3 p = m3.GetTrans(); @@ -337,16 +524,15 @@ void PosRotScaleNode(INode *n, Matrix3& m3, PosRotScale prs, TimeValue t) void PosRotScaleNode(INode *n, Point3 p, Quat& q, float s, PosRotScale prs, TimeValue t) { if (Control *c = n->GetTMController()) { + if (prs & prsRot && q.w == FloatNegINF) prs = PosRotScale(prs & ~prsRot); + if (prs & prsPos && p.x == FloatNegINF) prs = PosRotScale(prs & ~prsPos); + if (prs & prsScale && s == FloatNegINF) prs = PosRotScale(prs & ~prsScale); #ifdef USE_BIPED // Bipeds are special. And will crash if you dont treat them with care if ( (c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||(c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||(c->ClassID() == FOOTPRINT_CLASS_ID)) { - if (prs & prsRot && q.w == FloatNegINF) prs = PosRotScale(prs & ~prsRot); - if (prs & prsPos && p.x == FloatNegINF) prs = PosRotScale(prs & ~prsPos); - if (prs & prsScale && s == FloatNegINF) prs = PosRotScale(prs & ~prsScale); - ScaleValue sv(Point3(s,s,s)); // Get the Biped Export Interface from the controller //IBipedExport *BipIface = (IBipedExport *) c->GetInterface(I_BIPINTERFACE); @@ -361,6 +547,14 @@ void PosRotScaleNode(INode *n, Point3 p, Quat& q, float s, PosRotScale prs, Time } #endif PosRotScaleNode(c, p, q, s, prs, t); + +//#ifdef _DEBUG +// static TSTR sEmpty = "<Empty>"; +// TSTR spos = (prs & prsPos) ? TOSTRING(p) : sEmpty; +// TSTR srot = (prs & prsRot) ? TOSTRING(q) : sEmpty; +// TSTR sscl = (prs & prsScale) ? TOSTRING(s) : sEmpty; +// OutputDebugString(FormatText("Transform(%s, %s, %s, %s)\n", n->GetName(), spos.data(), srot.data(), sscl.data())); +//#endif } } @@ -685,4 +879,61 @@ TSTR GetFileVersion(const char *fileName) } } return retval; -} \ No newline at end of file +} + +// Calculate bounding sphere using minimum-volume axis-align bounding box. Its fast but not a very good fit. +void CalcAxisAlignedSphere(const vector<Vector3>& vertices, Vector3& center, float& radius) +{ + //--Calculate center & radius--// + + //Set lows and highs to first vertex + Vector3 lows = vertices[ 0 ]; + Vector3 highs = vertices[ 0 ]; + + //Iterate through the vertices, adjusting the stored values + //if a vertex with lower or higher values is found + for ( unsigned int i = 0; i < vertices.size(); ++i ) { + const Vector3 & v = vertices[ i ]; + + if ( v.x > highs.x ) highs.x = v.x; + else if ( v.x < lows.x ) lows.x = v.x; + + if ( v.y > highs.y ) highs.y = v.y; + else if ( v.y < lows.y ) lows.y = v.y; + + if ( v.z > highs.z ) highs.z = v.z; + else if ( v.z < lows.z ) lows.z = v.z; + } + + //Now we know the extent of the shape, so the center will be the average + //of the lows and highs + center = (highs + lows) / 2.0f; + + //The radius will be the largest distance from the center + Vector3 diff; + float dist2(0.0f), maxdist2(0.0f); + for ( unsigned int i = 0; i < vertices.size(); ++i ) { + const Vector3 & v = vertices[ i ]; + + diff = center - v; + dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; + if ( dist2 > maxdist2 ) maxdist2 = dist2; + }; + radius = sqrt(maxdist2); +} + +// Calculate bounding sphere using average position of the points. Better fit but slower. +void CalcCenteredSphere(const vector<Vector3>& vertices, Vector3& center, float& radius) +{ + size_t nv = vertices.size(); + Vector3 sum; + for (size_t i=0; i<nv; ++i) + sum += vertices[ i ]; + center = sum / float(nv); + radius = 0.0f; + for (size_t i=0; i<nv; ++i){ + Vector3 diff = vertices[ i ] - center; + float mag = diff.Magnitude(); + radius = max(radius, mag); + } +} diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index adc19d0..2af7484 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -140,6 +140,7 @@ inline bool strmatch(const TCHAR* lhs, const TCHAR* rhs) { return (0 == _tcsicmp(lhs, rhs)); } +bool wildmatch(const TCHAR* match, const TCHAR* value); bool wildmatch(const string& match, const std::string& value); bool wildmatch(const stringlist& matches, const std::string& value); @@ -211,6 +212,9 @@ extern TSTR FormatText(const TCHAR* format,...); extern std::string FormatString(const TCHAR* format,...); extern stringlist TokenizeString(LPCTSTR str, LPCTSTR delims, bool trim=false); +extern stringlist TokenizeCommandLine(LPCTSTR str, bool trim); +extern string JoinCommandLine(stringlist args); + extern string GetIndirectValue(LPCSTR path); extern NameValueCollection ReadIniSection(LPCTSTR Section, LPCTSTR iniFileName ); extern string ExpandQualifiers(const string& src, const NameValueCollection& map); @@ -277,6 +281,14 @@ static inline Niflib::Color3 TOCOLOR3(const Color& c3) { return Niflib::Color3(c3.r, c3.g, c3.b); } +static inline Niflib::Color3 TOCOLOR3(const Point3& c3) { + return Niflib::Color3(c3.x, c3.y, c3.z); +} + +static inline Point3 TOPOINT3(const Niflib::Color3& c3){ + return Point3(c3.r, c3.g, c3.b); +} + static inline Point3 TOPOINT3(const Niflib::Vector3& v){ return Point3(v.x, v.y, v.z); } @@ -322,6 +334,7 @@ static inline Matrix3 TOMATRIX3(const Niflib::Matrix44 &tm, bool invert = false) tm.Decompose(pos, rot, scale); Matrix3 m(rot.rows[0].data, rot.rows[1].data, rot.rows[2].data, Point3()); if (invert) m.Invert(); + m.Scale(Point3(scale, scale, scale)); m.SetTrans(Point3(pos.x, pos.y, pos.z)); return m; } @@ -334,6 +347,10 @@ static inline Niflib::Matrix44 TOMATRIX4(const Matrix3 &tm, bool invert = false) return m4; } +static inline Point3 GetScale(const Matrix3& mtx){ + return Point3( fabs(mtx.GetRow(0)[0]), fabs(mtx.GetRow(1)[1]), fabs(mtx.GetRow(2)[2]) ); +} + template <typename U, typename T> inline Niflib::Ref<U> SelectFirstObjectOfType( vector<Niflib::Ref<T> > const & objs ) { for (vector<Niflib::Ref<T> >::const_iterator itr = objs.begin(), end = objs.end(); itr != end; ++itr) { @@ -370,5 +387,4 @@ inline Niflib::Ref<T> CreateNiObject() { return Niflib::StaticCast<T>(Niflib::CreateObject(T::TypeConst().GetTypeName())); } - #endif // _NIUTILS_H_ \ No newline at end of file diff --git a/NifCommon/objectParams.h b/NifCommon/objectParams.h index 9773e3e..9751883 100644 --- a/NifCommon/objectParams.h +++ b/NifCommon/objectParams.h @@ -249,6 +249,7 @@ inline bool setMAXScriptController(ReferenceTarget* obj, LPTSTR name, Control* c 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 diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index f550c0e..8b79945 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -62,7 +62,7 @@ bool AnimationExport::doExport() seq->SetStartTime(0.0f); seq->SetStopTime(0.0f); seq->SetFrequency(1.0f); - seq->SetCycleType( NiControllerSequence::CYCLE_CLAMP ); + seq->SetCycleType( CYCLE_CLAMP ); seq->SetTargetName("Bip01"); return true; diff --git a/NifExport/Coll.cpp b/NifExport/Coll.cpp index d52d332..230687f 100755 --- a/NifExport/Coll.cpp +++ b/NifExport/Coll.cpp @@ -121,14 +121,14 @@ int Exporter::addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const P } void Exporter::addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3> &vnorms, - int face, const int vi[3], Mesh *mesh) + int face, const int vi[3], Mesh *mesh, Matrix3& tm) { Triangle tri; for (int i=0; i<3; i++) { - tri[i] = addVertex(verts, vnorms, - mesh->verts[ mesh->faces[ face ].v[ vi[i] ] ], - getVertexNormal(mesh, face, mesh->getRVertPtr(mesh->faces[ face ].v[ vi[i] ]))); + Point3 pt = VectorTransform(mesh->verts[ mesh->faces[ face ].v[ vi[i] ] ], tm); + Point3 norm = VectorTransform(getVertexNormal(mesh, face, mesh->getRVertPtr(mesh->faces[ face ].v[ vi[i] ])), tm); + tri[i] = addVertex(verts, vnorms, pt, norm); } tris.push_back(tri); } @@ -258,40 +258,22 @@ Exporter::Result Exporter::exportCollision(NiNodeRef &parent, INode *node) NiNodeRef newParent; if (coll) { -/* NiNodeRef n = DynamicCast<NiNode>(CreateBlock("NiNode")); - parent->AddChild(DynamicCast<NiAVObject>(n)); - - Matrix33 rot; - Vector3 trans; - TimeValue t = 0; - nodeTransform(rot, trans, node, t); - n->SetLocalRotation(rot); - n->SetLocalTranslation(trans); - string name = (char*)node->GetName(); - n->SetName(name); - - -/* Vector3 trans; - QuaternionXYZW q; - TimeValue t = 0; - nodeTransform(q, trans, node, t, false); - body->SetRotation(q); - body->SetTranslation(Vector3(trans.x/7, trans.y/7, trans.z/7)); -*/ newParent = nodeParent; // always have collision one level up? - bhkSphereRepShapeRef shape = makeCollisionShape(node); + TimeValue t = 0; + Matrix3 tm = getTransform(node, t, local); + Matrix44 rm4 = TOMATRIX4(tm, false); + Vector3 trans; Matrix33 rm; float scale; + rm4.Decompose(trans, rm, scale); + QuaternionXYZW q = TOQUATXYZW(rm.AsQuaternion()); + + bhkSphereRepShapeRef shape = makeCollisionShape(node, tm); bhkRigidBodyRef body = makeCollisionBody(node); body->SetShape(DynamicCast<bhkShape>(shape)); - - QuaternionXYZW q; - Vector3 trans; - TimeValue t = 0; - nodeTransform(q, trans, node, t, false); body->SetRotation(q); body->SetTranslation(trans / 7.0f); - bhkCollisionObjectRef co = DynamicCast<bhkCollisionObject>(CreateBlock("bhkCollisionObject")); + bhkCollisionObjectRef co = new bhkCollisionObject(); co->SetBody(DynamicCast<NiObject>(body)); co->SetParent(newParent); @@ -347,10 +329,10 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node) // setup body bhkRigidBodyRef body = DynamicCast<bhkRigidBody>(CreateBlock("bhkRigidBodyT")); - body->SetLayer(lyr); - body->SetLayerCopy(lyr); - body->SetMotionSystem(msys); - body->SetQualityType(qtype); + body->SetLayer(OblivionLayer(lyr)); + body->SetLayerCopy(OblivionLayer(lyr)); + body->SetMotionSystem(MotionSystem(msys)); + body->SetQualityType(MotionQuality(qtype)); body->SetMass(mass); body->SetLinearDamping(lindamp); body->SetAngularDamping(angdamp); @@ -366,36 +348,37 @@ bhkRigidBodyRef Exporter::makeCollisionBody(INode *node) return body; } -bhkSphereRepShapeRef Exporter::makeCollisionShape(INode *node) +bhkSphereRepShapeRef Exporter::makeCollisionShape(INode *node, const Matrix3& tm) { bhkSphereRepShapeRef shape; TimeValue t = 0; ObjectState os = node->EvalWorldState(t); if (os.obj->ClassID() == SCUBA_CLASS_ID) - shape = makeCapsuleShape(os.obj); + shape = makeCapsuleShape(os.obj, tm); else if (os.obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0)) - shape = makeBoxShape(os.obj); + shape = makeBoxShape(os.obj, tm); else if (os.obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0)) - shape = makeSphereShape(os.obj); + shape = makeSphereShape(os.obj, tm); else if (os.obj->SuperClassID() == GEOMOBJECT_CLASS_ID) - shape = makeTriStripsShape(node); + shape = makeTriStripsShape(node, tm); if (shape) { int mtl; npGetProp(node, NP_HVK_MATERIAL, mtl, NP_DEFAULT_HVK_MATERIAL); - shape->SetMaterial(mtl); + shape->SetMaterial(HavokMaterial(mtl)); } return shape; } -bhkSphereRepShapeRef Exporter::makeBoxShape(Object *obj) +bhkSphereRepShapeRef Exporter::makeBoxShape(Object *obj, const Matrix3& tm) { + Point3 scale = GetScale(tm); float length = 0; float height = 0; float width = 0; @@ -404,26 +387,32 @@ bhkSphereRepShapeRef Exporter::makeBoxShape(Object *obj) params->GetValue(obj->GetParamBlockIndex(BOXOBJ_HEIGHT), 0, height, FOREVER); params->GetValue(obj->GetParamBlockIndex(BOXOBJ_WIDTH), 0, width, FOREVER); - bhkBoxShapeRef box = DynamicCast<bhkBoxShape>(CreateBlock("bhkBoxShape")); - box->SetDimensions(Vector3(width, height, length)); + bhkBoxShapeRef box = new bhkBoxShape(); + box->SetDimensions(Vector3(width * scale[0], height * scale[1], length * scale[2])); return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(box)); } -bhkSphereRepShapeRef Exporter::makeSphereShape(Object *obj) +bhkSphereRepShapeRef Exporter::makeSphereShape(Object *obj, const Matrix3& tm) { + Point3 scale = GetScale(tm); + float s = (scale[0] + scale[1] + scale[2]) / 3.0; + float radius = 0; IParamArray *params = obj->GetParamBlock(); params->GetValue(obj->GetParamBlockIndex(SPHERE_RADIUS), 0, radius, FOREVER); - bhkSphereShapeRef sphere = DynamicCast<bhkSphereShape>(CreateBlock("bhkSphereShape")); - sphere->SetRadius(radius); + bhkSphereShapeRef sphere = new bhkSphereShape(); + sphere->SetRadius(radius * s); return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(sphere)); } -bhkSphereRepShapeRef Exporter::makeCapsuleShape(Object *obj) +bhkSphereRepShapeRef Exporter::makeCapsuleShape(Object *obj, const Matrix3& tm) { + Point3 scale = GetScale(tm); + float s = (scale[0] + scale[1] + scale[2]) / 3.0; + float radius = 0; float height = 0; IParamArray *params = obj->GetParamBlock(); @@ -435,10 +424,12 @@ bhkSphereRepShapeRef Exporter::makeCapsuleShape(Object *obj) return bhkSphereRepShapeRef(DynamicCast<bhkSphereRepShape>(capsule)); } -bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node) +bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node, const Matrix3& tm) { TimeValue t = 0; - Matrix3 tm = node->GetObjTMAfterWSM(t); + Matrix3 sm = ScaleMatrix( GetScale(tm) ); + + //Matrix3 tm = node->GetObjTMAfterWSM(t); // Order of the vertices. Get 'em counter clockwise if the objects is // negatively scaled. @@ -470,7 +461,7 @@ bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node) Triangles tris; for (int i=0; i<mesh->getNumFaces(); i++) - addFace(tris, verts, vnorms, i, vi, mesh); + addFace(tris, verts, vnorms, i, vi, mesh, sm); TriStrips strips; strippify(strips, verts, vnorms, tris); @@ -482,30 +473,7 @@ bhkSphereRepShapeRef Exporter::makeTriStripsShape(INode *node) bhkNiTriStripsShapeRef shape = DynamicCast<bhkNiTriStripsShape>(CreateBlock("bhkNiTriStripsShape")); shape->SetNumStripsData(1); shape->SetStripsData(0, data); -/* - array<float, 2> unknownFloats1; - uint i1 = 0x3DCCCCCD; - uint i2 = 0x004ABE60; - unknownFloats1[0] = *((float*)&i1); - unknownFloats1[1] = *((float*)&i2); - shape->SetUnknownFloats1(unknownFloats1); - - array<float, 3> unknownFloats2; - unknownFloats2[0] = 1; - unknownFloats2[1] = 1; - unknownFloats2[2] = 1; - shape->SetUnknownFloats2(unknownFloats2); -*/ -/* array<uint, 5> unknownInts1; - unknownInts1[4] = 1; - shape->SetUnknownInts1(unknownInts1); -*/ -/* Still not handled - vector<uint> unknownInts2; - unknownInts2.resize(1); - shape->SetUnknownInts2(unknownInts2); -*/ if (tri != os.obj) tri->DeleteMe(); diff --git a/NifExport/Config.cpp b/NifExport/Config.cpp index f9ab730..ea3262b 100755 --- a/NifExport/Config.cpp +++ b/NifExport/Config.cpp @@ -64,6 +64,10 @@ void Exporter::writeConfig(Interface *i) SetIniValue(NifExportSection, "FlattenHierarchy", mFlattenHierarchy, iniName); SetIniValue(NifExportSection, "RemoveUnreferencedBones", mRemoveUnreferencedBones, iniName); SetIniValue(NifExportSection, "SortNodesToEnd", mSortNodesToEnd, iniName); + SetIniValue(NifExportSection, "SkeletonOnly", mSkeletonOnly, iniName); + SetIniValue(NifExportSection, "Cameras", mExportCameras, iniName); + SetIniValue(NifExportSection, "GenerateBoneCollision", mGenerateBoneCollision, iniName); + } } @@ -115,6 +119,10 @@ void Exporter::readConfig(Interface *i) mFlattenHierarchy = GetIniValue(NifExportSection, "FlattenHierarchy", false, iniName); mRemoveUnreferencedBones = GetIniValue(NifExportSection, "RemoveUnreferencedBones", false, iniName); mSortNodesToEnd = GetIniValue(NifExportSection, "SortNodesToEnd", false, iniName); + mSkeletonOnly = GetIniValue(NifExportSection, "SkeletonOnly", false, iniName); + mExportCameras = GetIniValue(NifExportSection, "Cameras", false, iniName); + mGenerateBoneCollision = GetIniValue(NifExportSection, "GenerateBoneCollision", false, iniName); + } } diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index f081dde..a13f1df 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -2,6 +2,9 @@ #include "AppSettings.h" #include "niutils.h" +#include "obj/BSXFlags.h" +#include "obj/BSBound.h" + int Exporter::mVersion=013; bool Exporter::mSelectedOnly=false; bool Exporter::mTriStrips=true; @@ -23,39 +26,60 @@ bool Exporter::mSortNodesToEnd=false; string Exporter::mGameName = "User"; string Exporter::mNifVersion = "20.0.0.5"; int Exporter::mNifUserVersion = 0; +bool Exporter::mSkeletonOnly=false; +bool Exporter::mExportCameras=false; +bool Exporter::mGenerateBoneCollision=false; Exporter::Exporter(Interface *i, AppSettings *appSettings) : mI(i), mAppSettings(appSettings) { } + Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) { //root->SetName("Scene Root"); - if (mExportCollision) + int nifVersion = GetVersion(Exporter::mNifVersion); + mIsBethesda = (nifVersion == VER_20_0_0_5 || nifVersion == VER_20_0_0_4) && (Exporter::mNifUserVersion == 11); + + CalcBoundingBox(node, mBoundingBox); + + if (mSkeletonOnly && mIsBethesda) + { + BSBoundRef bsb = CreateNiObject<BSBound>(); + bsb->SetName("BBX"); + bsb->SetCenter( TOVECTOR3(mBoundingBox.Center()) ); + bsb->SetDimensions( TOVECTOR3(mBoundingBox.Width() / 2.0f) ); + root->AddExtraData(DynamicCast<NiExtraData>(bsb)); + + BSXFlagsRef bsx = CreateNiObject<BSXFlags>(); + bsx->SetName("BSX"); + bsx->SetFlags( 0x00000007 ); + root->AddExtraData(DynamicCast<NiExtraData>(bsx)); + } + else if (mExportCollision && mIsBethesda) { BSXFlagsRef bsx = CreateNiObject<BSXFlags>(); bsx->SetName("BSX"); - bsx->SetFlags(0x00000002); + bsx->SetFlags( 0x00000002 ); root->AddExtraData(DynamicCast<NiExtraData>(bsx)); } 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)); - } + //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; - Result result; - result = exportMeshes(root, node); - if (result != Ok) - return result; + Result result = exportNodes(root, node); + if (result != Ok) + return result; if (mExportCollision) { @@ -78,122 +102,75 @@ Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) return Ok; } -#if 0 - -Exporter::Result Exporter::exportMeshes(NiNodeRef &parent, INode *node) +// Primary recursive decent routine +Exporter::Result Exporter::exportNodes(NiNodeRef &parent, INode *node) { - bool coll = npIsCollision(node); - if ((coll && !mExportCollision) || - (node->IsHidden() && !mExportHidden && !coll) || - (mSelectedOnly && !node->Selected())) - return Skip; - - TimeValue t = 0; - NiNodeRef prevParent = parent; - if (!coll && node->IsGroupHead()) - { - NiNodeRef n = DynamicCast<NiNode>(CreateBlock("NiNode")); - Matrix33 rot; - Vector3 trans; - nodeTransform(rot, trans, node, t); - n->SetLocalRotation(rot); - n->SetLocalTranslation(trans); - string name = (char*)node->GetName(); - n->SetName(name); - - parent->AddChild(DynamicCast<NiAVObject>(n)); - parent = n; - } - - Result result; - - ObjectState os = node->EvalWorldState(t); - if (os.obj) - { - // We look at the super class ID to determine the type of the object. - switch(os.obj->SuperClassID()) - { - case GEOMOBJECT_CLASS_ID: -/* if (os.obj->ClassID() == SCUBA_CLASS_ID) - { - float radius = 0; - float height = 0; - IParamArray *params = os.obj->GetParamBlock(); - params->GetValue(os.obj->GetParamBlockIndex(CAPSULE_RADIUS), 0, radius, FOREVER); - params->GetValue(os.obj->GetParamBlockIndex(CAPSULE_HEIGHT), 0, height, FOREVER); - - int foo=1+2; - } else - if (os.obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0)) - { - float length = 0; - float height = 0; - float width = 0; - - IParamArray *params = os.obj->GetParamBlock(); - params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_LENGTH), 0, length, FOREVER); - params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_HEIGHT), 0, height, FOREVER); - params->GetValue(os.obj->GetParamBlockIndex(BOXOBJ_WIDTH), 0, width, FOREVER); - - int foo=1+2; - - } else - if (os.obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0)) - { - float radius = 0; - - IParamArray *params = os.obj->GetParamBlock(); - params->GetValue(os.obj->GetParamBlockIndex(SPHERE_RADIUS), 0, radius, FOREVER); - - int foo=1+2; - - } else - { -*/ - if (!coll) - { - - result = exportMesh(parent, node, t); - if (result != Ok) - return result; - } /*else - { - - if (!makeCollisionHierarchy(mNiRoot, node, t)) - return Error; - } - } -*/ - break; -/* - case CAMERA_CLASS_ID: - if (GetIncludeObjCamera()) ExportCameraObject(node, indentLevel); - break; - case LIGHT_CLASS_ID: - if (GetIncludeObjLight()) ExportLightObject(node, indentLevel); - break; - case SHAPE_CLASS_ID: - if (GetIncludeObjShape()) ExportShapeObject(node, indentLevel); - break; - case HELPER_CLASS_ID: - if (GetIncludeObjHelper()) ExportHelperObject(node, indentLevel); - break; - } -*/ - } - } - - for (int i=0; i<node->NumberOfChildren(); i++) - { - Result result = exportMeshes(parent, node->GetChildNode(i)); - if (result!=Ok && result!=Skip) - return result; - } - - if (node->IsGroupHead()) - parent = prevParent; + bool coll = npIsCollision(node); + if (coll || (node->IsHidden() && !mExportHidden && !coll) || (mSelectedOnly && !node->Selected())) + return Skip; + + bool local = !mFlattenHierarchy; + NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent; + + NiNodeRef newParent; + TimeValue t = 0; + ObjectState os = node->EvalWorldState(t); + + // Always skip bones and bipeds + SClass_ID scid = node->SuperClassID(); + Class_ID ncid = node->ClassID(); + TSTR nodeName = node->GetName(); + TSTR nodeClass; node->GetClassName(nodeClass); + + // For some unusual reason, bones named Helper are converted to Meshes and + // lose their Bone properties except a new node named Bone seem to show up + if (node->IsBoneShowing()) + newParent = exportBone(nodeParent, node); + else if (os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) + { + TSTR objClass; + os.obj->GetClassName(objClass); + SClass_ID oscid = os.obj->SuperClassID(); + Class_ID oncid = os.obj->ClassID(); + if ( os.obj + && ( os.obj->ClassID() == BONE_OBJ_CLASSID + || os.obj->ClassID() == Class_ID(BONE_CLASS_ID,0) + || os.obj->ClassID() == Class_ID(0x00009125,0) /* Biped Twist Helpers */ + ) + ) + { + newParent = exportBone(nodeParent, node); + } + else if (!mSkeletonOnly) + { + newParent = (mExportExtraNodes) ? makeNode(nodeParent, node, local) : nodeParent; + + Result result; + result = exportMesh(newParent, node, t); + if (result != Ok) + return result; + } + } + else if (mExportCameras && os.obj && os.obj->SuperClassID()==CAMERA_CLASS_ID) + { + newParent = makeNode(nodeParent, node, local); + } + else if (mExportLights && os.obj && os.obj->SuperClassID()==LIGHT_CLASS_ID) + { + return exportLight(nodeParent, node, (GenLight*)os.obj); + } + else if (isMeshGroup(node) && local) // only create node if local + { + newParent = makeNode(parent, node, local); + } + else + newParent = parent; - return Ok; + for (int i=0; i<node->NumberOfChildren(); i++) + { + Result result = exportNodes(newParent, node->GetChildNode(i)); + if (result!=Ok && result!=Skip) + return result; + } + return Ok; } - -#endif diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index 36a4bfd..44dd7b7 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -53,6 +53,9 @@ public: static string mGameName; static string mNifVersion; static int mNifUserVersion; + static bool mSkeletonOnly; + static bool mExportCameras; + static bool mGenerateBoneCollision; Exporter(Interface *i, AppSettings *appSettings); @@ -99,9 +102,11 @@ public: AppSettings *mAppSettings; NodeMap mNodeMap; CallbackList mPostExportCallbacks; + bool mIsBethesda; + Box3 mBoundingBox; + Result exportNodes(NiNodeRef &root, INode *node); Result exportCollision(NiNodeRef &root, INode *node); - Result exportMeshes(NiNodeRef &root, INode *node); /* utility functions */ Mtl *getMaterial(INode *node, int subMtl); @@ -109,6 +114,7 @@ public: void convertMatrix(Matrix33 &dst, const Matrix3 &src); void nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true); void nodeTransform(QuaternionXYZW &rot, Vector3 &trans, INode *node, TimeValue t, bool local=true); + Matrix3 getTransform(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); @@ -120,6 +126,8 @@ public: bool isCollisionGroup(INode *maxNode, bool root=true); // returns true if the node contains meshes bool isMeshGroup(INode *maxNode, bool root=true); + void CalcBoundingBox(INode *node, Box3& box, int all=1); + void CalcBoundingSphere(INode *node, Point3 center, float& radius, int all=1); /* tristrips */ void strippify(TriStrips &strips, vector<Vector3> &verts, vector<Vector3> &norms, const Triangles &tris); @@ -150,18 +158,18 @@ public: /* havok & collision */ int addVertex(vector<Vector3> &verts, vector<Vector3> &vnorms, const Point3 &pt, const Point3 &norm); void addFace(Triangles &tris, vector<Vector3> &verts, vector<Vector3> &vnorms, - int face, const int vi[3], Mesh *mesh); + int face, const int vi[3], Mesh *mesh, Matrix3& tm); bool makeCollisionHierarchy(NiNodeRef &parent, INode *node, TimeValue t); /* creates a bhkRigidBody */ bhkRigidBodyRef makeCollisionBody(INode *node); /* creates a collision shape from a node */ - bhkSphereRepShapeRef makeCollisionShape(INode *node); + bhkSphereRepShapeRef makeCollisionShape(INode *node, const Matrix3& tm = Matrix3::Identity); - bhkSphereRepShapeRef makeTriStripsShape(INode *node); - bhkSphereRepShapeRef makeBoxShape(Object *obj); - bhkSphereRepShapeRef makeSphereShape(Object *obj); - bhkSphereRepShapeRef makeCapsuleShape(Object *obj); + bhkSphereRepShapeRef makeTriStripsShape(INode *node, const Matrix3& tm); + bhkSphereRepShapeRef makeBoxShape(Object *obj, const Matrix3& tm); + bhkSphereRepShapeRef makeSphereShape(Object *obj, const Matrix3& tm); + bhkSphereRepShapeRef makeCapsuleShape(Object *obj, const Matrix3& tm); /* skin export */ bool makeSkin(NiTriBasedGeomRef shape, INode *node, FaceGroup &grp, TimeValue t); @@ -174,6 +182,8 @@ public: bool exportUPB(NiNodeRef &root, INode *node); bool removeUnreferencedBones(NiNodeRef node); void sortNodes(NiNodeRef node); + NiNodeRef exportBone(NiNodeRef parent, INode *node); + Result exportLight(NiNodeRef root, INode *node, GenLight* light); }; #endif diff --git a/NifExport/KfExport.cpp b/NifExport/KfExport.cpp index 52c73e2..c865cc3 100644 --- a/NifExport/KfExport.cpp +++ b/NifExport/KfExport.cpp @@ -110,17 +110,17 @@ const TCHAR *KfExport::AuthorName() const TCHAR *KfExport::CopyrightMessage() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } const TCHAR *KfExport::OtherMessage1() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } const TCHAR *KfExport::OtherMessage2() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } unsigned int KfExport::Version() diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index d0aad18..5ed4f0b 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -8,112 +8,12 @@ #include "obj/NiSkinInstance.h" #include "obj/NiSkinData.h" #include "obj/NiSkinPartition.h" -/* - -void FPUtility::GetAlphaVal(void) -{ - if(ip->GetSelNodeCount()<1)return; - INode *node = ip->GetSelNode(0); - if(!node)return; - ObjectState os = node->EvalWorldState(0); - Object *obj = os.obj; - BOOL delMesh = false; - - if (obj && obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { - TriObject * tri = NULL; - tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); - if (obj != tri) - delMesh = true; // we own the copy - if (tri) - { - Mesh * mesh = &(tri->GetMesh()); - MeshDelta md(*mesh); - BOOL support = mesh->mapSupport(MAP_ALPHA); - if(support) - { - UVVert *alpha = mesh->mapVerts(MAP_ALPHA); - for(int i=0;igetNumVerts();i++) - { - float a = alpha[i].x; - } - } - - } - - if (delMesh) - delete tri; - } -} - -*/ - - -Exporter::Result Exporter::exportMeshes(NiNodeRef &parent, INode *node) -{ - bool coll = npIsCollision(node); - if (coll || (node->IsHidden() && !mExportHidden && !coll) || (mSelectedOnly && !node->Selected())) - return Skip; - - bool local = !mFlattenHierarchy; - NiNodeRef nodeParent = mFlattenHierarchy ? mNiRoot : parent; - - NiNodeRef newParent; - TimeValue t = 0; - ObjectState os = node->EvalWorldState(t); - - // Always skip bones and bipeds - SClass_ID scid = node->SuperClassID(); - Class_ID ncid = node->ClassID(); - TSTR nodeName = node->GetName(); - TSTR nodeClass; node->GetClassName(nodeClass); - - // For some unusual reason, bones named Helper are converted to Meshes and - // lose their Bone properties except a new node named Bone seem to show up - if (node->IsBoneShowing() || strmatch(nodeName, "Bone")) - newParent = makeNode(nodeParent, node, local); - else if (os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) - { - TSTR objClass; - os.obj->GetClassName(objClass); - SClass_ID oscid = os.obj->SuperClassID(); - Class_ID oncid = os.obj->ClassID(); - if ( os.obj - && ( os.obj->ClassID() == BONE_OBJ_CLASSID - || os.obj->ClassID() == Class_ID(BONE_CLASS_ID,0) - || os.obj->ClassID() == Class_ID(0x00009125,0) /* Biped Twist Helpers */ - ) - ) - { - newParent = makeNode(nodeParent, node, local); - } - else - { - newParent = (mExportExtraNodes) ? makeNode(nodeParent, node, local) : nodeParent; - - Result result; - result = exportMesh(newParent, node, t); - if (result != Ok) - return result; - } - } - else if (isMeshGroup(node) && local) // only create node if local - { - newParent = makeNode(parent, node, local); - - } - else - newParent = parent; - - for (int i=0; i<node->NumberOfChildren(); i++) - { - Result result = exportMeshes(newParent, node->GetChildNode(i)); - if (result!=Ok && result!=Skip) - return result; - } - - return Ok; -} - +#include "obj/NiBSBoneLODController.h" +#include "obj/NiTransformController.h" +#include "obj/bhkBlendController.h" +#include "obj/bhkBlendCollisionObject.h" +#include "obj/bhkSphereShape.h" +#include "obj/bhkCapsuleShape.h" Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t) { @@ -127,6 +27,7 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue Mesh *mesh = &tri->GetMesh(); + // Note that calling setVCDisplayData will clear things like normals so we set this up first vector<Color4> vertColors; if (mVertexColors) @@ -169,6 +70,8 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->CheckNormals(); + if (specNorms->GetNumNormals() == 0) + mesh->checkNormals(TRUE); } else { mesh->checkNormals(TRUE); } @@ -206,6 +109,9 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue break; } + if (node->IsHidden()) + shape->SetHidden(true); + shape->SetName(name); shape->SetLocalTransform(tm); makeSkin(shape, node, grp->second, t); @@ -263,7 +169,7 @@ int Exporter::addVertex(FaceGroup &grp, int face, int vi, Mesh *mesh, const Matr Point3 norm; MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); - if (NULL != specNorms) + if (NULL != specNorms && specNorms->GetNumNormals() != 0) norm = specNorms->GetNormal(face, vi); else norm = getVertexNormal(mesh, face, mesh->getRVertPtr(vidx)); @@ -471,3 +377,200 @@ Exporter::Result SkinInstance::execute() shape->GenHardwareSkinInfo(); return Exporter::Ok; } + +static void InitializeTimeController(NiTimeControllerRef ctrl, NiNodeRef parent) +{ + ctrl->SetFrequency(1.0f); + ctrl->SetStartTime(FloatINF); + ctrl->SetStopTime(FloatNegINF); + ctrl->SetPhase(0.0f); + ctrl->SetFlags(0x0C); + ctrl->SetTarget( parent ); + parent->AddController(DynamicCast<NiTimeController>(ctrl)); +} + +static void FillBoneController(Exporter* exporter, NiBSBoneLODControllerRef boneCtrl, INode *node) +{ + for (int i=0; i<node->NumberOfChildren(); i++) + { + INode * child = node->GetChildNode(i); + FillBoneController(exporter, boneCtrl, child); + + TSTR upb; + child->GetUserPropBuffer(upb); + if (!upb.isNull()) + { + // Check for bonelod and add bones to bone controller + stringlist tokens = TokenizeString(upb.data(), "\r\n", true); + for (stringlist::iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { + string& line = (*itr); + if (wildmatch("*#", line)) { // ends with # + stringlist bonelod = TokenizeString(line.c_str(), "#", true); + for (stringlist::iterator token = bonelod.begin(); token != bonelod.end(); ++token) { + if ( wildmatch("??BoneLOD", (*token).c_str())) { + if (++token == bonelod.end()) + break; + if (strmatch("Bone", (*token).c_str())) { + if (++token == bonelod.end()) + break; + int group = 0; + std::stringstream str (*token); + str >> group; + boneCtrl->AddNodeToGroup(group, exporter->getNode(child->GetName())); + } + } + } + } + } + } + } +} + +void InitializeRigidBody(bhkRigidBodyRef body, INode *node) +{ + float value; + if (node->GetUserPropFloat("Mass", value)) + body->SetMass(value); + if (node->GetUserPropFloat("Ellasticity", value)) + body->SetRestitution(value); + if (node->GetUserPropFloat("Friction", value)) + body->SetFriction(value); + if (node->GetUserPropFloat("Unyielding", value)) + body->SetFriction(value); + + body->SetLayer(OblivionLayer(OL_BIPED|0x200)); + body->SetLayerCopy(OblivionLayer(OL_BIPED|0x200)); + + Matrix3 tm = node->GetObjTMAfterWSM(0); + body->SetRotation( TOQUATXYZW(Quat(tm)) ); + body->SetTranslation( TOVECTOR3(tm.GetTrans() / 7.0f) ); +} + +NiNodeRef Exporter::exportBone(NiNodeRef parent, INode *node) +{ + bool local = !mFlattenHierarchy; + NiNodeRef newParent = makeNode(parent, node, local); + + // Special Skeleton Only handling routines + if (mSkeletonOnly) + { + InitializeTimeController(new NiTransformController(), newParent); + + bool isBoneRoot = false; + if (mIsBethesda) + { + // Check for Bone Root + TSTR upb; + node->GetUserPropBuffer(upb); + stringlist tokens = TokenizeString(upb.data(), "\r\n", true); + for (stringlist::iterator itr = tokens.begin(); itr != tokens.end(); ++itr) { + string& line = (*itr); + if (wildmatch("*#", line)) { // ends with # + stringlist bonelod = TokenizeString(line.c_str(), "#", true); + for (stringlist::iterator token = bonelod.begin(); token != bonelod.end(); ++token) { + if (wildmatch("??BoneLOD", (*token).c_str())) { + if (++token == bonelod.end()) + break; + if (strmatch("BoneRoot", (*token).c_str())) { + isBoneRoot = true; + NiBSBoneLODControllerRef boneCtrl = new NiBSBoneLODController(); + InitializeTimeController(boneCtrl, newParent); + FillBoneController(this, boneCtrl, node); + break; + } + } + } + } + } + + if (!isBoneRoot) + InitializeTimeController(new bhkBlendController(), newParent); + + if (mGenerateBoneCollision) + { + Matrix3 tm = node->GetObjTMAfterWSM(0); + + bhkShapeRef shape; + int nc = node->NumberOfChildren(); + if (nc == 0) { + // Nothing + } else if (nc == 1) { + // Capsule + INode *child = node->GetChildNode(0); + Matrix3 ctm = Inverse(tm) * child->GetObjTMAfterWSM(0); + float len = ctm.GetTrans().Length(); + float boxLen = mBoundingBox.Width().Length(); + float ratio = len / boxLen; + if ( ratio < 0.05 ) { + // do nothing + } else if ( ratio < 0.15 ) { + // Perpendicular Capsule + Point3 center = (ctm.GetTrans() / 2.0f) + tm.GetTrans(); + Matrix3 rtm = tm * RotateXMatrix( TORAD(90) ); + rtm.SetTranslate(center); + + Point3 pt1 = VectorTransform( Point3(len, 0.0f, 0.0f), rtm ); + Point3 pt2 = VectorTransform( Point3(-len, 0.0f, 0.0f), rtm ); + float radius = len / 7.0f / 2.0f ; + + bhkCapsuleShapeRef capsule = new bhkCapsuleShape(); + capsule->SetRadius( radius ); + capsule->SetRadius1( radius ); + capsule->SetRadius2( radius ); + capsule->SetFirstPoint( TOVECTOR3(pt1 / 7.0f) ); + capsule->SetSecondPoint( TOVECTOR3(pt2 / 7.0f) ); + capsule->SetMaterial(HAV_MAT_SKIN); + + shape = StaticCast<bhkShape>(capsule); + } else { + // Normal Capsule + Point3 center = (ctm.GetTrans() / 2.0f) + tm.GetTrans(); + } + } else { + // Sphere + float radius = 0.0f; + CalcBoundingSphere(node,tm.GetTrans(), radius, 0); + + bhkSphereShapeRef sphere = new bhkSphereShape(); + sphere->SetRadius(radius / 7.0f); + sphere->SetMaterial(HAV_MAT_SKIN); + shape = StaticCast<bhkShape>(sphere); + } + + if (shape) + { + bhkBlendCollisionObjectRef blendObj = new bhkBlendCollisionObject(); + bhkRigidBodyRef body = new bhkRigidBody(); + + InitializeRigidBody(body, node); + body->SetMotionSystem(MotionSystem(6)); + body->SetQualityType(MO_QUAL_KEYFRAMED); + body->SetShape( StaticCast<bhkShape>(shape) ); + blendObj->SetBody( StaticCast<NiObject>(body) ); + newParent->SetCollisionObject( StaticCast<NiCollisionObject>(blendObj) ); + } + } + } + + + if (wildmatch("Bip??", node->GetName())) + { + NiNodeRef accumNode = new NiNode(); + accumNode->SetName(FormatString("%s NonAccum", node->GetName())); + accumNode->SetLocalTransform(Matrix44::IDENTITY); + newParent->AddChild(DynamicCast<NiAVObject>(accumNode)); + + // Transfer + if (mIsBethesda) { + InitializeTimeController(new bhkBlendController(), accumNode); + accumNode->SetCollisionObject(newParent->GetCollisionObject()); + newParent->SetCollisionObject( NiCollisionObjectRef() ); + } + InitializeTimeController(new NiTransformController(), accumNode); + + newParent = accumNode; + } + } + + return newParent; +} \ No newline at end of file diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index 17d12bd..c434a04 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -93,6 +93,9 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA CheckDlgButton(hWnd, IDC_CHK_HIER, Exporter::mFlattenHierarchy); CheckDlgButton(hWnd, IDC_CHK_REM_BONES, Exporter::mRemoveUnreferencedBones); CheckDlgButton(hWnd, IDC_CHK_SORTNODES, Exporter::mSortNodesToEnd); + CheckDlgButton(hWnd, IDC_CHK_SKEL_ONLY, Exporter::mSkeletonOnly); + CheckDlgButton(hWnd, IDC_CHK_CAMERA, Exporter::mExportCameras); + CheckDlgButton(hWnd, IDC_CHK_BONE_COLL, Exporter::mGenerateBoneCollision); string selection = Exporter::mGameName; string version = Exporter::mNifVersion; @@ -149,6 +152,9 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA Exporter::mFlattenHierarchy = IsDlgButtonChecked(hWnd, IDC_CHK_HIER); Exporter::mRemoveUnreferencedBones = IsDlgButtonChecked(hWnd, IDC_CHK_REM_BONES); Exporter::mSortNodesToEnd = IsDlgButtonChecked(hWnd, IDC_CHK_SORTNODES); + Exporter::mSkeletonOnly = IsDlgButtonChecked(hWnd, IDC_CHK_SKEL_ONLY); + Exporter::mExportCameras = IsDlgButtonChecked(hWnd, IDC_CHK_CAMERA); + Exporter::mGenerateBoneCollision = IsDlgButtonChecked(hWnd, IDC_CHK_BONE_COLL); GetDlgItemText(hWnd, IDC_ED_TEXPREFIX, tmp, MAX_PATH); Exporter::mTexPrefix = tmp; @@ -183,7 +189,7 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA { if (LOWORD(wParam) == IDC_LBL_LINK) { - ShellExecute(hWnd, "open", "http://niftools.sourceforge.net", + ShellExecute(hWnd, "open", "http://www.niftools.org", NULL, NULL, SW_SHOWDEFAULT); } } @@ -246,17 +252,17 @@ const TCHAR *NifExport::AuthorName() const TCHAR *NifExport::CopyrightMessage() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } const TCHAR *NifExport::OtherMessage1() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } const TCHAR *NifExport::OtherMessage2() { - return _T("http://niftools.sourceforge.net"); + return _T("http://www.niftools.org"); } unsigned int NifExport::Version() diff --git a/NifExport/NifExport.rc b/NifExport/NifExport.rc index 4108ce9..5c6fc3a 100755 --- a/NifExport/NifExport.rc +++ b/NifExport/NifExport.rc @@ -73,43 +73,44 @@ END // Dialog // -IDD_PANEL DIALOGEX 0, 0, 207, 187 +IDD_PANEL DIALOGEX 0, 0, 205, 203 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 - GROUPBOX "Export:",IDC_STATIC,7,7,81,97 + GROUPBOX "Export:",IDC_STATIC,7,7,81,107 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 "&Animation",IDC_CHK_ANIMATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,65,67,10 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,14,101,67,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,77,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,89,67,10 + GROUPBOX "Behaviors:",IDC_STATIC,94,7,104,107 CONTROL "Generate &Strips",IDC_CHK_STRIPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,17,88,10 - CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,102,89,88,10 CONTROL "Extra Nodes on Mesh",IDC_CHK_EXTRA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,28,88,11 CONTROL "Add User Prop Buffer",IDC_CHK_UPB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,40,88,11 CONTROL "Flatten Hierarchy",IDC_CHK_HIER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,52,88,10 CONTROL "Remove Extra Bones",IDC_CHK_REM_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,64,88,10 CONTROL "Sort Nodes",IDC_CHK_SORTNODES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,76,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 + CONTROL "&Remap Indices",IDC_CHK_REMAP,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | WS_TABSTOP,102,100,88,10 + CONTROL "Skeleton Only",IDC_CHK_SKEL_ONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,88,71,10 + LTEXT "Default Texture &Prefix:",IDC_STATIC,7,127,71,8 + EDITTEXT IDC_ED_TEXPREFIX,7,138,190,12,ES_AUTOHSCROLL + LTEXT "Game",IDC_STATIC,7,154,66,8 + COMBOBOX IDC_CB_GAME,7,165,105,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Version",IDC_STATIC,117,154,39,8 + EDITTEXT IDC_CB_VERSION,117,165,45,12,ES_AUTOHSCROLL + LTEXT "User",IDC_STATIC,167,154,25,8 + EDITTEXT IDC_CB_USER_VERSION,167,165,30,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "&Export",IDOK,5,182,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,182,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,103,182,95,14,SS_NOTIFY | SS_CENTERIMAGE + EDITTEXT IDC_ED_WELDTHRESH,185,118,11,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | WS_DISABLED + LTEXT "Auto-&Weld",IDC_LBL_WELDTHRESH,175,118,8,8,NOT WS_VISIBLE | WS_DISABLED + CONTROL "Gen. Bone Collision",IDC_CHK_BONE_COLL,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,100,118,73,10 END @@ -124,9 +125,9 @@ BEGIN IDD_PANEL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 200 + RIGHTMARGIN, 198 TOPMARGIN, 7 - BOTTOMMARGIN, 180 + BOTTOMMARGIN, 196 END END #endif // APSTUDIO_INVOKED diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index b310bc0..4c16184 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -1,4 +1,9 @@ #include "pch.h" +#include <obj/NiLight.h> +#include <obj/NiAmbientLight.h> +#include <obj/NiPointLight.h> +#include <obj/NiDirectionalLight.h> +#include <obj/NiSpotLight.h> bool Exporter::TMNegParity(const Matrix3 &m) { @@ -56,15 +61,21 @@ void Exporter::convertMatrix(Matrix33 &dst, const Matrix3 &src) r2.x, r2.y, r2.z); } +Matrix3 Exporter::getTransform(INode *node, TimeValue t, bool local) +{ + Matrix3 tm = node->GetObjTMAfterWSM(t); + if (local) + { + Matrix3 pm = node->GetParentTM(t); + pm.Invert(); + tm *= pm; + } + return tm; +} + void Exporter::nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local) { - Matrix3 tm = node->GetObjTMAfterWSM(t); - if (local) - { - Matrix3 pm = node->GetParentTM(t); - pm.Invert(); - tm *= pm; - } + Matrix3 tm = getTransform(node, t, local); convertMatrix(rot, tm); trans.Set(tm.GetTrans().x, tm.GetTrans().y, tm.GetTrans().z); } @@ -255,4 +266,149 @@ void Exporter::sortNodes(NiNodeRef node) vector<NiNodeRef> children = DynamicCast<NiNode>(node->GetChildren()); for (vector<NiNodeRef>::iterator itr = children.begin(); itr != children.end(); ++itr) sortNodes(*itr); -} \ No newline at end of file +} + + +Exporter::Result Exporter::exportLight(NiNodeRef parent, INode *node, GenLight* light) +{ + TimeValue t = 0; + NiLightRef niLight; + switch (light->Type()) + { + case OMNI_LIGHT: + { + if (light->GetAmbientOnly()) + { + niLight = new NiAmbientLight(); + } + else + { + NiPointLightRef pointLight = new NiPointLight(); + float atten = light->GetAtten(t, ATTEN_START); + switch (light->GetDecayType()) + { + case 0: pointLight->SetConstantAttenuation(1.0f); break; + case 1: pointLight->SetLinearAttenuation( atten / 4.0f ); break; + case 2: pointLight->SetQuadraticAttenuation( sqrt(atten / 4.0f) ); break; + } + niLight = StaticCast<NiLight>(pointLight); + } + } + break; + case TSPOT_LIGHT: + case FSPOT_LIGHT: + niLight = new NiSpotLight(); + break; + case DIR_LIGHT: + case TDIR_LIGHT: + niLight = new NiDirectionalLight(); + break; + } + if (niLight == NULL) + return Skip; + + niLight->SetName(node->GetName()); + + Matrix3 tm = getTransform(node, t, !mFlattenHierarchy); + niLight->SetLocalTransform( TOMATRIX4(tm, false) ); + + niLight->SetDimmer( light->GetIntensity(0) ); + Color3 rgbcolor = TOCOLOR3( light->GetRGBColor(0) ); + if (light->GetAmbientOnly()) + { + niLight->SetDiffuseColor(Color3(0,0,0)); + niLight->SetSpecularColor(Color3(0,0,0)); + niLight->SetAmbientColor(rgbcolor); + } + else + { + niLight->SetDiffuseColor(rgbcolor); + niLight->SetSpecularColor(rgbcolor); + niLight->SetAmbientColor(Color3(0,0,0)); + } + parent->AddChild( DynamicCast<NiAVObject>(niLight) ); + return Ok; +} + +void Exporter::CalcBoundingBox(INode *node, Box3& box, int all) +{ + if (NULL == node) + return; + + Matrix3 tm = node->GetObjTMAfterWSM(0); + if (node->IsBoneShowing()) { + box.IncludePoints(&tm.GetTrans(), 1, NULL); + } else { + if (Object *o = node->GetObjectRef()) { + if (o->SuperClassID()==GEOMOBJECT_CLASS_ID) { + if ( o->ClassID() == BONE_OBJ_CLASSID + || o->ClassID() == Class_ID(BONE_CLASS_ID,0) + || o->ClassID() == Class_ID(0x00009125,0) /* Biped Twist Helpers */ + ) + { + box.IncludePoints(&tm.GetTrans(), 1, NULL); + } + else + { + Box3 local; + o->GetLocalBoundBox(0, node, mI->GetActiveViewport(), local); + box.IncludePoints(&local.Min(), 1, NULL); + box.IncludePoints(&local.Max(), 1, NULL); + } + } + else if (mExportCameras && o->SuperClassID()==CAMERA_CLASS_ID) + { + box.IncludePoints(&tm.GetTrans(), 1, NULL); + } + } + } + if (all < 0) + return; + + all = (all>0 ? all : -1); + for (int i=0; i<node->NumberOfChildren(); i++) { + CalcBoundingBox(node->GetChildNode(i), box, all ); + } +} + +void Exporter::CalcBoundingSphere(INode *node, Point3 center, float& radius, int all) +{ + if (NULL == node) + return; + + Matrix3 tm = node->GetObjTMAfterWSM(0); + Point3 pt = (tm.GetTrans() - center); + float len = pt.Length(); + + if (node->IsBoneShowing()) { + radius = max(len, radius); + } else { + if (Object *o = node->GetObjectRef()) { + if (o->SuperClassID()==GEOMOBJECT_CLASS_ID) { + if ( o->ClassID() == BONE_OBJ_CLASSID + || o->ClassID() == Class_ID(BONE_CLASS_ID,0) + || o->ClassID() == Class_ID(0x00009125,0) /* Biped Twist Helpers */ + ) + { + radius = max(len, radius); + } + else + { + radius = max(len, radius); + } + } + else if (mExportCameras && o->SuperClassID()==CAMERA_CLASS_ID) + { + radius = max(len, radius); + } + } + } + if (all < 0) + return; + + all = (all>0 ? all : -1); + for (int i=0; i<node->NumberOfChildren(); i++) { + CalcBoundingSphere(node->GetChildNode(i), center, radius, all ); + } +} + diff --git a/NifExport/resource.h b/NifExport/resource.h index 26b1288..2aeda38 100755 --- a/NifExport/resource.h +++ b/NifExport/resource.h @@ -31,8 +31,11 @@ #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_CHK_SKEL_ONLY 1024 +#define IDC_CHK_CAMERA 1025 +#define IDC_CHK_SKEL_ONLY2 1026 +#define IDC_CHK_BONE_COLL 1026 #define IDC_COLOR 1456 #define IDC_EDIT 1490 #define IDC_SPIN 1496 @@ -43,7 +46,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1024 +#define _APS_NEXT_CONTROL_VALUE 1025 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 590949b..72ee9f4 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -11,10 +11,13 @@ HISTORY: *> Copyright (c) 2006, All Rights Reserved. **********************************************************************/ #include "stdafx.h" +#include <IFrameTagManager.h> +#include <notetrck.h> #include "MaxNifImport.h" #include "NIFImporter.h" #include "KFMImporter.h" #include "KFImporter.h" +#include "AnimKey.h" #include <obj/NiInterpolator.h> #include <obj/NiTransformInterpolator.h> #include <obj/NiTransformData.h> @@ -35,7 +38,12 @@ enum { IPOS_W_REF = 3, }; -#include "AnimKey.h" +void* operator new(size_t size, NoteKey* stub ) +{ return MAX_new(size); } + +void operator delete(void* memblock, NoteKey* stub ) +{ return MAX_delete(memblock); } + struct AnimationImport { @@ -135,6 +143,138 @@ void NifImporter::ClearAnimation(INode *node) } } } +void NifImporter::ClearAnimation() +{ + if (clearAnimation) + { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + + int n = tagMgr->GetTagCount(); + for (int i=n-1; i>=0; --i){ + tagMgr->DeleteTag( tagMgr->GetTagID(i) ); + } + } + ClearAnimation(gi->GetRootNode()); + } +} + +FPValue GetScriptedProperty( FPValue& thing, TCHAR* propName ) { + init_thread_locals(); + push_alloc_frame(); + two_value_locals( thingValue, propNameValue ); + save_current_frames(); + trace_back_active = FALSE; + + FPValue retVal( TYPE_INT, 0 ); + BOOL isUndefined = ((thing.type==TYPE_VALUE) && (thing.v==&undefined)); + if( (thing.i!=0) && (!isUndefined) ) try { //Safe handling for NULL + vl.thingValue = InterfaceFunction::FPValue_to_val( thing ); + vl.propNameValue = Name::intern( propName ); + vl.thingValue = vl.thingValue->get_property( &vl.propNameValue, 1 ); + vl.thingValue->to_fpvalue( retVal ); + } + 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 retVal; +} + +Value* GetFunction( Value* thing, TCHAR* funcName ) { + init_thread_locals(); + push_alloc_frame(); + one_value_local( funcNameValue ); + save_current_frames(); + trace_back_active = FALSE; + + Value* retval = NULL; + if( (thing!=0) ) try { //Safe handling for NULL + vl.funcNameValue = Name::intern( funcName ); + retval = thing->get_property( &vl.funcNameValue, 1 ); + } + 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 retval; +} + +static FPValue myAddNewNoteKey(Value* noteTrack, int frame) +{ + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + five_value_locals(name, fn, track, frame, result); + save_current_frames(); + trace_back_active = FALSE; + + FPValue retVal( TYPE_INT, 0 ); + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("addNewNoteKey")); + vl.fn = globals->get(vl.name); + + // For some reason we get a global thunk back, so lets + // check the cell which should point to the function. + // Just in case if it points to another global thunk + // try it again. + while (vl.fn != NULL && is_globalthunk(vl.fn)) + vl.fn = static_cast<GlobalThunk*>(vl.fn)->cell; + while (vl.fn != NULL && is_constglobalthunk(vl.fn)) + vl.fn = static_cast<ConstGlobalThunk*>(vl.fn)->cell; + + // Now we should have a MAXScriptFunction, which we can + // call to do the actual conversion. If we didn't + // get a MAXScriptFunction, we can't convert. + if (vl.fn != NULL && vl.fn->_is_function()) { + Value* args[4]; + + // Ok. convertToArchMat takes one parameter, the material + // and an optional keyword paramter, replace, which tells + // convertToArchMat whether to replace all reference to + // the old material by the new one. + args[0] = vl.track = noteTrack; // The original material + args[1] = Integer::intern(frame); + args[2] = &keyarg_marker; // Separates keyword params from mandatory + + // Call the funtion and save the result. + vl.result = vl.fn->apply(args, 2); + + // If the result isn't NULL, try to convert it to a material. + // If the convesion fails, an exception will be thrown. + if (vl.result != NULL) + vl.result->to_fpvalue(retVal); + } + } catch (...) { + clear_error_source_data(); + restore_current_frames(); + MAXScript_signals = 0; + if (progress_bar_up) + MAXScript_interface->ProgressEnd(), progress_bar_up = FALSE; + } + + // Magic Max Script stuff to clear the frame and locals. + pop_value_locals(); + pop_alloc_frame(); + + return retVal; +} bool KFMImporter::ImportAnimation() { @@ -151,8 +291,89 @@ bool KFMImporter::ImportAnimation() float maxTime = 0.0f; NiControllerSequenceRef cntr = (*itr); + float start = cntr->GetStartTime(); + float stop = cntr->GetStopTime(); + float total = (stop - start); + vector<ControllerLink> links = cntr->GetControllerData(); + NiTextKeyExtraDataRef textKeyData = cntr->GetTextKeyExtraData(); + vector<StringKey> textKeys = textKeyData->GetKeys(); + if (!textKeys.empty()) { + + if (addNoteTracks) { + string target = cntr->GetTargetName(); + if ( INode *n = gi->GetINodeByName(target.c_str()) ) { + + TSTR script; + script += + "fn getActorManager obj = (\n" + " local nt = undefined\n" + " n = numNoteTracks obj\n" + " for i = 1 to n do (\n" + " local nt = getNoteTrack obj i\n" + " if (nt.name == \"ActorManager\") then ( return nt )\n" + " )\n" + " nt = notetrack \"ActorManager\"\n" + " addNoteTrack obj nt\n" + " return nt\n" + ")\n" + "fn addNoteKey nt frame tag = (\n" + " local Key = addNewNoteKey nt.keys frame\n" + " Key.value = tag\n" + ")\n"; + + script += FormatText("nt = getActorManager $'%s'\n", target.c_str()); + + for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { + TimeValue t = TimeToFrame(time + (*itr).time) + 1; + + if (wildmatch("start*", (*itr).data)){ + stringlist args = TokenizeCommandLine((*itr).data.c_str(), true); + if (args.empty()) continue; + bool hasName = false; + bool hasLoop = false; + CycleType ct = cntr->GetCycleType(); + for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { + if (strmatch("-name", *itr)) { + if (++itr == args.end()) break; + hasName = true; + } else if (strmatch("-loop", *itr)) { + hasLoop = true; + } + } + if (!hasName) { + string name = cntr->GetName(); + if (name.empty()) + name = FormatString("EMPTY_SEQUENCE_AT_%df", int(t * FramesPerSecond / TicksPerFrame) ); + args.push_back("-name"); + args.push_back(name); + } + if (!hasLoop && ct == CYCLE_LOOP) { + args.push_back("-loop"); + } + + string line = JoinCommandLine(args); + script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, line.c_str()); + } else { + script += FormatText("addNoteKey nt (%d/ticksPerFrame) \"%s\"\n", t, (*itr).data.c_str()); + } + + //NoteKey *key = new NoteKey(TimeToFrame(time + (*itr).time), (*itr).data.c_str(), 0); + //nt->keys.Append(1, &key); + } + ExecuteMAXScriptScript(script, TRUE, NULL); + } + } + + if (addTimeTags) { + if (IFrameTagManager *tagMgr = (IFrameTagManager*)GetCOREInterface(FRAMETAGMANAGER_INTERFACE)) { + for (vector<StringKey>::iterator itr=textKeys.begin(); itr != textKeys.end(); ++itr) { + tagMgr->CreateNewTag(const_cast<TCHAR*>((*itr).data.c_str()), TimeToFrame(time + (*itr).time), 0, FALSE); + } + } + } + } for (vector<ControllerLink>::iterator lnk=links.begin(); lnk != links.end(); ++lnk) { string name = (*lnk).targetName; @@ -175,10 +396,6 @@ bool KFMImporter::ImportAnimation() INode *n = gi->GetINodeByName(name.c_str()); - float start = cntr->GetStartTime(); - float stop = cntr->GetStopTime(); - float total = (stop - start); - NiKeyframeDataRef data; Point3 p; Quat q; float s; if (ai.GetTransformData(*lnk, name, data, p, q, s)) { diff --git a/NifImport/ImportLights.cpp b/NifImport/ImportLights.cpp new file mode 100644 index 0000000..a48feb3 --- /dev/null +++ b/NifImport/ImportLights.cpp @@ -0,0 +1,116 @@ +/********************************************************************** +*< +FILE: ImportSkeleton.cpp + +DESCRIPTION: Skeleton import routines + +CREATED BY: tazpn (Theo) + +HISTORY: + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#include "stdafx.h" +#include "MaxNifImport.h" +#include <obj/NiLight.h> +#include <obj/NiAmbientLight.h> +#include <obj/NiPointLight.h> +#include <obj/NiDirectionalLight.h> +#include <obj/NiSpotLight.h> +#include <float.h> +#include <dummy.h> + +using namespace Niflib; + +// Targeted Lights +// Normal Lights +static GenLight *CreateLight(Interface *gi, const NiLightRef& light, int lightType) +{ + if (GenLight *ob = gi->CreateLightObject(lightType)) { + float dimmer = light->GetDimmer(); + Point3 ambient = TOPOINT3(light->GetAmbientColor()); + Point3 diffuse = TOPOINT3(light->GetDiffuseColor()); + Point3 specular = TOPOINT3(light->GetSpecularColor()); + Point3 black(0,0,0); + + ob->Enable(1); + ob->SetUseLight(1); + ob->SetIntensity(0, dimmer); + if (diffuse != black) { + ob->SetAffectDiffuse(TRUE); + ob->SetRGBColor(0, diffuse); + } else { + ob->SetAffectDiffuse(FALSE); + } + if (specular != black) { + ob->SetAffectSpecular(TRUE); + ob->SetRGBColor(0, specular); + } else { + ob->SetAffectSpecular(FALSE); + } + return ob; + } + return NULL; +} + +bool NifImporter::ImportLights(NiNodeRef node) +{ + bool ok = false; + vector<NiAVObjectRef> children = node->GetChildren(); + ok |= ImportLights(DynamicCast<NiLight>(children)); + vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); + for (vector<NiNodeRef>::iterator itr=childNodes.begin(), end=childNodes.end(); itr != end; ++itr) + ok |= ImportLights(*itr); + return ok; +} + +bool NifImporter::ImportLights(vector<NiLightRef> lights) +{ + bool ok = false; + for (vector<NiLightRef>::iterator itr=lights.begin(), end=lights.end(); itr != end; ++itr) + { + GenLight *ob = NULL; + NiLightRef& light = (*itr); + + if (light->IsSameType(NiPointLight::TypeConst())){ + ob = CreateLight(gi, light, OMNI_LIGHT); + NiPointLightRef ptLight = light; + float c = ptLight->GetConstantAttenuation(); + float l = ptLight->GetLinearAttenuation(); + float q = ptLight->GetQuadraticAttenuation(); + if (c != 0.0f){ + ob->SetDecayType(0); + } else if (l != 0.0f) { + ob->SetDecayType(1); + ob->SetUseAtten(1); + ob->SetAtten(0, ATTEN_START, 4.0f/l); + } else if (q != 0.0f) { + ob->SetDecayType(2); + ob->SetAtten(0, ATTEN_START, 4.0f/(l*l)); + } + } else if (light->IsSameType(NiDirectionalLight::TypeConst())){ + ob = CreateLight(gi, light, DIR_LIGHT); + } else if (light->IsSameType(NiAmbientLight::TypeConst())){ + ob = CreateLight(gi, light, OMNI_LIGHT); + ob->SetAmbientOnly(TRUE); + } else if (light->IsSameType(NiSpotLight::TypeConst())){ + ob = CreateLight(gi, light, FSPOT_LIGHT); + } + if (INode *n = gi->CreateObjectNode(ob)) { + string name = light->GetName(); + if (!name.empty()) { + n->SetName(const_cast<TCHAR*>(name.c_str())); + } + Matrix44 m4 = light->GetWorldTransform(); + Vector3 pos; Matrix33 rot; float scale; + m4.Decompose(pos, rot, scale); + Point3 p = TOPOINT3(pos); + Quat q = TOQUAT(rot.AsQuaternion()); + + PosRotScaleNode(n, p, q, scale, prsDefault); + n->Hide(light->GetHidden() ? TRUE : FALSE); + } + ok = true; + } + return ok; +} diff --git a/NifImport/ImportMeshAndSkin.cpp b/NifImport/ImportMeshAndSkin.cpp index ff29936..b759cb7 100644 --- a/NifImport/ImportMeshAndSkin.cpp +++ b/NifImport/ImportMeshAndSkin.cpp @@ -74,8 +74,9 @@ bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triG // uv texture info { int nUVSet = triGeomData->GetUVSetCount(); - int n = 0; - for (int j=0; j<nUVSet; j++){ + int n = 0, j = 0; + //for (int j=0; j<nUVSet; j++){ + if (nUVSet > 0) { vector<TexCoord> texCoords = triGeomData->GetUVSet(j); n = texCoords.size(); mesh.setNumTVerts(n, FALSE); @@ -414,28 +415,33 @@ bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom) int numWeightsPerVertex = 4; IParamBlock2 *params = skinMod->GetParamBlockByID(2/*advanced*/); params->SetValue(0x7/*bone_Limit*/, 0, numWeightsPerVertex); + + // Can get some truly bizarre animations without this in MAX with Civ4 Leaderheads + BOOL ignore = TRUE; + params->SetValue(0xE/*ignoreBoneScale*/, 0, ignore); + //RefTargetHandle advanced = skinMod->GetReference(3); //setMAXScriptValue(advanced, "bone_Limit", 0, numWeightsPerVertex); + Matrix3 geom = TOMATRIX3(triGeom->GetLocalTransform()); Matrix3 m3 = TOMATRIX3(data->GetOverallTransform()); Matrix3 im3 = Inverse(m3); - iskinImport->SetSkinTm(tnode, m3, m3); // ??? + Matrix3 nm3 = im3 * geom; + iskinImport->SetSkinTm(tnode, nm3, nm3); // ??? // Create Bone List Tab<INode*> bones; for (size_t i=0; i<nifBones.size(); ++i){ NiNodeRef bone = nifBones[i]; - Matrix3 b3 = TOMATRIX3(data->GetBoneTransform(i)); - Matrix3 ib3 = Inverse(b3); string name = bone->GetName(); if (INode *boneRef = gi->GetINodeByName(name.c_str())) { bones.Append(1, &boneRef); iskinImport->AddBoneEx(boneRef, TRUE); - // Set Bone Transform - Matrix3 tm = ib3; - if (applyOverallTransformToSkinAndBones) - ib3 *= im3; + //// Set Bone Transform + Matrix3 b3 = TOMATRIX3(data->GetBoneTransform(i)); + Matrix3 ib3 = Inverse(b3); + ib3 *= geom; iskinImport->SetBoneTm(boneRef, ib3, ib3); } } diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index e6c7df6..0649cb4 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -638,9 +638,11 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) || (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TypeConst())) ); if (wildmatch("Camera*", name)) { - if (bone = CreateCamera(name)) { - PosRotScaleNode(bone, p, q, scale, prs); - bone->Hide(node->GetHidden() ? TRUE : FALSE); + if (enableCameras) { + if (bone = CreateCamera(name)) { + PosRotScaleNode(bone, p, q, scale, prs); + bone->Hide(node->GetHidden() ? TRUE : FALSE); + } } }else if (isDummy && createNubsForBones) bone = CreateHelper(name, p); @@ -690,10 +692,11 @@ bool NifImporter::ImportUPB(INode *node, Niflib::NiNodeRef block) list<NiStringExtraDataRef> strings = DynamicCast<NiStringExtraData>(block->GetExtraData()); for (list<NiStringExtraDataRef>::iterator itr = strings.begin(); itr != strings.end(); ++itr){ if (strmatch((*itr)->GetName(), "UserPropBuffer") || strmatch((*itr)->GetName(), "UPB")) { - char buffer[1048], *line = buffer; + char buffer[1048]; istringstream istr((*itr)->GetData(), ios_base::out); while (!istr.eof()) { - line[0] = 0; + char *line = buffer; + buffer[0] = 0; istr.getline(buffer, _countof(buffer)-1); if (LPTSTR equals = _tcschr(line, TEXT('='))){ *equals++ = 0; @@ -702,6 +705,18 @@ bool NifImporter::ImportUPB(INode *node, Niflib::NiNodeRef block) node->SetUserPropString(TSTR(line), TSTR(equals)); ok |= true; } + } else { + Trim(line); + int len = strlen(line); + // Handle bethesda special values? + if (len > 0 && line[len-1] == '#'){ + TSTR buf, value; + node->GetUserPropBuffer(buf); + value.append(line).append("\r\n").append(buf); + if (wildmatch("BSBoneLOD#*", value)) + value[0] = 'N', value[1] = 'i'; // Use NIBoneLOD to be compatible with Civ4 code + node->SetUserPropBuffer(value); + } } } } diff --git a/NifImport/KFImporter.cpp b/NifImport/KFImporter.cpp index 44d73da..43180a3 100644 --- a/NifImport/KFImporter.cpp +++ b/NifImport/KFImporter.cpp @@ -31,10 +31,14 @@ void KFImporter::ReadBlocks() bool KFImporter::DoImport() { - if (clearAnimation) + if (!suppressPrompts) { - ClearAnimation(gi->GetRootNode()); + if (!ShowDialog()) + return true; + ApplyAppSettings(); + SaveIniSettings(); } + ClearAnimation(); return ImportAnimation(); } diff --git a/NifImport/KFMImporter.cpp b/NifImport/KFMImporter.cpp index 3b63d88..dd02b82 100644 --- a/NifImport/KFMImporter.cpp +++ b/NifImport/KFMImporter.cpp @@ -4,6 +4,8 @@ #include "gen/ControllerLink.h" using namespace Niflib; +extern LPCTSTR AnimImportSection; + KFMImporter::KFMImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL SuppressPrompts) : BaseClass() { @@ -29,7 +31,6 @@ void KFMImporter::ReadBlocks() TCHAR buffer[MAX_PATH]; GetFullPathName(name.c_str(), MAX_PATH, buffer, NULL); PathRemoveFileSpec(buffer); -#ifdef USE_UNSUPPORTED_CODE string nif_filename = path + '\\' + kfm.nif_filename; if (_taccess(nif_filename.c_str(), 0) != -1) root = ReadNifTree(nif_filename); @@ -55,7 +56,6 @@ void KFMImporter::ReadBlocks() } } } -#endif } } catch (std::exception&) @@ -68,6 +68,15 @@ void KFMImporter::ReadBlocks() bool KFMImporter::DoImport() { + bool ok = true; + if (!suppressPrompts) + { + if (!ShowDialog()) + return true; + ApplyAppSettings(); + SaveIniSettings(); + } + // might check if blocks exist and if not go ahead and import nif. if (root) { @@ -82,11 +91,14 @@ bool KFMImporter::DoImport() } } - if (clearAnimation) - { - ClearAnimation(gi->GetRootNode()); - } - + ClearAnimation(); return ImportAnimation(); //return BaseClass::DoImport(); } + +void KFMImporter::SaveIniSettings() +{ + SetIniValue(AnimImportSection, "ClearAnimation", clearAnimation); + SetIniValue(AnimImportSection, "AddNoteTracks", addNoteTracks); + SetIniValue(AnimImportSection, "AddTimeTags", addTimeTags); +} \ No newline at end of file diff --git a/NifImport/KFMImporter.h b/NifImport/KFMImporter.h index f07aa80..b673c46 100644 --- a/NifImport/KFMImporter.h +++ b/NifImport/KFMImporter.h @@ -33,7 +33,9 @@ public: // Implemented in ImportAnimation.cpp virtual bool ImportAnimation(); + virtual void SaveIniSettings(); + bool ShowDialog(); std::vector<Niflib::NiControllerSequenceRef> kf; }; diff --git a/NifImport/KfDialog.cpp b/NifImport/KfDialog.cpp new file mode 100644 index 0000000..f127a74 --- /dev/null +++ b/NifImport/KfDialog.cpp @@ -0,0 +1,89 @@ +/********************************************************************** +*< +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 "KFMImporter.h" +#include "resource.h" +#include "shellapi.h" + +using namespace Niflib; + +static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { + static KFMImporter *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 = (KFMImporter *)lParam; + CenterWindow(hWnd,GetParent(hWnd)); + + CheckDlgButton(hWnd, IDC_CHK_CLEARANIM, imp->clearAnimation); + CheckDlgButton(hWnd, IDC_CHK_KEYNOTES, imp->addNoteTracks); + CheckDlgButton(hWnd, IDC_CHK_TIMETAGS, imp->addTimeTags); + } + return TRUE; + + case WM_CLOSE: + { + EndDialog(hWnd, dlgRes); + } + return TRUE; + + case WM_COMMAND : + { + if (HIWORD(wParam) == BN_CLICKED) + { + switch (LOWORD(wParam)) + { + case IDOK: + imp->clearAnimation = IsDlgButtonChecked(hWnd, IDC_CHK_CLEARANIM) ? true : false; + imp->addNoteTracks = IsDlgButtonChecked(hWnd, IDC_CHK_KEYNOTES) ? true : false; + imp->addTimeTags = IsDlgButtonChecked(hWnd, IDC_CHK_TIMETAGS) ? true : false; + EndDialog(hWnd, dlgRes=IDOK); + return TRUE; + + case IDCANCEL: + EndDialog(hWnd, dlgRes=IDCANCEL); + return TRUE; + } + } + else if (HIWORD(wParam) == STN_CLICKED) + { + if (LOWORD(wParam) == IDC_LBL_LINK) + { + ShellExecute(hWnd, "open", "http://www.niftools.org", NULL, NULL, SW_SHOWDEFAULT); + } + } + } + break; + } + return FALSE; +} + +bool KFMImporter::ShowDialog() +{ + return (IDOK == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_KF_PANEL), GetActiveWindow(), MaxNifImportOptionsDlgProc, (LPARAM)this)); +} \ No newline at end of file diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp index 9af93ff..dcb5407 100644 --- a/NifImport/MaxNifImport.cpp +++ b/NifImport/MaxNifImport.cpp @@ -92,11 +92,7 @@ MaxNifImport::~MaxNifImport() int MaxNifImport::ExtCount() { -#ifdef USE_UNSUPPORTED_CODE return 3; -#else - return 2; -#endif } const TCHAR *MaxNifImport::Ext(int n) diff --git a/NifImport/MaxNifImport.h b/NifImport/MaxNifImport.h index 782ff5b..378671d 100644 --- a/NifImport/MaxNifImport.h +++ b/NifImport/MaxNifImport.h @@ -54,6 +54,7 @@ #include "obj\NiSkinData.h" #include "obj\NiSkinInstance.h" #include "obj\NiSkinPartition.h" +#include "obj\NiLight.h" #include "niutils.h" #include "AppSettings.h" diff --git a/NifImport/MaxNifImport.rc b/NifImport/MaxNifImport.rc index 0930a5b..158f7c5 100644 --- a/NifImport/MaxNifImport.rc +++ b/NifImport/MaxNifImport.rc @@ -26,19 +26,19 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Dialog // -IDD_PANEL DIALOGEX 0, 0, 206, 171 +IDD_NIF_PANEL DIALOGEX 0, 0, 218, 193 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 - GROUPBOX "Import:",IDC_STATIC,7,6,81,92 + GROUPBOX "Import:",IDC_STATIC,7,6,81,105 CONTROL "&Skeleton",IDC_CHK_BONES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,16,67,10 CONTROL "S&kin 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 "Co&llision",IDC_CHK_COLL,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,86,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 + CONTROL "Furniture &Markers",IDC_CHK_FURN,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,14,97,67,10 GROUPBOX "Behaviors:",IDC_STATIC,94,6,101,92 CONTROL "Flip U&V",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 @@ -46,15 +46,32 @@ BEGIN 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,84,87,10 - LTEXT "Skeleton:",IDC_STC_SKELETON,7,121,31,8 - EDITTEXT IDC_ED_SKELETON,7,133,171,12,ES_AUTOHSCROLL - PUSHBUTTON "...",IDC_BTN_BROWSE,180,133,19,13 - LTEXT "Game:",IDC_STATIC,7,107,31,8 - COMBOBOX IDC_CB_GAME,47,105,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - DEFPUSHBUTTON "&Import",IDOK,5,150,34,14 - PUSHBUTTON "&Cancel",IDCANCEL,45,150,33,14 - LTEXT "http://niftools.sourceforge.net",IDC_LBL_LINK,93,150,95,14,SS_NOTIFY | SS_CENTERIMAGE + LTEXT "Skeleton:",IDC_STC_SKELETON,7,143,31,8 + EDITTEXT IDC_ED_SKELETON,7,155,171,12,ES_AUTOHSCROLL + PUSHBUTTON "...",IDC_BTN_BROWSE,192,155,19,13 + LTEXT "Game:",IDC_STATIC,7,129,31,8 + COMBOBOX IDC_CB_GAME,47,127,131,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "&Import",IDOK,5,172,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,172,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,93,172,95,14,SS_NOTIFY | SS_CENTERIMAGE CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,73,88,10 + CONTROL "&Lights",IDC_CHK_LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,62,67,10 + CONTROL "Cameras",IDC_CHK_CAMERA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,74,67,10 +END + +IDD_KF_PANEL DIALOGEX 0, 0, 118, 99 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Import KF" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Import:",-1,7,6,104,51 + DEFPUSHBUTTON "&Import",IDOK,5,78,34,14 + PUSHBUTTON "&Cancel",IDCANCEL,45,78,33,14 + LTEXT "http://www.niftools.org",IDC_LBL_LINK,7,61,95,14,SS_NOTIFY | SS_CENTERIMAGE + CONTROL "Clear Animation",IDC_CHK_CLEARANIM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,72,10 + CONTROL "Add Key Notes",IDC_CHK_KEYNOTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,31,72,10 + CONTROL "Add Time Tags",IDC_CHK_TIMETAGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,44,72,10 END @@ -66,12 +83,20 @@ END #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN - IDD_PANEL, DIALOG + IDD_NIF_PANEL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 211 + TOPMARGIN, 7 + BOTTOMMARGIN, 186 + END + + IDD_KF_PANEL, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 199 + RIGHTMARGIN, 111 TOPMARGIN, 7 - BOTTOMMARGIN, 164 + BOTTOMMARGIN, 92 END END #endif // APSTUDIO_INVOKED diff --git a/NifImport/MaxNifImport_VC80.vcproj b/NifImport/MaxNifImport_VC80.vcproj index 245bcbb..93ff0e2 100644 --- a/NifImport/MaxNifImport_VC80.vcproj +++ b/NifImport/MaxNifImport_VC80.vcproj @@ -691,10 +691,6 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl" > - <File - RelativePath=".\KFImporter.h" - > - </File> <File RelativePath=".\resource.h" > @@ -728,6 +724,10 @@ RelativePath=".\ImportCollision.cpp" > </File> + <File + RelativePath=".\ImportLights.cpp" + > + </File> <File RelativePath=".\ImportMeshAndSkin.cpp" > @@ -740,10 +740,18 @@ RelativePath=".\ImportSkeleton.cpp" > </File> + <File + RelativePath=".\KfDialog.cpp" + > + </File> <File RelativePath=".\KFImporter.cpp" > </File> + <File + RelativePath=".\KFImporter.h" + > + </File> <File RelativePath=".\KFMImporter.cpp" > diff --git a/NifImport/NIFImport.cpp b/NifImport/NIFImport.cpp index 872417e..001a36d 100644 --- a/NifImport/NIFImport.cpp +++ b/NifImport/NIFImport.cpp @@ -142,6 +142,8 @@ void NifImporter::LoadIniSettings() flipUVTextures = GetIniValue(NifImportSection, "FlipUVTextures", true); enableSkinSupport = GetIniValue(NifImportSection, "EnableSkinSupport", true); enableCollision = GetIniValue(NifImportSection, "EnableCollision", true); + enableLights = GetIniValue(NifImportSection, "Lights", false); + enableCameras = GetIniValue(NifImportSection, "Cameras", false); vertexColorMode = GetIniValue<int>(NifImportSection, "VertexColorMode", 1); useCiv4Shader = GetIniValue(NifImportSection, "UseCiv4Shader", true); mergeNonAccum = GetIniValue(NifImportSection, "MergeNonAccum", true); @@ -170,6 +172,8 @@ void NifImporter::LoadIniSettings() requireMultipleKeys = GetIniValue(AnimImportSection, "RequireMultipleKeys", true); applyOverallTransformToSkinAndBones = GetIniValue(AnimImportSection, "ApplyOverallTransformToSkinAndBones", true); clearAnimation = GetIniValue(AnimImportSection, "ClearAnimation", true); + addNoteTracks = GetIniValue(AnimImportSection, "AddNoteTracks", true); + addTimeTags = GetIniValue(AnimImportSection, "AddTimeTags", true); // Collision bhkScaleFactor = GetIniValue<float>(CollisionSection, "bhkScaleFactor", 7.0f); @@ -196,6 +200,9 @@ void NifImporter::SaveIniSettings() SetIniValue(NifImportSection, "EnableSkinSupport", enableSkinSupport); SetIniValue(NifImportSection, "VertexColorMode", vertexColorMode); SetIniValue(NifImportSection, "EnableCollision", enableCollision); + SetIniValue(NifImportSection, "Lights", enableLights); + SetIniValue(NifImportSection, "Cameras", enableCameras); + //SetIniValue(NifImportSection, "EnableFurniture", enableAnimations); SetIniValue(NifImportSection, "FlipUVTextures", flipUVTextures); @@ -208,7 +215,7 @@ void NifImporter::SaveIniSettings() SetIniValue(BipedImportSection, "RemoveUnusedImportedBones", removeUnusedImportedBones); SetIniValue(AnimImportSection, "EnableAnimations", enableAnimations); - SetIniValue(BipedImportSection, "ClearAnimation", clearAnimation); + SetIniValue(AnimImportSection, "ClearAnimation", clearAnimation); } INode *NifImporter::GetNode(Niflib::NiNodeRef node) @@ -233,36 +240,6 @@ bool NifImporter::DoImport() 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 (importSkeleton && !skeleton.empty()) { NifImporter skelImport(skeleton.c_str(), i, gi, suppressPrompts); if (skelImport.isValid()) @@ -296,6 +273,11 @@ bool NifImporter::DoImport() ImportBones(rootNode); } + + if (enableLights){ + ok = ImportLights(rootNode); + } + ok = ImportMeshes(rootNode); if (importSkeleton && removeUnusedImportedBones){ @@ -324,12 +306,7 @@ bool NifImporter::DoImport() } } - if (clearAnimation) - { - ClearAnimation(gi->GetRootNode()); - } - - // Kick of animation import + ClearAnimation(); ImportAnimation(); return true; } \ No newline at end of file diff --git a/NifImport/NIFImporter.h b/NifImport/NIFImporter.h index 5f86474..087328b 100644 --- a/NifImport/NIFImporter.h +++ b/NifImport/NIFImporter.h @@ -34,6 +34,8 @@ public: int vertexColorMode; bool useCiv4Shader; bool mergeNonAccum; + bool enableLights; + bool enableCameras; // Biped/Bones related settings bool importBones; @@ -65,6 +67,8 @@ public: bool requireMultipleKeys; bool applyOverallTransformToSkinAndBones; bool clearAnimation; + bool addNoteTracks; + bool addTimeTags; // Collision settings float bhkScaleFactor; @@ -79,8 +83,8 @@ public: void BuildNodes(); // Ini File related routines - void LoadIniSettings(); - void SaveIniSettings(); + virtual void LoadIniSettings(); + virtual void SaveIniSettings(); void ApplyAppSettings(); @@ -110,6 +114,9 @@ public: INode *CreateHelper(const string& name, Point3 startPos); INode *CreateCamera(const string& name); + bool ImportLights(Niflib::NiNodeRef node); + bool ImportLights(vector<Niflib::NiLightRef> lights); + // Primary Collision entry point. Tests for bhk objects bool ImportCollision(Niflib::NiNodeRef node); @@ -121,6 +128,7 @@ public: // Animation Helpers bool ImportAnimation(); + void ClearAnimation(); void ClearAnimation(INode *node); diff --git a/NifImport/NifDialog.cpp b/NifImport/NifDialog.cpp index 2a9629e..2bf1152 100644 --- a/NifImport/NifDialog.cpp +++ b/NifImport/NifDialog.cpp @@ -17,7 +17,7 @@ HISTORY: using namespace Niflib; -BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { +static BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { static NifImporter *imp = NULL; static DWORD dlgRes = IDCANCEL; @@ -44,6 +44,9 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP 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_LIGHTS, imp->enableLights); + CheckDlgButton(hWnd, IDC_CHK_CAMERA, imp->enableCameras); + //CheckDlgButton(hWnd, IDC_CHK_FURN, imp->); CheckDlgButton(hWnd, IDC_CHK_FLIP_UV, imp->flipUVTextures); @@ -92,6 +95,8 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP 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->enableCameras = IsDlgButtonChecked(hWnd, IDC_CHK_CAMERA) ? true : false; + imp->enableLights = IsDlgButtonChecked(hWnd, IDC_CHK_LIGHTS) ? true : false; imp->enableAnimations = IsDlgButtonChecked(hWnd, IDC_CHK_ANIMATION) ? true : false; //IsDlgButtonChecked(hWnd, IDC_CHK_FURN, imp->); @@ -155,8 +160,7 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP { if (LOWORD(wParam) == IDC_LBL_LINK) { - ShellExecute(hWnd, "open", "http://niftools.sourceforge.net", - NULL, NULL, SW_SHOWDEFAULT); + ShellExecute(hWnd, "open", "http://www.niftools.org", NULL, NULL, SW_SHOWDEFAULT); } } else if (HIWORD(wParam) == CBN_SELCHANGE) @@ -186,5 +190,5 @@ BOOL CALLBACK MaxNifImportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LP bool NifImporter::ShowDialog() { - return (IDOK == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PANEL), GetActiveWindow(), MaxNifImportOptionsDlgProc, (LPARAM)this)); + return (IDOK == DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_NIF_PANEL), GetActiveWindow(), MaxNifImportOptionsDlgProc, (LPARAM)this)); } \ No newline at end of file diff --git a/NifImport/resource.h b/NifImport/resource.h index 0d6f568..a608a76 100644 --- a/NifImport/resource.h +++ b/NifImport/resource.h @@ -8,6 +8,8 @@ #define IDS_PARAMS 4 #define IDS_SPIN 5 #define IDD_PANEL 101 +#define IDD_NIF_PANEL 101 +#define IDD_KF_PANEL 102 #define IDC_CLOSEBUTTON 1000 #define IDC_DOSTUFF 1000 #define IDC_EDITHEIGHT 1001 @@ -18,6 +20,7 @@ #define IDC_CHK_FURN 1005 #define IDC_ED_SKELETON 1006 #define IDC_CHK_BIPED 1007 +#define IDC_CHK_LIGHTS 1008 #define IDC_CHK_COLL 1010 #define IDC_LBL_LINK 1011 #define IDC_CHK_VCOLORS 1012 @@ -31,6 +34,9 @@ #define IDC_STC_SKELETON 1021 #define IDC_CHK_REM_BONES 1022 #define IDC_CHK_CLEARANIM 1023 +#define IDC_CHK_KEYNOTES 1024 +#define IDC_CHK_CAMERA 1025 +#define IDC_CHK_TIMETAGS 1026 // Next default values for new objects // diff --git a/NifImport/stdafx.h b/NifImport/stdafx.h index 5b53f29..ccd7e8b 100644 --- a/NifImport/stdafx.h +++ b/NifImport/stdafx.h @@ -22,3 +22,4 @@ #include <shlwapi.h> #include "MaxNifImport.h" +#include "MAX_MemDirect.h" \ No newline at end of file -- GitLab