2
0

blitblit.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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:: /Commando/Library/blitblit.h $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 7/22/97 11:37a $*
  29. * *
  30. * $Revision:: 1 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #ifndef BLITBLIT_H
  36. #define BLITBLIT_H
  37. /*
  38. ** This module contains the pixel-pushing blitter objects. These objects only
  39. ** serve one purpose. That is, to move pixels from one location to another. These
  40. ** are prime candidates for optimization since they are called frequently and
  41. ** loop greatly.
  42. **
  43. ** The large variety of blitter objects is necessary because there is a rich
  44. ** set of pixel operations required by the game engine. Complicating this is that
  45. ** the game engine must support both 16 bit and 8 bit pixel formats. Some of these
  46. ** blitter objects are templates (this reduces the need for both 8 and 16 bit
  47. ** counterparts if the algorithm is constant between pixel formats). Also note
  48. ** that there are some assembly implementations where it seems appropriate.
  49. **
  50. ** If the blitter object has "Xlat" in the name, then this means that the source
  51. ** pixel is 8 bit and the destination pixel is 16 bit (probably). This hybrid system
  52. ** allows the game artwork to be shared between the two pixel format displays. To
  53. ** accomplish this, a translation table is supplied to the blit operation so that
  54. ** the 8 bit pixel can be converted into the appropriate 16 bit destination pixel.
  55. ** If the destination surface is also 8 bit, then the translation table converts
  56. ** the pixel to the logical palette color index appropriate for the display.
  57. */
  58. #include "blitter.h"
  59. #include <assert.h>
  60. #include <string.h>
  61. /*
  62. ** Blits without translation and source and dest are same pixel format. Note that
  63. ** this uses the memcpy and memmove routines. The C library has optimized these for
  64. ** maximum performance. This includes alignment issues and performing REP MOVSD
  65. ** instruction. This might be further optimized by using MMX instructions. However,
  66. ** this blitter process is not often required by the game.
  67. */
  68. template<class T>
  69. class BlitPlain : public Blitter {
  70. public:
  71. virtual void BlitForward(void * dest, void const * source, int length) const {memcpy(dest, source, length*sizeof(T));}
  72. virtual void BlitBackward(void * dest, void const * source, int length) const {memmove(dest, source, length*sizeof(T));}
  73. };
  74. /*
  75. ** Blits with transparency checking when and source and dest are same pixel format.
  76. ** This process is not often used.
  77. */
  78. template<class T>
  79. class BlitTrans : public Blitter {
  80. public:
  81. virtual void BlitForward(void * dest, void const * source, int len) const
  82. {
  83. for (int index = 0; index < len; index++) {
  84. T color = *(T const *)source;
  85. source = ((T *)source) + 1;
  86. if (color != 0) *((T *)dest) = color;
  87. dest = ((T *)dest) + 1;
  88. }
  89. }
  90. /*
  91. ** The backward moving method will probably never be called in actual practice.
  92. ** Implement in terms of the forward copying method until the need for this
  93. ** version arrises.
  94. */
  95. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  96. };
  97. /*
  98. ** Blits when source 8 bits and dest is T. This process is typically used
  99. ** when loading screen bitmaps or perform other non-transparent image blitting.
  100. ** It is used fairly frequently and is a good candidate for optimization.
  101. */
  102. template<class T>
  103. class BlitPlainXlat : public Blitter {
  104. public:
  105. BlitPlainXlat(T const * translator) : TranslateTable(translator) {assert(TranslateTable != NULL);}
  106. virtual void BlitForward(void * dest, void const * source, int len) const
  107. {
  108. for (int index = 0; index < len; index++) {
  109. unsigned char color = *(unsigned char const *)source;
  110. source = ((unsigned char const *)source)+1;
  111. *((T *)dest) = TranslateTable[color];
  112. dest = ((T *)dest) + 1;
  113. }
  114. }
  115. /*
  116. ** The backward moving method will probably never be called in actual practice.
  117. ** Implement in terms of the forward copying method until the need for this
  118. ** version arrises.
  119. */
  120. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  121. private:
  122. T const * TranslateTable;
  123. };
  124. /*
  125. ** Blits with source 8 bit with transparency and dest is T. This process is used
  126. ** frequently by trees and other terrain objects. It is a good candidate for
  127. ** optimization.
  128. */
  129. template<class T>
  130. class BlitTransXlat : public Blitter {
  131. public:
  132. BlitTransXlat(T const * translator) : TranslateTable(translator) {assert(TranslateTable != NULL);}
  133. virtual void BlitForward(void * dest, void const * source, int len) const
  134. {
  135. for (int index = 0; index < len; index++) {
  136. unsigned char color = *(unsigned char const *)source;
  137. source = ((unsigned char const *)source)+1;
  138. if (color != 0) {
  139. *((T *)dest) = TranslateTable[color];
  140. }
  141. dest = ((T *)dest) + 1;
  142. }
  143. }
  144. /*
  145. ** The backward moving method will probably never be called in actual practice.
  146. ** Implement in terms of the forward copying method until the need for this
  147. ** version arrises.
  148. */
  149. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  150. private:
  151. T const * TranslateTable;
  152. };
  153. /*
  154. ** Blits with source 8 bit, transparency check, then translate to pixel format T. This
  155. ** is occasionally used to render special remapping effects. Since the remap table is
  156. ** not doubly indirected, it is fixed to only using the remap table specified in the
  157. ** constructor. As such, it has limited value.
  158. */
  159. template<class T>
  160. class BlitTransRemapXlat : public Blitter {
  161. public:
  162. BlitTransRemapXlat(unsigned char const * remapper, T const * translator) : RemapTable(remapper), TranslateTable(translator) {assert(RemapTable != NULL);assert(TranslateTable != NULL);}
  163. virtual void BlitForward(void * dest, void const * source, int length) const
  164. {
  165. for (int index = 0; index < length; index++) {
  166. unsigned char color = *(unsigned char const *)source;
  167. source = ((unsigned char const *)source)+1;
  168. if (color != 0) {
  169. *((T *)dest) = TranslateTable[RemapTable[color]];
  170. }
  171. dest = ((T *)dest) + 1;
  172. }
  173. }
  174. /*
  175. ** The backward moving method will probably never be called in actual practice.
  176. ** Implement in terms of the forward copying method until the need for this
  177. ** version arrises.
  178. */
  179. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  180. private:
  181. unsigned char const * RemapTable;
  182. T const * TranslateTable;
  183. };
  184. /*
  185. ** Blits with source 8 bit with transparency then remap and dest is T. This is probably
  186. ** the most used blitter process. Units, infantry, buildings, and aircraft use this for
  187. ** their normal drawing needs. If any blitter process is to be optimized, this would be
  188. ** the one. Take note that the remapper table is doubly indirected. This allows a single
  189. ** blitter object to dynamically use alternate remap tables.
  190. */
  191. template<class T>
  192. class BlitTransZRemapXlat : public Blitter {
  193. public:
  194. BlitTransZRemapXlat(unsigned char const * const * remapper, T const * translator) : RemapTable(remapper), TranslateTable(translator) {assert(RemapTable != NULL);assert(TranslateTable != NULL);}
  195. virtual void BlitForward(void * dest, void const * source, int length) const
  196. {
  197. unsigned char const * rtable = *RemapTable;
  198. for (int index = 0; index < length; index++) {
  199. unsigned char color = *(unsigned char const *)source;
  200. source = ((unsigned char const *)source)+1;
  201. if (color != 0) {
  202. *((T *)dest) = TranslateTable[rtable[color]];
  203. }
  204. dest = ((T *)dest) + 1;
  205. }
  206. }
  207. /*
  208. ** The backward moving method will probably never be called in actual practice.
  209. ** Implement in terms of the forward copying method until the need for this
  210. ** version arrises.
  211. */
  212. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  213. private:
  214. unsigned char const * const * RemapTable;
  215. T const * TranslateTable;
  216. };
  217. /*
  218. ** Algorithmic darkening of hicolor pixels controlled by the source pixels. The source
  219. ** pixels are examined only to determine if the destination pixel should be darkened.
  220. ** If the source pixel is transparent, then the dest pixel is skipped. The darkening
  221. ** algorithm works only for hicolor pixels.
  222. */
  223. template<class T>
  224. class BlitTransDarken : public Blitter {
  225. public:
  226. BlitTransDarken(T mask) : Mask(mask) {}
  227. virtual void BlitForward(void * dest, void const * source, int length) const
  228. {
  229. for (int index = 0; index < length; index++) {
  230. unsigned char color = *(unsigned char const *)source;
  231. source = ((unsigned char const *)source)+1;
  232. if (color != 0) {
  233. *((T *)dest) = (T)((((*(T *)dest) >> 1) & Mask));
  234. }
  235. dest = ((T *)dest) + 1;
  236. }
  237. }
  238. /*
  239. ** The backward moving method will probably never be called in actual practice.
  240. ** Implement in terms of the forward copying method until the need for this
  241. ** version arrises.
  242. */
  243. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  244. private:
  245. T Mask;
  246. };
  247. /*
  248. ** This will remap the destination pixels but under the control of the source pixels.
  249. ** Where the source pixel is not transparent, the dest pixel is remapped. This algorithm
  250. ** really only applies to lowcolor display.
  251. */
  252. template<class T>
  253. class BlitTransRemapDest : public Blitter {
  254. public:
  255. BlitTransRemapDest(T const * remap) : RemapTable(remap) {}
  256. virtual void BlitForward(void * dest, void const * source, int length) const
  257. {
  258. for (int index = 0; index < length; index++) {
  259. unsigned char color = *(unsigned char const *)source;
  260. source = ((unsigned char const *)source)+1;
  261. if (color != 0) {
  262. *((T *)dest) = RemapTable[*((T *)dest)];
  263. }
  264. dest = ((T *)dest) + 1;
  265. }
  266. }
  267. /*
  268. ** The backward moving method will probably never be called in actual practice.
  269. ** Implement in terms of the forward copying method until the need for this
  270. ** version arrises.
  271. */
  272. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  273. private:
  274. T const * RemapTable;
  275. };
  276. /*
  277. ** This is similar to BlitTransDarken but instead of examining the source to determine what
  278. ** pixels should be darkened, every destination pixel is darkened. This means that the source
  279. ** pointer is unused.
  280. */
  281. template<class T>
  282. class BlitDarken : public Blitter {
  283. public:
  284. BlitDarken(T mask) : Mask(mask) {}
  285. virtual void BlitForward(void * dest, void const * , int length) const
  286. {
  287. for (int index = 0; index < length; index++) {
  288. *((T *)dest) = (T)(((*(T *)dest) >> 1) & Mask);
  289. dest = ((T *)dest) + 1;
  290. }
  291. }
  292. /*
  293. ** The backward moving method will probably never be called in actual practice.
  294. ** Implement in terms of the forward copying method until the need for this
  295. ** version arrises.
  296. */
  297. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  298. private:
  299. T Mask;
  300. };
  301. /*
  302. ** This blitter performs 50% translucency as it draws. It is commonly used for animation
  303. ** effects and other stealth like images. It only works with hicolor pixels but is a good
  304. ** candidate for optimization.
  305. */
  306. template<class T>
  307. class BlitTransLucent50 : public Blitter {
  308. public:
  309. BlitTransLucent50(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {assert(TranslateTable != NULL);}
  310. virtual void BlitForward(void * dest, void const * source, int length) const
  311. {
  312. for (int index = 0; index < length; index++) {
  313. unsigned char color = *(unsigned char const *)source;
  314. source = ((unsigned char *)source) + 1;
  315. if (color != 0) {
  316. *((T *)dest) = (T)((((*(T *)dest) >> 1) & Mask) + ((TranslateTable[color] >> 1) & Mask));
  317. }
  318. dest = ((T *)dest) + 1;
  319. }
  320. }
  321. /*
  322. ** The backward moving method will probably never be called in actual practice.
  323. ** Implement in terms of the forward copying method until the need for this
  324. ** version arrises.
  325. */
  326. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  327. private:
  328. T const * TranslateTable;
  329. T Mask;
  330. };
  331. /*
  332. ** This blitter performs 25% translucency as it draws. This effect is less than spectacular,
  333. ** but there are some uses for it. It only works with hicolor pixels.
  334. */
  335. template<class T>
  336. class BlitTransLucent25 : public Blitter {
  337. public:
  338. BlitTransLucent25(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {assert(TranslateTable != NULL);}
  339. virtual void BlitForward(void * dest, void const * source, int length) const
  340. {
  341. for (int index = 0; index < length; index++) {
  342. unsigned char color = *(unsigned char const *)source;
  343. source = ((unsigned char *)source) + 1;
  344. if (color != 0) {
  345. T qsource = (T)(((TranslateTable[color] >> 2) & Mask));
  346. T qdest = (T)((((*(T *)dest) >> 2) & Mask));
  347. *((T *)dest) = (T)(qdest + qsource + qsource + qsource);
  348. }
  349. dest = ((T *)dest) + 1;
  350. }
  351. }
  352. /*
  353. ** The backward moving method will probably never be called in actual practice.
  354. ** Implement in terms of the forward copying method until the need for this
  355. ** version arrises.
  356. */
  357. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  358. private:
  359. T const * TranslateTable;
  360. T Mask;
  361. };
  362. /*
  363. ** This blitter performs 75% translucency as it draws. This is quite useful for explosions and
  364. ** other gas animation effects. It only works with hicolor pixels and is a good candidate
  365. ** for optimization.
  366. */
  367. template<class T>
  368. class BlitTransLucent75 : public Blitter {
  369. public:
  370. BlitTransLucent75(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {assert(TranslateTable != NULL);}
  371. virtual void BlitForward(void * dest, void const * source, int length) const
  372. {
  373. for (int index = 0; index < length; index++) {
  374. unsigned char color = *(unsigned char const *)source;
  375. source = ((unsigned char *)source) + 1;
  376. if (color != 0) {
  377. T qsource = (T)(((TranslateTable[color] >> 2) & Mask));
  378. T qdest = (T)(((*(T *)dest) >> 2) & Mask);
  379. *((T *)dest) = (T)(qdest + qdest + qdest + qsource);
  380. }
  381. dest = ((T *)dest) + 1;
  382. }
  383. }
  384. /*
  385. ** The backward moving method will probably never be called in actual practice.
  386. ** Implement in terms of the forward copying method until the need for this
  387. ** version arrises.
  388. */
  389. virtual void BlitBackward(void * dest, void const * source, int length) const {BlitForward(dest, source, length);}
  390. private:
  391. T const * TranslateTable;
  392. T Mask;
  393. };
  394. /*
  395. ** Assembly versions of some of the templated blitter object functions. Borland and
  396. ** Visual C++ support a compatible inline-assembly formats. However, Borland compiler
  397. ** does not allow inline-assembly to be part of an inline function -- go figure.
  398. ** It will still compile, it just generates warning messages.
  399. */
  400. #if defined(_MSC_VER)
  401. inline void BlitTrans<unsigned char>::BlitForward(void * dest, void const * source, int len) const
  402. {
  403. __asm {
  404. mov esi,[source]
  405. mov edi,[dest]
  406. mov ecx,[len]
  407. dec edi
  408. inc ecx
  409. }
  410. again:
  411. __asm {
  412. dec ecx
  413. jz fini
  414. mov al,[esi]
  415. inc edi
  416. inc esi
  417. test al,al
  418. jz again
  419. mov [edi],al
  420. jmp again
  421. }
  422. fini:;
  423. }
  424. inline void BlitTransXlat<unsigned short>::BlitForward(void * dest, void const * source, int len) const
  425. {
  426. unsigned short const * xlator = TranslateTable;
  427. __asm {
  428. mov ebx,[xlator]
  429. mov ecx,[len]
  430. inc ecx
  431. mov edi,[dest]
  432. sub edi,2
  433. mov esi,[source]
  434. xor eax,eax
  435. }
  436. again:
  437. __asm {
  438. dec ecx
  439. jz over
  440. add edi,2
  441. mov al,[esi]
  442. inc esi
  443. or al,al
  444. jz again
  445. mov dx,[ebx+eax*2]
  446. mov [edi],dx
  447. jmp again
  448. }
  449. over:;
  450. }
  451. inline void BlitTransRemapXlat<unsigned short>::BlitForward(void * dest, void const * source, int len) const
  452. {
  453. unsigned short const * translator = TranslateTable;
  454. unsigned char const * remapper = RemapTable;
  455. __asm {
  456. mov ecx,[len]
  457. mov edi,[dest]
  458. sub edi,2
  459. mov esi,[source]
  460. mov ebx,[remapper]
  461. mov edx,[translator]
  462. xor eax,eax
  463. }
  464. /*
  465. ** This block is 11 cycles per pixel, if not transparent, and 5
  466. ** cycles per pixel, if transparent.
  467. */
  468. again:
  469. __asm {
  470. dec ecx
  471. jz over
  472. add edi,2
  473. xor eax,eax
  474. lodsb
  475. or al,al
  476. jz again
  477. mov al,[ebx+eax] // First remap step (8 bit to 8 bit).
  478. mov ax,[edx+eax*2] // Second remap step (8 bit to 16 bit).
  479. mov [edi],ax
  480. jmp again
  481. }
  482. over:;
  483. }
  484. inline void BlitTransZRemapXlat<unsigned short>::BlitForward(void * dest, void const * source, int len) const
  485. {
  486. unsigned short const * translator = TranslateTable;
  487. unsigned char const * remapper = *RemapTable;
  488. __asm {
  489. mov ecx,[len]
  490. mov edi,[dest]
  491. sub edi,2
  492. mov esi,[source]
  493. mov ebx,[remapper]
  494. mov edx,[translator]
  495. xor eax,eax
  496. }
  497. /*
  498. ** This block is 11 cycles per pixel, if not transparent, and 5
  499. ** cycles per pixel, if transparent.
  500. */
  501. again:
  502. __asm {
  503. dec ecx
  504. jz over
  505. add edi,2
  506. xor eax,eax
  507. lodsb
  508. or al,al
  509. jz again
  510. mov al,[ebx+eax] // First remap step (8 bit to 8 bit).
  511. mov ax,[edx+eax*2] // Second remap step (8 bit to 16 bit).
  512. mov [edi],ax
  513. jmp again
  514. }
  515. over:;
  516. }
  517. inline void BlitPlainXlat<unsigned short>::BlitForward(void * dest, void const * source, int len) const
  518. {
  519. unsigned short const * remapper = TranslateTable;
  520. __asm {
  521. mov ebx,[remapper]
  522. mov ecx,[len]
  523. mov esi,[source]
  524. mov edi,[dest]
  525. sub edi,2
  526. }
  527. again:
  528. /*
  529. ** This block processes pixels at 7 clocks per pixel.
  530. */
  531. __asm {
  532. xor eax,eax
  533. add edi,2
  534. mov al,[esi]
  535. inc esi
  536. mov ax,[ebx+eax*2]
  537. mov [edi],ax
  538. dec ecx
  539. jnz again
  540. }
  541. }
  542. #endif
  543. #endif