Skip to content
Snippets Groups Projects
Commit 92599f00 authored by Tazpn's avatar Tazpn
Browse files

o Importer

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