Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

pcx.cpp 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*!
  2. * \file src/utils/pcx.cpp
  3. * \brief PCX image reader
  4. *
  5. * Based on official technical documentation from ZSoft:
  6. * http://bespin.org/~qz/pc-gpe/pcx.txt
  7. *
  8. * \author xythobuz
  9. */
  10. #include <fstream>
  11. #include "global.h"
  12. #include "utils/pcx.h"
  13. #ifdef DEBUG
  14. #include "Console.h"
  15. #define pcxPrint getConsole().print
  16. #else
  17. void pcxPrint(...) { }
  18. #endif
  19. int pcxLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height) {
  20. std::ifstream file(filename, std::ios::in | std::ios::binary);
  21. // Read raw PCX header, 128 bytes
  22. unsigned char *header = new unsigned char[128];
  23. // Basic validation
  24. if (!file.read((char *)(&header[0]), 128)) {
  25. pcxPrint("File not big enough for valid PCX header!");
  26. delete [] header;
  27. return -1;
  28. }
  29. if (header[0] != 0x0A) {
  30. pcxPrint("Magic number at file start is wrong (0x%X != 0x0A)", header[0]);
  31. delete [] header;
  32. return -2;
  33. }
  34. if ((header[1] != 0) && ((header[1] < 2) || (header[1] > 5))) {
  35. // Valid: 0, 2, 3, 4, 5
  36. pcxPrint("Unknown PCX file format version (%d)", header[1]);
  37. delete [] header;
  38. return -3;
  39. }
  40. if ((header[2] != 0) && (header[2] != 1)) {
  41. pcxPrint("Unknown PCX file encoding (%d)", header[2]);
  42. delete [] header;
  43. return -4;
  44. }
  45. if (header[3] != 8) {
  46. pcxPrint("Only supporting 8bit (%dbit)", header[3]);
  47. delete [] header;
  48. return -5;
  49. }
  50. if (header[64] != 0) {
  51. pcxPrint("Reserved field is used (%d != 0)", header[64]);
  52. delete [] header;
  53. return -6;
  54. }
  55. // Read header informations
  56. bool versionFive = (header[1] == 5);
  57. bool compressed = (header[2] == 1);
  58. //unsigned char bitsPerPixel = header[3];
  59. unsigned int xMin = header[4] | (header[5] << 8);
  60. unsigned int yMin = header[6] | (header[7] << 8);
  61. unsigned int xMax = header[8] | (header[9] << 8);
  62. unsigned int yMax = header[10] | (header[11] << 8);
  63. //unsigned int hDPI = header[12] | (header[13] << 8);
  64. //unsigned int vDPI = header[14] | (header[15] << 8);
  65. //unsigned char *colormap = header + 16;
  66. unsigned char nPlanes = header[65];
  67. unsigned int bytesPerLine = header[66] | (header[67] << 8);
  68. //unsigned int paletteInfo = header[68] | (header[69] << 8);
  69. //unsigned int hScreenSize = header[70] | (header[71] << 8); // Only in some versionFive files
  70. //unsigned int vScreenSize = header[72] | (header[73] << 8); // Only in some versionFive files
  71. delete [] header;
  72. // Calculations
  73. *width = xMax - xMin + 1;
  74. *height = yMax - yMin + 1;
  75. unsigned long totalBytes = nPlanes * bytesPerLine; // total bytes per scan line
  76. unsigned long imageSize = totalBytes * *height;
  77. unsigned char *buffer = new unsigned char[imageSize];
  78. unsigned long b = 0;
  79. // Read encoded pixel data
  80. for (unsigned long i = 0; i < imageSize;) {
  81. unsigned int n = 1; // Run-length-encoding assumes 1
  82. int c = file.get();
  83. if (!file) {
  84. pcxPrint("Could not read data (%lu%s)", i, (file.eof() ? " EOF" : ""));
  85. delete [] buffer;
  86. return -7;
  87. }
  88. // Run-Length-Encoding
  89. if (compressed) {
  90. if ((c & 0xC0) == 0xC0) {
  91. n = c & 0x3F;
  92. c = file.get();
  93. if (!file) {
  94. pcxPrint("Could not read data rle (%lu%s)", i, (file.eof() ? " EOF" : ""));
  95. delete [] buffer;
  96. return -8;
  97. }
  98. }
  99. }
  100. for (unsigned int j = 0; j < n; j++)
  101. buffer[b++] = (unsigned char)c;
  102. i += n;
  103. }
  104. // Read color palette
  105. unsigned char *palette = NULL;
  106. if (versionFive) {
  107. int c = file.get();
  108. if ((c == 12) && file) {
  109. palette = new unsigned char[768];
  110. for (unsigned int i = 0; i < 768; i++) {
  111. palette[i] = (unsigned char)file.get();
  112. if (!file) {
  113. pcxPrint("Could not read 256 color palette (%d)", i);
  114. delete [] buffer;
  115. delete [] palette;
  116. return -9;
  117. }
  118. }
  119. }
  120. }
  121. // Bring buffer into preferred format
  122. unsigned long size = *width * *height * 4;
  123. *image = new unsigned char[size];
  124. for (unsigned int y = 0; y < *height; y++) {
  125. for (unsigned int x = 0; x < *width; x++) {
  126. unsigned long baseIndex = (x + (y * *width)) * 4;
  127. unsigned char alpha = 255, red = 0, green = 0, blue = 0;
  128. if (palette != NULL) {
  129. if (nPlanes == 1) {
  130. red = palette[buffer[(y * totalBytes) + x] * 3];
  131. green = palette[(buffer[(y * totalBytes) + x] * 3) + 1];
  132. blue = palette[(buffer[(y * totalBytes) + x] * 3) + 2];
  133. } else {
  134. pcxPrint("Unsupported number of planes (%d)", nPlanes);
  135. delete [] buffer;
  136. delete [] palette;
  137. delete [] *image;
  138. *image = NULL;
  139. return -10;
  140. }
  141. } else {
  142. if ((nPlanes == 3) || (nPlanes == 4)) {
  143. red = buffer[(y * totalBytes) + x];
  144. green = buffer[(y * totalBytes) + *width + x];
  145. blue = buffer[(y * totalBytes) + (2 * *width) + x];
  146. if (nPlanes == 4)
  147. alpha = buffer[(y * totalBytes) + (3 * *width) + x];
  148. } else if (nPlanes == 1) {
  149. red = green = blue = buffer[(y * totalBytes) + x];
  150. } else {
  151. pcxPrint("Unsupported number of planes (%d)", nPlanes);
  152. delete [] buffer;
  153. delete [] palette;
  154. delete [] *image;
  155. *image = NULL;
  156. return -11;
  157. }
  158. }
  159. (*image)[baseIndex + 0] = red;
  160. (*image)[baseIndex + 1] = green;
  161. (*image)[baseIndex + 2] = blue;
  162. (*image)[baseIndex + 3] = alpha;
  163. }
  164. }
  165. delete [] buffer;
  166. delete [] palette;
  167. return 0;
  168. }