[Top][All Lists]
[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