Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

741 lines
17 KiB
C++

// TextureDoc.cpp : implementation file
//
#include "stdafx.h"
#include "Multitron.h"
#include "TextureDoc.h"
#include "MultitronDoc.h"
#include "MainFrm.h"
#include <GameOs\TooLOS.hpp>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define FLAG_MEGATEXTURE 1
#define FLAG_TEXTUREMODIFIED 2
/////////////////////////////////////////////////////////////////////////////
// CTextureDoc
IMPLEMENT_DYNCREATE(CTextureDoc, CDocument)
CTextureDoc::CTextureDoc()
{
}
BOOL CTextureDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
return TRUE;
}
CTextureDoc::~CTextureDoc()
{
POSITION pos = m_listImages.GetHeadPosition();
while (pos)
{
Image *pImage = (Image *)m_listImages.GetNext(pos);
if (pImage)
delete pImage;
}
m_listImages.RemoveAll();
}
BEGIN_MESSAGE_MAP(CTextureDoc, CDocument)
//{{AFX_MSG_MAP(CTextureDoc)
ON_COMMAND(ID_FILE_SAVE, OnFileSave)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTextureDoc diagnostics
#ifdef _DEBUG
void CTextureDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CTextureDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CTextureDoc serialization
void CTextureDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
/*******************************************************************************
/* function name: OnOpenDocument
/* description:
/*******************************************************************************/
BOOL CTextureDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
Stuff::Page *page = (Stuff::Page *)lpszPathName;
Check_Object(page);
return TRUE;
}
/*******************************************************************************
/* function name: SetPathName
/* description: Called when a document/hint page is opened
/*******************************************************************************/
void CTextureDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
{
if (lpszPathName == NULL) {
ClearAllPages();
return;
}
Stuff::Page *page = (Stuff::Page *)lpszPathName;
Check_Object(page);
POSITION pos = m_listPages.GetHeadPosition();
while (pos)
{
Stuff::Page *oldpage = (Stuff::Page *)m_listPages.GetNext(pos);
if (page->GetName() == oldpage->GetName())
return;
}
m_listPages.AddTail((LPVOID)page);
DWORD flags = 0;
Image *pImage = NULL;
const char *entry;
if (page->GetEntry("PageSize",&entry))
{
flags |= FLAG_MEGATEXTURE;
pImage = ArrangeTextures(page);
if (pImage)
flags |= FLAG_TEXTUREMODIFIED;
}
if (NULL == pImage)
{
pImage = LoadTexture(page);
}
m_listImages.AddTail((LPVOID)pImage);
m_listFlags.AddTail((LPVOID)flags);
CString name;
if (GetCount() == 1)
{
Stuff::Page *p = GetPage(0);
name = p->GetName();
}
else
name = "Multiple Pages";
SetDefaults(page, pImage);
m_strPathName = name;
this->SetTitle(name);
}
static CDWordArray arrVerts;
CCell::CCell()
{
bSplit = false;
for (int x=0;x<4;x++)
m_arrChildren[x] = NULL;
m_image = NULL;
state = 0;
}
CCell::~CCell()
{
for (int x=0;x<4;x++)
if (m_arrChildren[x])
delete m_arrChildren[x];
}
CPoint CCell::GetPoint1()
{
DWORD dw = arrVerts[V1];
CPoint pt(LOWORD(dw),HIWORD(dw));
return pt;
}
int CCell::AddVert(int x,int y)
{
DWORD dw = MAKELONG(x,y);
return arrVerts.Add(dw);
}
int CCell::GetXDim()
{
DWORD dw1 = arrVerts[V1];
WORD x1 = LOWORD(dw1);
DWORD dw2 = arrVerts[V2];
WORD x2 = LOWORD(dw2);
return (x2-x1);
}
int CCell::GetYDim()
{
DWORD dw1 = arrVerts[V1];
WORD y1 = HIWORD(dw1);
DWORD dw2 = arrVerts[V2];
WORD y2 = HIWORD(dw2);
return (y2-y1);
}
int CCell::GetV1()
{
return V1;
}
int CCell::GetV2()
{
return V2;
}
int CCell::SetVerts(int a,int b)
{
V1 = a;
V2 = b;
return 1;
}
int CCell::CreateCell(int xSize,int ySize)
{
V1 = AddVert(0,0);
V2 = AddVert(xSize,ySize);
state = 0; // Empty
return 1;
}
CCell *CCell::FillCell(Image *image)
{
if (2==state)
return NULL;
int xSize = image->GetWidth();
int ySize = image->GetHeight();
int xdim = GetXDim();
int ydim = GetYDim();
if ((xSize==xdim)&&(ySize==ydim)&&(0==state))
{
// use this cell, fill it up totally
m_image = image;
name = image->GetFileName();
state = 2;
return this;
}
else
{
if ((xSize<=xdim) && (ySize<=ydim))
{
SplitCell(xSize,ySize);
BYTE flags = 0;
for (int x=0;x<4;x++)
{
CCell *cell = m_arrChildren[x]->FillCell(image);
flags |= (2==m_arrChildren[x]->state) << x;
if (cell)
{
if (15==flags)
state = 2;
else
state = 1;
return cell;
}
}
}
else
{
// Cannot fill this cell with something this big, unless I union with neighbors
return NULL;
}
}
return NULL;
}
int CCell::SplitCell(int xSize,int ySize)
{
if (!bSplit)
{
CPoint pt1 = GetPoint1();
int xdim = GetXDim();
int ydim = GetYDim();
int topleft = GetV1();
int bottomright = GetV2();
int middle = AddVert(pt1.x+xSize,pt1.y+ySize);
int middletop = AddVert(pt1.x+xSize,pt1.y);
int middleleft = AddVert(pt1.x,pt1.y+ySize);
int middlebottom = AddVert(pt1.x+xSize,pt1.y+ydim);
int middleright = AddVert(pt1.x+xdim,pt1.y+ySize);
CCell *cell = m_arrChildren[0] = new CCell;
cell->SetVerts(topleft,middle);
cell = m_arrChildren[1] = new CCell;
cell->SetVerts(middletop,middleright);
cell = m_arrChildren[2] = new CCell;
cell->SetVerts(middleleft,middlebottom);
cell = m_arrChildren[3] = new CCell;
cell->SetVerts(middle,bottomright);
bSplit = true;
}
return 4;
}
/*******************************************************************************
/* function name: BuildMegaTexture
/* description:
/*******************************************************************************/
int CTextureDoc::BuildMegaTexture(CCell *pCell,Image *pImage)
{
if (pCell)
{
if (pCell->m_image)
{
CPoint pt = pCell->GetPoint1();
pImage->Blt(*(pCell->m_image),pt.x,pt.y);
}
for (int x=0;x<4;x++)
BuildMegaTexture(pCell->m_arrChildren[x],pImage);
}
return 1;
}
/*******************************************************************************
/* function name: ConstructPage
/* description:
/*******************************************************************************/
int CTextureDoc::ConstructPage(CCell *pCell,Stuff::Page *page)
{
if (NULL == pCell)
return 0;
if (pCell->m_image)
// Acutally m_image is already deleted by now so I can't use it
{
char name[MAX_PATH];
_splitpath(pCell->name,NULL,NULL,name,NULL);
CString str;
CPoint pt = pCell->GetPoint1();
str.Format("%d %d",pt.x,pt.y);
page->SetEntry(name,str);
}
int count = 1;
for (int x=0;x<4;x++)
{
count += ConstructPage(pCell->m_arrChildren[x],page);
}
return count;
}
/*******************************************************************************
/* function name: ArrangeTextures
/* description:
/*******************************************************************************/
Image *CTextureDoc::ArrangeTextures(Stuff::Page *mega_page)
{
CMapStringToPtr mapImages;
int xSize=0,ySize=0;
Stuff::Page::NoteIterator *notes = mega_page->MakeNoteIterator();
Stuff::Note *note;
CCell *pCell = NULL;
int minBpp = 0;
while (NULL != (note=notes->ReadAndNext()))
{
const char *entry;
note->GetEntry(&entry);
if (stricmp(note->GetName(),"PageSize")==0)
{
sscanf(entry,"%d %d",&xSize,&ySize);
pCell = new CCell;
pCell->CreateCell(xSize,ySize);
}
else
{
CMultitronApp *pApp = (CMultitronApp *)AfxGetApp();
CString value;
CString name = note->GetName();
name.MakeLower();
if (!pApp->m_mapHintParams.Lookup(name,value))
{
//This is probably a valid texture name/location
const char *entry;
note->GetEntry(&entry);
int xpos,ypos;
if (2==sscanf(entry,"%d %d",&xpos,&ypos))
{
// This texture has already been created
delete pCell;
return NULL;
}
CString imagename = note->GetName();
CString path = "content\\textures\\"+imagename;
Image *image = new Image;
CString fullname = path+".png";
if (gos_DoesFileExist(fullname))
{
image->Load((char *)(LPCTSTR)fullname);
}
else
{
fullname = path+".tga";
if (gos_DoesFileExist(fullname))
{
image->Load((char *)(LPCTSTR)fullname);
}
}
int bpp = image->GetBpp();
if (bpp>minBpp)
minBpp = bpp;
RGBMask mask;
if(32 == bpp)
mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
else
mask.Set(0x00ff0000,0x0000ff00,0x000000ff);
image->MaskTo(mask);
Verify(pCell);
CCell *cell = pCell->FillCell(image);
if (NULL == cell)
{
CString str;
str.Format("Could not fit texture %s",imagename);
MessageBox(NULL,str,"Fill Cell",MB_OK);
}
mapImages[imagename] = image;
}
}
}
delete notes;
Image *mega_image = new Image;
mega_image->CreateSolid(xSize,ySize,ImgRGBColor(0xff,0xff,0xff,0xff),ITYPE_RGB,minBpp);
BuildMegaTexture(pCell,mega_image);
POSITION pos = mapImages.GetStartPosition();
while (pos)
{
CString imagename;
LPVOID lpvoid;
mapImages.GetNextAssoc(pos,imagename,lpvoid);
Image *pImage = (Image *)lpvoid;
delete pImage;
}
mapImages.RemoveAll();
ConstructPage(pCell,mega_page);
delete pCell;
if (24 == minBpp)
{
mega_page->SetEntry("Format","Solid");
}
RGBMask mask;
if(32 == minBpp)
mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
else
mask.Set(0x00ff0000,0x0000ff00,0x000000ff);
mega_image->MaskTo(mask);
return mega_image;
}
/*******************************************************************************
/* function name: LoadTexture
/* description: Load texture into an Image object
/*******************************************************************************/
Image *CTextureDoc::LoadTexture(Stuff::Page *page)
{
CString imagename = page->GetName();
const char *entry;
if (page->GetEntry("Alias",&entry))
{
imagename = entry;
}
Image *pImage = new Image;
CString path = "content\\textures\\"+imagename;
CString fullname = path+".png";
if (gos_DoesFileExist(fullname))
{
pImage->Load((char *)(LPCTSTR)fullname);
}
else
{
fullname = path+".tga";
if (gos_DoesFileExist(fullname))
{
pImage->Load((char *)(LPCTSTR)fullname);
}
else
{
delete pImage;
return NULL;
}
}
// Default Format entry to Solid if image doesn't have alpha channel
if (!page->GetEntry("Format",&entry))
{
if (pImage->GetBpp()==24)
page->SetEntry("Format","Solid");
}
RGBMask mask;
if(pImage->GetBpp()==32)
mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000);
else
mask.Set(0x00ff0000,0x0000ff00,0x000000ff);
pImage->MaskTo(mask);
return pImage;
}
/*******************************************************************************
/* function name: OnCloseDocument
/* description:
/*******************************************************************************/
void CTextureDoc::OnCloseDocument()
{
CMultitronApp *pApp = (CMultitronApp *)AfxGetApp();
POSITION pos = pApp->m_pMainDoc->GetFirstDocPosition();
while (pos)
{
CMultitronDoc *pDoc = (CMultitronDoc *)pApp->m_pMainDoc->GetNextDoc(pos);
pDoc->CloseTexture(this);
}
ClearAllPages();
CDocument::OnCloseDocument();
}
/*******************************************************************************
/* function name: ClearAllPages
/* description: Deleted all hosted hint pages and their image objects
/*******************************************************************************/
void CTextureDoc::ClearAllPages()
{
SaveModified();
m_listPages.RemoveAll();
m_listFlags.RemoveAll();
POSITION pos = m_listImages.GetHeadPosition();
while (pos)
{
Image *pImage = (Image *)m_listImages.GetNext(pos);
if (pImage)
delete pImage;
}
m_listImages.RemoveAll();
}
/*******************************************************************************
/* function name: GetCount
/* description: Return the number of hosted hint pages
/*******************************************************************************/
int CTextureDoc::GetCount()
{
return m_listPages.GetCount();
}
/*******************************************************************************
/* function name: GetPage
/* description: Return the hint page at index i
/*******************************************************************************/
Stuff::Page *CTextureDoc::GetPage(int i)
{
POSITION pos = m_listPages.FindIndex(i);
if (pos)
return (Stuff::Page *)m_listPages.GetAt(pos);
return NULL;
}
/*******************************************************************************
/* function name: GetImage
/* description: Return the texture image of hint page at index i
/*******************************************************************************/
Image *CTextureDoc::GetImage(int i)
{
POSITION pos = m_listImages.FindIndex(i);
if (pos)
return (Image *)m_listImages.GetAt(pos);
return NULL;
}
/*******************************************************************************
/* function name: SetImage
/* description: Set image object for hint page at index i
/*******************************************************************************/
void CTextureDoc::SetImage(Image* pImage, int i)
{
POSITION pos = m_listImages.FindIndex(i);
if (pos) {
Image* oldImage = (Image *)m_listImages.GetAt(pos);
m_listImages.SetAt(pos, pImage);
delete oldImage;
}
}
/*******************************************************************************
/* function name: ReplacePage
/* description: Replace hint page at index i
/*******************************************************************************/
int CTextureDoc::ReplacePage(Stuff::Page *oldpage,Stuff::Page *newpage)
{
POSITION pos = m_listPages.Find(oldpage);
if (pos)
{
m_listPages.SetAt(pos,newpage);
return 1;
}
return 0;
}
/*******************************************************************************
/* function name: SaveModified
/* description: Called when hint page is being closed without being saved
/*******************************************************************************/
BOOL CTextureDoc::SaveModified()
{
int count = 0;
POSITION pos = m_listPages.GetHeadPosition();
while (pos)
{
DWORD flags = 0;
POSITION fPos = m_listFlags.FindIndex(count);
if (fPos)
{
flags = (DWORD)m_listFlags.GetAt(fPos);
}
Stuff::Page *page = (Stuff::Page *)m_listPages.GetNext(pos);
if (flags & FLAG_MEGATEXTURE)
{
if (flags & FLAG_TEXTUREMODIFIED)
{
// Save the image?
CString str;
str.Format("Megatexture: %s created. Save Now?",page->GetName());
CString str1;
str1.Format("%s Image",page->GetName());
if (IDYES==AfxGetMainWnd()->MessageBox(str,str1,MB_YESNO))
{
CString path = "content\\textures\\";
path += page->GetName();
path += ".png";
POSITION iPos = m_listImages.FindIndex(count);
if (iPos)
{
Image *pImage = (Image *)m_listImages.GetAt(iPos);
if (pImage)
pImage->SavePng((char *)(LPCTSTR)path);
}
flags &= ~FLAG_TEXTUREMODIFIED;
m_listFlags.SetAt(fPos,(LPVOID)flags);
}
}
}
count++;
}
return CDocument::SaveModified();
}
/*******************************************************************************
/* function name: OnFileSave
/* description:
/*******************************************************************************/
void CTextureDoc::OnFileSave()
{
SaveModified();
CMultitronApp *pApp = (CMultitronApp *)AfxGetApp();
pApp->OnFileSave();
}
/*******************************************************************************
/* function name: SetDefaults
/* description: Set default values for entries in the hint page
/*******************************************************************************/
int CTextureDoc::SetDefaults(Stuff::Page *page, Image* pImage)
{
CMultitronApp *pApp = (CMultitronApp *)AfxGetApp();
POSITION pos = pApp->m_mapHintParams.GetStartPosition();
while (pos)
{
CString value,key;
pApp->m_mapHintParams.GetNextAssoc(pos,key,value);
value.MakeLower();
bool bSet = true;
const char *entry;
if (page->GetEntry(key,&entry))
{
CString strEntry(entry);
strEntry.MakeLower();
// Check that the entry is valid
if (value.Find(strEntry)>=0)
bSet = false;
}
if (bSet)
{
// Set to default
int i = value.Find('|');
if (i>0)
{
value = value.Left(i);
}
page->SetEntry(key,value);
if (stricmp(key, "format")==0 &&
pImage && !pImage->HasAlpha())
page->SetEntry("format", "solid");
CString name = page->GetName();
if (stricmp(key, "mipmap")==0 &&
name.GetAt(name.GetLength()-1) <= '9' &&
name.GetAt(name.GetLength()-1) >= '0')
page->SetEntry("mipmap", "explicit");
}
}
return 0;
}