Freeciv-3.3
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-sdl2-3.3-themespec-Devel-2023-Jun-07 duplicates_ok"
51/*
52 * Themespec capabilities acceptable to this program:
53 *
54 * +Freeciv-3.3-sdl2-themespec - basic format for Freeciv versions 3.3.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-sdl2-3.3-spec-Devel-2023-Jun-10"
63/*
64 * Individual spec file capabilities acceptable to this program:
65 *
66 * +Freeciv-3.3-sdl2-spec - basic format for Freeciv versions 3.3.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
142
143 /*
144 * This hash table maps themespec tags to struct small_sprites.
145 */
147
148/* struct named_sprites sprites;*/
149
152};
153
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
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) {
237
238 fc_snprintf(fname, sizeof(fname),
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
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
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 t->font_filename = NULL;
299 }
300
301 t->default_font_size = 0;
302
303 if (t->background_system) {
306 }
307
308 if (t->color_system) {
310 t->color_system = NULL;
311 }
312}
313
314/************************************************************************/
318{
319 if (ftheme != NULL) {
322 specfile_list_destroy(ftheme->specfiles);
323 small_sprite_list_destroy(ftheme->small_sprites);
324 free(ftheme);
325 }
326}
327
328/************************************************************************/
335{
338
339 strvec_iterate(list, file) {
340 struct theme *t = theme_read_toplevel(file);
341
342 if (t) {
344 active_theme = t;
345 } else {
346 theme_free(t);
347 }
348 }
351
352 if (active_theme == NULL) {
353 log_fatal(_("No usable default theme found, aborting!"));
354
356 }
357
358 log_verbose("Trying theme \"%s\".", active_theme->name);
359 }
360
361 /* sz_strlcpy(GUI_SDL_OPTION(default_theme_name),
362 theme_get_name(theme)); */
363}
364
365/************************************************************************/
377{
378 struct tile *center_tile;
379 enum client_states state = client_state();
381 char theme_name[strlen(name) + 1], old_name[strlen(active_theme->name) + 1];
382
383 /* Make local copies since these values may be freed down below */
385 sz_strlcpy(old_name, active_theme->name);
386
387 log_normal(_("Loading theme \"%s\"."), theme_name);
388
389 /* Step 0: Record old data.
390 *
391 * We record the current mapcanvas center, etc.
392 */
394
395 /* Step 1: Cleanup.
396 *
397 * We free all old data in preparation for re-reading it.
398 */
401
402 /* Step 2: Read.
403 *
404 * We read in the new theme. This should be pretty straightforward.
405 */
407 if (!(active_theme = theme_read_toplevel(old_name))) {
408 /* Always fails. */
410 "Failed to re-read the currently loaded theme.");
411 }
412 }
413 /* sz_strlcpy(GUI_SDL_OPTION(default_theme_name), theme->name); */
414
416
417 /* Step 3: Setup
418 *
419 * This is a seriously sticky problem. On startup, we build a hash
420 * from all the sprite data. Then, when we connect to a server, the
421 * server sends us ruleset data a piece at a time and we use this data
422 * to assemble the sprite structures. But if we change while connected
423 * we have to reassemble all of these. This should just involve
424 * calling themespec_setup_*** on everything. But how do we tell what
425 * "everything" is?
426 *
427 * The below code just does things straightforwardly, by setting up
428 * each possible sprite again. Hopefully it catches everything, and
429 * doesn't mess up too badly if we change themes while not connected
430 * to a server.
431 */
432 if (state < C_S_RUNNING) {
433 /* The ruleset data is not sent until this point. */
434 return;
435 }
436
437 /* Step 4: Draw.
438 *
439 * Do any necessary redraws.
440 */
443/* theme_changed();*/
446 /* update_map_canvas_visible() forces a full redraw. Otherwise with fast
447 * drawing we might not get one. Of course this is slower. */
449 can_slide = TRUE;
450}
451
452/************************************************************************/
456static struct sprite *load_sdl2_gfx_file(const char *gfx_filename)
457{
459 struct sprite *s;
460
461 /* Try out all supported file extensions to find one that works. */
462 while ((gfx_fileext = *gfx_fileexts++)) {
463 const char *real_full_name;
465 + strlen(gfx_fileext) + 1];
466
469 log_debug("trying to load gfx file \"%s\".", real_full_name);
471 if (s) {
472 return s;
473 }
474 }
475 }
476
477 log_error("Could not load gfx file \"%s\".", gfx_filename);
478
479 return NULL;
480}
481
482/************************************************************************/
485static void theme_ensure_big_sprite(struct specfile *sf)
486{
487 struct section_file *file;
488 const char *gfx_filename;
489
490 if (sf->big_sprite) {
491 /* Looks like it's already loaded. */
492 return;
493 }
494
495 /* Otherwise load it. The big sprite will sometimes be freed and will have
496 * to be reloaded, but most of the time it's just loaded once, the small
497 * sprites are extracted, and then it's freed. */
498 if (!(file = secfile_load(sf->file_name, TRUE))) {
499 log_fatal(_("Could not open '%s':\n%s"), sf->file_name, secfile_error());
501 }
502
503 if (!check_themespec_capabilities(file, "spec",
506 }
507
508 gfx_filename = secfile_lookup_str(file, "file.gfx");
509
511
512 if (!sf->big_sprite) {
513 log_fatal("Could not load gfx file for the spec file \"%s\".",
514 sf->file_name);
516 }
517
518 /* We don't check unused fields here as most fields are only read
519 * at the specs scanning time. */
520 /* secfile_check_unused(file); */
521
522 secfile_destroy(file);
523}
524
525/************************************************************************/
530static void scan_specfile(struct theme *t, struct specfile *sf,
531 bool duplicates_ok)
532{
533 struct section_file *file;
534 struct section_list *sections;
535 int i;
536
537 if (!(file = secfile_load(sf->file_name, TRUE))) {
538 log_fatal(_("Could not open '%s':\n%s"), sf->file_name, secfile_error());
540 }
541 if (!check_themespec_capabilities(file, "spec",
544 }
545
546 /* Currently unused */
547 (void) secfile_entry_by_path(file, "info.artists");
548
549 /* This isn't used during the scan, only when the gfx is really loaded */
550 (void) secfile_entry_by_path(file, "file.gfx");
551
552 sections = secfile_sections_by_name_prefix(file, "grid_");
553
554 if (NULL != sections) {
555 section_list_iterate(sections, psection) {
556 int j, k;
557 int x_top_left, y_top_left, dx, dy;
558 int pixel_border;
559 const char *gridname = section_name(psection);
560
561 pixel_border = secfile_lookup_int_default(file, 0, "%s.pixel_border",
562 gridname);
563
564 if (!secfile_lookup_int(file, &x_top_left, "%s.x_top_left", gridname)
566 "%s.y_top_left", gridname)
567 || !secfile_lookup_int(file, &dx, "%s.dx", gridname)
568 || !secfile_lookup_int(file, &dy, "%s.dy", gridname)) {
569 log_error("Grid \"%s\" invalid: %s", gridname, secfile_error());
570 continue;
571 }
572
573 j = -1;
574 while (NULL != secfile_entry_lookup(file, "%s.tiles%d.tag",
575 gridname, ++j)) {
576 struct small_sprite *ss;
577 int row, column;
578 int x1, y1;
579 const char **tags;
580 size_t num_tags;
581 int hot_x, hot_y;
582
583 if (!secfile_lookup_int(file, &row, "%s.tiles%d.row", gridname, j)
585 "%s.tiles%d.column", gridname, j)
587 "%s.tiles%d.tag",
588 gridname, j))) {
589 log_error("Small sprite \"%s.tiles%d\" invalid: %s",
590 gridname, j, secfile_error());
591 continue;
592 }
593 hot_x = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_x",
594 gridname, j);
595 hot_y = secfile_lookup_int_default(file, 0, "%s.tiles%d.hot_y",
596 gridname, j);
597
598 /* there must be at least 1 because of the while(): */
599 fc_assert_action(num_tags > 0, continue);
600
601 x1 = x_top_left + (dx + pixel_border) * column;
602 y1 = y_top_left + (dy + pixel_border) * row;
603
604 ss = fc_malloc(sizeof(*ss));
605 ss->ref_count = 0;
606 ss->file = NULL;
607 ss->x = x1;
608 ss->y = y1;
609 ss->width = dx;
610 ss->height = dy;
611 ss->sf = sf;
612 ss->sprite = NULL;
613 ss->hot_x = hot_x;
614 ss->hot_y = hot_y;
615
617
618 if (!duplicates_ok) {
619 for (k = 0; k < num_tags; k++) {
620 if (!small_sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
621 log_error("warning: already have a sprite for \"%s\".",
622 tags[k]);
623 }
624 }
625 } else {
626 for (k = 0; k < num_tags; k++) {
628 }
629 }
630
631 FC_FREE(tags);
632 }
634 section_list_destroy(sections);
635 }
636
637 /* Load "extra" sprites. Each sprite is one file. */
638 i = -1;
639 while (NULL != secfile_lookup_str(file, "extra.sprites%d.tag", ++i)) {
640 struct small_sprite *ss;
641 const char **tags;
642 const char *filename;
643 size_t num_tags, k;
644 int hot_x, hot_y;
645
646 if (!(tags = secfile_lookup_str_vec(file, &num_tags,
647 "extra.sprites%d.tag", i))
648 || !(filename = secfile_lookup_str(file,
649 "extra.sprites%d.file", i))) {
650 log_error("Small sprite \"extra.sprites%d\" invalid: %s",
651 i, secfile_error());
652 continue;
653 }
654
655 hot_x = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_x", i);
656 hot_y = secfile_lookup_int_default(file, 0, "extra.sprites%d.hot_y", i);
657
658 ss = fc_malloc(sizeof(*ss));
659 ss->ref_count = 0;
660 ss->file = fc_strdup(filename);
661 ss->sf = NULL;
662 ss->sprite = NULL;
663 ss->hot_x = hot_x;
664 ss->hot_y = hot_y;
665
667
668 if (!duplicates_ok) {
669 for (k = 0; k < num_tags; k++) {
670 if (!small_sprite_hash_insert(t->sprite_hash, tags[k], ss)) {
671 log_error("warning: already have a sprite for \"%s\".", tags[k]);
672 }
673 }
674 } else {
675 for (k = 0; k < num_tags; k++) {
677 }
678 }
679 FC_FREE(tags);
680 }
681
684}
685
686/************************************************************************/
691{
692 const char *gfx_current_fileext;
693 const char **gfx_fileexts = gfx_fileextensions();
694
695 while ((gfx_current_fileext = *gfx_fileexts++)) {
696 const char *real_full_name;
697 char *full_name =
700
704 if (real_full_name) {
706 }
707 }
708
709 log_fatal("Couldn't find a supported gfx file extension for \"%s\".",
711
713 return NULL;
714}
715
716/************************************************************************/
722{
723 struct section_file *file;
724 char *fname;
725 int i;
726 size_t num_spec_files;
727 const char **spec_filenames;
728 const char *file_capstr;
729 bool duplicates_ok;
730 struct theme *t = theme_new();
731 const char *langname;
732 const char *filename, *t_fontname;
733 const char *lang;
734
736 if (!fname) {
737 log_error("Can't find theme \"%s\".", theme_name);
738 theme_free(t);
739 return NULL;
740 }
741 log_verbose("themespec file is \"%s\".", fname);
742
743 if (!(file = secfile_load(fname, TRUE))) {
744 log_error("Could not open '%s':\n%s", fname, secfile_error());
745 FC_FREE(fname);
746 theme_free(t);
747
748 return NULL;
749 }
750
751 if (!check_themespec_capabilities(file, "themespec",
753 secfile_destroy(file);
754 FC_FREE(fname);
755 theme_free(t);
756
757 return NULL;
758 }
759
760 file_capstr = secfile_lookup_str(file, "themespec.options");
761 duplicates_ok = has_capabilities("+duplicates_ok", file_capstr);
762
763 (void) secfile_entry_by_path(file, "themespec.name"); /* Currently unused */
764
766 t->priority = secfile_lookup_int_default(file, 0, "themespec.priority");
767
769
771 for (i = 0;
772 (lang = secfile_lookup_str_default(file, NULL, "themespec.fonts%d.langname", i)) != NULL;
773 i++) {
774 if (langname != NULL && strstr(langname, lang) != NULL) {
775 t_fontname = secfile_lookup_str(file, "themespec.fonts%d.font_file", i);
776 /* Don't break the loop, but read all the entries to avoid "unused entry" warnings */
777 } else {
778 (void) secfile_entry_lookup(file, "themespec.fonts%d.font_file", i);
779 }
780 }
781
782 if (t_fontname == NULL) {
783 t_fontname = secfile_lookup_str(file, "themespec.default_font_file");
784 } else {
785 (void) secfile_entry_lookup(file, "themespec.default_font_file");
786 }
787
788 if ((filename = fileinfoname(get_data_dirs(), t_fontname))) {
789 t->font_filename = fc_strdup(filename);
790 } else {
791 log_fatal("Could not open font: %s", t_fontname);
792 secfile_destroy(file);
793 FC_FREE(fname);
794 theme_free(t);
795
796 return NULL;
797 }
798 log_debug("theme font file %s", t->font_filename);
799
800 t->default_font_size = secfile_lookup_int_default(file, 10, "themespec.default_font_size");
801 log_debug("theme default font size %d", t->default_font_size);
802
804 "themespec.files");
805 if (NULL == spec_filenames || 0 == num_spec_files) {
806 log_error("No theme graphics files specified in \"%s\"", fname);
807 secfile_destroy(file);
808 FC_FREE(fname);
809 theme_free(t);
810
811 return NULL;
812 }
813
816 for (i = 0; i < num_spec_files; i++) {
817 struct specfile *sf = fc_malloc(sizeof(*sf));
818
819 log_debug("spec file %s", spec_filenames[i]);
820
821 sf->big_sprite = NULL;
823 if (!filename) {
824 log_error("Can't find spec file \"%s\".", spec_filenames[i]);
825 secfile_destroy(file);
826 FC_FREE(fname);
827 theme_free(t);
828
829 return NULL;
830 }
831 sf->file_name = fc_strdup(filename);
833
835 }
837
840
842
843 secfile_destroy(file);
844 log_verbose("finished reading \"%s\".", fname);
845 FC_FREE(fname);
846
847 return t;
848}
849
850/************************************************************************/
855static struct sprite *theme_load_sprite(struct theme *t, const char *tag_name)
856{
857 /* Lookup information about where the sprite is found. */
858 struct small_sprite *ss;
859
860 log_debug("theme_load_sprite(tag='%s')", tag_name);
862 return NULL;
863 }
864
865 fc_assert_ret_val(ss->ref_count >= 0, NULL);
866
867 if (!ss->sprite) {
868 /* If the sprite hasn't been loaded already, then load it. */
869 fc_assert_ret_val(ss->ref_count == 0, NULL);
870 if (ss->file) {
871 ss->sprite = load_sdl2_gfx_file(ss->file);
872 if (!ss->sprite) {
873 log_fatal("Couldn't load gfx file \"%s\" for sprite '%s'.",
874 ss->file, tag_name);
876 }
877 } else {
878 int sf_w, sf_h;
879
881 get_sprite_dimensions(ss->sf->big_sprite, &sf_w, &sf_h);
882 if (ss->x < 0 || ss->x + ss->width > sf_w
883 || ss->y < 0 || ss->y + ss->height > sf_h) {
884 log_error("Sprite '%s' in file \"%s\" isn't within the image!",
885 tag_name, ss->sf->file_name);
886 return NULL;
887 }
888 ss->sprite =
889 crop_sprite(ss->sf->big_sprite, ss->x, ss->y, ss->width, ss->height,
890 NULL, -1, -1, 1.0, FALSE);
891 }
892 }
893
894 /* Track the reference count so we know when to free the sprite. */
895 ss->ref_count++;
896
897 return ss->sprite;
898}
899
900/************************************************************************/
904static void theme_unload_sprite(struct theme *t, const char *tag_name)
905{
906 struct small_sprite *ss;
907
910 fc_assert_ret(ss->ref_count >= 1);
911 fc_assert_ret(ss->sprite);
912
913 ss->ref_count--;
914
915 if (ss->ref_count == 0) {
916 /* Nobody's using the sprite anymore, so we should free it. We know
917 * where to find it if we need it again. */
918 log_debug("freeing sprite '%s'.", tag_name);
919 free_sprite(ss->sprite);
920 ss->sprite = NULL;
921 }
922}
923
924/* Not very safe, but convenient: */
925#define SET_SPRITE(field, tag) \
926 do { \
927 t->sprites.field = theme_load_sprite(t, tag); \
928 fc_assert_exit_msg(NULL != t->sprites.field, \
929 "Sprite tag '%s' missing.", tag); \
930 } while (FALSE)
931
932/* Sets sprites.field to tag or (if tag isn't available) to alt */
933#define SET_SPRITE_ALT(field, tag, alt) \
934 do { \
935 t->sprites.field = theme_load_sprite(t, tag); \
936 if (!t->sprites.field) { \
937 t->sprites.field = theme_load_sprite(t, alt); \
938 } \
939 fc_assert_exit_msg(NULL != t->sprites.field, \
940 "Sprite tag '%s' and alternate '%s' are " \
941 "both missing.", tag, alt); \
942 } while (FALSE)
943
944/* Sets sprites.field to tag, or NULL if not available */
945#define SET_SPRITE_OPT(field, tag) \
946 t->sprites.field = theme_load_sprite(t, tag)
947
948#define SET_SPRITE_ALT_OPT(field, tag, alt) \
949 do { \
950 t->sprites.field = theme_lookup_sprite_tag_alt(t, LOG_VERBOSE, tag, alt,\
951 "sprite", #field); \
952 } while (FALSE)
953
954/************************************************************************/
958static void theme_lookup_sprite_tags(struct theme *t)
959{
960 /* the 'sprites' structure is currently not used, for now we call some
961 * functions in gui_tilespec.c instead */
962
966}
967
968/************************************************************************/
975{
977 if (sf->big_sprite) {
979 sf->big_sprite = NULL;
980 }
982}
983
984/************************************************************************/
995
996/************************************************************************/
1001 enum log_level level,
1002 const char *tag, const char *alt,
1003 const char *what,
1004 const char *name)
1005{
1006 struct sprite *sp;
1007
1008 /* (should get sprite_hash before connection) */
1010 "attempt to lookup for %s \"%s\" before "
1011 "sprite_hash setup", what, name);
1012
1013 sp = theme_load_sprite(t, tag);
1014 if (sp) {
1015 return sp;
1016 }
1017
1018 sp = theme_load_sprite(t, alt);
1019 if (sp) {
1020 log_verbose("Using alternate graphic \"%s\" (instead of \"%s\") "
1021 "for %s \"%s\".", alt, tag, what, name);
1022 return sp;
1023 }
1024
1025 log_base(level, "Don't have graphics tags \"%s\" or \"%s\" for %s \"%s\".",
1026 tag, alt, what, name);
1027 if (LOG_FATAL >= level) {
1029 }
1030
1031 return NULL;
1032}
1033
1034#define FULL_TILE_X_OFFSET ((t->normal_tile_width - t->full_tile_width) / 2)
1035#define FULL_TILE_Y_OFFSET (t->normal_tile_height - t->full_tile_height)
1036
1037#define ADD_SPRITE(s, draw_fog, x_offset, y_offset) \
1038 (fc_assert(s != NULL), \
1039 sprs->sprite = s, \
1040 sprs->foggable = (draw_fog && t->fogstyle == FOG_AUTO), \
1041 sprs->offset_x = x_offset, \
1042 sprs->offset_y = y_offset, \
1043 sprs++)
1044#define ADD_SPRITE_SIMPLE(s) ADD_SPRITE(s, TRUE, 0, 0)
1045#define ADD_SPRITE_FULL(s) \
1046 ADD_SPRITE(s, TRUE, FULL_TILE_X_OFFSET, FULL_TILE_Y_OFFSET)
1047
1048/************************************************************************/
1051static void theme_unload_all_sprites(struct theme *t)
1052{
1053 if (t->sprite_hash) {
1055 while (ss->ref_count > 0) {
1057 }
1059 }
1060}
1061
1062/************************************************************************/
1066{
1067 log_debug("theme_free_sprites()");
1068
1070
1071 if (t->sprite_hash) {
1073 t->sprite_hash = NULL;
1074 }
1075
1078 if (ss->file) {
1079 FC_FREE(ss->file);
1080 }
1081 fc_assert(ss->sprite == NULL);
1082 FC_FREE(ss);
1084
1087 FC_FREE(sf->file_name);
1088 if (sf->big_sprite) {
1089 free_sprite(sf->big_sprite);
1090 sf->big_sprite = NULL;
1091 }
1092 FC_FREE(sf);
1094
1095#if 0
1096 /* TODO: may be useful for theme sprites, too */
1097 sprite_vector_iterate(&t->sprites.****, psprite) {
1100 sprite_vector_free(&t->sprites.****);
1101#endif /* 0 */
1102
1103 /* the 'sprites' structure is currently not used, for now we call some
1104 * functions in gui_tilespec.c instead */
1105
1109}
1110
1111/************************************************************************/
1115{
1116 return t->background_system;
1117}
1118
1119/************************************************************************/
1123{
1124 return t->color_system;
1125}
bool has_capabilities(const char *us, const char *them)
Definition capability.c:88
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 * incite_cost
Definition comments.c:76
char * tag_name
Definition events.c:77
#define _(String)
Definition fcintl.h:67
void popdown_all_game_dialogs(void)
Definition dialogs.c:1514
void free_sprite(struct sprite *s)
Definition sprite.c:278
struct sprite * load_gfxfile(const char *filename, bool svgflag)
Definition sprite.c:170
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)
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:855
void theme_free(struct theme *ftheme)
Definition themespec.c:317
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
#define specfile_list_iterate_end
Definition themespec.c:89
static void theme_unload_sprite(struct theme *t, const char *tag_name)
Definition themespec.c:904
struct theme_color_system * theme_get_color_system(const struct theme *t)
Definition themespec.c:1122
const char * theme_font_filename(const struct theme *t)
Definition themespec.c:169
char * themespec_gfx_filename(const char *gfx_filename)
Definition themespec.c:690
#define specfile_list_iterate(list, pitem)
Definition themespec.c:87
static void theme_finish_loading_sprites(struct theme *t)
Definition themespec.c:974
static void theme_ensure_big_sprite(struct specfile *sf)
Definition themespec.c:485
static void theme_lookup_sprite_tags(struct theme *t)
Definition themespec.c:958
#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:530
void theme_free_sprites(struct theme *t)
Definition themespec.c:1065
void theme_load_sprites(struct theme *t)
Definition themespec.c:990
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:1114
void themespec_try_read(const char *theme_name)
Definition themespec.c:334
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:1000
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:721
#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:376
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:1051
static struct theme * theme_new(void)
Definition themespec.c:185
static struct sprite * load_sdl2_gfx_file(const char *gfx_filename)
Definition themespec.c:456
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:192
#define fc_assert_exit_msg(condition, message,...)
Definition log.h:212
#define log_verbose(message,...)
Definition log.h:110
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_ret_val(condition, val)
Definition log.h:195
#define log_fatal(message,...)
Definition log.h:101
#define fc_assert_action(condition, action)
Definition log.h:188
#define log_debug(message,...)
Definition log.h:116
#define log_normal(message,...)
Definition log.h:108
#define log_base(level, message,...)
Definition log.h:95
log_level
Definition log.h:29
@ LOG_FATAL
Definition log.h:30
#define log_error(message,...)
Definition log.h:104
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:209
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:51
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)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
#define section_list_iterate(seclist, psection)
#define section_list_iterate_end
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:190
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
crop_sprite
Definition sprite_g.h:30
struct sprite int int int int struct sprite int int float bool smooth get_sprite_dimensions
Definition sprite_g.h:36
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 small_sprite_hash * sprite_hash
Definition themespec.c:146
struct small_sprite_list * small_sprites
Definition themespec.c:141
int default_font_size
Definition themespec.c:138
struct theme_color_system * color_system
Definition themespec.c:151
char name[512]
Definition themespec.c:134
struct specfile_list * specfiles
Definition themespec.c:140
char * font_filename
Definition themespec.c:137
int priority
Definition themespec.c:135
struct theme_background_system * background_system
Definition themespec.c:150
Definition tile.h:50
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sprite_vector_iterate_end
Definition tilespec.h:46
#define sprite_vector_iterate(sprite_vec, psprite)
Definition tilespec.h:44