[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash/backend render_handler_agg.cpp
From: |
Udo Giacomozzi |
Subject: |
[Gnash-commit] gnash/backend render_handler_agg.cpp |
Date: |
Tue, 17 Apr 2007 09:19:31 +0000 |
CVSROOT: /cvsroot/gnash
Module name: gnash
Changes by: Udo Giacomozzi <udog> 07/04/17 09:19:31
Modified files:
backend : render_handler_agg.cpp
Log message:
replaced drawVideoFrame() with a native AGG version
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg.cpp?cvsroot=gnash&r1=1.69&r2=1.70
Patches:
Index: render_handler_agg.cpp
===================================================================
RCS file: /cvsroot/gnash/gnash/backend/render_handler_agg.cpp,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -b -r1.69 -r1.70
--- render_handler_agg.cpp 11 Apr 2007 14:54:26 -0000 1.69
+++ render_handler_agg.cpp 17 Apr 2007 09:19:31 -0000 1.70
@@ -16,7 +16,7 @@
-/* $Id: render_handler_agg.cpp,v 1.69 2007/04/11 14:54:26 bjacques Exp $ */
+/* $Id: render_handler_agg.cpp,v 1.70 2007/04/17 09:19:31 udog Exp $ */
// Original version by Udo Giacomozzi and Hannes Mayr,
// INDUNET GmbH (www.indunet.it)
@@ -64,7 +64,7 @@
caching NONE IMPLEMENTED
- video NOT IMPLEMENTED, only stubs
+ video COMPLETE
Currently the renderer should be able to render everything correctly,
except videos.
@@ -422,67 +422,138 @@
return RGB;
}
- /** \brief Draws the video frames
- * This implementation blits (copies) the RGB buffer provided by the
caller
- * directly into the Agg render buffer.
- *
- * @param baseframe The RGB video buffer frame.
- *
- * @param mat The matrix with world coordinates used to retrieve the x
- * and y coordinate of the video object.
- *
- * @param bounds the width and height fields of this rect are used to
- * determine the width and height of the RGB image to be drawn. The x
and y
- * members of this field are ignored.
- */
- void drawVideoFrame(image::image_base* baseframe, const matrix* mat, const
rect* bounds)
- {
- point a;
- mat->transform(&a, point(bounds->get_x_min(), bounds->get_y_min()));
- int xpos = (int)round( TWIPS_TO_PIXELS(a.m_x) );
- int ypos = (int)round( TWIPS_TO_PIXELS(a.m_y) );
+ void drawVideoFrame(image::image_base* baseframe, const matrix* mat, const
rect* bounds) {
- // TODO: handle this by only blitting part of the source RGB image.
- if (xpos < 0) {
- xpos = 0;
- }
- if (ypos < 0) {
- ypos = 0;
- }
+ // NOTE: Assuming that the source image is RGB 8:8:8
+
+ // TODO: Currently only nearest-neighbor scaling is implemented here, since
+ // it's the fastest and Flash apparently uses this method most of the time.
+ // It would be easy to add other scaling methods (bilinear, bicubic,
+ // whatever), but we'd need some way to tell the renderer the desired
+ // quality.
+
+ // TODO: Test this with a rotated video. Maybe the image accessor
+ // will insert some ugly pixels (even if I don't think so) - Udo
+
+ // TODO: keep heavy instances alive accross frames for performance!
+
+ // TODO: Maybe implement specialization for 1:1 scaled videos
+
+
+ typedef agg::pixfmt_rgb24_pre baseformat;
+ //typedef agg::renderer_base<baseformat> renderer_base_pre;
- int bytes_per_pixel = 3;
image::rgb* frame = static_cast<image::rgb*>(baseframe);
- unsigned int frame_width = frame->m_width * bytes_per_pixel;
+ // compute video scaling relative to video obejct size
+ double vscaleX = TWIPS_TO_PIXELS(bounds->width()) / frame->m_width;
+ double vscaleY = TWIPS_TO_PIXELS(bounds->height()) / frame->m_height;
+
+ // convert Gnash matrix to AGG matrix and scale down to pixel coordinates
+ // while we're at it
+ agg::trans_affine img_mtx(
+ mat->m_[0][0]*20.0*vscaleX, mat->m_[1][0],
+ mat->m_[0][1], mat->m_[1][1]*20.0*vscaleY,
+ mat->m_[0][2], mat->m_[1][2]
+ );
+
+ // apply global movie scaling
+ img_mtx *= agg::trans_affine_scaling((xscale+yscale) * 0.5);
+
+ // invert matrix since this is used for the image source
+ img_mtx.invert();
+
+ // span allocator is used to apply the matrix
+ agg::span_allocator<agg::rgba8> sa;
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ interpolator_type interpolator(img_mtx);
+
+ // clipping image accessor is used to avoid repeating of the image
+ typedef agg::image_accessor_clip<baseformat> img_source_type;
+
+ // rendering buffer is used to access the frame pixels here
+ agg::rendering_buffer img_buf(frame->m_data, frame->m_width,
frame->m_height,
+ frame->m_width*3);
+
+ baseformat img_pixf(img_buf);
+
+ // The second parameter passed to the constructor is the color (R,G,B,A)
+ // used for pixels outside the source image (ie. when the movie aspect
+ // ratio does not match the video instance).
+ img_source_type img_src(img_pixf, agg::rgba_pre(255,0,0,0));
+
+ // renderer base for the stage buffer (not the frame image!)
+ renderer_base rbase(*m_pixf);
+
+ // nearest neighbor method for scaling
+ typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type>
+ span_gen_type;
+ span_gen_type sg(img_src, interpolator);
+
+ typedef agg::rasterizer_scanline_aa<> ras_type;
+ ras_type ras;
+
+ // make a path for the video outline
+ point a, b, c, d;
+ mat->transform(&a, point(bounds->get_x_min(),
bounds->get_y_min()));
+ mat->transform(&b, point(bounds->get_x_max(),
bounds->get_y_min()));
+ mat->transform(&c, point(bounds->get_x_max(),
bounds->get_y_max()));
+ mat->transform(&d, point(bounds->get_x_min(),
bounds->get_y_max()));
- if (frame_width + xpos * bytes_per_pixel > m_rbuf.width() *
bytes_per_pixel) {
- // the movie was placed too far to the right. let's cut it off at
- // the far right corner. (This is also how "that other player"
- // handles it, I'm told.)
- frame_width = (m_rbuf.width() * bytes_per_pixel - xpos *
bytes_per_pixel);
- }
-
- unsigned char* rgbbuf_ptr = frame->m_data;
- unsigned char* rgbbuf_end = rgbbuf_ptr + frame->m_pitch *
- frame->m_height;
-
- unsigned char* aggbuf_ptr = memaddr;
- unsigned char* aggbuf_end = memaddr + memsize;
-
- // Skip the first ypos rows.
- aggbuf_ptr += ypos * m_rbuf.stride();
- // Move xpos pixels to the right.
- aggbuf_ptr += xpos * bytes_per_pixel;
-
- while(rgbbuf_ptr < rgbbuf_end && aggbuf_ptr < aggbuf_end) {
- memcpy(aggbuf_ptr, rgbbuf_ptr, frame_width);
- aggbuf_ptr += m_rbuf.stride();
- rgbbuf_ptr += frame->m_pitch;
+ agg::path_storage path;
+ path.move_to(a.m_x*xscale, a.m_y*yscale);
+ path.line_to(b.m_x*xscale, b.m_y*yscale);
+ path.line_to(c.m_x*xscale, c.m_y*yscale);
+ path.line_to(d.m_x*xscale, d.m_y*yscale);
+ path.line_to(a.m_x*xscale, a.m_y*yscale);
+
+ if (m_alpha_mask.empty()) {
+
+ // No mask active
+
+ agg::scanline_u8 sl;
+
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++) {
+
+ const geometry::Range2d<int>& cbounds = _clipbounds[cno];
+ apply_clip_box<ras_type> (ras, cbounds);
+
+ // <Udo>: AFAIK add_path() rewinds the vertex list (clears previous
+ // path), so there should be no problem with multiple clipbounds.
+ ras.add_path(path);
+
+ agg::render_scanlines_aa(ras, sl, rbase, sa, sg);
}
+
+ } else {
+
+ // Mask is active!
+
+ // **** UNTESTED!!! ****
+
+ typedef agg::scanline_u8_am<agg::alpha_mask_gray8> scanline_type;
+ scanline_type sl(m_alpha_mask.back()->get_amask());
+
+ for (unsigned int cno=0; cno<_clipbounds.size(); cno++) {
+
+ const geometry::Range2d<int>& cbounds = _clipbounds[cno];
+ apply_clip_box<ras_type> (ras, cbounds);
+
+ // <Udo>: AFAIK add_path() rewinds the vertex list (clears previous
+ // path), so there should be no problem with multiple clipbounds.
+ ras.add_path(path);
+
+ agg::render_scanlines_aa(ras, sl, rbase, sa, sg);
}
+ } // if alpha mask
+
+ } // drawVideoFrame
+
+
// Constructor
render_handler_agg(int bits_per_pixel)
:
- [Gnash-commit] gnash/backend render_handler_agg.cpp,
Udo Giacomozzi <=