00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00020
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
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
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
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
00161
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
00175 updateBoundingBox(e);
00176
00177
00178 e->depth = n->depth;
00179 e->matrix = n->matrix;
00180 e->cxform = n->cxform;
00181 e->character = n->character;
00182
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
00196
00197
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
00209 n->next = list;
00210 list = n;
00211 } else {
00212
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
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;
00257 }
00258
00259 void
00260 DisplayList::updateBoundingBox(DisplayListEntry *e)
00261 {
00262 Rect rect;
00263
00264
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
00303
00304
00305
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;
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;
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
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
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
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
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;
00459 Program *prg;
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
00487
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
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;
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
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
00552
00553
00554
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
00575
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
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
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 }