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

graphic.cc

Go to the documentation of this file.
00001 
00002 // Flash Plugin and Player
00003 // Copyright (C) 1998 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: graphic.cc,v 1.1.1.1 2002/01/25 22:14:58 kergoth Exp $";
00027 #endif
00028 
00029 #define PRINT 0
00030 
00031 // Public
00032 
00033 GraphicDevice::GraphicDevice(FlashDisplay *fd)
00034 {
00035         flashDisplay = fd;
00036 
00037         bgInitialized = 0;
00038 
00039         // Reset flash refresh flag
00040         flashDisplay->flash_refresh = 0;
00041 
00042         /* 16 bits, RGB565 */
00043         redMask = 0xF800;
00044         greenMask = 0x07E0;
00045         blueMask = 0x001F;
00046 
00047         /* should be the actual window size */
00048         targetWidth = fd->width;
00049         targetHeight = fd->height;
00050         bpl = fd->bpl;
00051 
00052 #if PRINT
00053         printf("Target Width  = %d\n", targetWidth);
00054         printf("Target Height = %d\n", targetHeight);
00055 #endif
00056 
00057         zoom = FRAC;
00058         movieWidth = targetWidth;
00059         movieHeight = targetHeight;
00060 
00061         viewPort.xmin = 0;
00062         viewPort.xmax = targetWidth-1;
00063         viewPort.ymin = 0;
00064         viewPort.ymax = targetHeight-1;
00065 
00066         canvasBuffer = (unsigned char *) fd->pixels;
00067 
00068         adjust = new Matrix;
00069         foregroundColor.red = 0;
00070         foregroundColor.green = 0;
00071         foregroundColor.blue = 0;
00072         foregroundColor.alpha = ALPHA_OPAQUE;
00073 
00074         backgroundColor.red = 0;
00075         backgroundColor.green = 0;
00076         backgroundColor.blue = 0;
00077         backgroundColor.alpha = ALPHA_OPAQUE;
00078 
00079         showMore = 0;
00080 
00081         setClipping(0); // Reset
00082         setClipping(1);
00083  
00084         /* polygon rasterizer : handle memory errors ! */
00085 
00086         height = targetHeight;
00087         segs = (Segment **)malloc(height * sizeof(Segment *));
00088         memset(segs, 0, height * sizeof(Segment *));
00089         ymin = height;
00090         ymax = -1;
00091 
00092         seg_pool = (Segment *)malloc(NB_SEGMENT_MAX * sizeof(Segment));
00093         seg_pool_cur = seg_pool;
00094 }
00095 
00096 GraphicDevice::~GraphicDevice()
00097 {
00098     free(segs);
00099     free(seg_pool);
00100     
00101     if (adjust) {
00102         delete adjust;
00103     }
00104 }
00105 
00106 Color *
00107 GraphicDevice::getColormap(Color *old, long n, Cxform *cxform)
00108 {
00109         Color *newCmp;
00110 
00111         newCmp = new Color[n];
00112         if (newCmp == NULL) return NULL;
00113 
00114         if (cxform) {
00115                 for(long i = 0; i < n; i++)
00116                 {
00117                         newCmp[i] = cxform->getColor(old[i]);
00118                         newCmp[i].pixel = allocColor(newCmp[i]);
00119                 }
00120         } else {
00121                 for(long i = 0; i < n; i++)
00122                 {
00123                         newCmp[i] = old[i];
00124                         newCmp[i].pixel = allocColor(old[i]);
00125                 }
00126         }
00127 
00128         return newCmp;
00129 }
00130 
00131 long
00132 GraphicDevice::getHeight()
00133 {
00134         return targetHeight;
00135 }
00136 
00137 long
00138 GraphicDevice::getWidth()
00139 {
00140         return targetWidth;
00141 }
00142 
00143 Color
00144 GraphicDevice::getForegroundColor()
00145 {
00146         return foregroundColor;
00147 }
00148 
00149 void
00150 GraphicDevice::setForegroundColor(Color color)
00151 {
00152         foregroundColor = color;
00153 }
00154 
00155 Color
00156 GraphicDevice::getBackgroundColor()
00157 {
00158         return backgroundColor;
00159 }
00160 
00161 int
00162 GraphicDevice::setBackgroundColor(Color color)
00163 {
00164         if (bgInitialized == 0) {
00165                 backgroundColor = color;
00166                 clearCanvas();
00167                 bgInitialized = 1;
00168                 return 1;
00169         }
00170         return 0;
00171 }
00172 
00173 void
00174 GraphicDevice::setMovieDimension(long width, long height)
00175 {
00176         float xAdjust, yAdjust;
00177 
00178         movieWidth = width;
00179         movieHeight = height;
00180 
00181         xAdjust = (float)targetWidth*zoom/(float)width;
00182         yAdjust = (float)targetHeight*zoom/(float)height;
00183 
00184         if (xAdjust < yAdjust) {
00185                 adjust->a = xAdjust;
00186                 adjust->d = xAdjust;
00187                 adjust->ty = ((targetHeight*zoom) - (long)(height * xAdjust))/2;
00188                 viewPort.ymin = adjust->ty/zoom;
00189                 viewPort.ymax = targetHeight-viewPort.ymin-1;
00190         } else {
00191                 adjust->a = yAdjust;
00192                 adjust->d = yAdjust;
00193                 adjust->tx = ((targetWidth*zoom) - (long)(width * yAdjust))/2;
00194                 viewPort.xmin = adjust->tx/zoom;
00195                 viewPort.xmax = targetWidth-viewPort.xmin-1;
00196         }
00197 
00198         if (viewPort.xmin < 0) viewPort.xmin = 0;
00199         if (viewPort.ymin < 0) viewPort.ymin = 0;
00200         if (viewPort.xmax >= targetWidth) viewPort.xmax = targetWidth-1;
00201         if (viewPort.ymax >= targetHeight) viewPort.ymax = targetHeight-1;
00202 }
00203 
00204 void
00205 GraphicDevice::setMovieZoom(int z)
00206 {
00207         z *= FRAC;
00208         if (z <= 0 || z > 100) return;
00209         zoom = z;
00210         setMovieDimension(movieWidth,movieHeight);
00211 }
00212 
00213 void
00214 GraphicDevice::setMovieOffset(long x, long y)
00215 {
00216         adjust->tx = -zoom*x;
00217         adjust->ty = -zoom*y;
00218 }
00219 
00220 long
00221 GraphicDevice::clip(long &y, long &start, long &end)
00222 {
00223     long xmin,xend;
00224 
00225     if (y < clip_rect.ymin ||
00226         y >= clip_rect.ymax) return 1;
00227     if (end <= start)
00228         return 1;
00229     xmin = clip_rect.xmin * FRAC;
00230     xend = clip_rect.xmax * FRAC;
00231 
00232     if (end <= xmin || start >= xend) return 1;
00233 
00234     if (start < xmin) start = xmin;
00235     if (end > xend) end = xend;
00236 
00237     return 0;
00238 }
00239 
00240 void
00241 GraphicDevice::drawBox(long x1, long y1, long x2, long y2)
00242 {
00243     int i;
00244 
00245     for(i=0;i<FRAC*2;i++) {
00246         drawLine(x1+i, y1+i, x2-i, y1+i, 0);
00247         drawLine(x1+i, y2-i, x2-i, y2-i, 0);
00248 
00249         drawLine(x1+i, y1+i+1, x1+i, y2-i-1, 0);
00250         drawLine(x2-i, y1+i+1, x2-i, y2-i-1, 0);
00251     }
00252 }
00253 
00254 /* polygon rasteriser */
00255 
00256 inline Segment *
00257 GraphicDevice::allocSeg()
00258 {
00259     Segment *seg;
00260 
00261     if ( (seg_pool_cur - seg_pool) >= NB_SEGMENT_MAX )
00262         return NULL;
00263     seg = seg_pool_cur++;
00264 
00265     return seg;
00266 }
00267 
00268 /* add a segment to the current path */
00269 void
00270 GraphicDevice::addSegment(long x1, long y1, long x2, long y2,
00271                           FillStyleDef *f0,
00272                           FillStyleDef *f1,
00273                           int aa)
00274 {
00275     Segment *seg,**segs;
00276     long dX, X, Y, ymin, ymax, tmp;
00277     FillStyleDef *ff;
00278 
00279     if ( y1 == y2 ) {
00280         return;
00281     }
00282 
00283     if (y1 < y2) {
00284         ymin = y1;
00285         ymax = y2;
00286         ff = f0;
00287         f0 = f1;
00288         f1 = ff;
00289     } else {
00290         ymin = y2;
00291         ymax = y1;
00292         tmp = x1;
00293         x1 = x2;
00294         x2 = tmp;
00295     }
00296 
00297     if (ymax>>FRAC_BITS < clip_rect.ymin) {
00298         return;
00299     }
00300     if (ymin>>FRAC_BITS > clip_rect.ymax) {
00301         return;
00302     }
00303 
00304     X = x1 << SEGFRAC;
00305     dX = ((x2 - x1)<<SEGFRAC)/(ymax-ymin);
00306 
00307     if (ymin < 0) {
00308         X += dX * (-ymin);
00309         ymin = 0;
00310     }
00311 
00312     Y = (ymin + (FRAC-1)) & ~(FRAC-1);
00313     if (Y > ymax) {
00314         //printf("Elimine @ y = %d   ymin = %d, ymax = %d\n", Y, ymin, seg->ymax);
00315         return;
00316     }
00317     X += dX * (Y-ymin);
00318 
00319     Y >>= FRAC_BITS;
00320     if (Y >= clip_rect.ymax) {
00321         return;
00322     }
00323 
00324     seg = allocSeg();
00325     if (seg == NULL) {
00326         return;
00327     }
00328 
00329     seg->next = 0;
00330     seg->nextValid = 0;
00331     seg->aa = aa;
00332     seg->ymax = ymax;
00333     seg->x1 = x1;
00334     seg->x2 = x2;
00335     seg->X = X;
00336     seg->dX = dX;
00337     seg->fs[0] = f0;
00338     seg->fs[1] = f1;
00339 
00340     if (Y < this->ymin) this->ymin = Y;
00341     ymax = (seg->ymax + FRAC - 1) >> FRAC_BITS;
00342     if (ymax >= this->height) ymax = this->height-1;
00343     if (ymax > this->ymax) this->ymax = ymax;
00344 
00345     segs = this->segs;
00346 
00347     if (segs[Y] == 0) {
00348         segs[Y] = seg;
00349     } else {
00350         Segment *s,*prev;
00351 
00352         prev = 0;
00353         for(s = segs[Y]; s; prev = s, s = s->next) {
00354             if (s->X > seg->X) {
00355                 if (prev) {
00356                     prev->next = seg;
00357                     seg->next = s;
00358                 } else {
00359                     seg->next = segs[Y];
00360                     segs[Y] = seg;
00361                 }
00362                 break;
00363             }
00364         }
00365         if (s == 0) {
00366             prev->next = seg;
00367             seg->next = s;
00368         }
00369     }
00370 }
00371 
00372 inline Segment *
00373 GraphicDevice::progressSegments(Segment * curSegs, long y)
00374 {
00375     Segment *seg,*prev;
00376 
00377     // Update current segments
00378     seg = curSegs;
00379     prev = 0;
00380     while(seg)
00381     {
00382         if ((y*FRAC) > seg->ymax) {
00383             // Remove this segment, no more valid
00384             if (prev) {
00385                 prev->nextValid = seg->nextValid;
00386             } else {
00387                 curSegs = seg->nextValid;
00388             }
00389             seg = seg->nextValid;
00390         } else {
00391             seg->X += seg->dX * FRAC;
00392             prev = seg;
00393             seg = seg->nextValid;
00394         }
00395     }
00396     return curSegs;
00397 }
00398 
00399 inline Segment *
00400 GraphicDevice::newSegments(Segment *curSegs, Segment *newSegs)
00401 {
00402     Segment *s,*seg,*prev;
00403 
00404     s = curSegs;
00405     prev = 0;
00406 
00407     // Check for new segments
00408     for (seg = newSegs; seg; seg=seg->next)
00409     {
00410         // Place it at the correct position according to X
00411         if (curSegs == 0) {
00412             curSegs = seg;
00413             seg->nextValid = 0;
00414         } else {
00415             for(; s; prev = s, s = s->nextValid)
00416             {
00417                 if ( s->X > seg->X ||
00418                      ( (s->X == seg->X) && 
00419                        ( (seg->x1 == s->x1 && seg->dX < s->dX) ||
00420                          (seg->x2 == s->x2 && seg->dX > s->dX)
00421                          ))) {
00422                     // Insert before s
00423                     if (prev) {
00424                         seg->nextValid = s;
00425                         prev->nextValid = seg;
00426                     } else {
00427                         seg->nextValid = curSegs;
00428                         curSegs = seg;
00429                     }
00430                     break;
00431                 }
00432             }
00433             // Append at the end
00434             if (s == 0) {
00435                 prev->nextValid = seg;
00436                 seg->nextValid = 0;
00437             }
00438         }
00439 
00440         s = seg;
00441     }
00442 
00443     return curSegs;
00444 }
00445 
00446 #if 0
00447 static void
00448 printSeg(Segment *seg)
00449 {
00450     /*
00451     printf("Seg %08x : X = %5d, Ft = %d, Cl = %2x/%2x/%2x, Cr = %2x/%2x/%2x, x1=%5d, x2=%5d, ymin=%5d, ymax=%5d\n", seg,
00452         seg->X>>SEGFRAC,
00453         seg->right ? seg->right->type: -1,
00454         seg->left ? seg->left->color.red : -1,
00455         seg->left ? seg->left->color.green : -1,
00456         seg->left ? seg->left->color.blue : -1,
00457         seg->right ? seg->right->color.red : -1,
00458         seg->right ? seg->right->color.green : -1,
00459         seg->right ? seg->right->color.blue : -1,
00460         seg->x1, seg->x2, seg->ymin, seg->ymax);
00461     */
00462 }
00463 #endif
00464 
00465 inline void
00466 GraphicDevice::renderScanLine(long y, Segment *curSegs)
00467 {
00468     Segment *seg;
00469     long width;
00470     int fi = 1;
00471     FillStyleDef *f;
00472 
00473     width = targetWidth * FRAC;
00474 
00475     if (curSegs && curSegs->fs[0] && curSegs->fs[1] == 0) {
00476         fi = 0;
00477     }
00478     for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
00479     {
00480         if (seg->nextValid->X <0) continue;
00481         if ((seg->X>>SEGFRAC) > width) break;
00482         f = seg->fs[fi];
00483         if (f) {
00484             switch (f->type) {
00485                 case f_Solid:
00486                     if (seg->aa) {
00487                         fillLineAA(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00488                     } else  {
00489                         fillLine(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00490                     }
00491                     break;
00492                 case f_TiledBitmap:
00493                 case f_clippedBitmap:
00494                     fillLineBitmap(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00495                     break;
00496                 case f_LinearGradient:
00497                     fillLineLG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00498                     break;
00499                 case f_RadialGradient:
00500                     fillLineRG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00501                     break;
00502                 case f_None:
00503                     break;
00504             }
00505         }
00506     }
00507 }
00508 
00509 /* draw the current path */
00510 void
00511 GraphicDevice::drawPolygon(void)
00512 {
00513     long y;
00514     Segment *curSegs,*seg;
00515 
00516     // no segments ? 
00517     if (this->ymax == -1)
00518         return;
00519 
00520     // Foreach scanline
00521     curSegs = 0;
00522     for(y=this->ymin; y <= this->ymax; y++) {
00523         
00524         // Make X values progess and remove unuseful segments
00525         curSegs = progressSegments(curSegs, y);
00526         
00527         // Add the new segment starting at the y position.
00528         curSegs = newSegments(curSegs, this->segs[y]);
00529         
00530         // Render the scanline
00531         if (this->scan_line_func == NULL) {
00532             renderScanLine(y, curSegs);
00533         } else {
00534             for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid) {
00535                 if (seg->nextValid->X >= seg->X) {
00536                     scan_line_func(this->scan_line_func_id, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
00537                 }
00538             }
00539         }
00540     }
00541 
00542     /* free the segments */
00543     memset(this->segs + this->ymin, 0, 
00544            (this->ymax - this->ymin + 1) * sizeof(Segment *)); 
00545         
00546     this->ymax = -1;
00547     this->ymin = this->height;
00548 
00549     this->seg_pool_cur = this->seg_pool;
00550 }
00551 
00552 void
00553 GraphicDevice::updateClippingRegion(Rect *rect)
00554 {
00555         if (!clipping) return;
00556 
00557         transformBoundingBox(&clip_rect, adjust, rect, 1);
00558         clip_rect.xmin >>= FRAC_BITS;
00559         clip_rect.xmax >>= FRAC_BITS;
00560         clip_rect.ymin >>= FRAC_BITS;
00561         clip_rect.ymax >>= FRAC_BITS;
00562 
00563         clip_rect.xmin-=2;
00564         clip_rect.ymin-=2;
00565         clip_rect.xmax+=2;
00566         clip_rect.ymax+=2;
00567 
00568         if (clip_rect.xmin < viewPort.xmin) clip_rect.xmin = viewPort.xmin;
00569         if (clip_rect.xmax < viewPort.xmin) clip_rect.xmax = viewPort.xmin;
00570         if (clip_rect.ymin < viewPort.ymin) clip_rect.ymin = viewPort.ymin;
00571         if (clip_rect.ymax < viewPort.ymin) clip_rect.ymax = viewPort.ymin;
00572 
00573         if (clip_rect.xmax > viewPort.xmax) clip_rect.xmax = viewPort.xmax;
00574         if (clip_rect.ymax > viewPort.ymax) clip_rect.ymax = viewPort.ymax;
00575         if (clip_rect.xmin > viewPort.xmax) clip_rect.xmin = viewPort.xmax;
00576         if (clip_rect.ymin > viewPort.ymax) clip_rect.ymin = viewPort.ymax;
00577 }
00578 
00579 void
00580 GraphicDevice::setClipping(int value)
00581 {
00582         clipping = value;
00583         if (clipping == 0) {
00584                 // Reset region
00585                 clip_rect.xmin = viewPort.xmin;
00586                 clip_rect.xmax = viewPort.xmax;
00587                 clip_rect.ymin = viewPort.ymin;
00588                 clip_rect.ymax = viewPort.ymax;
00589         }
00590 }
00591 
00592 // Virtual
00593 void
00594 GraphicDevice::clearCanvas()
00595 {
00596 }
00597 
00598 long
00599 GraphicDevice::allocColor(Color color)
00600 {
00601         return 0;
00602 }
00603 
00604 void
00605 GraphicDevice::fillLineBitmap(FillStyleDef *f, long y, long start, long end)
00606 {
00607 }
00608 
00609 void
00610 GraphicDevice::fillLineLG(Gradient *grad, long y, long start, long end)
00611 {
00612 }
00613 
00614 void
00615 GraphicDevice::fillLineRG(Gradient *grad, long y, long start, long end)
00616 {
00617 }
00618 
00619 void
00620 GraphicDevice::fillLine(FillStyleDef *f, long y, long start, long end)
00621 {
00622 }
00623 
00624 void
00625 GraphicDevice::fillLineAA(FillStyleDef *f, long y, long start, long end)
00626 {
00627 }
00628 
00629 void
00630 GraphicDevice::drawLine(long x1, long y1, long x2, long y2, long width)
00631 {
00632 }

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