READ_PCX.C 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /******************************************************************************
  2. Plush Version 1.2
  3. read_pcx.c
  4. PCX Texture Reader
  5. Copyright (c) 1996-2000, Justin Frankel
  6. ******************************************************************************/
  7. #include "plush.h"
  8. static pl_uInt _plHiBit(pl_uInt16);
  9. static pl_uInt _plOptimizeImage(pl_uChar *, pl_uChar *, pl_uInt32);
  10. static pl_sInt _plReadPCX(char *filename, pl_uInt16 *width, pl_uInt16 *height,
  11. pl_uChar **pal, pl_uChar **data);
  12. static void _plRescaleImage(pl_uChar *in, pl_uChar *out, pl_uInt inx,
  13. pl_uInt iny, pl_uInt outx, pl_uInt outy);
  14. pl_Texture *plReadPCXTex(char *fn, pl_Bool rescale, pl_Bool optimize) {
  15. pl_uChar *data, *pal;
  16. pl_uInt16 x, y;
  17. pl_Texture *t;
  18. if (_plReadPCX(fn,&x,&y,&pal,&data) < 0) return 0;
  19. t = (pl_Texture *) malloc(sizeof(pl_Texture));
  20. if (!t) return 0;
  21. t->Width = _plHiBit(x);
  22. t->Height = _plHiBit(y);
  23. if (rescale && (1 << t->Width != x || 1 << t->Height != y)) {
  24. pl_uChar nx, ny, *newdata;
  25. nx = t->Width;
  26. if ((1 << t->Width) != x) nx++;
  27. ny = t->Height;
  28. if ((1 << t->Height) != y) ny++;
  29. newdata = (pl_uChar *) malloc((1<<nx)*(1<<ny));
  30. if (!newdata) {
  31. free(t);
  32. free(data);
  33. free(pal);
  34. return 0;
  35. }
  36. _plRescaleImage(data,newdata,x,y,1<<nx,1<<ny);
  37. free(data);
  38. data = newdata;
  39. t->Width = nx;
  40. t->Height = ny;
  41. x = 1<<nx; y = 1<<ny;
  42. }
  43. t->iWidth = x;
  44. t->iHeight = y;
  45. t->uScale = (pl_Float) (1<<t->Width);
  46. t->vScale = (pl_Float) (1<<t->Height);
  47. if (optimize) t->NumColors = _plOptimizeImage(pal, data,x*y);
  48. else t->NumColors = 256;
  49. t->Data = data;
  50. t->PaletteData = pal;
  51. return t;
  52. }
  53. static pl_uInt _plHiBit(pl_uInt16 x) {
  54. pl_uInt i = 16, mask = 1<<15;
  55. while (mask) {
  56. if (x & mask) return i;
  57. mask >>= 1; i--;
  58. }
  59. return 0;
  60. }
  61. static pl_uInt _plOptimizeImage(pl_uChar *pal, pl_uChar *data, pl_uInt32 len) {
  62. pl_uChar colors[256], *dd = data;
  63. pl_uChar remap[256];
  64. pl_sInt32 lastused, firstunused;
  65. pl_uInt32 x;
  66. memset(colors,0,256);
  67. for (x = 0; x < len; x ++) colors[(pl_uInt) *dd++] = 1;
  68. lastused = -1;
  69. for (x = 0; x < 256; x ++) remap[x] = (pl_uChar)x;
  70. lastused = 255;
  71. firstunused = 0;
  72. for (;;) {
  73. while (firstunused < 256 && colors[firstunused]) firstunused++;
  74. if (firstunused > 255) break;
  75. while (lastused >= 0 && !colors[lastused]) lastused--;
  76. if (lastused < 0) break;
  77. if (lastused <= firstunused) break;
  78. pal[firstunused*3] = pal[lastused*3];
  79. pal[firstunused*3+1] = pal[lastused*3+1];
  80. pal[firstunused*3+2] = pal[lastused*3+2];
  81. colors[lastused] = 0;
  82. colors[firstunused] = 1;
  83. remap[lastused] = (pl_uChar) firstunused;
  84. }
  85. x = len;
  86. while (x--) *data++ = remap[(pl_uInt) *data];
  87. return (lastused+1);
  88. }
  89. static pl_sInt _plReadPCX(char *filename, pl_uInt16 *width, pl_uInt16 *height,
  90. pl_uChar **pal, pl_uChar **data) {
  91. pl_uInt16 sx, sy, ex, ey;
  92. FILE *fp = fopen(filename,"rb");
  93. pl_uChar *data2;
  94. if (!fp) return -1;
  95. fgetc(fp);
  96. if (fgetc(fp) != 5) { fclose(fp); return -2; }
  97. if (fgetc(fp) != 1) { fclose(fp); return -2; }
  98. if (fgetc(fp) != 8) { fclose(fp); return -3; }
  99. sx = fgetc(fp); sx |= fgetc(fp)<<8;
  100. sy = fgetc(fp); sy |= fgetc(fp)<<8;
  101. ex = fgetc(fp); ex |= fgetc(fp)<<8;
  102. ey = fgetc(fp); ey |= fgetc(fp)<<8;
  103. *width = ex - sx + 1;
  104. *height = ey - sy + 1;
  105. fseek(fp,128,SEEK_SET);
  106. if (feof(fp)) { fclose(fp); return -4; }
  107. *data = (pl_uChar *) malloc((*width) * (*height));
  108. if (!*data) { fclose(fp); return -128; }
  109. sx = *height;
  110. data2 = *data;
  111. do {
  112. int xpos = 0;
  113. do {
  114. char c = fgetc(fp);
  115. if ((c & 192) == 192) {
  116. char oc = fgetc(fp);
  117. c &= ~192;
  118. do {
  119. *(data2++) = oc;
  120. xpos++;
  121. } while (--c && xpos < *width);
  122. } else {
  123. *(data2++) = c;
  124. xpos++;
  125. }
  126. } while (xpos < *width);
  127. } while (--sx);
  128. if (feof(fp)) { fclose(fp); free(*data); return -5; }
  129. fseek(fp,-769,SEEK_END);
  130. if (fgetc(fp) != 12) { fclose(fp); free(*data); return -6; }
  131. *pal = (pl_uChar *) malloc(768);
  132. if (!*pal) { fclose(fp); free(*data); return -7; }
  133. fread(*pal,3,256,fp);
  134. fclose(fp);
  135. return 0;
  136. }
  137. static void _plRescaleImage(pl_uChar *in, pl_uChar *out, pl_uInt inx,
  138. pl_uInt iny, pl_uInt outx, pl_uInt outy) {
  139. pl_uInt x;
  140. pl_uInt32 X, dX, dY, Y;
  141. dX = (inx<<16) / outx;
  142. dY = (iny<<16) / outy;
  143. Y = 0;
  144. do {
  145. pl_uChar *ptr = in + inx*(Y>>16);
  146. X = 0;
  147. Y += dY;
  148. x = outx;
  149. do {
  150. *out++ = ptr[X>>16];
  151. X += dX;
  152. } while (--x);
  153. } while (--outy);
  154. }