[cairo-commit]
cairo-demo/sproing COPYING, NONE, 1.1 Makefile, NONE,
1.1 sproing.c, NONE, 1.1
Kristian Hogsberg
commit at pdx.freedesktop.org
Thu Mar 10 22:52:18 PST 2005
Committed by: krh
Update of /cvs/cairo/cairo-demo/sproing
In directory gabe:/tmp/cvs-serv19263
Added Files:
COPYING Makefile sproing.c
Log Message:
2005-03-11 Kristian Høgsberg <krh at redhat.com>
* Makefile, sproing.c: New cairo demo. Drag a wobbly patch around
for fun.
--- NEW FILE: COPYING ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: Makefile ---
CFLAGS = -Wall -g
CPPFLAGS = $(shell pkg-config --cflags gtk+-2.0 cairo)
LDLIBS = $(shell pkg-config --libs gtk+-2.0 cairo)
LDFLAGS = -g
target = sproing
objs = sproing.o
$(target) : $(objs)
clean :
rm $(target) $(objs)
--- NEW FILE: sproing.c ---
/* -*- mode: c; c-basic-offset: 2 -*- */
#include <gtk/gtk.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <gdk/gdkx.h>
#include <math.h>
typedef struct _Point Point;
struct _Point {
double x, y;
};
typedef struct _Vector Vector;
struct _Vector {
double x, y;
};
typedef struct _Model Model;
typedef struct _Object Object;
typedef struct _Attractor Attractor;
#define MAX_ATTRACTORS 5
struct _Attractor {
Object *object;
Vector offset;
};
struct _Object {
int num_attractors;
Attractor attractors[MAX_ATTRACTORS];
Vector attractor_offset;
Point position;
Point next_position;
Vector velocity;
Vector prev_velocity;
Vector acceleration;
Vector prev_acceleration;
double mass;
double theta;
};
struct _Model {
int num_objects;
Object *objects;
Object attractor;
Object *current_attractor;
double k; /* Spring constant */
double friction; /* Friction constant */
};
static void
model_move_attractor (Model *model, double x, double y)
{
model->current_attractor->position.x = x;
model->current_attractor->position.y = y;
}
static void
model_init_object (Object *object,
double position_x, double position_y,
double velocity_x, double velocity_y, double mass)
{
object->num_attractors = 0;
object->position.x = position_x;
object->position.y = position_y;
object->velocity.x = velocity_x;
object->velocity.y = velocity_y;
object->prev_velocity.x = velocity_x;
object->prev_velocity.y = velocity_y;
object->acceleration.x = 0;
object->acceleration.y = 0;
object->prev_acceleration.x = 0;
object->prev_acceleration.y = 0;
object->mass = mass;
}
static void
model_add_object_attractor (Object *object, Object *attractor_object,
double offset_x, double offset_y)
{
Attractor *attractor;
attractor = &object->attractors[object->num_attractors];
object->num_attractors++;
attractor->object = attractor_object;
attractor->offset.x = offset_x;
attractor->offset.y = offset_y;
}
static void
model_init_grid (Model *model, int width, int height)
{
int x, y, i;
const int hpad = 50, vpad = 50;
model->objects = g_new (Object, width * height);
model->num_objects = width * height;
i = 0;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++) {
model_init_object (&model->objects[i], 200, 150, 0, 0, 20);
#if 1
if (i == 0)
model_add_object_attractor (&model->objects[i],
model->current_attractor,
0, 0);
#endif
#define CX 0
#define CY 0
#if 0
if (x < CX)
model_add_object_attractor (&model->objects[i],
&model->objects[i + 1],
-hpad, 0);
if (x > CX)
model_add_object_attractor (&model->objects[i],
&model->objects[i - 1],
hpad, 0);
if (y < CY)
model_add_object_attractor (&model->objects[i],
&model->objects[i + width],
0, -vpad);
if (y > CY)
model_add_object_attractor (&model->objects[i],
&model->objects[i - width],
0, vpad);
#endif
#if 1
if (x > 0)
model_add_object_attractor (&model->objects[i],
&model->objects[i - 1],
hpad, 0);
if (y > 0)
model_add_object_attractor (&model->objects[i],
&model->objects[i - width],
0, vpad);
#endif
#if 0
if (x < width - 1)
model_add_object_attractor (&model->objects[i],
&model->objects[i + 1],
-hpad, 0);
if (y < height - 1)
model_add_object_attractor (&model->objects[i],
&model->objects[i + width],
0, -vpad);
#endif
i++;
}
}
static void
model_init (Model *model)
{
model->current_attractor = &model->attractor;
model_move_attractor (model, 200, 140);
model->k = 2.0;
model->friction = 4.2;
model_init_grid (model, 4, 4);
}
static void
model_step_object (Model *model, Object *object)
{
Vector target;
Vector force;
int i;
force.x = 0;
force.y = 0;
for (i = 0; i < object->num_attractors; i++) {
target.x = object->attractors[i].object->position.x +
object->attractors[i].offset.x;
target.y = object->attractors[i].object->position.y +
object->attractors[i].offset.y;
force.x += model->k * (target.x - object->position.x) -
model->friction * object->velocity.x;
force.y += model->k * (target.y - object->position.y) -
model->friction * object->velocity.y;
}
object->prev_acceleration.x = object->acceleration.x;
object->prev_acceleration.y = object->acceleration.y;
object->acceleration.x = force.x / object->mass;
object->acceleration.y = force.y / object->mass;
object->prev_velocity.x = object->velocity.x;
object->prev_velocity.y = object->velocity.y;
object->velocity.x +=
(object->acceleration.x + object->prev_acceleration.x) / 2.0 +
object->acceleration.x - object->prev_acceleration.x;
object->velocity.y +=
(object->acceleration.y + object->prev_acceleration.y) / 2.0 +
object->acceleration.y - object->prev_acceleration.y;
object->next_position.x = object->position.x +
(object->velocity.x + object->prev_velocity.x) / 2.0 +
object->velocity.x - object->prev_velocity.x;
object->next_position.y = object->position.y +
(object->velocity.y + object->prev_velocity.y) / 2.0 +
object->velocity.y - object->prev_velocity.y;
object->theta += 0.05;
}
static void
model_step (Model *model)
{
int i;
for (i = 0; i < model->num_objects; i++)
model_step_object (model, &model->objects[i]);
for (i = 0; i < model->num_objects; i++) {
if (&model->objects[i] == model->current_attractor)
continue;
model->objects[i].position = model->objects[i].next_position;
}
}
static cairo_t *
begin_paint (GdkDrawable *window)
{
Display *dpy;
Drawable xid;
GdkDrawable *drawable;
gint x_offset, y_offset;
cairo_t *cr;
if (GDK_IS_WINDOW (window))
gdk_window_get_internal_paint_info (window, &drawable,
&x_offset, &y_offset);
else
drawable = window;
dpy = gdk_x11_drawable_get_xdisplay (drawable);
xid = gdk_x11_drawable_get_xid (drawable);
cr = cairo_create ();
cairo_set_target_drawable (cr, dpy, xid);
if (GDK_IS_WINDOW (window))
cairo_translate (cr, -x_offset, -y_offset);
return cr;
}
static void
end_paint (cairo_t *cr)
{
cairo_destroy (cr);
}
typedef struct _Color Color;
struct _Color {
double red, green, blue;
};
static Color red = { 1, 0, 0 };
static Color blue = { 0, 0, 1 };
static void
draw_ball (GtkWidget *widget,
gdouble x,
gdouble y,
Color *color)
{
cairo_t *cr;
cr = begin_paint (widget->window);
cairo_set_rgb_color (cr, color->red, color->green, color->blue);
cairo_set_alpha (cr, 0.5);
cairo_new_path (cr);
cairo_arc (cr, x, y, 3, 0, 2 * G_PI);
cairo_fill (cr);
cairo_new_path (cr);
cairo_arc (cr, x, y, 10, 0, 2 * G_PI);
cairo_stroke (cr);
end_paint (cr);
}
static void
draw_star (GtkWidget *widget,
gdouble cx,
gdouble cy,
double theta,
Color *color)
{
const int spike_count = 5;
const int inner_radius = 2;
const int outer_radius = 4;
cairo_t *cr;
double x, y;
int i;
cr = begin_paint (widget->window);
cairo_set_rgb_color (cr, color->red, color->green, color->blue);
cairo_set_alpha (cr, 0.5);
cairo_new_path (cr);
for (i = 0; i < spike_count; i++) {
x = cx + cos ((i * 2) * M_PI / spike_count + theta) * inner_radius;
y = cy + sin ((i * 2) * M_PI / spike_count + theta) * inner_radius;
if (i == 0)
cairo_move_to (cr, x, y);
else
cairo_line_to (cr, x, y);
x = cx + cos ((i * 2 + 1) * M_PI / spike_count + theta) * outer_radius;
y = cy + sin ((i * 2 + 1) * M_PI / spike_count + theta) * outer_radius;
cairo_line_to (cr, x, y);
}
cairo_fill (cr);
end_paint (cr);
}
void
evaluate_bezier_point (Object *objects,
double u, double v,
double *patch_x, double *patch_y)
{
double coeffs_u[4], coeffs_v[4];
double x, y;
int i, j;
coeffs_u[0] = (1 - u) * (1 - u) * (1 - u);
coeffs_u[1] = 3 * u * (1 - u) * (1 - u);
coeffs_u[2] = 3 * u * u * (1 - u);
coeffs_u[3] = u * u * u;
coeffs_v[0] = (1 - v) * (1 - v) * (1 - v);
coeffs_v[1] = 3 * v * (1 - v) * (1 - v);
coeffs_v[2] = 3 * v * v * (1 - v);
coeffs_v[3] = v * v * v;
x = 0;
y = 0;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
{
x += coeffs_u[i] * coeffs_v[j] * objects[j * 4 + i].position.x;
y += coeffs_u[i] * coeffs_v[j] * objects[j * 4 + i].position.y;
}
*patch_x = x;
*patch_y = y;
}
static void
draw_spline_grid (GtkWidget *widget,
Model *model)
{
cairo_t *cr;
double u, v;
double x, y;
cr = begin_paint (widget->window);
cairo_set_rgb_color (cr, 0, 0, 0);
cairo_set_line_width (cr, 0.8);
cairo_new_path (cr);
for (u = 0; u <= 1.01; u += 0.2)
{
for (v = 0; v <= 1.01; v += 0.05)
{
evaluate_bezier_point (model->objects, u, v, &x, &y);
if (v == 0)
cairo_move_to (cr, x, y);
else
cairo_line_to (cr, x, y);
}
}
for (v = 0; v <= 1.01; v += 0.2)
{
for (u = 0; u <= 1.01; u += 0.05)
{
evaluate_bezier_point (model->objects, u, v, &x, &y);
if (u == 0)
cairo_move_to (cr, x, y);
else
cairo_line_to (cr, x, y);
}
}
cairo_stroke (cr);
end_paint (cr);
}
static void
draw_spline_spiral (GtkWidget *widget,
Model *model)
{
cairo_t *cr;
double u, v, r, phi, offset;
double x, y;
cr = begin_paint (widget->window);
cairo_set_rgb_color (cr, 0, 0, 0);
cairo_set_line_width (cr, 0.8);
cairo_new_path (cr);
offset = 0.01;
for (phi = 0, r = 0; r < 0.5; phi += 0.1, r += 0.002)
{
u = cos (phi) * (r + offset) + 0.5;
v = sin (phi) * (r + offset)+ 0.5;
offset = -offset;
evaluate_bezier_point (model->objects, u, v, &x, &y);
if (phi < 0.05)
cairo_move_to (cr, x, y);
else
cairo_line_to (cr, x, y);
}
cairo_stroke (cr);
end_paint (cr);
}
static gboolean
scribble_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
Model *model = data;
int i;
#if 0
draw_spline_spiral (widget, model);
#else
draw_spline_grid (widget, model);
#endif
draw_ball (widget, model->current_attractor->position.x,
model->current_attractor->position.y, &red);
#if 1
for (i = 0; i < model->num_objects; i++) {
draw_star (widget, model->objects[i].position.x,
model->objects[i].position.y, model->objects[i].theta, &blue);
}
#endif
return TRUE;
}
static gboolean
scribble_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer data)
{
Model *model = data;
if (event->button == 1)
model_move_attractor (model, event->x, event->y);
return TRUE;
}
static gboolean
scribble_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer data)
{
Model *model = data;
int x, y;
GdkModifierType state;
gdk_window_get_pointer (event->window, &x, &y, &state);
if (state & GDK_BUTTON1_MASK)
model_move_attractor (model, x, y);
return TRUE;
}
static void
spring_constant_changed (GtkSpinButton *spinbutton, gpointer user_data)
{
Model *model = user_data;
model->k = gtk_spin_button_get_value (spinbutton);
}
static void
friction_changed (GtkSpinButton *spinbutton, gpointer user_data)
{
Model *model = user_data;
model->friction = gtk_spin_button_get_value (spinbutton);
}
GtkWidget *
create_spinners (Model *model)
{
GtkWidget *hbox;
GtkWidget *spinner, *label;
hbox = gtk_hbox_new (FALSE, 8);
label = gtk_label_new_with_mnemonic ("_Spring constant:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
spinner = gtk_spin_button_new_with_range (0.05, 15.00, 0.05);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinner), model->k);
g_signal_connect (spinner, "value-changed",
G_CALLBACK (spring_constant_changed), model);
label = gtk_label_new_with_mnemonic ("_Friction:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
spinner = gtk_spin_button_new_with_range (0.05, 15.00, 0.05);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinner);
gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinner), model->friction);
g_signal_connect (spinner, "value-changed",
G_CALLBACK (friction_changed), model);
return hbox;
}
GtkWidget *
create_window (Model *model)
{
GtkWidget *window;
GtkWidget *frame;
GtkWidget *vbox;
GtkWidget *da;
GtkWidget *spinners;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Drawing Area");
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), &window);
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
gtk_container_add (GTK_CONTAINER (window), vbox);
/*
* Create the scribble area
*/
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
da = gtk_drawing_area_new ();
/* set a minimum size */
gtk_widget_set_size_request (da, 400, 300);
gtk_container_add (GTK_CONTAINER (frame), da);
/* Signals used to handle backing pixmap */
g_signal_connect (da, "expose_event",
G_CALLBACK (scribble_expose_event), model);
/* Event signals */
g_signal_connect (da, "motion_notify_event",
G_CALLBACK (scribble_motion_notify_event), model);
g_signal_connect (da, "button_press_event",
G_CALLBACK (scribble_button_press_event), model);
/* Ask to receive events the drawing area doesn't normally
* subscribe to
*/
gtk_widget_set_events (da, gtk_widget_get_events (da)
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK);
spinners = create_spinners (model);
gtk_box_pack_start (GTK_BOX (vbox), spinners, FALSE, FALSE, 0);
return da;
}
typedef struct _Closure Closure;
struct _Closure {
GtkWidget *drawing_area;
Model *model;
int i;
};
static gint
timeout_callback (gpointer data)
{
Closure *closure = data;
model_step (closure->model);
closure->i++;
if (closure->i == 1) {
gtk_widget_queue_draw (closure->drawing_area);
closure->i = 0;
}
return TRUE;
}
int
main (int argc, char *argv[])
{
Closure closure;
Model model;
gtk_init (&argc, &argv);
model_init (&model);
closure.drawing_area = create_window (&model);
closure.i = 0;
gtk_widget_show_all (gtk_widget_get_toplevel (closure.drawing_area));
closure.model = &model;
g_timeout_add (10, timeout_callback, &closure);
gtk_main ();
return 0;
}
More information about the cairo-commit
mailing list