Serious-Engine/Sources/WorldEditor/DlgPgPolygon.cpp
2016-03-11 18:20:51 -06:00

419 lines
14 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
// DlgPgPolygon.cpp : implementation file
//
#include "stdafx.h"
#include "DlgPgPolygon.h"
#ifdef _DEBUG
#undef new
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDlgPgPolygon property page
IMPLEMENT_DYNCREATE(CDlgPgPolygon, CPropertyPage)
CDlgPgPolygon::CDlgPgPolygon() : CPropertyPage(CDlgPgPolygon::IDD)
{
//{{AFX_DATA_INIT(CDlgPgPolygon)
//}}AFX_DATA_INIT
}
CDlgPgPolygon::~CDlgPgPolygon()
{
}
void CDlgPgPolygon::DoDataExchange(CDataExchange* pDX)
{
if( theApp.m_bDisableDataExchange) return;
CPropertyPage::DoDataExchange(pDX);
// mark that property page has been modified
SetModified( TRUE);
// obtain document
CWorldEditorDoc* pDoc = theApp.GetDocument();
if( pDoc == NULL) return;
// polygon mode must be on
if( pDoc->GetEditingMode() != POLYGON_MODE) return;
// get flags of control activity
BOOL bSelectionExists = pDoc->m_selPolygonSelection.Count() != 0;
// if dialog is recieving data and control window is valid
if( (pDX->m_bSaveAndValidate == FALSE) && IsWindow( m_IsPortal.m_hWnd) )
{
// initialize combo boxes
InitComboBoxes();
// polygon controls exist if polygon selection exists
m_IsPortal.EnableWindow( bSelectionExists);
m_IsOldPortal.EnableWindow( bSelectionExists);
m_IsOccluder.EnableWindow( bSelectionExists);
m_IsPassable.EnableWindow( bSelectionExists);
m_bStairs.EnableWindow( bSelectionExists);
m_bShootThru.EnableWindow( bSelectionExists);
m_IsInvisible.EnableWindow( bSelectionExists);
m_IsDoubleSided.EnableWindow( bSelectionExists);
m_bIsDetail.EnableWindow( bSelectionExists);
m_IsTranslucent.EnableWindow( bSelectionExists);
m_IsTransparent.EnableWindow( bSelectionExists);
m_ComboMirror.EnableWindow( bSelectionExists);
m_ComboFriction.EnableWindow( bSelectionExists);
GetDlgItem( IDC_STATIC_MIRROR)->EnableWindow( bSelectionExists);
GetDlgItem( IDC_STATIC_FRICTION)->EnableWindow( bSelectionExists);
GetDlgItem( IDC_PRETENDER_DISTANCE)->EnableWindow( bSelectionExists);
GetDlgItem( IDC_STATIC_PRETENDER_DISTANCE)->EnableWindow( bSelectionExists);
// if selection exists, calculate tri-state value of attribute intersection
if( bSelectionExists)
{
// get friction, illumination, mirror and effect properties from first polygon
UBYTE ubFirstFriction;
UBYTE ubFirstMirror;
BOOL bSameFriction = TRUE;
BOOL bSameMirror = TRUE;
UWORD uwFirstPretenderDistance;
m_bPretenderDistance = TRUE;
ULONG ulFlagsOn = MAX_ULONG;
ULONG ulFlagsOff = MAX_ULONG;
INDEX iPolygon = 0;
// for each of the selected polygons
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
ulFlagsOn &= itbpo->bpo_ulFlags;
ulFlagsOff &= ~itbpo->bpo_ulFlags;
if( iPolygon == 0)
{
ubFirstFriction = itbpo->bpo_bppProperties.bpp_ubSurfaceType;
ubFirstMirror = itbpo->bpo_bppProperties.bpp_ubMirrorType;
uwFirstPretenderDistance = itbpo->bpo_bppProperties.bpp_uwPretenderDistance;
}
else
{
if( itbpo->bpo_bppProperties.bpp_ubSurfaceType != ubFirstFriction) bSameFriction = FALSE;
if( itbpo->bpo_bppProperties.bpp_ubMirrorType != ubFirstMirror) bSameMirror = FALSE;
if( itbpo->bpo_bppProperties.bpp_uwPretenderDistance != uwFirstPretenderDistance) m_bPretenderDistance = FALSE;
}
iPolygon++;
}
// apply flags to controls
#define SET_TRI_STATE_TO_CTRL( ctrl, flag)\
if((ulFlagsOn & flag) && !(ulFlagsOff & flag)) ctrl.SetCheck( 1);\
else if(!(ulFlagsOn & flag) && (ulFlagsOff & flag)) ctrl.SetCheck( 0);\
else ctrl.SetCheck( 2);
SET_TRI_STATE_TO_CTRL( m_IsPortal, BPOF_PORTAL);
SET_TRI_STATE_TO_CTRL( m_IsOldPortal, OPOF_PORTAL);
SET_TRI_STATE_TO_CTRL( m_IsOccluder, BPOF_OCCLUDER);
SET_TRI_STATE_TO_CTRL( m_IsPassable, BPOF_PASSABLE);
SET_TRI_STATE_TO_CTRL( m_bStairs, BPOF_STAIRS);
SET_TRI_STATE_TO_CTRL( m_bShootThru, BPOF_SHOOTTHRU);
SET_TRI_STATE_TO_CTRL( m_IsInvisible, BPOF_INVISIBLE);
SET_TRI_STATE_TO_CTRL( m_IsDoubleSided, BPOF_DOUBLESIDED);
SET_TRI_STATE_TO_CTRL( m_bIsDetail, BPOF_DETAILPOLYGON);
SET_TRI_STATE_TO_CTRL( m_IsTranslucent, BPOF_TRANSLUCENT);
SET_TRI_STATE_TO_CTRL( m_IsTransparent, BPOF_TRANSPARENT);
if( bSameFriction) m_ComboFriction.SetCurSel( ubFirstFriction);
else m_ComboFriction.SetCurSel(-1);
if( bSameMirror) m_ComboMirror.SetCurSel( ubFirstMirror);
else m_ComboMirror.SetCurSel(-1);
if( m_bPretenderDistance) m_fPretenderDistance = uwFirstPretenderDistance;
}
// mark that page is updated
m_udPolygonSelection.MarkUpdated();
}
//{{AFX_DATA_MAP(CDlgPgPolygon)
DDX_Control(pDX, IDC_DOUBLESIDED, m_IsDoubleSided);
DDX_Control(pDX, IDC_SHOOTTROUGH, m_bShootThru);
DDX_Control(pDX, IDC_IS_TRANSPARENT, m_IsTransparent);
DDX_Control(pDX, IDC_STAIRS, m_bStairs);
DDX_Control(pDX, IDC_IS_OCCLUDER, m_IsOccluder);
DDX_Control(pDX, IDC_MIRROR_COMBO, m_ComboMirror);
DDX_Control(pDX, IDC_IS_OLD_PORTAL, m_IsOldPortal);
DDX_Control(pDX, IDC_IS_DETAIL, m_bIsDetail);
DDX_Control(pDX, IDC_INVISIBLE, m_IsInvisible);
DDX_Control(pDX, IDC_IS_TRANSLUSCENT, m_IsTranslucent);
DDX_Control(pDX, IDC_IS_PASSABLE, m_IsPassable);
DDX_Control(pDX, IDC_IS_PORTAL, m_IsPortal);
DDX_Control(pDX, IDC_FRICTION_COMBO, m_ComboFriction);
//}}AFX_DATA_MAP
DDX_SkyFloat(pDX, IDC_PRETENDER_DISTANCE, m_fPretenderDistance, m_bPretenderDistance);
// if dialog is giving data
if( pDX->m_bSaveAndValidate != FALSE)
{
BOOL bFindShadowLayers = FALSE;
// calculate bounding box for all polygons
FLOATaabbox3D boxBoundingBoxPolygonSelection;
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
boxBoundingBoxPolygonSelection |= itbpo->bpo_boxBoundingBox;
if( m_ComboFriction.GetCurSel()!=-1) itbpo->bpo_bppProperties.bpp_ubSurfaceType = m_ComboFriction.GetCurSel();
INDEX iItemMirror = m_ComboMirror.GetCurSel();
if( iItemMirror!=CB_ERR)
{
if( itbpo->bpo_bppProperties.bpp_ubMirrorType != iItemMirror)
{
itbpo->bpo_bppProperties.bpp_ubMirrorType = (UBYTE) iItemMirror;
}
}
// if all polygons have same pretender distance
if( m_bPretenderDistance)
{
itbpo->bpo_bppProperties.bpp_uwPretenderDistance = UWORD (m_fPretenderDistance);
}
// set polygon's flags acording witg given tri-state ctrl
#define TRI_STATE_CTRL_TO_FLAGS( ctrl, flag, bDiscardShd, bFindShdLayers)\
if( (ctrl.GetCheck() == 1) && !(itbpo->bpo_ulFlags & flag) ) {\
itbpo->bpo_ulFlags |= flag;\
if( bDiscardShd) itbpo->DiscardShadows();\
if( bFindShdLayers) bFindShadowLayers = TRUE;\
} else if( (ctrl.GetCheck() == 0) && (itbpo->bpo_ulFlags & flag) ) {\
itbpo->bpo_ulFlags &= ~flag;\
if( bDiscardShd) itbpo->DiscardShadows();\
if( bFindShdLayers) bFindShadowLayers = TRUE;\
}
ULONG ulFlagsBefore = itbpo->bpo_ulFlags;
TRI_STATE_CTRL_TO_FLAGS( m_IsPortal, BPOF_PORTAL, TRUE, TRUE);
TRI_STATE_CTRL_TO_FLAGS( m_IsOccluder, BPOF_OCCLUDER, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_IsOldPortal, OPOF_PORTAL, TRUE, TRUE);
TRI_STATE_CTRL_TO_FLAGS( m_IsPassable, BPOF_PASSABLE, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_bStairs, BPOF_STAIRS, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_bShootThru, BPOF_SHOOTTHRU, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_IsInvisible, BPOF_INVISIBLE, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_IsDoubleSided, BPOF_DOUBLESIDED, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_bIsDetail, BPOF_DETAILPOLYGON, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_IsTranslucent, BPOF_TRANSLUCENT, FALSE, FALSE);
TRI_STATE_CTRL_TO_FLAGS( m_IsTransparent, BPOF_TRANSPARENT, FALSE, FALSE);
ULONG ulFlagsAfter = itbpo->bpo_ulFlags;
// occluder and detail flags can't be on at the same time
BOOL bOccluderSet = ((ulFlagsBefore&BPOF_OCCLUDER)!=(ulFlagsAfter&BPOF_OCCLUDER))&&(ulFlagsAfter&BPOF_OCCLUDER);
BOOL bDetailSet = ((ulFlagsBefore&BPOF_DETAILPOLYGON)!=(ulFlagsAfter&BPOF_DETAILPOLYGON))&&(ulFlagsAfter&BPOF_DETAILPOLYGON);
BOOL bDoubleSidedSet = ((ulFlagsBefore&BPOF_DOUBLESIDED)!=(ulFlagsAfter&BPOF_DOUBLESIDED))&&(ulFlagsAfter&BPOF_DOUBLESIDED);
// if occluder set
if( bOccluderSet)
{
// turn off detail
itbpo->bpo_ulFlags &= ~BPOF_DETAILPOLYGON;
itbpo->bpo_ulFlags |= BPOF_DOESNOTCASTSHADOW;
}
// if doublesided set
if(bDoubleSidedSet)
{
// turn on transparent and detail
itbpo->bpo_ulFlags |= BPOF_TRANSPARENT;
itbpo->bpo_ulFlags |= BPOF_DETAILPOLYGON;
}
// if detail set
if( bDetailSet)
{
// turn off occluder
itbpo->bpo_ulFlags &= ~BPOF_OCCLUDER;
}
}
// if we should find shadow layers
if( bFindShadowLayers)
{
pDoc->m_woWorld.FindShadowLayers( boxBoundingBoxPolygonSelection);
}
// mark that document is changed
theApp.GetDocument()->SetModifiedFlag( TRUE);
// redraw to show changes
pDoc->UpdateAllViews( NULL);
}
}
BEGIN_MESSAGE_MAP(CDlgPgPolygon, CPropertyPage)
//{{AFX_MSG_MAP(CDlgPgPolygon)
ON_CBN_SELCHANGE(IDC_FRICTION_COMBO, OnSelchangeFrictionCombo)
ON_CBN_DROPDOWN(IDC_FRICTION_COMBO, OnDropdownFrictionCombo)
ON_CBN_SELCHANGE(IDC_MIRROR_COMBO, OnSelchangeMirrorCombo)
ON_CBN_DROPDOWN(IDC_MIRROR_COMBO, OnDropdownMirrorCombo)
ON_WM_CONTEXTMENU()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDlgPgPolygon message handlers
void CDlgPgPolygon::InitComboBoxes(void)
{
CWorldEditorDoc* pDoc = theApp.GetDocument();
CTString strFrictionName;
CTString strMirrorName;
m_ComboFriction.ResetContent();
m_ComboMirror.ResetContent();
// add all available frictions
for(INDEX iFriction=0; iFriction<MAX_UBYTE; iFriction++)
{
strFrictionName = pDoc->m_woWorld.wo_astSurfaceTypes[iFriction].st_strName;
if( strFrictionName == "") break;
INDEX iAddedAs = m_ComboFriction.AddString( CString(strFrictionName));
}
// none must exist
m_ComboMirror.AddString( L"None");
// if there is polygon selection
if( pDoc->m_selPolygonSelection.Count() != 0)
{
// obtain first polygon's brush
CBrush3D *pbrBrush = NULL;
pDoc->m_selPolygonSelection.Lock();
if( !pDoc->m_selPolygonSelection.IsMember( pDoc->m_pbpoLastCentered))
{
pbrBrush = pDoc->m_selPolygonSelection[0].bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush;
}
pDoc->m_selPolygonSelection.Unlock();
BOOL bEnableMirror = TRUE;
// for each of the selected polygons
FOREACHINDYNAMICCONTAINER(pDoc->m_selPolygonSelection, CBrushPolygon, itbpo)
{
// disable mirror combo box if all polygons are not from same brush
if( pbrBrush != itbpo->bpo_pbscSector->bsc_pbmBrushMip->bm_pbrBrush)
{
bEnableMirror = FALSE;
break;
}
}
// if mirror combo is enabled
if( bEnableMirror)
{
// add mirrors
for(INDEX iMirror=1; iMirror<MAX_UBYTE; iMirror++)
{
CTString strMirrorName = pbrBrush->br_penEntity->GetMirrorName( iMirror);
if( strMirrorName == "") break;
m_ComboMirror.AddString( CString(strMirrorName));
}
}
}
}
BOOL CDlgPgPolygon::OnIdle(LONG lCount)
{
CWorldEditorDoc* pDoc = theApp.GetDocument();
if( (pDoc == NULL) || !IsWindow(m_hWnd) )
{
return TRUE;
}
// if selections have been changed (they are not up to date)
if( !pDoc->m_chSelections.IsUpToDate( m_udPolygonSelection) )
{
// update dialog data
UpdateData( FALSE);
}
return TRUE;
}
BOOL CDlgPgPolygon::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN)
{
// move data from page to polygon
UpdateData( TRUE);
// the message is handled
return TRUE;
}
return CPropertyPage::PreTranslateMessage(pMsg);
}
BOOL CDlgPgPolygon::OnInitDialog()
{
CPropertyPage::OnInitDialog();
if( IsWindow( m_ComboFriction.m_hWnd))
{
InitComboBoxes();
}
m_bIsDetail.SetDialogPtr( this);
m_IsInvisible.SetDialogPtr( this);
m_IsDoubleSided.SetDialogPtr( this);
m_IsTranslucent.SetDialogPtr( this);
m_IsTransparent.SetDialogPtr( this);
m_IsPassable.SetDialogPtr( this);
m_bStairs.SetDialogPtr( this);
m_bShootThru.SetDialogPtr( this);
m_IsPortal.SetDialogPtr( this);
m_IsOldPortal.SetDialogPtr( this);
m_IsOccluder.SetDialogPtr( this);
return TRUE;
}
void CDlgPgPolygon::OnSelchangeFrictionCombo()
{
UpdateData( TRUE);
}
void CDlgPgPolygon::OnDropdownFrictionCombo()
{
m_ComboFriction.SetDroppedWidth( 256);
}
void CDlgPgPolygon::OnSelchangeMirrorCombo()
{
UpdateData( TRUE);
}
void CDlgPgPolygon::OnDropdownMirrorCombo()
{
m_ComboMirror.SetDroppedWidth( 256);
}
void CDlgPgPolygon::OnContextMenu(CWnd* pWnd, CPoint point)
{
CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
CMenu menu;
if( pDoc->GetEditingMode() == POLYGON_MODE)
{
if( menu.LoadMenu(IDR_INFO_POLYGON_POPUP))
{
CMenu* pPopup = menu.GetSubMenu(0);
if( pDoc->m_selPolygonSelection.Count() != 1)
{
menu.EnableMenuItem(ID_SET_AS_DEFAULT, MF_DISABLED|MF_GRAYED);
}
pPopup->TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
point.x, point.y, this);
}
}
}