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 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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 <iostream>
  12. #include "global.h"
  13. #include "utils/pcx.h"
  14. int pcxCheck(const char* filename) {
  15. assert(filename != nullptr);
  16. assert(filename[0] != '\0');
  17. std::ifstream file(filename, std::ios::in | std::ios::binary);
  18. // Read raw PCX header, 128 bytes
  19. unsigned char* header = new unsigned char[128];
  20. // Basic validation
  21. if (!file.read((char*)(&header[0]), 128)) {
  22. std::cout << "File not big enough for valid PCX header!" << std::endl;
  23. delete [] header;
  24. return -1;
  25. }
  26. if (header[0] != 0x0A) {
  27. std::cout << "Magic number at file start is wrong (" << header[0] << " != 0x0A)" << std::endl;
  28. delete [] header;
  29. return -2;
  30. }
  31. if ((header[1] != 0) && ((header[1] < 2) || (header[1] > 5))) {
  32. // Valid: 0, 2, 3, 4, 5
  33. std::cout << "Unknown PCX file format version (" << header[1] << ")" << std::endl;
  34. delete [] header;
  35. return -3;
  36. }
  37. if ((header[2] != 0) && (header[2] != 1)) {
  38. std::cout << "Unknown PCX file encoding (" << header[2] << ")" << std::endl;
  39. delete [] header;
  40. return -4;
  41. }
  42. if (header[3] != 8) {
  43. std::cout << "Only supporting 8bit (" << header[3] << "bit)" << std::endl;
  44. delete [] header;
  45. return -5;
  46. }
  47. if (header[64] != 0) {
  48. std::cout << "Reserved field is used (" << header[64] << " != 0)" << std::endl;
  49. delete [] header;
  50. return -6;
  51. }
  52. delete [] header;
  53. return 0;
  54. }
  55. int pcxLoad(const char* filename, unsigned char** image,
  56. unsigned int* width, unsigned int* height,
  57. ColorMode* mode, unsigned int* bpp) {
  58. assert(filename != nullptr);
  59. assert(filename[0] != '\0');
  60. assert(image != nullptr);
  61. assert(width != nullptr);
  62. assert(height != nullptr);
  63. assert(mode != nullptr);
  64. assert(bpp != nullptr);
  65. std::ifstream file(filename, std::ios::in | std::ios::binary);
  66. // Read raw PCX header, 128 bytes
  67. unsigned char* header = new unsigned char[128];
  68. // Basic validation
  69. if (!file.read((char*)(&header[0]), 128)) {
  70. std::cout << "File not big enough for valid PCX header!" << std::endl;
  71. delete [] header;
  72. return -1;
  73. }
  74. if (header[0] != 0x0A) {
  75. std::cout << "Magic number at file start is wrong (" << header[0] << " != 0x0A)" << std::endl;
  76. delete [] header;
  77. return -2;
  78. }
  79. if ((header[1] != 0) && ((header[1] < 2) || (header[1] > 5))) {
  80. // Valid: 0, 2, 3, 4, 5
  81. std::cout << "Unknown PCX file format version (" << header[1] << ")" << std::endl;
  82. delete [] header;
  83. return -3;
  84. }
  85. if ((header[2] != 0) && (header[2] != 1)) {
  86. std::cout << "Unknown PCX file encoding (" << header[2] << ")" << std::endl;
  87. delete [] header;
  88. return -4;
  89. }
  90. if (header[3] != 8) {
  91. std::cout << "Only supporting 8bit (" << header[3] << "bit)" << std::endl;
  92. delete [] header;
  93. return -5;
  94. }
  95. if (header[64] != 0) {
  96. std::cout << "Reserved field is used (" << header[64] << " != 0)" << std::endl;
  97. delete [] header;
  98. return -6;
  99. }
  100. // Read header informations
  101. bool versionFive = (header[1] == 5);
  102. bool compressed = (header[2] == 1);
  103. //unsigned char bitsPerPixel = header[3];
  104. unsigned int xMin = header[4] | (header[5] << 8);
  105. unsigned int yMin = header[6] | (header[7] << 8);
  106. unsigned int xMax = header[8] | (header[9] << 8);
  107. unsigned int yMax = header[10] | (header[11] << 8);
  108. //unsigned int hDPI = header[12] | (header[13] << 8);
  109. //unsigned int vDPI = header[14] | (header[15] << 8);
  110. //unsigned char *colormap = header + 16;
  111. unsigned char nPlanes = header[65];
  112. unsigned int bytesPerLine = header[66] | (header[67] << 8);
  113. //unsigned int paletteInfo = header[68] | (header[69] << 8);
  114. //unsigned int hScreenSize = header[70] | (header[71] << 8); // Only in some versionFive files
  115. //unsigned int vScreenSize = header[72] | (header[73] << 8); // Only in some versionFive files
  116. delete [] header;
  117. // Calculations
  118. *width = xMax - xMin + 1;
  119. *height = yMax - yMin + 1;
  120. unsigned long totalBytes = nPlanes * bytesPerLine; // total bytes per scan line
  121. unsigned long imageSize = totalBytes** height;
  122. unsigned char* buffer = new unsigned char[imageSize];
  123. unsigned long b = 0;
  124. // Read encoded pixel data
  125. for (unsigned long i = 0; i < imageSize;) {
  126. unsigned int n = 1; // Run-length-encoding assumes 1
  127. int c = file.get();
  128. if (!file) {
  129. std::cout << "Could not read data (" << i
  130. << (file.eof() ? " EOF" : "") << ")" << std::endl;
  131. delete [] buffer;
  132. return -7;
  133. }
  134. // Run-Length-Encoding
  135. if (compressed) {
  136. if ((c & 0xC0) == 0xC0) {
  137. n = c & 0x3F;
  138. c = file.get();
  139. if (!file) {
  140. std::cout << "Could not read data rle (" << i
  141. << (file.eof() ? " EOF" : "") << ")" << std::endl;
  142. delete [] buffer;
  143. return -8;
  144. }
  145. }
  146. }
  147. for (unsigned int j = 0; j < n; j++)
  148. buffer[b++] = (unsigned char)c;
  149. i += n;
  150. }
  151. // Read color palette
  152. unsigned char* palette = nullptr;
  153. if (versionFive) {
  154. int c = file.get();
  155. if ((c == 12) && file) {
  156. palette = new unsigned char[768];
  157. for (unsigned int i = 0; i < 768; i++) {
  158. palette[i] = (unsigned char)file.get();
  159. if (!file) {
  160. std::cout << "Could not read 256 color palette (" << i << ")" << std::endl;
  161. delete [] buffer;
  162. delete [] palette;
  163. return -9;
  164. }
  165. }
  166. }
  167. }
  168. // Bring buffer into preferred format
  169. unsigned long size = *width** height * 4;
  170. *image = new unsigned char[size];
  171. for (unsigned int y = 0; y < *height; y++) {
  172. for (unsigned int x = 0; x < *width; x++) {
  173. unsigned long baseIndex = (x + (y** width)) * 4;
  174. unsigned char alpha = 255, red = 0, green = 0, blue = 0;
  175. if (palette != nullptr) {
  176. if (nPlanes == 1) {
  177. red = palette[buffer[(y * totalBytes) + x] * 3];
  178. green = palette[(buffer[(y * totalBytes) + x] * 3) + 1];
  179. blue = palette[(buffer[(y * totalBytes) + x] * 3) + 2];
  180. } else {
  181. std::cout << "Unsupported number of planes (" << nPlanes << ")" << std::endl;
  182. delete [] buffer;
  183. delete [] palette;
  184. delete [] *image;
  185. *image = nullptr;
  186. return -10;
  187. }
  188. } else {
  189. if ((nPlanes == 3) || (nPlanes == 4)) {
  190. red = buffer[(y * totalBytes) + x];
  191. green = buffer[(y * totalBytes) + *width + x];
  192. blue = buffer[(y * totalBytes) + (2 * *width) + x];
  193. if (nPlanes == 4)
  194. alpha = buffer[(y * totalBytes) + (3 * *width) + x];
  195. } else if (nPlanes == 1) {
  196. red = green = blue = buffer[(y * totalBytes) + x];
  197. } else {
  198. std::cout << "Unsupported number of planes (" << nPlanes << ")" << std::endl;
  199. delete [] buffer;
  200. delete [] palette;
  201. delete [] *image;
  202. *image = nullptr;
  203. return -11;
  204. }
  205. }
  206. (*image)[baseIndex + 0] = red;
  207. (*image)[baseIndex + 1] = green;
  208. (*image)[baseIndex + 2] = blue;
  209. (*image)[baseIndex + 3] = alpha;
  210. }
  211. }
  212. *mode = ColorMode::RGBA;
  213. *bpp = 32;
  214. delete [] buffer;
  215. delete [] palette;
  216. return 0;
  217. }