[cairo-commit] cairo-demo/path_paint ChangeLog, NONE, 1.1 Makefile,
NONE, 1.1 README.txt, NONE, 1.1 path_paint.c, NONE, 1.1
OEyvind Kolaas
commit at pdx.freedesktop.org
Thu May 27 12:54:28 PDT 2004
Committed by: pippin
Update of /cvs/cairo/cairo-demo/path_paint
In directory pdx:/tmp/cvs-serv16517
Added Files:
ChangeLog Makefile README.txt path_paint.c
Log Message:
initial import of path_paint
--- NEW FILE: ChangeLog ---
2004-05-27 OEyvind Kolaas <pippin at freedesktop.org>
Initial import
/* vim: set ts=4 noet : */
--- NEW FILE: Makefile ---
CFLAGS= -Wall
LDFLAGS = -lm
CFLAGS+= `pkg-config gtkcairo --cflags`
LDFLAGS+= `pkg-config gtkcairo --libs`
CC = gcc
all: path_paint
test: path_paint
./path_paint
--- NEW FILE: README.txt ---
path_paint |
------------'
A simple interactive paint core using cairo.
It displays the current stroke incrementally rendered as a path
over the composite of all previous strokes.
The concept itself could be used both for vector based drawing apps
and pixel based programs.
Build instructions |
-------------------'
you need gtkcairo and it's dependencies, most of this is located in the
cairo http://cairographics.org/ cvs
just running make should work fine
Not Implemented |
----------------'
Features this app would need, in approximate order of increments
to become a useful application.
- setting color
- load/save of png
- setting line width
- setting alpha
- changing canvas size
- path/data simplification
- editing sample points
- editing of bezier points of path before use
- closing of path
- filling path
- stroke/fill history (for undo)
- load/save of svg (using stroke history)
- zoom (redraw from stroke history)
-pippin / Ãyvind KolÃ¥s pippin at freedesktop.org
--- NEW FILE: path_paint.c ---
#include <gtk/gtk.h>
#include <math.h>
#include <gtkcairo.h>
#define WIDTH 800
#define HEIGHT 600
#define STRIDE WIDTH*4
#define MAX_COORDS 1024
/* uncomment this to decrease the density of coordinate samples used for
* the current stroke, this is not an optimal solution, a better solution
* would be to use actuall smoothing on the coordinate data
*/
#define USE_HINT
GtkWidget *gtkcairo = NULL;
int pen_color_is_black=1;
int pen_radius=8;
double coord_x [MAX_COORDS];
double coord_y [MAX_COORDS];
int coord_count = 0;
unsigned char buffer [WIDTH*HEIGHT*4];
unsigned char temp_buffer [WIDTH*HEIGHT*4];
cairo_surface_t *backbuffer = NULL;
cairo_t *cr_save = NULL;
int pen_is_down=0;
void
destroy ()
{
cairo_destroy (cr_save);
}
/* utility functions, defined at bottom,
* constructing a path from coordinate arrays
*/
void
points_to_linear_path (cairo_t *cr,
double coord_x[],
double coord_y[],
int n_coords);
void
points_to_bezier_path (cairo_t *cr,
double coord_x[],
double coord_y[],
int n_coords);
void
drawapp_render (cairo_t *cr,
unsigned char *buffer)
{
cairo_save (cr);
cairo_rectangle (cr, 0,0, WIDTH, HEIGHT);
cairo_set_rgb_color (cr, 1,1,1);
cairo_fill (cr);
cairo_move_to (cr, 0,0);
cairo_show_surface (cr, backbuffer, WIDTH, HEIGHT);
cairo_set_line_width (cr, pen_radius*2);
cairo_set_alpha (cr, 0.5);
if (pen_color_is_black) {
cairo_set_rgb_color (cr, 0,0,0);
} else {
cairo_set_rgb_color (cr, 1,1,1);
}
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
points_to_bezier_path (cr, coord_x, coord_y, coord_count);
cairo_stroke (cr);
cairo_restore (cr);
}
void
apply_coords (char *buffer)
{
drawapp_render (cr_save, buffer);
memcpy (buffer, temp_buffer, HEIGHT*STRIDE);
}
void
coords_clear (void)
{
coord_count = 0;
}
void
coords_add (double x, double y)
{
if (coord_count< MAX_COORDS-3) {
coord_x [coord_count]=x;
coord_y [coord_count]=y;
coord_count++;
}
}
void
redraw (GtkCairo *gtkcairo,
cairo_t *cr,
gpointer data)
{
drawapp_render (cr, buffer);
}
void
pen_motion (double x,
double y,
int pen_is_down)
{
if (pen_is_down) {
coords_add (x,y);
gtk_widget_queue_draw (gtkcairo);
}
}
void
pen_down (double x,
double y)
{
coords_add (x,y);
gtk_widget_queue_draw (gtkcairo);
}
void pen_up (double x,
double y)
{
apply_coords (buffer);
coords_clear ();
gtk_widget_queue_draw (gtkcairo);
}
void
init ()
{
coords_clear ();
cr_save = cairo_create ();
memset (buffer, sizeof(buffer), 0);
memset (temp_buffer, sizeof(temp_buffer), 0);
cairo_set_target_image (
cr_save, temp_buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE);
backbuffer = cairo_surface_create_for_image (
buffer, CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT, STRIDE);
}
static gboolean
event_press (GtkWidget *widget,
GdkEventButton *bev,
gpointer user_data)
{
pen_down (bev->x, bev->y);
pen_is_down = 1;
return TRUE;
}
static gboolean
event_release (GtkWidget *widget,
GdkEventButton *bev,
gpointer user_data)
{
pen_up (bev->x, bev->y);
pen_is_down = 0;
return TRUE;
}
static gboolean
event_motion (GtkWidget *widget,
GdkEventMotion *mev,
gpointer user_data)
{
pen_motion (mev->x, mev->y, pen_is_down);
gdk_window_get_pointer (widget->window, NULL, NULL, NULL);
return TRUE;
}
int main (int argc,
char **argv)
{
GtkWidget *mainwin;
gtk_init (&argc, &argv);
mainwin= gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtkcairo = gtk_cairo_new ();
gtk_widget_set_events (gtkcairo,
GDK_EXPOSURE_MASK |
#ifdef USE_HINT
GDK_POINTER_MOTION_HINT_MASK |
#endif
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
gtk_widget_set_size_request (gtkcairo, WIDTH, HEIGHT);
g_signal_connect (G_OBJECT (gtkcairo), "redraw",
G_CALLBACK (redraw), NULL);
g_signal_connect (G_OBJECT (gtkcairo), "motion_notify_event",
G_CALLBACK (event_motion), NULL);
g_signal_connect (G_OBJECT (gtkcairo), "button_press_event",
G_CALLBACK (event_press), NULL);
g_signal_connect (G_OBJECT (gtkcairo), "button_release_event",
G_CALLBACK (event_release), NULL);
gtk_container_add (GTK_CONTAINER (mainwin), gtkcairo);
init ();
gtk_widget_show_all (mainwin);
gtk_main ();
return 0;
}
/* utility function that creates a smooth path from a set
* of coordinates
*/
void
points_to_bezier_path (cairo_t *cr,
double coord_x[],
double coord_y[],
int n_coords)
{
int i;
double smooth_value = 1;
cairo_new_path (cr);
if (!n_coords)
return;
cairo_move_to (cr, coord_x[0], coord_y[0]);
for (i=1;i<n_coords;i++){
double x2 = coord_x[i];
double y2 = coord_y[i];
double x0,y0,x1,y1,x3,y3;
switch (i){
case 1:
x0=coord_x[i-1];
y0=coord_y[i-1];
x1 = coord_x[i-1];
y1 = coord_y[i-1];
break;
case 2:
default:
x0=coord_x[i-2];
y0=coord_y[i-2];
x1 = coord_x[i-1];
y1 = coord_y[i-1];
}
if (i<n_coords+1) {
x3 = coord_x[i+1];
y3 = coord_y[i+1];
} else {
x3 = coord_x[i];
y3 = coord_y[i];
}
{
double xc1 = (x0 + x1) / 2.0;
double yc1 = (y0 + y1) / 2.0;
double xc2 = (x1 + x2) / 2.0;
double yc2 = (y1 + y2) / 2.0;
double xc3 = (x2 + x3) / 2.0;
double yc3 = (y2 + y3) / 2.0;
double len1 = sqrt( (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0) );
double len2 = sqrt( (x2-x1) * (x2-x1) + (y2-y1) * (y2-y1) );
double len3 = sqrt( (x3-x2) * (x3-x2) + (y3-y2) * (y3-y2) );
double k1 = len1 / (len1 + len2);
double k2 = len2 / (len2 + len3);
double xm1 = xc1 + (xc2 - xc1) * k1;
double ym1 = yc1 + (yc2 - yc1) * k1;
double xm2 = xc2 + (xc3 - xc2) * k2;
double ym2 = yc2 + (yc3 - yc2) * k2;
double ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
double ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
double ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
double ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
cairo_curve_to (cr, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2,y2);
}
}
}
/* this function is included, just to be
* able to check the improvement over the easiest method
*/
void
points_to_linear_path (cairo_t *cr,
double coord_x[],
double coord_y[],
int n_coords)
{
int i;
if (!n_coords)
return;
cairo_move_to (cr, coord_x[0], coord_y[0]);
for (i=1;i<n_coords;i++)
cairo_line_to (cr, coord_x[i], coord_y[i]);
}
More information about the cairo-commit
mailing list