source-engine/hammer/faceedit_materialpage.cpp

1786 lines
47 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include <stdafx.h>
#include "hammer.h"
#include "IEditorTexture.h"
#include "FaceEditSheet.h"
#include "MapFace.h"
#include "MapWorld.h"
#include "MainFrm.h"
#include "History.h"
#include "GlobalFunctions.h"
#include "mathlib/vmatrix.h"
#include "MapSolid.h"
#include "TextureBrowser.h"
#include "TextureSystem.h"
#include "MapView3D.h"
#include "ReplaceTexDlg.h"
#include "WADTypes.h"
#include "FaceEdit_MaterialPage.h"
#include "Camera.h"
#include "MapDoc.h"
#include "MapDisp.h"
#include "ToolManager.h"
#include "Selection.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//=============================================================================
IMPLEMENT_DYNAMIC( CFaceEditMaterialPage, CPropertyPage )
BEGIN_MESSAGE_MAP( CFaceEditMaterialPage, CPropertyPage )
//{{AFX_MSG_MAP( CFaceEditMaterialPage )
ON_BN_CLICKED( ID_FACEEDIT_APPLY, OnButtonApply )
ON_COMMAND_EX( IDC_ALIGN_WORLD, OnAlign )
ON_COMMAND_EX( IDC_ALIGN_FACE, OnAlign )
ON_BN_CLICKED( IDC_HIDEMASK, OnHideMask )
ON_COMMAND_EX( IDC_JUSTIFY_TOP, OnJustify )
ON_COMMAND_EX( IDC_JUSTIFY_BOTTOM, OnJustify )
ON_COMMAND_EX( IDC_JUSTIFY_LEFT, OnJustify )
ON_COMMAND_EX( IDC_JUSTIFY_CENTER, OnJustify )
ON_COMMAND_EX( IDC_JUSTIFY_RIGHT, OnJustify )
ON_COMMAND_EX( IDC_JUSTIFY_FITTOFACE, OnJustify )
ON_BN_CLICKED( IDC_MODE, OnMode )
ON_WM_VSCROLL()
ON_NOTIFY( UDN_DELTAPOS, IDC_SPINSCALEX, OnDeltaPosFloatSpin )
ON_NOTIFY( UDN_DELTAPOS, IDC_SPINSCALEY, OnDeltaPosFloatSpin )
ON_WM_SIZE()
ON_CBN_SELCHANGE( IDC_TEXTURES, OnSelChangeTexture )
ON_BN_CLICKED( IDC_Q2_LIGHT, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_SLICK, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_SKY, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_WARP, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_TRANS33, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_TRANS66, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_FLOWING, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_NODRAW, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_SOLID, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_WINDOW, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_AUX, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_LAVA, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_SLIME, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_WATER, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_MIST, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENT90, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENT180, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENT270, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENTUP, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENTDN, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_ORIGIN, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_MONSTER, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CORPSE, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_DETAIL, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_TRANSLUCENT, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_LADDER, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_PLAYERCLIP, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_MONSTERCLIP, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_CURRENT0, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_HINT, OnCheckUnCheck )
ON_BN_CLICKED( IDC_Q2_SPLITTER, OnCheckUnCheck )
ON_COMMAND( IDC_TREAT_AS_ONE, OnTreatAsOne )
ON_BN_CLICKED( IDC_REPLACE, OnReplace )
ON_COMMAND_EX_RANGE( CFaceEditSheet::id_SwitchModeStart, CFaceEditSheet::id_SwitchModeEnd, OnSwitchMode )
ON_CBN_SELCHANGE( IDC_TEXTUREGROUPS, OnChangeTextureGroup )
ON_BN_CLICKED( IDC_BROWSE, OnBrowse )
ON_BN_CLICKED( ID_BUTTON_SMOOTHING_GROUPS, OnButtonSmoothingGroups )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//=============================================================================
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
// I don't think we need these currents. We'll stick to triggers for this
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEBRIS 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define CONTENTS_LADDER 0x20000000
//=============================================================================
const int NOT_INIT = -99999;
unsigned int CFaceEditMaterialPage::m_FaceContents = 0;
unsigned int CFaceEditMaterialPage::m_FaceSurface = 0;
//=============================================================================
//-----------------------------------------------------------------------------
// This table defines the mapping of checkbox controls to flags which are set
// in certain face attributes values.
//-----------------------------------------------------------------------------
CFaceEditMaterialPage::FaceAttributeInfo_t FaceAttributes[] =
{
//
// Contents.
//
{ IDC_CONTENTS_AREAPORTAL, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_AREAPORTAL },
{ IDC_CONTENTS_PLAYERCLIP, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_PLAYERCLIP },
{ IDC_CONTENTS_MONSTERCLIP, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_MONSTERCLIP },
{ IDC_CONTENTS_ORIGIN, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_ORIGIN },
{ IDC_CONTENTS_DETAIL, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_DETAIL },
{ IDC_CONTENTS_TRANSLUCENT, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_TRANSLUCENT },
{ IDC_CONTENTS_LADDER, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_LADDER },
//
// Surface attributes.
//
{ IDC_SURF_NODRAW, &CFaceEditMaterialPage::m_FaceSurface, SURF_NODRAW },
{ IDC_SURF_HINT, &CFaceEditMaterialPage::m_FaceSurface, SURF_HINT },
{ IDC_SURF_SKIP, &CFaceEditMaterialPage::m_FaceSurface, SURF_SKIP }
};
//=============================================================================
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CFaceEditMaterialPage::CFaceEditMaterialPage() : CPropertyPage( IDD )
{
m_bHideMask = FALSE;
m_bInitialized = FALSE;
m_bIgnoreResize = FALSE;
m_bTreatAsOneFace = FALSE;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CFaceEditMaterialPage::~CFaceEditMaterialPage()
{
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
BOOL CFaceEditMaterialPage::PreTranslateMessage( MSG *pMsg )
{
HACCEL hAccel = GetMainWnd()->GetAccelTable();
if( !(hAccel && ::TranslateAccelerator( GetMainWnd()->m_hWnd, hAccel, pMsg ) ) )
{
return CPropertyPage::PreTranslateMessage( pMsg );
}
else
{
return TRUE;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::Init( void )
{
//
// Connect dialog control objects to their control IDs.
//
m_shiftX.SubclassDlgItem( IDC_SHIFTX, this );
m_shiftY.SubclassDlgItem( IDC_SHIFTY, this );
m_scaleX.SubclassDlgItem( IDC_SCALEX, this );
m_scaleY.SubclassDlgItem( IDC_SCALEY, this );
m_rotate.SubclassDlgItem( IDC_ROTATE, this );
m_cHideMask.SubclassDlgItem( IDC_HIDEMASK, this );
m_cExpand.SubclassDlgItem( IDC_EXPAND, this );
m_cLightmapScale.SubclassDlgItem( IDC_LIGHTMAP_SCALE, this );
//
// Set spin ranges.
//
CWnd *pWnd = GetDlgItem(IDC_SPINSHIFTX);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(MAX_TEXTUREWIDTH, -MAX_TEXTUREWIDTH));
pWnd = GetDlgItem(IDC_SPINSHIFTY);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(MAX_TEXTUREHEIGHT, -MAX_TEXTUREHEIGHT));
pWnd = GetDlgItem(IDC_SPINROTATE);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(359, -359));
pWnd = GetDlgItem(IDC_SPINSCALEX);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, UD_MINVAL));
pWnd = GetDlgItem(IDC_SPINSCALEY);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, UD_MINVAL));
pWnd = GetDlgItem(IDC_SPIN_LIGHTMAP_SCALE);
::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, 1));
// set the initial switch mode
OnSwitchMode( CFaceEditSheet::ModeLiftSelect );
//
// set up controls
//
m_TextureGroupList.SubclassDlgItem( IDC_TEXTUREGROUPS, this );
m_TextureList.SubclassDlgItem( IDC_TEXTURES, this );
m_TexturePic.SubclassDlgItem( IDC_TEXTUREPIC, this );
m_pCurTex = NULL;
//
// initially update the texture controls
//
NotifyGraphicsChanged();
UpdateTexture();
// initialized!
m_bInitialized = TRUE;
}
//-----------------------------------------------------------------------------
// NOTE: clean this up and make a global function!!!
// Purpose:
// Input : fValue -
// *pSpin -
// bMantissa -
// Output : static void
//-----------------------------------------------------------------------------
void FloatToSpin(float fValue, CSpinButtonCtrl *pSpin, BOOL bMantissa)
{
char szNew[128];
CWnd *pEdit = pSpin->GetBuddy();
if (fValue == NOT_INIT)
{
szNew[0] = 0;
}
else
{
if(bMantissa)
sprintf(szNew, "%.2f", fValue);
else
sprintf(szNew, "%.0f", fValue);
}
pSpin->SetPos(atoi(szNew));
char szCurrent[128];
pEdit->GetWindowText(szCurrent, 128);
if (strcmp(szNew, szCurrent))
{
pEdit->SetWindowText(szNew);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nValue -
// pSpin -
// Output : static void
//-----------------------------------------------------------------------------
void IntegerToSpin(int nValue, CSpinButtonCtrl *pSpin)
{
char szNew[128];
CWnd *pEdit = pSpin->GetBuddy();
if (nValue == NOT_INIT)
{
szNew[0] = 0;
}
else
{
sprintf(szNew, "%d", abs(nValue));
}
pSpin->SetPos(atoi(szNew));
char szCurrent[128];
pEdit->GetWindowText(szCurrent, 128);
if (strcmp(szNew, szCurrent) != 0)
{
pEdit->SetWindowText(szNew);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : fValue -
// *pWnd -
// Output : static void
//-----------------------------------------------------------------------------
void FloatToWnd(float fValue, CWnd *pWnd)
{
char szCurrent[128];
char szNew[128];
if(fValue == NOT_INIT)
{
szNew[0] = 0;
}
else
{
sprintf(szNew, "%g", fValue);
}
pWnd->GetWindowText(szCurrent, 128);
if(strcmp(szNew, szCurrent))
pWnd->SetWindowText(szNew);
}
//-----------------------------------------------------------------------------
// Purpose: Fetches a string value from a window and places it in a float. The
// float is only modified if there is text in the window.
// Input : pWnd - Window from which to get text.
// fValue - Float in which to place value.
//-----------------------------------------------------------------------------
void TransferToFloat( CWnd *pWnd, float &fValue )
{
CString str;
pWnd->GetWindowText( str );
if( !str.IsEmpty() )
{
fValue = ( float )atof( str );
}
}
//-----------------------------------------------------------------------------
// Purpose: Fetches a string value from a window and places it in an integer. The
// integer is only modified if there is text in the window.
// Input : pWnd - Window from which to get text.
// nValue - Float in which to place value.
//-----------------------------------------------------------------------------
void TransferToInteger( CWnd *pWnd, int &nValue )
{
CString str;
pWnd->GetWindowText( str );
if( !str.IsEmpty() )
{
nValue = abs( atoi( str ) );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::ClickFace( CMapSolid *pSolid, int faceIndex, int cmd, int clickMode )
{
// get the face
CMapFace *pFace = pSolid->GetFace( faceIndex );
bool bIsEditable = pSolid->IsEditable();
//
// are updates enabled?
//
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
bool bEnableUpdate = pSheet->HasUpdateEnabled();
SetReadOnly( !bIsEditable );
//
// find the behavior of the page based on the "click mode"
//
switch( clickMode )
{
case CFaceEditSheet::ModeAlignToView:
{
if ( bIsEditable )
{
AlignToView( pFace );
}
break;
}
case CFaceEditSheet::ModeLift:
{
if( bEnableUpdate )
{
UpdateDialogData( pFace );
}
break;
}
case CFaceEditSheet::ModeLiftSelect:
{
if ( bEnableUpdate )
{
UpdateDialogData();
}
break;
}
case CFaceEditSheet::ModeApplyLightmapScale:
{
// Apply the lightmap scale only. Leave everything else alone.
if ( bIsEditable )
{
Apply(pFace, FACE_APPLY_LIGHTMAP_SCALE);
}
break;
}
case CFaceEditSheet::ModeApply:
case CFaceEditSheet::ModeApplyAll:
{
if ( bIsEditable )
{
int flags = 0;
if (cmd & CFaceEditSheet::cfEdgeAlign)
{
// Adust the mapping to align with a reference face.
flags |= FACE_APPLY_ALIGN_EDGE;
}
if (clickMode == CFaceEditSheet::ModeApplyAll)
{
// Apply the material, mapping, lightmap scale, etc.
flags |= FACE_APPLY_ALL;
}
else
{
// Apply the material only. Leave everything else alone.
flags |= FACE_APPLY_MATERIAL;
}
Apply(pFace, flags);
}
break;
}
}
}
//-----------------------------------------------------------------------------
// Maps the texture onto the face using the 3D view's up and right vectors.
// This can be useful for mapping curvy things like hills because if you don't
// move the 3D view, the texture will line up on any polies you map this way.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::AlignToView( CMapFace *pFace )
{
CView *pActiveView;
CMapView3D *pView3D;
CFrameWnd *pFrame;
Vector vView;
if((pFrame = GetMainWnd()->GetActiveFrame()) != NULL)
{
if((pActiveView = pFrame->GetActiveView()) != NULL)
{
if(pActiveView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
{
pView3D = dynamic_cast<CMapView3D*>(pActiveView);
if(pView3D)
{
const CCamera *pCamera = pView3D->GetCamera();
if(pCamera)
{
Vector right, up;
pCamera->GetViewRight(right);
pCamera->GetViewUp(up);
pCamera->GetViewPoint(vView);
pFace->texture.UAxis.AsVector3D() = right;
pFace->texture.VAxis.AsVector3D() = up;
pFace->texture.UAxis[3] = DotProduct( right, vView);
pFace->texture.VAxis[3] = DotProduct( up, vView);
pFace->NormalizeTextureShifts();
pFace->texture.rotate = 0.0f;
pFace->texture.scale[0] = g_pGameConfig->GetDefaultTextureScale();
pFace->texture.scale[1] = g_pGameConfig->GetDefaultTextureScale();
pFace->CalcTextureCoords();
}
}
}
}
}
}
//-----------------------------------------------------------------------------
// Copies the texture coordinate system from pFrom into pTo. Then it rotates
// the texture around the edge until it's as close to pTo's normal as possible.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::CopyTCoordSystem( const CMapFace *pFrom, CMapFace *pTo )
{
Vector axis[2], vEdge, vEdgePt, vOrigin;
Vector vFromPt, vNextFromPt;
Vector vToPt, vPrevToPt;
Vector vTestTextureNormal, vTextureNormal;
VMatrix mEdgeRotation, mOriginRotation, mTranslation;
float fAngle, fDot;
bool bRotate;
float fShift[2];
Vector vProjTexNormal;
Vector vProjPolyNormal;
// The edge vector lies on both planes.
vEdge = pFrom->plane.normal.Cross(pTo->plane.normal);
VectorNormalize( vEdge );
// To find a point on the plane, we make a plane from the edge vector and find the intersection
// between the three planes (without the third plane, there are an infinite number of solutions).
if( PlaneIntersection( VPlane(pFrom->plane.normal, pFrom->plane.dist),
VPlane(pTo->plane.normal, pTo->plane.dist),
VPlane(vEdge, 0.0f), vEdgePt ) )
{
bRotate = true;
}
else
{
// Ok, in this case, the planes are parallel so we don't need to rotate around the edge anyway!
bRotate = false;
}
// Copy the texture coordinate system.
axis[0] = pFrom->texture.UAxis.AsVector3D();
axis[1] = pFrom->texture.VAxis.AsVector3D();
fShift[0] = pFrom->texture.UAxis[3];
fShift[1] = pFrom->texture.VAxis[3];
vOrigin = axis[0]*fShift[0]*pFrom->texture.scale[0] + axis[1]*fShift[1]*pFrom->texture.scale[1];
vTextureNormal = axis[0].Cross(axis[1]);
VectorNormalize(vTextureNormal);
if(bRotate)
{
// Project texture normal and poly normal into the plane of rotation
// to get the angle between them.
vProjTexNormal = vTextureNormal - vEdge * vEdge.Dot(vTextureNormal);
vProjPolyNormal = pTo->plane.normal - vEdge * vEdge.Dot(pTo->plane.normal);
VectorNormalize( vProjTexNormal );
VectorNormalize( vProjPolyNormal );
fDot = vProjTexNormal.Dot(vProjPolyNormal);
fAngle = (float)(acos(fDot) * (180.0f / M_PI));
if(fDot < 0.0f)
fAngle = 180.0f - fAngle;
// Ok, rotate them for the final values.
mEdgeRotation = SetupMatrixAxisRot(vEdge, fAngle);
axis[0] = mEdgeRotation.ApplyRotation(axis[0]);
axis[1] = mEdgeRotation.ApplyRotation(axis[1]);
// Origin needs translation and rotation to rotate around the edge.
mTranslation = SetupMatrixTranslation(vEdgePt);
mOriginRotation = ~mTranslation * mEdgeRotation * mTranslation;
vOrigin = mOriginRotation * vOrigin;
}
pTo->texture.UAxis.AsVector3D() = axis[0];
pTo->texture.VAxis.AsVector3D() = axis[1];
pTo->texture.UAxis[3] = axis[0].Dot(vOrigin) / pFrom->texture.scale[0];
pTo->texture.VAxis[3] = axis[1].Dot(vOrigin) / pFrom->texture.scale[1];
pTo->NormalizeTextureShifts();
pTo->texture.scale[0] = pFrom->texture.scale[0];
pTo->texture.scale[1] = pFrom->texture.scale[1];
// rotate is only for UI purposes, it doesn't actually do anything.
pTo->texture.rotate = 0.0f;
pTo->CalcTextureCoords();
}
//-----------------------------------------------------------------------------
// Purpose: Applies dialog data to the list of selected faces.
// Input : *pOnlyFace -
// bAll -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::Apply( CMapFace *pOnlyFace, int flags )
{
int i;
CString str;
float fshiftX = NOT_INIT;
float fshiftY = NOT_INIT;
float fscaleX = NOT_INIT;
float fscaleY = NOT_INIT;
float frotate = NOT_INIT;
int material = NOT_INIT;
int nLightmapScale = NOT_INIT;
IEditorTexture *pTex = m_TexturePic.GetTexture();
CMapDoc *pMapDoc = CMapDoc::GetActiveMapDoc();
//
// Get numeric data.
//
if (flags & FACE_APPLY_MAPPING)
{
TransferToFloat( &m_shiftX, fshiftX );
TransferToFloat( &m_shiftY, fshiftY );
TransferToFloat( &m_scaleX, fscaleX );
TransferToFloat( &m_scaleY, fscaleY );
TransferToFloat( &m_rotate, frotate );
}
if (flags & FACE_APPLY_LIGHTMAP_SCALE)
{
TransferToInteger( &m_cLightmapScale, nLightmapScale );
}
if ( !pOnlyFace )
{
GetHistory()->MarkUndoPosition( NULL, "Apply Face Attributes" );
// make sure we apply everything in this case.
flags |= FACE_APPLY_ALL;
// Keep the solids that we are about to change.
// In the pOnlyFace case we do the Keep before calling ClickFace. Why?
CUtlVector<CMapSolid *> kept;
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
for( i = 0; i < pSheet->GetFaceListCount(); i++ )
{
CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
if ( kept.Find( pSolid ) == -1 )
{
GetHistory()->Keep( pSolid );
kept.AddToTail( pSolid );
}
}
}
//
// Run thru stored faces & apply.
//
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
int faceCount = pSheet->GetFaceListCount();
for( i = 0; i < faceCount || pOnlyFace; i++ )
{
CMapFace *pFace;
if( pOnlyFace )
{
pFace = pOnlyFace;
}
else
{
pFace = pSheet->GetFaceListDataFace( i );
}
//
// Get values for texture shift, scale, rotate, and material.
//
if ((flags & FACE_APPLY_MAPPING) && (!(flags & FACE_APPLY_ALIGN_EDGE)))
{
if ( fshiftX != NOT_INIT )
{
pFace->texture.UAxis[3] = fshiftX;
}
if ( fshiftY != NOT_INIT )
{
pFace->texture.VAxis[3] = fshiftY;
}
if ( fscaleX != NOT_INIT )
{
pFace->texture.scale[0] = fscaleX;
}
if ( fscaleY != NOT_INIT )
{
pFace->texture.scale[1] = fscaleY;
}
if ( frotate != NOT_INIT )
{
pFace->RotateTextureAxes( frotate - pFace->texture.rotate );
pFace->texture.rotate = frotate;
}
}
if (flags & FACE_APPLY_CONTENTS_DATA)
{
if ( material != NOT_INIT )
{
pFace->texture.material = material;
}
}
if (flags & FACE_APPLY_LIGHTMAP_SCALE)
{
if (nLightmapScale != NOT_INIT)
{
pFace->texture.nLightmapScale = max( nLightmapScale, 1 );
}
}
//
// Update the texture and recalculate texture coordinates.
//
if ((flags & FACE_APPLY_MATERIAL) && (pTex != NULL))
{
char szCurrentTexName[MAX_PATH];
char szNewTexName[MAX_PATH];
pFace->GetTextureName( szCurrentTexName );
pTex->GetShortName( szNewTexName );
if( stricmp( szCurrentTexName, szNewTexName ) != 0 )
{
pFace->SetTexture( szNewTexName );
CMapClass *pParent = dynamic_cast< CMapClass * >( pFace->GetParent() );
if ( pParent )
{
pMapDoc->RemoveFromAutoVisGroups( pParent );
pMapDoc->AddToAutoVisGroup( pParent );
}
}
}
//
// Copy texture coordinate system.
//
if ((flags & FACE_APPLY_ALIGN_EDGE) && (faceCount >= 1))
{
CopyTCoordSystem( pSheet->GetFaceListDataFace( faceCount - 1 ), pFace );
}
//
// Recalculate texture coordinates.
//
pFace->CalcTextureCoords();
//
// Update the face flags.
//
if (flags & FACE_APPLY_CONTENTS_DATA)
{
//
// Copy the bits from this face into our variables.
//
m_FaceContents = pFace->texture.q2contents;
m_FaceSurface = pFace->texture.q2surface;
//
// Update our variables based on the state of the checkboxes.
//
for( int nItem = 0; nItem < sizeof( FaceAttributes ) / sizeof( FaceAttributes[0] ); nItem++ )
{
CButton *pButton = ( CButton* )GetDlgItem( FaceAttributes[nItem].uControlID );
if( pButton != NULL )
{
int nSet = pButton->GetCheck();
if (nSet == 0)
{
*FaceAttributes[nItem].puAttribute &= ~FaceAttributes[nItem].uFlag;
}
else if (nSet == 1)
{
*FaceAttributes[nItem].puAttribute |= FaceAttributes[nItem].uFlag;
}
}
}
//
// Copy our variables back into this face.
//
pFace->texture.q2contents = m_FaceContents;
pFace->texture.q2surface = m_FaceSurface;
}
if( pOnlyFace )
{
break;
}
}
pMapDoc->SetModifiedFlag();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOnlyFace -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::UpdateDialogData( CMapFace *pOnlyFace )
{
BOOL bFirst;
int nFaceAlignCount;
int nWorldAlignCount;
float fshiftX = NOT_INIT;
float fshiftY = NOT_INIT;
float fscaleX = NOT_INIT;
float fscaleY = NOT_INIT;
float frotate = NOT_INIT;
//float fsmooth = NOT_INIT;
int material = NOT_INIT;
int nLightmapScale = NOT_INIT;
CString strTexture;
bFirst = TRUE;
nFaceAlignCount = 0;
nWorldAlignCount = 0;
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
int faceCount = pSheet->GetFaceListCount();
for( int i = 0; i < faceCount || pOnlyFace; i++ )
{
CMapFace *pFace;
if( pOnlyFace )
{
pFace = pOnlyFace;
}
else
{
pFace = pSheet->GetFaceListDataFace( i );
}
TEXTURE &t = pFace->texture;
//
// Gather statistics about the texture alignment of all the selected faces.
// This is used later to set the state of the alignment checkboxes.
//
int nAlignment = pFace->GetTextureAlignment();
if (nAlignment & TEXTURE_ALIGN_FACE)
{
nFaceAlignCount++;
}
if (nAlignment & TEXTURE_ALIGN_WORLD)
{
nWorldAlignCount++;
}
//
// First update - copy first face's stuff into edit fields.
//
if (bFirst)
{
fshiftX = t.UAxis[3];
fshiftY = t.VAxis[3];
fscaleX = t.scale[0];
fscaleY = t.scale[1];
frotate = t.rotate;
material = t.material;
strTexture = t.texture;
nLightmapScale = t.nLightmapScale;
//
// Get the face's orientation. This is used by Apply to make intelligent decisions.
//
m_eOrientation = pFace->GetOrientation();
Assert(m_eOrientation != FACE_ORIENTATION_INVALID);
//
// Set the appropriate checkbox state for the face attributes.
//
m_FaceContents = t.q2contents;
m_FaceSurface = t.q2surface;
for (int nItem = 0; nItem < sizeof(FaceAttributes) / sizeof(FaceAttributes[0]); nItem++)
{
int nSet = ((*FaceAttributes[nItem].puAttribute & FaceAttributes[nItem].uFlag) != 0);
CButton *pButton = (CButton *)GetDlgItem(FaceAttributes[nItem].uControlID);
if (pButton != NULL)
{
pButton->SetCheck(nSet);
}
}
bFirst = FALSE;
if (pOnlyFace) // use one face - now break
{
break;
}
}
else
{
// update fields with face's data
if (t.UAxis[3] != fshiftX)
{
fshiftX = NOT_INIT;
}
if (t.VAxis[3] != fshiftY)
{
fshiftY = NOT_INIT;
}
if (t.scale[0] != fscaleX)
{
fscaleX = NOT_INIT;
}
if (t.scale[1] != fscaleY)
{
fscaleY = NOT_INIT;
}
if (t.rotate != frotate)
{
frotate = NOT_INIT;
}
if (t.material != material)
{
material = NOT_INIT;
}
if (t.nLightmapScale != nLightmapScale)
{
nLightmapScale = NOT_INIT;
}
if (!strTexture.IsEmpty() && strTexture != t.texture)
{
strTexture = "";
}
//
// Update the checkbox state for the face attributes. If any of this face's
// attributes are different from the current checkbox state, set the checkbox
// to the undefined state.
//
m_FaceContents = t.q2contents;
m_FaceSurface = t.q2surface;
for (int nItem = 0; nItem < sizeof(FaceAttributes) / sizeof(FaceAttributes[0]); nItem++)
{
int nSet = ((*FaceAttributes[nItem].puAttribute & FaceAttributes[nItem].uFlag) != 0);
CButton *pButton = (CButton *)GetDlgItem(FaceAttributes[nItem].uControlID);
if (pButton != NULL)
{
if (pButton->GetCheck() != nSet)
{
pButton->SetButtonStyle(BS_AUTO3STATE);
pButton->SetCheck(2);
}
}
}
}
}
//
// Set the state of the face alignment checkbox.
//
CButton *pFaceAlign = (CButton *)GetDlgItem(IDC_ALIGN_FACE);
if (nFaceAlignCount == 0)
{
pFaceAlign->SetCheck(0);
}
else if (nFaceAlignCount == faceCount)
{
pFaceAlign->SetCheck(1);
}
else
{
pFaceAlign->SetCheck(2);
}
//
// Set the state of the world alignment checkbox.
//
CButton *pWorldAlign = (CButton *)GetDlgItem(IDC_ALIGN_WORLD);
if (nWorldAlignCount == 0)
{
pWorldAlign->SetCheck(0);
}
else if (nWorldAlignCount == faceCount)
{
pWorldAlign->SetCheck(1);
}
else
{
pWorldAlign->SetCheck(2);
}
//
// Set up fields.
//
FloatToSpin(fshiftX, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTX), FALSE);
FloatToSpin(fshiftY, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTY), FALSE);
IntegerToSpin(nLightmapScale, (CSpinButtonCtrl *)GetDlgItem(IDC_SPIN_LIGHTMAP_SCALE));
FloatToWnd(fscaleX, &m_scaleX);
FloatToWnd(fscaleY, &m_scaleY);
FloatToSpin(frotate, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINROTATE), TRUE);
if (!strTexture.IsEmpty())
{
SelectTexture( strTexture );
}
else
{
// make empty
m_TextureList.SetCurSel( -1 );
}
//
// if no faces selected -- get selection from texture bar
//
if( faceCount == 0 )
{
CString strTexName = GetDefaultTextureName();
SelectTexture( strTexName );
}
//
// Call ctexturebar implementation because OUR implementation sets the
// q2 checkboxes, which flashes the screen a bit (cuz we change them
// again three lines down.)
//
UpdateTexture();
// Update the smoothing group data.
if ( GetMaterialPageTool() == MATERIALPAGETOOL_SMOOTHING_GROUP )
{
m_FaceSmoothDlg.UpdateControls();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : uCmd -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CFaceEditMaterialPage::OnAlign( UINT uCmd )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
// mark position in undo stack
GetHistory()->MarkUndoPosition(NULL, "Align texture");
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
int faceCount = pSheet->GetFaceListCount();
for( int i = 0; i < faceCount; i++ )
{
CMapFace *pFace = pSheet->GetFaceListDataFace( i );
CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
GetHistory()->Keep( pSolid );
switch( uCmd )
{
case IDC_ALIGN_WORLD:
{
pFace->InitializeTextureAxes( TEXTURE_ALIGN_WORLD, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE );
break;
}
case IDC_ALIGN_FACE:
{
pFace->InitializeTextureAxes( TEXTURE_ALIGN_FACE, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE );
break;
}
}
}
CMapDoc::GetActiveMapDoc()->SetModifiedFlag();
UpdateDialogData();
return ( TRUE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnHideMask(void)
{
m_bHideMask = m_cHideMask.GetCheck();
CMapFace::SetShowSelection( m_bHideMask == FALSE );
CMapDoc::GetActiveMapDoc()->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D | MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_COLOR );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : Extents -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::GetAllFaceExtents( Extents_t Extents )
{
BOOL bFirst = TRUE;
Extents_t FaceExtents;
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
int faceCount = pSheet->GetFaceListCount();
for( int nFace = 0; nFace < faceCount; nFace++ )
{
CMapFace *pFace = pSheet->GetFaceListDataFace( nFace );
pFace->GetFaceExtents(FaceExtents);
if ((FaceExtents[EXTENTS_XMIN][0] < Extents[EXTENTS_XMIN][0]) || (bFirst))
{
Extents[EXTENTS_XMIN] = FaceExtents[EXTENTS_XMIN];
}
if ((FaceExtents[EXTENTS_XMAX][0] > Extents[EXTENTS_XMAX][0]) || (bFirst))
{
Extents[EXTENTS_XMAX] = FaceExtents[EXTENTS_XMAX];
}
if ((FaceExtents[EXTENTS_YMIN][1] < Extents[EXTENTS_YMIN][1]) || (bFirst))
{
Extents[EXTENTS_YMIN] = FaceExtents[EXTENTS_YMIN];
}
if ((FaceExtents[EXTENTS_YMAX][1] > Extents[EXTENTS_YMAX][1]) || (bFirst))
{
Extents[EXTENTS_YMAX] = FaceExtents[EXTENTS_YMAX];
}
if ((FaceExtents[EXTENTS_ZMIN][2] < Extents[EXTENTS_ZMIN][2]) || (bFirst))
{
Extents[EXTENTS_ZMIN] = FaceExtents[EXTENTS_ZMIN];
}
if ((FaceExtents[EXTENTS_ZMAX][2] > Extents[EXTENTS_ZMAX][2]) || (bFirst))
{
Extents[EXTENTS_ZMAX] = FaceExtents[EXTENTS_ZMAX];
}
bFirst = FALSE;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : uCmd -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CFaceEditMaterialPage::OnJustify( UINT uCmd )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
BOOL bTreatManyAsOneFace;
Extents_t Extents;
// mark undo position
GetHistory()->MarkUndoPosition( NULL, "Justify texture" );
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
int faceCount = pSheet->GetFaceListCount();
// If multiple faces are selected, use the m_bTreatManyAsOneFace variable to determine
// how to perform the justification.
if( faceCount > 1 )
{
bTreatManyAsOneFace = m_bTreatAsOneFace;
if( bTreatManyAsOneFace )
{
GetAllFaceExtents( Extents );
}
}
// If only one face is selected, treat it singly.
else
{
bTreatManyAsOneFace = FALSE;
}
for( int i = 0; i < faceCount; i++ )
{
CMapFace *pFace = pSheet->GetFaceListDataFace( i );
CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
GetHistory()->Keep( pSolid );
if( !bTreatManyAsOneFace )
{
pFace->GetFaceExtents( Extents );
}
switch (uCmd)
{
case IDC_JUSTIFY_TOP:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_TOP, Extents);
break;
}
case IDC_JUSTIFY_BOTTOM:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_BOTTOM, Extents);
break;
}
case IDC_JUSTIFY_LEFT:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_LEFT, Extents);
break;
}
case IDC_JUSTIFY_RIGHT:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_RIGHT, Extents);
break;
}
case IDC_JUSTIFY_CENTER:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_CENTER, Extents);
break;
}
case IDC_JUSTIFY_FITTOFACE:
{
pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_FIT, Extents);
break;
}
}
}
CMapDoc::GetActiveMapDoc()->SetModifiedFlag();
UpdateDialogData();
return(TRUE);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : id -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CFaceEditMaterialPage::OnSwitchMode( UINT id )
{
CWnd *pButton = GetDlgItem( IDC_MODE );
CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
pSheet->SetClickMode( id );
switch( id )
{
case CFaceEditSheet::ModeLiftSelect: // set
pButton->SetWindowText( "Mode: Lift+Select" );
break;
case CFaceEditSheet::ModeLift:
pButton->SetWindowText( "Mode: Lift" );
break;
case CFaceEditSheet::ModeSelect:
pButton->SetWindowText( "Mode: Select" );
break;
case CFaceEditSheet::ModeApply:
pButton->SetWindowText( "Mode: Apply (texture)" );
break;
case CFaceEditSheet::ModeApplyAll:
pButton->SetWindowText( "Mode: Apply (all)" );
break;
case CFaceEditSheet::ModeAlignToView:
pButton->SetWindowText( "Align To View" );
break;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnMode()
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
// switch mode -
// LIFT - lift texture from clicked face
// APPLY - apply selected texture to clicked face
// SELECT - mark each face
// LIFT/SELECT - mark clicked faces & lift textures
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeLiftSelect, "Lift+Select" );
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeLift, "Lift" );
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeSelect, "Select" );
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeApply, "Apply (texture only)" );
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeApplyAll, "Apply (texture + values)" );
menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeAlignToView, "Align To View" );
// track menu
CWnd *pButton = GetDlgItem( IDC_MODE );
CRect r;
pButton->GetWindowRect( r );
menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON, r.left, r.bottom, this, NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nSBCode -
// nPos -
// *pScrollBar -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar *pScrollBar )
{
Apply(NULL, FACE_APPLY_MAPPING);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pNMHDR -
// pResult -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnDeltaPosFloatSpin( NMHDR *pNMHDR, LRESULT *pResult )
{
NM_UPDOWN *pNMUpDown = ( NM_UPDOWN* )pNMHDR;
CEdit *pEdit = NULL;
switch( pNMUpDown->hdr.idFrom )
{
case IDC_SPINSCALEY:
{
pEdit = &m_scaleY;
break;
}
case IDC_SPINSCALEX:
{
pEdit = &m_scaleX;
break;
}
}
if( pEdit != NULL )
{
CString str;
pEdit->GetWindowText(str);
float fTmp = atof(str);
fTmp += 0.1f * float( pNMUpDown->iDelta );
str.Format( "%.2f", fTmp );
pEdit->SetWindowText( str );
*pResult = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nType -
// cx -
// cy -
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnSize( UINT nType, int cx, int cy )
{
return;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnSelChangeTexture( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
if( !m_bInitialized )
{
return;
}
UpdateTexture();
if( m_pCurTex != NULL )
{
m_TextureList.AddMRU( m_pCurTex );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnCheckUnCheck( void )
{
Apply(NULL, FACE_APPLY_MAPPING);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnTreatAsOne( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
CButton *pCheck = ( CButton* )GetDlgItem( IDC_TREAT_AS_ONE );
Assert( pCheck != NULL );
m_bTreatAsOneFace = pCheck->GetCheck();
}
//-----------------------------------------------------------------------------
// Purpose: Invokes the texture replace dialog.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnReplace( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
//
// get active map doc
//
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
if( !pDoc )
return;
// ready the replace dialog
CReplaceTexDlg dlg( pDoc->GetSelection()->GetCount() );
// get the texture to replace -- the default texture?!
dlg.m_strFind = GetDefaultTextureName();
//
// open replace dialog -- modal
//
if( dlg.DoModal() != IDOK )
return;
// mark undo position
GetHistory()->MarkUndoPosition( pDoc->GetSelection()->GetList(), "Replace Textures" );
if( dlg.m_bMarkOnly )
{
pDoc->SelectObject( NULL, scClear ); // clear selection first
}
dlg.DoReplaceTextures();
}
//-----------------------------------------------------------------------------
// Purpose: Updates the m_pTexture data member based on the current selection.
// Also updates the window text and the texture picture.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::UpdateTexture( void )
{
int iSel = m_TextureList.GetCurSel();
if( iSel == LB_ERR )
{
m_TexturePic.SetTexture( NULL );
m_pCurTex = NULL;
return;
}
m_pCurTex = ( IEditorTexture* )m_TextureList.GetItemDataPtr( iSel );
m_TexturePic.SetTexture( m_pCurTex );
if( m_pCurTex )
{
char szBuf[128];
sprintf( szBuf, "%dx%d", m_pCurTex->GetWidth(), m_pCurTex->GetHeight() );
GetDlgItem( IDC_TEXTURESIZE )->SetWindowText( szBuf );
char szTexName[128];
m_pCurTex->GetShortName( szTexName );
SetDefaultTextureName( szTexName );
}
}
//-----------------------------------------------------------------------------
// Purpose: Selects a texture by name.
// Input : pszTextureName - Texture name to select.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::SelectTexture( LPCSTR pszTextureName )
{
int nIndex = m_TextureList.SelectString( -1, pszTextureName );
//
// If the texture is not in the list, add it to the list.
//
if( nIndex == LB_ERR )
{
IEditorTexture *pTex = g_Textures.FindActiveTexture( pszTextureName );
if( pTex != NULL )
{
nIndex = m_TextureList.AddString( pszTextureName );
m_TextureList.SetItemDataPtr( nIndex, pTex );
m_TextureList.SetCurSel( nIndex );
}
}
UpdateTexture();
if( nIndex != LB_ERR )
{
IEditorTexture *pTex = ( IEditorTexture* )m_TextureList.GetItemDataPtr( nIndex );
m_TextureList.AddMRU( pTex );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::NotifyGraphicsChanged( void )
{
if( !IsWindow( m_hWnd ) )
{
return;
}
// load groups into group list
CString str;
int iCurSel = m_TextureGroupList.GetCurSel();
if (iCurSel != LB_ERR)
{
m_TextureGroupList.GetLBText(iCurSel, str);
}
m_TextureGroupList.SetRedraw(FALSE);
m_TextureGroupList.ResetContent();
m_TextureGroupList.AddString("All Textures");
int nCount = g_Textures.GroupsGetCount();
if (nCount > 1)
{
//
// Skip first group ("All Textures").
//
for (int i = 1; i < nCount; i++)
{
CTextureGroup *pGroup = g_Textures.GroupsGet(i);
if (pGroup->GetTextureFormat() == g_pGameConfig->GetTextureFormat())
{
const char *p = strstr(pGroup->GetName(), "textures\\");
if (p)
{
p += strlen("textures\\");
}
else
{
p = pGroup->GetName();
}
m_TextureGroupList.AddString(p);
}
}
}
m_TextureGroupList.SetRedraw(TRUE);
if (iCurSel == LB_ERR || m_TextureGroupList.SelectString(-1, str) == LB_ERR)
{
m_TextureGroupList.SetCurSel(0);
}
m_TextureGroupList.Invalidate();
char szName[MAX_PATH];
m_TextureGroupList.GetLBText(m_TextureGroupList.GetCurSel(), szName);
g_Textures.SetActiveGroup(szName);
//
// This is called when the loaded graphics list is changed,
// or on first init by this->Create().
//
m_TextureList.LoadGraphicList();
UpdateTexture();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnBrowse( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
CTextureBrowser *pBrowser = GetMainWnd()->pTextureBrowser;
int iSel = m_TextureList.GetCurSel();
if (iSel != LB_ERR)
{
IEditorTexture *pTex = (IEditorTexture *)m_TextureList.GetItemDataPtr(iSel);
if (pTex != NULL)
{
char sz[128];
pTex->GetShortName(sz);
pBrowser->SetInitialTexture(sz);
}
}
if (pBrowser->DoModal() == IDOK)
{
IEditorTexture *pTex = g_Textures.FindActiveTexture(pBrowser->m_cTextureWindow.szCurTexture);
if (pTex != NULL)
{
int iCount = m_TextureList.GetCount();
for (int i = 0; i < iCount; i++)
{
if (pTex == (IEditorTexture *)m_TextureList.GetItemDataPtr(i))
{
m_TextureList.SetCurSel(i);
UpdateTexture();
m_TextureList.AddMRU(pTex);
break;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnChangeTextureGroup( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
int iGroup = m_TextureGroupList.GetCurSel();
//
// Set the active texture group by name.
//
char szName[MAX_PATH];
m_TextureGroupList.GetLBText(iGroup, szName);
g_Textures.SetActiveGroup(szName);
//
// Refresh the texture list contents.
//
m_TextureList.LoadGraphicList();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnButtonApply( void )
{
// Set the material tool current.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
Apply(NULL, FACE_APPLY_ALL);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
BOOL CFaceEditMaterialPage::OnSetActive( void )
{
CMainFrame *pMainFrm = GetMainWnd();
if( !pMainFrm )
return FALSE;
ToolManager()->SetTool( TOOL_FACEEDIT_MATERIAL );
// Set the initial face edit tool state.
SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
return CPropertyPage::OnSetActive();
}
//-----------------------------------------------------------------------------
// Purpose: Brings up the smoothing group dialog.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::OnButtonSmoothingGroups( void )
{
if( !m_FaceSmoothDlg.Create( IDD_SMOOTHING_GROUPS, this ) )
return;
m_FaceSmoothDlg.ShowWindow( SW_SHOW );
// Set the initial face edit tool state.
SetMaterialPageTool( MATERIALPAGETOOL_SMOOTHING_GROUP );
return;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::SetMaterialPageTool( unsigned short iMaterialTool )
{
if ( m_iMaterialTool == MATERIALPAGETOOL_SMOOTHING_GROUP )
{
// Close the window.
m_FaceSmoothDlg.DestroyWindow();
}
// Set the new material tool.
m_iMaterialTool = iMaterialTool;
}
//-----------------------------------------------------------------------------
// Purpose: Called when a new material (.vmt file) is detected.
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::NotifyNewMaterial( IEditorTexture *pTex )
{
m_TextureList.LoadGraphicList();
UpdateTexture();
}
//-----------------------------------------------------------------------------
// Purpose: Called to set the enabled state of the dialog controls
//-----------------------------------------------------------------------------
void CFaceEditMaterialPage::SetReadOnly( bool bIsReadOnly )
{
BOOL State = ( bIsReadOnly ? FALSE : TRUE );
m_shiftX.EnableWindow( State );
m_shiftY.EnableWindow( State );
m_scaleX.EnableWindow( State );
m_scaleY.EnableWindow( State );
m_rotate.EnableWindow( State );
m_cLightmapScale.EnableWindow( State );
m_cHideMask.EnableWindow( State );
m_cExpand.EnableWindow( State );
m_TextureList.EnableWindow( State );
m_TextureGroupList.EnableWindow( State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_LEFT ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_RIGHT ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_FITTOFACE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_TOP ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_BOTTOM ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_CENTER ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_TREAT_AS_ONE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_ALIGN_WORLD ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_ALIGN_FACE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_BROWSE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_REPLACE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, ID_FACEEDIT_APPLY ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, IDC_MODE ), State );
::EnableWindow( ::GetDlgItem( m_hWnd, ID_BUTTON_SMOOTHING_GROUPS ), State );
}