From 751de4a50caeb3abf6ff90cc1f3d4dc1b8e7744a Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Thu, 12 Oct 2006 01:46:39 +0000 Subject: [PATCH] MaxPlugins 0.2.8 ----- o Exporter - Fix Collapse Transforms on dialog so that it actually triggers collapse - Change defaults for textures so Morrowind does not crash in CS - Fix export of animation for Morrowind - Introduce mechanism in Collapse Transforms so that poorly scaled models export better o Importer - Fix import of animation for Morrowind --- MaxNifPlugins_Readme.txt | 36 +- NifCommon/NifVersion.h | 4 +- NifExport/Animation.cpp | 10 +- NifExport/Exporter.cpp | 11 + NifExport/Mesh.cpp | 49 +- NifExport/MtlTex.cpp | 20 +- NifExport/NifExport.cpp | 3 + NifExport/Util.cpp | 42 +- NifExport/resource.h | 4 +- NifImport/ImportAnimation.cpp | 35 +- NifImport/ImportSkeleton.cpp | 2 +- NifPlugins/DllEntry.cpp | 8 +- NifProps/NifProps.rc | 327 +++++++++ NifProps/bhkCapsuleObj.cpp | 1010 ++++++++++++++++++++++++++++ NifProps/bhkRigidBodyInterface.cpp | 556 +++++++++++++++ NifProps/bhkRigidBodyInterface.h | 178 +++++ NifProps/bhkSphereObj.cpp | 679 +++++++++++++++++++ NifProps/resource.h | 45 +- 18 files changed, 2974 insertions(+), 45 deletions(-) create mode 100644 NifProps/bhkCapsuleObj.cpp create mode 100644 NifProps/bhkRigidBodyInterface.cpp create mode 100644 NifProps/bhkRigidBodyInterface.h create mode 100644 NifProps/bhkSphereObj.cpp diff --git a/MaxNifPlugins_Readme.txt b/MaxNifPlugins_Readme.txt index aa672eb..a3f959e 100644 --- a/MaxNifPlugins_Readme.txt +++ b/MaxNifPlugins_Readme.txt @@ -1,4 +1,4 @@ - MaxPlugins 0.2.7 + MaxPlugins 0.2.8 ================ @@ -32,18 +32,30 @@ Change log ---------- -0.2.7 ------ -o All -- Add options to disable certain parts of plug via INI -o Added so people who only want importer can disable exporter. -- Enhancements from NifLib including support for Freedom Force -- Max 5 build is available but untested. + 0.2.8 + ----- + o Exporter + - Fix Collapse Transforms on dialog so that it actually triggers collapse + - Change defaults for textures so Morrowind does not crash in CS + - Fix export of animation for Morrowind + - Introduce mechanism in Collapse Transforms so that poorly scaled + models export better -o Exporter -- Fix bug with NiTriShape export which created corrupted files. -- Add option to Update Tangent Space (for Oblivion) -- Add option to Collapse Transforms on meshes (mostly a debug aide) + o Importer + - Fix import of animation for Morrowind + + 0.2.7 + ----- + o All + - Add options to disable certain parts of plug via INI + o Added so people who only want importer can disable exporter. + - Enhancements from NifLib including support for Freedom Force + - Max 5 build is available but untested. + + o Exporter + - Fix bug with NiTriShape export which created corrupted files. + - Add option to Update Tangent Space (for Oblivion) + - Add option to Collapse Transforms on meshes (mostly a debug aide) 0.2.6 diff --git a/NifCommon/NifVersion.h b/NifCommon/NifVersion.h index d03d748..2248b4e 100644 --- a/NifCommon/NifVersion.h +++ b/NifCommon/NifVersion.h @@ -18,10 +18,10 @@ HISTORY: */ #define VERSION_MAJOR_INT 0 #define VERSION_MINOR_INT 2 -#define VERSION_BUILD_INT 7 +#define VERSION_BUILD_INT 8 #define VERSION_PATCH_INT 0 -#define VERSION_STRING "0, 2, 7, 0" +#define VERSION_STRING "0, 2, 8, 0" //#define DEF_VERSION_STRING(a,b,c,d) #a ", " #b ", " #c ", " #d //#define VERSION_STRING DEF_VERSION_STRING(a,b,c,d) diff --git a/NifExport/Animation.cpp b/NifExport/Animation.cpp index c8c5c94..44ad583 100644 --- a/NifExport/Animation.cpp +++ b/NifExport/Animation.cpp @@ -208,7 +208,8 @@ bool Exporter::isNodeTracked(INode *node) if ( defNT->NumKeys() > 0 ) { for (int j=0, m=defNT->keys.Count(); j<m; ++j) { NoteKey* key = defNT->keys[j]; - if (wildmatch("start*", key->note)) { + // Versions less than 20.0.0.4 will always export + if (Exporter::mNifVersionInt < VER_20_0_0_4 || wildmatch("start*", key->note) ) { return true; } } @@ -373,6 +374,13 @@ bool AnimationExport::doExport(NiControllerSequenceRef seq) } } } + // keys without explicit start/stop will + if (!textKeys.empty() && seq->GetStartTime() == FloatINF) + { + seq->SetStartTime(0.0f); + seq->SetStopTime(textKeys.back().time); + } + textKeyData->SetKeys(textKeys); // Now let the fun begin. diff --git a/NifExport/Exporter.cpp b/NifExport/Exporter.cpp index d65cecd..370d08f 100755 --- a/NifExport/Exporter.cpp +++ b/NifExport/Exporter.cpp @@ -175,6 +175,17 @@ Exporter::Result Exporter::doExport(NiNodeRef &root, INode *node) Result result = exportNodes(root, node); if (result != Ok) return result; + + // Fix Used Nodes that where never properly initialized. Happens normally during select export + for (NodeMap::iterator itr = mNodeMap.begin(); itr != mNodeMap.end(); ++itr) { + NiNodeRef bone = (*itr).second; + if (bone->GetParent() == NULL) { + if (INode* boneNode = mI->GetINodeByName((*itr).first.c_str())) { + makeNode(root, boneNode, false); + } + } + } + if (mExportCollision) { result = exportCollision(root, node); if (result != Ok) diff --git a/NifExport/Mesh.cpp b/NifExport/Mesh.cpp index 9faaab5..2539ea6 100755 --- a/NifExport/Mesh.cpp +++ b/NifExport/Mesh.cpp @@ -7,9 +7,6 @@ #ifdef USE_BIPED # include <cs/BipedApi.h> #endif -#include "obj/NiSkinInstance.h" -#include "obj/NiSkinData.h" -#include "obj/NiSkinPartition.h" #include "obj/NiBSBoneLODController.h" #include "obj/NiTransformController.h" #include "obj/bhkBlendController.h" @@ -18,7 +15,7 @@ #include "obj/bhkCapsuleShape.h" Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t) -{ +{ ObjectState os = node->EvalWorldState(t); bool local = !mFlattenHierarchy; @@ -27,8 +24,37 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue if (!tri) return Error; + 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 ( uint 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 ( uint 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) @@ -97,6 +123,7 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue 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"; @@ -132,6 +159,9 @@ Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue if (tri != os.obj) tri->DeleteMe(); + if (copymesh) + delete copymesh; + return result; } @@ -397,10 +427,13 @@ Exporter::Result SkinInstance::execute() for (BoneWeightList::iterator bitr = boneWeights.begin(); bitr != boneWeights.end(); ++bitr, ++bone) { shape->SetBoneWeights(bone, (*bitr)); } - if (Exporter::mMultiplePartitions) - shape->GenHardwareSkinInfo(Exporter::mBonesPerPartition, Exporter::mBonesPerVertex); - else - shape->GenHardwareSkinInfo(0, 0); + if (Exporter::mNifVersionInt > VER_4_0_0_2) + { + if (Exporter::mMultiplePartitions) + shape->GenHardwareSkinInfo(Exporter::mBonesPerPartition, Exporter::mBonesPerVertex); + else + shape->GenHardwareSkinInfo(0, 0); + } return Exporter::Ok; } diff --git a/NifExport/MtlTex.cpp b/NifExport/MtlTex.cpp index 9465d63..8624b17 100755 --- a/NifExport/MtlTex.cpp +++ b/NifExport/MtlTex.cpp @@ -30,7 +30,7 @@ void Exporter::makeTexture(NiAVObjectRef &parent, Mtl *mtl) bool Exporter::makeTextureDesc(BitmapTex *bmTex, TexDesc& td) { - td.source = CreateNiObject<NiSourceTexture>(); + td.source = new NiSourceTexture(); // Filtering switch (bmTex->GetFilterType()) @@ -378,7 +378,6 @@ bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) if (alphaMode != 0 || AlphaTestEnable) { // always add alpha ??? NiAlphaPropertyRef alphaProp = CreateNiObject<NiAlphaProperty>(); - parent->AddProperty(alphaProp); alphaProp->SetAlphaBlend(true); if (alphaMode == 0) { // automatic alphaProp->SetSourceBlendMode(NiAlphaProperty::BlendMode(srcBlend)); @@ -404,6 +403,7 @@ bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) alphaProp->SetAlphaSort(!NoSorter); alphaProp->SetAlphaTestThreshold(TestRef); alphaProp->SetAlphaTest(AlphaTestEnable); + parent->AddProperty(alphaProp); } int ntex = mtl->NumSubTexmaps(); @@ -411,15 +411,18 @@ bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) { ntex = min(ntex, 7); TexType texmap[] = {BASE_MAP, DARK_MAP, DETAIL_MAP, DECAL_0_MAP, BUMP_MAP, GLOSS_MAP, GLOW_MAP, DECAL_1_MAP}; - NiTexturingPropertyRef texProp = CreateNiObject<NiTexturingProperty>(); - texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode)); - texProp->SetTextureCount(7); + NiTexturingPropertyRef texProp; for (int i = 0; i < ntex; ++i) { - BitmapTex *bmTex = getTexture(mtl, i); if (!bmTex) continue; + if (texProp == NULL) + { + texProp = new NiTexturingProperty(); + texProp->SetApplyMode(Niflib::ApplyMode(ApplyMode)); + texProp->SetTextureCount(7); + } TexDesc td; if (makeTextureDesc(bmTex, td)) { TexType textype = texmap[i]; @@ -437,7 +440,10 @@ bool Exporter::exportCiv4Shader(NiAVObjectRef parent, Mtl* mtl) } } - parent->AddProperty(texProp); + if (texProp != NULL) + { + parent->AddProperty(texProp); + } } return true; } diff --git a/NifExport/NifExport.cpp b/NifExport/NifExport.cpp index 47a0bd4..22a8ad5 100755 --- a/NifExport/NifExport.cpp +++ b/NifExport/NifExport.cpp @@ -104,6 +104,8 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA CheckDlgButton(hWnd, IDC_CHK_CAMERA, Exporter::mExportCameras); CheckDlgButton(hWnd, IDC_CHK_BONE_COLL, Exporter::mGenerateBoneCollision); CheckDlgButton(hWnd, IDC_CHK_TANGENTS, Exporter::mTangentAndBinormalExtraData); + CheckDlgButton(hWnd, IDC_CHK_COLLAPSE_TRANS, Exporter::mCollapseTransforms); + string selection = Exporter::mGameName; string version = Exporter::mNifVersion; @@ -190,6 +192,7 @@ BOOL CALLBACK NifExportOptionsDlgProc(HWND hWnd,UINT message,WPARAM wParam,LPARA Exporter::mExportCameras = IsDlgButtonChecked(hWnd, IDC_CHK_CAMERA); Exporter::mGenerateBoneCollision = IsDlgButtonChecked(hWnd, IDC_CHK_BONE_COLL); Exporter::mTangentAndBinormalExtraData = IsDlgButtonChecked(hWnd, IDC_CHK_TANGENTS); + Exporter::mCollapseTransforms = IsDlgButtonChecked(hWnd, IDC_CHK_COLLAPSE_TRANS); Exporter::mExportTransforms = IsDlgButtonChecked(hWnd, IDC_CHK_TRANSFORMS2); //Exporter::mUseTimeTags = IsDlgButtonChecked(hWnd, IDC_CHK_USE_TIME_TAGS); diff --git a/NifExport/Util.cpp b/NifExport/Util.cpp index 446731c..610fd0f 100755 --- a/NifExport/Util.cpp +++ b/NifExport/Util.cpp @@ -427,12 +427,50 @@ void Exporter::getChildNodes(INode *node, vector<NiNodeRef>& list) for (int i=0; i<node->NumberOfChildren(); i++) { INode * child = node->GetChildNode(i); - list.push_back( getNode(child->GetName()) ); + ObjectState os = node->EvalWorldState(0); + bool addBone = false; + bool local = !mFlattenHierarchy; + + if (node->IsBoneShowing()) + { + addBone = true; + } + else if (os.obj && os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) + { + if ( os.obj + && ( os.obj->ClassID() == BONE_OBJ_CLASSID + || os.obj->ClassID() == Class_ID(BONE_CLASS_ID,0) + || os.obj->ClassID() == Class_ID(0x00009125,0) /* Biped Twist Helpers */ + ) + ) + { + addBone = true; + } + else if (!mSkeletonOnly) + { + if (mExportType != NIF_WO_ANIM && isNodeTracked(node)) { + addBone = true; + } else if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) { + addBone = true; + } + } + else if (mExportCameras && os.obj && os.obj->SuperClassID()==CAMERA_CLASS_ID) + { + addBone = true; + } + else if (isMeshGroup(node) && local) // only create node if local + { + addBone = true; + } + } + if (addBone) + { + list.push_back( getNode(child->GetName()) ); + } getChildNodes(child, list); } } - // Special case of a single branch being exported bool Exporter::exportPrn(NiNodeRef &obj, INode *node) { diff --git a/NifExport/resource.h b/NifExport/resource.h index b52595e..3bc59f1 100755 --- a/NifExport/resource.h +++ b/NifExport/resource.h @@ -64,6 +64,8 @@ #define IDC_SPIN 13496 #define IDC_LBL_WIKI 13497 #define IDC_CHK_TANGENTS 13498 +#define IDC_CHECK2 13499 +#define IDC_CHK_COLLAPSE_TRANS 13499 // Next default values for new objects // @@ -71,7 +73,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 13499 +#define _APS_NEXT_CONTROL_VALUE 13500 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/NifImport/ImportAnimation.cpp b/NifImport/ImportAnimation.cpp index 816c04d..a7a6386 100644 --- a/NifImport/ImportAnimation.cpp +++ b/NifImport/ImportAnimation.cpp @@ -47,6 +47,25 @@ void* operator new(size_t size, NoteKey* stub ) void operator delete(void* memblock, NoteKey* stub ) { return MAX_delete(memblock); } +#else +void* operator new(size_t size, NoteKey* stub ) +{ + void * (__cdecl *pfmalloc)(__in size_t _Size) = 0; + if (HMODULE hMod = GetModuleHandle("msvcrt.dll")) + *(FARPROC*)pfmalloc = GetProcAddress(hMod, "malloc"); + if (pfmalloc == 0) pfmalloc = malloc; + return pfmalloc(size); +} + +void operator delete(void* memblock, NoteKey* stub ) +{ + void (__cdecl *pffree)(void *memblock) = 0; + if (HMODULE hMod = GetModuleHandle("msvcrt.dll")) + *(FARPROC*)pffree = GetProcAddress(hMod, "free"); + if (pffree == 0) pffree = free; + return pffree(memblock); +} + #endif struct AnimationImport @@ -309,8 +328,9 @@ bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKe } gi->SetAnimRange(range); - if (addNoteTracks && (wildmatch("start*", textKeys.front().data)) ) { + if (addNoteTracks /*&& (wildmatch("start*", textKeys.front().data))*/ ) { if ( INode *n = gi->GetINodeByName(target.c_str()) ) { +//#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+ #if 1 DefNoteTrack* nt = (DefNoteTrack*)NewDefaultNoteTrack(); n->AddNoteTrack(nt); @@ -350,7 +370,7 @@ bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKe } } -#else +#else // Version 5 TSTR script; script += "fn getActorManager obj = (\n" @@ -378,8 +398,7 @@ bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKe stringlist args = TokenizeCommandLine((*itr).data.c_str(), true); if (args.empty()) continue; bool hasName = false; - bool hasLoop = false; - CycleType ct = cntr->GetCycleType(); + bool hasLoop = loop; for (stringlist::iterator itr = args.begin(); itr != args.end(); ++itr) { if (strmatch("-name", *itr)) { if (++itr == args.end()) break; @@ -389,13 +408,11 @@ bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKe } } if (!hasName) { - string name = cntr->GetName(); - if (name.empty()) - name = FormatString("EMPTY_SEQUENCE_AT_%df", int(t * FramesPerSecond / TicksPerFrame) ); + string name = FormatString("EMPTY_SEQUENCE_AT_%df", int(t * FramesPerSecond / TicksPerFrame) ); args.push_back("-name"); args.push_back(name); } - if (!hasLoop && ct == CYCLE_LOOP) { + if (!hasLoop) { args.push_back("-loop"); } @@ -408,7 +425,7 @@ bool NifImporter::AddNoteTracks(float time, string name, string target, NiTextKe //NoteKey *key = new NoteKey(TimeToFrame(time + (*itr).time), (*itr).data.c_str(), 0); //nt->keys.Append(1, &key); } - ExecuteMAXScriptScript(script, TRUE, NULL); + //ExecuteMAXScriptScript(script, TRUE, NULL); #endif } } diff --git a/NifImport/ImportSkeleton.cpp b/NifImport/ImportSkeleton.cpp index dc81a62..e5f5b60 100644 --- a/NifImport/ImportSkeleton.cpp +++ b/NifImport/ImportSkeleton.cpp @@ -574,7 +574,7 @@ void NifImporter::ImportBones(NiNodeRef node, bool recurse) vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children); NiAVObject::CollisionType cType = node->GetCollision(); - if (cType == NiAVObject::CT_BOUNDINGBOX && children.empty() && name=="Bounding Box") + if (children.empty() && name=="Bounding Box") return; // Do all node manipulations here diff --git a/NifPlugins/DllEntry.cpp b/NifPlugins/DllEntry.cpp index fea12c6..4df1a75 100644 --- a/NifPlugins/DllEntry.cpp +++ b/NifPlugins/DllEntry.cpp @@ -16,6 +16,8 @@ extern ClassDesc2* GetNifExportDesc(); extern ClassDesc2* GetNifPropsDesc(); extern ClassDesc2* GetNifFurnitureDesc(); extern ClassDesc2* GetKfExportDesc(); +extern ClassDesc2* GetbhkSphereDesc(); +extern ClassDesc2* GetbhkCapsuleDesc(); enum ClassDescType { @@ -34,7 +36,7 @@ static int controlsInit = FALSE; static int libVersion = VERSION_3DSMAX; static int foundOlderReleaseConflict = -1; static int nClasses = 0; -static ClassDesc2* classDescriptions[CD_Count]; +static ClassDesc2* classDescriptions[20]; static bool classDescEnabled[CD_Count]; @@ -91,6 +93,10 @@ void InitializeLibSettings() if ( GetIniValue<bool>("NifProps", "Enable", true, iniName) ) { classDescEnabled[CD_Props] = true; classDescriptions[nClasses++] = GetNifPropsDesc(); +#ifdef USE_UNSUPPORTED_CODE + classDescriptions[nClasses++] = GetbhkSphereDesc(); + classDescriptions[nClasses++] = GetbhkCapsuleDesc(); +#endif } if ( GetIniValue<bool>("NifFurniture", "Enable", true, iniName) ) { classDescEnabled[CD_Furniture] = true; diff --git a/NifProps/NifProps.rc b/NifProps/NifProps.rc index 7138fc9..d01af50 100755 --- a/NifProps/NifProps.rc +++ b/NifProps/NifProps.rc @@ -145,6 +145,84 @@ BEGIN CONTROL "",IDC_SP_ANIM_PRIORITY,"SpinnerControl",WS_DISABLED,55,17,7,10 END +IDD_SPHEREPARAM2 DIALOGEX 0, 0, 108, 51 +STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_RADIUS,"CustEdit",WS_TABSTOP,49,8,36,10 + CONTROL "",IDC_SEGMENTS,"CustEdit",WS_TABSTOP,49,21,36,10 + CONTROL "Smooth",IDC_OBSMOOTH,"Button",BS_AUTOCHECKBOX,49,36,36,10 + RTEXT "Radius:",-1,22,9,25,8 + RTEXT "Segments:",-1,11,21,36,8 + CONTROL "",IDC_SEGSPINNER,"SpinnerControl",0x0,87,21,7,10 + CONTROL "",IDC_RADSPINNER,"SpinnerControl",0x0,87,8,7,10 +END + +IDD_RigidBody DIALOGEX 0, 0, 107, 238 +STYLE DS_SETFONT | DS_3DLOOK | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + COMBOBOX IDC_CB_MATERIAL,9,22,83,157,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Material",IDC_LBL_MATERIAL,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,9,14,83,8 + COMBOBOX IDC_CB_LAYER,9,46,83,171,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Layer",IDC_LBL_LAYER,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,9,37,83,8 + GROUPBOX "Rigid Body",IDC_GRP_HAVOK,4,3,98,230 + CONTROL "Mass",IDC_LBL_MASS,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,9,63,56,8 + CONTROL "Friction",IDC_LBL_FRICTION,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,9,76,56,8 + LTEXT "Restitution",IDC_LBL_RESTITUTION,9,87,56,11 + CONTROL "Motion System",IDC_LBL_MOTION_SYSTEM,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,9,183,67,8 + COMBOBOX IDC_CB_MOTION_SYSTEM,9,192,83,74,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "Quality Type",IDC_LBL_QUALITY_TYPE,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,9,208,43,8 + COMBOBOX IDC_CB_QUALITY_TYPE,9,217,83,63,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "",IDC_ED_MASS,"CustEdit",WS_TABSTOP,67,63,22,10 + CONTROL "",IDC_SP_MASS,"SpinnerControl",0x0,90,63,7,10 + CONTROL "",IDC_ED_FRICTION,"CustEdit",WS_TABSTOP,67,75,22,10 + CONTROL "",IDC_SP_FRICTION,"SpinnerControl",0x0,90,75,7,10 + CONTROL "",IDC_ED_RESTITUTION,"CustEdit",WS_TABSTOP,67,87,22,10 + CONTROL "",IDC_SP_RESTITUTION,"SpinnerControl",0x0,90,87,7,10 + LTEXT "Linear Damping",IDC_LBL_LINEAR_DAMPING,9,100,56,11 + CONTROL "",IDC_ED_LINEAR_DAMPING,"CustEdit",WS_TABSTOP,67,100,22,10 + CONTROL "",IDC_SP_LINEAR_DAMPING,"SpinnerControl",0x0,90,100,7,10 + LTEXT "Angular Damping",IDC_LBL_ANGULAR_DAMPING,9,112,56,10 + CONTROL "",IDC_ED_ANGULAR_DAMPING,"CustEdit",WS_TABSTOP,67,112,22,10 + CONTROL "",IDC_SP_ANGULAR_DAMPING,"SpinnerControl",0x0,90,112,7,10 + LTEXT "Max. Linear Velocity",IDC_LBL_MAX_LINEAR_VELOCITY,9,124,56,16 + CONTROL "",IDC_ED_MAX_LINEAR_VELOCITY,"CustEdit",WS_TABSTOP,67,128,22,10 + CONTROL "",IDC_SP_MAX_LINEAR_VELOCITY,"SpinnerControl",0x0,90,128,7,10 + LTEXT "Max. Angular Velocity",IDC_LBL_MAX_ANGULAR_VELOCITY,9,143,56,16 + CONTROL "",IDC_ED_MAX_ANGULAR_VELOCITY,"CustEdit",WS_TABSTOP,67,147,22,10 + CONTROL "",IDC_SP_MAX_ANGULAR_VELOCITY,"SpinnerControl",0x0,90,147,7,10 + LTEXT "Penetration Depth",IDC_LBL_PENETRATION_DEPTH,9,162,56,16 + CONTROL "",IDC_ED_PENETRATION_DEPTH,"CustEdit",WS_TABSTOP,67,166,22,10 + CONTROL "",IDC_SP_PENETRATION_DEPTH,"SpinnerControl",0x0,90,166,7,10 +END + +IDD_CAPSULEPARAM DIALOGEX 0, 0, 112, 86 +STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_RADIUS1,"CustEdit",WS_TABSTOP,49,5,36,10 + RTEXT "Radius 1:",-1,15,6,31,8 + CONTROL "",IDC_RADSPINNER1,"SpinnerControl",0x0,87,5,7,10 + CONTROL "",IDC_RADIUS2,"CustEdit",WS_TABSTOP,49,18,36,10 + RTEXT "Radius 2:",-1,15,18,31,8 + CONTROL "",IDC_RADSPINNER2,"SpinnerControl",0x0,87,18,7,10 + CONTROL "Cap Pos 1:",IDC_LBL_POS1,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,12,31,39,8 + CONTROL "",IDC_ED_POS1_X,"CustEdit",WS_TABSTOP,7,42,20,10 + CONTROL "",IDC_SP_POS1_X,"SpinnerControl",0x0,28,42,7,10 + CONTROL "",IDC_ED_POS1_Y,"CustEdit",WS_TABSTOP,40,42,20,10 + CONTROL "",IDC_SP_POS1_Y,"SpinnerControl",0x0,61,42,7,10 + CONTROL "",IDC_ED_POS1_Z,"CustEdit",WS_TABSTOP,73,42,20,10 + CONTROL "",IDC_SP_POS1_Z,"SpinnerControl",0x0,94,42,7,10 + CONTROL "Cap Pos 2:",IDC_LBL_POS2,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | WS_GROUP,12,56,39,8 + CONTROL "",IDC_ED_POS2_X,"CustEdit",WS_TABSTOP,7,68,20,10 + CONTROL "",IDC_SP_POS2_X,"SpinnerControl",0x0,28,68,7,10 + CONTROL "",IDC_ED_POS2_Y,"CustEdit",WS_TABSTOP,40,68,20,10 + CONTROL "",IDC_SP_POS2_Y,"SpinnerControl",0x0,61,68,7,10 + CONTROL "",IDC_ED_POS2_Z,"CustEdit",WS_TABSTOP,73,68,20,10 + CONTROL "",IDC_SP_POS2_Z,"SpinnerControl",0x0,94,68,7,10 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -169,6 +247,20 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 34 END + + IDD_RigidBody, DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 102 + TOPMARGIN, 7 + BOTTOMMARGIN, 233 + END + + IDD_CAPSULEPARAM, DIALOG + BEGIN + RIGHTMARGIN, 108 + BOTTOMMARGIN, 85 + END END #endif // APSTUDIO_INVOKED @@ -362,6 +454,190 @@ BEGIN 0 END +IDD_RigidBody DLGINIT +BEGIN + IDC_CB_MATERIAL, 0x403, 6, 0 +0x7453, 0x6e6f, 0x0065, + IDC_CB_MATERIAL, 0x403, 6, 0 +0x6c43, 0x746f, 0x0068, + IDC_CB_MATERIAL, 0x403, 5, 0 +0x6944, 0x7472, "\000" + IDC_CB_MATERIAL, 0x403, 6, 0 +0x6c47, 0x7361, 0x0073, + IDC_CB_MATERIAL, 0x403, 6, 0 +0x7247, 0x7361, 0x0073, + IDC_CB_MATERIAL, 0x403, 6, 0 +0x654d, 0x6174, 0x006c, + IDC_CB_MATERIAL, 0x403, 8, 0 +0x724f, 0x6167, 0x696e, 0x0063, + IDC_CB_MATERIAL, 0x403, 5, 0 +0x6b53, 0x6e69, "\000" + IDC_CB_MATERIAL, 0x403, 6, 0 +0x6157, 0x6574, 0x0072, + IDC_CB_MATERIAL, 0x403, 5, 0 +0x6f57, 0x646f, "\000" + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6548, 0x7661, 0x2079, 0x7453, 0x6e6f, 0x0065, + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6548, 0x7661, 0x2079, 0x654d, 0x6174, 0x006c, + IDC_CB_MATERIAL, 0x403, 11, 0 +0x6548, 0x7661, 0x2079, 0x6f57, 0x646f, "\000" + IDC_CB_MATERIAL, 0x403, 6, 0 +0x6843, 0x6961, 0x006e, + IDC_CB_MATERIAL, 0x403, 5, 0 +0x6e53, 0x776f, "\000" + IDC_CB_MATERIAL, 0x403, 13, 0 +0x7453, 0x6e6f, 0x2065, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 13, 0 +0x6c43, 0x746f, 0x2068, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6944, 0x7472, 0x5320, 0x6174, 0x7269, 0x0073, + IDC_CB_MATERIAL, 0x403, 13, 0 +0x6c47, 0x7361, 0x2073, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 13, 0 +0x7247, 0x7361, 0x2073, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 13, 0 +0x654d, 0x6174, 0x206c, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 15, 0 +0x724f, 0x6167, 0x696e, 0x2063, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6b53, 0x6e69, 0x5320, 0x6174, 0x7269, 0x0073, + IDC_CB_MATERIAL, 0x403, 13, 0 +0x6157, 0x6574, 0x2072, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6f57, 0x646f, 0x5320, 0x6174, 0x7269, 0x0073, + IDC_CB_MATERIAL, 0x403, 19, 0 +0x6548, 0x7661, 0x2079, 0x7453, 0x6e6f, 0x2065, 0x7453, 0x6961, 0x7372, +"\000" + IDC_CB_MATERIAL, 0x403, 19, 0 +0x6548, 0x7661, 0x2079, 0x654d, 0x6174, 0x206c, 0x7453, 0x6961, 0x7372, +"\000" + IDC_CB_MATERIAL, 0x403, 18, 0 +0x6548, 0x7661, 0x2079, 0x6f57, 0x646f, 0x5320, 0x6174, 0x7269, 0x0073, + + IDC_CB_MATERIAL, 0x403, 13, 0 +0x6843, 0x6961, 0x206e, 0x7453, 0x6961, 0x7372, "\000" + IDC_CB_MATERIAL, 0x403, 12, 0 +0x6e53, 0x776f, 0x5320, 0x6174, 0x7269, 0x0073, + IDC_CB_MATERIAL, 0x403, 9, 0 +0x6c45, 0x7665, 0x7461, 0x726f, "\000" + IDC_CB_LAYER, 0x403, 13, 0 +0x6e55, 0x6469, 0x6e65, 0x6974, 0x6966, 0x6465, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x7453, 0x7461, 0x6369, "\000" + IDC_CB_LAYER, 0x403, 11, 0 +0x6e41, 0x6d69, 0x7453, 0x7461, 0x6369, "\000" + IDC_CB_LAYER, 0x403, 12, 0 +0x7254, 0x6e61, 0x7073, 0x7261, 0x6e65, 0x0074, + IDC_CB_LAYER, 0x403, 8, 0 +0x6c43, 0x7475, 0x6574, 0x0072, + IDC_CB_LAYER, 0x403, 7, 0 +0x6557, 0x7061, 0x6e6f, "\000" + IDC_CB_LAYER, 0x403, 11, 0 +0x7250, 0x6a6f, 0x6365, 0x6974, 0x656c, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x7053, 0x6c65, 0x006c, + IDC_CB_LAYER, 0x403, 6, 0 +0x6942, 0x6570, 0x0064, + IDC_CB_LAYER, 0x403, 5, 0 +0x7254, 0x6565, "\000" + IDC_CB_LAYER, 0x403, 5, 0 +0x7250, 0x706f, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x6157, 0x6574, 0x0072, + IDC_CB_LAYER, 0x403, 8, 0 +0x7254, 0x6769, 0x6567, 0x0072, + IDC_CB_LAYER, 0x403, 8, 0 +0x6554, 0x7272, 0x6961, 0x006e, + IDC_CB_LAYER, 0x403, 5, 0 +0x7254, 0x7061, "\000" + IDC_CB_LAYER, 0x403, 14, 0 +0x6f4e, 0x436e, 0x6c6f, 0x696c, 0x6164, 0x6c62, 0x0065, + IDC_CB_LAYER, 0x403, 10, 0 +0x6c43, 0x756f, 0x5464, 0x6172, 0x0070, + IDC_CB_LAYER, 0x403, 7, 0 +0x7247, 0x756f, 0x646e, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x6f50, 0x7472, 0x6c61, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x7453, 0x6961, 0x7372, "\000" + IDC_CB_LAYER, 0x403, 15, 0 +0x6843, 0x7261, 0x6f43, 0x746e, 0x6f72, 0x6c6c, 0x7265, "\000" + IDC_CB_LAYER, 0x403, 9, 0 +0x7641, 0x696f, 0x4264, 0x786f, "\000" + IDC_CB_LAYER, 0x403, 2, 0 +0x003f, + IDC_CB_LAYER, 0x403, 2, 0 +0x003f, + IDC_CB_LAYER, 0x403, 11, 0 +0x6143, 0x656d, 0x6172, 0x6950, 0x6b63, "\000" + IDC_CB_LAYER, 0x403, 9, 0 +0x7449, 0x6d65, 0x6950, 0x6b63, "\000" + IDC_CB_LAYER, 0x403, 12, 0 +0x694c, 0x656e, 0x664f, 0x6953, 0x6867, 0x0074, + IDC_CB_LAYER, 0x403, 9, 0 +0x6150, 0x6874, 0x6950, 0x6b63, "\000" + IDC_CB_LAYER, 0x403, 12, 0 +0x7543, 0x7473, 0x6d6f, 0x6950, 0x6b63, 0x0031, + IDC_CB_LAYER, 0x403, 12, 0 +0x7543, 0x7473, 0x6d6f, 0x6950, 0x6b63, 0x0032, + IDC_CB_LAYER, 0x403, 15, 0 +0x7053, 0x6c65, 0x456c, 0x7078, 0x6f6c, 0x6973, 0x6e6f, "\000" + IDC_CB_LAYER, 0x403, 13, 0 +0x7244, 0x706f, 0x6970, 0x676e, 0x6950, 0x6b63, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x744f, 0x6568, 0x0072, + IDC_CB_LAYER, 0x403, 5, 0 +0x6548, 0x6461, "\000" + IDC_CB_LAYER, 0x403, 5, 0 +0x6f42, 0x7964, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x7053, 0x6e69, 0x3165, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x7053, 0x6e69, 0x3265, "\000" + IDC_CB_LAYER, 0x403, 10, 0 +0x554c, 0x7070, 0x7265, 0x7241, 0x006d, + IDC_CB_LAYER, 0x403, 9, 0 +0x464c, 0x726f, 0x4165, 0x6d72, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x484c, 0x6e61, 0x0064, + IDC_CB_LAYER, 0x403, 7, 0 +0x544c, 0x6968, 0x6867, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x434c, 0x6c61, 0x0066, + IDC_CB_LAYER, 0x403, 6, 0 +0x464c, 0x6f6f, 0x0074, + IDC_CB_LAYER, 0x403, 10, 0 +0x5552, 0x7070, 0x7265, 0x7241, 0x006d, + IDC_CB_LAYER, 0x403, 9, 0 +0x4652, 0x726f, 0x4165, 0x6d72, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x4852, 0x6e61, 0x0064, + IDC_CB_LAYER, 0x403, 7, 0 +0x5452, 0x6968, 0x6867, "\000" + IDC_CB_LAYER, 0x403, 6, 0 +0x4352, 0x6c61, 0x0066, + IDC_CB_LAYER, 0x403, 6, 0 +0x4652, 0x6f6f, 0x0074, + IDC_CB_LAYER, 0x403, 5, 0 +0x6154, 0x6c69, "\000" + IDC_CB_LAYER, 0x403, 11, 0 +0x6953, 0x6564, 0x6557, 0x7061, 0x6e6f, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x6853, 0x6569, 0x646c, "\000" + IDC_CB_LAYER, 0x403, 7, 0 +0x7551, 0x7669, 0x7265, "\000" + IDC_CB_LAYER, 0x403, 11, 0 +0x6142, 0x6b63, 0x6557, 0x7061, 0x6e6f, "\000" + IDC_CB_LAYER, 0x403, 11, 0 +0x6142, 0x6b63, 0x6557, 0x7061, 0x6e6f, "\000" + IDC_CB_LAYER, 0x403, 9, 0 +0x6f50, 0x796e, 0x6154, 0x6c69, "\000" + IDC_CB_LAYER, 0x403, 5, 0 +0x6957, 0x676e, "\000" + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -376,6 +652,57 @@ BEGIN IDS_PARAMS "Parameters" IDS_SPIN "Spin" IDS_ANIM_PARAMS "Animation" + IDS_RB_Capsule "bhkCapsule" +END + +STRINGTABLE +BEGIN + IDS_RB_RADIUS "Radius" + IDS_RB_SEGS "Segments" +END + +STRINGTABLE +BEGIN + IDS_RB_RADIUS1 "Radius 1" + IDS_RB_RADIUS2 "Radius 2" +END + +STRINGTABLE +BEGIN + IDS_RB_SPHERE "bhkSphere" +END + +STRINGTABLE +BEGIN + IDS_RB_SPHERE_CLASS "bhkSphere" +END + +STRINGTABLE +BEGIN + IDS_RB_PRIMITIVES "Standard Primitives" +END + +STRINGTABLE +BEGIN + IDS_DS_PARAMCHG "Parameter Change" +END + +STRINGTABLE +BEGIN + IDS_RB_PARAMETERS "Parameters" +END + +STRINGTABLE +BEGIN + IDS_RB_SMOOTH "Smooth" +END + +STRINGTABLE +BEGIN + IDS_RB_CAPSULE_CLASS "bhkCapsule" + IDS_RB_RIGIDBODY_PARAM "Rigid Body Parameters" + IDS_RB_CAP_POS1 "Cap Position 1" + IDS_RB_CAP_POS2 "Cap Position 2" END #endif // English (U.S.) resources diff --git a/NifProps/bhkCapsuleObj.cpp b/NifProps/bhkCapsuleObj.cpp new file mode 100644 index 0000000..e237f2f --- /dev/null +++ b/NifProps/bhkCapsuleObj.cpp @@ -0,0 +1,1010 @@ +/********************************************************************** +*< +FILE: bhkCapsuleObj.cpp + +DESCRIPTION: Collision Capsule Object Implementation + +CREATED BY: tazpn (Theo) + +HISTORY: + V1.0 - Derived from 3ds max prim sphere example + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#pragma warning( disable:4800 ) +#include <max.h> +#include "MAX_Mem.h" +#include <map> +#include "NifProps.h" +#include "iparamm.h" +#include "Simpobj.h" +#include "surf_api.h" +#include "notify.h" +#include "macroRec.h" +#include "bhkRigidBodyInterface.h" +#ifndef _countof +#define _countof(x) (sizeof(x)/sizeof((x)[0])) +#endif + +static void BuildScubaMesh(Mesh &mesh, int segs, int smooth, int llsegs, + float radius1, float radius2, Point3 cap1, Point3 cap2); + +const Class_ID BHKCAPSULEOBJECT_CLASS_ID = Class_ID(0x7f8f629a, 0x1d88470a); + +class bhkCapsuleObject : public SimpleObject, public IParamArray, public bhkRigidBodyIfcHelper +{ +public: + // Class vars + static IParamMap *pmapParam; + static float crtRadius; + static float crtRadius1; + static float crtRadius2; + static Point3 crtCapPos1; + static Point3 crtCapPos2; + static IObjParam *ip; + + bhkCapsuleObject(BOOL loading); + ~bhkCapsuleObject(); + + // From Object + int CanConvertToType(Class_ID obtype); + Object* ConvertToType(TimeValue t, Class_ID obtype); + void GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist); + + CreateMouseCallBack* GetCreateMouseCallBack(); + void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev); + void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next); + RefTargetHandle Clone(RemapDir& remap = NoRemap()); + TCHAR *GetObjectName() { return GetString(IDS_RB_Capsule); } + + // Animatable methods + void DeleteThis() {delete this;} + Class_ID ClassID() { return BHKCAPSULEOBJECT_CLASS_ID; } + SClass_ID SuperClassID() { return HELPER_CLASS_ID; } + + // From ReferenceTarget + IOResult Load(ILoad *iload); + IOResult Save(ISave *isave); + + // From ref + int NumRefs() {return 2;} + RefTargetHandle GetReference(int i); + void SetReference(int i, RefTargetHandle rtarg); + + // From SimpleObject + void BuildMesh(TimeValue t); + BOOL OKtoDisplay(TimeValue t); + void InvalidateUI(); + ParamDimension *GetParameterDim(int pbIndex); + TSTR GetParameterName(int pbIndex); + + void UpdateUI(); + + BaseInterface* GetInterface(Interface_ID id); + +}; + +class CapsuleObjCreateCallBack : public CreateMouseCallBack { + IPoint2 sp[4]; + bhkCapsuleObject *ob; + Point3 p[4]; +public: + int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat); + void SetObj(bhkCapsuleObject *obj) {ob = obj;} +}; +static CapsuleObjCreateCallBack CapsuleCreateCB; + +// Misc stuff +#define MAX_SEGMENTS 200 +#define MIN_SEGMENTS 4 + +#define MIN_RADIUS float(0) +#define MAX_RADIUS float(1.0E30) + +#define MIN_SMOOTH 0 +#define MAX_SMOOTH 1 + +#define DEF_SEGMENTS 32 // 16 +#define DEF_RADIUS float(0.0) + +#define SMOOTH_ON 1 +#define SMOOTH_OFF 0 + +#define MIN_SLICE float(-1.0E30) +#define MAX_SLICE float( 1.0E30) + + +//--- ClassDescriptor and class vars --------------------------------- + +static BOOL sInterfaceAdded = FALSE; + +// The class descriptor for Capsule +class bhkCapsuleClassDesc : public ClassDesc2 +{ +public: + int IsPublic() { return 1; } + void * Create(BOOL loading = FALSE) + { + AddInterface (GetbhkRigidBodyInterfaceDesc()); + return new bhkCapsuleObject(loading); + } + const TCHAR * ClassName() { return GetString(IDS_RB_CAPSULE_CLASS); } + SClass_ID SuperClassID() { return HELPER_CLASS_ID; } + Class_ID ClassID() { return BHKCAPSULEOBJECT_CLASS_ID; } + const TCHAR* Category() { return "NifTools"; } + void ResetClassParams(BOOL fileReset); +}; + +static bhkCapsuleClassDesc CapsuleDesc; +extern ClassDesc2* GetbhkCapsuleDesc() { return &CapsuleDesc; } + +// in prim.cpp - The dll instance handle +extern HINSTANCE hInstance; + +IParamMap *bhkCapsuleObject::pmapParam = NULL; +IObjParam *bhkCapsuleObject::ip = NULL; +float bhkCapsuleObject::crtRadius1 = 0.0f; +float bhkCapsuleObject::crtRadius2 = 0.0f; +Point3 bhkCapsuleObject::crtCapPos1; +Point3 bhkCapsuleObject::crtCapPos2; + + +void bhkCapsuleClassDesc::ResetClassParams(BOOL fileReset) +{ + bhkCapsuleObject::crtRadius1 = 0.0f; + bhkCapsuleObject::crtRadius2 = 0.0f; + bhkCapsuleObject::crtCapPos1.Set(0,0,0); + bhkCapsuleObject::crtCapPos2.Set(0,0,0); +} + + +//--- Parameter map/block descriptors ------------------------------- + +// Parameter block indices +enum CapsuleParamIndicies +{ + PB_RADIUS1, + PB_RADIUS2, + PB_CAP_POS1, + PB_CAP_POS2, +}; + + +// +// +// Parameters + +static ParamUIDesc descParam[] = { + // Radius 1 + ParamUIDesc( + PB_RADIUS1, + EDITTYPE_UNIVERSE, + IDC_RADIUS1,IDC_RADSPINNER1, + MIN_RADIUS,MAX_RADIUS, + SPIN_AUTOSCALE), + + // Radius 2 + ParamUIDesc( + PB_RADIUS2, + EDITTYPE_UNIVERSE, + IDC_RADIUS2,IDC_RADSPINNER2, + MIN_RADIUS,MAX_RADIUS, + SPIN_AUTOSCALE), + + ParamUIDesc( + PB_CAP_POS1, + EDITTYPE_UNIVERSE, + IDC_ED_POS1_X,IDC_SP_POS1_X, + IDC_ED_POS1_Y,IDC_SP_POS1_Y, + IDC_ED_POS1_Z,IDC_SP_POS1_Z, + float(-1.0E30),float(1.0E30), + SPIN_AUTOSCALE), + + ParamUIDesc( + PB_CAP_POS2, + EDITTYPE_UNIVERSE, + IDC_ED_POS2_X,IDC_SP_POS2_X, + IDC_ED_POS2_Y,IDC_SP_POS2_Y, + IDC_ED_POS2_Z,IDC_SP_POS2_Z, + float(-1.0E30),float(1.0E30), + SPIN_AUTOSCALE), + +}; +const int PARAMDESC_LENGTH = _countof(descParam); + +static ParamBlockDescID descVer0[] = { + { TYPE_FLOAT, NULL, TRUE, 0 }, + { TYPE_FLOAT, NULL, TRUE, 1 }, + { TYPE_POINT3, NULL, TRUE, 2 }, + { TYPE_POINT3, NULL, TRUE, 3 } +}; +const int PBLOCK_LENGTH = _countof(descVer0); +static ParamBlockDescID *curDescVer = descVer0; + +// Array of old versions +//static ParamVersionDesc versions[] = { +// ParamVersionDesc(descVer0,_countof(descVer0),0), +//}; +//const int NUM_OLDVERSIONS = _countof(versions); +static ParamVersionDesc* versions = NULL; +const int NUM_OLDVERSIONS = 0; + +// Current version +const int CURRENT_VERSION = NUM_OLDVERSIONS + 1; +static ParamVersionDesc curVersion(descVer0,_countof(descVer0),CURRENT_VERSION); + +class CapsuleParamDlgProc : public ParamMapUserDlgProc { +public: + bhkCapsuleObject *so; + HWND thishWnd; + + CapsuleParamDlgProc(bhkCapsuleObject *s) {so=s;thishWnd=NULL;} + BOOL DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); + void Update(TimeValue t); + void DeleteThis() {delete this;} + + //--- ParamDlgProc -------------------------------- + void TurnSpinner(HWND hWnd,int SpinNum,BOOL ison) + { + ISpinnerControl *spin2 = GetISpinner(GetDlgItem(hWnd,SpinNum)); + if (ison) spin2->Enable();else spin2->Disable(); + ReleaseISpinner(spin2); + }; + +}; + +void CapsuleParamDlgProc::Update(TimeValue t) +{ + if (!thishWnd) + return; + return; +} + +BOOL CapsuleParamDlgProc::DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + thishWnd=hWnd; + switch (msg) + { + case WM_INITDIALOG: + { + Update(t); + break; + } + case WM_COMMAND: + //switch (LOWORD(wParam)) + //{ + //} + break; + } + return FALSE; +} + +//--- Capsule methods ------------------------------- + + +bhkCapsuleObject::bhkCapsuleObject(BOOL loading) +{ + SetAFlag(A_PLUGIN1); + MakeRefByID(FOREVER, 0, CreateParameterBlock(curDescVer, PBLOCK_LENGTH, CURRENT_VERSION)); + assert(pblock); + MakeRefByID(FOREVER, 1, GetRBBlock()); + + pblock->SetValue(PB_RADIUS1,0,crtRadius1); + pblock->SetValue(PB_RADIUS2,0,crtRadius2); + pblock->SetValue(PB_CAP_POS1,0,crtCapPos1); + pblock->SetValue(PB_CAP_POS2,0,crtCapPos2); +} + +bhkCapsuleObject::~bhkCapsuleObject() +{ + CapsuleCreateCB.SetObj(NULL); + if (pmapParam) { + pmapParam->SetUserDlgProc(NULL); + DestroyCPParamMap(pmapParam); + pmapParam = NULL; + } +} + +#define NEWMAP_CHUNKID 0x0100 + +IOResult bhkCapsuleObject::Load(ILoad *iload) +{ + ClearAFlag(A_PLUGIN1); + + IOResult res; + while (IO_OK==(res=iload->OpenChunk())) + { + switch (iload->CurChunkID()) + { + case NEWMAP_CHUNKID: + SetAFlag(A_PLUGIN1); + break; + } + iload->CloseChunk(); + if (res!=IO_OK) return res; + } + return IO_OK; +} + +IOResult bhkCapsuleObject::Save(ISave *isave) +{ + if (TestAFlag(A_PLUGIN1)) { + isave->BeginChunk(NEWMAP_CHUNKID); + isave->EndChunk(); + } + return IO_OK; +} + +RefTargetHandle bhkCapsuleObject::GetReference(int i) +{ + if (i == 1) + return GetRBBlock(); + return pblock; +} + +void bhkCapsuleObject::SetReference(int i, RefTargetHandle rtarg) +{ + if (i == 1) + return; + pblock=(IParamBlock*)rtarg; +} + +BaseInterface* bhkCapsuleObject::GetInterface(Interface_ID id) +{ + if (id == BHKRIGIDBODYINTERFACE_DESC) + return this; + return SimpleObject::GetInterface(id); +} + + + +void bhkCapsuleObject::BeginEditParams(IObjParam *ip,ULONG flags,Animatable *prev) +{ + SimpleObject::BeginEditParams(ip,flags,prev); + + // Gotta make a new one. + if (NULL == pmapParam) + { + pmapParam = CreateCPParamMap( + descParam,PARAMDESC_LENGTH, + pblock, + ip, + hInstance, + MAKEINTRESOURCE(IDD_CAPSULEPARAM), + GetString(IDS_RB_PARAMETERS), + 0); + } + this->ip = ip; + + if(pmapParam) { + // A callback for the type in. + pmapParam->SetUserDlgProc(new CapsuleParamDlgProc(this)); + } + BeginEditRBParams(ip, flags, prev); +} + +void bhkCapsuleObject::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next ) +{ + SimpleObject::EndEditParams(ip,flags,next); + this->ip = NULL; + + if (pmapParam && flags&END_EDIT_REMOVEUI ) { + pmapParam->SetUserDlgProc(NULL); + DestroyCPParamMap(pmapParam); + pmapParam = NULL; + } + EndEditRBParams(ip, flags, next); +} + +void bhkCapsuleObject::BuildMesh(TimeValue t) +{ + int segs = 12; + int hsegs = 1; + int smooth = 1; + + // Start the validity interval at forever and widdle it down. + //FixHeight(pblock,t,(pmapParam?pmapParam->GetHWnd():NULL),increate); + ivalid = FOREVER; + + float radius1, radius2; + Point3 pos1, pos2; + pblock->GetValue(PB_RADIUS1,t,radius1,ivalid); + pblock->GetValue(PB_RADIUS2,t,radius2,ivalid); + pblock->GetValue(PB_CAP_POS1,t,pos1,ivalid); + pblock->GetValue(PB_CAP_POS2,t,pos2,ivalid); + LimitValue(radius1, MIN_RADIUS, MAX_RADIUS); + LimitValue(radius2, MIN_RADIUS, MAX_RADIUS); + if (radius2 == MIN_RADIUS) radius2 = radius1; + + if (radius1 == 0) + { + mesh.setNumVerts(0); + mesh.setNumFaces(0); + mesh.setNumTVerts(0); + mesh.setNumTVFaces(0); + mesh.setSmoothFlags(smooth != 0); + } + else + { + BuildScubaMesh(mesh, segs, smooth, hsegs, radius2, radius1, pos2, pos1); + } +} + +Object* bhkCapsuleObject::ConvertToType(TimeValue t, Class_ID obtype) +{ + return 0; + //return SimpleObject::ConvertToType(t,obtype); +} + +int bhkCapsuleObject::CanConvertToType(Class_ID obtype) +{ + return 0; +} + +void bhkCapsuleObject::GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist) +{ + Object::GetCollapseTypes(clist, nlist); +} + +int CapsuleObjCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) +{ + float r; + Point3 center; + if (ob == NULL) + { + return CREATE_ABORT; + } + + if (msg == MOUSE_FREEMOVE) + { + vpt->SnapPreview(m,m,NULL, SNAP_IN_3D); + } + + if (msg==MOUSE_POINT||msg==MOUSE_MOVE) + { + switch(point) + { + case 0: // only happens with MOUSE_POINT msg + ob->pblock->SetValue(PB_RADIUS1,0,0.0f); + ob->pblock->SetValue(PB_RADIUS2,0,0.0f); + ob->suspendSnap = TRUE; + sp[0] = m; + p[0] = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + ob->pblock->SetValue(PB_CAP_POS1,0,p[0]); + ob->pblock->SetValue(PB_CAP_POS2,0,p[0]); + mat.SetTrans(p[0]); + break; + + case 1: // Fix radius of first cap + mat.IdentityMatrix(); + //mat.PreRotateZ(HALFPI); + sp[1] = m; + p[1] = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + r = Length(p[1]-p[0]); + mat.SetTrans(p[0]); + + ob->pblock->SetValue(PB_RADIUS1,0,r); + ob->pblock->SetValue(PB_RADIUS2,0,r); + ob->pmapParam->Invalidate(); + + if (flags&MOUSE_CTRL) + { + float ang = (float)atan2(p[1].y-p[0].y,p[1].x-p[0].x); + mat.PreRotateZ(ob->ip->SnapAngle(ang)); + } + if (msg==MOUSE_POINT) + { + if (Length(m-sp[0])<3 || Length(p[1]-p[0])<0.1f) { + ob->suspendSnap = FALSE; + return CREATE_ABORT; + } + } + break; + + case 2: // Get second point + mat.IdentityMatrix(); + //mat.PreRotateZ(HALFPI); + sp[2] = m; + p[2] = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + r = Length(p[1]-p[0]); + mat.SetTrans(p[0]); + + ob->pblock->SetValue(PB_CAP_POS2,0,p[2]); + ob->pmapParam->Invalidate(); + + //if (flags&MOUSE_CTRL) + //{ + // float ang = (float)atan2(p1.y-p[0].y,p1.x-p[0].x); + // mat.PreRotateZ(ob->ip->SnapAngle(ang)); + //} + //if (msg==MOUSE_POINT) + //{ + // ob->suspendSnap = FALSE; + // return (Length(m-sp[0])<3 || Length(p1-p[0])<0.1f)?CREATE_ABORT:CREATE_STOP; + //} + break; + + case 3: // Get second point + mat.IdentityMatrix(); + //mat.PreRotateZ(HALFPI); + sp[3] = m; + p[3] = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + if (flags&MOUSE_CTRL) // ignore radius + { + r = Length(p[1]-p[0]); + ob->pblock->SetValue(PB_RADIUS2,0,r); + } + else + { + // start radius at r1 + r = Length((p[3]-p[2]) + (p[1]-p[0])); + ob->pblock->SetValue(PB_RADIUS2,0,r); + } + ob->pmapParam->Invalidate(); + if (msg==MOUSE_POINT) + { + ob->suspendSnap = FALSE; + return CREATE_STOP; + } + break; + } + } + else if (msg == MOUSE_ABORT) + { + ob->suspendSnap = FALSE; + return CREATE_ABORT; + } + return TRUE; +} + +CreateMouseCallBack* bhkCapsuleObject::GetCreateMouseCallBack() +{ + CapsuleCreateCB.SetObj(this); + return(&CapsuleCreateCB); +} + + +BOOL bhkCapsuleObject::OKtoDisplay(TimeValue t) +{ + float radius; + pblock->GetValue(PB_RADIUS1,t,radius,FOREVER); + if (radius==0.0f) return FALSE; + else return TRUE; +} + +void bhkCapsuleObject::InvalidateUI() +{ + if (pmapParam) pmapParam->Invalidate(); +} + +ParamDimension *bhkCapsuleObject::GetParameterDim(int pbIndex) +{ + switch (pbIndex) + { + case PB_RADIUS1: + return stdWorldDim; + case PB_RADIUS2: + return stdWorldDim; + case PB_CAP_POS1: + return stdWorldDim; + case PB_CAP_POS2: + return stdWorldDim; + default: + return defaultDim; + } +} + +TSTR bhkCapsuleObject::GetParameterName(int pbIndex) +{ + switch (pbIndex) + { + case PB_RADIUS1: + return TSTR(GetString(IDS_RB_RADIUS1)); + case PB_RADIUS2: + return TSTR(GetString(IDS_RB_RADIUS2)); + case PB_CAP_POS1: + return TSTR(GetString(IDS_RB_CAP_POS1)); + case PB_CAP_POS2: + return TSTR(GetString(IDS_RB_CAP_POS2)); + default: + return TSTR(_T("")); + } +} + +RefTargetHandle bhkCapsuleObject::Clone(RemapDir& remap) +{ + bhkCapsuleObject* newob = new bhkCapsuleObject(FALSE); + newob->ReplaceReference(0,remap.CloneRef(pblock)); + newob->ivalid.SetEmpty(); + BaseClone(this, newob, remap); + return(newob); +} + +void bhkCapsuleObject::UpdateUI() +{ + if (ip == NULL) + return; + CapsuleParamDlgProc* dlg = static_cast<CapsuleParamDlgProc*>(pmapParam->GetUserDlgProc()); + dlg->Update(ip->GetTime()); +} + +void AddFace(Face *f,int a,int b,int c,int evis,int smooth_group) +{ + const int ALLF = 4; + f[0].setSmGroup(smooth_group); + f[0].setMatID((MtlID)0); /*default */ + if (evis==0) f[0].setEdgeVisFlags(1,1,0); + else if (evis==1) f[0].setEdgeVisFlags(0,1,1); + else if (evis==2) f[0].setEdgeVisFlags(0,0,1); + else if (evis==ALLF) f[0].setEdgeVisFlags(1,1,1); + else f[0].setEdgeVisFlags(1,0,1); + f[0].setVerts(a,b,c); +} + +void BuildScubaMesh(Mesh &mesh, int segs, int smooth, int llsegs, + float radius1, float radius2, Point3 cap1, Point3 cap2) +{ + Point3 p; + int ix,jx,ic = 1; + int nf=0,nv=0, capsegs=(int)(segs/2.0f),csegs=0; + float ang; + float startAng = 0.0f; + float totalPie = TWOPI; + int lsegs = llsegs-1 + 2*capsegs; + int levels=csegs*2+(llsegs-1); + int capv=segs,sideedge=capsegs+csegs; + int totlevels=levels+capsegs*2+2; + int tvinslice=totlevels+totlevels-2; + float delta = (float)2.0*PI/(float)segs; + int VertexPerLevel=segs; + int nfaces=2*segs*(levels+1); + int ntverts=2*(segs+1)+llsegs-1; + int *edgelstl=new int[totlevels]; + int *edgelstr=new int[totlevels]; + int lastlevel=totlevels-1,dcapv=capv-1,dvertper=VertexPerLevel-1; + edgelstr[0] = edgelstl[0] = 0; + edgelstr[1] = 1; + edgelstl[1] = capv; + for (int i=2;i<=sideedge;i++){ + edgelstr[i]=edgelstr[i-1]+capv; + edgelstl[i]=edgelstr[i]+dcapv; + } + while ((i<lastlevel)&&(i<=totlevels-sideedge)){ + edgelstr[i]=edgelstr[i-1]+VertexPerLevel; + edgelstl[i]=edgelstr[i]+dcapv; + i++; + } + while (i<lastlevel) { + edgelstr[i]=edgelstr[i-1]+capv; + edgelstl[i]=edgelstr[i]+dcapv; + i++; + } + edgelstl[lastlevel]= (edgelstr[lastlevel]=edgelstl[i-1]+1); + int nverts=edgelstl[lastlevel]+1; + nfaces+=2*segs*(2*capsegs-1); + + mesh.setNumVerts(nverts); + mesh.setNumFaces(nfaces); + mesh.setSmoothFlags(smooth != 0); + mesh.setNumTVerts(0); + mesh.setNumTVFaces(0); + mesh.setSmoothFlags(smooth != 0); + + // bottom vertex + float cylh = (cap1 - cap2).Length(); + float height = cylh + radius1 + radius2; + mesh.setVert(nv, Point3(0.0f,0.0f,height)); + mesh.setVert(nverts-1, Point3(0.0f,0.0f,0.0f)); + + // Top (1) and bottom (2) cap vertices + float ru,cang,sang; + int msegs=segs,deltaend=nverts-capv-1; + ang = startAng; + msegs--; + float rincr=PI/(2.0f*capsegs),aincr; + for (jx = 0; jx<=msegs; jx++) + { + cang=(float)cos(ang); + sang=(float)sin(ang); + for(ix=1; ix<=sideedge; ix++) { + aincr = (rincr*(float)ix); + ru=(float)sin(aincr); + + p.x = cang*radius1*ru; + p.y = sang*radius1*ru; + p.z = (jx==0) ? height-radius1*(1.0f-(float)cos(aincr)) : mesh.verts[edgelstr[ix]].z; + mesh.setVert(edgelstr[ix]+jx, p); + + p.x = cang*radius2*ru; + p.y = sang*radius2*ru; + p.z = (jx==0) ? radius2*(1.0f-(float)cos(aincr)) : mesh.verts[edgelstr[lastlevel-ix]].z ; + mesh.setVert(edgelstr[lastlevel-ix]+jx,p); + } + ang += delta; + } + + //// Middle vertices + //int sidevs,startv=edgelstr[sideedge],deltav; + //for(ix=1; ix<llsegs; ix++) { + // // Put center vertices all the way up + // float u = float(ix)/float(llsegs); + // float rad = (radius1*(1.0f-u) + radius2*u); + // p.z = cylh *((float)ix/float(llsegs)) + radius2; + // ang = startAng; + // for (sidevs=0;sidevs<VertexPerLevel;sidevs++) + // p.x = (float)cos(ang)*rad; + // p.y = (float)sin(ang)*rad; + // mesh.setVert(nv, p); + // nv++; + // ang += delta; + // } + //} + + //top layer done, now reflect sides down + int sidevs,deltav; + int startv=edgelstr[sideedge]; + int endv=edgelstr[totlevels-capsegs-1]; + if (llsegs>1) + { + float sincr = cylh/llsegs; + for (sidevs=0;sidevs<VertexPerLevel;sidevs++) + { + Point3 topp = mesh.verts[startv]; + Point3 botp = mesh.verts[endv]; + p.x = (topp.x + botp.x) / 2.0f; + p.y = (topp.y + botp.y) / 2.0f; + deltav=VertexPerLevel; + for (ic=1;ic<llsegs;ic++) + { + p.z = topp.z-sincr*ic; + mesh.setVert(startv+deltav, p); + deltav+=VertexPerLevel; + } + startv++; + } + } + int lasttvl=0,lasttvr=0; + int lvert=segs; + int t0,t1,b0,b1,tvt0=0,tvt1=0,tvb0=1,tvb1=2,fc=0,smoothgr=(smooth?4:0),vseg=segs+1; + int tvcount=0,lowerside=lastlevel-sideedge,onside=0; + + BOOL ok,wrap; + // Now make faces --- + for (int clevel=0;clevel<lastlevel-1;clevel++) + { + t1=(t0=edgelstr[clevel])+1; + b1=(b0=edgelstr[clevel+1])+1; + ok=1; wrap=FALSE; + if ((clevel>0)&&(onside==1)) { + tvt0++;tvt1++;tvb0++,tvb1++; + } + if (clevel==1) { + tvt0=1;tvt1=2; + } + if (clevel==sideedge) { + tvt1+=lvert;tvt0+=lvert;tvb0+=vseg;tvb1+=vseg;onside++; + } else if (clevel==lowerside) { + tvt1+=vseg;tvt0+=vseg;tvb0+=lvert;tvb1+=lvert;onside++; + } + while ((b0<edgelstl[clevel+1])||ok) + { + if (b1==edgelstr[clevel+2]) { + b1=edgelstr[clevel+1]; + t1=edgelstr[clevel]; + ok=FALSE; + wrap=(onside!=1); + } + if (smooth) smoothgr=4; + AddFace(&mesh.faces[fc++],t0,b0,b1,0,smoothgr); + if (clevel>0) { + AddFace(&mesh.faces[fc++],t0,b1,t1,1,smoothgr); + t0++;t1++; + } + b0++;b1++;tvb0++,tvb1++; + } + } + smoothgr=(smooth?4:0); + t1=(t0=edgelstr[lastlevel-1])+1;b0=edgelstr[lastlevel]; + int lastpt=lastlevel; + if (onside==1) { + tvt0++; + tvt1++; + tvb0++; + tvb1++; + } + if (sideedge==1) { + tvt1+=vseg; + tvt0+=vseg; + tvb0+=lvert; + tvb1+=lvert; + onside++; + } + while (t0<edgelstl[lastpt]) { + if (t1==edgelstr[lastlevel]) { + t1=edgelstr[lastlevel-1]; + tvt1-=segs; + } + AddFace(&mesh.faces[fc++],t0,b0,t1,1,smoothgr); + t0++;t1++; + } + for (i=0;i<nverts;i++) + mesh.verts[i].z -= radius2; + + if (edgelstr) delete []edgelstr; + if (edgelstl) delete []edgelstl; + assert(fc==mesh.numFaces); + // assert(nv==mesh.numVerts); + mesh.InvalidateTopologyCache(); +} + +#if 0 +void BuildCylinderMesh(Mesh &mesh, + int segs, int smooth, int llsegs, int capsegs, + float radius1, float radius2, float height, + int doPie, float pie1, float pie2) +{ + Point3 p; + int ix,na,nb,nc,nd,jx,kx, ic = 1; + int nf=0,nv=0, lsegs; + float delta,ang, u; + float totalPie, startAng = 0.0f; + + lsegs = llsegs-1 + 2*capsegs; + + // Make pie2 < pie1 and pie1-pie2 < TWOPI + while (pie1 < pie2) pie1 += TWOPI; + while (pie1 > pie2+TWOPI) pie1 -= TWOPI; + if (pie1==pie2) totalPie = TWOPI; + else totalPie = pie1-pie2; + + delta = (float)2.0*PI/(float)segs; + + if (height<0) delta = -delta; + + int nverts; + int nfaces; + nverts = 2+segs*(lsegs); + nfaces = 2*segs*(lsegs); + mesh.setNumVerts(nverts); + mesh.setNumFaces(nfaces); + mesh.setSmoothFlags(smooth != 0); + mesh.setNumTVerts(0); + mesh.setNumTVFaces(0); + + // bottom vertex + mesh.setVert(nv, Point3(0.0,0.0,0.0)); + nv++; + + // Bottom cap vertices + for(ix=0; ix<capsegs; ix++) { + + // Put center vertices all the way up + p.z = 0.0f; + u = float(ix+1)/float(capsegs); + ang = startAng; + for (jx = 0; jx<segs; jx++) { + p.x = (float)cos(ang)*radius1*u; + p.y = (float)sin(ang)*radius1*u; + mesh.setVert(nv, p); + nv++; + ang += delta; + } + } + + // Middle vertices + for(ix=1; ix<llsegs; ix++) { + + // Put center vertices all the way up + float u = float(ix)/float(llsegs); + float rad = (radius1*(1.0f-u) + radius2*u); + p.z = height*((float)ix/float(llsegs)); + ang = startAng; + for (jx = 0; jx<segs; jx++) { + p.x = (float)cos(ang)*rad; + p.y = (float)sin(ang)*rad; + mesh.setVert(nv, p); + nv++; + ang += delta; + } + } + + // Top cap vertices + for(ix=0; ix<capsegs; ix++) { + + // Put center vertices all the way up + p.z = height; + u = 1.0f-float(ix)/float(capsegs); + ang = startAng; + for (jx = 0; jx<segs; jx++) { + p.x = (float)cos(ang)*radius2*u; + p.y = (float)sin(ang)*radius2*u; + mesh.setVert(nv, p); + nv++; + ang += delta; + } + } + + /* top vertex */ + mesh.setVert(nv, (float)0.0, (float)0.0, height); + nv++; + + // Now make faces --- + + BitArray startSliceFaces; + BitArray endSliceFaces; + BitArray topCapFaces; + BitArray botCapFaces; + + // Make bottom cap + + for(ix=1; ix<=segs; ++ix) { + nc=(ix==segs)?1:ix+1; + mesh.faces[nf].setEdgeVisFlags(capsegs>1,1,capsegs>1); + mesh.faces[nf].setSmGroup(1); + mesh.faces[nf].setVerts(0,nc,ix); + mesh.faces[nf].setMatID(1); + nf++; + } + + int topCapStartFace = 0; + + /* Make midsection */ + for(ix=0; ix<lsegs-1; ++ix) { + jx=ix*segs+1; + for(kx=0; kx<segs; ++kx) { + DWORD grp = 0; + int mtlid; + BOOL inSlice = FALSE; + + if (kx==segs) { + mtlid = 4; + grp = (1<<2); + inSlice = TRUE; + } else if (ix < capsegs-1 || ix >= capsegs+llsegs-1) { + grp = 1; + mtlid = (ix<capsegs-1)?0:1; + } else { + mtlid = 2; + if (smooth) { + grp = (1<<3); + } + } + + na = jx+kx; + nb = na+segs; + nc = (kx==(segs-1))? jx+segs: nb+1; + nd = (kx==(segs-1))? jx : na+1; + + mesh.faces[nf].setEdgeVisFlags(0,!inSlice,1); + mesh.faces[nf].setSmGroup(grp); + mesh.faces[nf].setVerts(na,nc,nb); + mesh.faces[nf].setMatID(mtlid); + nf++; + + mesh.faces[nf].setEdgeVisFlags(!inSlice,1,0); + mesh.faces[nf].setSmGroup(grp); + mesh.faces[nf].setVerts(na,nd,nc); + mesh.faces[nf].setMatID(mtlid); + nf++; + } + } + + //Make Top cap + na = mesh.getNumVerts()-1; + jx = (lsegs-1)*segs+1; + + for(ix=0; ix<segs; ++ix) { + nb = jx+ix; + nc = (ix==segs-1)? jx: nb+1; + mesh.faces[nf].setEdgeVisFlags(capsegs>1,1,capsegs>1); + mesh.faces[nf].setSmGroup( 1); + mesh.faces[nf].setVerts(na,nb,nc); + mesh.faces[nf].setMatID(0); + nf++; + } + + assert(nf==mesh.numFaces); + assert(nv==mesh.numVerts); + mesh.InvalidateTopologyCache(); +} +#endif \ No newline at end of file diff --git a/NifProps/bhkRigidBodyInterface.cpp b/NifProps/bhkRigidBodyInterface.cpp new file mode 100644 index 0000000..24c62f1 --- /dev/null +++ b/NifProps/bhkRigidBodyInterface.cpp @@ -0,0 +1,556 @@ +/********************************************************************** +*< +FILE: bhkRigidBodyInterface.cpp + +DESCRIPTION: Collision RigidBody Object Implementation + +CREATED BY: tazpn (Theo) + +HISTORY: + V1.0 - Derived from 3ds max prim sphere example + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#pragma warning( disable:4800 ) +#include <max.h> +#include "MAX_Mem.h" +#include <map> +#include "NifProps.h" +#include "iparamm.h" +#include "Simpobj.h" +#include "notify.h" +#include "macroRec.h" +#include "bhkRigidBodyInterface.h" +#include "NifPlugins.h" +#include "NifGui.h" +#include "NifStrings.h" +//--- Parameter map/block descriptors ------------------------------- + + +FPInterfaceDesc thebhkRigidBodyInterface( + BHKRIGIDBODYINTERFACE_DESC, _T("bhkRigidBody"), -1/*IDS_OPS*/, 0, FP_CORE, + properties, + bhkRigidBodyInterface::get_material, bhkRigidBodyInterface::set_material, _T("Material"), 0, TYPE_ENUM, bhkRigidBodyInterface::enum_material, + bhkRigidBodyInterface::get_layer, bhkRigidBodyInterface::set_layer, _T("Layer"), 0, TYPE_ENUM, bhkRigidBodyInterface::enum_layer, + bhkRigidBodyInterface::get_mass, bhkRigidBodyInterface::set_mass, _T("Mass"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_friction, bhkRigidBodyInterface::set_friction, _T("Friction"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_restitution, bhkRigidBodyInterface::set_restitution, _T("Restitution"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_lineardamping, bhkRigidBodyInterface::set_lineardamping, _T("LinearDamping"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_angulardamping, bhkRigidBodyInterface::set_angulardamping, _T("AngularDamping"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_maxlinearvelocity, bhkRigidBodyInterface::set_maxlinearvelocity, _T("MaxLinearVelocity"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_maxangularvelocity, bhkRigidBodyInterface::set_maxangularvelocity, _T("MaxAngularVelocity"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_penetrationdepth, bhkRigidBodyInterface::get_penetrationdepth, _T("PenetrationDepth"), 0, TYPE_FLOAT, + bhkRigidBodyInterface::get_motionsystem, bhkRigidBodyInterface::set_motionsystem, _T("MotionSystem"), 0, TYPE_ENUM, bhkRigidBodyInterface::enum_motionsystem, + bhkRigidBodyInterface::get_qualitytype, bhkRigidBodyInterface::set_qualitytype, _T("QualityType"), 0, TYPE_ENUM, bhkRigidBodyInterface::enum_qualitytype, + enums, + bhkRigidBodyInterface::enum_material, 31, + "Stone", 0, + "Cloth", 1, + "Dirt", 2, + "Glass", 3, + "Grass", 4, + "Metal", 5, + "Organic", 6, + "Skin", 7, + "Water", 8, + "Wood", 9, + "Heavy Stone", 10, + "Heavy Metal", 11, + "Heavy Wood", 12, + "Chain", 13, + "Snow", 14, + "Stone Stairs", 15, + "Cloth Stairs", 16, + "Dirt Stairs", 17, + "Glass Stairs", 18, + "Grass Stairs", 19, + "Metal Stairs", 20, + "Organic Stairs", 21, + "Skin Stairs", 22, + "Water Stairs", 23, + "Wood Stairs", 24, + "Heavy Stone Stairs", 25, + "Heavy Metal Stairs", 26, + "Heavy Wood Stairs", 27, + "Chain Stairs", 28, + "Snow Stairs", 29, + "Elevator", 30, + bhkRigidBodyInterface::enum_layer, 57, + "Unidentified", 0, + "Static", 1, + "AnimStatic", 2, + "Transparent", 3, + "Clutter", 4, + "Weapon", 5, + "Projectile", 6, + "Spell", 7, + "Biped", 8, + "Tree", 9, + "Prop", 10, + "Water", 11, + "Trigger", 12, + "Terrain", 13, + "Trap", 14, + "NonCollidable", 15, + "CloudTrap", 16, + "Ground", 17, + "Portal", 18, + "Stairs", 19, + "CharController", 20, + "AvoidBox", 21, + "Unknown(22)", 22, + "Unknown(23)", 23, + "CameraPick", 24, + "ItemPick", 25, + "LineOfSight", 26, + "PathPick", 27, + "CustomPick1", 28, + "CustomPick2", 29, + "SpellExplosion", 30, + "DroppingPick", 31, + "Other", 32, + "Head", 33, + "Body", 34, + "Spine1", 35, + "Spine2", 36, + "LUpperArm", 37, + "LForeArm", 38, + "LHand", 39, + "LThigh", 40, + "LCalf", 41, + "LFoot", 42, + "RUpperArm", 43, + "RForeArm", 44, + "RHand", 45, + "RThigh", 46, + "RCalf", 47, + "RFoot", 48, + "Tail", 49, + "SideWeapon", 50, + "Shield", 51, + "Quiver", 52, + "BackWeapon", 53, + "BackWeapon", 54, + "PonyTail", 55, + "Wing", 56, + bhkRigidBodyInterface::enum_motionsystem, 10, + "Keyframed(0)", 0, + "Box(1)", 1, + "Sphere(2)", 2, + "Sphere(2)", 3, + "Box(4)", 4, + "Box(5)", 5, + "Keyframed(6)", 6, + "Keyframed(7)", 7, + "Box(8)", 8, + "Keyframed(9)", 9, + bhkRigidBodyInterface::enum_qualitytype, 9, + "Moving", 0, + "Fixed", 1, + "Keyframed", 2, + "Moving(3)", 3, + "Moving(4)", 4, + "Critical", 5, + "Bullet", 6, + "User", 7, + "Null", 8, + end); + +FPInterfaceDesc *bhkRigidBodyInterface::GetDesc() { + return &thebhkRigidBodyInterface; +} + +FPInterfaceDesc* GetbhkRigidBodyInterfaceDesc() +{ + return &thebhkRigidBodyInterface; +} + +// +// +// Parameters + +static ParamUIDesc descRigidBodyParam[] = { + + // Mass + ParamUIDesc( + PB_RB_MASS, + EDITTYPE_UNIVERSE, + IDC_ED_MASS,IDC_SP_MASS, + 0, 1000, + SPIN_AUTOSCALE), + + // Friction + ParamUIDesc( + PB_RB_FRICTION, + EDITTYPE_UNIVERSE, + IDC_ED_FRICTION,IDC_SP_FRICTION, + 0, 10, + SPIN_AUTOSCALE), + + // Restitution + ParamUIDesc( + PB_RB_RESTITUTION, + EDITTYPE_UNIVERSE, + IDC_ED_RESTITUTION,IDC_SP_RESTITUTION, + 0, 10, + SPIN_AUTOSCALE), + + // Linear Damping + ParamUIDesc( + PB_RB_LINEAR_DAMPING, + EDITTYPE_UNIVERSE, + IDC_ED_LINEAR_DAMPING,IDC_SP_LINEAR_DAMPING, + 0, 10, + SPIN_AUTOSCALE), + + // Angular Damping + ParamUIDesc( + PB_RB_ANGULAR_DAMPING, + EDITTYPE_UNIVERSE, + IDC_ED_ANGULAR_DAMPING,IDC_SP_ANGULAR_DAMPING, + 0, 10, + SPIN_AUTOSCALE), + + // Max Linear Velocity + ParamUIDesc( + PB_RB_MAX_LINEAR_VELOCITY, + EDITTYPE_UNIVERSE, + IDC_ED_MAX_LINEAR_VELOCITY,IDC_SP_MAX_LINEAR_VELOCITY, + 0, 10, + SPIN_AUTOSCALE), + + // Max Angular Velocity + ParamUIDesc( + PB_RB_MAX_ANGULAR_VELOCITY, + EDITTYPE_UNIVERSE, + IDC_ED_MAX_ANGULAR_VELOCITY,IDC_SP_MAX_ANGULAR_VELOCITY, + 0, 10, + SPIN_AUTOSCALE), + + // Penetration Depth + ParamUIDesc( + PB_RB_PENETRATION_DEPTH, + EDITTYPE_UNIVERSE, + IDC_ED_PENETRATION_DEPTH,IDC_SP_PENETRATION_DEPTH, + 0, 10, + SPIN_AUTOSCALE), +}; +const int descRigidBodyParamLength = _countof(descRigidBodyParam); + +static ParamBlockDescID gRigidBlockParamDesc[] = { + { TYPE_INT, NULL, FALSE, PB_RB_MATERIAL }, + { TYPE_INT, NULL, FALSE, PB_RB_LAYER }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_MASS }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_FRICTION }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_RESTITUTION }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_LINEAR_DAMPING }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_ANGULAR_DAMPING }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_MAX_LINEAR_VELOCITY }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_MAX_ANGULAR_VELOCITY }, + { TYPE_FLOAT, NULL, FALSE, PB_RB_PENETRATION_DEPTH }, + { TYPE_INT, NULL, FALSE, PB_RB_MOTION_SYSTEM }, + { TYPE_INT, NULL, FALSE, PB_RB_QUALITY_TYPE }, +}; +const int descRigidBodyDescIDLength = _countof(gRigidBlockParamDesc); + +class RigidBodyParamDlgProc : public ParamMapUserDlgProc { +public: + bhkRigidBodyInterface *so; + HWND thishWnd; + NpComboBox mCbLayer; + NpComboBox mCbMaterial; + NpComboBox mCbMotionSystem; + NpComboBox mCbQualityType; + + RigidBodyParamDlgProc(bhkRigidBodyInterface *s) {so=s;thishWnd=NULL;} + BOOL DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); + void Update(TimeValue t); + void DeleteThis() {delete this;} + + //--- ParamDlgProc -------------------------------- + void TurnSpinner(HWND hWnd,int SpinNum,BOOL ison) + { + ISpinnerControl *spin2 = GetISpinner(GetDlgItem(hWnd,SpinNum)); + if (ison) spin2->Enable();else spin2->Disable(); + ReleaseISpinner(spin2); + }; + +}; + +void RigidBodyParamDlgProc::Update(TimeValue t) +{ + if (!thishWnd) + return; + + + mCbMaterial.select(max(0, min(so->GetMaterial(t), mCbMaterial.count()-1))); + mCbLayer.select(max(0, min(so->GetLayer(t), mCbLayer.count()-1))); + mCbMotionSystem.select(max(0, min(so->GetMotionSystem(t), mCbMotionSystem.count()-1))); + mCbQualityType.select(max(0, min(so->GetQualityType(t), mCbQualityType.count()-1))); + return; +} + +BOOL RigidBodyParamDlgProc::DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + thishWnd=hWnd; + switch (msg) + { + case WM_INITDIALOG: + { + mCbMaterial.init(GetDlgItem(hWnd, IDC_CB_MATERIAL)); + for (const char **str = NpHvkMaterialNames; *str; ++str) + mCbMaterial.add(*str); + + mCbLayer.init(GetDlgItem(hWnd, IDC_CB_LAYER)); + for (const char **str = NpHvkLayerNames; *str; ++str) + mCbLayer.add(*str); + + mCbMotionSystem.init(GetDlgItem(hWnd, IDC_CB_MOTION_SYSTEM)); + for (const char **str = NpHvkMotionSystems; *str; ++str) + mCbMotionSystem.add(*str); + + mCbQualityType.init(GetDlgItem(hWnd, IDC_CB_QUALITY_TYPE)); + for (const char **str = NpHvkQualityTypes; *str; ++str) + mCbQualityType.add(*str); + + Update(t); + break; + } + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CB_MATERIAL: + if (HIWORD(wParam)==CBN_SELCHANGE) { + so->SetMaterial( mCbMaterial.selection(), t ); + } + break; + + case IDC_CB_LAYER: + if (HIWORD(wParam)==CBN_SELCHANGE) { + so->SetLayer( mCbLayer.selection(), t ); + } + break; + + case IDC_CB_MOTION_SYSTEM: + if (HIWORD(wParam)==CBN_SELCHANGE) { + so->SetMotionSystem( mCbMotionSystem.selection(), t ); + } + break; + + case IDC_CB_QUALITY_TYPE: + if (HIWORD(wParam)==CBN_SELCHANGE) { + so->SetQualityType( mCbQualityType.selection(), t ); + } + break; + } + break; + } + return FALSE; +} + +//--- RigidBody methods ------------------------------- + +IParamMap *bhkRigidBodyIfcHelper::rbpmapParam = NULL; +IObjParam *bhkRigidBodyIfcHelper::rbip = NULL; + +bhkRigidBodyIfcHelper::bhkRigidBodyIfcHelper() +{ + rbpblock = CreateParameterBlock(gRigidBlockParamDesc, descRigidBodyDescIDLength, 1); + rbpblock->SetValue(PB_RB_MATERIAL,0,NP_DEFAULT_HVK_MATERIAL); + rbpblock->SetValue(PB_RB_LAYER,0,NP_DEFAULT_HVK_LAYER); + rbpblock->SetValue(PB_RB_MASS,0,NP_DEFAULT_HVK_MASS); + rbpblock->SetValue(PB_RB_FRICTION,0,NP_DEFAULT_HVK_FRICTION); + rbpblock->SetValue(PB_RB_RESTITUTION,0,NP_DEFAULT_HVK_RESTITUTION); + rbpblock->SetValue(PB_RB_LINEAR_DAMPING,0,NP_DEFAULT_HVK_LINEAR_DAMPING); + rbpblock->SetValue(PB_RB_ANGULAR_DAMPING,0,NP_DEFAULT_HVK_ANGULAR_DAMPING); + rbpblock->SetValue(PB_RB_MAX_LINEAR_VELOCITY,0,NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY); + rbpblock->SetValue(PB_RB_MAX_ANGULAR_VELOCITY,0,NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY); + rbpblock->SetValue(PB_RB_PENETRATION_DEPTH,0,NP_DEFAULT_HVK_PENETRATION_DEPTH); + rbpblock->SetValue(PB_RB_MOTION_SYSTEM,0,NP_DEFAULT_HVK_MOTION_SYSTEM); + rbpblock->SetValue(PB_RB_QUALITY_TYPE,0,NP_DEFAULT_HVK_QUALITY_TYPE); + +} + +bhkRigidBodyIfcHelper::~bhkRigidBodyIfcHelper() +{ + if (rbpmapParam) { + rbpmapParam->SetUserDlgProc(NULL); + DestroyCPParamMap(rbpmapParam); + rbpmapParam = NULL; + } +} + +IParamBlock* bhkRigidBodyIfcHelper::GetRBBlock() +{ + return rbpblock; +} + +void bhkRigidBodyIfcHelper::BeginEditRBParams(IObjParam *ip,ULONG flags,Animatable *prev) +{ + // Gotta make a new one. + if (NULL == rbpmapParam) + { + rbpmapParam = CreateCPParamMap( + descRigidBodyParam,descRigidBodyParamLength, + rbpblock, + ip, + hInstance, + MAKEINTRESOURCE(IDD_RigidBody), + GetString(IDS_RB_RIGIDBODY_PARAM), + 0); + } + this->rbip = ip; + + if(rbpmapParam) { + // A callback for the type in. + rbpmapParam->SetUserDlgProc(new RigidBodyParamDlgProc(this)); + } +} + +void bhkRigidBodyIfcHelper::EndEditRBParams( IObjParam *ip, ULONG flags,Animatable *next ) +{ + if (rbpmapParam && flags&END_EDIT_REMOVEUI ) { + rbpmapParam->SetUserDlgProc(NULL); + DestroyCPParamMap(rbpmapParam); + rbpmapParam = NULL; + } +} + + +void bhkRigidBodyIfcHelper::SetMaterial(int value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_MATERIAL,time,value); +} + +int bhkRigidBodyIfcHelper::GetMaterial(TimeValue time, Interval& valid) const +{ + int value = NP_DEFAULT_HVK_MATERIAL; + rbpblock->GetValue(PB_RB_MATERIAL,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetLayer(int value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_LAYER,time,value); +} +int bhkRigidBodyIfcHelper::GetLayer(TimeValue time, Interval& valid) const +{ + int value = NP_DEFAULT_HVK_LAYER; + rbpblock->GetValue(PB_RB_LAYER,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetMass(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_MASS,time,value); +} +float bhkRigidBodyIfcHelper::GetMass(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_MASS; + rbpblock->GetValue(PB_RB_MASS,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetFriction(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_FRICTION,time,value); +} + +float bhkRigidBodyIfcHelper::GetFriction(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_FRICTION; + rbpblock->GetValue(PB_RB_FRICTION,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetRestitution (float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_RESTITUTION,time,value); +} + +float bhkRigidBodyIfcHelper::GetRestitution (TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_RESTITUTION; + rbpblock->GetValue(PB_RB_RESTITUTION,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetLinearDamping(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_LINEAR_DAMPING,time,value); +} + +float bhkRigidBodyIfcHelper::GetLinearDamping(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_LINEAR_DAMPING; + rbpblock->GetValue(PB_RB_LINEAR_DAMPING,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetAngularDamping(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_ANGULAR_DAMPING,time,value); +} + +float bhkRigidBodyIfcHelper::GetAngularDamping(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_ANGULAR_DAMPING; + rbpblock->GetValue(PB_RB_ANGULAR_DAMPING,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetMaxLinearVelocity(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_MAX_LINEAR_VELOCITY,time,value); +} + +float bhkRigidBodyIfcHelper::GetMaxLinearVelocity(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_MAX_LINEAR_VELOCITY; + rbpblock->GetValue(PB_RB_MAX_LINEAR_VELOCITY,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetMaxAngularVelocity(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_MAX_ANGULAR_VELOCITY,time,value); +} +float bhkRigidBodyIfcHelper::GetMaxAngularVelocity(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_MAX_ANGULAR_VELOCITY; + rbpblock->GetValue(PB_RB_MAX_ANGULAR_VELOCITY,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetPenetrationDepth(float value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_PENETRATION_DEPTH,time,value); +} +float bhkRigidBodyIfcHelper::GetPenetrationDepth(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_PENETRATION_DEPTH; + rbpblock->GetValue(PB_RB_PENETRATION_DEPTH,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetMotionSystem(int value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_MOTION_SYSTEM,time,value); +} +int bhkRigidBodyIfcHelper::GetMotionSystem(TimeValue time, Interval& valid) const +{ + int value = NP_DEFAULT_HVK_MOTION_SYSTEM; + rbpblock->GetValue(PB_RB_MOTION_SYSTEM,time,value,valid); + return value; +} + +void bhkRigidBodyIfcHelper::SetQualityType(int value, TimeValue time) +{ + rbpblock->SetValue(PB_RB_QUALITY_TYPE,time,value); +} +int bhkRigidBodyIfcHelper::GetQualityType(TimeValue time, Interval& valid) const +{ + float value = NP_DEFAULT_HVK_QUALITY_TYPE; + rbpblock->GetValue(PB_RB_QUALITY_TYPE,time,value,valid); + return value; +} diff --git a/NifProps/bhkRigidBodyInterface.h b/NifProps/bhkRigidBodyInterface.h new file mode 100644 index 0000000..28cab3e --- /dev/null +++ b/NifProps/bhkRigidBodyInterface.h @@ -0,0 +1,178 @@ +/********************************************************************** +*< +FILE: bhkRigidBodyInterface.hpp + +DESCRIPTION: Collision RigidBody Object Declration + +CREATED BY: tazpn (Theo) + +HISTORY: + V1.0 - Derived from 3ds max prim RigidBody example + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#ifndef __BHKRIGIDBODYINTERFACE__H +#define __BHKRIGIDBODYINTERFACE__H + +#include <ifnpub.h> + +#ifndef _countof +#define _countof(x) (sizeof(x)/sizeof((x)[0])) +#endif + +//! The unique instance of the rigid body interface +extern CoreExport FPInterfaceDesc gbhkRigidBodyDesc; + +#define BHKRIGIDBODYINTERFACE_DESC Interface_ID(0x056aad53, 0x52c54024) +extern FPInterfaceDesc* GetbhkRigidBodyInterfaceDesc(); + +class bhkRigidBodyInterface : public FPMixinInterface +{ +public: + virtual void SetMaterial(int value, TimeValue time) = 0; + virtual int GetMaterial(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetLayer(int value, TimeValue time) = 0; + virtual int GetLayer(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetMass(float value, TimeValue time) = 0; + virtual float GetMass(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetFriction(float value, TimeValue time) = 0; + virtual float GetFriction(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetRestitution (float value, TimeValue time) = 0; + virtual float GetRestitution (TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetLinearDamping(float value, TimeValue time) = 0; + virtual float GetLinearDamping(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetAngularDamping(float value, TimeValue time) = 0; + virtual float GetAngularDamping(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetMaxLinearVelocity(float value, TimeValue time) = 0; + virtual float GetMaxLinearVelocity(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetMaxAngularVelocity(float value, TimeValue time) = 0; + virtual float GetMaxAngularVelocity(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetPenetrationDepth(float value, TimeValue time) = 0; + virtual float GetPenetrationDepth(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetMotionSystem(int value, TimeValue time) = 0; + virtual int GetMotionSystem(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + virtual void SetQualityType(int value, TimeValue time) = 0; + virtual int GetQualityType(TimeValue time, Interval& valid = FOREVER) const = 0 ; + + //Function Publishing System + enum { + get_material, set_material, enum_material, + get_layer, set_layer, enum_layer, + get_mass, set_mass, + get_friction, set_friction, + get_restitution, set_restitution, + get_lineardamping, set_lineardamping, + get_angulardamping, set_angulardamping, + get_maxlinearvelocity, set_maxlinearvelocity, + get_maxangularvelocity, set_maxangularvelocity, + get_penetrationdepth, set_penetrationdepth, + get_motionsystem, set_motionsystem, enum_motionsystem, + get_qualitytype, set_qualitytype, enum_qualitytype, + }; + + //Function Map For Mixin Interface + //************************************************* + BEGIN_FUNCTION_MAP + PROP_TFNS(get_material, GetMaterial, set_material, SetMaterial, TYPE_INT); + PROP_TFNS(get_layer, GetLayer, set_layer, SetLayer, TYPE_INT); + PROP_TFNS(get_mass, GetMass, set_mass, SetMass, TYPE_FLOAT); + PROP_TFNS(get_friction, GetFriction, set_friction, SetFriction, TYPE_FLOAT); + PROP_TFNS(get_restitution, GetRestitution, set_restitution, SetRestitution, TYPE_FLOAT); + PROP_TFNS(get_lineardamping, GetLinearDamping, set_lineardamping, SetLinearDamping, TYPE_FLOAT); + PROP_TFNS(get_angulardamping, GetAngularDamping, set_angulardamping, SetAngularDamping, TYPE_FLOAT); + PROP_TFNS(get_maxlinearvelocity, GetMaxLinearVelocity, set_maxlinearvelocity, SetMaxLinearVelocity, TYPE_FLOAT); + PROP_TFNS(get_maxangularvelocity, GetMaxAngularVelocity, set_maxangularvelocity, SetMaxAngularVelocity, TYPE_FLOAT); + PROP_TFNS(get_penetrationdepth, GetPenetrationDepth, set_penetrationdepth, SetPenetrationDepth, TYPE_FLOAT); + PROP_TFNS(get_motionsystem, GetMotionSystem, set_motionsystem, SetMotionSystem, TYPE_INT); + PROP_TFNS(get_qualitytype, GetQualityType, set_qualitytype, SetQualityType, TYPE_INT); + END_FUNCTION_MAP + + FPInterfaceDesc* GetDesc(); // <-- must implement + //************************************************** +}; + +//--- Parameter map/block descriptors ------------------------------- + +// Parameter block indices +enum RigidBodyParamIndicies +{ + PB_RB_MATERIAL, + PB_RB_LAYER, + PB_RB_MASS, + PB_RB_FRICTION, + PB_RB_RESTITUTION, + PB_RB_LINEAR_DAMPING, + PB_RB_ANGULAR_DAMPING, + PB_RB_MAX_LINEAR_VELOCITY, + PB_RB_MAX_ANGULAR_VELOCITY, + PB_RB_PENETRATION_DEPTH, + PB_RB_MOTION_SYSTEM, + PB_RB_QUALITY_TYPE, +}; + +class bhkRigidBodyIfcHelper : public bhkRigidBodyInterface +{ +public: + bhkRigidBodyIfcHelper(); + ~bhkRigidBodyIfcHelper(); + + IParamBlock* GetRBBlock(); + void BeginEditRBParams(IObjParam *ip,ULONG flags,Animatable *prev); + void EndEditRBParams(IObjParam *ip,ULONG flags,Animatable *next); + + virtual void SetMaterial(int value, TimeValue time); + virtual int GetMaterial(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetLayer(int value, TimeValue time); + virtual int GetLayer(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetMass(float value, TimeValue time); + virtual float GetMass(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetFriction(float value, TimeValue time); + virtual float GetFriction(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetRestitution (float value, TimeValue time); + virtual float GetRestitution (TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetLinearDamping(float value, TimeValue time); + virtual float GetLinearDamping(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetAngularDamping(float value, TimeValue time); + virtual float GetAngularDamping(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetMaxLinearVelocity(float value, TimeValue time); + virtual float GetMaxLinearVelocity(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetMaxAngularVelocity(float value, TimeValue time); + virtual float GetMaxAngularVelocity(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetPenetrationDepth(float value, TimeValue time); + virtual float GetPenetrationDepth(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetMotionSystem(int value, TimeValue time); + virtual int GetMotionSystem(TimeValue time, Interval& valid = FOREVER) const ; + + virtual void SetQualityType(int value, TimeValue time); + virtual int GetQualityType(TimeValue time, Interval& valid = FOREVER) const ; + + virtual FPInterfaceDesc* GetDesc() { return GetbhkRigidBodyInterfaceDesc(); } + +protected: + IParamBlock* rbpblock; + static IParamMap *rbpmapParam; + static IObjParam *rbip; +}; + +#endif \ No newline at end of file diff --git a/NifProps/bhkSphereObj.cpp b/NifProps/bhkSphereObj.cpp new file mode 100644 index 0000000..8b8984c --- /dev/null +++ b/NifProps/bhkSphereObj.cpp @@ -0,0 +1,679 @@ +/********************************************************************** +*< +FILE: bhkSphereObj.cpp + +DESCRIPTION: Collision Sphere Object Implementation + +CREATED BY: tazpn (Theo) + +HISTORY: + V1.0 - Derived from 3ds max prim sphere example + +*> Copyright (c) 2006, All Rights Reserved. +**********************************************************************/ +#pragma warning( disable:4800 ) +#include <max.h> +#include "MAX_Mem.h" +#include <map> +#include "NifProps.h" +#include "iparamm.h" +#include "Simpobj.h" +#include "surf_api.h" +#include "notify.h" +#include "macroRec.h" +#include "bhkRigidBodyInterface.h" +#ifndef _countof +#define _countof(x) (sizeof(x)/sizeof((x)[0])) +#endif + +const Class_ID bhkSphereObject_CLASS_ID = Class_ID(0x8d532427, 0x8b4c64c7); + +class bhkSphereObject : public SimpleObject, public IParamArray, public bhkRigidBodyIfcHelper +{ +public: + // Class vars + static IParamMap *pmapParam; + static int dlgSegments; + static int dlgSmooth; + static float crtRadius; + static IObjParam *ip; + + bhkSphereObject(BOOL loading); + ~bhkSphereObject(); + + // From Object + int CanConvertToType(Class_ID obtype); + Object* ConvertToType(TimeValue t, Class_ID obtype); + void GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist); + + CreateMouseCallBack* GetCreateMouseCallBack(); + void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev); + void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next); + RefTargetHandle Clone(RemapDir& remap = NoRemap()); + TCHAR *GetObjectName() { return GetString(IDS_RB_SPHERE); } + + // From GeomObject + int IntersectRay(TimeValue t, Ray& ray, float& at, Point3& norm); + + // Animatable methods + void DeleteThis() {delete this;} + Class_ID ClassID() { return bhkSphereObject_CLASS_ID; } + SClass_ID SuperClassID() { return HELPER_CLASS_ID; } + + // From ReferenceTarget + IOResult Load(ILoad *iload); + IOResult Save(ISave *isave); + + // From ref + int NumRefs() {return 2;} + RefTargetHandle GetReference(int i); + void SetReference(int i, RefTargetHandle rtarg); + + // From SimpleObject + void BuildMesh(TimeValue t); + BOOL OKtoDisplay(TimeValue t); + void InvalidateUI(); + ParamDimension *GetParameterDim(int pbIndex); + TSTR GetParameterName(int pbIndex); + + void SetParams(float rad, int segs, BOOL smooth=TRUE); + void UpdateUI(); + + BaseInterface* GetInterface(Interface_ID id); + +}; + + +// Misc stuff +#define MAX_SEGMENTS 200 +#define MIN_SEGMENTS 4 + +#define MIN_RADIUS float(0) +#define MAX_RADIUS float(1.0E30) + +#define MIN_SMOOTH 0 +#define MAX_SMOOTH 1 + +#define DEF_SEGMENTS 32 // 16 +#define DEF_RADIUS float(0.0) + +#define SMOOTH_ON 1 +#define SMOOTH_OFF 0 + +#define MIN_SLICE float(-1.0E30) +#define MAX_SLICE float( 1.0E30) + + +//--- ClassDescriptor and class vars --------------------------------- + +static BOOL sInterfaceAdded = FALSE; + +// The class descriptor for sphere +class bhkSphereClassDesc : public ClassDesc2 +{ +public: + int IsPublic() { return 1; } + void * Create(BOOL loading = FALSE) + { + AddInterface (GetbhkRigidBodyInterfaceDesc()); + return new bhkSphereObject(loading); + } + const TCHAR * ClassName() { return GetString(IDS_RB_SPHERE_CLASS); } + SClass_ID SuperClassID() { return HELPER_CLASS_ID; } + Class_ID ClassID() { return bhkSphereObject_CLASS_ID; } + const TCHAR* Category() { return "NifTools"; } + void ResetClassParams(BOOL fileReset); +}; + +static bhkSphereClassDesc sphereDesc; +extern ClassDesc2* GetbhkSphereDesc() { return &sphereDesc; } + +// in prim.cpp - The dll instance handle +extern HINSTANCE hInstance; + +int bhkSphereObject::dlgSegments = DEF_SEGMENTS; +int bhkSphereObject::dlgSmooth = SMOOTH_ON; +IParamMap *bhkSphereObject::pmapParam = NULL; +IObjParam *bhkSphereObject::ip = NULL; +float bhkSphereObject::crtRadius = 0.0f; + +void bhkSphereClassDesc::ResetClassParams(BOOL fileReset) +{ + bhkSphereObject::dlgSegments = DEF_SEGMENTS; + bhkSphereObject::dlgSmooth = SMOOTH_ON; + bhkSphereObject::crtRadius = 0.0f; +} + + +//--- Parameter map/block descriptors ------------------------------- + +// Parameter block indices +enum SphereParamIndicies +{ + PB_RADIUS = 0, + PB_SEGS = 1, + PB_SMOOTH = 2, +}; + + +// +// +// Parameters + +static ParamUIDesc descParam[] = { + // Radius + ParamUIDesc( + PB_RADIUS, + EDITTYPE_UNIVERSE, + IDC_RADIUS,IDC_RADSPINNER, + MIN_RADIUS,MAX_RADIUS, + SPIN_AUTOSCALE), + + // Segments + ParamUIDesc( + PB_SEGS, + EDITTYPE_INT, + IDC_SEGMENTS,IDC_SEGSPINNER, + (float)MIN_SEGMENTS,(float)MAX_SEGMENTS, + 0.1f), + + // Smooth + ParamUIDesc(PB_SMOOTH,TYPE_SINGLECHEKBOX,IDC_OBSMOOTH), +}; +const int PARAMDESC_LENGTH = _countof(descParam); + +static ParamBlockDescID descVer0[] = { + { TYPE_FLOAT, NULL, TRUE, 0 }, + { TYPE_INT, NULL, TRUE, 1 }, + { TYPE_INT, NULL, TRUE, 2 } +}; +const int PBLOCK_LENGTH = _countof(descVer0); +static ParamBlockDescID *curDescVer = descVer0; + +// Array of old versions +//static ParamVersionDesc versions[] = { +// ParamVersionDesc(descVer0,_countof(descVer0),0), +//}; +//const int NUM_OLDVERSIONS = _countof(versions); +static ParamVersionDesc* versions = NULL; +const int NUM_OLDVERSIONS = 0; + +// Current version +const int CURRENT_VERSION = NUM_OLDVERSIONS + 1; +static ParamVersionDesc curVersion(descVer0,_countof(descVer0),CURRENT_VERSION); + +class SphereParamDlgProc : public ParamMapUserDlgProc { +public: + bhkSphereObject *so; + HWND thishWnd; + + SphereParamDlgProc(bhkSphereObject *s) {so=s;thishWnd=NULL;} + BOOL DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); + void Update(TimeValue t); + void DeleteThis() {delete this;} + + //--- ParamDlgProc -------------------------------- + void TurnSpinner(HWND hWnd,int SpinNum,BOOL ison) + { + ISpinnerControl *spin2 = GetISpinner(GetDlgItem(hWnd,SpinNum)); + if (ison) spin2->Enable();else spin2->Disable(); + ReleaseISpinner(spin2); + }; + +}; + +void SphereParamDlgProc::Update(TimeValue t) +{ + if (!thishWnd) + return; + return; +} + +BOOL SphereParamDlgProc::DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) +{ + thishWnd=hWnd; + switch (msg) + { + case WM_INITDIALOG: + { + Update(t); + break; + } + case WM_COMMAND: + //switch (LOWORD(wParam)) + //{ + //} + break; + } + return FALSE; +} + +//--- Sphere methods ------------------------------- + + +bhkSphereObject::bhkSphereObject(BOOL loading) +{ + SetAFlag(A_PLUGIN1); + MakeRefByID(FOREVER, 0, CreateParameterBlock(curDescVer, PBLOCK_LENGTH, CURRENT_VERSION)); + assert(pblock); + MakeRefByID(FOREVER, 1, GetRBBlock()); + + pblock->SetValue(PB_RADIUS,0,crtRadius); + pblock->SetValue(PB_SMOOTH,0,dlgSmooth); + pblock->SetValue(PB_SEGS,0,dlgSegments); +} + +bhkSphereObject::~bhkSphereObject() { +} + +#define NEWMAP_CHUNKID 0x0100 + +IOResult bhkSphereObject::Load(ILoad *iload) +{ + ClearAFlag(A_PLUGIN1); + + IOResult res; + while (IO_OK==(res=iload->OpenChunk())) + { + switch (iload->CurChunkID()) + { + case NEWMAP_CHUNKID: + SetAFlag(A_PLUGIN1); + break; + } + iload->CloseChunk(); + if (res!=IO_OK) return res; + } + return IO_OK; +} + +IOResult bhkSphereObject::Save(ISave *isave) +{ + if (TestAFlag(A_PLUGIN1)) { + isave->BeginChunk(NEWMAP_CHUNKID); + isave->EndChunk(); + } + return IO_OK; +} + +RefTargetHandle bhkSphereObject::GetReference(int i) +{ + if (i == 1) + return GetRBBlock(); + return pblock; +} + +void bhkSphereObject::SetReference(int i, RefTargetHandle rtarg) +{ + if (i == 1) + return; + pblock=(IParamBlock*)rtarg; +} + +BaseInterface* bhkSphereObject::GetInterface(Interface_ID id) +{ + if (id == BHKRIGIDBODYINTERFACE_DESC) + return this; + return SimpleObject::GetInterface(id); +} + + + +void bhkSphereObject::BeginEditParams(IObjParam *ip,ULONG flags,Animatable *prev) +{ + SimpleObject::BeginEditParams(ip,flags,prev); + + // Gotta make a new one. + if (NULL == pmapParam) + { + pmapParam = CreateCPParamMap( + descParam,PARAMDESC_LENGTH, + pblock, + ip, + hInstance, + MAKEINTRESOURCE(IDD_SPHEREPARAM2), + GetString(IDS_RB_PARAMETERS), + 0); + } + this->ip = ip; + + if(pmapParam) { + // A callback for the type in. + pmapParam->SetUserDlgProc(new SphereParamDlgProc(this)); + } + BeginEditRBParams(ip, flags, prev); +} + +void bhkSphereObject::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next ) +{ + SimpleObject::EndEditParams(ip,flags,next); + this->ip = NULL; + + if (flags&END_EDIT_REMOVEUI ) { + DestroyCPParamMap(pmapParam); + pmapParam = NULL; + } + EndEditRBParams(ip, flags, next); + + // Save these values in class variables so the next object created will inherit them. + pblock->GetValue(PB_SEGS,ip->GetTime(),dlgSegments,FOREVER); + pblock->GetValue(PB_SMOOTH,ip->GetTime(),dlgSmooth,FOREVER); +} + +void bhkSphereObject::SetParams(float rad, int segs, BOOL smooth) +{ + pblock->SetValue(PB_RADIUS,0, rad); + pblock->SetValue(PB_SEGS,0, segs); + pblock->SetValue(PB_SMOOTH,0, smooth); +} + +void bhkSphereObject::BuildMesh(TimeValue t) +{ + Point3 p; + int ix,na,nb,nc,nd,jx,kx; + int nf=0,nv=0; + float delta, delta2; + float a,alt,secrad,secang,b,c; + int segs, smooth; + float radius; + float hemi = 0.0f; + BOOL genUVs = TRUE; + float startAng = 0.0f; + if (TestAFlag(A_PLUGIN1)) startAng = HALFPI; + + // Start the validity interval at forever and whittle it down. + ivalid = FOREVER; + pblock->GetValue(PB_RADIUS, t, radius, ivalid); + pblock->GetValue(PB_SEGS, t, segs, ivalid); + pblock->GetValue(PB_SMOOTH, t, smooth, ivalid); + LimitValue(segs, MIN_SEGMENTS, MAX_SEGMENTS); + LimitValue(smooth, MIN_SMOOTH, MAX_SMOOTH); + LimitValue(radius, MIN_RADIUS, MAX_RADIUS); + + float totalPie(0.0f); + if (hemi>=1.0f) hemi = 0.9999f; + hemi = (1.0f-hemi) * PI; + float basedelta=2.0f*PI/(float)segs; + delta2 = basedelta; + delta = basedelta; + + int rows = int(hemi/delta) + 1; + int realsegs=segs; + int nverts = rows * realsegs + 2; + int nfaces = rows * realsegs * 2; + mesh.setNumVerts(nverts); + mesh.setNumFaces(nfaces); + mesh.setSmoothFlags(smooth != 0); + int lastvert=nverts-1; + + // Top vertex + mesh.setVert(nv, 0.0f, 0.0f, radius); + nv++; + + // Middle vertices + alt=delta; + for(ix=1; ix<=rows; ix++) { + a = (float)cos(alt)*radius; + secrad = (float)sin(alt)*radius; + secang = startAng; //0.0f + for(jx=0; jx<segs; ++jx) { + b = (float)cos(secang)*secrad; + c = (float)sin(secang)*secrad; + mesh.setVert(nv++,b,c,a); + secang+=delta2; + } + alt+=delta; + } + + /* Bottom vertex */ + mesh.setVert(nv++, 0.0f, 0.0f,-radius); + + // Now make faces + + BitArray startSliceFaces; + BitArray endSliceFaces; + + // Make top conic cap + for(ix=1; ix<=segs; ++ix) { + nc=(ix==segs)?1:ix+1; + mesh.faces[nf].setEdgeVisFlags(1,1,1); + mesh.faces[nf].setSmGroup(smooth?1:0); + mesh.faces[nf].setMatID(1); + mesh.faces[nf].setVerts(0, ix, nc); + nf++; + } + + /* Make midsection */ + int lastrow=rows-1,lastseg=segs-1,almostlast=lastseg-1; + for(ix=1; ix<rows; ++ix) { + jx=(ix-1)*segs+1; + for(kx=0; kx<segs; ++kx) { + na = jx+kx; + nb = na+segs; + nc = (kx==lastseg)? jx+segs: nb+1; + nd = (kx==lastseg)? jx : na+1; + + mesh.faces[nf].setEdgeVisFlags(1,1,0); + mesh.faces[nf].setSmGroup(smooth?1:0); + mesh.faces[nf].setMatID(1); + mesh.faces[nf].setVerts(na,nb,nc); + nf++; + + mesh.faces[nf].setEdgeVisFlags(0,1,1); + mesh.faces[nf].setSmGroup(smooth?1:0); + mesh.faces[nf].setMatID(1); + mesh.faces[nf].setVerts(na,nc,nd); + nf++; + } + } + + // Make bottom conic cap + na = mesh.getNumVerts()-1; + int botsegs=segs; + jx = (rows-1)*segs+1;lastseg=botsegs-1; + int fstart = nf; + for(ix=0; ix<botsegs; ++ix) { + nc = ix + jx; + nb = (ix==lastseg)?jx:nc+1; + mesh.faces[nf].setEdgeVisFlags(1,1,1); + mesh.faces[nf].setSmGroup(smooth?1:0); + mesh.faces[nf].setMatID(1); + mesh.faces[nf].setVerts(na, nb, nc); + nf++; + } + + mesh.setNumTVerts(0); + mesh.setNumTVFaces(0); + mesh.InvalidateTopologyCache(); +} + +Object* bhkSphereObject::ConvertToType(TimeValue t, Class_ID obtype) +{ + return 0; + //return SimpleObject::ConvertToType(t,obtype); +} + +int bhkSphereObject::CanConvertToType(Class_ID obtype) +{ + return 0; +} + + +void bhkSphereObject::GetCollapseTypes(Tab<Class_ID> &clist,Tab<TSTR*> &nlist) +{ + Object::GetCollapseTypes(clist, nlist); +} + +class SphereObjCreateCallBack : public CreateMouseCallBack { + IPoint2 sp0; + bhkSphereObject *ob; + Point3 p0; +public: + int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat); + void SetObj(bhkSphereObject *obj) {ob = obj;} +}; + +int SphereObjCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) +{ + float r; + Point3 p1,center; + + if (msg == MOUSE_FREEMOVE) + { + vpt->SnapPreview(m,m,NULL, SNAP_IN_3D); + } + + if (msg==MOUSE_POINT||msg==MOUSE_MOVE) + { + switch(point) + { + case 0: // only happens with MOUSE_POINT msg + ob->pblock->SetValue(PB_RADIUS,0,0.0f); + ob->suspendSnap = TRUE; + sp0 = m; + p0 = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + mat.SetTrans(p0); + break; + case 1: + mat.IdentityMatrix(); + //mat.PreRotateZ(HALFPI); + p1 = vpt->SnapPoint(m,m,NULL,SNAP_IN_3D); + r = Length(p1-p0); + mat.SetTrans(p0); + + ob->pblock->SetValue(PB_RADIUS,0,r); + ob->pmapParam->Invalidate(); + + if (flags&MOUSE_CTRL) + { + float ang = (float)atan2(p1.y-p0.y,p1.x-p0.x); + mat.PreRotateZ(ob->ip->SnapAngle(ang)); + } + + if (msg==MOUSE_POINT) + { + ob->suspendSnap = FALSE; + return (Length(m-sp0)<3 || Length(p1-p0)<0.1f)?CREATE_ABORT:CREATE_STOP; + } + break; + } + } + else + if (msg == MOUSE_ABORT) + { + return CREATE_ABORT; + } + + return TRUE; +} + +static SphereObjCreateCallBack sphereCreateCB; + +CreateMouseCallBack* bhkSphereObject::GetCreateMouseCallBack() +{ + sphereCreateCB.SetObj(this); + return(&sphereCreateCB); +} + + +BOOL bhkSphereObject::OKtoDisplay(TimeValue t) +{ + float radius; + pblock->GetValue(PB_RADIUS,t,radius,FOREVER); + if (radius==0.0f) return FALSE; + else return TRUE; +} + +// From GeomObject +int bhkSphereObject::IntersectRay(TimeValue t, Ray& ray, float& at, Point3& norm) +{ + int smooth; + pblock->GetValue(PB_SMOOTH,t,smooth,FOREVER); + + float r; + float a, b, c, ac4, b2, at1, at2; + float root; + BOOL neg1, neg2; + + pblock->GetValue(PB_RADIUS,t,r,FOREVER); + + a = DotProd(ray.dir,ray.dir); + b = DotProd(ray.dir,ray.p) * 2.0f; + c = DotProd(ray.p,ray.p) - r*r; + + ac4 = 4.0f * a * c; + b2 = b*b; + + if (ac4 > b2) return 0; + + // We want the smallest positive root + root = float(sqrt(b2-ac4)); + at1 = (-b + root) / (2.0f * a); + at2 = (-b - root) / (2.0f * a); + neg1 = at1<0.0f; + neg2 = at2<0.0f; + if (neg1 && neg2) + return 0; + else if (neg1 && !neg2) + at = at2; + else if (!neg1 && neg2) + at = at1; + else if (at1<at2) + at = at1; + else + at = at2; + norm = Normalize(ray.p + at*ray.dir); + return 1; +} + +void bhkSphereObject::InvalidateUI() +{ + if (pmapParam) pmapParam->Invalidate(); +} + +ParamDimension *bhkSphereObject::GetParameterDim(int pbIndex) +{ + switch (pbIndex) + { + case PB_RADIUS: + return stdWorldDim; + case PB_SEGS: + return stdSegmentsDim; + case PB_SMOOTH: + return stdNormalizedDim; + default: + return defaultDim; + } +} + +TSTR bhkSphereObject::GetParameterName(int pbIndex) +{ + switch (pbIndex) + { + case PB_RADIUS: + return TSTR(GetString(IDS_RB_RADIUS)); + case PB_SEGS: + return TSTR(GetString(IDS_RB_SEGS)); + case PB_SMOOTH: + return TSTR(GetString(IDS_RB_SMOOTH)); + default: + return TSTR(_T("")); + } +} + +RefTargetHandle bhkSphereObject::Clone(RemapDir& remap) +{ + bhkSphereObject* newob = new bhkSphereObject(FALSE); + newob->ReplaceReference(0,remap.CloneRef(pblock)); + newob->ivalid.SetEmpty(); + BaseClone(this, newob, remap); + return(newob); +} + +void bhkSphereObject::UpdateUI() +{ + if (ip == NULL) + return; + SphereParamDlgProc* dlg = static_cast<SphereParamDlgProc*>(pmapParam->GetUserDlgProc()); + dlg->Update(ip->GetTime()); +} diff --git a/NifProps/resource.h b/NifProps/resource.h index dca7d86..53b8d4f 100755 --- a/NifProps/resource.h +++ b/NifProps/resource.h @@ -2,6 +2,29 @@ // Microsoft Visual C++ generated include file. // Used by NifProps.rc // +#define IDD_SPHEREPARAM2 101 +#define IDC_RADIUS 1000 +#define IDC_SEGMENTS 1001 +#define IDC_RADIUS1 1002 +#define IDC_RADIUS2 1003 +#define IDC_SEGSPINNER 1004 +#define IDC_RADSPINNER 1005 +#define IDC_OBSMOOTH 1006 +#define IDC_RADSPINNER1 1007 +#define IDC_RADSPINNER2 1008 +#define IDC_ED_POS1_X 1700 +#define IDC_SP_POS1_X 1701 +#define IDC_ED_POS1_Y 1702 +#define IDC_SP_POS1_Y 1703 +#define IDC_ED_POS1_Z 1704 +#define IDC_SP_POS1_Z 1705 +#define IDC_ED_POS2_X 1706 +#define IDC_SP_POS2_X 1707 +#define IDC_ED_POS2_Y 1708 +#define IDC_SP_POS2_Y 1709 +#define IDC_ED_POS2_Z 1710 +#define IDC_SP_POS2_Z 1711 +#define IDC_LBL_POS1 1712 #define IDS_LIBDESCRIPTION 11001 #define IDD_PANEL 11001 #define IDC_LBL_BSXFLAGS 11001 @@ -10,19 +33,29 @@ #define IDC_ED_BSXFLAGS 11002 #define IDS_CLASS_NAME 11003 #define IDC_ED_STRINGSEXTRA 11003 +#define IDD_RigidBody 11003 #define IDS_PARAMS 11004 #define IDC_LBL_STRINGSEXTRA 11004 +#define IDD_CAPSULEPARAM 11004 #define IDS_SPIN 11005 #define IDC_GRP_OBJECT 11005 #define IDS_ANIM_PARAMS 11006 #define IDC_CHK_ISCOLL 11006 #define IDC_GRP_HAVOK 11007 #define IDC_HVK_BEGIN 11007 +#define IDS_RB_Capsule 11007 +#define IDS_RB_CAPSULE 11007 +#define IDS_RB_Capsule 11007 #define IDC_LBL_MATERIAL 11008 +#define IDS_RB_CAPSULE_CLASS 11008 #define IDC_CB_MATERIAL 11009 +#define IDS_RB_RIGIDBODY_PARAM 11009 #define IDC_LBL_LAYER 11010 +#define IDS_RB_CAP_POS1 11010 #define IDC_CB_LAYER 11011 +#define IDS_RB_CAP_POS2 11011 #define IDC_LBL_CENTER 11012 +#define IDC_LBL_POS2 11013 #define IDC_ED_CENTER_X 11490 #define IDC_SP_CENTER_X 11491 #define IDC_ED_CENTER_Y 11492 @@ -63,6 +96,16 @@ #define IDC_ED_ANIM_PRIORITY 11601 #define IDC_SP_ANIM_PRIORITY 11602 #define IDC_ANIM_END 11602 +#define IDS_RB_PARAMETERS 30028 +#define IDS_RB_RADIUS 30045 +#define IDS_RB_SEGS 30046 +#define IDS_RB_SMOOTH 30048 +#define IDS_RB_PRIMITIVES 30264 +#define IDS_RB_SPHERE 30503 +#define IDS_RB_RADIUS1 30516 +#define IDS_RB_RADIUS2 30517 +#define IDS_RB_SPHERE_CLASS 31298 +#define IDS_DS_PARAMCHG 31316 // Next default values for new objects // @@ -70,7 +113,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1700 +#define _APS_NEXT_CONTROL_VALUE 1713 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif -- GitLab