main.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/sysinfo.h>
  5. #include "texture.h"
  6. #include "ds.h"
  7. static char* strappend(char* a, const char* const b);
  8. static char* strappendf(char* a, const char* const b);
  9. static char* strappendf(char* a, const char* const b) {
  10. char* o = strappend(a, b);
  11. free(a);
  12. return o;
  13. }
  14. static char* strappend(char* a, const char* const b) {
  15. if(a == NULL) return strdup(b);
  16. if(b == NULL) return a;
  17. size_t la = strlen(a);
  18. size_t lb = strlen(b);
  19. char* o = malloc(la + lb + 1);
  20. strcpy(o, a);
  21. strcpy(o + la, b);
  22. o[la + lb] = '\0';
  23. return o;
  24. }
  25. char* helpText = "" \
  26. "Usage:\n" \
  27. "atlasgen [GLOBAL OPTION]... [-f FONT SIZES [OPTION]...]... [outfile]\n" \
  28. "\n" \
  29. "EXAMPLE:\n" \
  30. " atlasgen -b -m 8 -o 4 -t 256 -f \"Courier\" 8,12,16 -i -f \"Arial\" 32 myfonts_sdf\n" \
  31. " -b - generate bold for all fonts\n" \
  32. " -m 8 - SDF magnitude of 8 pixels\n" \
  33. " -o 4 - oversample by 4x\n" \
  34. " -t 256 - output textures have 256px dimensions\n" \
  35. " -f \"Courier\" - first font name \n" \
  36. " 8,12,16 - generate outputs of size 8, 12, and 16 px for this font \n" \
  37. " -i - also generate italic for this font\n" \
  38. " -f \"Arial\" - second font name \n" \
  39. " 32 - generate outputs of size 32px for this font \n" \
  40. " myfonts_sdf - output will be myfonts_sdf_[n].png and myfonts_sdf.json\n" \
  41. "\n" \
  42. "OPTIONS:\n" \
  43. " All Font Options can be included as global options for all fonts.\n" \
  44. " -f ... Add a font to render\n" \
  45. " -J Specify the output JSON file name\n" \
  46. " -l N Limit computation to N threads\n" \
  47. " -m SDF magnitude in pixels. Default 8.\n" \
  48. " -o Amount of pixels to oversample by. Default 16.\n" \
  49. " -P FORMAT Specify the png file name; %d will be expanded to the index.\n" \
  50. " -q Quiet. Suppress all output, even warnings and errors.\n" \
  51. " -t [N|fit] Size of output texture in pixels\n" \
  52. " 'fit' generates a single texture large enough to hold all images\n" \
  53. " -v Verbose.\n" \
  54. "\n" \
  55. "MISC OPTIONS:\n" \
  56. " --help Print this message and exit\n" \
  57. " --pretend Verify parameters but do not actually generate output.\n" \
  58. ;
  59. int main(int argc, char* argv[]) {
  60. int an;
  61. #define default_outfile "atlas-output"
  62. #define default_png_outfile default_outfile "-%d";
  63. char* outfile = NULL;
  64. char* json_outfile = NULL;
  65. char* png_outfile = NULL;
  66. int maxCores = get_nprocs();
  67. int verbose = 0;
  68. char pretend = 0;
  69. int texSize = 0;
  70. VEC(char*) imagePaths;
  71. VEC_INIT(&imagePaths);
  72. for(an = 1; an < argc; an++) {
  73. char* arg = argv[an];
  74. if(arg[0] != '-') {
  75. VEC_PUSH(&imagePaths, arg);
  76. }
  77. if(0 == strcmp(arg, "--")) {
  78. printf("invalid usage of '--'\n");
  79. exit(1);
  80. };
  81. if(0 == strcmp(arg, "--help")) {
  82. puts(helpText);
  83. exit(0);
  84. }
  85. if(0 == strcmp(arg, "-J")) {
  86. an++;
  87. json_outfile = strdup(argv[an]);
  88. continue;
  89. }
  90. if(0 == strcmp(arg, "-l")) {
  91. an++;
  92. int n = strtol(argv[an], NULL, 10);
  93. if(n > 0) maxCores = n;
  94. continue;
  95. }
  96. // oversample
  97. if(0 == strcmp(arg, "-o")) {
  98. // an++;
  99. // int n = strtol(argv[an], NULL, 10);
  100. // if(n > 0) oversample = n;
  101. continue;
  102. }
  103. if(0 == strcmp(arg, "-P")) {
  104. an++;
  105. png_outfile = strdup(argv[an]);
  106. continue;
  107. }
  108. if(0 == strcmp(arg, "--pretend")) {
  109. pretend = 1;
  110. continue;
  111. }
  112. if(0 == strcmp(arg, "-q")) {
  113. verbose = -1;
  114. continue;
  115. }
  116. if(0 == strcmp(arg, "-t")) {
  117. an++;
  118. arg = argv[an];
  119. if(0 == strcmp(arg, "fit")) {
  120. texSize = 0;
  121. }
  122. else {
  123. int n = strtol(arg, NULL, 10);
  124. if(n > 0) texSize = n;
  125. }
  126. continue;
  127. }
  128. if(0 == strcmp(arg, "-v")) {
  129. verbose = 1;
  130. continue;
  131. }
  132. if(0 == strcmp(arg, "-vv")) {
  133. verbose = 2;
  134. continue;
  135. }
  136. // output file
  137. // TODO: check for -'s and error
  138. }
  139. // check and print the options
  140. if(!outfile) {
  141. json_outfile = default_outfile;
  142. png_outfile = default_png_outfile;
  143. }
  144. else {
  145. if(!json_outfile) {
  146. json_outfile = outfile;
  147. }
  148. if(!png_outfile) {
  149. png_outfile = outfile;
  150. }
  151. }
  152. // TODO: check for and append %d if needed
  153. // TODO: check for and append .png and .json
  154. json_outfile = strappend(json_outfile, ".json");
  155. png_outfile = strappend(png_outfile, ".png");
  156. // sanity check
  157. if(texSize > 0 && texSize < 16 ) {
  158. if(verbose >= 0) printf("WARNING: Texure Size is suspiciously low: %dpx\n", texSize);
  159. }
  160. // check for power of 2
  161. if(texSize > 0 && (texSize != (texSize & (1 - texSize)))) {
  162. if(verbose >= 0) printf("WARNING: Texure Size is not a power of two: %dpx\n GPUs like power of two textures.\n", texSize);
  163. }
  164. if(verbose >= 1) {
  165. printf("JSON output: %s\n", json_outfile);
  166. printf("PNG output: %s\n", png_outfile);
  167. printf("Verbosity: %d\n", verbose);
  168. printf("Max Threads: %d\n", maxCores);
  169. if(texSize == 0) {
  170. printf("Tex Size: fit\n");
  171. }
  172. else {
  173. printf("Tex Size: %dx%d\n", texSize, texSize);
  174. }
  175. }
  176. // start rendering
  177. if(pretend) {
  178. if(verbose >= 0) printf("Skipping generation (--pretend)\n");
  179. }
  180. else {
  181. if(0 == VEC_LEN(&imagePaths)) {
  182. if(verbose >= 0) printf("Nothing to generate. Check your options (use -v).\n");
  183. exit(0);
  184. }
  185. TextureAtlas* tm;
  186. tm = TextureAtlas_alloc();
  187. tm->pngFileFormat = png_outfile;
  188. // fm->maxThreads = maxCores;
  189. tm->verbose = verbose;
  190. tm->maxAtlasSize = texSize;
  191. VEC_EACH(&imagePaths, ii, ip) {
  192. TextureAtlas_addPNG(tm, ip);
  193. }
  194. TextureAtlas_finalize(tm);
  195. // FontManager_createAtlas(fm);
  196. // FontManager_saveJSON(fm, json_outfile);
  197. // FontManager_saveAtlas(fm, "fonts.atlas");
  198. }
  199. return 0;
  200. }
  201. char* pathJoin(const char* a, const char* b) {
  202. int alen, blen;
  203. char* o;
  204. alen = a ? strlen(a) : 0;
  205. blen = b ? strlen(b) : 0;
  206. o = malloc(alen + blen + 2);
  207. strcpy(o, a ? a : "");
  208. o[alen] = '/'; // TODO: fix the concat here
  209. strcpy(o + alen + 1, b ? b : "");
  210. o[alen + blen + 1] = 0;
  211. return o;
  212. }
  213. // gets a pointer to the first character of the file extension, or to the null terminator if none
  214. const char* pathExt(const char* path) {
  215. int i;
  216. int len = strlen(path);
  217. for(i = len - 1; i >= 0; i--) {
  218. char c = path[i];
  219. if(c == '.') return path + i;
  220. else if(c == '/') break;
  221. }
  222. return path + len;
  223. }
  224. // gets a pointer to the first character of the file extension, or to the null terminator if none
  225. // also provides the length of the path without the period and extension
  226. const char* pathExt2(const char* path, int* end) {
  227. int i;
  228. int len = strlen(path);
  229. for(i = len - 1; i >= 0; i--) {
  230. char c = path[i];
  231. if(c == '.') {
  232. if(end) *end = i > 0 ? i : 0;
  233. return path + i + 1;
  234. }
  235. else if(c == '/') break;
  236. }
  237. if(end) *end = len;
  238. return path + len;
  239. }