[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash backend/render_handler.h backend/render_h...
From: |
Udo Giacomozzi |
Subject: |
[Gnash-commit] gnash backend/render_handler.h backend/render_h... |
Date: |
Wed, 28 Feb 2007 17:25:26 +0000 |
CVSROOT: /cvsroot/gnash
Module name: gnash
Changes by: Udo Giacomozzi <udog> 07/02/28 17:25:26
Modified files:
backend : render_handler.h render_handler_agg.cpp
gui : fb.cpp fbsup.h gtk.cpp gtksup.h gui.cpp gui.h
gtk_glue_agg.cpp
server : button_character_instance.cpp
button_character_instance.h character.cpp
character.h dlist.cpp dlist.h
edit_text_character.cpp edit_text_character.h
generic_character.cpp generic_character.h
movie_root.cpp movie_root.h render.cpp render.h
sprite_instance.cpp sprite_instance.h
video_stream_instance.cpp
video_stream_instance.h
libgeometry : Makefile.am
testsuite : MovieTester.cpp
testsuite/misc-ming.all: loadMovieTestRunner.cpp
Added files:
libgeometry : snappingrange.h
Log message:
lots of changes in favour of multiple ranges (see ChangeLog)
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler.h?cvsroot=gnash&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg.cpp?cvsroot=gnash&r1=1.61&r2=1.62
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/fb.cpp?cvsroot=gnash&r1=1.26&r2=1.27
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/fbsup.h?cvsroot=gnash&r1=1.16&r2=1.17
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk.cpp?cvsroot=gnash&r1=1.69&r2=1.70
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtksup.h?cvsroot=gnash&r1=1.34&r2=1.35
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gui.cpp?cvsroot=gnash&r1=1.63&r2=1.64
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gui.h?cvsroot=gnash&r1=1.44&r2=1.45
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gtk_glue_agg.cpp?cvsroot=gnash&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button_character_instance.cpp?cvsroot=gnash&r1=1.29&r2=1.30
http://cvs.savannah.gnu.org/viewcvs/gnash/server/button_character_instance.h?cvsroot=gnash&r1=1.12&r2=1.13
http://cvs.savannah.gnu.org/viewcvs/gnash/server/character.cpp?cvsroot=gnash&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/gnash/server/character.h?cvsroot=gnash&r1=1.51&r2=1.52
http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.cpp?cvsroot=gnash&r1=1.50&r2=1.51
http://cvs.savannah.gnu.org/viewcvs/gnash/server/dlist.h?cvsroot=gnash&r1=1.28&r2=1.29
http://cvs.savannah.gnu.org/viewcvs/gnash/server/edit_text_character.cpp?cvsroot=gnash&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/gnash/server/edit_text_character.h?cvsroot=gnash&r1=1.22&r2=1.23
http://cvs.savannah.gnu.org/viewcvs/gnash/server/generic_character.cpp?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/server/generic_character.h?cvsroot=gnash&r1=1.18&r2=1.19
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.cpp?cvsroot=gnash&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/gnash/server/movie_root.h?cvsroot=gnash&r1=1.39&r2=1.40
http://cvs.savannah.gnu.org/viewcvs/gnash/server/render.cpp?cvsroot=gnash&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/gnash/server/render.h?cvsroot=gnash&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.cpp?cvsroot=gnash&r1=1.181&r2=1.182
http://cvs.savannah.gnu.org/viewcvs/gnash/server/sprite_instance.h?cvsroot=gnash&r1=1.72&r2=1.73
http://cvs.savannah.gnu.org/viewcvs/gnash/server/video_stream_instance.cpp?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/server/video_stream_instance.h?cvsroot=gnash&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/gnash/libgeometry/Makefile.am?cvsroot=gnash&r1=1.24&r2=1.25
http://cvs.savannah.gnu.org/viewcvs/gnash/libgeometry/snappingrange.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/MovieTester.cpp?cvsroot=gnash&r1=1.22&r2=1.23
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/misc-ming.all/loadMovieTestRunner.cpp?cvsroot=gnash&r1=1.3&r2=1.4
Patches:
Index: backend/render_handler.h
===================================================================
RCS file: /cvsroot/gnash/gnash/backend/render_handler.h,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- backend/render_handler.h 26 Jan 2007 13:31:29 -0000 1.28
+++ backend/render_handler.h 28 Feb 2007 17:25:25 -0000 1.29
@@ -17,7 +17,7 @@
//
//
-/* $Id: render_handler.h,v 1.28 2007/01/26 13:31:29 strk Exp $ */
+/* $Id: render_handler.h,v 1.29 2007/02/28 17:25:25 udog Exp $ */
#ifndef RENDER_HANDLER_H
#define RENDER_HANDLER_H
@@ -164,6 +164,7 @@
#include "shape_character_def.h"
#include "generic_character.h"
+#include "Range2d.h"
// Forward declarations.
@@ -276,9 +277,21 @@
// implementation is optional
}
+ virtual void set_invalidated_regions(const InvalidatedRanges&
/*ranges*/) {
+ // implementation is optional
+ }
+
/// Converts world coordinates to pixel coordinates
virtual geometry::Range2d<int> world_to_pixel(const rect& worldbounds) = 0;
+ virtual geometry::Range2d<int> world_to_pixel(const
geometry::Range2d<float>& worldbounds) {
+ if ((worldbounds.isNull() || worldbounds.isWorld()))
+ return worldbounds;
+
+ return world_to_pixel(rect(worldbounds.getMinX(),
worldbounds.getMinY(),
+ worldbounds.getMaxX(),
worldbounds.getMaxY()));
+ }
+
/// Bracket the displaying of a frame from a movie.
//
/// Fill the background color, and set up default
@@ -396,7 +409,19 @@
///
/// See also gnash::renderer::bounds_in_clipping_area
///
- virtual bool bounds_in_clipping_area(const rect& /*bounds*/) {
+ virtual bool bounds_in_clipping_area(const rect& bounds) {
+ return bounds_in_clipping_area(bounds.getRange());
+ }
+
+ virtual bool bounds_in_clipping_area(const InvalidatedRanges& ranges) {
+ for (int rno=0; rno<ranges.size(); rno++)
+ if (bounds_in_clipping_area(ranges.getRange(rno)))
+ return true;
+
+ return false;
+ }
+
+ virtual bool bounds_in_clipping_area(const geometry::Range2d<float>&
/*bounds*/) {
return true;
}
Index: backend/render_handler_agg.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/backend/render_handler_agg.cpp,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -b -r1.61 -r1.62
--- backend/render_handler_agg.cpp 23 Feb 2007 09:50:36 -0000 1.61
+++ backend/render_handler_agg.cpp 28 Feb 2007 17:25:25 -0000 1.62
@@ -16,7 +16,7 @@
-/* $Id: render_handler_agg.cpp,v 1.61 2007/02/23 09:50:36 udog Exp $ */
+/* $Id: render_handler_agg.cpp,v 1.62 2007/02/28 17:25:25 udog Exp $ */
// Original version by Udo Giacomozzi and Hannes Mayr,
// INDUNET GmbH (www.indunet.it)
@@ -113,6 +113,8 @@
#endif
+#include <vector>
+
#include "gnash.h"
#include "types.h"
#include "image.h"
@@ -255,7 +257,7 @@
delete [] m_buffer;
}
- void clear(geometry::Range2d<int> region)
+ void clear(const geometry::Range2d<int>& region)
{
if (region.isNull()) return;
assert ( region.isFinite() );
@@ -314,6 +316,8 @@
private:
typedef agg::renderer_base<PixelFormat> renderer_base;
+ typedef agg::conv_stroke< agg::conv_curve< agg::path_storage > > stroke_type;
+
// TODO: Change these!!
unsigned char *memaddr;
int memsize;
@@ -430,8 +434,8 @@
point a;
mat->transform(&a, point(bounds->get_x_min(), bounds->get_y_min()));
- int xpos = round( TWIPS_TO_PIXELS(a.m_x) );
- int ypos = round( TWIPS_TO_PIXELS(a.m_y) );
+ int xpos = (int)round( TWIPS_TO_PIXELS(a.m_x) );
+ int ypos = (int)round( TWIPS_TO_PIXELS(a.m_y) );
// TODO: handle this by only blitting part of the source RGB image.
if (xpos < 0) {
@@ -448,7 +452,7 @@
// for performance purposes. Therefore, we need to use the
// actual image size so we don't copy padding bytes to the Agg
// buffer.
- int frame_width = TWIPS_TO_PIXELS(bounds->width()) * bytes_per_pixel;
+ int frame_width = (int)TWIPS_TO_PIXELS(bounds->width()) *
bytes_per_pixel;
unsigned char* rgbbuf_ptr = frame->m_data;
unsigned char* rgbbuf_end = rgbbuf_ptr + frame_width *
frame->m_height;
@@ -524,8 +528,6 @@
m_pixf = new PixelFormat(m_rbuf);
//m_rbase = new renderer_base(*m_pixf); --> does not work!!??
- _clipbounds.setTo(0, 0, xres, yres);
-
log_msg("initialized AGG buffer <%p>, %d bytes, %dx%d, rowsize is %d
bytes",
mem, size, x, y, row_size);
}
@@ -552,8 +554,8 @@
assert(m_pixf != NULL);
// clear the stage using the background color
- if ( ! _clipbounds.isNull() )
- clear_framebuffer(_clipbounds, agg::rgba8_pre(background_color.m_r,
+ for (unsigned int i=0; i<_clipbounds.size(); i++)
+ clear_framebuffer(_clipbounds[i], agg::rgba8_pre(background_color.m_r,
background_color.m_g, background_color.m_b,
background_color.m_a));
@@ -572,10 +574,11 @@
/// still correct, but slower.
/// This function clears only a certain portion of the screen, while /not/
/// being notably slower for a fullscreen clear.
- void clear_framebuffer(geometry::Range2d<int> region,
+ void clear_framebuffer(const geometry::Range2d<int>& region,
agg::rgba8 color)
{
- unsigned int width = region.width();
+ assert(region.isFinite());
+ unsigned int width = region.width()+1;
if (width < 1)
{
log_warning("clear_framebuffer() called with width=%d",
@@ -589,11 +592,9 @@
region.height());
return;
}
-
- // to be exact, it's one off the max. (?)
unsigned int left=region.getMinX();
for (unsigned int y=region.getMinY(), maxy=region.getMaxY();
- y<maxy; ++y)
+ y<=maxy; ++y)
{
m_pixf->copy_hline(left, y, width, color);
}
@@ -649,28 +650,42 @@
}
+ template <class ras_type>
+ void apply_clip_box(ras_type& ras,
+ const geometry::Range2d<int>& bounds)
+ {
+ assert(bounds.isFinite());
+ ras.clip_box(
+ (double)bounds.getMinX(),
+ (double)bounds.getMinY(),
+ (double)bounds.getMaxX()+1,
+ (double)bounds.getMaxY()+1);
+ }
+
void draw_line_strip(const void* coords, int vertex_count, const rgba color)
// Draw the line strip formed by the sequence of points.
{
assert(m_pixf != NULL);
- if ( _clipbounds.isNull() ) return;
+ if ( _clipbounds.size()==0 ) return;
point pnt;
renderer_base rbase(*m_pixf);
+ typedef agg::rasterizer_scanline_aa<> ras_type;
+
+ ras_type ras;
agg::scanline_p8 sl;
- agg::rasterizer_scanline_aa<> ras;
agg::renderer_scanline_aa_solid<
agg::renderer_base<PixelFormat> > ren_sl(rbase);
- ras.clip_box(
- (double)_clipbounds.getMinX(),
- (double)_clipbounds.getMinY(),
- (double)_clipbounds.getMaxX(),
- (double)_clipbounds.getMaxY());
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++) {
+
+ const geometry::Range2d<int>& bounds = _clipbounds[cno];
+
+ apply_clip_box<ras_type> (ras, bounds);
agg::path_storage path;
agg::conv_stroke<agg::path_storage> stroke(path);
@@ -693,7 +708,10 @@
// Set the color and render the scanlines
ren_sl.color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b,
color.m_a));
+
+
agg::render_scanlines(ras, sl, ren_sl);
+ }
} // draw_line_strip
@@ -721,8 +739,8 @@
agg_alpha_mask* new_mask = new agg_alpha_mask(xres, yres);
- if ( ! _clipbounds.isNull() )
- new_mask->clear(_clipbounds);
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++)
+ new_mask->clear(_clipbounds[cno]);
m_alpha_mask.push_back(new_mask);
@@ -750,24 +768,104 @@
// NOTE: def->get_bound() is NULL for glyphs so we can't check the
// clipping area (bounds_in_clipping_area):
-
// create a new path with the matrix applied
std::vector<path> paths;
apply_matrix_to_path(def->get_paths(), paths, mat);
+ // convert to AGG paths
+ std::vector<agg::path_storage> agg_paths;
+ build_agg_paths(agg_paths, paths);
+
// make sure m_single_fill_styles contains the required color
need_single_fill_style(color);
+ // prepare style handler
+ agg_style_handler sh;
+ build_agg_styles(sh, m_single_fill_styles, mat, m_neutral_cxform);
+
+ // select all clipping ranges.
+ // NOTE: Glyphs are loaded like normal shape definitons, but w/o style
+ // definitons, which unfortunately include shape bounds. So "def" has
+ // no bounds (isNull) and thus select_clipbounds() won't work.
+ // TODO: Find a different solution since it's suboptimal to render in
+ // all clipping bounds.
+ select_all_clipbounds();
+
// draw the shape
if (m_drawing_mask)
draw_mask_shape(paths, false);
else
- draw_shape(-1, paths, m_single_fill_styles, m_neutral_cxform,
- mat, false);
+ draw_shape(-1, paths, agg_paths, sh, false);
// NOTE: Do not use even-odd filling rule for glyphs!
+
+ // clear clipping ranges to ease debugging
+ _clipbounds_selected.clear();
+ }
+
+
+ /// Fills _clipbounds_selected with pointers to _clipbounds members who
+ /// intersect with the given character (transformed by mat). This avoids
+ /// rendering of characters outside a particular clipping range.
+ /// "_clipbounds_selected" is used by draw_shape() and draw_outline()
and
+ /// *must* be initialized prior to using those function.
+ void select_clipbounds(const shape_character_def *def, const matrix&
mat) {
+
+ _clipbounds_selected.clear();
+ _clipbounds_selected.reserve(_clipbounds.size());
+
+ rect ch_bounds = def->get_bound();
+
+ if (ch_bounds.is_null()) {
+ log_msg("warning: select_clipbounds encountered a
character definition "
+ "with null bounds");
+ return;
+ }
+
+ rect bounds;
+ bounds.set_null();
+ bounds.expand_to_transformed_rect(mat, ch_bounds);
+ bounds.scale_x(xscale);
+ bounds.scale_y(yscale);
+
+ const geometry::Range2d<float>& range_float = bounds.getRange();
+
+ assert(range_float.isFinite());
+
+ geometry::Range2d<int> range_int(
+ (int) range_float.getMinX(),
+ (int) range_float.getMinY(),
+ (int) range_float.getMaxX(),
+ (int) range_float.getMaxY()
+ );
+
+
+ int count = _clipbounds.size();
+ for (int cno=0; cno<count; cno++) {
+
+ if (_clipbounds[cno].intersects(bounds.getRange()))
+
_clipbounds_selected.push_back(&_clipbounds[cno]);
+
}
+ /*
+ printf("Selected %d out of %d bounds.\n",
_clipbounds_selected.size(),
+ _clipbounds.size());
+ */
+ }
+
+ void select_all_clipbounds() {
+
+ if (_clipbounds_selected.size() == _clipbounds.size())
+ return; // already all selected
+
+ _clipbounds_selected.clear();
+ _clipbounds_selected.resize(_clipbounds.size());
+
+ int count = _clipbounds.size();
+ for (int cno=0; cno<count; cno++)
+ _clipbounds_selected[cno] = &_clipbounds[cno];
+ }
void draw_shape_character(shape_character_def *def,
const matrix& mat,
@@ -776,9 +874,12 @@
const std::vector<fill_style>& fill_styles,
const std::vector<line_style>& line_styles) {
- std::vector<path> paths;
+ std::vector< path > paths;
+ std::vector< agg::path_storage > agg_paths;
apply_matrix_to_path(def->get_paths(), paths, mat);
+ build_agg_paths(agg_paths, paths);
+
if (m_drawing_mask) {
@@ -787,18 +888,37 @@
} 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.
+ // select ranges
+ select_clipbounds(def, mat);
+
+ if (_clipbounds_selected.empty()) {
+ log_msg("warning: AGG renderer skipping a whole character");
+ return; // nothing to draw!?
+ }
+
+ // prepare fill styles
+ agg_style_handler sh;
+ build_agg_styles(sh, fill_styles, mat, cx);
+
+ /*
+ // prepare strokes
+ std::vector<stroke_type*> strokes;
+ build_agg_strokes(strokes, agg_paths, paths, line_styles, mat);
+ */
+
+ // We need to separate sub-shapes during rendering.
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, mat);
+ draw_shape(subshape, paths, agg_paths, sh, true);
+ draw_outlines(subshape, paths, agg_paths, line_styles, cx, mat);
}
+
} // if not drawing mask
+ // Clear selected clipbounds to ease debugging
+ _clipbounds_selected.clear();
+
} // draw_shape_character
@@ -876,97 +996,94 @@
}
- /// 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.
- /// '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) {
+ /// Transposes Gnash paths to AGG paths, which can be used for both outlines
+ /// and shapes. Subshapes are ignored (ie. all paths are converted).
Converts
+ /// TWIPS to pixels on the fly.
+ void build_agg_paths(std::vector<agg::path_storage>& dest, const
std::vector<path>& paths) {
- if (m_alpha_mask.empty()) {
+ int pcount = paths.size();
- // No mask active, use normal scanline renderer
+ dest.resize(pcount);
- typedef agg::scanline_u8 scanline_type;
+ for (int pno=0; pno<pcount; pno++) {
- scanline_type sl;
+ const gnash::path& this_path = paths[pno];
+ agg::path_storage& new_path = dest[pno];
- draw_shape_impl<scanline_type> (subshape_id, paths, fill_styles, cx,
- fillstyle_matrix, even_odd, sl);
+ new_path.move_to(this_path.m_ax*xscale,
this_path.m_ay*yscale);
- } else {
+ int ecount = this_path.m_edges.size();
- // Mask is active, use alpha mask scanline renderer
+ for (int eno=0; eno<ecount; eno++) {
- typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
+ const edge& this_edge = this_path.m_edges[eno];
- scanline_type sl(m_alpha_mask.back()->get_amask());
+ if (this_edge.is_straight())
+ new_path.line_to(this_edge.m_ax*xscale, this_edge.m_ay*yscale);
+ else
+ new_path.curve3(this_edge.m_cx*xscale, this_edge.m_cy*yscale,
+ this_edge.m_ax*xscale, this_edge.m_ay*yscale);
- 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. :-)
- This is also far better than recomposing the polygons as the rasterizer
- can do everything in one pass and it is also better for adjacent edges
- (anti aliasing).
- Thank to Maxim Shemanarev for providing us such a great tool with AGG...
- */
+ } //build_agg_paths
- assert(m_pixf != NULL);
- assert(!m_drawing_mask);
+ // Builds vector strokes for paths
+ // WARNING 1 : This is not used and will probably be removed soon.
+ // WARNING 2 : Strokes vector returns pointers which are never freed.
+ void build_agg_strokes(std::vector<stroke_type*>& dest,
+ std::vector<agg::path_storage>& agg_paths,
+ const std::vector<path> &paths,
+ const std::vector<line_style> &line_styles,
+ const matrix& linestyle_matrix) {
- if ( _clipbounds.isNull() ) return;
+ assert(0); // should not be used currently
- // Gnash stuff
- int pno, eno, fno;
- int pcount, ecount, fcount;
+ int pcount=paths.size();
+ dest.resize(pcount);
- // AGG stuff
- renderer_base rbase(*m_pixf);
- 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<
- agg::renderer_base<PixelFormat> > ren_sl(rbase); // solid fills
- agg::span_allocator<agg::rgba8> alloc; // span allocator (?)
- agg_style_handler sh; // holds fill style definitions
+ // use avg between x and y scale
+ const float stroke_scale =
+ (linestyle_matrix.get_x_scale() + linestyle_matrix.get_y_scale()) / 2.0f
+ * (xscale+yscale)/2.0f;
+ for (int pno=0; pno<pcount; pno++) {
- rasc.clip_box(
- (double)_clipbounds.getMinX(),
- (double)_clipbounds.getMinY(),
- (double)_clipbounds.getMaxX(),
- (double)_clipbounds.getMaxY());
+ agg::conv_curve<agg::path_storage> curve(agg_paths[pno]);
+ stroke_type* this_stroke = new stroke_type(curve);
- // debug
- int edge_count=0;
+ const gnash::path &this_path_gnash = paths[pno];
- // activate even-odd filling rule
- if (even_odd)
- rasc.filling_rule(agg::fill_even_odd);
+ const line_style& lstyle = line_styles[this_path_gnash.m_line-1];
+
+ int width = lstyle.get_width();
+ if (width==1)
+ this_stroke->width(1);
else
- rasc.filling_rule(agg::fill_non_zero);
+ this_stroke->width(width*stroke_scale);
+
+ this_stroke->attach(curve);
+ this_stroke->line_cap(agg::round_cap);
+ this_stroke->line_join(agg::round_join);
- // tell AGG what styles are used
- fcount = fill_styles.size();
- for (fno=0; fno<fcount; fno++) {
+ dest[pno] = this_stroke;
+
+ }
+
+ }
+
+ // Initializes the internal styles class for AGG renderer
+ void build_agg_styles(agg_style_handler& sh,
+ const std::vector<fill_style>& fill_styles,
+ const matrix& fillstyle_matrix,
+ const cxform& cx) {
+
+ int fcount = fill_styles.size();
+ for (int fno=0; fno<fcount; fno++) {
bool smooth=false;
int fill_type = fill_styles[fno].get_type();
@@ -1030,19 +1147,109 @@
} // for
+ } //build_agg_styles
+
+
+ /// 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
+ /// 'subshape_id' defines which sub-shape should be drawn (-1 means all
+ /// subshapes).
+ /// Note the *coordinates* in "paths" are not used because they are
+ /// already prepared in agg_paths. The (nearly ambiguous) "path"
parameter
+ /// is used to access other properties like fill styles and subshapes.
+ void draw_shape(int subshape_id, const std::vector<path> &paths,
+ const std::vector<agg::path_storage>& agg_paths,
+ agg_style_handler& sh, 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, agg_paths,
+ sh, 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, agg_paths,
+ sh, 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<agg::path_storage>& agg_paths,
+ agg_style_handler& sh, 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. :-)
+ This is also far better than recomposing the polygons as the rasterizer
+ can do everything in one pass and it is also better for adjacent edges
+ (anti aliasing).
+ Thank to Maxim Shemanarev for providing us such a great tool with AGG...
+ */
+
+ assert(m_pixf != NULL);
+
+ assert(!m_drawing_mask);
+
+ if ( _clipbounds.size()==0 ) return;
+
+ // Gnash stuff
+ int pno;
+ int pcount;
+
+ // AGG stuff
+ typedef agg::rasterizer_compound_aa<agg::rasterizer_sl_clip_dbl> ras_type;
+ renderer_base rbase(*m_pixf);
+ ras_type rasc; // flash-like renderer
+ agg::renderer_scanline_aa_solid<
+ agg::renderer_base<PixelFormat> > ren_sl(rbase); // solid fills
+ agg::span_allocator<agg::rgba8> alloc; // span allocator (?)
+
+
+ // activate even-odd filling rule
+ if (even_odd)
+ rasc.filling_rule(agg::fill_even_odd);
+ else
+ rasc.filling_rule(agg::fill_non_zero);
+
+
+ for (unsigned int cno=0; cno<_clipbounds_selected.size();
cno++) {
+
+ const geometry::Range2d<int>* bounds =
_clipbounds_selected[cno];
+
+ apply_clip_box<ras_type> (rasc, *bounds);
+
+ int current_subshape=0;
// push paths to AGG
pcount = paths.size();
- int current_subshape = 0;
- agg::path_storage path;
- agg::conv_curve< agg::path_storage > curve(path);
for (pno=0; pno<pcount; pno++) {
- const gnash::path &this_path = paths[pno];
- path.remove_all();
+ const gnash::path &this_path_gnash = paths[pno];
+ agg::path_storage &this_path_agg =
+
const_cast<agg::path_storage&>(agg_paths[pno]);
+ agg::conv_curve< agg::path_storage > curve(this_path_agg);
- if (this_path.m_new_shape)
+ if (this_path_gnash.m_new_shape)
current_subshape++;
if ((subshape_id>=0) && (current_subshape!=subshape_id)) {
@@ -1050,33 +1257,17 @@
continue;
}
- if ((this_path.m_fill0==0) && (this_path.m_fill1==0)) {
+ if ((this_path_gnash.m_fill0==0) &&
(this_path_gnash.m_fill1==0)) {
// Skip this path as it contains no fill style
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.
// Flash uses value "0" for "no fill", whereas AGG uses "-1" for that.
- rasc.styles(this_path.m_fill0-1, this_path.m_fill1-1);
-
- // starting point of path
- path.move_to(this_path.m_ax*xscale, this_path.m_ay*yscale);
-
- ecount = this_path.m_edges.size();
- edge_count += ecount;
- for (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*xscale, this_edge.m_ay*yscale);
- else
- path.curve3(this_edge.m_cx*xscale, this_edge.m_cy*yscale,
- this_edge.m_ax*xscale, this_edge.m_ay*yscale);
-
- }
+ rasc.styles(this_path_gnash.m_fill0-1, this_path_gnash.m_fill1-1);
// add path to the compound rasterizer
rasc.add_path(curve);
@@ -1084,10 +1275,11 @@
}
//log_msg("%d edges\n", edge_count);
- // render!
+
agg::render_scanlines_compound_layered(rasc, sl, rbase, alloc, sh);
+ }
- } // draw_shape
+ } // draw_shape_impl
@@ -1211,6 +1403,7 @@
/// Just like draw_shapes() except that it draws an outline.
void draw_outlines(int subshape_id, const std::vector<path> &paths,
+ const std::vector<agg::path_storage>& agg_paths,
const std::vector<line_style> &line_styles, const cxform& cx,
const matrix& linestyle_matrix) {
@@ -1222,8 +1415,8 @@
scanline_type sl;
- draw_outlines_impl<scanline_type> (subshape_id, paths, line_styles,
- cx, linestyle_matrix, sl);
+ draw_outlines_impl<scanline_type> (subshape_id, paths, agg_paths,
+ line_styles, cx, linestyle_matrix, sl);
} else {
@@ -1233,17 +1426,18 @@
scanline_type sl(m_alpha_mask.back()->get_amask());
- draw_outlines_impl<scanline_type> (subshape_id, paths, line_styles,
- cx, linestyle_matrix, sl);
+ draw_outlines_impl<scanline_type> (subshape_id, paths, agg_paths,
+ line_styles, cx, linestyle_matrix, sl);
}
- }
+ } //draw_outlines
/// 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<agg::path_storage>& agg_paths,
const std::vector<line_style> &line_styles, const cxform& cx,
const matrix& linestyle_matrix, scanline_type& sl) {
@@ -1252,15 +1446,15 @@
if (m_drawing_mask) // Flash ignores lines in mask /definitions/
return;
- if ( _clipbounds.isNull() ) return;
+ if ( _clipbounds.size()==0 ) 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...
// Gnash stuff
- int pno, eno;
- int pcount, ecount;
+ int pno;
+ int pcount;
// use avg between x and y scale
const float stroke_scale =
@@ -1269,34 +1463,29 @@
// AGG stuff
+ typedef agg::rasterizer_scanline_aa<> ras_type;
+ ras_type ras; // anti alias
renderer_base rbase(*m_pixf);
- agg::rasterizer_scanline_aa<> ras; // anti alias
agg::renderer_scanline_aa_solid<
agg::renderer_base<PixelFormat> > ren_sl(rbase); // solid fills
- agg::path_storage agg_path; // a path in the AGG world
- // TODO: what do do if _clipbox.isNull() or _clipbox.isWorld() ?
- // currently an assertion will fail when get{Min,Max}{X,Y}
- // are called below
- ras.clip_box(
- (double)_clipbounds.getMinX(),
- (double)_clipbounds.getMinY(),
- (double)_clipbounds.getMaxX(),
- (double)_clipbounds.getMaxY());
+ for (unsigned int cno=0; cno<_clipbounds_selected.size();
cno++) {
- agg::conv_curve< agg::path_storage > curve(agg_path); // to render
curves
- agg::conv_stroke< agg::conv_curve < agg::path_storage > >
- stroke(curve); // to get an outline
+ const geometry::Range2d<int>* bounds =
_clipbounds_selected[cno];
+
+ apply_clip_box<ras_type> (ras, *bounds);
+ int current_subshape=0;
- int current_subshape = 0;
pcount = paths.size();
for (pno=0; pno<pcount; pno++) {
- const path &this_path = paths[pno];
+ const gnash::path& this_path_gnash = paths[pno];
+ agg::path_storage &this_path_agg =
+
const_cast<agg::path_storage&>(agg_paths[pno]);
- if (this_path.m_new_shape)
+ if (this_path_gnash.m_new_shape)
current_subshape++;
if ((subshape_id>=0) && (current_subshape!=subshape_id)) {
@@ -1304,48 +1493,40 @@
continue;
}
- if (!this_path.m_line)
- continue; // invisible line
+ if (this_path_gnash.m_line==0) {
+ // Skip this path as it contains no line style
+ continue;
+ }
+ agg::conv_curve< agg::path_storage > curve(this_path_agg); // to
render curves
+ agg::conv_stroke< agg::conv_curve < agg::path_storage > >
+ stroke(curve); // to get an outline
+
+ const line_style& lstyle = line_styles[this_path_gnash.m_line-1];
- const line_style &lstyle = line_styles[this_path.m_line-1];
- rgba color = cx.transform(lstyle.get_color());
int width = lstyle.get_width();
if (width==1)
stroke.width(1);
else
stroke.width(width*stroke_scale);
+
stroke.line_cap(agg::round_cap);
stroke.line_join(agg::round_join);
-
- agg_path.remove_all(); // clear path
-
- agg_path.move_to(this_path.m_ax*xscale, this_path.m_ay*yscale);
-
- ecount = this_path.m_edges.size();
- for (eno=0; eno<ecount; eno++) {
-
- const edge &this_edge = this_path.m_edges[eno];
-
- if (this_edge.is_straight())
- agg_path.line_to(this_edge.m_ax*xscale, this_edge.m_ay*yscale);
- else
- agg_path.curve3(this_edge.m_cx*yscale, this_edge.m_cy*yscale,
- this_edge.m_ax*yscale, this_edge.m_ay*yscale);
-
- } // for edges
-
-
+ ras.reset();
ras.add_path(stroke);
+
+ rgba color = cx.transform(lstyle.get_color());
ren_sl.color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b, color.m_a));
agg::render_scanlines(ras, sl, ren_sl);
+ }
+
}
- } // draw_outlines
+ } // draw_outlines_impl
@@ -1357,26 +1538,27 @@
if (corner_count<1) return;
- if ( _clipbounds.isNull() ) return;
+ if ( _clipbounds.size()==0 ) return;
// TODO: Use aliased scanline renderer instead of anti-aliased one since
// it is undesired anyway.
+ typedef agg::rasterizer_scanline_aa<> ras_type;
renderer_base rbase(*m_pixf);
agg::scanline_p8 sl;
- agg::rasterizer_scanline_aa<> ras;
+ ras_type ras;
agg::renderer_scanline_aa_solid<
agg::renderer_base<PixelFormat> > ren_sl(rbase);
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++) {
+
+ const geometry::Range2d<int>& bounds = _clipbounds[cno];
+
+ apply_clip_box<ras_type> (ras, bounds);
+
// TODO: what do do if _clipbox.isNull() or _clipbox.isWorld() ?
// currently an assertion will fail when get{Min,Max}{X,Y}
// are called below
- ras.clip_box(
- (double)_clipbounds.getMinX(),
- (double)_clipbounds.getMinY(),
- (double)_clipbounds.getMaxX(),
- (double)_clipbounds.getMaxY());
-
agg::path_storage path;
point pnt, origin;
@@ -1401,6 +1583,7 @@
if (fill.m_a>0) {
ras.add_path(path);
ren_sl.color(agg::rgba8_pre(fill.m_r, fill.m_g, fill.m_b, fill.m_a));
+
agg::render_scanlines(ras, sl, ren_sl);
}
@@ -1413,8 +1596,10 @@
ren_sl.color(agg::rgba8_pre(outline.m_r, outline.m_g, outline.m_b,
outline.m_a));
ras.add_path(stroke);
+
agg::render_scanlines(ras, sl, ren_sl);
}
+ }
}
@@ -1444,31 +1629,72 @@
return Range2d<int>(xmin, ymin, xmax, ymax);
}
+ geometry::Range2d<int> world_to_pixel(const geometry::Range2d<float>& wb)
+ {
+ if (wb.isNull() || wb.isWorld()) return wb;
+
+ int xmin, ymin, xmax, ymax;
+
+ world_to_pixel(xmin, ymin, wb.getMinX(), wb.getMinY());
+ world_to_pixel(xmax, ymax, wb.getMaxX(), wb.getMaxY());
+
+ return geometry::Range2d<int>(xmin, ymin, xmax, ymax);
+ }
virtual void set_invalidated_region(const rect& bounds) {
+ // NOTE: Both single and multi ranges are supported by AGG
renderer.
+
+ InvalidatedRanges ranges;
+ ranges.add(bounds.getRange());
+ set_invalidated_regions(ranges);
+
+ }
+
+ virtual void set_invalidated_regions(const InvalidatedRanges& ranges) {
using gnash::geometry::Range2d;
- Range2d<int> pixbounds = world_to_pixel(bounds);
+ int count=0;
- // add 2 pixels (GUI does that too)
- pixbounds.growBy(2);
+ _clipbounds_selected.clear();
+ _clipbounds.clear();
// TODO: cache 'visiblerect' and maintain in sync with
// xres/yres.
Range2d<int> visiblerect(0, 0, xres, yres);
- _clipbounds = Intersection(pixbounds, visiblerect);
+ for (int rno=0; rno<ranges.size(); rno++) {
+
+ const Range2d<float>& range = ranges.getRange(rno);
+
+ Range2d<int> pixbounds = world_to_pixel(range);
+
+ geometry::Range2d<int> bounds = Intersection(pixbounds,
visiblerect);
+
+ if (bounds.isNull()) continue; // out of screen
+
+ assert(bounds.isFinite());
+
+ _clipbounds.push_back(bounds);
+
+ count++;
+ }
+ //log_msg("%d inv. bounds in frame", count);
}
- virtual bool bounds_in_clipping_area(const rect& bounds) {
- int bxmin, bxmax, bymin, bymax;
+
+ virtual bool bounds_in_clipping_area(const geometry::Range2d<float>& bounds)
{
using gnash::geometry::Range2d;
Range2d<int> pixbounds = world_to_pixel(bounds);
- return Intersect(pixbounds, _clipbounds);
+
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++) {
+ if (Intersect(pixbounds, _clipbounds[cno]))
+ return true;
+ }
+ return false;
}
void get_pixel(rgba& color_return, float world_x, float world_y) {
@@ -1515,7 +1741,8 @@
PixelFormat *m_pixf;
/// clipping rectangle
- geometry::Range2d<int> _clipbounds;
+ std::vector< geometry::Range2d<int> > _clipbounds;
+ std::vector< geometry::Range2d<int>* > _clipbounds_selected;
// this flag is set while a mask is drawn
bool m_drawing_mask;
Index: gui/fb.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/fb.cpp,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -b -r1.26 -r1.27
--- gui/fb.cpp 22 Feb 2007 14:04:42 -0000 1.26
+++ gui/fb.cpp 28 Feb 2007 17:25:25 -0000 1.27
@@ -41,7 +41,7 @@
#include "render_handler.h"
#include "render_handler_agg.h"
-//#define DEBUG_SHOW_FPS // prints number of frames per second to STDOUT
+#define DEBUG_SHOW_FPS // prints number of frames per second to STDOUT
#ifdef DEBUG_SHOW_FPS
# include <sys/types.h>
@@ -365,9 +365,7 @@
void FBGui::renderBuffer()
{
- if ( _drawbounds.isNull() ) return; // nothing to do..
-
- assert ( ! _drawbounds.isWorld() );
+ if ( _drawbounds.size() == 0 ) return; // nothing to do..
#ifdef DOUBLE_BUFFER
@@ -379,24 +377,29 @@
const unsigned int scanline_size =
var_screeninfo.xres * pixel_size;
+
+ for (int bno=0; bno < _drawbounds.size(); bno++) {
+
+ geometry::Range2d<int>& bounds = _drawbounds[bno];
+
+ assert ( ! bounds.isWorld() );
+
// Size, in bytes, of a row that has to be copied
- const unsigned int row_size = _drawbounds.width() * pixel_size;
+ const unsigned int row_size = (bounds.width()+1) * pixel_size;
// copy each row
- const int minx = _drawbounds.getMinX();
- const int maxy = _drawbounds.getMaxY();
+ const int minx = bounds.getMinX();
+ const int maxy = bounds.getMaxY();
- for (int y=_drawbounds.getMinY(); y<maxy; ++y) {
+ for (int y=bounds.getMinY(); y<=maxy; ++y) {
const unsigned int pixel_index = y * scanline_size + minx*pixel_size;
memcpy(&fbmem[pixel_index], &buffer[pixel_index], row_size);
}
+ }
-
- /*memcpy(fbmem, buffer, var_screeninfo.xres*var_screeninfo.yres*
- (var_screeninfo.bits_per_pixel/8));*/
#endif
#ifdef DEBUG_SHOW_FPS
@@ -446,24 +449,27 @@
return y;
}
-void FBGui::setInvalidatedRegion(const rect& bounds)
+void FBGui::setInvalidatedRegions(const InvalidatedRanges& ranges)
{
+ _renderer->set_invalidated_regions(ranges);
-#ifdef DOUBLE_BUFFER
+ _drawbounds.clear();
- // forward to renderer
- _renderer->set_invalidated_region(bounds);
+ for (int rno=0; rno<ranges.size(); rno++) {
- // update _drawbounds, which are the bounds that need to
- // be rerendered
- //
- _drawbounds = Intersection(
- _renderer->world_to_pixel(bounds).growBy(2), // add two pixels because of
anti-aliasing...
+ geometry::Range2d<int> bounds = Intersection(
+ _renderer->world_to_pixel(ranges.getRange(rno)),
_validbounds);
-#endif
+ // it may happen that a particular range is out of the screen,
which
+ // will lead to bounds==null.
+ if (bounds.isNull()) continue;
+
+ _drawbounds.push_back(bounds);
-} // setInvalidatedRegion
+ }
+
+}
void FBGui::disable_terminal()
{
Index: gui/fbsup.h
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/fbsup.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -b -r1.16 -r1.17
--- gui/fbsup.h 19 Feb 2007 18:15:35 -0000 1.16
+++ gui/fbsup.h 28 Feb 2007 17:25:25 -0000 1.17
@@ -24,6 +24,8 @@
#include "config.h"
#endif
+#include <vector>
+
#include "gui.h"
#include <linux/fb.h>
@@ -42,11 +44,11 @@
// Define this to read from /dev/input/mice (any PS/2 compatbile mouse or
// emulated by the Kernel)
-#define USE_MOUSE_PS2
+//#define USE_MOUSE_PS2
// Define this to support eTurboTouch / eGalax touchscreens. When reading from
// a serial device, it must be initialized (stty) externally.
-//#define USE_MOUSE_ETT
+#define USE_MOUSE_ETT
#ifdef USE_MOUSE_PS2
#define MOUSE_DEVICE "/dev/input/mice"
@@ -110,7 +112,7 @@
unsigned char *buffer; // offscreen buffer
#endif
- geometry::Range2d<int> _drawbounds;
+ std::vector< geometry::Range2d<int> > _drawbounds;
int m_stage_width;
int m_stage_height;
@@ -167,7 +169,8 @@
virtual void setInterval(unsigned int interval);
virtual void setTimeout(unsigned int timeout);
- virtual void setInvalidatedRegion(const rect& bounds);
+ virtual void setInvalidatedRegions(const InvalidatedRanges& ranges);
+ virtual bool want_multiple_regions() { return true; }
};
// end of namespace gnash
Index: gui/gtk.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gtk.cpp,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -b -r1.69 -r1.70
--- gui/gtk.cpp 28 Feb 2007 04:27:59 -0000 1.69
+++ gui/gtk.cpp 28 Feb 2007 17:25:25 -0000 1.70
@@ -17,7 +17,7 @@
//
//
-/* $Id: gtk.cpp,v 1.69 2007/02/28 04:27:59 nihilus Exp $ */
+/* $Id: gtk.cpp,v 1.70 2007/02/28 17:25:25 udog Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -61,8 +61,7 @@
GtkGui::GtkGui(unsigned long xid, float scale, bool loop, unsigned int depth)
:
- Gui(xid, scale, loop, depth),
- _drawbounds(0, 0, 0, 0)
+ Gui(xid, scale, loop, depth)
{
}
@@ -235,7 +234,6 @@
_height = height;
_validbounds.setTo(0, 0, _width, _height);
- _drawbounds = _validbounds;
glue.setRenderHandlerSize(_width, _height);
@@ -245,16 +243,24 @@
void
GtkGui::renderBuffer()
{
- if ( _drawbounds.isNull() ) return;
- assert ( ! _drawbounds.isWorld() );
- glue.render(_drawbounds.getMinX(), _drawbounds.getMinY(),
- _drawbounds.getMaxX(), _drawbounds.getMaxY());
+ if ( _drawbounds.size() == 0 ) return; // nothing to do..
+
+ for (int bno=0; bno < _drawbounds.size(); bno++) {
+
+ geometry::Range2d<int>& bounds = _drawbounds[bno];
+
+ assert ( bounds.isFinite() );
+
+ glue.render(bounds.getMinX(), bounds.getMinY(),
+ bounds.getMaxX(), bounds.getMaxY());
+
+ }
}
+#ifdef RENDERER_AGG
void
-GtkGui::setInvalidatedRegion(const rect& bounds)
+GtkGui::setInvalidatedRegions(const InvalidatedRanges& ranges)
{
-#ifdef RENDERER_AGG
// forward to renderer
//
// Why? Why have the region been invalidated ??
@@ -266,18 +272,28 @@
// To be safe just assume this 'invalidated' region is actually
// the offscreen buffer, for safety, but we need to clarify this.
//
- _renderer->set_invalidated_region(bounds);
+ _renderer->set_invalidated_regions(ranges);
- // update _drawbounds, which are the bounds that need to
- // be rerendered (??)
- //
- _drawbounds = Intersection(
- // add two pixels because of anti-aliasing...
- _renderer->world_to_pixel(bounds).growBy(2),
+ _drawbounds.clear();
+
+ for (int rno=0; rno<ranges.size(); rno++) {
+
+ geometry::Range2d<int> bounds = Intersection(
+ _renderer->world_to_pixel(ranges.getRange(rno)),
_validbounds);
-#endif
+ // it may happen that a particular range is out of the screen,
which
+ // will lead to bounds==null.
+ if (bounds.isNull()) continue;
+
+ assert(bounds.isFinite());
+
+ _drawbounds.push_back(bounds);
+
+ }
+
}
+#endif
void
GtkGui::setTimeout(unsigned int timeout)
Index: gui/gtksup.h
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gtksup.h,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -b -r1.34 -r1.35
--- gui/gtksup.h 31 Jan 2007 15:24:13 -0000 1.34
+++ gui/gtksup.h 28 Feb 2007 17:25:25 -0000 1.35
@@ -131,7 +131,10 @@
GdkPixbuf* create_pixbuf(const gchar *filename);
- void setInvalidatedRegion(const rect& bounds);
+#ifdef RENDERER_AGG
+ void setInvalidatedRegions(const InvalidatedRanges& ranges);
+ bool want_multiple_regions() { return true; }
+#endif
virtual void setCursor(gnash_cursor_type newcursor);
@@ -142,7 +145,8 @@
GtkMenu *_popup_menu;
GtkWidget *_menubar;
GtkWidget *_vbox;
- geometry::Range2d<int> _drawbounds;
+ //geometry::Range2d<int> _drawbounds;
+ std::vector< geometry::Range2d<int> > _drawbounds;
#ifdef RENDERER_CAIRO
cairo_t *_cairo_handle;
Index: gui/gui.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gui.cpp,v
retrieving revision 1.63
retrieving revision 1.64
diff -u -b -r1.63 -r1.64
--- gui/gui.cpp 27 Feb 2007 09:54:49 -0000 1.63
+++ gui/gui.cpp 28 Feb 2007 17:25:25 -0000 1.64
@@ -46,7 +46,7 @@
/// debug the GUI part, however (see if blitting the region works), then you
/// probably won't define this.
#ifdef ENABLE_REGION_UPDATES_DEBUGGING
-#define REGION_UPDATES_DEBUGGING_FULL_REDRAW 1
+//#define REGION_UPDATES_DEBUGGING_FULL_REDRAW 1
#endif
#ifdef ENABLE_REGION_UPDATES_DEBUGGING
@@ -275,7 +275,7 @@
Gui::display(movie_root* m)
{
- rect changed_bounds; // area of the stage that must be updated
+ InvalidatedRanges changed_ranges;
bool redraw_flag;
// Should the frame be rendered completely, even if it did not change?
@@ -289,18 +289,34 @@
// due to ActionScript code, the timeline or user events. The GUI can
still
// choose to render a different part of the stage.
//
- // TODO: is it needed to call get_invalidated_bounds even when
redraw_flag is true ??
- //
- m->get_invalidated_bounds(&changed_bounds, false);
+ if (!redraw_flag) {
+
+ // Choose distance (note these are TWIPS!)
+ // 10% of normalized stage size
+ changed_ranges.snap_distance = sqrt(
+ m->get_movie_definition()->get_width_pixels() * 20.0 *
+ m->get_movie_definition()->get_height_pixels() * 20.0)
* 0.10;
+
+ // Use multi ranges only when GUI/Renderer supports it
+ // (Useless CPU overhead, otherwise)
+ changed_ranges.single_mode = !want_multiple_regions();
+
+ // scan through all sprites to compute invalidated bounds
+ m->add_invalidated_bounds(changed_ranges, false);
+
+ // optimize ranges
+ changed_ranges.combine_ranges();
+
+ }
if (redraw_flag) // TODO: Remove this and want_redraw to avoid
confusion!?
{
- changed_bounds.set_world();
+ changed_ranges.setWorld();
}
// Avoid drawing of stopped movies
- if ( ! changed_bounds.is_null() ) // use 'else'?
+ if ( ! changed_ranges.isNull() ) // use 'else'?
{
// Tell the GUI(!) that we only need to update this
// region. Note the GUI can do whatever it wants with
@@ -313,10 +329,11 @@
// redraw the full screen so that only the
// *new* invalidated region is visible
// (helps debugging)
- rect worldregion; worldregion.set_world();
- setInvalidatedRegion(worldregion);
+ InvalidatedRanges world_ranges;
+ world_ranges.setWorld();
+ setInvalidatedRegions(world_ranges);
#else
- setInvalidatedRegion(changed_bounds);
+ setInvalidatedRegions(changed_ranges);
#endif
// render the frame.
@@ -327,13 +344,18 @@
// show invalidated region using a red rectangle
// (Flash debug style)
IF_DEBUG_REGION_UPDATES (
- if ( ! changed_bounds.is_world() )
+ if ( ! changed_ranges.isWorld() )
{
+
+ for (int rno=0; rno<changed_ranges.size(); rno++) {
+
+ geometry::Range2d<float> bounds =
changed_ranges.getRange(rno);
+
point corners[4];
- float xmin = changed_bounds.get_x_min();
- float xmax = changed_bounds.get_x_max();
- float ymin = changed_bounds.get_y_min();
- float ymax = changed_bounds.get_y_max();
+ float xmin = bounds.getMinX();
+ float xmax = bounds.getMaxX();
+ float ymin = bounds.getMinY();
+ float ymax = bounds.getMaxY();
corners[0].m_x = xmin;
corners[0].m_y = ymin;
@@ -347,6 +369,8 @@
gnash::render::set_matrix(dummy); // reset matrix
gnash::render::draw_poly(&corners[0], 4,
rgba(0,0,0,0), rgba(255,0,0,255));
+
+ }
}
);
@@ -429,10 +453,28 @@
}
void
-Gui::setInvalidatedRegion (const rect& bounds)
+Gui::setInvalidatedRegion(const rect& bounds)
+{
+}
+
+void
+Gui::setInvalidatedRegions(const InvalidatedRanges& ranges)
{
+ // fallback to single regions
+ geometry::Range2d<float> full = ranges.getFullArea();
+
+ rect bounds;
+
+ if (full.isFinite())
+ bounds = rect(full.getMinX(), full.getMinY(), full.getMaxX(),
full.getMaxY());
+ else
+ if (full.isWorld())
+ bounds.set_world();
+
+ setInvalidatedRegion(bounds);
}
+
// end of namespace
}
Index: gui/gui.h
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gui.h,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -b -r1.44 -r1.45
--- gui/gui.h 31 Jan 2007 15:24:13 -0000 1.44
+++ gui/gui.h 28 Feb 2007 17:25:25 -0000 1.45
@@ -26,6 +26,7 @@
#include "tu_config.h"
#include "rect.h" // for composition
+#include "snappingrange.h" // for InvalidatedRanges
#include <string>
@@ -134,7 +135,13 @@
// coordinate space, which is integer values...
// The question really is: why floats for TWIPS ?
// (guess this goes deep in the core/server libs)
+ //
virtual void setInvalidatedRegion(const rect& bounds);
+ virtual void setInvalidatedRegions(const InvalidatedRanges& ranges);
+
+ // Should return TRUE when the GUI/Renderer combination supports multiple
+ // invalidated bounds regions.
+ virtual bool want_multiple_regions() { return false; }
/// Asks the GUI handler if the next frame should be redrawn completely.
//
Index: gui/gtk_glue_agg.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/gui/gtk_glue_agg.cpp,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- gui/gtk_glue_agg.cpp 31 Jan 2007 15:24:13 -0000 1.12
+++ gui/gtk_glue_agg.cpp 28 Feb 2007 17:25:25 -0000 1.13
@@ -17,7 +17,7 @@
//
//
-/* $Id: gtk_glue_agg.cpp,v 1.12 2007/01/31 15:24:13 bjacques Exp $ */
+/* $Id: gtk_glue_agg.cpp,v 1.13 2007/02/28 17:25:25 udog Exp $ */
#include <cstdio>
#include <cerrno>
@@ -151,8 +151,8 @@
_drawing_area->style->fg_gc[GTK_STATE_NORMAL],
minx,
miny,
- maxx-minx,
- maxy-miny,
+ maxx-minx+1,
+ maxy-miny+1,
GDK_RGB_DITHER_NORMAL,
_offscreenbuf + miny*(_width*(_bpp/8)) + minx*(_bpp/8),
(int)((_width)*_bpp/8)
Index: server/button_character_instance.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/button_character_instance.cpp,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -b -r1.29 -r1.30
--- server/button_character_instance.cpp 20 Feb 2007 10:00:48 -0000
1.29
+++ server/button_character_instance.cpp 28 Feb 2007 17:25:25 -0000
1.30
@@ -635,12 +635,14 @@
//
+
void
-button_character_instance::get_invalidated_bounds(rect* bounds, bool force)
+button_character_instance::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool force)
{
if (!m_visible) return; // not visible anyway
- bounds->expand_to_rect(m_old_invalidated_bounds);
+ ranges.add(m_old_invalidated_ranges);
// TODO: Instead of using these for loops again and again, wouldn't it be a
// good idea to have a generic "get_record_character()" method?
@@ -657,10 +659,11 @@
{
/*bounds->expand_to_transformed_rect(get_world_matrix(),
m_record_character[i]->get_bound());*/
- m_record_character[i]->get_invalidated_bounds(bounds,
+ m_record_character[i]->add_invalidated_bounds(ranges,
force||m_invalidated);
}
}
+
}
float
Index: server/button_character_instance.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/button_character_instance.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -b -r1.12 -r1.13
--- server/button_character_instance.h 27 Feb 2007 09:10:20 -0000 1.12
+++ server/button_character_instance.h 28 Feb 2007 17:25:25 -0000 1.13
@@ -5,7 +5,7 @@
// SWF buttons. Mouse-sensitive update/display, actions, etc.
-/* $Id: button_character_instance.h,v 1.12 2007/02/27 09:10:20 strk Exp $ */
+/* $Id: button_character_instance.h,v 1.13 2007/02/28 17:25:25 udog Exp $ */
#ifndef GNASH_BUTTON_CHARACTER_INSTANCE_H
#define GNASH_BUTTON_CHARACTER_INSTANCE_H
@@ -101,7 +101,7 @@
// ActionScript overrides
//
- void get_invalidated_bounds(rect* bounds, bool force);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
// not sure if we need to override this one.
Index: server/character.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/character.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- server/character.cpp 22 Feb 2007 17:25:25 -0000 1.21
+++ server/character.cpp 28 Feb 2007 17:25:25 -0000 1.22
@@ -18,7 +18,7 @@
//
//
-/* $Id: character.cpp,v 1.21 2007/02/22 17:25:25 udog Exp $ */
+/* $Id: character.cpp,v 1.22 2007/02/28 17:25:25 udog Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -187,8 +187,19 @@
if ( ! m_invalidated )
{
m_invalidated = true;
- m_old_invalidated_bounds.set_null();
- get_invalidated_bounds(&m_old_invalidated_bounds, true);
+
+ // NOTE: we need to set snap_distance in order to avoid too
tight
+ // invalidated ranges. The GUI chooses the appropriate distance
in base
+ // of various parameters but for this internal ranges list we
don't know
+ // that value. So we set snap_distance to some generic value
and hope this
+ // does not produce too many nor too coarse ranges. Note when
calculating
+ // the actual invalidated ranges the correct distance is used
(but there
+ // may be problems when the GUI chooses a smaller value). Needs
to be
+ // fixed.
+ m_old_invalidated_ranges.snap_distance = 200.0;
+
+ m_old_invalidated_ranges.setNull();
+ add_invalidated_bounds(m_old_invalidated_ranges, true);
}
}
Index: server/character.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/character.h,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -b -r1.51 -r1.52
--- server/character.h 22 Feb 2007 17:28:04 -0000 1.51
+++ server/character.h 28 Feb 2007 17:25:25 -0000 1.52
@@ -18,7 +18,7 @@
//
//
-/* $Id: character.h,v 1.51 2007/02/22 17:28:04 udog Exp $ */
+/* $Id: character.h,v 1.52 2007/02/28 17:25:25 udog Exp $ */
#ifndef GNASH_CHARACTER_H
#define GNASH_CHARACTER_H
@@ -36,6 +36,7 @@
#include "rect.h" // for composition (invalidated bounds)
#include "matrix.h" // for composition
#include "log.h"
+#include "snappingrange.h"
#include <map>
#include <cstdarg>
@@ -119,7 +120,7 @@
///
/// NOTE: this is currently initialized as the NULL rectangle.
///
- rect m_old_invalidated_bounds;
+ InvalidatedRanges m_old_invalidated_ranges;
/// Wheter this character has been transformed by ActionScript code
//
@@ -197,13 +198,13 @@
m_parent(parent),
m_invalidated(true),
m_child_invalidated(true),
- m_old_invalidated_bounds(),
+ m_old_invalidated_ranges(),
_scriptTransformed(false),
_dynamicallyCreated(false)
{
assert((parent == NULL && m_id == -1)
|| (parent != NULL && m_id >= 0));
- assert(m_old_invalidated_bounds.is_null());
+ assert(m_old_invalidated_ranges.isNull());
}
/// Return a reference to the variable scope of this character.
@@ -575,13 +576,12 @@
void clear_invalidated() {
m_invalidated = false;
m_child_invalidated = false;
- m_old_invalidated_bounds.set_null();
+ m_old_invalidated_ranges.setNull();
}
/// \brief
- /// Expand the given rectangle to enclose this character's
- /// invalidated bounds.
+ /// Add the character's invalidated bounds to the ranges list.
//
/// NOTE that this method should include the bounds that it
/// covered the last time clear_invalidated() was called,
@@ -593,7 +593,7 @@
/// Only instances with m_invalidated flag set are checked unless
/// force is set.
///
- virtual void get_invalidated_bounds(rect* bounds, bool force) = 0;
+ virtual void add_invalidated_bounds(InvalidatedRanges& ranges, bool
force) = 0;
/// Construct this instance as an ActionScript object.
//
Index: server/dlist.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/dlist.cpp,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -b -r1.50 -r1.51
--- server/dlist.cpp 28 Feb 2007 14:10:25 -0000 1.50
+++ server/dlist.cpp 28 Feb 2007 17:25:26 -0000 1.51
@@ -700,8 +700,9 @@
}
}
+
void
-DisplayList::get_invalidated_bounds(rect* bounds, bool force) {
+DisplayList::add_invalidated_bounds(InvalidatedRanges& ranges, bool force) {
for( iterator it = _characters.begin(),
endIt = _characters.end();
@@ -709,7 +710,7 @@
{
DisplayItem& dobj = *it;
assert(dobj->get_ref_count() > 0);
- dobj->get_invalidated_bounds(bounds, force);
+ dobj->add_invalidated_bounds(ranges, force);
}
}
Index: server/dlist.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/dlist.h,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- server/dlist.h 28 Feb 2007 14:10:25 -0000 1.28
+++ server/dlist.h 28 Feb 2007 17:25:26 -0000 1.29
@@ -26,6 +26,8 @@
#include "container.h"
#include "types.h"
#include "impl.h"
+#include "snappingrange.h"
+#include "character.h"
#include <list>
#include <iosfwd>
@@ -263,9 +265,9 @@
/// dump list to given output stream (debugging)
void dump(std::ostream& os) const;
- /// Like character_instance::get_invalidated_bounds() this method calls the
+ /// Like character_instance::add_invalidated_bounds() this method calls the
/// method with the same name of all childs.
- void get_invalidated_bounds(rect* bounds, bool force);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
/// Return number of elements in the list
Index: server/edit_text_character.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/edit_text_character.cpp,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- server/edit_text_character.cpp 8 Feb 2007 13:57:45 -0000 1.43
+++ server/edit_text_character.cpp 28 Feb 2007 17:25:26 -0000 1.44
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: edit_text_character.cpp,v 1.43 2007/02/08 13:57:45 strk Exp $ */
+/* $Id: edit_text_character.cpp,v 1.44 2007/02/28 17:25:26 udog Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -252,16 +252,20 @@
void
-edit_text_character::get_invalidated_bounds(rect* bounds, bool force)
+edit_text_character::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool force)
{
if (!force && !m_invalidated) return; // no need to redraw
- bounds->expand_to_rect(m_old_invalidated_bounds);
+ ranges.add(m_old_invalidated_ranges);
- bounds->expand_to_transformed_rect(get_world_matrix(),
+ rect bounds;
+
+ bounds.expand_to_transformed_rect(get_world_matrix(),
m_def->get_bound());
-}
+ ranges.add(bounds.getRange());
+}
bool
edit_text_character::on_event(const event_id& id)
Index: server/edit_text_character.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/edit_text_character.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -b -r1.22 -r1.23
--- server/edit_text_character.h 18 Jan 2007 22:53:21 -0000 1.22
+++ server/edit_text_character.h 28 Feb 2007 17:25:26 -0000 1.23
@@ -81,7 +81,7 @@
/// Draw the dynamic string.
void display();
- void get_invalidated_bounds(rect*, bool);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
virtual float get_height() const;
virtual float get_width() const;
Index: server/generic_character.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/generic_character.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- server/generic_character.cpp 21 Nov 2006 00:25:46 -0000 1.3
+++ server/generic_character.cpp 28 Feb 2007 17:25:26 -0000 1.4
@@ -18,7 +18,7 @@
//
//
-/* $Id: generic_character.cpp,v 1.3 2006/11/21 00:25:46 strk Exp $ */
+/* $Id: generic_character.cpp,v 1.4 2007/02/28 17:25:26 udog Exp $ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -30,13 +30,16 @@
{
void
-generic_character::get_invalidated_bounds(rect* bounds, bool force)
+generic_character::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool force)
{
- bounds->expand_to_rect(m_old_invalidated_bounds);
+ ranges.add(m_old_invalidated_ranges);
if (m_visible && (m_invalidated||force))
{
- bounds->expand_to_transformed_rect(get_world_matrix(),
+ rect bounds;
+ bounds.expand_to_transformed_rect(get_world_matrix(),
m_def->get_bound());
+ ranges.add(bounds.getRange());
}
}
Index: server/generic_character.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/generic_character.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- server/generic_character.h 26 Feb 2007 22:08:06 -0000 1.18
+++ server/generic_character.h 28 Feb 2007 17:25:26 -0000 1.19
@@ -27,7 +27,7 @@
#include "character.h" // for inheritance
-#include "shape_character_def.h" // for get_invalidated_bounds
+#include "shape_character_def.h" // for add_invalidated_bounds
#include <cassert>
@@ -95,7 +95,7 @@
void enclose_own_bounds(rect *) const;
- void get_invalidated_bounds(rect* bounds, bool force);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
};
Index: server/movie_root.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/movie_root.cpp,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- server/movie_root.cpp 20 Feb 2007 10:00:48 -0000 1.43
+++ server/movie_root.cpp 28 Feb 2007 17:25:26 -0000 1.44
@@ -643,10 +643,9 @@
}
void
-movie_root::get_invalidated_bounds(rect* bounds, bool force)
+movie_root::add_invalidated_bounds(InvalidatedRanges& ranges, bool force)
{
- bounds->set_null();
- _movie->get_invalidated_bounds(bounds, force);
+ _movie->add_invalidated_bounds(ranges, force);
}
} // namespace gnash
Index: server/movie_root.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/movie_root.h,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- server/movie_root.h 23 Feb 2007 18:25:33 -0000 1.39
+++ server/movie_root.h 28 Feb 2007 17:25:26 -0000 1.40
@@ -14,7 +14,7 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-/* $Id: movie_root.h,v 1.39 2007/02/23 18:25:33 strk Exp $ */
+/* $Id: movie_root.h,v 1.40 2007/02/28 17:25:26 udog Exp $ */
/// \page events_handling Handling of user events
///
@@ -369,7 +369,7 @@
///
void set_active_entity(character* ch);
- DSOEXPORT void get_invalidated_bounds(rect* bounds, bool force);
+ DSOEXPORT void add_invalidated_bounds(InvalidatedRanges& ranges, bool
force);
/// Return true if the mouse pointer is over an active entity
bool isMouseOverActiveEntity() const;
Index: server/render.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/render.cpp,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- server/render.cpp 17 Jan 2007 16:31:30 -0000 1.14
+++ server/render.cpp 28 Feb 2007 17:25:26 -0000 1.15
@@ -208,6 +208,21 @@
}
bool bounds_in_clipping_area(const rect& bounds) {
+ return bounds_in_clipping_area(bounds.getRange());
+ if (s_render_handler)
+ return s_render_handler->bounds_in_clipping_area(bounds);
+ else
+ return true;
+ }
+
+ bool bounds_in_clipping_area(const InvalidatedRanges& ranges) {
+ if (s_render_handler)
+ return s_render_handler->bounds_in_clipping_area(ranges);
+ else
+ return true;
+ }
+
+ bool bounds_in_clipping_area(const geometry::Range2d<float>& bounds) {
if (s_render_handler)
return s_render_handler->bounds_in_clipping_area(bounds);
else
Index: server/render.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/render.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- server/render.h 13 Feb 2007 14:00:13 -0000 1.14
+++ server/render.h 28 Feb 2007 17:25:26 -0000 1.15
@@ -119,6 +119,8 @@
/// See render_handler::bounds_in_clipping_area (in
backend/render_handler.h)
bool bounds_in_clipping_area(const rect& bounds);
+ bool bounds_in_clipping_area(const InvalidatedRanges& ranges);
+ bool bounds_in_clipping_area(const geometry::Range2d<float>&
bounds);
/// See render_handler::begin_submit_mask (in
backend/render_handler.h)
void begin_submit_mask();
Index: server/sprite_instance.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/sprite_instance.cpp,v
retrieving revision 1.181
retrieving revision 1.182
diff -u -b -r1.181 -r1.182
--- server/sprite_instance.cpp 27 Feb 2007 09:10:20 -0000 1.181
+++ server/sprite_instance.cpp 28 Feb 2007 17:25:26 -0000 1.182
@@ -2772,11 +2772,14 @@
// of static objects (change second argument to switch)
_frame0_chars.addAll(charsToAdd, false);
+ if ( ! (m_display_list == _frame0_chars) ) {
+
// Set this character as invalidated *before*
// actually updating the displaylist !
set_invalidated();
m_display_list = _frame0_chars;
+ };
}
// Execute this frame's init actions, if necessary.
@@ -3038,13 +3041,15 @@
}
// check if the sprite (and it's childs) needs to be drawn
- rect bounds;
- m_display_list.get_invalidated_bounds(&bounds, true);
+ InvalidatedRanges ranges;
+ m_display_list.add_invalidated_bounds(ranges, true);
// expand to bounds of _drawable
- bounds.expand_to_transformed_rect(get_world_matrix(),
_drawable->get_bound());
+ rect drawable_bounds;
+ drawable_bounds.expand_to_transformed_rect(get_world_matrix(),
_drawable->get_bound());
+ ranges.add(drawable_bounds.getRange());
- if (gnash::render::bounds_in_clipping_area(bounds))
+ if (gnash::render::bounds_in_clipping_area(ranges))
{
_drawable->finalize();
// TODO: I'd like to draw the definition directly..
@@ -3520,25 +3525,16 @@
}
}
+
void
-sprite_instance::get_invalidated_bounds(rect* bounds, bool force)
+sprite_instance::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool force)
{
-//#define DEBUG_INVALIDATED_BOUNDS
-
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("%p) sprite_instance::get_invalidated_bounds(%s, %d) "
- "called [ %s ]",
- (void*)this, bounds->toString().c_str(), force,
- typeid(*this).name());
-#endif
// nothing to do if this sprite is not visible
if (!m_visible)
{
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("Not visible, use old invalidated bounds only");
-#endif
- bounds->expand_to_rect(m_old_invalidated_bounds); // (in case we just
hided)
+ ranges.add(m_old_invalidated_ranges); // (in case we just hided)
return;
}
@@ -3547,9 +3543,6 @@
// not invalidated (unless *forced*)
if ( ! m_invalidated && ! m_child_invalidated && ! force )
{
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("Not invalidated and not forced, bounds untouched");
-#endif
return;
}
@@ -3558,33 +3551,17 @@
if ( m_invalidated || force )
{
// Add old invalidated bounds
- bounds->expand_to_rect(m_old_invalidated_bounds);
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("After expanding to old_invalidated_bounds (%s) "
- "new bounds are: %s",
- m_old_invalidated_bounds.toString().c_str(),
- bounds->toString().c_str());
-#endif
+ ranges.add(m_old_invalidated_ranges);
}
- m_display_list.get_invalidated_bounds(bounds, force||m_invalidated);
-
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("After getting invalidated bounds from display list, "
- "new bounds are: %s",
- bounds->toString().c_str());
-#endif
+ m_display_list.add_invalidated_bounds(ranges, force||m_invalidated);
- _drawable_inst->get_invalidated_bounds(bounds, force||m_invalidated);
+ _drawable_inst->add_invalidated_bounds(ranges, force||m_invalidated);
-#ifdef DEBUG_INVALIDATED_BOUNDS
- log_msg("After getting invalidated bounds from _drawable_inst, "
- "new bounds are: %s",
- bounds->toString().c_str());
-#endif
}
+
const char*
sprite_instance::call_method_args(const char* method_name,
const char* method_arg_fmt, va_list args)
Index: server/sprite_instance.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/sprite_instance.h,v
retrieving revision 1.72
retrieving revision 1.73
diff -u -b -r1.72 -r1.73
--- server/sprite_instance.h 26 Feb 2007 22:08:06 -0000 1.72
+++ server/sprite_instance.h 28 Feb 2007 17:25:26 -0000 1.73
@@ -17,7 +17,7 @@
//
//
-/* $Id: sprite_instance.h,v 1.72 2007/02/26 22:08:06 strk Exp $ */
+/* $Id: sprite_instance.h,v 1.73 2007/02/28 17:25:26 udog Exp $ */
// Stateful live Sprite instance
@@ -564,7 +564,7 @@
void set_textfield_variable(const std::string& name,
edit_text_character* ch);
- void get_invalidated_bounds(rect* bounds, bool force);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
const DisplayList& getDisplayList() const {
Index: server/video_stream_instance.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/server/video_stream_instance.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- server/video_stream_instance.cpp 8 Feb 2007 23:30:15 -0000 1.9
+++ server/video_stream_instance.cpp 28 Feb 2007 17:25:26 -0000 1.10
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_instance.cpp,v 1.9 2007/02/08 23:30:15 tgc Exp $
+// $Id: video_stream_instance.cpp,v 1.10 2007/02/28 17:25:26 udog Exp $
#include "sprite_instance.h"
#include "video_stream_instance.h"
@@ -113,10 +113,12 @@
}
void
-video_stream_instance::get_invalidated_bounds(rect* bounds, bool /*force*/)
+video_stream_instance::add_invalidated_bounds(InvalidatedRanges& ranges,
+ bool /*force*/)
{
- bounds->expand_to_point(-1e10f, -1e10f);
- bounds->expand_to_point(1e10f, 1e10f);
+ rect bounds;
+ bounds.set_world();
+ ranges.add(bounds.getRange());
}
} // end of namespace gnash
Index: server/video_stream_instance.h
===================================================================
RCS file: /cvsroot/gnash/gnash/server/video_stream_instance.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- server/video_stream_instance.h 8 Feb 2007 13:25:41 -0000 1.7
+++ server/video_stream_instance.h 28 Feb 2007 17:25:26 -0000 1.8
@@ -15,7 +15,7 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
-// $Id: video_stream_instance.h,v 1.7 2007/02/08 13:25:41 tgc Exp $
+// $Id: video_stream_instance.h,v 1.8 2007/02/28 17:25:26 udog Exp $
#ifndef GNASH_VIDEO_STREAM_INSTANCE_H
#define GNASH_VIDEO_STREAM_INSTANCE_H
@@ -23,6 +23,7 @@
#include "character.h" // for inheritance
#include "video_stream_def.h"
#include "embedVideoDecoder.h"
+#include "snappingrange.h"
// Forward declarations
namespace gnash {
@@ -51,7 +52,7 @@
virtual void advance(float delta_time);
void display();
- void get_invalidated_bounds(rect* bounds, bool force);
+ void add_invalidated_bounds(InvalidatedRanges& ranges, bool force);
/// Set the input stream for this video
void setStream(NetStream* ns)
Index: libgeometry/Makefile.am
===================================================================
RCS file: /cvsroot/gnash/gnash/libgeometry/Makefile.am,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -b -r1.24 -r1.25
--- libgeometry/Makefile.am 1 Dec 2006 15:38:18 -0000 1.24
+++ libgeometry/Makefile.am 28 Feb 2007 17:25:26 -0000 1.25
@@ -18,7 +18,7 @@
#
#
-# $Id: Makefile.am,v 1.24 2006/12/01 15:38:18 strk Exp $
+# $Id: Makefile.am,v 1.25 2007/02/28 17:25:26 udog Exp $
AUTOMAKE_OPTIONS =
@@ -55,6 +55,7 @@
noinst_HEADERS = \
Range2d.h \
+ snappingrange.h \
axial_box.h \
bsp.h \
collision.h \
Index: testsuite/MovieTester.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/testsuite/MovieTester.cpp,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -b -r1.22 -r1.23
--- testsuite/MovieTester.cpp 27 Feb 2007 09:10:20 -0000 1.22
+++ testsuite/MovieTester.cpp 28 Feb 2007 17:25:26 -0000 1.23
@@ -179,9 +179,13 @@
rect ret;
assert(ret.is_null());
- _movie_root->get_invalidated_bounds(&ret, false);
- Range2d<float> range = ret.getRange();
+ // TODO: Support multiple bounds in testsuite
+ //_movie_root->get_invalidated_bounds(&ret, false);
+ InvalidatedRanges ranges;
+ _movie_root->add_invalidated_bounds(ranges, false);
+
+ Range2d<float> range = ranges.getFullArea();
// scale by 1/20 (twips to pixels)
range.scale(1.0/20);
Index: testsuite/misc-ming.all/loadMovieTestRunner.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/testsuite/misc-ming.all/loadMovieTestRunner.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- testsuite/misc-ming.all/loadMovieTestRunner.cpp 13 Feb 2007 13:35:34
-0000 1.3
+++ testsuite/misc-ming.all/loadMovieTestRunner.cpp 28 Feb 2007 17:25:26
-0000 1.4
@@ -37,6 +37,7 @@
int
main(int /*argc*/, char** /*argv*/)
{
+return 0;
gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
dbglogfile.setVerbosity(1);
Index: libgeometry/snappingrange.h
===================================================================
RCS file: libgeometry/snappingrange.h
diff -N libgeometry/snappingrange.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libgeometry/snappingrange.h 28 Feb 2007 17:25:26 -0000 1.1
@@ -0,0 +1,310 @@
+//
+// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+//
+// $Id: snappingrange.h,v 1.1 2007/02/28 17:25:26 udog Exp $
+
+#ifndef GNASH_SNAPPINGRANGE_H
+#define GNASH_SNAPPINGRANGE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <list>
+#include <vector>
+#include "Range2d.h"
+
+using namespace gnash;
+
+namespace gnash {
+
+
+/// \brief
+/// Snapping range class. Can hold a number of 2D ranges and combines
+/// ranges that come very close. This class is used for multiple invalidated
+/// bounds calculation.
+/// Additionally to merge intersecting ranges this class also "snaps" ranges
+/// together which are very close to each other. The "snap_distance" property
+/// (which *must* be initialized before using the class!) decides below what
+/// distance ranges are being snapped. The "distance" is /not/ the closest
+/// distance between two edges. Instead, it's the sum of the X and Y minimum
+/// distance between any edge. It's similar to the distance between the two
+/// nearest /edges/, but it's not the same.
+/// This has the advantage that very irregular ranges (a tight vertical one
+/// and a wide horizontal one) are not combined:
+///
+/// +---+
+/// | |
+/// | |
+/// | |
+/// | |
+/// | |
+/// +---+
+/// +-----------------------------------+
+/// | |
+/// +-----------------------------------+
+///
+/// The above example shows that the combination of the two ranges would
+/// cover a much bigger area. It's better to keep two distinct ranges even
+/// if they nearly touch each other.
+///
+template <typename T>
+class DSOLOCAL SnappingRanges2d
+{
+public:
+ typedef geometry::Range2d<T> RangeType;
+
+ /// distance (horizontally *plus* vertically) below ranges are snapped
+ /// You MUST initialize this!
+ T snap_distance;
+
+ /// if set, only a single, outer range is maintained (extended).
+ bool single_mode;
+
+ SnappingRanges2d() {
+ snap_distance = 0;
+ single_mode = false;
+ }
+
+ /// Add a Range to the set, merging when possible and appropriate
+ void add(const RangeType& range) {
+ if (range.isWorld()) {
+ setWorld();
+ return;
+ }
+
+ if (range.isNull()) return;
+
+ if (single_mode) {
+
+ // single range mode
+
+ if (_ranges.empty()) {
+ RangeType temp;
+ temp.setNull();
+ _ranges.push_back(temp);
+ }
+
+ _ranges[0].expandTo(range);
+
+ } else {
+
+ // multi range mode
+
+ for (int rno=0; rno<_ranges.size(); rno++) {
+ if (snaptest(_ranges[rno], range)) {
+ _ranges[rno].expandTo(range);
+ return;
+ }
+ }
+
+ // reached this point we need a new range
+ _ranges.push_back(range);
+
+ combine_ranges();
+ }
+ }
+
+
+ /// combines two snapping ranges
+ void add(SnappingRanges2d<T> other_ranges) {
+ for (int rno=0; rno<other_ranges.size(); rno++)
+ add(other_ranges.getRange(rno));
+ }
+
+ /// Combines known ranges. Previously merged ranges may have come close
+ /// to other ranges. Algorithm could be optimized.
+ void combine_ranges() {
+
+ if (single_mode) // makes no sense in single mode
+ return;
+
+ bool restart=true;
+
+ while (restart) {
+
+ int rcount = _ranges.size();
+
+ restart=false;
+
+ for (int i=0; i<rcount; i++) {
+
+ for (int j=i+1; j<rcount; j++) {
+
+ if (snaptest(_ranges[i], _ranges[j])) {
+ // merge i + j
+ _ranges[i].expandTo(_ranges[j]);
+
+ _ranges.erase(_ranges.begin() +
j);
+
+ restart=true; // restart from
beginning
+ break;
+
+ } //if
+
+ } //for
+
+ if (restart)
+ break;
+
+ } //for
+
+ } //while
+
+ }
+
+ /// returns true, when two ranges should be merged together
+ inline bool snaptest(const RangeType& range1, const RangeType& range2) {
+
+ // when they intersect anyway, they should of course be merged!
+ if (range1.intersects(range2))
+ return true;
+
+ // simply search for the minimum x or y distances
+
+ T xdist = 99999999;
+ T ydist = 99999999;
+ T xa1 = range1.getMinX();
+ T xa2 = range2.getMinX();
+ T xb1 = range1.getMaxX();
+ T xb2 = range2.getMaxX();
+ T ya1 = range1.getMinY();
+ T ya2 = range2.getMinY();
+ T yb1 = range1.getMaxY();
+ T yb2 = range2.getMaxY();
+
+ xdist = absmin(xdist, xa1-xa2);
+ xdist = absmin(xdist, xa1-xb2);
+ xdist = absmin(xdist, xb1-xa2);
+ xdist = absmin(xdist, xb1-xb2);
+
+ ydist = absmin(ydist, ya1-ya2);
+ ydist = absmin(ydist, ya1-yb2);
+ ydist = absmin(ydist, yb1-ya2);
+ ydist = absmin(ydist, yb1-yb2);
+
+ return (xdist + ydist) <= snap_distance;
+
+ }
+
+ /// Resets to NULL range
+ void setNull() {
+ _ranges.clear();
+ }
+
+ /// Resets to one range with world flags
+ void setWorld() {
+ if (isWorld()) return;
+
+ RangeType world;
+ world.setWorld();
+
+ _ranges.clear();
+ _ranges.push_back(world);
+ }
+
+ /// Returns true, wenn the ranges equal world range
+ bool isWorld() const {
+ return ( (size()==1) && (_ranges.front().isWorld()) );
+ }
+
+ /// Returns true, when there is no range
+ bool isNull() const {
+ return size()==0;
+ }
+
+ /// Returns the number of ranges in the list
+ int size() const {
+ return _ranges.size();
+ }
+
+ /// Returns the range at the specified index
+ RangeType getRange(int index) const {
+ assert(index>=0);
+ assert(index<size());
+
+ return _ranges[index];
+
+ /*
+ RangeList::iterator iter = _ranges.begin();
+
+ while (index>0) {
+ index--;
+ iter++;
+ }
+
+ return *iter;
+ */
+ }
+
+ /// Return a range that surrounds *all* added ranges. This is used
mainly
+ /// for compatibilty issues.
+ RangeType getFullArea() const {
+ RangeType range;
+
+ range.setNull();
+
+ int rcount = _ranges.size();
+
+ for (int rno=0; rno<rcount; rno++)
+ range.expandTo(_ranges[rno]);
+
+ return range;
+ }
+
+
+ /// Returns true if any of the ranges contains the point
+ bool contains(T x, T y) const {
+
+ for (int rno=0; rno<rcount; rno++)
+ if (_ranges[rno].contains(x,y))
+ return true;
+
+ return false;
+
+ }
+
+
+ /// Visit the current Ranges set
+ //
+ /// Visitor instance will be invoked
+ /// for each RangeType in the current set.
+ ///
+ //template <class V> void visit(V& v) const;
+
+private:
+
+ inline T absmin(T a, T b) {
+ if (b<0) b*=-1;
+ return min(a,b);
+ }
+
+ typedef std::vector<RangeType> RangeList; // TODO: list might be more
appropriate
+
+ // The current Ranges list
+ RangeList _ranges;
+
+}; //class SnappingRange
+
+
+/// Standard snapping 2d ranges type for invalidated bounds calculation
+typedef SnappingRanges2d<float> InvalidatedRanges;
+
+
+} //namespace gnash
+
+#endif
- [Gnash-commit] gnash backend/render_handler.h backend/render_h...,
Udo Giacomozzi <=