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