Descent3/legacy/editor/ProceduralDialog.cpp

677 lines
17 KiB
C++
Raw Normal View History

/*
* 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 <http://www.gnu.org/licenses/>.
*/
// ProceduralDialog.cpp : implementation file
//
#include "stdafx.h"
#include "editor.h"
#include "ProceduralDialog.h"
#include "bitmap.h"
#include "gametexture.h"
#include "manage.h"
#include "texpage.h"
#include "pserror.h"
#include "mono.h"
#include "vclip.h"
#include "macros.h"
#include "texture.h"
#include "EditLineDialog.h"
#include "ddio.h"
#include "game.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define MAX_SLIDER_RANGE 255
/////////////////////////////////////////////////////////////////////////////
// CProceduralDialog dialog
CProceduralDialog::CProceduralDialog(CWnd* pParent /*=NULL*/)
: CDialog(CProceduralDialog::IDD, pParent)
{
//{{AFX_DATA_INIT(CProceduralDialog)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void CProceduralDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CProceduralDialog)
DDX_Control(pDX, IDC_FP_HEAT_SLIDER, m_heat_slider);
DDX_Control(pDX, IDC_FREQ_SLIDER, m_freq_slider);
DDX_Control(pDX, IDC_SIZE_SLIDER, m_size_slider);
DDX_Control(pDX, IDC_SPEED_SLIDER, m_speed_slider);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CProceduralDialog, CDialog)
//{{AFX_MSG_MAP(CProceduralDialog)
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_BN_CLICKED(IDC_CLEAR_PROCEDURALS, OnClearProcedurals)
ON_CBN_SELENDOK(IDC_PROCEDURAL_PULLDOWN, OnSelendokProceduralPulldown)
ON_BN_CLICKED(IDC_PROCEDURAL_UPDATE, OnProceduralUpdate)
ON_BN_CLICKED(IDC_IMPORT_PALETTE, OnImportPalette)
ON_BN_CLICKED(IDC_DEFAULT_PALETTE, OnDefaultPalette)
ON_BN_CLICKED(IDC_COPY_PROCEDURAL, OnCopyProcedural)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CProceduralDialog message handlers
static static_proc_element save_elements[8000];
BOOL CProceduralDialog::OnInitDialog()
{
CDialog::OnInitDialog();
CWnd::SetTimer(1,33,NULL); // 30 frames per second
int save_num=0;
int n=D3EditState.texdlg_texture;
// Make a temp buffer for our static elements
if (GameTextures[n].procedural->num_static_elements>0)
{
save_num=GameTextures[n].procedural->num_static_elements;
memcpy (save_elements,GameTextures[n].procedural->static_proc_elements,save_num*sizeof(static_proc_element));
}
FreeStaticProceduralsForTexture (n);
Sleep(2000);
AllocateStaticProceduralsForTexture (n,8000);
memcpy (GameTextures[n].procedural->static_proc_elements,save_elements,save_num*sizeof(static_proc_element));
GameTextures[n].procedural->num_static_elements=save_num;
m_button_down=0;
m_proc_type=0;
m_size=255;
m_saturate=0;
m_speed=0;
m_frequency=0;
m_cur_color=255;
// Allocate bitmap memory
CWnd *texwnd;
RECT rect;
texwnd = GetDlgItem(IDC_PALETTE_VIEW);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
m_palette_bitmap=bm_AllocBitmap (w,h,((w*h)/3)*2);
ASSERT (m_palette_bitmap>=0);
m_PaletteSurf.create(bm_w(m_palette_bitmap,0), bm_h(m_palette_bitmap,0), bm_bpp(m_palette_bitmap));
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
w=rect.right-rect.left;
h=rect.bottom-rect.top;
m_window_bitmap=bm_AllocBitmap (w,h,((w*h)/3)*2);
ASSERT (m_window_bitmap>=0);
m_TextureSurf.create(bm_w(m_window_bitmap,0), bm_h(m_window_bitmap,0), bm_bpp(m_window_bitmap));
// Set default slider values
m_freq_slider.SetRange(0, MAX_SLIDER_RANGE);
m_freq_slider.SetPos(255-m_frequency);
m_speed_slider.SetRange(0, MAX_SLIDER_RANGE);
m_speed_slider.SetPos(m_speed);
m_size_slider.SetRange(1, MAX_SLIDER_RANGE);
m_size_slider.SetPos(m_size);
m_heat_slider.SetRange(0, MAX_SLIDER_RANGE);
m_heat_slider.SetPos(GameTextures[n].procedural->heat);
UpdateDialog();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
2024-05-24 03:07:26 +00:00
void CProceduralDialog::PrintValue (int whichbox,uint8_t val)
{
CEdit *ebox;
char str[255];
ebox=(CEdit *) GetDlgItem (whichbox);
sprintf (str,"%d",val);
ebox->SetWindowText (str);
}
void CProceduralDialog::UpdateDialog ()
{
int n=D3EditState.texdlg_texture;
// Update procedural box
SendDlgItemMessage( IDC_PROCEDURAL_PULLDOWN, CB_RESETCONTENT,0,0);
for (int i=0;stricmp ("End",ProcNames[i])!=0;i++)
{
SendDlgItemMessage( IDC_PROCEDURAL_PULLDOWN, CB_ADDSTRING,0,(LPARAM) (LPCTSTR) ProcNames[i]);
}
SendDlgItemMessage( IDC_PROCEDURAL_PULLDOWN, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) ProcNames[m_proc_type]);
// Update palette box
CWnd *texwnd;
RECT rect;
texwnd = GetDlgItem(IDC_PALETTE_VIEW);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
Desktop_surf->attach_to_window((unsigned)m_hWnd);
uint16_t *data=bm_data(m_palette_bitmap,0);
for (i=0;i<h;i++)
{
float cur_color=0;
float color_delta=256.0/(float)w;
for (int t=0;t<w;t++,cur_color+=color_delta)
{
data[i*w+t]=GameTextures[n].procedural->palette[(int)cur_color];
}
}
m_PaletteSurf.load(m_palette_bitmap);
int x = rect.left + ((rect.right-rect.left)/2) - m_PaletteSurf.width()/2;
int y = rect.top + ((rect.bottom-rect.top)/2) - m_PaletteSurf.height()/2;
Desktop_surf->blt(x, y, &m_PaletteSurf);
// fill in the combo box for copy procedural data
CComboBox *combo;
combo = (CComboBox *)GetDlgItem(IDC_PROC_COPY_LIST);
combo->ResetContent();
for(i=0;i<MAX_TEXTURES;i++)
{
if(!GameTextures[i].used)
continue;
if(i==D3EditState.texdlg_texture)
continue;
if(!(GameTextures[i].flags&TF_PROCEDURAL))
continue;
if((GameTextures[i].flags&TF_WATER_PROCEDURAL))
continue;
combo->AddString(GameTextures[i].name);
}
combo->SetCurSel(0);
}
void CProceduralDialog::UpdateProcView ()
{
int n=D3EditState.texdlg_texture;
FrameCount++;
CWnd *texwnd;
RECT rect;
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
ScreenToClient(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
Desktop_surf->attach_to_window((unsigned)m_hWnd);
int bm_handle=GetTextureBitmap (n,0,1);
if (GameBitmaps[bm_handle].flags & BF_MIPMAPPED)
GameBitmaps[m_window_bitmap].flags|=BF_MIPMAPPED;
bm_ScaleBitmapToBitmap (m_window_bitmap,bm_handle);
m_TextureSurf.load(m_window_bitmap);
int x = rect.left + ((rect.right-rect.left)/2) - m_TextureSurf.width()/2;
int y = rect.top + ((rect.bottom-rect.top)/2) - m_TextureSurf.height()/2;
Desktop_surf->blt(x, y, &m_TextureSurf);
// Do slider values
m_frequency = 255-m_freq_slider.GetPos();
m_speed = m_speed_slider.GetPos();
m_size = m_size_slider.GetPos();
GameTextures[n].procedural->heat=m_heat_slider.GetPos();
PrintValue (IDC_SPEED_TEXT,m_speed);
PrintValue (IDC_SIZE_TEXT2,m_size);
PrintValue (IDC_FREQUENCY_TEXT,255-m_frequency);
PrintValue (IDC_HEAT_TEXT,GameTextures[n].procedural->heat);
}
void CProceduralDialog::OnTimer(UINT nIDEvent)
{
UpdateProcView ();
CDialog::OnTimer(nIDEvent);
}
BOOL CProceduralDialog::DestroyWindow()
{
CWnd::KillTimer (1);
int n=D3EditState.texdlg_texture;
int save_num=0;
// Restore our static proc elements
save_num=GameTextures[n].procedural->num_static_elements;
if (save_num>0)
memcpy (save_elements,GameTextures[n].procedural->static_proc_elements,save_num*sizeof(static_proc_element));
FreeStaticProceduralsForTexture (n);
Sleep(2000);
if (save_num>0)
{
AllocateStaticProceduralsForTexture (n,save_num);
memcpy (GameTextures[n].procedural->static_proc_elements,save_elements,save_num*sizeof(static_proc_element));
GameTextures[n].procedural->num_static_elements=save_num;
}
else
GameTextures[n].flags &=~(TF_PROCEDURAL|TF_WATER_PROCEDURAL);
bm_FreeBitmap (m_palette_bitmap);
m_PaletteSurf.free();
bm_FreeBitmap (m_window_bitmap);
m_TextureSurf.free();
return CDialog::DestroyWindow();
}
void CProceduralDialog::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CPoint tpoint=point;
CWnd *texwnd;
RECT rect;
int n=D3EditState.texdlg_texture;
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
MapWindowPoints(texwnd,&tpoint,1);
if (tpoint.x<0)
return;
if (tpoint.y<0)
return;
if (tpoint.x>=w)
return;
if (tpoint.y>=h)
return;
int bm_handle=GameTextures[n].procedural->procedural_bitmap;
int bw=bm_w(bm_handle,0);
int bh=bm_h(bm_handle,0);
int dest_x=((float)tpoint.x*(float)((float)bw/(float)w));
int dest_y=((float)tpoint.y*(float)((float)bh/(float)h));
if (m_proc_type==PROC_LINE_LIGHTNING)
{
m_save_x=dest_x;
m_save_y=dest_y;
}
else if (m_proc_type!=PROC_NONE)
{
CreateElement (tpoint.x,tpoint.y);
}
m_button_down=1;
CDialog::OnLButtonDown(nFlags, point);
}
// Creates a procedural element at x,y
static_proc_element *CProceduralDialog::CreateElement(int x,int y)
{
int n=D3EditState.texdlg_texture;
proc_struct *procedural=GameTextures[n].procedural;
int index;
if (GameTextures[n].procedural->num_static_elements>=MAX_PROC_ELEMENTS)
return NULL;
else
index=GameTextures[n].procedural->num_static_elements;
static_proc_element *proc_elem=&procedural->static_proc_elements[index];
CWnd *texwnd;
RECT rect;
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
int bm_handle=GameTextures[n].procedural->procedural_bitmap;
int bw=bm_w(bm_handle,0);
int bh=bm_h(bm_handle,0);
int dest_x=((float)x*(float)((float)bw/(float)w));
int dest_y=((float)y*(float)((float)bh/(float)h));
proc_elem->type=m_proc_type;
proc_elem->x1=dest_x;
proc_elem->y1=dest_y;
proc_elem->color=m_cur_color;
proc_elem->size=m_size;
proc_elem->speed=m_speed;
proc_elem->frequency=m_frequency;
procedural->num_static_elements++;
return &procedural->static_proc_elements[index];
}
void CProceduralDialog::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CPoint tpoint=point;
CWnd *texwnd;
RECT rect;
int n=D3EditState.texdlg_texture;
if (m_button_down==0)
return;
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
MapWindowPoints(texwnd,&tpoint,1);
if (tpoint.x<0)
return;
if (tpoint.y<0)
return;
if (tpoint.x>=w)
return;
if (tpoint.y>=h)
return;
if (m_proc_type!=PROC_NONE && m_proc_type!=PROC_LINE_LIGHTNING)
{
CreateElement (tpoint.x,tpoint.y);
}
CDialog::OnMouseMove(nFlags, point);
}
void CProceduralDialog::OnLButtonUp(UINT nFlags, CPoint point)
{
int n=D3EditState.texdlg_texture;
CPoint tpoint=point;
if (m_button_down==1 && m_proc_type==PROC_LINE_LIGHTNING)
{
CWnd *texwnd;
RECT rect;
texwnd = GetDlgItem(IDC_PROCEDURAL_VIEW);
texwnd->GetWindowRect(&rect);
int w=rect.right-rect.left;
int h=rect.bottom-rect.top;
int bm_handle=GameTextures[n].procedural->procedural_bitmap;
int bw=bm_w(bm_handle,0);
int bh=bm_h(bm_handle,0);
int dest_x=((float)tpoint.x*(float)((float)bw/(float)w));
int dest_y=((float)tpoint.y*(float)((float)bh/(float)h));
static_proc_element *proc_elem=CreateElement (0,0);
if (proc_elem!=NULL)
{
proc_elem->x1=m_save_x;
proc_elem->y1=m_save_y;
proc_elem->x2=dest_x;
proc_elem->y2=dest_y;
}
}
m_button_down=0;
CDialog::OnLButtonUp(nFlags, point);
}
void CProceduralDialog::OnClearProcedurals()
{
ClearAllProceduralsFromTexture (D3EditState.texdlg_texture);
}
void CProceduralDialog::OnSelendokProceduralPulldown()
{
int cur=SendDlgItemMessage( IDC_PROCEDURAL_PULLDOWN, CB_GETCURSEL,0,0);
m_proc_type=cur;
UpdateDialog();
}
void CProceduralDialog::OnProceduralUpdate()
{
UpdateDialog();
}
2024-05-24 03:07:26 +00:00
void CProceduralDialog::HarvestValue(int whichbox,uint8_t *val)
{
CEdit *ebox;
char name[20];
int num=0;
ebox=(CEdit *) GetDlgItem (whichbox);
ebox->GetWindowText (name,20);
num=atoi (name);
if (num<0)
num=0;
if (num>255)
num=255;
*val=num;
UpdateDialog();
}
void CProceduralDialog::OnImportPalette()
{
CFILE *infile;
char filename[255];
2024-05-24 03:07:26 +00:00
uint8_t r[256],g[256],b[256];
int n=D3EditState.texdlg_texture;
CString filter = "PCX files (*.pcx)|*.pcx||";
if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
return;
if ((infile=cfopen (filename,"rb"))==NULL)
{
OutrageMessageBox ("Couldn't open that PCX file!");
return;
}
cfseek (infile,-768,SEEK_END);
for (int i=0;i<256;i++)
{
r[i]=cf_ReadByte (infile);
g[i]=cf_ReadByte (infile);
b[i]=cf_ReadByte (infile);
}
cfclose (infile);
GeneratePaletteForProcedural (r,g,b,GameTextures[n].procedural->palette);
UpdateDialog();
}
void CProceduralDialog::OnDefaultPalette()
{
int n=D3EditState.texdlg_texture;
memcpy (GameTextures[n].procedural->palette,DefaultProcPalette,256*2);
UpdateDialog();
}
void CProceduralDialog::OnCopyProcedural()
{
// get the name of the texture
CComboBox *combo;
CString str;
int src_id;
combo = (CComboBox *)GetDlgItem(IDC_PROC_COPY_LIST);
combo->GetLBText(combo->GetCurSel(),str);
src_id = FindTextureName(str.GetBuffer(0));
ASSERT(src_id!=-1);
bool do_pal =false;
char buffer[512];
sprintf(buffer,"Are you sure you want to replace the procedural elements of %s with %s?",GameTextures[D3EditState.texdlg_texture].name,GameTextures[src_id].name);
if(MessageBox(buffer,"Confirm",MB_YESNO)!=IDYES)
return;
if(MessageBox("Would you like to replace the palette also?","Palette",MB_YESNO)==IDYES)
do_pal = true;
mngs_texture_page src_page,dest_page;
mng_AssignTextureToTexPage(src_id,&src_page);
mng_AssignTextureToTexPage(D3EditState.texdlg_texture,&dest_page);
ClearAllProceduralsFromTexture(D3EditState.texdlg_texture);
FreeProceduralForTexture(D3EditState.texdlg_texture);
int i;
if(src_page.tex_struct.flags&TF_WATER_PROCEDURAL)
dest_page.tex_struct.flags |= TF_WATER_PROCEDURAL;
else
dest_page.tex_struct.flags &= ~TF_WATER_PROCEDURAL;
if(do_pal)
{
for(i=0;i<255;i++)
{
dest_page.proc_palette[i] = src_page.proc_palette[i];
}
}
dest_page.proc_heat = src_page.proc_heat;
dest_page.proc_light = src_page.proc_light;
dest_page.proc_thickness = src_page.proc_thickness;
dest_page.proc_evaluation_time = src_page.proc_evaluation_time;
dest_page.osc_time = src_page.osc_time;
dest_page.osc_value = src_page.osc_value;
dest_page.num_proc_elements = src_page.num_proc_elements;
for(i=0;i<dest_page.num_proc_elements;i++)
{
dest_page.proc_type[i]=src_page.proc_type[i];
dest_page.proc_frequency[i]=src_page.proc_frequency[i];
dest_page.proc_speed[i]=src_page.proc_speed[i];
dest_page.proc_size[i]=src_page.proc_size[i];
dest_page.proc_x1[i]=src_page.proc_x1[i];
dest_page.proc_y1[i]=src_page.proc_y1[i];
dest_page.proc_x2[i]=src_page.proc_x2[i];
dest_page.proc_y2[i]=src_page.proc_y2[i];
}
AllocateProceduralForTexture(D3EditState.texdlg_texture);
AllocateStaticProceduralsForTexture(D3EditState.texdlg_texture,dest_page.num_proc_elements);
GameTextures[D3EditState.texdlg_texture].procedural->num_static_elements=dest_page.num_proc_elements;
GameTextures[D3EditState.texdlg_texture].procedural->heat=dest_page.proc_heat;
GameTextures[D3EditState.texdlg_texture].procedural->light=dest_page.proc_light;
GameTextures[D3EditState.texdlg_texture].procedural->thickness=dest_page.proc_thickness;
GameTextures[D3EditState.texdlg_texture].procedural->evaluation_time=dest_page.proc_evaluation_time;
GameTextures[D3EditState.texdlg_texture].procedural->osc_time=dest_page.osc_time;
GameTextures[D3EditState.texdlg_texture].procedural->osc_value=dest_page.osc_value;
// Last 2 colors are the same
dest_page.proc_palette[255]=dest_page.proc_palette[254];
memcpy (GameTextures[D3EditState.texdlg_texture].procedural->palette,dest_page.proc_palette,256*2);
for (i=0;i<dest_page.num_proc_elements;i++)
{
static_proc_element *proc=&GameTextures[D3EditState.texdlg_texture].procedural->static_proc_elements[i];
proc->type=dest_page.proc_type[i];
proc->frequency=dest_page.proc_frequency[i];
proc->speed=dest_page.proc_speed[i];
proc->size=dest_page.proc_size[i];
proc->x1=dest_page.proc_x1[i];
proc->y1=dest_page.proc_y1[i];
proc->x2=dest_page.proc_x2[i];
proc->y2=dest_page.proc_y2[i];
}
UpdateDialog();
}