W3DMouse.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DMouse.cpp /////////////////////////////////////////////////////////////////////////////
  24. // Author: Mark W.
  25. // Desc: W3D Mouse cursor implementations
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #include "Common/GameMemory.h"
  28. #include "WW3D2/DX8Wrapper.h"
  29. #include "WW3D2/RendObj.h"
  30. #include "WW3D2/HAnim.h"
  31. #include "WW3D2/Camera.h"
  32. #include "assetmgr.h"
  33. #include "W3DDevice/Common/W3DConvert.h"
  34. #include "W3DDevice/GameClient/W3DMouse.h"
  35. #include "W3DDevice/GameClient/W3DDisplay.h"
  36. #include "W3DDevice/GameClient/W3DAssetManager.h"
  37. #include "W3DDevice/GameClient/W3DScene.h"
  38. #include "GameClient/Display.h"
  39. #include "GameClient/Image.h"
  40. #include "GameClient/InGameUI.h"
  41. #include "mutex.h"
  42. #include "thread.h"
  43. #ifdef _INTERNAL
  44. // for occasional debugging...
  45. //#pragma optimize("", off)
  46. //#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
  47. #endif
  48. //Since there can't be more than 1 mouse, might as well keep these static.
  49. static CriticalSectionClass mutex;
  50. static Bool isThread;
  51. static TextureClass *cursorTextures[Mouse::NUM_MOUSE_CURSORS][MAX_2D_CURSOR_ANIM_FRAMES]; ///<Textures for each cursor type
  52. static const Image *cursorImages[Mouse::NUM_MOUSE_CURSORS]; ///<Images for use with the RM_POLYGON method.
  53. static RenderObjClass *cursorModels[Mouse::NUM_MOUSE_CURSORS]; ///< W3D models for each cursor type
  54. static HAnimClass *cursorAnims[Mouse::NUM_MOUSE_CURSORS]; ///< W3D animations for each cursor type
  55. ///Mouse polling/update thread function
  56. static class MouseThreadClass : public ThreadClass
  57. {
  58. public:
  59. MouseThreadClass::MouseThreadClass() : ThreadClass() {}
  60. void Thread_Function();
  61. } thread;
  62. void MouseThreadClass::Thread_Function()
  63. {
  64. //poll mouse and update position
  65. while (running)
  66. {
  67. isThread=TRUE;
  68. if (TheMouse)
  69. TheMouse->draw();
  70. isThread=FALSE;
  71. Switch_Thread();
  72. }
  73. }
  74. W3DMouse::W3DMouse( void )
  75. {
  76. // zero our event list
  77. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  78. {
  79. for (Int j=0; j<MAX_2D_CURSOR_ANIM_FRAMES; j++)
  80. cursorTextures[i][j]=NULL;
  81. cursorModels[i]=NULL;
  82. cursorAnims[i]=NULL;
  83. }
  84. m_currentD3DCursor=NONE;
  85. m_currentW3DCursor=NONE;
  86. m_currentPolygonCursor=NONE;
  87. m_currentAnimFrame = 0;
  88. m_currentD3DFrame = 0;
  89. m_currentFrames = 0;
  90. m_currentFMS= 1.0f/1000.0f;
  91. m_camera = NULL;
  92. m_drawing = FALSE;
  93. } // end Win32Mouse
  94. W3DMouse::~W3DMouse( void )
  95. {
  96. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  97. if (m_pDev)
  98. {
  99. m_pDev->ShowCursor(FALSE); //kill DX8 cursor
  100. Win32Mouse::setCursor(ARROW); //enable default windows cursor
  101. }
  102. freeD3DAssets();
  103. freeW3DAssets();
  104. thread.Stop();
  105. } // end Win32Mouse
  106. void W3DMouse::initPolygonAssets(void)
  107. {
  108. CriticalSectionClass::LockClass m(mutex);
  109. //don't allow the mouse thread to initialize
  110. //wait for main app to do initialization.
  111. if (isThread)
  112. return;
  113. //Check if texture assets already loaded
  114. if (m_currentRedrawMode == RM_POLYGON && cursorImages[1] == NULL)
  115. {
  116. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  117. {
  118. m_currentPolygonCursor = m_currentCursor;
  119. if (!m_cursorInfo[i].imageName.isEmpty())
  120. cursorImages[i]=TheMappedImageCollection->findImageByName(m_cursorInfo[i].imageName);
  121. }
  122. }
  123. }
  124. void W3DMouse::freePolygonAssets(void)
  125. {
  126. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  127. {
  128. cursorImages[i]=NULL;
  129. }
  130. }
  131. /**Release the textures required to display the selected cursor*/
  132. Bool W3DMouse::releaseD3DCursorTextures(MouseCursor cursor)
  133. {
  134. if (cursor == NONE || !cursorTextures[cursor][0])
  135. return TRUE; //no texture for this cursor or texture never loaded
  136. for (Int i=0; i<MAX_2D_CURSOR_ANIM_FRAMES; i++)
  137. {
  138. REF_PTR_RELEASE(m_currentD3DSurface[i]);
  139. REF_PTR_RELEASE(cursorTextures[cursor][i]);
  140. }
  141. return TRUE;
  142. }
  143. /**Load the textures required to display the selected cursor*/
  144. Bool W3DMouse::loadD3DCursorTextures(MouseCursor cursor)
  145. {
  146. if (cursor == NONE || cursorTextures[cursor][0])
  147. return TRUE; //no texture for this cursor or texture already loaded
  148. WW3DAssetManager *am=WW3DAssetManager::Get_Instance();
  149. Int animFrames=m_cursorInfo[cursor].numFrames;
  150. if (!animFrames)
  151. return FALSE; //no animation frames defined.
  152. const char *baseName=m_cursorInfo[cursor].textureName.str();
  153. char FrameName[64];
  154. //Clamp to reasonable number
  155. if (animFrames > MAX_2D_CURSOR_ANIM_FRAMES)
  156. animFrames = MAX_2D_CURSOR_ANIM_FRAMES;
  157. m_currentFrames=0;
  158. if (animFrames == 1)
  159. { //single animation frame without trailing numbers
  160. sprintf(FrameName,"%s.tga",baseName);
  161. cursorTextures[cursor][0]= am->Get_Texture(FrameName);
  162. m_currentD3DSurface[0]=cursorTextures[cursor][0]->Get_Surface_Level();
  163. m_currentFrames = 1;
  164. }
  165. else
  166. for (Int i=0; i<animFrames; i++)
  167. {
  168. sprintf(FrameName,"%s%04d.tga",baseName,i);
  169. if ((cursorTextures[cursor][i]=am->Get_Texture(FrameName)) != NULL)
  170. { m_currentD3DSurface[m_currentFrames]=cursorTextures[cursor][i]->Get_Surface_Level();
  171. m_currentFrames++;
  172. }
  173. }
  174. return TRUE;
  175. }
  176. void W3DMouse::initD3DAssets(void)
  177. {
  178. //Nothing to do here unless we want to preload all possible cursors which would
  179. //probably not be practical for memory reasons.
  180. CriticalSectionClass::LockClass m(mutex);
  181. //don't allow the mouse thread to initialize
  182. //wait for main app to do initialization.
  183. if (isThread)
  184. return;
  185. WW3DAssetManager *am=WW3DAssetManager::Get_Instance();
  186. //Check if texture assets already loaded
  187. if (m_currentRedrawMode == RM_DX8 && cursorTextures[1] == NULL && am)
  188. {
  189. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  190. {
  191. for (Int j=0; j < MAX_2D_CURSOR_ANIM_FRAMES; j++)
  192. {
  193. cursorTextures[i][j]=NULL;//am->Get_Texture(m_cursorInfo[i].textureName.str());
  194. m_currentD3DSurface[i]=NULL;
  195. }
  196. }
  197. }
  198. }
  199. void W3DMouse::freeD3DAssets(void)
  200. {
  201. //free pointers to texture surfaces.
  202. for (Int i=0; i<MAX_2D_CURSOR_ANIM_FRAMES; i++)
  203. REF_PTR_RELEASE(m_currentD3DSurface[i]);
  204. //free textures.
  205. for (i=0; i<NUM_MOUSE_CURSORS; i++)
  206. {
  207. for (Int j=0; j<MAX_2D_CURSOR_ANIM_FRAMES; j++)
  208. REF_PTR_RELEASE(cursorTextures[i][j]);
  209. }
  210. }
  211. void W3DMouse::initW3DAssets(void)
  212. {
  213. CriticalSectionClass::LockClass m(mutex);
  214. //don't allow the mouse thread to initialize
  215. //wait for main app to do initialization.
  216. if (isThread)
  217. return;
  218. //Check if model assets already loaded
  219. if ((cursorModels[1] == NULL && W3DDisplay::m_assetManager))
  220. {
  221. for (Int i=1; i<NUM_MOUSE_CURSORS; i++)
  222. {
  223. if (!m_cursorInfo[i].W3DModelName.isEmpty())
  224. {
  225. if (m_orthoCamera)
  226. cursorModels[i] = W3DDisplay::m_assetManager->Create_Render_Obj(m_cursorInfo[i].W3DModelName.str(), m_cursorInfo[i].W3DScale*m_orthoZoom, 0);
  227. else
  228. cursorModels[i] = W3DDisplay::m_assetManager->Create_Render_Obj(m_cursorInfo[i].W3DModelName.str(), m_cursorInfo[i].W3DScale, 0);
  229. if (cursorModels[i])
  230. {
  231. cursorModels[i]->Set_Position(Vector3(0.0f, 0.0f, -1.0f));
  232. //W3DDisplay::m_3DInterfaceScene->Add_Render_Object(cursorModels[i]);
  233. }
  234. }
  235. }
  236. }
  237. if ((cursorAnims[1] == NULL && W3DDisplay::m_assetManager))
  238. {
  239. for (Int i=1; i<NUM_MOUSE_CURSORS; i++)
  240. {
  241. if (!m_cursorInfo[i].W3DAnimName.isEmpty())
  242. {
  243. DEBUG_ASSERTCRASH(cursorAnims[i] == NULL, ("hmm, leak festival"));
  244. cursorAnims[i] = W3DDisplay::m_assetManager->Get_HAnim(m_cursorInfo[i].W3DAnimName.str());
  245. if (cursorAnims[i] && cursorModels[i])
  246. {
  247. cursorModels[i]->Set_Animation(cursorAnims[i], 0, (m_cursorInfo[i].loop) ? RenderObjClass::ANIM_MODE_LOOP : RenderObjClass::ANIM_MODE_ONCE);
  248. }
  249. }
  250. }
  251. }
  252. // create the camera
  253. m_camera = NEW_REF( CameraClass, () );
  254. m_camera->Set_Position( Vector3( 0, 1, 1 ) );
  255. Vector2 min = Vector2( -1, -1 );
  256. Vector2 max = Vector2( +1, +1 );
  257. m_camera->Set_View_Plane( min, max );
  258. m_camera->Set_Clip_Planes( 0.995f, 20.0f );
  259. if (m_orthoCamera)
  260. m_camera->Set_Projection_Type( CameraClass::ORTHO );
  261. }
  262. void W3DMouse::freeW3DAssets(void)
  263. {
  264. for (Int i=0; i<NUM_MOUSE_CURSORS; i++)
  265. {
  266. if (W3DDisplay::m_3DInterfaceScene && cursorModels[i])
  267. {
  268. W3DDisplay::m_3DInterfaceScene->Remove_Render_Object(cursorModels[i]);
  269. }
  270. REF_PTR_RELEASE(cursorModels[i]);
  271. REF_PTR_RELEASE(cursorAnims[i]);
  272. }
  273. REF_PTR_RELEASE(m_camera);
  274. }
  275. //-------------------------------------------------------------------------------------------------
  276. /** Initialize our device */
  277. //-------------------------------------------------------------------------------------------------
  278. void W3DMouse::init( void )
  279. {
  280. //check if system already initialized and texture assets loaded.
  281. Win32Mouse::init();
  282. setCursor(ARROW); //set default starting cursor image
  283. WWASSERT(!thread.Is_Running());
  284. isThread=FALSE;
  285. if (m_currentRedrawMode == RM_DX8)
  286. thread.Execute();
  287. thread.Set_Priority(0);
  288. } // end int
  289. //-------------------------------------------------------------------------------------------------
  290. /** Reset */
  291. //-------------------------------------------------------------------------------------------------
  292. void W3DMouse::reset( void )
  293. {
  294. // extend
  295. Win32Mouse::reset();
  296. } // end reset
  297. //-------------------------------------------------------------------------------------------------
  298. /** Super basic simplistic cursor */
  299. //-------------------------------------------------------------------------------------------------
  300. void W3DMouse::setCursor( MouseCursor cursor )
  301. {
  302. CriticalSectionClass::LockClass m(mutex);
  303. m_directionFrame=0;
  304. if (m_currentRedrawMode == RM_WINDOWS)
  305. { //Windows default cursor needs to refreshed whenever we get a WM_SETCURSOR
  306. m_currentD3DCursor=NONE;
  307. m_currentW3DCursor=NONE;
  308. m_currentPolygonCursor=NONE;
  309. setCursorDirection(cursor);
  310. if (m_drawing) //only allow cursor to change when drawing the cursor (once per frame) to fix flickering.
  311. Win32Mouse::setCursor(cursor);
  312. m_currentCursor = cursor;
  313. return;
  314. }
  315. // extend
  316. Mouse::setCursor( cursor );
  317. // if we're already on this cursor ignore the rest of code to stop cursor flickering.
  318. if( m_currentCursor == cursor && m_currentD3DCursor == cursor)
  319. return;
  320. //make sure Windows didn't reset our cursor
  321. if (m_currentRedrawMode == RM_DX8)
  322. {
  323. SetCursor(NULL); //Kill Windows Cursor
  324. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  325. Bool doImageChange=FALSE;
  326. if (m_pDev != NULL)
  327. {
  328. m_pDev->ShowCursor(FALSE); //disable DX8 cursor
  329. if (cursor != m_currentD3DCursor)
  330. { if (!isThread)
  331. { releaseD3DCursorTextures(m_currentD3DCursor);
  332. //Since this type of cursor is updated from a non-D3D thread, we need
  333. //to preallocate all surfaces in main thread.
  334. loadD3DCursorTextures(cursor);
  335. }
  336. }
  337. if (m_currentD3DSurface[0])
  338. doImageChange=TRUE;
  339. }
  340. //For DX8 Cursors, we continually set the image on every call even when
  341. //it didn't change. This is needed to prevent the cursor from flickering.
  342. if (doImageChange)
  343. {
  344. HRESULT res;
  345. m_currentHotSpot = m_cursorInfo[cursor].hotSpotPosition;
  346. m_currentFMS = m_cursorInfo[cursor].fps/1000.0f;
  347. m_currentAnimFrame = 0; //reset animation when cursor changes
  348. res = m_pDev->SetCursorProperties(m_currentHotSpot.x,m_currentHotSpot.y,m_currentD3DSurface[(Int)m_currentAnimFrame]->Peek_D3D_Surface());
  349. m_pDev->ShowCursor(TRUE); //Enable DX8 cursor
  350. m_currentD3DFrame=(Int)m_currentAnimFrame;
  351. m_currentD3DCursor = cursor;
  352. m_lastAnimTime=timeGetTime();
  353. }
  354. }
  355. else if (m_currentRedrawMode == RM_POLYGON)
  356. {
  357. SetCursor(NULL); //Kill Windows Cursor
  358. m_currentD3DCursor=NONE;
  359. m_currentW3DCursor=NONE;
  360. m_currentPolygonCursor = cursor;
  361. m_currentHotSpot = m_cursorInfo[cursor].hotSpotPosition;
  362. }
  363. else if (m_currentRedrawMode == RM_W3D)
  364. {
  365. SetCursor(NULL); //Kill Windows Cursor
  366. m_currentD3DCursor=NONE;
  367. m_currentPolygonCursor=NONE;
  368. if (cursor != m_currentW3DCursor)
  369. {
  370. // set the new model visible
  371. if (!cursorModels[1])
  372. initW3DAssets();
  373. if (cursorModels[1])
  374. {
  375. if (cursorModels[m_currentW3DCursor])
  376. {
  377. W3DDisplay::m_3DInterfaceScene->Remove_Render_Object(cursorModels[m_currentW3DCursor]);
  378. }
  379. m_currentW3DCursor=cursor;
  380. if (cursorModels[m_currentW3DCursor])
  381. {
  382. W3DDisplay::m_3DInterfaceScene->Add_Render_Object(cursorModels[m_currentW3DCursor]);
  383. if (m_cursorInfo[m_currentW3DCursor].loop == FALSE && cursorAnims[m_currentW3DCursor])
  384. {
  385. cursorModels[m_currentW3DCursor]->Set_Animation(cursorAnims[m_currentW3DCursor], 0, RenderObjClass::ANIM_MODE_ONCE);
  386. }
  387. }
  388. }
  389. }
  390. else
  391. {
  392. m_currentW3DCursor=cursor;
  393. }
  394. }
  395. // save current cursor
  396. m_currentCursor = cursor;
  397. } // end setCursor
  398. extern HWND ApplicationHWnd;
  399. void W3DMouse::draw(void)
  400. {
  401. CriticalSectionClass::LockClass m(mutex);
  402. m_drawing = TRUE;
  403. //make sure the correct cursor image is selected
  404. setCursor(m_currentCursor);
  405. if (m_currentRedrawMode == RM_DX8 && m_currentD3DCursor != NONE)
  406. {
  407. //called from upate thread or rendering loop. Tells D3D where
  408. //to draw the mouse cursor.
  409. LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8();
  410. if (m_pDev)
  411. { m_pDev->ShowCursor(TRUE); //Enable DX8 cursor
  412. if (TheDisplay && !TheDisplay->getWindowed())
  413. { //if we're full-screen, need to manually move cursor image
  414. POINT ptCursor;
  415. GetCursorPos( &ptCursor );
  416. ScreenToClient( ApplicationHWnd, &ptCursor );
  417. m_pDev->SetCursorPosition( ptCursor.x, ptCursor.y, D3DCURSOR_IMMEDIATE_UPDATE);
  418. }
  419. //Check if animated cursor and new frame
  420. if (m_currentFrames > 1)
  421. {
  422. Int msTime=timeGetTime();
  423. m_currentAnimFrame += (msTime-m_lastAnimTime) * m_currentFMS;
  424. m_currentAnimFrame=fmod(m_currentAnimFrame,m_currentFrames);
  425. m_lastAnimTime=msTime;
  426. if ((Int)m_currentAnimFrame != m_currentD3DFrame)
  427. {
  428. m_currentD3DFrame=(Int)m_currentAnimFrame;
  429. m_pDev->SetCursorProperties(m_currentHotSpot.x,m_currentHotSpot.y,m_currentD3DSurface[m_currentD3DFrame]->Peek_D3D_Surface());
  430. }
  431. }
  432. }
  433. }
  434. else if (m_currentRedrawMode == RM_POLYGON)
  435. {
  436. const Image *image=cursorImages[m_currentPolygonCursor];
  437. if (image)
  438. {
  439. TheDisplay->drawImage(image,m_currMouse.pos.x-m_currentHotSpot.x,m_currMouse.pos.y-m_currentHotSpot.y,
  440. m_currMouse.pos.x+image->getImageWidth()-m_currentHotSpot.x, m_currMouse.pos.y+image->getImageHeight()-m_currentHotSpot.y);
  441. }
  442. }
  443. else if (m_currentRedrawMode == RM_WINDOWS)
  444. {
  445. }
  446. else if (m_currentRedrawMode == RM_W3D)
  447. {
  448. if ( W3DDisplay::m_3DInterfaceScene && m_camera && m_visible)
  449. {
  450. if (cursorModels[m_currentW3DCursor])
  451. {
  452. Real xPercent = (1.0f - (TheDisplay->getWidth() - m_currMouse.pos.x) / (Real)TheDisplay->getWidth());
  453. Real yPercent = ((TheDisplay->getHeight() - m_currMouse.pos.y) / (Real)TheDisplay->getHeight());
  454. Real x, y, z = -1.0f;
  455. if (m_orthoCamera)
  456. {
  457. x = xPercent*2 - 1;
  458. y = yPercent*2;
  459. }
  460. else
  461. {
  462. //W3D Screen coordinates are -1 to 1, so we need to do some conversion:
  463. Real logX, logY;
  464. PixelScreenToW3DLogicalScreen(m_currMouse.pos.x - 0, m_currMouse.pos.y - 0, &logX, &logY, TheDisplay->getWidth(), TheDisplay->getHeight());
  465. Vector3 rayStart;
  466. Vector3 rayEnd;
  467. rayStart = m_camera->Get_Position(); //get camera location
  468. m_camera->Un_Project(rayEnd,Vector2(logX,logY)); //get world space point
  469. rayEnd -= rayStart; //vector camera to world space point
  470. rayEnd.Normalize(); //make unit vector
  471. rayEnd *= m_camera->Get_Depth(); //adjust length to reach far clip plane
  472. rayEnd += rayStart; //get point on far clip plane along ray from camera.
  473. x = Vector3::Find_X_At_Z(z, rayStart, rayEnd);
  474. y = Vector3::Find_Y_At_Z(z, rayStart, rayEnd);
  475. }
  476. Matrix3D tm(1);
  477. tm.Set_Translation(Vector3(x, y, z));
  478. Coord2D offset = {0, 0};
  479. if (TheInGameUI && TheInGameUI->isScrolling())
  480. {
  481. offset = TheInGameUI->getScrollAmount();
  482. offset.normalize();
  483. Real theta = atan2(-offset.y, offset.x);
  484. theta -= (Real)M_PI/2;
  485. tm.Rotate_Z(theta);
  486. }
  487. cursorModels[m_currentW3DCursor]->Set_Transform(tm);
  488. WW3D::Render( W3DDisplay::m_3DInterfaceScene, m_camera );
  489. }
  490. }
  491. }
  492. //@todo: In DX8 mode the mouse is drawn in another thread which isn't allowed
  493. //access to D3D so we can't do any drawing here.
  494. // draw the cursor text
  495. if (!isThread)
  496. drawCursorText();
  497. // draw tooltip text
  498. if (m_visible && !isThread)
  499. drawTooltip();
  500. m_drawing = FALSE;
  501. }
  502. void W3DMouse::setRedrawMode(RedrawMode mode)
  503. {
  504. MouseCursor cursor = getMouseCursor();
  505. //Turn off the previous cursor mode
  506. setCursor(NONE);
  507. m_currentRedrawMode=mode;
  508. switch (mode)
  509. {
  510. case RM_WINDOWS:
  511. { //Windows mouse doesn't need an update thread.
  512. if (thread.Is_Running())
  513. thread.Stop();
  514. freeD3DAssets(); //using Windows resources
  515. freeW3DAssets();
  516. freePolygonAssets();
  517. m_currentD3DCursor = NONE;
  518. m_currentW3DCursor = NONE;
  519. m_currentPolygonCursor = NONE;
  520. }
  521. break;
  522. case RM_W3D:
  523. { //Model mouse updated only at render time so doesn't
  524. //require thread.
  525. if (thread.Is_Running())
  526. thread.Stop();
  527. freeD3DAssets(); //using packed Image data, not textures.
  528. freePolygonAssets();
  529. m_currentD3DCursor = NONE;
  530. m_currentPolygonCursor = NONE;
  531. initW3DAssets();
  532. }
  533. break;
  534. case RM_POLYGON:
  535. { //Polygon mouse updated only at render time so doesn't
  536. //require thread.
  537. if (thread.Is_Running())
  538. thread.Stop();
  539. freeD3DAssets(); //using packed Image data, not textures.
  540. freeW3DAssets();
  541. m_currentD3DCursor = NONE;
  542. m_currentW3DCursor = NONE;
  543. m_currentPolygonCursor = NONE;
  544. initPolygonAssets();
  545. }
  546. break;
  547. case RM_DX8:
  548. { //this cursor type is drawn by DX8 and can be refreshed
  549. //independent of rendering rate. Uses another thread to do
  550. //position updates.
  551. initD3DAssets(); //make sure textures loaded.
  552. freeW3DAssets();
  553. freePolygonAssets();
  554. if (!thread.Is_Running())
  555. thread.Execute();
  556. m_currentW3DCursor = NONE;
  557. m_currentPolygonCursor = NONE;
  558. break;
  559. }
  560. }
  561. setCursor(NONE);
  562. setCursor(cursor);
  563. }
  564. void W3DMouse::setCursorDirection(MouseCursor cursor)
  565. {
  566. Coord2D offset = {0, 0};
  567. //Check if we have a directional cursor that needs different images for each direction
  568. if (m_cursorInfo[cursor].numDirections > 1 && TheInGameUI && TheInGameUI->isScrolling())
  569. {
  570. offset = TheInGameUI->getScrollAmount();
  571. if (offset.x || offset.y)
  572. {
  573. offset.normalize();
  574. Real theta = atan2(offset.y, offset.x);
  575. theta = fmod(theta+M_PI*2,M_PI*2);
  576. Int numDirections=m_cursorInfo[m_currentCursor].numDirections;
  577. //Figure out which of our predrawn cursor orientations best matches the
  578. //actual cursor direction. Frame 0 is assumed to point right and continue
  579. //clockwise.
  580. m_directionFrame=(Int)(theta/(2.0f*M_PI/(Real)numDirections)+0.5f);
  581. if (m_directionFrame >= numDirections)
  582. m_directionFrame = 0;
  583. }
  584. else
  585. {
  586. m_directionFrame=0;
  587. }
  588. }
  589. else
  590. m_directionFrame = 0;
  591. }