dsurface.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  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. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /G/wwlib/dsurface.cpp $*
  25. * *
  26. * $Author:: Neal_k $*
  27. * *
  28. * $Modtime:: 6/23/00 2:26p $*
  29. * *
  30. * $Revision:: 2 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * DSurface::Blit_From -- Blit from one surface to this one. *
  35. * DSurface::Blit_From -- Blit graphic memory from one rectangle to another. *
  36. * DSurface::Build_Hicolor_Pixel -- Construct a hicolor pixel according to the surface pixel *
  37. * DSurface::Build_Remap_Table -- Build a highcolor remap table. *
  38. * DSurface::Bytes_Per_Pixel -- Fetches the bytes per pixel of the surface. *
  39. * DSurface::Create_Primary -- Creates a primary (visible) surface. *
  40. * DSurface::DSurface -- Create a surface attached to specified DDraw Surface Object. *
  41. * DSurface::DSurface -- Default constructor for surface object. *
  42. * DSurface::DSurface -- Off screen direct draw surface constructor. *
  43. * DSurface::Fill_Rect -- Fills a rectangle with clipping control. *
  44. * DSurface::Fill_Rect -- This routine will fill the specified rectangle. *
  45. * DSurface::Lock -- Fetches a working pointer into surface memory. *
  46. * DSurface::Restore_Check -- Checks for and restores surface memory if necessary. *
  47. * DSurface::Stride -- Fetches the bytes between rows. *
  48. * DSurface::Unlock -- Unlock a previously locked surface. *
  49. * DSurface::~DSurface -- Destructor for a direct draw surface object. *
  50. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  51. #include "always.h"
  52. #include "dsurface.h"
  53. #include <assert.h>
  54. extern LPDIRECTDRAW DirectDrawObject; //pointer to direct draw object
  55. extern LPDIRECTDRAWSURFACE PaletteSurface;
  56. /*
  57. ** Clipper object (for primary surface).
  58. */
  59. LPDIRECTDRAWCLIPPER DSurface::Clipper = NULL;
  60. int DSurface::RedRight = 0;
  61. int DSurface::RedLeft = 0;
  62. int DSurface::BlueRight = 0;
  63. int DSurface::BlueLeft = 0;
  64. int DSurface::GreenRight = 0;
  65. int DSurface::GreenLeft = 0;
  66. unsigned short DSurface::HalfbrightMask = 0;
  67. unsigned short DSurface::QuarterbrightMask = 0;
  68. unsigned short DSurface::EighthbrightMask = 0;
  69. DDPIXELFORMAT DSurface::PixelFormat;
  70. /***********************************************************************************************
  71. * DSurface::DSurface -- Off screen direct draw surface constructor. *
  72. * *
  73. * This constructor will create a Direct Draw enabled surface in video memory if possible. *
  74. * Such a surface will be able to use hardware assist if possible. The surface created *
  75. * is NOT visible. It only exists as a work surface and cannot be flipped to the visible *
  76. * surface. It can only be blitted to the visible surface. *
  77. * *
  78. * INPUT: width -- The width of the surface to create. *
  79. * *
  80. * height -- The height of the surface to create. *
  81. * *
  82. * OUTPUT: none *
  83. * *
  84. * WARNINGS: The surface pixel format is the same as that of the visible display mode. It *
  85. * is important to construct surfaces using this routine, only AFTER the display *
  86. * mode has been set. *
  87. * *
  88. * HISTORY: *
  89. * 02/07/1997 JLB : Created. *
  90. *=============================================================================================*/
  91. DSurface::DSurface(int width, int height, bool system_memory, DDPIXELFORMAT *pixform) :
  92. XSurface(width, height),
  93. BytesPerPixel(0),
  94. LockPtr(NULL),
  95. IsPrimary(false),
  96. IsVideoRam(false),
  97. SurfacePtr(NULL),
  98. Description(NULL),
  99. DCUnlockCount(0)
  100. {
  101. Description = W3DNEW DDSURFACEDESC;
  102. if (Description != NULL) {
  103. memset(Description, '\0', sizeof(DDSURFACEDESC));
  104. Description->dwSize = sizeof(DDSURFACEDESC);
  105. Description->dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
  106. Description->dwWidth = width;
  107. Description->dwHeight = height;
  108. Description->ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  109. if (system_memory == true)
  110. Description->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  111. /*
  112. ** Was a custom (non-display-depth) pixel format specified?
  113. */
  114. if (pixform)
  115. {
  116. Description->ddpfPixelFormat=*pixform;
  117. Description->dwFlags |= DDSD_PIXELFORMAT;
  118. }
  119. DirectDrawObject->CreateSurface(Description, &SurfacePtr, NULL);
  120. /*
  121. ** Get a description of the surface that was just allocated.
  122. */
  123. if (SurfacePtr != NULL) {
  124. memset(Description, '\0', sizeof(DDSURFACEDESC));
  125. Description->dwSize = sizeof(DDSURFACEDESC);
  126. SurfacePtr->GetSurfaceDesc(Description);
  127. BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8;
  128. IsVideoRam = ((Description->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) != 0);
  129. /*
  130. ** If this is a hicolor surface, then build the shift values for
  131. ** building and extracting the colors from the hicolor pixel.
  132. */
  133. if (BytesPerPixel == 2) {
  134. int index;
  135. int shift = Description->ddpfPixelFormat.dwRBitMask;
  136. ThisRedRight = 0;
  137. ThisRedLeft = 0;
  138. for (index = 0; index < 16; index++) {
  139. if (shift & 0x01) break;
  140. shift >>= 1;
  141. ThisRedRight++;
  142. }
  143. for (index = 0; index < 8; index++) {
  144. if (shift & 0x80) break;
  145. shift <<= 1;
  146. ThisRedLeft++;
  147. }
  148. shift = Description->ddpfPixelFormat.dwGBitMask;
  149. ThisGreenRight = 0;
  150. ThisGreenLeft = 0;
  151. for (index = 0; index < 16; index++) {
  152. if (shift & 0x01) break;
  153. ThisGreenRight++;
  154. shift >>= 1;
  155. }
  156. for (index = 0; index < 8; index++) {
  157. if (shift & 0x80) break;
  158. ThisGreenLeft++;
  159. shift <<= 1;
  160. }
  161. shift = Description->ddpfPixelFormat.dwBBitMask;
  162. ThisBlueRight = 0;
  163. ThisBlueLeft = 0;
  164. for (index = 0; index < 16; index++) {
  165. if (shift & 0x01) break;
  166. ThisBlueRight++;
  167. shift >>= 1;
  168. }
  169. for (index = 0; index < 8; index++) {
  170. if (shift & 0x80) break;
  171. ThisBlueLeft++;
  172. shift <<= 1;
  173. }
  174. }
  175. }
  176. }
  177. }
  178. /***********************************************************************************************
  179. * DSurface::~DSurface -- Destructor for a direct draw surface object. *
  180. * *
  181. * This will destruct (make invalid) the direct draw surface. *
  182. * *
  183. * INPUT: none *
  184. * *
  185. * OUTPUT: none *
  186. * *
  187. * WARNINGS: none *
  188. * *
  189. * HISTORY: *
  190. * 02/07/1997 JLB : Created. *
  191. *=============================================================================================*/
  192. DSurface::~DSurface(void)
  193. {
  194. /*
  195. ** If this is the primary surface, then the clipper must be detached from
  196. ** this surface and the clipper object deleted.
  197. */
  198. if (IsPrimary && SurfacePtr != NULL && Clipper != NULL) {
  199. SurfacePtr->SetClipper(NULL);
  200. Clipper->Release();
  201. Clipper = NULL;
  202. }
  203. /*
  204. ** Delete the description of the surface.
  205. */
  206. delete Description;
  207. Description = NULL;
  208. if (SurfacePtr != NULL) {
  209. SurfacePtr->Release();
  210. }
  211. SurfacePtr = NULL;
  212. }
  213. /***********************************************************************************************
  214. * DSurface::DSurface -- Default constructor for surface object. *
  215. * *
  216. * This default constructor for a surface object should not be used. Although it properly *
  217. * creates a non-functional surface, there is no use for such a surface. This default *
  218. * constructor is provided for those rare cases where symatics require a default *
  219. * constructor. *
  220. * *
  221. * INPUT: none *
  222. * *
  223. * OUTPUT: none *
  224. * *
  225. * WARNINGS: none *
  226. * *
  227. * HISTORY: *
  228. * 02/07/1997 JLB : Created. *
  229. *=============================================================================================*/
  230. DSurface::DSurface(void) :
  231. BytesPerPixel(0),
  232. LockPtr(NULL),
  233. SurfacePtr(NULL),
  234. Description(NULL),
  235. DCUnlockCount(0)
  236. {
  237. Description = W3DNEW DDSURFACEDESC;
  238. memset(Description, '\0', sizeof(DDSURFACEDESC));
  239. Description->dwSize = sizeof(DDSURFACEDESC);
  240. }
  241. /***********************************************************************************************
  242. * DSurface::GetDC -- Get the windows device context from our surface *
  243. * *
  244. * INPUT: none *
  245. * *
  246. * OUTPUT: none *
  247. * *
  248. * WARNINGS: Any current locks will get unlocked while the DC is held *
  249. * *
  250. * HISTORY: *
  251. * 06/21/2000 NAK : Created. *
  252. *=============================================================================================*/
  253. HDC DSurface::GetDC(void)
  254. {
  255. HDC hdc = NULL;
  256. HRESULT hr;
  257. // We have to remove all current locks to get the device context unfortunately...
  258. while (LockCount) {
  259. Unlock();
  260. DCUnlockCount++;
  261. }
  262. hr = SurfacePtr->GetDC(&hdc);
  263. if (hr != DD_OK)
  264. {
  265. while(DCUnlockCount) // restore the lock state
  266. {
  267. Lock();
  268. DCUnlockCount--;
  269. }
  270. return(NULL);
  271. }
  272. // GetDC() locks the surface internally, so we need to reflect that here
  273. if (hr == DD_OK) {
  274. LockCount++;
  275. }else{
  276. hdc = NULL;
  277. }
  278. return (hdc);
  279. }
  280. /***********************************************************************************************
  281. * DSurface::ReleaseDC -- Release the windows device context from our surface *
  282. * *
  283. * INPUT: none *
  284. * *
  285. * OUTPUT: none *
  286. * *
  287. * WARNINGS: Restores any locks held before the call to GetDC() *
  288. * *
  289. * HISTORY: *
  290. * 06/21/2000 NAK : Created. *
  291. *=============================================================================================*/
  292. int DSurface::ReleaseDC(HDC hdc)
  293. {
  294. HRESULT hr;
  295. hr = SurfacePtr->ReleaseDC(hdc);
  296. assert(hr == DD_OK);
  297. // ReleaseDC() unlocks the surface internally, so we need to reflect that here.
  298. if ((hr == DD_OK) && (LockCount > 0)) {
  299. LockCount--;
  300. }
  301. while(DCUnlockCount) // restore the lock state
  302. {
  303. Lock();
  304. DCUnlockCount--;
  305. }
  306. return (1);
  307. }
  308. /***********************************************************************************************
  309. * DSurface::Create_Primary -- Creates a primary (visible) surface. *
  310. * *
  311. * This routine is used to create the surface object that represents the currently *
  312. * visible display. The surface is not allocated, it is merely linked to the preexisting *
  313. * surface that the Windows GDI is also currently using. *
  314. * *
  315. * INPUT: backsurface -- Optional pointer to specify where the backpage (flip enabled) *
  316. * pointer will be placed. If this parameter is NULL, then no *
  317. * back surface will be created. *
  318. * *
  319. * OUTPUT: Returns with a pointer to the primary surface. *
  320. * *
  321. * WARNINGS: There can be only one primary surface. If an additional call to this routine *
  322. * is made, another surface pointer will be returned, but it will point to the *
  323. * same surface as before. *
  324. * *
  325. * HISTORY: *
  326. * 02/07/1997 JLB : Created. *
  327. *=============================================================================================*/
  328. DSurface * DSurface::Create_Primary(DSurface ** backsurface1)
  329. {
  330. DSurface * surface = W3DNEW DSurface();
  331. int backcount = (backsurface1 != NULL) ? 1 : 0;
  332. /*
  333. ** Setup parameter for creating the primary surface. This will
  334. ** always be the visible surface plus optional back buffers of identical
  335. ** dimensions.
  336. */
  337. surface->Description->dwFlags = DDSD_CAPS;
  338. surface->Description->ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  339. if (backcount > 0) {
  340. surface->Description->ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  341. surface->Description->dwFlags |= DDSD_BACKBUFFERCOUNT;
  342. surface->Description->dwBackBufferCount = backcount;
  343. }
  344. HRESULT result = DirectDrawObject->CreateSurface(surface->Description, &surface->SurfacePtr, NULL);
  345. /*
  346. ** If the primary surface object was created, then fetch a pointer to the
  347. ** back buffer if there is one present.
  348. */
  349. if (result == DD_OK) {
  350. if (backcount > 0) {
  351. LPDIRECTDRAWSURFACE back;
  352. DDSCAPS caps;
  353. caps.dwCaps = DDSCAPS_BACKBUFFER;
  354. result = surface->SurfacePtr->GetAttachedSurface(&caps, &back);
  355. if (result == DD_OK) {
  356. *backsurface1 = W3DNEW DSurface(back);
  357. }
  358. }
  359. /*
  360. ** Get a description of the surface that was just allocated.
  361. */
  362. memset(surface->Description, '\0', sizeof(DDSURFACEDESC));
  363. surface->Description->dwSize = sizeof(DDSURFACEDESC);
  364. surface->SurfacePtr->GetSurfaceDesc(surface->Description);
  365. surface->BytesPerPixel = (surface->Description->ddpfPixelFormat.dwRGBBitCount+7)/8;
  366. surface->IsPrimary = true;
  367. // surface->Window.Set(Rect(0, 0, surface->Description->dwWidth, surface->Description->dwHeight));
  368. surface->Width = surface->Description->dwWidth;
  369. surface->Height = surface->Description->dwHeight;
  370. PaletteSurface = surface->SurfacePtr;
  371. /*
  372. ** Attach a clipper object to the surface so that it can cooperate
  373. ** with the system GDI. This only comes into play if there are going
  374. ** to be GDI graphical elements on top of the surface (normally this
  375. ** isn't the case for full screen games). It doesn't hurt to attach
  376. ** a clipper object anyway -- just in case.
  377. */
  378. if (DirectDrawObject->CreateClipper(0, &Clipper, NULL) == DD_OK) {
  379. if (Clipper->SetHWnd(0, GetActiveWindow()) == DD_OK) {
  380. surface->SurfacePtr->SetClipper(Clipper);
  381. }
  382. }
  383. /*
  384. ** Fetch the pixel format for the surface.
  385. */
  386. memcpy(&PixelFormat, &surface->Description->ddpfPixelFormat, sizeof(DDPIXELFORMAT));
  387. /*
  388. ** If this is a hicolor surface, then build the shift values for
  389. ** building and extracting the colors from the hicolor pixel.
  390. */
  391. if (surface->Bytes_Per_Pixel() == 2) {
  392. int index;
  393. int shift = PixelFormat.dwRBitMask;
  394. RedRight = 0;
  395. RedLeft = 0;
  396. for (index = 0; index < 16; index++) {
  397. if (shift & 0x01) break;
  398. shift >>= 1;
  399. RedRight++;
  400. }
  401. for (index = 0; index < 8; index++) {
  402. if (shift & 0x80) break;
  403. shift <<= 1;
  404. RedLeft++;
  405. }
  406. shift = PixelFormat.dwGBitMask;
  407. GreenRight = 0;
  408. GreenLeft = 0;
  409. for (index = 0; index < 16; index++) {
  410. if (shift & 0x01) break;
  411. GreenRight++;
  412. shift >>= 1;
  413. }
  414. for (index = 0; index < 8; index++) {
  415. if (shift & 0x80) break;
  416. GreenLeft++;
  417. shift <<= 1;
  418. }
  419. shift = PixelFormat.dwBBitMask;
  420. BlueRight = 0;
  421. BlueLeft = 0;
  422. for (index = 0; index < 16; index++) {
  423. if (shift & 0x01) break;
  424. BlueRight++;
  425. shift >>= 1;
  426. }
  427. for (index = 0; index < 8; index++) {
  428. if (shift & 0x80) break;
  429. BlueLeft++;
  430. shift <<= 1;
  431. }
  432. /*
  433. ** Create the halfbright mask.
  434. */
  435. HalfbrightMask = (unsigned short)Build_Hicolor_Pixel(127, 127, 127);
  436. QuarterbrightMask = (unsigned short)Build_Hicolor_Pixel(63, 63, 63);
  437. EighthbrightMask = (unsigned short)Build_Hicolor_Pixel(31, 31, 31);
  438. }
  439. } else {
  440. delete surface;
  441. surface = NULL;
  442. }
  443. return(surface);
  444. }
  445. /***********************************************************************************************
  446. * DSurface::DSurface -- Create a surface attached to specified DDraw Surface Object. *
  447. * *
  448. * If an existing Direct Draw Surface Object is available, use this constructor to create *
  449. * a DSurface object that is attached to the surface specified. *
  450. * *
  451. * INPUT: surfaceptr -- Pointer to a preexisting Direct Draw Surface Object. *
  452. * *
  453. * OUTPUT: none *
  454. * *
  455. * WARNINGS: none *
  456. * *
  457. * HISTORY: *
  458. * 02/07/1997 JLB : Created. *
  459. *=============================================================================================*/
  460. DSurface::DSurface(LPDIRECTDRAWSURFACE surfaceptr) :
  461. BytesPerPixel(0),
  462. LockPtr(NULL),
  463. SurfacePtr(surfaceptr),
  464. Description(NULL)
  465. {
  466. if (SurfacePtr != NULL) {
  467. Description = W3DNEW DDSURFACEDESC;
  468. memset(Description, '\0', sizeof(DDSURFACEDESC));
  469. Description->dwSize = sizeof(DDSURFACEDESC);
  470. HRESULT result = SurfacePtr->GetSurfaceDesc(Description);
  471. if (result == DD_OK) {
  472. BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8;
  473. // Window.Set(Rect(0, 0, Description->dwWidth, Description->dwHeight));
  474. Width = Description->dwWidth;
  475. Height = Description->dwHeight;
  476. }
  477. }
  478. }
  479. /***********************************************************************************************
  480. * DSurface::Bytes_Per_Pixel -- Fetches the bytes per pixel of the surface. *
  481. * *
  482. * This routine will return with the number of bytes that each pixel consumes. The value *
  483. * is dependant upon the graphic mode of the display. *
  484. * *
  485. * INPUT: none *
  486. * *
  487. * OUTPUT: Returns with the bytes per pixel of the surface object. *
  488. * *
  489. * WARNINGS: none *
  490. * *
  491. * HISTORY: *
  492. * 02/07/1997 JLB : Created. *
  493. *=============================================================================================*/
  494. int DSurface::Bytes_Per_Pixel(void) const
  495. {
  496. return(BytesPerPixel);
  497. }
  498. /***********************************************************************************************
  499. * DSurface::Stride -- Fetches the bytes between rows. *
  500. * *
  501. * This routine will return the number of bytes to add so that the pointer will be *
  502. * positioned at the same column, but one row down the screen. This value may very well *
  503. * NOT be equal to the width multiplied by the bytes per pixel. *
  504. * *
  505. * INPUT: none *
  506. * *
  507. * OUTPUT: Returns with the byte difference between subsequent pixel rows. *
  508. * *
  509. * WARNINGS: none *
  510. * *
  511. * HISTORY: *
  512. * 02/07/1997 JLB : Created. *
  513. *=============================================================================================*/
  514. int DSurface::Stride(void) const
  515. {
  516. return(Description->lPitch);
  517. }
  518. /***********************************************************************************************
  519. * DSurface::Lock -- Fetches a working pointer into surface memory. *
  520. * *
  521. * This routine will return with a pointer to the pixel at the location specified. In order *
  522. * to directly manipulate surface memory, the surface memory must be mapped into the *
  523. * program's logical address space. In addition, all blitter activity on the surface will *
  524. * be suspended. Every call to Lock must be have a corresponding call to Unlock if the *
  525. * pointer returned is not equal to NULL. *
  526. * *
  527. * INPUT: point -- Pixel coordinate to return a pointer to. *
  528. * *
  529. * OUTPUT: Returns with a pointer to the pixel specified. If the return value is NULL, then *
  530. * the surface could not be locked and no call to Unlock should be performed. *
  531. * *
  532. * WARNINGS: It is important not to keep a surface locked indefinately since the blitter *
  533. * will not be able to function. Due to the time that locking consumes, it is *
  534. * also important to not perform unnecessarily frequent Lock calls. *
  535. * *
  536. * HISTORY: *
  537. * 02/07/1997 JLB : Created. *
  538. *=============================================================================================*/
  539. void * DSurface::Lock(Point2D point) const
  540. {
  541. Restore_Check();
  542. if (LockCount == 0) {
  543. DDSURFACEDESC desc;
  544. memset(&desc, '\0', sizeof(desc));
  545. desc.dwSize = sizeof(desc);
  546. HRESULT result = SurfacePtr->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR|DDLOCK_WAIT, NULL);
  547. if (result != DD_OK) return(NULL);
  548. memcpy(Description, &desc, sizeof(DDSURFACEDESC));
  549. BytesPerPixel = (Description->ddpfPixelFormat.dwRGBBitCount+7)/8;
  550. LockPtr = Description->lpSurface;
  551. }
  552. XSurface::Lock();
  553. return(((char*)LockPtr) + point.Y * Stride() + point.X * Bytes_Per_Pixel());
  554. }
  555. /***********************************************************************************************
  556. * DSurface::Unlock -- Unlock a previously locked surface. *
  557. * *
  558. * After a surface has been successfully locked, a call to the Unlock() function is *
  559. * required. *
  560. * *
  561. * INPUT: none *
  562. * *
  563. * OUTPUT: bool; Was the unlock successful? *
  564. * *
  565. * WARNINGS: Only pair a call to Unlock if the prior Lock actually returned a non-NULL *
  566. * value. *
  567. * *
  568. * HISTORY: *
  569. * 02/07/1997 JLB : Created. *
  570. *=============================================================================================*/
  571. bool DSurface::Unlock(void) const
  572. {
  573. Restore_Check();
  574. if (LockCount > 0) {
  575. XSurface::Unlock();
  576. if (LockCount == 0) {
  577. SurfacePtr->Unlock(LockPtr);
  578. LockPtr = NULL;
  579. }
  580. return(true);
  581. }
  582. return(false);
  583. }
  584. /***********************************************************************************************
  585. * DSurface::Restore_Check -- Checks for and restores surface memory if necessary. *
  586. * *
  587. * This routine will check to see if surface memory has been lost to the surface. If it *
  588. * has, then the surface memory will be restored. *
  589. * *
  590. * INPUT: none *
  591. * *
  592. * OUTPUT: none *
  593. * *
  594. * WARNINGS: none *
  595. * *
  596. * HISTORY: *
  597. * 02/07/1997 JLB : Created. *
  598. *=============================================================================================*/
  599. void DSurface::Restore_Check(void) const
  600. {
  601. if (SurfacePtr->IsLost() == DDERR_SURFACELOST) {
  602. SurfacePtr->Restore();
  603. if (LockCount > 0 && SurfacePtr->IsLost() != DDERR_SURFACELOST) {
  604. int oldlockcount = LockCount;
  605. LockCount = 0;
  606. Lock();
  607. LockCount++;
  608. Unlock();
  609. LockCount = oldlockcount;
  610. }
  611. }
  612. }
  613. /***********************************************************************************************
  614. * DSurface::Blit_From -- Blit graphic memory from one rectangle to another. *
  615. * *
  616. * This routine will use the blitter (if possible) to blit a block of graphic memory from *
  617. * one screen rectangle to another. If the rectangles do no match in size, scaling may *
  618. * be performed. *
  619. * *
  620. * INPUT: destrect -- The destination rectangle. *
  621. * *
  622. * ssource -- The source surface to blit from. *
  623. * *
  624. * sourecrect -- The source rectangle. *
  625. * *
  626. * trans -- Should transparency checking be performed? *
  627. * *
  628. * OUTPUT: bool; Was the blit performed without error? *
  629. * *
  630. * WARNINGS: none *
  631. * *
  632. * HISTORY: *
  633. * 02/07/1997 JLB : Created. *
  634. *=============================================================================================*/
  635. bool DSurface::Blit_From(Rect const & destrect, Surface const & ssource, Rect const & sourcerect, bool trans)
  636. {
  637. return(Blit_From(Get_Rect(), destrect, ssource, ssource.Get_Rect(), sourcerect, trans));
  638. }
  639. /***********************************************************************************************
  640. * DSurface::Blit_From -- Blit from one surface to this one. *
  641. * *
  642. * Use this routine to blit a rectangle from the specified surface to this surface while *
  643. * performing clipping upon the blit rectangles specified. *
  644. * *
  645. * INPUT: dcliprect -- The clipping rectangle to use for this surface. *
  646. * *
  647. * destrect -- The destination rectangle of the blit. The is relative to the *
  648. * dcliprect parameter. *
  649. * *
  650. * ssource -- The source surface of the blit. *
  651. * *
  652. * scliprect -- The source clipping rectangle. *
  653. * *
  654. * sourcrect -- The source rectangle of the blit. This rectangle is relative to *
  655. * the source clipping rectangle. *
  656. * *
  657. * trans -- Is this a transparent blit request? *
  658. * *
  659. * OUTPUT: bool; Was there a blit performed? A 'false' return value would indicate that the *
  660. * blit was clipped into nothing. *
  661. * *
  662. * WARNINGS: none *
  663. * *
  664. * HISTORY: *
  665. * 05/27/1997 JLB : Created. *
  666. *=============================================================================================*/
  667. bool DSurface::Blit_From(Rect const & dcliprect, Rect const & destrect, Surface const & ssource, Rect const & scliprect, Rect const & sourcerect, bool trans)
  668. {
  669. if (!dcliprect.Is_Valid() || !scliprect.Is_Valid() || !destrect.Is_Valid() || !sourcerect.Is_Valid()) return(false);
  670. /*
  671. ** For non-direct draw surfaces, perform a manual blit operation. This is also
  672. ** necessary if any of the surfaces are currently locked. It is also necessary if the
  673. ** blit regions overlap and the blitter cannot handle overlapped regions.
  674. **
  675. ** NOTE: Its legal to blit to a locked surface but not from a locked surface.
  676. ** ST - 4/23/97 1:03AM
  677. */
  678. if (!ssource.Is_Direct_Draw() || ((DSurface&)ssource).Is_Locked() || trans || Bytes_Per_Pixel() != ssource.Bytes_Per_Pixel()) {
  679. return(XSurface::Blit_From(destrect, ssource, sourcerect, trans));
  680. }
  681. Restore_Check();
  682. DSurface const & source = (DSurface const &)ssource;
  683. Rect drect = destrect;
  684. Rect srect = sourcerect;
  685. Rect swindow = scliprect.Intersect(ssource.Get_Rect());
  686. Rect dwindow = dcliprect.Intersect(Get_Rect());
  687. if (Blit_Clip(drect, dwindow, srect, swindow)) {
  688. RECT xdestrect;
  689. xdestrect.left = drect.X+dwindow.X;
  690. xdestrect.top = drect.Y+dwindow.Y;
  691. xdestrect.right = drect.X+dwindow.X+drect.Width;
  692. xdestrect.bottom = drect.Y+dwindow.Y+drect.Height;
  693. RECT xsrcrect;
  694. xsrcrect.left = srect.X+swindow.X;
  695. xsrcrect.top = srect.Y+swindow.Y;
  696. xsrcrect.right = srect.X+swindow.X+srect.Width;
  697. xsrcrect.bottom = srect.Y+swindow.Y+srect.Height;
  698. HRESULT result = SurfacePtr->Blt(&xdestrect, source.SurfacePtr, &xsrcrect, DDBLT_WAIT, NULL);
  699. return(result == DD_OK);
  700. }
  701. return(false);
  702. }
  703. /***********************************************************************************************
  704. * DSurface::Fill_Rect -- This routine will fill the specified rectangle. *
  705. * *
  706. * This routine will fill the specified rectangle with a color. *
  707. * *
  708. * INPUT: fillrect -- The rectangle to fill. *
  709. * *
  710. * color -- The color to fill with. *
  711. * *
  712. * OUTPUT: bool; Was the fill performed without error? *
  713. * *
  714. * WARNINGS: none *
  715. * *
  716. * HISTORY: *
  717. * 02/07/1997 JLB : Created. *
  718. *=============================================================================================*/
  719. bool DSurface::Fill_Rect(Rect const & fillrect, int color)
  720. {
  721. return(DSurface::Fill_Rect(Get_Rect(), fillrect, color));
  722. }
  723. /***********************************************************************************************
  724. * DSurface::Fill_Rect -- Fills a rectangle with clipping control. *
  725. * *
  726. * This routine will fill a rectangle on this surface, but will clip the request against *
  727. * a clipping rectangle first. *
  728. * *
  729. * INPUT: cliprect -- The clipping rectangle to use for this surface. *
  730. * *
  731. * fillrect -- The rectangle to fill with the specified color. The rectangle is *
  732. * relative to the clipping rectangle. *
  733. * *
  734. * color -- The color (surface dependant format) to use when filling the rectangle *
  735. * pixels. *
  736. * *
  737. * OUTPUT: bool; Was a fill operation performed? A 'false' return value would mean that the *
  738. * fill request was clipped into nothing. *
  739. * *
  740. * WARNINGS: none *
  741. * *
  742. * HISTORY: *
  743. * 05/27/1997 JLB : Created. *
  744. *=============================================================================================*/
  745. bool DSurface::Fill_Rect(Rect const & cliprect, Rect const & fillrect, int color)
  746. {
  747. if (!fillrect.Is_Valid()) return(false);
  748. /*
  749. ** If the buffer is locked, then using the blitter to perform the fill is not possible.
  750. ** In such a case, perform a manual fill of the region.
  751. */
  752. if (Is_Locked()) {
  753. return(XSurface::Fill_Rect(cliprect, fillrect, color));
  754. }
  755. Restore_Check();
  756. /*
  757. ** Ensure that the clipping rectangle is legal.
  758. */
  759. Rect crect = cliprect.Intersect(Get_Rect());
  760. /*
  761. ** Bias the fill rect to the clipping rectangle.
  762. */
  763. Rect frect = fillrect.Bias_To(cliprect);
  764. /*
  765. ** Find the region that should be filled after being clipped by the
  766. ** clipping rectangle. This could result in no fill operation being performed
  767. ** if the desired fill rectangle has been completely clipped away.
  768. */
  769. frect = frect.Intersect(crect);
  770. if (!frect.Is_Valid()) return(false);
  771. RECT rect;
  772. rect.left = frect.X;
  773. rect.top = frect.Y;
  774. rect.right = rect.left + frect.Width;
  775. rect.bottom = rect.top + frect.Height;
  776. DDBLTFX fx;
  777. memset(&fx, '\0', sizeof(fx));
  778. fx.dwSize = sizeof(fx);
  779. fx.dwFillColor = color;
  780. HRESULT result = SurfacePtr->Blt(&rect, NULL, NULL, DDBLT_WAIT|DDBLT_COLORFILL, &fx);
  781. return(result == DD_OK);
  782. }
  783. /***********************************************************************************************
  784. * DSurface::Build_Hicolor_Pixel -- Construct a hicolor pixel according to the surface pixel f *
  785. * *
  786. * This routine will construct a pixel according to the highcolor pixel format for this *
  787. * surface. *
  788. * *
  789. * INPUT: red -- The red component of the color (0..255). *
  790. * *
  791. * green -- The green component of the color (0..255). *
  792. * *
  793. * blue -- The blue component of the color (0..255). *
  794. * *
  795. * OUTPUT: Returns with a screen format pixel number that most closesly matches the color *
  796. * specified. *
  797. * *
  798. * WARNINGS: The return value is card dependant and only applies to hicolor displays. *
  799. * *
  800. * HISTORY: *
  801. * 05/27/1997 JLB : Created. *
  802. *=============================================================================================*/
  803. int DSurface::Build_Hicolor_Pixel(int red, int green, int blue)
  804. {
  805. return(((red >> RedLeft) << RedRight) | ((green >> GreenLeft) << GreenRight) | ((blue >> BlueLeft) << BlueRight));
  806. }
  807. /***********************************************************************************************
  808. * DSurface::Build_Remap_Table -- Build a highcolor remap table. *
  809. * *
  810. * This will build a complete hicolor remap table for the palette specified. This table *
  811. * can then be used to quickly fetch a pixel that matches the color index of the palette. *
  812. * *
  813. * INPUT: table -- The location to store the hicolor table. The buffer must be 256*2 bytes *
  814. * long. *
  815. * *
  816. * palette -- The palette to use to create the remap table. *
  817. * *
  818. * OUTPUT: none *
  819. * *
  820. * WARNINGS: none *
  821. * *
  822. * HISTORY: *
  823. * 05/27/1997 JLB : Created. *
  824. *=============================================================================================*/
  825. void DSurface::Build_Remap_Table(unsigned short * table, PaletteClass const & palette)
  826. {
  827. assert(table != NULL);
  828. /*
  829. ** Build the hicolor index table according to the palette.
  830. */
  831. for (int index = 0; index < 256; index++) {
  832. table[index] = (unsigned short)Build_Hicolor_Pixel(palette[index].Get_Red(), palette[index].Get_Green(), palette[index].Get_Blue());
  833. }
  834. }