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