diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/faceedit_materialpage.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/faceedit_materialpage.cpp')
| -rw-r--r-- | hammer/faceedit_materialpage.cpp | 1785 |
1 files changed, 1785 insertions, 0 deletions
diff --git a/hammer/faceedit_materialpage.cpp b/hammer/faceedit_materialpage.cpp new file mode 100644 index 0000000..fb72068 --- /dev/null +++ b/hammer/faceedit_materialpage.cpp @@ -0,0 +1,1785 @@ +//========= 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 ); +} |