WRITELBM.CPP 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. ** Command & Conquer Red Alert(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. /* $Header: g:/library/wwlib32/file/rcs/writelbm.cpp 1.1 1994/04/20 14:38:57 scott_bowen Exp $ */
  19. /***************************************************************************
  20. ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
  21. ***************************************************************************
  22. * *
  23. * Project Name : Write LBM File *
  24. * *
  25. * File Name : writelbm.c *
  26. * *
  27. * Programmer : Scott Bowen *
  28. * *
  29. * Start Date : November 18, 1991 *
  30. * *
  31. * Last Update : November 19, 1991 [SB] *
  32. * *
  33. *-------------------------------------------------------------------------*
  34. * Functions: *
  35. * Get_Line -- convert one plane of one row to a packed plane *
  36. * Write_BMHD -- writes out the bit map header (LocalHeader) *
  37. * Write_Body -- writes out compressed data in an LBM file *
  38. * Write_CMAP -- Writes out CMAP (palette) information *
  39. * Write_LBM_File -- Writes out a file in LBM format *
  40. * Write_Row -- compresses and writes a row plane to .lbm file *
  41. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  42. // At the end of this file there is an IFF definition for a .LBM file.
  43. #include "iff.h"
  44. #include "file.h"
  45. #include <wwstd.h>
  46. #include <stdio.h>
  47. #include <string.h>
  48. // A BitMapHeader is stored in a BMHD chunk. This structure MUST be an even size
  49. typedef struct {
  50. unsigned short w, h; // raster width & height in pixels
  51. unsigned short x, y; // position for this image
  52. unsigned char planes; // # source bitplanes
  53. unsigned char masking; // masking technique
  54. unsigned char compression; // compression algoithm
  55. unsigned char pad1; // UNUSED. For consistency, put 0 here.
  56. unsigned short transcolor; // transparent "color number"
  57. unsigned char xaspect, yaspect; // aspect ratio, a rational number x/y
  58. unsigned short pagewidth, pageheight; // source "page" size in pixels
  59. } BitMapHeaderType;
  60. // All values in LocalHeader are always the same except planes. This is set in Write_BMHD
  61. // the short values must be in low-high order for compatibility.
  62. PRIVATE BitMapHeaderType LocalHeader = {
  63. 0x4001, 0xc800, 0, 0, 0, 0, // width, height, x, y, planes, mask
  64. 1, 0, 0xFF00, 5, 6, // compress, pad1, transcolor, xasptect, yaspect
  65. 0x4001, 0xC800 }; // pagewidth, pageheight
  66. // Used to verify that the write of the header was valid
  67. #define BM_HEADER_SIZE (((sizeof(BitMapHeaderType) + 1) & 0xFFFE) + 8L)
  68. /*=========================================================================*/
  69. /* The following PRIVATE functions are in this file: */
  70. /*=========================================================================*/
  71. PRIVATE long Write_BMHD(int lbmhandle, int bitplanes);
  72. PRIVATE long Write_CMAP(int lbmhandle, unsigned char * palette, int bitplanes);
  73. PRIVATE long Write_BODY(int lbmhandle, BufferClass& buff, int bitplanes);
  74. PRIVATE long Write_Row(int lbmhandle, unsigned char *buffer);
  75. /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  76. /***************************************************************************
  77. * WRITE_LBM_FILE -- Writes out a file in LBM format *
  78. * *
  79. * INPUT: int lbmhandle -- lbm file handle already opened by caller *
  80. * BufferClass buff -- buff where MCGA picture is *
  81. * int bitplane -- number of bitplanes to convert to *
  82. * char *palette -- pointer to palette for buff *
  83. * *
  84. * OUTPUT: Returns BOOL -- successfull or not *
  85. * *
  86. * WARNINGS: *
  87. * *
  88. * HISTORY: *
  89. * 11/18/1991 SB : Created. *
  90. *=========================================================================*/
  91. PUBLIC BOOL Write_LBM_File(int lbmhandle, BufferClass& buff, int bitplanes, unsigned char *palette)
  92. {
  93. long filesize;
  94. Seek_File(lbmhandle, 0L, SEEK_SET); // goto beginning of file
  95. Write_File(lbmhandle, "FORM????ILBM", 12L); // First 12 bytes of all .lbm files
  96. // size is unkown so write ????
  97. filesize = 12L; // 4 bytes for "ILBM"
  98. filesize += Write_BMHD(lbmhandle, bitplanes); // write out BMHD (fixed size)
  99. filesize += Write_CMAP(lbmhandle, palette, bitplanes); // write out CMAP
  100. // Write out the body, or compressed picture image. This size will depend
  101. // on the compression, but the value passed back is what the compressor
  102. // assumed was written to file
  103. filesize += Write_BODY(lbmhandle, buff, bitplanes);
  104. // Verify that we were able to write out the file without running out of space
  105. if (Seek_File(lbmhandle, 0L, SEEK_END) != filesize) {
  106. return(FALSE);
  107. }
  108. Seek_File(lbmhandle, 4L, SEEK_SET); // goto beginning of file
  109. filesize = Reverse_Long(filesize - 8L); // - 8 because of "FORM" + WORD (size)
  110. Write_File(lbmhandle, (char *) &filesize, 4L); // patch in filesize
  111. return(TRUE);
  112. }
  113. /***************************************************************************
  114. * WRITE_BMHD -- writes out the bit map header (LocalHeader) *
  115. * *
  116. * INPUT: int lbmhandle -- file handle for lbm file *
  117. * int pitplanes -- number of bitplanes to write out *
  118. * *
  119. * OUTPUT: long number of bytes hopefully written out to .LBM file *
  120. * *
  121. * WARNINGS: *
  122. * *
  123. * HISTORY: *
  124. * 11/19/1991 SB : Created. *
  125. *=========================================================================*/
  126. PRIVATE long Write_BMHD(int lbmhandle, int bitplanes)
  127. {
  128. long size;
  129. Write_File(lbmhandle, "BMHD", 4L); // write out chunk title
  130. size = Reverse_Long(sizeof(LocalHeader)); // write out size of LocalHeader chunk
  131. Write_File(lbmhandle, (char *) &size, 4L);
  132. LocalHeader.planes = bitplanes; // only nonconstant value in LocalHeader
  133. // Make sure size is even. Return 8 = "BMHD" + size of the bitmap header structure
  134. return(Write_File(lbmhandle, (char *) &LocalHeader,
  135. (sizeof(LocalHeader) + 1) & 0xFFFE) + 8L);
  136. }
  137. /***************************************************************************
  138. * WRITE_CMAP -- Writes out CMAP (palette) information *
  139. * *
  140. * *
  141. * INPUT: int lbmhandle -- file handle of lbm file *
  142. * char * palette -- pointer to paletter information *
  143. * int bitplanes -- used to figure out size of palette *
  144. * *
  145. * OUTPUT: long number of bytes that should have been written out to .LBM. *
  146. * *
  147. * WARNINGS: *
  148. * *
  149. * HISTORY: *
  150. * 11/19/1991 SB : Created. *
  151. *=========================================================================*/
  152. PRIVATE long Write_CMAP(int lbmhandle, unsigned char * palette, int bitplanes)
  153. {
  154. int color, r, g, b, colors;
  155. long size;
  156. unsigned char *pal_ptr;
  157. char rgb[3];
  158. Write_File(lbmhandle, "CMAP", 4L); // write out palette info
  159. colors = 1 << bitplanes; // colors = 2 to the bitplanes
  160. size = Reverse_Long(colors * 3L); // size = colors * 3 guns
  161. Write_File(lbmhandle, (char *) &size, 4L);
  162. for (pal_ptr = palette, color = 0; color < colors; color++) { // for each color
  163. if ((r = *pal_ptr++) != 0) { // DPaint changes allows 0 - 100 for gun values
  164. r = (r << 2) | 0x03; // this must be converted to 0 - 256 for LBM
  165. } // so LBM_val = (DP_val * 4) | 3 if DP_val != 0
  166. if ((g = *pal_ptr++) != 0) {
  167. g = (g << 2) | 0x03;
  168. }
  169. if ((b = *pal_ptr++) != 0) {
  170. b = (b << 2) | 0x03;
  171. }
  172. rgb[0] = r; // assign gun values to an array to write out
  173. rgb[1] = g;
  174. rgb[2] = b;
  175. Write_File(lbmhandle, rgb, 3L);
  176. }
  177. // size = colors * 3
  178. return(((colors << 1) + colors) + 8L); // total size of CMAP 8 = "CMAP" + WORD (size)
  179. }
  180. /***************************************************************************
  181. * WRITE_BODY -- writes out compressed data in an LBM file *
  182. * *
  183. * INPUT: int lbmhandle -- file handle of lbm file *
  184. * *
  185. * OUTPUT: long - number of byte written *
  186. * *
  187. * WARNINGS: *
  188. * *
  189. * HISTORY: *
  190. * 11/19/1991 SB : Created. *
  191. *=========================================================================*/
  192. PRIVATE long Write_BODY(int lbmhandle, BufferClass& buff, int bitplanes)
  193. {
  194. long bodysize = 0;
  195. long actualsize;
  196. long size;
  197. int planebit;
  198. int line, plane;
  199. unsigned char buffer[40];
  200. unsigned char *buffptr;
  201. Write_File(lbmhandle, "BODY????", 8L); // BODY chunk ID, ???? reserved for chuncksize
  202. buffptr = (unsigned char *) buff.Get_Buffer(); // point to beginning of buff
  203. for (line = 0; line < 200; line++) {
  204. planebit = 1; // start with bit 1 set
  205. for (plane = 0; plane < bitplanes; plane++) {
  206. Pack_2_Plane(buffer, buffptr, planebit); // convert to planar
  207. bodysize += Write_Row(lbmhandle, buffer); // write to to the BODY in the LBM
  208. planebit <<= 1; // set next bit
  209. }
  210. buffptr += 320; // row size is 320
  211. }
  212. actualsize = bodysize + (bodysize&0x01);
  213. if (actualsize != bodysize) {
  214. Write_File(lbmhandle, buffer, 1); // Padd the block.
  215. }
  216. Seek_File(lbmhandle, -(actualsize + 4L), SEEK_CUR); // Patch in chunksize
  217. size = Reverse_Long(bodysize);
  218. Write_File(lbmhandle, (char *) &size ,4L);
  219. return(actualsize + 8L); // total size of BODY, "BODY????" = 8 bytes
  220. }
  221. /***************************************************************************
  222. * WRITE_ROW -- compresses and writes a row plane to .lbm file *
  223. * *
  224. * INPUT: int lbmhandle -- lbm file handle *
  225. * unsigned char *buffer -- pointer to buffer to be written out *
  226. * *
  227. * OUTPUT: long size of chunk that should have been written out *
  228. * *
  229. * WARNINGS: *
  230. * *
  231. * HISTORY: *
  232. * 11/19/1991 SB : Created. *
  233. *=========================================================================*/
  234. // this algorithm was taken from WILBM.c written by EA that was in the
  235. // 1985 yearbook. This is the compression method that DP.EXE uses.
  236. // Change only if DP.EXE changes.
  237. PRIVATE long Write_Row(int lbmhandle, unsigned char *buffer)
  238. {
  239. int i;
  240. int chunksize = 0;
  241. int dataLength = 40; // 320 rows / 8 ( 1 plane per row)
  242. unsigned char repCode, current, curr_plus_2;
  243. unsigned char *buffptr;
  244. while (dataLength) {
  245. // If at least 2 more bytes and they are equal, then replicate
  246. if ((dataLength >= 2) && (buffer[0] == buffer[1])) {
  247. buffptr = buffer;
  248. for (i = 0; (i <= 128) && (i < (dataLength - 1)); i++) {
  249. if (*buffptr != buffptr[1]) {
  250. break;
  251. }
  252. buffptr++;
  253. }
  254. i++;
  255. repCode = -i + 1;
  256. Write_File(lbmhandle, &repCode, 1L); // Write count as -count+1
  257. Write_File(lbmhandle, buffer, 1L); // Write byte to replicate
  258. buffer += i;
  259. dataLength -= i;
  260. chunksize += 2;
  261. }
  262. else { // Copy literally till 3 byte run or two 2 byte runs found
  263. for (i = 0; (i <= 128) && (i < dataLength); i++) {
  264. current = buffer[i];
  265. curr_plus_2 = buffer[i + 2];
  266. if (i == dataLength - 1)
  267. continue;
  268. if (current != buffer[i + 1])
  269. continue;
  270. if (i == dataLength - 2)
  271. continue;
  272. if (current == curr_plus_2)
  273. break;
  274. if (i == dataLength - 3)
  275. continue;
  276. if (curr_plus_2 == buffer[i + 3])
  277. break;
  278. }
  279. repCode = i - 1;
  280. Write_File(lbmhandle, &repCode, 1L); // Write count as count-1
  281. Write_File(lbmhandle, buffer, (long) i); // Write 'count' bytes
  282. buffer += i;
  283. dataLength -= i;
  284. chunksize += i + 1;
  285. }
  286. } // end while
  287. return(chunksize);
  288. }
  289. #if(FALSE)
  290. This is a definition of a DPII .LBM file.
  291. Below this definition are differences in DPIIe .LMB files.
  292. Created by : Scott K. Bowen Nov 18, 1991
  293. Start with .LBM to read definition :
  294. .LBM -> "FORM" + FILESIZE + "ILMB" + CHUNKS
  295. BITPLANES -> (word) // number of bit planes used
  296. BLUE -> (byte) // blue color gun value
  297. BMHD -> "BMHD" + CHUNKSIZE + CONTEXT
  298. BODY ->
  299. CHUNKS -> BMHD | BODY | CMAP | DPPV | CRNG | ????
  300. CHUNKSIZE -> (long) // size of chunk not including header or size.
  301. CMAP -> "CMAP" + CHUNKSIZE + PALETTE_INFO
  302. COMPRESS_METHOD -> (byte) // compression method used
  303. CONTEXT -> WIDTH + HEIGHT + POSX + POSY + #_BITPLANES + MASKING +
  304. COMPRESS_METHOD + PAD + TRANS_COL + XASPECT + YASPECT +
  305. PAGEWIDTH + PAGEHEIGHT
  306. CRNG -> // we do not use
  307. DPPV -> // we do not use
  308. FILESIZE -> (long) //size of file minus (sizeof(FORM) + sizeof(FILESIZE)
  309. GREEN -> (byte) // green color gun value
  310. HEIGHT -> (word) // of picture
  311. MASKING -> (byte) // masking type ?
  312. NUM_COLORS -> //number of colors used depending on format
  313. PAGE_WIDTH -> (word) // width of page
  314. PAGE_HEIGHT -> (word) // height of page
  315. PALETTE_INFO-> (RED+GREEN+BLUE) @ NUM_COLORS
  316. PAD -> (byte) // not used. used as a padding
  317. POSX -> (word) // staring position
  318. POSY -> (word) // staring position
  319. RED -> (byte) // red color gun value
  320. TRANS_COL -> (word) // transparrent color
  321. WIDTH -> (word) // of picture
  322. XASPECT -> (byte) // x aspect ratio
  323. YASPECT -> (byte) // y aspect ratio
  324. ???? -> // other possibilities
  325. Differences in DPII enhance version
  326. .LBM -> "FORM" + FILESIZE + "PBM " + CHUNKS
  327. DPPV -> DPPS // uses dpps instead of dppv
  328. CHUNKS -> + TINY // add these to old definition
  329. #endif
  330.