/*
* 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/>.

--- HISTORICAL COMMENTS FOLLOW ---

 * $Logfile: /DescentIII/Main/editor/WorldTexturesDialog.cpp $
 * $Revision: 1.1.1.1 $
 * $Date: 2003-08-26 03:57:40 $
 * $Author: kevinb $
 *
 * Implementation funcs for textures dialog
 *
 * $Log: not supported by cvs2svn $
 *
 * 61    4/21/99 12:23p Matt
 * Added checkbox for breakable textures
 *
 * 60    4/12/99 3:04p Jason
 * changes for low memory
 *
 * 59    4/09/99 7:04p Jason
 * changed some texture defines
 *
 * 58    4/01/99 5:14p Matt
 * Made ambient sound combo update when the sound is changed, and added a
 * "select" button to bring up the Dallas sound selection dialog.
 *
 * 57    3/10/99 7:12p Jason
 * added smooth specular shading for curved surfaces
 *
 * 56    2/20/99 2:17p Matt
 * Added texture sounds
 *
 * 55    1/29/99 6:29p Jason
 * first pass at adding bumpmaps
 *
 * 54    1/27/99 3:39p Mark
 * fixed 256 problem
 *
 * 53    1/26/99 4:04p Jason
 * added some more texture flags
 *
 * 52    1/22/99 3:59p Jason
 * added 256x256 textures to help with terrain skies
 *
 * 51    12/23/98 4:59p Jason
 * some new texture features added
 *
 * 50    12/18/98 5:25p Jason
 * added specularity to mine walls
 *
 * 49    12/17/98 5:38p Jason
 * added 4444 texture format support
 *
 * 48    11/11/98 12:29p Jason
 * fixed texture panel redrawing
 *
 * 47    11/09/98 11:47a Jason
 * working on multiple checkins
 *
 * 46    11/06/98 12:35p Jason
 * more speedups for manage system
 *
 * 45    11/05/98 7:54p Jason
 * changes for new manage system
 *
 * 44    10/29/98 6:01p Jason
 * added multiple coronas
 *
 * 43    10/14/98 12:09p Jason
 * fixed some long standing name problems
 *
 * 42    10/08/98 4:24p Kevin
 * Changed code to comply with memory library usage. Always use mem_malloc
 * , mem_free and mem_strdup
 *
 * 41    10/07/98 5:03p Jason
 * more options for textures
 *
 * 40    8/24/98 5:20p Keneta
 * fixed bug in assigning texture slot to a texture with a previously
 * repeated name.
 *
 * 39    8/13/98 11:57a Jason
 * added water procedurals
 *
 * 38    7/15/98 12:39p Jason
 * fixed bug with new textures
 *
 * 37    7/07/98 4:13p Jason
 * checkin for procedurals
 *
 * 36    7/06/98 12:55p Jason
 * added first pass at procedurals
 *
 * 35    7/01/98 3:09p Luke
 * added assert
 *
 * 34    7/01/98 2:42p Jason
 * fixed bug with unused texture
 *
 * 33    6/23/98 2:43p Matt
 * Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with
 * int return value (instead of bool).
 *
 * 32    6/10/98 12:21p Matt
 * Revamped system that controls what textures are displayed on the
 * texture tab.  Should work correctly now, and will now save the settings
 * to the registry.  Also, textures now default to no type set, not all
 * types set.
 *
 * 31    6/03/98 3:46p Jason
 * made megacell system more robust
 *
 * 30    6/02/98 6:04p Jason
 * added specular lightmaps
 *
 * 29    5/26/98 5:08p Matt
 * Don't put a '1' at the end of new texture names unless the name is
 * already in use without the '1'.
 *
 * 28    5/20/98 5:44p Jason
 * incremental checkin for bumpmapping
 *
 * 27    5/19/98 3:19p Jason
 * cleaned up some texture flags
 *
 * 26    4/15/98 3:28p Jason
 * changed glow stuff to work with new system
 *
 * 25    4/15/98 12:22p Jason
 * lots of miscellaneous stuff pertaining to lighting and vis effects
 *
 * 24    4/06/98 4:42p Jason
 * added texture alpha change
 *
 * 23    3/17/98 4:33p Jason
 * Added size changing to bitmaps/textures
 *
 * 22    3/02/98 6:47p Jason
 * added texture lighting swatch
 *
 * 21    2/23/98 1:00p Jason
 * added saving of textures as tgas
 *
 * 20    2/19/98 1:52p Jason
 * added emergency override to unlock function
 *
 * 19    2/10/98 11:20a Jason
 * fixed a couple of strange bugs
 *
 * 18    2/09/98 3:38p Jason
 * changed tex size problem in LoadBitmap function
 *
 * 17    2/03/98 3:15p Jason
 * added the ability to specify saturation textures for models
 *
 * 16    1/13/98 3:09p Jason
 * added glow effect for engines
 *
 * 15    12/02/97 5:31p Samir
 * New file dialog interface implemented.
 *
 * 14    11/21/97 2:01p Jason
 * made light textures on model render that model face fully bright
 *
 * 13    10/15/97 5:20p Jason
 * did a HUGE overhaul of the bitmap system
 *
 * 12    9/26/97 12:09p Jason
 * tweaked animation on destroyed texture
 *
 * 11    9/25/97 4:30p Jason
 * got destroyable textures working
 *
 * 10    9/25/97 2:58p Jason
 * fixed locker file bug
 *
 * 9     9/09/97 6:08p Matt
 * Changes to texture dialog:
 *   Added done button
 *   Added 'change name' button & removed edit box
 *   Removed pass through checkbox
 *
 * 8     9/03/97 12:19p Jason
 * made deletion ask for lock
 *
 * 7     8/19/97 1:57a Jason
 * made rgb lighting take floats
 *
 * 6     8/12/97 1:10a Jason
 * added code to support radiosity lighting
 *
 * 5     8/08/97 2:25p Matt
 * Took out error messages which are now handled by mng_MakeLocker()
 *
 * 4     8/08/97 12:58p Jason
 * got texture sliding and pingponging working
 *
 * 3     8/05/97 4:28p Chris
 * Added the fly thru and fly back flags
 *
 * 2     8/04/97 3:28p Jason
 * added alpha blending per texture
 *
 * 54    6/24/97 1:15p Jason
 *
 * 53    6/06/97 3:57p Jason
 * implemented changes for small textures and automatic tmap2 recognition
 *
 * 52    6/03/97 5:26p Mark
 *
 * 52	6/03/97	5:17p	Jeff
 *	Added Context Sensitive Help
 * 51    5/30/97 5:46p Jason
 * added colored light functionality on a vertex level
 *
 * 50    5/23/97 7:07p Matt
 * Added code, data, & dialogs to keep track of what a texture is used for
 * (mine, terrain, object) so we can display in the texture dialog only
 * the ones we're interested in.
 *
 * $NoKeywords: $
 */

#include <algorithm>

#include "mfc_compatibility.h"
#include "editor.h"
#include "WorldTexturesDialog.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 "EditLineDialog.h"
#include "ddio.h"
#include "polymodel.h"
#include "bumpmap.h"
#include "ProceduralDialog.h"
#include "WaterProceduralDialog.h"
#include "mem.h"
#include "ManageCheckin.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TEXTURES_PER_ROW 12

/////////////////////////////////////////////////////////////////////////////
// CWorldTexturesDialog dialog

CWorldTexturesDialog::CWorldTexturesDialog(CWnd *pParent /*=NULL*/) : CDialog(CWorldTexturesDialog::IDD, pParent) {
  //{{AFX_DATA_INIT(CWorldTexturesDialog)
  // NOTE: the ClassWizard will add member initialization here
  //}}AFX_DATA_INIT

  m_bumpmap = 0;
  m_TexStart = 0;
  m_TexListPos = 0;
  m_RedrawListbox = 0;
  m_TexPageLen = 0;
  m_CheckForTextureList = 0;
  m_CheckX = m_CheckY = 0;
}

void CWorldTexturesDialog::DoDataExchange(CDataExchange *pDX) {
  CDialog::DoDataExchange(pDX);
  //{{AFX_DATA_MAP(CWorldTexturesDialog)
  DDX_Control(pDX, IDC_TEXTURE_AMBIENT_SOUND_PULLDOWN, m_ambient_sound_combo);
  //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CWorldTexturesDialog, CDialog)
//{{AFX_MSG_MAP(CWorldTexturesDialog)
ON_BN_CLICKED(IDC_WTEXDLG_ADDNEW, OnWtexdlgAddnew)
ON_WM_PAINT()
ON_BN_CLICKED(IDC_NEXT, OnNext)
ON_BN_CLICKED(IDC_PREVIOUS, OnPrevious)
ON_CBN_SELENDOK(IDC_TEX_LIST, OnSelendokTexList)
ON_BN_CLICKED(IDC_LOCK, OnLock)
ON_BN_CLICKED(IDC_CHECKIN, OnCheckin)
ON_BN_CLICKED(IDC_RCS_STATUS, OnRcsStatus)
ON_BN_CLICKED(IDC_DELETE, OnDelete)
ON_BN_CLICKED(IDC_VOLATILE, OnVolatile)
ON_BN_CLICKED(IDC_WATER, OnWater)
ON_BN_CLICKED(IDC_FORCEFIELD, OnForcefield)
ON_BN_CLICKED(IDC_CHECK_ANIMATE, OnCheckAnimate)
ON_BN_CLICKED(IDC_LOAD_BITMAP, OnLoadBitmap)
ON_BN_CLICKED(IDC_CHECK_DESTROY, OnCheckDestroy)
ON_EN_KILLFOCUS(IDC_REFLECT, OnKillfocusReflect)
ON_EN_KILLFOCUS(IDC_SLIDEU, OnKillfocusSlideu)
ON_EN_KILLFOCUS(IDC_SLIDEV, OnKillfocusSlidev)
ON_EN_KILLFOCUS(IDC_DAMAGE, OnKillfocusDamage)
ON_EN_KILLFOCUS(IDC_TEX_NUM, OnKillfocusTexNum)
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(IDC_TEXTURE_CURRENT, OnTextureCurrent)
ON_WM_VSCROLL()
ON_BN_CLICKED(IDC_MINE_TEXTURE, OnMineTexture)
ON_BN_CLICKED(IDC_OBJECT_TEXTURE, OnObjectTexture)
ON_BN_CLICKED(IDC_TERRAIN_TEXTURE, OnTerrainTexture)
ON_EN_KILLFOCUS(IDC_BLUE_LIGHTING, OnKillfocusBlueLighting)
ON_EN_KILLFOCUS(IDC_GREEN_LIGHTING, OnKillfocusGreenLighting)
ON_EN_KILLFOCUS(IDC_RED_LIGHTING, OnKillfocusRedLighting)
ON_WM_HELPINFO()
ON_BN_CLICKED(IDC_ADD_NEW_SMALL, OnAddNewSmall)
ON_BN_CLICKED(IDC_ADD_NEW_TINY, OnAddNewTiny)
ON_EN_KILLFOCUS(IDC_ALPHA_EDIT, OnKillfocusAlphaEdit)
ON_BN_CLICKED(IDC_TEXTURE_FLY_THRU_CHECK, OnTextureFlyThruCheck)
ON_BN_CLICKED(IDC_PING_PONG, OnPingPong)
ON_BN_CLICKED(IDC_TEXTURE_CHANGE_NAME, OnTextureChangeName)
ON_CBN_SELENDOK(IDC_DESTROY_PULLDOWN, OnSelendokDestroyPulldown)
ON_BN_CLICKED(IDC_SATURATE, OnSaturate)
ON_BN_CLICKED(IDC_OVERRIDE, OnOverride)
ON_BN_CLICKED(IDC_SAVE_AS_TGA, OnSaveAsTga)
ON_BN_CLICKED(IDC_CONVERT_TO_NORMAL, OnConvertToNormal)
ON_BN_CLICKED(IDC_CONVERT_TO_SMALL, OnConvertToSmall)
ON_BN_CLICKED(IDC_CONVERT_TO_TINY, OnConvertToTiny)
ON_EN_KILLFOCUS(IDC_SPEED_EDIT, OnKillfocusSpeedEdit)
ON_BN_CLICKED(IDC_IMPORT_BUMP, OnImportBump)
ON_BN_CLICKED(IDC_GENERATE_OMNI, OnGenerateOmni)
ON_BN_CLICKED(IDC_SRC_BUMP, OnSrcBump)
ON_BN_CLICKED(IDC_BUMP1, OnBump1)
ON_BN_CLICKED(IDC_BUMP2, OnBump2)
ON_BN_CLICKED(IDC_BUMP3, OnBump3)
ON_BN_CLICKED(IDC_BUMP4, OnBump4)
ON_BN_CLICKED(IDC_METAL_CHECK, OnMetalCheck)
ON_BN_CLICKED(IDC_MARBLE_CHECK, OnMarbleCheck)
ON_BN_CLICKED(IDC_PLASTIC_CHECK, OnPlasticCheck)
ON_BN_CLICKED(IDC_EFFECT_TEXTURE, OnEffectTexture)
ON_BN_CLICKED(IDC_HUD_COCKPIT_TEXTURE, OnHudCockpitTexture)
ON_BN_CLICKED(IDC_LIGHT_TEXTURE, OnLightTexture)
ON_BN_CLICKED(IDC_PROCEDURAL_CHECK, OnProceduralCheck)
ON_BN_CLICKED(IDC_PROCEDURAL_BUTTON, OnProceduralButton)
ON_BN_CLICKED(IDC_WATER_PROCEDURAL_CHECK, OnWaterProceduralCheck)
ON_BN_CLICKED(IDC_FORCE_LIGHTMAPS, OnForceLightmaps)
ON_BN_CLICKED(IDC_CORONA_A, OnCoronaA)
ON_BN_CLICKED(IDC_CORONA_B, OnCoronaB)
ON_BN_CLICKED(IDC_CORONA_C, OnCoronaC)
ON_BN_CLICKED(IDC_CORONA_D, OnCoronaD)
ON_BN_CLICKED(IDC_MULTICHECKTEX, OnMultichecktex)
ON_BN_CLICKED(IDC_IMPORT_4444, OnImport4444)
ON_BN_CLICKED(IDC_SATURATE_LIGHTMAP, OnSaturateLightmap)
ON_BN_CLICKED(IDC_ADD_NEW_HUGE, OnAddNewHuge)
ON_BN_CLICKED(IDC_LAVA_CHECKBOX, OnLavaCheckbox)
ON_BN_CLICKED(IDC_RUBBLE_CHECKBOX, OnRubbleCheckbox)
ON_CBN_SELENDOK(IDC_TEXTURE_AMBIENT_SOUND_PULLDOWN, OnSelendokTextureAmbientSoundPulldown)
ON_EN_KILLFOCUS(IDC_TEXTURE_AMBIENT_SOUND_VOLUME, OnKillfocusTextureAmbientSoundVolume)
ON_BN_CLICKED(IDC_SMOOTH_SPEC_CHECK, OnSmoothSpecCheck)
ON_BN_CLICKED(IDC_AMBIENT_SOUND_SELECT, OnAmbientSoundSelect)
ON_BN_CLICKED(IDC_CHECK_BREAKABLE, OnCheckBreakable)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWorldTexturesDialog message handlers

bool InputTextureName(char *buf, int len, char *title, char *prompt, CWnd *wnd);

void CWorldTexturesDialog::OnWtexdlgAddnew() {
  char filename[255], dir[255], fname[128], ext[32];
  char cur_name[100];
  int bm_handle, tex_handle;
  int anim = 0, c;

  if (!Network_up) {
    OutrageMessageBox("Sorry babe, the network is down.  This action is a no-no.\n");
    return;
  }

  int alt_format = IsDlgButtonChecked(IDC_IMPORT_4444);
  int format = 0;

  if (alt_format) {
    int answer = MessageBox("Are you sure you wish to import this texture with a 4444 format?", "Question", MB_YESNO);
    if (answer == IDNO)
      return;

    format = BITMAP_FORMAT_4444;
  }

  CString filter =
      "Descent III files "
      "(*.itl,*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl;*.itl||";

  if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
    return;

  ddio_SplitPath(filename, dir, fname, ext);

  //	Okay, we selected a file. Lets do what needs to be done here.
  if (!strnicmp(ext, "ITL", 3)) {
    LoadITLFile(filename, NORMAL_TEXTURE);
    UpdateDialog();
    return;
  }

  bm_handle = LoadTextureImage(filename, &anim, NORMAL_TEXTURE, 0, 0, format);

  if (bm_handle < 0) {
    OutrageMessageBox("Couldn't open that bitmap/anim file.");
    return;
  }

  tex_handle = AllocTexture();

  strcpy(cur_name, fname);         // Start with the filename
  char *t = strchr(cur_name, '.'); // Strip the extention
  if (!t)
    t = cur_name + strlen(cur_name);
  *t = 0;
  c = 0;
  do { // Make sure the name not already in use
    if (FindTextureName(cur_name) == -1)
      break;

    *t = 0;
    sprintf(cur_name, "%s%d", cur_name, ++c);
  } while (1);
  cur_name[0] = toupper(cur_name[0]); // make first char uppercase

  // Get the name from the user
  if (!InputTextureName(cur_name, sizeof(cur_name), "Texture name", "Enter a name for your texture:", this)) {
    FreeTexture(tex_handle);
    return;
  }

  strcpy(GameTextures[tex_handle].name, cur_name);

  if (anim)
    GameTextures[tex_handle].flags |= TF_ANIMATED;
  else
    GameTextures[tex_handle].flags &= ~TF_ANIMATED;

  GameTextures[tex_handle].bm_handle = bm_handle;

  mprintf(0, "Making a copy of this bitmap/anim locally...\n");

  if (!anim) {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[tex_handle].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
  } else {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameVClips[GameTextures[tex_handle].bm_handle].name);
    SaveVClip(filename, GameTextures[tex_handle].bm_handle);
  }

  CheckIfTextureIsTmap2(tex_handle);

  mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);

  D3EditState.texdlg_texture = tex_handle;

  UpdateDialog();
}

void CWorldTexturesDialog::OnPaint() {
  CPaintDC dc(this); // device context for painting

  // TODO: Add your message handler code here

  // Do not call CDialog::OnPaint() for painting messages
  m_RedrawListbox = 1;
  UpdateDialog();
}

void CWorldTexturesDialog::OnNext() {
  D3EditState.texdlg_texture = GetNextTexture(D3EditState.texdlg_texture);

  UpdateDialog();
}

void CWorldTexturesDialog::OnPrevious() {

  D3EditState.texdlg_texture = GetPreviousTexture(D3EditState.texdlg_texture);

  UpdateDialog();
}

// Redraw the dialog based on our current texture
void CWorldTexturesDialog::UpdateDialog(void) {
  CEdit *ebox;
  CButton *bbox;
  int n = D3EditState.texdlg_texture;
  int last_texture = -1;
  char str[50];
  int i;

  if (GameTextures[n].used == 0) {
    n = 0;
    D3EditState.texdlg_texture = 0;
  }

  ebox = (CEdit *)GetDlgItem(IDC_TEX_NUM);
  sprintf(str, "%d", n);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_BITMAP_NAME);
  if (GameTextures[n].flags & TF_ANIMATED)
    ebox->SetWindowText(GameVClips[GameTextures[n].bm_handle].name);
  else
    ebox->SetWindowText(GameBitmaps[GameTextures[n].bm_handle].name);

  SendDlgItemMessage(IDC_DESTROY_PULLDOWN, CB_RESETCONTENT, 0, 0);
  for (i = 0; i < MAX_TEXTURES; i++) {
    if (GameTextures[i].used)
      SendDlgItemMessage(IDC_DESTROY_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)GameTextures[i].name);
  }

  ebox = (CEdit *)GetDlgItem(IDC_DESTROY_PULLDOWN);

  if (GameTextures[n].flags & TF_DESTROYABLE)
    SendDlgItemMessage(IDC_DESTROY_PULLDOWN, CB_SELECTSTRING, 0,
                       (LPARAM)(LPCTSTR)GameTextures[GameTextures[n].destroy_handle].name);
  else
    ebox->SetWindowText("NOT DESTROYABLE");

  ebox = (CEdit *)GetDlgItem(IDC_REFLECT);
  sprintf(str, "%f", GameTextures[n].reflectivity);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_ALPHA_EDIT);
  sprintf(str, "%f", GameTextures[n].alpha);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_SPEED_EDIT);
  sprintf(str, "%f", GameTextures[n].speed);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_TEXTURE_WIDTH);
  if (GameTextures[n].flags & TF_ANIMATED)
    sprintf(str, "Width: %d", bm_w(GameVClips[GameTextures[n].bm_handle].frames[0], 0));
  else
    sprintf(str, "Width: %d", bm_w(GameTextures[n].bm_handle, 0));

  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_TEXTURE_HEIGHT);
  if (GameTextures[n].flags & TF_ANIMATED)
    sprintf(str, "Height: %d", bm_h(GameVClips[GameTextures[n].bm_handle].frames[0], 0));
  else
    sprintf(str, "Height: %d", bm_h(GameTextures[n].bm_handle, 0));
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_RED_LIGHTING);
  sprintf(str, "%f", GameTextures[n].r);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_GREEN_LIGHTING);
  sprintf(str, "%f", GameTextures[n].g);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_BLUE_LIGHTING);
  sprintf(str, "%f", GameTextures[n].b);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_DAMAGE);
  itoa(GameTextures[n].damage, str, 10);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_SLIDEU);
  sprintf(str, "%f", GameTextures[n].slide_u);
  ebox->SetWindowText(str);

  ebox = (CEdit *)GetDlgItem(IDC_SLIDEV);
  sprintf(str, "%f", GameTextures[n].slide_v);
  ebox->SetWindowText(str);

  // Update combo
  if (n != last_texture)
    m_ambient_sound_combo.SetSelected(GameTextures[n].sound);

  ebox = (CEdit *)GetDlgItem(IDC_TEXTURE_AMBIENT_SOUND_VOLUME);
  sprintf(str, "%.1f", GameTextures[n].sound_volume);
  ebox->SetWindowText(str);

  SendDlgItemMessage(IDC_PALETTIZED_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR) "Running in 16bit mode");

  SendDlgItemMessage(IDC_TEX_LIST, CB_RESETCONTENT, 0, 0);
  for (i = 0; i < MAX_TEXTURES; i++) {
    if (GameTextures[i].used)
      SendDlgItemMessage(IDC_TEX_LIST, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)GameTextures[i].name);
  }
  SendDlgItemMessage(IDC_TEX_LIST, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)GameTextures[n].name);

  bbox = (CButton *)GetDlgItem(IDC_CHECKIN);
  if (mng_FindTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE) == -1) {
    bbox->EnableWindow(FALSE);
    bbox = (CButton *)GetDlgItem(IDC_LOCK);
    bbox->EnableWindow(TRUE);
  } else {
    bbox->EnableWindow(TRUE);
    bbox = (CButton *)GetDlgItem(IDC_LOCK);
    bbox->EnableWindow(FALSE);
  }

  bbox = (CButton *)GetDlgItem(IDC_CHECK_ANIMATE);
  bbox->EnableWindow(FALSE);

  // Prevent some schmo from locking the sample texture
  if (!stricmp(GameTextures[n].name, "SAMPLE TEXTURE")) {
    bbox = (CButton *)GetDlgItem(IDC_LOCK);
    bbox->EnableWindow(FALSE);
  }

  if (GameTextures[n].r > 0 || GameTextures[n].g > 0 || GameTextures[n].b > 0)
    GameTextures[n].flags |= TF_LIGHT;
  else
    GameTextures[n].flags &= ~TF_LIGHT;

  // Do the damn bitmask stuff

  CheckDlgButton(IDC_VOLATILE, GameTextures[n].flags & TF_VOLATILE ? 1 : 0);
  CheckDlgButton(IDC_WATER, GameTextures[n].flags & TF_WATER ? 1 : 0);
  CheckDlgButton(IDC_LAVA_CHECKBOX, GameTextures[n].flags & TF_LAVA ? 1 : 0);
  CheckDlgButton(IDC_RUBBLE_CHECKBOX, GameTextures[n].flags & TF_RUBBLE ? 1 : 0);
  CheckDlgButton(IDC_SMOOTH_SPEC_CHECK, GameTextures[n].flags & TF_SMOOTH_SPECULAR ? 1 : 0);
  CheckDlgButton(IDC_FORCEFIELD, GameTextures[n].flags & TF_FORCEFIELD ? 1 : 0);
  CheckDlgButton(IDC_CHECK_ANIMATE, GameTextures[n].flags & TF_ANIMATED ? 1 : 0);
  CheckDlgButton(IDC_CHECK_TMAP2, GameTextures[n].flags & TF_TMAP2 ? 1 : 0);
  CheckDlgButton(IDC_CHECK_DESTROY, GameTextures[n].flags & TF_DESTROYABLE ? 1 : 0);
  CheckDlgButton(IDC_CHECK_BREAKABLE, GameTextures[n].flags & TF_BREAKABLE ? 1 : 0);
  CheckDlgButton(IDC_4444_CHECK, GameBitmaps[GetTextureBitmap(n, 0)].format == BITMAP_FORMAT_4444 ? 1 : 0);

  // Do coronas
  CheckDlgButton(IDC_CORONA_A, GameTextures[n].corona_type == 0);
  CheckDlgButton(IDC_CORONA_B, GameTextures[n].corona_type == 1);
  CheckDlgButton(IDC_CORONA_C, GameTextures[n].corona_type == 2);
  CheckDlgButton(IDC_CORONA_D, GameTextures[n].corona_type == 3);

  CheckDlgButton(IDC_LIGHT_CHECK, GameTextures[n].flags & TF_LIGHT ? 1 : 0);
  CheckDlgButton(IDC_MINE_TEXTURE, GameTextures[n].flags & TF_MINE ? 1 : 0);
  CheckDlgButton(IDC_TERRAIN_TEXTURE, GameTextures[n].flags & TF_TERRAIN ? 1 : 0);
  CheckDlgButton(IDC_OBJECT_TEXTURE, GameTextures[n].flags & TF_OBJECT ? 1 : 0);
  CheckDlgButton(IDC_EFFECT_TEXTURE, GameTextures[n].flags & TF_EFFECT ? 1 : 0);
  CheckDlgButton(IDC_HUD_COCKPIT_TEXTURE, GameTextures[n].flags & TF_HUD_COCKPIT ? 1 : 0);
  CheckDlgButton(IDC_LIGHT_TEXTURE, GameTextures[n].flags & TF_LIGHT ? 1 : 0);
  CheckDlgButton(IDC_PROCEDURAL_CHECK, GameTextures[n].flags & TF_PROCEDURAL ? 1 : 0);
  CheckDlgButton(IDC_WATER_PROCEDURAL_CHECK, GameTextures[n].flags & TF_WATER_PROCEDURAL ? 1 : 0);
  CheckDlgButton(IDC_FORCE_LIGHTMAPS, GameTextures[n].flags & TF_FORCE_LIGHTMAP ? 1 : 0);
  CheckDlgButton(IDC_SATURATE_LIGHTMAP, GameTextures[n].flags & TF_SATURATE_LIGHTMAP ? 1 : 0);

  CheckDlgButton(IDC_METAL_CHECK, GameTextures[n].flags & TF_METAL ? 1 : 0);
  CheckDlgButton(IDC_MARBLE_CHECK, GameTextures[n].flags & TF_MARBLE ? 1 : 0);
  CheckDlgButton(IDC_PLASTIC_CHECK, GameTextures[n].flags & TF_PLASTIC ? 1 : 0);

  CheckDlgButton(IDC_TEXTURE_FLY_THRU_CHECK, GameTextures[n].flags & TF_FLY_THRU ? 1 : 0);

  CheckDlgButton(IDC_PING_PONG, GameTextures[n].flags & TF_PING_PONG ? 1 : 0);
  CheckDlgButton(IDC_SATURATE, GameTextures[n].flags & TF_SATURATE ? 1 : 0);

  CheckDlgButton(IDC_SRC_BUMP, m_bumpmap == 0 ? 1 : 0);
  CheckDlgButton(IDC_BUMP1, m_bumpmap == 1 ? 1 : 0);
  CheckDlgButton(IDC_BUMP2, m_bumpmap == 2 ? 1 : 0);
  CheckDlgButton(IDC_BUMP3, m_bumpmap == 3 ? 1 : 0);
  CheckDlgButton(IDC_BUMP4, m_bumpmap == 4 ? 1 : 0);

  if (GameTextures[n].flags & TF_ANIMATED)
    CheckDlgButton(IDC_CHECK_MIPPED, 0);
  else {
    if (bm_mipped(GameTextures[n].bm_handle))
      CheckDlgButton(IDC_CHECK_MIPPED, 1);
    else
      CheckDlgButton(IDC_CHECK_MIPPED, 0);
  }

  bbox = (CButton *)GetDlgItem(IDC_PROCEDURAL_BUTTON);
  if (GameTextures[n].flags & TF_PROCEDURAL)
    bbox->EnableWindow(TRUE);
  else
    bbox->EnableWindow(FALSE);

  bbox = (CButton *)GetDlgItem(IDC_WATER_PROCEDURAL_CHECK);
  if (GameTextures[n].flags & TF_PROCEDURAL)
    bbox->EnableWindow(TRUE);
  else
    bbox->EnableWindow(FALSE);

  UpdateTextureViews(1);

  last_texture = n;
}

void CWorldTexturesDialog::UpdateTextureViews(int frame) {
  //	Display texture in IDC_TEXTUREVIEW
  int n = D3EditState.texdlg_texture;
  int freebitmap = 0;

  if (!GameTextures[n].used) {
    n = GetNextTexture(n);
    D3EditState.texdlg_texture = n;
    return;
  }

  CWnd *texwnd;
  RECT rect;
  int x, y, bm_handle, w, h;
  static int last_frame = 0;
  static int last_texture = -1;
  static int last_tex_count = -1;
  int update_listbox = 0;

  DrawSwatch(IDC_TEXTURE_SWATCH, GameTextures[n].r, GameTextures[n].g, GameTextures[n].b);

  if (last_texture == n && last_tex_count == Num_textures && m_RedrawListbox == 0)
    update_listbox = 0;
  else {
    m_RedrawListbox = 0;
    update_listbox = 1;
    last_texture = n;
    last_tex_count = Num_textures;
  }

  if (!GameTextures[m_TexStart].used)
    m_TexStart = GetNextTexture(m_TexStart);

  frame = last_frame++;

  texwnd = GetDlgItem(IDC_TEXTUREVIEW);
  texwnd->GetWindowRect(&rect);
  ScreenToClient(&rect);

  Desktop_surf->attach_to_window((unsigned)m_hWnd);

  w = rect.right - rect.left;
  h = rect.bottom - rect.top;

  // Desktop_surf->clear(rect.left,rect.top,w,h);

  bm_handle = GetTextureBitmap(n, frame);

  if (GameTextures[n].flags & TF_TEXTURE_256 && bm_w(bm_handle, 0) == 256) {
    // Downsize this bitmap to make it fit on screen
    int temp_bm = bm_AllocBitmap(128, 128, (128 * 128 * 2) / 3);
    GameBitmaps[temp_bm].format = GameBitmaps[bm_handle].format;
    if (GameBitmaps[bm_handle].flags & BF_MIPMAPPED)
      GameBitmaps[temp_bm].flags |= BF_MIPMAPPED;
    bm_ScaleBitmapToBitmap(temp_bm, bm_handle);
    bm_handle = temp_bm;
    freebitmap = 1;
  }

  m_TextureSurf.create(bm_w(bm_handle, 0), bm_h(bm_handle, 0), bm_bpp(bm_handle));
  m_TextureSurf.load(bm_handle);

  x = rect.left + ((rect.right - rect.left) / 2) - m_TextureSurf.width() / 2;
  y = rect.top + ((rect.bottom - rect.top) / 2) - m_TextureSurf.height() / 2;

  Desktop_surf->blt(x, y, &m_TextureSurf);
  m_TextureSurf.free();
  if (freebitmap)
    bm_FreeBitmap(bm_handle);

  //	Display texture in IDC_DESTROYVIEW

  if (GameTextures[n].flags & TF_DESTROYABLE && GameTextures[n].destroy_handle >= 0) {
    CWnd *texwnd;
    RECT rect;
    int x, y, bm_handle;

    texwnd = GetDlgItem(IDC_DESTROYVIEW);
    texwnd->GetWindowRect(&rect);
    ScreenToClient(&rect);

    bm_handle = GetTextureBitmap(GameTextures[n].destroy_handle, frame);
    m_TextureSurf.create(bm_w(bm_handle, 0), bm_h(bm_handle, 0), bm_bpp(bm_handle));
    m_TextureSurf.load(bm_handle);

    x = rect.left + ((rect.right - rect.left) / 2) - m_TextureSurf.width() / 2;
    y = rect.top + ((rect.bottom - rect.top) / 2) - m_TextureSurf.height() / 2;

    Desktop_surf->blt(x, y, &m_TextureSurf);
    m_TextureSurf.free();
  } else {
    CWnd *texwnd;
    RECT rect;

    texwnd = GetDlgItem(IDC_DESTROYVIEW);
    texwnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;

    Desktop_surf->clear(rect.left, rect.top, w, h);
  }

  /*// Display bumpmaps
  if ((GameTextures[n].src_bumpmap!=-1 && m_bumpmap==0) || (GameTextures[n].bumpmaps[m_bumpmap-1]!=-1))
  {
          CWnd *texwnd;
          RECT rect;
          int x, y, bm_handle;
          uint16_t *src_data,*dest_data;
          int bump_handle;

          if (m_bumpmap==0)
                  bump_handle=GameTextures[n].src_bumpmap;
          else
                  bump_handle=GameTextures[n].bumpmaps[m_bumpmap-1];

          ASSERT (bump_handle>=0);

          texwnd = GetDlgItem(IDC_BUMPVIEW);
          texwnd->GetWindowRect(&rect);
          ScreenToClient(&rect);

          bm_handle=bm_AllocBitmap (BUMP_WIDTH,BUMP_HEIGHT,0);
          ASSERT (bm_handle>=0);

          src_data=(uint16_t *)bump_data(bump_handle);
          dest_data=(uint16_t *)bm_data(bm_handle,0);

          memcpy (dest_data,src_data,BUMP_WIDTH*BUMP_HEIGHT*2);

          bm_ChangeSize (bm_handle,128,128);

          m_TextureSurf.create(bm_w(bm_handle,0), bm_h(bm_handle,0), bm_bpp(bm_handle));
          m_TextureSurf.load(bm_handle);

          x = rect.left + ((rect.right-rect.left)/2) - m_TextureSurf.width()/2;
          y = rect.top + ((rect.bottom-rect.top)/2) - m_TextureSurf.height()/2;

          Desktop_surf->blt(x, y, &m_TextureSurf);
          m_TextureSurf.free();
          bm_FreeBitmap (bm_handle);
  }
  else*/
  {
    CWnd *texwnd;
    RECT rect;

    texwnd = GetDlgItem(IDC_BUMPVIEW);
    texwnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;

    Desktop_surf->clear(rect.left, rect.top, w, h);
  }

  // Now do that listbox

  if (update_listbox) {
    //	resume updating this damned 'listbox'
    texwnd = GetDlgItem(IDC_TEXTURE_LISTBOX);
    texwnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    w = rect.right - rect.left;
    h = rect.bottom - rect.top;

    Desktop_surf->clear(rect.left, rect.top, w, h);

    int texnum = m_TexStart;
    int count = 0, done = 0;

    while (!done) {
      m_TextureSurf.create(32, 32, BPP_16);

      bm_handle = GetTextureBitmap(texnum, 0);

      if (bm_handle >= 0) {
        m_TextureSurf.load(bm_handle);

        x = 4 + rect.left + ((count % TEXTURES_PER_ROW) * 40);
        y = 4 + rect.top + ((count / TEXTURES_PER_ROW) * 40);

        if (m_CheckForTextureList) {

          if (m_CheckX >= x && m_CheckX <= (x + 40) && m_CheckY >= y && m_CheckY <= (y + 40)) {
            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);
      ASSERT(GameTextures[texnum].used);
      m_TextureSurf.free();
      count++;
      if (count == TEXTURES_PER_ROW * 9)
        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);
  }

  m_CheckForTextureList = 0;
  Desktop_surf->attach_to_window((unsigned)NULL);
}

void CWorldTexturesDialog::OnSelendokTexList() {
  int i, cur;
  char name[200];

  cur = SendDlgItemMessage(IDC_TEX_LIST, CB_GETCURSEL, 0, 0);
  SendDlgItemMessage(IDC_TEX_LIST, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name);

  i = FindTextureName(name);

  if (i == -1) {
    mprintf(0, "Possible corrupted texture list, but probably nothing.");
    UpdateDialog();
  }

  D3EditState.texdlg_texture = i;
  UpdateDialog();
}

int TlockState = 0;
int AutoChecking = 0;

void CWorldTexturesDialog::OnLock() {
  int n = D3EditState.texdlg_texture;
  mngs_Pagelock temp_pl;
  mngs_texture_page texpage;
  int r;

  if (AutoChecking != 2 && !mng_MakeLocker()) {
    TlockState = 0;
    return;
  }

  strcpy(temp_pl.name, GameTextures[n].name);
  temp_pl.pagetype = PAGETYPE_TEXTURE;

  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!");
        if (AutoChecking != 2)
          mng_EraseLocker();
        return;
      }
    }
  } else if (r < 0) {
    OutrageMessageBox(ErrorString);
    TlockState = 0;

    if (AutoChecking != 2)
      mng_EraseLocker();

    return;

  } else if (r == 1) {
    OutrageMessageBox(InfoString);
    TlockState = 0;

    if (AutoChecking != 2)
      mng_EraseLocker();
    return;

  } 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!");
      if (AutoChecking != 2)
        mng_EraseLocker();

      TlockState = 0;
      return;
    } else {
      if (mng_FindSpecificTexPage(temp_pl.name, &texpage)) {
        if (mng_AssignTexPageToTexture(&texpage, n)) {
          if (!mng_ReplacePage(GameTextures[n].name, GameTextures[n].name, n, PAGETYPE_TEXTURE, 1)) {
            OutrageMessageBox("There was problem writing that page locally!");

            if (AutoChecking != 2)
              mng_EraseLocker();

            TlockState = 0;
            return;
          }
          if (!AutoChecking)
            OutrageMessageBox("Texture locked.");
        } else
          OutrageMessageBox("There was a problem loading this texture.  You might encounter problems in dealing with "
                            "it.  Good luck!");

        mng_AllocTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE);

        if (AutoChecking != 2)
          UpdateDialog();
        TlockState = 1;
      } else
        OutrageMessageBox("Couldn't find that texture in the table file!");
    }
  }

  if (AutoChecking != 2)
    mng_EraseLocker();
}

void CWorldTexturesDialog::OnCheckin() {
  int n = D3EditState.texdlg_texture;
  mngs_Pagelock temp_pl;
  int r;

  if (!(GameTextures[n].flags & TF_TEXTURE_TYPES)) {
    OutrageMessageBox(
        "You need to select what type of texture this is before checking it in (ie robot, mine, terrain, etc).");
    return;
  }

  if (!mng_MakeLocker())
    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);
        }

        if (!AutoChecking)
          OutrageMessageBox("Texture checked in.");
        int dret = mng_DeletePage(GameTextures[n].name, PAGETYPE_TEXTURE, 1);
        ASSERT(dret == 1);
        mng_EraseLocker();

        int p = mng_FindTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE);
        ASSERT(p != -1);
        mng_FreeTrackLock(p);
        UpdateDialog();
      }
    }
  }
  mng_EraseLocker();
}

void CWorldTexturesDialog::OnRcsStatus() {
  char str[10000];
  int total = 0;

  mng_DisplayLockList(TableUser);

  sprintf(str, "User %s has these textures held locally:\n\n", TableUser);
  for (int i = 0; i < MAX_TRACKLOCKS; i++) {
    if (GlobalTrackLocks[i].used && GlobalTrackLocks[i].pagetype == PAGETYPE_TEXTURE) {
      char temp[90];

      sprintf(temp, "%s", GlobalTrackLocks[i].name);
      strcat(str, temp);
      strcat(str, "\n");
      total++;
    }
  }

  if (total != 0) {
    // Display that string
    MessageBox(str, "Textures", MB_OK);
  }
}

void CWorldTexturesDialog::SaveTexturesOnClose() {
  int i, t;

  // When closing, save all our textures locally

  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);

      std::filesystem::path fname;

      if (GameTextures[t].flags & TF_ANIMATED) {
        fname = LocalManageGraphicsDir / GameVClips[GameTextures[t].bm_handle].name;
        SaveVClip(fname, GameTextures[t].bm_handle);
      } else {
        fname = LocalManageGraphicsDir / GameBitmaps[GameTextures[t].bm_handle].name;
        bm_SaveFileBitmap(fname, GameTextures[t].bm_handle);
      }
    }
  }
}

BOOL CWorldTexturesDialog::DestroyWindow() {

  CWnd::KillTimer(1);
  SaveTexturesOnClose();

  return CDialog::DestroyWindow();
}

void CWorldTexturesDialog::OnDelete() {
  int answer, tl;
  mngs_Pagelock pl;
  int n = D3EditState.texdlg_texture;

  if ((tl = mng_FindTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE)) == -1) {
    // OutrageMessageBox ("This texture is not yours to delete.  Lock first.");
    answer = MessageBox("This texture is not locked...do you wish to lock it so you can delete it?",
                        GameTextures[n].name, MB_YESNO);
    if (answer == IDNO)
      return;

    AutoChecking = 1;
    TlockState = 0;

    OnLock();
    if (!TlockState) {
      OutrageMessageBox("Couldn't lock that texture to delete it!");
      AutoChecking = 0;
      return;
    }
    AutoChecking = 0;
    tl = mng_FindTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE);
    ASSERT(tl != -1);

    // return;
  }
  answer = MessageBox("Are you sure you want to delete this texture?", GameTextures[n].name, MB_YESNO);
  if (answer == IDNO)
    return;

  if (!mng_MakeLocker())
    return;

  strncpy(pl.name, GameTextures[n].name, 30);
  pl.pagetype = PAGETYPE_TEXTURE;
  if (mng_CheckIfPageOwned(&pl, TableUser) != 1) {
    mng_FreeTrackLock(tl);
    if (!mng_DeletePage(GameTextures[n].name, PAGETYPE_TEXTURE, 1)) {
      mprintf(0, ErrorString);
      Int3();
    }
  } else {
    mng_FreeTrackLock(tl);
    mng_DeletePage(GameTextures[n].name, PAGETYPE_TEXTURE, 0);
    mng_DeletePage(GameTextures[n].name, PAGETYPE_TEXTURE, 1);

    mng_DeletePagelock(GameTextures[n].name, PAGETYPE_TEXTURE);
  }

  if (GameTextures[n].flags & TF_ANIMATED)
    FreeVClip(GameTextures[n].bm_handle);
  else
    bm_FreeBitmap(GameTextures[n].bm_handle);

  FreeTexture(n);
  mng_EraseLocker();

  MessageBox("Texture deleted.");
  D3EditState.texdlg_texture = GetNextTexture(n);
  if (D3EditState.texdlg_texture == n)
    mprintf(0, "Wrapped!\n");

  UpdateDialog();
}

// The following functions harvest the checkbuttons

void CWorldTexturesDialog::OnVolatile() {
  int c = IsDlgButtonChecked(IDC_VOLATILE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_VOLATILE;
  else
    GameTextures[n].flags &= ~TF_VOLATILE;
}

void CWorldTexturesDialog::OnWater() {
  int c = IsDlgButtonChecked(IDC_WATER);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_WATER;
  else
    GameTextures[n].flags &= ~TF_WATER;
}

void CWorldTexturesDialog::OnForcefield() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_FORCEFIELD);

  if (c)
    GameTextures[n].flags |= TF_FORCEFIELD;
  else
    GameTextures[n].flags &= ~TF_FORCEFIELD;
}

void CWorldTexturesDialog::OnCheckAnimate() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_CHECK_ANIMATE);

  if (c)
    GameTextures[n].flags |= TF_ANIMATED;
  else
    GameTextures[n].flags &= ~TF_ANIMATED;
}

void CWorldTexturesDialog::OnLoadBitmap() {
  char filename[255];
  int bm_handle;
  int anim = 0;
  int n = D3EditState.texdlg_texture;
  int tex_size = NORMAL_TEXTURE;

  CString filter =
      "Descent III files (*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl||";

  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.
  if (GameTextures[n].flags & TF_TEXTURE_64)
    tex_size = SMALL_TEXTURE;
  else if (GameTextures[n].flags & TF_TEXTURE_32)
    tex_size = TINY_TEXTURE;
  else if (GameTextures[n].flags & TF_TEXTURE_256)
    tex_size = HUGE_TEXTURE;

  int format = GameBitmaps[GetTextureBitmap(n, 0)].format;

  bm_handle = LoadTextureImage(filename, &anim, tex_size, 0, 0, format);

  if (bm_handle < 0) {
    OutrageMessageBox("Could not load that bitmap...restoring previous bitmap.");
    return;
  }

  GameTextures[n].bm_handle = bm_handle;

  if (anim)
    GameTextures[n].flags |= TF_ANIMATED;
  else
    GameTextures[n].flags &= ~TF_ANIMATED;

  mprintf(0, "Making a copy of this bitmap locally...\n");

  if (anim) {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameVClips[GameTextures[n].bm_handle].name);
    SaveVClip(filename, GameTextures[n].bm_handle);
  } else {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[n].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[n].bm_handle);
  }

  CheckIfTextureIsTmap2(n);
  UpdateDialog();
}

void CWorldTexturesDialog::OnCheckDestroy() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_CHECK_DESTROY);

  if (c) {
    GameTextures[n].flags |= TF_DESTROYABLE;
    GameTextures[n].destroy_handle = n;
  } else
    GameTextures[n].flags &= ~TF_DESTROYABLE;

  UpdateDialog();
}

void CWorldTexturesDialog::OnKillfocusReflect() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_REFLECT);
  ebox->GetWindowText(name, 20);

  GameTextures[n].reflectivity = atof(name);

  if (GameTextures[n].reflectivity > 1)
    GameTextures[n].reflectivity = 1.0f;
  if (GameTextures[n].reflectivity < 0)
    GameTextures[n].reflectivity = 0.0f;
}

void CWorldTexturesDialog::OnKillfocusSlideu() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_SLIDEU);
  ebox->GetWindowText(name, 20);

  GameTextures[n].slide_u = atof(name);
}

void CWorldTexturesDialog::OnKillfocusSlidev() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_SLIDEV);
  ebox->GetWindowText(name, 20);

  GameTextures[n].slide_v = atof(name);
}

void CWorldTexturesDialog::OnKillfocusDamage() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_DAMAGE);
  ebox->GetWindowText(name, 20);

  GameTextures[n].damage = atoi(name);
}

void CWorldTexturesDialog::OnKillfocusTexNum() {
  CEdit *ebox;
  char name[20];
  int n;

  ebox = (CEdit *)GetDlgItem(IDC_TEX_NUM);
  ebox->GetWindowText(name, 20);

  n = atoi(name);

  if (!GameTextures[n].used) {
    int a = MessageBox("That is not a valid texture number...show anyway? (may cause a crash)", "WARNING", MB_YESNO);
    if (a == IDNO) {
      char str[30];
      sprintf(str, "%d", D3EditState.texdlg_texture);
      ebox->SetWindowText(str);
      return;
    }
  }

  D3EditState.texdlg_texture = n;
  UpdateDialog();
}

BOOL CWorldTexturesDialog::OnInitDialog() {
  CDialog::OnInitDialog();
  CWnd::SetTimer(1, 100, NULL);

  int n = D3EditState.texdlg_texture;
  m_ambient_sound_combo.Init(GameTextures[n].sound);

  return TRUE; // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}

void CWorldTexturesDialog::OnTimer(UINT nIDEvent) {

  int n = D3EditState.texdlg_texture;

  if (GameTextures[n].flags & TF_ANIMATED ||
      ((GameTextures[n].flags & TF_DESTROYABLE) && (GameTextures[GameTextures[n].destroy_handle].flags & TF_ANIMATED)))
    UpdateTextureViews(1);

  CDialog::OnTimer(nIDEvent);
}

void CWorldTexturesDialog::OnLButtonDown(UINT nFlags, CPoint point) {
  // TODO: Add your message handler code here and/or call default

  m_CheckForTextureList = 1;
  m_CheckX = point.x;
  m_CheckY = point.y;

  CDialog::OnLButtonDown(nFlags, point);

  m_RedrawListbox = 1;
  UpdateDialog();
}

void CWorldTexturesDialog::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 CWorldTexturesDialog::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 CWorldTexturesDialog::OnTextureCurrent() {

  // m_TexStart=D3EditState.texdlg_texture/TEXTURES_PER_ROW;
  // m_RedrawListbox=1;

  // UpdateDialog();
}

void CWorldTexturesDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) {
  // TODO: Add your message handler code here and/or call default
  //	pScrollBar is one of the scroll bars in the dialog.  to determine which one, get
  //	its id. (Note that for a window's scrollbar, this object is invalid)
  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);
}

// Opens a ITL text file and individually adds each on of those bitmaps as a texture
int CWorldTexturesDialog::LoadITLFile(char *filename, int type) {
  CFILE *infile;
  char name[PAGENAME_LEN];
  uint32_t i, done = 0, total = 0;
  char cur_name[100];
  int tex_handle, tex_list[200];
  int c = 1, finding_name = 1;

  ASSERT(filename != NULL);

  infile = (CFILE *)cfopen(filename, "rt");
  if (!infile) {
    mprintf(0, "Couldn't load ITL file %s!\n", filename);
    return -1;
  }

  mprintf(0, "Loading ITL file %s\n", name);

  while (!done) {
    char curline[200];
    char texname[200];

    if (cfeof(infile)) {
      done = 1;
      continue;
    }

    // Read a line and parse it
    cf_ReadString(curline, 200, infile);

    if (curline[0] == ';' || curline[1] == ';' || curline[0] == ' ' || curline[1] == ' ' || curline[0] == '\n')
      continue;
    else {
      int lastslash = -1;
      char bmname[200];

      strcpy(texname, curline);

      for (i = 0; i < strlen(curline); i++)
        if (curline[i] == '\\')
          lastslash = i;

      if (lastslash == -1) {
        for (i = 0; i < strlen(filename); i++)
          if (filename[i] == '\\')
            lastslash = i;

        ASSERT(lastslash != -1);

        strcpy(bmname, filename);
        bmname[lastslash + 1] = 0;
        strcat(bmname, curline);
      } else
        strcpy(bmname, curline);

      // Try and load this file

      int bm = LoadTextureImage(bmname, 0, type, 0);
      if (bm <= 0) {
        mprintf(0, "Error loading frame %d of ITL file %s!\n", total, filename);
        goto Here;
      }

      tex_handle = AllocTexture();
      GameTextures[tex_handle].bm_handle = bm;

      finding_name = 1;
      c = 1;

      while (finding_name) {
        if (c == 1)
          sprintf(cur_name, "%s", texname);
        else
          sprintf(cur_name, "%s%d", texname, c);

        if (FindTextureName(cur_name) != -1)
          c++;
        else
          finding_name = 0;
      }

      strcpy(GameTextures[tex_handle].name, cur_name);

      GameTextures[tex_handle].flags &= ~TF_ANIMATED;

      if (type == SMALL_TEXTURE)
        GameTextures[tex_handle].flags |= TF_TEXTURE_64;
      else if (type == TINY_TEXTURE)
        GameTextures[tex_handle].flags |= TF_TEXTURE_32;
      else if (type == HUGE_TEXTURE)
        GameTextures[tex_handle].flags |= TF_TEXTURE_256;

      GameTextures[tex_handle].bm_handle = bm;
      mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);

      tex_list[total] = tex_handle;

      total++;
    }
  }

Here:

  cfclose(infile);

  mprintf(0, "Making a copy of these textures locally...\n");

  for (i = 0; i < total; i++) {
    tex_handle = tex_list[i];

    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[tex_handle].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
  }

  return 1;
}

void CWorldTexturesDialog::OnMineTexture() {
  int c = IsDlgButtonChecked(IDC_MINE_TEXTURE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_MINE;
  else
    GameTextures[n].flags &= ~TF_MINE;
}

void CWorldTexturesDialog::OnObjectTexture() {
  int c = IsDlgButtonChecked(IDC_OBJECT_TEXTURE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_OBJECT;
  else
    GameTextures[n].flags &= ~TF_OBJECT;
}

void CWorldTexturesDialog::OnTerrainTexture() {
  int c = IsDlgButtonChecked(IDC_TERRAIN_TEXTURE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_TERRAIN;
  else
    GameTextures[n].flags &= ~TF_TERRAIN;
}

void CWorldTexturesDialog::OnKillfocusBlueLighting() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_BLUE_LIGHTING);
  ebox->GetWindowText(name, 20);

  GameTextures[n].b = atof(name);
  UpdateDialog();
}

void CWorldTexturesDialog::OnKillfocusGreenLighting() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_GREEN_LIGHTING);
  ebox->GetWindowText(name, 20);

  GameTextures[n].g = atof(name);
  UpdateDialog();
}

void CWorldTexturesDialog::OnKillfocusRedLighting() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_RED_LIGHTING);
  ebox->GetWindowText(name, 20);

  GameTextures[n].r = atof(name);
  UpdateDialog();
}

BOOL CWorldTexturesDialog::OnHelpInfo(HELPINFO *pHelpInfo) {
  // TODO: Add your message handler code here and/or call default
  WinHelp(HID_TEXTURESDLG, HELP_CONTEXT);
  return TRUE;
  // return CDialog::OnHelpInfo(pHelpInfo);
}

void CWorldTexturesDialog::OnAddNewSmall() {
  char filename[255], dir[255], fname[128], ext[32];
  char cur_name[100];
  int bm_handle, tex_handle;
  int c = 1, finding_name = 1;
  int anim = 0;

  if (!Network_up) {
    OutrageMessageBox("Sorry babe, the network is down.  This action is a no-no.\n");
    return;
  }

  int alt_format = IsDlgButtonChecked(IDC_IMPORT_4444);
  int format = 0;

  if (alt_format) {
    int answer = MessageBox("Are you sure you wish to import this texture with a 4444 format?", "Question", MB_YESNO);
    if (answer == IDNO)
      return;

    format = BITMAP_FORMAT_4444;
  }

  CString filter =
      "Descent III files "
      "(*.itl,*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl;*.itl||";

  if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
    return;

  ddio_SplitPath(filename, dir, fname, ext);

  //	Okay, we selected a file. Lets do what needs to be done here.
  if (!strnicmp(ext, "ITL", 3)) {
    LoadITLFile(filename, SMALL_TEXTURE);
    UpdateDialog();
    return;
  }

  bm_handle = LoadTextureImage(filename, &anim, SMALL_TEXTURE, 0, 0, format);

  if (bm_handle < 0) {
    OutrageMessageBox("Couldn't open that bitmap/anim file.");
    return;
  }

  tex_handle = AllocTexture();

  while (finding_name) {
    if (c == 1)
      sprintf(cur_name, "%s", fname);
    else
      sprintf(cur_name, "%s%d", fname, c);

    if (FindTextureName(cur_name) != -1)
      c++;
    else
      finding_name = 0;
  }

  strcpy(GameTextures[tex_handle].name, cur_name);

  if (anim)
    GameTextures[tex_handle].flags |= TF_ANIMATED;
  else
    GameTextures[tex_handle].flags &= ~TF_ANIMATED;

  GameTextures[tex_handle].flags |= TF_TEXTURE_64;

  GameTextures[tex_handle].bm_handle = bm_handle;

  mprintf(0, "Making a copy of this bitmap/anim locally...\n");

  if (!anim) {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[tex_handle].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
  } else {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameVClips[GameTextures[tex_handle].bm_handle].name);
    SaveVClip(filename, GameTextures[tex_handle].bm_handle);
  }

  CheckIfTextureIsTmap2(tex_handle);

  mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);

  D3EditState.texdlg_texture = tex_handle;

  UpdateDialog();
}

void CWorldTexturesDialog::OnAddNewTiny() {
  char filename[255], dir[255], fname[128], ext[32];
  char cur_name[100];
  int bm_handle, tex_handle;
  int c = 1, finding_name = 1;
  int anim = 0;

  if (!Network_up) {
    OutrageMessageBox("Sorry babe, the network is down.  This action is a no-no.\n");
    return;
  }

  int alt_format = IsDlgButtonChecked(IDC_IMPORT_4444);
  int format = 0;

  if (alt_format) {
    int answer = MessageBox("Are you sure you wish to import this texture with a 4444 format?", "Question", MB_YESNO);
    if (answer == IDNO)
      return;

    format = BITMAP_FORMAT_4444;
  }

  CString filter =
      "Descent III files "
      "(*.itl,*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl;*.itl||";

  if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
    return;

  ddio_SplitPath(filename, dir, fname, ext);

  //	Okay, we selected a file. Lets do what needs to be done here.
  if (!strnicmp(ext, "ITL", 3)) {
    LoadITLFile(filename, TINY_TEXTURE);
    UpdateDialog();
    return;
  }

  bm_handle = LoadTextureImage(filename, &anim, TINY_TEXTURE, 0, 0, format);

  if (bm_handle < 0) {
    OutrageMessageBox("Couldn't open that bitmap/anim file.");
    return;
  }

  tex_handle = AllocTexture();

  while (finding_name) {
    if (c == 1)
      sprintf(cur_name, "%s", fname);
    else
      sprintf(cur_name, "%s%d", fname, c);
    if (FindTextureName(cur_name) != -1)
      c++;
    else
      finding_name = 0;
  }

  strcpy(GameTextures[tex_handle].name, cur_name);

  if (anim)
    GameTextures[tex_handle].flags |= TF_ANIMATED;
  else
    GameTextures[tex_handle].flags &= ~TF_ANIMATED;

  GameTextures[tex_handle].flags |= TF_TEXTURE_32;

  GameTextures[tex_handle].bm_handle = bm_handle;

  mprintf(0, "Making a copy of this bitmap/anim locally...\n");

  if (!anim) {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[tex_handle].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
  } else {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameVClips[GameTextures[tex_handle].bm_handle].name);
    SaveVClip(filename, GameTextures[tex_handle].bm_handle);
  }

  CheckIfTextureIsTmap2(tex_handle);

  mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);

  D3EditState.texdlg_texture = tex_handle;

  UpdateDialog();
}

void CWorldTexturesDialog::OnKillfocusAlphaEdit() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_ALPHA_EDIT);
  ebox->GetWindowText(name, 20);

  GameTextures[n].alpha = atof(name);

  if (GameTextures[n].alpha < .9999)
    GameTextures[n].flags |= TF_ALPHA;
  else
    GameTextures[n].flags &= ~TF_ALPHA;

  UpdateDialog();
}

void CWorldTexturesDialog::OnTextureFlyThruCheck() {
  // TODO: Add your control notification handler code here
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_TEXTURE_FLY_THRU_CHECK);

  if (c)
    GameTextures[n].flags |= TF_FLY_THRU;
  else
    GameTextures[n].flags &= ~TF_FLY_THRU;
}

void CWorldTexturesDialog::OnPingPong() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_PING_PONG);

  if (c)
    GameTextures[n].flags |= TF_PING_PONG;
  else
    GameTextures[n].flags &= ~TF_PING_PONG;
}

// Gets a name from the user, making sure it's unique
// Returns true if got new name, false if cancelled.
// the data in buf not changed if cancel is pressed
bool InputTextureName(char *buf, int len, char *title, char *prompt, CWnd *wnd) {
  char *tempbuf = (char *)mem_malloc(len);

  strcpy(tempbuf, buf);

try_again:

  if (!InputString(tempbuf, len, title, prompt, wnd)) {
    mem_free(tempbuf);
    return 0;
  }

  if (FindTextureName(tempbuf) != -1) {
    OutrageMessageBox("The name you specified is already in use.  Enter another name.");
    goto try_again;
  }

  strcpy(buf, tempbuf);
  mem_free(tempbuf);

  return 1;
}

void CWorldTexturesDialog::OnTextureChangeName() {
  int n = D3EditState.texdlg_texture;
  char name[PAGENAME_LEN];
  mngs_Pagelock pl;

  // Make sure we have this texture locked, if not reset name and bail
  int p = mng_FindTrackLock(GameTextures[n].name, PAGETYPE_TEXTURE);
  if (p == -1) {
    OutrageMessageBox("You must lock this texture if you wish to change its name.");
    return;
  }

  // Get new name
  strcpy(name, GameTextures[n].name);
  if (!InputTextureName(name, sizeof(name), "Texture name", "Enter a new name for this texture:", this))
    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, GameTextures[n].name);
  pl.pagetype = PAGETYPE_TEXTURE;

  int ret = mng_CheckIfPageOwned(&pl, TableUser);
  if (ret < 0)
    OutrageMessageBox(ErrorString);
  else if (ret == 1)
    mng_RenamePage(GameTextures[n].name, name, PAGETYPE_TEXTURE);
  else if (ret == 2) {
    // This page has never been checked in, replace only local copy

    char oldname[PAGENAME_LEN];
    strcpy(oldname, GameTextures[n].name);
    strcpy(GameTextures[n].name, name);
    mng_ReplacePage(oldname, GameTextures[n].name, n, PAGETYPE_TEXTURE, 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(GameTextures[n].name, name);
  UpdateDialog();
  mng_EraseLocker();
}

void CWorldTexturesDialog::OnSelendokDestroyPulldown() {
  int i, cur;
  char name[200];

  cur = SendDlgItemMessage(IDC_DESTROY_PULLDOWN, CB_GETCURSEL, 0, 0);
  SendDlgItemMessage(IDC_DESTROY_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name);

  i = FindTextureName(name);

  if (i == -1) {
    mprintf(0, "Possible corrupted texture list, but probably nothing.");
    UpdateDialog();
  }

  GameTextures[D3EditState.texdlg_texture].destroy_handle = i;
  UpdateDialog();
}

void CWorldTexturesDialog::OnSaturate() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_SATURATE);

  if (c)
    GameTextures[n].flags |= TF_SATURATE;
  else
    GameTextures[n].flags &= ~TF_SATURATE;
}

void CWorldTexturesDialog::OnOverride() {
  int n = D3EditState.texdlg_texture;
  mngs_Pagelock temp_pl;

  strcpy(temp_pl.name, GameTextures[n].name);
  temp_pl.pagetype = PAGETYPE_TEXTURE;

  mng_OverrideToUnlocked(&temp_pl);
}

void CWorldTexturesDialog::OnSaveAsTga() {
  int n = D3EditState.texdlg_texture;

  if (GameTextures[n].flags & TF_ANIMATED) {
    OutrageMessageBox("You cannot save an animated texture!");
    return;
  }

  CString filter = "TGA files (*.tga)|*.tga||";
  char filename[255];
  if (!SaveFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
    return;

  if (!strchr(filename, '.'))
    strcat(filename, ".tga");

  // FIXME: Save as PNG
  // bm_SaveBitmapTGA (filename,GameTextures[n].bm_handle);
  OutrageMessageBox("TGA saved!");
}

void CWorldTexturesDialog::DrawSwatch(int handle, float r, float g, float b) {
  CWnd *texwnd;
  RECT rect;
  int w, h;
  float rmax = std::max(r, g);
  rmax = std::max(rmax, b);

  if (rmax >= .001) {
    r /= rmax;
    g /= rmax;
    b /= rmax;
  }

  texwnd = GetDlgItem(handle);
  texwnd->GetWindowRect(&rect);
  ScreenToClient(&rect);

  Desktop_surf->attach_to_window((unsigned)m_hWnd);

  w = rect.right - rect.left;
  h = rect.bottom - rect.top;

  ddgr_color color = GR_RGB(r * 255, g * 255, b * 255);

  Desktop_surf->clear(rect.left, rect.top, w, h, color);

  Desktop_surf->attach_to_window(NULL);
}

void CWorldTexturesDialog::ChangeSize(int w, int h) {
  int n = D3EditState.texdlg_texture;
  char str[255];

  sprintf(str, "Are you sure you wish to change this texture to %d x %d?", w, h);

  int answer = MessageBox(str, GameTextures[n].name, MB_YESNO);
  if (answer == IDNO)
    return;

  if (GameTextures[n].flags & TF_ANIMATED) {
    vclip *vc = &GameVClips[GameTextures[n].bm_handle];
    for (int i = 0; i < vc->num_frames; i++)
      bm_ChangeSize(vc->frames[i], w, h);
  } else {
    bm_ChangeSize(GameTextures[n].bm_handle, w, h);
  }

  GameTextures[n].flags &= ~(TF_TEXTURE_32 | TF_TEXTURE_64 | TF_TEXTURE_256);
  if (w == 64)
    GameTextures[n].flags |= TF_TEXTURE_64;
  else if (w == 32)
    GameTextures[n].flags |= TF_TEXTURE_32;

  mprintf(0, "Texture changed to %d x %d!\n", w, h);

  UpdateDialog();
}

void CWorldTexturesDialog::OnConvertToNormal() { ChangeSize(128, 128); }

void CWorldTexturesDialog::OnConvertToSmall() { ChangeSize(64, 64); }

void CWorldTexturesDialog::OnConvertToTiny() { ChangeSize(32, 32); }

void CWorldTexturesDialog::OnKillfocusSpeedEdit() {
  CEdit *ebox;
  char name[20];
  int n = D3EditState.texdlg_texture;

  ebox = (CEdit *)GetDlgItem(IDC_SPEED_EDIT);
  ebox->GetWindowText(name, 20);

  GameTextures[n].speed = atof(name);
  UpdateDialog();
}

void CWorldTexturesDialog::OnImportBump() {
  /*char filename[255];
  int bm_handle;
  int n=D3EditState.texdlg_texture;


  CString filter = "Descent III files (*.tga,*.ogf,*.pcx)|*.pcx;*.tga;*.ogf;||";

  if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
          return;

  bm_handle=bm_AllocLoadFileBitmap (filename,0);

  if (bm_handle<0)
  {
          OutrageMessageBox ("Could not load that bumpmap!");
          return;
  }

  if (bm_w(bm_handle,0)!=BUMP_WIDTH || bm_h(bm_handle,0)!=BUMP_HEIGHT)
  {
          OutrageMessageBox ("Bumpmaps must be 32x32 in size!");
          return;
  }

  if (GameTextures[n].bumpmap!=-1)
  {
          bump_FreeBumpmap (GameTextures[n].bumpmap);
          GameTextures[n].src_bumpmap=-1;
  }

  int src_bump=bump_AllocBumpmap ();
  ASSERT (src_bump>=0);

  // Do the memcopy from the bitmap to the bumpmap
  uint16_t *src_data,*dest_data;
  src_data=(uint16_t *)bm_data(bm_handle,0);
  dest_data=(uint16_t *)bump_data(src_bump);

  memcpy (dest_data,src_data,BUMP_WIDTH*BUMP_HEIGHT*2);

  GameTextures[n].src_bumpmap=src_bump;

  mprintf(0,"Making a copy of this bumpmap locally...\n");

  sprintf (filename,"%s\\%s",LocalManageGraphicsDir,GameBitmaps[bm_handle].name);
  bm_SaveFileBitmap (filename,bm_handle);

  // Free useless bitmap
  bm_FreeBitmap(bm_handle);

  UpdateDialog ();*/
}

void CWorldTexturesDialog::OnGenerateOmni() {
  int n = D3EditState.texdlg_texture;

  if (GameTextures[n].bumpmap == -1) {
    OutrageMessageBox("You first need to import a source bumpmap!");
    return;
  }

  BuildTextureBumpmaps(n);

  OutrageMessageBox("Bumpmaps built!");
}

void CWorldTexturesDialog::OnSrcBump() {
  m_bumpmap = 0;
  UpdateDialog();
}

void CWorldTexturesDialog::OnBump1() {
  m_bumpmap = 1;
  UpdateDialog();
}

void CWorldTexturesDialog::OnBump2() {
  m_bumpmap = 2;
  UpdateDialog();
}

void CWorldTexturesDialog::OnBump3() {
  m_bumpmap = 3;
  UpdateDialog();
}

void CWorldTexturesDialog::OnBump4() {
  m_bumpmap = 4;
  UpdateDialog();
}

void CWorldTexturesDialog::OnMetalCheck() {
  int c = IsDlgButtonChecked(IDC_METAL_CHECK);
  int n = D3EditState.texdlg_texture;

  GameTextures[n].flags &= ~(TF_SPECULAR);

  if (c)
    GameTextures[n].flags |= TF_METAL;
  else
    GameTextures[n].flags &= ~TF_METAL;

  UpdateDialog();
}

void CWorldTexturesDialog::OnMarbleCheck() {
  int c = IsDlgButtonChecked(IDC_MARBLE_CHECK);
  int n = D3EditState.texdlg_texture;

  GameTextures[n].flags &= ~(TF_SPECULAR);

  if (c)
    GameTextures[n].flags |= TF_MARBLE;
  else
    GameTextures[n].flags &= ~TF_MARBLE;

  UpdateDialog();
}

void CWorldTexturesDialog::OnPlasticCheck() {
  int c = IsDlgButtonChecked(IDC_PLASTIC_CHECK);
  int n = D3EditState.texdlg_texture;

  GameTextures[n].flags &= ~(TF_SPECULAR);

  if (c)
    GameTextures[n].flags |= TF_PLASTIC;
  else
    GameTextures[n].flags &= ~TF_PLASTIC;

  UpdateDialog();
}

void CWorldTexturesDialog::OnEffectTexture() {
  int c = IsDlgButtonChecked(IDC_EFFECT_TEXTURE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_EFFECT;
  else
    GameTextures[n].flags &= ~TF_EFFECT;
}

void CWorldTexturesDialog::OnHudCockpitTexture() {
  int c = IsDlgButtonChecked(IDC_HUD_COCKPIT_TEXTURE);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_HUD_COCKPIT;
  else
    GameTextures[n].flags &= ~TF_HUD_COCKPIT;
}

void CWorldTexturesDialog::OnLightTexture() {
  int n = D3EditState.texdlg_texture;

  OutrageMessageBox("You cannot change this setting.  Change the RGB values instead.");

  CheckDlgButton(IDC_LIGHT_TEXTURE, GameTextures[n].flags & TF_LIGHT ? 1 : 0);
}

void CWorldTexturesDialog::OnProceduralCheck() {
  int c = IsDlgButtonChecked(IDC_PROCEDURAL_CHECK);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_PROCEDURAL;
  else
    GameTextures[n].flags &= ~TF_PROCEDURAL;

  UpdateDialog();
}

void CWorldTexturesDialog::OnProceduralButton() {
  int n = D3EditState.texdlg_texture;

  if (GameTextures[n].used == 0)
    return;

  if (GameTextures[n].flags & TF_WATER_PROCEDURAL) {
    CWaterProceduralDialog dlg;
    dlg.DoModal();
  } else {
    CProceduralDialog dlg;
    dlg.DoModal();
  }

  UpdateDialog();
}

void CWorldTexturesDialog::OnWaterProceduralCheck() {
  int c = IsDlgButtonChecked(IDC_WATER_PROCEDURAL_CHECK);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_WATER_PROCEDURAL;
  else
    GameTextures[n].flags &= ~TF_WATER_PROCEDURAL;

  UpdateDialog();
}

void CWorldTexturesDialog::OnForceLightmaps() {
  int c = IsDlgButtonChecked(IDC_FORCE_LIGHTMAPS);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_FORCE_LIGHTMAP;
  else
    GameTextures[n].flags &= ~TF_FORCE_LIGHTMAP;

  UpdateDialog();
}

void CWorldTexturesDialog::OnCoronaA() {
  int n = D3EditState.texdlg_texture;

  GameTextures[n].corona_type = 0;
  UpdateDialog();
}

void CWorldTexturesDialog::OnCoronaB() {
  int n = D3EditState.texdlg_texture;

  GameTextures[n].corona_type = 1;
  UpdateDialog();
}

void CWorldTexturesDialog::OnCoronaC() {
  int n = D3EditState.texdlg_texture;

  GameTextures[n].corona_type = 2;
  UpdateDialog();
}

void CWorldTexturesDialog::OnCoronaD() {
  int n = D3EditState.texdlg_texture;

  GameTextures[n].corona_type = 3;
  UpdateDialog();
}

void CWorldTexturesDialog::OnMultichecktex() {
  // CManageCheckin dlg;

  // dlg.DoModal();
  UpdateDialog();
}

void CWorldTexturesDialog::OnImport4444() {
  // TODO: Add your control notification handler code here
}

void CWorldTexturesDialog::OnSaturateLightmap() {
  int c = IsDlgButtonChecked(IDC_SATURATE_LIGHTMAP);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_SATURATE_LIGHTMAP;
  else
    GameTextures[n].flags &= ~TF_SATURATE_LIGHTMAP;

  UpdateDialog();
}

void CWorldTexturesDialog::OnAddNewHuge() {
  char filename[255], dir[255], fname[128], ext[32];
  char cur_name[100];
  int bm_handle, tex_handle;
  int c = 1, finding_name = 1;
  int anim = 0;

  if (!Network_up) {
    OutrageMessageBox("Sorry babe, the network is down.  This action is a no-no.\n");
    return;
  }

  int answer = MessageBox("256x256 textures are for SKIES ONLY.  If you are caught using them for any other purpose "
                          "you will be killed!  Are you sure this is what you want to do?",
                          "WARNING!", MB_YESNO);
  if (answer == IDNO)
    return;

  int alt_format = IsDlgButtonChecked(IDC_IMPORT_4444);
  int format = 0;

  if (alt_format) {
    answer = MessageBox("Are you sure you wish to import this texture with a 4444 format?", "Question", MB_YESNO);
    if (answer == IDNO)
      return;

    format = BITMAP_FORMAT_4444;
  }

  CString filter =
      "Descent III files "
      "(*.itl,*.tga,*.bbm,*.lbm,*.ogf,*.oaf,*.ilf,*.pcx)|*.pcx;*.tga;*.bbm;*.lbm;*.ogf;*.oaf;*.ifl;*.itl||";

  if (!OpenFileDialog(this, (LPCSTR)filter, filename, Current_bitmap_dir, sizeof(Current_bitmap_dir)))
    return;

  ddio_SplitPath(filename, dir, fname, ext);

  //	Okay, we selected a file. Lets do what needs to be done here.
  if (!strnicmp(ext, "ITL", 3)) {
    LoadITLFile(filename, HUGE_TEXTURE);
    UpdateDialog();
    return;
  }

  bm_handle = LoadTextureImage(filename, &anim, HUGE_TEXTURE, 0, 0, format);

  if (bm_handle < 0) {
    OutrageMessageBox("Couldn't open that bitmap/anim file.");
    return;
  }

  tex_handle = AllocTexture();

  while (finding_name) {
    if (c == 1)
      sprintf(cur_name, "%s", fname);
    else
      sprintf(cur_name, "%s%d", fname, c);
    if (FindTextureName(cur_name) != -1)
      c++;
    else
      finding_name = 0;
  }

  strcpy(GameTextures[tex_handle].name, cur_name);

  if (anim)
    GameTextures[tex_handle].flags |= TF_ANIMATED;
  else
    GameTextures[tex_handle].flags &= ~TF_ANIMATED;

  GameTextures[tex_handle].flags |= TF_TEXTURE_256;

  GameTextures[tex_handle].bm_handle = bm_handle;

  mprintf(0, "Making a copy of this bitmap/anim locally...\n");

  if (!anim) {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameBitmaps[GameTextures[tex_handle].bm_handle].name);
    bm_SaveFileBitmap(filename, GameTextures[tex_handle].bm_handle);
  } else {
    sprintf(filename, "%s\\%s", LocalManageGraphicsDir.u8string().c_str(),
      GameVClips[GameTextures[tex_handle].bm_handle].name);
    SaveVClip(filename, GameTextures[tex_handle].bm_handle);
  }

  CheckIfTextureIsTmap2(tex_handle);

  mng_AllocTrackLock(cur_name, PAGETYPE_TEXTURE);

  D3EditState.texdlg_texture = tex_handle;

  UpdateDialog();
}

void CWorldTexturesDialog::OnLavaCheckbox() {
  int c = IsDlgButtonChecked(IDC_LAVA_CHECKBOX);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_LAVA;
  else
    GameTextures[n].flags &= ~TF_LAVA;
}

void CWorldTexturesDialog::OnRubbleCheckbox() {
  int c = IsDlgButtonChecked(IDC_RUBBLE_CHECKBOX);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_RUBBLE;
  else
    GameTextures[n].flags &= ~TF_RUBBLE;
}

void CWorldTexturesDialog::OnSelendokTextureAmbientSoundPulldown() {
  int n = D3EditState.texdlg_texture;

  GameTextures[n].sound = m_ambient_sound_combo.GetSelected();
}

void CWorldTexturesDialog::OnKillfocusTextureAmbientSoundVolume() {
  char str[256];

  ((CEdit *)GetDlgItem(IDC_TEXTURE_AMBIENT_SOUND_VOLUME))->GetWindowText(str, sizeof(str));

  float volume = atof(str);

  if ((volume > 100) || (volume < 0))
    OutrageMessageBox("Volume must be between 0 and 100");
  else {
    int n = D3EditState.texdlg_texture;
    GameTextures[n].sound_volume = volume;
  }
}

void CWorldTexturesDialog::OnSmoothSpecCheck() {
  // TODO: Add your control notification handler code here
  int c = IsDlgButtonChecked(IDC_SMOOTH_SPEC_CHECK);
  int n = D3EditState.texdlg_texture;

  if (c)
    GameTextures[n].flags |= TF_SMOOTH_SPECULAR;
  else
    GameTextures[n].flags &= ~TF_SMOOTH_SPECULAR;
}

#include "soundload.h"
#include "DallasSoundDlg.h"

void CWorldTexturesDialog::OnAmbientSoundSelect() {
  CDallasSoundDlg dlg;

  int selected = m_ambient_sound_combo.GetSelected();
  if (selected != -1)
    dlg.m_SoundName = Sounds[selected].name;

  if (dlg.DoModal() == IDCANCEL)
    return;

  m_ambient_sound_combo.SetSelected(dlg.m_SoundIndex);
}

void CWorldTexturesDialog::OnCheckBreakable() {
  int n = D3EditState.texdlg_texture;
  int c = IsDlgButtonChecked(IDC_CHECK_BREAKABLE);

  if (c)
    GameTextures[n].flags |= TF_BREAKABLE;
  else
    GameTextures[n].flags &= ~TF_BREAKABLE;

  UpdateDialog();
}
