texture.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include "texture.h"
  2. #include "dxt.h"
  3. #include "vtf.h"
  4. #include "cache.h"
  5. #include "collection.h"
  6. #include "mempools.h"
  7. #include "common.h"
  8. const char *vtfFormatStr(enum VTFImageFormat fmt) {
  9. switch(fmt) {
  10. case VTFImage_None: return "None";
  11. case VTFImage_RGBA8: return "RGBA8";
  12. case VTFImage_ABGR8: return "ABGR8";
  13. case VTFImage_RGB8: return "RGB8";
  14. case VTFImage_BGR8: return "BGR8";
  15. case VTFImage_RGB565: return "RGB565";
  16. case VTFImage_I8: return "I8";
  17. case VTFImage_IA8: return "IA8";
  18. case VTFImage_P8: return "P8";
  19. case VTFImage_A8: return "A8";
  20. case VTFImage_RGB8_Bluescreen: return "RGB8_Bluescreen";
  21. case VTFImage_BGR8_Bluescreen: return "BGR8_Bluescreen";
  22. case VTFImage_ARGB8: return "ARGB8";
  23. case VTFImage_BGRA8: return "BGRA8";
  24. case VTFImage_DXT1: return "DXT1";
  25. case VTFImage_DXT3: return "DXT3";
  26. case VTFImage_DXT5: return "DXT5";
  27. case VTFImage_BGRX8: return "BGRX8";
  28. case VTFImage_BGR565: return "BGR565";
  29. case VTFImage_BGRX5551: return "BGRX5551";
  30. case VTFImage_BGRA4: return "BGRA4";
  31. case VTFImage_DXT1_A1: return "DXT1_A1";
  32. case VTFImage_BGRA5551: return "BGRA5551";
  33. case VTFImage_UV8: return "UV8";
  34. case VTFImage_UVWQ8: return "UVWQ8";
  35. case VTFImage_RGBA16F: return "RGBA16F";
  36. case VTFImage_RGBA16: return "RGBA16";
  37. case VTFImage_UVLX8: return "UVLX8";
  38. }
  39. return "None";
  40. }
  41. static int vtfImageSize(enum VTFImageFormat fmt, int width, int height) {
  42. int pixel_bits = 0;
  43. switch(fmt) {
  44. case VTFImage_None: break;
  45. case VTFImage_RGBA8:
  46. case VTFImage_ABGR8:
  47. case VTFImage_ARGB8:
  48. case VTFImage_BGRA8:
  49. case VTFImage_BGRX8:
  50. case VTFImage_UVWQ8:
  51. case VTFImage_UVLX8:
  52. pixel_bits = 32;
  53. break;
  54. case VTFImage_BGR565:
  55. case VTFImage_BGRX5551:
  56. case VTFImage_BGRA5551:
  57. case VTFImage_BGRA4:
  58. case VTFImage_RGB565:
  59. case VTFImage_UV8:
  60. pixel_bits = 16;
  61. break;
  62. case VTFImage_RGB8:
  63. case VTFImage_BGR8:
  64. case VTFImage_RGB8_Bluescreen:
  65. case VTFImage_BGR8_Bluescreen:
  66. pixel_bits = 24;
  67. break;
  68. case VTFImage_I8:
  69. case VTFImage_IA8:
  70. case VTFImage_P8:
  71. case VTFImage_A8:
  72. pixel_bits = 8;
  73. break;
  74. case VTFImage_DXT3:
  75. case VTFImage_DXT5:
  76. pixel_bits = 4;
  77. break;
  78. case VTFImage_DXT1:
  79. case VTFImage_DXT1_A1:
  80. pixel_bits += 4;
  81. width = 4 * ((width + 3) / 4);
  82. height = 4 * ((height + 3) / 4);
  83. break;
  84. case VTFImage_RGBA16F:
  85. case VTFImage_RGBA16:
  86. pixel_bits = 64;
  87. break;
  88. }
  89. return width * height * pixel_bits / 8;
  90. }
  91. static int textureUploadMipmap(struct Stack *tmp, struct IFile *file, size_t cursor,
  92. const struct VTFHeader *hdr, int miplevel, AGLTexture *tex) {
  93. for (int mip = hdr->mipmap_count - 1; mip > miplevel; --mip) {
  94. const unsigned int mip_width = hdr->width >> mip;
  95. const unsigned int mip_height = hdr->height >> mip;
  96. const int mip_image_size = vtfImageSize(hdr->hires_format, mip_width, mip_height);
  97. cursor += mip_image_size * hdr->frames;
  98. /*PRINTF("cur: %d; size: %d, mip: %d, %dx%d",
  99. cursor, mip_image_size, mip, mip_width, mip_height);
  100. */
  101. }
  102. const int src_texture_size = vtfImageSize(hdr->hires_format, hdr->width, hdr->height);
  103. void *src_texture = stackAlloc(tmp, src_texture_size);
  104. if (!src_texture) {
  105. PRINTF("Cannot allocate %d bytes for texture", src_texture_size);
  106. return 0;
  107. }
  108. const int dst_texture_size = sizeof(uint16_t) * hdr->width * hdr->height;
  109. void *dst_texture = stackAlloc(tmp, dst_texture_size);
  110. if (!dst_texture) {
  111. PRINTF("Cannot allocate %d bytes for texture", dst_texture_size);
  112. return 0;
  113. }
  114. if (src_texture_size != (int)file->read(file, cursor, src_texture_size, src_texture)) {
  115. PRINT("Cannot read texture data");
  116. return 0;
  117. }
  118. const struct DXTUnpackContext dxt_ctx = {
  119. .width = hdr->width,
  120. .height = hdr->height,
  121. .packed = src_texture,
  122. .output = dst_texture
  123. };
  124. if (hdr->hires_format == VTFImage_DXT1)
  125. dxt1Unpack(dxt_ctx);
  126. else
  127. dxt5Unpack(dxt_ctx);
  128. const AGLTextureUploadData data = {
  129. .x = 0,
  130. .y = 0,
  131. .width = hdr->width,
  132. .height = hdr->height,
  133. .format = AGLTF_U565_RGB,
  134. .pixels = dst_texture
  135. };
  136. aGLTextureUpload(tex, &data);
  137. return 1;
  138. }
  139. static int textureLoad(struct IFile *file, Texture *tex, struct Stack *tmp) {
  140. struct VTFHeader hdr;
  141. size_t cursor = 0;
  142. int retval = 0;
  143. if (file->read(file, 0, sizeof(hdr), &hdr) != sizeof(hdr)) {
  144. PRINT("Cannot read texture");
  145. return 0;
  146. }
  147. if (hdr.signature[0] != 'V' || hdr.signature[1] != 'T' ||
  148. hdr.signature[2] != 'F' || hdr.signature[3] != '\0') {
  149. PRINT("Invalid file signature");
  150. return 0;
  151. }
  152. PRINTF("Texture: %dx%d, %s",
  153. hdr.width, hdr.height, vtfFormatStr(hdr.hires_format));
  154. if (hdr.hires_format != VTFImage_DXT1 && hdr.hires_format != VTFImage_DXT5) {
  155. PRINTF("Not implemented texture format: %s", vtfFormatStr(hdr.hires_format));
  156. return 0;
  157. }
  158. cursor += hdr.header_size;
  159. if (hdr.lores_format != (unsigned)VTFImage_None)
  160. cursor += vtfImageSize(hdr.lores_format, hdr.lores_width, hdr.lores_height);
  161. /*
  162. PRINTF("Texture lowres: %dx%d, %s; mips %d; header_size: %u",
  163. hdr.lores_width, hdr.lores_height, vtfFormatStr(hdr.lores_format), hdr.mipmap_count, hdr.header_size);
  164. */
  165. tex->gltex = aGLTextureCreate();
  166. void *pre_alloc_cursor = stackGetCursor(tmp);
  167. retval = textureUploadMipmap(tmp, file, cursor, &hdr, 0, &tex->gltex);
  168. stackFreeUpToPosition(tmp, pre_alloc_cursor);
  169. if(!retval)
  170. aGLTextureDestroy(&tex->gltex);
  171. return retval;
  172. }
  173. const Texture *textureGet(const char *name, struct ICollection *collection, struct Stack *tmp) {
  174. const Texture *tex = cacheGetTexture(name);
  175. if (tex) return tex;
  176. struct IFile *texfile;
  177. if (CollectionOpen_Success != collectionChainOpen(collection, name, File_Texture, &texfile)) {
  178. PRINTF("Texture \"%s\" not found", name);
  179. return cacheGetTexture("opensource/placeholder");
  180. }
  181. struct Texture localtex;
  182. if (textureLoad(texfile, &localtex, tmp) == 0) {
  183. PRINTF("Texture \"%s\" found, but could not be loaded", name);
  184. } else {
  185. cachePutTexture(name, &localtex);
  186. tex = cacheGetTexture(name);
  187. }
  188. texfile->close(texfile);
  189. return tex ? tex : cacheGetTexture("opensource/placeholder");
  190. }