mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
25c4837b1d
Add `"mono.h"` where needed.
2000 lines
50 KiB
C++
2000 lines
50 KiB
C++
/*
|
|
* 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/LightingDialog.cpp $
|
|
* $Revision: 1.1.1.1 $
|
|
* $Date: 2003-08-26 03:57:38 $
|
|
* $Author: kevinb $
|
|
*
|
|
* Lighting keypad dialog
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
*
|
|
* 67 9/13/99 12:24p Matt
|
|
* Changed the copy-light-multiple function to work either in the whole
|
|
* mine or the current room.
|
|
*
|
|
* 66 8/17/99 4:09p Matt
|
|
* Added some accelerator keys, and a function to copy face light
|
|
* multiples.
|
|
*
|
|
* 65 5/05/99 12:58a Matt
|
|
* Added button to clear the lightmaps on a level.
|
|
*
|
|
* 64 4/18/99 5:42a Chris
|
|
* Added the FQ_IGNORE_RENDER_THROUGH_PORTALS flag
|
|
*
|
|
* 63 4/03/99 7:55p Matt
|
|
* Use new keypad update system instead of timer to update.
|
|
*
|
|
* 62 3/24/99 5:53p Jason
|
|
* added per room ambience settings
|
|
*
|
|
* 61 3/23/99 5:13p Jason
|
|
* fixed counting of invisible terrain cells
|
|
*
|
|
* 60 2/18/99 12:32p Jason
|
|
* added room multiplier
|
|
*
|
|
* 59 2/05/99 4:54p Jason
|
|
* added extra option to reset multiples
|
|
*
|
|
* 58 1/21/99 12:22p Jason
|
|
* adding strobing and flickering
|
|
*
|
|
* 57 1/20/99 10:50a Jason
|
|
* added new terrain
|
|
*
|
|
* 56 1/15/99 3:15p Jason
|
|
* fixed global multilier bug
|
|
*
|
|
* 55 1/15/99 2:33p Jason
|
|
* added global multiplier
|
|
*
|
|
* 54 10/06/98 11:48a Jason
|
|
* fixed bug with last rev
|
|
*
|
|
* 53 10/06/98 11:45a Jason
|
|
* added extra feature for Sean
|
|
*
|
|
* 52 8/04/98 11:52a Jason
|
|
* fixed stupid bug
|
|
*
|
|
* 51 8/04/98 11:52a Jason
|
|
* added reverse corona check
|
|
*
|
|
* 50 7/24/98 4:44p Jason
|
|
* added corona button functionality
|
|
*
|
|
* 49 6/22/98 12:00p Chris
|
|
* Working on sound system to make it in a nice shape.
|
|
*
|
|
* 48 6/16/98 3:48p Chris
|
|
* Updated the sound system and added the start of sound streaming
|
|
*
|
|
* 47 6/05/98 5:22p Jason
|
|
* added volumetric fog
|
|
*
|
|
* 46 5/26/98 5:56p Jason
|
|
* only render coronas which are flagged
|
|
*
|
|
* 45 5/22/98 3:28p Jason
|
|
* added specular lighting
|
|
*
|
|
* 44 5/20/98 5:44p Jason
|
|
* incremental checkin for bumpmapping
|
|
*
|
|
* 43 4/29/98 2:19p Jason
|
|
* added yes/no question to confirm lighting
|
|
*
|
|
* 42 4/24/98 12:58p Jason
|
|
* added functions to resave all bitmaps
|
|
*
|
|
* 41 4/21/98 2:36p Jason
|
|
* added some lighting options
|
|
*
|
|
* 40 4/02/98 12:23p Jason
|
|
* trimmed some fat from our structures
|
|
*
|
|
* 39 3/24/98 10:40p Jason
|
|
* made closer lightmap spacing
|
|
*
|
|
* 38 3/16/98 9:55p Chris
|
|
* Working on optimizing fvi
|
|
*
|
|
* 37 2/26/98 10:48a Jason
|
|
* fixed floating point/int problem in inputting face light multiplier
|
|
*
|
|
* 36 2/23/98 7:35p Chris
|
|
* Made the rad. floating point
|
|
*
|
|
* 35 2/16/98 2:12p Jason
|
|
* fixed bug with lightmaps and door shells
|
|
*
|
|
* 34 2/13/98 12:57p Jason
|
|
* changes for adjusting light multiples
|
|
*
|
|
* 33 2/10/98 5:09p Jason
|
|
* added a SetRoomPulse function for settinng pulse parameters for an
|
|
* entire room
|
|
*
|
|
* 32 2/10/98 3:50p Jason
|
|
* added pulsing walls
|
|
*
|
|
* 31 2/04/98 8:25p Jason
|
|
* added light multiplier for faces
|
|
*
|
|
* 30 2/04/98 6:23p Matt
|
|
* Changed object room number to indicate a terrain cell via a flag. Got
|
|
* rid of the object flag which used to indicate terrain.
|
|
*
|
|
* 29 1/15/98 7:34p Matt
|
|
* Revamped error checking when computing face normals
|
|
*
|
|
* 28 1/02/98 5:32p Chris
|
|
* More radical changes to the sound system
|
|
*
|
|
* 27 12/31/97 12:51p Jason
|
|
* debugged and implementd BSP tree for lighting
|
|
*
|
|
* 26 12/18/97 12:24p Chris
|
|
* Turned off sound system while doing casting rays.
|
|
*
|
|
* 25 12/16/97 4:17p Jason
|
|
* added ignore_satellites and ignore terrain
|
|
*
|
|
* 24 12/10/97 12:23p Jason
|
|
* added "SuperDetail"
|
|
*
|
|
*
|
|
* 23 12/05/97 12:34p Jason
|
|
* added ambient light to the terrain
|
|
*
|
|
* 22 11/28/97 6:41p Jason
|
|
* added functions to blur lightmaps - not very helpful though
|
|
*
|
|
* 21 11/25/97 12:28p Jason
|
|
* another pass at shadows
|
|
*
|
|
* 20 11/19/97 12:39p Jason
|
|
* added dynamic terrain button
|
|
*
|
|
* 19 11/14/97 6:38p Jason
|
|
* added ability to do lighting on a single room
|
|
*
|
|
* 18 11/14/97 1:13p Jason
|
|
* added better light counting
|
|
*
|
|
* 17 10/28/97 3:41p Jason
|
|
* added "use hemicubes" option
|
|
*
|
|
* 16 10/10/97 2:34p Jason
|
|
* tweaked volumetrics
|
|
*
|
|
* 15 10/10/97 1:10p Jason
|
|
* more support for volumetrics
|
|
*
|
|
* 14 10/10/97 11:38a Jason
|
|
* put in better volumetric support
|
|
*
|
|
* 13 9/26/97 11:51a Jason
|
|
* tweaked terrain radiosity
|
|
*
|
|
* 12 9/25/97 4:47p Jason
|
|
* update alpha edit box via timer
|
|
*
|
|
* 11 9/23/97 5:53p Jason
|
|
* added more custom options to radiosity
|
|
*
|
|
* 10 9/09/97 12:22p Matt
|
|
* Renamed a flag
|
|
*
|
|
* 9 9/04/97 2:54p Jason
|
|
* fixed small radiosity bug that wasn't flagging invisible elements
|
|
*
|
|
* 8 9/04/97 12:12p Jason
|
|
* added lightmap visibility
|
|
*
|
|
* 7 9/02/97 12:54p Jason
|
|
* classify faces as alphaed or not
|
|
*
|
|
* 6 9/02/97 11:47a Jason
|
|
* Got alpha per vertex working
|
|
*
|
|
* 5 8/28/97 2:59p Jason
|
|
* added confirmation for terrain radiosity
|
|
*
|
|
* 4 8/27/97 5:19p Jason
|
|
* added "Count lights"
|
|
*
|
|
* 3 8/26/97 4:36p Jason
|
|
* added terrain radiosity
|
|
*
|
|
* 2 8/12/97 1:10a Jason
|
|
* added code to support radiosity lighting
|
|
*
|
|
* 8 6/03/97 4:55p Mark
|
|
*
|
|
* 8 6/03/97 4:53p Jeff
|
|
* Added Context Sensitive Help
|
|
*
|
|
* 7 5/30/97 5:45p Jason
|
|
* changes to support user-definable lighting parameters
|
|
*
|
|
* 6 5/23/97 10:48a Jason
|
|
* checked in for safekeeping...
|
|
*
|
|
* 5 2/20/97 2:37p Mark
|
|
*
|
|
* 4 1/27/97 11:38a Samir
|
|
* Added horizontal scrolling of keypad modeless dialog.
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "editor.h"
|
|
#include "LightingDialog.h"
|
|
#include "editor_lighting.h"
|
|
#include "gametexture.h"
|
|
#include "radiosity.h"
|
|
#include "hemicube.h"
|
|
#include "findintersection.h"
|
|
#include "erooms.h"
|
|
#include "vecmat.h"
|
|
#include "polymodel.h"
|
|
#include "lightmap_info.h"
|
|
#include "hlsoundlib.h"
|
|
#include "lighting.h"
|
|
#include "bsp.h"
|
|
#include "ddio.h"
|
|
#include "mono.h"
|
|
#include "vclip.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CLightingDialog dialog
|
|
|
|
CLightingDialog::CLightingDialog(CWnd *pParent /*=NULL*/) : CKeypadDialog(CLightingDialog::IDD, pParent) {
|
|
//{{AFX_DATA_INIT(CLightingDialog)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
void CLightingDialog::DoDataExchange(CDataExchange *pDX) {
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CLightingDialog)
|
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CLightingDialog, CDialog)
|
|
//{{AFX_MSG_MAP(CLightingDialog)
|
|
ON_WM_SIZE()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_HSCROLL()
|
|
ON_BN_CLICKED(IDC_LITEPAD_SETDEFAULT, OnLitepadSetdefault)
|
|
ON_BN_CLICKED(IDC_LITEPAD_SMOOTHALL, OnLitepadSmoothall)
|
|
ON_EN_KILLFOCUS(IDC_LIGHT_ITERATION_EDIT, OnKillfocusLightIterationEdit)
|
|
ON_WM_HELPINFO()
|
|
ON_BN_CLICKED(IDC_LITEPAD_TERRAIN_RADIOSITY, OnLitepadTerrainRadiosity)
|
|
ON_BN_CLICKED(IDC_LITEPAD_COUNT_LIGHTS, OnLitepadCountLights)
|
|
ON_BN_CLICKED(IDC_LITEPAD_NEXTVERTEX, OnLitepadNextvertex)
|
|
ON_WM_PAINT()
|
|
ON_EN_KILLFOCUS(IDC_ALPHA_EDIT, OnKillfocusAlphaEdit)
|
|
ON_BN_CLICKED(IDC_SHOW_LIGHTMAPS, OnShowLightmaps)
|
|
ON_EN_KILLFOCUS(IDC_HEMICUBE_RES_EDIT, OnKillfocusHemicubeResEdit)
|
|
ON_EN_KILLFOCUS(IDC_LIGHT_SPACING_EDIT, OnKillfocusLightSpacingEdit)
|
|
ON_BN_CLICKED(IDC_BESTFIT_CHECK, OnBestfitCheck)
|
|
ON_BN_CLICKED(IDC_CREATE_VOLUME_CONE, OnCreateVolumeCone)
|
|
ON_BN_CLICKED(IDC_CLEAR_VOLUMETRIC_ROOM, OnClearVolumetricRoom)
|
|
ON_BN_CLICKED(IDC_FILL_VOLUME_TEXTURE, OnFillVolumeTexture)
|
|
ON_EN_KILLFOCUS(IDC_ANGLE_EDIT, OnKillfocusAngleEdit)
|
|
ON_EN_KILLFOCUS(IDC_START_ALPHA_EDIT, OnKillfocusStartAlphaEdit)
|
|
ON_EN_KILLFOCUS(IDC_RESOLUTION_EDIT, OnKillfocusResolutionEdit)
|
|
ON_BN_CLICKED(IDC_EDGE_VOLUMETRIC, OnEdgeVolumetric)
|
|
ON_EN_KILLFOCUS(IDC_FALLOFF_EDIT, OnKillfocusFalloffEdit)
|
|
ON_BN_CLICKED(IDC_FARTHEST_POINT, OnFarthestPoint)
|
|
ON_EN_KILLFOCUS(IDC_PITCH_ANGLE_EDIT, OnKillfocusPitchAngleEdit)
|
|
ON_EN_KILLFOCUS(IDC_HEADING_ANGLE_EDIT, OnKillfocusHeadingAngleEdit)
|
|
ON_BN_CLICKED(IDC_HEMICUBE_CHECK, OnHemicubeCheck)
|
|
ON_BN_CLICKED(IDC_COUNT_TERRAIN_LIGHTS, OnCountTerrainLights)
|
|
ON_BN_CLICKED(IDC_CURROOM_RADIOSITY, OnCurroomRadiosity)
|
|
ON_BN_CLICKED(IDC_DYNAMIC_TERRAIN, OnDynamicTerrain)
|
|
ON_BN_CLICKED(IDC_BLUR_LIGHTMAPS, OnBlurLightmaps)
|
|
ON_EN_KILLFOCUS(IDC_IGNORE_LIMIT_EDIT, OnKillfocusIgnoreLimitEdit)
|
|
ON_EN_KILLFOCUS(IDC_RED_AMBIENT_EDIT, OnKillfocusRedAmbientEdit)
|
|
ON_EN_KILLFOCUS(IDC_GREEN_AMBIENT_EDIT, OnKillfocusGreenAmbientEdit)
|
|
ON_EN_KILLFOCUS(IDC_BLUE_AMBIENT_EDIT, OnKillfocusBlueAmbientEdit)
|
|
ON_BN_CLICKED(IDC_ELEMENT_CHECK, OnElementCheck)
|
|
ON_BN_CLICKED(IDC_IGNORE_TERRAIN, OnIgnoreTerrain)
|
|
ON_BN_CLICKED(IDC_IGNORE_SATELLITES, OnIgnoreSatellites)
|
|
ON_BN_CLICKED(IDC_USE_BSP_CHECK, OnUseBspCheck)
|
|
ON_EN_KILLFOCUS(IDC_LIGHT_MULTIPLY_EDIT, OnKillfocusLightMultiplyEdit)
|
|
ON_EN_KILLFOCUS(IDC_PULSE_TIME_EDIT, OnKillfocusPulseTimeEdit)
|
|
ON_EN_KILLFOCUS(IDC_PULSE_OFFSET_EDIT, OnKillfocusPulseOffsetEdit)
|
|
ON_BN_CLICKED(IDC_PULSE_ROOM, OnPulseRoom)
|
|
ON_BN_CLICKED(IDC_RESET_MULTIPLES, OnResetMultiples)
|
|
ON_BN_CLICKED(IDC_DESTROY_BSP, OnDestroyBsp)
|
|
ON_BN_CLICKED(IDC_COMBINE_FACES, OnCombineFaces)
|
|
ON_BN_CLICKED(IDC_VOLUME_LIGHTS, OnVolumeLights)
|
|
ON_BN_CLICKED(IDC_CORONA_CHECK, OnCoronaCheck)
|
|
ON_BN_CLICKED(IDC_FOG_CHECK, OnFogCheck)
|
|
ON_EN_KILLFOCUS(IDC_FOG_DENSITY, OnKillfocusFogDensity)
|
|
ON_EN_KILLFOCUS(IDC_FOG_RED, OnKillfocusFogRed)
|
|
ON_EN_KILLFOCUS(IDC_FOG_GREEN, OnKillfocusFogGreen)
|
|
ON_EN_KILLFOCUS(IDC_FOG_BLUE, OnKillfocusFogBlue)
|
|
ON_BN_CLICKED(IDC_ROOM_CORONAS, OnRoomCoronas)
|
|
ON_BN_CLICKED(IDC_MINE_CORONAS, OnMineCoronas)
|
|
ON_BN_CLICKED(IDC_REVERSE_CORONA, OnReverseCorona)
|
|
ON_EN_KILLFOCUS(IDC_GLOBAL_MULTIPLIER_EDIT, OnKillfocusGlobalMultiplierEdit)
|
|
ON_BN_CLICKED(IDC_STROBE_CHECK, OnStrobeCheck)
|
|
ON_BN_CLICKED(IDC_FLICKER_CHECK, OnFlickerCheck)
|
|
ON_EN_KILLFOCUS(IDC_ROOM_MULTIPLIER_EDIT, OnKillfocusRoomMultiplierEdit)
|
|
ON_EN_KILLFOCUS(IDC_ROOM_AMRED, OnKillfocusRoomAmred)
|
|
ON_EN_KILLFOCUS(IDC_ROOM_AMGREEN, OnKillfocusRoomAmgreen)
|
|
ON_EN_KILLFOCUS(IDC_ROOM_AMBLUE, OnKillfocusRoomAmblue)
|
|
ON_BN_CLICKED(IDC_CLEAR_LIGHTMAPS, OnClearLightmaps)
|
|
ON_BN_CLICKED(IDC_COPY_MULTIPLIER, OnCopyMultiplier)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CLightingDialog message handlers
|
|
|
|
void CLightingDialog::OnSize(UINT nType, int cx, int cy) { CKeypadDialog::OnSize(nType, cx, cy); }
|
|
|
|
void CLightingDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) {
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
CKeypadDialog::OnVScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void CLightingDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar) {
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
CKeypadDialog::OnHScroll(nSBCode, nPos, pScrollBar);
|
|
}
|
|
|
|
void CLightingDialog::OnLitepadSetdefault() {
|
|
int i, alphaed = 0;
|
|
|
|
Curroomp->faces[Curface].face_uvls[Curvert].alpha = 255;
|
|
|
|
for (i = 0; i < Curroomp->faces[Curface].num_verts; i++)
|
|
if (Curroomp->faces[Curface].face_uvls[i].alpha != 255)
|
|
alphaed = 1;
|
|
|
|
if (alphaed)
|
|
Curroomp->faces[Curface].flags |= FF_VERTEX_ALPHA;
|
|
else
|
|
Curroomp->faces[Curface].flags &= ~FF_VERTEX_ALPHA;
|
|
|
|
World_changed = 1;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnLitepadSmoothall() {
|
|
int answer =
|
|
MessageBox("Are you sure you wish to calculate lighting on the indoor mine?", "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
MessageBox("I will now calculate radiosity for the indoor engine. You may prematurely break out by pressing any key "
|
|
"during the calculations",
|
|
"Message", MB_OK);
|
|
|
|
DoRadiosityForRooms();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusLightIterationEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_ITERATION_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
rad_MaxStep = atoi(str);
|
|
}
|
|
|
|
BOOL CLightingDialog::OnInitDialog() {
|
|
CDialog::OnInitDialog();
|
|
|
|
m_angle = 30;
|
|
m_resolution = 50;
|
|
m_start_alpha = 1.0;
|
|
m_falloff = 20;
|
|
m_pitch_angle = 0;
|
|
m_heading_angle = 0;
|
|
UpdateDialog();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
BOOL CLightingDialog::OnHelpInfo(HELPINFO *pHelpInfo) {
|
|
// TODO: Add your message handler code here and/or call default
|
|
WinHelp(HID_LIGHTINGTAB, HELP_CONTEXT);
|
|
return TRUE;
|
|
// return CDialog::OnHelpInfo(pHelpInfo);
|
|
}
|
|
|
|
void CLightingDialog::OnLitepadTerrainRadiosity() {
|
|
int answer = MessageBox("Are you sure you wish to calculate lighting on the terrain?", "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
Sound_system.KillSoundLib(false);
|
|
|
|
MessageBox("I will now calculate radiosity for the terrain engine. You may prematurely break out by pressing any "
|
|
"key during the calculations",
|
|
"Message", MB_OK);
|
|
DoRadiosityForTerrain();
|
|
World_changed = 1;
|
|
|
|
Sound_system.InitSoundLib(Descent, Sound_mixer, Sound_quality, false);
|
|
}
|
|
|
|
void CLightingDialog::OnLitepadCountLights() {
|
|
int lightcount, i, t;
|
|
char str[1000];
|
|
|
|
for (lightcount = 0, i = 0; i < MAX_ROOMS; i++) {
|
|
if (Rooms[i].used && !(Rooms[i].flags & RF_EXTERNAL)) {
|
|
for (t = 0; t < Rooms[i].num_faces; t++) {
|
|
int texnum = Rooms[i].faces[t].tmap;
|
|
if (GameTextures[texnum].r > 0 || GameTextures[texnum].g > 0 || GameTextures[texnum].b > 0)
|
|
lightcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= Highest_object_index; i++) {
|
|
if (OBJECT_OUTSIDE(&Objects[i]))
|
|
continue;
|
|
|
|
if (Objects[i].type != OBJ_NONE && Objects[i].lighting_render_type == LRT_LIGHTMAPS) {
|
|
poly_model *po = &Poly_models[Objects[i].rtype.pobj_info.model_num];
|
|
|
|
if (!po->new_style)
|
|
continue;
|
|
|
|
for (t = 0; t < po->n_models; t++) {
|
|
bsp_info *sm = &po->submodel[t];
|
|
|
|
if (IsNonRenderableSubmodel(po, t))
|
|
continue;
|
|
|
|
for (int j = 0; j < sm->num_faces; j++) {
|
|
if (sm->faces[j].texnum == -1)
|
|
continue;
|
|
|
|
int texnum = po->textures[sm->faces[j].texnum];
|
|
if (GameTextures[texnum].r > 0 || GameTextures[texnum].g > 0 || GameTextures[texnum].b > 0)
|
|
lightcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(str,
|
|
"There are %d lights present in the mine. Do you wish for me to set the 'light iterations' control to match "
|
|
"this number?",
|
|
lightcount);
|
|
int answer = MessageBox(str, "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
CEdit *ebox;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_ITERATION_EDIT);
|
|
sprintf(str, "%d", lightcount);
|
|
ebox->SetWindowText(str);
|
|
|
|
rad_MaxStep = lightcount;
|
|
}
|
|
|
|
void CLightingDialog::OnLitepadNextvertex() {
|
|
if (++Curvert >= Curroomp->faces[Curface].num_verts)
|
|
Curvert = 0;
|
|
|
|
EditorStatus("Vertex %d selected.", Curvert);
|
|
UpdateDialog();
|
|
|
|
State_changed = 1;
|
|
}
|
|
|
|
extern float GlobalMultiplier;
|
|
void CLightingDialog::UpdateDialog() {
|
|
CEdit *ebox;
|
|
float aval;
|
|
char str[100];
|
|
|
|
// Do volumetrics
|
|
if (Curroomp && Curroomp->used) {
|
|
aval = Ubyte_to_float[Curroomp->faces[Curface].face_uvls[Curvert].alpha];
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ALPHA_EDIT);
|
|
sprintf(str, "%f", aval);
|
|
ebox->SetWindowText(str);
|
|
|
|
uint8_t pval = Curroomp->pulse_time;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PULSE_TIME_EDIT);
|
|
sprintf(str, "%d", pval);
|
|
ebox->SetWindowText(str);
|
|
|
|
pval = Curroomp->pulse_offset;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PULSE_OFFSET_EDIT);
|
|
sprintf(str, "%d", pval);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_DENSITY);
|
|
sprintf(str, "%f", Curroomp->fog_depth);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_RED);
|
|
sprintf(str, "%f", Curroomp->fog_r);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_GREEN);
|
|
sprintf(str, "%f", Curroomp->fog_g);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_BLUE);
|
|
sprintf(str, "%f", Curroomp->fog_b);
|
|
ebox->SetWindowText(str);
|
|
} else {
|
|
ebox = (CEdit *)GetDlgItem(IDC_ALPHA_EDIT);
|
|
ebox->SetWindowText("No room selected");
|
|
}
|
|
|
|
// Set element check
|
|
CheckDlgButton(IDC_ELEMENT_CHECK, Shoot_from_patch ? 0 : 1);
|
|
CheckDlgButton(IDC_COMBINE_FACES, AllowCombining);
|
|
CheckDlgButton(IDC_IGNORE_TERRAIN, Ignore_terrain);
|
|
CheckDlgButton(IDC_IGNORE_SATELLITES, Ignore_satellites);
|
|
CheckDlgButton(IDC_USE_BSP_CHECK, UseBSP);
|
|
CheckDlgButton(IDC_VOLUME_LIGHTS, UseVolumeLights);
|
|
|
|
if (Curroomp == NULL) {
|
|
CheckDlgButton(IDC_CORONA_CHECK, 0);
|
|
CheckDlgButton(IDC_FOG_CHECK, 0);
|
|
CheckDlgButton(IDC_STROBE_CHECK, 0);
|
|
CheckDlgButton(IDC_FLICKER_CHECK, 0);
|
|
|
|
} else {
|
|
CheckDlgButton(IDC_CORONA_CHECK, (Curroomp->faces[Curface].flags & FF_CORONA) ? 1 : 0);
|
|
CheckDlgButton(IDC_FOG_CHECK, (Curroomp->flags & RF_FOG) ? 1 : 0);
|
|
CheckDlgButton(IDC_STROBE_CHECK, (Curroomp->flags & RF_STROBE) ? 1 : 0);
|
|
CheckDlgButton(IDC_FLICKER_CHECK, (Curroomp->flags & RF_FLICKER) ? 1 : 0);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_MULTIPLIER_EDIT);
|
|
sprintf(str, "%f", Room_multiplier[Curroomp - Rooms]);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMRED);
|
|
sprintf(str, "%f", Room_ambience_r[Curroomp - Rooms]);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMGREEN);
|
|
sprintf(str, "%f", Room_ambience_g[Curroomp - Rooms]);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMBLUE);
|
|
sprintf(str, "%f", Room_ambience_b[Curroomp - Rooms]);
|
|
ebox->SetWindowText(str);
|
|
}
|
|
|
|
// Do Global multiplier
|
|
ebox = (CEdit *)GetDlgItem(IDC_GLOBAL_MULTIPLIER_EDIT);
|
|
sprintf(str, "%f", GlobalMultiplier);
|
|
ebox->SetWindowText(str);
|
|
|
|
// Do maxsteps for radiosity
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_ITERATION_EDIT);
|
|
sprintf(str, "%d", rad_MaxStep);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_HEMICUBE_RES_EDIT);
|
|
sprintf(str, "%d", Hemicube_resolution);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_SPACING_EDIT);
|
|
sprintf(str, "%d", LightSpacing);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ANGLE_EDIT);
|
|
sprintf(str, "%d", m_angle);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_RESOLUTION_EDIT);
|
|
sprintf(str, "%d", m_resolution);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_START_ALPHA_EDIT);
|
|
sprintf(str, "%f", m_start_alpha);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FALLOFF_EDIT);
|
|
sprintf(str, "%f", m_falloff);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PITCH_ANGLE_EDIT);
|
|
sprintf(str, "%d", m_pitch_angle);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_HEADING_ANGLE_EDIT);
|
|
sprintf(str, "%d", m_heading_angle);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_IGNORE_LIMIT_EDIT);
|
|
sprintf(str, "%f", Ignore_limit);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_RED_AMBIENT_EDIT);
|
|
sprintf(str, "%.2f", Ambient_red);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_GREEN_AMBIENT_EDIT);
|
|
sprintf(str, "%.2f", Ambient_green);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_BLUE_AMBIENT_EDIT);
|
|
sprintf(str, "%.2f", Ambient_blue);
|
|
ebox->SetWindowText(str);
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_MULTIPLY_EDIT);
|
|
sprintf(str, "%.2f", (Curroomp->faces[Curface].light_multiple) / 4.0);
|
|
ebox->SetWindowText(str);
|
|
}
|
|
|
|
void CLightingDialog::OnPaint() {
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
UpdateDialog();
|
|
|
|
// Do not call CDialog::OnPaint() for painting messages
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusAlphaEdit() {
|
|
CEdit *ebox;
|
|
char str[40];
|
|
float aval;
|
|
int i, alphaed = 0;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ALPHA_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 1.0)
|
|
aval = 1.0;
|
|
|
|
Curroomp->faces[Curface].face_uvls[Curvert].alpha = Float_to_ubyte(aval);
|
|
|
|
for (i = 0; i < Curroomp->faces[Curface].num_verts; i++)
|
|
if (Curroomp->faces[Curface].face_uvls[i].alpha != 255)
|
|
alphaed = 1;
|
|
|
|
if (alphaed)
|
|
Curroomp->faces[Curface].flags |= FF_VERTEX_ALPHA;
|
|
else
|
|
Curroomp->faces[Curface].flags &= ~FF_VERTEX_ALPHA;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
extern bool Outline_lightmaps;
|
|
void CLightingDialog::OnShowLightmaps() {
|
|
int c = IsDlgButtonChecked(IDC_SHOW_LIGHTMAPS);
|
|
|
|
if (c)
|
|
Outline_lightmaps = 1;
|
|
else
|
|
Outline_lightmaps = 0;
|
|
|
|
State_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusHemicubeResEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_HEMICUBE_RES_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < 50)
|
|
val = 50;
|
|
if (val > 2048)
|
|
val = 2048;
|
|
|
|
if ((val % 2) == 1)
|
|
val++;
|
|
|
|
Hemicube_resolution = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusLightSpacingEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_SPACING_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < 1)
|
|
val = 1;
|
|
if (val > 20)
|
|
val = 20;
|
|
|
|
LightSpacing = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnBestfitCheck() {
|
|
int c = IsDlgButtonChecked(IDC_BESTFIT_CHECK);
|
|
|
|
BestFit = c;
|
|
|
|
State_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::UpdateKeypad(int mask) {
|
|
if (mask & (KUF_CURROOM_CHANGED + KUF_CURFACE_CHANGED + KUF_CURPORTAL_CHANGED))
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::ShootRayForLighting(vector *dest, vector *from, vector *to, int startseg) {
|
|
fvi_info hit_info;
|
|
fvi_query fq;
|
|
|
|
// shoot a ray from the light position to the current vertex
|
|
fq.p0 = from;
|
|
fq.p1 = to;
|
|
fq.startroom = startseg;
|
|
|
|
fq.rad = 0.0f;
|
|
fq.flags = FQ_CHECK_OBJS | FQ_IGNORE_NON_LIGHTMAP_OBJECTS | FQ_NO_RELINK | FQ_IGNORE_RENDER_THROUGH_PORTALS;
|
|
fq.thisobjnum = -1;
|
|
fq.ignore_obj_list = NULL;
|
|
|
|
fvi_FindIntersection(&fq, &hit_info);
|
|
|
|
*dest = hit_info.hit_pnt;
|
|
}
|
|
|
|
#define MAX_VOLUMETRIC_DISTANCE 5000
|
|
|
|
// Creates a volumetric cone of light that casts from the center of the current face
|
|
void CLightingDialog::OnCreateVolumeCone() {
|
|
int i, t;
|
|
|
|
ASSERT(Curface < Curroomp->num_faces);
|
|
int resolution = m_resolution;
|
|
int first_vert_index, first_face_index, center_index;
|
|
|
|
vector faceverts[MAX_VERTS_PER_FACE];
|
|
vector center;
|
|
matrix face_matrix;
|
|
|
|
vector fvec = Curroomp->faces[Curface].normal;
|
|
|
|
float pitch_increment = 65536 / resolution;
|
|
float heading_increment = 65536 / resolution;
|
|
float desired_angle = m_angle;
|
|
float pitch, heading;
|
|
|
|
// Fixup angle for our system
|
|
desired_angle = (desired_angle / 360.0) * 65536;
|
|
|
|
// Get face matrix
|
|
vm_VectorToMatrix(&face_matrix, &fvec, NULL, NULL);
|
|
vm_TransposeMatrix(&face_matrix);
|
|
|
|
// Get polygon center
|
|
face *fp = &Curroomp->faces[Curface];
|
|
for (i = 0; i < fp->num_verts; i++)
|
|
faceverts[i] = Curroomp->verts[fp->face_verts[i]];
|
|
vm_GetCentroid(¢er, faceverts, fp->num_verts);
|
|
|
|
// Add vertices to room
|
|
center_index = Curroomp->num_verts;
|
|
RoomAddVertices(Curroomp, resolution + 1);
|
|
Curroomp->verts[center_index] = center;
|
|
first_vert_index = center_index + 1;
|
|
|
|
for (i = 0; i < resolution; i++) {
|
|
vector dest_vec;
|
|
vector hit_vec;
|
|
|
|
matrix tempm;
|
|
|
|
// Get our direction
|
|
heading = FixCos(heading_increment * i);
|
|
pitch = FixSin(pitch_increment * i);
|
|
|
|
vm_AnglesToMatrix(&tempm, pitch * desired_angle, heading * desired_angle, 0);
|
|
vm_MatrixMulVector(&dest_vec, &tempm.fvec, &face_matrix);
|
|
|
|
dest_vec *= m_falloff;
|
|
dest_vec += center;
|
|
|
|
// Now shoot a ray out
|
|
ShootRayForLighting(&hit_vec, ¢er, &dest_vec, Curroomp - Rooms);
|
|
|
|
Curroomp->verts[first_vert_index + i] = hit_vec;
|
|
}
|
|
|
|
// Add faces to room
|
|
first_face_index = Curroomp->num_faces;
|
|
RoomAddFaces(Curroomp, resolution);
|
|
|
|
for (i = 0; i < resolution; i++) {
|
|
int a = center_index;
|
|
int b = first_vert_index + i;
|
|
int c = first_vert_index + ((i + 1) % resolution);
|
|
|
|
// First do front face
|
|
fp = &Curroomp->faces[first_face_index + i];
|
|
|
|
InitRoomFace(fp, 3);
|
|
fp->flags |= FF_VOLUMETRIC;
|
|
fp->tmap = D3EditState.texdlg_texture;
|
|
|
|
fp->face_verts[0] = a;
|
|
fp->face_verts[1] = b;
|
|
fp->face_verts[2] = c;
|
|
|
|
if (!ComputeFaceNormal(Curroomp, first_face_index + i))
|
|
Int3(); // Get Jason
|
|
|
|
AssignDefaultUVsToRoomFace(Curroomp, first_face_index + i);
|
|
|
|
// Now assign appropriate alpha
|
|
|
|
fp->face_uvls[0].alpha = Float_to_ubyte(m_start_alpha);
|
|
for (t = 1; t < 3; t++) {
|
|
vector subvec = Curroomp->verts[fp->face_verts[t]] - center;
|
|
float mag = vm_GetMagnitude(&subvec);
|
|
float norm = 1 - (mag / m_falloff);
|
|
if (norm < 0)
|
|
norm = 0;
|
|
fp->face_uvls[t].alpha = Float_to_ubyte(norm * m_start_alpha);
|
|
}
|
|
}
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnClearVolumetricRoom() {
|
|
int i;
|
|
|
|
StartOver:
|
|
for (i = 0; i < Curroomp->num_faces; i++) {
|
|
face *fp = &Curroomp->faces[i];
|
|
if (fp->flags & FF_VOLUMETRIC) {
|
|
DeleteRoomFace(Curroomp, i);
|
|
goto StartOver;
|
|
}
|
|
}
|
|
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnFillVolumeTexture() {
|
|
int i;
|
|
|
|
for (i = 0; i < Curroomp->num_faces; i++) {
|
|
face *fp = &Curroomp->faces[i];
|
|
if (fp->flags & FF_VOLUMETRIC)
|
|
Curroomp->faces[i].tmap = D3EditState.texdlg_texture;
|
|
}
|
|
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusAngleEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ANGLE_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < 0)
|
|
val = 0;
|
|
if (val > 90)
|
|
val = 70;
|
|
|
|
m_angle = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusStartAlphaEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_START_ALPHA_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < 0)
|
|
val = 0;
|
|
if (val > 1)
|
|
val = 1;
|
|
|
|
m_start_alpha = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusResolutionEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_RESOLUTION_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < 1)
|
|
val = 1;
|
|
if (val > 200)
|
|
val = 200;
|
|
|
|
m_resolution = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnEdgeVolumetric() {
|
|
int i, t;
|
|
float rad, mytan, tan_table[360];
|
|
|
|
ASSERT(Curface < Curroomp->num_faces);
|
|
int resolution = m_resolution;
|
|
int first_vert_index, first_face_index, index, face_index;
|
|
face *cur_fp = &Curroomp->faces[Curface];
|
|
vector subvec;
|
|
int total_face_verts, num_new_verts;
|
|
|
|
float falloff_distance = 0;
|
|
vector nvec = Curroomp->faces[Curface].normal;
|
|
vector fvec;
|
|
|
|
vector faceverts[MAX_VERTS_PER_FACE];
|
|
vector center;
|
|
int pitch = m_pitch_angle;
|
|
int heading = m_heading_angle;
|
|
|
|
if (pitch < 0)
|
|
pitch += 360;
|
|
if (heading < 0)
|
|
heading += 360;
|
|
|
|
int desired_pitch = pitch * (65536.0 / 360.0);
|
|
int desired_heading = heading * (65536.0 / 360.0);
|
|
matrix tempm, face_matrix;
|
|
|
|
// Get facematrix
|
|
vm_VectorToMatrix(&face_matrix, &nvec, NULL, NULL);
|
|
vm_TransposeMatrix(&face_matrix);
|
|
|
|
// Get adjusted angle of direction
|
|
vm_AnglesToMatrix(&tempm, desired_pitch, desired_heading, 0);
|
|
vm_MatrixMulVector(&fvec, &tempm.fvec, &face_matrix);
|
|
|
|
// Build tan table
|
|
for (i = 0; i < 360; i++) {
|
|
rad = (float)(3.14 * (float)i / 180.0);
|
|
mytan = tan(rad);
|
|
tan_table[i] = mytan;
|
|
}
|
|
|
|
// Get polygon center
|
|
face *fp = &Curroomp->faces[Curface];
|
|
for (i = 0; i < fp->num_verts; i++)
|
|
faceverts[i] = Curroomp->verts[fp->face_verts[i]];
|
|
vm_GetCentroid(¢er, faceverts, fp->num_verts);
|
|
|
|
// Add vertices to room
|
|
total_face_verts = cur_fp->num_verts;
|
|
first_vert_index = Curroomp->num_verts;
|
|
RoomAddVertices(Curroomp, cur_fp->num_verts * resolution * 2);
|
|
num_new_verts = cur_fp->num_verts * resolution * 2;
|
|
index = first_vert_index;
|
|
|
|
// Compute the rays
|
|
for (i = 0; i < total_face_verts; i++) {
|
|
vector vec_a = Curroomp->verts[cur_fp->face_verts[i]];
|
|
vector vec_b = Curroomp->verts[cur_fp->face_verts[(i + 1) % total_face_verts]];
|
|
subvec = vec_b - vec_a;
|
|
vector add_vec = subvec / resolution;
|
|
|
|
for (t = 0; t < resolution; t++, index += 2) {
|
|
vector dest_vec;
|
|
vector hit_vec;
|
|
vector src_vec;
|
|
vector norm_vec;
|
|
vector subvec;
|
|
float cone_distance, mag;
|
|
|
|
src_vec = vec_a + (add_vec * t);
|
|
src_vec += (cur_fp->normal / 64.0);
|
|
dest_vec = src_vec + (fvec * m_falloff);
|
|
|
|
cone_distance = tan_table[m_angle] * m_falloff;
|
|
norm_vec = center + (fvec * m_falloff);
|
|
subvec = dest_vec - norm_vec;
|
|
mag = vm_GetMagnitude(&subvec);
|
|
if (mag < cone_distance) {
|
|
vm_NormalizeVector(&subvec);
|
|
dest_vec = norm_vec + (subvec * cone_distance);
|
|
}
|
|
|
|
// Now shoot a ray out
|
|
ShootRayForLighting(&hit_vec, &src_vec, &dest_vec, Curroomp - Rooms);
|
|
|
|
Curroomp->verts[index] = src_vec;
|
|
Curroomp->verts[index + 1] = hit_vec;
|
|
}
|
|
}
|
|
|
|
// Add faces to room
|
|
first_face_index = Curroomp->num_faces;
|
|
RoomAddFaces(Curroomp, resolution * total_face_verts);
|
|
index = first_vert_index;
|
|
face_index = first_face_index;
|
|
|
|
for (i = 0; i < total_face_verts; i++) {
|
|
for (t = 0; t < resolution; t++, index += 2, face_index++) {
|
|
int a = index;
|
|
int b = (index + 2);
|
|
int c = (index + 3);
|
|
int d = index + 1;
|
|
|
|
if ((b - first_vert_index) >= num_new_verts)
|
|
b -= num_new_verts;
|
|
if ((c - first_vert_index) >= num_new_verts)
|
|
c -= num_new_verts;
|
|
|
|
// First do front face
|
|
face *fp = &Curroomp->faces[face_index];
|
|
|
|
InitRoomFace(fp, 4);
|
|
fp->flags |= FF_VOLUMETRIC;
|
|
fp->tmap = D3EditState.texdlg_texture;
|
|
|
|
fp->face_verts[0] = a;
|
|
fp->face_verts[1] = b;
|
|
fp->face_verts[2] = c;
|
|
fp->face_verts[3] = d;
|
|
|
|
if (!ComputeFaceNormal(Curroomp, face_index))
|
|
Int3(); // Get Jason
|
|
|
|
AssignDefaultUVsToRoomFace(Curroomp, face_index);
|
|
|
|
// Now assign appropriate alpha
|
|
|
|
fp->face_uvls[0].alpha = Float_to_ubyte(m_start_alpha);
|
|
fp->face_uvls[1].alpha = Float_to_ubyte(m_start_alpha);
|
|
|
|
subvec = Curroomp->verts[c] - Curroomp->verts[b];
|
|
float mag = vm_GetMagnitude(&subvec);
|
|
float norm = 1 - (mag / m_falloff);
|
|
if (norm < 0)
|
|
norm = 0;
|
|
fp->face_uvls[2].alpha = Float_to_ubyte(norm * m_start_alpha);
|
|
|
|
subvec = Curroomp->verts[d] - Curroomp->verts[a];
|
|
mag = vm_GetMagnitude(&subvec);
|
|
norm = 1 - (mag / m_falloff);
|
|
if (norm < 0)
|
|
norm = 0;
|
|
fp->face_uvls[3].alpha = Float_to_ubyte(norm * m_start_alpha);
|
|
}
|
|
}
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusFalloffEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FALLOFF_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < 2)
|
|
val = 2;
|
|
if (val > 2000)
|
|
val = 2000;
|
|
|
|
m_falloff = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnFarthestPoint() {
|
|
face *fp = &Curroomp->faces[Curface];
|
|
float max_distance = 0;
|
|
char str[255];
|
|
int i;
|
|
|
|
for (i = 0; i < fp->num_verts; i++) {
|
|
vector dest_vec;
|
|
vector hit_vec;
|
|
vector src_vec;
|
|
vector subvec;
|
|
|
|
src_vec = Curroomp->verts[fp->face_verts[i]];
|
|
src_vec += (fp->normal / 64.0);
|
|
dest_vec = src_vec + (fp->normal * MAX_VOLUMETRIC_DISTANCE);
|
|
|
|
// Now shoot a ray out
|
|
ShootRayForLighting(&hit_vec, &src_vec, &dest_vec, Curroomp - Rooms);
|
|
|
|
subvec = hit_vec - src_vec;
|
|
float mag = vm_GetMagnitude(&subvec);
|
|
if (mag > max_distance)
|
|
max_distance = mag;
|
|
}
|
|
|
|
sprintf(str, "The farthest point is %f units away. Do you wish to set the falloff rate to this value?",
|
|
max_distance);
|
|
int answer = MessageBox(str, "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
m_falloff = max_distance;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusPitchAngleEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PITCH_ANGLE_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < -70)
|
|
val = -70;
|
|
if (val > 70)
|
|
val = 70;
|
|
|
|
m_pitch_angle = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusHeadingAngleEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_HEADING_ANGLE_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atoi(str);
|
|
|
|
if (val < -70)
|
|
val = -70;
|
|
if (val > 70)
|
|
val = 70;
|
|
|
|
m_heading_angle = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnHemicubeCheck() {
|
|
int c = IsDlgButtonChecked(IDC_HEMICUBE_CHECK);
|
|
|
|
if (c)
|
|
D3EditState.hemicube_radiosity = 1;
|
|
else
|
|
D3EditState.hemicube_radiosity = 0;
|
|
}
|
|
|
|
void CLightingDialog::OnCountTerrainLights() {
|
|
int lightcount, i, t;
|
|
char str[1000];
|
|
|
|
for (lightcount = 0, i = 0; i < TERRAIN_WIDTH * TERRAIN_DEPTH; i++) {
|
|
if (Terrain_seg[i].flags & TF_INVISIBLE)
|
|
continue;
|
|
|
|
int texnum = Terrain_tex_seg[Terrain_seg[i].texseg_index].tex_index;
|
|
if (GameTextures[texnum].r > 0 || GameTextures[texnum].g > 0 || GameTextures[texnum].b > 0)
|
|
lightcount += 2;
|
|
}
|
|
|
|
lightcount += Terrain_sky.num_satellites;
|
|
|
|
for (i = 0; i <= Highest_object_index; i++) {
|
|
if (!OBJECT_OUTSIDE(&Objects[i]))
|
|
continue;
|
|
|
|
if (Objects[i].type != OBJ_NONE && Objects[i].lighting_render_type == LRT_LIGHTMAPS) {
|
|
poly_model *po = &Poly_models[Objects[i].rtype.pobj_info.model_num];
|
|
|
|
if (!po->new_style)
|
|
continue;
|
|
|
|
for (t = 0; t < po->n_models; t++) {
|
|
bsp_info *sm = &po->submodel[t];
|
|
|
|
if (IsNonRenderableSubmodel(po, t))
|
|
continue;
|
|
|
|
for (int j = 0; j < sm->num_faces; j++) {
|
|
if (sm->faces[j].texnum == -1)
|
|
continue;
|
|
|
|
int texnum = po->textures[sm->faces[j].texnum];
|
|
if (GameTextures[texnum].r > 0 || GameTextures[texnum].g > 0 || GameTextures[texnum].b > 0)
|
|
lightcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Count rooms
|
|
for (i = 0; i < MAX_ROOMS; i++) {
|
|
if (Rooms[i].used && (Rooms[i].flags & RF_EXTERNAL)) {
|
|
for (t = 0; t < Rooms[i].num_faces; t++) {
|
|
int texnum = Rooms[i].faces[t].tmap;
|
|
if (GameTextures[texnum].r > 0 || GameTextures[texnum].g > 0 || GameTextures[texnum].b > 0)
|
|
lightcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(str,
|
|
"There are %d lights present on the terrain. Do you wish for me to set the 'light iterations' control to "
|
|
"match this number?",
|
|
lightcount);
|
|
int answer = MessageBox(str, "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
CEdit *ebox;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_ITERATION_EDIT);
|
|
sprintf(str, "%d", lightcount);
|
|
ebox->SetWindowText(str);
|
|
|
|
rad_MaxStep = lightcount;
|
|
}
|
|
|
|
void CLightingDialog::OnCurroomRadiosity() {
|
|
MessageBox("I will now calculate radiosity for the current room. You may prematurely break out by pressing any key "
|
|
"during the calculations",
|
|
"Message", MB_OK);
|
|
|
|
DoRadiosityForCurrentRoom(Curroomp);
|
|
World_changed = 1;
|
|
}
|
|
|
|
void DoTerrainDynamicTable();
|
|
void CLightingDialog::OnDynamicTerrain() {
|
|
if ((MessageBox("Are you sure you wish to do dynamic lighting on the terrain. The reason I ask is that this "
|
|
"procedure takes a long time, and I don't want to upset you.",
|
|
"Question", MB_YESNO)) == IDYES)
|
|
DoTerrainDynamicTable();
|
|
}
|
|
|
|
void CLightingDialog::OnBlurLightmaps() {
|
|
|
|
if ((MessageBox("Are you sure you wish to blur all lightmaps? This operation cannot be undone...", "Question",
|
|
MB_YESNO)) == IDYES) {
|
|
BlurLightmapInfos(LMI_ROOM);
|
|
BlurLightmapInfos(LMI_ROOM_OBJECT);
|
|
BlurLightmapInfos(LMI_EXTERNAL_ROOM);
|
|
BlurLightmapInfos(LMI_TERRAIN_OBJECT);
|
|
|
|
OutrageMessageBox("Blurring complete.");
|
|
}
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusIgnoreLimitEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_IGNORE_LIMIT_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < 0 || val > .5) {
|
|
OutrageMessageBox("Invalid value. Must be in the range 0 to .5!");
|
|
return;
|
|
}
|
|
|
|
Ignore_limit = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusRedAmbientEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_RED_AMBIENT_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < 0 || val > 1.0) {
|
|
OutrageMessageBox("Invalid value. Must be in the range 0 to 1.0!");
|
|
return;
|
|
}
|
|
|
|
Ambient_red = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusGreenAmbientEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_GREEN_AMBIENT_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < 0 || val > 1.0) {
|
|
OutrageMessageBox("Invalid value. Must be in the range 0 to 1.0!");
|
|
return;
|
|
}
|
|
|
|
Ambient_green = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusBlueAmbientEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_BLUE_AMBIENT_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < 0 || val > 1.0) {
|
|
OutrageMessageBox("Invalid value. Must be in the range 0 to 1.0!");
|
|
return;
|
|
}
|
|
|
|
Ambient_blue = val;
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnElementCheck() {
|
|
int c = IsDlgButtonChecked(IDC_ELEMENT_CHECK);
|
|
|
|
if (c)
|
|
Shoot_from_patch = 0;
|
|
else
|
|
Shoot_from_patch = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnIgnoreTerrain() {
|
|
int c = IsDlgButtonChecked(IDC_IGNORE_TERRAIN);
|
|
|
|
if (c)
|
|
Ignore_terrain = 1;
|
|
else
|
|
Ignore_terrain = 0;
|
|
}
|
|
|
|
void CLightingDialog::OnIgnoreSatellites() {
|
|
int c = IsDlgButtonChecked(IDC_IGNORE_SATELLITES);
|
|
|
|
if (c)
|
|
Ignore_satellites = 1;
|
|
else
|
|
Ignore_satellites = 0;
|
|
}
|
|
|
|
void CLightingDialog::OnUseBspCheck() {
|
|
int c = IsDlgButtonChecked(IDC_USE_BSP_CHECK);
|
|
|
|
if (c)
|
|
UseBSP = 1;
|
|
else
|
|
UseBSP = 0;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusLightMultiplyEdit() {
|
|
if (Curroomp == NULL)
|
|
return;
|
|
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float val;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_LIGHT_MULTIPLY_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
val = atof(str);
|
|
|
|
if (val < .25 || val > 63.75) {
|
|
OutrageMessageBox("Invalid value, setting to one!");
|
|
val = 1.0;
|
|
}
|
|
|
|
Curroomp->faces[Curface].light_multiple = (val * 4.0);
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusPulseTimeEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PULSE_TIME_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atol(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 255)
|
|
aval = 255;
|
|
|
|
Curroomp->pulse_time = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusPulseOffsetEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
int aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_PULSE_OFFSET_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atol(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 255)
|
|
aval = 255;
|
|
|
|
Curroomp->pulse_offset = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnPulseRoom() {
|
|
int ptime = Curroomp->pulse_time;
|
|
int poffset = Curroomp->pulse_offset;
|
|
|
|
SetRoomPulse(Curroomp, ptime, poffset);
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnResetMultiples() {
|
|
int testroom;
|
|
int answer = MessageBox("Are you sure you wish to reset all light multiples?", "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
answer = MessageBox("Just for this room? (Answering no does it for the entire mine)", "Light Question", MB_YESNO);
|
|
|
|
if (answer == IDNO)
|
|
testroom = -1;
|
|
else
|
|
testroom = Curroomp - Rooms;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i <= Highest_room_index; i++) {
|
|
if (Rooms[i].used) {
|
|
if (testroom != -1 && i != testroom)
|
|
continue;
|
|
|
|
for (int t = 0; t < Rooms[i].num_faces; t++) {
|
|
Rooms[i].faces[t].light_multiple = 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
OutrageMessageBox("Light multiples reset!");
|
|
}
|
|
|
|
void CLightingDialog::OnDestroyBsp() {
|
|
int answer = MessageBox("Are you sure you wish to destroy the BSP tree?", "Light Question", MB_YESNO);
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
if (BSP_initted) {
|
|
DestroyBSPTree(&MineBSP);
|
|
}
|
|
|
|
OutrageMessageBox("BSP tree destroyed!");
|
|
}
|
|
|
|
void CLightingDialog::OnCombineFaces() {
|
|
int c = IsDlgButtonChecked(IDC_COMBINE_FACES);
|
|
|
|
if (c)
|
|
AllowCombining = 1;
|
|
else
|
|
AllowCombining = 0;
|
|
}
|
|
|
|
// Takes a bitmap name and resaves it
|
|
void ResaveBitmap(const char *name) {
|
|
int bm_handle = bm_FindBitmapName(name);
|
|
if (bm_handle >= 0) {
|
|
char search[256];
|
|
|
|
// Make sure it is paged in
|
|
bm_data(bm_handle, 0);
|
|
|
|
ddio_MakePath(search, LocalD3Dir, "data", "graphics", GameBitmaps[bm_handle].name, NULL);
|
|
mprintf(0, "Resaving bitmap %s.\n", search);
|
|
|
|
bm_SaveFileBitmap(search, bm_handle);
|
|
} else {
|
|
char search[256];
|
|
|
|
ddio_MakePath(search, LocalD3Dir, "data", "graphics", name, NULL);
|
|
|
|
bm_handle = bm_AllocLoadFileBitmap(search, 0);
|
|
if (bm_handle >= 0) {
|
|
// Make sure it is paged in
|
|
bm_data(bm_handle, 0);
|
|
|
|
mprintf(0, "Resaving bitmap %s.\n", search);
|
|
|
|
bm_SaveFileBitmap(search, bm_handle);
|
|
} else
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
// Takes a vclip name and resaves it
|
|
void ResaveVClip(const char *name) {
|
|
int bm_handle = FindVClipName(name);
|
|
if (bm_handle >= 0) {
|
|
char search[256];
|
|
|
|
ddio_MakePath(search, LocalD3Dir, "data", "graphics", GameVClips[bm_handle].name, NULL);
|
|
mprintf(0, "Resaving vclip %s.\n", search);
|
|
|
|
SaveVClip(search, bm_handle);
|
|
} else {
|
|
char search[256];
|
|
|
|
ddio_MakePath(search, LocalD3Dir, "data", "graphics", name, NULL);
|
|
|
|
bm_handle = AllocLoadVClip(search, NOT_TEXTURE, 0);
|
|
if (bm_handle >= 0) {
|
|
mprintf(0, "Resaving vclip %s.\n", search);
|
|
|
|
SaveVClip(search, bm_handle);
|
|
} else
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
void ResaveAllBitmaps() {
|
|
ddio_DoForeachFile(std::filesystem::path(LocalD3Dir) / "data" / "graphics", std::regex(".+\\.ogf"),
|
|
[](const std::filesystem::path &path) { ResaveBitmap(path.filename().u8string().c_str()); });
|
|
ddio_DoForeachFile(std::filesystem::path(LocalD3Dir) / "data" / "graphics", std::regex(".+\\.oaf"),
|
|
[](const std::filesystem::path &path) { ResaveVClip(path.filename().u8string().c_str()); });
|
|
}
|
|
|
|
void CLightingDialog::OnVolumeLights() {
|
|
int c = IsDlgButtonChecked(IDC_VOLUME_LIGHTS);
|
|
|
|
if (c)
|
|
UseVolumeLights = 1;
|
|
else
|
|
UseVolumeLights = 0;
|
|
}
|
|
|
|
void CLightingDialog::OnCoronaCheck() {
|
|
if (Curroomp == NULL)
|
|
return;
|
|
|
|
int c = IsDlgButtonChecked(IDC_CORONA_CHECK);
|
|
|
|
if (c)
|
|
Curroomp->faces[Curface].flags |= FF_CORONA;
|
|
else
|
|
Curroomp->faces[Curface].flags &= ~FF_CORONA;
|
|
}
|
|
|
|
void CLightingDialog::OnFogCheck() {
|
|
if (Curroomp == NULL)
|
|
return;
|
|
|
|
int c = IsDlgButtonChecked(IDC_FOG_CHECK);
|
|
|
|
if (c)
|
|
Curroomp->flags |= RF_FOG;
|
|
else
|
|
Curroomp->flags &= ~RF_FOG;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusFogDensity() {
|
|
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_DENSITY);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 5;
|
|
if (aval > 5000)
|
|
aval = 5000;
|
|
|
|
Curroomp->fog_depth = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusFogRed() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_RED);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 1.0)
|
|
aval = 1;
|
|
|
|
Curroomp->fog_r = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusFogGreen() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_GREEN);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 1.0)
|
|
aval = 1;
|
|
|
|
Curroomp->fog_g = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusFogBlue() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_FOG_BLUE);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
if (aval > 1.0)
|
|
aval = 1;
|
|
|
|
Curroomp->fog_b = aval;
|
|
|
|
UpdateDialog();
|
|
World_changed = 1;
|
|
}
|
|
|
|
void CLightingDialog::OnRoomCoronas() {
|
|
int rev, answer, only_cur_texture;
|
|
|
|
rev = IsDlgButtonChecked(IDC_REVERSE_CORONA);
|
|
|
|
if (rev)
|
|
answer = MessageBox("Are you sure you wish to remove all coronas in the current room?", "Light Question", MB_YESNO);
|
|
else
|
|
answer = MessageBox("Are you sure you wish to make all lights in the current room have coronas?", "Light Question",
|
|
MB_YESNO);
|
|
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
only_cur_texture = MessageBox(
|
|
"Do you wish to do this operation only on the faces that have the same texture as the currently selected face?",
|
|
"Light Question", MB_YESNO);
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < Curroomp->num_faces; i++) {
|
|
if (only_cur_texture == IDYES) {
|
|
if (Curroomp->faces[i].tmap != Curroomp->faces[Curface].tmap)
|
|
continue;
|
|
}
|
|
|
|
if (rev)
|
|
Curroomp->faces[i].flags &= ~FF_CORONA;
|
|
else
|
|
Curroomp->faces[i].flags |= FF_CORONA;
|
|
}
|
|
|
|
World_changed = 1;
|
|
|
|
OutrageMessageBox("Operation complete!");
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnMineCoronas() {
|
|
int answer, only_cur_texture;
|
|
int rev;
|
|
|
|
rev = IsDlgButtonChecked(IDC_REVERSE_CORONA);
|
|
|
|
if (rev)
|
|
answer = MessageBox("Are you sure you wish to remove all coronas in this level?", "Light Question", MB_YESNO);
|
|
else
|
|
answer =
|
|
MessageBox("Are you sure you wish to make all lights in the mine have coronas?", "Light Question", MB_YESNO);
|
|
|
|
if (answer == IDNO)
|
|
return;
|
|
|
|
only_cur_texture = MessageBox(
|
|
"Do you wish to do this operation only on the faces that have the same texture as the currently selected face?",
|
|
"Light Question", MB_YESNO);
|
|
|
|
int i, t;
|
|
|
|
for (i = 0; i <= Highest_room_index; i++) {
|
|
if (!Rooms[i].used)
|
|
continue;
|
|
if ((Rooms[i].flags & RF_EXTERNAL))
|
|
continue;
|
|
|
|
for (t = 0; t < Rooms[i].num_faces; t++) {
|
|
if (only_cur_texture == IDYES) {
|
|
if (Rooms[i].faces[t].tmap != Curroomp->faces[Curface].tmap)
|
|
continue;
|
|
}
|
|
|
|
if (!rev)
|
|
Rooms[i].faces[t].flags |= FF_CORONA;
|
|
else
|
|
Rooms[i].faces[t].flags &= ~FF_CORONA;
|
|
}
|
|
}
|
|
|
|
World_changed = 1;
|
|
|
|
OutrageMessageBox("Operation complete!");
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnReverseCorona() {
|
|
// TODO: Add your control notification handler code here
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusGlobalMultiplierEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_GLOBAL_MULTIPLIER_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
|
|
GlobalMultiplier = aval;
|
|
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnStrobeCheck() {
|
|
if (Curroomp == NULL)
|
|
return;
|
|
|
|
int c = IsDlgButtonChecked(IDC_STROBE_CHECK);
|
|
|
|
if (c)
|
|
Curroomp->flags |= RF_STROBE;
|
|
else
|
|
Curroomp->flags &= ~RF_STROBE;
|
|
}
|
|
|
|
void CLightingDialog::OnFlickerCheck() {
|
|
if (Curroomp == NULL)
|
|
return;
|
|
|
|
int c = IsDlgButtonChecked(IDC_FLICKER_CHECK);
|
|
|
|
if (c)
|
|
Curroomp->flags |= RF_FLICKER;
|
|
else
|
|
Curroomp->flags &= ~RF_FLICKER;
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusRoomMultiplierEdit() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_MULTIPLIER_EDIT);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
|
|
Room_multiplier[Curroomp - Rooms] = aval;
|
|
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusRoomAmred() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMRED);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
|
|
Room_ambience_r[Curroomp - Rooms] = aval;
|
|
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusRoomAmgreen() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMGREEN);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
|
|
Room_ambience_g[Curroomp - Rooms] = aval;
|
|
|
|
UpdateDialog();
|
|
}
|
|
|
|
void CLightingDialog::OnKillfocusRoomAmblue() {
|
|
CEdit *ebox;
|
|
char str[20];
|
|
float aval;
|
|
|
|
ebox = (CEdit *)GetDlgItem(IDC_ROOM_AMBLUE);
|
|
ebox->GetWindowText(str, 20);
|
|
|
|
aval = atof(str);
|
|
if (aval < 0)
|
|
aval = 0;
|
|
|
|
Room_ambience_b[Curroomp - Rooms] = aval;
|
|
|
|
UpdateDialog();
|
|
}
|
|
|
|
#include "object_lighting.h"
|
|
|
|
void CLightingDialog::OnClearLightmaps() {
|
|
if (OutrageMessageBox(
|
|
MBOX_YESNO,
|
|
"Are you sure you want to clear the lightmaps? If you say yes, your level will have no lighting.") != IDYES)
|
|
return;
|
|
|
|
ClearAllRoomLightmaps(0);
|
|
ClearAllObjectLightmaps(0);
|
|
}
|
|
|
|
int CopyFaceLightMultipleRoom(room *rp, int tmap, float multiple) {
|
|
int n_changed = 0;
|
|
|
|
for (int f = 0; f < rp->num_faces; f++)
|
|
if (rp->faces[f].tmap == tmap) {
|
|
rp->faces[f].light_multiple = multiple;
|
|
n_changed++;
|
|
}
|
|
|
|
return n_changed;
|
|
}
|
|
|
|
void CopyFaceLightMultiple(room *rp, int facenum) {
|
|
int answer = OutrageMessageBox(
|
|
MBOX_YESNOCANCEL,
|
|
"Do you want to copy the light multiple from face %d to all faces in the mine that have the same texture?\n\n"
|
|
"YES means copy to faces in the whole mine.\n"
|
|
"NO means copy just to faces in the same room.\n"
|
|
"CANCEL will abort this operation.",
|
|
facenum);
|
|
|
|
if (answer == IDCANCEL)
|
|
return;
|
|
|
|
int n_changed = 0;
|
|
if (answer == IDNO)
|
|
n_changed = CopyFaceLightMultipleRoom(rp, rp->faces[facenum].tmap, rp->faces[facenum].light_multiple);
|
|
else {
|
|
for (int r = 0; r <= Highest_room_index; r++) {
|
|
if (Rooms[r].used)
|
|
n_changed += CopyFaceLightMultipleRoom(&Rooms[r], rp->faces[facenum].tmap, rp->faces[facenum].light_multiple);
|
|
}
|
|
}
|
|
|
|
n_changed--; // don't count the source face
|
|
|
|
if (n_changed) {
|
|
EditorStatus("The light multiple has been changed for %d faces.", n_changed);
|
|
World_changed = 1;
|
|
} else
|
|
EditorStatus("No faces had the same texture as face %d.", facenum);
|
|
}
|
|
|
|
void CLightingDialog::OnCopyMultiplier() { CopyFaceLightMultiple(Curroomp, Curface); }
|