Re: cairo-1.13 finally opens
"Henry (Yu) Song - SISA" <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <3955FA337689574EB32F94B12A7E6E9E59F13FFE@sisaex01sj> |
Hi, Chris I have added Guassian blur and shadow support in cairo. It is available in filters-wip branch from https://github.com/SRA-SiliconValley/cairogles The gaussian blur and shadow support are available for GL/GLES, image, xcb and quartz backend. features in filters-wip 1. synced with cairo-1.12.14 2. gaussian blur for gl/gles, image, xcb and quartz backends 3. gl msaa compositor supports GL, GLESv3 4. gl msaa compositor supports GLESv2 with the following three extensions: GL_EXT_multisampled_render_to_texture, GL_IMG_multisampled_render_to_texture, and GL_ANGLE_multisample_framebuffer/GL_ANGLE_framebuffer_blit 5. support both drop shadow and inset shadow for gl/gles, image, xcb and quartz backends 6. support shadow caching 7. support custom shadow (e.g., you can draw arbitrary shadow path) Few side notes 1. Both drop shadow and inset shadow work correctly with CAIRO_OPERATOR_OVER. I am not sure what are supposed to be for shadow with other operators, Once that is cleared, I can certainly make it work 2. The shadow calls start at each backend surface (e.g, cairo-image-surface, cairo-gl-surface, and etc), I would really like to move shadow calls into cairo-surface.c 3. I added a cairo API to allow arbitrary inset shadow path that I am not too happy about it, the API might change later. Attached please find four examples of shadows (both inset and drop shadow) for image, xcb, gl and gles backends run like this "./cairo-xcb-shadow-ring --enable-cache 50" - renders 50 shadowed rings with shadow cache enabled "./cairo-xcb-shadow-ring --disable-cache 50" - renders 50 shadowed rings with shadow cache disabled. To run gl/gles sample with msaa compositor, set CAIRO_GL_COMPOSITOR=msaa, set and unset this env to observe performance difference. You need HD3000/HD4000, mesa 9.1+ to support multisampling. Otherwise, you can test on amd fglrx or nvidia drivers with glx which also supports MSAA. No open source radeon or nouveau though. For cairo-egl-shadow-ring, you need HD3000/Hd4000 with mesa 9.1+ that supports glesv3. You can configure cairo to support glesv3 - "./configure --prefix=.... --enable-gl=no --enable-egl=yes --enable-glesv2=no --enable-glesv3=yes" I have other sample codes to demo shadow/blur with paint/stroke/mask/glyph. Anyone interested, I will provide. If you are interested in quartz shadow/blur, or interested in shadow in wayland, I will provide as well. Any comments. patches are extremely welcome. Thanks Henry ________________________________________ From: [email protected] [[email protected]] on behalf of Chris Wilson [[email protected]] Sent: Thursday, September 05, 2013 8:23 AM To: [email protected] Subject: [cairo] cairo-1.13 finally opens But not for long! I've merged the two features that had been posted over the last 6 months (sorry it has taken so long :(, and I plan to make the first snapshot relatively quickly, say next w/e (14th September). After that, fix some more of the known and latent bugs in 1.12, and make sure the new API in cairo-1.13 is well tested before blessing it with a full release (say mid-October). If you do have any other features ready for Cairo, please do post them now. Otherwise, please check over the device-scale and downscaling work! As always, have fun with Cairo! -Chris -- Chris Wilson, Intel Open Source Technology Centre -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo
cairo-glx-shadow-ring.c
(text/x-csrc, 8.8 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cairo.h>
#include <cairo-gl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define WIDTH 800
#define HEIGHT 768
//#define MAX_VELOCITY WIDTH / 5
#define MAX_VELOCITY 500
//#define RADIUS 48
double RADIUS = 50;
typedef struct _particle
{
double angle;
double velocity;
double x;
double y;
double color[3];
double line_width;
double shadow_color[4];
double shadow_x_blur;
double shadow_y_blur;
double shadow_x_offset;
double shadow_y_offset;
double spread_color[4];
double spread_x_blur;
double spread_y_blur;
double spread_x_offset;
double spread_y_offset;
double spread_line_width;
double drop_color[4];
double drop_x_blur;
double drop_y_blur;
double drop_x_offset;
double drop_y_offset;
} particle_t;
static void
generate_color (double *color)
{
int i;
for (i = 0; i < 3; i++)
color[i] = (int)(drand48 () * 3)/3.0;
}
static void particle_init (particle_t *particle)
{
particle->angle = drand48 () * 2 * M_PI;
particle->velocity = MAX_VELOCITY / 8.0 * 7 * drand48 () + MAX_VELOCITY / 8.0;
particle->x = WIDTH / 2 - RADIUS;
particle->y = HEIGHT / 2 - RADIUS;
generate_color (particle->color);
particle->line_width = 20;
particle->shadow_color[0] = 0;
particle->shadow_color[1] = 0;
particle->shadow_color[2] = 0;
particle->shadow_color[3] = 1;
particle->shadow_x_blur = 5;
particle->shadow_y_blur = 2;
particle->shadow_x_offset = 6;
particle->shadow_y_offset = 1;
particle->spread_color[0] = 1;
particle->spread_color[1] = 1;
particle->spread_color[2] = 1;
particle->spread_color[3] = 1;
particle->spread_x_blur = 5;
particle->spread_y_blur = 2;
particle->spread_x_offset = 6;
particle->spread_y_offset = 1;
particle->spread_line_width = 3;
particle->drop_color[0] = 0;
particle->drop_color[1] = 0;
particle->drop_color[2] = 0;
particle->drop_color[3] = 0.8;
particle->drop_x_blur = 10;
particle->drop_y_blur = 10;
particle->drop_x_offset = -42;
particle->drop_y_offset = -7;
}
static void particle_position (particle_t *particle, double delta)
{
double x = particle->x + cos (particle->angle) * particle->velocity * delta;
double y = particle->y + sin (particle->angle) * particle->velocity * delta;
if (x + RADIUS > WIDTH) {
if (particle->angle >= 0 && particle->angle < M_PI / 2)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI / 2 * 3)
particle->angle -= (particle->angle - M_PI /2 * 3) * 2;
x = WIDTH - RADIUS;
}
if (x - RADIUS < 0) {
if (particle->angle > M_PI / 2 && particle->angle < M_PI)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI && particle->angle < M_PI / 2 * 3)
particle->angle += (M_PI / 2 * 3 - particle->angle) * 2;
x = RADIUS;
}
if (y + RADIUS > HEIGHT) {
if (particle->angle > 0 && particle->angle < 2 * M_PI)
particle->angle = M_PI * 2 - particle->angle;
y = HEIGHT - RADIUS;
}
if (y - RADIUS < 0) {
if (particle->angle > M_PI && particle->angle < M_PI * 2)
particle->angle = particle->angle - (particle->angle - M_PI) * 2;
y = RADIUS;
}
particle->x = x;
particle->y = y;
}
static void
fill_particle (cairo_t *cr, particle_t *particle)
{
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
/* drop shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->drop_color[0],
particle->drop_color[1],
particle->drop_color[2],
particle->drop_color[3]);
cairo_set_shadow_blur (cr, particle->drop_x_blur, particle->drop_y_blur);
cairo_set_shadow_offset (cr, particle->drop_x_offset, particle->drop_y_offset);
cairo_stroke (cr);
/* ring with inset shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 0);
cairo_set_shadow (cr, CAIRO_SHADOW_INSET);
cairo_set_shadow_rgba (cr, particle->shadow_color[0],
particle->shadow_color[1],
particle->shadow_color[2],
particle->shadow_color[3]);
cairo_set_shadow_blur (cr, particle->shadow_x_blur, particle->shadow_y_blur);
cairo_set_shadow_offset (cr, particle->shadow_x_offset, particle->shadow_y_offset);
cairo_stroke (cr);
/* draw spread */
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->spread_color[0],
particle->spread_color[1],
particle->spread_color[2],
particle->spread_color[3]);
cairo_set_shadow_blur (cr, particle->spread_x_blur, particle->spread_y_blur);
cairo_set_line_width (cr, particle->spread_line_width);
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
cairo_set_shadow_offset (cr, particle->spread_x_offset, particle->spread_y_offset);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_stroke (cr);
//cairo_fill (cr);
}
static double
get_tick (void)
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_sec + now.tv_usec / 1000000.0;
}
static void
fill (cairo_t *cr, particle_t *particles, int num_particles, double delta)
{
int i;
for (i = 0; i < num_particles; i++) {
particle_position (&particles[i], delta);
fill_particle (cr, &particles[i]);
}
}
static void
render (cairo_t *cr, cairo_surface_t *surface,
particle_t *particles, int num_particles, double delta,
int enable)
{
cairo_save (cr);
/* clear surface */
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
cairo_fill (cr);
cairo_shadow_set_enable (cr, enable);
//cairo_set_tolerance (cr, 0.45);
fill (cr, particles, num_particles, delta);
/* swap buffers */
cairo_gl_surface_swapbuffers (surface);
cairo_restore (cr);
}
int main (int argc, char **argv)
{
int attribs[] = {
GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_ALPHA_SIZE, 1,
GLX_STENCIL_SIZE, 1,
GLX_SAMPLES, 4,
GLX_SAMPLE_BUFFERS, 1,
GLX_DOUBLEBUFFER,
None
};
XVisualInfo *vi;
GLXContext ctx;
cairo_surface_t *window_surface;
cairo_t *window_cr;
Display *dpy;
XSetWindowAttributes xattr;
Window window;
cairo_device_t *device;
int counter;
int total;
int i;
double start, stop;
particle_t *particles;
int num_particles = 500;
double start_frame, stop_frame, delta;
int enable = 0;
counter = 0;
total = 50;
if (argc == 2)
enable = ! (strcmp (argv[1], "--enable-cache"));
else if (argc == 3) {
enable = ! (strcmp (argv[1], "--enable-cache"));
num_particles = atoi (argv[2]);
}
dpy = XOpenDisplay (NULL);
if (!dpy) {
fprintf (stderr, "fail to open display: %s\n", XDisplayName (0));
return -1;
}
vi = glXChooseVisual (dpy, DefaultScreen (dpy), attribs);
if (!vi) {
fprintf (stderr, "fail to crete rgba, double-buffered visual\n");
XCloseDisplay (dpy);
return -1;
}
xattr.colormap = XCreateColormap (dpy, RootWindow (dpy, vi->screen),
vi->visual, AllocNone);
xattr.border_pixel = 0;
window = XCreateWindow (dpy, DefaultRootWindow (dpy), 100, 50,
WIDTH, HEIGHT, 0, vi->depth,
InputOutput, vi->visual,
CWBorderPixel | CWColormap,
&xattr);
XMapWindow (dpy, window);
ctx = glXCreateContext (dpy, vi, NULL, True);
XFree (vi);
device = cairo_glx_device_create (dpy, ctx);
cairo_gl_device_set_thread_aware (device, 0);
window_surface = cairo_gl_surface_create_for_window (device,
window,
WIDTH,
HEIGHT);
window_cr = cairo_create (window_surface);
cairo_shadow_enable_cache (window_cr, enable);
particles = (particle_t *) malloc (sizeof (particle_t) * num_particles);
for (i = 0; i < num_particles; i++)
particle_init (&particles[i]);
delta = 0;
for (;;) {
if (counter == 0)
start = get_tick ();
start_frame = get_tick ();
render (window_cr, window_surface, particles, num_particles,
delta, enable);
stop_frame = get_tick ();
delta = stop_frame - start_frame;
counter++;
if (counter == total) {
counter = 0;
stop = get_tick ();
fprintf (stdout, "fps = %0.2f\n", total / (stop - start));
}
}
free (particles);
cairo_destroy (window_cr);
sleep (10);
cairo_surface_destroy (window_surface);
cairo_device_destroy (device);
glXDestroyContext (dpy, ctx);
XDestroyWindow (dpy, window);
XCloseDisplay (dpy);
return 0;
}
cairo-image-shadow-ring.c
(text/x-csrc, 9.3 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cairo.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define WIDTH 1024
#define HEIGHT 768
//#define MAX_VELOCITY WIDTH / 5
#define MAX_VELOCITY 500
//#define RADIUS 48
double RADIUS = 50;
typedef struct _particle
{
double angle;
double velocity;
double x;
double y;
double color[3];
double line_width;
double shadow_color[4];
double shadow_x_blur;
double shadow_y_blur;
double shadow_x_offset;
double shadow_y_offset;
double spread_color[4];
double spread_x_blur;
double spread_y_blur;
double spread_x_offset;
double spread_y_offset;
double spread_line_width;
double drop_color[4];
double drop_x_blur;
double drop_y_blur;
double drop_x_offset;
double drop_y_offset;
} particle_t;
static void
generate_color (double *color)
{
int i;
for (i = 0; i < 3; i++)
color[i] = (int)(drand48 () * 3)/3.0;
}
static void particle_init (particle_t *particle)
{
particle->angle = drand48 () * 2 * M_PI;
particle->velocity = MAX_VELOCITY / 8.0 * 7 * drand48 () + MAX_VELOCITY / 8.0;
particle->x = WIDTH / 2 - RADIUS;
particle->y = HEIGHT / 2 - RADIUS;
generate_color (particle->color);
particle->line_width = 20;
particle->shadow_color[0] = 0;
particle->shadow_color[1] = 0;
particle->shadow_color[2] = 0;
particle->shadow_color[3] = 1;
particle->shadow_x_blur = 5;
particle->shadow_y_blur = 2;
particle->shadow_x_offset = 6;
particle->shadow_y_offset = 1;
particle->spread_color[0] = 1;
particle->spread_color[1] = 1;
particle->spread_color[2] = 1;
particle->spread_color[3] = 1;
particle->spread_x_blur = 5;
particle->spread_y_blur = 2;
particle->spread_x_offset = 6;
particle->spread_y_offset = 1;
particle->spread_line_width = 3;
particle->drop_color[0] = 0;
particle->drop_color[1] = 0;
particle->drop_color[2] = 0;
particle->drop_color[3] = 0.8;
particle->drop_x_blur = 10;
particle->drop_y_blur = 10;
particle->drop_x_offset = -42;
particle->drop_y_offset = -7;
}
static void particle_position (particle_t *particle, double delta)
{
double x = particle->x + cos (particle->angle) * particle->velocity * delta;
double y = particle->y + sin (particle->angle) * particle->velocity * delta;
if (x + RADIUS > WIDTH) {
if (particle->angle >= 0 && particle->angle < M_PI / 2)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI / 2 * 3)
particle->angle -= (particle->angle - M_PI /2 * 3) * 2;
x = WIDTH - RADIUS;
}
if (x - RADIUS < 0) {
if (particle->angle > M_PI / 2 && particle->angle < M_PI)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI && particle->angle < M_PI / 2 * 3)
particle->angle += (M_PI / 2 * 3 - particle->angle) * 2;
x = RADIUS;
}
if (y + RADIUS > HEIGHT) {
if (particle->angle > 0 && particle->angle < 2 * M_PI)
particle->angle = M_PI * 2 - particle->angle;
y = HEIGHT - RADIUS;
}
if (y - RADIUS < 0) {
if (particle->angle > M_PI && particle->angle < M_PI * 2)
particle->angle = particle->angle - (particle->angle - M_PI) * 2;
y = RADIUS;
}
particle->x = x;
particle->y = y;
}
static void
fill_particle (cairo_t *cr, particle_t *particle)
{
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
/* drop shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->drop_color[0],
particle->drop_color[1],
particle->drop_color[2],
particle->drop_color[3]);
cairo_set_shadow_blur (cr, particle->drop_x_blur, particle->drop_y_blur);
cairo_set_shadow_offset (cr, particle->drop_x_offset, particle->drop_y_offset);
cairo_stroke (cr);
/* ring with inset shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 0);
cairo_set_shadow (cr, CAIRO_SHADOW_INSET);
cairo_set_shadow_rgba (cr, particle->shadow_color[0],
particle->shadow_color[1],
particle->shadow_color[2],
particle->shadow_color[3]);
cairo_set_shadow_blur (cr, particle->shadow_x_blur, particle->shadow_y_blur);
cairo_set_shadow_offset (cr, particle->shadow_x_offset, particle->shadow_y_offset);
cairo_stroke (cr);
/* draw spread */
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->spread_color[0],
particle->spread_color[1],
particle->spread_color[2],
particle->spread_color[3]);
cairo_set_shadow_blur (cr, particle->spread_x_blur, particle->spread_y_blur);
cairo_set_line_width (cr, particle->spread_line_width);
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
cairo_set_shadow_offset (cr, particle->spread_x_offset, particle->spread_y_offset);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_stroke (cr);
//cairo_fill (cr);
}
static double
get_tick (void)
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_sec + now.tv_usec / 1000000.0;
}
static void
fill (cairo_t *cr, particle_t *particles, int num_particles, double delta)
{
int i;
for (i = 0; i < num_particles; i++) {
particle_position (&particles[i], delta);
fill_particle (cr, &particles[i]);
}
}
static void
render (cairo_t *cr, cairo_surface_t *surface,
particle_t *particles, int num_particles, double delta,
int enable)
{
cairo_save (cr);
/* clear surface */
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
cairo_fill (cr);
cairo_shadow_enable_cache (cr, enable);
cairo_set_tolerance (cr, 0.45);
fill (cr, particles, num_particles, delta);
cairo_restore (cr);
}
static int
convert_surface_to_ximage (XImage *image, cairo_surface_t *surface)
{
unsigned char *data = cairo_image_surface_get_data (surface);
image->width = cairo_image_surface_get_width (surface);
image->height = cairo_image_surface_get_height (surface);
image->format = ZPixmap;
image->data = data;
image->bitmap_unit = 4 * 8;
image->byte_order = LSBFirst;
image->bitmap_bit_order = LSBFirst;
image->bitmap_pad = 4 * 8;
image->depth = 32;
image->bytes_per_line = image->width * 4;
image->bits_per_pixel = 4 * 8;
Status status = XInitImage (image);
return status;
}
static Bool wait_for_notify (Display *dpy, XEvent *event, XPointer arg)
{
Window win = (Window) arg;
return (event->type == MapNotify) && (event->xmap.window == win);
}
int main (int argc, char **argv)
{
cairo_surface_t *window_surface;
cairo_t *window_cr;
cairo_device_t *device;
int counter;
int total;
int i;
double start, stop;
particle_t *particles;
int num_particles = 500;
double start_frame, stop_frame, delta;
int enable = 0;
counter = 0;
total = 50;
if (argc == 2)
enable = ! (strcmp (argv[1], "--enable-cache"));
else if (argc == 3) {
enable = ! (strcmp (argv[1], "--enable-cache"));
num_particles = atoi (argv[2]);
}
Display *dpy = XOpenDisplay (NULL);
if (!dpy) {
fprintf (stderr, "fail to open display: %s\n", XDisplayName (0));
return -1;
}
int screen = DefaultScreen (dpy);
XVisualInfo vi;
XSetWindowAttributes attrs;
XMatchVisualInfo (dpy, screen, 32, TrueColor, &vi);
attrs.border_pixel = 0;
attrs.event_mask = StructureNotifyMask;
attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy),
vi.visual, AllocNone);
Window win = XCreateWindow (dpy, DefaultRootWindow (dpy),
0, 0,
WIDTH, HEIGHT,
0,
vi.depth,
InputOutput, vi.visual,
CWBorderPixel | CWColormap | CWEventMask,
&attrs);
XMapWindow (dpy, win);
XEvent event;
XIfEvent (dpy, &event, wait_for_notify, (XPointer)win);
GC gc = XCreateGC (dpy, win, 0, NULL);
window_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
WIDTH, HEIGHT);
window_cr = cairo_create (window_surface);
particles = (particle_t *) malloc (sizeof (particle_t) * num_particles);
for (i = 0; i < num_particles; i++)
particle_init (&particles[i]);
XImage image;
delta = 0;
for (;;) {
if (counter == 0)
start = get_tick ();
start_frame = get_tick ();
render (window_cr, window_surface, particles, num_particles,
delta, enable);
stop_frame = get_tick ();
delta = stop_frame - start_frame;
counter++;
if (convert_surface_to_ximage (&image, window_surface)) {
XPutImage (dpy, win, gc, &image,
0, 0,
0, 0,
WIDTH, HEIGHT);
XSync (dpy, False);
}
if (counter == total) {
counter = 0;
stop = get_tick ();
fprintf (stdout, "fps = %0.2f\n", total / (stop - start));
}
}
free (particles);
cairo_destroy (window_cr);
sleep (10);
cairo_surface_destroy (window_surface);
XFreeGC (dpy, gc);
XDestroyImage (&image);
XDestroyWindow (dpy, win);
XCloseDisplay (dpy);
return 0;
}
cairo-xcb-shadow-ring.c
(text/x-csrc, 9.1 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cairo.h>
#include <cairo-xcb.h>
#include <xcb/xcb.h>
#include <xcb/xcb_util.h>
#define WIDTH 1024
#define HEIGHT 768
//#define MAX_VELOCITY WIDTH / 5
#define MAX_VELOCITY 500
double RADIUS = 50;
typedef struct _particle
{
double angle;
double velocity;
double x;
double y;
double color[3];
double line_width;
double shadow_color[4];
double shadow_x_blur;
double shadow_y_blur;
double shadow_x_offset;
double shadow_y_offset;
double spread_color[4];
double spread_x_blur;
double spread_y_blur;
double spread_x_offset;
double spread_y_offset;
double spread_line_width;
double drop_color[4];
double drop_x_blur;
double drop_y_blur;
double drop_x_offset;
double drop_y_offset;
} particle_t;
static void
generate_color (double *color)
{
int i;
for (i = 0; i < 3; i++)
color[i] = (int)(drand48 () * 3)/3.0;
}
static void particle_init (particle_t *particle)
{
particle->angle = drand48 () * 2 * M_PI;
particle->velocity = MAX_VELOCITY / 8.0 * 7 * drand48 () + MAX_VELOCITY / 8.0;
particle->x = WIDTH / 2 - RADIUS;
particle->y = HEIGHT / 2 - RADIUS;
generate_color (particle->color);
particle->line_width = 20;
particle->shadow_color[0] = 0;
particle->shadow_color[1] = 0;
particle->shadow_color[2] = 0;
particle->shadow_color[3] = 1;
particle->shadow_x_blur = 5;
particle->shadow_y_blur = 2;
particle->shadow_x_offset = 6;
particle->shadow_y_offset = 1;
particle->spread_color[0] = 1;
particle->spread_color[1] = 1;
particle->spread_color[2] = 1;
particle->spread_color[3] = 1;
particle->spread_x_blur = 5;
particle->spread_y_blur = 2;
particle->spread_x_offset = 6;
particle->spread_y_offset = 1;
particle->spread_line_width = 3;
particle->drop_color[0] = 0;
particle->drop_color[1] = 0;
particle->drop_color[2] = 0;
particle->drop_color[3] = 0.8;
particle->drop_x_blur = 10;
particle->drop_y_blur = 10;
particle->drop_x_offset = -42;
particle->drop_y_offset = -7;
}
static void particle_position (particle_t *particle, double delta)
{
double x = particle->x + cos (particle->angle) * particle->velocity * delta;
double y = particle->y + sin (particle->angle) * particle->velocity * delta;
if (x + RADIUS > WIDTH) {
if (particle->angle >= 0 && particle->angle < M_PI / 2)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI / 2 * 3)
particle->angle -= (particle->angle - M_PI /2 * 3) * 2;
x = WIDTH - RADIUS;
}
if (x - RADIUS < 0) {
if (particle->angle > M_PI / 2 && particle->angle < M_PI)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI && particle->angle < M_PI / 2 * 3)
particle->angle += (M_PI / 2 * 3 - particle->angle) * 2;
x = RADIUS;
}
if (y + RADIUS > HEIGHT) {
if (particle->angle > 0 && particle->angle < 2 * M_PI)
particle->angle = M_PI * 2 - particle->angle;
y = HEIGHT - RADIUS;
}
if (y - RADIUS < 0) {
if (particle->angle > M_PI && particle->angle < M_PI * 2)
particle->angle = particle->angle - (particle->angle - M_PI) * 2;
y = RADIUS;
}
particle->x = x;
particle->y = y;
}
static void
fill_particle (cairo_t *cr, particle_t *particle)
{
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
/* drop shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->drop_color[0],
particle->drop_color[1],
particle->drop_color[2],
particle->drop_color[3]);
cairo_set_shadow_blur (cr, particle->drop_x_blur, particle->drop_y_blur);
cairo_set_shadow_offset (cr, particle->drop_x_offset, particle->drop_y_offset);
cairo_stroke (cr);
/* ring with inset shadow */
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_set_draw_shadow_only (cr, 0);
cairo_set_shadow (cr, CAIRO_SHADOW_INSET);
cairo_set_shadow_rgba (cr, particle->shadow_color[0],
particle->shadow_color[1],
particle->shadow_color[2],
particle->shadow_color[3]);
cairo_set_shadow_blur (cr, particle->shadow_x_blur, particle->shadow_y_blur);
cairo_set_shadow_offset (cr, particle->shadow_x_offset, particle->shadow_y_offset);
cairo_stroke (cr);
/* draw spread */
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_shadow_rgba (cr, particle->spread_color[0],
particle->spread_color[1],
particle->spread_color[2],
particle->spread_color[3]);
cairo_set_shadow_blur (cr, particle->spread_x_blur, particle->spread_y_blur);
cairo_set_line_width (cr, particle->spread_line_width);
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
cairo_set_shadow_offset (cr, particle->spread_x_offset, particle->spread_y_offset);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_stroke (cr);
//cairo_fill (cr);
}
static double
get_tick (void)
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_sec + now.tv_usec / 1000000.0;
}
static void
fill (cairo_t *cr, particle_t *particles, int num_particles, double delta)
{
int i;
for (i = 0; i < num_particles; i++) {
particle_position (&particles[i], delta);
fill_particle (cr, &particles[i]);
}
}
static void
render (cairo_t *cr, cairo_surface_t *surface,
particle_t *particles, int num_particles, double delta,
int enable)
{
cairo_save (cr);
/* clear surface */
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
cairo_fill (cr);
cairo_shadow_enable_cache (cr, enable);
cairo_set_tolerance (cr, 0.25);
fill (cr, particles, num_particles, delta);
cairo_restore (cr);
}
static xcb_visualtype_t *
lookup_visual (xcb_screen_t *s, xcb_visualid_t visual)
{
xcb_depth_iterator_t iter;
iter = xcb_screen_allowed_depths_iterator (s);
for (; iter.rem; xcb_depth_next (&iter)) {
xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (iter.data);
for (; v.rem; xcb_visualtype_next (&v)) {
if (v.data->visual_id == visual)
return v.data;
}
}
return 0;
}
int main (int argc, char **argv)
{
xcb_connection_t *c;
xcb_window_t win;
xcb_screen_t *screen;
cairo_surface_t *window_surface;
cairo_surface_t *offscreen_surface;
cairo_t *window_cr, *offscreen_cr;
cairo_device_t *device;
int counter;
int total;
int i;
double start, stop;
particle_t *particles;
int num_particles = 500;
double start_frame, stop_frame, delta;
int enable = 0;
counter = 0;
total = 50;
if (argc == 2)
enable = ! (strcmp (argv[1], "--enable-cache"));
else if (argc == 3) {
enable = ! (strcmp (argv[1], "--enable-cache"));
num_particles = atoi (argv[2]);
}
c = xcb_connect (NULL, NULL);
if (xcb_connection_has_error (c)) {
fprintf (stderr, "fail to xcb_connect\n");
return -1;
}
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
win = xcb_generate_id (c);
uint32_t values[] = {1};
xcb_void_cookie_t cookie =
xcb_create_window_checked (c,
screen->root_depth,
win,
screen->root,
0, 0,
WIDTH, HEIGHT,
0, /* border */
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
XCB_CW_BORDER_PIXEL,
values);
xcb_map_window (c, win);
window_surface = cairo_xcb_surface_create (c,
win,
lookup_visual (screen, screen->root_visual),
WIDTH, HEIGHT);
device = cairo_device_reference (cairo_surface_get_device (window_surface));
offscreen_surface = cairo_surface_create_similar (window_surface,
CAIRO_CONTENT_COLOR_ALPHA,
WIDTH,
HEIGHT);
window_cr = cairo_create (window_surface);
offscreen_cr = cairo_create (offscreen_surface);
particles = (particle_t *) malloc (sizeof (particle_t) * num_particles);
for (i = 0; i < num_particles; i++)
particle_init (&particles[i]);
delta = 0;
for (;;) {
if (counter == 0)
start = get_tick ();
start_frame = get_tick ();
render (offscreen_cr, offscreen_surface, particles, num_particles, delta,
enable);
stop_frame = get_tick ();
delta = stop_frame - start_frame;
counter++;
cairo_save (window_cr);
cairo_set_source_surface (window_cr, offscreen_surface, 0, 0);
cairo_set_operator (window_cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (window_cr);
cairo_restore (window_cr);
xcb_aux_sync (c);
if (counter == total) {
counter = 0;
stop = get_tick ();
fprintf (stdout, "fps = %0.2f\n", total / (stop - start));
}
}
cairo_destroy (window_cr);
cairo_destroy (offscreen_cr);
cairo_surface_destroy (window_surface);
cairo_surface_destroy (offscreen_surface);
cairo_device_destroy (device);
xcb_disconnect (c);
return 0;
}
cairo-egl-shadow-ring.c
(text/x-csrc, 10.1 KB)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cairo.h>
#include <cairo-gl.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define WIDTH 1024
#define HEIGHT 768
#define MAX_VELOCITY 500
//#define RADIUS 48
double RADIUS = 50;
typedef struct _particle
{
double angle;
double velocity;
double x;
double y;
double color[3];
double line_width;
double shadow_color[4];
double shadow_x_blur;
double shadow_y_blur;
double spread_color[4];
double spread_line_width;
double spread_x_blur;
double spread_y_blur;
double drop_color[4];
double drop_x_blur;
double drop_y_blur;
double drop_x_offset;
double drop_y_offset;
double drop_line_width;
double x_offset;
double y_offset;
} particle_t;
static void
generate_color (double *color)
{
int i;
for (i = 0; i < 3; i++)
color[i] = drand48 ();
//color[i] = (int) (drand48 () * 2) / 2.0;
}
static void particle_init (particle_t *particle)
{
particle->angle = drand48 () * 2 * M_PI;
particle->velocity = MAX_VELOCITY / 8.0 * 7 * drand48 () + MAX_VELOCITY / 8.0;
particle->x = WIDTH / 2 - RADIUS;
particle->y = HEIGHT / 2 - RADIUS;
generate_color (particle->color);
particle->line_width = 20.0;
/* inset shadow */
particle->shadow_color[0] = 0;
particle->shadow_color[1] = 0;
particle->shadow_color[2] = 0;
particle->shadow_color[3] = 1;
particle->shadow_x_blur = 5;
particle->shadow_y_blur = 5;
particle->x_offset = 6;
particle->y_offset = 1;
/* spread */
particle->spread_color[0] = 1;
particle->spread_color[1] = 1;
particle->spread_color[2] = 1;
particle->spread_color[3] = 1;
particle->spread_x_blur = 4;
particle->spread_y_blur = 4;
particle->spread_line_width = 3;
/* drop shadow */
particle->drop_color[0] = 0;
particle->drop_color[1] = 0;
particle->drop_color[2] = 0;
particle->drop_color[3] = 0.5;
particle->drop_x_blur = 10;
particle->drop_y_blur = 10;
particle->drop_x_offset = -30;
particle->drop_y_offset = -5;
particle->drop_line_width = particle->line_width;
}
static void particle_position (particle_t *particle, double delta)
{
double x = particle->x + cos (particle->angle) * particle->velocity * delta;
double y = particle->y + sin (particle->angle) * particle->velocity * delta;
if (x + RADIUS > WIDTH) {
if (particle->angle >= 0 && particle->angle < M_PI / 2)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI / 2 * 3)
particle->angle -= (particle->angle - M_PI /2 * 3) * 2;
x = WIDTH - RADIUS;
}
if (x - RADIUS < 0) {
if (particle->angle > M_PI / 2 && particle->angle < M_PI)
particle->angle = M_PI - particle->angle;
else if (particle->angle > M_PI && particle->angle < M_PI / 2 * 3)
particle->angle += (M_PI / 2 * 3 - particle->angle) * 2;
x = RADIUS;
}
if (y + RADIUS > HEIGHT) {
if (particle->angle > 0 && particle->angle < 2 * M_PI)
particle->angle = M_PI * 2 - particle->angle;
y = HEIGHT - RADIUS;
}
if (y - RADIUS < 0) {
if (particle->angle > M_PI && particle->angle < M_PI * 2)
particle->angle = particle->angle - (particle->angle - M_PI) * 2;
y = RADIUS;
}
particle->x = x;
particle->y = y;
}
static void
fill_particle (cairo_t *cr, particle_t *particle)
{
/* drop shadow first */
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow_rgba (cr, particle->drop_color[0],
particle->drop_color[1],
particle->drop_color[2],
particle->drop_color[3]);
cairo_set_shadow_offset (cr, particle->drop_x_offset,
particle->drop_y_offset);
cairo_set_shadow_blur (cr, particle->drop_x_blur,
particle->drop_y_blur);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->drop_line_width);
cairo_stroke (cr);
//cairo_surface_write_to_png (cairo_get_target (cr), "./test.png");
/* ring itself */
cairo_set_source_rgb (cr, particle->color[0],
particle->color[1], particle->color[2]);
cairo_set_shadow (cr, CAIRO_SHADOW_INSET);
cairo_set_draw_shadow_only (cr, 0);
cairo_set_shadow_rgba (cr, particle->shadow_color[0],
particle->shadow_color[1],
particle->shadow_color[2],
particle->shadow_color[3]);
cairo_set_shadow_offset (cr, particle->x_offset,
particle->y_offset);
cairo_set_shadow_blur (cr, particle->shadow_x_blur,
particle->shadow_y_blur);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->line_width);
cairo_stroke (cr);
//cairo_fill (cr);
//cairo_surface_write_to_png (cairo_get_target (cr), "./test.png");
/* spread */
cairo_set_shadow (cr, CAIRO_SHADOW_DROP);
cairo_set_draw_shadow_only (cr, 1);
cairo_set_shadow_rgba (cr, particle->spread_color[0],
particle->spread_color[1],
particle->spread_color[2],
particle->spread_color[3]);
cairo_set_shadow_offset (cr, particle->x_offset,
particle->y_offset);
cairo_set_shadow_blur (cr, particle->spread_x_blur,
particle->spread_y_blur);
cairo_arc (cr, particle->x, particle->y, RADIUS, 0, 2.0 * M_PI);
cairo_set_line_width (cr, particle->spread_line_width);
cairo_stroke (cr);
//cairo_surface_write_to_png (cairo_get_target (cr), "./test.png");
}
static double
get_tick (void)
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_sec + now.tv_usec / 1000000.0;
}
static void
fill (cairo_t *cr, particle_t *particles, int num_particles, double delta)
{
int i;
for (i = 0; i < num_particles; i++) {
particle_position (&particles[i], delta);
fill_particle (cr, &particles[i]);
}
}
static void
render (cairo_t *cr, cairo_surface_t *surface,
particle_t *particles, int num_particles, double delta, int enable)
{
cairo_save (cr);
cairo_shadow_enable_cache (cr, enable);
/* clear surface */
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
cairo_fill (cr);
fill (cr, particles, num_particles, delta);
/* swap buffers */
cairo_gl_surface_swapbuffers (surface);
cairo_restore (cr);
}
int main (int argc, char **argv)
{
EGLint attr[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 1,
EGL_STENCIL_SIZE, 1,
EGL_SAMPLES, 4,
EGL_SAMPLE_BUFFERS, 1,
EGL_NONE
};
EGLint ctx_attr[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
cairo_surface_t *window_surface;
cairo_t *window_cr;
Display *dpy;
Window window;
EGLDisplay display;
EGLConfig config;
EGLint num;
EGLSurface surface;
EGLContext context;
cairo_device_t *device;
int counter;
int total;
int i;
double start, stop;
particle_t *particles;
int num_particles = 500;
double start_frame, stop_frame, delta;
int cache = 0;
counter = 0;
total = 50;
if (argc == 2) {
if (strcmp (argv[1], "--enable-cache") == 0)
cache = 1;
}
else if (argc == 3) {
if (strcmp (argv[1], "--enable-cache") == 0)
cache = 1;
num_particles = atoi (argv[2]);
}
else if (argc == 4) {
if (strcmp (argv[1], "--enable-cache") == 0)
cache = 1;
num_particles = atoi (argv[2]);
RADIUS = atoi (argv[3]);
}
dpy = XOpenDisplay (NULL);
if (!dpy) {
fprintf (stderr, "fail to open display: %s\n", XDisplayName (0));
return -1;
}
window = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy),
0, 0,
WIDTH, HEIGHT,
0,
BlackPixel (dpy, DefaultRootWindow (dpy)),
BlackPixel (dpy, DefaultRootWindow (dpy)));
XMapWindow (dpy, window);
display = eglGetDisplay ((EGLNativeDisplayType) dpy);
if (display == EGL_NO_DISPLAY) {
printf ("Cannot get egl display\n");
exit (-1);
}
EGLint major, minor;
if (! eglInitialize (display, &major, &minor)) {
printf ("Cannot initialize egl\n");
exit (-1);
}
if (! eglBindAPI (EGL_OPENGL_ES_API)) {
printf ("Cannot bind egl to gles2 API\n");
exit (-1);
}
if (! eglChooseConfig (display, attr, &config, 1, &num)) {
printf ("cannot get egl configuration\n");
exit (-1);
}
if (num != 1) {
printf ("did not get exact one configuration\n");
exit (-1);
}
context = eglCreateContext (display, config, NULL, ctx_attr);
if (context == EGL_NO_CONTEXT) {
printf ("cannot egl context\n");
exit (-1);
}
surface = eglCreateWindowSurface (display, config, window, NULL);
if (surface == EGL_NO_SURFACE) {
printf ("cannot create egl window surface\n");
exit (-1);
}
eglMakeCurrent (display, surface, surface, context);
eglSwapInterval (display, 0);
device = cairo_egl_device_create (display, context);
cairo_gl_device_set_thread_aware (device, 0);
window_surface = cairo_gl_surface_create_for_egl (device,
surface,
WIDTH, HEIGHT);
window_cr = cairo_create (window_surface);
particles = (particle_t *) malloc (sizeof (particle_t) * num_particles);
for (i = 0; i < num_particles; i++)
particle_init (&particles[i]);
delta = 0;
for (;;) {
if (counter == 0)
start = get_tick ();
start_frame = get_tick ();
render (window_cr, window_surface, particles, num_particles, delta, cache);
stop_frame = get_tick ();
delta = stop_frame - start_frame;
counter++;
if (counter == total) {
counter = 0;
stop = get_tick ();
fprintf (stdout, "fps = %0.2f\n", total / (stop - start));
}
}
free (particles);
cairo_destroy (window_cr);
sleep (10);
cairo_surface_destroy (window_surface);
cairo_device_destroy (device);
eglDestroyContext (display, context);
eglDestroySurface (display, surface);
eglTerminate (display);
XDestroyWindow (dpy, window);
XCloseDisplay (dpy);
return 0;
}