Diffstat (limited to 'core/multimedia/opieplayer/libflash/program.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/libflash/program.cc | 921 |
1 files changed, 921 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/libflash/program.cc b/core/multimedia/opieplayer/libflash/program.cc new file mode 100644 index 0000000..c6e8c0f --- a/dev/null +++ b/core/multimedia/opieplayer/libflash/program.cc @@ -0,0 +1,921 @@ +///////////////////////////////////////////////////////////// +// Flash Plugin and Player +// Copyright (C) 1998,1999 Olivier Debon +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +/////////////////////////////////////////////////////////////// +// Author : Olivier Debon <odebon@club-internet.fr> +// + +#include "swf.h" + +#define NOTHING 0x0 +#define WAKEUP 0x1 +#define GOTO 0x2 +#define REFRESH 0x4 + +#ifdef RCSID +static char *rcsid = "$Id$"; +#endif + +#define PRINT 0 + +int debug = 0; + +Program::Program(FlashMovie *movie, long n) +{ + long f; + + this->movie = movie; + + totalFrames = 0; + + dl = new DisplayList(movie); + if (dl == NULL) return; + frames = new Frame[n]; + if (frames == NULL) { + delete dl; + return; + } + + nbFrames = 0; + totalFrames = n; + currentFrame = 0; + loadingFrame = 0; + movieWait = 1; + nextFrame = currentFrame; + for(f = 0; f < n; f++) + { + frames[f].controls = 0; + frames[f].label = NULL; + } + + movieStatus = MoviePlay; + settings = 0; +} + +Program::~Program() +{ + int i; + Control *ctrl, *ctrl1; + + delete dl; + + if (frames != NULL) { + for(i=0;i<nbFrames;i++) { + ctrl = frames[i].controls; + if (frames[i].label) free(frames[i].label); + while (ctrl != NULL) { + ctrl1 = ctrl->next; + ctrl->next = NULL; + delete ctrl; + ctrl = ctrl1; + } + } + + delete[] frames; + } +} + +void +Program::validateLoadingFrame() +{ + nbFrames = loadingFrame; + loadingFrame++; + movieWait = 0; +} + +Frame * +Program::getFrames() +{ + return frames; +} + +long +Program::getNbFrames() +{ + return nbFrames; +} + +DisplayList * +Program::getDisplayList() +{ + return dl; +} + +long +Program::getCurrentFrame() +{ + return currentFrame; +} + +void +Program::setCurrentFrame(long n) +{ + currentFrame = n; + nextFrame = n; + //refresh = 1; +} + +void +Program::gotoFrame(GraphicDevice *gd, long frame) +{ + long f; + + //printf("GotoFrame %d (Current = %d)\n", frame, currentFrame); + dl->clearList(); + + for(f=0; f <= frame; f++) { + runFrame(gd, 0, f, 0); + } +} + +long +Program::runFrame(GraphicDevice *gd, SoundMixer *sm, long f, long action) +{ + Control *ctrl; + Character *character; + Matrix *matrix; + Cxform *cxform; + long status = NOTHING; + long update = 0; + char *name; + +#if PRINT&1 + if (action) printf("Prog %x (dl=%x): Frame N° %d/%d\n", this, this->dl, f, nbFrames-1); +#endif + movie->buttons_updated = 0; + + for(ctrl = frames[f].controls; ctrl; ctrl = ctrl->next) + { + switch (ctrl->type) + { + case ctrlPlaceObject: + case ctrlPlaceObject2: + character = 0; + matrix = 0; + cxform = 0; + name = ""; + if (ctrl->flags & placeHasCharacter) { + character = ctrl->character; + } + if (ctrl->flags & placeHasMatrix) { + matrix = &ctrl->matrix; + } + if (ctrl->flags & placeHasColorXform) { + cxform = &ctrl->cxform; + } + if (ctrl->flags & placeHasName) { + name = ctrl->name; + } + if (!ctrl->clipDepth) { // Ignore + dl->placeObject(gd,character, ctrl->depth, matrix, cxform, name); + update = 1; + } + break; + case ctrlRemoveObject: + character = ctrl->character; + + if (!character) break; // Should not happen + + dl->removeObject(gd, character, ctrl->depth); + if (action) { + character->reset(); + update = 1; + } + break; + case ctrlRemoveObject2: + character = dl->removeObject(gd,NULL, ctrl->depth); + if (character && action) { + character->reset(); + update = 1; + } + break; + // Actions + case ctrlDoAction: + if (action) { + status = doAction(gd, ctrl->actionRecords, sm); + } + break; + case ctrlStartSound: + if (action && sm) { + sm->startSound( (Sound *)ctrl->character ); + } + break; + case ctrlStopSound: + if (action && sm) { + sm->stopSounds(); + } + break; + case ctrlBackgroundColor: + if (action) { + if (gd->setBackgroundColor(ctrl->color)) { + dl->bbox.xmin = -32768; + dl->bbox.ymin = -32768; + dl->bbox.xmax = 32768; + dl->bbox.ymax = 32768; + } + } + break; + } + } + if (movie->buttons_updated) { + dl->updateButtons(movie); + } + + if (status & GOTO) { + if (nextFrame < nbFrames) { + gotoFrame(gd,nextFrame); + if (nextFrame != f) + if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame); + update = 1; + } + } + +#if PRINT&1 + if (action) printf("Frame N° %d ready\n", f); +#endif + return update; +} + +long +Program::nestedMovie(GraphicDevice *gd, SoundMixer *sm, Matrix *mat, Cxform *cxform) +{ + if (movieStatus == MoviePlay) { + // Movie Beeing Played + advanceFrame(); + if (currentFrame == 0) { + dl->clearList(); + } + runFrame(gd, sm, currentFrame); + if (nbFrames == 1) { + pauseMovie(); + } + } + + return (movieStatus == MoviePlay); +} + +long +Program::processMovie(GraphicDevice *gd, SoundMixer *sm) +{ + int wakeUp = 0; + +#if PRINT&1 + printf("Prog %x (dl=%x): Current = %d Next = %d Wait = %d Status = %d\n", this, this->dl, currentFrame, nextFrame, movieWait, movieStatus); +#endif + + if (movieStatus == MoviePlay && movieWait == 0) { + // Movie Beeing Played + advanceFrame(); + if (currentFrame == 0) { + dl->clearList(); + } + wakeUp |= runFrame(gd, sm, currentFrame); + wakeUp |= dl->updateSprites(); + if (nextFrame == nbFrames) { + if (nbFrames != totalFrames) { + movieWait = 1; + } else if ((settings & PLAYER_LOOP) == 0) { + pauseMovie(); + } + } + } else { + wakeUp |= dl->updateSprites(); + } + + if (wakeUp) { + render = 1; + } + + return (wakeUp || movieStatus == MoviePlay); +} + +/* timer (ms) -1 = delete timer */ +void setFlashTimer(struct timeval *tv, int time_ms) +{ + if (time_ms == -1) { + tv->tv_sec = -1; + } else { + gettimeofday(tv,0); + + tv->tv_usec += time_ms*1000; + while (tv->tv_usec > 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + } +} + +int checkFlashTimer(struct timeval *tv) +{ + struct timeval now; + + if (tv->tv_sec == -1) return 0; + + gettimeofday(&now,0); + return (now.tv_sec > tv->tv_sec || + (now.tv_sec == tv->tv_sec && now.tv_usec >= tv->tv_usec)); +} + +/* bbox */ +typedef struct { + long x1,y1,x2,y2; +} ButtonBoundingBox; + + +static void button_bbox_func(void *id, long y, long start, long end) +{ + ButtonBoundingBox *h = (ButtonBoundingBox *) id; + + if (y < h->y1) h->y1 = y; + if (y > h->y2) h->y2 = y; + if (start < h->x1) h->x1 = start; + if (end > h->x2) h->x2 = end; +} + +void computeBBox(FlashMovie *movie, Rect *rect, DisplayListEntry *e) +{ + ButtonBoundingBox bb; + + bb.x1 = LONG_MAX; + bb.y1 = LONG_MAX; + bb.x2 = LONG_MIN; + bb.y2 = LONG_MIN; + + e->character->getRegion(movie->gd,&e->renderMatrix,&bb,button_bbox_func); + + rect->xmin = bb.x1 / FRAC; + rect->xmax = bb.x2 / FRAC; + rect->ymin = bb.y1; + rect->ymax = bb.y2; +} + +void transform_coords(long *x_ptr,long *y_ptr, long cx, long cy, long dx, long dy) +{ + long x,y,x1,y1; + x = *x_ptr; + y = *y_ptr; + + x -= cx; + y -= cy; + + if (dx < 0) { + /* left */ + x1 = - x; + y1 = y; + } else if (dy < 0) { + /* up */ + y1 = x; + x1 = -y; + } else if (dy > 0) { + /* down */ + y1 = x; + x1 = y; + } else { + /* right */ + x1 = x; + y1 = y; + } + + *x_ptr = x1; + *y_ptr = y1; +} + +typedef struct { + FlashMovie *movie; + DisplayListEntry *emin,*cur_focus; + long dmin; + long w,cx,cy,dx,dy; +} ButtonFocus; + +static int button_focus(void *opaque, Program *prg, DisplayListEntry *e) +{ + ButtonFocus *h=(ButtonFocus *)opaque; + Rect rect; + long d,x,y; + + if (e != h->cur_focus) { + computeBBox(h->movie,&rect,e); + x = (rect.xmin + rect.xmax) / 2; + y = (rect.ymin + rect.ymax) / 2; + + /* transform the coords so that the angular sector is directed to the right */ + transform_coords(&x,&y,h->cx,h->cy,h->dx,h->dy); + + /* inside it ? */ + if ( x >= 0 && + (y - x - h->w) <= 0 && + (y + x + h->w) >= 0) { + d = x*x + y*y; + + if (d < h->dmin) { + h->dmin = d; + h->emin = e; + } + } + } + return 0; +} + +DisplayListEntry *moveFocus(FlashMovie *movie, long dx, long dy, + DisplayListEntry *cur_focus) +{ + Rect cur_rect; + ButtonFocus h; + + h.movie = movie; + h.dx = dx; + h.dy = dy; + + computeBBox(movie,&cur_rect,cur_focus); + /* center */ + h.cx = (cur_rect.xmin + cur_rect.xmax) / 2; + h.cy = (cur_rect.ymin + cur_rect.ymax) / 2; + + /* width/2 of the 45 degrees angular sector */ + if (dy != 0) { + /* for vertical displacement, we have a larger width */ + h.w = (cur_rect.xmax - cur_rect.xmin) / 2; + } else { + /* zero width for horizontal displacement */ + h.w = 0; + } + + /* now we select the nearest button in the angular sector */ + h.dmin = LONG_MAX; + h.emin = NULL; + h.cur_focus = cur_focus; + + exploreButtons(movie, &h, button_focus); + + return h.emin; +} + +static int button_newfocus(void *opaque, Program *prg, DisplayListEntry *e) +{ + * (DisplayListEntry **)opaque = e; + return 2; +} + +static int button_nextfocus(void *opaque, Program *prg, DisplayListEntry *e) +{ + static int found = 0; + DisplayListEntry **focus; + + focus = (DisplayListEntry **)opaque; + if (found) { + *focus = e; + found = 0; + return 2; + } + if (e == *focus) { + found = 1; + } + return 0; +} + + +/* XXX: should not be here (one level upper) */ +long +Program::handleEvent(GraphicDevice *gd, SoundMixer *sm, FlashEvent *fe) +{ + ActionRecord *action; + Program *prog; + long status = 0; + DisplayListEntry *cur_focus, *new_focus; + long dx,dy; + int refresh; + + refresh = 0; + + switch(fe->type) { + + case FeKeyRelease: + if (movie->mouse_active == 0) { + + if (movie->cur_focus) { + movie->cur_focus->owner->updateBoundingBox(movie->cur_focus); + movie->cur_focus->renderState = stateOver; + movie->cur_focus->owner->updateBoundingBox(movie->cur_focus); + } + } + break; + + case FeKeyPress: + + movie->mouse_active = 0; + + /* find the button which has the focus */ + cur_focus = movie->cur_focus; + + if (fe->key == FeKeyEnter) { + /* selection */ + if (cur_focus) { + /* select the button */ + cur_focus->owner->updateBoundingBox(cur_focus); + cur_focus->renderState = stateDown; + ((Button *)cur_focus->character)->updateButtonState(cur_focus); + cur_focus->owner->updateBoundingBox(cur_focus); + + movie->scheduledEvent.type = FeKeyRelease; + movie->scheduledEvent.key = FeKeyEnter; + + setFlashTimer(&movie->scheduledTime, 250); /* 250 ms down */ + } + } else { + /* displacement */ + + if (cur_focus == NULL) { + /* no current focus : set one */ + exploreButtons(movie, &cur_focus, button_newfocus); + if (cur_focus) { + cur_focus->renderState = stateOver; + ((Button *)cur_focus->character)->updateButtonState(cur_focus); + cur_focus->owner->updateBoundingBox(cur_focus); + } + movie->cur_focus = cur_focus; + } else { + /* move the focus (test) */ + switch(fe->key) { + case FeKeyNext: + /* Next available */ + cur_focus->owner->updateBoundingBox(cur_focus); + cur_focus->renderState = stateUp; + ((Button *)cur_focus->character)->updateButtonState(cur_focus); + cur_focus->owner->updateBoundingBox(cur_focus); + exploreButtons(movie, &cur_focus, button_nextfocus); + if (cur_focus) { + cur_focus->renderState = stateOver; + ((Button *)cur_focus->character)->updateButtonState(cur_focus); + cur_focus->owner->updateBoundingBox(cur_focus); + } + movie->cur_focus = cur_focus; + dx = 0; + dy = 0; + break; + case FeKeyUp: + dx = 0; + dy = -1; + break; + case FeKeyDown: + dx = 0; + dy = 1; + break; + case FeKeyLeft: + dx = -1; + dy = 0; + break; + case FeKeyRight: + dx = 1; + dy = 0; + break; + default: + /* should not happen */ + dx = 0; + dy = 0; + break; + } + + if (dx != 0 || dy != 0) { + + new_focus = moveFocus(movie, dx, dy, cur_focus); + if (new_focus) { + cur_focus->owner->updateBoundingBox(cur_focus); + cur_focus->renderState = stateUp; + ((Button *)cur_focus->character)->updateButtonState(cur_focus); + cur_focus->owner->updateBoundingBox(cur_focus); + + if (computeActions(movie, &prog, &action)) { + status |= prog->doAction(gd, action, sm); + } + + new_focus->renderState = stateOver; + ((Button *)new_focus->character)->updateButtonState(new_focus); + movie->cur_focus = new_focus; + new_focus->owner->updateBoundingBox(new_focus); + } else { + return 0; + } + } + } + if (movie->cur_focus == NULL) return 0; + } + break; + + case FeMouseMove: + movie->mouse_active = 1; + movie->mouse_x = fe->x * FRAC; + movie->mouse_y = fe->y * FRAC; + dl->updateButtons(movie); + break; + + case FeButtonPress: + movie->mouse_active = 1; + movie->button_pressed = 1; + dl->updateButtons(movie); + break; + + case FeButtonRelease: + movie->mouse_active = 1; + movie->button_pressed = 0; + dl->updateButtons(movie); + break; + + default: + return 0; + } + + if (computeActions(movie, &prog, &action)) { + status |= prog->doAction(gd, action, sm); + } + + if (status & REFRESH) { + status |= WAKEUP; + refresh = 1; + } + if (status & GOTO) { + if (nextFrame < nbFrames) { + gotoFrame(gd, nextFrame); + if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame); + refresh = 1; + } + } + + if (refresh) { + dl->updateSprites(); + render = 1; + } + return (refresh || movieStatus == MoviePlay); +} + +long +Program::doAction(GraphicDevice *gd, ActionRecord *action, SoundMixer *sm) +{ + long status = NOTHING; + long f; + char *target = ""; + long skip = 0; + + while(action) + { + if (skip) skip--; + else + switch (action->action) + { + case ActionPlaySound: +#if PRINT&2 + printf("Prog %x : PlaySound\n", this); +#endif + if (sm) { + sm->startSound(action->sound); + } + status |= WAKEUP; + break; + case ActionRefresh: +#if PRINT&2 + printf("Prog %x : Refresh\n", this); +#endif + status |= REFRESH; + break; + case ActionGotoFrame: +#if PRINT&2 + printf("Prog %x : GotoFrame %d\n", this, action->frameIndex); +#endif + if (target[0] == 0) { + if (action->frameIndex < nbFrames) { + currentFrame = action->frameIndex; + pauseMovie(); + status |= WAKEUP|GOTO; + } + } + break; + case ActionGetURL: +#if PRINT&2 + printf("Prog %x : GetURL %s target = %s\n", this, action->url, action->target); +#endif + { + int len,level; + len = strlen(action->target); + + if (len > 6 && memcmp(action->target,"_level", 6) == 0) { + level = atoi(action->target + 6); + loadNewSwf(movie, action->url, level); + } else { + if (movie->getUrl) { + movie->getUrl(action->url, action->target, movie->getUrlClientData); + } + } + } + break; + case ActionNextFrame: + nextFrame = currentFrame+1; + movieStatus = MoviePlay; + status |= WAKEUP; + break; + case ActionPrevFrame: + nextFrame = currentFrame-1; + status |= WAKEUP|GOTO; + break; + case ActionPlay: +#if PRINT&2 + printf("Prog %x : Play\n", this); +#endif + if (target[0] == 0) { + movieStatus = MoviePlay; + if ((status & GOTO) == 0) { + if (currentFrame == nextFrame) advanceFrame(); + } + status |= WAKEUP; + } + break; + case ActionStop: +#if PRINT&2 + printf("Prog %x : Stop\n", this); +#endif + if (target[0] == 0) { + movieStatus = MoviePaused; + nextFrame = currentFrame; + } + break; + case ActionToggleQuality: + break; + case ActionStopSounds: + if (sm) { + sm->stopSounds(); + } + break; + case ActionWaitForFrame: + if (action->frameIndex >= nbFrames) { + skip = action->skipCount; + } + break; + case ActionSetTarget: +#if PRINT&2 + printf("Prog %x : SetTarget '%s'\n", this, action->target); +#endif + target = action->target; + break; + case ActionGoToLabel: +#if PRINT&2 + printf("Prog %x : GotoFrame '%s'\n", this, action->frameLabel); +#endif + f = searchFrame(gd, action->frameLabel, target); + if (f >= 0) { + currentFrame = f; + pauseMovie(); + status |= WAKEUP|GOTO; + } else { + status |= REFRESH; + } + break; + } + action = action->next; + } + return status; +} + +void +Program::setCurrentFrameLabel(char *label) +{ + frames[loadingFrame].label = label; +} + +void +Program::rewindMovie() +{ + currentFrame = 0; + nextFrame = 0; +} + +void +Program::pauseMovie() +{ + movieStatus = MoviePaused; + nextFrame = currentFrame; +} + +void +Program::continueMovie() +{ + movieStatus = MoviePlay; +} + +void +Program::nextStepMovie() +{ + if (movieStatus == MoviePaused) { + advanceFrame(); + } +} + +void +Program::advanceFrame() +{ + currentFrame = nextFrame; + nextFrame = currentFrame+1; + if (currentFrame == nbFrames) { + currentFrame = 0; + nextFrame = 0; + movieStatus = MoviePlay; + } +} + +void +Program::addControlInCurrentFrame(Control *ctrl) +{ + Control *c; + + ctrl->next = 0; + if (frames[loadingFrame].controls == 0) { + frames[loadingFrame].controls = ctrl; + } else { + for(c = frames[loadingFrame].controls; c->next; c = c->next); + c->next = ctrl; + } +} + +void +Program::modifySettings(long flags) +{ + settings = flags; +} + +long +Program::searchFrame(GraphicDevice *gd, char *label, char *target) +{ + long f; + DisplayListEntry *e; + Program *prg; + + // Current movie + if (target[0] == 0) { + for(f=0; f < nbFrames; f++) + { + if (frames[f].label && !strcmp(label,frames[f].label)) { + return f; + } + } + } + + // Kludge !!! + for (e = dl->list; e; e = e->next) { + if (e->character->isSprite()) { + prg = ((Sprite *)e->character)->program; + f = prg->searchFrame(gd,label,""); + if (f >= 0 && f < prg->nbFrames) { + prg->dl->updateBoundingBox(e); + prg->gotoFrame(gd, f); + prg->nextFrame = f; + prg->dl->updateBoundingBox(e); + return -1; + } + } + } + + return -1; +} + +void loadNewSwf(FlashMovie *movie, char *url, int level) +{ + CInputScript *s,*prev,**l; + + if (movie->getSwf == NULL) return; + + for(s = movie->main, prev = 0; s != NULL; prev = s, s = s->next) { + if (s->level == level) { + // Mark movie to be deleted + s->level = -1; + break; + } + } + + //printf("Unload movie @ %d\n", level); + + if (*url == 0) return; // Just UnloadMovie + + s = new CInputScript(level); + if (s == NULL) return; + + /* insert it in the right order */ + l = &movie->main; + while (*l != NULL && (*l)->level < level) l = &(*l)->next; + s->next = *l; + *l = s; + + // Notify the external loader of a new movie to load + movie->getSwf(url, level, movie->getSwfClientData); +} |