Freeciv-3.1
Loading...
Searching...
No Matches
themespec.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2005 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14/***********************************************************************
15 Functions for handling the themespec files which describe
16 the files and contents of themes.
17 original author: David Pfitzner <dwp@mso.anu.edu.au>
18***********************************************************************/
19
20#ifdef HAVE_CONFIG_H
21#include <fc_config.h>
22#endif
23
24#include <stdio.h>
25#include <stdlib.h> /* exit */
26#include <string.h>
27
28/* utility */
29#include "capability.h"
30#include "fcintl.h"
31#include "log.h"
32#include "registry.h"
33#include "string_vector.h"
34
35/* common */
36#include "game.h"
37
38/* client */
39#include "citydlg_common.h"
40#include "client_main.h" /* for client_state() */
41
42/* gui-sdl2 */
43#include "dialogs.h"
44#include "gui_tilespec.h"
45#include "mapview.h"
46#include "sprite.h"
47
48#include "themespec.h"
49
50#define THEMESPEC_SDL2_CAPSTR "+Freeciv-2.6-sdl2-themespec duplicates_ok"
51/*
52 * Themespec capabilities acceptable to this program:
53 *
54 * +Freeciv-2.6-sdl2-themespec - basic format for Freeciv versions 2.6.x;
55 * required
56 *
57 * duplicates_ok - we can handle existence of duplicate tags
58 * (lattermost tag which appears is used; themes which
59 * have duplicates should specify "+duplicates_ok")
60 */
61
62#define SPEC_SDL2_CAPSTR "+Freeciv-3.1-sdl2-spec"
63/*
64 * Individual spec file capabilities acceptable to this program:
65 *
66 * +Freeciv-3.1-sdl2-spec - basic format for Freeciv versions 3.1.x; required
67 */
68
69#define THEMESPEC_SUFFIX ".themespec"
70
71#if 0
72/* TODO: may be useful for theme sprites, too */
73struct named_sprites {
74 ....
75};
76#endif /* 0 */
77
78struct specfile {
80 char *file_name;
81};
82
83#define SPECLIST_TAG specfile
84#define SPECLIST_TYPE struct specfile
85#include "speclist.h"
86
87#define specfile_list_iterate(list, pitem) \
88 TYPED_LIST_ITERATE(struct specfile, list, pitem)
89#define specfile_list_iterate_end LIST_ITERATE_END
90
91/*
92 * Information about an individual sprite. All fields except 'sprite' are
93 * filled at the time of the scan of the specfile. 'Sprite' is
94 * set/cleared on demand in theme_load_sprite/theme_unload_sprite.
95 */
98
99 /* The sprite is in this file. */
100 char *file;
101
102 /* Or, the sprite is in this file at the location. */
103 struct specfile *sf;
104 int x, y, width, height;
105
106 /* A little more (optional) data. */
108
109 struct sprite *sprite;
110};
111
112#define SPECLIST_TAG small_sprite
113#define SPECLIST_TYPE struct small_sprite
114#include "speclist.h"
115
116#define small_sprite_list_iterate(list, pitem) \
117 TYPED_LIST_ITERATE(struct small_sprite, list, pitem)
118#define small_sprite_list_iterate_end LIST_ITERATE_END
119
120#define SPECHASH_TAG small_sprite
121#define SPECHASH_IKEY_TYPE char *
122#define SPECHASH_IDATA_TYPE struct small_sprite *
123#define SPECHASH_IKEY_VAL genhash_str_val_func
124#define SPECHASH_IKEY_COMP genhash_str_comp_func
125#define SPECHASH_IKEY_COPY genhash_str_copy_func
126#define SPECHASH_IKEY_FREE genhash_str_free_func
127#include "spechash.h"
128#define small_sprite_hash_iterate(hash, tag_name, pitem) \
129 TYPED_HASH_ITERATE(const char *, struct small_sprite *, hash, \
130 tag_name, pitem)
131#define small_sprite_hash_iterate_end HASH_ITERATE_END
132
133struct theme {
134 char name[512];
136
139
140 struct specfile_list *specfiles;
141 struct small_sprite_list *small_sprites;
142
143 /*
144 * This hash table maps themespec tags to struct small_sprites.
145 */
146 struct small_sprite_hash *sprite_hash;
147
148/* struct named_sprites sprites;*/
149
152};
153
154struct theme *active_theme = NULL;
155
156
157/************************************************************************/
160const char *theme_get_name(const struct theme *t)
161{
162 return t->name;
163}
164
165/************************************************************************/
169const char *theme_font_filename(const struct theme *t)
170{
171 return t->font_filename;
172}
173
174/************************************************************************/
177int theme_default_font_size(const struct theme *t)
178{
179 return t->default_font_size;
180}
181
182/************************************************************************/
185static struct theme *theme_new(void)
186{
187 struct theme *t = fc_calloc(1, sizeof(*t));
188
189 t->specfiles = specfile_list_new();
190 t->small_sprites = small_sprite_list_new();
191
192 return t;
193}
194
195/************************************************************************/
200const char **get_theme_list(void)
201{
202 static const char **themes = NULL;
203
204 if (!themes) {
205 /* Note: this means you must restart the client after installing a new
206 theme. */
208 int count = 0;
209
210 themes = fc_malloc((1 + strvec_size(list)) * sizeof(*themes));
211 strvec_iterate(list, file) {
212 struct theme *t = theme_read_toplevel(file);
213
214 if (t) {
215 themes[count++] = fc_strdup(file);
216 theme_free(t);
217 }
219 themes[count] = NULL;
221 }
222
223 return themes;
224}
225
226/************************************************************************/
233static char *themespec_fullname(const char *theme_name)
234{
235 if (theme_name) {
236 char fname[strlen(theme_name) + strlen(THEMESPEC_SUFFIX) + 1], *dname;
237
238 fc_snprintf(fname, sizeof(fname),
239 "%s%s", theme_name, THEMESPEC_SUFFIX);
240
241 dname = fname;
242
243 if (dname) {
244 return fc_strdup(dname);
245 }
246 }
247
248 return NULL;
249}
250
251/************************************************************************/
257 const char *which,
258 const char *us_capstr,
259 const char *filename)
260{
261 const char *file_capstr = secfile_lookup_str(file, "%s.options", which);
262
263 if (NULL == file_capstr) {
264 log_debug("\"%s\": %s file doesn't have capability string",
265 filename, which);
266 return FALSE;
267 }
268
269 if (!has_capabilities(us_capstr, file_capstr)) {
270 log_debug("\"%s\": %s file appears incompatible:", filename, which);
271 log_debug(" datafile options: %s", file_capstr);
272 log_debug(" supported options: %s", us_capstr);
273
274 return FALSE;
275 }
276
277 if (!has_capabilities(file_capstr, us_capstr)) {
278 log_debug("\"%s\": %s file requires option(s)"
279 " that client doesn't support:", filename, which);
280 log_debug(" datafile options: %s", file_capstr);
281 log_debug(" supported options: %s", us_capstr);
282
283 return FALSE;
284 }
285
286 return TRUE;
287}
288
289/************************************************************************/
294static void theme_free_toplevel(struct theme *t)
295{
296 if (t->font_filename) {
298 }
299
300 t->default_font_size = 0;
301
302 if (t->background_system) {
304 t->background_system = NULL;
305 }
306
307 if (t->color_system) {
309 t->color_system = NULL;
310 }
311}
312
313/************************************************************************/
316void theme_free(struct theme *ftheme)
317{
318 if (ftheme != NULL) {
319 theme_free_sprites(ftheme);
320 theme_free_toplevel(ftheme);
321 specfile_list_destroy(ftheme->specfiles);
322 small_sprite_list_destroy(ftheme->small_sprites);
323 free(ftheme);
324 }
325}
326
327/************************************************************************/
333void themespec_try_read(const char *theme_name)
334{
335 if (!(active_theme = theme_read_toplevel(theme_name))) {
337
338 strvec_iterate(list, file) {
339 struct theme *t = theme_read_toplevel(file);
340
341 if (t) {
342 if (active_theme == NULL || t->priority > active_theme->priority) {
343 active_theme = t;
344 } else {
345 theme_free(t);
346 }
347 }
350
351 if (active_theme == NULL) {
352 log_fatal(_("No usable default theme found, aborting!"));
353 exit(EXIT_FAILURE);
354 }
355
356 log_verbose("Trying theme \"%s\".", active_theme->name);
357 }
358/* sz_strlcpy(gui_sdl2_default_theme_name, theme_get_name(theme));*/
359}
360
361/************************************************************************/
372void themespec_reread(const char *new_theme_name)
373{
374 struct tile *center_tile;
375 enum client_states state = client_state();
376 const char *name = new_theme_name ? new_theme_name : active_theme->name;
377 char theme_name[strlen(name) + 1], old_name[strlen(active_theme->name) + 1];
378
379 /* Make local copies since these values may be freed down below */
380 sz_strlcpy(theme_name, name);
381 sz_strlcpy(old_name, active_theme->name);
382
383 log_normal(_("Loading theme \"%s\"."), theme_name);
384
385 /* Step 0: Record old data.
386 *
387 * We record the current mapcanvas center, etc.
388 */
390
391 /* Step 1: Cleanup.
392 *
393 * We free all old data in preparation for re-reading it.
394 */
397
398 /* Step 2: Read.
399 *
400 * We read in the new theme. This should be pretty straightforward.
401 */
402 if (!(active_theme = theme_read_toplevel(theme_name))) {
403 if (!(active_theme = theme_read_toplevel(old_name))) {
404 /* Always fails. */
406 "Failed to re-read the currently loaded theme.");
407 }
408 }
409/* sz_strlcpy(gui_sdl2_default_theme_name, theme->name);*/
411
412 /* Step 3: Setup
413 *
414 * This is a seriously sticky problem. On startup, we build a hash
415 * from all the sprite data. Then, when we connect to a server, the
416 * server sends us ruleset data a piece at a time and we use this data
417 * to assemble the sprite structures. But if we change while connected
418 * we have to reassemble all of these. This should just involve
419 * calling themespec_setup_*** on everything. But how do we tell what
420 * "everything" is?
421 *
422 * The below code just does things straightforwardly, by setting up
423 * each possible sprite again. Hopefully it catches everything, and
424 * doesn't mess up too badly if we change themes while not connected
425 * to a server.
426 */
427 if (state < C_S_RUNNING) {
428 /* The ruleset data is not sent until this point. */
429 return;
430 }
431
432 /* Step 4: Draw.
433 *
434 * Do any necessary redraws.
435 */
438/* theme_changed();*/
441 /* update_map_canvas_visible forces a full redraw. Otherwise with fast
442 * drawing we might not get one. Of course this is slower. */
444 can_slide = TRUE;
445}
446
447/************************************************************************/
451static struct sprite *load_gfx_file(const char *gfx_filename)
452{
453 const char **gfx_fileexts = gfx_fileextensions(), *gfx_fileext;
454 struct sprite *s;
455
456 /* Try out all supported file extensions to find one that works. */
457 while ((gfx_fileext = *gfx_fileexts++)) {
458 const char *real_full_name;
459 char full_name[strlen(gfx_filename) + strlen(".")
460 + strlen(gfx_fileext) + 1];
461
462 sprintf(full_name, "%s.%s", gfx_filename, gfx_fileext);
463 if ((real_full_name = fileinfoname(get_data_dirs(), full_name))) {
464 log_debug("trying to load gfx file \"%s\".", real_full_name);
465 s = load_gfxfile(real_full_name);
466 if (s) {
467 return s;
468 }
469 }
470 }
471
472 log_error("Could not load gfx file \"%s\".", gfx_filename);
473
474 return NULL;
475}
476
477/************************************************************************/
480static void theme_ensure_big_sprite(struct specfile *sf)
481{
482 struct section_file *file;
483 const char *gfx_filename;
484
485 if (sf->big_sprite) {
486 /* Looks like it's already loaded. */
487 return;
488 }
489
490 /* Otherwise load it. The big sprite will sometimes be freed and will have
491 * to be reloaded, but most of the time it's just loaded once, the small
492 * sprites are extracted, and then it's freed. */
493 if (!(file = secfile_load(sf->file_name, TRUE))) {
494 log_fatal(_("Could not open '%s':\n%s"), sf->file_name, secfile_error());
495 exit(EXIT_FAILURE);
496 }
497
498 if (!check_themespec_capabilities(file, "spec",
500 exit(EXIT_FAILURE);
501 }
502
503 gfx_filename = secfile_lookup_str(file, "file.gfx");
504
505 sf->big_sprite = load_gfx_file(gfx_filename);
506
507 if (!sf->big_sprite) {
508 log_fatal("Could not load gfx file for the spec file \"%s\".",
509 sf->file_name);
510 exit(EXIT_FAILURE);
511 }
512
513 /* We don't check unused fields here as most fields are only read
514 * at the specs scanning time. */
515 /* secfile_check_unused(file); */
516
517 secfile_destroy(file);
518}
519
520/************************************************************************/
525static void scan_specfile(struct theme *t, struct specfile *sf,
526 bool duplicates_ok)
527{
528 struct section_file *file;
529 struct section_list *sections;
530 int i;
531
532 if (!(file = secfile_load(sf->file_name, TRUE))) {
533 log_fatal(_("Could not open '%s':\n%s"), sf->file_name, secfile_error());
534 exit(EXIT_FAILURE);
535 }
536 if (!check_themespec_capabilities(file, "spec",
538 exit(EXIT_FAILURE);
539 }
540
541 /* Currently unused */
542 (void) secfile_entry_by_path(file, "info.artists");
543
544 /* This isn't used during the scan, only when the gfx is really loaded */
545 (void) secfile_entry_by_path(file, "file.gfx");
546
547 sections = secfile_sections_by_name_prefix(file, "grid_");
548
549 if (NULL != sections) {
550 section_list_iterate(sections, psection) {
551 int j, k;
552 int x_top_left, y_top_left, dx, dy;
553 int pixel_border;
554 const char *gridname = section_name(psection);
555
556 pixel_border = secfile_lookup_int_default(file, 0, "%s.pixel_border",
557 gridname);
558
559 if (!secfile_lookup_int(file, &x_top_left, "%s.x_top_left", gridname)
560 || !secfile_lookup_int(file, &y_top_left,
561 "%s.y_top_left", gridname)
562 || !secfile_lookup_int(file, &dx, "%s.dx", gridname)
563 || !secfile_lookup_int(file, &dy, "%s.dy", gridname)) {
564 log_error("Grid \"%s\" invalid: %s", gridname, secfile_error());
565 continue;
566 }
567
568 j = -1;
569 while (NULL != secfile_entry_lookup(file, "%s.tiles%d.tag",
570 gridname, ++j)) {
571 struct small_sprite *ss;
572 int row, column;
573 int x1, y1;
574 const char **tags;
575 size_t num_tags;
576 int hot_x, hot_y;
577
578 if (!secfile_lookup_int(file, &row, "%s.tiles%d.row", gridname, j)
579 || !secfile_lookup_int(file, &column,
580 "%s.tiles%d.column", gridname, j)
581 || !(tags = secfile_lookup_str_vec(file, &num_tags,
582 "%s.tiles%d.tag",
583 gridname, j))) {
584 log_error("Small sprite \"%s.tiles%d\" invalid: %s",
585 gridname, j, secfile_error());
586 continue;
587 }
588 hot_x = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_x",
589 gridname, j);
590 hot_y = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_y",
591 gridname, j);
592
593 /* there must be at least 1 because of the while(): */
594 fc_assert_action(num_tags > 0, continue);
595
596 x1 = x_top_left + (dx + pixel_border) * column;
597 y1 = y_top_left + (dy + pixel_border) * row;
598
599 ss = fc_malloc(sizeof(*ss));
600 ss->ref_count = 0;
601 ss->file = NULL;
602 ss->x = x1;
603 ss->y = y1;
604 ss->width = dx;
605 ss->height = dy;
606 ss->sf = sf;
607 ss->sprite = NULL;
608 ss->hot_x = hot_x;
609 ss->hot_y = hot_y;
610
611 small_sprite_list_prepend(t->small_sprites, ss);
612
613 if (!duplicates_ok) {
614 for (k = 0; k < num_tags; k++) {
615 if (!small_sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
616 log_error("warning: already have a sprite for \"%s\".",
617 tags[k]);
618 }
619 }
620 } else {
621 for (k = 0; k < num_tags; k++) {
622 (void) small_sprite_hash_replace(t->sprite_hash, tags[k], ss);
623 }
624 }
625
626 FC_FREE(tags);
627 }
629 section_list_destroy(sections);
630 }
631
632 /* Load "extra" sprites. Each sprite is one file. */
633 i = -1;
634 while (NULL != secfile_lookup_str(file, "extra.sprites%d.tag", ++i)) {
635 struct small_sprite *ss;
636 const char **tags;
637 const char *filename;
638 size_t num_tags, k;
639 int hot_x, hot_y;
640
641 if (!(tags = secfile_lookup_str_vec(file, &num_tags,
642 "extra.sprites%d.tag", i))
643 || !(filename = secfile_lookup_str(file,
644 "extra.sprites%d.file", i))) {
645 log_error("Small sprite \"extra.sprites%d\" invalid: %s",
646 i, secfile_error());
647 continue;
648 }
649
650 hot_x = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_x", i);
651 hot_y = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_y", i);
652
653 ss = fc_malloc(sizeof(*ss));
654 ss->ref_count = 0;
655 ss->file = fc_strdup(filename);
656 ss->sf = NULL;
657 ss->sprite = NULL;
658 ss->hot_x = hot_x;
659 ss->hot_y = hot_y;
660
661 small_sprite_list_prepend(t->small_sprites, ss);
662
663 if (!duplicates_ok) {
664 for (k = 0; k < num_tags; k++) {
665 if (!small_sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
666 log_error("warning: already have a sprite for \"%s\".", tags[k]);
667 }
668 }
669 } else {
670 for (k = 0; k < num_tags; k++) {
671 (void) small_sprite_hash_replace(t->sprite_hash, tags[k], ss);
672 }
673 }
674 FC_FREE(tags);
675 }
676
679}
680
681/************************************************************************/
685char *themespec_gfx_filename(const char *gfx_filename)
686{
687 const char *gfx_current_fileext;
688 const char **gfx_fileexts = gfx_fileextensions();
689
690 while ((gfx_current_fileext = *gfx_fileexts++)) {
691 const char *real_full_name;
692 char *full_name =
693 fc_malloc(strlen(gfx_filename) + strlen(".")
694 + strlen(gfx_current_fileext) + 1);
695
696 sprintf(full_name, "%s.%s", gfx_filename, gfx_current_fileext);
697 real_full_name = fileinfoname(get_data_dirs(), full_name);
698 FC_FREE(full_name);
699 if (real_full_name) {
700 return fc_strdup(real_full_name);
701 }
702 }
703
704 log_fatal("Couldn't find a supported gfx file extension for \"%s\".",
705 gfx_filename);
706
707 exit(EXIT_FAILURE);
708 return NULL;
709}
710
711/************************************************************************/
716struct theme *theme_read_toplevel(const char *theme_name)
717{
718 struct section_file *file;
719 char *fname;
720 int i;
721 size_t num_spec_files;
722 const char **spec_filenames;
723 const char *file_capstr;
724 bool duplicates_ok;
725 struct theme *t = theme_new();
726 const char *langname;
727 const char *filename, *c;
728
729 fname = themespec_fullname(theme_name);
730 if (!fname) {
731 log_error("Can't find theme \"%s\".", theme_name);
732 theme_free(t);
733 return NULL;
734 }
735 log_verbose("themespec file is \"%s\".", fname);
736
737 if (!(file = secfile_load(fname, TRUE))) {
738 log_error("Could not open '%s':\n%s", fname, secfile_error());
739 FC_FREE(fname);
740 theme_free(t);
741
742 return NULL;
743 }
744
745 if (!check_themespec_capabilities(file, "themespec",
746 THEMESPEC_SDL2_CAPSTR, fname)) {
747 secfile_destroy(file);
748 FC_FREE(fname);
749 theme_free(t);
750
751 return NULL;
752 }
753
754 file_capstr = secfile_lookup_str(file, "themespec.options");
755 duplicates_ok = has_capabilities("+duplicates_ok", file_capstr);
756
757 (void) secfile_entry_by_path(file, "themespec.name"); /* currently unused */
758
759 sz_strlcpy(t->name, theme_name);
760 t->priority = secfile_lookup_int_default(file, 0, "themespec.priority");
761
762 langname = setup_langname();
763
764 c = NULL;
765
766 if (langname != NULL && strstr(langname, "zh_CN") != NULL) {
767 c = secfile_lookup_str(file, "themespec.font_file_zh_CN");
768 } else {
769 (void) secfile_entry_lookup(file, "themespec.font_file_zh_CN");
770 }
771
772 if (c == NULL && langname != NULL && strstr(langname, "ja") != NULL) {
773 c = secfile_lookup_str(file, "themespec.font_file_ja");
774 } else {
775 (void) secfile_entry_lookup(file, "themespec.font_file_ja");
776 }
777
778 if (c == NULL && langname != NULL && strstr(langname, "ko") != NULL) {
779 c = secfile_lookup_str(file, "themespec.font_file_ko");
780 } else {
781 (void) secfile_entry_lookup(file, "themespec.font_file_ko");
782 }
783
784 if (c == NULL) {
785 c = secfile_lookup_str(file, "themespec.font_file");
786 } else {
787 (void) secfile_entry_lookup(file, "themespec.font_file");
788 }
789
790 if ((filename = fileinfoname(get_data_dirs(), c))) {
791 t->font_filename = fc_strdup(filename);
792 } else {
793 log_fatal("Could not open font: %s", c);
794 secfile_destroy(file);
795 FC_FREE(fname);
796 theme_free(t);
797
798 return NULL;
799 }
800 log_debug("theme font file %s", t->font_filename);
801
802 t->default_font_size = secfile_lookup_int_default(file, 10, "themespec.default_font_size");
803 log_debug("theme default font size %d", t->default_font_size);
804
805 spec_filenames = secfile_lookup_str_vec(file, &num_spec_files,
806 "themespec.files");
807 if (NULL == spec_filenames || 0 == num_spec_files) {
808 log_error("No theme graphics files specified in \"%s\"", fname);
809 secfile_destroy(file);
810 FC_FREE(fname);
811 theme_free(t);
812
813 return NULL;
814 }
815
816 fc_assert(t->sprite_hash == NULL);
817 t->sprite_hash = small_sprite_hash_new();
818 for (i = 0; i < num_spec_files; i++) {
819 struct specfile *sf = fc_malloc(sizeof(*sf));
820
821 log_debug("spec file %s", spec_filenames[i]);
822
823 sf->big_sprite = NULL;
824 filename = fileinfoname(get_data_dirs(), spec_filenames[i]);
825 if (!filename) {
826 log_error("Can't find spec file \"%s\".", spec_filenames[i]);
827 secfile_destroy(file);
828 FC_FREE(fname);
829 theme_free(t);
830
831 return NULL;
832 }
833 sf->file_name = fc_strdup(filename);
834 scan_specfile(t, sf, duplicates_ok);
835
836 specfile_list_prepend(t->specfiles, sf);
837 }
838 FC_FREE(spec_filenames);
839
842
844
845 secfile_destroy(file);
846 log_verbose("finished reading \"%s\".", fname);
847 FC_FREE(fname);
848
849 return t;
850}
851
852/************************************************************************/
857static struct sprite *theme_load_sprite(struct theme *t, const char *tag_name)
858{
859 /* Lookup information about where the sprite is found. */
860 struct small_sprite *ss;
861
862 log_debug("theme_load_sprite(tag='%s')", tag_name);
863 if (!small_sprite_hash_lookup(t->sprite_hash, tag_name, &ss)) {
864 return NULL;
865 }
866
867 fc_assert_ret_val(ss->ref_count >= 0, NULL);
868
869 if (!ss->sprite) {
870 /* If the sprite hasn't been loaded already, then load it. */
871 fc_assert_ret_val(ss->ref_count == 0, NULL);
872 if (ss->file) {
873 ss->sprite = load_gfx_file(ss->file);
874 if (!ss->sprite) {
875 log_fatal("Couldn't load gfx file \"%s\" for sprite '%s'.",
876 ss->file, tag_name);
877 exit(EXIT_FAILURE);
878 }
879 } else {
880 int sf_w, sf_h;
881
883 get_sprite_dimensions(ss->sf->big_sprite, &sf_w, &sf_h);
884 if (ss->x < 0 || ss->x + ss->width > sf_w
885 || ss->y < 0 || ss->y + ss->height > sf_h) {
886 log_error("Sprite '%s' in file \"%s\" isn't within the image!",
887 tag_name, ss->sf->file_name);
888 return NULL;
889 }
890 ss->sprite =
891 crop_sprite(ss->sf->big_sprite, ss->x, ss->y, ss->width, ss->height,
892 NULL, -1, -1, 1.0, FALSE);
893 }
894 }
895
896 /* Track the reference count so we know when to free the sprite. */
897 ss->ref_count++;
898
899 return ss->sprite;
900}
901
902/************************************************************************/
906static void theme_unload_sprite(struct theme *t, const char *tag_name)
907{
908 struct small_sprite *ss;
909
910 small_sprite_hash_lookup(t->sprite_hash, tag_name, &ss);
911 fc_assert_ret(ss);
912 fc_assert_ret(ss->ref_count >= 1);
914
915 ss->ref_count--;
916
917 if (ss->ref_count == 0) {
918 /* Nobody's using the sprite anymore, so we should free it. We know
919 * where to find it if we need it again. */
920 log_debug("freeing sprite '%s'.", tag_name);
921 free_sprite(ss->sprite);
922 ss->sprite = NULL;
923 }
924}
925
926/* Not very safe, but convenient: */
927#define SET_SPRITE(field, tag) \
928 do { \
929 t->sprites.field = theme_load_sprite(t, tag); \
930 fc_assert_exit_msg(NULL != t->sprites.field, \
931 "Sprite tag '%s' missing.", tag); \
932 } while (FALSE)
933
934/* Sets sprites.field to tag or (if tag isn't available) to alt */
935#define SET_SPRITE_ALT(field, tag, alt) \
936 do { \
937 t->sprites.field = theme_load_sprite(t, tag); \
938 if (!t->sprites.field) { \
939 t->sprites.field = theme_load_sprite(t, alt); \
940 } \
941 fc_assert_exit_msg(NULL != t->sprites.field, \
942 "Sprite tag '%s' and alternate '%s' are " \
943 "both missing.", tag, alt); \
944 } while (FALSE)
945
946/* Sets sprites.field to tag, or NULL if not available */
947#define SET_SPRITE_OPT(field, tag) \
948 t->sprites.field = theme_load_sprite(t, tag)
949
950#define SET_SPRITE_ALT_OPT(field, tag, alt) \
951 do { \
952 t->sprites.field = theme_lookup_sprite_tag_alt(t, LOG_VERBOSE, tag, alt,\
953 "sprite", #field); \
954 } while (FALSE)
955
956/************************************************************************/
960static void theme_lookup_sprite_tags(struct theme *t)
961{
962 /* the 'sprites' structure is currently not used, for now we call some
963 * functions in gui_tilespec.c instead */
964
968}
969
970/************************************************************************/
977{
979 if (sf->big_sprite) {
981 sf->big_sprite = NULL;
982 }
984}
985
986/************************************************************************/
997
998/************************************************************************/
1003 enum log_level level,
1004 const char *tag, const char *alt,
1005 const char *what,
1006 const char *name)
1007{
1008 struct sprite *sp;
1009
1010 /* (should get sprite_hash before connection) */
1011 fc_assert_ret_val_msg(NULL != t->sprite_hash, NULL,
1012 "attempt to lookup for %s \"%s\" before "
1013 "sprite_hash setup", what, name);
1014
1015 sp = theme_load_sprite(t, tag);
1016 if (sp) {
1017 return sp;
1018 }
1019
1020 sp = theme_load_sprite(t, alt);
1021 if (sp) {
1022 log_verbose("Using alternate graphic \"%s\" (instead of \"%s\") "
1023 "for %s \"%s\".", alt, tag, what, name);
1024 return sp;
1025 }
1026
1027 log_base(level, "Don't have graphics tags \"%s\" or \"%s\" for %s \"%s\".",
1028 tag, alt, what, name);
1029 if (LOG_FATAL >= level) {
1030 exit(EXIT_FAILURE);
1031 }
1032
1033 return NULL;
1034}
1035
1036#define FULL_TILE_X_OFFSET ((t->normal_tile_width - t->full_tile_width) / 2)
1037#define FULL_TILE_Y_OFFSET (t->normal_tile_height - t->full_tile_height)
1038
1039#define ADD_SPRITE(s, draw_fog, x_offset, y_offset) \
1040 (fc_assert(s != NULL), \
1041 sprs->sprite = s, \
1042 sprs->foggable = (draw_fog && t->fogstyle == FOG_AUTO), \
1043 sprs->offset_x = x_offset, \
1044 sprs->offset_y = y_offset, \
1045 sprs++)
1046#define ADD_SPRITE_SIMPLE(s) ADD_SPRITE(s, TRUE, 0, 0)
1047#define ADD_SPRITE_FULL(s) \
1048 ADD_SPRITE(s, TRUE, FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET)
1049
1050/************************************************************************/
1053static void theme_unload_all_sprites(struct theme *t)
1054{
1055 if (t->sprite_hash) {
1057 while (ss->ref_count > 0) {
1059 }
1061 }
1062}
1063
1064/************************************************************************/
1068{
1069 log_debug("theme_free_sprites()");
1070
1072
1073 if (t->sprite_hash) {
1074 small_sprite_hash_destroy(t->sprite_hash);
1075 t->sprite_hash = NULL;
1076 }
1077
1079 small_sprite_list_remove(t->small_sprites, ss);
1080 if (ss->file) {
1081 FC_FREE(ss->file);
1082 }
1083 fc_assert(ss->sprite == NULL);
1084 FC_FREE(ss);
1086
1088 specfile_list_remove(t->specfiles, sf);
1089 FC_FREE(sf->file_name);
1090 if (sf->big_sprite) {
1091 free_sprite(sf->big_sprite);
1092 sf->big_sprite = NULL;
1093 }
1094 FC_FREE(sf);
1096
1097#if 0
1098 /* TODO: may be useful for theme sprites, too */
1099 sprite_vector_iterate(&t->sprites.****, psprite) {
1102 sprite_vector_free(&t->sprites.****);
1103#endif /* 0 */
1104
1105 /* the 'sprites' structure is currently not used, for now we call some
1106 * functions in gui_tilespec.c instead */
1107
1111}
1112
1113/************************************************************************/
1117{
1118 return t->background_system;
1119}
1120
1121/************************************************************************/
1125{
1126 return t->color_system;
1127}
struct canvas int int struct sprite * psprite
Definition canvas_g.h:50
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
void generate_citydlg_dimensions(void)
enum client_states client_state(void)
client_states
Definition client_main.h:43
@ C_S_RUNNING
Definition client_main.h:47
static struct fc_sockaddr_list * list
Definition clinet.c:102
char * tag_name
Definition events.c:77
#define _(String)
Definition fcintl.h:67
void popdown_all_game_dialogs(void)
Definition dialogs.c:1523
void get_sprite_dimensions(struct sprite *sprite, int *width, int *height)
Definition sprite.c:107
void free_sprite(struct sprite *s)
Definition sprite.c:278
struct sprite * load_gfxfile(const char *filename)
Definition sprite.c:170
struct sprite * crop_sprite(struct sprite *source, int x, int y, int width, int height, struct sprite *mask, int mask_offset_x, int mask_offset_y, float scale, bool smooth)
Definition sprite.c:52
const char ** gfx_fileextensions(void)
Definition sprite.c:117
void tilespec_setup_city_gfx(void)
void tilespec_free_city_icons(void)
void tilespec_setup_theme(void)
void tilespec_free_city_gfx(void)
void tilespec_setup_city_icons(void)
void tilespec_free_theme(void)
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:191
#define fc_assert_exit_msg(condition, message,...)
Definition log.h:211
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_fatal(message,...)
Definition log.h:100
#define fc_assert_action(condition, action)
Definition log.h:187
#define log_debug(message,...)
Definition log.h:115
#define log_normal(message,...)
Definition log.h:107
#define log_base(level, message,...)
Definition log.h:94
log_level
Definition log.h:28
@ LOG_FATAL
Definition log.h:29
#define log_error(message,...)
Definition log.h:103
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
void update_map_canvas_visible(void)
struct tile * get_center_tile_mapcanvas(void)
void center_tile_mapcanvas(const struct tile *ptile)
const struct tile * center_tile
bool can_slide
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
struct section_file * secfile_load(const char *filename, bool allow_duplicates)
Definition registry.c:50
const char * secfile_error(void)
const char * section_name(const struct section *psection)
void secfile_destroy(struct section_file *secfile)
void secfile_check_unused(const struct section_file *secfile)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
#define section_list_iterate(seclist, psection)
#define section_list_iterate_end
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
struct strvec * fileinfolist(const struct strvec *dirs, const char *suffix)
Definition shared.c:1020
const char * setup_langname(void)
Definition shared.c:1281
const struct strvec * get_data_dirs(void)
Definition shared.c:886
void strvec_destroy(struct strvec *psv)
size_t strvec_size(const struct strvec *psv)
#define strvec_iterate(psv, str)
#define strvec_iterate_end
struct sprite * sprite
Definition themespec.c:109
char * file
Definition themespec.c:100
struct specfile * sf
Definition themespec.c:103
char * file_name
Definition themespec.c:80
struct sprite * big_sprite
Definition themespec.c:79
struct theme_color_system * color_system
Definition themespec.c:151
char name[512]
Definition themespec.c:134
int default_font_size
Definition themespec.c:138
struct theme_background_system * background_system
Definition themespec.c:150
char * font_filename
Definition themespec.c:137
int priority
Definition themespec.c:135
struct specfile_list * specfiles
Definition themespec.c:140
struct small_sprite_list * small_sprites
Definition themespec.c:141
struct small_sprite_hash * sprite_hash
Definition themespec.c:146
Definition tile.h:49
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct theme_background_system * theme_background_system_read(struct section_file *file)
void theme_background_system_free(struct theme_background_system *backgrounds)
void theme_color_system_free(struct theme_color_system *colors)
struct theme_color_system * theme_color_system_read(struct section_file *file)
static struct sprite * theme_load_sprite(struct theme *t, const char *tag_name)
Definition themespec.c:857
void theme_free(struct theme *ftheme)
Definition themespec.c:316
static bool check_themespec_capabilities(struct section_file *file, const char *which, const char *us_capstr, const char *filename)
Definition themespec.c:256
#define THEMESPEC_SDL2_CAPSTR
Definition themespec.c:50
static struct sprite * load_gfx_file(const char *gfx_filename)
Definition themespec.c:451
#define specfile_list_iterate_end
Definition themespec.c:89
static void theme_unload_sprite(struct theme *t, const char *tag_name)
Definition themespec.c:906
struct theme_color_system * theme_get_color_system(const struct theme *t)
Definition themespec.c:1124
const char * theme_font_filename(const struct theme *t)
Definition themespec.c:169
char * themespec_gfx_filename(const char *gfx_filename)
Definition themespec.c:685
#define specfile_list_iterate(list, pitem)
Definition themespec.c:87
static void theme_finish_loading_sprites(struct theme *t)
Definition themespec.c:976
static void theme_ensure_big_sprite(struct specfile *sf)
Definition themespec.c:480
static void theme_lookup_sprite_tags(struct theme *t)
Definition themespec.c:960
#define small_sprite_list_iterate_end
Definition themespec.c:118
#define small_sprite_list_iterate(list, pitem)
Definition themespec.c:116
static void theme_free_toplevel(struct theme *t)
Definition themespec.c:294
static void scan_specfile(struct theme *t, struct specfile *sf, bool duplicates_ok)
Definition themespec.c:525
void theme_free_sprites(struct theme *t)
Definition themespec.c:1067
void theme_load_sprites(struct theme *t)
Definition themespec.c:992
const char ** get_theme_list(void)
Definition themespec.c:200
struct theme_background_system * theme_get_background_system(const struct theme *t)
Definition themespec.c:1116
void themespec_try_read(const char *theme_name)
Definition themespec.c:333
struct sprite * theme_lookup_sprite_tag_alt(struct theme *t, enum log_level level, const char *tag, const char *alt, const char *what, const char *name)
Definition themespec.c:1002
const char * theme_get_name(const struct theme *t)
Definition themespec.c:160
struct theme * theme_read_toplevel(const char *theme_name)
Definition themespec.c:716
#define small_sprite_hash_iterate(hash, tag_name, pitem)
Definition themespec.c:128
#define SPEC_SDL2_CAPSTR
Definition themespec.c:62
#define THEMESPEC_SUFFIX
Definition themespec.c:69
int theme_default_font_size(const struct theme *t)
Definition themespec.c:177
#define small_sprite_hash_iterate_end
Definition themespec.c:131
void themespec_reread(const char *new_theme_name)
Definition themespec.c:372
struct theme * active_theme
Definition themespec.c:154
static char * themespec_fullname(const char *theme_name)
Definition themespec.c:233
static void theme_unload_all_sprites(struct theme *t)
Definition themespec.c:1053
static struct theme * theme_new(void)
Definition themespec.c:185
#define sprite_vector_iterate_end
Definition tilespec.h:45
#define sprite_vector_iterate(sprite_vec, psprite)
Definition tilespec.h:43