Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

741 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // lbmlib.c
  9. #include <WINDOWS.H>
  10. #include <STDIO.H>
  11. #include "lbmlib.h"
  12. #include "goldsrc_standin.h"
  13. /*
  14. ============================================================================
  15. LBM STUFF
  16. ============================================================================
  17. */
  18. #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
  19. #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
  20. #define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
  21. #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
  22. #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
  23. #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
  24. bmhd_t bmhd;
  25. int Align (int l)
  26. {
  27. if (l&1)
  28. return l+1;
  29. return l;
  30. }
  31. /*
  32. ================
  33. =
  34. = LBMRLEdecompress
  35. =
  36. = Source must be evenly aligned!
  37. =
  38. ================
  39. */
  40. byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
  41. {
  42. int count;
  43. byte b,rept;
  44. count = 0;
  45. do
  46. {
  47. rept = *source++;
  48. if (rept > 0x80)
  49. {
  50. rept = (rept^0xff)+2;
  51. b = *source++;
  52. memset(unpacked,b,rept);
  53. unpacked += rept;
  54. }
  55. else if (rept < 0x80)
  56. {
  57. rept++;
  58. memcpy(unpacked,source,rept);
  59. unpacked += rept;
  60. source += rept;
  61. }
  62. else
  63. rept = 0; // rept of 0x80 is NOP
  64. count += rept;
  65. } while (count<bpwidth);
  66. if (count>bpwidth)
  67. Error ("Decompression exceeded width!\n");
  68. return source;
  69. }
  70. #define BPLANESIZE 128
  71. byte bitplanes[9][BPLANESIZE]; // max size 1024 by 9 bit planes
  72. /*
  73. =================
  74. =
  75. = MungeBitPlanes8
  76. =
  77. = This destroys the bit plane data!
  78. =
  79. =================
  80. */
  81. void MungeBitPlanes8 (int width, byte *dest)
  82. {
  83. *dest=width; // shut up the compiler warning
  84. Error ("MungeBitPlanes8 not rewritten!");
  85. #if 0
  86. asm les di,[dest]
  87. asm mov si,-1
  88. asm mov cx,[width]
  89. mungebyte:
  90. asm inc si
  91. asm mov dx,8
  92. mungebit:
  93. asm shl [BYTE PTR bitplanes + BPLANESIZE*7 +si],1
  94. asm rcl al,1
  95. asm shl [BYTE PTR bitplanes + BPLANESIZE*6 +si],1
  96. asm rcl al,1
  97. asm shl [BYTE PTR bitplanes + BPLANESIZE*5 +si],1
  98. asm rcl al,1
  99. asm shl [BYTE PTR bitplanes + BPLANESIZE*4 +si],1
  100. asm rcl al,1
  101. asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
  102. asm rcl al,1
  103. asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
  104. asm rcl al,1
  105. asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
  106. asm rcl al,1
  107. asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
  108. asm rcl al,1
  109. asm stosb
  110. asm dec cx
  111. asm jz done
  112. asm dec dx
  113. asm jnz mungebit
  114. asm jmp mungebyte
  115. done:
  116. #endif
  117. }
  118. void MungeBitPlanes4 (int width, byte *dest)
  119. {
  120. *dest=width; // shut up the compiler warning
  121. Error ("MungeBitPlanes4 not rewritten!");
  122. #if 0
  123. asm les di,[dest]
  124. asm mov si,-1
  125. asm mov cx,[width]
  126. mungebyte:
  127. asm inc si
  128. asm mov dx,8
  129. mungebit:
  130. asm xor al,al
  131. asm shl [BYTE PTR bitplanes + BPLANESIZE*3 +si],1
  132. asm rcl al,1
  133. asm shl [BYTE PTR bitplanes + BPLANESIZE*2 +si],1
  134. asm rcl al,1
  135. asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
  136. asm rcl al,1
  137. asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
  138. asm rcl al,1
  139. asm stosb
  140. asm dec cx
  141. asm jz done
  142. asm dec dx
  143. asm jnz mungebit
  144. asm jmp mungebyte
  145. done:
  146. #endif
  147. }
  148. void MungeBitPlanes2 (int width, byte *dest)
  149. {
  150. *dest=width; // shut up the compiler warning
  151. Error ("MungeBitPlanes2 not rewritten!");
  152. #if 0
  153. asm les di,[dest]
  154. asm mov si,-1
  155. asm mov cx,[width]
  156. mungebyte:
  157. asm inc si
  158. asm mov dx,8
  159. mungebit:
  160. asm xor al,al
  161. asm shl [BYTE PTR bitplanes + BPLANESIZE*1 +si],1
  162. asm rcl al,1
  163. asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
  164. asm rcl al,1
  165. asm stosb
  166. asm dec cx
  167. asm jz done
  168. asm dec dx
  169. asm jnz mungebit
  170. asm jmp mungebyte
  171. done:
  172. #endif
  173. }
  174. void MungeBitPlanes1 (int width, byte *dest)
  175. {
  176. *dest=width; // shut up the compiler warning
  177. Error ("MungeBitPlanes1 not rewritten!");
  178. #if 0
  179. asm les di,[dest]
  180. asm mov si,-1
  181. asm mov cx,[width]
  182. mungebyte:
  183. asm inc si
  184. asm mov dx,8
  185. mungebit:
  186. asm xor al,al
  187. asm shl [BYTE PTR bitplanes + BPLANESIZE*0 +si],1
  188. asm rcl al,1
  189. asm stosb
  190. asm dec cx
  191. asm jz done
  192. asm dec dx
  193. asm jnz mungebit
  194. asm jmp mungebyte
  195. done:
  196. #endif
  197. }
  198. int LoadBMP (const char* szFile, BYTE** ppbBits, BYTE** ppbPalette)
  199. {
  200. int i, rc = 0;
  201. FILE *pfile = NULL;
  202. BITMAPFILEHEADER bmfh;
  203. BITMAPINFOHEADER bmih;
  204. RGBQUAD rgrgbPalette[256];
  205. ULONG cbBmpBits;
  206. BYTE* pbBmpBits;
  207. byte *pb, *pbPal = NULL;
  208. ULONG cbPalBytes;
  209. ULONG biTrueWidth;
  210. // Bogus parameter check
  211. if (!(ppbPalette != NULL && ppbBits != NULL))
  212. { fprintf(stderr, "invalid BMP file\n"); rc = -1000; goto GetOut; }
  213. // File exists?
  214. if ((pfile = fopen(szFile, "rb")) == NULL)
  215. { fprintf(stderr, "unable to open BMP file\n"); rc = -1; goto GetOut; }
  216. // Read file header
  217. if (fread(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1)
  218. { rc = -2; goto GetOut; }
  219. // Bogus file header check
  220. if (!(bmfh.bfReserved1 == 0 && bmfh.bfReserved2 == 0))
  221. { rc = -2000; goto GetOut; }
  222. // Read info header
  223. if (fread(&bmih, sizeof bmih, 1/*count*/, pfile) != 1)
  224. { rc = -3; goto GetOut; }
  225. // Bogus info header check
  226. if (!(bmih.biSize == sizeof bmih && bmih.biPlanes == 1))
  227. { fprintf(stderr, "invalid BMP file header\n"); rc = -3000; goto GetOut; }
  228. // Bogus bit depth? Only 8-bit supported.
  229. if (bmih.biBitCount != 8)
  230. { fprintf(stderr, "BMP file not 8 bit\n"); rc = -4; goto GetOut; }
  231. // Bogus compression? Only non-compressed supported.
  232. if (bmih.biCompression != BI_RGB)
  233. { fprintf(stderr, "invalid BMP compression type\n"); rc = -5; goto GetOut; }
  234. // Figure out how many entires are actually in the table
  235. if (bmih.biClrUsed == 0)
  236. {
  237. bmih.biClrUsed = 256;
  238. cbPalBytes = (1 << bmih.biBitCount) * sizeof( RGBQUAD );
  239. }
  240. else
  241. {
  242. cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
  243. }
  244. // Read palette (bmih.biClrUsed entries)
  245. if (fread(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1)
  246. { rc = -6; goto GetOut; }
  247. // convert to a packed 768 byte palette
  248. pbPal = (unsigned char*)malloc(768);
  249. if (pbPal == NULL)
  250. { rc = -7; goto GetOut; }
  251. pb = pbPal;
  252. // Copy over used entries
  253. for (i = 0; i < (int)bmih.biClrUsed; i++)
  254. {
  255. *pb++ = rgrgbPalette[i].rgbRed;
  256. *pb++ = rgrgbPalette[i].rgbGreen;
  257. *pb++ = rgrgbPalette[i].rgbBlue;
  258. }
  259. // Fill in unused entires will 0,0,0
  260. for (i = bmih.biClrUsed; i < 256; i++)
  261. {
  262. *pb++ = 0;
  263. *pb++ = 0;
  264. *pb++ = 0;
  265. }
  266. // Read bitmap bits (remainder of file)
  267. cbBmpBits = bmfh.bfSize - ftell(pfile);
  268. pb = (unsigned char*)malloc(cbBmpBits);
  269. if (fread(pb, cbBmpBits, 1/*count*/, pfile) != 1)
  270. { rc = -7; goto GetOut; }
  271. pbBmpBits = (unsigned char*)malloc(cbBmpBits);
  272. // data is actually stored with the width being rounded up to a multiple of 4
  273. biTrueWidth = (bmih.biWidth + 3) & ~3;
  274. // reverse the order of the data.
  275. pb += (bmih.biHeight - 1) * biTrueWidth;
  276. for(i = 0; i < bmih.biHeight; i++)
  277. {
  278. memmove(&pbBmpBits[biTrueWidth * i], pb, biTrueWidth);
  279. pb -= biTrueWidth;
  280. }
  281. pb += biTrueWidth;
  282. free(pb);
  283. bmhd.w = (WORD)bmih.biWidth;
  284. bmhd.h = (WORD)bmih.biHeight;
  285. // Set output parameters
  286. *ppbPalette = pbPal;
  287. *ppbBits = pbBmpBits;
  288. GetOut:
  289. if (pfile)
  290. fclose(pfile);
  291. return rc;
  292. }
  293. int WriteBMPfile (char *szFile, byte *pbBits, int width, int height, byte *pbPalette)
  294. {
  295. int i, rc = 0;
  296. FILE *pfile = NULL;
  297. BITMAPFILEHEADER bmfh;
  298. BITMAPINFOHEADER bmih;
  299. RGBQUAD rgrgbPalette[256];
  300. ULONG cbBmpBits;
  301. BYTE* pbBmpBits;
  302. byte *pb, *pbPal = NULL;
  303. ULONG cbPalBytes;
  304. ULONG biTrueWidth;
  305. // Bogus parameter check
  306. if (!(pbPalette != NULL && pbBits != NULL))
  307. { rc = -1000; goto GetOut; }
  308. // File exists?
  309. if ((pfile = fopen(szFile, "wb")) == NULL)
  310. { rc = -1; goto GetOut; }
  311. biTrueWidth = ((width + 3) & ~3);
  312. cbBmpBits = biTrueWidth * height;
  313. cbPalBytes = 256 * sizeof( RGBQUAD );
  314. // Bogus file header check
  315. bmfh.bfType = MAKEWORD( 'B', 'M' );
  316. bmfh.bfSize = sizeof bmfh + sizeof bmih + cbBmpBits + cbPalBytes;
  317. bmfh.bfReserved1 = 0;
  318. bmfh.bfReserved2 = 0;
  319. bmfh.bfOffBits = sizeof bmfh + sizeof bmih + cbPalBytes;
  320. // Write file header
  321. if (fwrite(&bmfh, sizeof bmfh, 1/*count*/, pfile) != 1)
  322. { rc = -2; goto GetOut; }
  323. // Size of structure
  324. bmih.biSize = sizeof bmih;
  325. // Width
  326. bmih.biWidth = biTrueWidth;
  327. // Height
  328. bmih.biHeight = height;
  329. // Only 1 plane
  330. bmih.biPlanes = 1;
  331. // Only 8-bit supported.
  332. bmih.biBitCount = 8;
  333. // Only non-compressed supported.
  334. bmih.biCompression = BI_RGB;
  335. bmih.biSizeImage = 0;
  336. // huh?
  337. bmih.biXPelsPerMeter = 0;
  338. bmih.biYPelsPerMeter = 0;
  339. // Always full palette
  340. bmih.biClrUsed = 256;
  341. bmih.biClrImportant = 0;
  342. // Write info header
  343. if (fwrite(&bmih, sizeof bmih, 1/*count*/, pfile) != 1)
  344. { rc = -3; goto GetOut; }
  345. // convert to expanded palette
  346. pb = pbPalette;
  347. // Copy over used entries
  348. for (i = 0; i < (int)bmih.biClrUsed; i++)
  349. {
  350. rgrgbPalette[i].rgbRed = *pb++;
  351. rgrgbPalette[i].rgbGreen = *pb++;
  352. rgrgbPalette[i].rgbBlue = *pb++;
  353. rgrgbPalette[i].rgbReserved = 0;
  354. }
  355. // Write palette (bmih.biClrUsed entries)
  356. cbPalBytes = bmih.biClrUsed * sizeof( RGBQUAD );
  357. if (fwrite(rgrgbPalette, cbPalBytes, 1/*count*/, pfile) != 1)
  358. { rc = -6; goto GetOut; }
  359. pbBmpBits = (unsigned char*)malloc(cbBmpBits);
  360. pb = pbBits;
  361. // reverse the order of the data.
  362. pb += (height - 1) * width;
  363. for(i = 0; i < bmih.biHeight; i++)
  364. {
  365. memmove(&pbBmpBits[biTrueWidth * i], pb, width);
  366. pb -= width;
  367. }
  368. // Write bitmap bits (remainder of file)
  369. if (fwrite(pbBmpBits, cbBmpBits, 1/*count*/, pfile) != 1)
  370. { rc = -7; goto GetOut; }
  371. free(pbBmpBits);
  372. GetOut:
  373. if (pfile)
  374. fclose(pfile);
  375. return rc;
  376. }
  377. /*
  378. =================
  379. =
  380. = LoadLBM
  381. =
  382. =================
  383. */
  384. void LoadLBM (char *filename, byte **picture, byte **palette)
  385. {
  386. byte *LBMbuffer, *picbuffer, *cmapbuffer;
  387. int y,p,planes;
  388. byte *LBM_P, *LBMEND_P;
  389. byte *pic_p;
  390. byte *body_p;
  391. unsigned rowsize;
  392. int formtype,formlength;
  393. int chunktype,chunklength;
  394. void (*mungecall) (int, byte *);
  395. // qiet compiler warnings
  396. picbuffer = NULL;
  397. cmapbuffer = NULL;
  398. mungecall = NULL;
  399. //
  400. // load the LBM
  401. //
  402. LoadFile (filename, (void **)&LBMbuffer);
  403. //
  404. // parse the LBM header
  405. //
  406. LBM_P = LBMbuffer;
  407. if ( *(int *)LBMbuffer != LittleLong(FORMID) )
  408. Error ("No FORM ID at start of file!\n");
  409. LBM_P += 4;
  410. formlength = BigLong( *(int *)LBM_P );
  411. LBM_P += 4;
  412. LBMEND_P = LBM_P + Align(formlength);
  413. formtype = LittleLong(*(int *)LBM_P);
  414. if (formtype != ILBMID && formtype != PBMID)
  415. Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
  416. ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
  417. LBM_P += 4;
  418. //
  419. // parse chunks
  420. //
  421. while (LBM_P < LBMEND_P)
  422. {
  423. chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
  424. LBM_P += 4;
  425. chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
  426. LBM_P += 4;
  427. switch ( chunktype )
  428. {
  429. case BMHDID:
  430. memcpy (&bmhd,LBM_P,sizeof(bmhd));
  431. bmhd.w = BigShort(bmhd.w);
  432. bmhd.h = BigShort(bmhd.h);
  433. bmhd.x = BigShort(bmhd.x);
  434. bmhd.y = BigShort(bmhd.y);
  435. bmhd.pageWidth = BigShort(bmhd.pageWidth);
  436. bmhd.pageHeight = BigShort(bmhd.pageHeight);
  437. break;
  438. case CMAPID:
  439. cmapbuffer = (unsigned char*)malloc (768);
  440. memset (cmapbuffer, 0, 768);
  441. memcpy (cmapbuffer, LBM_P, chunklength);
  442. break;
  443. case BODYID:
  444. body_p = LBM_P;
  445. pic_p = picbuffer = (unsigned char*)malloc (bmhd.w*bmhd.h);
  446. if (formtype == PBMID)
  447. {
  448. //
  449. // unpack PBM
  450. //
  451. for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
  452. {
  453. if (bmhd.compression == cm_rle1)
  454. body_p = LBMRLEDecompress ((byte *)body_p
  455. , pic_p , bmhd.w);
  456. else if (bmhd.compression == cm_none)
  457. {
  458. memcpy (pic_p,body_p,bmhd.w);
  459. body_p += Align(bmhd.w);
  460. }
  461. }
  462. }
  463. else
  464. {
  465. //
  466. // unpack ILBM
  467. //
  468. planes = bmhd.nPlanes;
  469. if (bmhd.masking == ms_mask)
  470. planes++;
  471. rowsize = (bmhd.w+15)/16 * 2;
  472. switch (bmhd.nPlanes)
  473. {
  474. case 1:
  475. mungecall = MungeBitPlanes1;
  476. break;
  477. case 2:
  478. mungecall = MungeBitPlanes2;
  479. break;
  480. case 4:
  481. mungecall = MungeBitPlanes4;
  482. break;
  483. case 8:
  484. mungecall = MungeBitPlanes8;
  485. break;
  486. default:
  487. Error ("Can't munge %i bit planes!\n",bmhd.nPlanes);
  488. }
  489. for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
  490. {
  491. for (p=0 ; p<planes ; p++)
  492. if (bmhd.compression == cm_rle1)
  493. body_p = LBMRLEDecompress ((byte *)body_p
  494. , bitplanes[p] , rowsize);
  495. else if (bmhd.compression == cm_none)
  496. {
  497. memcpy (bitplanes[p],body_p,rowsize);
  498. body_p += rowsize;
  499. }
  500. mungecall (bmhd.w , pic_p);
  501. }
  502. }
  503. break;
  504. }
  505. LBM_P += Align(chunklength);
  506. }
  507. free (LBMbuffer);
  508. *picture = picbuffer;
  509. *palette = cmapbuffer;
  510. }
  511. /*
  512. ============================================================================
  513. WRITE LBM
  514. ============================================================================
  515. */
  516. /*
  517. ==============
  518. =
  519. = WriteLBMfile
  520. =
  521. ==============
  522. */
  523. void WriteLBMfile (char *filename, byte *data, int width, int height, byte *palette)
  524. {
  525. byte *lbm, *lbmptr;
  526. int *formlength, *bmhdlength, *cmaplength, *bodylength;
  527. int length;
  528. bmhd_t basebmhd;
  529. lbm = lbmptr = (unsigned char*)malloc (width*height+1000);
  530. //
  531. // start FORM
  532. //
  533. *lbmptr++ = 'F';
  534. *lbmptr++ = 'O';
  535. *lbmptr++ = 'R';
  536. *lbmptr++ = 'M';
  537. formlength = (int*)lbmptr;
  538. lbmptr+=4; // leave space for length
  539. *lbmptr++ = 'P';
  540. *lbmptr++ = 'B';
  541. *lbmptr++ = 'M';
  542. *lbmptr++ = ' ';
  543. //
  544. // write BMHD
  545. //
  546. *lbmptr++ = 'B';
  547. *lbmptr++ = 'M';
  548. *lbmptr++ = 'H';
  549. *lbmptr++ = 'D';
  550. bmhdlength = (int *)lbmptr;
  551. lbmptr+=4; // leave space for length
  552. memset (&basebmhd,0,sizeof(basebmhd));
  553. basebmhd.w = BigShort((short)width);
  554. basebmhd.h = BigShort((short)height);
  555. basebmhd.nPlanes = (BYTE)BigShort(8);
  556. basebmhd.xAspect = (BYTE)BigShort(5);
  557. basebmhd.yAspect = (BYTE)BigShort(6);
  558. basebmhd.pageWidth = BigShort((short)width);
  559. basebmhd.pageHeight = BigShort((short)height);
  560. memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
  561. lbmptr += sizeof(basebmhd);
  562. length = lbmptr-(byte *)bmhdlength-4;
  563. *bmhdlength = BigLong(length);
  564. if (length&1)
  565. *lbmptr++ = 0; // pad chunk to even offset
  566. //
  567. // write CMAP
  568. //
  569. *lbmptr++ = 'C';
  570. *lbmptr++ = 'M';
  571. *lbmptr++ = 'A';
  572. *lbmptr++ = 'P';
  573. cmaplength = (int *)lbmptr;
  574. lbmptr+=4; // leave space for length
  575. memcpy (lbmptr,palette,768);
  576. lbmptr += 768;
  577. length = lbmptr-(byte *)cmaplength-4;
  578. *cmaplength = BigLong(length);
  579. if (length&1)
  580. *lbmptr++ = 0; // pad chunk to even offset
  581. //
  582. // write BODY
  583. //
  584. *lbmptr++ = 'B';
  585. *lbmptr++ = 'O';
  586. *lbmptr++ = 'D';
  587. *lbmptr++ = 'Y';
  588. bodylength = (int *)lbmptr;
  589. lbmptr+=4; // leave space for length
  590. memcpy (lbmptr,data,width*height);
  591. lbmptr += width*height;
  592. length = lbmptr-(byte *)bodylength-4;
  593. *bodylength = BigLong(length);
  594. if (length&1)
  595. *lbmptr++ = 0; // pad chunk to even offset
  596. //
  597. // done
  598. //
  599. length = lbmptr-(byte *)formlength-4;
  600. *formlength = BigLong(length);
  601. if (length&1)
  602. *lbmptr++ = 0; // pad chunk to even offset
  603. //
  604. // write output file
  605. //
  606. SaveFile (filename, lbm, lbmptr-lbm);
  607. free (lbm);
  608. }