home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Archived / Updates / Flash / flashplayer / flashlib / c++ / graphic < prev    next >
Encoding:
Text File  |  2000-03-18  |  15.4 KB  |  651 lines

  1. ////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998 Olivier Debon
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. //
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //
  22.  
  23. #include "swf.h"
  24.  
  25. #ifdef RCSID
  26. static char *rcsid = "$Id: graphic.cc,v 1.5 1999/09/03 15:17:40 ode Exp $";
  27. #endif
  28.  
  29. #include "sqrt.h"
  30.  
  31. #define FULL_AA
  32.  
  33. #define PRINT 0
  34.  
  35.  
  36. // Public
  37.  
  38. GraphicDevice::GraphicDevice(FlashDisplay *fd)
  39. {
  40.     flashDisplay = fd;
  41.  
  42.     bgInitialized = 0;
  43.  
  44.     // Reset flash refresh flag
  45.     flashDisplay->flash_refresh = 0;
  46.  
  47.         bpp = fd->depth;
  48.  
  49.         /* should be the actual window size */
  50.     targetWidth = fd->width;
  51.     targetHeight = fd->height;
  52.         bpl = fd->bpl;
  53.  
  54. #if PRINT
  55.     printf("Target Width  = %d\n", targetWidth);
  56.     printf("Target Height = %d\n", targetHeight);
  57. #endif
  58.  
  59.     zoom = FRAC;
  60.     movieWidth = targetWidth;
  61.     movieHeight = targetHeight;
  62.  
  63.     viewPort.xmin = 0;
  64.     viewPort.xmax = targetWidth-1;
  65.     viewPort.ymin = 0;
  66.     viewPort.ymax = targetHeight-1;
  67.  
  68.     canvasBuffer = (unsigned char *) fd->pixels;
  69.  
  70.     adjust = new Matrix;
  71.     foregroundColor.red = 0;
  72.     foregroundColor.green = 0;
  73.     foregroundColor.blue = 0;
  74.     foregroundColor.alpha = ALPHA_OPAQUE;
  75.  
  76.     backgroundColor.red = 0;
  77.     backgroundColor.green = 0;
  78.     backgroundColor.blue = 0;
  79.     backgroundColor.alpha = ALPHA_OPAQUE;
  80.  
  81.     showMore = 0;
  82.  
  83.     setClipping(0);    // Reset
  84.     setClipping(1);
  85.  
  86.         /* polygon rasterizer : handle memory errors ! */
  87.  
  88.         height = targetHeight;
  89.         segs = (Segment **)malloc(height * sizeof(Segment *));
  90.         memset(segs, 0, height * sizeof(Segment *));
  91.         ymin = height;
  92.         ymax = -1;
  93.  
  94.         seg_pool = (Segment *)malloc(NB_SEGMENT_MAX * sizeof(Segment));
  95.         seg_pool_cur = seg_pool;
  96. }
  97.  
  98. GraphicDevice::~GraphicDevice()
  99. {
  100.     free(segs);
  101.     free(seg_pool);
  102.  
  103.     if (adjust) {
  104.         delete adjust;
  105.     }
  106. }
  107.  
  108. ///////////// PLATFORM INDEPENDENT
  109. Color *
  110. GraphicDevice::getColormap(Color *old, long n, Cxform *cxform)
  111. {
  112.     Color *newCmp;
  113.  
  114.     newCmp = new Color[n];
  115.     if (newCmp == NULL) return NULL;
  116.  
  117.     if (cxform) {
  118.         for(long i = 0; i < n; i++)
  119.         {
  120.             newCmp[i] = cxform->getColor(old[i]);
  121.             newCmp[i].pixel = allocColor(newCmp[i]);
  122.         }
  123.     } else {
  124.         for(long i = 0; i < n; i++)
  125.         {
  126.             newCmp[i].pixel = allocColor(old[i]);
  127.         }
  128.     }
  129.  
  130.     return newCmp;
  131. }
  132.  
  133. ///////////// PLATFORM INDEPENDENT
  134. long
  135. GraphicDevice::getHeight()
  136. {
  137.     return targetHeight;
  138. }
  139.  
  140. ///////////// PLATFORM INDEPENDENT
  141. long
  142. GraphicDevice::getWidth()
  143. {
  144.     return targetWidth;
  145. }
  146.  
  147. ///////////// PLATFORM INDEPENDENT
  148. Color
  149. GraphicDevice::getForegroundColor()
  150. {
  151.     return foregroundColor;
  152. }
  153.  
  154. void
  155. GraphicDevice::setForegroundColor(Color color)
  156. {
  157.     foregroundColor = color;
  158. }
  159.  
  160. ///////////// PLATFORM INDEPENDENT
  161. Color
  162. GraphicDevice::getBackgroundColor()
  163. {
  164.     return backgroundColor;
  165. }
  166.  
  167. ///////////// PLATFORM INDEPENDENT
  168. int
  169. GraphicDevice::setBackgroundColor(Color color)
  170. {
  171.     if (bgInitialized == 0) {
  172.         backgroundColor = color;
  173.         clearCanvas();
  174.         bgInitialized = 1;
  175.         return 1;
  176.     }
  177.     return 0;
  178. }
  179.  
  180. ///////////// PLATFORM INDEPENDENT
  181. void
  182. GraphicDevice::setMovieDimension(long width, long height)
  183. {
  184.     float xAdjust, yAdjust;
  185.  
  186.     movieWidth = width;
  187.     movieHeight = height;
  188.  
  189.     xAdjust = (float)targetWidth*zoom/(float)width;
  190.     yAdjust = (float)targetHeight*zoom/(float)height;
  191.  
  192.     if (xAdjust < yAdjust) {
  193.         adjust->a = xAdjust;
  194.         adjust->d = xAdjust;
  195.                 adjust->ty = ((targetHeight*zoom) - (long)(height * xAdjust))/2;
  196.         viewPort.ymin = adjust->ty/zoom;
  197.         viewPort.ymax = targetHeight-viewPort.ymin-1;
  198.     } else {
  199.         adjust->a = yAdjust;
  200.         adjust->d = yAdjust;
  201.                 adjust->tx = ((targetWidth*zoom) - (long)(width * yAdjust))/2;
  202.         viewPort.xmin = adjust->tx/zoom;
  203.         viewPort.xmax = targetWidth-viewPort.xmin-1;
  204.     }
  205.  
  206.     if (viewPort.xmin < 0) viewPort.xmin = 0;
  207.     if (viewPort.ymin < 0) viewPort.ymin = 0;
  208.     if (viewPort.xmax >= targetWidth) viewPort.xmax = targetWidth-1;
  209.     if (viewPort.ymax >= targetHeight) viewPort.ymax = targetHeight-1;
  210. }
  211.  
  212. ///////////// PLATFORM INDEPENDENT
  213. void
  214. GraphicDevice::setMovieZoom(int z)
  215. {
  216.     z *= FRAC;
  217.     if (z <= 0 || z > 100) return;
  218.     zoom = z;
  219.     setMovieDimension(movieWidth,movieHeight);
  220. }
  221.  
  222. ///////////// PLATFORM INDEPENDENT
  223. void
  224. GraphicDevice::setMovieOffset(long x, long y)
  225. {
  226.     adjust->tx = -zoom*x;
  227.     adjust->ty = -zoom*y;
  228. }
  229.  
  230. ///////////// PLATFORM INDEPENDENT
  231. long
  232. GraphicDevice::clip(long &y, long &start, long &end)
  233. {
  234.     long xmin,xend;
  235.  
  236.     if (y < clip_rect.ymin ||
  237.         y >= clip_rect.ymax) return 1;
  238.     if (end <= start)
  239.         return 1;
  240.     xmin = clip_rect.xmin * FRAC;
  241.     xend = clip_rect.xmax * FRAC;
  242.  
  243.     if (end <= xmin || start >= xend) return 1;
  244.  
  245.     if (start < xmin) start = xmin;
  246.     if (end > xend) end = xend;
  247.  
  248.     return 0;
  249. }
  250.  
  251.  
  252. /* alpha = 0 : select c1, alpha = 255 select c2 */
  253. unsigned long
  254. GraphicDevice::mix_alpha(unsigned long c1,
  255.                          unsigned long c2, int alpha)
  256. {
  257.         Color col1;
  258.         Color col2;
  259.         Color col;
  260.  
  261.         col1 = getColor(c1);
  262.         col2 = getColor(c2);
  263.         col.red   = ((col2.red - col1.red) * alpha + (col1.red << 8)) >> 8;
  264.         col.green = ((col2.green - col1.green) * alpha + (col1.green << 8)) >> 8;
  265.         col.blue = ((col2.blue - col1.blue) * alpha + (col1.blue << 8)) >> 8;
  266.         return allocColor(col);
  267. }
  268.  
  269. void
  270. GraphicDevice::drawBox(long x1, long y1, long x2, long y2)
  271. {
  272.     int i;
  273.  
  274.     for(i=0;i<FRAC*2;i++) {
  275.         drawLine(x1+i, y1+i, x2-i, y1+i, 0);
  276.         drawLine(x1+i, y2-i, x2-i, y2-i, 0);
  277.  
  278.         drawLine(x1+i, y1+i+1, x1+i, y2-i-1, 0);
  279.         drawLine(x2-i, y1+i+1, x2-i, y2-i-1, 0);
  280.     }
  281. }
  282.  
  283. /************************************************************************/
  284.  
  285. /* polygon rasteriser */
  286.  
  287. static inline Segment *allocSeg(GraphicDevice *gd)
  288. {
  289.     Segment *seg;
  290.  
  291.     if ( (gd->seg_pool_cur - gd->seg_pool) >= NB_SEGMENT_MAX ) {
  292.         seg = NULL;
  293.     } else {
  294.         seg = gd->seg_pool_cur++;
  295.     }
  296.  
  297.     return seg;
  298. }
  299.  
  300. /* add a segment to the current path */
  301. /* XXX: handle reverse here ? */
  302. /* XXX: should not malloc here */
  303. /* XXX: handle y1 == y2 case (different for fill / line) */
  304. void GraphicDevice::addSegment(long x1, long y1, long x2, long y2,
  305.                                FillStyleDef *f0,
  306.                                FillStyleDef *f1,
  307.                                int aa)
  308. {
  309.     Segment *seg,**segs;
  310.     long dX, X, Y, ymin, ymax, tmp;
  311.     FillStyleDef *ff;
  312.  
  313. #if 0
  314.     if ( ((y1 + (FRAC-1)) & ~(FRAC-1)) == ((y2 + (FRAC-1)) & ~(FRAC-1)) ) {
  315.         return;
  316.     }
  317. #else
  318.     if ( y1 == y2 ) {
  319.         return;
  320.     }
  321. #endif
  322.  
  323.     if (y1 < y2) {
  324.         ymin = y1;
  325.         ymax = y2;
  326.         ff = f0;
  327.         f0 = f1;
  328.         f1 = ff;
  329.     } else {
  330.         ymin = y2;
  331.         ymax = y1;
  332.         tmp = x1;
  333.         x1 = x2;
  334.         x2 = tmp;
  335.     }
  336.  
  337.     if (ymin>>FRAC_BITS > clip_rect.ymax) {
  338.         return;
  339.     }
  340.  
  341.     X = x1 << SEGFRAC;
  342.     dX = ((x2 - x1)<<SEGFRAC)/(ymax-ymin);
  343.  
  344.     if (ymin < 0) {
  345.         X += dX * (-ymin);
  346.         ymin = 0;
  347.     }
  348.  
  349.     Y = (ymin + (FRAC-1)) & ~(FRAC-1);
  350.     if (Y > ymax) {
  351.         //printf("Elimine @ y = %d   ymin = %d, ymax = %d\n", Y, ymin, seg->ymax);
  352.         return;
  353.     }
  354.     X += dX * (Y-ymin);
  355.  
  356.     Y >>= FRAC_BITS;
  357.     if (Y >= clip_rect.ymax) {
  358.         return;
  359.     }
  360.  
  361.     seg = allocSeg(this);
  362.     if (seg == NULL) {
  363.         //        printf("addSegment: too many segments\n");
  364.         return;
  365.     }
  366.  
  367.     seg->next = 0;
  368.     seg->nextValid = 0;
  369.     seg->aa = aa;
  370.     seg->ymax = ymax;
  371.     seg->x1 = x1;
  372.     seg->x2 = x2;
  373.     seg->X = X;
  374.     seg->dX = dX;
  375.     seg->fs[0] = f0;
  376.     seg->fs[1] = f1;
  377.  
  378.     if (Y < this->ymin) this->ymin = Y;
  379.     ymax = (seg->ymax + FRAC - 1) >> FRAC_BITS;
  380.     if (ymax >= this->height) ymax = this->height-1;
  381.     if (ymax > this->ymax) this->ymax = ymax;
  382.  
  383.     segs = this->segs;
  384.  
  385.     if (segs[Y] == 0) {
  386.         segs[Y] = seg;
  387.     } else {
  388.         Segment *s,*prev;
  389.  
  390.         prev = 0;
  391.         for(s = segs[Y]; s; prev = s, s = s->next) {
  392.             if (s->X > seg->X) {
  393.                 if (prev) {
  394.                     prev->next = seg;
  395.                     seg->next = s;
  396.                 } else {
  397.                     seg->next = segs[Y];
  398.                     segs[Y] = seg;
  399.                 }
  400.                 break;
  401.             }
  402.         }
  403.         if (s == 0) {
  404.             prev->next = seg;
  405.             seg->next = s;
  406.         }
  407.     }
  408. }
  409.  
  410. static Segment *progressSegments(Segment * curSegs, long y)
  411. {
  412.     Segment *seg,*prev;
  413.  
  414.     // Update current segments
  415.     seg = curSegs;
  416.     prev = 0;
  417.     while(seg)
  418.     {
  419.         if ((y*FRAC) > seg->ymax) {
  420.             // Remove this segment, no more valid
  421.             if (prev) {
  422.                 prev->nextValid = seg->nextValid;
  423.             } else {
  424.                 curSegs = seg->nextValid;
  425.             }
  426.             seg = seg->nextValid;
  427.         } else {
  428.             seg->X += seg->dX * FRAC;
  429. #if 0
  430.             if (prev && prev->X > seg->X) {
  431.                 s = &curSegs;
  432.                 while ((*s)->X < seg->X) s=&(*s)->nextValid;
  433.                 prev->nextValid = seg->nextValid;
  434.                 seg->nextValid = *s;
  435.                 *s = seg;
  436.                 seg = prev->nextValid;
  437.             } else
  438. #endif
  439.                 {
  440.                 prev = seg;
  441.                 seg = seg->nextValid;
  442.             }
  443.         }
  444.     }
  445.     return curSegs;
  446. }
  447.  
  448. static Segment *newSegments(Segment *curSegs, Segment *newSegs)
  449. {
  450.     Segment *s,*seg,*prev;
  451.  
  452.     s = curSegs;
  453.     prev = 0;
  454.  
  455.     // Check for new segments
  456.     for (seg = newSegs; seg; seg=seg->next)
  457.     {
  458.         // Place it at the correct position according to X
  459.         if (curSegs == 0) {
  460.             curSegs = seg;
  461.             seg->nextValid = 0;
  462.         } else {
  463.             for(; s; prev = s, s = s->nextValid)
  464.             {
  465.                 if ( s->X > seg->X ||
  466.                      ( (s->X == seg->X) &&
  467.                        ( (seg->x1 == s->x1 && seg->dX < s->dX) ||
  468.                          (seg->x2 == s->x2 && seg->dX > s->dX)
  469.                          ))) {
  470.                     // Insert before s
  471.                     if (prev) {
  472.                         seg->nextValid = s;
  473.                         prev->nextValid = seg;
  474.                     } else {
  475.                         seg->nextValid = curSegs;
  476.                         curSegs = seg;
  477.                     }
  478.                     break;
  479.                 }
  480.             }
  481.             // Append at the end
  482.             if (s == 0) {
  483.                 prev->nextValid = seg;
  484.                 seg->nextValid = 0;
  485.             }
  486.         }
  487.  
  488.         s = seg;
  489.     }
  490.  
  491.     return curSegs;
  492. }
  493.  
  494. #if 0
  495. static void
  496. printSeg(Segment *seg)
  497. {
  498.     /*
  499.     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,
  500.         seg->X>>SEGFRAC,
  501.         seg->right ? seg->right->type: -1,
  502.         seg->left ? seg->left->color.red : -1,
  503.         seg->left ? seg->left->color.green : -1,
  504.         seg->left ? seg->left->color.blue : -1,
  505.         seg->right ? seg->right->color.red : -1,
  506.         seg->right ? seg->right->color.green : -1,
  507.         seg->right ? seg->right->color.blue : -1,
  508.         seg->x1, seg->x2, seg->ymin, seg->ymax);
  509.     */
  510. }
  511. #endif
  512.  
  513. static void
  514. renderScanLine(GraphicDevice *gd, long y, Segment *curSegs)
  515. {
  516.     Segment *seg;
  517.     long width;
  518.     int fi = 1;
  519.     FillStyleDef *f;
  520.  
  521.     width = gd->getWidth() * FRAC;
  522.  
  523.     if (curSegs && curSegs->fs[0] && curSegs->fs[1] == 0) {
  524.         fi = 0;
  525.     }
  526.     for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
  527.     {
  528.         if (seg->nextValid->X <0) continue;
  529.         if ((seg->X>>SEGFRAC) > width) break;
  530. #if 0
  531.         if (seg->X > seg->nextValid->X) {
  532.             printf("error %d %d\n",seg->X,seg->nextValid->X);
  533.         }
  534. #endif
  535.         f = seg->fs[fi];
  536.         if (f) {
  537.             switch (f->type) {
  538.                 case f_Solid:
  539.                     if (seg->aa) {
  540.                         gd->fillLineAA(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  541.                     } else  {
  542.                         gd->fillLine(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  543.                     }
  544.                     break;
  545.                 case f_TiledBitmap:
  546.                 case f_clippedBitmap:
  547.                     gd->fillLineBitmap(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  548.                     break;
  549.                 case f_LinearGradient:
  550.                     gd->fillLineLG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  551.                     break;
  552.                 case f_RadialGradient:
  553.                     gd->fillLineRG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  554.                     break;
  555.             case f_None:
  556.             break;
  557.             }
  558.         }
  559.     }
  560. }
  561.  
  562.  
  563. /* draw the current path */
  564. void GraphicDevice::drawPolygon(void)
  565. {
  566.     long y;
  567.     Segment *curSegs,*seg;
  568.  
  569.     // no segments ?
  570.     if (this->ymax == -1)
  571.         return;
  572.  
  573.     // Foreach scanline
  574.     curSegs = 0;
  575.  
  576.     for(y=this->ymin; y <= this->ymax; y++) {
  577.  
  578.         // Make X values progess and remove unuseful segments
  579.         curSegs = progressSegments(curSegs, y);
  580.  
  581.         // Add the new segment starting at the y position.
  582.         curSegs = newSegments(curSegs, this->segs[y]);
  583.  
  584.         // Render the scanline
  585.         if (this->scan_line_func == NULL) {
  586.             renderScanLine(this, y, curSegs);
  587.         } else {
  588.             for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid) {
  589.                 if (seg->nextValid->X >= seg->X) {
  590.                     this->scan_line_func(this->scan_line_func_id,
  591.                                          y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
  592.                 }
  593.             }
  594.         }
  595.     }
  596.  
  597.     /* free the segments */
  598.     memset(this->segs + this->ymin, 0,
  599.            (this->ymax - this->ymin + 1) * sizeof(Segment *));
  600.  
  601.     this->ymax = -1;
  602.     this->ymin = this->height;
  603.  
  604.     this->seg_pool_cur = this->seg_pool;
  605. }
  606.  
  607. void
  608. GraphicDevice::updateClippingRegion(Rect *rect)
  609. {
  610.     if (!clipping) return;
  611.  
  612.     transformBoundingBox(&clip_rect, adjust, rect, 1);
  613.     clip_rect.xmin >>= FRAC_BITS;
  614.     clip_rect.xmax >>= FRAC_BITS;
  615.     clip_rect.ymin >>= FRAC_BITS;
  616.     clip_rect.ymax >>= FRAC_BITS;
  617.  
  618. #if PRINT&1
  619.     clip_rect.print();
  620. #endif
  621.  
  622.     clip_rect.xmin-=2;
  623.     clip_rect.ymin-=2;
  624.     clip_rect.xmax+=2;
  625.     clip_rect.ymax+=2;
  626.  
  627.     if (clip_rect.xmin < viewPort.xmin) clip_rect.xmin = viewPort.xmin;
  628.     if (clip_rect.xmax < viewPort.xmin) clip_rect.xmax = viewPort.xmin;
  629.     if (clip_rect.ymin < viewPort.ymin) clip_rect.ymin = viewPort.ymin;
  630.     if (clip_rect.ymax < viewPort.ymin) clip_rect.ymax = viewPort.ymin;
  631.  
  632.     if (clip_rect.xmax > viewPort.xmax) clip_rect.xmax = viewPort.xmax;
  633.     if (clip_rect.ymax > viewPort.ymax) clip_rect.ymax = viewPort.ymax;
  634.     if (clip_rect.xmin > viewPort.xmax) clip_rect.xmin = viewPort.xmax;
  635.     if (clip_rect.ymin > viewPort.ymax) clip_rect.ymin = viewPort.ymax;
  636. }
  637.  
  638. void
  639. GraphicDevice::setClipping(int value)
  640. {
  641.     clipping = value;
  642.     if (clipping == 0) {
  643.         //printf("Clipping Off\n");
  644.         // Reset region
  645.         clip_rect.xmin = viewPort.xmin;
  646.         clip_rect.xmax = viewPort.xmax;
  647.         clip_rect.ymin = viewPort.ymin;
  648.         clip_rect.ymax = viewPort.ymax;
  649.     }
  650. }
  651.