almost done with the level reorganization
[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;
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(str, 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(node) {
54                 node = iter;
55                 iter = iter->next;
56                 if(strcmp(node->name, "tile") == 0) {
57                         if(!(str = ts_get_attr_str(node, "prefix", 0))) {
58                                 continue;
59                         }
60
61                         if((type = tile_type(ts_get_attr_str(node, "type", 0))) == -1) {
62                                 fprintf(stderr, "load_tileset: missing or invalid tile type\n");
63                                 continue;
64                         }
65
66                         if(!(tile = malloc(sizeof *tile))) {
67                                 fprintf(stderr, "load_tileset: failed to allocate tile\n");
68                                 continue;
69                         }
70                         tile->type = type;
71
72                         cgm_midentity(xform);
73                         if((vec = ts_get_attr_vec(node, "pos", 0))) {
74                                 cgm_mtranslation(xform, vec[0], vec[1], vec[2]);
75                         }
76
77                         init_meshgroup(&tile->mgrp);
78
79                         mesh = tset->scn.meshlist;
80                         while(mesh) {
81                                 if(match_prefix(mesh->name, str)) {
82                                         if(vec) {
83                                                 xform_mesh(mesh, xform);
84                                         }
85                                         add_meshgroup_mesh(&tile->mgrp, mesh);
86                                 }
87                                 mesh = mesh->next;
88                         }
89                 }
90         }
91
92         return 0;
93 }
94
95 void destroy_tileset(struct tileset *tset)
96 {
97         struct tile *tile;
98
99         free(tset->name);
100         free(tset->fname);
101
102         while(tset->tiles) {
103                 tile = tset->tiles;
104                 tset->tiles = tile->next;
105
106                 free(tile->name);
107                 free(tile);
108         }
109
110         destroy_scenefile(&tset->scn);
111 }
112
113 struct tileset *get_tileset(const char *fname)
114 {
115         struct tileset *ts = tset_list;
116         while(ts) {
117                 if(strcmp(ts->fname, fname) == 0) {
118                         return ts;
119                 }
120                 ts = ts->next;
121         }
122
123         if(!(ts = malloc(sizeof *ts))) {
124                 fprintf(stderr, "failed to allocate tileset\n");
125                 return 0;
126         }
127         if(load_tileset(ts, fname) == -1) {
128                 free(ts);
129                 return 0;
130         }
131         ts->next = tset_list;
132         tset_list = ts;
133         return ts;
134 }
135
136 void free_all_tilesets(void)
137 {
138         struct tileset *ts;
139
140         while(tset_list) {
141                 ts = tset_list;
142                 tset_list = ts->next;
143                 destroy_tileset(ts);
144                 free(ts);
145         }
146 }
147
148 struct tile *get_tile(struct tileset *tset, int ttype)
149 {
150         struct tile *tile = tset->tiles;
151         while(tile) {
152                 if(tile->type == ttype) {
153                         return tile;
154                 }
155                 tile = tile->next;
156         }
157         return 0;
158 }
159
160 int tile_type(const char *tstr)
161 {
162         static const char *typenames[] = {
163                 "open", "straight", "corner", "tee", "cross", "str2open", "stropen", 0
164         };
165         int i;
166
167         if(!tstr) return -1;
168
169         for(i=0; typenames[i]; i++) {
170                 if(strcmp(tstr, typenames[i]) == 0) {
171                         return i;
172                 }
173         }
174         return -1;
175 }
176
177 static int match_prefix(const char *str, const char *prefix)
178 {
179         while(*str && *prefix) {
180                 if(*str++ != *prefix++) {
181                         return 0;
182                 }
183         }
184         return 1;
185 }