Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
MagicDoc.cpp
Go to the documentation of this file.
1 /* Project Magic 2.0
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Magic.exe
6  FILE: MagicDoc.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Implementation of the MagicDoc class
13 */
14 
15 #include "stdafx.h"
16 #include "Magic.h"
17 
18 #include "MagicDoc.h"
19 #include "ModelFileMAG.h"
20 #include "ModelFileOBJ.h"
21 #include "ModelFile3DS.h"
22 #include "Selection.h"
23 #include "Selector.h"
24 #include "Editor.h"
25 #include "Command.h"
26 
27 #include "Bitmap.h"
28 #include "Color.h"
29 #include "D3DXImage.h"
30 #include "Geometry.h"
31 #include "Pcx.h"
32 #include "Polygon.h"
33 #include "Solid.h"
34 
35 #ifdef _DEBUG
36 #define new DEBUG_NEW
37 #undef THIS_FILE
38 static char THIS_FILE[] = __FILE__;
39 #endif
40 
41 // +--------------------------------------------------------------------+
42 
43 IMPLEMENT_DYNCREATE(MagicDoc, CDocument)
44 
45 BEGIN_MESSAGE_MAP(MagicDoc, CDocument)
46  //{{AFX_MSG_MAP(MagicDoc)
47  ON_COMMAND(ID_SURFACE_OPTIMIZE, OnSurfaceOptimize)
48  ON_COMMAND(ID_SURFACE_EXPLODE, OnSurfaceExplode)
49  ON_UPDATE_COMMAND_UI(ID_SURFACE_OPTIMIZE, OnUpdateSurfaceOptimize)
50  ON_UPDATE_COMMAND_UI(ID_SURFACE_EXPLODE, OnUpdateSurfaceExplode)
51  //}}AFX_MSG_MAP
52 END_MESSAGE_MAP()
53 
54 // +--------------------------------------------------------------------+
55 
56 MagicDoc::MagicDoc()
57  : solid(0), selection(0)
58 {
59  solid = new Solid;
60  selection = new Selection;
61  selector = new Selector(selection);
62  editor = new Editor(this);
63 }
64 
66 {
67  if (editor) delete editor;
68  if (selector) delete selector;
69  if (selection) delete selection;
70  if (solid) delete solid;
71 }
72 
73 // +--------------------------------------------------------------------+
74 
75 void
77 {
78  nundo = 0;
79  commands.destroy();
80 }
81 
82 void
84 {
85  int nredo = commands.size() - nundo;
86 
87  while (nredo) {
88  delete commands.removeIndex(commands.size()-1);
89  nredo--;
90  }
91 
92  if (nundo < 100) {
93  nundo++;
94  }
95  else {
96  delete commands.removeIndex(0);
97  }
98 
99  command->Do();
100  commands.append(command);
101 }
102 
103 int
105 {
106  return nundo;
107 }
108 
109 int
111 {
112  return commands.size() - nundo;
113 }
114 
115 const char*
117 {
118  if (nundo > 0 && nundo <= commands.size())
119  return commands[nundo-1]->Name();
120  else
121  return "";
122 }
123 
124 const char*
126 {
127  if (nundo >= 0 && nundo < commands.size())
128  return commands[nundo]->Name();
129  else
130  return "";
131 }
132 
133 void
135 {
136  if (nundo > 0 && nundo <= commands.size())
137  commands[--nundo]->Undo();
138 }
139 
140 void
142 {
143  if (nundo >= 0 && nundo < commands.size())
144  commands[nundo++]->Do();
145 }
146 
147 // +--------------------------------------------------------------------+
148 
150 {
151  if (!CDocument::OnNewDocument())
152  return FALSE;
153 
155 
156  if (solid) delete solid;
157  solid = new Solid;
158 
159  if (selection)
160  selection->Clear();
161 
162  return TRUE;
163 }
164 
165 // +--------------------------------------------------------------------+
166 
167 void MagicDoc::Serialize(CArchive& ar)
168 {
169 }
170 
171 // +--------------------------------------------------------------------+
172 
173 #ifdef _DEBUG
174 void MagicDoc::AssertValid() const
175 {
176  CDocument::AssertValid();
177 }
178 
179 void MagicDoc::Dump(CDumpContext& dc) const
180 {
181  CDocument::Dump(dc);
182 }
183 #endif //_DEBUG
184 
185 // +--------------------------------------------------------------------+
186 
187 BOOL MagicDoc::OnSaveDocument(LPCTSTR path_name)
188 {
189  SetModifiedFlag(FALSE);
190 
191  ModelFileMAG mod_file(path_name);
192  mod_file.Save(solid->GetModel());
193 
194  SetModifiedFlag(FALSE);
195  UpdateAllViews(NULL);
196  return TRUE;
197 }
198 
199 BOOL MagicDoc::OnOpenDocument(LPCTSTR path_name)
200 {
201  FILE* fp = fopen(path_name, "rb");
202  if (!fp) {
203  ::MessageBox(0, "Open Failed: could not open file", "ERROR", MB_OK);
204  return FALSE;
205  }
206 
207  int version = 1;
208  char file_id[5];
209  fread(file_id, 4, 1, fp);
210  file_id[4] = '\0';
211  fclose(fp);
212 
213  if (strncmp(file_id, "MAG", 3)) {
214  ::MessageBox(0, "Open Failed: Invalid file type", "ERROR", MB_OK);
215  return FALSE;
216  }
217 
218  switch (file_id[3]) {
219  case '6': version = 6; break;
220  case '5': version = 5; break;
221  default: version = 0; break;
222  }
223 
224  if (version < 5 || version > 6) {
225  ::MessageBox(0, "Open Failed: Unsupported version", "ERROR", MB_OK);
226  return FALSE;
227  }
228 
229  DeleteContents();
230 
231  ModelFileMAG mod_file(path_name);
232  solid->Load(&mod_file);
233  solid->CreateShadows();
234 
235  SetModifiedFlag(FALSE);
236  UpdateAllViews(NULL);
237  return TRUE;
238 }
239 
240 bool
241 MagicDoc::ImportFile(LPCTSTR path_name)
242 {
243  if (strstr(path_name, ".obj") || strstr(path_name, ".OBJ")) {
244  ModelFileOBJ obj_file(path_name);
245 
246  if (solid->GetModel()) {
247  Solid* s = new Solid;
248 
249  if (s->Load(&obj_file)) {
250  // todo: insert command here
251  Model* orig = solid->GetModel();
252  Model* imported = s->GetModel();
253 
254  orig->GetMaterials().append(imported->GetMaterials());
255  orig->GetSurfaces().append(imported->GetSurfaces());
256  orig->OptimizeMaterials();
257 
258  imported->GetMaterials().clear();
259  imported->GetSurfaces().clear();
260 
261  SetModifiedFlag(FALSE);
262  UpdateAllViews(NULL);
263  delete s;
264  return true;
265  }
266 
267  delete s;
268  }
269  else {
270  if (solid->Load(&obj_file)) {
271  SetModifiedFlag(FALSE);
272  UpdateAllViews(NULL);
273  return true;
274  }
275  }
276 
277  return false;
278  }
279 
280  if (strstr(path_name, ".3ds") || strstr(path_name, ".3DS")) {
281  ModelFile3DS model_file(path_name);
282 
283  if (solid->GetModel()) {
284  Solid* s = new Solid;
285 
286  if (s->Load(&model_file)) {
287  // todo: insert command here
288  Model* orig = solid->GetModel();
289  Model* imported = s->GetModel();
290 
291  orig->GetMaterials().append(imported->GetMaterials());
292  orig->GetSurfaces().append(imported->GetSurfaces());
293  orig->OptimizeMaterials();
294 
295  imported->GetMaterials().clear();
296  imported->GetSurfaces().clear();
297 
298  SetModifiedFlag(FALSE);
299  UpdateAllViews(NULL);
300  delete s;
301  return true;
302  }
303 
304  delete s;
305  }
306  else {
307  if (solid->Load(&model_file)) {
308  SetModifiedFlag(FALSE);
309  UpdateAllViews(NULL);
310  return true;
311  }
312  }
313 
314  return false;
315  }
316 
317  FILE* fp = fopen(path_name, "rb");
318  if (!fp) {
319  ::MessageBox(0, "Import Failed: could not open file", "ERROR", MB_OK);
320  return false;
321  }
322 
323  int version = 1;
324  char file_id[5];
325  fread(file_id, 4, 1, fp);
326  file_id[4] = '\0';
327  fclose(fp);
328 
329  if (strncmp(file_id, "MAG", 3)) {
330  ::MessageBox(0, "Open Failed: Invalid file type", "ERROR", MB_OK);
331  return false;
332  }
333 
334  switch (file_id[3]) {
335  case '6': version = 6; break;
336  case '5': version = 5; break;
337  default: version = 0; break;
338  }
339 
340  if (version < 5 || version > 6) {
341  ::MessageBox(0, "Open Failed: Unsupported version", "ERROR", MB_OK);
342  return false;
343  }
344 
345  ModelFileMAG mag_file(path_name);
346 
347  if (solid->GetModel()) {
348  Solid* s = new Solid;
349  if (s->Load(&mag_file)) {
350  // todo: insert command here
351  Model* orig = solid->GetModel();
352  Model* imported = s->GetModel();
353 
354  orig->GetMaterials().append(imported->GetMaterials());
355  orig->GetSurfaces().append(imported->GetSurfaces());
356  orig->OptimizeMaterials();
357 
358  imported->GetMaterials().clear();
359  imported->GetSurfaces().clear();
360 
361  SetModifiedFlag(FALSE);
362  UpdateAllViews(NULL);
363  delete s;
364  return true;
365  }
366 
367  delete s;
368  }
369  else {
371 
372  if (solid->Load(&mag_file)) {
373  SetModifiedFlag(FALSE);
374  UpdateAllViews(NULL);
375  return true;
376  }
377  }
378 
379  return false;
380 }
381 
382 bool
383 MagicDoc::ExportFile(LPCTSTR path_name)
384 {
385  if (!solid->GetModel())
386  return false;
387 
388  if (strstr(path_name, ".obj") || strstr(path_name, ".OBJ")) {
389  ModelFileOBJ obj_file(path_name);
390  obj_file.Save(solid->GetModel());
391  return true;
392  }
393 
394  if (strstr(path_name, ".3ds") || strstr(path_name, ".3DS")) {
395  return false;
396  }
397 
398  if (strstr(path_name, ".mag") || strstr(path_name, ".MAG")) {
399  ModelFileMAG mod_file(path_name);
400  mod_file.Save(solid->GetModel());
401  return true;
402  }
403 
404  return false;
405 }
406 
407 // +--------------------------------------------------------------------+
408 
409 int LoadBuffer(const char* filename, BYTE*& buf, bool null_terminate)
410 {
411  buf = 0;
412 
413  FILE* f = ::fopen(filename, "rb");
414 
415  if (f) {
416  ::fseek(f, 0, SEEK_END);
417  int len = ftell(f);
418  ::fseek(f, 0, SEEK_SET);
419 
420  if (null_terminate) {
421  buf = new BYTE[len+1];
422  if (buf)
423  buf[len] = 0;
424  }
425 
426  else {
427  buf = new BYTE[len];
428  }
429 
430  if (buf)
431  ::fread(buf, len, 1, f);
432 
433  ::fclose(f);
434 
435  return len;
436  }
437 
438  return 0;
439 }
440 
441 // +--------------------------------------------------------------------+
442 
444 {
447 
448  if (solid) {
449  delete solid;
450  solid = new Solid;
451  }
452 
453  if (selection)
454  selection->Clear();
455 }
456 
457 // +--------------------------------------------------------------------+
458 
459 int LoadTexture(const char* fname, Bitmap*& bitmap, int type)
460 {
461  int result = 0;
462 
463  if (!fname || !*fname)
464  return result;
465 
466  bitmap = Bitmap::CheckCache(fname);
467 
468  if (!bitmap) {
469  bool pcx_file = strstr(fname, ".pcx") || strstr(fname, ".PCX");
470 
471  // handle PCX formats:
472  if (pcx_file) {
473  PcxImage pcx;
474 
475  if (pcx.Load((char*) fname) == PCX_OK) {
476  bitmap = new Bitmap;
477 
478  // 32-bit image
479  if (pcx.himap) {
480  bitmap->CopyHighColorImage(pcx.width, pcx.height, pcx.himap);
481  }
482 
483  // 8-bit image, check for 32-bit image as well
484  else if (pcx.bitmap) {
485  bitmap->CopyImage(pcx.width, pcx.height, pcx.bitmap);
486 
487  char tmp[256];
488  int len = strlen(fname);
489  bool found = false;
490 
491  ZeroMemory(tmp, sizeof(tmp));
492 
493  for (int i = 0; i < len && !found; i++) {
494  if (strstr(fname + i, ".pcx") == (fname+i)) {
495  found = true;
496  }
497  else {
498  tmp[i] = fname[i];
499  }
500  }
501 
502  if (found) {
503  strcat_s(tmp, "+.pcx");
504  if (pcx.Load(tmp) == PCX_OK && pcx.himap != 0) {
505  bitmap->CopyHighColorImage(pcx.width, pcx.height, pcx.himap);
506  }
507  }
508  }
509  }
510  }
511 
512  // for all other formats, use D3DX:
513  else {
514  D3DXImage d3dx;
515  if (d3dx.Load((char*) fname)) {
516  bitmap = new Bitmap;
517  bitmap->CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image);
518  }
519  }
520 
521  if (bitmap) {
522  LoadAlpha(fname, *bitmap, type);
523 
524  bitmap->SetFilename(fname);
525  bitmap->SetType(type);
526  bitmap->MakeTexture();
527 
528  Bitmap::AddToCache(bitmap);
529  }
530  }
531 
532  return result;
533 }
534 
535 int LoadAlpha(const char* name, Bitmap& bitmap, int type)
536 {
537  PcxImage pcx;
538  D3DXImage d3dx;
539  bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX");
540  bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP");
541  bool jpg_file = strstr(name, ".jpg") || strstr(name, ".JPG");
542  bool png_file = strstr(name, ".png") || strstr(name, ".PNG");
543  bool tga_file = strstr(name, ".tga") || strstr(name, ".TGA");
544 
545  // check for an associated alpha-only (grayscale) bitmap:
546  char filename[256];
547  strcpy_s(filename, name);
548 
549  char* dot = strrchr(filename, '.');
550  if (dot && pcx_file)
551  strcpy(dot, "@.pcx");
552  else if (dot && bmp_file)
553  strcpy(dot, "@.bmp");
554  else if (dot && jpg_file)
555  strcpy(dot, "@.jpg");
556  else if (dot && png_file)
557  strcpy(dot, "@.png");
558  else if (dot && tga_file)
559  strcpy(dot, "@.tga");
560  else
561  return 0;
562 
563  // first try to load from current directory:
564  bool loaded = false;
565 
566  if (pcx_file)
567  loaded = pcx.Load(filename) == PCX_OK;
568 
569  else
570  loaded = d3dx.Load(filename);
571 
572  // now copy the alpha values into the bitmap:
573  if (loaded) {
574  if (pcx_file && pcx.bitmap) {
575  bitmap.CopyAlphaImage(pcx.width, pcx.height, pcx.bitmap);
576  }
577  else if (pcx_file && pcx.himap) {
578  bitmap.CopyAlphaRedChannel(pcx.width, pcx.height, pcx.himap);
579  }
580  else if (d3dx.image) {
581  bitmap.CopyAlphaRedChannel(d3dx.width, d3dx.height, d3dx.image);
582  }
583  }
584 
585  return 0;
586 }
587 
588 
590 {
591  if (solid && solid->GetModel()) {
595  }
596 }
597 
599 {
600  pCmdUI->Enable(solid && solid->GetModel());
601 }
602 
604 {
605  if (solid && solid->GetModel()) {
606  solid->GetModel()->ExplodeMesh();
609  }
610 }
611 
612 void MagicDoc::OnUpdateSurfaceExplode(CCmdUI* pCmdUI)
613 {
614  pCmdUI->Enable(solid && solid->GetModel());
615 }