blit.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. /***********************************************************************************************
  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/blit.cpp $*
  25. * *
  26. * $Author:: Eric_c $*
  27. * *
  28. * $Modtime:: 4/15/99 10:13a $*
  29. * *
  30. * $Revision:: 3 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * Bit_Blit -- Blit a block of pixels to the destination surface. *
  35. * Bit_Blit -- Blits data to a surface w/ clipping. *
  36. * Buffer_Size -- Determines size of buffer for given dimensions. *
  37. * From_Buffer -- Copy graphic data from a buffer to a surface. *
  38. * RLE_Blit -- Blits RLE compressed data without extra clipping. *
  39. * RLE_Blit -- Blits a rectangle of RLE compressed data to a surface. *
  40. * To_Buffer -- Copies a graphic region into a linear RAM buffer. *
  41. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  42. #include "always.h"
  43. #include "blit.h"
  44. #include "bsurface.h"
  45. //#include "rle.h"
  46. #include "xsurface.h"
  47. //#include <stdlib.h>
  48. /***********************************************************************************************
  49. * Buffer_Size -- Determines size of buffer for given dimensions. *
  50. * *
  51. * This routine will determine the byte size of a buffer if it were to hold the pixels *
  52. * of the dimensions specified. It takes into account the bytes per pixel. *
  53. * *
  54. * INPUT: surface -- The surface to base the buffer size calculation upon. *
  55. * *
  56. * width -- Pixel width of a graphic region. *
  57. * *
  58. * height -- Pixel height of a graphic region. *
  59. * *
  60. * OUTPUT: Returns with the number of bytes such a region would consume if it were linearly *
  61. * packed into a memory buffer. *
  62. * *
  63. * WARNINGS: none *
  64. * *
  65. * HISTORY: *
  66. * 02/07/1997 JLB : Created. *
  67. *=============================================================================================*/
  68. int Buffer_Size(Surface const & surface, int width, int height)
  69. {
  70. return(width * height * surface.Bytes_Per_Pixel());
  71. }
  72. /***********************************************************************************************
  73. * To_Buffer -- Copies a graphic region into a linear RAM buffer. *
  74. * *
  75. * This routine will copy the graphic rectangle specified, into a RAM buffer. The size of *
  76. * the RAM buffer must be big enough to hold the pixel data. Use the Buffer_Size() function *
  77. * to determine how big it must be. *
  78. * *
  79. * INPUT: surface -- The surface to copy the pixel data from. *
  80. * *
  81. * rect -- The graphic rectangle to copy from. *
  82. * *
  83. * buffer -- Reference to the buffer that will be filled with the pixel data. *
  84. * *
  85. * OUTPUT: bool; Was the data copy performed without error? *
  86. * *
  87. * WARNINGS: none *
  88. * *
  89. * HISTORY: *
  90. * 02/07/1997 JLB : Created. *
  91. *=============================================================================================*/
  92. bool To_Buffer(Surface const & surface, Rect const & rect, Buffer & buffer)
  93. {
  94. if (!rect.Is_Valid()) return(false);
  95. BSurface from(rect.Width, rect.Height, surface.Bytes_Per_Pixel(), buffer);
  96. return(from.Blit_From(Rect(0, 0, rect.Width, rect.Height), surface, rect));
  97. }
  98. /***********************************************************************************************
  99. * From_Buffer -- Copy graphic data from a buffer to a surface. *
  100. * *
  101. * This routine will take pixel data and move it from the specified buffer and into the *
  102. * surface rectangle specified. It is the counterpart routine of To_Buffer(). *
  103. * *
  104. * INPUT: surface -- The surface to store the pixel data to. *
  105. * *
  106. * rect -- The destination rectangle to store the pixel data to. *
  107. * *
  108. * buffer -- Reference to the buffer that contains the pixel data. *
  109. * *
  110. * OUTPUT: bool; Was the pixel data copy performed without error? *
  111. * *
  112. * WARNINGS: none *
  113. * *
  114. * HISTORY: *
  115. * 02/07/1997 JLB : Created. *
  116. *=============================================================================================*/
  117. bool From_Buffer(Surface & surface, Rect const & rect, Buffer const & buffer)
  118. {
  119. if (!rect.Is_Valid()) return(false);
  120. BSurface from(rect.Width, rect.Height, surface.Bytes_Per_Pixel(), buffer);
  121. return(surface.Blit_From(rect, from, Rect(0, 0, rect.Width, rect.Height)));
  122. }
  123. /***********************************************************************************************
  124. * Bit_Blit -- Blits data to a surface w/ clipping. *
  125. * *
  126. * This routine will take source pixel data and blit it to the surface specified while *
  127. * also performing clipping on both the source and the destination data. Typical users of *
  128. * this routine would be to draw shape (sprite) data. *
  129. * *
  130. * INPUT: dest -- Destintaion surface rect. This specifies the destination surface and *
  131. * any coordinate clipping rectangle. *
  132. * *
  133. * destrect -- The destination rectangle of the blit. The coordinates are relative *
  134. * to the destination clipping rectangle. *
  135. * *
  136. * source -- Source surface rect. This specifies the source surface as well as any *
  137. * clipping rectangle it may contain. *
  138. * *
  139. * srcrect -- The rectange, relative to the source clipping rectangle, that *
  140. * specifies the source blit data. It is presumed that the dimensions of *
  141. * the source rectangle are the same as the destination rectangle. *
  142. * *
  143. * blitter -- The blitter to use for moving the source pixels to the destination *
  144. * surface. *
  145. * *
  146. * OUTPUT: bool; Was the blit performed even if it was for only a single pixel. Failure would *
  147. * indicate that the blit was completely clipped away. *
  148. * *
  149. * WARNINGS: none *
  150. * *
  151. * HISTORY: *
  152. * 05/19/1997 JLB : Created. *
  153. *=============================================================================================*/
  154. bool Bit_Blit(Surface & dest, Rect const & destrect, Surface const & source, Rect const & sourcerect, Blitter const & blitter)
  155. {
  156. return(Bit_Blit(dest, dest.Get_Rect(), destrect, source, source.Get_Rect(), sourcerect, blitter));
  157. }
  158. /***********************************************************************************************
  159. * Bit_Blit -- Blit a block of pixels to the destination surface. *
  160. * *
  161. * This routine will blit a block of pixels and perform clipping on the blit as controlled *
  162. * by the clipping rectangles. *
  163. * *
  164. * INPUT: dest -- Surface to blit to. *
  165. * *
  166. * dcliprect-- The destination surface clipping rectangle. *
  167. * *
  168. * ddrect -- The destination rect of the blit. It is relative to the clipping *
  169. * rectangle and will be clipped against same. *
  170. * *
  171. * source -- The source surface to blit from. *
  172. * *
  173. * scliprect-- The source surface clipping rectangle. *
  174. * *
  175. * ssrect -- The source rectangle of the blit. It is relative to the source *
  176. * clipping rectangle and will be clipped against same. *
  177. * *
  178. * blitter -- The blitter to use for blitting of this rectangle. *
  179. * *
  180. * OUTPUT: bool; Was the blit performed? A 'false' return value would indicate that the *
  181. * blit was clipped into nothing. *
  182. * *
  183. * WARNINGS: none *
  184. * *
  185. * HISTORY: *
  186. * 05/27/1997 JLB : Created. *
  187. *=============================================================================================*/
  188. bool Bit_Blit(Surface & dest, Rect const & dcliprect, Rect const & ddrect, Surface const & source, Rect const & scliprect, Rect const & ssrect, Blitter const & blitter)
  189. {
  190. Rect srect = ssrect;
  191. Rect drect = ddrect;
  192. bool overlapped = false;
  193. void * dbuffer = NULL;
  194. void * sbuffer = NULL;
  195. /*
  196. ** Prepare for the blit by performing any clipping as well as fetching pointers into the
  197. ** pixel buffers. If there were any errors, then this blit cannot be performed.
  198. */
  199. if (!XSurface::Prep_For_Blit(dest, dcliprect, drect, source, scliprect, srect, overlapped, dbuffer, sbuffer)) {
  200. return(false);
  201. }
  202. /*
  203. ** If there is no difference between the width and the stride of the source and
  204. ** destination surfaces, then the copy can be performed as one huge copy operation.
  205. ** This is the simplist case and the one that is performed with a full screen
  206. ** blit.
  207. */
  208. if (drect.Width * dest.Bytes_Per_Pixel() == dest.Stride() && dest.Stride() == source.Stride()) {
  209. int length = MIN(srect.Height*srect.Width, drect.Height*drect.Width);
  210. if (overlapped) {
  211. blitter.BlitBackward(dbuffer, sbuffer, length);
  212. } else {
  213. blitter.BlitForward(dbuffer, sbuffer, length);
  214. }
  215. } else {
  216. /*
  217. ** If the rectangles overlap, then the copy must proceed from the
  218. ** last row to the first rather than the normal direction.
  219. */
  220. int sstride = source.Stride();
  221. int dstride = dest.Stride();
  222. if (overlapped) {
  223. sstride = -sstride;
  224. dstride = -dstride;
  225. sbuffer = ((char*)sbuffer) + (srect.Height-1) * source.Stride();
  226. dbuffer = ((char*)dbuffer) + (drect.Height-1) * dest.Stride();
  227. }
  228. /*
  229. ** This perform a line-by-line pixel copy.
  230. */
  231. int height = MIN(srect.Height, drect.Height);
  232. if (overlapped) {
  233. for (int y = 0; y < height; y++) {
  234. blitter.BlitBackward(dbuffer, sbuffer, srect.Width);
  235. dbuffer = (void*)(((char*)dbuffer) + dstride);
  236. sbuffer = (void*)(((char*)sbuffer) + sstride);
  237. }
  238. } else {
  239. for (int y = 0; y < height; y++) {
  240. blitter.BlitForward(dbuffer, sbuffer, srect.Width);
  241. dbuffer = (void*)(((char*)dbuffer) + dstride);
  242. sbuffer = (void*)(((char*)sbuffer) + sstride);
  243. }
  244. }
  245. }
  246. dest.Unlock();
  247. source.Unlock();
  248. return(true);
  249. }
  250. /***********************************************************************************************
  251. * RLE_Blit -- Blits RLE compressed data without extra clipping. *
  252. * *
  253. * This routine will blit a rectangle of RLE compressed data to the specified surface. It *
  254. * is functionally similar to the other RLE blit routine, but does not use any sub *
  255. * clipping rectangles. The blit is naturally clipped to the edge of the destination *
  256. * surface. *
  257. * *
  258. * INPUT: dest -- Reference to the destination surface. *
  259. * *
  260. * destrect -- The destination rectangle to draw the pixels to. *
  261. * *
  262. * source -- Reference to the source RLE surface data. *
  263. * *
  264. * sourcerect -- The source rectangle of from the RLE surface to blit from. *
  265. * *
  266. * blitter -- Reference to the blitter to perform the blit operation with. *
  267. * *
  268. * OUTPUT: bool; Was a blit performed? A 'false' value would mean that the blit has been *
  269. * clipped into nothing. *
  270. * *
  271. * WARNINGS: The dimensions of the source and destination rectangles should be the same *
  272. * until such time that the blitter can support scaling (as of this writing, it *
  273. * cannot). *
  274. * *
  275. * HISTORY: *
  276. * 05/27/1997 JLB : Created. *
  277. *=============================================================================================*/
  278. bool RLE_Blit(Surface & dest, Rect const & destrect, Surface const & source, Rect const & sourcerect, RLEBlitter const & blitter)
  279. {
  280. return(RLE_Blit(dest, dest.Get_Rect(), destrect, source, source.Get_Rect(), sourcerect, blitter));
  281. }
  282. /***********************************************************************************************
  283. * RLE_Blit -- Blits a rectangle of RLE compressed data to a surface. *
  284. * *
  285. * This routine will blit a rectangle of REL compressed pixel data from a sprite to the *
  286. * surface specified. Appropriate clipping and coordinate adjustments will occur as *
  287. * controlled by the parameters. This is the workhorse RLE blit dispatcher routine. *
  288. * *
  289. * INPUT: dest -- The destination surface to blit to. *
  290. * *
  291. * dcliprect-- The clipping rectangle to use on the destination. Pixels won't be *
  292. * drawn outside of this rectangle and the destination rect coordinates *
  293. * are biased to this clipping rectange. *
  294. * *
  295. * ddrect -- The destination rectangle of the blit. The upper left coordinates are *
  296. * biased to the destination clipping rectangle when blitted. Thus, *
  297. * a dest X,Y position of 0,0 really means the upper left corner of the *
  298. * destination clipping rectangle. *
  299. * *
  300. * source -- The source surface of the RLE compressed data. *
  301. * *
  302. * scliprect-- It is quite likely that this will be the full size of the source *
  303. * surface. *
  304. * *
  305. * ssrect -- The source rectangle to blit from within the source surface. It *
  306. * behaves similarly to the ddrect parameter, but for the source. The *
  307. * width and height of this rectangle should match the width and height *
  308. * of the ddrect parameter (scaling is not yet supported). *
  309. * *
  310. * blitter -- The blitter to use for this pixel copy. It must be an RLE blitter. *
  311. * *
  312. * OUTPUT: bool; Did the blit draw at least one pixel? *
  313. * *
  314. * WARNINGS: none *
  315. * *
  316. * HISTORY: *
  317. * 05/24/1997 JLB : Created. *
  318. *=============================================================================================*/
  319. bool RLE_Blit(Surface & dest, Rect const & dcliprect, Rect const & ddrect, Surface const & source, Rect const & scliprect, Rect const & ssrect, RLEBlitter const & blitter)
  320. {
  321. Rect srect = ssrect; // Desired source rect.
  322. Rect drect = ddrect; // Desired destination rect.
  323. /*
  324. ** Adjust the desired draw rectangles to account for clipping. This is where the desired rectangles
  325. ** get clipped to the bounding rectangles of the surfaces.
  326. */
  327. if (!Blit_Clip(drect, dcliprect, srect, scliprect)) {
  328. return(false);
  329. }
  330. /*
  331. ** Determine the top and left skip margins. These require special handling
  332. ** since the shape is compressed.
  333. */
  334. int leftmargin = srect.X - scliprect.X;
  335. int topmargin = srect.Y - scliprect.Y;
  336. void * dbuffer = dest.Lock(dcliprect.Top_Left() + drect.Top_Left());
  337. // void * dbuffer = dest.Lock(Point2D(dcliprect.X + drect.X, dcliprect.Y + drect.Y));
  338. if (dbuffer == NULL) return(false);
  339. /*
  340. ** Lock the source pointer. This must always lock at location 0,0 since
  341. ** normal pixel offset logic does not work for RLE compressed buffers. If there
  342. ** is a pixel offset required, it is handled below.
  343. */
  344. void * sbuffer = source.Lock();
  345. if (sbuffer == NULL) {
  346. dest.Unlock();
  347. return(false);
  348. }
  349. /*
  350. ** Skip any top margin lines. This must be manually performed on a line
  351. ** by line basis because the length of each line is Variable.
  352. */
  353. while (topmargin > 0) {
  354. sbuffer = ((unsigned char *)sbuffer) + (*(unsigned short *)sbuffer);
  355. topmargin--;
  356. }
  357. /*
  358. ** This perform a line-by-line pixel copy.
  359. */
  360. int dstride = dest.Stride();
  361. int height = MIN(srect.Height, drect.Height);
  362. for (int y = 0; y < height; y++) {
  363. /*
  364. ** Blit the correct sub-portion to the destination surface.
  365. */
  366. blitter.Blit(dbuffer, ((unsigned short *)sbuffer)+1, srect.Width, leftmargin);
  367. /*
  368. ** Advance the source and dest pointers for the next line processing.
  369. */
  370. sbuffer = ((unsigned char *)sbuffer) + (*(unsigned short *)sbuffer);
  371. dbuffer = (void*)(((char*)dbuffer) + dstride);
  372. }
  373. dest.Unlock();
  374. source.Unlock();
  375. return(true);
  376. }