fifi.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. #include <stdarg.h>
  2. #include <allegro5/allegro_ttf.h>
  3. #include "eruta.h"
  4. #include "fifi.h"
  5. #include "monolog.h"
  6. /* Fifi contain functionality that helps finding back the file resouces,
  7. such as images, music, etc that Eruta needs.
  8. An important concept here is the "virtual path", that is the path under the
  9. location of the data directory. So, for example, if the data of the
  10. app is installed on Linux in /usr/share/app/data,
  11. then a vpath of
  12. font/my_nice_font.ttf
  13. will be resolved as
  14. /usr/share/app/data/font/my_nice_font.ttf.
  15. Or, if, on another OS, the data of the app is installed in
  16. C:\Program Files\App\data
  17. then the same vpath will refer to
  18. C:\Program Files\App\data\font\my_nice_font.ttf.
  19. So Fifi is a nice way to get OS-independence and location-independence of
  20. the data files all at once.
  21. For save files or scores, the vpath is similar, but relative to the
  22. "writeable" directory of the application.
  23. */
  24. /*
  25. Some tests with al_get_standard_path:
  26. ALLEGRO_RESOURCES_PATH: /usr/local/var/arch/bjmey/src/eruta/bin/
  27. This could be useful to look for the resouces, look in
  28. ALLEGRO_RESOURCES_PATH/data
  29. ALLEGRO_RESOURCES_PATH/share/data
  30. ALLEGRO_RESOURCES_PATH/share
  31. ALLEGRO_RESOURCES_PATH/../data
  32. ALLEGRO_RESOURCES_PATH/../share/data
  33. ALLEGRO_RESOURCES_PATH/../share
  34. for the file eruta.txt to find back the resources.
  35. Also it looks for:
  36. ALLEGRO_RESOURCES_PATH/data.zip
  37. ALLEGRO_RESOURCES_PATH/share/data.zip
  38. ALLEGRO_RESOURCES_PATH/../data.zip
  39. ALLEGRO_RESOURCES_PATH/../share/data.zip
  40. /usr/local/var/arch/bjmey/src/eruta/../data
  41. ALLEGRO_EXENAME_PATH: ~/src/eruta/bin/eruta
  42. RESOURCES_PATH: /usr/local/var/arch/bjmey/dl/varia/allegro-5.0.5/examples/
  43. TEMP_PATH: /tmp/
  44. USER_DATA_PATH: /home/bjmey/.local/share/liballeg.org/ex_get_path/
  45. */
  46. /** Helper for al_path_cstr. */
  47. const char * fifi_path_cstr(Path * path) {
  48. if(!path) return NULL;
  49. return al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP);
  50. }
  51. /** Helper for al_filename_exists with a path. */
  52. int fifi_path_exists(Path * path) {
  53. if(!path) return 0;
  54. return al_filename_exists(fifi_path_cstr(path));
  55. }
  56. /*
  57. static ALLEGRO_PATH * fifi_try_path(ALLEGRO_PATH base, char * name) {
  58. al_
  59. }
  60. */
  61. /* This is the path where the resources of Eruta are stored. */
  62. ALLEGRO_PATH * fifi_data_path_ = NULL;
  63. /* Looks for the data folder in various places, return NULL if not found. */
  64. static ALLEGRO_PATH * fifi_find_data_path(void) {
  65. char * cwd;
  66. ALLEGRO_PATH * path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
  67. // ALLEGRO_RESOURCES_PATH is normally where the program itself is installed.
  68. // ALLEGRO_RESOURCES_PATH/data (Windows-ish)
  69. al_append_path_component(path, "data");
  70. if(PATH_EXISTS(path)) return path;
  71. al_remove_path_component(path, -1);
  72. // ALLEGRO_RESOURCES_PATH/../data (Local install, linux-ish)
  73. al_replace_path_component(path, -1, "data");
  74. if(PATH_EXISTS(path)) return path;
  75. // ALLEGRO_RESOURCES_PATH/../share/eruta/data (global linux-ish install)
  76. al_replace_path_component(path, -1, "share");
  77. al_append_path_component(path, "eruta");
  78. al_append_path_component(path, "data");
  79. if(PATH_EXISTS(path)) return path;
  80. al_destroy_path(path);
  81. /** $CWD /data */
  82. cwd = al_get_current_directory();
  83. path = al_create_path_for_directory(cwd);
  84. al_free(cwd);
  85. al_append_path_component(path, "data");
  86. if(PATH_EXISTS(path)) return path;
  87. al_destroy_path(path);
  88. return NULL;
  89. }
  90. ALLEGRO_PATH * fifi_make_data_path(void) {
  91. ALLEGRO_PATH * path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
  92. al_replace_path_component(path, -1, "data");
  93. return path;
  94. }
  95. /** Initializes the file finding dir */
  96. ALLEGRO_PATH * fifi_init(void) {
  97. fifi_data_path_ = fifi_find_data_path();
  98. if (fifi_data_path_) {
  99. LOG("Data path: %s\n", PATH_CSTR(fifi_data_path_));
  100. } else {
  101. LOG_WARNING("NULL data path!\n");
  102. }
  103. return fifi_data_path_ ;
  104. }
  105. /** Returns a pointer to the data path. Must be cloned before use.*/
  106. ALLEGRO_PATH * fifi_data_path(void) {
  107. return fifi_data_path_;
  108. }
  109. /** Returns a pointer to the data path converted to a c string. */
  110. const char * fifi_data_path_cstr(void) {
  111. return al_path_cstr(fifi_data_path(), ALLEGRO_NATIVE_PATH_SEP);
  112. }
  113. /**
  114. * Returns an ALLEGRO_PATH path concatenated with the
  115. * const char * strings in args, of which the last one should be NULL.
  116. * modifies * path
  117. */
  118. static ALLEGRO_PATH * path_append_va(ALLEGRO_PATH * path, va_list args) {
  119. const char * aid;
  120. if(!path) return NULL;
  121. for(aid = va_arg(args, const char *); aid; aid = va_arg(args, const char *)){
  122. al_append_path_component(path, aid);
  123. }
  124. return path;
  125. }
  126. /**
  127. * Returns an ALLEGRO_PATH path concatednated with the
  128. * const char * strings, of which the last one should be NULL.
  129. */
  130. static ALLEGRO_PATH * path_append(ALLEGRO_PATH * path, ...) {
  131. ALLEGRO_PATH * result;
  132. va_list args;
  133. va_start(args, path);
  134. result = path_append_va(path, args);
  135. va_end(args);
  136. return result;
  137. }
  138. /**
  139. * helper like strncpy, but null terminates. Takes space and size
  140. * amount is actual characters to copy , space is space available.
  141. * Does nothing if space is less than 1.
  142. */
  143. static char *help_strncpy(char * dest, const char * src, size_t amount, size_t space){
  144. if (space < 1) return NULL;
  145. if (amount > (space-1)) amount = space - 1;
  146. strncpy(dest, src, amount);
  147. dest[amount] = '\0';
  148. return dest;
  149. }
  150. /**
  151. * Helper function to split up character strings with a separator.
  152. */
  153. static char * help_strsplit(const char * in, int ch, char * store, size_t space) {
  154. char * aid = strchr(in, ch);
  155. if (aid) {
  156. help_strncpy(store, in, aid - in, space);
  157. } else {
  158. help_strncpy(store, in, strlen(in), space);
  159. }
  160. return aid;
  161. }
  162. #define PATH_APPEND_VPATH_SIZE 256
  163. /**
  164. * Returns an ALLEGRO_PATH path concatenated with the path in vpath.
  165. * The const char * vpath is split on '/' characters, and the path
  166. * is constructed like that. .. or . is not supported.
  167. * if the last part contains a . it will be added as a file part.
  168. **/
  169. static ALLEGRO_PATH * path_append_vpath(ALLEGRO_PATH * path, const char * vpath) {
  170. char part[PATH_APPEND_VPATH_SIZE], * aid;
  171. if(!vpath) return path;
  172. aid = strchr(vpath, '/');
  173. aid = help_strsplit(vpath, '/', part, PATH_APPEND_VPATH_SIZE);
  174. while(aid) {
  175. al_append_path_component(path, part);
  176. vpath = aid + 1;
  177. aid = help_strsplit(vpath, '/', part, PATH_APPEND_VPATH_SIZE);
  178. }
  179. size_t len = strlen(part);
  180. if (len > 0) {
  181. if(strchr(part, '.')) { // it's a file name
  182. al_set_path_filename(path, part);
  183. } else {
  184. al_append_path_component(path, part);
  185. }
  186. }
  187. return path;
  188. }
  189. /** Returns a path to data which has the given virtual path.
  190. * You need to free the result with al_destroy_path.
  191. */
  192. ALLEGRO_PATH * fifi_data_vpath(const char * vpath) {
  193. ALLEGRO_PATH * path = al_clone_path(fifi_data_path());
  194. return path_append_vpath(path, vpath);
  195. }
  196. /**
  197. * Returns a path to data. Last of the arguments should be NULL.
  198. * You need to free the result with al_destroy_path.
  199. * returns NULL if no such file exists.
  200. */
  201. ALLEGRO_PATH * fifi_data_pathva(const char * filename, va_list args) {
  202. ALLEGRO_PATH * path = al_clone_path(fifi_data_path());
  203. if(!path) return NULL;
  204. path_append_va(path, args);
  205. al_set_path_filename(path, filename);
  206. LOG("Loading: %s for %s\n", PATH_CSTR(path), filename);
  207. if(PATH_EXISTS(path)) { return path; }
  208. // if we get here, we must destroy the path any way.
  209. al_destroy_path(path);
  210. return NULL;
  211. }
  212. /**
  213. * Returns a path to data. Last of the arguments should be NULL.
  214. * You need to free the result with al_destroy_path.
  215. * returns NULL if no such file exists.
  216. */
  217. ALLEGRO_PATH * fifi_data_pathargs(const char * filename, ...) {
  218. ALLEGRO_PATH * path;
  219. va_list args;
  220. va_start(args, filename);
  221. path = fifi_data_pathva(filename, args);
  222. va_end(args);
  223. return path;
  224. }
  225. /**
  226. * simple test function
  227. */
  228. void fifi_data_vpath_print(const char * vpath) {
  229. ALLEGRO_PATH * path = fifi_data_vpath(vpath);
  230. LOG("Fifi data vpath: %s\n", PATH_CSTR(path));
  231. al_destroy_path(path);
  232. }
  233. /**
  234. * Loads file that is in the data directory using the given loader.
  235. * returns NULL if the file doesn't exist or wasn't loaded correctly.
  236. */
  237. void * fifi_load_vpath(FifiLoader * load, void * extra, const char * vpath) {
  238. void * data = NULL;
  239. ALLEGRO_PATH * path;
  240. if(!load) return NULL;
  241. path = fifi_data_vpath(vpath);
  242. if(!path) return NULL;
  243. if(!al_get_path_filename(path)) {
  244. LOG_WARNING("Filename not set for path: %s.\n", PATH_CSTR(path));
  245. goto cleanup;
  246. }
  247. LOG("Loading: %s for %s\n", PATH_CSTR(path), vpath);
  248. if(PATH_EXISTS(path)) {
  249. data = load(extra, PATH_CSTR(path)); // load the data
  250. } else {
  251. LOG_WARNING("File %s does not exist!?", PATH_CSTR(path));
  252. }
  253. cleanup:
  254. // if we get here, we must destroy the path any way.
  255. al_destroy_path(path);
  256. // return the data anyway.
  257. return data;
  258. }
  259. /**
  260. * Loads file that is in the data directory using the given loader.
  261. * returns NULL if the file doesn't exist or wasn't loaded correctly.
  262. */
  263. void * fifi_loadsimple_vpath(FifiSimpleLoader * load, const char * vpath) {
  264. void * data = NULL;
  265. ALLEGRO_PATH * path;
  266. if(!load) return NULL;
  267. path = fifi_data_vpath(vpath);
  268. if(!path) return NULL;
  269. if(!al_get_path_filename(path)) {
  270. LOG_WARNING("Filename not set for path: %s.\n", PATH_CSTR(path));
  271. goto cleanup;
  272. }
  273. LOG("Loading: %s for %s\n", PATH_CSTR(path), vpath);
  274. if(PATH_EXISTS(path)) {
  275. data = load(PATH_CSTR(path)); // load the data
  276. } else {
  277. LOG_WARNING("File %s does not exist!?", PATH_CSTR(path));
  278. }
  279. cleanup:
  280. // if we get here, we must destroy the path any way.
  281. al_destroy_path(path);
  282. // return the data anyway.
  283. return data;
  284. }
  285. /**
  286. * Loads file that is in the data directory using the given loader.
  287. * returns NULL if the file doesn't exist or wasn't loaded correctly.
  288. */
  289. void * fifi_loadsimple_va(FifiSimpleLoader * load, const char * filename,
  290. va_list args) {
  291. void * data = NULL;
  292. ALLEGRO_PATH * path;
  293. if(!load) return NULL;
  294. path = al_clone_path(fifi_data_path());
  295. if(!path) return NULL;
  296. path_append_va(path, args);
  297. al_set_path_filename(path, filename);
  298. LOG("Loading: %s for %s\n", PATH_CSTR(path), filename);
  299. if(PATH_EXISTS(path)) {
  300. data = load(PATH_CSTR(path)); // load the data
  301. } else {
  302. LOG_WARNING("File %s does not exist!?", PATH_CSTR(path));
  303. }
  304. // if we get here, we must destroy the path any way.
  305. al_destroy_path(path);
  306. // return the data anyway.
  307. return data;
  308. }
  309. /**
  310. * Loads file that is in the data directory using the given loader.
  311. * the filename is specified first, then the directories under which
  312. * it should be, one by one, ended with NULL
  313. * returns NULL if the file doesn't exist or wasn't loaded correctly.
  314. */
  315. void * fifi_loadsimple(FifiSimpleLoader * load, const char * filename, ...) {
  316. void * result;
  317. va_list args;
  318. va_start(args, filename);
  319. result = fifi_loadsimple_va(load, filename, args);
  320. va_end(args);
  321. return result;
  322. }
  323. /**
  324. * Loads a font from the data directory, with the given filename, size and
  325. * flags. No directory name is needed, the fonts must be in te data/font dir.
  326. */
  327. ALLEGRO_FONT * fifi_loadfont(const char * filename, int size, int flags) {
  328. ALLEGRO_FONT * font = NULL;
  329. ALLEGRO_PATH * path;
  330. path = al_clone_path(fifi_data_path());
  331. if(!path) return NULL;
  332. path_append(path, "font", NULL);
  333. al_set_path_filename(path, filename);
  334. font = al_load_font(PATH_CSTR(path), size, flags);
  335. al_destroy_path(path);
  336. return font;
  337. }
  338. /**
  339. * Loads a bitmap with the given filename under the NULL-terminated list
  340. * of subdirectory names
  341. */
  342. ALLEGRO_BITMAP * fifi_loadbitmap_va(const char * filename, va_list args) {
  343. return fifi_loadsimple_va(
  344. (FifiSimpleLoader *)al_load_bitmap, filename, args);
  345. }
  346. /**
  347. * Loads a bitmap with the given filename under the NULL-terminated list
  348. * of subdirectory names
  349. */
  350. ALLEGRO_BITMAP * fifi_loadbitmap(const char * filename, ...) {
  351. void * result;
  352. va_list args;
  353. va_start(args, filename);
  354. result = fifi_loadsimple_va(
  355. (FifiSimpleLoader *)al_load_bitmap, filename, args);
  356. va_end(args);
  357. return result;
  358. }
  359. /**
  360. * Loads a bitmap with the given vpath
  361. */
  362. ALLEGRO_BITMAP * fifi_loadbitmap_vpath(const char * vpath) {
  363. return fifi_loadsimple_vpath(
  364. (FifiSimpleLoader *)al_load_bitmap, vpath);
  365. }
  366. /** Loads an audio stream from the data directory. Since audi streams are usually music, no there's no nedto inicatet hedi, but all music must go under
  367. data/music */
  368. ALLEGRO_AUDIO_STREAM * fifi_loadaudiostream(const char *filename,
  369. size_t buffer_count, unsigned int samples) {
  370. ALLEGRO_AUDIO_STREAM * result = NULL;
  371. ALLEGRO_PATH * path;
  372. path = al_clone_path(fifi_data_path());
  373. if(!path) return NULL;
  374. path_append(path, "music", NULL);
  375. al_set_path_filename(path, filename);
  376. result = al_load_audio_stream(PATH_CSTR(path), buffer_count, samples);
  377. al_destroy_path(path);
  378. return result;
  379. }
  380. #define DATA_PATH_BUFSIZE 1024
  381. /**
  382. * returns an ALLEGRO_PATH that points to the tileset image for the given
  383. * file name. Must be destroyed after use.
  384. */
  385. ALLEGRO_PATH * fifi_tileset_filename(const char * name) {
  386. ALLEGRO_PATH * path = al_clone_path(fifi_data_path());
  387. path_append(path, "map", NULL);
  388. al_set_path_filename(path, name);
  389. return path;
  390. }
  391. /** The follwoing loadable objects exist:
  392. * 1) maps
  393. * 2) map scripts
  394. * 3) tilesets
  395. * 4) sound effects
  396. * 4) music
  397. * 5) tiles
  398. * 6) gui elements
  399. * 7) backgrounds
  400. * 8) Sprites of course!
  401. */
  402. /**
  403. * Loads a TTF font from the data directory, with the given virtual path, width, height
  404. * and flags.
  405. */
  406. ALLEGRO_FONT * fifi_load_ttf_font_stretch(const char * vpath, int w, int h, int flags) {
  407. ALLEGRO_FONT * font = NULL;
  408. ALLEGRO_PATH * path;
  409. path = fifi_data_vpath(vpath);
  410. if (!path) return NULL;
  411. font = al_load_ttf_font_stretch(PATH_CSTR(path), w, h, flags);
  412. al_destroy_path(path);
  413. return font;
  414. }
  415. /**
  416. * Loads a TTF font from the data directory, with the given virtual path, height
  417. * and flags.
  418. */
  419. ALLEGRO_FONT * fifi_load_ttf_font(const char * vpath, int h, int flags) {
  420. ALLEGRO_FONT * font = NULL;
  421. ALLEGRO_PATH * path;
  422. path = fifi_data_vpath(vpath);
  423. if (!path) return NULL;
  424. font = al_load_ttf_font(PATH_CSTR(path), h, flags);
  425. al_destroy_path(path);
  426. return font;
  427. }
  428. /**
  429. * Loads a bitmap font from the data directory, with the given virtual path,
  430. * and flags.
  431. */
  432. ALLEGRO_FONT * fifi_load_bitmap_font_flags(const char * vpath, int flags) {
  433. ALLEGRO_FONT * font = NULL;
  434. ALLEGRO_PATH * path;
  435. path = fifi_data_vpath(vpath);
  436. if (!path) return NULL;
  437. font = al_load_bitmap_font_flags(PATH_CSTR(path), flags);
  438. al_destroy_path(path);
  439. return font;
  440. }
  441. /**
  442. * Loads a bitmap font from the data directory, with the given virtual path.
  443. */
  444. ALLEGRO_FONT * fifi_load_bitmap_font(const char * vpath) {
  445. ALLEGRO_FONT * font = NULL;
  446. ALLEGRO_PATH * path;
  447. path = fifi_data_vpath(vpath);
  448. if (!path) return NULL;
  449. font = al_load_bitmap_font(PATH_CSTR(path));
  450. al_destroy_path(path);
  451. return font;
  452. }
  453. /**
  454. * Loads an audio stream from the data directory, with the given virtual path,
  455. * and parameters as per al_load_audio_stream.
  456. */
  457. ALLEGRO_AUDIO_STREAM * fifi_load_audio_stream(const char * vpath, size_t buffer_count, int samples) {
  458. ALLEGRO_AUDIO_STREAM * data = NULL;
  459. ALLEGRO_PATH * path;
  460. path = fifi_data_vpath(vpath);
  461. if (!path) return NULL;
  462. data = al_load_audio_stream(PATH_CSTR(path), buffer_count, samples);
  463. al_destroy_path(path);
  464. return data;
  465. }
  466. /**
  467. * Loads a sample from the data directory, with the given virtual path,
  468. * and parameters as per al_load_sample.
  469. */
  470. ALLEGRO_SAMPLE * fifi_load_sample(const char * vpath) {
  471. ALLEGRO_SAMPLE * data = NULL;
  472. ALLEGRO_PATH * path;
  473. path = fifi_data_vpath(vpath);
  474. if (!path) return NULL;
  475. data = al_load_sample(PATH_CSTR(path));
  476. al_destroy_path(path);
  477. return data;
  478. }
  479. /**
  480. * Loads a bitmap from the data directory, with the given virtual path,
  481. * and parameters as per al_load_bitmap_flags.
  482. */
  483. ALLEGRO_BITMAP * fifi_load_bitmap_flags(const char * vpath, int flags) {
  484. ALLEGRO_BITMAP * data = NULL;
  485. ALLEGRO_PATH * path;
  486. path = fifi_data_vpath(vpath);
  487. if (!path) return NULL;
  488. data = al_load_bitmap_flags(PATH_CSTR(path), flags);
  489. al_destroy_path(path);
  490. return data;
  491. }
  492. /**
  493. * Loads a bitmap from the data directory, with the given virtual path.
  494. */
  495. ALLEGRO_BITMAP * fifi_load_bitmap(const char * vpath) {
  496. return fifi_load_bitmap_flags(vpath, 0);
  497. }