Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

displaylist.cc

Go to the documentation of this file.
00001 
00002 // Flash Plugin and Player
00003 // Copyright (C) 1998,1999 Olivier Debon
00004 // 
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 // 
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 // 
00020 //  Author : Olivier Debon  <odebon@club-internet.fr>
00021 //  
00022 
00023 #include "swf.h"
00024 
00025 #ifdef RCSID
00026 static char *rcsid = "$Id: displaylist.cc,v 1.1.1.1 2002/01/25 22:14:58 kergoth Exp $";
00027 #endif
00028 
00029 #define PRINT 0
00030 
00031 void deleteButton(FlashMovie *movie, DisplayListEntry *e)
00032 {
00033     /* save the focus */
00034     if (movie->mouse_active == 0 && e->renderState == stateOver) {
00035         movie->lost_over = (Button *)e->character;
00036         movie->cur_focus = NULL;
00037     }
00038 
00039     if (e == movie->cur_focus) {
00040         movie->cur_focus = NULL;
00041     }
00042 }
00043 
00044 void addButton(FlashMovie *movie, DisplayListEntry *e)
00045 {
00046     if (movie->mouse_active == 0 && 
00047         movie->cur_focus == NULL &&
00048         movie->lost_over == (Button *)e->character) {
00049         /* restore the lost focus */
00050         e->renderState = stateOver;
00051         e->oldState = stateOver;
00052         ((Button *)e->character)->updateButtonState(e);
00053         movie->lost_over = NULL;
00054         movie->cur_focus = e;
00055     }
00056 }
00057 
00058 DisplayList::DisplayList(FlashMovie *movie)
00059 {
00060         list = NULL;
00061         this->movie = movie;
00062         bbox.reset();
00063         isSprite = 0;
00064 }
00065 
00066 DisplayList::~DisplayList()
00067 {
00068         clearList();
00069 }
00070 
00071 void
00072 DisplayList::clearList()
00073 {
00074         DisplayListEntry *del, *e;
00075 
00076         for(e = list; e;)
00077         {
00078                 updateBoundingBox(e);
00079                 if (e->character->isButton()) {
00080                     deleteButton(movie,e);
00081                 }
00082                 del = e;
00083                 e = e->next;
00084                 delete del;
00085         }
00086         list = 0;
00087 }
00088 
00089 DisplayListEntry *
00090 DisplayList::getList()
00091 {
00092         return list;
00093 }
00094 
00095 static void bbox(Rect *rect, Matrix *m, long x1, long y1)
00096 {
00097     long x,y;
00098 
00099     x = m->getX(x1,y1);
00100     y = m->getY(x1,y1);
00101     if (x < rect->xmin) rect->xmin = x;
00102     if (x > rect->xmax) rect->xmax = x;
00103     if (y < rect->ymin) rect->ymin = y;
00104     if (y > rect->ymax) rect->ymax = y;
00105 }
00106 
00107 // Update bb to include boundary, optional reset of bb
00108 void transformBoundingBox(Rect *bb, Matrix *matrix, Rect *boundary, int reset)
00109 {
00110     if (reset) {
00111         bb->reset();
00112     }
00113     
00114     if (boundary->xmin != LONG_MAX) {
00115         bbox(bb, matrix, boundary->xmin, boundary->ymin);
00116         bbox(bb, matrix, boundary->xmax, boundary->ymin);
00117         bbox(bb, matrix, boundary->xmin, boundary->ymax);
00118         bbox(bb, matrix, boundary->xmax, boundary->ymax);
00119     }
00120 }
00121 
00122 void
00123 DisplayList::placeObject(GraphicDevice *gd,Character *character, long depth, Matrix *matrix, Cxform *cxform, char *name)
00124 {
00125         DisplayListEntry *n,*e,*prev;
00126 
00127         n = new DisplayListEntry;
00128         if (n == NULL) return;
00129 
00130         n->depth = depth;
00131         n->matrix = matrix;
00132         n->cxform = cxform;
00133         n->character = character;
00134         n->instanceName = name;
00135         n->owner = this;
00136 
00137 #if 0
00138         printf("Dl %lx: placeObject: depth=%d character=%d cxform=%p\n",
00139                this, n->depth,n->character ? n->character->getTagId() : 0, cxform);
00140 #endif
00141 
00142         if (character == 0 || matrix == 0 || cxform == 0) {
00143                 for (e = list; e; prev = e, e = e->next) {
00144                         if (e->depth == n->depth) {
00145                                 if (character == 0) {
00146                                         n->character = e->character;
00147                                 }
00148                                 if (matrix == 0) {
00149                                         n->matrix = e->matrix;
00150                                 }
00151                                 if (cxform == 0) {
00152                                         n->cxform = e->cxform;
00153                                 }
00154                                 break;
00155                         }
00156                 }
00157         }
00158 
00159         if (n->character == 0) {
00160                 // Not found !!!    Should not happen
00161             //          printf("PlaceObject cannot find character at depth %ld\n", n->depth);
00162                 delete n;
00163                 return;
00164         }
00165 
00166         prev = 0;
00167         for (e = list; e; prev = e, e = e->next)
00168         {
00169                 if (e->depth == n->depth) {
00170                         if (e->character->isButton()) {
00171                             deleteButton(movie, e);
00172                         }
00173 
00174                         // Do update, object has moved or been resized
00175                         updateBoundingBox(e);
00176 
00177                         // Replace object
00178                         e->depth = n->depth;
00179                         e->matrix = n->matrix;
00180                         e->cxform = n->cxform;
00181                         e->character = n->character;
00182                         /* if it is a button, we must update its state */
00183                         if (e->character->isButton()) {
00184                             movie->buttons_updated = 1;
00185                             addButton(movie, e);
00186                         }
00187 
00188                         updateBoundingBox(e);
00189 
00190                         delete n;
00191                         return;
00192                 }
00193                 if (e->depth > n->depth) break;
00194         }
00195         /* new object */
00196 
00197         /* button instantiation */
00198         if (n->character->isButton()) {
00199             n->renderState = stateUp;
00200             n->oldState = stateUp;
00201             ((Button *)n->character)->updateButtonState(n);
00202             addButton(movie,n);
00203         }
00204 
00205         updateBoundingBox(n);
00206 
00207         if (prev == 0) {
00208                 // Object comes at first place
00209                 n->next = list;
00210                 list = n;
00211         } else {
00212                 // Insert object
00213                 n->next = prev->next;
00214                 prev->next = n;
00215         }
00216 }
00217 
00218 
00219 Character *
00220 DisplayList::removeObject(GraphicDevice *gd,Character *character, long depth)
00221 {
00222     DisplayListEntry *e,*prev;
00223     
00224     // List should not be empty
00225     if (list == 0) return 0;
00226     
00227 #if 0
00228     printf("removeObject: depth=%d character=%d\n",
00229            depth,character ? character->getTagId() : 0);
00230 #endif
00231     
00232     prev = 0;
00233     for (e = list; e; prev = e, e = e->next) {
00234         if (e->depth == depth) {
00235             if (prev) {
00236                 prev->next = e->next;
00237             } else {
00238                 list = e->next;
00239             }
00240             if (character == 0) {
00241                 character = e->character;
00242             }
00243             if (e->character->isButton()) {
00244                 deleteButton(movie, e);
00245             }
00246             if (e->character->isSprite()) {
00247                 ((Sprite*)e->character)->reset();
00248             }
00249                 
00250             updateBoundingBox(e);
00251 
00252             delete e;
00253             return character;
00254         }
00255     }
00256     return 0;   // Should not happen
00257 }
00258 
00259 void
00260 DisplayList::updateBoundingBox(DisplayListEntry *e)
00261 {
00262         Rect     rect;
00263 
00264         //rect.reset();
00265         e->character->getBoundingBox(&rect,e);
00266         transformBoundingBox(&this->bbox, e->matrix, &rect, 0);
00267 }
00268 
00269 int
00270 DisplayList::updateSprites()
00271 {
00272     Sprite *sprite;
00273     DisplayListEntry *e;
00274     int refresh = 0;
00275 
00276     for (e = this->list; e != NULL; e = e->next) {
00277         if (e->character->isButton() && e->buttonCharacter) {
00278                 if (e->buttonCharacter->isSprite()) {
00279                         Matrix mat;
00280 
00281                         sprite = (Sprite *)e->buttonCharacter;
00282                         refresh |= sprite->program->dl->updateSprites();
00283                         refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
00284                         mat = (*e->matrix) * e->buttonMatrix;
00285                         transformBoundingBox(&this->bbox, &mat,
00286                                         &(sprite->program->dl->bbox),
00287                                         0);
00288                 }
00289         }
00290         if (e->character->isSprite()) {
00291                 sprite = (Sprite *)e->character;
00292                 refresh |= sprite->program->dl->updateSprites();
00293                 refresh |= sprite->program->nestedMovie(this->movie->gd,this->movie->sm, e->matrix, e->cxform);
00294                 transformBoundingBox(&this->bbox, e->matrix,
00295                                 &(sprite->program->dl->bbox),
00296                                 0);
00297         }
00298     }
00299     return refresh;
00300 }
00301 
00302 /* Function can return either 0,1 or 2
00303    0:  Nothing match, continue
00304    1:  Something matches, but continue searching
00305    2:  Something matches, but stop searching
00306 */
00307 
00308 static int exploreButtons1(Program *prg, void *opaque, 
00309                            ExploreButtonFunc func)
00310 {
00311     DisplayListEntry *e;
00312     int ret, ret2 = 0;
00313 
00314     for(e=prg->dl->list; e != NULL; e = e->next) {
00315         if (e->character == NULL) continue;
00316         if (e->character->isButton()) {
00317             ret = func(opaque,prg,e);
00318             if (ret == 2) return ret;   // Func asks to return at once !!!
00319             if (ret) ret2 = 1;
00320         }
00321         if (e->character->isSprite()) {
00322             ret = exploreButtons1(((Sprite *)e->character)->program,
00323                                   opaque,func);
00324             if (ret == 2) return ret;   // Func asks to return at once !!!
00325             if (ret) ret2 = 1;
00326         }
00327     }
00328     return ret2;
00329 }
00330 
00331 int exploreButtons(FlashMovie *movie, void *opaque, ExploreButtonFunc func)
00332 {
00333     CInputScript *script;
00334     int ret;
00335 
00336     script = movie->main;
00337     while (script != NULL) {
00338         if (script->program) {
00339                 ret = exploreButtons1(script->program, opaque, func);
00340                 if (ret) return ret;
00341         }
00342         script = script->next;
00343     }
00344     return 0;
00345 }
00346 
00347 typedef struct {
00348     long x,y;
00349     int hit;
00350     DisplayListEntry *bhit;
00351 } HitTable;
00352 
00353 static void button_hit_func(void *id, long y, long start, long end)
00354 {
00355     HitTable *h = (HitTable *) id;
00356     if ( y == h->y && (h->x >= start && h->x < end) )
00357         h->hit = 1;
00358 }
00359 
00360 typedef struct {
00361     FlashMovie *movie;
00362     DisplayListEntry *bhit;
00363 } ButtonHit;
00364 
00365 static int button_hit(void *opaque, Program *prg, DisplayListEntry *e)
00366 {
00367     ButtonHit *h = (ButtonHit *) opaque;
00368     HitTable hit_table;
00369     FlashMovie *movie = h->movie;
00370     Rect bb,boundary;
00371     Matrix mat;
00372     ButtonState save;
00373 
00374     hit_table.x = movie->mouse_x;
00375     hit_table.y = movie->mouse_y / FRAC;
00376     hit_table.hit = 0;
00377     
00378     // Compute the bounding box in screen coordinates
00379     save = e->renderState;
00380     e->renderState = stateHitTest;
00381     e->character->getBoundingBox(&boundary,e);
00382     e->renderState = save;
00383     mat = (*movie->gd->adjust) * e->renderMatrix;
00384     transformBoundingBox(&bb, &mat, &boundary, 1);
00385     // Check if mouse is within bb
00386     if (movie->mouse_x < bb.xmin) return 0;
00387     if (movie->mouse_x > bb.xmax) return 0;
00388     if (movie->mouse_y < bb.ymin) return 0;
00389     if (movie->mouse_y > bb.ymax) return 0;
00390 
00391     e->character->getRegion(movie->gd, &e->renderMatrix, 
00392                             &hit_table, button_hit_func);
00393                 
00394     if (hit_table.hit) {
00395         h->bhit = e;
00396         return 1;
00397     } else {
00398         return 0;
00399     }
00400 }
00401 
00402 static int button_reset(void *opaque, Program *prg, DisplayListEntry *e)
00403 {
00404     if (e->renderState != stateUp) {
00405             e->owner->updateBoundingBox(e);
00406             e->oldState = e->renderState;
00407             e->renderState = stateUp;
00408             ((Button *)e->character)->updateButtonState(e);
00409             e->owner->updateBoundingBox(e);
00410     }
00411     return 0;
00412 }
00413 
00414 /* update the button states according to the current mouse state & return the list of actions */
00415 void
00416 DisplayList::updateButtons(FlashMovie *movie)
00417 {
00418     DisplayListEntry *bhit;
00419     ButtonHit h;
00420 
00421     if (movie->mouse_active) {
00422 
00423         h.bhit = NULL;
00424         h.movie = movie;
00425 
00426         exploreButtons(movie, &h, button_hit);
00427 
00428         bhit = h.bhit;
00429 
00430         /* set every button to not hit */
00431         exploreButtons(movie, NULL, button_reset);
00432 
00433         if (bhit) {
00434             ButtonState state;
00435 
00436             if (movie->button_pressed) {
00437                 state = stateDown;
00438             } else {
00439                 state = stateOver;
00440             }
00441             if (state != bhit->renderState) {
00442                     bhit->owner->updateBoundingBox(bhit);
00443                     bhit->renderState = state;
00444                     ((Button *)bhit->character)->updateButtonState(bhit);
00445                     bhit->owner->updateBoundingBox(bhit);
00446                     movie->cur_focus = bhit;
00447                     if (movie->cursorOnOff)
00448                             movie->cursorOnOff(1,movie->cursorOnOffClientData);
00449             }
00450         } else {
00451             if (movie->cursorOnOff)
00452                     movie->cursorOnOff(0,movie->cursorOnOffClientData);
00453         }
00454     }
00455 }
00456 
00457 typedef struct {
00458     ActionRecord *action;       // Action to do
00459     Program      *prg;          // Context program
00460 } ButtonAction;
00461 
00462 static int button_action(void *opaque, Program *prg, DisplayListEntry *e)
00463 {
00464     ButtonAction *h = (ButtonAction *)opaque;
00465     static ActionRecord actionRefresh;
00466     static ActionRecord soundFx;
00467     Button *b;
00468     ActionRecord **paction;
00469     int n;
00470 
00471     actionRefresh.action = ActionRefresh;
00472     actionRefresh.next = 0;
00473     
00474     soundFx.action = ActionPlaySound;
00475     soundFx.next = &actionRefresh;
00476 
00477     b = (Button *)e->character;
00478 
00479     if (e->oldState != e->renderState) {
00480         
00481         paction = &actionRefresh.next;
00482         
00483         if (b->conditionList) {
00484             *paction = b->getActionFromTransition(e->renderState, e->oldState);
00485         } else if (e->renderState == stateDown) {
00486             /* if the button is pressed and 
00487                no condition list is defined*/
00488             *paction = b->actionRecords;
00489         }
00490         
00491         switch(e->renderState) {
00492         case stateUp:
00493             n = 0;
00494             break;
00495         case stateOver:
00496             n = 1;
00497             break;
00498         default:
00499             /* case stateDown: */
00500             n = 2;
00501             break;
00502         }
00503         
00504         if (b->sound[n]) {
00505             soundFx.sound = b->sound[n];
00506             h->action = &soundFx;
00507         } else {
00508             h->action = &actionRefresh;
00509         }
00510         
00511         e->oldState = e->renderState;
00512 
00513         h->prg = prg;
00514         return 2;
00515     }
00516     h->action = 0;      // Nothing to do about this
00517     return 0;
00518 }
00519 
00520 int computeActions(FlashMovie *movie, Program **prg, ActionRecord **ar)
00521 {
00522     ButtonAction h;
00523 
00524     h.action = NULL;
00525     exploreButtons(movie, &h, button_action);
00526     if (h.action) {
00527         *prg = h.prg;
00528         *ar = h.action;
00529         return 1;
00530     }
00531     return 0;
00532 }
00533 
00534 #define FOCUS_ZOOM       1.5
00535 /* in pixels */
00536 #define FOCUS_SIZE_MIN   50
00537 #define FOCUS_TRANSLATE  15
00538 
00539 int
00540 DisplayList::render(GraphicDevice *gd, Matrix *render_matrix, Cxform *cxform)
00541 {
00542         DisplayListEntry *e,*cur_focus;
00543         int sprite = 0;
00544         long n = 0;
00545         Cxform cxf,*cxf1;
00546         Rect bb,boundary;
00547 
00548         cur_focus = NULL;
00549 
00550         /*
00551         if (isSprite == 0) {
00552                 if (this->bbox.xmin == LONG_MAX) return 0;
00553                 gd->updateClippingRegion(&this->bbox, render_matrix);
00554                 gd->clearCanvas();
00555         }
00556         */
00557 
00558         for (e = list; e; e = e->next)
00559         {
00560 #if PRINT
00561                 printf("Character %3d @ %3d\n", e->character ? e->character->getTagId() : 0, e->depth);
00562 #endif
00563                 if (e->character) {
00564                         Matrix mat;
00565 
00566                         if (render_matrix) {
00567                                 mat = *render_matrix;
00568                         }
00569 
00570                         if (e->matrix) {
00571                                 mat = mat * (*e->matrix);
00572                         }
00573 
00574                         /* fast clipping */
00575                         // If object boundaries are outside current clip region give up with rendering
00576                         e->character->getBoundingBox(&boundary,e);
00577                         if (boundary.xmin != LONG_MAX) {
00578                             Matrix tmat;
00579 
00580                             tmat = (*gd->adjust) * mat;
00581                             transformBoundingBox(&bb, &tmat, &boundary, 1);
00582 
00583                             bb.xmin = bb.xmin >> FRAC_BITS;
00584                             bb.ymin = bb.ymin >> FRAC_BITS;
00585                             bb.xmax = (bb.xmax + FRAC - 1) >> FRAC_BITS;
00586                             bb.ymax = (bb.ymax + FRAC - 1) >> FRAC_BITS;
00587 
00588                             if (bb.xmin >= gd->clip_rect.xmax ||
00589                                 bb.xmax <= gd->clip_rect.xmin ||
00590                                 bb.ymin >= gd->clip_rect.ymax ||
00591                                 bb.ymax <= gd->clip_rect.ymin) {
00592                                 continue;
00593                             }
00594                         }
00595 
00596                         if (cxform == NULL) {
00597                             cxf1 = e->cxform;
00598                         }
00599                         else if (e->cxform == NULL) {
00600                             cxf1 = cxform;
00601                         }
00602                         else {
00603                             cxf1 = &cxf;
00604                             cxf.ra = cxform->ra * e->cxform->ra;
00605                             cxf.ga = cxform->ga * e->cxform->ga;
00606                             cxf.ba = cxform->ba * e->cxform->ba;
00607                             cxf.aa = cxform->aa * e->cxform->aa;
00608                             
00609                             cxf.rb = (long)(cxform->ra * e->cxform->rb + cxform->rb);
00610                             cxf.gb = (long)(cxform->ga * e->cxform->gb + cxform->gb);
00611                             cxf.bb = (long)(cxform->ba * e->cxform->bb + cxform->bb);
00612                             cxf.ab = (long)(cxform->aa * e->cxform->ab + cxform->ab);
00613                         }
00614 
00615                         if (e->character->isButton()) {
00616                             Button *b = (Button *) e->character;
00617 
00618                             e->renderMatrix = mat;
00619 
00620                             if (e->renderState != stateUp && movie->mouse_active == 0) {
00621                                 cur_focus = e;
00622                                 ((Button *)e->character)->updateButtonState(e);
00623                             }
00624 
00625                             if (b->execute(gd, &mat, cxf1, e->renderState)) {
00626                                 sprite = 1;
00627                             }
00628                         } else {
00629                             if (e->character->execute(gd, &mat, cxf1)) {
00630                                 sprite = 1;
00631                             }
00632                         }
00633 
00634                         n++;
00635                 }
00636         }
00637 
00638 #if 0
00639     {
00640         /* display the bounding box (debug) */
00641         Matrix tmat;
00642         long x1,x2,y1,y2;
00643         Color white;
00644 
00645         white.red = 255;
00646         white.green = white.blue = 0;
00647         gd->setForegroundColor(white);
00648 
00649         if (render_matrix) {
00650                 tmat = (*gd->adjust) * (*render_matrix);
00651         } else {
00652                 tmat = *gd->adjust;
00653         }
00654         x1 = bbox.xmin;
00655         y1 = bbox.ymin;
00656         x2 = bbox.xmax;
00657         y2 = bbox.ymax;
00658         gd->drawLine(tmat.getX(x1,y1),tmat.getY(x1,y1),tmat.getX(x2,y1),tmat.getY(x2,y1),10*FRAC);
00659         gd->drawLine(tmat.getX(x2,y1),tmat.getY(x2,y1),tmat.getX(x2,y2),tmat.getY(x2,y2),10*FRAC);
00660         gd->drawLine(tmat.getX(x2,y2),tmat.getY(x2,y2),tmat.getX(x1,y2),tmat.getY(x1,y2),10*FRAC);
00661         gd->drawLine(tmat.getX(x1,y2),tmat.getY(x1,y2),tmat.getX(x1,y1),tmat.getY(x1,y1),10*FRAC);
00662         bbox.print();
00663     }
00664 #endif
00665         
00666         // Reset clipping zone
00667         bbox.reset();
00668 
00669         return sprite;
00670 }
00671 
00672 void
00673 DisplayList::getBoundary(Rect *bb)
00674 {
00675         DisplayListEntry *e;
00676         Rect boundary;
00677 
00678         bb->reset();
00679         for (e = list; e; e = e->next)
00680         {
00681                 if (e->character) {
00682                         e->character->getBoundingBox(&boundary,e);
00683                         transformBoundingBox(bb, e->matrix, &boundary, 0);
00684                 }
00685         }
00686 }
00687 
00688 extern "C" {
00689 
00690 void dump_buttons(FlashHandle flashHandle)
00691 {
00692 #if 0
00693     Rect rect;
00694     DisplayListEntry *e;
00695     FlashMovie *movie;
00696 
00697     movie = (FlashMovie *)flashHandle;
00698 
00699     for (e = movie->first_button; e; e = e->next_button) {
00700         computeBBox(movie,&rect,e);
00701         printf("button: id=%d pos=%d %d %d %d\n",
00702                e->character->getTagId(),
00703                rect.xmin, rect.ymin, rect.xmax, rect.ymax);
00704     }
00705 #endif
00706 }
00707 
00708 }

Generated on Sat Nov 5 16:15:35 2005 for OPIE by  doxygen 1.4.2