gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog backend/render_handler_agg.cpp ...


From: Udo Giacomozzi
Subject: [Gnash-commit] gnash ChangeLog backend/render_handler_agg.cpp ...
Date: Tue, 31 Oct 2006 08:54:23 +0000

CVSROOT:        /cvsroot/gnash
Module name:    gnash
Changes by:     Udo Giacomozzi <udog>   06/10/31 08:54:23

Modified files:
        .              : ChangeLog 
        backend        : render_handler_agg.cpp 
                         render_handler_agg_style.h 

Log message:
        Implemented masks for AGG renderer

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.1451&r2=1.1452
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg.cpp?cvsroot=gnash&r1=1.32&r2=1.33
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg_style.h?cvsroot=gnash&r1=1.6&r2=1.7

Patches:
Index: ChangeLog
===================================================================
RCS file: /cvsroot/gnash/gnash/ChangeLog,v
retrieving revision 1.1451
retrieving revision 1.1452
diff -u -b -r1.1451 -r1.1452
--- ChangeLog   31 Oct 2006 08:32:34 -0000      1.1451
+++ ChangeLog   31 Oct 2006 08:54:23 -0000      1.1452
@@ -1,3 +1,9 @@
+2006-10-31 Udo Giacomozzi <address@hidden>
+
+       * backend/render_handler_agg.cpp, 
+         backend/render_handler_agg_style.h: Implemented masks for 
+         AGG renderer
+
 2006-10-31 Sandro Santilli <address@hidden>
 
        * backend/sound_handler_gst.cpp (stop_all_sounds): fixed infinite

Index: backend/render_handler_agg.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/backend/render_handler_agg.cpp,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -b -r1.32 -r1.33
--- backend/render_handler_agg.cpp      29 Oct 2006 18:34:17 -0000      1.32
+++ backend/render_handler_agg.cpp      31 Oct 2006 08:54:23 -0000      1.33
@@ -16,7 +16,7 @@
 
  
 
-/* $Id: render_handler_agg.cpp,v 1.32 2006/10/29 18:34:17 rsavoye Exp $ */
+/* $Id: render_handler_agg.cpp,v 1.33 2006/10/31 08:54:23 udog Exp $ */
 
 // Original version by Udo Giacomozzi and Hannes Mayr, 
 // INDUNET GmbH (www.indunet.it)
@@ -28,10 +28,14 @@
 /// rendering to the Linux FrameBuffer device, or be blitted inside a 
 /// window (regardless of what operating system). It should also be no problem
 /// to render into a file...
+/// This file uses *very* heavily templates and is optimized mainly for speed,
+/// meaning that the compiler generates very, very, very much specialized 
+/// code. That's good for speed but bloats up the resulting machine code. 
 
 /*
 
-Status:
+Status
+------
 
   outlines:
     solid             COMPLETE
@@ -56,15 +60,49 @@
     
   fonts               COMPLETE
     
-  masks               NOT IMPLEMENTED (masks are drawn as shapes)
+  masks               COMPLETE
   
   caching             NONE IMPLEMENTED
   
-  video               don't know how that works
+  video               NOT IMPLEMENTED, only stubs
   
+  Currently the renderer should be able to render everything correctly,
+  except videos.
   
   
-AGG ressources:
+What could and should be /optimized/
+------------------------------------  
+  
+  - EASY: Do not even start rendering shapes that are abviously out of the
+    invalidated bounds!  
+    
+  - The alpha mask buffers (masks) are allocated and freed for each mask which
+    results in many large-size buffer allocations during a second. Maybe this
+    should be optimized.
+    
+  - Converted fill styles (for AGG) are recreated for each sub-shape, even if
+    they never change for a shape. This should be changed.
+    
+  - Matrix-transformed paths (generated before drawing a shape) should be 
cached
+    and re-used to avoid recalculation of the same coordinates.
+    
+  - Characters (or sprites) may be cached as bitmaps with alpha channel (RGBA).
+    The mechanism could be automatically activated when the same character is
+    being rendered the 3rd or 5th time in a row with the same transformations
+    (regardless of the instance itself!). It's not a good idea to always
+    render into a bitmap buffer because this eats up memory and adds an 
+    additional pass in rendering (blitting the bitmap buffer). This may be
+    tricky to implement anyway.
+    
+  - Masks are a very good candidate for bitmap caching as they do not change
+    that often. With other words, the alpha mask should not be discarded after
+    rendering and should be reused if possible.
+    
+  - there are also a few TODO comments in the code!
+  
+  
+AGG ressources
+--------------
   http://www.antigrain.com/    
   http://haiku-os.org/node/86
 
@@ -124,6 +162,7 @@
 #include <agg_span_interpolator_linear.h>
 #include <agg_span_gradient.h>
 #include <agg_gradient_lut.h>
+#include <agg_alpha_mask_u8.h>
 
 #include "render_handler_agg_bitmap.h"
 #include "render_handler_agg_style.h"
@@ -137,20 +176,10 @@
 namespace gnash {
 
 // --- CACHE 
-------------------------------------------------------------------
-
-// Possible caching mechanisms (ideas):
-//  - cache paths after applying matrix
-//  - cache characters as bitmap
-//  - try to update only changed parts of the stage!! This may require 
-//    additional code in the character instances, something like a 
-//    "invalidated" flag.
-//  - smart cache: start caching after 3 or 5 hyptothetical cache hits
-//    (hits to cache objects that contain no data, yet)
- 
-
 /// This class holds a completely transformed path (fixed position). Speeds
 /// up characters that stay fixed on a certain position on the stage. 
 // ***CURRENTLY***NOT***USED***
+
 class agg_transformed_path 
 {
   /// Original transformation matrix 
@@ -190,6 +219,83 @@
 }; // class agg_YUV_video
 
 
+
+// --- ALPHA MASK BUFFER CONTAINER 
---------------------------------------------
+// How masks are implemented: A mask is basically a full alpha buffer. Each 
+// pixel in the alpha buffer defines the fraction of color values that are
+// copied to the main buffer. The alpha mask buffer has 256 alpha levels per
+// pixel, which is good as it allows anti-aliased masks. A full size buffer
+// is allocated for each mask even if the invalidated bounds may be much 
+// smaller. The advantage of this is that the alpha mask adaptor does not need
+// to do any clipping which results in better performance.
+// Masks can be nested, which means the intersection of all masks should be 
+// visible (logical AND). To allow this we hold a stack of alpha masks and the 
+// topmost mask is used itself as a mask to draw any new mask. When rendering 
+// visible shapes only the topmost mask must be used and when a mask should 
not 
+// be used anymore it's simply discarded so that the next mask becomes active 
+// again.
+// To be exact, Flash is a bit restrictive regarding to what can be a mask
+// (dynamic text, shapes, ...) but our rebderer can build a mask from 
everything 
+// we can draw otherwise (except lines, which are excluded explicitely).    
+
+class agg_alpha_mask 
+{
+
+  typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base;
+  typedef agg::alpha_mask_gray8 amask_type;
+
+public:
+
+  agg_alpha_mask(int width, int height) :
+    m_rbuf(NULL, width, height, width),    // *
+    m_pixf(m_rbuf),
+    m_rbase(m_pixf),
+    m_amask(m_rbuf)
+  {
+  
+    // * = m_rbuf is first initialized with a NULL buffer so that m_pixf and
+    // m_rbase initialize with the correct buffer extents
+  
+    m_buffer = new uint8_t[width*height];
+    
+    m_rbuf.attach(m_buffer, width, height, width);
+    
+    m_rbase.clear(agg::gray8(0));
+  }
+  
+  ~agg_alpha_mask() 
+  {
+    delete [] m_buffer;
+  }
+  
+  renderer_base& get_rbase() {
+    return m_rbase;
+  }
+  
+  amask_type& get_amask() {
+    return m_amask;
+  }  
+  
+  
+private:
+  // in-memory buffer
+  uint8_t* m_buffer;
+  
+  // agg class to access the buffer
+  agg::rendering_buffer m_rbuf;
+  
+  // pixel access
+  agg::pixfmt_gray8 m_pixf;  
+  
+  // renderer base
+  renderer_base m_rbase;
+  
+  // alpha mask
+  amask_type m_amask;
+};
+
+
+
 // --- RENDER HANDLER 
----------------------------------------------------------
 // The class is implemented using templates so that it supports any kind of
 // pixel format. LUT (look up tables) are not supported, however.
@@ -388,6 +494,9 @@
     scaleX = (double)xres / (double)viewport_width / 20.0;  // 20=TWIPS
     scaleY = (double)yres / (double)viewport_height / 20.0;
     scale = scaleX<scaleY ? scaleX : scaleY;
+    
+    // reset status variables
+    m_drawing_mask = false;
        }
 
   bool allow_glyph_textures() {
@@ -399,6 +508,15 @@
        // Clean up after rendering a frame.  Client program is still
        // responsible for calling glSwapBuffers() or whatever.
        {
+       
+         if (m_drawing_mask) 
+           log_msg("warning: rendering ended while drawing a mask");
+           
+         while (! m_alpha_mask.empty()) {
+           log_msg("warning: rendering ended while masks were still active");
+      disable_mask();       
+         }
+       
     // nothing to do
        }
 
@@ -493,225 +611,29 @@
 
   void begin_submit_mask()
        {
-    // not implemented
-       }
-
-  void end_submit_mask()
-       {
-    // not implemented
-       }
-
-  void disable_mask()
-       {
-    // not implemented
-       }
+         // Set flag so that rendering of shapes is simplified (only solid 
fill) 
+    m_drawing_mask = true;
        
+    agg_alpha_mask* new_mask = new agg_alpha_mask(xres, yres); 
 
+    m_alpha_mask.push_back(new_mask);
 
-  /*
-   Takes a list of paths and combines them according to their fill style so 
-   that each path is a closed polygon. Each path will have exactly one fill 
-   style.
-   This is necessary because Flash uses up to two fill styles for each path,
-   one for each side. It can happen that a path contains only one edge. In that
-   case it just divides a shape in two (two colors). Since this is impossible
-   to draw directly we need to restore the original polygons so that they can
-   be drawn independently.
-   
-   IMPORTANT NOTE: This is currently *not* used for AGG anymore, because AGG
-   has a direct rasterizer for double styles...   
-   */   
-  void combine_paths(std::vector<path> &paths_in, std::vector<path> 
&paths_out) {
-    
-    int ino;      // index of input path
-    int incount;  // cache value for paths_in.size()
-    int ono;      // index of output path
-    int eno;      // edge index 
-    
-    #define EQUAL(a,b) (fabs(a-b)<0.000000001)
-    
-    incount = paths_in.size();
-    
-    /*
-    Strategy: For fill style 0, each path is compared with other paths sharing
-    the same fill style and it is tried to attach the new path to a already 
-    known path. The start point of the new path must match the end point of the
-    previous path. Only distant shapes will not find a matching path and thus
-    will create a new one.
-    For fill style 1 the same is done except that the path is reversed first.
-    The resulting paths will use exactly one fill style (fill style 0).
-    Each source path may be used for two different resulting shapes (one time
-    normally and the other reversed).    
-    */
-    
-    // browse through all paths...
-    for (ino=0; ino<incount; ino++) {
-    
-      path &new_path = paths_in[ino];
-      int found;
-
-      // === FILL STYLE 0 ===
-      
-      if (new_path.m_fill0) {
-        found=0;
-        
-        // Search paths sharing the same fill style and whose end point matches
-        // the START point of <new_path>
-        for (ono=0; ono < paths_out.size(); ono++) {
-        
-          path &cp = paths_out[ono];
-          edge &last_edge = cp.m_edges.back();
-          
-          log_msg("  = [FS0] compare style %d with %d: ", new_path.m_fill0,
-            paths_out[ono].m_fill0);
-          if (new_path.m_fill0 != paths_out[ono].m_fill0) {
-            log_msg("no match\n"); 
-            continue;  // fill style mismatch
-          }
-          log_msg("match!\n");
-            
-          log_msg("  = [FS0] compare edge %f/%f with %f/%f: ", 
-            new_path.m_ax, new_path.m_ay,
-            last_edge.m_ax, last_edge.m_ay);  
-          if (!EQUAL(new_path.m_ax, last_edge.m_ax) ||
-              !EQUAL(new_path.m_ay, last_edge.m_ay)) {
-            log_msg("no match\n");
-            continue;  // cannot attach
-          }
-          log_msg("match!\n");
-            
-            
-          // ==> ok, attach "this_path" to "cp"
-          
-          log_msg(" == [FS0] attach path #%d\n", ino);
-           
-          // TODO: Resize vector and set elements directly, avoiding multiple
-          // resizing...
-          //cp->resize( cp->size() + new_path->size() );
-          
-          for (eno=0; eno<new_path.m_edges.size(); eno++) {
-            cp.m_edges.push_back(new_path.m_edges[eno]);
-          }
-          
-          found=1;
-          
-          break;
-        
-        }  // for ono
-        
-        if (!found) {
-          // We found no matching path, so start a new one...
-          log_msg(" == [FS0] start new path #%d\n", ino);
-          path temp = new_path;
-          temp.m_fill1=0;   // use only fill style 0
-          paths_out.push_back(temp);
-        }
-
-      } // if m_fill0
-      
-    
-      // === FILL STYLE 1 ===
-      
-      if (new_path.m_fill1) {
-        float last_cx;
-        float last_cy;
-        float next_cx;
-        float next_cy;
-        found=0;
-        
-        // create a new, reversed path
-        path rev_path;
-        rev_path.m_fill0 = new_path.m_fill1;
-        rev_path.m_ax = new_path.m_edges.back().m_ax;
-        rev_path.m_ay = new_path.m_edges.back().m_ay;
-        last_cx = new_path.m_edges.back().m_cx;
-        last_cy = new_path.m_edges.back().m_cy;
-        for (eno=new_path.m_edges.size()-2; eno>=0; eno--) {  
-          edge temp = new_path.m_edges[eno];
-          next_cx = temp.m_cx;
-          next_cy = temp.m_cy;
-          temp.m_cx = last_cx;
-          temp.m_cy = last_cy;
-          rev_path.m_edges.push_back(temp);
-          last_cx=next_cx;
-          last_cy=next_cy;
         }
         
+  void end_submit_mask()
         {
-          edge temp;
-          temp.m_ax = new_path.m_ax;
-          temp.m_ay = new_path.m_ay;
-          temp.m_cx = last_cx;
-          temp.m_cy = last_cy;
-          rev_path.m_edges.push_back(temp);   // add anchor of new_path as 
last edge
-        }
-        
-        
-        
-        // ==> now proceed just as like with fill style 0...
-        
-        
-        
-        // Search paths sharing the same fill style and whose end point matches
-        // the START point of <new_path>
-        for (ono=0; ono < paths_out.size(); ono++) {
-        
-          path &cp = paths_out[ono];
-          edge &last_edge = cp.m_edges.back();
-          
-          log_msg("  = [FS1] compare style %d with %d: ", rev_path.m_fill0,
-            paths_out[ono].m_fill0);
-          if (rev_path.m_fill0 != paths_out[ono].m_fill0) {
-            log_msg("no match\n"); 
-            continue;  // fill style mismatch
-          }
-          log_msg("match!\n");
-            
-          log_msg("  = [FS1] compare edge %f/%f with %f/%f: ", 
-            rev_path.m_ax, rev_path.m_ay,
-            last_edge.m_ax, last_edge.m_ay);  
-          if (!EQUAL(rev_path.m_ax, last_edge.m_ax) ||
-              !EQUAL(rev_path.m_ay, last_edge.m_ay)) {
-            log_msg("no match\n");
-            continue;  // cannot attach
-          }
-          log_msg("match!\n");
-            
-            
-          // ==> ok, attach "this_path" to "cp"
-          
-          log_msg(" == [FS1] attach path #%d\n", ino);
-           
-          // TODO: Resize vector and set elements directly, avoiding multiple
-          // resizing...
-          //cp->resize( cp->size() + new_path->size() );
-          
-          for (eno=0; eno<rev_path.m_edges.size(); eno++) {
-            cp.m_edges.push_back(rev_path.m_edges[eno]);
-          }
-          
-          found=1;
-          
-          break;
-        
-        }  // for ono
-        
-        if (!found) {
-          // We found no matching path, so start a new one...
-          log_msg(" == [FS1] start new path #%d\n", ino);
-          path temp = rev_path;
-          temp.m_fill1=0;   // use only fill style 0
-          paths_out.push_back(temp);
+    m_drawing_mask = false;
         }
 
+  void disable_mask()
+       {
+         agg_alpha_mask* old_mask = m_alpha_mask.back();
+    m_alpha_mask.pop_back();
+    delete old_mask; 
       }
 
     
-    }
     
-    #undef EQUAL   
-    
-  }
 
 
 
@@ -726,7 +648,8 @@
     need_single_fill_style(color);
 
     // draw the shape
-    draw_shape(-1, paths, m_single_fill_styles, m_neutral_cxform, mat, false);
+    draw_shape(-1, paths, m_single_fill_styles, m_neutral_cxform,  
+      mat, false);
     
     // NOTE: Do not use even-odd filling rule for glyphs!
   }
@@ -743,6 +666,13 @@
     
     apply_matrix_to_path(def->get_paths(), paths, mat);
     
+    if (m_drawing_mask) {
+      
+      // Shape is drawn inside a mask, skip sub-shapes handling and outlines
+      draw_mask_shape(paths, true);      
+    
+    } else {
+      
     // We need to separate sub-shapes during rendering. The current 
     // implementation is a bit sub-optimal because the fill styles get
     // re-initialized for each sub-shape. Maybe this will be no more a problem
@@ -753,7 +683,9 @@
       draw_shape(subshape, paths, fill_styles, cx, mat, true);    
       draw_outlines(subshape, paths, line_styles, cx);
     }
-  }
+    } // if not drawing mask
+    
+  } // draw_shape_character
 
 
   /// Takes a path and translates it using the given matrix. The new path
@@ -838,6 +770,40 @@
   void draw_shape(int subshape_id, const std::vector<path> &paths,
     const std::vector<fill_style> &fill_styles, const cxform& cx,
     const matrix& fillstyle_matrix, int even_odd) {
+    
+    if (m_alpha_mask.empty()) {
+    
+      // No mask active, use normal scanline renderer
+      
+      typedef agg::scanline_u8 scanline_type;
+      
+      scanline_type sl;
+      
+      draw_shape_impl<scanline_type> (subshape_id, paths, fill_styles, cx, 
+        fillstyle_matrix, even_odd, sl);
+        
+    } else {
+    
+      // Mask is active, use alpha mask scanline renderer
+      
+      typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
+      
+      scanline_type sl(m_alpha_mask.back()->get_amask());
+      
+      draw_shape_impl<scanline_type> (subshape_id, paths, fill_styles, cx, 
+        fillstyle_matrix, even_odd, sl);
+        
+    }
+    
+  }
+   
+  /// Template for draw_shape(). Two different scanline types are suppored, 
+  /// one with and one without an alpha mask. This makes drawing without masks
+  /// much faster.  
+  template <class scanline_type>
+  void draw_shape_impl(int subshape_id, const std::vector<path> &paths,
+    const std::vector<fill_style> &fill_styles, const cxform& cx,
+    const matrix& fillstyle_matrix, int even_odd, scanline_type& sl) {
     /*
     Fortunately, AGG provides a rasterizer that fits perfectly to the flash
     data model. So we just have to feed AGG with all data and we're done. :-)
@@ -849,13 +815,14 @@
     
          assert(m_pixf != NULL);
 
+         assert(!m_drawing_mask);
+
     // Gnash stuff 
     int pno, eno, fno;
     int pcount, ecount, fcount;
     
     // AGG stuff
     renderer_base rbase(*m_pixf);
-    agg::scanline_u8 sl;                // scanline renderer
     agg::rasterizer_scanline_aa<> ras;  // anti alias
     agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> rasc;  // 
flash-like renderer
     agg::renderer_scanline_aa_solid<
@@ -939,6 +906,7 @@
         } 
         
       } // switch
+        
     } // for
     
       
@@ -996,12 +964,164 @@
 
 
 
+
+  // very similar to draw_shape but used for generating masks. There are no
+  // fill styles nor subshapes and such. Just render plain solid shapes.
+  void draw_mask_shape(const std::vector<path> &paths, int even_odd) {
+  
+    unsigned int mask_count = m_alpha_mask.size();
+    
+    if (mask_count < 2) {
+    
+      // This is the first level mask
+      
+      typedef agg::scanline_u8 scanline_type;
+      
+      scanline_type sl;
+      
+      draw_mask_shape_impl<scanline_type> (paths, even_odd, sl);
+        
+    } else {
+    
+      // Woohoo! We're drawing a nested mask! Use the previous mask while 
+      // drawing the new one, the result will be the intersection.
+      
+      typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
+      
+      scanline_type sl(m_alpha_mask[mask_count-2]->get_amask());
+      
+      draw_mask_shape_impl<scanline_type> (paths, even_odd, sl);
+        
+    }
+    
+  }
+  
+  
+  template <class scanline_type>
+  void draw_mask_shape_impl(const std::vector<path> &paths, int even_odd,
+    scanline_type& sl) {
+    
+    typedef agg::pixfmt_gray8 pixfmt;
+    typedef agg::renderer_base<pixfmt> renderer_base;
+    
+    assert(!m_alpha_mask.empty());
+    
+    // dummy style handler
+    typedef agg_mask_style_handler sh_type;
+    sh_type sh;                   
+       
+    // anti-aliased scanline rasterizer
+    typedef agg::rasterizer_scanline_aa<> ras_type;
+    ras_type ras;
+    
+    // compound rasterizer used for flash shapes
+    typedef agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> 
rasc_type;  
+    rasc_type rasc;
+    
+    // renderer base
+    renderer_base& rbase = m_alpha_mask.back()->get_rbase();
+    
+    // solid fills
+    typedef agg::renderer_scanline_aa_solid< renderer_base > ren_sl_type;
+    ren_sl_type ren_sl(rbase);
+    
+    // span allocator
+    typedef agg::span_allocator<agg::gray8> alloc_type;
+    alloc_type alloc;   // why does gray8 not work?
+      
+
+    // activate even-odd filling rule
+    if (even_odd)
+      rasc.filling_rule(agg::fill_even_odd);
+    else
+      rasc.filling_rule(agg::fill_non_zero);
+      
+    
+    // push paths to AGG
+    unsigned int pcount = paths.size();
+    for (unsigned int pno=0; pno < pcount; pno++) {
+    
+      const path& this_path = paths[pno];
+      agg::path_storage path;
+      agg::conv_curve< agg::path_storage > curve(path);
+      
+      // reduce everything to just one fill style!
+      rasc.styles(this_path.m_fill0==0 ? -1 : 0,
+                  this_path.m_fill1==0 ? -1 : 0);
+                  
+      // starting point of path
+      path.move_to(this_path.m_ax*scale, this_path.m_ay*scale);
+    
+      unsigned int ecount = this_path.m_edges.size();
+      for (unsigned int eno=0; eno<ecount; eno++) {
+      
+        const edge &this_edge = this_path.m_edges[eno];
+
+        if (this_edge.is_straight())
+          path.line_to(this_edge.m_ax*scale, this_edge.m_ay*scale);
+        else
+          path.curve3(this_edge.m_cx*scale, this_edge.m_cy*scale,
+                      this_edge.m_ax*scale, this_edge.m_ay*scale);
+        
+      } // for edge
+      
+      // add to rasterizer
+      rasc.add_path(curve);
+    
+    } // for path
+    
+    
+    // now render that thing!
+    agg::render_scanlines_compound_layered (rasc, sl, rbase, alloc, sh);
+    //agg::render_scanlines(rasc, sl, ren_sl);
+        
+        
+  } // draw_mask_shape
+
+
+
   /// Just like draw_shapes() except that it draws an outline.
   void draw_outlines(int subshape_id, const std::vector<path> &paths,
     const std::vector<line_style> &line_styles, const cxform& cx) {
     
+    if (m_alpha_mask.empty()) {
+    
+      // No mask active, use normal scanline renderer
+      
+      typedef agg::scanline_u8 scanline_type;
+      
+      scanline_type sl;
+      
+      draw_outlines_impl<scanline_type> (subshape_id, paths, line_styles, 
+        cx, sl);
+        
+    } else {
+    
+      // Mask is active, use alpha mask scanline renderer
+      
+      typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
+      
+      scanline_type sl(m_alpha_mask.back()->get_amask());
+      
+      draw_outlines_impl<scanline_type> (subshape_id, paths, line_styles, 
+        cx, sl);
+        
+    }
+    
+  }
+
+
+  /// Template for draw_outlines(), see draw_shapes_impl().
+  template <class scanline_type>
+  void draw_outlines_impl(int subshape_id, const std::vector<path> &paths,
+    const std::vector<line_style> &line_styles, const cxform& cx, 
+    scanline_type& sl) {
+    
          assert(m_pixf != NULL);
 
+         if (m_drawing_mask)    // Flash ignores lines in mask /definitions/
+      return;  
+
     // TODO: While walking the paths for filling them, remember when a path
     // has a line style associated, so that we avoid walking the paths again
     // when there really are no outlines to draw...
@@ -1012,7 +1132,6 @@
     
     // AGG stuff
     renderer_base rbase(*m_pixf);
-    agg::scanline_p8 sl;                // scanline renderer
     agg::rasterizer_scanline_aa<> ras;  // anti alias
     agg::renderer_scanline_aa_solid<
       agg::renderer_base<PixelFormat> > ren_sl(rbase); // solid fills
@@ -1147,222 +1266,6 @@
   }
                       
                       
-  /*
-  This method is *not* being used anymore, because we use a special AGG 
-  rasterizer that can deal with Flash edges directly. 
-  It is kept here since it was hard work and who knows it it becomes useful
-  again some day. 
-  It works for 95% of the shapes. There is just a special case where it does
-  not draw a curve when it should do so. I guess there is some bug in the
-  combine_paths() method when reversing a path. Probably control point of the
-  first or last edge of a path is wrong (gets lost) somehow.  
-  */
-  void draw_shape_character_old(shape_character_def *def, 
-    character *inst) {
-    
-    // replaces: shape_character_def::display()   (both versions)
-    // replaces: shape_character_def::tesselate() 
-
-    // Gnash stuff
-    std::vector<path> paths, orig_paths;
-    std::vector<fill_style> fill_styles;
-    path current_path;
-    int paths_count;
-    int pathno, edgeno, edge_count;    
-    rgba color;
-    int fillno;
-    int fillidx;
-    
-    // AGG stuff
-    PixelFormat pixf(m_rbuf);
-    renderer_base rbase(pixf);
-    agg::scanline_p8 sl;
-    agg::rasterizer_scanline_aa<> ras;
-    agg::renderer_scanline_aa_solid<
-      agg::renderer_base<PixelFormat> > ren_sl(rbase);
-     
-    // We need one AGG path (polygon) for each fill style
-    std::vector< agg::path_storage > agg_paths; 
-
-    log_msg("draw_shape_character() called.\n");
-    
-    /*
-    
-    Flash will tend to save outlines in clockwise rotating order.
-    We use the "non zero" filling rule of AGG, that is, when you raw a 
rectangle 
-    in clockwise order and another rectangle inside the other with 
-    counter-clockwise order, it will keep the inner rectangle transparent.
-    
-    AGG could also do the "even odd" filling rule where the order does not 
-    matter (so we don't need to reverse fill style #1), however this leads to
-    noticeable borders between polygons. Don't know exactly why, however the
-    typical fill style text (Flash SDK) shows two green triangles instead of
-    a green rectangle. 
-    
-    So, we simple draw all paths for fill style 1 in reverse order, as opposed
-    to fill style 0, which is drawn normally. 
-    
-    */
-    ras.filling_rule(agg::fill_non_zero);
-    //ras.filling_rule(agg::fill_even_odd);
-    
-    
-    //--
-    
-    // Combine paths, so that they are easier to draw
-    orig_paths = def->get_paths();
-    combine_paths(orig_paths, paths);
-      
-  
-    
-    fill_styles = def->get_fill_styles();
-    
-    paths_count = paths.size();     // fasten access
-    
-    log_msg("Fill styles vector contains %d items.\n", fill_styles.size());
-    
-    log_msg("Preparing paths vector...\n");
-    agg_paths.resize(fill_styles.size());
-    
-    log_msg("Paths vector contains %d items.\n", paths_count);
-    
-    for (pathno=0; pathno<paths_count; pathno++) {
-    
-      log_msg("Processing path #%d\n", pathno);
-      
-      current_path = paths[pathno];
-      
-      log_msg("  path fill0 has index %d\n", current_path.m_fill0);
-      log_msg("  path fill1 has index %d\n", current_path.m_fill1);
-      
-      log_msg("  path anchor at %f / %f\n", 
-        current_path.m_ax/20, current_path.m_ay/20);
-
-      edge_count = current_path.m_edges.size();      
-      log_msg("  path has %d edges.\n", edge_count);
-      
-
-      //=== DRAW FILL STYLE 0 IN NORMAL ORDER ===
-
-      fillidx = current_path.m_fill0-1;
-      
-      if (fillidx>=0) {
-      
-        agg::path_storage *the_path = &agg_paths[fillidx];
-        
-        log_msg("  adding path for fill style 0 (normal)\n");
-
-        the_path->move_to(current_path.m_ax*scale, current_path.m_ay*scale);   
   
-        
-        for (edgeno=0; edgeno<edge_count; edgeno++) {
-          log_msg("    edge #%d anchor %f/%f control %f/%f\n", edgeno,
-            current_path.m_edges[edgeno].m_ax/20,
-            current_path.m_edges[edgeno].m_ay/20,
-            current_path.m_edges[edgeno].m_cx/20,
-            current_path.m_edges[edgeno].m_cy/20);
-            
-          if (current_path.m_edges[edgeno].is_straight()) {
-            the_path->line_to(current_path.m_edges[edgeno].m_ax*scale, 
-              current_path.m_edges[edgeno].m_ay*scale);
-          }
-          else 
-          {
-            log_msg("    drawing curve\n");
-            the_path->curve3(
-              current_path.m_edges[edgeno].m_cx*scale, 
-              current_path.m_edges[edgeno].m_cy*scale,
-              current_path.m_edges[edgeno].m_ax*scale, 
-              current_path.m_edges[edgeno].m_ay*scale);
-          }
-        } // for edge
-        
-        
-      } // if fillidx
-
-
-
-      //=== DRAW FILL STYLE 1 IN REVERSED ORDER ===
-
-      fillidx = current_path.m_fill1-1;
-      
-      if (fillidx>=0) {
-      
-        float next_ax, next_ay, next_cx, next_cy;
-        float last_ax, last_ay, last_cx, last_cy;
-      
-        agg::path_storage *the_path = &agg_paths[fillidx];
-        
-        log_msg("  adding path for fill style 1 (reversed)\n");
-
-        /*the_path->move_to(current_path.m_edges[edge_count-1].m_ax*scale, 
-                         current_path.m_edges[edge_count-1].m_ay*scale);*/
-                         
-        last_ax = current_path.m_ax*scale;       
-        last_ay = current_path.m_ay*scale;
-        last_cx = last_ax;        
-        last_cy = last_ay;
-        the_path->move_to(last_ax, last_ay);      
-        
-        for (edgeno=edge_count-1; edgeno>=0; edgeno--) {
-          log_msg("    edge #%d anchor %f/%f control %f/%f\n", edgeno,
-            current_path.m_edges[edgeno].m_ax/20,
-            current_path.m_edges[edgeno].m_ay/20,
-            current_path.m_edges[edgeno].m_cx/20,
-            current_path.m_edges[edgeno].m_cy/20);
-            
-          next_ax = current_path.m_edges[edgeno].m_ax*scale;
-          next_ay = current_path.m_edges[edgeno].m_ay*scale;
-          next_cx = current_path.m_edges[edgeno].m_cx*scale;
-          next_cy = current_path.m_edges[edgeno].m_cy*scale;
-          
-          log_msg("      the_path->curve3(%f, %f, %f, %f);\n", last_cx, 
last_cy, next_ax, next_ay);
-          the_path->curve3(last_cx, last_cy, next_ax, next_ay);
-          
-          // TODO: Do not add a curve when it is a straight line
-          
-          last_cx = next_cx;
-          last_cy = next_cy;
-          
-        } // for edge
-        
-        the_path->curve3(last_cx, last_cy, current_path.m_ax*scale, 
current_path.m_ay*scale);      
-        // TODO: Do not add a curve when it is a straight line
-
-      }
-                              
-    } // for path
-    
-    
-    /*
-    Ok, now we have prepared all the paths for all fill styles. Note that AGG
-    won't render curves unless we use conv_curve. The next step is to feed the
-    single paths to AGG with the right color.
-    Some paths may be empty (unused fill styles).    
-    */
-    
-    for (fillidx=0; fillidx<fill_styles.size(); fillidx++) {
-    
-      agg::conv_curve< agg::path_storage > curve(agg_paths[fillidx]);
-    
-      log_msg("  drawing fill style #%d ...\n", fillidx);     
-    
-      color = fill_styles[fillidx].get_color();
-      
-      log_msg("    color is R/G/B/A %d/%d/%d/%d\n", 
-        color.m_r, color.m_g, color.m_b, color.m_a);
-      
-      ren_sl.color(agg::rgba8(color.m_r, color.m_g, color.m_b, color.m_a));    
-          
-      ras.add_path(curve);
-    
-      agg::render_scanlines(ras, sl, ren_sl);
-      usleep(1000000);
-     }
-     
-      
-  }    // draw_shape_character_old
-
-  
   void world_to_pixel(int *x, int *y, const float world_x, const float 
world_y) 
   {
     *x = (int) (world_x * scale);
@@ -1440,6 +1343,11 @@
   int m_clip_xmax;
   int m_clip_ymax;
   
+  // this flag is set while a mask is drawn
+  bool m_drawing_mask; 
+  
+  // Alpha mask stack
+  std::vector< agg_alpha_mask* > m_alpha_mask;
 };     // end class render_handler_agg
 
 

Index: backend/render_handler_agg_style.h
===================================================================
RCS file: /cvsroot/gnash/gnash/backend/render_handler_agg_style.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- backend/render_handler_agg_style.h  29 Oct 2006 18:34:17 -0000      1.6
+++ backend/render_handler_agg_style.h  31 Oct 2006 08:54:23 -0000      1.7
@@ -634,6 +634,46 @@
 };  // class agg_style_handler
 
 
+
+class agg_mask_style_handler 
+{
+public:
+
+  agg_mask_style_handler() :
+    m_color(255,255)
+  {
+  }
+
+  bool is_solid(unsigned style) const
+  {
+    return true;
+  }
+  
+  const agg::gray8& color(unsigned style) const 
+  {
+    return m_color;
+  }
+  
+  #if 0
+  void generate_span(agg::gray8* span, int x, int y, int len, unsigned style)
+  {
+    log_msg("  -- generate_span(%p, %d, %d, %d, %d);", span, x, y, len, style);
+    span->v=255;
+    span->a=255;
+  }
+  #else
+  void generate_span(agg::gray8* /*span*/, int /*x*/, int /*y*/, int /*len*/, 
unsigned /*style*/)
+  {
+    assert(0); // never call generate_span for solid fill styles
+  }
+  #endif
+
+private:
+  agg::gray8 m_color;
+  
+};  // class agg_mask_style_handler
+
+
 } // namespace gnash
 
 #endif // BACKEND_RENDER_HANDLER_AGG_STYLE_H




reply via email to

[Prev in Thread] Current Thread [Next in Thread]