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 ... [relea


From: Markus Gothe
Subject: [Gnash-commit] gnash ChangeLog backend/render_handler_agg.cpp ... [release_0_7_2]
Date: Tue, 31 Oct 2006 09:34:22 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Branch:         release_0_7_2
Changes by:     Markus Gothe <nihilus>  06/10/31 09:34:22

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

Log message:
        2006-10-31 Udo Giacomozzi <address@hidden>
        
                * backend/render_handler_agg.cpp, 
                  backend/render_handler_agg_style.h: Implemented masks for 
                  AGG renderer

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&only_with_tag=release_0_7_2&r1=1.1412.2.18&r2=1.1412.2.19
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg.cpp?cvsroot=gnash&only_with_tag=release_0_7_2&r1=1.29.2.1&r2=1.29.2.2
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg_style.h?cvsroot=gnash&only_with_tag=release_0_7_2&r1=1.3.2.1&r2=1.3.2.2

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.1412.2.18
retrieving revision 1.1412.2.19
diff -u -b -r1.1412.2.18 -r1.1412.2.19
--- ChangeLog   31 Oct 2006 08:00:53 -0000      1.1412.2.18
+++ ChangeLog   31 Oct 2006 09:34:22 -0000      1.1412.2.19
@@ -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: /sources/gnash/gnash/backend/render_handler_agg.cpp,v
retrieving revision 1.29.2.1
retrieving revision 1.29.2.2
diff -u -b -r1.29.2.1 -r1.29.2.2
--- backend/render_handler_agg.cpp      30 Oct 2006 14:28:46 -0000      1.29.2.1
+++ backend/render_handler_agg.cpp      31 Oct 2006 09:34:22 -0000      1.29.2.2
@@ -16,7 +16,7 @@
 
  
 
-/* $Id: render_handler_agg.cpp,v 1.29.2.1 2006/10/30 14:28:46 rsavoye Exp $ */
+/* $Id: render_handler_agg.cpp,v 1.29.2.2 2006/10/31 09:34:22 nihilus Exp $ */
 
 // Original version by Udo Giacomozzi and Hannes Mayr, 
 // INDUNET GmbH (www.indunet.it)
@@ -28,14 +28,18 @@
 /// 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
-    patterns          NOT IMPLEMENTED (seems like Gnash does not support them 
yet)
+    patterns          don't exist (they're converted at compile time by Flash!)
     widths            COMPLETE
     colors, alpha     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
 
@@ -98,6 +136,7 @@
 #include <agg_conv_transform.h>
 #include <agg_trans_affine.h>
 #include <agg_scanline_u.h>
+#include <agg_scanline_bin.h>
 #include <agg_scanline_p.h>
 #include <agg_renderer_scanline.h>
 // must only include if render_scanlines_compound_layered is not defined
@@ -123,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"
@@ -136,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 
@@ -171,6 +201,98 @@
 
 
 
+// --- YUV VIDEO 
---------------------------------------------------------------
+// Currently not implemented.
+
+class agg_YUV_video : public gnash::YUV_video
+{
+public:
+
+  agg_YUV_video(int width, int height): YUV_video(width, height)
+  {
+    log_msg("warning: YUV_video not supported by AGG renderer");
+  }
+  
+  ~agg_YUV_video() {
+  }
+  
+}; // 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;
+};
 
 
 
@@ -278,6 +400,17 @@
        }
 
 
+       gnash::YUV_video*       create_YUV_video(int w, int h)
+       {         
+         return new agg_YUV_video(w, h);
+  }
+  
+  void delete_YUV_video(gnash::YUV_video* yuv)
+       {
+         if (yuv) delete yuv;
+       }
+
+
   // Constructor
   render_handler_agg(int bits_per_pixel)
   {
@@ -361,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() {
@@ -372,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
        }
 
@@ -466,225 +611,29 @@
 
   void begin_submit_mask()
        {
-    // not implemented
-       }
-
-  void end_submit_mask()
-       {
-    // not implemented
-       }
-
-  void disable_mask()
-       {
-    // not implemented
-       }
-       
-
-
-  /*
-   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;
+         // Set flag so that rendering of shapes is simplified (only solid 
fill) 
+    m_drawing_mask = true;
         
-        // 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++) {
+    agg_alpha_mask* new_mask = new agg_alpha_mask(xres, yres); 
         
-          path &cp = paths_out[ono];
-          edge &last_edge = cp.m_edges.back();
+    m_alpha_mask.push_back(new_mask);
           
-          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   
     
-  }
 
 
 
@@ -699,7 +648,8 @@
     need_single_fill_style(color);
 
     // draw the shape
-    draw_shape(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!
   }
@@ -716,10 +666,26 @@
     
     apply_matrix_to_path(def->get_paths(), paths, mat);
     
-    draw_shape(paths, fill_styles, cx, mat, true);
+    if (m_drawing_mask) {
+      
+      // Shape is drawn inside a mask, skip sub-shapes handling and outlines
+      draw_mask_shape(paths, true);      
     
-    draw_outlines(paths, line_styles, cx);
+    } 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
+      // once fill styles get cached, anyway.     
+      const int subshape_count=count_sub_shapes(paths);
+      
+      for (int subshape=0; subshape<subshape_count; subshape++) {
+        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
@@ -769,15 +735,75 @@
   } // apply_matrix
 
 
+
+  /// A shape can have sub-shapes. This can happen when there are multiple
+  /// layers of the same frame count. Flash combines them to one single shape.
+  /// The problem with sub-shapes is, that outlines can be hidden by other
+  /// layers so they must be rendered separately. 
+  unsigned int count_sub_shapes(const std::vector<path> &paths) {
+  
+    int sscount=1;
+    
+    int pcount = paths.size();
+    
+    for (int pno=0; pno<pcount; pno++) {    // skip first path!
+      const path &this_path = paths[pno];
+      
+      if (pno==0) 
+        assert(!this_path.m_new_shape); // this would break draw_XXX
+      
+      if (this_path.m_new_shape)
+        sscount++;
+    }
+    
+    return sscount;
+  }
+  
+
   /// Draws the given path using the given fill style and color transform.
   /// Normally, Flash shapes are drawn using even-odd filling rule. However,
   /// for glyphs non-zero filling rule should be used (even_odd=0).
   /// Note the paths have already been transformed by the matrix and 
   /// 'fillstyle_matrix' is only provided for bitmap transformations. 
-  void draw_shape(const std::vector<path> &paths,
+  /// 'subshape_id' defines which sub-shape should be drawn (-1 means all 
+  /// subshapes)  
+  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. :-)
@@ -789,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<
@@ -818,7 +845,6 @@
       
     // tell AGG what styles are used
     fcount = fill_styles.size();
-    //log_msg("%d fill styles\n", fcount);
     for (fno=0; fno<fcount; fno++) {
     
       bool smooth=false;
@@ -880,11 +906,13 @@
         } 
         
       } // switch
+        
     } // for
     
       
     // push paths to AGG
     pcount = paths.size();
+    int current_subshape = 0; 
 
     for (pno=0; pno<pcount; pno++) {
     
@@ -892,6 +920,14 @@
       agg::path_storage path;
       agg::conv_curve< agg::path_storage > curve(path);
     
+      if (this_path.m_new_shape) 
+        current_subshape++;
+        
+      if ((subshape_id>=0) && (current_subshape!=subshape_id)) {
+        // Skip this path as it is not part of the requested sub-shape.
+        continue;
+      }
+        
       // Tell the rasterizer which styles the following path will use.
       // The good thing is, that it already supports two fill styles out of
       // the box. 
@@ -928,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(const std::vector<path> &paths,
+  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...
@@ -944,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
@@ -958,14 +1145,24 @@
       stroke(curve);  // to get an outline
     
     
+    int current_subshape = 0; 
     pcount = paths.size();   
     for (pno=0; pno<pcount; pno++) {
       
       const path &this_path = paths[pno];
       
+      if (this_path.m_new_shape)
+        current_subshape++;
+        
+      if ((subshape_id>=0) && (current_subshape!=subshape_id)) {
+        // Skip this path as it is not part of the requested sub-shape.
+        continue;
+      }
+      
       if (!this_path.m_line)  
         continue;     // invisible line
         
+        
       const line_style &lstyle = line_styles[this_path.m_line-1];
       rgba color = cx.transform(lstyle.get_color());
       int width = lstyle.get_width();
@@ -1069,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);
@@ -1362,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: /sources/gnash/gnash/backend/render_handler_agg_style.h,v
retrieving revision 1.3.2.1
retrieving revision 1.3.2.2
diff -u -b -r1.3.2.1 -r1.3.2.2
--- backend/render_handler_agg_style.h  30 Oct 2006 14:28:46 -0000      1.3.2.1
+++ backend/render_handler_agg_style.h  31 Oct 2006 09:34:22 -0000      1.3.2.2
@@ -72,10 +72,10 @@
 class image_accessor_clip_transp : public agg::image_accessor_clip<PixelFormat>
 {
 public:
-  image_accessor_clip_transp(const PixelFormat& pixf) : 
-    agg::image_accessor_clip<PixelFormat>::image_accessor_clip(pixf, 
-      agg::rgba8(255, 0, 0, 0))
+  image_accessor_clip_transp(const PixelFormat& pixf)  
   {
+    agg::image_accessor_clip<PixelFormat>::image_accessor_clip(pixf, 
+      agg::rgba8_pre(255, 0, 0, 0).premultiply());
   }
 };
 
@@ -89,6 +89,22 @@
 #define image_accessor_clip_transp agg::image_accessor_clone
 
 
+/// Quick hack to make radial gradients work properly. For some strange reason
+/// the xform matrix leads to incorrect results even if it is the same for
+/// linear gradients (which work). This implementation is sub-optimal because
+/// it adds two addition operations for each pixel(?), so this needs to be
+/// solved in another way (ie. calculate correct matrix)   
+class my_gradient_radial
+{
+  public:
+  static AGG_INLINE int calculate(int x, int y, int d)
+  {
+    x-=512; 
+    y-=512; 
+    return int(sqrt(x*x + y*y));
+  }
+};
+
 /// AGG bitmap fill style. There are quite a few combinations possible and so
 /// the class types are defined outside. The bitmap can be tiled or clipped.
 /// It can have any transformation matrix and color transform. Any pixel format
@@ -215,6 +231,11 @@
   } // agg_style_gradient constructor
 
 
+  virtual ~agg_style_gradient() 
+  {
+  }
+
+
   void generate_span(color_type* span, int x, int y, unsigned len) 
   {
     m_sg.generate(span, x, y, len);
@@ -237,6 +258,9 @@
   // Span allocator
   span_allocator_type m_sa;
   
+  // Transformer
+  agg::trans_affine m_tr;
+  
   // Span interpolator
   interpolator_type m_span_interpolator;
   
@@ -248,9 +272,6 @@
   // Gradient LUT
   color_func_type m_gradient_lut;
   
-  // Transformer
-  agg::trans_affine m_tr;
-  
   // Span generator
   sg_type m_sg;  
 
@@ -569,7 +590,8 @@
       typedef agg::rgba8 color_type;            
       typedef agg::span_allocator<color_type> span_allocator_type;
       typedef agg::span_interpolator_linear<agg::trans_affine> 
interpolator_type;
-      typedef agg::gradient_radial gradient_func_type;
+      //typedef agg::gradient_radial gradient_func_type;
+      typedef my_gradient_radial gradient_func_type;
       typedef gradient_func_type gradient_adaptor_type;
       typedef agg::gradient_lut<agg::color_interpolator<agg::rgba8>, 256> 
color_func_type;
       typedef agg::span_gradient<color_type,
@@ -581,7 +603,7 @@
         interpolator_type, gradient_func_type, gradient_adaptor_type, 
         color_func_type, sg_type> st_type;
       
-      st_type* st = new st_type(fs, mat, cx, 64);       
+      st_type* st = new st_type(fs, mat, cx, 64/2);  // div 2 because of 
my_gradient_radial     
         
       // NOTE: The value 64 is based on the bitmap texture used by other
       // Gnash renderers which is normally 64x64 pixels for linear gradients.  
     
@@ -612,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]