#include #ifndef _plan9_ #include #ifdef NO_MALLOC_H #include #else #include #endif #include #else #include #include #endif #include #include #include #include #include #include #include #include "play.h" #ifdef HAVE_GETTEXT #include #else #define gettext(STRING) STRING #endif #define nextchar() (uih->playstring==NULL?xio_getc(FD):uih->playstring[uih->playpos++]) #define ungetchar(c) (uih->playstring==NULL?xio_ungetc(c,FD):uih->playpos--) #define endoffile() (uih->playstring==NULL?xio_feof(FD):uih->playstring[uih->playpos]==0) static int nonblockmode; static catalog_t *catalog; /*The message catalog should be "session wide" */ CONST static char *errstring; #define seterr(str) {if(errstring==NULL) errstring=str;} #define FD uih->playc->file static char token[1024]; static int first; static int last; static int parsenext; static CONST char *CONST animroot = "animroot"; static inline struct uih_line *uih_findkey(uih_context * c, int key) { struct uih_line *l = c->playc->lines.first; while (l != NULL) { if (l->key == key) return l; l = l->next; } return NULL; } static inline void uih_removeline(uih_context * c, struct uih_line *l) { if (l == NULL) return; uih_removew(c, l->w); if (l->prev) l->prev->next = l->next; else c->playc->lines.first = l->next; if (l->next) l->next->prev = l->prev; free(l); } void uih_line(uih_context * c, dialogparam * d) { struct uih_window *w; struct uih_line *l; if (c->playstring != NULL) { seterr(gettext("line available only in animation replay")); return; } w = uih_registerline(c, 0, -1, -1, -1, -1); uih_removeline(c, uih_findkey(c, c->playc->lines.currkey)); l = (struct uih_line *) calloc(1, sizeof(*l)); l->posmode = d[0].dint; l->w = w; l->x1 = d[1].dcoord[0]; l->y1 = d[1].dcoord[1]; l->x2 = d[2].dcoord[0]; l->y2 = d[2].dcoord[1]; l->color = c->color; l->morph = 0; l->key = c->playc->lines.currkey++; l->prev = NULL; l->next = c->playc->lines.first; c->playc->lines.first = l; } void uih_morphline(uih_context * c, dialogparam * d) { struct uih_line *l; l = uih_findkey(c, c->playc->lines.currkey); if (l == NULL) { seterr(gettext("Morphing non existing line!")); return; } c->playc->lines.currkey++; l->mposmode = d[0].dint; l->mx1 = d[1].dcoord[0]; l->my1 = d[1].dcoord[1]; l->mx2 = d[2].dcoord[0]; l->my2 = d[2].dcoord[1]; l->morph = 1; c->playc->lines.morphing = 1; } void uih_morphlastline(uih_context * c, dialogparam * d) { c->playc->lines.currkey--; uih_morphline(c, d); } void uih_setkey(uih_context * c, int line) { if (!c->play) { seterr(gettext("linekey not available in this context!")); return; } c->playc->lines.currkey = line; } static void uih_stopmorphing(uih_context * c) { struct uih_line *l = c->playc->lines.first; while (l) { if (l->morph) { l->x1 = l->mx1; l->y1 = l->my1; l->x2 = l->mx2; l->y2 = l->my2; l->posmode = l->mposmode; l->morph = 0; c->playc->lines.morphing = 1; } l = l->next; } } void uih_update_lines(uih_context * c) { int m = 0; int co; struct uih_line *l = c->playc->lines.first; int x1, y1, x2, y2; number_t x, y; int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime; number_t mmul = /*(tl_lookup_timer (c->playc->timer) - c->playc->starttime) / (number_t) (c->playc->frametime - c->playc->starttime); */ MORPHVALUE(timer, c->playc->frametime - c->playc->starttime, c->playc->morphlinetimes[0], c->playc->morphlinetimes[1]); while (l) { switch (l->posmode) { case 0: x1 = (int) (c->image->width * l->x1); y1 = (int) (c->image->height * l->y1); x2 = (int) (c->image->width * l->x2); y2 = (int) (c->image->height * l->y2); break; case 1: x = c->image->width * c->image->pixelwidth; y = c->image->height * c->image->pixelheight; if (x > y) x = y; x1 = (int) (c->image->width / 2 + (l->x1 - 0.5) * x / c->image->pixelwidth); y1 = (int) (c->image->height / 2 + (l->y1 - 0.5) * x / c->image->pixelheight); x2 = (int) (c->image->width / 2 + (l->x2 - 0.5) * x / c->image->pixelwidth); y2 = (int) (c->image->height / 2 + (l->y2 - 0.5) * x / c->image->pixelheight); break; case 2: x = l->x1; y = l->y1; rotate(*(c->fcontext), x, y); x = (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc - c->fcontext->rs.nc) * c->zengine->image->width; y = (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi - c->fcontext->rs.ni) * c->zengine->image->height; x1 = (int) x; y1 = (int) y; c->zengine->action->convertup(c->zengine, &x1, &y1); x = l->x2; y = l->y2; rotate(*(c->fcontext), x, y); x = (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc - c->fcontext->rs.nc) * c->zengine->image->width; y = (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi - c->fcontext->rs.ni) * c->zengine->image->height; x2 = (int) x; y2 = (int) y; c->zengine->action->convertup(c->zengine, &x2, &y2); break; } if (l->morph) { int mx1, mx2, my1, my2; m = 1; switch (l->mposmode) { case 0: mx1 = (int) (c->image->width * l->mx1); my1 = (int) (c->image->height * l->my1); mx2 = (int) (c->image->width * l->mx2); my2 = (int) (c->image->height * l->my2); break; case 1: x = c->image->width * c->image->pixelwidth; y = c->image->height * c->image->pixelheight; if (x > y) x = y; mx1 = (int) (c->image->width / 2 + (l->mx1 - 0.5) * x / c->image->pixelwidth); my1 = (int) (c->image->height / 2 + (l->my1 - 0.5) * x / c->image->pixelheight); mx2 = (int) (c->image->width / 2 + (l->mx2 - 0.5) * x / c->image->pixelwidth); my2 = (int) (c->image->height / 2 + (l->my2 - 0.5) * x / c->image->pixelheight); break; default: x = l->mx1; y = l->my1; rotate(*(c->fcontext), x, y); x = (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc - c->fcontext->rs.nc) * c->zengine->image->width; y = (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi - c->fcontext->rs.ni) * c->zengine->image->height; mx1 = (int) x; my1 = (int) y; c->zengine->action->convertup(c->zengine, &mx1, &my1); x = l->mx2; y = l->my2; rotate(*(c->fcontext), x, y); x = (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc - c->fcontext->rs.nc) * c->zengine->image->width; y = (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi - c->fcontext->rs.ni) * c->zengine->image->height; mx2 = (int) x; my2 = (int) y; c->zengine->action->convertup(c->zengine, &mx2, &my2); break; } x1 = (int) (x1 + (mx1 - x1) * mmul); y1 = (int) (y1 + (my1 - y1) * mmul); x2 = (int) (x2 + (mx2 - x2) * mmul); y2 = (int) (y2 + (my2 - y2) * mmul); } switch (l->color) { case 1: co = BGCOLOR(c); break; case 0: co = FGCOLOR(c); break; default: co = SELCOLOR(c); break; } uih_setline(c, l->w, co, x1, y1, x2, y2); l = l->next; } c->playc->lines.morphing = m; if (m) c->display = 1; } void uih_clear_line(uih_context * c) { if (c->playstring != NULL) { seterr(gettext("clear_line available only in animation replay")); return; } uih_removeline(c, uih_findkey(c, c->playc->lines.currkey++)); } void uih_clear_lines(uih_context * c) { if (c->playstring != NULL) { seterr(gettext("clear_lines available only in animation replay")); return; } while (c->playc->lines.first != NULL) uih_removeline(c, c->playc->lines.first); c->playc->lines.currkey = 0; } void uih_freecatalog(uih_context * c) { if (catalog != NULL) free_catalog(catalog), catalog = NULL; } void uih_setfont(struct uih_context *uih) { if (catalog != NULL && find_text(catalog, "encoding") && find_text(catalog, "encoding")[0] == '2') uih->encoding = 2; else uih->encoding = 1; if (uih->image->flags & AAIMAGE) uih->font = &xaafont; else { if (uih->encoding == 2) { // A better heuristics would be used later. if (uih->image->width > 1000 && uih->image->height > 720) uih->font = &xbigfont3; else { if (uih->image->width > 800 && uih->image->height > 600) uih->font = &xbigfont2; else { if (uih->image->pixelheight < 0.07) uih->font = &xbigfont; else uih->font = &xsmallfont; } } } else { if (uih->image->pixelheight < 0.04) uih->font = &xbigfontil1; else if (uih->image->pixelheight < 0.07) uih->font = &xmedfontil1; else uih->font = &xsmallfontil1; } } } int uih_loadcatalog(uih_context * c, CONST char *name) { static int firsttime = 1; static CONST char *str; xio_file f = xio_getcatalog(name); if (f == XIO_FAILED) { if (firsttime) { firsttime = 0; return 0; } /*Let XaoS work as stand alone executable */ uih_error(c, gettext("Catalog file not found")); return 0; } firsttime = 0; if (catalog != NULL) free_catalog(catalog); catalog = load_catalog(f, &str); if (str != NULL) uih_error(c, str); uih_setfont(c); return (catalog != NULL); } static void handler(void *userdata) { struct uih_context *uih = (struct uih_context *) userdata; uih->playc->playframe++; uih->inanimation = 2; if (uih->playc->timerin) tl_remove_timer(uih->playc->timer); uih->playc->timerin = 0; } static void handler1(void *userdata) { struct uih_context *uih = (struct uih_context *) userdata; uih->playc->playframe++; uih->inanimation = 2; tl_update_time(); tl_reset_timer(uih->playc->timer); uih_setcomplettehandler(uih, NULL, NULL); } void uih_skipframe(struct uih_context *uih) { if (uih->play && uih->playc->timerin) handler(uih), tl_reset_timer(uih->playc->timer); } int uih_replayenable(struct uih_context *uih, xio_file f, xio_constpath filename, int animr) { struct uih_playcontext *p; CONST char *s; if (uih->play) { uih_error(uih, gettext("Replay is already active")); return 0; } if (f == XIO_FAILED) { uih_error(uih, gettext("File open failed")); return 0; } p = (struct uih_playcontext *) calloc(1, sizeof(*p)); if (p == NULL) { uih_error(uih, gettext("Out of memory")); return 0; } if (animr) { uih->menuroot = animroot; uih_updatemenus(uih, NULL); } p->file = f; p->playframe = 1; p->timer = tl_create_timer(); p->frametime = 0; p->morph = 0; p->morphjulia = 0; p->lines.first = NULL; p->lines.morphing = 0; p->lines.currkey = 0; tl_update_time(); tl_set_handler(p->timer, handler, uih); uih_stoptimers(uih); if (uih->stoppedtimers) tl_stop_timer(p->timer); uih->playc = p; uih->play = 1; uih_emulatetimers(uih); tl_reset_timer(p->timer); uih->playc->line = 1; if (filename != NULL) { uih->playc->directory = xio_getdirectory(filename); } else { uih->playc->directory = xio_getdirectory(XIO_EMPTYPATH); } uih->playc->level = 0; s = uih->playstring; uih->playstring = NULL; uih_playupdate(uih); uih->playstring = s; return 1; } void uih_replaydisable(struct uih_context *uih) { if (uih->play) { int i; uih->play = 0; tl_free_timer(uih->playc->timer); if (uih->menuroot == animroot) { uih->menuroot = "root"; uih_updatemenus(uih, NULL); } xio_close(uih->playc->file); for (i = 0; i < uih->playc->level; i++) xio_close(uih->playc->prevfiles[i]); uih->display = 1; uih->nonfractalscreen = 0; uih_setcomplettehandler(uih, NULL, NULL); uih_clear_lines(uih); free(uih->playc->directory); free(uih->playc); uih_display(uih); } } static void skipblank(struct uih_context *uih) { int c; if (uih->playstring != NULL) { while ((uih->playstring[uih->playpos] == ' ' || uih->playstring[uih->playpos] == '\t' || uih->playstring[uih->playpos] == '\r' || uih->playstring[uih->playpos] == '\n')) uih->playpos++; return; } do { c = xio_getc(FD); if (c == '\n') uih->playc->line++; if (c == ';') while (c != '\n' && !xio_feof(FD)) { c = xio_getc(FD); if (c == '\n') uih->playc->line++; } while (xio_feof(FD) && uih->playc->level) { c = XIO_EOF + 1; xio_close(FD); uih->playc->file = uih->playc->prevfiles[--uih->playc->level]; uih->playc->line = 1; } } while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == XIO_EOF + 1); if (c != XIO_EOF) xio_ungetc(c, FD); } static int gettoken(struct uih_context *uih) { int c; int i = 0; skipblank(uih); if (first && ((c = nextchar()) != '(')) { if (c && !endoffile()) { seterr("'(' expected"); } last = 1; return -1; } if (first) skipblank(uih), first = 0; if (endoffile()) { if (uih->playstring) { seterr(gettext("Missing parameter")); } else seterr(gettext("Unexpected end of file")); return 0; } if ((c = nextchar()) == '"') { while (c == '\r') c = nextchar(); token[i] = '"'; i++; do { c = nextchar(); while (c == '\r') c = nextchar(); if (c == XIO_EOF || c == 0) { if (uih->playstring) { seterr(gettext("Missing parameter")); } else seterr(gettext("Unexpected end of file")); return 0; } if (c == '\n' && uih->playstring == NULL) uih->playc->line++; if (c == '\\') token[i] = nextchar(); else token[i] = c; i++; if (i >= 1024) { seterr(gettext("Token is too long")); i = 0; } } while (c != '"'); } else ungetchar(c); do { c = nextchar(); if (c == XIO_EOF || c == 0) { if (uih->playstring) { seterr(gettext("Missing parameter")); } else seterr(gettext("Unexpected end of file")); return 0; } token[i] = c; i++; if (i >= 1024) { seterr(gettext("Token is too long")); i = 0; } } while (c != ' ' && c != '\t' && c != ')' && c != '\n' && c != '\r'); i--; token[i] = 0; skipblank(uih); if (c == ')') { last = 1; return i; } c = nextchar(); if (uih->playstring == NULL) { while (xio_feof(FD) && uih->playc->level) uih->playc->file = uih->playc->prevfiles[--uih->playc->level], uih->playc->line = 1; } if (c == XIO_EOF || c == 0) { if (uih->playstring) { seterr(gettext("Missing parameter")); } else seterr(gettext("Unexpected end of file")); return 0; } if (c == ')') { last = 1; return i; } ungetchar(c); return i; } static char *gettokenwr(struct uih_context *c) { if (last) return NULL; if (gettoken(c) < 0) return NULL; if (errstring) return NULL; return (token); } void uih_play_formula(struct uih_context *uih, char *fname) { int i; for (i = 0; i < nformulas; i++) { if (!strcmp(formulas[i].shortname, fname)) { set_formula(uih->fcontext, i); uih_newimage(uih); return; } } seterr(gettext("Unknown formula type")); } void uih_playmorph(struct uih_context *uih, dialogparam * d) { if (uih->playstring != NULL) { seterr(gettext("morph available only in animation replay")); return; } if (d[2].number <= 0 || d[3].number <= 0) { seterr(gettext("morphview: Invalid viewpoint")); uih->playc->destination = uih->fcontext->currentformula->v; } uih->playc->source = uih->fcontext->s; uih->playc->destination.cr = d[0].number; uih->playc->destination.ci = d[1].number; uih->playc->destination.rr = d[2].number; uih->playc->destination.ri = d[3].number; uih->playc->morph = 1; } void uih_playmove(struct uih_context *uih, number_t x, number_t y) { if (uih->playstring != NULL) { seterr(gettext("move available only in animation replay")); return; } uih->playc->source = uih->fcontext->s; uih->playc->destination.cr = x; uih->playc->destination.ci = y; uih->playc->destination.rr = uih->fcontext->s.rr; uih->playc->destination.ri = uih->fcontext->s.ri; uih->playc->morph = 1; } void uih_playmorphjulia(struct uih_context *uih, number_t x, number_t y) { if (uih->playstring != NULL) { seterr(gettext("morphjulia available only in animation replay")); return; } uih->playc->sr = uih->fcontext->pre; uih->playc->si = uih->fcontext->pim; uih->playc->dr = x; uih->playc->di = y; uih->playc->morphjulia = 1; } void uih_playmorphangle(struct uih_context *uih, number_t angle) { if (uih->playstring != NULL) { seterr(gettext("morphangle available only in animation replay")); return; } uih->playc->morphangle = 1; uih->playc->srcangle = uih->fcontext->angle; uih->playc->destangle = angle; } void uih_playautorotate(struct uih_context *uih, int mode) { if (mode) { uih_fastrotateenable(uih); uih_rotatemode(uih, ROTATE_CONTINUOUS); } else uih_rotatemode(uih, ROTATE_NONE); } void uih_playfilter(struct uih_context *uih, dialogparam * p) { CONST char *fname = p[0].dstring; int mode; int i; for (i = 0; i < uih_nfilters; i++) { if (!strcmp(uih_filters[i]->shortname, fname)) { mode = p[1].dint; if (mode) uih_enablefilter(uih, i); else uih_disablefilter(uih, i); return; } } seterr(gettext("Unknown filter")); } void uih_playdefpalette(struct uih_context *uih, int shift) { if (uih->zengine->fractalc->palette == NULL) return; if (mkdefaultpalette(uih->zengine->fractalc->palette) != 0) { uih_newimage(uih); } uih->palettetype = 0; uih->palettechanged = 1; if (shiftpalette(uih->zengine->fractalc->palette, shift)) { uih_newimage(uih); } uih->manualpaletteshift = 0; uih->paletteshift = shift; } void uih_zoomcenter(struct uih_context *uih, number_t x, number_t y) { uih->xcenter = x; uih->ycenter = y; uih->xcenterm = INT_MAX; uih->ycenterm = INT_MAX; } extern char *xtextposnames[]; extern char *ytextposnames[]; void uih_playtextpos(struct uih_context *uih, dialogparam * p) { int x, y; x = p[0].dint; y = p[1].dint; uih_settextpos(uih, x, y); } void uih_playusleep(struct uih_context *uih, int time) { parsenext = 0; if (uih->playstring != NULL) { seterr(gettext("sleep available only in animation replay")); return; } uih->playc->frametime = time; if (time < tl_lookup_timer(uih->playc->timer) /*&&((!uih->step)||(!uih->zoomactive)) */ ) { tl_slowdown_timer(uih->playc->timer, time); uih->playc->playframe++; } else { tl_set_interval(uih->playc->timer, time); if (!uih->playc->timerin) { uih->playc->timerin = 1; tl_add_timer(syncgroup, uih->playc->timer); } else printf(gettext("Internal program error #12 %i\n"), uih->playc->playframe); } uih->playc->starttime = tl_lookup_timer(uih->playc->timer); } void uih_playtextsleep(struct uih_context *uih) { uih_playusleep(uih, 500000 + 1000000 * (uih->nletters + uih->todisplayletters) / uih->letterspersec); uih->nletters = 0; uih->todisplayletters = 0; } void uih_playwait(struct uih_context *uih) { parsenext = 0; if (uih->playstring != NULL) { seterr(gettext("wait available only in animation replay")); return; } if (!uih->uncomplette && !uih->display && !uih->recalculatemode && !uih->displaytext && !uih->clearscreen) { uih->playc->playframe++; } else { uih_setcomplettehandler(uih, handler1, uih); } } void uih_playjulia(struct uih_context *uih, int julia) { julia = !julia; if (julia != uih->fcontext->mandelbrot) { uih->fcontext->mandelbrot = julia; uih->fcontext->version++; uih_updatemenus(uih, "uimandelbrot"); uih_newimage(uih); } } void uih_playcalculate(struct uih_context *uih) { uih_newimage(uih); } void uih_playzoom(struct uih_context *uih) { uih->zoomactive = 1; } void uih_playunzoom(struct uih_context *uih) { uih->zoomactive = -1; } void uih_playstop(struct uih_context *uih) { uih->zoomactive = 0; } void uih_playmessage(struct uih_context *uih, char *name) { char *message; if (catalog == NULL) { uih_text(uih, gettext("No catalog file loaded")); return; } message = find_text(catalog, name); if (message == NULL) { uih_text(uih, gettext("Message not found in catalog file")); return; } uih_text(uih, message); } void uih_playload(struct uih_context *uih, xio_path file) { xio_file f; xio_pathdata tmp; if (uih->playstring != NULL) { seterr(gettext("load available only in animation replay")); return; } if (uih->playc->level == MAXLEVEL) { seterr(gettext("Include level overflow")); return; } xio_addfname(tmp, uih->playc->directory, file); f = xio_ropen(tmp); if (f == XIO_FAILED) { seterr(gettext("File not found")); return; } uih->playc->prevfiles[uih->playc->level] = uih->playc->file; uih->playc->level++; uih->playc->file = f; uih->playc->line = 1; } static void uih_processcommand(struct uih_context *uih, int flags) { CONST char *error; first = 1; last = 0; error = menu_processcommand(uih, gettokenwr, 1, flags, uih->menuroot); if (error != NULL) seterr(error); if (!last) { seterr(gettext("Too many parameters")); } } void uih_playupdate(struct uih_context *uih) { static char errtext[1024]; errstring = NULL; while (uih->play && uih->playc->playframe && errstring == NULL) { parsenext = 1; uih->playc->playframe--; if (uih->playc->lines.morphing) { uih_stopmorphing(uih); uih->display = 1; } if (uih->playc->morph) { uih->fcontext->s = uih->playc->destination; uih_animate_image(uih); uih->playc->morph = 0; } if (uih->playc->morphangle) { uih_angle(uih, uih->playc->destangle); uih->playc->morphangle = 0; } if (uih->playc->morphjulia) { uih_setjuliaseed(uih, uih->playc->dr, uih->playc->di); uih->playc->morphjulia = 0; } while (!xio_feof(FD) && parsenext && errstring == NULL) { uih_processcommand(uih, MENUFLAG_NOPLAY); } /*while parsenext */ uih_update_lines(uih); if (errstring != NULL) { uih_error(uih, errstring); if (uih->play) { sprintf(errtext, gettext("Replay disabled at line %i"), uih->playc->line); uih_message(uih, errtext); } /*errstring[255]=0; */ } if ((xio_feof(FD) && parsenext) || errstring) { uih_replaydisable(uih); } } /*while play&&playframe */ } void uih_load(struct uih_context *uih, xio_file f, xio_constpath filename) { nonblockmode = 1; uih_replayenable(uih, f, filename, 0); uih_replaydisable(uih); nonblockmode = 0; } void uih_command(struct uih_context *uih, CONST char *command) { errstring = NULL; uih->playpos = 0; uih->playstring = command; uih_processcommand(uih, (uih->play ? MENUFLAG_NOMENU : 0)); uih->playstring = NULL; if (errstring != NULL) { uih_error(uih, errstring); } }