Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1785 lines
47 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <stdafx.h>
  7. #include "hammer.h"
  8. #include "IEditorTexture.h"
  9. #include "FaceEditSheet.h"
  10. #include "MapFace.h"
  11. #include "MapWorld.h"
  12. #include "MainFrm.h"
  13. #include "History.h"
  14. #include "GlobalFunctions.h"
  15. #include "mathlib/vmatrix.h"
  16. #include "MapSolid.h"
  17. #include "TextureBrowser.h"
  18. #include "TextureSystem.h"
  19. #include "MapView3D.h"
  20. #include "ReplaceTexDlg.h"
  21. #include "WADTypes.h"
  22. #include "FaceEdit_MaterialPage.h"
  23. #include "Camera.h"
  24. #include "MapDoc.h"
  25. #include "MapDisp.h"
  26. #include "ToolManager.h"
  27. #include "Selection.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include <tier0/memdbgon.h>
  30. //=============================================================================
  31. IMPLEMENT_DYNAMIC( CFaceEditMaterialPage, CPropertyPage )
  32. BEGIN_MESSAGE_MAP( CFaceEditMaterialPage, CPropertyPage )
  33. //{{AFX_MSG_MAP( CFaceEditMaterialPage )
  34. ON_BN_CLICKED( ID_FACEEDIT_APPLY, OnButtonApply )
  35. ON_COMMAND_EX( IDC_ALIGN_WORLD, OnAlign )
  36. ON_COMMAND_EX( IDC_ALIGN_FACE, OnAlign )
  37. ON_BN_CLICKED( IDC_HIDEMASK, OnHideMask )
  38. ON_COMMAND_EX( IDC_JUSTIFY_TOP, OnJustify )
  39. ON_COMMAND_EX( IDC_JUSTIFY_BOTTOM, OnJustify )
  40. ON_COMMAND_EX( IDC_JUSTIFY_LEFT, OnJustify )
  41. ON_COMMAND_EX( IDC_JUSTIFY_CENTER, OnJustify )
  42. ON_COMMAND_EX( IDC_JUSTIFY_RIGHT, OnJustify )
  43. ON_COMMAND_EX( IDC_JUSTIFY_FITTOFACE, OnJustify )
  44. ON_BN_CLICKED( IDC_MODE, OnMode )
  45. ON_WM_VSCROLL()
  46. ON_NOTIFY( UDN_DELTAPOS, IDC_SPINSCALEX, OnDeltaPosFloatSpin )
  47. ON_NOTIFY( UDN_DELTAPOS, IDC_SPINSCALEY, OnDeltaPosFloatSpin )
  48. ON_WM_SIZE()
  49. ON_CBN_SELCHANGE( IDC_TEXTURES, OnSelChangeTexture )
  50. ON_BN_CLICKED( IDC_Q2_LIGHT, OnCheckUnCheck )
  51. ON_BN_CLICKED( IDC_Q2_SLICK, OnCheckUnCheck )
  52. ON_BN_CLICKED( IDC_Q2_SKY, OnCheckUnCheck )
  53. ON_BN_CLICKED( IDC_Q2_WARP, OnCheckUnCheck )
  54. ON_BN_CLICKED( IDC_Q2_TRANS33, OnCheckUnCheck )
  55. ON_BN_CLICKED( IDC_Q2_TRANS66, OnCheckUnCheck )
  56. ON_BN_CLICKED( IDC_Q2_FLOWING, OnCheckUnCheck )
  57. ON_BN_CLICKED( IDC_Q2_NODRAW, OnCheckUnCheck )
  58. ON_BN_CLICKED( IDC_Q2_SOLID, OnCheckUnCheck )
  59. ON_BN_CLICKED( IDC_Q2_WINDOW, OnCheckUnCheck )
  60. ON_BN_CLICKED( IDC_Q2_AUX, OnCheckUnCheck )
  61. ON_BN_CLICKED( IDC_Q2_LAVA, OnCheckUnCheck )
  62. ON_BN_CLICKED( IDC_Q2_SLIME, OnCheckUnCheck )
  63. ON_BN_CLICKED( IDC_Q2_WATER, OnCheckUnCheck )
  64. ON_BN_CLICKED( IDC_Q2_MIST, OnCheckUnCheck )
  65. ON_BN_CLICKED( IDC_Q2_CURRENT90, OnCheckUnCheck )
  66. ON_BN_CLICKED( IDC_Q2_CURRENT180, OnCheckUnCheck )
  67. ON_BN_CLICKED( IDC_Q2_CURRENT270, OnCheckUnCheck )
  68. ON_BN_CLICKED( IDC_Q2_CURRENTUP, OnCheckUnCheck )
  69. ON_BN_CLICKED( IDC_Q2_CURRENTDN, OnCheckUnCheck )
  70. ON_BN_CLICKED( IDC_Q2_ORIGIN, OnCheckUnCheck )
  71. ON_BN_CLICKED( IDC_Q2_MONSTER, OnCheckUnCheck )
  72. ON_BN_CLICKED( IDC_Q2_CORPSE, OnCheckUnCheck )
  73. ON_BN_CLICKED( IDC_Q2_DETAIL, OnCheckUnCheck )
  74. ON_BN_CLICKED( IDC_Q2_TRANSLUCENT, OnCheckUnCheck )
  75. ON_BN_CLICKED( IDC_Q2_LADDER, OnCheckUnCheck )
  76. ON_BN_CLICKED( IDC_Q2_PLAYERCLIP, OnCheckUnCheck )
  77. ON_BN_CLICKED( IDC_Q2_MONSTERCLIP, OnCheckUnCheck )
  78. ON_BN_CLICKED( IDC_Q2_CURRENT0, OnCheckUnCheck )
  79. ON_BN_CLICKED( IDC_Q2_HINT, OnCheckUnCheck )
  80. ON_BN_CLICKED( IDC_Q2_SPLITTER, OnCheckUnCheck )
  81. ON_COMMAND( IDC_TREAT_AS_ONE, OnTreatAsOne )
  82. ON_BN_CLICKED( IDC_REPLACE, OnReplace )
  83. ON_COMMAND_EX_RANGE( CFaceEditSheet::id_SwitchModeStart, CFaceEditSheet::id_SwitchModeEnd, OnSwitchMode )
  84. ON_CBN_SELCHANGE( IDC_TEXTUREGROUPS, OnChangeTextureGroup )
  85. ON_BN_CLICKED( IDC_BROWSE, OnBrowse )
  86. ON_BN_CLICKED( ID_BUTTON_SMOOTHING_GROUPS, OnButtonSmoothingGroups )
  87. //}}AFX_MSG_MAP
  88. END_MESSAGE_MAP()
  89. //=============================================================================
  90. #define CONTENTS_AREAPORTAL 0x8000
  91. #define CONTENTS_PLAYERCLIP 0x10000
  92. #define CONTENTS_MONSTERCLIP 0x20000
  93. // I don't think we need these currents. We'll stick to triggers for this
  94. #define CONTENTS_CURRENT_0 0x40000
  95. #define CONTENTS_CURRENT_90 0x80000
  96. #define CONTENTS_CURRENT_180 0x100000
  97. #define CONTENTS_CURRENT_270 0x200000
  98. #define CONTENTS_CURRENT_UP 0x400000
  99. #define CONTENTS_CURRENT_DOWN 0x800000
  100. #define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
  101. #define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
  102. #define CONTENTS_DEBRIS 0x4000000
  103. #define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
  104. #define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
  105. #define CONTENTS_LADDER 0x20000000
  106. //=============================================================================
  107. const int NOT_INIT = -99999;
  108. unsigned int CFaceEditMaterialPage::m_FaceContents = 0;
  109. unsigned int CFaceEditMaterialPage::m_FaceSurface = 0;
  110. //=============================================================================
  111. //-----------------------------------------------------------------------------
  112. // This table defines the mapping of checkbox controls to flags which are set
  113. // in certain face attributes values.
  114. //-----------------------------------------------------------------------------
  115. CFaceEditMaterialPage::FaceAttributeInfo_t FaceAttributes[] =
  116. {
  117. //
  118. // Contents.
  119. //
  120. { IDC_CONTENTS_AREAPORTAL, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_AREAPORTAL },
  121. { IDC_CONTENTS_PLAYERCLIP, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_PLAYERCLIP },
  122. { IDC_CONTENTS_MONSTERCLIP, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_MONSTERCLIP },
  123. { IDC_CONTENTS_ORIGIN, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_ORIGIN },
  124. { IDC_CONTENTS_DETAIL, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_DETAIL },
  125. { IDC_CONTENTS_TRANSLUCENT, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_TRANSLUCENT },
  126. { IDC_CONTENTS_LADDER, &CFaceEditMaterialPage::m_FaceContents, CONTENTS_LADDER },
  127. //
  128. // Surface attributes.
  129. //
  130. { IDC_SURF_NODRAW, &CFaceEditMaterialPage::m_FaceSurface, SURF_NODRAW },
  131. { IDC_SURF_HINT, &CFaceEditMaterialPage::m_FaceSurface, SURF_HINT },
  132. { IDC_SURF_SKIP, &CFaceEditMaterialPage::m_FaceSurface, SURF_SKIP }
  133. };
  134. //=============================================================================
  135. //-----------------------------------------------------------------------------
  136. //-----------------------------------------------------------------------------
  137. CFaceEditMaterialPage::CFaceEditMaterialPage() : CPropertyPage( IDD )
  138. {
  139. m_bHideMask = FALSE;
  140. m_bInitialized = FALSE;
  141. m_bIgnoreResize = FALSE;
  142. m_bTreatAsOneFace = FALSE;
  143. }
  144. //-----------------------------------------------------------------------------
  145. //-----------------------------------------------------------------------------
  146. CFaceEditMaterialPage::~CFaceEditMaterialPage()
  147. {
  148. }
  149. //-----------------------------------------------------------------------------
  150. //-----------------------------------------------------------------------------
  151. BOOL CFaceEditMaterialPage::PreTranslateMessage( MSG *pMsg )
  152. {
  153. HACCEL hAccel = GetMainWnd()->GetAccelTable();
  154. if( !(hAccel && ::TranslateAccelerator( GetMainWnd()->m_hWnd, hAccel, pMsg ) ) )
  155. {
  156. return CPropertyPage::PreTranslateMessage( pMsg );
  157. }
  158. else
  159. {
  160. return TRUE;
  161. }
  162. }
  163. //-----------------------------------------------------------------------------
  164. //-----------------------------------------------------------------------------
  165. void CFaceEditMaterialPage::Init( void )
  166. {
  167. //
  168. // Connect dialog control objects to their control IDs.
  169. //
  170. m_shiftX.SubclassDlgItem( IDC_SHIFTX, this );
  171. m_shiftY.SubclassDlgItem( IDC_SHIFTY, this );
  172. m_scaleX.SubclassDlgItem( IDC_SCALEX, this );
  173. m_scaleY.SubclassDlgItem( IDC_SCALEY, this );
  174. m_rotate.SubclassDlgItem( IDC_ROTATE, this );
  175. m_cHideMask.SubclassDlgItem( IDC_HIDEMASK, this );
  176. m_cExpand.SubclassDlgItem( IDC_EXPAND, this );
  177. m_cLightmapScale.SubclassDlgItem( IDC_LIGHTMAP_SCALE, this );
  178. //
  179. // Set spin ranges.
  180. //
  181. CWnd *pWnd = GetDlgItem(IDC_SPINSHIFTX);
  182. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(MAX_TEXTUREWIDTH, -MAX_TEXTUREWIDTH));
  183. pWnd = GetDlgItem(IDC_SPINSHIFTY);
  184. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(MAX_TEXTUREHEIGHT, -MAX_TEXTUREHEIGHT));
  185. pWnd = GetDlgItem(IDC_SPINROTATE);
  186. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(359, -359));
  187. pWnd = GetDlgItem(IDC_SPINSCALEX);
  188. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, UD_MINVAL));
  189. pWnd = GetDlgItem(IDC_SPINSCALEY);
  190. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, UD_MINVAL));
  191. pWnd = GetDlgItem(IDC_SPIN_LIGHTMAP_SCALE);
  192. ::PostMessage(pWnd->m_hWnd, UDM_SETRANGE, 0, MAKELONG(UD_MAXVAL, 1));
  193. // set the initial switch mode
  194. OnSwitchMode( CFaceEditSheet::ModeLiftSelect );
  195. //
  196. // set up controls
  197. //
  198. m_TextureGroupList.SubclassDlgItem( IDC_TEXTUREGROUPS, this );
  199. m_TextureList.SubclassDlgItem( IDC_TEXTURES, this );
  200. m_TexturePic.SubclassDlgItem( IDC_TEXTUREPIC, this );
  201. m_pCurTex = NULL;
  202. //
  203. // initially update the texture controls
  204. //
  205. NotifyGraphicsChanged();
  206. UpdateTexture();
  207. // initialized!
  208. m_bInitialized = TRUE;
  209. }
  210. //-----------------------------------------------------------------------------
  211. // NOTE: clean this up and make a global function!!!
  212. // Purpose:
  213. // Input : fValue -
  214. // *pSpin -
  215. // bMantissa -
  216. // Output : static void
  217. //-----------------------------------------------------------------------------
  218. void FloatToSpin(float fValue, CSpinButtonCtrl *pSpin, BOOL bMantissa)
  219. {
  220. char szNew[128];
  221. CWnd *pEdit = pSpin->GetBuddy();
  222. if (fValue == NOT_INIT)
  223. {
  224. szNew[0] = 0;
  225. }
  226. else
  227. {
  228. if(bMantissa)
  229. sprintf(szNew, "%.2f", fValue);
  230. else
  231. sprintf(szNew, "%.0f", fValue);
  232. }
  233. pSpin->SetPos(atoi(szNew));
  234. char szCurrent[128];
  235. pEdit->GetWindowText(szCurrent, 128);
  236. if (strcmp(szNew, szCurrent))
  237. {
  238. pEdit->SetWindowText(szNew);
  239. }
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. // Input : nValue -
  244. // pSpin -
  245. // Output : static void
  246. //-----------------------------------------------------------------------------
  247. void IntegerToSpin(int nValue, CSpinButtonCtrl *pSpin)
  248. {
  249. char szNew[128];
  250. CWnd *pEdit = pSpin->GetBuddy();
  251. if (nValue == NOT_INIT)
  252. {
  253. szNew[0] = 0;
  254. }
  255. else
  256. {
  257. sprintf(szNew, "%d", abs(nValue));
  258. }
  259. pSpin->SetPos(atoi(szNew));
  260. char szCurrent[128];
  261. pEdit->GetWindowText(szCurrent, 128);
  262. if (strcmp(szNew, szCurrent) != 0)
  263. {
  264. pEdit->SetWindowText(szNew);
  265. }
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Purpose:
  269. // Input : fValue -
  270. // *pWnd -
  271. // Output : static void
  272. //-----------------------------------------------------------------------------
  273. void FloatToWnd(float fValue, CWnd *pWnd)
  274. {
  275. char szCurrent[128];
  276. char szNew[128];
  277. if(fValue == NOT_INIT)
  278. {
  279. szNew[0] = 0;
  280. }
  281. else
  282. {
  283. sprintf(szNew, "%g", fValue);
  284. }
  285. pWnd->GetWindowText(szCurrent, 128);
  286. if(strcmp(szNew, szCurrent))
  287. pWnd->SetWindowText(szNew);
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose: Fetches a string value from a window and places it in a float. The
  291. // float is only modified if there is text in the window.
  292. // Input : pWnd - Window from which to get text.
  293. // fValue - Float in which to place value.
  294. //-----------------------------------------------------------------------------
  295. void TransferToFloat( CWnd *pWnd, float &fValue )
  296. {
  297. CString str;
  298. pWnd->GetWindowText( str );
  299. if( !str.IsEmpty() )
  300. {
  301. fValue = ( float )atof( str );
  302. }
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Purpose: Fetches a string value from a window and places it in an integer. The
  306. // integer is only modified if there is text in the window.
  307. // Input : pWnd - Window from which to get text.
  308. // nValue - Float in which to place value.
  309. //-----------------------------------------------------------------------------
  310. void TransferToInteger( CWnd *pWnd, int &nValue )
  311. {
  312. CString str;
  313. pWnd->GetWindowText( str );
  314. if( !str.IsEmpty() )
  315. {
  316. nValue = abs( atoi( str ) );
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. //-----------------------------------------------------------------------------
  321. void CFaceEditMaterialPage::ClickFace( CMapSolid *pSolid, int faceIndex, int cmd, int clickMode )
  322. {
  323. // get the face
  324. CMapFace *pFace = pSolid->GetFace( faceIndex );
  325. bool bIsEditable = pSolid->IsEditable();
  326. //
  327. // are updates enabled?
  328. //
  329. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  330. bool bEnableUpdate = pSheet->HasUpdateEnabled();
  331. SetReadOnly( !bIsEditable );
  332. //
  333. // find the behavior of the page based on the "click mode"
  334. //
  335. switch( clickMode )
  336. {
  337. case CFaceEditSheet::ModeAlignToView:
  338. {
  339. if ( bIsEditable )
  340. {
  341. AlignToView( pFace );
  342. }
  343. break;
  344. }
  345. case CFaceEditSheet::ModeLift:
  346. {
  347. if( bEnableUpdate )
  348. {
  349. UpdateDialogData( pFace );
  350. }
  351. break;
  352. }
  353. case CFaceEditSheet::ModeLiftSelect:
  354. {
  355. if ( bEnableUpdate )
  356. {
  357. UpdateDialogData();
  358. }
  359. break;
  360. }
  361. case CFaceEditSheet::ModeApplyLightmapScale:
  362. {
  363. // Apply the lightmap scale only. Leave everything else alone.
  364. if ( bIsEditable )
  365. {
  366. Apply(pFace, FACE_APPLY_LIGHTMAP_SCALE);
  367. }
  368. break;
  369. }
  370. case CFaceEditSheet::ModeApply:
  371. case CFaceEditSheet::ModeApplyAll:
  372. {
  373. if ( bIsEditable )
  374. {
  375. int flags = 0;
  376. if (cmd & CFaceEditSheet::cfEdgeAlign)
  377. {
  378. // Adust the mapping to align with a reference face.
  379. flags |= FACE_APPLY_ALIGN_EDGE;
  380. }
  381. if (clickMode == CFaceEditSheet::ModeApplyAll)
  382. {
  383. // Apply the material, mapping, lightmap scale, etc.
  384. flags |= FACE_APPLY_ALL;
  385. }
  386. else
  387. {
  388. // Apply the material only. Leave everything else alone.
  389. flags |= FACE_APPLY_MATERIAL;
  390. }
  391. Apply(pFace, flags);
  392. }
  393. break;
  394. }
  395. }
  396. }
  397. //-----------------------------------------------------------------------------
  398. // Maps the texture onto the face using the 3D view's up and right vectors.
  399. // This can be useful for mapping curvy things like hills because if you don't
  400. // move the 3D view, the texture will line up on any polies you map this way.
  401. //-----------------------------------------------------------------------------
  402. void CFaceEditMaterialPage::AlignToView( CMapFace *pFace )
  403. {
  404. CView *pActiveView;
  405. CMapView3D *pView3D;
  406. CFrameWnd *pFrame;
  407. Vector vView;
  408. if((pFrame = GetMainWnd()->GetActiveFrame()) != NULL)
  409. {
  410. if((pActiveView = pFrame->GetActiveView()) != NULL)
  411. {
  412. if(pActiveView->IsKindOf(RUNTIME_CLASS(CMapView3D)))
  413. {
  414. pView3D = dynamic_cast<CMapView3D*>(pActiveView);
  415. if(pView3D)
  416. {
  417. const CCamera *pCamera = pView3D->GetCamera();
  418. if(pCamera)
  419. {
  420. Vector right, up;
  421. pCamera->GetViewRight(right);
  422. pCamera->GetViewUp(up);
  423. pCamera->GetViewPoint(vView);
  424. pFace->texture.UAxis.AsVector3D() = right;
  425. pFace->texture.VAxis.AsVector3D() = up;
  426. pFace->texture.UAxis[3] = DotProduct( right, vView);
  427. pFace->texture.VAxis[3] = DotProduct( up, vView);
  428. pFace->NormalizeTextureShifts();
  429. pFace->texture.rotate = 0.0f;
  430. pFace->texture.scale[0] = g_pGameConfig->GetDefaultTextureScale();
  431. pFace->texture.scale[1] = g_pGameConfig->GetDefaultTextureScale();
  432. pFace->CalcTextureCoords();
  433. }
  434. }
  435. }
  436. }
  437. }
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Copies the texture coordinate system from pFrom into pTo. Then it rotates
  441. // the texture around the edge until it's as close to pTo's normal as possible.
  442. //-----------------------------------------------------------------------------
  443. void CFaceEditMaterialPage::CopyTCoordSystem( const CMapFace *pFrom, CMapFace *pTo )
  444. {
  445. Vector axis[2], vEdge, vEdgePt, vOrigin;
  446. Vector vFromPt, vNextFromPt;
  447. Vector vToPt, vPrevToPt;
  448. Vector vTestTextureNormal, vTextureNormal;
  449. VMatrix mEdgeRotation, mOriginRotation, mTranslation;
  450. float fAngle, fDot;
  451. bool bRotate;
  452. float fShift[2];
  453. Vector vProjTexNormal;
  454. Vector vProjPolyNormal;
  455. // The edge vector lies on both planes.
  456. vEdge = pFrom->plane.normal.Cross(pTo->plane.normal);
  457. VectorNormalize( vEdge );
  458. // To find a point on the plane, we make a plane from the edge vector and find the intersection
  459. // between the three planes (without the third plane, there are an infinite number of solutions).
  460. if( PlaneIntersection( VPlane(pFrom->plane.normal, pFrom->plane.dist),
  461. VPlane(pTo->plane.normal, pTo->plane.dist),
  462. VPlane(vEdge, 0.0f), vEdgePt ) )
  463. {
  464. bRotate = true;
  465. }
  466. else
  467. {
  468. // Ok, in this case, the planes are parallel so we don't need to rotate around the edge anyway!
  469. bRotate = false;
  470. }
  471. // Copy the texture coordinate system.
  472. axis[0] = pFrom->texture.UAxis.AsVector3D();
  473. axis[1] = pFrom->texture.VAxis.AsVector3D();
  474. fShift[0] = pFrom->texture.UAxis[3];
  475. fShift[1] = pFrom->texture.VAxis[3];
  476. vOrigin = axis[0]*fShift[0]*pFrom->texture.scale[0] + axis[1]*fShift[1]*pFrom->texture.scale[1];
  477. vTextureNormal = axis[0].Cross(axis[1]);
  478. VectorNormalize(vTextureNormal);
  479. if(bRotate)
  480. {
  481. // Project texture normal and poly normal into the plane of rotation
  482. // to get the angle between them.
  483. vProjTexNormal = vTextureNormal - vEdge * vEdge.Dot(vTextureNormal);
  484. vProjPolyNormal = pTo->plane.normal - vEdge * vEdge.Dot(pTo->plane.normal);
  485. VectorNormalize( vProjTexNormal );
  486. VectorNormalize( vProjPolyNormal );
  487. fDot = vProjTexNormal.Dot(vProjPolyNormal);
  488. fAngle = (float)(acos(fDot) * (180.0f / M_PI));
  489. if(fDot < 0.0f)
  490. fAngle = 180.0f - fAngle;
  491. // Ok, rotate them for the final values.
  492. mEdgeRotation = SetupMatrixAxisRot(vEdge, fAngle);
  493. axis[0] = mEdgeRotation.ApplyRotation(axis[0]);
  494. axis[1] = mEdgeRotation.ApplyRotation(axis[1]);
  495. // Origin needs translation and rotation to rotate around the edge.
  496. mTranslation = SetupMatrixTranslation(vEdgePt);
  497. mOriginRotation = ~mTranslation * mEdgeRotation * mTranslation;
  498. vOrigin = mOriginRotation * vOrigin;
  499. }
  500. pTo->texture.UAxis.AsVector3D() = axis[0];
  501. pTo->texture.VAxis.AsVector3D() = axis[1];
  502. pTo->texture.UAxis[3] = axis[0].Dot(vOrigin) / pFrom->texture.scale[0];
  503. pTo->texture.VAxis[3] = axis[1].Dot(vOrigin) / pFrom->texture.scale[1];
  504. pTo->NormalizeTextureShifts();
  505. pTo->texture.scale[0] = pFrom->texture.scale[0];
  506. pTo->texture.scale[1] = pFrom->texture.scale[1];
  507. // rotate is only for UI purposes, it doesn't actually do anything.
  508. pTo->texture.rotate = 0.0f;
  509. pTo->CalcTextureCoords();
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Purpose: Applies dialog data to the list of selected faces.
  513. // Input : *pOnlyFace -
  514. // bAll -
  515. //-----------------------------------------------------------------------------
  516. void CFaceEditMaterialPage::Apply( CMapFace *pOnlyFace, int flags )
  517. {
  518. int i;
  519. CString str;
  520. float fshiftX = NOT_INIT;
  521. float fshiftY = NOT_INIT;
  522. float fscaleX = NOT_INIT;
  523. float fscaleY = NOT_INIT;
  524. float frotate = NOT_INIT;
  525. int material = NOT_INIT;
  526. int nLightmapScale = NOT_INIT;
  527. IEditorTexture *pTex = m_TexturePic.GetTexture();
  528. CMapDoc *pMapDoc = CMapDoc::GetActiveMapDoc();
  529. //
  530. // Get numeric data.
  531. //
  532. if (flags & FACE_APPLY_MAPPING)
  533. {
  534. TransferToFloat( &m_shiftX, fshiftX );
  535. TransferToFloat( &m_shiftY, fshiftY );
  536. TransferToFloat( &m_scaleX, fscaleX );
  537. TransferToFloat( &m_scaleY, fscaleY );
  538. TransferToFloat( &m_rotate, frotate );
  539. }
  540. if (flags & FACE_APPLY_LIGHTMAP_SCALE)
  541. {
  542. TransferToInteger( &m_cLightmapScale, nLightmapScale );
  543. }
  544. if ( !pOnlyFace )
  545. {
  546. GetHistory()->MarkUndoPosition( NULL, "Apply Face Attributes" );
  547. // make sure we apply everything in this case.
  548. flags |= FACE_APPLY_ALL;
  549. // Keep the solids that we are about to change.
  550. // In the pOnlyFace case we do the Keep before calling ClickFace. Why?
  551. CUtlVector<CMapSolid *> kept;
  552. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  553. for( i = 0; i < pSheet->GetFaceListCount(); i++ )
  554. {
  555. CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
  556. if ( kept.Find( pSolid ) == -1 )
  557. {
  558. GetHistory()->Keep( pSolid );
  559. kept.AddToTail( pSolid );
  560. }
  561. }
  562. }
  563. //
  564. // Run thru stored faces & apply.
  565. //
  566. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  567. int faceCount = pSheet->GetFaceListCount();
  568. for( i = 0; i < faceCount || pOnlyFace; i++ )
  569. {
  570. CMapFace *pFace;
  571. if( pOnlyFace )
  572. {
  573. pFace = pOnlyFace;
  574. }
  575. else
  576. {
  577. pFace = pSheet->GetFaceListDataFace( i );
  578. }
  579. //
  580. // Get values for texture shift, scale, rotate, and material.
  581. //
  582. if ((flags & FACE_APPLY_MAPPING) && (!(flags & FACE_APPLY_ALIGN_EDGE)))
  583. {
  584. if ( fshiftX != NOT_INIT )
  585. {
  586. pFace->texture.UAxis[3] = fshiftX;
  587. }
  588. if ( fshiftY != NOT_INIT )
  589. {
  590. pFace->texture.VAxis[3] = fshiftY;
  591. }
  592. if ( fscaleX != NOT_INIT )
  593. {
  594. pFace->texture.scale[0] = fscaleX;
  595. }
  596. if ( fscaleY != NOT_INIT )
  597. {
  598. pFace->texture.scale[1] = fscaleY;
  599. }
  600. if ( frotate != NOT_INIT )
  601. {
  602. pFace->RotateTextureAxes( frotate - pFace->texture.rotate );
  603. pFace->texture.rotate = frotate;
  604. }
  605. }
  606. if (flags & FACE_APPLY_CONTENTS_DATA)
  607. {
  608. if ( material != NOT_INIT )
  609. {
  610. pFace->texture.material = material;
  611. }
  612. }
  613. if (flags & FACE_APPLY_LIGHTMAP_SCALE)
  614. {
  615. if (nLightmapScale != NOT_INIT)
  616. {
  617. pFace->texture.nLightmapScale = max( nLightmapScale, 1 );
  618. }
  619. }
  620. //
  621. // Update the texture and recalculate texture coordinates.
  622. //
  623. if ((flags & FACE_APPLY_MATERIAL) && (pTex != NULL))
  624. {
  625. char szCurrentTexName[MAX_PATH];
  626. char szNewTexName[MAX_PATH];
  627. pFace->GetTextureName( szCurrentTexName );
  628. pTex->GetShortName( szNewTexName );
  629. if( stricmp( szCurrentTexName, szNewTexName ) != 0 )
  630. {
  631. pFace->SetTexture( szNewTexName );
  632. CMapClass *pParent = dynamic_cast< CMapClass * >( pFace->GetParent() );
  633. if ( pParent )
  634. {
  635. pMapDoc->RemoveFromAutoVisGroups( pParent );
  636. pMapDoc->AddToAutoVisGroup( pParent );
  637. }
  638. }
  639. }
  640. //
  641. // Copy texture coordinate system.
  642. //
  643. if ((flags & FACE_APPLY_ALIGN_EDGE) && (faceCount >= 1))
  644. {
  645. CopyTCoordSystem( pSheet->GetFaceListDataFace( faceCount - 1 ), pFace );
  646. }
  647. //
  648. // Recalculate texture coordinates.
  649. //
  650. pFace->CalcTextureCoords();
  651. //
  652. // Update the face flags.
  653. //
  654. if (flags & FACE_APPLY_CONTENTS_DATA)
  655. {
  656. //
  657. // Copy the bits from this face into our variables.
  658. //
  659. m_FaceContents = pFace->texture.q2contents;
  660. m_FaceSurface = pFace->texture.q2surface;
  661. //
  662. // Update our variables based on the state of the checkboxes.
  663. //
  664. for( int nItem = 0; nItem < sizeof( FaceAttributes ) / sizeof( FaceAttributes[0] ); nItem++ )
  665. {
  666. CButton *pButton = ( CButton* )GetDlgItem( FaceAttributes[nItem].uControlID );
  667. if( pButton != NULL )
  668. {
  669. int nSet = pButton->GetCheck();
  670. if (nSet == 0)
  671. {
  672. *FaceAttributes[nItem].puAttribute &= ~FaceAttributes[nItem].uFlag;
  673. }
  674. else if (nSet == 1)
  675. {
  676. *FaceAttributes[nItem].puAttribute |= FaceAttributes[nItem].uFlag;
  677. }
  678. }
  679. }
  680. //
  681. // Copy our variables back into this face.
  682. //
  683. pFace->texture.q2contents = m_FaceContents;
  684. pFace->texture.q2surface = m_FaceSurface;
  685. }
  686. if( pOnlyFace )
  687. {
  688. break;
  689. }
  690. }
  691. pMapDoc->SetModifiedFlag();
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Purpose:
  695. // Input : *pOnlyFace -
  696. //-----------------------------------------------------------------------------
  697. void CFaceEditMaterialPage::UpdateDialogData( CMapFace *pOnlyFace )
  698. {
  699. BOOL bFirst;
  700. int nFaceAlignCount;
  701. int nWorldAlignCount;
  702. float fshiftX = NOT_INIT;
  703. float fshiftY = NOT_INIT;
  704. float fscaleX = NOT_INIT;
  705. float fscaleY = NOT_INIT;
  706. float frotate = NOT_INIT;
  707. //float fsmooth = NOT_INIT;
  708. int material = NOT_INIT;
  709. int nLightmapScale = NOT_INIT;
  710. CString strTexture;
  711. bFirst = TRUE;
  712. nFaceAlignCount = 0;
  713. nWorldAlignCount = 0;
  714. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  715. int faceCount = pSheet->GetFaceListCount();
  716. for( int i = 0; i < faceCount || pOnlyFace; i++ )
  717. {
  718. CMapFace *pFace;
  719. if( pOnlyFace )
  720. {
  721. pFace = pOnlyFace;
  722. }
  723. else
  724. {
  725. pFace = pSheet->GetFaceListDataFace( i );
  726. }
  727. TEXTURE &t = pFace->texture;
  728. //
  729. // Gather statistics about the texture alignment of all the selected faces.
  730. // This is used later to set the state of the alignment checkboxes.
  731. //
  732. int nAlignment = pFace->GetTextureAlignment();
  733. if (nAlignment & TEXTURE_ALIGN_FACE)
  734. {
  735. nFaceAlignCount++;
  736. }
  737. if (nAlignment & TEXTURE_ALIGN_WORLD)
  738. {
  739. nWorldAlignCount++;
  740. }
  741. //
  742. // First update - copy first face's stuff into edit fields.
  743. //
  744. if (bFirst)
  745. {
  746. fshiftX = t.UAxis[3];
  747. fshiftY = t.VAxis[3];
  748. fscaleX = t.scale[0];
  749. fscaleY = t.scale[1];
  750. frotate = t.rotate;
  751. material = t.material;
  752. strTexture = t.texture;
  753. nLightmapScale = t.nLightmapScale;
  754. //
  755. // Get the face's orientation. This is used by Apply to make intelligent decisions.
  756. //
  757. m_eOrientation = pFace->GetOrientation();
  758. Assert(m_eOrientation != FACE_ORIENTATION_INVALID);
  759. //
  760. // Set the appropriate checkbox state for the face attributes.
  761. //
  762. m_FaceContents = t.q2contents;
  763. m_FaceSurface = t.q2surface;
  764. for (int nItem = 0; nItem < sizeof(FaceAttributes) / sizeof(FaceAttributes[0]); nItem++)
  765. {
  766. int nSet = ((*FaceAttributes[nItem].puAttribute & FaceAttributes[nItem].uFlag) != 0);
  767. CButton *pButton = (CButton *)GetDlgItem(FaceAttributes[nItem].uControlID);
  768. if (pButton != NULL)
  769. {
  770. pButton->SetCheck(nSet);
  771. }
  772. }
  773. bFirst = FALSE;
  774. if (pOnlyFace) // use one face - now break
  775. {
  776. break;
  777. }
  778. }
  779. else
  780. {
  781. // update fields with face's data
  782. if (t.UAxis[3] != fshiftX)
  783. {
  784. fshiftX = NOT_INIT;
  785. }
  786. if (t.VAxis[3] != fshiftY)
  787. {
  788. fshiftY = NOT_INIT;
  789. }
  790. if (t.scale[0] != fscaleX)
  791. {
  792. fscaleX = NOT_INIT;
  793. }
  794. if (t.scale[1] != fscaleY)
  795. {
  796. fscaleY = NOT_INIT;
  797. }
  798. if (t.rotate != frotate)
  799. {
  800. frotate = NOT_INIT;
  801. }
  802. if (t.material != material)
  803. {
  804. material = NOT_INIT;
  805. }
  806. if (t.nLightmapScale != nLightmapScale)
  807. {
  808. nLightmapScale = NOT_INIT;
  809. }
  810. if (!strTexture.IsEmpty() && strTexture != t.texture)
  811. {
  812. strTexture = "";
  813. }
  814. //
  815. // Update the checkbox state for the face attributes. If any of this face's
  816. // attributes are different from the current checkbox state, set the checkbox
  817. // to the undefined state.
  818. //
  819. m_FaceContents = t.q2contents;
  820. m_FaceSurface = t.q2surface;
  821. for (int nItem = 0; nItem < sizeof(FaceAttributes) / sizeof(FaceAttributes[0]); nItem++)
  822. {
  823. int nSet = ((*FaceAttributes[nItem].puAttribute & FaceAttributes[nItem].uFlag) != 0);
  824. CButton *pButton = (CButton *)GetDlgItem(FaceAttributes[nItem].uControlID);
  825. if (pButton != NULL)
  826. {
  827. if (pButton->GetCheck() != nSet)
  828. {
  829. pButton->SetButtonStyle(BS_AUTO3STATE);
  830. pButton->SetCheck(2);
  831. }
  832. }
  833. }
  834. }
  835. }
  836. //
  837. // Set the state of the face alignment checkbox.
  838. //
  839. CButton *pFaceAlign = (CButton *)GetDlgItem(IDC_ALIGN_FACE);
  840. if (nFaceAlignCount == 0)
  841. {
  842. pFaceAlign->SetCheck(0);
  843. }
  844. else if (nFaceAlignCount == faceCount)
  845. {
  846. pFaceAlign->SetCheck(1);
  847. }
  848. else
  849. {
  850. pFaceAlign->SetCheck(2);
  851. }
  852. //
  853. // Set the state of the world alignment checkbox.
  854. //
  855. CButton *pWorldAlign = (CButton *)GetDlgItem(IDC_ALIGN_WORLD);
  856. if (nWorldAlignCount == 0)
  857. {
  858. pWorldAlign->SetCheck(0);
  859. }
  860. else if (nWorldAlignCount == faceCount)
  861. {
  862. pWorldAlign->SetCheck(1);
  863. }
  864. else
  865. {
  866. pWorldAlign->SetCheck(2);
  867. }
  868. //
  869. // Set up fields.
  870. //
  871. FloatToSpin(fshiftX, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTX), FALSE);
  872. FloatToSpin(fshiftY, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINSHIFTY), FALSE);
  873. IntegerToSpin(nLightmapScale, (CSpinButtonCtrl *)GetDlgItem(IDC_SPIN_LIGHTMAP_SCALE));
  874. FloatToWnd(fscaleX, &m_scaleX);
  875. FloatToWnd(fscaleY, &m_scaleY);
  876. FloatToSpin(frotate, (CSpinButtonCtrl*)GetDlgItem(IDC_SPINROTATE), TRUE);
  877. if (!strTexture.IsEmpty())
  878. {
  879. SelectTexture( strTexture );
  880. }
  881. else
  882. {
  883. // make empty
  884. m_TextureList.SetCurSel( -1 );
  885. }
  886. //
  887. // if no faces selected -- get selection from texture bar
  888. //
  889. if( faceCount == 0 )
  890. {
  891. CString strTexName = GetDefaultTextureName();
  892. SelectTexture( strTexName );
  893. }
  894. //
  895. // Call ctexturebar implementation because OUR implementation sets the
  896. // q2 checkboxes, which flashes the screen a bit (cuz we change them
  897. // again three lines down.)
  898. //
  899. UpdateTexture();
  900. // Update the smoothing group data.
  901. if ( GetMaterialPageTool() == MATERIALPAGETOOL_SMOOTHING_GROUP )
  902. {
  903. m_FaceSmoothDlg.UpdateControls();
  904. }
  905. }
  906. //-----------------------------------------------------------------------------
  907. // Purpose:
  908. // Input : uCmd -
  909. // Output : Returns TRUE on success, FALSE on failure.
  910. //-----------------------------------------------------------------------------
  911. BOOL CFaceEditMaterialPage::OnAlign( UINT uCmd )
  912. {
  913. // Set the material tool current.
  914. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  915. // mark position in undo stack
  916. GetHistory()->MarkUndoPosition(NULL, "Align texture");
  917. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  918. int faceCount = pSheet->GetFaceListCount();
  919. for( int i = 0; i < faceCount; i++ )
  920. {
  921. CMapFace *pFace = pSheet->GetFaceListDataFace( i );
  922. CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
  923. GetHistory()->Keep( pSolid );
  924. switch( uCmd )
  925. {
  926. case IDC_ALIGN_WORLD:
  927. {
  928. pFace->InitializeTextureAxes( TEXTURE_ALIGN_WORLD, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE );
  929. break;
  930. }
  931. case IDC_ALIGN_FACE:
  932. {
  933. pFace->InitializeTextureAxes( TEXTURE_ALIGN_FACE, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE );
  934. break;
  935. }
  936. }
  937. }
  938. CMapDoc::GetActiveMapDoc()->SetModifiedFlag();
  939. UpdateDialogData();
  940. return ( TRUE );
  941. }
  942. //-----------------------------------------------------------------------------
  943. // Purpose:
  944. //-----------------------------------------------------------------------------
  945. void CFaceEditMaterialPage::OnHideMask(void)
  946. {
  947. m_bHideMask = m_cHideMask.GetCheck();
  948. CMapFace::SetShowSelection( m_bHideMask == FALSE );
  949. CMapDoc::GetActiveMapDoc()->UpdateAllViews( MAPVIEW_UPDATE_ONLY_3D | MAPVIEW_UPDATE_OBJECTS | MAPVIEW_UPDATE_COLOR );
  950. }
  951. //-----------------------------------------------------------------------------
  952. // Purpose:
  953. // Input : Extents -
  954. //-----------------------------------------------------------------------------
  955. void CFaceEditMaterialPage::GetAllFaceExtents( Extents_t Extents )
  956. {
  957. BOOL bFirst = TRUE;
  958. Extents_t FaceExtents;
  959. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  960. int faceCount = pSheet->GetFaceListCount();
  961. for( int nFace = 0; nFace < faceCount; nFace++ )
  962. {
  963. CMapFace *pFace = pSheet->GetFaceListDataFace( nFace );
  964. pFace->GetFaceExtents(FaceExtents);
  965. if ((FaceExtents[EXTENTS_XMIN][0] < Extents[EXTENTS_XMIN][0]) || (bFirst))
  966. {
  967. Extents[EXTENTS_XMIN] = FaceExtents[EXTENTS_XMIN];
  968. }
  969. if ((FaceExtents[EXTENTS_XMAX][0] > Extents[EXTENTS_XMAX][0]) || (bFirst))
  970. {
  971. Extents[EXTENTS_XMAX] = FaceExtents[EXTENTS_XMAX];
  972. }
  973. if ((FaceExtents[EXTENTS_YMIN][1] < Extents[EXTENTS_YMIN][1]) || (bFirst))
  974. {
  975. Extents[EXTENTS_YMIN] = FaceExtents[EXTENTS_YMIN];
  976. }
  977. if ((FaceExtents[EXTENTS_YMAX][1] > Extents[EXTENTS_YMAX][1]) || (bFirst))
  978. {
  979. Extents[EXTENTS_YMAX] = FaceExtents[EXTENTS_YMAX];
  980. }
  981. if ((FaceExtents[EXTENTS_ZMIN][2] < Extents[EXTENTS_ZMIN][2]) || (bFirst))
  982. {
  983. Extents[EXTENTS_ZMIN] = FaceExtents[EXTENTS_ZMIN];
  984. }
  985. if ((FaceExtents[EXTENTS_ZMAX][2] > Extents[EXTENTS_ZMAX][2]) || (bFirst))
  986. {
  987. Extents[EXTENTS_ZMAX] = FaceExtents[EXTENTS_ZMAX];
  988. }
  989. bFirst = FALSE;
  990. }
  991. }
  992. //-----------------------------------------------------------------------------
  993. // Purpose:
  994. // Input : uCmd -
  995. // Output : Returns TRUE on success, FALSE on failure.
  996. //-----------------------------------------------------------------------------
  997. BOOL CFaceEditMaterialPage::OnJustify( UINT uCmd )
  998. {
  999. // Set the material tool current.
  1000. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1001. BOOL bTreatManyAsOneFace;
  1002. Extents_t Extents;
  1003. // mark undo position
  1004. GetHistory()->MarkUndoPosition( NULL, "Justify texture" );
  1005. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  1006. int faceCount = pSheet->GetFaceListCount();
  1007. // If multiple faces are selected, use the m_bTreatManyAsOneFace variable to determine
  1008. // how to perform the justification.
  1009. if( faceCount > 1 )
  1010. {
  1011. bTreatManyAsOneFace = m_bTreatAsOneFace;
  1012. if( bTreatManyAsOneFace )
  1013. {
  1014. GetAllFaceExtents( Extents );
  1015. }
  1016. }
  1017. // If only one face is selected, treat it singly.
  1018. else
  1019. {
  1020. bTreatManyAsOneFace = FALSE;
  1021. }
  1022. for( int i = 0; i < faceCount; i++ )
  1023. {
  1024. CMapFace *pFace = pSheet->GetFaceListDataFace( i );
  1025. CMapSolid *pSolid = pSheet->GetFaceListDataSolid( i );
  1026. GetHistory()->Keep( pSolid );
  1027. if( !bTreatManyAsOneFace )
  1028. {
  1029. pFace->GetFaceExtents( Extents );
  1030. }
  1031. switch (uCmd)
  1032. {
  1033. case IDC_JUSTIFY_TOP:
  1034. {
  1035. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_TOP, Extents);
  1036. break;
  1037. }
  1038. case IDC_JUSTIFY_BOTTOM:
  1039. {
  1040. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_BOTTOM, Extents);
  1041. break;
  1042. }
  1043. case IDC_JUSTIFY_LEFT:
  1044. {
  1045. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_LEFT, Extents);
  1046. break;
  1047. }
  1048. case IDC_JUSTIFY_RIGHT:
  1049. {
  1050. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_RIGHT, Extents);
  1051. break;
  1052. }
  1053. case IDC_JUSTIFY_CENTER:
  1054. {
  1055. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_CENTER, Extents);
  1056. break;
  1057. }
  1058. case IDC_JUSTIFY_FITTOFACE:
  1059. {
  1060. pFace->JustifyTextureUsingExtents(TEXTURE_JUSTIFY_FIT, Extents);
  1061. break;
  1062. }
  1063. }
  1064. }
  1065. CMapDoc::GetActiveMapDoc()->SetModifiedFlag();
  1066. UpdateDialogData();
  1067. return(TRUE);
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose:
  1071. // Input : id -
  1072. // Output : Returns TRUE on success, FALSE on failure.
  1073. //-----------------------------------------------------------------------------
  1074. BOOL CFaceEditMaterialPage::OnSwitchMode( UINT id )
  1075. {
  1076. CWnd *pButton = GetDlgItem( IDC_MODE );
  1077. CFaceEditSheet *pSheet = ( CFaceEditSheet* )GetParent();
  1078. pSheet->SetClickMode( id );
  1079. switch( id )
  1080. {
  1081. case CFaceEditSheet::ModeLiftSelect: // set
  1082. pButton->SetWindowText( "Mode: Lift+Select" );
  1083. break;
  1084. case CFaceEditSheet::ModeLift:
  1085. pButton->SetWindowText( "Mode: Lift" );
  1086. break;
  1087. case CFaceEditSheet::ModeSelect:
  1088. pButton->SetWindowText( "Mode: Select" );
  1089. break;
  1090. case CFaceEditSheet::ModeApply:
  1091. pButton->SetWindowText( "Mode: Apply (texture)" );
  1092. break;
  1093. case CFaceEditSheet::ModeApplyAll:
  1094. pButton->SetWindowText( "Mode: Apply (all)" );
  1095. break;
  1096. case CFaceEditSheet::ModeAlignToView:
  1097. pButton->SetWindowText( "Align To View" );
  1098. break;
  1099. }
  1100. return TRUE;
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. // Purpose:
  1104. //-----------------------------------------------------------------------------
  1105. void CFaceEditMaterialPage::OnMode()
  1106. {
  1107. // Set the material tool current.
  1108. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1109. // switch mode -
  1110. // LIFT - lift texture from clicked face
  1111. // APPLY - apply selected texture to clicked face
  1112. // SELECT - mark each face
  1113. // LIFT/SELECT - mark clicked faces & lift textures
  1114. CMenu menu;
  1115. menu.CreatePopupMenu();
  1116. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeLiftSelect, "Lift+Select" );
  1117. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeLift, "Lift" );
  1118. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeSelect, "Select" );
  1119. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeApply, "Apply (texture only)" );
  1120. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeApplyAll, "Apply (texture + values)" );
  1121. menu.AppendMenu( MF_STRING, CFaceEditSheet::ModeAlignToView, "Align To View" );
  1122. // track menu
  1123. CWnd *pButton = GetDlgItem( IDC_MODE );
  1124. CRect r;
  1125. pButton->GetWindowRect( r );
  1126. menu.TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON, r.left, r.bottom, this, NULL );
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. // Purpose:
  1130. // Input : nSBCode -
  1131. // nPos -
  1132. // *pScrollBar -
  1133. //-----------------------------------------------------------------------------
  1134. void CFaceEditMaterialPage::OnVScroll( UINT nSBCode, UINT nPos, CScrollBar *pScrollBar )
  1135. {
  1136. Apply(NULL, FACE_APPLY_MAPPING);
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. // Purpose:
  1140. // Input : pNMHDR -
  1141. // pResult -
  1142. //-----------------------------------------------------------------------------
  1143. void CFaceEditMaterialPage::OnDeltaPosFloatSpin( NMHDR *pNMHDR, LRESULT *pResult )
  1144. {
  1145. NM_UPDOWN *pNMUpDown = ( NM_UPDOWN* )pNMHDR;
  1146. CEdit *pEdit = NULL;
  1147. switch( pNMUpDown->hdr.idFrom )
  1148. {
  1149. case IDC_SPINSCALEY:
  1150. {
  1151. pEdit = &m_scaleY;
  1152. break;
  1153. }
  1154. case IDC_SPINSCALEX:
  1155. {
  1156. pEdit = &m_scaleX;
  1157. break;
  1158. }
  1159. }
  1160. if( pEdit != NULL )
  1161. {
  1162. CString str;
  1163. pEdit->GetWindowText(str);
  1164. float fTmp = atof(str);
  1165. fTmp += 0.1f * float( pNMUpDown->iDelta );
  1166. str.Format( "%.2f", fTmp );
  1167. pEdit->SetWindowText( str );
  1168. *pResult = 0;
  1169. }
  1170. }
  1171. //-----------------------------------------------------------------------------
  1172. // Purpose:
  1173. // Input : nType -
  1174. // cx -
  1175. // cy -
  1176. //-----------------------------------------------------------------------------
  1177. void CFaceEditMaterialPage::OnSize( UINT nType, int cx, int cy )
  1178. {
  1179. return;
  1180. }
  1181. //-----------------------------------------------------------------------------
  1182. // Purpose:
  1183. //-----------------------------------------------------------------------------
  1184. void CFaceEditMaterialPage::OnSelChangeTexture( void )
  1185. {
  1186. // Set the material tool current.
  1187. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1188. if( !m_bInitialized )
  1189. {
  1190. return;
  1191. }
  1192. UpdateTexture();
  1193. if( m_pCurTex != NULL )
  1194. {
  1195. m_TextureList.AddMRU( m_pCurTex );
  1196. }
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. // Purpose:
  1200. //-----------------------------------------------------------------------------
  1201. void CFaceEditMaterialPage::OnCheckUnCheck( void )
  1202. {
  1203. Apply(NULL, FACE_APPLY_MAPPING);
  1204. }
  1205. //-----------------------------------------------------------------------------
  1206. // Purpose:
  1207. //-----------------------------------------------------------------------------
  1208. void CFaceEditMaterialPage::OnTreatAsOne( void )
  1209. {
  1210. // Set the material tool current.
  1211. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1212. CButton *pCheck = ( CButton* )GetDlgItem( IDC_TREAT_AS_ONE );
  1213. Assert( pCheck != NULL );
  1214. m_bTreatAsOneFace = pCheck->GetCheck();
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. // Purpose: Invokes the texture replace dialog.
  1218. //-----------------------------------------------------------------------------
  1219. void CFaceEditMaterialPage::OnReplace( void )
  1220. {
  1221. // Set the material tool current.
  1222. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1223. //
  1224. // get active map doc
  1225. //
  1226. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  1227. if( !pDoc )
  1228. return;
  1229. // ready the replace dialog
  1230. CReplaceTexDlg dlg( pDoc->GetSelection()->GetCount() );
  1231. // get the texture to replace -- the default texture?!
  1232. dlg.m_strFind = GetDefaultTextureName();
  1233. //
  1234. // open replace dialog -- modal
  1235. //
  1236. if( dlg.DoModal() != IDOK )
  1237. return;
  1238. // mark undo position
  1239. GetHistory()->MarkUndoPosition( pDoc->GetSelection()->GetList(), "Replace Textures" );
  1240. if( dlg.m_bMarkOnly )
  1241. {
  1242. pDoc->SelectObject( NULL, scClear ); // clear selection first
  1243. }
  1244. dlg.DoReplaceTextures();
  1245. }
  1246. //-----------------------------------------------------------------------------
  1247. // Purpose: Updates the m_pTexture data member based on the current selection.
  1248. // Also updates the window text and the texture picture.
  1249. //-----------------------------------------------------------------------------
  1250. void CFaceEditMaterialPage::UpdateTexture( void )
  1251. {
  1252. int iSel = m_TextureList.GetCurSel();
  1253. if( iSel == LB_ERR )
  1254. {
  1255. m_TexturePic.SetTexture( NULL );
  1256. m_pCurTex = NULL;
  1257. return;
  1258. }
  1259. m_pCurTex = ( IEditorTexture* )m_TextureList.GetItemDataPtr( iSel );
  1260. m_TexturePic.SetTexture( m_pCurTex );
  1261. if( m_pCurTex )
  1262. {
  1263. char szBuf[128];
  1264. sprintf( szBuf, "%dx%d", m_pCurTex->GetWidth(), m_pCurTex->GetHeight() );
  1265. GetDlgItem( IDC_TEXTURESIZE )->SetWindowText( szBuf );
  1266. char szTexName[128];
  1267. m_pCurTex->GetShortName( szTexName );
  1268. SetDefaultTextureName( szTexName );
  1269. }
  1270. }
  1271. //-----------------------------------------------------------------------------
  1272. // Purpose: Selects a texture by name.
  1273. // Input : pszTextureName - Texture name to select.
  1274. //-----------------------------------------------------------------------------
  1275. void CFaceEditMaterialPage::SelectTexture( LPCSTR pszTextureName )
  1276. {
  1277. int nIndex = m_TextureList.SelectString( -1, pszTextureName );
  1278. //
  1279. // If the texture is not in the list, add it to the list.
  1280. //
  1281. if( nIndex == LB_ERR )
  1282. {
  1283. IEditorTexture *pTex = g_Textures.FindActiveTexture( pszTextureName );
  1284. if( pTex != NULL )
  1285. {
  1286. nIndex = m_TextureList.AddString( pszTextureName );
  1287. m_TextureList.SetItemDataPtr( nIndex, pTex );
  1288. m_TextureList.SetCurSel( nIndex );
  1289. }
  1290. }
  1291. UpdateTexture();
  1292. if( nIndex != LB_ERR )
  1293. {
  1294. IEditorTexture *pTex = ( IEditorTexture* )m_TextureList.GetItemDataPtr( nIndex );
  1295. m_TextureList.AddMRU( pTex );
  1296. }
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // Purpose:
  1300. //-----------------------------------------------------------------------------
  1301. void CFaceEditMaterialPage::NotifyGraphicsChanged( void )
  1302. {
  1303. if( !IsWindow( m_hWnd ) )
  1304. {
  1305. return;
  1306. }
  1307. // load groups into group list
  1308. CString str;
  1309. int iCurSel = m_TextureGroupList.GetCurSel();
  1310. if (iCurSel != LB_ERR)
  1311. {
  1312. m_TextureGroupList.GetLBText(iCurSel, str);
  1313. }
  1314. m_TextureGroupList.SetRedraw(FALSE);
  1315. m_TextureGroupList.ResetContent();
  1316. m_TextureGroupList.AddString("All Textures");
  1317. int nCount = g_Textures.GroupsGetCount();
  1318. if (nCount > 1)
  1319. {
  1320. //
  1321. // Skip first group ("All Textures").
  1322. //
  1323. for (int i = 1; i < nCount; i++)
  1324. {
  1325. CTextureGroup *pGroup = g_Textures.GroupsGet(i);
  1326. if (pGroup->GetTextureFormat() == g_pGameConfig->GetTextureFormat())
  1327. {
  1328. const char *p = strstr(pGroup->GetName(), "textures\\");
  1329. if (p)
  1330. {
  1331. p += strlen("textures\\");
  1332. }
  1333. else
  1334. {
  1335. p = pGroup->GetName();
  1336. }
  1337. m_TextureGroupList.AddString(p);
  1338. }
  1339. }
  1340. }
  1341. m_TextureGroupList.SetRedraw(TRUE);
  1342. if (iCurSel == LB_ERR || m_TextureGroupList.SelectString(-1, str) == LB_ERR)
  1343. {
  1344. m_TextureGroupList.SetCurSel(0);
  1345. }
  1346. m_TextureGroupList.Invalidate();
  1347. char szName[MAX_PATH];
  1348. m_TextureGroupList.GetLBText(m_TextureGroupList.GetCurSel(), szName);
  1349. g_Textures.SetActiveGroup(szName);
  1350. //
  1351. // This is called when the loaded graphics list is changed,
  1352. // or on first init by this->Create().
  1353. //
  1354. m_TextureList.LoadGraphicList();
  1355. UpdateTexture();
  1356. }
  1357. //-----------------------------------------------------------------------------
  1358. // Purpose:
  1359. //-----------------------------------------------------------------------------
  1360. void CFaceEditMaterialPage::OnBrowse( void )
  1361. {
  1362. // Set the material tool current.
  1363. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1364. CTextureBrowser *pBrowser = GetMainWnd()->pTextureBrowser;
  1365. int iSel = m_TextureList.GetCurSel();
  1366. if (iSel != LB_ERR)
  1367. {
  1368. IEditorTexture *pTex = (IEditorTexture *)m_TextureList.GetItemDataPtr(iSel);
  1369. if (pTex != NULL)
  1370. {
  1371. char sz[128];
  1372. pTex->GetShortName(sz);
  1373. pBrowser->SetInitialTexture(sz);
  1374. }
  1375. }
  1376. if (pBrowser->DoModal() == IDOK)
  1377. {
  1378. IEditorTexture *pTex = g_Textures.FindActiveTexture(pBrowser->m_cTextureWindow.szCurTexture);
  1379. if (pTex != NULL)
  1380. {
  1381. int iCount = m_TextureList.GetCount();
  1382. for (int i = 0; i < iCount; i++)
  1383. {
  1384. if (pTex == (IEditorTexture *)m_TextureList.GetItemDataPtr(i))
  1385. {
  1386. m_TextureList.SetCurSel(i);
  1387. UpdateTexture();
  1388. m_TextureList.AddMRU(pTex);
  1389. break;
  1390. }
  1391. }
  1392. }
  1393. }
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. // Purpose:
  1397. //-----------------------------------------------------------------------------
  1398. void CFaceEditMaterialPage::OnChangeTextureGroup( void )
  1399. {
  1400. // Set the material tool current.
  1401. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1402. int iGroup = m_TextureGroupList.GetCurSel();
  1403. //
  1404. // Set the active texture group by name.
  1405. //
  1406. char szName[MAX_PATH];
  1407. m_TextureGroupList.GetLBText(iGroup, szName);
  1408. g_Textures.SetActiveGroup(szName);
  1409. //
  1410. // Refresh the texture list contents.
  1411. //
  1412. m_TextureList.LoadGraphicList();
  1413. }
  1414. //-----------------------------------------------------------------------------
  1415. //-----------------------------------------------------------------------------
  1416. void CFaceEditMaterialPage::OnButtonApply( void )
  1417. {
  1418. // Set the material tool current.
  1419. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1420. Apply(NULL, FACE_APPLY_ALL);
  1421. }
  1422. //-----------------------------------------------------------------------------
  1423. //-----------------------------------------------------------------------------
  1424. BOOL CFaceEditMaterialPage::OnSetActive( void )
  1425. {
  1426. CMainFrame *pMainFrm = GetMainWnd();
  1427. if( !pMainFrm )
  1428. return FALSE;
  1429. ToolManager()->SetTool( TOOL_FACEEDIT_MATERIAL );
  1430. // Set the initial face edit tool state.
  1431. SetMaterialPageTool( MATERIALPAGETOOL_MATERIAL );
  1432. return CPropertyPage::OnSetActive();
  1433. }
  1434. //-----------------------------------------------------------------------------
  1435. // Purpose: Brings up the smoothing group dialog.
  1436. //-----------------------------------------------------------------------------
  1437. void CFaceEditMaterialPage::OnButtonSmoothingGroups( void )
  1438. {
  1439. if( !m_FaceSmoothDlg.Create( IDD_SMOOTHING_GROUPS, this ) )
  1440. return;
  1441. m_FaceSmoothDlg.ShowWindow( SW_SHOW );
  1442. // Set the initial face edit tool state.
  1443. SetMaterialPageTool( MATERIALPAGETOOL_SMOOTHING_GROUP );
  1444. return;
  1445. }
  1446. //-----------------------------------------------------------------------------
  1447. // Purpose:
  1448. //-----------------------------------------------------------------------------
  1449. void CFaceEditMaterialPage::SetMaterialPageTool( unsigned short iMaterialTool )
  1450. {
  1451. if ( m_iMaterialTool == MATERIALPAGETOOL_SMOOTHING_GROUP )
  1452. {
  1453. // Close the window.
  1454. m_FaceSmoothDlg.DestroyWindow();
  1455. }
  1456. // Set the new material tool.
  1457. m_iMaterialTool = iMaterialTool;
  1458. }
  1459. //-----------------------------------------------------------------------------
  1460. // Purpose: Called when a new material (.vmt file) is detected.
  1461. //-----------------------------------------------------------------------------
  1462. void CFaceEditMaterialPage::NotifyNewMaterial( IEditorTexture *pTex )
  1463. {
  1464. m_TextureList.LoadGraphicList();
  1465. UpdateTexture();
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. // Purpose: Called to set the enabled state of the dialog controls
  1469. //-----------------------------------------------------------------------------
  1470. void CFaceEditMaterialPage::SetReadOnly( bool bIsReadOnly )
  1471. {
  1472. BOOL State = ( bIsReadOnly ? FALSE : TRUE );
  1473. m_shiftX.EnableWindow( State );
  1474. m_shiftY.EnableWindow( State );
  1475. m_scaleX.EnableWindow( State );
  1476. m_scaleY.EnableWindow( State );
  1477. m_rotate.EnableWindow( State );
  1478. m_cLightmapScale.EnableWindow( State );
  1479. m_cHideMask.EnableWindow( State );
  1480. m_cExpand.EnableWindow( State );
  1481. m_TextureList.EnableWindow( State );
  1482. m_TextureGroupList.EnableWindow( State );
  1483. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_LEFT ), State );
  1484. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_RIGHT ), State );
  1485. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_FITTOFACE ), State );
  1486. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_TOP ), State );
  1487. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_BOTTOM ), State );
  1488. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_JUSTIFY_CENTER ), State );
  1489. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_TREAT_AS_ONE ), State );
  1490. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_ALIGN_WORLD ), State );
  1491. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_ALIGN_FACE ), State );
  1492. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_BROWSE ), State );
  1493. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_REPLACE ), State );
  1494. ::EnableWindow( ::GetDlgItem( m_hWnd, ID_FACEEDIT_APPLY ), State );
  1495. ::EnableWindow( ::GetDlgItem( m_hWnd, IDC_MODE ), State );
  1496. ::EnableWindow( ::GetDlgItem( m_hWnd, ID_BUTTON_SMOOTHING_GROUPS ), State );
  1497. }