Counter Strike : Global Offensive Source Code
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.

1823 lines
48 KiB

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