rlerle.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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/RLERLE.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 RLERLE_H
  36. #define RLERLE_H
  37. /*
  38. ** This class holds the RLE enabled blitter object definitions. There is a blitter object
  39. ** type for every kind of pixel operation required of RLE shapes. These are defined as
  40. ** templates to support the different destination pixel formats.
  41. */
  42. #include "blitter.h"
  43. #include <assert.h>
  44. #include <string.h>
  45. /*
  46. ** This is a helper function that will skip N pixels in the RLE compressed source. This is
  47. ** necessary for clipping purposes. The return value represents the number of transparent
  48. ** pixels before actual pixel data starts when the RLE uncompression is resumed.
  49. */
  50. inline int Skip_Leading_Pixels(unsigned char const * & sptr, int skipper)
  51. {
  52. /*
  53. ** Skip leading pixels as requested.
  54. */
  55. while (skipper > 0) {
  56. if (*sptr++ == '\0') {
  57. skipper -= *sptr++;
  58. } else {
  59. skipper--;
  60. }
  61. }
  62. /*
  63. ** Return with then number of leading transparent pixels in the pixel stream
  64. ** after the end of the skip process. This value must be tracked since the pixel
  65. ** skip process may have ended in the middle of a transparent pixel run.
  66. */
  67. return(-skipper);
  68. }
  69. /*
  70. ** Blits with transparency checking and translation to destination pixel format.
  71. */
  72. template<class T>
  73. class RLEBlitTransXlat : public RLEBlitter {
  74. public:
  75. RLEBlitTransXlat(T const * translator) : TranslateTable(translator) {assert(TranslateTable != NULL);}
  76. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  77. {
  78. unsigned char const * sptr = (unsigned char const *)source;
  79. T * dptr = (T *)dest;
  80. /*
  81. ** Skip any leading pixels as requested.
  82. */
  83. if (leadskip > 0) {
  84. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  85. dptr += transcount;
  86. length -= transcount;
  87. }
  88. /*
  89. ** Uncompress and store the pixel stream until the length has been
  90. ** exhausted.
  91. */
  92. while (length > 0) {
  93. unsigned char value = *sptr++;
  94. if (value == '\0') {
  95. value = *sptr++;
  96. length -= value;
  97. dptr += value;
  98. } else {
  99. *dptr++ = TranslateTable[value];
  100. length -= 1;
  101. }
  102. }
  103. }
  104. private:
  105. T const * TranslateTable;
  106. };
  107. /*
  108. ** This blits RLE compressed pixels by first remapping through a 256 byte table and then
  109. ** translating the pixel to screen format.
  110. */
  111. template<class T>
  112. class RLEBlitTransRemapXlat : public RLEBlitter {
  113. public:
  114. RLEBlitTransRemapXlat(unsigned char const * remapper, T const * translator) : RemapTable(remapper), TranslateTable(translator) {assert(TranslateTable != NULL);assert(RemapTable != NULL);}
  115. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  116. {
  117. unsigned char const * sptr = (unsigned char const *)source;
  118. T * dptr = (T *)dest;
  119. /*
  120. ** Skip any leading pixels as requested.
  121. */
  122. if (leadskip > 0) {
  123. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  124. dptr += transcount;
  125. length -= transcount;
  126. }
  127. /*
  128. ** Uncompress and store the pixel stream until the length has been
  129. ** exhausted.
  130. */
  131. while (length > 0) {
  132. unsigned char value = *sptr++;
  133. if (value == '\0') {
  134. value = *sptr++;
  135. length -= value;
  136. dptr += value;
  137. } else {
  138. *dptr++ = TranslateTable[RemapTable[value]];
  139. length -= 1;
  140. }
  141. }
  142. }
  143. private:
  144. unsigned char const * RemapTable;
  145. T const * TranslateTable;
  146. };
  147. /*
  148. ** This blits RLE compressed pixels by first remapping through a 256 byte table and then
  149. ** translating the pixel to screen format. The remapping table is doubly indirected so that
  150. ** it is possible to change the remapping table pointer without creating a separate blitter
  151. ** object.
  152. */
  153. template<class T>
  154. class RLEBlitTransZRemapXlat : public RLEBlitter {
  155. public:
  156. RLEBlitTransZRemapXlat(unsigned char const * const * remapper, T const * translator) : RemapTable(remapper), TranslateTable(translator) {assert(TranslateTable != NULL);assert(RemapTable != NULL);}
  157. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  158. {
  159. unsigned char const * sptr = (unsigned char const *)source;
  160. unsigned char const * remapper = *RemapTable;
  161. T * dptr = (T *)dest;
  162. /*
  163. ** Skip any leading pixels as requested.
  164. */
  165. if (leadskip > 0) {
  166. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  167. dptr += transcount;
  168. length -= transcount;
  169. }
  170. /*
  171. ** Uncompress and store the pixel stream until the length has been
  172. ** exhausted.
  173. */
  174. while (length > 0) {
  175. unsigned char value = *sptr++;
  176. if (value == '\0') {
  177. value = *sptr++;
  178. length -= value;
  179. dptr += value;
  180. } else {
  181. *dptr++ = TranslateTable[remapper[value]];
  182. length -= 1;
  183. }
  184. }
  185. }
  186. private:
  187. unsigned char const * const * RemapTable;
  188. T const * TranslateTable;
  189. };
  190. /*
  191. ** This will remap the destination pixels but under the control of the source pixels.
  192. ** Where the source pixel is not transparent, the dest pixel is remapped. This algorithm
  193. ** really only applies to lowcolor display.
  194. */
  195. template<class T>
  196. class RLEBlitTransRemapDest : public RLEBlitter {
  197. public:
  198. RLEBlitTransRemapDest(T const * remap) : RemapTable(remap) {}
  199. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  200. {
  201. unsigned char const * sptr = (unsigned char const *)source;
  202. T * dptr = (T *)dest;
  203. /*
  204. ** Skip any leading pixels as requested.
  205. */
  206. if (leadskip > 0) {
  207. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  208. dptr += transcount;
  209. length -= transcount;
  210. }
  211. /*
  212. ** Uncompress and store the pixel stream until the length has been
  213. ** exhausted.
  214. */
  215. while (length > 0) {
  216. unsigned char value = *sptr++;
  217. if (value == '\0') {
  218. value = *sptr++;
  219. length -= value;
  220. dptr += value;
  221. } else {
  222. *dptr = RemapTable[*dptr];
  223. length -= 1;
  224. dptr++;
  225. }
  226. }
  227. }
  228. private:
  229. T const * RemapTable;
  230. };
  231. /*
  232. ** Algorithmic darkening of hicolor pixels controlled by the source pixels. The source
  233. ** pixels are examined only to determine if the destination pixel should be darkened.
  234. ** If the source pixel is transparent, then the dest pixel is skipped. The darkening
  235. ** algorithm works only for hicolor pixels.
  236. */
  237. template<class T>
  238. class RLEBlitTransDarken : public RLEBlitter {
  239. public:
  240. RLEBlitTransDarken(T mask) : Mask(mask) {}
  241. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  242. {
  243. unsigned char const * sptr = (unsigned char const *)source;
  244. T * dptr = (T *)dest;
  245. /*
  246. ** Skip any leading pixels as requested.
  247. */
  248. if (leadskip > 0) {
  249. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  250. dptr += transcount;
  251. length -= transcount;
  252. }
  253. /*
  254. ** Uncompress and store the pixel stream until the length has been
  255. ** exhausted.
  256. */
  257. while (length > 0) {
  258. unsigned char value = *sptr++;
  259. if (value == '\0') {
  260. value = *sptr++;
  261. length -= value;
  262. dptr += value;
  263. } else {
  264. *dptr = (T)((*dptr >> 1) & Mask);
  265. length -= 1;
  266. dptr++;
  267. }
  268. }
  269. }
  270. private:
  271. T Mask;
  272. };
  273. /*
  274. ** This blitter performs 50% translucency as it draws. It is commonly used for animation
  275. ** effects and other stealth like images. It only works with hicolor pixels but is a good
  276. ** candidate for optimization.
  277. */
  278. template<class T>
  279. class RLEBlitTransLucent50 : public RLEBlitter {
  280. public:
  281. RLEBlitTransLucent50(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {}
  282. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  283. {
  284. unsigned char const * sptr = (unsigned char const *)source;
  285. T * dptr = (T *)dest;
  286. /*
  287. ** Skip any leading pixels as requested.
  288. */
  289. if (leadskip > 0) {
  290. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  291. dptr += transcount;
  292. length -= transcount;
  293. }
  294. /*
  295. ** Uncompress and store the pixel stream until the length has been
  296. ** exhausted.
  297. */
  298. while (length > 0) {
  299. unsigned char value = *sptr++;
  300. if (value == '\0') {
  301. value = *sptr++;
  302. length -= value;
  303. dptr += value;
  304. } else {
  305. *dptr = (T)((((*dptr) >> 1) & Mask) + ((TranslateTable[value] >> 1) & Mask));
  306. length -= 1;
  307. dptr++;
  308. }
  309. }
  310. }
  311. private:
  312. T const * TranslateTable;
  313. T Mask;
  314. };
  315. /*
  316. ** This blitter performs 25% translucency as it draws. This effect is less than spectacular,
  317. ** but there are some uses for it. It only works with hicolor pixels.
  318. */
  319. template<class T>
  320. class RLEBlitTransLucent25 : public RLEBlitter {
  321. public:
  322. RLEBlitTransLucent25(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {}
  323. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  324. {
  325. unsigned char const * sptr = (unsigned char const *)source;
  326. T * dptr = (T *)dest;
  327. /*
  328. ** Skip any leading pixels as requested.
  329. */
  330. if (leadskip > 0) {
  331. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  332. dptr += transcount;
  333. length -= transcount;
  334. }
  335. /*
  336. ** Uncompress and store the pixel stream until the length has been
  337. ** exhausted.
  338. */
  339. while (length > 0) {
  340. unsigned char value = *sptr++;
  341. if (value == '\0') {
  342. value = *sptr++;
  343. length -= value;
  344. dptr += value;
  345. } else {
  346. T qsource = (T)(((TranslateTable[value] >> 2) & Mask));
  347. T qdest = (T)(((*dptr) >> 2) & Mask);
  348. *dptr++ = (T)(qdest + qsource + qsource + qsource);
  349. length -= 1;
  350. }
  351. }
  352. }
  353. private:
  354. T const * TranslateTable;
  355. T Mask;
  356. };
  357. /*
  358. ** This blitter performs 75% translucency as it draws. This is quite useful for explosions and
  359. ** other gas animation effects. It only works with hicolor pixels and is a good candidate
  360. ** for optimization.
  361. */
  362. template<class T>
  363. class RLEBlitTransLucent75 : public RLEBlitter {
  364. public:
  365. RLEBlitTransLucent75(T const * translator, T mask) : TranslateTable(translator), Mask(mask) {}
  366. virtual void Blit(void * dest, void const * source, int length, int leadskip=0) const
  367. {
  368. unsigned char const * sptr = (unsigned char const *)source;
  369. T * dptr = (T *)dest;
  370. /*
  371. ** Skip any leading pixels as requested.
  372. */
  373. if (leadskip > 0) {
  374. int transcount = Skip_Leading_Pixels(sptr, leadskip);
  375. dptr += transcount;
  376. length -= transcount;
  377. }
  378. /*
  379. ** Uncompress and store the pixel stream until the length has been
  380. ** exhausted.
  381. */
  382. while (length > 0) {
  383. unsigned char value = *sptr++;
  384. if (value == '\0') {
  385. value = *sptr++;
  386. length -= value;
  387. dptr += value;
  388. } else {
  389. T qsource = (T)(((TranslateTable[value] >> 2) & Mask));
  390. T qdest = (T)(((*dptr) >> 2) & Mask);
  391. *dptr++ = (T)(qdest + qdest + qdest + qsource);
  392. length -= 1;
  393. }
  394. }
  395. }
  396. private:
  397. T const * TranslateTable;
  398. T Mask;
  399. };
  400. #if defined(_MSC_VER)
  401. void RLEBlitTransZRemapXlat<unsigned short>::Blit(void * dest, void const * source, int len, int leadskip) const
  402. {
  403. unsigned char const * remapper = *RemapTable;
  404. unsigned short const * transtable = TranslateTable;
  405. /*
  406. ** Set up the working registers for the blit operation.
  407. */
  408. __asm {
  409. mov ecx,[len]
  410. mov edi,[dest]
  411. mov esi,[source]
  412. mov ebx,[remapper]
  413. mov edx,[leadskip]
  414. xor eax,eax
  415. }
  416. /*
  417. ** Skip leading pixels by analyzing the RLE data until the entire
  418. ** requested skip pixel count has been processed. This could result in
  419. ** unprocessed transparent pixels if it ended up in the middle of
  420. ** a transparent pixel run. This is handled in the next block.
  421. */
  422. moreskip:
  423. __asm {
  424. test edx,edx
  425. jle nomoreskip
  426. dec edx
  427. lodsb
  428. test al,al
  429. jnz moreskip
  430. lodsb
  431. sub edx,eax
  432. inc edx
  433. jmp moreskip
  434. }
  435. nomoreskip:
  436. /*
  437. ** Handle any left over transparent pixels that would be part of
  438. ** a transparent pixel run that occurs at the end of the leading
  439. ** pixel skip process.
  440. */
  441. __asm {
  442. neg edx
  443. sub ecx,edx // Account for any left over transparent pixels
  444. lea edi,[edi+edx*2]
  445. mov edx,[transtable]
  446. }
  447. /*
  448. ** Output the pixel data to the destination.
  449. */
  450. moredata:
  451. __asm {
  452. xor eax,eax
  453. or ecx,ecx
  454. jle fini
  455. lodsb
  456. test al,al
  457. jz transparent
  458. mov al,[ebx+eax]
  459. mov ax,[edx+eax*2]
  460. dec ecx
  461. stosw
  462. jmp moredata
  463. }
  464. /*
  465. ** A transparent pixel run just causes the destination pointer
  466. ** and length count to be adjusted by the length of the run.
  467. */
  468. transparent:
  469. __asm {
  470. lodsb
  471. lea edi,[edi+eax*2]
  472. sub ecx,eax
  473. jmp moredata
  474. }
  475. fini:;
  476. }
  477. void RLEBlitTransRemapXlat<unsigned short>::Blit(void * dest, void const * source, int len, int leadskip) const
  478. {
  479. unsigned char const * remapper = RemapTable;
  480. unsigned short const * transtable = TranslateTable;
  481. /*
  482. ** Set up the working registers for the blit operation.
  483. */
  484. __asm {
  485. mov ecx,[len]
  486. mov edi,[dest]
  487. mov esi,[source]
  488. mov ebx,[remapper]
  489. mov edx,[leadskip]
  490. xor eax,eax
  491. }
  492. /*
  493. ** Skip leading pixels by analyzing the RLE data until the entire
  494. ** requested skip pixel count has been processed. This could result in
  495. ** unprocessed transparent pixels if it ended up in the middle of
  496. ** a transparent pixel run. This is handled in the next block.
  497. */
  498. moreskip:
  499. __asm {
  500. test edx,edx
  501. jle nomoreskip
  502. dec edx
  503. lodsb
  504. test al,al
  505. jnz moreskip
  506. lodsb
  507. sub edx,eax
  508. inc edx
  509. jmp moreskip
  510. }
  511. nomoreskip:
  512. /*
  513. ** Handle any left over transparent pixels that would be part of
  514. ** a transparent pixel run that occurs at the end of the leading
  515. ** pixel skip process.
  516. */
  517. __asm {
  518. neg edx
  519. sub ecx,edx // Account for any left over transparent pixels
  520. lea edi,[edi+edx*2]
  521. mov edx,[transtable]
  522. }
  523. /*
  524. ** Output the pixel data to the destination.
  525. */
  526. moredata:
  527. __asm {
  528. xor eax,eax
  529. or ecx,ecx
  530. jle fini
  531. lodsb
  532. test al,al
  533. jz transparent
  534. mov al,[ebx+eax]
  535. mov ax,[edx+eax*2]
  536. dec ecx
  537. stosw
  538. jmp moredata
  539. }
  540. /*
  541. ** A transparent pixel run just causes the destination pointer
  542. ** and length count to be adjusted by the length of the run.
  543. */
  544. transparent:
  545. __asm {
  546. lodsb
  547. lea edi,[edi+eax*2]
  548. sub ecx,eax
  549. jmp moredata
  550. }
  551. fini:;
  552. }
  553. void RLEBlitTransXlat<unsigned short>::Blit(void * dest, void const * source, int len, int leadskip) const
  554. {
  555. unsigned short const * transtable = TranslateTable;
  556. /*
  557. ** Set up the working registers for the blit operation.
  558. */
  559. __asm {
  560. mov ecx,[len]
  561. mov edi,[dest]
  562. mov esi,[source]
  563. mov ebx,[transtable]
  564. mov edx,[leadskip]
  565. xor eax,eax
  566. }
  567. /*
  568. ** Skip leading pixels by analyzing the RLE data until the entire
  569. ** requested skip pixel count has been processed. This could result in
  570. ** unprocessed transparent pixels if it ended up in the middle of
  571. ** a transparent pixel run. This is handled in the next block.
  572. */
  573. moreskip:
  574. __asm {
  575. test edx,edx
  576. jle nomoreskip
  577. dec edx
  578. lodsb
  579. test al,al
  580. jnz moreskip
  581. lodsb
  582. sub edx,eax
  583. inc edx
  584. jmp moreskip
  585. }
  586. nomoreskip:
  587. /*
  588. ** Handle any left over transparent pixels that would be part of
  589. ** a transparent pixel run that occurs at the end of the leading
  590. ** pixel skip process.
  591. */
  592. __asm {
  593. neg edx
  594. sub ecx,edx // Account for any left over transparent pixels
  595. lea edi,[edi+edx*2]
  596. }
  597. /*
  598. ** Output the pixel data to the destination.
  599. */
  600. moredata:
  601. __asm {
  602. xor eax,eax
  603. or ecx,ecx
  604. jle fini
  605. lodsb
  606. test al,al
  607. jz transparent
  608. mov ax,[ebx+eax*2]
  609. dec ecx
  610. stosw
  611. jmp moredata
  612. }
  613. /*
  614. ** A transparent pixel run just causes the destination pointer
  615. ** and length count to be adjusted by the length of the run.
  616. */
  617. transparent:
  618. __asm {
  619. lodsb
  620. lea edi,[edi+eax*2]
  621. sub ecx,eax
  622. jmp moredata
  623. }
  624. fini:;
  625. }
  626. #endif
  627. #endif