summaryrefslogtreecommitdiffhomepage
path: root/Magic2/MagicDoc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Magic2/MagicDoc.cpp')
-rw-r--r--Magic2/MagicDoc.cpp639
1 files changed, 639 insertions, 0 deletions
diff --git a/Magic2/MagicDoc.cpp b/Magic2/MagicDoc.cpp
new file mode 100644
index 0000000..f0c7929
--- /dev/null
+++ b/Magic2/MagicDoc.cpp
@@ -0,0 +1,639 @@
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name "Destroyer Studios" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ SUBSYSTEM: Magic.exe
+ FILE: MagicDoc.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Implementation of the MagicDoc class
+*/
+
+#include "stdafx.h"
+#include "Magic.h"
+
+#include "MagicDoc.h"
+#include "ModelFileMAG.h"
+#include "ModelFileOBJ.h"
+#include "ModelFile3DS.h"
+#include "Selection.h"
+#include "Selector.h"
+#include "Editor.h"
+#include "Command.h"
+
+#include "Bitmap.h"
+#include "Color.h"
+#include "D3DXImage.h"
+#include "Geometry.h"
+#include "Pcx.h"
+#include "Polygon.h"
+#include "Solid.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+// +--------------------------------------------------------------------+
+
+IMPLEMENT_DYNCREATE(MagicDoc, CDocument)
+
+BEGIN_MESSAGE_MAP(MagicDoc, CDocument)
+ //{{AFX_MSG_MAP(MagicDoc)
+ ON_COMMAND(ID_SURFACE_OPTIMIZE, OnSurfaceOptimize)
+ ON_COMMAND(ID_SURFACE_EXPLODE, OnSurfaceExplode)
+ ON_UPDATE_COMMAND_UI(ID_SURFACE_OPTIMIZE, OnUpdateSurfaceOptimize)
+ ON_UPDATE_COMMAND_UI(ID_SURFACE_EXPLODE, OnUpdateSurfaceExplode)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// +--------------------------------------------------------------------+
+
+MagicDoc::MagicDoc()
+ : solid(0), selection(0)
+{
+ solid = new Solid;
+ selection = new Selection;
+ selector = new Selector(selection);
+ editor = new Editor(this);
+}
+
+MagicDoc::~MagicDoc()
+{
+ if (editor) delete editor;
+ if (selector) delete selector;
+ if (selection) delete selection;
+ if (solid) delete solid;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+MagicDoc::InitCommandStack()
+{
+ nundo = 0;
+ commands.destroy();
+}
+
+void
+MagicDoc::Exec(Command* command)
+{
+ int nredo = commands.size() - nundo;
+
+ while (nredo) {
+ delete commands.removeIndex(commands.size()-1);
+ nredo--;
+ }
+
+ if (nundo < 100) {
+ nundo++;
+ }
+ else {
+ delete commands.removeIndex(0);
+ }
+
+ command->Do();
+ commands.append(command);
+}
+
+int
+MagicDoc::NumUndo() const
+{
+ return nundo;
+}
+
+int
+MagicDoc::NumRedo() const
+{
+ return commands.size() - nundo;
+}
+
+const char*
+MagicDoc::GetUndoName() const
+{
+ if (nundo > 0 && nundo <= commands.size())
+ return commands[nundo-1]->Name();
+ else
+ return "";
+}
+
+const char*
+MagicDoc::GetRedoName() const
+{
+ if (nundo >= 0 && nundo < commands.size())
+ return commands[nundo]->Name();
+ else
+ return "";
+}
+
+void
+MagicDoc::Undo()
+{
+ if (nundo > 0 && nundo <= commands.size())
+ commands[--nundo]->Undo();
+}
+
+void
+MagicDoc::Redo()
+{
+ if (nundo >= 0 && nundo < commands.size())
+ commands[nundo++]->Do();
+}
+
+// +--------------------------------------------------------------------+
+
+BOOL MagicDoc::OnNewDocument()
+{
+ if (!CDocument::OnNewDocument())
+ return FALSE;
+
+ InitCommandStack();
+
+ if (solid) delete solid;
+ solid = new Solid;
+
+ if (selection)
+ selection->Clear();
+
+ return TRUE;
+}
+
+// +--------------------------------------------------------------------+
+
+void MagicDoc::Serialize(CArchive& ar)
+{
+}
+
+// +--------------------------------------------------------------------+
+
+#ifdef _DEBUG
+void MagicDoc::AssertValid() const
+{
+ CDocument::AssertValid();
+}
+
+void MagicDoc::Dump(CDumpContext& dc) const
+{
+ CDocument::Dump(dc);
+}
+#endif //_DEBUG
+
+// +--------------------------------------------------------------------+
+
+BOOL MagicDoc::OnSaveDocument(LPCTSTR path_name)
+{
+ SetModifiedFlag(FALSE);
+
+ ModelFileMAG mod_file(path_name);
+ mod_file.Save(solid->GetModel());
+
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ return TRUE;
+}
+
+BOOL MagicDoc::OnOpenDocument(LPCTSTR path_name)
+{
+ FILE* fp = fopen(path_name, "rb");
+ if (!fp) {
+ ::MessageBox(0, "Open Failed: could not open file", "ERROR", MB_OK);
+ return FALSE;
+ }
+
+ int version = 1;
+ char file_id[5];
+ fread(file_id, 4, 1, fp);
+ file_id[4] = '\0';
+ fclose(fp);
+
+ if (strncmp(file_id, "MAG", 3)) {
+ ::MessageBox(0, "Open Failed: Invalid file type", "ERROR", MB_OK);
+ return FALSE;
+ }
+
+ switch (file_id[3]) {
+ case '6': version = 6; break;
+ case '5': version = 5; break;
+ default: version = 0; break;
+ }
+
+ if (version < 5 || version > 6) {
+ ::MessageBox(0, "Open Failed: Unsupported version", "ERROR", MB_OK);
+ return FALSE;
+ }
+
+ DeleteContents();
+
+ ModelFileMAG mod_file(path_name);
+ solid->Load(&mod_file);
+ solid->CreateShadows();
+
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ return TRUE;
+}
+
+bool
+MagicDoc::ImportFile(LPCTSTR path_name)
+{
+ if (strstr(path_name, ".obj") || strstr(path_name, ".OBJ")) {
+ ModelFileOBJ obj_file(path_name);
+
+ if (solid->GetModel()) {
+ Solid* s = new Solid;
+
+ if (s->Load(&obj_file)) {
+ // todo: insert command here
+ Model* orig = solid->GetModel();
+ Model* imported = s->GetModel();
+
+ orig->GetMaterials().append(imported->GetMaterials());
+ orig->GetSurfaces().append(imported->GetSurfaces());
+ orig->OptimizeMaterials();
+
+ imported->GetMaterials().clear();
+ imported->GetSurfaces().clear();
+
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ delete s;
+ return true;
+ }
+
+ delete s;
+ }
+ else {
+ if (solid->Load(&obj_file)) {
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ if (strstr(path_name, ".3ds") || strstr(path_name, ".3DS")) {
+ ModelFile3DS model_file(path_name);
+
+ if (solid->GetModel()) {
+ Solid* s = new Solid;
+
+ if (s->Load(&model_file)) {
+ // todo: insert command here
+ Model* orig = solid->GetModel();
+ Model* imported = s->GetModel();
+
+ orig->GetMaterials().append(imported->GetMaterials());
+ orig->GetSurfaces().append(imported->GetSurfaces());
+ orig->OptimizeMaterials();
+
+ imported->GetMaterials().clear();
+ imported->GetSurfaces().clear();
+
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ delete s;
+ return true;
+ }
+
+ delete s;
+ }
+ else {
+ if (solid->Load(&model_file)) {
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ FILE* fp = fopen(path_name, "rb");
+ if (!fp) {
+ ::MessageBox(0, "Import Failed: could not open file", "ERROR", MB_OK);
+ return false;
+ }
+
+ int version = 1;
+ char file_id[5];
+ fread(file_id, 4, 1, fp);
+ file_id[4] = '\0';
+ fclose(fp);
+
+ if (strncmp(file_id, "MAG", 3)) {
+ ::MessageBox(0, "Open Failed: Invalid file type", "ERROR", MB_OK);
+ return false;
+ }
+
+ switch (file_id[3]) {
+ case '6': version = 6; break;
+ case '5': version = 5; break;
+ default: version = 0; break;
+ }
+
+ if (version < 5 || version > 6) {
+ ::MessageBox(0, "Open Failed: Unsupported version", "ERROR", MB_OK);
+ return false;
+ }
+
+ ModelFileMAG mag_file(path_name);
+
+ if (solid->GetModel()) {
+ Solid* s = new Solid;
+ if (s->Load(&mag_file)) {
+ // todo: insert command here
+ Model* orig = solid->GetModel();
+ Model* imported = s->GetModel();
+
+ orig->GetMaterials().append(imported->GetMaterials());
+ orig->GetSurfaces().append(imported->GetSurfaces());
+ orig->OptimizeMaterials();
+
+ imported->GetMaterials().clear();
+ imported->GetSurfaces().clear();
+
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ delete s;
+ return true;
+ }
+
+ delete s;
+ }
+ else {
+ InitCommandStack();
+
+ if (solid->Load(&mag_file)) {
+ SetModifiedFlag(FALSE);
+ UpdateAllViews(NULL);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+MagicDoc::ExportFile(LPCTSTR path_name)
+{
+ if (!solid->GetModel())
+ return false;
+
+ if (strstr(path_name, ".obj") || strstr(path_name, ".OBJ")) {
+ ModelFileOBJ obj_file(path_name);
+ obj_file.Save(solid->GetModel());
+ return true;
+ }
+
+ if (strstr(path_name, ".3ds") || strstr(path_name, ".3DS")) {
+ return false;
+ }
+
+ if (strstr(path_name, ".mag") || strstr(path_name, ".MAG")) {
+ ModelFileMAG mod_file(path_name);
+ mod_file.Save(solid->GetModel());
+ return true;
+ }
+
+ return false;
+}
+
+// +--------------------------------------------------------------------+
+
+int LoadBuffer(const char* filename, BYTE*& buf, bool null_terminate)
+{
+ buf = 0;
+
+ FILE* f = ::fopen(filename, "rb");
+
+ if (f) {
+ ::fseek(f, 0, SEEK_END);
+ int len = ftell(f);
+ ::fseek(f, 0, SEEK_SET);
+
+ if (null_terminate) {
+ buf = new BYTE[len+1];
+ if (buf)
+ buf[len] = 0;
+ }
+
+ else {
+ buf = new BYTE[len];
+ }
+
+ if (buf)
+ ::fread(buf, len, 1, f);
+
+ ::fclose(f);
+
+ return len;
+ }
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+void MagicDoc::DeleteContents()
+{
+ CDocument::DeleteContents();
+ InitCommandStack();
+
+ if (solid) {
+ delete solid;
+ solid = new Solid;
+ }
+
+ if (selection)
+ selection->Clear();
+}
+
+// +--------------------------------------------------------------------+
+
+int LoadTexture(const char* fname, Bitmap*& bitmap, int type)
+{
+ int result = 0;
+
+ if (!fname || !*fname)
+ return result;
+
+ bitmap = Bitmap::CheckCache(fname);
+
+ if (!bitmap) {
+ bool pcx_file = strstr(fname, ".pcx") || strstr(fname, ".PCX");
+
+ // handle PCX formats:
+ if (pcx_file) {
+ PcxImage pcx;
+
+ if (pcx.Load((char*) fname) == PCX_OK) {
+ bitmap = new Bitmap;
+
+ // 32-bit image
+ if (pcx.himap) {
+ bitmap->CopyHighColorImage(pcx.width, pcx.height, pcx.himap);
+ }
+
+ // 8-bit image, check for 32-bit image as well
+ else if (pcx.bitmap) {
+ bitmap->CopyImage(pcx.width, pcx.height, pcx.bitmap);
+
+ char tmp[256];
+ int len = strlen(fname);
+ bool found = false;
+
+ ZeroMemory(tmp, sizeof(tmp));
+
+ for (int i = 0; i < len && !found; i++) {
+ if (strstr(fname + i, ".pcx") == (fname+i)) {
+ found = true;
+ }
+ else {
+ tmp[i] = fname[i];
+ }
+ }
+
+ if (found) {
+ strcat_s(tmp, "+.pcx");
+ if (pcx.Load(tmp) == PCX_OK && pcx.himap != 0) {
+ bitmap->CopyHighColorImage(pcx.width, pcx.height, pcx.himap);
+ }
+ }
+ }
+ }
+ }
+
+ // for all other formats, use D3DX:
+ else {
+ D3DXImage d3dx;
+ if (d3dx.Load((char*) fname)) {
+ bitmap = new Bitmap;
+ bitmap->CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image);
+ }
+ }
+
+ if (bitmap) {
+ LoadAlpha(fname, *bitmap, type);
+
+ bitmap->SetFilename(fname);
+ bitmap->SetType(type);
+ bitmap->MakeTexture();
+
+ Bitmap::AddToCache(bitmap);
+ }
+ }
+
+ return result;
+}
+
+int LoadAlpha(const char* name, Bitmap& bitmap, int type)
+{
+ PcxImage pcx;
+ D3DXImage d3dx;
+ bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX");
+ bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP");
+ bool jpg_file = strstr(name, ".jpg") || strstr(name, ".JPG");
+ bool png_file = strstr(name, ".png") || strstr(name, ".PNG");
+ bool tga_file = strstr(name, ".tga") || strstr(name, ".TGA");
+
+ // check for an associated alpha-only (grayscale) bitmap:
+ char filename[256];
+ strcpy_s(filename, name);
+
+ char* dot = strrchr(filename, '.');
+ if (dot && pcx_file)
+ strcpy(dot, "@.pcx");
+ else if (dot && bmp_file)
+ strcpy(dot, "@.bmp");
+ else if (dot && jpg_file)
+ strcpy(dot, "@.jpg");
+ else if (dot && png_file)
+ strcpy(dot, "@.png");
+ else if (dot && tga_file)
+ strcpy(dot, "@.tga");
+ else
+ return 0;
+
+ // first try to load from current directory:
+ bool loaded = false;
+
+ if (pcx_file)
+ loaded = pcx.Load(filename) == PCX_OK;
+
+ else
+ loaded = d3dx.Load(filename);
+
+ // now copy the alpha values into the bitmap:
+ if (loaded) {
+ if (pcx_file && pcx.bitmap) {
+ bitmap.CopyAlphaImage(pcx.width, pcx.height, pcx.bitmap);
+ }
+ else if (pcx_file && pcx.himap) {
+ bitmap.CopyAlphaRedChannel(pcx.width, pcx.height, pcx.himap);
+ }
+ else if (d3dx.image) {
+ bitmap.CopyAlphaRedChannel(d3dx.width, d3dx.height, d3dx.image);
+ }
+ }
+
+ return 0;
+}
+
+
+void MagicDoc::OnSurfaceOptimize()
+{
+ if (solid && solid->GetModel()) {
+ solid->GetModel()->OptimizeMesh();
+ solid->InvalidateSurfaceData();
+ solid->InvalidateSegmentData();
+ }
+}
+
+void MagicDoc::OnUpdateSurfaceOptimize(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(solid && solid->GetModel());
+}
+
+void MagicDoc::OnSurfaceExplode()
+{
+ if (solid && solid->GetModel()) {
+ solid->GetModel()->ExplodeMesh();
+ solid->InvalidateSurfaceData();
+ solid->InvalidateSegmentData();
+ }
+}
+
+void MagicDoc::OnUpdateSurfaceExplode(CCmdUI* pCmdUI)
+{
+ pCmdUI->Enable(solid && solid->GetModel());
+}