06aa8c2141d609dd1681ce7fb5a2a5b372df00fa
[andemo] / src / demosys.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "demo.h"
4 #include "demosys.h"
5 #include "treestore.h"
6 #include "assfile.h"
7 #include "rbtree.h"
8 #include "darray.h"
9
10 void regscr_testa(void);
11 void regscr_testb(void);
12
13 static void proc_screen_script(struct demoscreen *scr, struct ts_node *node);
14 static void proc_track(struct ts_node *node, const char *pname);
15 static long io_read(void *buf, size_t bytes, void *uptr);
16 static void del_rbnode(struct rbnode *node, void *cls);
17
18
19 int dsys_init(const char *fname)
20 {
21         int i;
22         struct ts_io io = {0};
23         struct ts_node *ts, *tsnode;
24         struct demoscreen *scr;
25
26         memset(&dsys, 0, sizeof dsys);
27         if(!(dsys.trackmap = rb_create(RB_KEY_STRING))) {
28                 return -1;
29         }
30         rb_set_delete_func(dsys.trackmap, del_rbnode, 0);
31
32         dsys.track = darr_alloc(0, sizeof *dsys.track);
33         dsys.value = darr_alloc(0, sizeof *dsys.value);
34
35         regscr_testa();
36         regscr_testb();
37
38         for(i=0; i<dsys.num_screens; i++) {
39                 if(dsys.screens[i]->init() == -1) {
40                         fprintf(stderr, "failed to initialize demo screen: %s\n", dsys.screens[i]->name);
41                         return -1;
42                 }
43         }
44
45         if(!fname || !(io.data = ass_fopen(fname, "rb"))) {
46                 dsys_run_screen(dsys.screens[0]);
47                 return 0;
48         }
49         io.read = io_read;
50
51         if(!(ts = ts_load_io(&io)) || strcmp(ts->name, "demo") != 0) {
52                 ass_fclose(io.data);
53                 fprintf(stderr, "failed to read demoscript\n");
54                 return -1;
55         }
56
57         tsnode = ts->child_list;
58         while(tsnode) {
59                 if(strcmp(tsnode->name, "screen") == 0 &&
60                                 (scr = dsys_find_screen(ts_get_attr_str(tsnode, "name", 0)))) {
61                         proc_screen_script(scr, tsnode);
62
63                 } else if(strcmp(tsnode->name, "track") == 0) {
64                         proc_track(tsnode, 0);
65                 }
66                 tsnode = tsnode->next;
67         }
68
69         ass_fclose(io.data);
70         return 0;
71 }
72
73 static void proc_screen_script(struct demoscreen *scr, struct ts_node *node)
74 {
75         struct ts_node *sub;
76         struct ts_attr *attr;
77         long tm;
78
79         attr = node->attr_list;
80         while(attr) {
81                 if(sscanf(attr->name, "key_%ld", &tm) == 1 && attr->val.type == TS_NUMBER) {
82                         anm_set_value(&scr->track, tm, attr->val.fnum);
83                 }
84                 attr = attr->next;
85         }
86
87         sub = node->child_list;
88         while(sub) {
89                 if(strcmp(sub->name, "track") == 0) {
90                         proc_track(sub, scr->name);
91                 }
92                 sub = sub->next;
93         }
94 }
95
96 static void proc_track(struct ts_node *node, const char *pname)
97 {
98         char *name, *buf;
99         struct ts_attr *attr;
100         long tm;
101         int tidx;
102         struct anm_track *trk;
103
104         if(!(name = (char*)ts_get_attr_str(node, "name", 0))) {
105                 return;
106         }
107         if(pname) {
108                 buf = alloca(strlen(name) + strlen(pname) + 2);
109                 sprintf(buf, "%s.%s", pname, name);
110                 name = buf;
111         }
112
113         if((tidx = dsys_add_track(name)) == -1) {
114                 return;
115         }
116         trk = dsys.track + tidx;
117
118         attr = node->attr_list;
119         while(attr) {
120                 if(sscanf(attr->name, "key_%ld", &tm) == 1 && attr->val.type == TS_NUMBER) {
121                         anm_set_value(trk, tm, attr->val.fnum);
122                 }
123                 attr = attr->next;
124         }
125 }
126
127 static long io_read(void *buf, size_t bytes, void *uptr)
128 {
129         return ass_fread(buf, 1, bytes, uptr);
130 }
131
132
133 void dsys_destroy(void)
134 {
135         int i;
136
137         for(i=0; i<dsys.num_screens; i++) {
138                 anm_destroy_track(&dsys.screens[i]->track);
139                 if(dsys.screens[i]->destroy) {
140                         dsys.screens[i]->destroy();
141                 }
142         }
143         dsys.num_screens = 0;
144
145         darr_free(dsys.track);
146         darr_free(dsys.value);
147         rb_free(dsys.trackmap);
148 }
149
150 void dsys_update(void)
151 {
152         int i, j, sort_needed = 0;
153         struct demoscreen *scr;
154
155         dsys.tmsec = time_msec;
156
157         /* evaluate tracks */
158         for(i=0; i<dsys.num_tracks; i++) {
159                 dsys.value[i] = anm_get_value(dsys.track + i, dsys.tmsec);
160         }
161
162         if(dsys.scr_override) {
163                 scr = dsys.scr_override;
164                 scr->vis = 1;
165                 if(scr->update) scr->update(dsys.tmsec);
166                 return;
167         }
168
169         dsys.num_act = 0;
170         for(i=0; i<dsys.num_screens; i++) {
171                 scr = dsys.screens[i];
172                 scr->vis = anm_get_value(&scr->track, dsys.tmsec);
173
174                 if(scr->vis > 0.0f) {
175                         if(!scr->active) {
176                                 if(scr->start) scr->start();
177                                 scr->active = 1;
178                         }
179                         if(scr->update) scr->update(dsys.tmsec);
180
181                         if(dsys.num_act && scr->prio != dsys.act[dsys.num_act - 1]->prio) {
182                                 sort_needed = 1;
183                         }
184                         dsys.act[dsys.num_act++] = scr;
185                 } else {
186                         if(scr->active) {
187                                 if(scr->stop) scr->stop();
188                                 scr->active = 0;
189                         }
190                 }
191         }
192
193         if(sort_needed) {
194                 for(i=0; i<dsys.num_act; i++) {
195                         for(j=i+1; j<dsys.num_act; j++) {
196                                 if(dsys.act[j]->prio > dsys.act[j - 1]->prio) {
197                                         void *tmp = dsys.act[j];
198                                         dsys.act[j] = dsys.act[j - 1];
199                                         dsys.act[j - 1] = tmp;
200                                 }
201                         }
202                 }
203         }
204 }
205
206 /* TODO: do something about draw ordering of the active screens */
207 void dsys_draw(void)
208 {
209         int i;
210
211         if(dsys.scr_override) {
212                 dsys.scr_override->draw();
213                 return;
214         }
215
216         for(i=0; i<dsys.num_act; i++) {
217                 dsys.act[i]->draw();
218         }
219 }
220
221 void dsys_run(void)
222 {
223 }
224
225 void dsys_stop(void)
226 {
227 }
228
229 void dsys_seek_abs(long tm)
230 {
231 }
232
233 void dsys_seek_rel(long dt)
234 {
235 }
236
237 void dsys_seek_norm(float t)
238 {
239 }
240
241
242 struct demoscreen *dsys_find_screen(const char *name)
243 {
244         int i;
245
246         if(!name) return 0;
247
248         for(i=0; i<dsys.num_screens; i++) {
249                 if(strcmp(dsys.screens[i]->name, name) == 0) {
250                         return dsys.screens[i];
251                 }
252         }
253         return 0;
254 }
255
256 void dsys_run_screen(struct demoscreen *scr)
257 {
258         int i;
259
260         if(!scr) {
261                 if(dsys.scr_override) {
262                         scr = dsys.scr_override;
263                         if(scr->stop) scr->stop();
264                 }
265                 dsys.scr_override = 0;
266                 return;
267         }
268
269         for(i=0; i<dsys.num_act; i++) {
270                 if(dsys.act[i]->stop) dsys.act[i]->stop();
271                 dsys.act[i]->active = 0;
272         }
273         dsys.num_act = 0;
274
275         dsys.scr_override = scr;
276
277         if(scr->start) scr->start();
278         scr->active = 1;
279 }
280
281
282 int dsys_add_screen(struct demoscreen *scr)
283 {
284         if(!scr->name || !scr->init || !scr->draw) {
285                 fprintf(stderr, "dsys_add_screen: invalid screen\n");
286                 return -1;
287         }
288         if(anm_init_track(&scr->track) == -1) {
289                 fprintf(stderr, "dsys_add_screen: failed to initialize keyframe track\n");
290                 return -1;
291         }
292         anm_set_track_interpolator(&scr->track, ANM_INTERP_LINEAR);
293         anm_set_track_extrapolator(&scr->track, ANM_EXTRAP_CLAMP);
294         anm_set_track_default(&scr->track, 0);
295
296         dsys.screens[dsys.num_screens++] = scr;
297         return 0;
298 }
299
300 int dsys_add_track(const char *name)
301 {
302         struct anm_track trk;
303         int idx;
304
305         if(rb_find(dsys.trackmap, (char*)name)) {
306                 fprintf(stderr, "ignoring duplicate track: %s\n", name);
307                 return -1;
308         }
309
310         idx = darr_size(dsys.track);
311         darr_push(dsys.track, &trk);
312         darr_pushf(dsys.value, 0);
313
314         anm_init_track(dsys.track + idx);
315
316         if(rb_insert(dsys.trackmap, (char*)strdup_nf(name), (void*)(intptr_t)idx) == -1) {
317                 fprintf(stderr, "failed to insert to track map: %s\n", name);
318                 abort();
319         }
320         dsys.num_tracks = idx + 1;
321         return idx;
322 }
323
324 int dsys_find_track(const char *name)
325 {
326         struct rbnode *n = rb_find(dsys.trackmap, (char*)name);
327         if(!n) return -1;
328
329         return (intptr_t)n->data;
330 }
331
332 float dsys_value(const char *name)
333 {
334         int idx = dsys_find_track(name);
335         return idx == -1 ? 0.0f : dsys.value[idx];
336 }
337
338 static void del_rbnode(struct rbnode *node, void *cls)
339 {
340         free(node->key);
341 }