[ Return to Articles | Show Comments | Submit Comment ]
Article #898: Using the Anti-Grain Light 2D rendering engine with FLTK
Created at 08:40 Apr 06, 2009 by MCO
Last modified at 10:43 Apr 06, 2009
Anti-Grain a high quality rendering engine for C++, it was written by Maxim Shemanarev and is available here : http://www.antigrain.com/
The author also produced a lighter version of that library, called 'The Lighweight Rasterizer', available here : http://www.antigrain.com/lite/agg2_lite.zip
The tiny object code produced by that library seems to fit the FLTK philosophy perfectly. Of course, it is also lighter in terms of features, eg there is no font drawing code.
The main idea is to use AGG Lite primitives to draw in a buffer that's blitted with fl_draw_image in an FLTK surface.
Here is some 'proof of concept' code :
AGG_Lite_Window.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_draw.H>
#include "agg.h"
#include <math.h>
#include
#ifndef AGG_LITE_WINDOW_DEF
#define AGG_LITE_WINDOW_DEF
typedef unsigned char uchar8;
class AGG_Lite_Window : public Fl_Double_Window {
public:
AGG_Lite_Window(int x, int y, int w, int h, char *s);
~AGG_Lite_Window() { delete [] buf; delete rbuf; delete ren; };
private:
uchar8 *buf;
agg::rendering_buffer *rbuf;
agg::rasterizer ras;
agg::renderer *ren;
void draw(void);
int handle(int event);
void move_to(double x, double y);
void line_to(double x, double y);
void draw_ellipse(double x, double y, double rx, double ry);
void draw_line(double x1, double y1, double x2, double y2, double width);
void clear_buffer(void);
void blit_buffer(void);
void render(uchar8 r,uchar8 g,uchar8 b,uchar8 a);
};
#endif
AGG_Lite_Window.cpp
#include "AGG_Lite_Window.h"
AGG_Lite_Window::AGG_Lite_Window(int x, int y, int w, int h, char *s)
: Fl_Double_Window(x,y,w,h,s) {
buf = new uchar8[w * h * 3];
rbuf = new agg::rendering_buffer(buf, w, h, w * 3);
ren = new agg::renderer(*rbuf);
ras.gamma(1.3);
ras.filling_rule(agg::fill_non_zero);
}
void AGG_Lite_Window::move_to(double x, double y) {
ras.move_to_d(x, y);
}
void AGG_Lite_Window::line_to(double x, double y) {
ras.line_to_d(x, y);
}
void AGG_Lite_Window::draw_ellipse(double x, double y, double rx, double ry) {
ras.move_to_d(x + rx, y);
for(int i = 1; i < 360; i++) {
double a = double(i) * 3.1415926 / 180.0;
ras.line_to_d(x + cos(a) * rx, y + sin(a) * ry);
}
}
void AGG_Lite_Window::draw_line(double x1, double y1, double x2, double y2, double width) {
double dx = x2 - x1;
double dy = y2 - y1;
double d = sqrt(dx*dx + dy*dy);
dx = width * (y2 - y1) / d;
dy = width * (x2 - x1) / d;
ras.move_to_d(x1 - dx, y1 + dy);
ras.line_to_d(x2 - dx, y2 + dy);
ras.line_to_d(x2 + dx, y2 - dy);
ras.line_to_d(x1 + dx, y1 - dy);
}
void AGG_Lite_Window::clear_buffer(void) {
ren->clear(agg::rgba8(210, 210, 210));
ras.reset();
}
void AGG_Lite_Window::blit_buffer(void) {
fl_draw_image(buf, 0, 0, w(), h()) ;
}
void AGG_Lite_Window::render(uchar8 r, uchar8 g, uchar8 b, uchar8 a ) {
ras.render(*ren, agg::rgba8(r, g, b, a));
}
and a simple test program :
#include <FL/Fl.H>
#include "AGG_Lite_Window.h"
#include "stdlib.h"
enum { width = 1000, height = 700 };
void AGG_Lite_Window::draw(void) {
int x = Fl::event_x();
int y = Fl::event_y();
// Draw with AGG Lite
clear_buffer();
draw_ellipse(x, y, 10, 10);
render(0xAF, 0xAF, 0xAF, 20);
draw_line(x, y, 50, 50, 1.0);
render(0, 0, 0, 120);
draw_ellipse( x, y, 100, 50);
render(0xFF, 0xCF, 0x5F,230);
draw_ellipse( 50, 250, 100, 50);
render(0x0F, 0xFF, 0x5F,30);
move_to(10,10);
line_to(60,10);
line_to(50,50);
line_to(10,60);
render(0xFF, 0, 0, 180);
blit_buffer();
// Draw with FLTK functions on top
fl_font(FL_HELVETICA, 24);
fl_color(FL_RED);
fl_draw("Click and drag the mouse...",450,450);
fl_color(FL_BLACK);
fl_line_style(FL_SOLID, 1);
fl_line(100,100,600,200);
fl_font(FL_HELVETICA, 12);
fl_draw("< Line drawn with FLTK",600,200);
}
int AGG_Lite_Window::handle(int e) {
if ( Fl_Double_Window::handle(e) )
return(1);
int x = Fl::event_x();
int y = Fl::event_y();
switch (e) {
case FL_PUSH:
redraw();
return 1;
case FL_DRAG:
redraw();
return 1;
}
return 0;
}
int main(int argc, char ** argv)
{
AGG_Lite_Window *window;
window = new AGG_Lite_Window( 10, 10, width, height, "FLTK + AGG Lite - Test program");
window->end();
Fl::visual(FL_DOUBLE|FL_INDEX);
window->show(argc, argv);
return(Fl::run());
}
This blog post : http://dtedm.blogspot.com/2009/03/fltk-agg-lite.html provides a screenshot and a small windows executable that shows both anti-aliased drawing and transparency.
Manuel Cornes
[ Download | Home Page | Listing ]
[ Submit Comment ] |