texture.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #include "texture.h"
  2. #include "etcpack.h"
  3. #include "dxt.h"
  4. #include "vtf.h"
  5. #include "cache.h"
  6. #include "collection.h"
  7. #include "mempools.h"
  8. #include "common.h"
  9. const char *vtfFormatStr(enum VTFImageFormat fmt) {
  10. switch(fmt) {
  11. case VTFImage_None: return "None";
  12. case VTFImage_RGBA8: return "RGBA8";
  13. case VTFImage_ABGR8: return "ABGR8";
  14. case VTFImage_RGB8: return "RGB8";
  15. case VTFImage_BGR8: return "BGR8";
  16. case VTFImage_RGB565: return "RGB565";
  17. case VTFImage_I8: return "I8";
  18. case VTFImage_IA8: return "IA8";
  19. case VTFImage_P8: return "P8";
  20. case VTFImage_A8: return "A8";
  21. case VTFImage_RGB8_Bluescreen: return "RGB8_Bluescreen";
  22. case VTFImage_BGR8_Bluescreen: return "BGR8_Bluescreen";
  23. case VTFImage_ARGB8: return "ARGB8";
  24. case VTFImage_BGRA8: return "BGRA8";
  25. case VTFImage_DXT1: return "DXT1";
  26. case VTFImage_DXT3: return "DXT3";
  27. case VTFImage_DXT5: return "DXT5";
  28. case VTFImage_BGRX8: return "BGRX8";
  29. case VTFImage_BGR565: return "BGR565";
  30. case VTFImage_BGRX5551: return "BGRX5551";
  31. case VTFImage_BGRA4: return "BGRA4";
  32. case VTFImage_DXT1_A1: return "DXT1_A1";
  33. case VTFImage_BGRA5551: return "BGRA5551";
  34. case VTFImage_UV8: return "UV8";
  35. case VTFImage_UVWQ8: return "UVWQ8";
  36. case VTFImage_RGBA16F: return "RGBA16F";
  37. case VTFImage_RGBA16: return "RGBA16";
  38. case VTFImage_UVLX8: return "UVLX8";
  39. }
  40. return "None";
  41. }
  42. static int vtfImageSize(enum VTFImageFormat fmt, int width, int height) {
  43. int pixel_bits = 0;
  44. switch(fmt) {
  45. case VTFImage_None: break;
  46. case VTFImage_RGBA8:
  47. case VTFImage_ABGR8:
  48. case VTFImage_ARGB8:
  49. case VTFImage_BGRA8:
  50. case VTFImage_BGRX8:
  51. case VTFImage_UVWQ8:
  52. case VTFImage_UVLX8:
  53. pixel_bits = 32;
  54. break;
  55. case VTFImage_BGR565:
  56. case VTFImage_BGRX5551:
  57. case VTFImage_BGRA5551:
  58. case VTFImage_BGRA4:
  59. case VTFImage_RGB565:
  60. case VTFImage_UV8:
  61. pixel_bits = 16;
  62. break;
  63. case VTFImage_RGB8:
  64. case VTFImage_BGR8:
  65. case VTFImage_RGB8_Bluescreen:
  66. case VTFImage_BGR8_Bluescreen:
  67. pixel_bits = 24;
  68. break;
  69. case VTFImage_I8:
  70. case VTFImage_IA8:
  71. case VTFImage_P8:
  72. case VTFImage_A8:
  73. pixel_bits = 8;
  74. break;
  75. case VTFImage_DXT3:
  76. case VTFImage_DXT5:
  77. pixel_bits = 4;
  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 void textureUnpackDXTto565(uint8_t *src, uint16_t *dst, int width, int height, enum VTFImageFormat format) {
  92. const struct DXTUnpackContext dxt_ctx = {
  93. .width = width,
  94. .height = height,
  95. .packed = src,
  96. .output = dst
  97. };
  98. if (format == VTFImage_DXT1)
  99. dxt1Unpack(dxt_ctx);
  100. else
  101. dxt5Unpack(dxt_ctx);
  102. }
  103. static void textureUnpackBGR8to565(uint8_t *src, uint16_t *dst, int width, int height) {
  104. const int pixels = width * height;
  105. for (int i = 0; i < pixels; ++i, src+=3) {
  106. const int r = (src[0] >> 3) << 11;
  107. const int g = (src[1] >> 2) << 5;
  108. const int b = (src[2] >> 3);
  109. dst[i] = r | g | b;
  110. }
  111. }
  112. static void textureUnpackBGRX8to565(uint8_t *src, uint16_t *dst, int width, int height) {
  113. const int pixels = width * height;
  114. for (int i = 0; i < pixels; ++i, src+=4) {
  115. const int r = (src[0] & 0xf8) << 8;
  116. const int g = (src[1] & 0xfc) << 3;
  117. const int b = (src[2] >> 3);
  118. dst[i] = r | g | b;
  119. }
  120. }
  121. static void textureUnpackBGRA8to565(uint8_t *src, uint16_t *dst, int width, int height) {
  122. const int pixels = width * height;
  123. for (int i = 0; i < pixels; ++i, src+=4) {
  124. const int a = src[3] * 8; /* FIXME this is likely HDR and need proper color correction */
  125. const int r = ((a * src[0]) >> 11);
  126. const int g = ((a * src[1]) >> 10);
  127. const int b = (a * src[2]) >> 11;
  128. dst[i] = ((r>31?31:r) << 11) | ((g>63?63:g) << 5) | (b>31?31:b);
  129. }
  130. }
  131. /* FIXME: taken from internets: https://gist.github.com/martinkallman/5049614 */
  132. float float32(uint16_t value) {
  133. const uint32_t result =
  134. (((value & 0x7fffu) << 13) + 0x38000000u) | // mantissa + exponent
  135. ((value & 0x8000u) << 16); // sign
  136. float retval;
  137. memcpy(&retval, &result, sizeof(retval));
  138. return retval;
  139. }
  140. static void textureUnpackRGBA16Fto565(const uint16_t *src, uint16_t *dst, int width, int height) {
  141. const int pixels = width * height;
  142. for (int i = 0; i < pixels; ++i, src+=4) {
  143. const float scale = 255.f * 1.5f;
  144. const int rf = (int)(sqrtf(float32(src[0])) * scale) >> 3;
  145. const int gf = (int)(sqrtf(float32(src[1])) * scale) >> 2;
  146. const int bf = (int)(sqrtf(float32(src[2])) * scale) >> 3;
  147. dst[i] = ((rf>31?31:rf) << 11) | ((gf>63?63:gf) << 5) | (bf>31?31:bf);
  148. }
  149. }
  150. static uint16_t *textureUnpackToTemp(struct Stack *tmp, struct IFile *file, size_t cursor,
  151. int width, int height, enum VTFImageFormat format) {
  152. const int src_texture_size = vtfImageSize(format, width, height);
  153. const int dst_texture_size = sizeof(uint16_t) * width * height;
  154. void *dst_texture = stackAlloc(tmp, dst_texture_size);
  155. if (!dst_texture) {
  156. PRINTF("Cannot allocate %d bytes for texture", dst_texture_size);
  157. return 0;
  158. }
  159. void *src_texture = stackAlloc(tmp, src_texture_size);
  160. if (!src_texture) {
  161. PRINTF("Cannot allocate %d bytes for texture", src_texture_size);
  162. return 0;
  163. }
  164. if (src_texture_size != (int)file->read(file, cursor, src_texture_size, src_texture)) {
  165. PRINT("Cannot read texture data");
  166. return 0;
  167. }
  168. switch (format) {
  169. case VTFImage_DXT1:
  170. case VTFImage_DXT5:
  171. textureUnpackDXTto565(src_texture, dst_texture, width, height, format);
  172. break;
  173. case VTFImage_BGR8:
  174. textureUnpackBGR8to565(src_texture, dst_texture, width, height);
  175. break;
  176. case VTFImage_BGRA8:
  177. textureUnpackBGRA8to565(src_texture, dst_texture, width, height);
  178. break;
  179. case VTFImage_BGRX8:
  180. textureUnpackBGRX8to565(src_texture, dst_texture, width, height);
  181. break;
  182. case VTFImage_RGBA16F:
  183. textureUnpackRGBA16Fto565(src_texture, dst_texture, width, height);
  184. break;
  185. default:
  186. PRINTF("Unsupported texture format %s", vtfFormatStr(format));
  187. return 0;
  188. }
  189. stackFreeUpToPosition(tmp, src_texture);
  190. return dst_texture;
  191. }
  192. static int textureUploadMipmapType(struct Stack *tmp, struct IFile *file, size_t cursor,
  193. const struct VTFHeader *hdr, int miplevel, RTexture *tex, RTexType tex_type) {
  194. for (int mip = hdr->mipmap_count - 1; mip > miplevel; --mip) {
  195. const unsigned int mip_width = hdr->width >> mip;
  196. const unsigned int mip_height = hdr->height >> mip;
  197. const int mip_image_size = vtfImageSize(hdr->hires_format, mip_width, mip_height);
  198. cursor += mip_image_size * hdr->frames;
  199. /*PRINTF("cur: %d; size: %d, mip: %d, %dx%d",
  200. cursor, mip_image_size, mip, mip_width, mip_height);
  201. */
  202. }
  203. void *dst_texture = textureUnpackToTemp(tmp, file, cursor, hdr->width, hdr->height, hdr->hires_format);
  204. if (!dst_texture) {
  205. PRINT("Failed to unpack texture");
  206. return 0;
  207. }
  208. #ifdef ATTO_PLATFORM_RPI
  209. {
  210. const uint16_t *p565 = dst_texture;
  211. uint8_t *etc1_data = stackAlloc(tmp, hdr->width * hdr->height / 2);
  212. uint8_t *block = etc1_data;
  213. // FIXME assumes w and h % 4 == 0
  214. for (int by = 0; by < hdr->height; by += 4) {
  215. for (int bx = 0; bx < hdr->width; bx += 4) {
  216. const uint16_t *bp = p565 + bx + by * hdr->width;
  217. ETC1Color ec[16];
  218. for (int x = 0; x < 4; ++x) {
  219. for (int y = 0; y < 4; ++y) {
  220. const unsigned p = bp[x + y * hdr->width];
  221. ec[x*4+y].r = (p & 0xf800u) >> 8;
  222. ec[x*4+y].g = (p & 0x07e0u) >> 3;
  223. ec[x*4+y].b = (p & 0x001fu) << 3;
  224. }
  225. }
  226. etc1PackBlock(ec, block);
  227. block += 8;
  228. }
  229. }
  230. const RTextureUploadParams params = {
  231. .type = tex_type,
  232. .width = hdr->width,
  233. .height = hdr->height,
  234. .format = RTexFormat_Compressed_ETC1,
  235. .pixels = etc1_data,
  236. .mip_level = -2,//miplevel,
  237. .wrap = RTexWrap_Repeat
  238. };
  239. renderTextureUpload(tex, params);
  240. stackFreeUpToPosition(tmp, etc1_data);
  241. }
  242. #else
  243. const RTextureUploadParams params = {
  244. .type = tex_type,
  245. .width = hdr->width,
  246. .height = hdr->height,
  247. .format = RTexFormat_RGB565,
  248. .pixels = dst_texture,
  249. .mip_level = -1,//miplevel,
  250. .wrap = RTexWrap_Repeat
  251. };
  252. renderTextureUpload(tex, params);
  253. #endif
  254. return 1;
  255. }
  256. static int textureLoad(struct IFile *file, Texture *tex, struct Stack *tmp, RTexType type) {
  257. struct VTFHeader hdr;
  258. size_t cursor = 0;
  259. int retval = 0;
  260. if (file->read(file, 0, sizeof(hdr), &hdr) != sizeof(hdr)) {
  261. PRINT("Cannot read texture");
  262. return 0;
  263. }
  264. if (hdr.signature[0] != 'V' || hdr.signature[1] != 'T' ||
  265. hdr.signature[2] != 'F' || hdr.signature[3] != '\0') {
  266. PRINT("Invalid file signature");
  267. return 0;
  268. }
  269. /*
  270. if (!(hdr.version[0] > 7 || hdr.version[1] > 2)) {
  271. PRINTF("VTF version %d.%d is not supported", hdr.version[0], hdr.version[1]);
  272. return 0;
  273. }
  274. */
  275. //PRINTF("Texture: %dx%d, %s",
  276. // hdr.width, hdr.height, vtfFormatStr(hdr.hires_format));
  277. /*
  278. if (hdr.hires_format != VTFImage_DXT1 && hdr.hires_format != VTFImage_DXT5 && hdr.hires_format != VTFImage_BGR8) {
  279. PRINTF("Not implemented texture format: %s", vtfFormatStr(hdr.hires_format));
  280. return 0;
  281. }
  282. */
  283. cursor += hdr.header_size;
  284. /* Compute averaga color from lowres image */
  285. void *pre_alloc_cursor = stackGetCursor(tmp);
  286. if (hdr.lores_format != VTFImage_DXT1 && hdr.lores_format != VTFImage_DXT5) {
  287. PRINTF("Not implemented lores texture format: %s", vtfFormatStr(hdr.lores_format));
  288. tex->avg_color = aVec3ff(1.f);
  289. } else {
  290. uint16_t *pixels = textureUnpackToTemp(tmp, file, cursor, hdr.lores_width, hdr.lores_height, hdr.lores_format);
  291. if (!pixels) {
  292. PRINT("Cannot unpack lowres image");
  293. return 0;
  294. }
  295. tex->avg_color = aVec3ff(0);
  296. const int pixels_count = hdr.lores_width * hdr.lores_height;
  297. for (int i = 0; i < pixels_count; ++i) {
  298. tex->avg_color.x += (pixels[i] >> 11);
  299. tex->avg_color.y += (pixels[i] >> 5) & 0x3f;
  300. tex->avg_color.z += (pixels[i] & 0x1f);
  301. }
  302. tex->avg_color = aVec3fMul(tex->avg_color,
  303. aVec3fMulf(aVec3f(1.f/31.f, 1.f/63.f, 1.f/31.f), 1.f / pixels_count));
  304. //PRINTF("Average color %f %f %f", tex->avg_color.x, tex->avg_color.y, tex->avg_color.z);
  305. }
  306. cursor += vtfImageSize(hdr.lores_format, hdr.lores_width, hdr.lores_height);
  307. /*
  308. PRINTF("Texture lowres: %dx%d, %s; mips %d; header_size: %u",
  309. hdr.lores_width, hdr.lores_height, vtfFormatStr(hdr.lores_format), hdr.mipmap_count, hdr.header_size);
  310. */
  311. for (int mip = 0; mip <= 0/*< hdr.mipmap_count*/; ++mip) {
  312. retval = textureUploadMipmapType(tmp, file, cursor, &hdr, mip, &tex->texture, type);
  313. if (retval != 1)
  314. break;
  315. }
  316. stackFreeUpToPosition(tmp, pre_alloc_cursor);
  317. return retval;
  318. }
  319. const Texture *textureGet(const char *name, struct ICollection *collection, struct Stack *tmp) {
  320. const Texture *tex = cacheGetTexture(name);
  321. if (tex) return tex;
  322. struct IFile *texfile;
  323. if (CollectionOpen_Success != collectionChainOpen(collection, name, File_Texture, &texfile)) {
  324. PRINTF("Texture \"%s\" not found", name);
  325. return cacheGetTexture("opensource/placeholder");
  326. }
  327. struct Texture localtex;
  328. renderTextureInit(&localtex.texture);
  329. if (textureLoad(texfile, &localtex, tmp, RTexType_2D) == 0) {
  330. PRINTF("Texture \"%s\" found, but could not be loaded", name);
  331. } else {
  332. cachePutTexture(name, &localtex);
  333. tex = cacheGetTexture(name);
  334. }
  335. texfile->close(texfile);
  336. return tex ? tex : cacheGetTexture("opensource/placeholder");
  337. }