gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash gui/fb.cpp gui/fbsup.h backend/render_han...


From: Rob Savoye
Subject: [Gnash-commit] gnash gui/fb.cpp gui/fbsup.h backend/render_han...
Date: Sat, 07 Oct 2006 14:05:45 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Rob Savoye <rsavoye>    06/10/07 14:05:44

Added files:
        gui            : fb.cpp fbsup.h 
        backend        : render_handler_agg.cpp render_handler_tri.cpp 
                         render_handler_tri.h 

Log message:
        New files for AGG backend with framebuffer "no gui" support.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/fb.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/fbsup.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_agg.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_tri.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/backend/render_handler_tri.h?cvsroot=gnash&rev=1.1

Patches:
Index: gui/fb.cpp
===================================================================
RCS file: gui/fb.cpp
diff -N gui/fb.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gui/fb.cpp  7 Oct 2006 14:05:44 -0000       1.1
@@ -0,0 +1,367 @@
+//
+//   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
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+//
+//
+
+// 
-----------------------------------------------------------------------------
+
+/// A Framebuffer-based GUI for Gnash. It required the AGG backend to render
+/// the frames. It operates in fullscreen mode and uses the screen mode 
+/// currently active.
+///
+/// Supported graphics modes:
+///
+///   Resolution: any
+///
+///   Pixel formats:
+///     8 bit: none yet
+///     15 bit: R5/G5/B5
+///     16 bit: R5/G6/B5
+///     24 bit: R8/G8/B8, B8/G8/R8
+///
+///
+/// Supported input devices:
+///
+///   None, yet. But may be added easily.    
+   
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include <unistd.h>
+
+#include "gnash.h"
+#include "gui.h"
+#include "fbsup.h"
+#include "log.h"
+
+//#define DEBUG_SHOW_FPS  // prints number of frames per second to STDOUT
+
+#ifdef DEBUG_SHOW_FPS
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#endif
+//--
+
+
+namespace gnash
+{
+
+
+//---------------
+#ifdef DEBUG_SHOW_FPS
+double fps_timer=0;
+int fps_counter=0;
+void profile() {
+  int fd;
+  double uptime, idletime;
+  char buffer[20];
+  int readcount;
+
+  fd = open("/proc/uptime", O_RDONLY);
+  if (fd<0) return;
+  readcount = read(fd, buffer, sizeof(buffer)-1);
+  buffer[readcount]=0;
+  sscanf(buffer, "%lf %lf", &uptime, &idletime);
+  close(fd);
+  
+  fps_counter++;
+
+  if (fps_counter<2) {
+    fps_timer = uptime;
+    return;    
+  }
+  
+  printf("FPS: %.3f (%.2f)\n", fps_counter/(uptime-fps_timer), 
uptime-fps_timer);
+  
+}
+#endif
+//---------------
+
+FBGui::FBGui() : Gui()
+{
+}
+
+FBGui::FBGui(unsigned long xid, float scale, bool loop, unsigned int depth)
+       : Gui(xid, scale, loop, depth)
+{
+       fd                      = -1;
+       fbmem   = NULL;
+       buffer  = NULL;
+}
+
+FBGui::~FBGui()
+{
+       if (fd>0) {
+               log_msg("Closing framebuffer device\n");
+               close(fd);
+       }
+
+       if (buffer) {
+               log_msg("Free'ing offscreen buffer\n");
+               free(buffer);
+       }
+}
+
+
+/// For 8 bit (palette / LUT) modes, sets a grayscale palette. This GUI 
+/// currently does not support palette modes. 
+bool FBGui::set_grayscale_lut8()
+{
+  #define TO_16BIT(x) (x | (x<<8))
+
+  struct fb_cmap cmap;
+  int i;
+
+  log_msg("LUT8: Setting up colormap\n");
+
+  cmap.start=0;
+  cmap.len=256;
+  cmap.red = (__u16*)malloc(CMAP_SIZE);
+  cmap.green = (__u16*)malloc(CMAP_SIZE);
+  cmap.blue = (__u16*)malloc(CMAP_SIZE);
+  cmap.transp = NULL;
+
+  for (i=0; i<256; i++) {
+
+    int r = i;
+    int g = i;
+    int b = i;
+
+    cmap.red[i] = TO_16BIT(r);
+    cmap.green[i] = TO_16BIT(g);
+    cmap.blue[i] = TO_16BIT(b);
+
+  }
+
+  if (ioctl(fd, FBIOPUTCMAP, &cmap)) {
+    log_error("LUT8: Error setting colormap: %s\n", strerror(errno));
+    return false;
+  }
+
+  return true;
+
+  #undef TO_16BIT
+}
+
+bool FBGui::init(int argc, char **argv[])
+{
+  // Open the framebuffer device
+  fd = open("/dev/fb0", O_RDWR);
+  if (fd<0) {
+    log_error("Could not open framebuffer device: %s", strerror(errno));
+    return false;
+  }
+  
+  // Load framebuffer properties
+  ioctl(fd, FBIOGET_VSCREENINFO, &var_screeninfo);
+  ioctl(fd, FBIOGET_FSCREENINFO, &fix_screeninfo);
+  log_msg("Framebuffer device uses %d bytes of memory.\n",
+       fix_screeninfo.smem_len);
+  log_msg("Video mode: %dx%d with %d bits per pixel.\n",
+    var_screeninfo.xres, var_screeninfo.yres, var_screeninfo.bits_per_pixel);
+
+  // map framebuffer into memory
+  fbmem = (unsigned char *)
+    mmap(0, fix_screeninfo.smem_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+#ifdef DOUBLE_BUFFER
+  // allocate offscreen buffer
+  buffer = (unsigned char*)malloc(fix_screeninfo.smem_len);
+  memset(buffer, 0, fix_screeninfo.smem_len);
+#endif  
+
+#ifdef PIXELFORMAT_LUT8
+  // Set grayscale for 8 bit modes
+  if (var_screeninfo.bits_per_pixel==8) {
+       if (!set_grayscale_lut8())
+               return false;
+  }
+#endif
+
+  // Ok, now initialize AGG
+  return initialize_renderer();
+}
+
+bool FBGui::initialize_renderer() {
+  int _width           = var_screeninfo.xres;
+  int _height  = var_screeninfo.yres;
+  int _bpp = var_screeninfo.bits_per_pixel;
+  int _size = fix_screeninfo.smem_len;   // TODO: should recalculate!  
+  unsigned char *_mem;
+  
+  
+  #ifdef DOUBLE_BUFFER
+  _mem = buffer;
+  #else
+  _mem = fbmem;
+  #endif
+  
+  
+  _renderer = NULL;
+  
+  // choose apropriate pixel format
+  
+  log_msg("red channel: %d / %d", var_screeninfo.red.offset, 
+    var_screeninfo.red.length);
+  log_msg("green channel: %d / %d", var_screeninfo.green.offset, 
+    var_screeninfo.green.length);
+  log_msg("blue channel: %d / %d", var_screeninfo.blue.offset, 
+    var_screeninfo.blue.length);
+  
+  // 15 bits RGB (hicolor)
+  if ((var_screeninfo.red.offset==10)
+   && (var_screeninfo.red.length==5)
+   && (var_screeninfo.green.offset==5)
+   && (var_screeninfo.green.length==5)
+   && (var_screeninfo.blue.offset==0)
+   && (var_screeninfo.blue.length==5) ) {
+   
+    _renderer = create_render_handler_agg("RGB555", 
+      _mem, _size, _width, _height, _bpp);
+      
+  } else   
+  // 16 bits RGB (hicolor)
+  if ((var_screeninfo.red.offset=11)
+   && (var_screeninfo.red.length==5)
+   && (var_screeninfo.green.offset==5)
+   && (var_screeninfo.green.length==6)
+   && (var_screeninfo.blue.offset==0)
+   && (var_screeninfo.blue.length==5) ) {
+   
+    _renderer = create_render_handler_agg("RGB565", 
+      _mem, _size, _width, _height, _bpp);
+      
+  } else   
+  // 24 bits RGB (truecolor)
+  if ((var_screeninfo.red.offset==16)
+   && (var_screeninfo.red.length==8)
+   && (var_screeninfo.green.offset==8)
+   && (var_screeninfo.green.length==8)
+   && (var_screeninfo.blue.offset==0)
+   && (var_screeninfo.blue.length==8) ) {
+   
+    _renderer = create_render_handler_agg("RGB24", 
+      _mem, _size, _width, _height, _bpp);
+      
+  } else   
+  // 24 bits BGR (truecolor)
+  if ((var_screeninfo.red.offset==0)
+   && (var_screeninfo.red.length==8)
+   && (var_screeninfo.green.offset==8)
+   && (var_screeninfo.green.length==8)
+   && (var_screeninfo.blue.offset==16)
+   && (var_screeninfo.blue.length==8) ) {
+   
+    _renderer = create_render_handler_agg("BGR24", 
+      _mem, _size, _width, _height, _bpp);
+      
+  } else {
+    log_msg("ERROR: The pixel format of your framebuffer is not supported.");
+  }
+
+  assert(_renderer!=NULL);
+
+  set_render_handler(_renderer);
+
+  return true;
+}
+
+bool FBGui::run(void *)
+{
+       while (true) {
+               // sleep for _interval milliseconds
+    // TODO: Instead of sleeping, use a timer to compensate render time        
        
+               usleep(_interval*1000);
+               Gui::advance_movie(this);
+       }
+       return true;
+}
+
+void FBGui::renderBuffer()
+{
+
+#ifdef DOUBLE_BUFFER
+       // TODO: Copy only updated parts of the screen!
+       memcpy(fbmem, buffer, var_screeninfo.xres*var_screeninfo.yres*
+    (var_screeninfo.bits_per_pixel/8));
+#endif
+       
+#ifdef DEBUG_SHOW_FPS
+       profile();
+#endif
+}
+
+bool FBGui::createWindow(int width, int height)
+{
+  // Framebuffer has no windows... :-)
+
+       return true;
+}
+
+bool FBGui::createMenu()
+{
+  // no menu support! 
+       return true;
+}
+
+bool FBGui::setupEvents()
+{
+  // events currently not supported!
+       return true;
+}
+
+void FBGui::setCallback(unsigned int interval)
+{
+       _interval = interval;
+}
+
+void FBGui::setTimeout(unsigned int timeout)
+{
+
+}
+
+
+// end of namespace gnash
+}

Index: gui/fbsup.h
===================================================================
RCS file: gui/fbsup.h
diff -N gui/fbsup.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gui/fbsup.h 7 Oct 2006 14:05:44 -0000       1.1
@@ -0,0 +1,90 @@
+//
+//   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
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+//
+//
+
+#ifndef __FBSUP_H__
+#define __FBSUP_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gui.h"
+#include <linux/fb.h>
+
+#define PIXELFORMAT_LUT8
+#define CMAP_SIZE (256*2)
+
+#define DOUBLE_BUFFER
+
+
+namespace gnash
+{
+
+class FBGui : public Gui
+{
+       private:
+               int fd;
+               unsigned char *fbmem;  // framebuffer memory
+#ifdef DOUBLE_BUFFER
+               unsigned char *buffer; // offscreen buffer
+#endif         
+    struct fb_var_screeninfo var_screeninfo;
+       struct fb_fix_screeninfo fix_screeninfo;
+
+       bool set_grayscale_lut8();
+       
+       bool initialize_renderer();
+
+       public:
+               FBGui();
+               FBGui(unsigned long xid, float scale, bool loop, unsigned int 
depth);
+    virtual ~FBGui();
+    virtual bool init(int argc, char **argv[]);
+    virtual bool createWindow(int width, int height);
+    virtual bool run(void *);
+    virtual bool createMenu();
+    virtual bool setupEvents();
+    virtual void renderBuffer();
+    virtual void setCallback(unsigned int interval);
+    virtual void setTimeout(unsigned int timeout);
+};
+
+// end of namespace gnash
+}
+
+#endif
+

Index: backend/render_handler_agg.cpp
===================================================================
RCS file: backend/render_handler_agg.cpp
diff -N backend/render_handler_agg.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ backend/render_handler_agg.cpp      7 Oct 2006 14:05:44 -0000       1.1
@@ -0,0 +1 @@
+// 
//   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

// Linking Gnash statically or dynamically with other modules is making a
// combined work based on Gnash. Thus, the terms and conditions of the GNU
// General Public License cover the whole combination.
//
// As a special exception, the copyright holders of Gnash give you
// permission to combine Gnash with free software programs or libraries
// that are released under the GNU LGPL and with code included in any
// release of Talkback distributed by the Mozilla Foundation. You may
// copy and distribute such a system following the terms of the GNU GPL
// for all but the LGPL-covered parts and Talkback, and following the
// LGPL for the LGPL-covered parts.
//
// Note that people who make modified versions of Gnash are not obligated
// to grant this special exception for their modified versions; it is their
// choice whether to do so. The GNU General Public License gives permission
// to release a modified version without this exception; this exception
// also makes it possible to release a modified version which carries
// forward this exception.
 

// Original version by Udo Giacomozzi and Hannes Mayr, 
// INDUNET GmbH (www.indunet.it)


/// A render_handler that uses the Anti-Grain Geometry Toolkit (antigrain.com)
/// and renders directly to a buffer (for example to the framebuffer). This 
/// backend is *completely* independent of any hardware. It can be used for
/// 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...

/*

Status:

  outlines:
    solid          COMPLETE
    patterns       NOT IMPLEMENTED (seems like Gnash does not support them yet)
    widths         COMPLETE
    colors, alpha  COMPLETE
    
  fills:
    solid fills    COMPLETE
    gradients      NOT IMPLEMENTED
    bitmaps        NOT IMPLEMENTED
    
  fonts            COMPLETE
    
  masks            NOT IMPLEMENTED (masks are drawn as shapes)
  
  caching          currently working on it...
  
  video            don't know how that works    

*/


#include "gnash.h"
#include "types.h"
#include "image.h"
#include "utility.h"
#include "log.h"
#include "render_handler.h"
//#include "render_handler_tri.h"   // test only!

#include "shape_character_def.h" 
#include "generic_character.h"  

#include "agg_rendering_buffer.h"
#include "agg_renderer_base.h"
#include "agg_pixfmt_rgb.h"
#include "agg_pixfmt_rgb_packed.h"
#include "agg_pixfmt_rgba.h"
#include "agg_pixfmt_gray.h"
#include "agg_color_rgba.h"
#include "agg_color_gray.h"
#include "agg_ellipse.h"
#include "agg_conv_transform.h"
#include "agg_trans_affine.h"
#include "agg_scanline_u.h"
#include "agg_scanline_p.h"
#include "agg_renderer_scanline.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_rasterizer_compound_aa.h"
#include "agg_span_allocator.h"
#include "agg_path_storage.h"
#include "agg_conv_curve.h"
#include "agg_conv_stroke.h"
#include "agg_vcgen_stroke.h"
#include "agg_bezier_arc.h"
#include "agg_renderer_primitives.h"
#include "agg_gamma_functions.h"
#include "agg_math_stroke.h"



using namespace gnash;




class bitmap_info_agg : public gnash::bitmap_info
{
public:

  bitmap_info_agg() {
    //log_msg("bitmap_info_agg instance");
    // dummy
  }

};


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 
  matrix m_mat;  
  
  /// Number of cache hits 
  int hits;
  
  /// Number of cache misses
  int misses;
  
  /// Contents of this cache item. First dimension is fill style 
  std::vector <std::vector <agg::path_storage> > data;
};

class agg_cache_manager : private render_cache_manager
{
};


// --- AGG HELPER CLASSES ------------------------------------------------------

// Style handler for AGG's compound rasterizer.
class agg_style_handler
{
public:
    agg_style_handler() : 
        m_transparent(0, 0, 0, 0)
    {}

    /// Called by AGG to ask if a certain style is a solid color
    bool is_solid(unsigned style) const { 
      return true;  // The backend currently only supports solid fills 
    }
    
    /// Adds a new solid fill color style
    void add(const agg::rgba8 color) {
      m_colors.push_back(color);
    }

    /// Returns the color of a certain fill style (solid)
    const agg::rgba8& color(unsigned style) const 
    {
        if (style < m_colors.size())
            return m_colors[style];

        return m_transparent;
    }

    /// Called by AGG to generate a scanline span for non-solid fills 
    void generate_span(agg::rgba8* span, int x, int y, unsigned len, unsigned 
style)
    { 
      // non-solid fills currently not supported
    }


private:
    std::vector<agg::rgba8> m_colors;
    agg::rgba8          m_transparent;
};  // class agg_style_handler




// --- 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.

template <class PixelFormat>
class render_handler_agg : public render_handler
{
private:
  typedef agg::renderer_base<PixelFormat> renderer_base;
    
  // TODO: Change these!!
        unsigned char *memaddr;
        int     memsize;
        int xres;
        int yres;
        int bpp;        // bits per pixel
        double scale;


  // initialize AGG
        void agg_init()
        {
        log_msg("agg_init()\n");

        // set rendering buffer
        m_rbuf.attach(memaddr, xres, yres, xres*(bpp/8));
        
        // clear screen
        renderer_base rbase(*m_pixf);
        rbase.clear(agg::rgba8(0, 0, 0));

        log_msg("AGG initialized.\n");

        //agg_drawtest();
  }

public:
  int              m_view_width;      // TODO: remove these??
  int              m_view_height;

  // Enable/disable antialiasing.
  bool  m_enable_antialias;

  // Output size.
  float m_display_width;
  float m_display_height;

  gnash::matrix m_current_matrix;
  gnash::cxform m_current_cxform;

  void set_antialiased(bool enable) {
                // dummy
  }

  // Style state.
  enum style_index
  {
        LEFT_STYLE = 0,
        RIGHT_STYLE,
        LINE_STYLE,
        STYLE_COUNT
  };


  gnash::bitmap_info*   create_bitmap_info_rgb(image::rgb* im)
        // Given an image, returns a pointer to a bitmap_info class
        // that can later be passed to fill_styleX_bitmap(), to set a
        // bitmap fill style.
        {          
          UNUSED(im);
          // bitmaps currently not supported! - return dummy for fontlib
          return new bitmap_info_agg(); 
    return NULL;
        }


  gnash::bitmap_info*   create_bitmap_info_rgba(image::rgba* im)
        // Given an image, returns a pointer to a bitmap_info class
        // that can later be passed to fill_style_bitmap(), to set a
        // bitmap fill style.
        //
        // This version takes an image with an alpha channel.
        {
          UNUSED(im);
          // bitmaps currently not supported! - return dummy for fontlib
          return new bitmap_info_agg();
    return NULL;
        }


  gnash::bitmap_info*   create_bitmap_info_empty()
        // Create a placeholder bitmap_info.  Used when
        // DO_NOT_LOAD_BITMAPS is set; then later on the host program
        // can use movie_definition::get_bitmap_info_count() and
        // movie_definition::get_bitmap_info() to stuff precomputed
        // textures into these bitmap infos.
        {
          // bitmaps currently not supported! - return dummy for fontlib
          return new bitmap_info_agg();
    return NULL;
        }

  gnash::bitmap_info*   create_bitmap_info_alpha(int w, int h, uint8_t* data)
        // Create a bitmap_info so that it contains an alpha texture
        // with the given data (1 byte per texel).
        {
          UNUSED(w);
    UNUSED(h);
    UNUSED(data); 
          // bitmaps currently not supported! - return dummy for fontlib
          return new bitmap_info_agg();
    return NULL;
        }


  void  delete_bitmap_info(gnash::bitmap_info* bi)
        // Delete the given bitmap info class.
        {
    free(bi);
        }


  // Constructor
  render_handler_agg(unsigned char *mem, int size, int x, int y,
        int bits_per_pixel)
  {
        memaddr = mem;
        memsize = size;
        xres            = x;
        yres            = y;
        bpp                     = bits_per_pixel;
        scale           = 1/20.0;

    // allocate pixel format accessor   
    m_pixf = new PixelFormat(m_rbuf);
    //m_rbase = new renderer_base(*m_pixf);  --> does not work!!??

        agg_init();
  }

  // Destructor
  ~render_handler_agg()
  {

  }

  void begin_display(
        gnash::rgba background_color,
        int viewport_x0, int viewport_y0,
        int viewport_width, int viewport_height,
        float x0, float x1, float y0, float y1)
        // Set up to render a full frame from a movie and fills the
        // background.  Sets up necessary transforms, to scale the
        // movie to fit within the given dimensions.  Call
        // end_display() when you're done.
        //
        // The rectangle (viewport_x0, viewport_y0, viewport_x0 +
        // viewport_width, viewport_y0 + viewport_height) defines the
        // window coordinates taken up by the movie.
        //
        // The rectangle (x0, y0, x1, y1) defines the pixel
        // coordinates of the movie that correspond to the viewport
        // bounds.
        {
          UNUSED(viewport_x0);
          UNUSED(viewport_y0);
          UNUSED(viewport_width);
          UNUSED(viewport_height);
          UNUSED(x0);
          UNUSED(y0);
          UNUSED(x1);
          UNUSED(y1);
          
          double scaleX, scaleY;
          
          // clear the stage using the background color   
          renderer_base rbase(*m_pixf);
    rbase.clear(agg::rgba8(background_color.m_r, background_color.m_g,
        background_color.m_b, background_color.m_a));

    // calculate final pixel scale
    scaleX = (double)xres / (double)viewport_width / 20.0;  // 20=TWIPS
    scaleY = (double)yres / (double)viewport_height / 20.0;
    scale = scaleX<scaleY ? scaleX : scaleY;
        }

  bool allow_glyph_textures() {
    // We want to render all glyphs in place 
    return false; 
  }

  void  end_display()
        // Clean up after rendering a frame.  Client program is still
        // responsible for calling glSwapBuffers() or whatever.
        {
    // nothing to do
        }

  void  set_matrix(const gnash::matrix& m)
        // Set the current transform for mesh & line-strip rendering.
        {
    // used only for drawing line strips...        
          m_current_matrix = m;
        }

  void  set_cxform(const gnash::cxform& cx)
        // Set the current color transform for mesh & line-strip rendering.
        {
    // used only for drawing line strips...        
    m_current_cxform = cx;
        }

  static void   apply_matrix(const gnash::matrix& m)
        // add user space transformation
        {
    // TODO: what's the use for this, anyway?? 
    log_msg("apply_matrix(); called - NOT IMPLEMENTED");
        }

  static void   apply_color(const gnash::rgba& c)
        // Set the given color.
        {
    // TODO: what's the use for this, anyway?? 
    log_msg("apply_color(); called - NOT IMPLEMENTED");
        }


  void  line_style_width(float width)
        {
                line_width=width;
        }



  void  draw_line_strip(const void* coords, int vertex_count, const rgba color)
        // Draw the line strip formed by the sequence of points.
        {
    point pnt;
    
    renderer_base rbase(*m_pixf);

        agg::scanline_p8 sl;
        agg::rasterizer_scanline_aa<> ras;
        agg::renderer_scanline_aa_solid<
        agg::renderer_base<PixelFormat> > ren_sl(rbase);

    agg::path_storage path;
    agg::conv_stroke<agg::path_storage> stroke(path);
    stroke.width(1);
    stroke.line_cap(agg::round_cap);
    stroke.line_join(agg::round_join);
    path.remove_all(); // Not obligatory in this case

    const int16_t *vertex = (int16_t*)coords;
    
    m_current_matrix.transform(&pnt, point(vertex[0], vertex[1]));
        path.move_to(pnt.m_x * scale, pnt.m_y * scale);

    for (vertex += 2;  vertex_count > 1;  vertex_count--, vertex += 2) {
      m_current_matrix.transform(&pnt, point(vertex[0], vertex[1]));
        path.line_to(pnt.m_x * scale, pnt.m_y * scale);
    }
                // The vectorial pipeline
        ras.add_path(stroke);

        // Set the color and render the scanlines
        ren_sl.color(agg::rgba8(color.m_r, color.m_g, color.m_b, color.m_a));
        agg::render_scanlines(ras, sl, ren_sl);

        } // draw_line_strip


  void  draw_bitmap(
        const gnash::matrix& m,
        const gnash::bitmap_info* bi,
        const gnash::rect& coords,
        const gnash::rect& uv_coords,
        gnash::rgba color)
        // Draw a rectangle textured with the given bitmap, with the
        // given color.  Apply given transform; ignore any currently
        // set transforms.
        //
        // Intended for textured glyph rendering.
        {
          UNUSED(color);
    log_msg("  draw_bitmap NOT IMPLEMENTED\n");
        }

  void begin_submit_mask()
        {
    // not implemented
        }

  void end_submit_mask()
        {
    // not implemented
        }

  void disable_mask()
        {
    // not implemented
        }
        


  /*
   Takes a list of paths and combines them according to their fill style so 
   that each path is a closed polygon. Each path will have exactly one fill 
   style.
   This is necessary because Flash uses up to two fill styles for each path,
   one for each side. It can happen that a path contains only one edge. In that
   case it just divides a shape in two (two colors). Since this is impossible
   to draw directly we need to restore the original polygons so that they can
   be drawn independently.
   
   IMPORTANT NOTE: This is currently *not* used for AGG anymore, because AGG
   has a direct rasterizer for double styles...   
   */   
  void combine_paths(std::vector<path> &paths_in, std::vector<path> &paths_out) 
{
    
    int ino;      // index of input path
    int incount;  // cache value for paths_in.size()
    int ono;      // index of output path
    int eno;      // edge index 
    
    #define EQUAL(a,b) (fabs(a-b)<0.000000001)
    
    incount = paths_in.size();
    
    /*
    Strategy: For fill style 0, each path is compared with other paths sharing
    the same fill style and it is tried to attach the new path to a already 
    known path. The start point of the new path must match the end point of the
    previous path. Only distant shapes will not find a matching path and thus
    will create a new one.
    For fill style 1 the same is done except that the path is reversed first.
    The resulting paths will use exactly one fill style (fill style 0).
    Each source path may be used for two different resulting shapes (one time
    normally and the other reversed).    
    */
    
    // browse through all paths...
    for (ino=0; ino<incount; ino++) {
    
      path &new_path = paths_in[ino];
      int found;

      // === FILL STYLE 0 ===
      
      if (new_path.m_fill0) {
        found=0;
        
        // 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;
        }
        
        {
          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);
        }

      }

    
    }
    
    #undef EQUAL   
    
  }



  void draw_glyph(shape_character_def *def,
      const matrix& mat, rgba color, float pixel_scale) {
      
    // create a new path with the matrix applied   
    std::vector<path> paths;    
    apply_matrix_to_path(def->get_paths(), paths, mat);
      
    // make sure m_single_fill_styles contains the required color 
    need_single_fill_style(color);

    // draw the shape
    draw_shape(paths, m_single_fill_styles, m_neutral_cxform, false);
    
    // NOTE: Do not use even-odd filling rule for glyphs!
  }


  void draw_shape_character(shape_character_def *def, 
    const matrix& mat,
    const cxform& cx,
    float pixel_scale,
    const std::vector<fill_style>& fill_styles,
    const std::vector<line_style>& line_styles) {
    
    std::vector<path> paths;
    
    apply_matrix_to_path(def->get_paths(), paths, mat);
    
    draw_shape(paths, fill_styles, cx, true);
    
    draw_outlines(paths, line_styles, cx);
  }


  /// Takes a path and translates it using the given matrix. The new path
  /// is stored in paths_out.  
  void apply_matrix_to_path(const std::vector<path> &paths_in, 
    std::vector<path> &paths_out, const matrix &mat) {
    
    int pcount, ecount;
    int pno, eno;
    
    // copy path
    paths_out = paths_in;    
    pcount = paths_out.size();
        
    
    for (pno=0; pno<pcount; pno++) {
    
      path &the_path = paths_out[pno];     
      point oldpnt(the_path.m_ax, the_path.m_ay);
      point newpnt;
       
      mat.transform(&newpnt, oldpnt);
      the_path.m_ax = newpnt.m_x;    
      the_path.m_ay = newpnt.m_y;
      
      ecount = the_path.m_edges.size();
      for (eno=0; eno<ecount; eno++) {
      
        edge &the_edge = the_path.m_edges[eno];
        
        oldpnt.m_x = the_edge.m_ax;
        oldpnt.m_y = the_edge.m_ay;
        mat.transform(&newpnt, oldpnt);
        the_edge.m_ax = newpnt.m_x;
        the_edge.m_ay = newpnt.m_y;
        
        oldpnt.m_x = the_edge.m_cx;
        oldpnt.m_y = the_edge.m_cy;
        mat.transform(&newpnt, oldpnt);
        the_edge.m_cx = newpnt.m_x;
        the_edge.m_cy = newpnt.m_y;
      
      }          
      
    } 
    
  } // apply_matrix


  /// 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).
  void draw_shape(const std::vector<path> &paths,
    const std::vector<fill_style> &fill_styles, const cxform& cx, int even_odd) 
{
    
    /*
    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...
    */
    

    // 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<
      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
    
    // debug
    int edge_count=0;
    
    // activate even-odd filling rule
    if (even_odd)
      rasc.filling_rule(agg::fill_even_odd);
    else
      rasc.filling_rule(agg::fill_non_zero);
  
      
    // tell AGG what styles are used
    fcount = fill_styles.size();
    //log_msg("%d fill styles\n", fcount);
    for (fno=0; fno<fcount; fno++) {
      rgba color = cx.transform(fill_styles[fno].get_color());
      
      // add the color to our self-made style handler (basically just a list)
      sh.add(agg::rgba8(color.m_r, color.m_g, color.m_b, color.m_a)); 
    }
    
      
    // push paths to AGG
    pcount = paths.size();
    //log_msg("%d paths\n", pcount);
    for (pno=0; pno<pcount; pno++) {
    
      const path &this_path = paths[pno];
      agg::path_storage path;
      agg::conv_curve< agg::path_storage > curve(path);
    
      // 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*scale, this_path.m_ay*scale);      
      
      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*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);
        
      }
      
      // add path to the compound rasterizer
      rasc.add_path(curve); 
    
    }
    //log_msg("%d edges\n", edge_count);
    
    // render!
    agg::render_scanlines_compound_layered(rasc, sl, rbase, alloc, sh);
    
  } // draw_shape



  /// Just like draw_shapes() except that it draws an outline.
  void draw_outlines(const std::vector<path> &paths,
    const std::vector<line_style> &line_styles, const cxform& cx) {
    
    // 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;
    
    // 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
    agg::path_storage agg_path;             // a path in the AGG world
    
    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
    
    
    pcount = paths.size();   
    for (pno=0; pno<pcount; pno++) {
      
      const path &this_path = paths[pno];
      
      if (!this_path.m_line)  
        continue;     // invisible line
        
      const line_style &lstyle = line_styles[this_path.m_line-1];
      rgba color = cx.transform(lstyle.get_color());
      int width = lstyle.get_width();

      if (width==1)
        stroke.width(1);
      else
        stroke.width(width*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*scale, this_path.m_ay*scale);
        
      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*scale, this_edge.m_ay*scale);
        else
          agg_path.curve3(this_edge.m_cx*scale, this_edge.m_cy*scale,
                      this_edge.m_ax*scale, this_edge.m_ay*scale);
        
      } // for edges
      
      
      ras.add_path(stroke);
      ren_sl.color(agg::rgba8(color.m_r, color.m_g, color.m_b, color.m_a));
      
      agg::render_scanlines(ras, sl, ren_sl);
    
    
    }
      
  } // draw_outlines


  
  /// Draws the given polygon.
  void  draw_poly(const point* corners, int corner_count, const rgba fill, 
    const rgba outline) {
    
    if (corner_count<1) return;
    
    // TODO: Use aliased scanline renderer instead of anti-aliased one since
    // it is undesired anyway.
    renderer_base rbase(*m_pixf);
    agg::scanline_p8 sl;
    agg::rasterizer_scanline_aa<> ras;
    agg::renderer_scanline_aa_solid<
      agg::renderer_base<PixelFormat> > ren_sl(rbase);
      
    agg::path_storage path;
    point pnt, origin;
    
    // Note: The coordinates are rounded and 0.5 is added to snap them to the 
    // center of the pixel. This avoids blurring caused by anti-aliasing.
    
    m_current_matrix.transform(&origin, 
      point(trunc(corners[0].m_x), trunc(corners[0].m_y)));
    path.move_to(trunc(origin.m_x*scale)+0.5, trunc(origin.m_y*scale)+0.5);
    
    for (int i=1; i<corner_count; i++) {
    
      m_current_matrix.transform(&pnt, point(corners[i].m_x, corners[i].m_y));
        
      path.line_to(trunc(pnt.m_x*scale)+0.5, trunc(pnt.m_y*scale)+0.5);
    }
    
    // close polygon
    path.line_to(trunc(origin.m_x*scale)+0.5, trunc(origin.m_y*scale)+0.5);
    
    // commit path
    ras.add_path(path);
    
    // fill polygon
    if (fill.m_a>0) {
      ren_sl.color(agg::rgba8(fill.m_r, fill.m_g, fill.m_b, fill.m_a));
      agg::render_scanlines(ras, sl, ren_sl);
    }
    
    // draw outline
    if (outline.m_a>0) {
      agg::conv_stroke<agg::path_storage> stroke(path);
      
      stroke.width(1);
      
      ren_sl.color(agg::rgba8(outline.m_r, outline.m_g, outline.m_b, 
outline.m_a));
      
      ras.add_path(stroke);
      agg::render_scanlines(ras, sl, ren_sl);
    }
    
  }
                      
                      
  /*
  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(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

  
private:  // private methods  

  /// Returns the cache manager instance of the given character definition.
  /// Allocates a new manager if necessary.
  agg_cache_manager* get_cache_of(character* def) {
  
    if (def->m_render_cache == NULL) {
      def->m_render_cache = new agg_cache_manager;
    }
    
    return def->m_render_cache;
  
  }
  
private:  // private variables

  agg::rendering_buffer m_rbuf;  
  PixelFormat *m_pixf;
  
};      // end class render_handler_agg




// TODO: Replace "pixelformat" with a enum!

DSOEXPORT render_handler*       create_render_handler_agg(char *pixelformat, 
  unsigned char *mem, int memsize, int xres, int yres, int bpp)
{

  log_msg("framebuffer pixel format is %s", pixelformat);

  if (!strcmp(pixelformat, "RGB555"))
          return new render_handler_agg<agg::pixfmt_rgb555> (mem, memsize, 
xres, yres, bpp);
        
        else if (!strcmp(pixelformat, "RGB565"))
          return new render_handler_agg<agg::pixfmt_rgb565> (mem, memsize, 
xres, yres, bpp);
        
        else if (!strcmp(pixelformat, "RGB24"))
          return new render_handler_agg<agg::pixfmt_rgb24> (mem, memsize, xres, 
yres, bpp);
                
        else if (!strcmp(pixelformat, "BGR24"))
          return new render_handler_agg<agg::pixfmt_rgb565> (mem, memsize, 
xres, yres, bpp);
          
        else assert(0);
        
        return NULL; // avoid compiler warning
}

} // end of namespace gnash


// Local Variables:
// mode: C++
// indent-tabs-mode: t
// End:
/* vim: set cindent tabstop=8 softtabstop=4 shiftwidth=4: */
\ No newline at end of file

Index: backend/render_handler_tri.cpp
===================================================================
RCS file: backend/render_handler_tri.cpp
diff -N backend/render_handler_tri.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ backend/render_handler_tri.cpp      7 Oct 2006 14:05:44 -0000       1.1
@@ -0,0 +1,356 @@
+// 
+//   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
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
+
+#include "render_handler_tri.h"
+
+#ifndef RENDER_HANDLER_H
+#error missing includes!
+#endif
+
+#ifndef GNASH_RENDER_HANDLER_TRI_H
+#error missing includes!
+#endif
+
+namespace gnash {
+
+
+// helper function for tri_cache_manager
+static int     sort_by_decreasing_error(const void* A, const void* B)
+{
+  const mesh_set*      a = *(const mesh_set* const *) A;
+  const mesh_set*      b = *(const mesh_set* const *) B;
+  float atol = a->get_error_tolerance(); 
+  float btol = b->get_error_tolerance(); 
+  
+  if (atol < btol) {
+    return 1;
+  } else if (atol > btol) {
+    return -1;
+  } else {
+    return 0;
+  }
+}
+
+//------------------------------------------------------------------------------
+
+mesh_set* tri_cache_manager::search_candidate(float max_error)  {
+
+  for (unsigned int i=0,n=m_cached_meshes.size(); i<n; i++) {
+  
+    mesh_set* candidate = m_cached_meshes[i];
+    float candidate_etol = candidate->get_error_tolerance();
+  
+    if (max_error > candidate_etol * 3.0f) {
+      // Mesh is too high-res; the remaining meshes are higher res,
+      // so stop searching and build an appropriately scaled mesg.
+      break;
+    }
+    
+    if (max_error > candidate_etol) {
+      // found it!
+      return candidate;
+    }
+  
+  } // for
+  
+  // when we come here it means that no candidate could be found... :-(
+  return NULL;
+  
+} // search_candidate
+  
+  
+/// Adds a mesh set to the cache. 
+void tri_cache_manager::add(mesh_set* m) {
+  m_cached_meshes.push_back(m);
+  sort_and_clean_meshes();
+} // add
+
+
+/// Maintain cached meshes. Clean out mesh_sets that haven't been used 
+/// recently, and make sure they're sorted from high error to low error.
+void tri_cache_manager::sort_and_clean_meshes() {
+
+  // Re-sort.
+  if (m_cached_meshes.size() > 0) {
+  
+    qsort(
+      &m_cached_meshes[0],
+      m_cached_meshes.size(),
+      sizeof(m_cached_meshes[0]),
+      sort_by_decreasing_error
+    );
+  
+    // TODO: The cache will grow forever, without any limit. Add code that
+    // limits the vector to a certain size. The older Gnash implementation
+    // appears to never have removed unused cache objects!
+  
+  }
+  
+  // Sort check omitted!
+
+} // sort_and_clean_meshes
+  
+
+
+//------------------------------------------------------------------------------
+
+void triangulating_render_handler::draw_glyph(shape_character_def *def,
+    const matrix& mat, rgba color, float pixel_scale) {
+    
+  // Make sure m_single_fill_styles contains the desired color
+  need_single_fill_style(color);
+    
+  // A glyph is a notmal character, so draw it normally
+  draw_shape_character(def, mat, m_neutral_cxform, pixel_scale, 
+    m_single_fill_styles, m_dummy_line_styles);
+}
+
+
+  
+  
+void triangulating_render_handler::draw_shape_character(shape_character_def 
*def, 
+  const matrix& mat,
+  const cxform& cx,
+  float pixel_scale,
+  const std::vector<fill_style>& fill_styles,
+  const std::vector<line_style>& line_styles) {    
+  tri_cache_manager* cman = get_cache_of(def);
+  mesh_set* m;
+  int from_cache;
+  
+  // Compute the error tolerance in object-space.
+  float        max_scale = mat.get_max_scale();
+  
+  if (fabsf(max_scale) < 1e-6f) {
+    // Scale is essentially zero.
+    return;
+  }    
+  
+  float        object_space_max_error = 
+    20.0f / max_scale / pixel_scale * s_curve_max_pixel_error;
+    
+    
+  // NOTE: gnash_debug_show_paths ommitted
+  
+  // Try to find a usable mesh set in the cache
+  m = cman->search_candidate(object_space_max_error);
+  from_cache = m != NULL;
+   
+  if (!from_cache) {
+    // no cache hit, construct a new mesh to handle this error tolerance.
+    m = new mesh_set(def, object_space_max_error * 0.75f);
+  };
+
+  // draw the mesh set    
+  draw_mesh_set(*m, mat, cx, fill_styles, line_styles, 1.0);
+    
+  
+  if (!from_cache) {
+    // add to cache (do this after drawing the mesh!)
+    cman->add(m);    
+  }
+  
+} // draw_shape_character
+
+
+
+void triangulating_render_handler::draw_mesh_set(const mesh_set& m, 
+  const matrix& mat, const cxform& cx,
+  const std::vector<fill_style> &fill_styles,
+  const std::vector<line_style> &line_styles, float ratio) {
+  
+  set_matrix(mat);
+  set_cxform(cx);
+  
+  // draw fills
+  for (unsigned int i = 0; i < m.m_meshes.size(); i++) {
+    const mesh& the_mesh = m.m_meshes[i];
+    const fill_style& the_style = fill_styles[i];    
+    
+    if (!the_mesh.m_triangle_strip.size()) continue; // nothing to draw
+    
+    apply_fill_style(the_style, 0, ratio);
+    draw_mesh_strip(&the_mesh.m_triangle_strip[0], 
+      the_mesh.m_triangle_strip.size() / 2);   
+  }
+  
+  // draw outlines
+  for (unsigned int i = 0; i < m.m_line_strips.size(); i++)
+  {
+    int        style = m.m_line_strips[i].get_style();
+    const line_strip& strip = m.m_line_strips[i];
+    
+    assert(strip.m_coords.size() > 1);
+    assert((strip.m_coords.size() & 1) == 0);
+    apply_line_style(line_styles[style], ratio);
+    
+    draw_line_strip(&strip.m_coords[0], strip.m_coords.size() >> 1);
+  }
+    
+  
+} // draw_mesh_set
+
+
+void triangulating_render_handler::apply_fill_style(const fill_style& style, 
+  int fill_side, float ratio) {
+
+  UNUSED(ratio);
+  
+  if (style.m_type == SWF::FILL_SOLID)
+  {
+    // 0x00: solid fill
+    fill_style_color(fill_side, style.m_color); 
+  }
+  else if (style.m_type == SWF::FILL_LINEAR_GRADIENT
+    || style.m_type == SWF::FILL_RADIAL_GRADIENT)
+  {
+    // 0x10: linear gradient fill
+    // 0x12: radial gradient fill
+    
+    style.need_gradient_bitmap();
+    
+    if (style.m_gradient_bitmap_info != NULL) {
+      fill_style_bitmap(
+        fill_side,
+        style.m_gradient_bitmap_info.get_ptr(),
+        style.m_gradient_matrix,
+        gnash::render_handler::WRAP_CLAMP);
+    }
+  }
+  else if (style.m_type == SWF::FILL_TILED_BITMAP
+    || style.m_type == SWF::FILL_CLIPPED_BITMAP
+    || style.m_type == SWF::FILL_TILED_BITMAP_HARD
+    || style.m_type == SWF::FILL_CLIPPED_BITMAP_HARD)
+  {
+    
+    // bitmap fill (either tiled or clipped)
+    
+    gnash::bitmap_info*        bi = NULL;
+    
+    if (style.m_bitmap_character != NULL)      {
+    
+      bi = style.m_bitmap_character->get_bitmap_info();
+      
+      if (bi != NULL)  {
+      
+        gnash::render_handler::bitmap_wrap_mode        
+          wmode = gnash::render_handler::WRAP_REPEAT;
+          
+        if (style.m_type == SWF::FILL_CLIPPED_BITMAP
+          || style.m_type == SWF::FILL_CLIPPED_BITMAP_HARD)
+        {
+          wmode = gnash::render_handler::WRAP_CLAMP;
+        }
+        fill_style_bitmap(
+          fill_side,
+          bi,
+          style.m_bitmap_matrix,
+          wmode);
+      }
+    }
+  }  
+
+} // apply_fill_stype
+
+
+void triangulating_render_handler::apply_line_style(const line_style& style, 
+  float ratio) {
+  
+  UNUSED(ratio);
+  line_style_color(style.m_color);
+  line_style_width(style.m_width);  
+} // apply_line_style
+
+
+
+void   triangulating_render_handler::draw_line_strip(const void* coords, 
+  int vertex_count, const rgba color) {
+  
+  line_style_color(color);
+  line_style_width(1);
+  draw_line_strip(coords, vertex_count);
+  
+}
+
+void  triangulating_render_handler::draw_poly(const point* corners, 
+  int corner_count, const rgba fill, const rgba outline) {
+
+  // Create points array to vertex array
+  int cno, vno=0;  
+  int16_t *vertex = (int16_t*)malloc((corner_count+1)*2*sizeof(int16_t));
+  for (cno=0; cno<corner_count; cno++) {
+    vertex[vno  ] = (float)corners[cno].m_x;
+    vertex[vno+1] = (float)corners[cno].m_y;
+    vno+=2;
+  }
+  // add one more point to close the polygon
+  vertex[vno  ] = vertex[0];
+  vertex[vno+1] = vertex[1];
+  
+  // fill the polygon
+  if (fill.m_a>0) {
+    fill_style_color(0, fill);
+    draw_mesh_strip(vertex, corner_count+1);
+  }
+  
+  // draw the polygon outline
+  if (outline.m_a>0) {
+    line_style_color(outline);
+    line_style_width(1.0f);
+    draw_line_strip(vertex, corner_count+1);
+  } 
+  
+  free(vertex);
+  
+} // draw_poly
+
+
+
+
+tri_cache_manager* triangulating_render_handler::get_cache_of(character_def* 
def) {
+
+  if (def->m_render_cache == NULL) {
+    def->m_render_cache = new tri_cache_manager;
+  }
+  
+  return (tri_cache_manager*) def->m_render_cache;
+
+} // get_cache_of
+ 
+
+
+} // namespace gnash

Index: backend/render_handler_tri.h
===================================================================
RCS file: backend/render_handler_tri.h
diff -N backend/render_handler_tri.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ backend/render_handler_tri.h        7 Oct 2006 14:05:44 -0000       1.1
@@ -0,0 +1,207 @@
+// 
+//   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
+
+// Linking Gnash statically or dynamically with other modules is making a
+// combined work based on Gnash. Thus, the terms and conditions of the GNU
+// General Public License cover the whole combination.
+//
+// As a special exception, the copyright holders of Gnash give you
+// permission to combine Gnash with free software programs or libraries
+// that are released under the GNU LGPL and with code included in any
+// release of Talkback distributed by the Mozilla Foundation. You may
+// copy and distribute such a system following the terms of the GNU GPL
+// for all but the LGPL-covered parts and Talkback, and following the
+// LGPL for the LGPL-covered parts.
+//
+// Note that people who make modified versions of Gnash are not obligated
+// to grant this special exception for their modified versions; it is their
+// choice whether to do so. The GNU General Public License gives permission
+// to release a modified version without this exception; this exception
+// also makes it possible to release a modified version which carries
+// forward this exception.
+// 
+//
+
+#ifndef GNASH_RENDER_HANDLER_TRI_H
+#define GNASH_RENDER_HANDLER_TRI_H
+
+/// This is the base class for all triangle-based renderers (hardware 
+/// accelerated ones, for example). It shields the renderer from the special
+/// Flash edges that have two fill styles - one for each side. Also, Flash 
+/// shapes do not contain single, closed polygons. 
+/// The triangulating_render_handler contains algorithms that transform the
+/// shapes to simplified triangle sets ("mesh sets") that are relatively easy
+/// to render.
+  
+
+// Original version by Udo Giacomozzi, Indunet GmbH (www.indunet.it)
+
+
+#include "gnash.h"
+#include "types.h"
+#include "image.h"
+#include "utility.h"
+#include "log.h"
+
+#include "render_handler.h"
+
+#ifndef RENDER_HANDLER_H
+#error missing includes!
+#endif
+
+namespace gnash
+{
+
+class DSOEXPORT tri_cache_manager : public render_cache_manager
+{
+private:
+  /// A list of pre-computed meshes. Each mesh set was computed with a certain
+  /// error tolerance. The error tolerance defines the number of straight 
lines 
+  /// that are used to reconstruct a curve. As this approximation becomes
+  /// visible when magnifing a character, different mesh sets are cached.  
+  /// Of course, more edge lines produce more triangles which slows down 
+  /// rendering. So we try to use a mesh set with the minimal triangle amount
+  /// that's still acceptable when viewed.
+  /// To draw these meshes they still have to be transformed using the desired
+  /// matrix!
+  std::vector <mesh_set*> m_cached_meshes;
+  
+public:  
+
+  /// Searches a mesh set with a error tolerance below max_error.
+  /// Returns NULL when no candidate could be found.
+  mesh_set* search_candidate(float max_error);
+    
+  /// Adds a mesh set to the cache. 
+  void add(mesh_set* m);
+    
+  /// Maintain cached meshes. Clean out mesh_sets that haven't been used 
+  /// recently, and make sure they're sorted from high error to low error.
+  void sort_and_clean_meshes();  
+  
+}; // class tri_cache_manager
+
+
+
+
+class triangulating_render_handler : public render_handler 
+{
+public:
+  
+  // --- reimplemented methods 
-------------------------------------------------  
+  // The implementation of this virtual method takes care that the shape is
+  // translated to a mesh set. Triangulating backends do not need to declare
+  // their own draw_shape_character. 
+  
+  /// This method is required by all render handlers. The triangulating render
+  /// handler has already a common implementation that uses a tesselator and
+  /// generates mesh sets that can be used by simpler handlers.  
+  /*void draw_shape_character(shape_character_def *def, 
+    character *inst);*/
+    
+  /// Alterante version of draw_shape_character() which does not depend on any
+  /// character instance and accepts arbitrary line and fill styles. 
+       void draw_shape_character(shape_character_def *def, 
+    const matrix& mat,
+    const cxform& cx,
+    float pixel_scale,
+    const std::vector<fill_style>& fill_styles,
+    const std::vector<line_style>& line_styles);    
+
+  /// Triangulating render handlers do not need to support this special version
+  /// of draw_line_strip().     
+  void draw_line_strip(const void* coords, int vertex_count, const rgba color);
+  
+  /// The given polygon is translated to a mesh strip by this class.
+  void  draw_poly(const point* corners, int corner_count, const rgba fill, 
+    const rgba outline);
+    
+  /// The glyph is drawn just like a normal shape character.
+  virtual void draw_glyph(shape_character_def *def,
+    const matrix& mat, rgba color, float pixel_scale);
+    
+  /// Older backends always used glyph textures, so any triangulating render
+  /// handler activates glyph textures by default.
+  bool allow_glyph_textures() { return true; }
+  
+    
+  // --- helper methods 
--------------------------------------------------------
+  // These methods are called by draw_shape_character() and normally don't need
+  // to be accessed by other classes. They are here to make the class more
+  // readable and flexible.
+  // Note: The old methods mesh_set::display(), fill_style::apply() etc. have 
+  // been removed to disallow them completely since these methods rely on 
+  // triangular renderers which may not be available. This is the reason why
+  // the methods have been re-implemented inside triangulating_render_handler. 
+  
+  void draw_mesh_set(const mesh_set& m, const matrix& mat, const cxform& cx,
+    const std::vector<fill_style> &fill_styles,
+    const std::vector<line_style> &line_styles, float ratio);
+    
+  void apply_fill_style(const fill_style& style, int fill_side, float ratio);
+  void apply_line_style(const line_style& style, float ratio);
+  
+  
+  
+  // --- low level graphic methods 
---------------------------------------------
+  // These methods were defined in the older render_handler design. They must 
be
+  // implemented by the real handlers as they are defined abstract.   
+  
+  /// Disables the current fill style (so that it is transparent) for the 
+  /// given fill side (which is always zero?).
+       virtual void    fill_style_disable(int fill_side) = 0;
+       
+       /// Sets the fill style to the given solid color. 
+       virtual void    fill_style_color(int fill_side, rgba color) = 0;
+       
+       /// Sets the fill style to the given bitmap. This is also used for 
gradients
+       /// which are transformed to a bitmap prior to this call. 
+       virtual void    fill_style_bitmap(int fill_side, const bitmap_info* bi, 
+    const matrix& m, bitmap_wrap_mode wm) = 0;
+  
+  /// Disables the current line style
+       virtual void    line_style_disable() = 0;
+       
+       /// Sets the stroke color for subsequent draw_line_strip() calls 
+       virtual void    line_style_color(rgba color) = 0;
+       
+       /// Sets the stroke width for subsequent draw_line_strip() calls. When 
+  /// width==1.0 a "hairline" should be drawn. 
+       virtual void    line_style_width(float width) = 0;
+       
+       /// Draws the given line strip using the current transformation matrix.
+  virtual void draw_line_strip(const void* coords, int vertex_count) = 0;
+       
+       /// Draws the given mesh strip (trianges) using the current 
transformation 
+  /// matrix.
+  virtual void draw_mesh_strip(const void* coords, int vertex_count) = 0; 
+  
+    
+
+protected:
+  static const float   s_curve_max_pixel_error = 1.0f;
+    
+  
+  /// Returns the cache manager instance of the given character definition.
+  /// Allocates a new manager if necessary.
+  tri_cache_manager* get_cache_of(character_def* def);
+  
+
+}; // class render_handler_impl
+
+} // namespace gnash
+
+#endif // GNASH_RENDER_HANDLER_IMPL_H




reply via email to

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