Skip to content
Snippets Groups Projects
Commit 2fe85421 authored by Tazpn's avatar Tazpn
Browse files

Miscellaneous fixes for Skin for DAoC and MW and trying not to breaking Civ4 and Ob.

parent b6f13338
No related branches found
No related tags found
No related merge requests found
MaxPlugins 0.1.2
MaxPlugins 0.1.3
================
This releases introduces an importer and fixes some bugs in the exporter.
This plugin set currently consists of an exporter, importer and a utility
plugin. This is a early release, so expect it to be buggy.
......@@ -26,12 +25,23 @@
choose "Reset XForm" and click "Reset Selected". This should fix it.
Change log
----------
Changes since 0.1
-----------------
- Introduced the importer
0.1.3
-----
o Importer
- Fixed alignment issues when importing Morrowind Armor nifs
- Added initial animation support (only for animations internal to nif, no kf file support yet)
- Fixed numerous issues with bone system (biped is still broken)
- Fixed issues with skin and doac nifs
0.1.2
-----
- Introduced the importer
- Fixed collision generation, turned out that Oblivion
doesn't like NvTriStrip's strips. Thanks to Razorwing
for discovering the bug and Tanguy Fautré for his
......@@ -47,7 +57,7 @@
3D Studio Max 6, 7 and 8
Importer
3d Studio Max 8, untested with previous releases
3d Studio Max 8
Installation
------------
......
......@@ -56,6 +56,10 @@ void AppSettings::ReadSettings(string iniFile)
Skeleton = GetSetting<string>("Skeleton");
useSkeleton = GetSetting<bool>("UseSkeleton", useSkeleton);
goToSkeletonBindPosition = GetSetting<bool>("GoToSkeletonBindPosition", goToSkeletonBindPosition);
disableCreateNubsForBones = GetSetting<bool>("DisableCreateNubsForBones", disableCreateNubsForBones);
applyOverallTransformToSkinAndBones = GetSetting<int>("ApplyOverallTransformToSkinAndBones", -1);
dummyNodeMatches = TokenizeString(GetSetting<string>("DummyNodeMatches").c_str(), ";");
}
string AppSettings::FindImage(const string& fname){
......
......@@ -24,6 +24,7 @@ public:
, parsedImages(false)
, useSkeleton(false)
, goToSkeletonBindPosition(true)
, disableCreateNubsForBones(false)
{}
std::string Name;
......@@ -36,8 +37,11 @@ public:
std::string Skeleton;
bool useSkeleton;
bool goToSkeletonBindPosition;
bool disableCreateNubsForBones;
NameValueCollection Environment;
NameValueCollection imgTable;
stringlist dummyNodeMatches;
int applyOverallTransformToSkinAndBones;
static void Initialize(Interface *gi);
void ReadSettings(std::string iniFile);
......
......@@ -35,6 +35,8 @@ enum {
};
const float FramesPerSecond = 30.0f;
const float FramesIncrement = 1.0f/30.0f;
const int TicksPerFrame = GetTicksPerFrame();
inline TimeValue TimeToFrame(float t) {
......@@ -260,6 +262,9 @@ bool NifImporter::ImportAnimation()
if (!enableAnimations)
return false;
if (nodes.empty())
return false;
AnimationImport ai(*this);
return ai.AddValues(DynamicCast<NiObjectNET>(nodes[0]->GetChildren()));
}
......@@ -267,7 +272,6 @@ bool NifImporter::ImportAnimation()
bool KFMImporter::ImportAnimation()
{
bool ok = false;
const float FramesIncrement = 1.0f/30.0f;
int curFrame = 0;
// Read Kf files
#ifdef USE_UNSUPPORTED_CODE
......@@ -367,10 +371,6 @@ bool AnimationImport::AddValues(NiObjectNETRef nref)
if (NULL == c)
return false;
/* vector<KeyTextValue> tkeys = BuildKeyValues(nref);
if (tkeys.empty())
return false;*/
float time = 0.0f;
list< NiTimeControllerRef > clist = nref->GetControllers();
if (NiTransformControllerRef tc = SelectFirstObjectOfType<NiTransformController>(clist)) {
......@@ -389,13 +389,33 @@ bool AnimationImport::AddValues(NiObjectNETRef nref)
bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
{
vector<Vector3Key> posKeys = data->GetTranslateKeys();
vector<QuatKey> quatKeys = data->GetQuatRotateKeys();
vector<FloatKey> sclKeys = data->GetScaleKeys();
vector<FloatKey> xKeys = data->GetXRotateKeys();
vector<FloatKey> yKeys = data->GetYRotateKeys();
vector<FloatKey> zKeys = data->GetZRotateKeys();
// Require more than one key to import (to avoid zero frame positioning used in mw and daoc
if (ni.requireMultipleKeys &&
!( posKeys.size() > 1
|| quatKeys.size() > 1
|| sclKeys.size() > 1
|| xKeys.size() > 1
|| yKeys.size() > 1
|| zKeys.size() > 1
))
{
return false;
}
// Handle Translation
switch (data->GetTranslateType())
{
case LINEAR_KEY:
if (Control *subCtrl = MakePositionXYZ(c, Class_ID(LININTERP_FLOAT_CLASS_ID,0))) {
vector<FloatKey> xkeys, ykeys, zkeys;
SplitKeys(data->GetTranslateKeys(), xkeys, ykeys, zkeys);
SplitKeys(posKeys, xkeys, ykeys, zkeys);
SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time);
SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time);
SetKeys<ILinFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time);
......@@ -406,7 +426,7 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
case XYZ_ROTATION_KEY:
if (Control *subCtrl = MakePositionXYZ(c, Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) {
vector<FloatKey> xkeys, ykeys, zkeys;
SplitKeys(data->GetTranslateKeys(), xkeys, ykeys, zkeys);
SplitKeys(posKeys, xkeys, ykeys, zkeys);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time);
......@@ -416,7 +436,7 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
case TBC_KEY:
if (Control *subCtrl = MakePositionXYZ(c, Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))) {
vector<FloatKey> xkeys, ykeys, zkeys;
SplitKeys(data->GetTranslateKeys(), xkeys, ykeys, zkeys);
SplitKeys(posKeys, xkeys, ykeys, zkeys);
SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetXController(), xkeys, time);
SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetYController(), ykeys, time);
SetKeys<ITCBFloatKey, FloatKey>(subCtrl->GetZController(), zkeys, time);
......@@ -429,21 +449,21 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
{
case LINEAR_KEY:
if (Control *subCtrl = MakeRotation(c, Class_ID(LININTERP_ROTATION_CLASS_ID,0), Class_ID(LININTERP_FLOAT_CLASS_ID,0))) {
SetKeys<ILinRotKey, QuatKey>(subCtrl, data->GetQuatRotateKeys(), time);
SetKeys<ILinRotKey, QuatKey>(subCtrl, quatKeys, time);
}
break;
case QUADRATIC_KEY:
if (Control *subCtrl = MakeRotation(c, Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) {
SetKeys<IBezQuatKey, QuatKey>(subCtrl, data->GetQuatRotateKeys(), time);
SetKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time);
}
break;
case XYZ_ROTATION_KEY:
if (Control *subCtrl = MakeRotation(c, Class_ID(EULER_CONTROL_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) {
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), data->GetXRotateKeys(), time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), data->GetYRotateKeys(), time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), data->GetZRotateKeys(), time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetXController(), xKeys, time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetYController(), yKeys, time);
SetKeys<IBezFloatKey, FloatKey>(subCtrl->GetZController(), zKeys, time);
}
break;
......@@ -451,11 +471,11 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
if (ni.replaceTCBRotationWithBezier) {
// TCB simply is not working for me. Better off with Bezier as a workaround
if (Control *subCtrl = MakeRotation(c, Class_ID(HYBRIDINTERP_ROTATION_CLASS_ID,0), Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0))) {
SetKeys<IBezQuatKey, QuatKey>(subCtrl, data->GetQuatRotateKeys(), time);
SetKeys<IBezQuatKey, QuatKey>(subCtrl, quatKeys, time);
}
} else {
if (Control *subCtrl = MakeRotation(c, Class_ID(TCBINTERP_ROTATION_CLASS_ID,0), Class_ID(TCBINTERP_FLOAT_CLASS_ID,0))) {
SetKeys<ITCBRotKey, QuatKey>(subCtrl, data->GetQuatRotateKeys(), time);
SetKeys<ITCBRotKey, QuatKey>(subCtrl, quatKeys, time);
}
}
break;
......@@ -465,18 +485,18 @@ bool AnimationImport::AddValues(Control *c, NiKeyframeDataRef data, float time)
{
case LINEAR_KEY:
if (Control *subCtrl = MakeScale(c, Class_ID(LININTERP_SCALE_CLASS_ID,0))) {
SetKeys<ILinScaleKey, FloatKey>(subCtrl, data->GetScaleKeys(), time);
SetKeys<ILinScaleKey, FloatKey>(subCtrl, sclKeys, time);
}
break;
case QUADRATIC_KEY:
case XYZ_ROTATION_KEY:
if (Control *subCtrl = MakeScale(c, Class_ID(HYBRIDINTERP_SCALE_CLASS_ID,0))) {
SetKeys<IBezScaleKey, FloatKey>(subCtrl, data->GetScaleKeys(), time);
SetKeys<IBezScaleKey, FloatKey>(subCtrl, sclKeys, time);
}
break;
case TBC_KEY:
if (Control *subCtrl = MakeScale(c, Class_ID(TCBINTERP_SCALE_CLASS_ID,0))) {
SetKeys<ITCBScaleKey, FloatKey>(subCtrl, data->GetScaleKeys(), time);
SetKeys<ITCBScaleKey, FloatKey>(subCtrl, sclKeys, time);
}
break;
}
......
......@@ -311,6 +311,15 @@ bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom)
if (ISkin *skin = (ISkin *) skinMod->GetInterface(I_SKIN)){
ISkinImportData* iskinImport = (ISkinImportData*) skinMod->GetInterface(I_SKINIMPORTDATA);
Matrix3 m3;
if (applyOverallTransformToSkinAndBones) {
Matrix3 initNodeTM, initObjTM;
initNodeTM.IdentityMatrix(), initObjTM.IdentityMatrix();
skin->GetSkinInitTM(tnode, initNodeTM, false);
skin->GetSkinInitTM(tnode, initObjTM, true);
m3 = TOMATRIX3(data->GetOverallTransform());
iskinImport->SetSkinTm(tnode, initNodeTM * m3, initObjTM * m3);
}
// Create Bone List
Tab<INode*> bones;
int i=0;
......@@ -319,12 +328,16 @@ bool NifImporter::ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom)
if (INode *boneRef = gi->GetINodeByName(name.c_str())) {
bones.Append(1, &boneRef);
iskinImport->AddBoneEx(boneRef, TRUE);
}
// Set Bone Transform
//Matrix3 tm = boneRef->GetObjectTM(0);
//Matrix3 m = TOMATRIX3(data->GetBoneTransform(i));
//iskinImport->SetBoneTm(boneRef, tm, m);
// Set Bone Transform
if (applyOverallTransformToSkinAndBones) {
Matrix3 initNodeTM, initBoneTM;
initNodeTM.IdentityMatrix(), initBoneTM.IdentityMatrix();
skin->GetBoneInitTM(boneRef, initNodeTM, false);
skin->GetBoneInitTM(boneRef, initBoneTM, true);
iskinImport->SetBoneTm(boneRef, initNodeTM * m3, initBoneTM * m3);
}
}
}
ObjectState os = tnode->EvalWorldState(0);
......
......@@ -15,6 +15,9 @@ HISTORY:
#include <obj/NiTriBasedGeom.h>
#include <obj/NiTriBasedGeomData.h>
#include <obj/NiTimeController.h>
#include <obj/NiMultiTargetTransformController.h>
#include <obj/NiStringExtraData.h>
#include <obj/NiBillboardNode.h>
#include <float.h>
#include <dummy.h>
......@@ -316,7 +319,6 @@ INode *NifImporter::CreateBone(const string& name, Point3 startPos, Point3 endPo
INode *NifImporter::CreateHelper(const string& name, Point3 startPos)
{
//POINTHELP_CLASS_ID
if (DummyObject *ob = (DummyObject *)gi->CreateInstance(HELPER_CLASS_ID,Class_ID(DUMMY_CLASS_ID,0))) {
const float DUMSZ = 1.0f;
ob->SetBox(Box3(Point3(-DUMSZ,-DUMSZ,-DUMSZ),Point3(DUMSZ,DUMSZ,DUMSZ)));
......@@ -327,6 +329,14 @@ INode *NifImporter::CreateHelper(const string& name, Point3 startPos)
return n;
}
}
//if (Object *ob = (Object *)gi->CreateInstance(HELPER_CLASS_ID,Class_ID(BONE_CLASS_ID,0))) {
// if (INode *n = gi->CreateObjectNode(ob)) {
// n->SetName(const_cast<TCHAR*>(name.c_str()));
// Quat q; q.Identity();
// PosRotScaleNode(n, startPos, q, 1.0f, prsPos);
// return n;
// }
//}
return NULL;
}
......@@ -350,10 +360,52 @@ float GetObjectLength(NiAVObjectRef obj)
return clen;
}
static void BuildControllerRefList(NiNodeRef node, map<string,int>& ctrlCount)
{
list<NiTimeControllerRef> ctrls = node->GetControllers();
for (list<NiTimeControllerRef>::iterator itr = ctrls.begin(), end = ctrls.end(); itr != end; ++itr) {
list<NiNodeRef> nlist = DynamicCast<NiNode>((*itr)->GetRefs());
// Append extra targets. Goes away if GetRefs eventually returns the extra targets
if (NiMultiTargetTransformControllerRef multiCtrl = DynamicCast<NiMultiTargetTransformController>(*itr)) {
vector<NiNodeRef> extra = multiCtrl->GetExtraTargets();
nlist.insert(nlist.end(), extra.begin(), extra.end());
}
for (list<NiNodeRef>::iterator nitr = nlist.begin(); nitr != nlist.end(); ++nitr){
string name = (*nitr)->GetName();
map<string,int>::iterator citr = ctrlCount.find(name);
if (citr != ctrlCount.end())
++(*citr).second;
else
ctrlCount[name] = 1;
}
}
}
static bool HasControllerRef(map<string,int>& ctrlCount, const string& name)
{
return (ctrlCount.find(name) != ctrlCount.end());
}
static bool HasUserPropBuffer(NiNodeRef node)
{
if (node) {
if (NiStringExtraDataRef data = SelectFirstObjectOfType<NiStringExtraData>(node->GetExtraData())){
if (strmatch(data->GetName(), "UserPropBuffer"))
return true;
}
}
return false;
}
void NifImporter::ImportBones(NiNodeRef node)
{
try
{
if (uncontrolledDummies)
BuildControllerRefList(node, ctrlCount);
string name = node->GetName();
vector<NiAVObjectRef> children = node->GetChildren();
vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children);
......@@ -404,22 +456,19 @@ void NifImporter::ImportBones(NiNodeRef node)
}
else
{
list<NiTimeControllerRef> ctrls = node->GetControllers();
if (parent == NULL || parent->GetParent() == NULL || ctrls.empty())
{
bool isDummy = ( (uncontrolledDummies && !HasControllerRef(ctrlCount, name))
|| (!dummyNodeMatches.empty() && wildmatch(dummyNodeMatches, name))
|| (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TypeConst()))
);
if (isDummy && createNubsForBones)
bone = CreateHelper(name, p);
if (ctrls.empty())
bone->Hide(TRUE);
}
else if (bone = CreateBone(name, p, pp, zAxis))
{
PosRotScaleNode(bone, p, q, scale, prs);
if (createNubsForBones && childNodes.empty()){
if (INode *helper = CreateHelper(string().assign(name).append(" Nub"), pp)){
helper->Hide(TRUE);
bone->AttachChild(helper, 1);
}
}
if (isDummy)
bone->Hide(TRUE);
else
bone->Hide(node->GetHidden() ? TRUE : FALSE);
}
if (bone)
{
......@@ -428,7 +477,6 @@ void NifImporter::ImportBones(NiNodeRef node)
if (INode *pn = gi->GetINodeByName(parent->GetName().c_str()))
pn->AttachChild(bone, 1);
}
bone->Hide(node->GetHidden() ? TRUE : FALSE);
}
}
if (bone)
......
......@@ -88,7 +88,7 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,1,3,2
FILEVERSION 0,1,3,4
PRODUCTVERSION 0,1,3,0
FILEFLAGSMASK 0x37L
#ifdef _DEBUG
......@@ -105,7 +105,7 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "3ds Max Nif Importer"
VALUE "FileVersion", "0, 1, 3, 2"
VALUE "FileVersion", "0, 1, 3, 4"
VALUE "InternalName", "MaxNifImport.dli"
VALUE "LegalCopyright", "Copyright (c) 2006, NIF File Format Library and Tools\r\nAll rights reserved."
VALUE "OriginalFilename", "MaxNifImport.dli"
......
......@@ -49,7 +49,7 @@
Name="VCCLCompilerTool"
AdditionalOptions="/LD "
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="C:\3dsmax8\maxsdk\include"
AdditionalIncludeDirectories=""
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;USE_NIFLIB_TEMPLATE_HELPERS;_USE_MATH_DEFINES"
StringPooling="true"
ExceptionHandling="2"
......
......@@ -6,7 +6,7 @@
ShortDescription=Netimmerse/Gamebryo
; KnownApplications - Used to indicate which sections in the ini file point
; to "Applications" which have their own settings in a section below.
KnownApplications=Oblivion;Morrowind;Civ4
KnownApplications=Oblivion;Morrowind;Civ4;DAoC
; Reparse the Applications (and therefore Texture directory cache) on every import/export
Reparse=0
......@@ -53,14 +53,25 @@ ForceRotation=0
BrowseForSkeleton=1
; DefaultName for Skeletons (use if in same directory as imported nif)
DefaultSkeletonName=skeleton.nif
; Create Nubs for final bone in chain (not supported yet)
CreateNubsForBones=1
; Create Dummy nodes for bones that appear to be helper objects. Default: 0
CreateNubsForBones=0
; Dummy nodes wildcard matching. (Hide these when not created as Dummy) Default: Bip??;Bip* NonAccum
DummyNodeMatches=Bip??;* NonAccum
; Make Billboard nodes to Dummy nodes rather than bones. Default: 1
ConvertBillboardsToDummyNodes=1
; Add Bones not controlled by a controller as dummy. Default: 1
UncontrolledDummies=1
[AnimationImport]
; Enable Animation Import. Default: 1
EnableAnimations=1
; Require Multiple Keys to be present to before importing animation. (Kludge to workaround DOaC issues.) Default: 1
RequireMultipleKeys=1
; Replace TCB Rotation with Bezier (workaround for unexpected behavior with TCB rotations)
ReplaceTCBRotationWithBezier=1
; Apply the overall transform to skin and bones. Default: 0
ApplyOverallTransformToSkinAndBones=0
; [Applications]
; RootPaths - Semicolon separated list of base directories to use when determining which app the imported file is from
......@@ -88,6 +99,7 @@ TextureRootPaths=${RootPath};${TextureRootPath}
TextureExtensions=.dds;
TextureSearchPaths=${RootPath}\Textures;${TextureRootPath}\Textures\Characters;${TextureRootPath}\Textures\Armor
GoToSkeletonBindPosition=1
ApplyOverallTransformToSkinAndBones=0
[Morrowind]
InstallPath=[HKLM\SOFTWARE\Bethesda Softworks\Morrowind]=@"Installed Path"
......@@ -98,6 +110,7 @@ TextureRootPaths=${RootPath}\Textures;${ExtractFolder}\Textures
TextureExtensions=.tga;
TextureSearchPaths=${RootPath}\Textures
GoToSkeletonBindPosition=1
ApplyOverallTransformToSkinAndBones=1
[Civ4]
InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Firaxis Games\Sid Meier's Civilization 4]=@"INSTALLDIR"
......@@ -107,4 +120,17 @@ RootPaths=${ExtractFolder};${InstallPath}\Assets;${InstallPath}\Mods;%USERPROFIL
TextureRootPaths=$(ExtractFolder)\art\shared\
TextureExtensions=.dds;.bmp
TextureSearchPaths=
GoToSkeletonBindPosition=1
\ No newline at end of file
GoToSkeletonBindPosition=1
DummyNodeMatches=MD;Bip;Bip??;* NonAccum;Effect*;Sound*;Dummy*
ApplyOverallTransformToSkinAndBones=0
[DAoC]
Isles_InstallPath=[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Dark Age of Camelot - Shrouded Isles_is1]=@"InstallLocation"
RootPath=
ExtractFolder=
RootPaths=${Isles_InstallPath};${ExtractFolder}
TextureRootPaths=$(ExtractFolder)
TextureExtensions=.dds;.bmp;.tga
TextureSearchPaths=
GoToSkeletonBindPosition=1
ApplyOverallTransformToSkinAndBones=1
......@@ -46,8 +46,8 @@ static void BuildNodes(NiNodeRef object, vector<NiNodeRef>& nodes)
{
if (!object)
return;
nodes.push_back(object);
vector<NiNodeRef> links = DynamicCast<NiNode>(object->GetChildren());
nodes.insert(nodes.end(), links.begin(), links.end());
for (vector<NiNodeRef>::iterator itr = links.begin(), end = links.end(); itr != end; ++itr)
BuildNodes(*itr, nodes);
}
......@@ -136,11 +136,26 @@ void NifImporter::LoadIniSettings()
maxBoneWidth = GetIniValue<float>(BipedImportSection, "MaxBoneWidth", 3.0f);
boneWidthToLengthRatio = GetIniValue<float>(BipedImportSection, "BoneWidthToLengthRatio", 0.25f);
createNubsForBones = GetIniValue<bool>(BipedImportSection, "CreateNubsForBones", true);
dummyNodeMatches = TokenizeString(GetIniValue<string>(BipedImportSection, "DummyNodeMatches", "").c_str(), ";");
convertBillboardsToDummyNodes = GetIniValue<bool>(BipedImportSection, "ConvertBillboardsToDummyNodes", true);
uncontrolledDummies = GetIniValue<bool>(BipedImportSection, "UncontrolledDummies", true);
replaceTCBRotationWithBezier = GetIniValue<bool>(AnimImportSection, "ReplaceTCBRotationWithBezier", true);
enableAnimations = GetIniValue<bool>(AnimImportSection, "EnableAnimations", true);
goToSkeletonBindPosition = (appSettings ? appSettings->goToSkeletonBindPosition : false);
requireMultipleKeys = GetIniValue<bool>(AnimImportSection, "RequireMultipleKeys", true);
applyOverallTransformToSkinAndBones = GetIniValue<bool>(AnimImportSection, "ApplyOverallTransformToSkinAndBones", true);
goToSkeletonBindPosition = false;
// Override specific settings
if (appSettings) {
if (appSettings->disableCreateNubsForBones)
createNubsForBones = false;
goToSkeletonBindPosition = appSettings->goToSkeletonBindPosition;
if (!appSettings->dummyNodeMatches.empty())
dummyNodeMatches = appSettings->dummyNodeMatches;
if (appSettings->applyOverallTransformToSkinAndBones != -1)
applyOverallTransformToSkinAndBones = appSettings->applyOverallTransformToSkinAndBones ? true : false;
}
}
void NifImporter::SaveIniSettings()
......@@ -229,7 +244,11 @@ bool NifImporter::DoImport()
}
if (isValid()) {
ImportBones(DynamicCast<NiNode>(rootNode->GetChildren()));
if (strmatch(rootNode->GetName(), "Scene Root"))
ImportBones(DynamicCast<NiNode>(rootNode->GetChildren()));
else
ImportBones(rootNode);
ok = ImportMeshes(rootNode);
if (importSkeleton && removeUnusedImportedBones){
......
......@@ -48,13 +48,19 @@ public:
float maxBoneWidth;
float boneWidthToLengthRatio;
bool createNubsForBones;
stringlist dummyNodeMatches;
bool convertBillboardsToDummyNodes;
bool uncontrolledDummies;
// Animation related Settings
bool replaceTCBRotationWithBezier;
bool enableAnimations;
bool requireMultipleKeys;
bool applyOverallTransformToSkinAndBones;
vector<Niflib::NiObjectRef> blocks;
vector<Niflib::NiNodeRef> nodes;
map<string,int> ctrlCount; // counter for number of controllers referencing a node
NifImporter(const TCHAR *Name,ImpInterface *I,Interface *GI, BOOL SuppressPrompts);
virtual void Initialize();
......
......@@ -299,6 +299,20 @@ int wildcmpi(const TCHAR *wild, const TCHAR *string) {
return !*wild;
}
bool wildmatch(const string& match, const std::string& value)
{
return (wildcmpi(match.c_str(), value.c_str())) ? true : false;
}
bool wildmatch(const stringlist& matches, const std::string& value)
{
for (stringlist::const_iterator itr=matches.begin(), end=matches.end(); itr != end; ++itr){
if (wildcmpi((*itr).c_str(), value.c_str()))
return true;
}
return false;
}
//! Renames Max Node if it exists
void RenameNode(Interface *gi, LPCTSTR SrcName, LPCTSTR DstName)
{
......
......@@ -41,9 +41,6 @@ INFO: See Implementation for minimalist comments
#define _countof(x) (sizeof(x)/sizeof((x)[0]))
#endif
extern int wildcmp(const TCHAR *wild, const TCHAR *string);
extern int wildcmpi(const TCHAR *wild, const TCHAR *string);
// Trim whitespace before and after a string
inline TCHAR *Trim(TCHAR*&p) {
while(_istspace(*p)) *p++ = 0;
......@@ -114,6 +111,30 @@ struct NumericStringEquivalence
}
};
// Common collections that I use
typedef std::map<std::string, std::string, ltstr> NameValueCollection;
typedef std::pair<std::string, std::string> KeyValuePair;
typedef std::list<std::string> stringlist;
extern int wildcmp(const TCHAR *wild, const TCHAR *string);
extern int wildcmpi(const TCHAR *wild, const TCHAR *string);
inline bool strmatch(const string& lhs, const std::string& rhs) {
return (0 == _tcsicmp(lhs.c_str(), rhs.c_str()));
}
inline bool strmatch(const TCHAR* lhs, const std::string& rhs) {
return (0 == _tcsicmp(lhs, rhs.c_str()));
}
inline bool strmatch(const string& lhs, const TCHAR* rhs) {
return (0 == _tcsicmp(lhs.c_str(), rhs));
}
inline bool strmatch(const TCHAR* lhs, const TCHAR* rhs) {
return (0 == _tcsicmp(lhs, rhs));
}
bool wildmatch(const string& match, const std::string& value);
bool wildmatch(const stringlist& matches, const std::string& value);
// Generic IniFile reading routine
template<typename T>
inline T GetIniValue(LPCTSTR Section, LPCTSTR Setting, T Default, LPCTSTR iniFileName){
......@@ -178,11 +199,6 @@ inline void SetIniValue<TSTR>(LPCTSTR Section, LPCTSTR Setting, TSTR value, LPCT
WritePrivateProfileString(Section, Setting, value.data(), iniFileName);
}
// Common collections that I use
typedef std::map<std::string, std::string, ltstr> NameValueCollection;
typedef std::pair<std::string, std::string> KeyValuePair;
typedef std::list<std::string> stringlist;
extern TSTR FormatText(const TCHAR* format,...);
extern std::string FormatString(const TCHAR* format,...);
......
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