summaryrefslogtreecommitdiff
path: root/groupexplode
diff options
context:
space:
mode:
Diffstat (limited to 'groupexplode')
-rw-r--r--groupexplode/config.cpp7
-rw-r--r--groupexplode/config.h4
-rw-r--r--groupexplode/dialog.cpp5
-rw-r--r--groupexplode/dialog.h1
-rw-r--r--groupexplode/main.cpp230
-rw-r--r--groupexplode/resource.h1
-rw-r--r--groupexplode/resource.rc9
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
}