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