7be9c157699c8f88e8718f814c4a4b28be836256
[vrlugburz] / src / tileset.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <alloca.h>
5 #include "treestore.h"
6 #include "tileset.h"
7 #include "level.h"
8 #include "fs.h"
9
10 static int match_prefix(const char *str, const char *prefix);
11
12 static struct tileset *tset_list;
13
14 int load_tileset(struct tileset *tset, const char *fname)
15 {
16         struct ts_node *ts, *node, *iter;
17         const char *str, *prefix;
18         char *path;
19         struct mesh *mesh;
20         struct tile *tile;
21         int type;
22         float xform[16], *vec;
23
24         if(!(ts = ts_load(fname))) {
25                 fprintf(stderr, "failed to load tileset: %s\n", fname);
26                 return -1;
27         }
28         if(strcmp(ts->name, "tileset") != 0) {
29                 fprintf(stderr, "invalid or corrupted tileset file: %s\n", fname);
30                 ts_free_tree(ts);
31                 return -1;
32         }
33
34         if(!(str = ts_get_attr_str(ts, "file", 0))) {
35                 fprintf(stderr, "tileset %s is missing the file attribute\n", fname);
36                 ts_free_tree(ts);
37                 return -1;
38         }
39         path = alloca(strlen(fname) + strlen(str) + 2);
40         path_dir(fname, path);
41         combine_path(path, str, path);
42
43         if(load_scenefile(&tset->scn, path) == -1) {
44                 fprintf(stderr, "tileset %s: failed to load scene file: %s\n", fname, path);
45                 ts_free_tree(ts);
46                 return -1;
47         }
48
49         tset->fname = strdup(fname);
50         tset->name = strdup(ts_get_attr_str(ts, "name", fname));
51
52         iter = ts->child_list;
53         while(iter) {
54                 node = iter;
55                 iter = iter->next;
56                 if(strcmp(node->name, "tile") == 0) {
57                         if(!(prefix = ts_get_attr_str(node, "prefix", 0))) {
58                                 continue;
59                         }
60
61                         if(!(str = ts_get_attr_str(node, "type", 0))) {
62                                 fprintf(stderr, "load_tileset: missing tile type\n");
63                                 continue;
64                         }
65                         if((type = tile_type(str)) == -1) {
66                                 fprintf(stderr, "load_tileset: invalid tile type: %s\n", str);
67                                 continue;
68                         }
69
70                         if(!(tile = malloc(sizeof *tile))) {
71                                 fprintf(stderr, "load_tileset: failed to allocate tile\n");
72                                 continue;
73                         }
74                         tile->type = type;
75
76                         cgm_midentity(xform);
77                         if((vec = ts_get_attr_vec(node, "pos", 0))) {
78                                 cgm_mtranslation(xform, vec[0], vec[1], vec[2]);
79                         }
80
81                         init_meshgroup(&tile->mgrp);
82
83                         mesh = tset->scn.meshlist;
84                         while(mesh) {
85                                 if(mesh->name && match_prefix(mesh->name, prefix)) {
86                                         if(vec) {
87                                                 xform_mesh(mesh, xform);
88                                         }
89                                         add_meshgroup_mesh(&tile->mgrp, mesh);
90                                 }
91                                 mesh = mesh->next;
92                         }
93
94                         tile->next = tset->tiles;
95                         tset->tiles = tile;
96                 }
97         }
98
99         return 0;
100 }
101
102 void destroy_tileset(struct tileset *tset)
103 {
104         struct tile *tile;
105
106         free(tset->name);
107         free(tset->fname);
108
109         while(tset->tiles) {
110                 tile = tset->tiles;
111                 tset->tiles = tile->next;
112
113                 free(tile->name);
114                 free(tile);
115         }
116
117         destroy_scenefile(&tset->scn);
118 }
119
120 struct tileset *get_tileset(const char *fname)
121 {
122         struct tileset *ts = tset_list;
123         while(ts) {
124                 if(strcmp(ts->fname, fname) == 0) {
125                         return ts;
126                 }
127                 ts = ts->next;
128         }
129
130         if(!(ts = malloc(sizeof *ts))) {
131                 fprintf(stderr, "failed to allocate tileset\n");
132                 return 0;
133         }
134         if(load_tileset(ts, fname) == -1) {
135                 free(ts);
136                 return 0;
137         }
138         ts->next = tset_list;
139         tset_list = ts;
140         return ts;
141 }
142
143 void free_all_tilesets(void)
144 {
145         struct tileset *ts;
146
147         while(tset_list) {
148                 ts = tset_list;
149                 tset_list = ts->next;
150                 destroy_tileset(ts);
151                 free(ts);
152         }
153 }
154
155 struct tile *get_tile(struct tileset *tset, int ttype)
156 {
157         struct tile *tile = tset->tiles;
158         while(tile) {
159                 if(tile->type == ttype) {
160                         return tile;
161                 }
162                 tile = tile->next;
163         }
164         return 0;
165 }
166
167 int tile_type(const char *tstr)
168 {
169         static const char *typenames[] = {
170                 "open", "straight", "corner", "tee", "cross", "str2open", "stropen", 0
171         };
172         int i;
173
174         if(!tstr) return -1;
175
176         for(i=0; typenames[i]; i++) {
177                 if(strcmp(tstr, typenames[i]) == 0) {
178                         return i;
179                 }
180         }
181         return -1;
182 }
183
184 static int match_prefix(const char *str, const char *prefix)
185 {
186         while(*str && *prefix) {
187                 if(*str++ != *prefix++) {
188                         return 0;
189                 }
190         }
191         return 1;
192 }