VisWindowDialog.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. ** Command & Conquer Renegade(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. // VisWindowDialog.cpp : implementation file
  19. //
  20. #include "stdafx.h"
  21. #include "leveledit.h"
  22. #include "viswindowdialog.h"
  23. #include "visrasterizer.h"
  24. #include "visrendercontext.h"
  25. #include "pscene.h"
  26. #include "phys.h"
  27. #ifdef _DEBUG
  28. #define new DEBUG_NEW
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32. /////////////////////////////////////////////////////////////////////////////
  33. //
  34. // VisWindowDialogClass
  35. //
  36. /////////////////////////////////////////////////////////////////////////////
  37. VisWindowDialogClass::VisWindowDialogClass(CWnd* pParent /*=NULL*/) :
  38. BitmapBits (NULL),
  39. Bitmap (NULL),
  40. Width (0),
  41. Height (0),
  42. MemDC (NULL),
  43. CurToolTipVisId(-1),
  44. CDialog(VisWindowDialogClass::IDD, pParent)
  45. {
  46. //{{AFX_DATA_INIT(VisWindowDialogClass)
  47. // NOTE: the ClassWizard will add member initialization here
  48. //}}AFX_DATA_INIT
  49. //
  50. // Create a screen compatible DC
  51. //
  52. MemDC = ::CreateCompatibleDC (NULL);
  53. return ;
  54. }
  55. /////////////////////////////////////////////////////////////////////////////
  56. //
  57. // ~VisWindowDialogClass
  58. //
  59. /////////////////////////////////////////////////////////////////////////////
  60. VisWindowDialogClass::~VisWindowDialogClass (void)
  61. {
  62. Free_DIB_Section ();
  63. ::DeleteDC (MemDC);
  64. MemDC = NULL;
  65. return ;
  66. }
  67. /////////////////////////////////////////////////////////////////////////////
  68. //
  69. // DoDataExchange
  70. //
  71. /////////////////////////////////////////////////////////////////////////////
  72. void
  73. VisWindowDialogClass::DoDataExchange (CDataExchange *pDX)
  74. {
  75. CDialog::DoDataExchange(pDX);
  76. //{{AFX_DATA_MAP(VisWindowDialogClass)
  77. // NOTE: the ClassWizard will add DDX and DDV calls here
  78. //}}AFX_DATA_MAP
  79. return ;
  80. }
  81. BEGIN_MESSAGE_MAP(VisWindowDialogClass, CDialog)
  82. //{{AFX_MSG_MAP(VisWindowDialogClass)
  83. ON_WM_PAINT()
  84. ON_WM_MOUSEMOVE()
  85. //}}AFX_MSG_MAP
  86. END_MESSAGE_MAP()
  87. /////////////////////////////////////////////////////////////////////////////
  88. //
  89. // Create
  90. //
  91. /////////////////////////////////////////////////////////////////////////////
  92. void
  93. VisWindowDialogClass::Create (void)
  94. {
  95. CDialog::Create (VisWindowDialogClass::IDD, NULL);
  96. return ;
  97. }
  98. /////////////////////////////////////////////////////////////////////////////
  99. //
  100. // OnInitDialog
  101. //
  102. /////////////////////////////////////////////////////////////////////////////
  103. BOOL VisWindowDialogClass::OnInitDialog()
  104. {
  105. CDialog::OnInitDialog();
  106. // create the tool-tip
  107. if (ToolTip.Create(this, TTS_ALWAYSTIP) && ToolTip.AddTool(this))
  108. {
  109. ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, SHRT_MAX);
  110. ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX);
  111. ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_INITIAL, 200);
  112. ToolTip.SendMessage(TTM_SETDELAYTIME, TTDT_RESHOW, 200);
  113. }
  114. else
  115. {
  116. TRACE("Error in creating ToolTip");
  117. }
  118. return TRUE; // return TRUE unless you set the focus to a control
  119. // EXCEPTION: OCX Property Pages should return FALSE
  120. }
  121. /////////////////////////////////////////////////////////////////////////////
  122. //
  123. // Update_Display
  124. //
  125. /////////////////////////////////////////////////////////////////////////////
  126. void
  127. VisWindowDialogClass::Update_Display (VisRasterizerClass &rasterizer)
  128. {
  129. //
  130. // Don't do anything if the user has not enabled the vis window
  131. //
  132. if (m_hWnd == NULL || IsWindowVisible () == false) {
  133. return;
  134. }
  135. //
  136. // Get the resolution of rasterizer
  137. //
  138. int width = 0;
  139. int height = 0;
  140. rasterizer.Get_Resolution (&width, &height);
  141. //
  142. // Recreate DIB section
  143. //
  144. Create_DIB_Section (width, height);
  145. //
  146. // Loop over all the rows in the bitmap
  147. //
  148. int index = 0;
  149. int stride = (((Width * 3) + 3) & ~3);
  150. for (int row = 0; row < Height; row ++) {
  151. //
  152. // DIB sections are aligned on DWORD boundaries, so ensure
  153. // our starting index for this row is mapped appropriately.
  154. //
  155. index = row * stride;
  156. //
  157. // Get a pointer to the raw vis-render data for this row of the bitmap
  158. //
  159. const uint32 *pixel_ptr = rasterizer.Get_Pixel_Row (row, 0, Width - 1);
  160. //
  161. // Loop over all the columns of the bitmap
  162. //
  163. for (int col = 0; col < Width; col ++) {
  164. unsigned int id = pixel_ptr[col];// + 1;
  165. unsigned int pixel = Id_To_Pixel(id);
  166. //
  167. // Convert the pixel into red, green, and blue components
  168. //
  169. BYTE red = BYTE(pixel & 0x000000FF);
  170. BYTE green = BYTE((pixel & 0x0000FF00) >> 8);
  171. BYTE blue = BYTE((pixel & 0x00FF0000) >> 16);
  172. //
  173. // Store the pixel in the bitmap
  174. //
  175. BitmapBits[index ++] = blue;
  176. BitmapBits[index ++] = green;
  177. BitmapBits[index ++] = red;
  178. }
  179. }
  180. //
  181. // Update the window
  182. //
  183. Paint_Display ();
  184. return ;
  185. }
  186. /////////////////////////////////////////////////////////////////////////////
  187. //
  188. // Free_DIB_Section
  189. //
  190. /////////////////////////////////////////////////////////////////////////////
  191. void
  192. VisWindowDialogClass::Free_DIB_Section (void)
  193. {
  194. Width = 0;
  195. Height = 0;
  196. //
  197. // Free the bitmap
  198. //
  199. if (Bitmap != NULL) {
  200. ::DeleteObject (Bitmap);
  201. Bitmap = NULL;
  202. }
  203. return ;
  204. }
  205. /////////////////////////////////////////////////////////////////////////////
  206. //
  207. // Create_DIB_Section
  208. //
  209. /////////////////////////////////////////////////////////////////////////////
  210. void
  211. VisWindowDialogClass::Create_DIB_Section (int width, int height)
  212. {
  213. if (Width == width && Height == height) {
  214. return ;
  215. }
  216. //
  217. // Calculate what size to make the window
  218. //
  219. RECT rect = { 0, 0, width * 2, height * 2 };
  220. LONG style = ::GetWindowLong (m_hWnd, GWL_STYLE);
  221. ::AdjustWindowRect (&rect, style, FALSE);
  222. //
  223. // Resize the window
  224. //
  225. SetWindowPos (NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE);
  226. //
  227. // Release our old DIB section
  228. //
  229. Free_DIB_Section ();
  230. //
  231. // Cache the new width and height
  232. //
  233. Width = width;
  234. Height = height;
  235. //
  236. // Set-up the fields of the BITMAPINFOHEADER
  237. // Note: Top-down DIBs use negative height in Win32.
  238. //
  239. BITMAPINFOHEADER bitmap_info = { 0 };
  240. bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
  241. bitmap_info.biWidth = Width;
  242. bitmap_info.biHeight = -Height;
  243. bitmap_info.biPlanes = 1;
  244. bitmap_info.biBitCount = 24;
  245. bitmap_info.biCompression = BI_RGB;
  246. bitmap_info.biSizeImage = ((Width * Height) * 3);
  247. bitmap_info.biXPelsPerMeter = 0;
  248. bitmap_info.biYPelsPerMeter = 0;
  249. bitmap_info.biClrUsed = 0;
  250. bitmap_info.biClrImportant = 0;
  251. //
  252. // Create a bitmap that we can access the bits directly of
  253. //
  254. HDC screen_dc = ::GetDC (NULL);
  255. Bitmap = ::CreateDIBSection ( screen_dc,
  256. (const BITMAPINFO *)&bitmap_info,
  257. DIB_RGB_COLORS,
  258. (void **)&BitmapBits,
  259. NULL,
  260. 0L);
  261. //
  262. // Release our temporary screen DC
  263. //
  264. ::ReleaseDC (NULL, screen_dc);
  265. return ;
  266. }
  267. /////////////////////////////////////////////////////////////////////////////
  268. //
  269. // Paint_Display
  270. //
  271. /////////////////////////////////////////////////////////////////////////////
  272. void
  273. VisWindowDialogClass::Paint_Display (void)
  274. {
  275. if (m_hWnd == NULL || Bitmap == NULL) {
  276. return ;
  277. }
  278. //
  279. // Setup the DCs for blitting
  280. //
  281. HDC wnd_dc = ::GetDC (m_hWnd);
  282. HBITMAP old_bmp = (HBITMAP)::SelectObject (MemDC, Bitmap);
  283. //
  284. // Copy the contents of the bitmap to the screen
  285. //
  286. ::StretchBlt (wnd_dc, 0, 0, Width * 2, Height * 2, MemDC, 0, 0, Width, Height, SRCCOPY);
  287. //
  288. // Restore the DCs
  289. //
  290. ::SelectObject (MemDC, old_bmp);
  291. ::ReleaseDC (m_hWnd, wnd_dc);
  292. return ;
  293. }
  294. /////////////////////////////////////////////////////////////////////////////
  295. //
  296. // OnPaint
  297. //
  298. /////////////////////////////////////////////////////////////////////////////
  299. void
  300. VisWindowDialogClass::OnPaint (void)
  301. {
  302. CPaintDC dc (this);
  303. Paint_Display ();
  304. return ;
  305. }
  306. /////////////////////////////////////////////////////////////////////////////
  307. //
  308. // Hit_Test - determines the vis-id under the cursor
  309. //
  310. /////////////////////////////////////////////////////////////////////////////
  311. int
  312. VisWindowDialogClass::Hit_Test(CPoint point) const
  313. {
  314. //
  315. // If we don't have a bitmap, just return
  316. //
  317. if (BitmapBits == NULL) {
  318. return -1;
  319. }
  320. //
  321. // Look up the pixel, we are StretchBlt'ing the bitmap to 2x the normal size
  322. // so we divide the coordinates by two
  323. //
  324. int x = point.x / 2;
  325. int y = point.y / 2;
  326. if ((x <= 0) || (x >= Width) || (y <= 0) || (y >= Height)) {
  327. return -1;
  328. }
  329. int stride = (((Width * 3) + 3) & ~3);
  330. int pixel_address = x * 3 + stride * y;
  331. BYTE blue = BitmapBits[pixel_address ++];
  332. BYTE green = BitmapBits[pixel_address ++];
  333. BYTE red = BitmapBits[pixel_address ++];
  334. //
  335. // Map the color back to a vis ID
  336. //
  337. unsigned int color = red | (green<<8) | (blue<<16);
  338. unsigned int id = Pixel_To_Id(color);
  339. return id;
  340. }
  341. /////////////////////////////////////////////////////////////////////////////
  342. //
  343. // Id_To_Pixel
  344. //
  345. /////////////////////////////////////////////////////////////////////////////
  346. unsigned int
  347. VisWindowDialogClass::Id_To_Pixel(unsigned int id) const
  348. {
  349. uint32 pixel = 0;
  350. pixel |= ((id & 0x0000000F) >> 0) << 20; // LSN (Least Significant Nibble) goes into MSN of red
  351. pixel |= ((id & 0x000000F0) >> 4) << 12; // next LSN goes into MSN of green
  352. pixel |= ((id & 0x00000F00) >> 8) << 4; // next LSN goes into MSN of blue
  353. pixel |= ((id & 0x0000F000) >> 12) << 16; // put into LSN of red
  354. pixel |= ((id & 0x000F0000) >> 16) << 8; // put into LSN of green
  355. pixel |= ((id & 0x00F00000) >> 20) << 0; // put into LSN of blue
  356. return pixel;
  357. }
  358. /////////////////////////////////////////////////////////////////////////////
  359. //
  360. // Pixel_To_Id
  361. //
  362. /////////////////////////////////////////////////////////////////////////////
  363. unsigned int
  364. VisWindowDialogClass::Pixel_To_Id(unsigned int pixel) const
  365. {
  366. uint32 id = 0;
  367. id |= ((pixel & 0x0000000F) >> 0) << 20;
  368. id |= ((pixel & 0x000000F0) >> 4) << 8;
  369. id |= ((pixel & 0x00000F00) >> 8) << 16;
  370. id |= ((pixel & 0x0000F000) >> 12) << 4;
  371. id |= ((pixel & 0x000F0000) >> 16) << 12;
  372. id |= ((pixel & 0x00F00000) >> 20) << 0;
  373. return id;
  374. }
  375. /////////////////////////////////////////////////////////////////////////////
  376. //
  377. // PreTranslateMessage
  378. //
  379. /////////////////////////////////////////////////////////////////////////////
  380. BOOL
  381. VisWindowDialogClass::PreTranslateMessage(MSG* pMsg)
  382. {
  383. if (::IsWindow(ToolTip.m_hWnd) && pMsg->hwnd == m_hWnd)
  384. {
  385. switch(pMsg->message)
  386. {
  387. case WM_LBUTTONDOWN:
  388. case WM_MOUSEMOVE:
  389. case WM_LBUTTONUP:
  390. case WM_RBUTTONDOWN:
  391. case WM_MBUTTONDOWN:
  392. case WM_RBUTTONUP:
  393. case WM_MBUTTONUP:
  394. ToolTip.RelayEvent(pMsg);
  395. break;
  396. }
  397. }
  398. return CDialog::PreTranslateMessage(pMsg);
  399. }
  400. /////////////////////////////////////////////////////////////////////////////
  401. //
  402. // OnMouseMove
  403. //
  404. /////////////////////////////////////////////////////////////////////////////
  405. void VisWindowDialogClass::OnMouseMove(UINT nFlags, CPoint point)
  406. {
  407. if (::IsWindow(ToolTip.m_hWnd))
  408. {
  409. unsigned int vis_id = Hit_Test(point);
  410. if ((vis_id == -1) || (vis_id != CurToolTipVisId)) {
  411. // Use Activate() to hide the tooltip.
  412. ToolTip.Activate(FALSE);
  413. }
  414. if (vis_id != -1) {
  415. ToolTip.Activate(TRUE);
  416. if (vis_id == BACKFACE_VIS_ID) {
  417. CString tooltip_string;
  418. tooltip_string.Format("Vis Id: %d, Backface!",vis_id);
  419. ToolTip.UpdateTipText(tooltip_string,this);
  420. } else {
  421. PhysClass * obj = NULL;
  422. RefPhysListIterator it = PhysicsSceneClass::Get_Instance()->Get_Static_Object_Iterator();
  423. while ((!it.Is_Done()) && (obj == NULL)) {
  424. if (it.Peek_Obj()->Get_Vis_Object_ID()==(int)vis_id) {
  425. obj = it.Peek_Obj();
  426. }
  427. it.Next();
  428. }
  429. if (obj != NULL) {
  430. CString tooltip_string;
  431. tooltip_string.Format("Vis Id: %d, Model Name: %s",vis_id,obj->Peek_Model()->Get_Name());
  432. ToolTip.UpdateTipText(tooltip_string,this);
  433. } else {
  434. CString tooltip_string;
  435. tooltip_string.Format("Vis Id: %d, Unknown Model",vis_id);
  436. ToolTip.UpdateTipText(tooltip_string,this);
  437. }
  438. }
  439. CurToolTipVisId = vis_id;
  440. }
  441. }
  442. CDialog::OnMouseMove(nFlags, point);
  443. }