//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include #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 //============================================================================= 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 ) ON_BN_CLICKED( ID_BUTTON_SHIFTX_RANDOM, OnButtonShiftXRandom ) ON_BN_CLICKED( ID_BUTTON_SHIFTY_RANDOM, OnButtonShiftYRandom ) //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_FACE_MARK_BUTTON, &CFaceEditMaterialPage::OnBnClickedFaceMarkButton) 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_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, "%.3f", 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(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 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.005f * float( pNMUpDown->iDelta ); str.Format( "%.3f", 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: Apply a random value to the x shift //----------------------------------------------------------------------------- void CFaceEditMaterialPage::OnButtonShiftXRandom( void ) { IntegerToSpin( rand() % 512, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTX) ); Apply(NULL, FACE_APPLY_MAPPING); } //----------------------------------------------------------------------------- // Purpose: Apply a random value to the y shift //----------------------------------------------------------------------------- void CFaceEditMaterialPage::OnButtonShiftYRandom( void ) { IntegerToSpin( rand() % 512, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTY) ); Apply(NULL, FACE_APPLY_MAPPING); } //----------------------------------------------------------------------------- // 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 ); } //----------------------------------------------------------------------------- // Purpose: Select all faces that have the currently selected texture applied //----------------------------------------------------------------------------- void CFaceEditMaterialPage::OnBnClickedFaceMarkButton() { CMapDoc *pDoc = CMapDoc::GetActiveMapDoc(); if (pDoc == NULL) return; int iSel = m_TextureList.GetCurSel(); if (iSel == LB_ERR) return; IEditorTexture *pTex = (IEditorTexture *)m_TextureList.GetItemDataPtr(iSel); if (pTex == NULL) return; char sz[128]; pTex->GetShortName(sz); pDoc->ReplaceTextures(sz, "", TRUE, 0x100, FALSE, FALSE); }