/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at golgotha_source@usa.net (Subject should have "GOLG" in it) ***********************************************************************/ #include#include "crkutil.hh" #include "obj3d.hh" #include #include #include #include "maxcomm.hh" #include "file/file.hh" #include "string/string.hh" #include "max_object.hh" #include "memory/array.hh" #include "debug.hh" m1_mail_slot_class slot; HINSTANCE my_instance; int my_nCmdShow; #define G3DF_VERSION 3 #define MAXANIMATIONS 2 #define MAXFRAMES 300 #define MAXVERT 100 #define MAXTOTALVERT (MAXFRAMES*MAXVERT) #define MAXCOUNTS 10000 #define MAXQUAD 150 #define UTILTEST_CLASS_ID 0x99bb61a5 int m1_cur_trans=31; class m1_utility_class : public UtilityObj { protected: class property_modifier { class prop_list { public: int rotation,flip,reverse,trans,tint; prop_list() : rotation(0), flip(0), reverse(0), trans(31) {} }; protected: void modify_node(INode *node); public: void modify_selected(Interface *ip); virtual void modify(prop_list &p) = 0; }; class rotate_left_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.rotation = (p.rotation+11)%12; } }; class rotate_right_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.rotation = (p.rotation+1)%12; } }; class flip_normal_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.flip = !p.flip; } }; class reverse_texture_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.reverse = !p.reverse; } }; class tint_texture_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.tint = !p.tint; } }; class set_trans_texture_modifier : public property_modifier { public: virtual void modify(prop_list &p) { p.trans=m1_cur_trans; } }; char *set_g1_name(char *dest, char *name); int add_vert(i4_array &vert_list, w32 vert_start, g1_vert_class &vt); public: IUtil *iu; TimeValue time; Interface *ip; HWND hPanel; // HWND hwnd; m1_poly_object_class *max_obj; m1_utility_class(); void BeginEditParams(Interface *ip,IUtil *iu); void EndEditParams(Interface *ip,IUtil *iu); void DeleteThis() {} void Init(HWND hWnd); void Destroy(HWND hWnd); void create_objects(); void grab_model_instance(int level, INode *node, m1_poly_object_class *o, w16 anim, w16 frame); void grab_model_instance2(int level, INode *node, m1_poly_object_class *o, w16 anim, w16 frame); void clean_objects(); void restart_fly(); void render(); void rotate_selected_left() { rotate_left_modifier tmp; tmp.modify_selected(ip); } void rotate_selected_right() { rotate_right_modifier tmp; tmp.modify_selected(ip); } void tint_toggle() { tint_texture_modifier tmp; tmp.modify_selected(ip); } void flip_normal() { flip_normal_modifier tmp; tmp.modify_selected(ip); } void reverse_texture() { reverse_texture_modifier tmp; tmp.modify_selected(ip); } void set_trans() { if (m1_cur_trans>=1 && m1_cur_trans<=31) { set_trans_texture_modifier tmp; tmp.modify_selected(ip); } } }; static m1_utility_class m1_utility; class m1_utility_descriptor_class : public ClassDesc { public: int IsPublic() {return 1;} void * Create(BOOL loading = FALSE) {return &m1_utility;} const TCHAR * ClassName() {return _T("Crack Utilities");} SClass_ID SuperClassID() {return UTILITY_CLASS_ID;} Class_ID ClassID() { return Class_ID(0x34713748, 0x5b4c1417); } const TCHAR* Category() {return _T("");} }; static m1_utility_descriptor_class m1_utility_descriptor; ClassDesc* GetCrackUtilDesc() {return &m1_utility_descriptor;} i4_bool accel_disabled=i4_F; HWND dlg_wnd; static BOOL CALLBACK UtilTestDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: dlg_wnd=hWnd; m1_utility.Init(hWnd); SetFocus(hWnd); return FALSE; break; case WM_DESTROY: m1_utility.Destroy(hWnd); break; case WM_KILLFOCUS : { if (accel_disabled) { accel_disabled=i4_F; EnableAccelerators(); } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case 0x3f6 : // not sure what command this is, but it works.. :) jc { if (!accel_disabled) { accel_disabled=i4_T; DisableAccelerators(); // turn 3ds's keyboard accelerators so we can type text } else { accel_disabled=i4_F; EnableAccelerators(); // turn on the accels } return FALSE; } break; case IDC_CRKUTIL_APPLY : { char buf[100]; GetDlgItemText(hWnd, IDC_CRKUTIL_EDIT, buf, 99); m1_cur_trans=atoi(buf); m1_utility.set_trans(); } break; case IDC_CRACKUTIL_RENDER: m1_utility.render(); break; case IDC_CRACKUTIL_ROTLEFT: m1_utility.rotate_selected_left(); break; case IDC_CRACKUTIL_ROTRIGHT: m1_utility.rotate_selected_right(); break; case IDC_CRACKUTIL_FLIP: m1_utility.flip_normal(); break; case IDC_CRKUTIL_TINT: m1_utility.tint_toggle(); break; case IDC_CRACKUTIL_REVERSE: m1_utility.reverse_texture(); break; } break; case WM_LBUTTONDOWN : case WM_LBUTTONUP: case WM_MOUSEMOVE: m1_utility.ip->RollupMouseMessage(hWnd,msg,wParam,lParam); break; default: return FALSE; } return TRUE; } m1_utility_class::m1_utility_class() { } void m1_utility_class::BeginEditParams(Interface *_ip,IUtil *_iu) { iu = _iu; ip = _ip; hPanel = ip->AddRollupPage(my_instance, MAKEINTRESOURCE(IDD_CRACKUTIL), (DLGPROC)UtilTestDlgProc, _T("Golgotha Utilities"), 0); } void m1_utility_class::EndEditParams(Interface *_ip,IUtil *_iu) { iu = NULL; ip = NULL; _ip->DeleteRollupPage(hPanel); hPanel = NULL; } void m1_utility_class::Init(HWND hWnd) { max_obj = 0; initialize_i4(); } void m1_utility_class::Destroy(HWND hWnd) { // clean_objects(); } char *m1_utility_class::set_g1_name(char *dest, char *name) { char s[256]; #if 0 static char *remap[][2] = { {"f:/", "/u/"}, {"//alpha1/", "/u/"}, { 0, 0 } }; #endif char *p,*q; p = name; q = s; while (*p) { if (*p == '\\') *q = '/'; else if (*p>='A' && *p<='Z') *q = *p + 'a' - 'A'; else *q = *p; ++p; ++q; } *q = 0; p = s; q = dest; #if 0 for (int i=0; remap[i][0]; i++) { int len = strlen(remap[i][0]); if (strncmp(p, remap[i][0], len) == 0) { p += len; strcpy(q, remap[i][1]); q += strlen(q); } } #endif strcpy(q,p); return dest; } int m1_utility_class::add_vert(i4_array &vert_list, w32 vert_start, g1_vert_class &vt) { float E_DELTA=0.001; for (int i=vert_start; i quad_a.size(); TSTR str; char *mat_name[1024], *mat_uv[1024]; int mat_size=0; char *name = node->GetName(); node->GetUserPropBuffer(str); char *p = str; if (strncmp(p, gmod_sig, strlen(gmod_sig))==0) { // skip first signature line while (*p && *p!='\n') p++; if (*p) p++; dbg("previously assigned polygon parameters\n"); char *mat, *uv; while (*p) { max_obj->quad_a.add(0); mat = p+1; while (*p && *p!='\n' && *p!=' ') p++; if (*p==' ') { // tokenize all the texture names *p = 0; p++; uv = p; } while (*p && *p!='\n') p++; if (*p=='\n') { // tokenize UV stuff *p = 0; p++; } mat_name[mat_size] = mat; mat_uv[mat_size] = uv; mat_size++; } dbg("grabbed %d polygon materials\n", mat_size); } // Get base state of object Object *obj = node->EvalWorldState(0).obj; if (!obj) { // do nothing } else if (obj->ClassID() == Class_ID(POINTHELP_CLASS_ID,0)) { Matrix3 tm = node->GetObjectTM(time); Point3 o(0,0,0),v; v = o * tm; max_obj->mount_a.add(new m1_mount_point_class(new i4_str(name), i4_3d_vector(v.x, v.y, v.z))); } else if (obj->CanConvertToType(triObjectClassID)) { TriObject *tri = (TriObject *)obj->ConvertToType(time, triObjectClassID); Mesh &mesh = tri->mesh; Matrix3 tm = node->GetObjectTM(time); w16 vert_id[1024]; int i,j; int verts = mesh.getNumVerts(); // Add vertexes to object dbg("getting %d verts\n", verts); for(i=0; i anim_a[anim]->vertex_a, vert_start, vt); } int faces = mesh.getNumFaces(); dbg("getting %d faces\n", faces); for (i=0; i =0? "Quad":"Tri ", found); // order vertex from missing edge tri[0] = vert_id[face.v[(found+1)%3]]; tri[1] = vert_id[face.v[(found+2)%3]]; tri[2] = vert_id[face.v[(found+3)%3]]; if (tri[0]==tri[1] || tri[0]==tri[2] || tri[1]==tri[2]) { dbg("Malformed!\n"); continue; } if (found>=0) { // this is part of a quad // search for matching triangle found=-1; for (j=quad_offset; j quad_a.size() && found<0; j++) { if (max_obj->quad_a[j] && max_obj->quad_a[j]->vertex_ref[0] == tri[2] && max_obj->quad_a[j]->vertex_ref[2] == tri[0]) found = j; } if (found>=0) { m1_quad_class *q = max_obj->quad_a[found]; dbg("Part of %d, added [%d]", found, tri[1]); // found other half. add the remaining vertex q->vertex_ref[3] = tri[1]; q->calc_texture_scale(max_obj->anim_a[anim]->vertex_a, vert_start); } } if (found<0) { dbg("Unallocated "); // need to add this triangle m1_quad_class *q = new m1_quad_class(tri[0], tri[1], tri[2]); dbg("Created [%d, %d, %d]", tri[0], tri[1], tri[2]); if (face.getMatID()>=MAX_MATERIAL_OFFSET) { // has a preassigned material id? found = face.getMatID() - MAX_MATERIAL_OFFSET; if (found>=mat_size) { dbg("Missing Material "); found = -1; } else { if (!max_obj->quad_a[found+quad_offset]) { dbg("Preassigned at %d ", found); max_obj->quad_a[found+quad_offset] = q; } else { dbg("Repeated "); // a repeat id, assume the latter ones are wrong. // found = -1; } q->set_texture(mat_name[found]); sscanf(mat_uv[found],"%f %f %f %f %f %f %f %f", &q->u[0],&q->v[0],&q->u[1],&q->v[1],&q->u[2],&q->v[2],&q->u[3],&q->v[3]); dbg(" = [%s] <%f,%f> <%f,%f> <%f,%f> <%f,%f>", q->texture_name, q->u[0],q->v[0],q->u[1],q->v[1],q->u[2],q->v[2],q->u[3],q->v[3]); q->calc_texture_scale(max_obj->anim_a[anim]->vertex_a, vert_start); textured = 1; } } if (!textured) { q->set_texture(""); q->u[0] = 0.0; q->v[0] = 0.0; q->u[1] = 1.0; q->v[1] = 0.0; q->u[2] = 1.0; q->v[2] = 1.0; q->u[3] = 0.0; q->v[3] = 1.0; q->calc_texture_scale(max_obj->anim_a[anim]->vertex_a,vert_start); } if (found<0) { dbg("New "); // add in a new quad found = max_obj->quad_a.add(q); dbg("at %d", found); } } dbg("\n"); } // compact quad array i=quad_offset; while (i quad_a.size()) if (max_obj->quad_a[i]) i++; else max_obj->quad_a.remove(i); if (max_obj->quad_a.size()-quad_offset==1 && mat_size==0) // assume old style poly grab_model_instance(level, node, max_obj, anim, frame); dbg("Final Quads %d\n", max_obj->quad_a.size()); // Delete the working object, if necessary if(obj != (Object *)tri) tri->DeleteThis(); } // Dump children info for (int i=0; i NumberOfChildren(); i++) grab_model_instance2(level+1, node->GetChildNode(i), max_obj, anim, frame); dbg("Got the model! Yes!\n"); } void m1_utility_class::grab_model_instance(int level, INode *node, m1_poly_object_class *max_obj, w16 anim, w16 frame) { w32 vert_start = 0; char st[256],matname[256]; memset(st,' ',level*2); st[level*2] = 0; strcat(st,node->GetName()); dbg("%-40s", st); matname[0] = 0; // Get material Mtl *mat = node->GetMtl(); if (mat) { // Check for a diffuse bitmap as real texture name if (mat->NumSubTexmaps()) { Texmap *tex = mat->GetSubTexmap(ID_DI); if (tex && tex->ClassID()==Class_ID(BMTEX_CLASS_ID,0)) { BitmapTex *bmt = (BitmapTex*)tex; set_g1_name(matname,bmt->GetMapName()); } } } m1_quad_class *q = max_obj->quad_a[max_obj->quad_a.size()-1]; int quad_off=0,flip=0,reverse=0,trans=31,tint=0; TSTR tst; node->GetUserPropBuffer(tst); sscanf(tst,"%d %d %d %d %d",&quad_off,&flip,&reverse,&trans,&tint); w16 quad[4]; quad[0] = q->vertex_ref[0]; quad[1] = q->vertex_ref[1]; quad[2] = q->vertex_ref[2]; quad[3] = q->vertex_ref[3]; // Add quad to object if (q->num_verts()==4) if (!flip) q->set(quad[(0+quad_off)%4],quad[(3+quad_off)%4],quad[(2+quad_off)%4],quad[(1+quad_off)%4]); else q->set(quad[(0+quad_off)%4],quad[(1+quad_off)%4],quad[(2+quad_off)%4],quad[(3+quad_off)%4]); else if (!flip) q->set(quad[(0+quad_off)%3],quad[(2+quad_off)%3],quad[(1+quad_off)%3]); else q->set(quad[(0+quad_off)%3],quad[(1+quad_off)%3],quad[(2+quad_off)%3]); q->calc_texture(reverse,max_obj->anim_a[anim]->vertex_a,vert_start,matname); q->set_flags(g1_quad_class::TINT, tint?g1_quad_class::TINT:0); q->set_flags(g1_quad_class::TRANSLUCENCY, trans); dbg("\n"); } void m1_utility_class::create_objects() //Note: // Normally, root level groups are separate objects // For now, the whole scene is one object { int i; dbg.restart(); if (max_obj) delete max_obj; max_obj = new m1_poly_object_class; time = ip->GetTime(); Interval interval = ip->GetAnimRange(); for (time=interval.Start(); time anim_a.add(new m1_animation_class(i4gets("default_animation_name"))); grab_model_instance2(0, ip->GetRootNode(), max_obj, 0 ,0); max_obj->num_vertex=max_obj->anim_a[0]->vertex_a.size(); } else if (IsDlgButtonChecked(dlg_wnd, IDC_CRKUTIL_ANIM)) { i4_array quad_list(100,100); grab_model_instance2(0, ip->GetRootNode(), max_obj, 0, 0); for (i=0; i quad_a.size() && max_obj->num_vertex) { dbg("Save Objects\n"); i4_file_class *f = i4_open(i4gets("fly_name"),I4_WRITE); i4_saver_class *g1_saver=new i4_saver_class(f); if (f) { max_obj->save(g1_saver); g1_saver->begin_data_write(); max_obj->save(g1_saver); delete g1_saver; } if (!slot.initialized()) restart_fly(); char *name; if (slot.initialized()) { dbg("Contacting maxtool\n"); char buf[256]; name = i4_os_string(i4gets("fly_name"),buf, sizeof(buf)); if (slot.write(name, strlen(name) + 1) == 0) { restart_fly(); name = i4_os_string(i4gets("fly_name"),buf, sizeof(buf)); slot.write(name, strlen(name) + 1); } } } dbg("Cleaning up!\n"); clean_objects(); dbg("Done!\n"); } void m1_utility_class::property_modifier::modify_selected(Interface *ip) { for (int i=0; i GetSelNodeCount(); i++) modify_node(ip->GetSelNode(i)); } void m1_utility_class::property_modifier::modify_node(INode *node) { prop_list p; TSTR tst; char str[1024]; node->GetUserPropBuffer(tst); sscanf(tst,"%d %d %d %d %d",&p.rotation, &p.flip, &p.reverse, &p.trans, &p.tint); modify(p); sprintf(str,"%d %d %d %d %d",p.rotation, p.flip, p.reverse, p.trans, p.tint); node->SetUserPropBuffer(TSTR(str)); }