display.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. {
  2. Free Pascal port of the OpenPTC C++ library.
  3. Copyright (C) 2001-2003 Nikolay Nikolov ([email protected])
  4. Original C++ version by Glenn Fiedler ([email protected])
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. }
  17. Constructor TDirectXDisplay.Create;
  18. Begin
  19. m_information := '';
  20. m_mode := Nil;
  21. m_cursorsaved := False;
  22. m_open := False;
  23. m_fullscreen := False;
  24. m_ddraw := Nil;
  25. m_window := 0;
  26. // m_foreground := 0;
  27. FillChar(m_modes, SizeOf(m_modes), 0);
  28. FillChar(m_resolutions, SizeOf(m_resolutions), 0);
  29. m_mode := TPTCMode.Create;
  30. End;
  31. Destructor TDirectXDisplay.Destroy;
  32. Begin
  33. close;
  34. m_mode.Free;
  35. internal_dispose_modes;
  36. internal_dispose_resolutions;
  37. Inherited Destroy;
  38. End;
  39. Procedure TDirectXDisplay.internal_dispose_modes;
  40. Var
  41. i : Integer;
  42. Begin
  43. For i := Low(m_modes) To High(m_modes) Do
  44. FreeAndNil(m_modes[i]);
  45. End;
  46. Procedure TDirectXDisplay.internal_dispose_resolutions;
  47. Var
  48. i : Integer;
  49. Begin
  50. For i := Low(m_resolutions) To High(m_resolutions) Do
  51. FreeAndNil(m_resolutions[i]);
  52. End;
  53. Function TDirectXDisplay_callback(descriptor : LPDDSURFACEDESC; Context : Pointer) : HRESULT; StdCall;
  54. Var
  55. display : TDirectXDisplay;
  56. tmp : TPTCFormat;
  57. Begin
  58. If (descriptor = Nil) Or (Context = Nil) Then
  59. Begin
  60. TDirectXDisplay_callback := DDENUMRET_CANCEL;
  61. Exit;
  62. End;
  63. display := TDirectXDisplay(Context);
  64. If ((descriptor^.dwFlags And DDSD_WIDTH) <> 0) And
  65. ((descriptor^.dwFlags And DDSD_HEIGHT) <> 0) And
  66. ((descriptor^.dwFlags And DDSD_PIXELFORMAT) <> 0) Then
  67. Begin
  68. tmp := DirectXTranslate(descriptor^.ddpfPixelFormat);
  69. Try
  70. FreeAndNil(display.m_modes[display.m_modes_count]);
  71. display.m_modes[display.m_modes_count] :=
  72. TPTCMode.Create(descriptor^.dwWidth, descriptor^.dwHeight, tmp);
  73. Finally
  74. tmp.Free;
  75. End;
  76. Inc(display.m_modes_count);
  77. End
  78. Else
  79. Begin
  80. LOG('EnumDisplayModesCallback was not given enough mode information');
  81. End;
  82. TDirectXDisplay_callback := DDENUMRET_OK;
  83. End;
  84. Procedure TDirectXDisplay.setup(ddraw : LPDIRECTDRAW2);
  85. Var
  86. version : OSVERSIONINFO;
  87. match, found : Boolean;
  88. i, j : Integer;
  89. temp : TPTCMode;
  90. temp2 : TPTCFormat;
  91. S, S2 : String;
  92. Begin
  93. LOG('setting up display lpDD2');
  94. m_ddraw := ddraw;
  95. m_information := 'windows version x.xx.x' + #13 + #10 + 'ddraw version x.xx' + #13 + #10 + 'display driver name xxxxx' +
  96. #13 + #10 + 'display driver vendor xxxxx' + #13 + #10 + 'certified driver? x' + #13 + #10;
  97. m_modes_count := 0;
  98. DirectXCheck(m_ddraw^.lpVtbl^.EnumDisplayModes(m_ddraw, 0, Nil, {this}Self, LPDDENUMMODESCALLBACK(@TDirectXDisplay_callback)));
  99. version.dwOSVersionInfoSize := SizeOf(version);
  100. If GetVersionEx(version) Then
  101. Begin
  102. If version.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then
  103. Begin
  104. LOG('detected windows 95/98');
  105. temp2 := TPTCFormat.Create(8);
  106. Try
  107. found := False;
  108. For i := 0 To m_modes_count - 1 Do
  109. If (m_modes[i].width = 320) And (m_modes[i].height = 200) And
  110. m_modes[i].format.Equals(temp2) Then
  111. found := True;
  112. If Not found Then
  113. Begin
  114. LOG('adding 320x200x8 to mode list');
  115. FreeAndNil(m_modes[m_modes_count]);
  116. m_modes[m_modes_count] := TPTCMode.Create(320, 200, temp2);
  117. Inc(m_modes_count);
  118. End;
  119. found := False;
  120. For i := 0 To m_modes_count - 1 Do
  121. If (m_modes[i].width = 320) And (m_modes[i].height = 240) And
  122. m_modes[i].format.Equals(temp2) Then
  123. found := True;
  124. If Not found Then
  125. Begin
  126. LOG('adding 320x240x8 to mode list');
  127. FreeAndNil(m_modes[m_modes_count]);
  128. m_modes[m_modes_count] := TPTCMode.Create(320, 240, temp2);
  129. Inc(m_modes_count);
  130. End;
  131. Finally
  132. temp2.Free;
  133. End;
  134. End
  135. Else
  136. If version.dwPlatformId = VER_PLATFORM_WIN32_NT Then
  137. Begin
  138. LOG('detected windows nt');
  139. End;
  140. End;
  141. LOG('number of display modes', m_modes_count);
  142. FreeAndNil(m_modes[m_modes_count]);
  143. m_modes[m_modes_count] := TPTCMode.Create;
  144. m_resolutions_count := 0;
  145. For i := 0 To m_modes_count - 1 Do
  146. Begin
  147. match := False;
  148. For j := 0 To m_resolutions_count - 1 Do
  149. If (m_modes[i].width = m_resolutions[j].width) And
  150. (m_modes[i].height = m_resolutions[j].height) Then
  151. Begin
  152. match := True;
  153. Break;
  154. End;
  155. If Not match Then
  156. Begin
  157. FreeAndNil(m_resolutions[m_resolutions_count]);
  158. m_resolutions[m_resolutions_count] := TPTCMode.Create(m_modes[i]);
  159. Inc(m_resolutions_count);
  160. End;
  161. End;
  162. FreeAndNil(m_resolutions[m_resolutions_count]);
  163. m_resolutions[m_resolutions_count] := TPTCMode.Create;
  164. { kludge sort... :) }
  165. For i := 0 To m_resolutions_count - 1 Do
  166. For j := i + 1 To m_resolutions_count - 1 Do
  167. If (m_resolutions[i].width > m_resolutions[j].width) Or
  168. (m_resolutions[i].height > m_resolutions[j].height) Then
  169. Begin
  170. temp := m_resolutions[i];
  171. m_resolutions[i] := m_resolutions[j];
  172. m_resolutions[j] := temp;
  173. End;
  174. LOG('number of unique resolutions', m_resolutions_count);
  175. For i := 0 To m_resolutions_count - 1 Do
  176. Begin
  177. Str(m_resolutions[i].width, S);
  178. Str(m_resolutions[i].height, S2);
  179. LOG(S + ' x ' + S2);
  180. End;
  181. End;
  182. Function TDirectXDisplay.modes : PPTCMode;
  183. Begin
  184. modes := @m_modes;
  185. End;
  186. Function TDirectXDisplay.test(Const _mode : TPTCMode; exact : Boolean) : Boolean;
  187. Var
  188. i : Integer;
  189. Begin
  190. If m_modes_count = 0 Then
  191. Begin
  192. LOG('mode test success with empty mode list');
  193. test := True;
  194. Exit;
  195. End;
  196. If exact Then
  197. Begin
  198. For i := 0 To m_modes_count - 1 Do
  199. If m_modes[i].Equals(_mode) Then
  200. Begin
  201. LOG('test exact mode success');
  202. test := True;
  203. Exit;
  204. End;
  205. LOG('test exact mode failure');
  206. test := False;
  207. End
  208. Else
  209. Begin
  210. For i := 0 To m_resolutions_count - 1 Do
  211. If (_mode.width <= m_resolutions[i].width) And
  212. (_mode.height <= m_resolutions[i].height) Then
  213. Begin
  214. LOG('test nearest mode success');
  215. test := True;
  216. Exit;
  217. End;
  218. LOG('test nearest mode failure');
  219. test := False;
  220. End;
  221. End;
  222. Procedure TDirectXDisplay.cooperative(window : HWND; _fullscreen : Boolean);
  223. Begin
  224. If _fullscreen Then
  225. Begin
  226. LOG('entering exclusive mode');
  227. DirectXCheck(m_ddraw^.lpVtbl^.SetCooperativeLevel(m_ddraw, window, DDSCL_EXCLUSIVE Or DDSCL_FULLSCREEN Or DDSCL_ALLOWMODEX));
  228. End
  229. Else
  230. Begin
  231. LOG('entering normal cooperative mode');
  232. DirectXCheck(m_ddraw^.lpVtbl^.SetCooperativeLevel(m_ddraw, window, DDSCL_NORMAL));
  233. End;
  234. m_window := window;
  235. m_fullscreen := _fullscreen;
  236. End;
  237. Procedure TDirectXDisplay.open;
  238. Begin
  239. FreeAndNil(m_mode);
  240. m_mode := TPTCMode.Create;
  241. m_open := True;
  242. LOG('opening windowed display');
  243. End;
  244. Procedure TDirectXDisplay.open(Const _mode : TPTCMode; exact : Boolean; frequency : Integer);
  245. Begin
  246. If exact Then
  247. Begin
  248. LOG('opening exact fullscreen display mode');
  249. internal_open(_mode, True, frequency);
  250. End
  251. Else
  252. Begin
  253. LOG('opening nearest fullscreen mode');
  254. internal_open_nearest(_mode, False, frequency);
  255. End;
  256. LOG('successfully opened fullscreen display mode');
  257. End;
  258. Procedure TDirectXDisplay.close;
  259. Begin
  260. If m_open And (m_ddraw <> Nil) Then
  261. Begin
  262. LOG('closing display');
  263. If m_fullscreen Then
  264. Begin
  265. LOG('restoring display mode');
  266. m_ddraw^.lpVtbl^.RestoreDisplayMode(m_ddraw);
  267. LOG('leaving exclusive mode');
  268. m_ddraw^.lpVtbl^.SetCooperativeLevel(m_ddraw, m_window, DDSCL_NORMAL);
  269. End;
  270. End;
  271. m_open := False;
  272. m_fullscreen := False;
  273. End;
  274. Procedure TDirectXDisplay.save;
  275. Var
  276. p : POINT;
  277. Begin
  278. LOG('saving desktop');
  279. m_cursorsaved := GetCursorPos(p);
  280. m_cursorX := p.x;
  281. m_cursorY := p.y;
  282. { m_foreground := GetForegroundWindow;
  283. GetWindowRect(m_foreground, m_foreground_rect);
  284. m_foreground_placement.length := SizeOf(WINDOWPLACEMENT);
  285. GetWindowPlacement(m_foreground, m_foreground_placement);}
  286. End;
  287. Procedure TDirectXDisplay.restore;
  288. Begin
  289. { If (m_foreground <> 0) And IsWindow(m_foreground) And (m_foreground <> m_window) Then
  290. Begin}
  291. LOG('restoring desktop');
  292. If IsWindow(m_window) And m_fullscreen Then
  293. SetWindowPos(m_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE);
  294. If m_cursorsaved Then
  295. Begin
  296. SetCursorPos(m_cursorX, m_cursorY);
  297. m_cursorsaved := False;
  298. End;
  299. { SetForegroundWindow(m_foreground);
  300. SetWindowPlacement(m_foreground, m_foreground_placement);
  301. SetWindowPos(m_foreground, HWND_TOP, m_foreground_rect.left, m_foreground_rect.top, m_foreground_rect.right - m_foreground_rect.left, m_foreground_rect.bottom - m_foreground_rect.top, SWP_FRAMECHANGED Or SWP_NOCOPYBITS);
  302. m_foreground := 0;
  303. End;}
  304. End;
  305. Function TDirectXDisplay.mode : TPTCMode;
  306. Begin
  307. mode := m_mode;
  308. End;
  309. Function TDirectXDisplay.fullscreen : Boolean;
  310. Begin
  311. fullscreen := m_fullscreen;
  312. End;
  313. Function TDirectXDisplay.information : String;
  314. Begin
  315. information := m_information;
  316. End;
  317. Procedure TDirectXDisplay.internal_open(Const _mode : TPTCMode; exact : Boolean; frequency : Integer);
  318. Begin
  319. LOG('internal display open');
  320. LOG('mode width', _mode.width);
  321. LOG('mode height', _mode.height);
  322. LOG('mode format', _mode.format);
  323. LOG('mode frequency', frequency);
  324. If exact Then
  325. Begin
  326. LOG('setting exact mode');
  327. DirectXCheck(m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, _mode.format.bits, frequency, 0));
  328. End
  329. Else
  330. Case _mode.format.bits Of
  331. 32 : Begin
  332. LOG('setting virtual 32 mode');
  333. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 32, frequency, 0) <> DD_OK Then
  334. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 24, frequency, 0) <> DD_OK Then
  335. DirectXCheck(m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 16, frequency, 0));
  336. End;
  337. 24 : Begin
  338. LOG('setting virtual 24 mode');
  339. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 24, frequency, 0) <> DD_OK Then
  340. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 32, frequency, 0) <> DD_OK Then
  341. DirectXCheck(m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 16, frequency, 0));
  342. End;
  343. 16 : Begin
  344. LOG('setting virtual 16 mode');
  345. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 16, frequency, 0) <> DD_OK Then
  346. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 24, frequency, 0) <> DD_OK Then
  347. DirectXCheck(m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 32, frequency, 0));
  348. End;
  349. 8 : Begin
  350. LOG('setting virtual 8 mode');
  351. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 8, frequency, 0) <> DD_OK Then
  352. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 24, frequency, 0) <> DD_OK Then {yes, 24bit is now faster than 32bit!}
  353. If m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 32, frequency, 0) <> DD_OK Then
  354. DirectXCheck(m_ddraw^.lpVtbl^.SetDisplayMode(m_ddraw, _mode.width, _mode.height, 16, frequency, 0));
  355. End;
  356. Else
  357. Raise TPTCError.Create('unsupported pixel format');
  358. End;
  359. LOG('internal display open success');
  360. FreeAndNil(m_mode);
  361. m_mode := TPTCMode.Create(_mode);
  362. m_open := True;
  363. End;
  364. Procedure TDirectXDisplay.internal_open_nearest(Const _mode : TPTCMode; exact : Boolean; frequency : Integer);
  365. Var
  366. index : Integer;
  367. match, match_exact : TPTCMode;
  368. tmp : TPTCMode;
  369. i : Integer;
  370. width, height : Integer;
  371. dx1, dy1, dx2, dy2 : Integer;
  372. Begin
  373. If m_resolutions_count <> 0 Then
  374. Begin
  375. LOG('searching for nearest mode in resolutions list');
  376. index := 0;
  377. match_exact := Nil;
  378. match := TPTCMode.Create;
  379. Try
  380. match_exact := TPTCMode.Create;
  381. For i := 0 To m_resolutions_count - 1 Do
  382. Begin
  383. width := m_resolutions[i].width;
  384. height := m_resolutions[i].height;
  385. If (_mode.width <= width) And (_mode.height <= height) Then
  386. Begin
  387. If (width = _mode.width) And (height = _mode.height) Then
  388. Begin
  389. LOG('found an exact match');
  390. tmp := TPTCMode.Create(width, height, _mode.format);
  391. Try
  392. match_exact.ASSign(tmp);
  393. Finally
  394. tmp.Free;
  395. End;
  396. End;
  397. If match.valid Then
  398. Begin
  399. dx1 := match.width - _mode.width;
  400. dy1 := match.height - _mode.height;
  401. dx2 := width - _mode.width;
  402. dy2 := height - _mode.height;
  403. If (dx2 <= dx1) And (dy2 <= dy1) Then
  404. Begin
  405. LOG('found a better nearest match');
  406. tmp := TPTCMode.Create(width, height, _mode.format);
  407. Try
  408. match.ASSign(tmp);
  409. Finally
  410. tmp.Free;
  411. End;
  412. End;
  413. End
  414. Else
  415. Begin
  416. LOG('found first nearest match');
  417. tmp := TPTCMode.Create(width, height, _mode.format);
  418. Try
  419. match.ASSign(tmp);
  420. Finally
  421. tmp.Free;
  422. End;
  423. End;
  424. End
  425. Else
  426. Begin
  427. { LOG('stopping nearest mode search');
  428. Break;}
  429. End;
  430. End;
  431. If match_exact.valid Then
  432. Try
  433. LOG('trying an exact match');
  434. internal_open(match_exact, exact, frequency);
  435. Exit;
  436. Except
  437. On TPTCError Do;
  438. End;
  439. If match.valid Then
  440. Try
  441. LOG('trying nearest match');
  442. internal_open(match, exact, frequency);
  443. Exit;
  444. Except
  445. On TPTCError Do;
  446. End;
  447. Finally
  448. match.Free;
  449. match_exact.Free;
  450. End;
  451. End
  452. Else
  453. Begin
  454. LOG('no resolutions list for nearest mode search');
  455. End;
  456. { match.Free;
  457. match_exact.Free;}
  458. LOG('could not find a nearest match in first pass');
  459. Try
  460. LOG('trying requested mode first');
  461. internal_open(_mode, exact, frequency);
  462. Exit;
  463. Except
  464. On TPTCError Do
  465. Begin
  466. LOG('falling back to nearest standard mode');
  467. If (_mode.width <= 320) And (_mode.height <= 200) Then
  468. Try
  469. tmp := TPTCMode.Create(320, 200, _mode.format);
  470. Try
  471. internal_open(tmp, exact, frequency);
  472. Finally
  473. tmp.Free;
  474. End;
  475. Exit;
  476. Except
  477. On TPTCError Do;
  478. End;
  479. If (_mode.width <= 320) And (_mode.height <= 240) Then
  480. Try
  481. tmp := TPTCMode.Create(320, 240, _mode.format);
  482. Try
  483. internal_open(tmp, exact, frequency);
  484. Finally
  485. tmp.Free;
  486. End;
  487. Exit;
  488. Except
  489. On TPTCError Do;
  490. End;
  491. If (_mode.width <= 512) And (_mode.height <= 384) Then
  492. Try
  493. tmp := TPTCMode.Create(512, 384, _mode.format);
  494. Try
  495. internal_open(tmp, exact, frequency);
  496. Finally
  497. tmp.Free;
  498. End;
  499. Exit;
  500. Except
  501. On TPTCError Do;
  502. End;
  503. If (_mode.width <= 640) And (_mode.height <= 400) Then
  504. Try
  505. tmp := TPTCMode.Create(640, 400, _mode.format);
  506. Try
  507. internal_open(tmp, exact, frequency);
  508. Finally
  509. tmp.Free;
  510. End;
  511. Exit;
  512. Except
  513. On TPTCError Do;
  514. End;
  515. If (_mode.width <= 640) And (_mode.height <= 480) Then
  516. Try
  517. tmp := TPTCMode.Create(640, 480, _mode.format);
  518. Try
  519. internal_open(tmp, exact, frequency);
  520. Finally
  521. tmp.Free;
  522. End;
  523. Exit;
  524. Except
  525. On TPTCError Do;
  526. End;
  527. If (_mode.width <= 800) And (_mode.height <= 600) Then
  528. Try
  529. tmp := TPTCMode.Create(800, 600, _mode.format);
  530. Try
  531. internal_open(tmp, exact, frequency);
  532. Finally
  533. tmp.Free;
  534. End;
  535. Exit;
  536. Except
  537. On TPTCError Do;
  538. End;
  539. If (_mode.width <= 1024) And (_mode.height <= 768) Then
  540. Try
  541. tmp := TPTCMode.Create(1024, 768, _mode.format);
  542. Try
  543. internal_open(tmp, exact, frequency);
  544. Finally
  545. tmp.Free;
  546. End;
  547. Exit;
  548. Except
  549. On TPTCError Do;
  550. End;
  551. If (_mode.width <= 1280) And (_mode.height <= 1024) Then
  552. Try
  553. tmp := TPTCMode.Create(1280, 1024, _mode.format);
  554. Try
  555. internal_open(tmp, exact, frequency);
  556. Finally
  557. tmp.Free;
  558. End;
  559. Exit;
  560. Except
  561. On TPTCError Do;
  562. End;
  563. If (_mode.width <= 1600) And (_mode.height <= 1200) Then
  564. Try
  565. tmp := TPTCMode.Create(1600, 1200, _mode.format);
  566. Try
  567. internal_open(tmp, exact, frequency);
  568. Finally
  569. tmp.Free;
  570. End;
  571. Exit;
  572. Except
  573. On TPTCError Do;
  574. End;
  575. End;
  576. End;
  577. Raise TPTCError.Create('could not set display mode');
  578. End;