diff options
Diffstat (limited to 'Magic2/MagicDoc.cpp')
-rw-r--r-- | Magic2/MagicDoc.cpp | 639 |
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()); +} |