textureAtlas.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dirent.h>
  5. #include <unistd.h>
  6. #include "hash.h"
  7. #include "texture.h"
  8. // for debugging
  9. #include "dumpImage.h"
  10. TextureAtlas* TextureAtlas_alloc() {
  11. TextureAtlas* ta;
  12. ta = calloc(1, sizeof(*ta));
  13. TextureAtlas_init(ta);
  14. return ta;
  15. }
  16. void TextureAtlas_init(TextureAtlas* ta) {
  17. VEC_INIT(&ta->sources);
  18. VEC_INIT(&ta->atlas);
  19. HT_init(&ta->items, 4);
  20. }
  21. void TextureAtlas_addPNG(TextureAtlas* ta, char* path) {
  22. BitmapRGBA8 bmp;
  23. TextureAtlasSource* src;
  24. int ret;
  25. char* name = "fixme";
  26. bmp.data = NULL;
  27. ret = readPNG2(path, &bmp);
  28. if(ret) {
  29. if(bmp.data) free(bmp.data);
  30. return;
  31. }
  32. src = calloc(1, sizeof(*src));
  33. src->name = strdup(name);
  34. src->size.x = bmp.width;
  35. src->size.y = bmp.height;
  36. src->aspectRatio = src->size.x / src->size.y;
  37. src->data = (void*)bmp.data;
  38. VEC_PUSH(&ta->sources, src);
  39. }
  40. // not the most efficient function. could use some optimization later.
  41. void TextureAtlas_addFolder(TextureAtlas* ta, char* prefix, char* dirPath, int recursive) {
  42. DIR* d;
  43. struct dirent *dir;
  44. char* path;
  45. int prefixlen = strlen(prefix);
  46. d = opendir(dirPath);
  47. if(!d) return;
  48. while(dir = readdir(d)) {
  49. if(0 == strncmp(dir->d_name, ".", 1)) continue;
  50. if(0 == strncmp(dir->d_name, "..", 2)) continue;
  51. path = pathJoin(dirPath, dir->d_name);
  52. if(dir->d_type == DT_REG) { // regular file
  53. int namelen;
  54. char* ext = pathExt2(dir->d_name, &namelen);
  55. char* name = malloc(namelen + prefixlen + 2);
  56. strcpy(name, prefix);
  57. strcat(name, "/");
  58. strncat(name, dir->d_name, namelen);
  59. if(streq(ext, "png")) {
  60. // printf("loading '%s' into atlas as '%s'\n", path, name);
  61. TextureAtlas_addPNG(ta, path);
  62. }
  63. free(name);
  64. }
  65. else if(recursive && dir->d_type == DT_DIR) {
  66. char* dirpre = pathJoin(prefix, dir->d_name);
  67. TextureAtlas_addFolder(ta, dirpre, path, 1);
  68. free(dirpre);
  69. }
  70. free(path);
  71. }
  72. closedir(d);
  73. }
  74. static void blit32(
  75. int src_x, int src_y, int dst_x, int dst_y, int w, int h,
  76. int src_w, int dst_w, uint32_t* src, uint32_t* dst) {
  77. int y, x, s, d;
  78. for(y = 0; y < h; y++) {
  79. for(x = 0; x < w; x++) {
  80. s = ((y + src_y) * src_w) + src_x + x;
  81. d = ((y + dst_y) * dst_w) + dst_x + x;
  82. dst[d] = src[s];
  83. }
  84. }
  85. }
  86. // sort tallest and widest first
  87. static int source_sort_comp(const void* aa, const void * bb) {
  88. TextureAtlasSource* a = *((TextureAtlasSource**)aa);
  89. TextureAtlasSource* b = *((TextureAtlasSource**)bb);
  90. if(a->size.y == b->size.y) {
  91. return b->size.x - a->size.x;
  92. }
  93. else {
  94. return b->size.y - a->size.y;
  95. }
  96. }
  97. void TextureAtlas_finalize(TextureAtlas* ta) {
  98. char buf[32]; // for debugging
  99. if(VEC_LEN(&ta->sources) == 0) {
  100. printf("Texture atlas finalized without any sources\n");
  101. return;
  102. }
  103. VEC_SORT(&ta->sources, source_sort_comp);
  104. int width = ta->width;
  105. int width2 = width * width;
  106. float fwidth = width;
  107. uint32_t* texData = malloc(sizeof(*texData) * width2);
  108. memset(texData, 0, sizeof(*texData) * width2);
  109. int row = 0;
  110. int hext = 0;
  111. int prevhext = VEC_ITEM(&ta->sources, 0)->size.y;
  112. int rowWidth = 0;
  113. VEC_EACH(&ta->sources, ind, src) {
  114. if(rowWidth + src->size.x > width) {
  115. row++;
  116. rowWidth = 0;
  117. hext += prevhext;
  118. prevhext = src->size.y;
  119. // next texture
  120. if(hext + prevhext > width) { // the texture is square; width == height
  121. VEC_PUSH(&ta->atlas, texData);
  122. // sprintf(buf, "texatlas-%d.png", VEC_LEN(&ta->atlas));
  123. // writePNG(buf, 4, texData, width, width);
  124. //
  125. texData = malloc(sizeof(*texData) * width2);
  126. memset(texData, 0, sizeof(*texData) * width2);
  127. hext = 0;
  128. }
  129. }
  130. // blit the sdf bitmap data
  131. blit32(
  132. 0, 0, // src x and y offset for the image
  133. rowWidth, hext, // dst offset
  134. src->size.x, src->size.y, // width and height
  135. src->size.x, width, // src and dst row widths
  136. (void*)src->data, // source
  137. texData); // destination
  138. TextureAtlasItem* it = calloc(1, sizeof(it));
  139. *it = (TextureAtlasItem){
  140. .offsetPx = {rowWidth, hext},
  141. .offsetNorm = {(float)rowWidth / fwidth, (float)hext / fwidth},
  142. .sizePx = src->size,
  143. .sizeNorm = {src->size.x / fwidth, src->size.y / fwidth},
  144. .index = VEC_LEN(&ta->atlas)
  145. };
  146. // printf("added icon '%s'\n", src->name);
  147. HT_set(&ta->items, strdup(src->name), it);
  148. rowWidth += src->size.x;
  149. // writePNG("sourceour.png", 4, src->data, src->size.x, src->size.y);
  150. free(src->name);
  151. free(src->data);
  152. free(src);
  153. // break;
  154. }
  155. // printf("last push %p\n", texData);
  156. VEC_PUSH(&ta->atlas, texData);
  157. // sprintf(buf, "texatlas-%d.png", VEC_LEN(&ta->atlas));
  158. // writePNG(buf, 4, texData, width, width);
  159. }
  160. // bump on format changes. there is no backward compatibility. saving is for caching only.
  161. static uint16_t TEXTURE_ATLAS_FILE_VERSION = 0;
  162. void TextureAtlas_saveAtlas(TextureAtlas* ta, char* path) {
  163. }
  164. int TextureAtlas_loadAtlas(TextureAtlas* ta, char* path) {
  165. }