/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
// MegacellDialog.cpp : implementation file
//
#include
#include "stdafx.h"
#include "editor.h"
#include "MegacellDialog.h"
#include "WorldTexturesDialog.h"
#include "megapage.h"
#include "megacell.h"
#include "manage.h"
#include "gametexture.h"
#include "vclip.h"
#include "texpage.h"
#include "bitmap.h"
#include "ddio.h"
#include "mem.h"
#include "EditLineDialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static megacell m_CopyMegacell;
/////////////////////////////////////////////////////////////////////////////
// CMegacellDialog dialog
CMegacellDialog::CMegacellDialog(CWnd *pParent /*=NULL*/) : CDialog(CMegacellDialog::IDD, pParent) {
//{{AFX_DATA_INIT(CMegacellDialog)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_TexStart = 0;
m_TexListPos = 0;
m_RedrawListbox = 0;
m_TexPageLen = 0;
m_CheckForTextureList = 0;
m_CheckX = m_CheckY = 0;
memset(&m_CopyMegacell, 0, sizeof(megacell));
}
void CMegacellDialog::DoDataExchange(CDataExchange *pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMegacellDialog)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMegacellDialog, CDialog)
//{{AFX_MSG_MAP(CMegacellDialog)
ON_BN_CLICKED(IDC_NEW_MEGACELL, OnNewMegacell)
ON_BN_CLICKED(IDC_LOCK_MEGACELL, OnLockMegacell)
ON_BN_CLICKED(IDC_CHECKIN_MEGACELL, OnCheckinMegacell)
ON_BN_CLICKED(IDC_DELETE_MEGACELL, OnDeleteMegacell)
ON_BN_CLICKED(IDC_NEXT_MEGACELL, OnNextMegacell)
ON_BN_CLICKED(IDC_PREVIOUS_MEGACELL, OnPreviousMegacell)
ON_CBN_SELENDOK(IDC_MEGACELL_PULLDOWN, OnSelendokMegacellPulldown)
ON_BN_CLICKED(IDC_MEGACELLS_OUT, OnMegacellsOut)
ON_EN_KILLFOCUS(IDC_MEGACELL_NAME_EDIT, OnKillfocusMegacellNameEdit)
ON_EN_KILLFOCUS(IDC_MEGA_WIDTH_EDIT, OnKillfocusMegaWidthEdit)
ON_EN_KILLFOCUS(IDC_MEGA_HEIGHT_EDIT, OnKillfocusMegaHeightEdit)
ON_WM_LBUTTONDOWN()
ON_WM_VSCROLL()
ON_WM_PAINT()
ON_BN_CLICKED(IDC_REMAP_MEGACELL, OnRemapMegacell)
ON_BN_CLICKED(IDC_ROTATE_MEGACELL, OnRotateMegacell)
ON_BN_CLICKED(IDC_COPY_MEGACELL, OnCopyMegacell)
ON_BN_CLICKED(IDC_PASTE_MEGACELL, OnPasteMegacell)
ON_BN_CLICKED(IDC_IMPORT_TINY, OnImportTiny)
ON_WM_HELPINFO()
ON_BN_CLICKED(IDC_IMPORT_SKY, OnImportSky)
ON_BN_CLICKED(IDC_IMPORT_SKY_BAND, OnImportSkyBand)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMegacellDialog message handlers
void CMegacellDialog::OnNewMegacell() {
char filename[255];
char cur_name[100];
int cell_handle;
int c = 1, finding_name = 1;
if (!Network_up) {
OutrageMessageBox("Sorry babe, the network is down. This action is a no-no.\n");
return;
}
// Get megacell name
CEditLineDialog dlg("Enter megacell name", this);
int ret = dlg.DoModal();
if (ret == IDCANCEL)
return;
strcpy(filename, (char *)dlg.GetText());
// Alloc a megacell and give a name not already taken by some other cell
cell_handle = AllocMegacell();
while (finding_name) {
sprintf(cur_name, "%s%d", filename, c);
if (FindMegacellName(cur_name) != -1)
c++;
else
finding_name = 0;
}
strcpy(Megacells[cell_handle].name, cur_name);
mng_AllocTrackLock(cur_name, PAGETYPE_MEGACELL);
D3EditState.current_megacell = cell_handle;
UpdateDialog();
}
void CMegacellDialog::OnLockMegacell() {
int n = D3EditState.current_megacell;
mngs_Pagelock temp_pl;
mngs_megacell_page megacellpage;
int r;
if (Num_megacells < 1)
return;
if (!mng_MakeLocker())
return;
// Make sure it can be locked
strcpy(temp_pl.name, Megacells[n].name);
temp_pl.pagetype = PAGETYPE_MEGACELL;
r = mng_CheckIfPageLocked(&temp_pl);
if (r == 2) {
int answer;
answer = OutrageMessageBox(MBOX_YESNO, "This page is not even in the table file, or the database maybe corrupt. "
"Override to 'Unlocked'? (Select NO if you don't know what you're doing)");
if (answer == IDYES) {
strcpy(temp_pl.holder, "UNLOCKED");
if (!mng_ReplacePagelock(temp_pl.name, &temp_pl))
MessageBox(ErrorString, "Error!");
}
} else if (r < 0)
OutrageMessageBox(ErrorString);
else if (r == 1)
OutrageMessageBox(InfoString);
else {
// Everything is ok. Tell the network we're locking it and get a copy to
// our local drive
strcpy(temp_pl.holder, TableUser);
if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) {
MessageBox(ErrorString, "Error!");
mng_EraseLocker();
return;
} else {
// Search thru the net pagefile and get a new copy in RAM in case anyone
// changed it since we started the editor
if (mng_FindSpecificMegacellPage(temp_pl.name, &megacellpage, 0)) {
if (mng_AssignMegacellPageToMegacell(&megacellpage, n)) {
if (!mng_ReplacePage(Megacells[n].name, Megacells[n].name, n, PAGETYPE_MEGACELL, 1)) {
OutrageMessageBox("There was problem writing that page locally!");
mng_EraseLocker();
return;
}
OutrageMessageBox("Megacell locked.");
} else
OutrageMessageBox("There was a problem loading this megacell. You might encounter problems in dealing with "
"it. Good luck!");
mng_AllocTrackLock(Megacells[n].name, PAGETYPE_MEGACELL);
UpdateDialog();
} else
OutrageMessageBox("Couldn't find that megacell in the table file!");
}
}
mng_EraseLocker();
}
void CMegacellDialog::OnCheckinMegacell() {
int n = D3EditState.current_megacell;
mngs_Pagelock temp_pl;
int r;
int i;
if (Num_megacells < 1)
return;
if (!mng_MakeLocker())
return;
// Make sure we own this megacell
strcpy(temp_pl.name, Megacells[n].name);
temp_pl.pagetype = PAGETYPE_MEGACELL;
r = mng_CheckIfPageOwned(&temp_pl, TableUser);
if (r < 0)
OutrageMessageBox(ErrorString);
else if (r == 0)
OutrageMessageBox(InfoString);
else {
// Change the pagelock state to UNLOCKED
strcpy(temp_pl.holder, "UNLOCKED");
if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) {
MessageBox(ErrorString, "Error!");
mng_EraseLocker();
return;
} else {
// Now actually replace the copy on the net with our local one
int answer = MessageBox("Do you wish to check in all the textures associated with this megacell (if any)?",
Megacells[n].name, MB_YESNO);
if (answer == IDYES) {
// Check in all these textures
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++) {
int mx = i % MAX_MEGACELL_WIDTH;
int my = i / MAX_MEGACELL_WIDTH;
if (mx >= Megacells[n].width || my >= Megacells[n].height)
continue;
int index = Megacells[n].texture_handles[i];
if (!GameTextures[index].used || index == 0)
continue;
int tl;
if ((tl = mng_FindTrackLock(GameTextures[index].name, PAGETYPE_TEXTURE)) != -1)
CheckinTexture(index, tl);
}
}
if (!mng_ReplacePage(Megacells[n].name, Megacells[n].name, n, PAGETYPE_MEGACELL, 0))
OutrageMessageBox(ErrorString);
else {
OutrageMessageBox("Megacell checked in.");
// Delete it from local pagefile if its there
int dret = mng_DeletePage(Megacells[n].name, PAGETYPE_MEGACELL, 1);
ASSERT(dret == 1);
mng_EraseLocker();
// Free the tracklock
int p = mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL);
ASSERT(p != -1);
mng_FreeTrackLock(p);
UpdateDialog();
}
}
}
}
extern int TlockState;
extern int AutoChecking;
void CMegacellDialog::OnDeleteMegacell() {
int answer, tl;
mngs_Pagelock pl;
CWorldTexturesDialog texdlg;
int n = D3EditState.current_megacell;
int i;
if (Num_megacells < 1)
return;
// Check to see if we even have it locked
if ((tl = mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL)) == -1) {
OutrageMessageBox("This megacell is not yours to delete. Lock first.");
return;
}
// Make sure its to be deleted
answer = MessageBox("Are you sure you want to delete this megacell?", Megacells[n].name, MB_YESNO);
if (answer == IDNO)
return;
answer =
MessageBox("Do you wish to delete all the textures associated with this megacell?", Megacells[n].name, MB_YESNO);
if (!mng_MakeLocker())
return;
strcpy(pl.name, Megacells[n].name);
pl.pagetype = PAGETYPE_MEGACELL;
// Check to see if this is a local megacell only. If so, only delete it locally
if (mng_CheckIfPageOwned(&pl, TableUser) != 1) {
mng_FreeTrackLock(tl);
if (!mng_DeletePage(Megacells[n].name, PAGETYPE_MEGACELL, 1)) {
mprintf(0, ErrorString);
Int3();
}
} else // if its network, delete it from both the net and local drives
{
mng_FreeTrackLock(tl);
mng_DeletePage(Megacells[n].name, PAGETYPE_MEGACELL, 0);
mng_DeletePage(Megacells[n].name, PAGETYPE_MEGACELL, 1);
mng_DeletePagelock(Megacells[n].name, PAGETYPE_MEGACELL);
}
// Advance to the next megacell
D3EditState.current_megacell = GetNextMegacell(n);
// Now delete those textures if need be
if (answer == IDYES) {
uint8_t can_delete[MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT];
memset(can_delete, 0, MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT);
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++) {
int mx = i % MAX_MEGACELL_WIDTH;
int my = i / MAX_MEGACELL_WIDTH;
if (mx >= Megacells[n].width || my >= Megacells[n].height)
continue;
int index = Megacells[n].texture_handles[i];
if (index == 0 || index == 1)
continue;
int tl;
tl = mng_FindTrackLock(GameTextures[index].name, PAGETYPE_TEXTURE);
if (tl == -1) {
// We need to lock this texture
AutoChecking = 2;
D3EditState.texdlg_texture = index;
texdlg.OnLock();
if (!TlockState)
continue;
tl = mng_FindTrackLock(GameTextures[index].name, PAGETYPE_TEXTURE);
can_delete[i] = 1;
} else {
can_delete[i] = 1;
}
}
int num_to_delete = 0;
char *texnames[MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT];
uint16_t texindices[MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT];
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++) {
texnames[i] = (char *)mem_malloc(PAGENAME_LEN);
ASSERT(texnames[i]);
if (!can_delete[i])
continue;
int index = Megacells[n].texture_handles[i];
int duplicate = 0;
for (int k = 0; k < num_to_delete && !duplicate; k++) {
if (texindices[k] == index)
duplicate = 1;
}
if (duplicate)
continue;
strcpy(texnames[num_to_delete], GameTextures[index].name);
texindices[num_to_delete] = index;
num_to_delete++;
}
mng_DeleteTexPageSeries(texnames, num_to_delete, 0);
mng_DeleteTexPageSeries(texnames, num_to_delete, 1);
mng_DeletePagelockSeries(texnames, num_to_delete, PAGETYPE_TEXTURE);
// Now free all pagelocks and textures
for (i = 0; i < num_to_delete; i++) {
tl = mng_FindTrackLock(GameTextures[texindices[i]].name, PAGETYPE_TEXTURE);
if (tl != -1)
mng_FreeTrackLock(tl);
if (GameTextures[texindices[i]].flags & TF_ANIMATED)
FreeVClip(GameTextures[texindices[i]].bm_handle);
else
bm_FreeBitmap(GameTextures[texindices[i]].bm_handle);
FreeTexture(texindices[i]);
}
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++)
mem_free(texnames[i]);
}
AutoChecking = 0;
FreeMegacell(n);
mng_EraseLocker();
OutrageMessageBox("Megacell deleted.");
UpdateDialog();
}
void CMegacellDialog::OnNextMegacell() {
D3EditState.current_megacell = GetNextMegacell(D3EditState.current_megacell);
UpdateDialog();
}
void CMegacellDialog::OnPreviousMegacell() {
D3EditState.current_megacell = GetPrevMegacell(D3EditState.current_megacell);
UpdateDialog();
}
void CMegacellDialog::OnSelendokMegacellPulldown() {
int i, cur;
char name[200];
cur = SendDlgItemMessage(IDC_MEGACELL_PULLDOWN, CB_GETCURSEL, 0, 0);
SendDlgItemMessage(IDC_MEGACELL_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name);
i = FindMegacellName(name);
if (i == -1) {
mprintf(0, "Possible corrupted megacell list, but probably nothing.");
UpdateDialog();
}
D3EditState.current_megacell = i;
UpdateDialog();
}
void CMegacellDialog::OnMegacellsOut() {}
void CMegacellDialog::OnKillfocusMegacellNameEdit() {
CEdit *ebox;
int n = D3EditState.current_megacell;
char name[PAGENAME_LEN];
mngs_Pagelock pl;
// Make sure we have this megacell locked, if not reset name and bail
int p = mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL);
if (p == -1) {
OutrageMessageBox("You must lock this megacell if you wish to change its name.");
CEdit *ebox = (CEdit *)GetDlgItem(IDC_MEGACELL_NAME_EDIT);
ebox->SetWindowText(Megacells[n].name);
return;
}
// Get the new name
ebox = (CEdit *)GetDlgItem(IDC_MEGACELL_NAME_EDIT);
ebox->GetWindowText(name, PAGENAME_LEN);
// Check to see if there is already a cell with this name. If so, reset and bail
if (FindMegacellName(name) != -1) {
OutrageMessageBox("There already is a cell with that name...choose another name.");
CEdit *ebox = (CEdit *)GetDlgItem(IDC_MEGACELL_NAME_EDIT);
ebox->SetWindowText(Megacells[n].name);
return;
}
if (!mng_MakeLocker())
return;
// Check to see if this page exists on the network. If so, we have to
// rename it so we can prevent havoc
strcpy(pl.name, Megacells[n].name);
pl.pagetype = PAGETYPE_MEGACELL;
int ret = mng_CheckIfPageOwned(&pl, TableUser);
if (ret < 0)
OutrageMessageBox(ErrorString);
else if (ret == 1)
mng_RenamePage(Megacells[n].name, name, PAGETYPE_MEGACELL);
else if (ret == 2) {
// This page has never been checked in, replace only local copy
char oldname[PAGENAME_LEN];
strcpy(oldname, Megacells[n].name);
strcpy(Megacells[n].name, name);
mng_ReplacePage(oldname, Megacells[n].name, n, PAGETYPE_MEGACELL, 1);
} else if (ret == 0) {
OutrageMessageBox("You don't own this page. Get Jason now!");
mng_FreeTrackLock(p);
return;
}
// Finally, copy our new name to the appropriate arrays
strcpy(GlobalTrackLocks[p].name, name);
strcpy(Megacells[n].name, name);
mng_EraseLocker();
UpdateDialog();
}
void CMegacellDialog::OnKillfocusMegaWidthEdit() {
CEdit *ebox;
char name[20];
int n = D3EditState.current_megacell;
int width;
ebox = (CEdit *)GetDlgItem(IDC_MEGA_WIDTH_EDIT);
ebox->GetWindowText(name, 20);
width = atoi(name);
if (width < 0)
width = 2;
if (width > 8)
width = 8;
Megacells[n].width = width;
UpdateDialog();
}
void CMegacellDialog::OnKillfocusMegaHeightEdit() {
CEdit *ebox;
char name[20];
int n = D3EditState.current_megacell;
int height;
ebox = (CEdit *)GetDlgItem(IDC_MEGA_HEIGHT_EDIT);
ebox->GetWindowText(name, 20);
height = atoi(name);
if (height < 0)
height = 2;
if (height > 8)
height = 8;
Megacells[n].height = height;
UpdateDialog();
}
BOOL CMegacellDialog::DestroyWindow() {
SaveMegacellsOnClose();
return CDialog::DestroyWindow();
}
BOOL CMegacellDialog::OnInitDialog() {
static int first_time = 1;
CDialog::OnInitDialog();
mngs_megacell_page megacellpage;
// Remap all megacells
if (Network_up && first_time) {
for (int i = 0; i < MAX_MEGACELLS; i++) {
if (Megacells[i].used) {
if (Megacells[i].texture_handles[0] > 0)
continue;
if (mng_FindSpecificMegacellPage(Megacells[i].name, &megacellpage, 1)) {
if (!mng_AssignMegacellPageToMegacell(&megacellpage, i))
Int3(); // Get Jason
} else if (mng_FindSpecificMegacellPage(Megacells[i].name, &megacellpage, 0)) {
if (!mng_AssignMegacellPageToMegacell(&megacellpage, i))
Int3(); // Get Jason
}
}
}
}
first_time = 0;
UpdateDialog();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CMegacellDialog::SaveMegacellsOnClose() {
int i, t;
if (!Network_up)
return; // don't save a damn thing if the network is down
for (i = 0; i < MAX_TRACKLOCKS; i++) {
if (GlobalTrackLocks[i].used == 1 && GlobalTrackLocks[i].pagetype == PAGETYPE_TEXTURE) {
t = FindTextureName(GlobalTrackLocks[i].name);
ASSERT(t != -1);
mng_ReplacePage(GameTextures[t].name, GameTextures[t].name, t, PAGETYPE_TEXTURE, 1);
}
if (GlobalTrackLocks[i].used == 1 && GlobalTrackLocks[i].pagetype == PAGETYPE_MEGACELL) {
t = FindMegacellName(GlobalTrackLocks[i].name);
mng_DeletePage(Megacells[t].name, PAGETYPE_MEGACELL, 1);
ASSERT(t != -1);
mng_ReplacePage(Megacells[t].name, Megacells[t].name, t, PAGETYPE_MEGACELL, 1);
}
}
}
void CMegacellDialog::OnLButtonDown(UINT nFlags, CPoint point) {
m_CheckForTextureList = 1;
m_CheckX = point.x;
m_CheckY = point.y;
CDialog::OnLButtonDown(nFlags, point);
UpdateDialog();
CDialog::OnLButtonDown(nFlags, point);
}
void CMegacellDialog::UpdateDialog() {
CEdit *ebox;
CButton *bbox;
int n = D3EditState.current_megacell;
char str[50];
UpdateTextureView();
if (Num_megacells < 1) {
bbox = (CButton *)GetDlgItem(IDC_NEXT_MEGACELL);
bbox->EnableWindow(FALSE);
bbox = (CButton *)GetDlgItem(IDC_PREVIOUS_MEGACELL);
bbox->EnableWindow(FALSE);
m_CheckForTextureList = 0;
return;
} else {
bbox = (CButton *)GetDlgItem(IDC_NEXT_MEGACELL);
bbox->EnableWindow(TRUE);
bbox = (CButton *)GetDlgItem(IDC_PREVIOUS_MEGACELL);
bbox->EnableWindow(TRUE);
}
if (!Megacells[n].used)
n = D3EditState.current_megacell = GetNextMegacell(n);
ebox = (CEdit *)GetDlgItem(IDC_MEGACELL_NAME_EDIT);
ebox->SetWindowText(Megacells[n].name);
ebox = (CEdit *)GetDlgItem(IDC_MEGA_WIDTH_EDIT);
sprintf(str, "%d", Megacells[n].width);
ebox->SetWindowText(str);
ebox = (CEdit *)GetDlgItem(IDC_MEGA_HEIGHT_EDIT);
sprintf(str, "%d", Megacells[n].height);
ebox->SetWindowText(str);
bbox = (CButton *)GetDlgItem(IDC_CHECKIN_MEGACELL);
if (mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL) == -1) {
bbox->EnableWindow(FALSE);
bbox = (CButton *)GetDlgItem(IDC_LOCK_MEGACELL);
bbox->EnableWindow(TRUE);
} else {
bbox->EnableWindow(TRUE);
bbox = (CButton *)GetDlgItem(IDC_LOCK_MEGACELL);
bbox->EnableWindow(FALSE);
}
SendDlgItemMessage(IDC_MEGACELL_PULLDOWN, CB_RESETCONTENT, 0, 0);
for (int i = 0; i < MAX_MEGACELLS; i++) {
if (Megacells[i].used)
SendDlgItemMessage(IDC_MEGACELL_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)Megacells[i].name);
}
SendDlgItemMessage(IDC_MEGACELL_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)Megacells[n].name);
UpdateMegacellView();
}
#define TEXTURES_PER_ROW 4
void CMegacellDialog::UpdateTextureView() {
int n = D3EditState.texdlg_texture;
CWnd *texwnd;
RECT rect;
int x, y, bm_handle, w, h;
int update_listbox = 1;
Desktop_surf->attach_to_window((unsigned)m_hWnd);
if (1 || update_listbox) {
texwnd = GetDlgItem(IDC_TEXTURE_LISTBOX);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
w = rect.right - rect.left;
h = rect.bottom - rect.top;
int texwidth = (w - 1) / 4;
int texheight = (h - 1) / 8;
Desktop_surf->clear(rect.left, rect.top, w, h);
int texnum = m_TexStart;
int count = 0, done = 0;
while (!done) {
m_TextureSurf.create(texwidth, texheight, BPP_16);
bm_handle = GetTextureBitmap(texnum, 0);
m_TextureSurf.load(bm_handle);
x = 1 + rect.left + ((count % TEXTURES_PER_ROW) * texwidth);
y = 1 + rect.top + ((count / TEXTURES_PER_ROW) * texheight);
if (m_CheckForTextureList) {
if (m_CheckX >= x && m_CheckX <= (x + texwidth) && m_CheckY >= y && m_CheckY <= (y + texheight)) {
m_CheckForTextureList = 0;
D3EditState.texdlg_texture = texnum;
m_TextureSurf.free();
Desktop_surf->attach_to_window((unsigned)NULL);
UpdateDialog();
return;
}
}
if (texnum == n) // draw a white box if this is the current texture
{
grViewport *vport = new grViewport(&m_TextureSurf);
int x = 0, y = 0;
vport->lock();
vport->line(GR_RGB(255, 255, 255), x, y, x + vport->width() - 1, y);
vport->line(GR_RGB(255, 255, 255), x + vport->width() - 1, y, x + vport->width() - 1, y + vport->height() - 1);
vport->line(GR_RGB(255, 255, 255), x + vport->width() - 1, y + vport->height() - 1, x, y + vport->height() - 1);
vport->line(GR_RGB(255, 255, 255), x, y + vport->height() - 1, x, y);
vport->unlock();
delete vport;
}
Desktop_surf->blt(x, y, &m_TextureSurf);
texnum = GetNextTexture(texnum);
m_TextureSurf.free();
count++;
if (count == TEXTURES_PER_ROW * 8)
done = 1;
if (texnum <= m_TexStart)
done = 1;
}
// must define the vertical scroll bar dimensions
CScrollBar *bar = (CScrollBar *)GetDlgItem(IDC_TEXLIST_VERT);
SCROLLINFO si;
m_TexPageLen = (count / TEXTURES_PER_ROW) + ((count % TEXTURES_PER_ROW) ? 1 : 0);
m_TexListPos = bar->GetScrollPos();
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
si.nMin = 0;
si.nMax = (Num_textures / TEXTURES_PER_ROW) + ((Num_textures % TEXTURES_PER_ROW) ? 1 : 0) - 1;
si.nPos = m_TexListPos;
si.nPage = m_TexPageLen;
bar->SetScrollInfo(&si);
bar->ShowScrollBar(TRUE);
}
Desktop_surf->attach_to_window((unsigned)NULL);
}
void CMegacellDialog::TextureListUp(int rows) {
int old = m_TexStart;
int done = 0, count = 0;
while ((count < (TEXTURES_PER_ROW * rows)) && !done) {
m_TexStart = GetPreviousTexture(m_TexStart);
if (old <= m_TexStart) {
m_TexStart = old;
done = 1;
} else
count++;
}
m_RedrawListbox = 1;
UpdateDialog();
}
void CMegacellDialog::TextureListDown(int rows) {
int old = m_TexStart;
int done = 0, count = 0;
while ((count < (TEXTURES_PER_ROW * rows)) && !done) {
m_TexStart = GetNextTexture(m_TexStart);
if (old >= m_TexStart) {
m_TexStart = old;
done = 1;
} else
count++;
}
m_RedrawListbox = 1;
UpdateDialog();
}
void CMegacellDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) {
int id = -1, min, max;
int new_pos = 0;
if (pScrollBar) {
id = pScrollBar->GetDlgCtrlID();
pScrollBar->GetScrollRange(&min, &max);
}
switch (id) {
case IDC_TEXLIST_VERT:
// vertically scroll the texture list box
switch (nSBCode) {
case SB_LINEDOWN:
new_pos = m_TexListPos + 1;
break;
case SB_LINEUP:
new_pos = m_TexListPos - 1;
break;
case SB_THUMBPOSITION:
new_pos = nPos;
break;
case SB_THUMBTRACK:
new_pos = nPos;
break;
case SB_PAGEDOWN:
new_pos = m_TexListPos + m_TexPageLen;
break;
case SB_PAGEUP:
new_pos = m_TexListPos - m_TexPageLen;
break;
default:
new_pos = m_TexListPos;
}
if (new_pos < 0)
new_pos = 0;
if (new_pos > (max - m_TexPageLen))
new_pos = (max - m_TexPageLen) + 1;
if (new_pos != m_TexListPos) {
// ok, new_pos will be an index into the listbox, NOT the texture list.
// so we will get the number of texture rows we went up or down and change
// tex_start accordingly.
mprintf(0, "scroll new_pos = %d. original_pos = %d\n", new_pos, m_TexListPos);
if (new_pos < m_TexListPos)
TextureListUp(abs(m_TexListPos - new_pos));
if (new_pos > m_TexListPos)
TextureListDown(abs(new_pos - m_TexListPos));
m_TexListPos = new_pos;
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = m_TexListPos;
pScrollBar->SetScrollInfo(&si);
}
break;
default:
Int3(); // WHAT THE FUCK!!
}
CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}
void CMegacellDialog::UpdateMegacellView() {
int n = D3EditState.current_megacell;
CWnd *texwnd;
RECT rect;
int x, y, bm_handle, w, h;
int megawidth = Megacells[n].width;
int megaheight = Megacells[n].height;
int i, t;
Desktop_surf->attach_to_window((unsigned)m_hWnd);
texwnd = GetDlgItem(IDC_MEGACELL_VIEW);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
w = rect.right - rect.left;
h = rect.bottom - rect.top;
int texwidth = w / megawidth;
int texheight = h / megaheight;
// Don't have to clear if we're overwriting the whole area!
// if (megawidth<8 || megaheight<8)
// Desktop_surf->clear(rect.left,rect.top,w,h);
for (i = 0; i < megaheight; i++) {
for (t = 0; t < megawidth; t++) {
m_TextureSurf.create(texwidth, texheight, BPP_16);
bm_handle = GetTextureBitmap(Megacells[n].texture_handles[i * MAX_MEGACELL_WIDTH + t], 0);
m_TextureSurf.load(bm_handle);
x = 1 + rect.left + (t * texwidth);
y = 1 + rect.top + (i * texheight);
if (m_CheckForTextureList) {
if (m_CheckX >= x && m_CheckX <= (x + texwidth) && m_CheckY >= y && m_CheckY <= (y + texheight)) {
m_CheckForTextureList = 0;
Megacells[n].texture_handles[i * MAX_MEGACELL_WIDTH + t] = D3EditState.texdlg_texture;
m_TextureSurf.free();
Desktop_surf->attach_to_window((unsigned)NULL);
UpdateDialog();
return;
}
}
// Draw a separation line on the right and bottom side
{
grViewport *vport = new grViewport(&m_TextureSurf);
int x = 0, y = 0;
vport->lock();
vport->line(GR_RGB(0, 0, 0), 0, vport->height() - 1, vport->width() - 1, vport->height() - 1);
vport->line(GR_RGB(0, 0, 0), vport->width() - 1, 0, vport->width() - 1, vport->height() - 1);
vport->unlock();
delete vport;
}
Desktop_surf->blt(x, y, &m_TextureSurf);
m_TextureSurf.free();
}
}
m_CheckForTextureList = 0;
Desktop_surf->attach_to_window((unsigned)NULL);
}
void CMegacellDialog::OnPaint() {
CPaintDC dc(this); // device context for painting
UpdateDialog();
// Do not call CDialog::OnPaint() for painting messages
}
void CMegacellDialog::OnRemapMegacell() {
int n = D3EditState.current_megacell;
mngs_megacell_page megacellpage;
if (mng_FindSpecificMegacellPage(Megacells[n].name, &megacellpage, 1)) {
if (!mng_AssignMegacellPageToMegacell(&megacellpage, n))
Int3(); // Get Jason
} else if (mng_FindSpecificMegacellPage(Megacells[n].name, &megacellpage, 0)) {
if (!mng_AssignMegacellPageToMegacell(&megacellpage, n))
Int3(); // Get Jason
} else
OutrageMessageBox("This megacell was not found in the local table file.");
UpdateDialog();
}
void CMegacellDialog::OnRotateMegacell() {
int n = D3EditState.current_megacell;
int buffer[MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT];
int i;
if (!Megacells[n].used)
return;
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++)
buffer[i] = 0;
int oldwidth = Megacells[n].width;
int oldheight = Megacells[n].height;
for (i = 0; i < MAX_MEGACELL_HEIGHT; i++) {
for (int t = 0; t < MAX_MEGACELL_WIDTH; t++) {
buffer[((MAX_MEGACELL_HEIGHT - 1) - t) * MAX_MEGACELL_WIDTH + i] =
Megacells[n].texture_handles[i * MAX_MEGACELL_WIDTH + t];
}
}
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++)
Megacells[n].texture_handles[i] = buffer[i];
Megacells[n].width = oldheight;
Megacells[n].height = oldwidth;
UpdateDialog();
}
void CMegacellDialog::OnCopyMegacell() {
int n = D3EditState.current_megacell;
int i;
if (!Megacells[n].used)
return;
m_CopyMegacell.width = Megacells[n].width;
m_CopyMegacell.height = Megacells[n].height;
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++)
m_CopyMegacell.texture_handles[i] = Megacells[n].texture_handles[i];
mprintf(0, "Megacell copied.\n");
}
void CMegacellDialog::OnPasteMegacell() {
int n = D3EditState.current_megacell;
int i;
if (!Megacells[n].used)
return;
Megacells[n].width = m_CopyMegacell.width;
Megacells[n].height = m_CopyMegacell.height;
for (i = 0; i < MAX_MEGACELL_WIDTH * MAX_MEGACELL_HEIGHT; i++)
Megacells[n].texture_handles[i] = m_CopyMegacell.texture_handles[i];
UpdateDialog();
}
void CMegacellDialog::CheckinTexture(int n, int tracklock_num) {
mngs_Pagelock temp_pl;
int r;
if (!GameTextures[n].used) {
mprintf(0, "Whoa, trying to save non-used texture %s!\n", GameTextures[n].name);
return;
}
strcpy(temp_pl.name, GameTextures[n].name);
temp_pl.pagetype = PAGETYPE_TEXTURE;
r = mng_CheckIfPageOwned(&temp_pl, TableUser);
if (r < 0)
OutrageMessageBox(ErrorString);
else if (r == 0)
OutrageMessageBox(InfoString);
else {
strcpy(temp_pl.holder, "UNLOCKED");
if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) {
OutrageMessageBox(ErrorString, "Error!");
mng_EraseLocker();
return;
} else {
if (!mng_ReplacePage(GameTextures[n].name, GameTextures[n].name, n, PAGETYPE_TEXTURE, 0))
OutrageMessageBox(ErrorString);
else {
// Save this textures bitmap to the network for all
std::filesystem::path fname;
if (GameTextures[n].flags & TF_ANIMATED) {
fname = ManageGraphicsDir / GameVClips[GameTextures[n].bm_handle].name;
SaveVClip(fname, GameTextures[n].bm_handle);
fname = LocalManageGraphicsDir / GameVClips[GameTextures[n].bm_handle].name;
SaveVClip(fname, GameTextures[n].bm_handle);
} else {
fname = ManageGraphicsDir / GameBitmaps[GameTextures[n].bm_handle].name;
bm_SaveFileBitmap(fname, GameTextures[n].bm_handle);
fname = LocalManageGraphicsDir / GameBitmaps[GameTextures[n].bm_handle].name;
bm_SaveFileBitmap(fname, GameTextures[n].bm_handle);
}
mprintf(0, "%s texture checked in.\n", GameTextures[n].name);
int dret = mng_DeletePage(GameTextures[n].name, PAGETYPE_TEXTURE, 1);
ASSERT(dret == 1);
mng_FreeTrackLock(tracklock_num);
}
}
}
}
void CMegacellDialog::OnImportTiny() {
char filename[255];
int n = D3EditState.current_megacell;
int megawidth = Megacells[n].width;
int megaheight = Megacells[n].height;
int src_handle;
int count = 0;
int i, t;
if (!Network_up) {
OutrageMessageBox("Sorry babe, the network is down. This action is a no-no.\n");
return;
}
if (Num_megacells < 1) {
OutrageMessageBox("You must first create a megacell before using this feature.");
return;
}
if ((mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL)) == -1) {
OutrageMessageBox("You must have this megacell locked before you can import!");
return;
}
CString filter = "Descent III files (*.tga,*.bbm,*.lbm,*.ogf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;||";
if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
return;
// Okay, we selected a file. Lets do what needs to be done here.
src_handle = bm_AllocLoadFileBitmap(filename, 0);
if (src_handle < 0) {
OutrageMessageBox("Couldn't read that bitmap!");
return;
}
int w = bm_w(src_handle, 0);
int h = bm_h(src_handle, 0);
float width_per_cell = (float)w / (float)megawidth;
float height_per_cell = (float)h / (float)megaheight;
for (i = 0; i < megaheight; i++) {
for (t = 0; t < megawidth; t++) {
float startx = width_per_cell * t;
float starty = height_per_cell * i;
float u = startx;
float v = starty;
float du = width_per_cell / 32.0;
float dv = height_per_cell / 32.0;
int bm_handle = bm_AllocBitmap(32, 32, 0);
ASSERT(bm_handle >= 0);
uint16_t *dest_data = bm_data(bm_handle, 0);
uint16_t *src_data = bm_data(src_handle, 0);
for (int ty = 0; ty < 32; ty++, u = startx, v += dv) {
for (int tx = 0; tx < 32; tx++, u += du) {
int cu = u;
int cv = v;
uint16_t pix = src_data[cv * w + cu];
dest_data[ty * 32 + tx] = pix;
}
}
// Alloc a texture and assign it this bitmap handle
int tex_handle;
tex_handle = AllocTexture();
ASSERT(tex_handle > 0);
GameTextures[tex_handle].flags &= ~(TF_TEXTURE_TYPES);
GameTextures[tex_handle].flags |= TF_TEXTURE_32;
GameTextures[tex_handle].flags |= TF_TERRAIN;
GameTextures[tex_handle].bm_handle = bm_handle;
Megacells[n].texture_handles[i * MAX_MEGACELL_WIDTH + t] = tex_handle;
// Find a unique name for this texture
int finding_name = 1;
char cur_name[255];
while (finding_name) {
sprintf(cur_name, "%s%d", Megacells[n].name, count);
if (FindTextureName(cur_name) != -1)
count++;
else
finding_name = 0;
}
strcpy(GameTextures[tex_handle].name, cur_name);
bm_ChangeEndName(Megacells[n].name, filename);
strcpy(GameBitmaps[bm_handle].name, filename);
// Save this textures image locally
sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
GameBitmaps[GameTextures[tex_handle].bm_handle].name);
mprintf(0, "Saving bitmap %s from megacell!\n", GameBitmaps[bm_handle].name);
bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
// Allocate a track lock for this texture
mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);
}
}
bm_FreeBitmap(src_handle);
UpdateDialog();
}
BOOL CMegacellDialog::OnHelpInfo(HELPINFO *pHelpInfo) {
// TODO: Add your message handler code here and/or call default
WinHelp(HID_MEGACELLDLG, HELP_CONTEXT);
return TRUE;
// return CDialog::OnHelpInfo(pHelpInfo);
}
#define SKY_TEXTURE_SIZE 128
void CMegacellDialog::OnImportSky() {
char filename[255];
int n = D3EditState.current_megacell;
int megawidth = Megacells[n].width;
int megaheight = Megacells[n].height;
int src_handle;
int count = 0;
int i, t;
if (!Network_up) {
OutrageMessageBox("Sorry babe, the network is down. This action is a no-no.\n");
return;
}
if (Num_megacells < 1) {
OutrageMessageBox("You must first create a megacell before using this feature.");
return;
}
if (megawidth != 2 || megaheight != 2) {
OutrageMessageBox("All sky dome megacells must be 2x2 in dimensions!");
return;
}
if ((mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL)) == -1) {
OutrageMessageBox("You must have this megacell locked before you can import!");
return;
}
CString filter = "Descent III files (*.tga,*.bbm,*.lbm,*.ogf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;||";
if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
return;
// Okay, we selected a file. Lets do what needs to be done here.
src_handle = bm_AllocLoadFileBitmap(filename, 0);
if (src_handle < 0) {
OutrageMessageBox("Couldn't read that bitmap!");
return;
}
int w = bm_w(src_handle, 0);
int h = bm_h(src_handle, 0);
float width_per_cell = (float)w / (float)megawidth;
float height_per_cell = (float)h / (float)megaheight;
for (i = 0; i < megaheight; i++) {
for (t = 0; t < megawidth; t++) {
float startx = width_per_cell * t;
float starty = height_per_cell * i;
float u = startx;
float v = starty;
float du = width_per_cell / (float)SKY_TEXTURE_SIZE;
float dv = height_per_cell / (float)SKY_TEXTURE_SIZE;
int bm_handle = bm_AllocBitmap(SKY_TEXTURE_SIZE, SKY_TEXTURE_SIZE, 0);
ASSERT(bm_handle >= 0);
uint16_t *dest_data = bm_data(bm_handle, 0);
uint16_t *src_data = bm_data(src_handle, 0);
for (int ty = 0; ty < SKY_TEXTURE_SIZE; ty++, u = startx, v += dv) {
for (int tx = 0; tx < SKY_TEXTURE_SIZE; tx++, u += du) {
int cu = u;
int cv = v;
uint16_t pix = src_data[cv * w + cu];
dest_data[ty * SKY_TEXTURE_SIZE + tx] = pix;
}
}
// Alloc a texture and assign it this bitmap handle
int tex_handle;
tex_handle = AllocTexture();
ASSERT(tex_handle > 0);
GameTextures[tex_handle].flags |= TF_TERRAIN;
GameTextures[tex_handle].bm_handle = bm_handle;
Megacells[n].texture_handles[i * MAX_MEGACELL_WIDTH + t] = tex_handle;
// Find a unique name for this texture
int finding_name = 1;
char cur_name[255];
while (finding_name) {
sprintf(cur_name, "%s%d", Megacells[n].name, count);
if (FindTextureName(cur_name) != -1)
count++;
else
finding_name = 0;
}
strcpy(GameTextures[tex_handle].name, cur_name);
bm_ChangeEndName(Megacells[n].name, filename);
strcpy(GameBitmaps[bm_handle].name, filename);
// Save this textures image locally
sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
GameBitmaps[GameTextures[tex_handle].bm_handle].name);
mprintf(0, "Saving bitmap %s from megacell!\n", GameBitmaps[bm_handle].name);
bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
// Allocate a track lock for this texture
mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);
}
}
bm_FreeBitmap(src_handle);
UpdateDialog();
}
#define SKY_BAND_SIZE 64
void CMegacellDialog::OnImportSkyBand() {
char filename[255];
int n = D3EditState.current_megacell;
int megawidth = Megacells[n].width;
int megaheight = Megacells[n].height;
int src_handle;
int count = 0;
int t;
if (!Network_up) {
OutrageMessageBox("Sorry babe, the network is down. This action is a no-no.\n");
return;
}
if (Num_megacells < 1) {
OutrageMessageBox("You must first create a megacell before using this feature.");
return;
}
if (megawidth != 8 || megaheight != 2) {
OutrageMessageBox("All sky band megacells must be 8x2 in dimensions!");
return;
}
if ((mng_FindTrackLock(Megacells[n].name, PAGETYPE_MEGACELL)) == -1) {
OutrageMessageBox("You must have this megacell locked before you can import!");
return;
}
CString filter = "Descent III files (*.tga,*.bbm,*.lbm,*.ogf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;||";
if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
return;
// Okay, we selected a file. Lets do what needs to be done here.
src_handle = bm_AllocLoadFileBitmap(filename, 0);
if (src_handle < 0) {
OutrageMessageBox("Couldn't read that bitmap!");
return;
}
int w = bm_w(src_handle, 0);
int h = bm_h(src_handle, 0);
float width_per_cell = (float)w / (float)16;
float height_per_cell = (float)h / (float)1;
for (t = 0; t < 16; t++) {
float startx = width_per_cell * t;
float starty = 0;
float u = startx;
float v = starty;
float du = width_per_cell / (float)SKY_BAND_SIZE;
float dv = height_per_cell / (float)SKY_BAND_SIZE;
int bm_handle = bm_AllocBitmap(SKY_BAND_SIZE, SKY_BAND_SIZE, 0);
ASSERT(bm_handle >= 0);
uint16_t *dest_data = bm_data(bm_handle, 0);
uint16_t *src_data = bm_data(src_handle, 0);
for (int ty = 0; ty < SKY_BAND_SIZE; ty++, u = startx, v += dv) {
for (int tx = 0; tx < SKY_BAND_SIZE; tx++, u += du) {
int cu = u;
int cv = v;
uint16_t pix = src_data[cv * w + cu];
dest_data[ty * SKY_BAND_SIZE + tx] = pix;
}
}
// Alloc a texture and assign it this bitmap handle
int tex_handle;
tex_handle = AllocTexture();
ASSERT(tex_handle > 0);
GameTextures[tex_handle].flags &= ~(TF_TEXTURE_TYPES);
GameTextures[tex_handle].flags |= (TF_TERRAIN | TF_TEXTURE_64);
GameTextures[tex_handle].bm_handle = bm_handle;
int row = t / MAX_MEGACELL_WIDTH;
int column = t % MAX_MEGACELL_WIDTH;
Megacells[n].texture_handles[row * MAX_MEGACELL_WIDTH + column] = tex_handle;
// Find a unique name for this texture
int finding_name = 1;
char cur_name[255];
while (finding_name) {
sprintf(cur_name, "%s%d", Megacells[n].name, count);
if (FindTextureName(cur_name) != -1)
count++;
else
finding_name = 0;
}
strcpy(GameTextures[tex_handle].name, cur_name);
bm_ChangeEndName(Megacells[n].name, filename);
strcpy(GameBitmaps[bm_handle].name, filename);
// Save this textures image locally
sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
GameBitmaps[GameTextures[tex_handle].bm_handle].name);
mprintf(0, "Saving bitmap %s from megacell!\n", GameBitmaps[bm_handle].name);
bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
// Allocate a track lock for this texture
mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);
}
bm_FreeBitmap(src_handle);
UpdateDialog();
}