tga-compiler.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include <stdio.h>
  2. #include "Filesystem.h"
  3. #include "Stream.h"
  4. #include "Path.h"
  5. #include "String.h"
  6. #include "Hash.h"
  7. #include "Resource.h"
  8. #include "ResourceArchive.h"
  9. #include "FileStream.h"
  10. #include "Pixel.h"
  11. #include "TextureResource.h"
  12. #include <cstring>
  13. using namespace crown;
  14. struct TGAHeader
  15. {
  16. char id_length; // 00h Size of Image ID field
  17. char color_map_type; // 01h Color map type
  18. char image_type; // 02h Image type code
  19. char c_map_spec[5]; // 03h Color map origin 05h Color map length 07h Depth of color map entries
  20. uint16_t x_offset; // 08h X origin of image
  21. uint16_t y_offset; // 0Ah Y origin of image
  22. uint16_t width; // 0Ch Width of image
  23. uint16_t height; // 0Eh Height of image
  24. char pixel_depth; // 10h Image pixel size
  25. char image_descriptor; // 11h Image descriptor byte
  26. };
  27. void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
  28. void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels);
  29. void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels);
  30. /// TGA compiler for "tga" resource type
  31. /// TODO: Explain supported formats, usage etc.
  32. int main(int argc, char** argv)
  33. {
  34. if (argc != 4)
  35. {
  36. printf("Usage: %s /path/to/resources /path/to/compiled resource.tga\n", argv[0]);
  37. return -1;
  38. }
  39. Filesystem fs_root(argv[1]);
  40. Filesystem fs_dest(argv[2]);
  41. const char* resource = argv[3];
  42. if (!fs_root.exists(resource))
  43. {
  44. printf("Fatal: resource %s does not exists. Aborting.\n", resource);
  45. return -1;
  46. }
  47. char resource_basename[256];
  48. char resource_extension[256];
  49. path::basename(resource, resource_basename, 256);
  50. path::extension(resource, resource_extension, 256);
  51. printf("Resource basename : %s\n", resource_basename);
  52. printf("Resource extension : %s\n", resource_extension);
  53. uint32_t resource_basename_hash = hash::fnv1a_32(resource_basename, string::strlen(resource_basename));
  54. uint32_t resource_extension_hash = hash::fnv1a_32(resource_extension, string::strlen(resource_extension));
  55. printf("Resource basename (hash) : %X\n", resource_basename_hash);
  56. printf("Resource extension (hash) : %X\n", resource_extension_hash);
  57. FileStream* src_file = (FileStream*)fs_root.open(resource, SOM_READ);
  58. //-------------------------------------------------------------------------
  59. // Read TGA Header
  60. //-------------------------------------------------------------------------
  61. // The TGA header used throughout the code
  62. TGAHeader header;
  63. memset(&header, 0, sizeof(TGAHeader));
  64. // Read the header
  65. src_file->read(&header, sizeof(TGAHeader));
  66. // Skip TGA ID
  67. src_file->skip(header.id_length);
  68. // Pixel format currently unknown
  69. PixelFormat format = PF_UNKNOWN;
  70. // Compute color channels
  71. uint32_t channels = header.pixel_depth / 8;
  72. // Compute image size
  73. uint64_t image_size = header.width * header.height;
  74. uint8_t* image_data = NULL;
  75. // Select the appropriate pixel format and allocate resource data based on tga size and channels
  76. switch (channels)
  77. {
  78. case 2:
  79. case 3:
  80. {
  81. format = PF_RGB_8;
  82. image_data = new uint8_t[(uint32_t)(image_size * 3)];
  83. break;
  84. }
  85. case 4:
  86. {
  87. format = PF_RGBA_8;
  88. image_data = new uint8_t[(uint32_t)(image_size * channels)];
  89. break;
  90. }
  91. default:
  92. {
  93. printf("Fatal: Unable to determine TGA channels. Aborting.\n");
  94. return -1;
  95. }
  96. }
  97. printf("Debug: w = %d, h = %d, channels = %d\n", header.width, header.height, channels);
  98. // Determine image type (compressed/uncompressed) and call proper function to load TGA
  99. switch (header.image_type)
  100. {
  101. case 0:
  102. {
  103. printf("Fatal: The resource does not contain image data. Aborting.");
  104. return -1;
  105. }
  106. case 2:
  107. {
  108. printf("Debug: loading uncompressed...\n");
  109. load_uncompressed(image_data, src_file, header.width, header.height, channels);
  110. break;
  111. }
  112. case 10:
  113. {
  114. printf("Debug: loading compressed...\n");
  115. load_compressed(image_data, src_file, header.width, header.height, channels);
  116. break;
  117. }
  118. default:
  119. {
  120. printf("Fatal: Image type not supported. Aborting.");
  121. return -1;
  122. }
  123. }
  124. // FIXME Fixed options for now until proper settings management implemented
  125. TextureMode mode = TM_MODULATE;
  126. TextureFilter filter = TF_BILINEAR;
  127. TextureWrap wrap = TW_REPEAT;
  128. // Open output file
  129. FileStream* dest_file = (FileStream*)fs_dest.open(resource, SOM_WRITE);
  130. ArchiveEntry archive_entry;
  131. archive_entry.name = resource_basename_hash;
  132. archive_entry.type = resource_extension_hash;
  133. archive_entry.offset = sizeof(ArchiveEntry);
  134. archive_entry.size = image_size * channels + sizeof(PixelFormat) + sizeof(uint16_t) * 2 +
  135. sizeof(TextureMode) + sizeof(TextureFilter) + sizeof(TextureWrap);
  136. // Write out the archive entry
  137. dest_file->write(&archive_entry, sizeof(ArchiveEntry));
  138. // Write out the data
  139. dest_file->write(&format, sizeof(PixelFormat));
  140. dest_file->write(&header.width, sizeof(uint16_t));
  141. dest_file->write(&header.height, sizeof(uint16_t));
  142. dest_file->write(&mode, sizeof(TextureMode));
  143. dest_file->write(&filter, sizeof(TextureFilter));
  144. dest_file->write(&wrap, sizeof(TextureWrap));
  145. dest_file->write(image_data, image_size * channels);
  146. // Done, free the resources and exit
  147. if (image_data != NULL)
  148. {
  149. delete[] image_data;
  150. }
  151. return 0;
  152. }
  153. //-----------------------------------------------------------------------------
  154. void load_uncompressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
  155. {
  156. uint64_t size = width * height;
  157. uint8_t* data = (uint8_t*)dest;
  158. if (channels == 2)
  159. {
  160. int32_t j = 0;
  161. for (uint64_t i = 0; i < size * channels; i++)
  162. {
  163. uint16_t pixel_data;
  164. stream->read(&pixel_data, sizeof(pixel_data));
  165. data[j + 0] = (pixel_data & 0x7c) >> 10;
  166. data[j + 1] = (pixel_data & 0x3e) >> 5;
  167. data[j + 2] = (pixel_data & 0x1f);
  168. j += 3;
  169. }
  170. }
  171. else
  172. {
  173. stream->read(data, (size_t)(size * channels));
  174. swap_red_blue(data, size * channels, channels);
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. void load_compressed(void* dest, Stream* stream, uint32_t width, uint32_t height, uint32_t channels)
  179. {
  180. uint8_t rle_id = 0;
  181. uint32_t i = 0;
  182. uint32_t colors_read = 0;
  183. uint64_t size = width * height;
  184. uint8_t* data = (uint8_t*)dest;
  185. uint8_t* colors = new uint8_t[channels];
  186. while (i < size)
  187. {
  188. stream->read(&rle_id, sizeof(uint8_t));
  189. // If MSB == 1
  190. if (rle_id & 0x80)
  191. {
  192. rle_id -= 127;
  193. stream->read(colors, channels);
  194. while (rle_id)
  195. {
  196. data[colors_read + 0] = colors[2];
  197. data[colors_read + 1] = colors[1];
  198. data[colors_read + 2] = colors[0];
  199. if (channels == 4)
  200. {
  201. data[colors_read + 3] = colors[3];
  202. }
  203. rle_id--;
  204. colors_read += channels;
  205. i++;
  206. }
  207. }
  208. else
  209. {
  210. rle_id++;
  211. while (rle_id)
  212. {
  213. stream->read(colors, channels);
  214. data[colors_read + 0] = colors[2];
  215. data[colors_read + 1] = colors[1];
  216. data[colors_read + 2] = colors[0];
  217. if (channels == 4)
  218. {
  219. data[colors_read + 3] = colors[3];
  220. }
  221. rle_id--;
  222. colors_read += channels;
  223. i++;
  224. }
  225. }
  226. }
  227. delete[] colors;
  228. }
  229. //-----------------------------------------------------------------------------
  230. void swap_red_blue(uint8_t* data, uint64_t size, uint32_t channels)
  231. {
  232. for (uint64_t i = 0; i < size; i += channels)
  233. {
  234. data[i] ^= data[i+2];
  235. data[i+2] ^= data[i];
  236. data[i] ^= data[i+2];
  237. }
  238. }