42ae20b2983a505648161e537fca4e108767a2e8
[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
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         dsys.track = darr_alloc(0, sizeof *dsys.track);
30         dsys.value = darr_alloc(0, sizeof *dsys.value);
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, "");
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, node->name);
88                 }
89                 sub = sub->next;
90         }
91 }
92
93 static void proc_track(struct ts_node *node, const char *pname)
94 {
95         char *name, *fullname;
96 }
97
98 static long io_read(void *buf, size_t bytes, void *uptr)
99 {
100         return ass_fread(buf, 1, bytes, uptr);
101 }
102
103
104 void dsys_destroy(void)
105 {
106         int i;
107
108         for(i=0; i<dsys.num_screens; i++) {
109                 anm_destroy_track(&dsys.screens[i]->track);
110                 if(dsys.screens[i]->destroy) {
111                         dsys.screens[i]->destroy();
112                 }
113         }
114         dsys.num_screens = 0;
115
116         darr_free(dsys.track);
117         darr_free(dsys.value);
118         rb_free(dsys.trackmap);
119 }
120
121 void dsys_update(void)
122 {
123         int i, j, sort_needed = 0;
124         struct demoscreen *scr;
125
126         dsys.tmsec = time_msec;
127
128         dsys.num_act = 0;
129         for(i=0; i<dsys.num_screens; i++) {
130                 scr = dsys.screens[i];
131                 scr->vis = anm_get_value(&scr->track, dsys.tmsec);
132
133                 if(scr->vis > 0.0f) {
134                         if(!scr->active) {
135                                 if(scr->start) scr->start();
136                                 scr->active = 1;
137                         }
138                         if(scr->update) scr->update(dsys.tmsec);
139
140                         if(dsys.num_act && scr->prio != dsys.act[dsys.num_act - 1]->prio) {
141                                 sort_needed = 1;
142                         }
143                         dsys.act[dsys.num_act++] = scr;
144                 } else {
145                         if(scr->active) {
146                                 if(scr->stop) scr->stop();
147                                 scr->active = 0;
148                         }
149                 }
150         }
151
152         if(sort_needed) {
153                 for(i=0; i<dsys.num_act; i++) {
154                         for(j=i+1; j<dsys.num_act; j++) {
155                                 if(dsys.act[j]->prio > dsys.act[j - 1]->prio) {
156                                         void *tmp = dsys.act[j];
157                                         dsys.act[j] = dsys.act[j - 1];
158                                         dsys.act[j - 1] = tmp;
159                                 }
160                         }
161                 }
162         }
163
164         /* evaluate tracks */
165         for(i=0; i<dsys.num_tracks; i++) {
166                 dsys.value[i] = anm_get_value(dsys.track + i, dsys.tmsec);
167         }
168 }
169
170 /* TODO: do something about draw ordering of the active screens */
171 void dsys_draw(void)
172 {
173         int i;
174         for(i=0; i<dsys.num_act; i++) {
175                 dsys.act[i]->draw();
176         }
177 }
178
179 void dsys_run(void)
180 {
181 }
182
183 void dsys_stop(void)
184 {
185 }
186
187 void dsys_seek_abs(long tm)
188 {
189 }
190
191 void dsys_seek_rel(long dt)
192 {
193 }
194
195 void dsys_seek_norm(float t)
196 {
197 }
198
199
200 struct demoscreen *dsys_find_screen(const char *name)
201 {
202         int i;
203
204         if(!name) return 0;
205
206         for(i=0; i<dsys.num_screens; i++) {
207                 if(strcmp(dsys.screens[i]->name, name) == 0) {
208                         return dsys.screens[i];
209                 }
210         }
211         return 0;
212 }
213
214 void dsys_run_screen(struct demoscreen *scr)
215 {
216         int i;
217
218         if(!scr) return;
219         if(dsys.num_act == 1 && dsys.act[0] == scr) return;
220
221         for(i=0; i<dsys.num_act; i++) {
222                 if(dsys.act[i]->stop) dsys.act[i]->stop();
223                 dsys.act[i]->active = 0;
224         }
225
226         dsys.act[0] = scr;
227         dsys.num_act = 1;
228
229         if(scr->start) scr->start();
230         scr->active = 1;
231 }
232
233
234 int dsys_add_screen(struct demoscreen *scr)
235 {
236         if(!scr->name || !scr->init || !scr->draw) {
237                 fprintf(stderr, "dsys_add_screen: invalid screen\n");
238                 return -1;
239         }
240         if(anm_init_track(&scr->track) == -1) {
241                 fprintf(stderr, "dsys_add_screen: failed to initialize keyframe track\n");
242                 return -1;
243         }
244         anm_set_track_interpolator(&scr->track, ANM_INTERP_LINEAR);
245         anm_set_track_extrapolator(&scr->track, ANM_EXTRAP_CLAMP);
246         anm_set_track_default(&scr->track, 0);
247
248         dsys.screens[dsys.num_screens++] = scr;
249         return 0;
250 }
251
252 int dsys_add_track(const char *name)
253 {
254         struct anm_track trk;
255         int idx;
256
257         if(rb_find(dsys.trackmap, (char*)name)) {
258                 fprintf(stderr, "ignoring duplicate track: %s\n", name);
259                 return -1;
260         }
261
262         idx = darr_size(dsys.track);
263         darr_push(dsys.track, &trk);
264         darr_pushf(dsys.value, 0);
265
266         if(rb_insert(dsys.trackmap, (char*)name, (void*)(intptr_t)idx) == -1) {
267                 fprintf(stderr, "failed to insert to track map: %s\n", name);
268                 abort();
269         }
270         return 0;
271 }
272
273 int dsys_find_track(const char *name)
274 {
275         struct rbnode *n = rb_find(dsys.trackmap, (char*)name);
276         if(!n) return -1;
277
278         return (intptr_t)n->data;
279 }
280
281 float dsys_value(const char *name)
282 {
283         int idx = dsys_find_track(name);
284         return idx == -1 ? 0.0f : dsys.value[idx];
285 }