// TextureDoc.cpp : implementation file // #include "stdafx.h" #include "Multitron.h" #include "TextureDoc.h" #include "MultitronDoc.h" #include "MainFrm.h" #include #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; }