diff options
Diffstat (limited to 'groupexplode')
-rw-r--r-- | groupexplode/config.cpp | 7 | ||||
-rw-r--r-- | groupexplode/config.h | 4 | ||||
-rw-r--r-- | groupexplode/dialog.cpp | 5 | ||||
-rw-r--r-- | groupexplode/dialog.h | 1 | ||||
-rw-r--r-- | groupexplode/main.cpp | 230 | ||||
-rw-r--r-- | groupexplode/resource.h | 1 | ||||
-rw-r--r-- | groupexplode/resource.rc | 9 |
7 files changed, 249 insertions, 8 deletions
diff --git a/groupexplode/config.cpp b/groupexplode/config.cpp index 59f87f0..740fd9d 100644 --- a/groupexplode/config.cpp +++ b/groupexplode/config.cpp @@ -27,6 +27,7 @@ bool Config::m_init=false; bool Config::m_rmOrig=false; +bool Config::m_collate=false; void Config::Load() { @@ -35,12 +36,14 @@ void Config::Load() m_init=true; m_rmOrig=false; + m_collate=true; #if REGISTRY_USAGE!=0 W32DLib::Registry r(HKEY_CURRENT_USER,KEY); r.Read("RemoveOriginal",m_rmOrig); + r.Read("Collate",m_collate); #endif @@ -54,9 +57,13 @@ void Config::Save() W32DLib::Registry r(HKEY_CURRENT_USER,KEY,REGISTRY_USAGE==2); r.Write("RemoveOriginal",m_rmOrig); + r.Write("Collate",m_collate); #endif } bool Config::RemoveOriginal() {return m_rmOrig;} void Config::RemoveOriginal(bool flag) {m_rmOrig=flag;} + +bool Config::Collate() {return m_collate;} +void Config::Collate(bool flag) {m_collate=flag;} diff --git a/groupexplode/config.h b/groupexplode/config.h index 8d00356..302e2fb 100644 --- a/groupexplode/config.h +++ b/groupexplode/config.h @@ -36,12 +36,16 @@ public: static bool RemoveOriginal(); static void RemoveOriginal(bool flag); + static bool Collate(); + static void Collate(bool flag); + private: Config(); static bool m_init; static bool m_rmOrig; + static bool m_collate; }; #endif // CONFIG_H diff --git a/groupexplode/dialog.cpp b/groupexplode/dialog.cpp index 6816de9..c8d30f7 100644 --- a/groupexplode/dialog.cpp +++ b/groupexplode/dialog.cpp @@ -33,6 +33,7 @@ Dialog::Dialog(const StringList& groups) : m_ok(this,IDC_OKBUT,0) , m_cancel(this,IDC_CANCELBUT,0) , m_rmOrig(this,IDC_RMORIG,0) + , m_collate(this,IDC_COLLATE,0) , m_groups(this,IDC_GROUP,0) , m_sel(-1) , m_groupList(groups) @@ -67,6 +68,7 @@ void Dialog::OnInit() m_groups.SelectedIndex(0); + m_collate.SetState(Config::Collate()); m_rmOrig.SetState(Config::RemoveOriginal()); } @@ -82,7 +84,10 @@ int Dialog::GetSelectedGroup() BOOL Dialog::OnOK(UINT msg, WPARAM wp, LPARAM lp) { + Config::Collate(m_collate.GetState()); Config::RemoveOriginal(m_rmOrig.GetState()); + Config::Save(); + m_sel=m_groups.SelectedIndex(); Close(IDOK); diff --git a/groupexplode/dialog.h b/groupexplode/dialog.h index f68efa5..4620eec 100644 --- a/groupexplode/dialog.h +++ b/groupexplode/dialog.h @@ -43,6 +43,7 @@ private: W32DLib::Button m_ok; W32DLib::Button m_cancel; W32DLib::AutoCheck m_rmOrig; + W32DLib::AutoCheck m_collate; W32DLib::ComboBox m_groups; int m_sel; const StringList& m_groupList; diff --git a/groupexplode/main.cpp b/groupexplode/main.cpp index dbee433..2979b7b 100644 --- a/groupexplode/main.cpp +++ b/groupexplode/main.cpp @@ -20,10 +20,229 @@ // static const char rcs_id[]="$Id$"; +#include <algorithm> +#include <cstdio> +#include <cstring> +#include <stdarg.h> + #include "mingwms.h" #include "msLib.h" #include "dialog.h" +#include "config.h" + + +// ---------------------------------------------------------------------- +// TYPES +// +typedef std::vector<int> IntList; +typedef std::vector<IntList> TriangleList; + +class IndexMap : public std::map<int,int> +{ +public: + IndexMap() : std::map<int,int> () {} + + bool Has(int key) + { + return find(key)!=end(); + } +}; + + +// ---------------------------------------------------------------------- +// UTILS +// +static bool VecMatch(const msVec3 v1, const msVec3 v2) +{ + for(int f=0;f<3;f++) + { + if (v1[f]!=v2[f]) + { + return false; + } + } + + return true; +} + + +static void CopyVec3(msVec3 to, const msVec3 from) +{ + for(int f=0;f<3;f++) + { + to[f]=from[f]; + } +} + + +static bool VertexNormalsMatch(msMesh *m, int t1, int t2) +{ + msVec3 v1; + msVec3 v2; + + for(int f=0;f<3;f++) + { + msMesh_GetVertexNormalAt(m,(m->pTriangles+t1)->nNormalIndices[f],v1); + msMesh_GetVertexNormalAt(m,(m->pTriangles+t2)->nNormalIndices[f],v2); + + if (!VecMatch(v1,v2)) + { + return false; + } + } + + return true; +} + + +static void SetName(char *name, const char *base, int num) +{ + int len=std::min(static_cast<int>(std::strlen(base)),MS_MAX_NAME-10); + + std::sprintf(name,"%*.*s_%d",len,len,base,num); +} + + +static void DEBUG(const char *fmt, ...) +{ + static char buff[4096]; + + va_list va; + va_start(va,fmt); + std::vsprintf(buff,fmt,va); + va_end(va); + + W32DLib::Common::Message(0,"DEBUG",buff); +} + + +// ---------------------------------------------------------------------- +// GROUP SPLITTER -- This is *very* ugly code, so look away if you're of +// a nervous disposition. +// +static void SplitGroup(msModel *model, int group) +{ + TriangleList list; + msMesh *orig_mesh=msModel_GetMeshAt(model,group); + int num=orig_mesh->nNumTriangles; + bool *used=new bool[num]; + std::string name=orig_mesh->szName; + + for(int f=0;f<num;f++) + { + used[f]=false; + } + + for(int f=0;f<num;f++) + { + if (!used[f]) + { + IntList sublist; + + sublist.push_back(f); + used[f]=true; + + if (Config::Collate()) + { + for(int i=0;i<num;i++) + { + if (!used[i] && VertexNormalsMatch(orig_mesh,f,i)) + { + sublist.push_back(i); + used[i]=true; + } + } + } + + list.push_back(sublist); + } + } + + delete[] used; + + TriangleList::const_iterator i; + IntList::const_iterator j; + + num=1; + + for(i=list.begin();i!=list.end();++i) + { + IndexMap vmap; + IndexMap nmap; + + msMesh *mesh=msModel_GetMeshAt(model,msModel_AddMesh(model)); + + SetName(mesh->szName,name.c_str(),num++); + + mesh->nMaterialIndex=orig_mesh->nMaterialIndex; + + for(j=i->begin();j!=i->end();++j) + { + msTriangle *old_tri=msMesh_GetTriangleAt(orig_mesh,*j); + msTriangle *new_tri=msMesh_GetTriangleAt + (mesh,msMesh_AddTriangle(mesh)); + + CopyVec3(new_tri->Normal,old_tri->Normal); + new_tri->nFlags=old_tri->nFlags; + + for(int f=0;f<3;f++) + { + int old_vi=old_tri->nVertexIndices[f]; + int new_vi; + int old_ni=old_tri->nNormalIndices[f]; + int new_ni; + + if (vmap.Has(old_vi)) + { + new_vi=vmap[old_vi]; + } + else + { + new_vi=msMesh_AddVertex(mesh); + vmap[old_vi]=new_vi; + } + + if (nmap.Has(old_ni)) + { + new_ni=nmap[old_ni]; + } + else + { + new_ni=msMesh_AddVertexNormal(mesh); + nmap[old_ni]=new_ni; + } + + msVertex *old_ver=msMesh_GetVertexAt(orig_mesh,old_vi); + msVertex *new_ver=msMesh_GetVertexAt(mesh,new_vi); + + *new_ver=*old_ver; + + msVec3 normal; + + msMesh_GetVertexNormalAt(orig_mesh,old_ni,normal); + msMesh_SetVertexNormalAt(mesh,new_ni,normal); + + new_tri->nVertexIndices[f]=new_vi; + new_tri->nNormalIndices[f]=new_ni; + } + } + } + + if (Config::RemoveOriginal()) + { + msMesh_Destroy(orig_mesh); + + for(int f=group;f<model->nNumMeshes-1;f++) + { + model->pMeshes[f]=model->pMeshes[f+1]; + } + + model->nNumMeshes--; + model->nNumAllocedMeshes--; + } +} + // ---------------------------------------------------------------------- // MINGW WRAPPER FUNCTIONS @@ -38,8 +257,6 @@ static int Execute(msModel* model) W32DLib::Common::Initialise(); W32DLib::Common::MessageTitle("Group Exploder"); - // Unfortunately this is the best you can hope for with Milkshape... - // HWND parent=GetForegroundWindow(); if (!model) @@ -67,12 +284,17 @@ static int Execute(msModel* model) if (dlg.ShowModal(W32DLib::Common::GetInstance(),parent)==IDOK) { - int sel=dlg.GetSelectedGroup(); + SetCursor(LoadCursor(NULL,IDC_WAIT)); + SplitGroup(model,dlg.GetSelectedGroup()); + SetCursor(LoadCursor(NULL,IDC_ARROW)); + + return MS_MODEL_CHANGED; } - return 1; + return MS_MODEL_UNCHANGED; } + PLUGIN_SPEC void* CreatePlugIn() { return CreateMINGWPlugin(MS_TYPE_TOOL, GetTitle, Execute); diff --git a/groupexplode/resource.h b/groupexplode/resource.h index 1da17e5..445191d 100644 --- a/groupexplode/resource.h +++ b/groupexplode/resource.h @@ -28,3 +28,4 @@ #define IDC_CANCELBUT 4 #define IDC_GROUP 5 #define IDC_RMORIG 6 +#define IDC_COLLATE 7 diff --git a/groupexplode/resource.rc b/groupexplode/resource.rc index 31ddf19..470ba45 100644 --- a/groupexplode/resource.rc +++ b/groupexplode/resource.rc @@ -1,7 +1,7 @@ #include <windows.h> #include "resource.h" -GR_DIALOG DIALOG 100, 100, 200, 85 +GR_DIALOG DIALOG 100, 100, 200, 105 STYLE WS_POPUP | WS_BORDER CAPTION "Group Exploder" FONT 8,"MS Shell Dlg" @@ -10,8 +10,9 @@ GR_DIALOG DIALOG 100, 100, 200, 85 COMBOBOX IDC_GROUP, 10, 20, 180, 200, CBS_DROPDOWNLIST | WS_TABSTOP - AUTOCHECKBOX "Remove Original Group", IDC_RMORIG, 10,40,180,18 + AUTOCHECKBOX "Remove original mesh", IDC_RMORIG, 10,40,180,18 + AUTOCHECKBOX "Collate triangles with identical normals", IDC_COLLATE, 10,60,180,18 - PUSHBUTTON "OK", IDC_OKBUT, 10,60,80,18 - PUSHBUTTON "Cancel", IDC_CANCELBUT, 110,60,80,18 + PUSHBUTTON "OK", IDC_OKBUT, 10,80,80,18 + PUSHBUTTON "Cancel", IDC_CANCELBUT, 110,80,80,18 } |