From 53fd4116151439480bb25242428d4b200ee7759d Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Mon, 25 Jun 2007 04:58:26 +0000 Subject: [PATCH] 0.2.14 ----- o Exporter - Fix issues with bhkConvexShape and bhkRigidBody o Exporter/Importer - Introduce Morpher animation support --- MaxNifPlugins_Readme.txt | 9 +- NifCommon/nimorph.cpp | 125 +++++++++++++++ NifCommon/niutils.h | 1 + NifExport/Animation.cpp | 121 +++++++++++++- NifExport/Exporter.cpp | 2 +- NifExport/Exporter.h | 3 +- NifExport/Mesh.cpp | 287 +++++++++++++++++++++------------- NifImport/BaseImporter.h | 2 +- NifImport/ImportAnimation.cpp | 38 +++-- NifPlugins_VC80.vcproj | 64 ++++---- 10 files changed, 483 insertions(+), 169 deletions(-) diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index 3b3a97e..ccdd24b 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -36,10 +36,11 @@ 0.2.14 ----- o Exporter - - Fix a number of issues with bhkConvexShape and bhkRigidBody - o Importer - - Introduce Morph animation support - + - Fix issues with bhkConvexShape and bhkRigidBody + o Exporter/Importer + - Introduce Morpher animation support + + 0.2.13 ----- o Properties diff --git a/NifCommon/nimorph.cpp b/NifCommon/nimorph.cpp index 9904715..5b971e2 100644 --- a/NifCommon/nimorph.cpp +++ b/NifCommon/nimorph.cpp @@ -542,4 +542,129 @@ INode *MorpherGetProgMorph(Modifier* mod, int index, int morphIdx) pop_value_locals(); pop_alloc_frame(); return retval; +} + +int MorpherGetNumVerts(Modifier* mod, int index) +{ + int retval = 0; + // 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, mod, index, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_NumPts")); + 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. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[2]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 2); + if (vl.result->tag == class_tag(Integer)) + retval = vl.result->to_int(); + } + } 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; +} + +void MorpherGetMorphVerts(Modifier* mod, int index, vector<Vector3>& verts) +{ + int nverts = MorpherGetNumVerts(mod, index); + verts.resize(nverts, Vector3(0.0f,0.0f,0.0f)); + if (nverts == 0) + return; + + // Magic initialization stuff for maxscript. + static bool script_initialized = false; + if (!script_initialized) { + init_MAXScript(); + script_initialized = TRUE; + } + init_thread_locals(); + push_alloc_frame(); + six_value_locals(name, fn, mod, index, midx, result); + save_current_frames(); + trace_back_active = FALSE; + try { + // Create the name of the maxscript function we want. + // and look it up in the global names + vl.name = Name::intern(_T("WM3_MC_GetMorphPoint")); + 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. + // class_tag(MAXScriptFunction) + if (vl.fn != NULL && vl.fn->tag == class_tag(Primitive)) { + Value* args[3]; + + // Ok. WM3_MC_BuildFromNode takes three parameters + args[0] = vl.mod = MAXModifier::intern(mod); // The original material + args[1] = vl.index = Integer::intern(index); + + for (int i=0; i<nverts; ++i) + { + args[2] = vl.midx = Integer::intern(i); + // Call the function and save the result. + vl.result = static_cast<Primitive*>(vl.fn)->apply(args, 3); + if (vl.result->tag == class_tag(Point3Value)) + verts[i] = TOVECTOR3(vl.result->to_point3()); + } + } + } 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(); } \ No newline at end of file diff --git a/NifCommon/niutils.h b/NifCommon/niutils.h index b9ef787..362f64b 100644 --- a/NifCommon/niutils.h +++ b/NifCommon/niutils.h @@ -441,5 +441,6 @@ extern bool MorpherIsActive(Modifier* mod, int index); extern bool MorpherHasData(Modifier* mod, int index); extern int MorpherNumProgMorphs(Modifier* mod, int index); extern INode *MorpherGetProgMorph(Modifier* mod, int index, int morphIdx); +extern void MorpherGetMorphVerts(Modifier* mod, int index, vector<Niflib::Vector3>& verts); #endif // _NIUTILS_H_ \ No newline at end of file diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index 8a5af4d..8ea410c 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -64,8 +64,7 @@ struct AnimationExport NiTimeControllerRef exportController(INode *node, Interval range, bool setTM ); bool GetTextKeys(INode *node, vector<StringKey>& textKeys); Interval GetTimeRange(INode *n); - void GetTimeRange(Control *n, Interval& range); - + void GetTimeRange(Control *c, Interval& range); Exporter ≠ Interval range; @@ -205,6 +204,7 @@ NiNodeRef Exporter::createAccumNode(NiNodeRef parent, INode *node) } return accumNode; } + Exporter::Result Exporter::doAnimExport(NiControllerSequenceRef root) { AnimationExport animExporter(*this); @@ -247,7 +247,7 @@ bool Exporter::isNodeTracked(INode *node) } Exporter::Result Exporter::scanForAnimation(INode *node) -{ +{ if (NULL == node) return Exporter::Skip; @@ -602,7 +602,7 @@ Control *AnimationExport::GetTMController(INode *n) return c; } -void AnimationExport::GetTimeRange(Control *c, Interval& range) +static void GetTimeRange(Control *c, Interval& range) { if (IKeyControl *ikeys = GetKeyControlInterface(c)){ int n = ikeys->GetNumKeys(); @@ -620,6 +620,11 @@ void AnimationExport::GetTimeRange(Control *c, Interval& range) } } } +void AnimationExport::GetTimeRange(Control *c, Interval& range) +{ + ::GetTimeRange(c, range); +} + Interval AnimationExport::GetTimeRange(INode *node) { @@ -1055,4 +1060,110 @@ bool AnimationExport::exportController(INode *node, bool hasAccum) ok |= exportController(child, false); } return ok; -} \ No newline at end of file +} + +Exporter::Result Exporter::exportGeomMorpherControl(Modifier* mod, vector<Vector3>& baseVerts, NiObjectNETRef owner) +{ + // Check for morphs + //if ( mExportType != NIF_WO_ANIM ) + if (mod != NULL) + { + if (mod->IsEnabled()) { + NiGeomMorpherControllerRef ctrl = new NiGeomMorpherController(); + NiMorphDataRef data = new NiMorphData(); + vector<NiInterpolatorRef> interpolators; + vector<int> indices; + for (int i=1; i<100; ++i) { + if (MorpherHasData(mod, i) && MorpherIsActive(mod, i)) { + indices.push_back(i); + } + } + data->SetMorphCount( indices.size() + 1); + data->SetFrameName(0, string("Base")); + data->SetMorphKeyType(0, LINEAR_KEY); + + Interval range; range.SetEmpty(); + + int nbaseverts = baseVerts.size(); + data->SetVertexCount( nbaseverts ); + data->SetMorphVerts(0, baseVerts); + if (NiFloatInterpolatorRef interp = new NiFloatInterpolator()) + { + NiFloatDataRef fdata = new NiFloatData(); + vector<FloatKey> keys; + keys.resize(2); + data->SetMorphKeyType(0, LINEAR_KEY); + data->SetMorphKeys(0, keys); + fdata->SetKeyType(LINEAR_KEY); + fdata->SetKeys(keys); + interp->SetFloatValue(FloatNegINF); + interp->SetData(fdata); + interpolators.push_back(interp); + } + + for (int i=0; i<indices.size(); ++i) { + int idx = indices[i]; + if (IParamBlock* pblock = (IParamBlock*)mod->GetReference(idx)) { + if (Control *c = pblock->GetController(0)) { + GetTimeRange(c, range); + } + } + } + + for (int i=0; i<indices.size(); ++i) { + int idx = indices[i]; + + IParamBlock* pblock = (IParamBlock*)mod->GetReference(idx); + TSTR name = MorpherGetName(mod, idx); + data->SetFrameName(i+1, string(name)); + + KeyType keyType = LINEAR_KEY; + vector<FloatKey> keys; + if (Control *c = pblock->GetController(0)) { + if (c->ClassID() == Class_ID(LININTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ILinFloatKey>(c, keys, range); + keyType = LINEAR_KEY; + } else if (c->ClassID() == Class_ID(HYBRIDINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, IBezFloatKey>(c, keys, range); + keyType = QUADRATIC_KEY; + } else if (c->ClassID() == Class_ID(TCBINTERP_FLOAT_CLASS_ID,0)) { + GetKeys<FloatKey, ITCBFloatKey>(c, keys, range); + keyType = TBC_KEY; + } else { + GetKeys<FloatKey, IBezFloatKey>(c, keys, range); + keyType = QUADRATIC_KEY; + } + } + ScaleKeys(keys, 1.0f/100.0f); + if (NiFloatInterpolatorRef interp = new NiFloatInterpolator()) + { + NiFloatDataRef fdata = new NiFloatData(); + data->SetMorphKeyType(i+1, keyType); + data->SetMorphKeys(i+1, keys); + fdata->SetKeyType(keyType); + fdata->SetKeys(keys); + interp->SetFloatValue(FloatNegINF); + interp->SetData(fdata); + interpolators.push_back(interp); + } + + vector<Vector3> verts; + MorpherGetMorphVerts(mod, idx, verts); + for (int j=0; j<verts.size(); j++) + verts[j] = verts[j] - baseVerts[j]; + data->SetMorphVerts(i+1, verts); + } + ctrl->SetData(data); + if (Exporter::mNifVersionInt >= VER_10_1_0_106) + ctrl->SetInterpolators(interpolators); + ctrl->SetFlags( 0x000C ); + ctrl->SetFrequency(1.0f); + ctrl->SetPhase(0.0f); + ctrl->SetStartTime( 0.0f ); + ctrl->SetStopTime( FrameToTime( range.Duration()-1 ) ); + owner->AddController(ctrl); + } + } + return Exporter::Ok; +} + diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index ac68da3..c9c21de 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -275,7 +275,7 @@ Exporter::Result Exporter::exportNodes(NiNodeRef &parent, INode *node) // Create node if using Extra Nodes or if exporting with anim and node has key values newParent = makeNode(nodeParent, node, local); } else { - // Else dont create a node + // Else don't create a node newParent = nodeParent; } // No need to export meshes when NIF is not exported. diff --git a/NifExport/Exporter.h b/NifExport/Exporter.h index feb1b66..16aafb0 100755 --- a/NifExport/Exporter.h +++ b/NifExport/Exporter.h @@ -207,7 +207,7 @@ public: // adds a face to a face group 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, vector<Color4>& vertColors); + bool splitMesh(INode *node, Mesh &, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors, bool noSplit); // creates a NiTriStrips or NiTriShape hierarchy from a face group NiTriBasedGeomRef makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp, bool exportStrips); // splits mesh and converts it into nif blocks @@ -271,6 +271,7 @@ public: bool isNodeKeyed(INode *node); Ref<NiTimeController> CreateController(INode *node, Interval range); static void InitializeTimeController(Ref<NiTimeController> ctrl, NiNodeRef parent); + Result exportGeomMorpherControl(Modifier* mod, vector<Niflib::Vector3>& verts, NiObjectNETRef owner); /* misc export */ bool exportUPB(NiNodeRef &root, INode *node); diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index f36fcf7..9ce3def 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -18,139 +18,150 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue { ObjectState os = node->EvalWorldState(t); - bool local = !mFlattenHierarchy; + bool local = !mFlattenHierarchy; TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0)); if (!tri) return Error; - Mesh *copymesh = NULL; + Mesh *copymesh = NULL; Mesh *mesh = &tri->GetMesh(); - Matrix3 mtx(true); - if (Exporter::mCollapseTransforms) - { - mtx = GetNodeLocalTM(node, t); - //if ( fabs(mtx.GetRow(0)[0]) != fabs(mtx.GetRow(1)[1]) - // ||fabs(mtx.GetRow(0)[0]) != fabs(mtx.GetRow(2)[2]) - // ) - { - mtx.NoTrans(); - mesh = copymesh = new Mesh(*mesh); - int n = mesh->getNumVerts(); - for ( unsigned int i = 0; i < n; ++i ) { - Point3& vert = mesh->getVert(i); - vert = mtx * vert; - } - mesh->checkNormals(TRUE); + Matrix3 mtx(true); + if (Exporter::mCollapseTransforms) + { + mtx = GetNodeLocalTM(node, t); + //if ( fabs(mtx.GetRow(0)[0]) != fabs(mtx.GetRow(1)[1]) + // ||fabs(mtx.GetRow(0)[0]) != fabs(mtx.GetRow(2)[2]) + // ) + { + mtx.NoTrans(); + mesh = copymesh = new Mesh(*mesh); + int n = mesh->getNumVerts(); + for ( unsigned int i = 0; i < n; ++i ) { + Point3& vert = mesh->getVert(i); + vert = mtx * vert; + } + mesh->checkNormals(TRUE); #if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+ - MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); - if (NULL != specNorms) { - specNorms->CheckNormals(); - for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) { - Point3& norm = specNorms->Normal(i); - norm = (mtx * norm).Normalize(); - } - } + MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); + if (NULL != specNorms) { + specNorms->CheckNormals(); + for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) { + Point3& norm = specNorms->Normal(i); + norm = (mtx * norm).Normalize(); + } + } #endif - } - } - // 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(); - } - + } + } + // 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(); + } + #if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5 - mesh->checkNormals(TRUE); + mesh->checkNormals(TRUE); #else - MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); - if (NULL != specNorms) { - specNorms->CheckNormals(); - if (specNorms->GetNumNormals() == 0) - mesh->checkNormals(TRUE); - } else { - mesh->checkNormals(TRUE); - } + MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); + if (NULL != specNorms) { + specNorms->CheckNormals(); + if (specNorms->GetNumNormals() == 0) + mesh->checkNormals(TRUE); + } else { + mesh->checkNormals(TRUE); + } #endif Result result = Ok; + + Modifier* geomMorpherMod = GetMorpherModifier(node); + bool noSplit = (NULL != geomMorpherMod); + while (1) { FaceGroups grps; - if (!splitMesh(node, mesh, grps, t, vertColors)) + if (!splitMesh(node, *mesh, grps, t, vertColors, noSplit)) { result = Error; break; } - bool exportStrips = mTriStrips; + bool exportStrips = mTriStrips; - Matrix44 tm = Matrix44::IDENTITY; - if (!mExportExtraNodes) { - Matrix33 rot; Vector3 trans; - nodeTransform(rot, trans, node, t, local); - tm = Matrix44(trans, rot, 1.0f); - } - tm = TOMATRIX4(Inverse(mtx)) * tm; + Matrix44 tm = Matrix44::IDENTITY; + if (!mExportExtraNodes) { + Matrix33 rot; Vector3 trans; + nodeTransform(rot, trans, node, t, local); + tm = Matrix44(trans, rot, 1.0f); + } + tm = TOMATRIX4(Inverse(mtx)) * tm; - TSTR basename = node->NodeName(); - TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s"; + TSTR basename = node->NodeName(); + TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s"; - int i=1; + int i=1; FaceGroups::iterator grp; for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i) { - string name = FormatString(format, basename.data(), i); - NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips); - if (shape == NULL) + string name = FormatString(format, basename.data(), i); + NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips); + if (shape == NULL) { result = Error; break; } - if (node->IsHidden()) - shape->SetVisibility(false); + if (node->IsHidden()) + shape->SetVisibility(false); - shape->SetName(name); - shape->SetLocalTransform(tm); + shape->SetName(name); + shape->SetLocalTransform(tm); + + if (Exporter::mCollapseTransforms) { + shape->ApplyTransforms(); + } + + makeSkin(shape, node, grp->second, t); + + if (geomMorpherMod) { + vector<Vector3> verts = shape->GetData()->GetVertices(); + exportGeomMorpherControl(geomMorpherMod, verts, shape); + shape->GetData()->SetConsistencyFlags(CT_VOLATILE); + } - if (Exporter::mCollapseTransforms) { - shape->ApplyTransforms(); - } - - makeSkin(shape, node, grp->second, t); } break; @@ -159,8 +170,8 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue if (tri != os.obj) tri->DeleteMe(); - if (copymesh) - delete copymesh; + if (copymesh) + delete copymesh; return result; } @@ -193,6 +204,7 @@ NiTriBasedGeomRef Exporter::makeMesh(NiNodeRef &parent, Mtl *mtl, FaceGroup &grp if (grp.vcolors.size() > 0) data->SetVertexColors(grp.vcolors); + data->SetConsistencyFlags(CT_STATIC); shape->SetData(data); if (Exporter::mTangentAndBinormalExtraData) @@ -277,7 +289,7 @@ void Exporter::addFace(FaceGroup &grp, int face, const int vi[3], Mesh *mesh, co grp.faces.push_back(tri); } -bool Exporter::splitMesh(INode *node, Mesh *mesh, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors) +bool Exporter::splitMesh(INode *node, Mesh& mesh, FaceGroups &grps, TimeValue t, vector<Color4>& vertColors, bool noSplit) { Mtl* nodeMtl = node->GetMtl(); Matrix3 tm = node->GetObjTMAfterWSM(t); @@ -301,17 +313,68 @@ bool Exporter::splitMesh(INode *node, Mesh *mesh, FaceGroups &grps, TimeValue t, flip.IdentityMatrix(); flip.Scale(Point3(1, -1, 1)); - int i, numSubMtls = nodeMtl?nodeMtl->NumSubMtls():0; - for (i=0; i<mesh->getNumFaces(); i++) + if (noSplit) { - int mtlID = (numSubMtls!=0) ? (mesh->faces[i].getMatID() % numSubMtls) : 0; - - Matrix3 texm; - getTextureMatrix(texm, getMaterial(node, mtlID)); - - texm *= flip; - - addFace(grps[mtlID], i, vi, mesh, texm, vertColors); + int nv = mesh.getNumVerts(); + int nf = mesh.getNumFaces(); + // Dont split the mesh at all. For debugging purposes. + FaceGroup& grp = grps[0]; + grp.vidx.resize(nv, -1); + grp.verts.resize(nv); + grp.faces.resize(nf); + grp.uvs.resize(nv); + grp.vnorms.resize(nv); + + for (int face=0; face<nf; ++face) { + for (int vi=0; vi<3; ++vi) { + int idx = mesh.faces[face].getVert(vi); + grp.faces[face][vi] = idx; + + // Calculate normal + Point3 norm; +#if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5 + norm = getVertexNormal(&mesh, face, mesh.getRVertPtr(idx)); +#else + MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals (); + if (NULL != specNorms && specNorms->GetNumNormals() != 0) + norm = specNorms->GetNormal(face, vi); + else + norm = getVertexNormal(&mesh, face, mesh.getRVertPtr(idx)); +#endif + if (grp.vidx[idx] == idx){ + ASSERT(grp.verts[idx] == TOVECTOR3(mesh.getVert(idx))); + //ASSERT(vg.norm == norm); + Point3 uv = mesh.getTVert(idx); + if (mesh.getNumTVerts() > 0) + { + uv.y = -uv.y; + ASSERT(grp.uvs[idx].u == uv.x && grp.uvs[idx].v == uv.y); + } + } else { + grp.vidx[idx] = idx; + grp.verts[idx] = TOVECTOR3(mesh.getVert(idx)); + Point3 uv = (mesh.getNumTVerts() > 0) ? mesh.getTVert(idx) : Point3(0.0f,0.0f,0.0f); + grp.uvs[idx].u = uv.x; + grp.uvs[idx].v = -uv.y; + grp.vnorms[idx] = TOVECTOR3(norm); + } + } + } + for (int i=0; i<nv; ++i) { + ASSERT(grp.vidx[i] != -1); + } + } + else + { + int i, numSubMtls = nodeMtl?nodeMtl->NumSubMtls():0; + for (i=0; i<mesh.getNumFaces(); i++) + { + int mtlID = (numSubMtls!=0) ? (mesh.faces[i].getMatID() % numSubMtls) : 0; + Matrix3 texm; + getTextureMatrix(texm, getMaterial(node, mtlID)); + texm *= flip; + addFace(grps[mtlID], i, vi, &mesh, texm, vertColors); + } } return true; diff --git a/NifImport/BaseImporter.h b/NifImport/BaseImporter.h index d36b8c4..12c271e 100644 --- a/NifImport/BaseImporter.h +++ b/NifImport/BaseImporter.h @@ -72,7 +72,7 @@ public: webSite = GetIniValue<TSTR>("System", "Website", "http://www.niftools.org"); wikiSite = GetIniValue<TSTR>("System", "Wiki", "http://www.niftools.org/wiki/index.php/3ds_Max"); - nifVersion = Niflib::GetNifVersion(this->path); + nifVersion = Niflib::GetNifVersion(this->name); // Load ini settings iniFileValid = false; diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 0459234..edbead6 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -975,8 +975,26 @@ bool AnimationImport::ImportGeoMorph(INode *n, NiGeomMorpherControllerRef ctrl, return false; vector<NiInterpolatorRef> interpolators = ctrl->GetInterpolators(); int nmorphs = data->GetMorphCount(); - if ((interpolators.size() > nmorphs) || nmorphs == 0) - return false; + if (ni.nifVersion >= VER_10_1_0_106) + { + if ((interpolators.size() > nmorphs) || nmorphs == 0) + return false; + } + else + { + for (int i=0; i<nmorphs; i++) + { + if (NiFloatInterpolatorRef interp = new NiFloatInterpolator()) + { + NiFloatDataRef fdata = new NiFloatData(); + fdata->SetKeyType( data->GetMorphKeyType(i) ); + fdata->SetKeys( data->GetMorphKeys(i) ); + interp->SetFloatValue(FloatNegINF); + interp->SetData(fdata); + interpolators.push_back(interp); + } + } + } NiGeometryDataRef geoData = parentGeom->GetData(); int nBaseVerts = geoData->GetVertexCount(); vector<Triangle> tris; @@ -986,11 +1004,13 @@ bool AnimationImport::ImportGeoMorph(INode *n, NiGeomMorpherControllerRef ctrl, if (triShapeData == NULL) return false; tris = triShapeData->GetTriangles(); + baseVerts = triShapeData->GetVertices(); } else if (geoData->IsDerivedType(NiTriStripsData::TYPE)) { NiTriStripsDataRef triStripData = StaticCast<NiTriStripsData>(geoData); if (triStripData == NULL) return false; tris = triStripData->GetTriangles(); + baseVerts = triStripData->GetVertices(); } else { return false; } @@ -1002,23 +1022,15 @@ bool AnimationImport::ImportGeoMorph(INode *n, NiGeomMorpherControllerRef ctrl, n->EvalWorldState(0, TRUE); // Create meshes for morph - for (int i=0; i<nmorphs; ++i) + for (int i=1; i<nmorphs; ++i) // Skip first morph as its the baseline { string frameName = (ni.nifVersion >= VER_10_1_0_106) ? data->GetFrameName(i) : FormatString("Frame #%d", i); vector<Vector3> verts = data->GetMorphVerts(i); if (verts.size() != nBaseVerts) continue; - // All verts after the first index are differentials - if (i == 0) - { - baseVerts = verts; - } - else - { - for (int j=0; j<nBaseVerts; ++j) - verts[j] += baseVerts[j]; - } + for (int j=0; j<nBaseVerts; ++j) + verts[j] += baseVerts[j]; TSTR name(frameName.c_str()); INode *geoNode = CreateGeoMesh(verts, tris, tm, n); diff --git a/NifPlugins_VC80.vcproj b/NifPlugins_VC80.vcproj index e351957..192deaf 100644 --- a/NifPlugins_VC80.vcproj +++ b/NifPlugins_VC80.vcproj @@ -124,8 +124,8 @@ </Configuration> <Configuration Name="Release - Max 6|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -331,8 +331,8 @@ </Configuration> <Configuration Name="Debug - Max 6|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -538,8 +538,8 @@ </Configuration> <Configuration Name="Release - Max 7|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -745,8 +745,8 @@ </Configuration> <Configuration Name="Debug - Max 7|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -952,8 +952,8 @@ </Configuration> <Configuration Name="Release - Max 8|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -1159,8 +1159,8 @@ </Configuration> <Configuration Name="Debug - Max 8|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -1364,8 +1364,8 @@ </Configuration> <Configuration Name="Debug - Max 5|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -1572,8 +1572,8 @@ </Configuration> <Configuration Name="Release - Max 5|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -1780,8 +1780,8 @@ </Configuration> <Configuration Name="Debug - Max 9|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -1988,8 +1988,8 @@ </Configuration> <Configuration Name="Release - Max 9|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -2198,8 +2198,8 @@ </Configuration> <Configuration Name="Release - Max 4|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -2406,8 +2406,8 @@ </Configuration> <Configuration Name="Debug - Max 4|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -2612,8 +2612,8 @@ </Configuration> <Configuration Name="Debug - gmax|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -2820,8 +2820,8 @@ </Configuration> <Configuration Name="Release - gmax|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -3028,8 +3028,8 @@ </Configuration> <Configuration Name="Debug - Max 4.2|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" @@ -3236,8 +3236,8 @@ </Configuration> <Configuration Name="Release - Max 4.2|x64" - OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) $(PlatformName)\" - IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) $(PlatformName)\" + OutputDirectory="$(SolutionDir)Staging\$(ConfigurationName) - $(PlatformName)\" + IntermediateDirectory="$(SolutionDir)Temp\$(ProjectName)\$(ConfigurationName) - $(PlatformName)\" ConfigurationType="2" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" UseOfMFC="0" -- GitLab