nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@7: #include nuclear@2: #include nuclear@13: #include "dsys.h" nuclear@2: #include "dsys_impl.h" nuclear@2: nuclear@4: static int read_script(struct dsys_demo *demo, FILE *fp, const char *fname); nuclear@7: static char *strip_ws(char *buf); nuclear@7: static void dbg_print_events(struct dsys_event *ev); nuclear@4: nuclear@6: static void proc_event(struct dsys_event *ev, demotime_t tm); nuclear@6: static void link_callback(struct dsys_event *ev, void *cls); nuclear@2: static void free_event(struct dsys_event *ev); nuclear@2: nuclear@4: static struct dsys_event *sort_evlist(struct dsys_event *list, int num_ev); nuclear@4: static struct dsys_event *merge_evlists(struct dsys_event *list1, struct dsys_event *list2); nuclear@2: nuclear@2: nuclear@2: struct dsys_demo *dsys_open(const char *fname) nuclear@2: { nuclear@2: FILE *fp; nuclear@4: struct dsys_demo *demo; nuclear@2: nuclear@2: if(!(fp = fopen(fname, "r"))) { nuclear@2: fprintf(stderr, "failed to open demoscript: %s: %s\n", fname, strerror(errno)); nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@4: if(!(demo = malloc(sizeof *demo))) { nuclear@4: perror("failed to allocate memory"); nuclear@4: fclose(fp); nuclear@4: return 0; nuclear@4: } nuclear@4: memset(demo, 0, sizeof *demo); nuclear@4: nuclear@4: demo->src_tm = demo->start_tm = -1; nuclear@4: nuclear@4: if(read_script(demo, fp, fname) == -1) { nuclear@4: free(demo); nuclear@4: fclose(fp); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@2: fclose(fp); nuclear@4: return demo; nuclear@2: } nuclear@2: nuclear@2: struct dsys_demo *dsys_open_stream(FILE *fp) nuclear@2: { nuclear@2: struct dsys_demo *demo; nuclear@2: nuclear@2: if(!(demo = malloc(sizeof *demo))) { nuclear@2: perror("failed to allocate memory"); nuclear@2: return 0; nuclear@2: } nuclear@2: memset(demo, 0, sizeof *demo); nuclear@2: nuclear@2: demo->src_tm = demo->start_tm = -1; nuclear@2: nuclear@4: if(read_script(demo, fp, 0) == -1) { nuclear@3: free(demo); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@2: return demo; nuclear@2: } nuclear@2: nuclear@2: void dsys_close(struct dsys_demo *demo) nuclear@2: { nuclear@4: while(demo->evlist) { nuclear@4: struct dsys_event *ev = demo->evlist; nuclear@4: demo->evlist = demo->evlist->next; nuclear@2: free_event(ev); nuclear@2: } nuclear@2: nuclear@2: free(demo); nuclear@2: } nuclear@2: nuclear@2: nuclear@4: #define SEP " \t\n\r" nuclear@3: nuclear@4: static int read_script(struct dsys_demo *demo, FILE *fp, const char *fname) nuclear@3: { nuclear@3: int nline = 0; nuclear@4: char buf[512], *line, *tok, *endp; nuclear@4: unsigned int t0, t1; nuclear@3: struct dsys_event *ev; nuclear@3: nuclear@4: if(!fname) { nuclear@4: fname = ""; nuclear@4: } nuclear@4: nuclear@7: demo->duration = dsys_msec_to_dtime(0); nuclear@7: nuclear@3: while(fgets(buf, sizeof buf, fp)) { nuclear@3: nline++; nuclear@3: nuclear@7: line = strip_ws(buf); nuclear@3: nuclear@3: if(!line || !*line) { nuclear@3: continue; nuclear@3: } nuclear@3: nuclear@4: if(!(tok = strtok(line, SEP)) || (t0 = strtol(tok, &endp, 10), endp == tok)) { nuclear@4: fprintf(stderr, "%s line: %d, error: expected timestamp t0\n", fname, nline); nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@3: if(!(tok = strtok(0, SEP))) { nuclear@4: fprintf(stderr, "%s line: %d, error: expected second timestamp or event name\n", fname, nline); nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@4: t1 = strtol(tok, &endp, 10); nuclear@4: if(endp == tok) { nuclear@4: t1 = t0; nuclear@4: } else { nuclear@4: if(!(tok = strtok(0, SEP))) { nuclear@4: fprintf(stderr, "%s line: %d, error: expected event name\n", fname, nline); nuclear@4: return -1; nuclear@4: } nuclear@4: } nuclear@4: nuclear@3: if(!(ev = malloc(sizeof *ev))) { nuclear@3: perror("read_script: failed to allocate memory for an event\n"); nuclear@3: return -1; nuclear@3: } nuclear@10: memset(ev, 0, sizeof *ev); nuclear@7: ev->t0 = dsys_msec_to_dtime(t0); nuclear@7: ev->t1 = dsys_msec_to_dtime(t1); nuclear@3: nuclear@3: if(!(ev->name = malloc(strlen(tok) + 1))) { nuclear@3: free(ev); nuclear@5: fprintf(stderr, "read_script: failed to allocate memory for the event name: %s\n", tok); nuclear@3: return -1; nuclear@3: } nuclear@4: strcpy(ev->name, tok); nuclear@4: nuclear@6: ev->eval = t0 == t1 ? dsys_eval_step : dsys_eval_lerp; nuclear@4: nuclear@4: ev->next = demo->evlist; nuclear@4: ev->prev = 0; nuclear@4: if(demo->evlist) { nuclear@4: demo->evlist->prev = ev; nuclear@4: } nuclear@4: demo->evlist = ev; nuclear@4: demo->num_ev++; nuclear@7: nuclear@7: if(ev->t1 > demo->duration) { nuclear@7: demo->duration = ev->t1; nuclear@7: } nuclear@3: } nuclear@3: nuclear@4: demo->evlist = sort_evlist(demo->evlist, demo->num_ev); nuclear@4: nuclear@10: /*dbg_print_events(demo->evlist);*/ nuclear@7: nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@7: static char *strip_ws(char *buf) nuclear@7: { nuclear@7: char *ptr; nuclear@7: nuclear@7: while(isspace(*buf)) { nuclear@7: buf++; nuclear@7: } nuclear@7: nuclear@7: ptr = buf; nuclear@7: while(*ptr) { nuclear@7: if(*ptr == '\n' || *ptr == '\r' || *ptr == '#') { nuclear@7: *ptr = 0; nuclear@7: break; nuclear@7: } nuclear@7: ptr++; nuclear@7: } nuclear@7: nuclear@7: return buf; nuclear@7: } nuclear@7: nuclear@7: static void dbg_print_events(struct dsys_event *ev) nuclear@7: { nuclear@7: int i; nuclear@7: nuclear@7: for(i=0; ev; i++) { nuclear@7: printf("%02d - %s (%f -> %f) [%s]\n", i, ev->eval == dsys_eval_step ? "step" : "lerp", nuclear@7: ev->t0, ev->t1, ev->name); nuclear@7: ev = ev->next; nuclear@7: } nuclear@7: } nuclear@3: nuclear@2: void dsys_update(struct dsys_demo *demo, demotime_t tm) nuclear@2: { nuclear@6: struct dsys_event *ev; nuclear@6: nuclear@2: demo->src_tm = tm; nuclear@2: nuclear@2: if(demo->start_tm == -1) { nuclear@2: dsys_start(demo); nuclear@2: } nuclear@2: nuclear@12: if(!demo->running) { nuclear@12: return; /* nothing changes */ nuclear@12: } nuclear@12: nuclear@6: demo->tm = tm - demo->start_tm - demo->stoppage_tm; nuclear@6: nuclear@7: if(demo->tm < 0) { nuclear@7: demo->tm = 0; nuclear@7: } nuclear@7: if(demo->tm > demo->duration) { nuclear@7: demo->tm = demo->duration; nuclear@7: } nuclear@7: nuclear@10: while(demo->active && demo->active->t1 <= demo->tm) { nuclear@6: proc_event(demo->active, demo->tm); nuclear@6: demo->active = demo->active->next; nuclear@6: } nuclear@6: nuclear@6: ev = demo->active; nuclear@7: while(ev && ev->t0 <= demo->tm) { nuclear@6: proc_event(ev, demo->tm); nuclear@6: ev = ev->next; nuclear@6: } nuclear@6: demo->nextev = ev; nuclear@7: nuclear@7: nuclear@7: if(demo->tm >= demo->duration) { nuclear@7: dsys_stop(demo); nuclear@7: } nuclear@6: } nuclear@6: nuclear@6: static void proc_event(struct dsys_event *ev, demotime_t tm) nuclear@6: { nuclear@6: float val = ev->eval(ev, tm); nuclear@6: nuclear@6: if(ev->val != val) { nuclear@6: struct callback *cb = ev->cblist; nuclear@6: nuclear@10: ev->val = val; nuclear@10: nuclear@6: while(cb) { nuclear@6: cb->func(ev, cb->cls); nuclear@6: cb = cb->next; nuclear@6: } nuclear@6: } nuclear@2: } nuclear@2: nuclear@2: void dsys_start(struct dsys_demo *demo) nuclear@2: { nuclear@2: if(demo->running) { nuclear@2: return; nuclear@2: } nuclear@2: nuclear@2: if(demo->start_tm == -1) { nuclear@2: demo->start_tm = demo->src_tm; nuclear@6: demo->nextev = demo->active = demo->evlist; nuclear@2: } else { nuclear@2: demo->stoppage_tm += demo->src_tm - demo->stop_tm; nuclear@2: } nuclear@2: nuclear@2: demo->running = 1; nuclear@2: } nuclear@2: nuclear@2: void dsys_stop(struct dsys_demo *demo) nuclear@2: { nuclear@2: if(!demo->running) { nuclear@2: return; nuclear@2: } nuclear@2: nuclear@2: demo->stop_tm = demo->src_tm; nuclear@2: demo->running = 0; nuclear@2: } nuclear@2: nuclear@2: int dsys_is_running(struct dsys_demo *demo) nuclear@2: { nuclear@2: return demo->running; nuclear@2: } nuclear@2: nuclear@2: nuclear@2: demotime_t dsys_duration(struct dsys_demo *demo) nuclear@2: { nuclear@2: return demo->duration; nuclear@2: } nuclear@2: nuclear@2: demotime_t dsys_time(struct dsys_demo *demo) nuclear@2: { nuclear@2: return demo->tm; nuclear@2: } nuclear@2: nuclear@2: float dsys_progress(struct dsys_demo *demo) nuclear@2: { nuclear@2: return demo->tm / demo->duration; nuclear@2: } nuclear@2: nuclear@2: /* seek without continuity */ nuclear@2: void dsys_seek(struct dsys_demo *demo, demotime_t tm) nuclear@2: { nuclear@8: struct dsys_event *ev; nuclear@8: nuclear@7: if(tm < 0) { nuclear@7: tm = 0; nuclear@7: } nuclear@7: if(tm > demo->duration) { nuclear@7: tm = demo->duration; nuclear@7: } nuclear@7: nuclear@10: if(tm < demo->tm) { nuclear@10: /* on backwards seek, invalidate the sliding window */ nuclear@10: demo->nextev = demo->active = demo->evlist; nuclear@10: } nuclear@10: nuclear@6: demo->start_tm = demo->src_tm - tm; nuclear@6: demo->stoppage_tm = 0; nuclear@10: demo->stop_tm = demo->src_tm; nuclear@10: demo->tm = tm; nuclear@8: nuclear@8: /* recalculate events */ nuclear@8: ev = demo->evlist; nuclear@8: while(ev) { nuclear@8: proc_event(ev, tm); nuclear@8: ev = ev->next; nuclear@8: } nuclear@2: } nuclear@2: nuclear@2: void dsys_seek_norm(struct dsys_demo *demo, float t) nuclear@2: { nuclear@2: dsys_seek(demo, t * demo->duration); nuclear@2: } nuclear@2: nuclear@2: /* seek by accelerating time */ nuclear@6: void dsys_warp(struct dsys_demo *demo, demotime_t tm) nuclear@6: { nuclear@6: fprintf(stderr, "dsys_warp not implemented yet\n"); nuclear@6: } nuclear@6: nuclear@6: void dsys_warp_norm(struct dsys_demo *demo, float t) nuclear@6: { nuclear@6: dsys_warp(demo, t * demo->duration); nuclear@6: } nuclear@2: nuclear@2: nuclear@2: /* events */ nuclear@5: struct dsys_event *dsys_event(struct dsys_demo *demo, const char *name) nuclear@5: { nuclear@5: struct dsys_event *iter = demo->evlist; nuclear@2: nuclear@5: while(iter) { nuclear@5: if(strcmp(iter->name, name) == 0) { nuclear@5: return iter; nuclear@5: } nuclear@5: iter = iter->next; nuclear@5: } nuclear@5: return 0; nuclear@5: } nuclear@2: nuclear@5: enum dsys_evtype dsys_event_type(struct dsys_event *ev) nuclear@5: { nuclear@5: return ev->type; nuclear@5: } nuclear@5: nuclear@5: float dsys_event_value(struct dsys_event *ev) nuclear@5: { nuclear@6: return ev->val; nuclear@5: } nuclear@5: nuclear@6: int dsys_event_callback(struct dsys_event *ev, void (*func)(struct dsys_event*, void*), void *cls) nuclear@5: { nuclear@6: struct callback *cb; nuclear@6: nuclear@6: if(!(cb = malloc(sizeof *cb))) { nuclear@6: perror("failed to allocate memory"); nuclear@6: return -1; nuclear@6: } nuclear@6: cb->func = func; nuclear@6: cb->cls = cls; nuclear@6: cb->next = ev->cblist; nuclear@6: ev->cblist = cb; nuclear@6: return 0; nuclear@5: } nuclear@5: nuclear@6: int dsys_event_link(struct dsys_event *ev, float *link) nuclear@6: { nuclear@6: return dsys_event_callback(ev, link_callback, link); nuclear@6: } nuclear@6: nuclear@6: static void link_callback(struct dsys_event *ev, void *cls) nuclear@6: { nuclear@6: *(float*)cls = ev->val; nuclear@6: } nuclear@2: nuclear@2: nuclear@2: /* time conversion */ nuclear@2: demotime_t dsys_sec_to_dtime(float sec) nuclear@2: { nuclear@2: return sec; nuclear@2: } nuclear@2: nuclear@2: demotime_t dsys_msec_to_dtime(unsigned long msec) nuclear@2: { nuclear@2: return (demotime_t)msec / 1000.0; nuclear@2: } nuclear@2: nuclear@2: float dsys_dtime_to_sec(demotime_t tm) nuclear@2: { nuclear@2: return tm; nuclear@2: } nuclear@2: nuclear@2: unsigned long dsys_dtime_to_msec(demotime_t tm) nuclear@2: { nuclear@2: return (unsigned long)(tm * 1000.0); nuclear@2: } nuclear@2: nuclear@2: nuclear@5: float dsys_eval_step(struct dsys_event *ev, demotime_t t) nuclear@2: { nuclear@2: return t >= ev->t1 ? 1.0 : 0.0; nuclear@2: } nuclear@2: nuclear@7: #define CLAMP(x, low, high) ((x) < (low) ? (low) : ((x) > (high) ? (high) : (x))) nuclear@7: nuclear@5: float dsys_eval_lerp(struct dsys_event *ev, demotime_t t) nuclear@2: { nuclear@7: float res = (t - ev->t0) / (ev->t1 - ev->t0); nuclear@7: return CLAMP(res, 0.0, 1.0); nuclear@2: } nuclear@2: nuclear@5: float dsys_eval_sigmoid(struct dsys_event *ev, demotime_t t) nuclear@2: { nuclear@5: t = dsys_eval_lerp(ev, t); nuclear@2: return 1.0 - (cos(t * M_PI) * 0.5 + 0.5); nuclear@2: } nuclear@2: nuclear@2: static void free_event(struct dsys_event *ev) nuclear@2: { nuclear@2: while(ev->cblist) { nuclear@2: struct callback *cb = ev->cblist; nuclear@2: ev->cblist = ev->cblist->next; nuclear@2: free(cb); nuclear@2: } nuclear@2: } nuclear@4: nuclear@4: static struct dsys_event *sort_evlist(struct dsys_event *list, int num_ev) nuclear@4: { nuclear@4: int i, num_left, num_right; nuclear@4: struct dsys_event *left, *right, *node = list; nuclear@4: nuclear@4: if(num_ev < 2) { nuclear@4: return list; nuclear@4: } nuclear@4: nuclear@4: num_left = num_ev / 2; nuclear@4: num_right = num_ev - num_left; nuclear@4: nuclear@4: for(i=0; inext; nuclear@4: } nuclear@4: nuclear@4: if(node->prev) { nuclear@4: node->prev->next = 0; nuclear@4: node->prev = 0; nuclear@4: } nuclear@4: nuclear@4: left = sort_evlist(list, num_left); nuclear@4: right = sort_evlist(node, num_right); nuclear@4: nuclear@4: return merge_evlists(left, right); nuclear@4: } nuclear@4: nuclear@4: static struct dsys_event *merge_evlists(struct dsys_event *list1, struct dsys_event *list2) nuclear@4: { nuclear@4: struct dsys_event *head, *tail, *node; nuclear@4: nuclear@4: if(!list1) { nuclear@4: return list2; nuclear@4: } nuclear@4: if(!list2) { nuclear@4: return list1; nuclear@4: } nuclear@4: nuclear@4: head = tail = 0; nuclear@4: nuclear@4: while(list1 && list2) { nuclear@4: if(list1->t0 < list2->t0) { nuclear@4: node = list1; nuclear@4: list1 = list1->next; nuclear@4: } else { nuclear@4: node = list2; nuclear@4: list2 = list2->next; nuclear@4: } nuclear@4: nuclear@4: node->next = 0; nuclear@4: node->prev = tail; nuclear@4: nuclear@4: if(!head) { nuclear@4: head = node; nuclear@4: } else { nuclear@4: tail->next = node; nuclear@4: } nuclear@4: tail = node; nuclear@4: } nuclear@4: nuclear@4: if(list1) { nuclear@4: tail->next = list1; nuclear@4: list1->prev = tail; nuclear@4: } else if(list2) { nuclear@4: tail->next = list2; nuclear@4: list2->prev = tail; nuclear@4: } nuclear@4: nuclear@4: return head; nuclear@4: }