render to image surface
This commit is contained in:
parent
c3deff6d64
commit
000d8a53b9
112
initcairo.c
112
initcairo.c
@ -54,9 +54,17 @@ GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char
|
|||||||
|
|
||||||
XMapWindow(info->display, info->win);
|
XMapWindow(info->display, info->win);
|
||||||
|
|
||||||
|
// create xlib surface
|
||||||
info->surface = cairo_xlib_surface_create(info->display, info->win, visual, width, height);
|
info->surface = cairo_xlib_surface_create(info->display, info->win, visual, width, height);
|
||||||
cairo_xlib_surface_set_size(info->surface, width, height);
|
cairo_xlib_surface_set_size(info->surface, width, height);
|
||||||
info->context->cairo = cairo_create(info->surface);
|
info->front_context = cairo_create(info->surface);
|
||||||
|
cairo_set_antialias(info->front_context, CAIRO_ANTIALIAS_NONE);
|
||||||
|
|
||||||
|
// create backbuffer surface
|
||||||
|
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
|
||||||
|
info->buffer = malloc(stride*height);
|
||||||
|
info->buffer_surface = cairo_image_surface_create_for_data(info->buffer, CAIRO_FORMAT_ARGB32, width, height, stride);
|
||||||
|
info->context->cairo = cairo_create(info->buffer_surface);
|
||||||
cairo_matrix_init_identity(&info->context->matrix);
|
cairo_matrix_init_identity(&info->context->matrix);
|
||||||
info->context->width = width;
|
info->context->width = width;
|
||||||
info->context->height = height;
|
info->context->height = height;
|
||||||
@ -65,11 +73,18 @@ GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char
|
|||||||
info->wm_protocols = XInternAtom(info->display, "WM_PROTOCOLS", 0);
|
info->wm_protocols = XInternAtom(info->display, "WM_PROTOCOLS", 0);
|
||||||
XSetWMProtocols(info->display, info->win, &info->wm_delete_window, 1);
|
XSetWMProtocols(info->display, info->win, &info->wm_delete_window, 1);
|
||||||
|
|
||||||
|
XFlush(info->display);
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyCairo(GraphicsInfo *info)
|
void destroyCairo(GraphicsInfo *info)
|
||||||
{
|
{
|
||||||
|
cairo_destroy(info->context->cairo);
|
||||||
|
cairo_destroy(info->front_context);
|
||||||
|
cairo_surface_destroy(info->surface);
|
||||||
|
cairo_surface_destroy(info->buffer_surface);
|
||||||
|
free(info->buffer);
|
||||||
XDestroyWindow(info->display, info->win);
|
XDestroyWindow(info->display, info->win);
|
||||||
XFreeColormap(info->display, info->cmap);
|
XFreeColormap(info->display, info->cmap);
|
||||||
XCloseDisplay(info->display);
|
XCloseDisplay(info->display);
|
||||||
@ -107,26 +122,35 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
|||||||
{
|
{
|
||||||
int state;
|
int state;
|
||||||
static int last_x, last_y;
|
static int last_x, last_y;
|
||||||
|
int stride;
|
||||||
|
int status = STATUS_NOTHING;
|
||||||
|
|
||||||
switch(ev->type) {
|
switch(ev->type) {
|
||||||
|
|
||||||
case Expose:
|
case Expose:
|
||||||
draw(info->context);
|
return STATUS_REDRAW;
|
||||||
break;
|
|
||||||
|
|
||||||
case ConfigureNotify:
|
case ConfigureNotify:
|
||||||
printf("ConfigureNotify Event, new dimensions: %d %d %d %d\n", ev->xconfigure.x, ev->xconfigure.y, ev->xconfigure.width, ev->xconfigure.height);
|
printf("ConfigureNotify Event, new dimensions: %d %d %d %d\n", ev->xconfigure.x, ev->xconfigure.y, ev->xconfigure.width, ev->xconfigure.height);
|
||||||
info->context->width = ev->xconfigure.width;
|
info->context->width = ev->xconfigure.width;
|
||||||
info->context->height = ev->xconfigure.height;
|
info->context->height = ev->xconfigure.height;
|
||||||
cairo_xlib_surface_set_size(info->surface, ev->xconfigure.width, ev->xconfigure.height);
|
cairo_xlib_surface_set_size(info->surface, info->context->width, info->context->height);
|
||||||
draw(info->context);
|
|
||||||
break;
|
cairo_destroy(info->context->cairo);
|
||||||
|
cairo_surface_destroy(info->buffer_surface);
|
||||||
|
free(info->buffer);
|
||||||
|
stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, info->context->width);
|
||||||
|
info->buffer = malloc(stride*info->context->height);
|
||||||
|
info->buffer_surface = cairo_image_surface_create_for_data(info->buffer, CAIRO_FORMAT_ARGB32, info->context->width, info->context->height, stride);
|
||||||
|
info->context->cairo = cairo_create(info->buffer_surface);
|
||||||
|
|
||||||
|
return STATUS_REDRAW;
|
||||||
|
|
||||||
case KeyPress:
|
case KeyPress:
|
||||||
state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
|
state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
|
||||||
if(state == 0 && ev->xkey.keycode == 24)
|
if(state == 0 && ev->xkey.keycode == 24)
|
||||||
return true;
|
return STATUS_QUIT;
|
||||||
break;
|
return STATUS_NOTHING;
|
||||||
|
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
if(ev->xbutton.button == 4) {
|
if(ev->xbutton.button == 4) {
|
||||||
@ -136,7 +160,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
|||||||
cairo_matrix_scale(&transform, 5.0/4.0, 5.0/4.0);
|
cairo_matrix_scale(&transform, 5.0/4.0, 5.0/4.0);
|
||||||
cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
||||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||||
draw(info->context);
|
status = STATUS_REDRAW;
|
||||||
} else if(ev->xbutton.button == 5) {
|
} else if(ev->xbutton.button == 5) {
|
||||||
cairo_matrix_t transform;
|
cairo_matrix_t transform;
|
||||||
cairo_matrix_init_identity(&transform);
|
cairo_matrix_init_identity(&transform);
|
||||||
@ -144,11 +168,12 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
|||||||
cairo_matrix_scale(&transform, 4.0/5.0, 4.0/5.0);
|
cairo_matrix_scale(&transform, 4.0/5.0, 4.0/5.0);
|
||||||
cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
cairo_matrix_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
||||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||||
draw(info->context);
|
status = STATUS_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_x = ev->xbutton.x;
|
last_x = ev->xbutton.x;
|
||||||
last_y = ev->xbutton.y;
|
last_y = ev->xbutton.y;
|
||||||
break;
|
return status;
|
||||||
|
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
if(ev->xmotion.state & Button1Mask && !(ev->xmotion.state & ShiftMask)) {
|
if(ev->xmotion.state & Button1Mask && !(ev->xmotion.state & ShiftMask)) {
|
||||||
@ -159,7 +184,7 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
|||||||
cairo_matrix_init_identity(&transform);
|
cairo_matrix_init_identity(&transform);
|
||||||
cairo_matrix_translate(&transform, dx, dy);
|
cairo_matrix_translate(&transform, dx, dy);
|
||||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||||
draw(info->context);
|
status = STATUS_REDRAW;
|
||||||
} else if(ev->xmotion.state & Button1Mask && ev->xmotion.state & ShiftMask) {
|
} else if(ev->xmotion.state & Button1Mask && ev->xmotion.state & ShiftMask) {
|
||||||
double width = (double) cairo_xlib_surface_get_width(info->surface);
|
double width = (double) cairo_xlib_surface_get_width(info->surface);
|
||||||
double height = (double) cairo_xlib_surface_get_height(info->surface);
|
double height = (double) cairo_xlib_surface_get_height(info->surface);
|
||||||
@ -174,50 +199,67 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
|||||||
cairo_matrix_rotate(&transform, angle);
|
cairo_matrix_rotate(&transform, angle);
|
||||||
cairo_matrix_translate(&transform, -width/2, -height/2);
|
cairo_matrix_translate(&transform, -width/2, -height/2);
|
||||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||||
draw(info->context);
|
status = STATUS_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_x = ev->xmotion.x;
|
last_x = ev->xmotion.x;
|
||||||
last_y = ev->xmotion.y;
|
last_y = ev->xmotion.y;
|
||||||
break;
|
|
||||||
|
return status;
|
||||||
|
|
||||||
case ClientMessage:
|
case ClientMessage:
|
||||||
if((Atom)ev->xclient.message_type == info->wm_protocols && (Atom)ev->xclient.data.l[0] == info->wm_delete_window) {
|
if((Atom)ev->xclient.message_type == info->wm_protocols && (Atom)ev->xclient.data.l[0] == info->wm_delete_window) {
|
||||||
// printf("Window closed\n");
|
// printf("Window closed\n");
|
||||||
return true;
|
return STATUS_QUIT;
|
||||||
}
|
}
|
||||||
break;
|
return STATUS_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return STATUS_NOTHING;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(DrawingContext*)) // get any events from the queue and the server, process them if neccessary, quit if wanted
|
int checkEvents(GraphicsInfo *info, int (*process)(GraphicsInfo*, XEvent*), void (*draw)(DrawingContext*)) // get any events from the queue and the server, process them if neccessary, quit if wanted
|
||||||
{
|
{
|
||||||
XEvent ev;
|
XEvent ev;
|
||||||
|
int x11_fd;
|
||||||
|
fd_set fds;
|
||||||
|
int status = STATUS_NOTHING, result;
|
||||||
|
|
||||||
// while(XCheckIfEvent(info->display, &ev, alwaysTruePredicate, NULL)) { // we essentially want XCheckWindowEvent, but we want to avoid that events for other windows fill up the queue
|
int x11_event = 0;
|
||||||
|
|
||||||
|
if(XPending(info->display)) { // select() would miss events which are picked up already, so we have to catch them first
|
||||||
|
x11_event = 1;
|
||||||
|
} else {
|
||||||
|
x11_fd = ConnectionNumber(info->display);
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(x11_fd, &fds);
|
||||||
|
|
||||||
|
select(x11_fd + 1, &fds, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if(FD_ISSET(x11_fd, &fds))
|
||||||
|
x11_event = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(x11_event) {
|
||||||
|
while(XPending(info->display)) {
|
||||||
XNextEvent(info->display, &ev);
|
XNextEvent(info->display, &ev);
|
||||||
|
|
||||||
if(ev.xany.window != info->win)
|
if(ev.xany.window != info->win)
|
||||||
return 0;
|
continue;
|
||||||
|
|
||||||
/* if(ev.type == KeyRelease) { // deal with autorepeat
|
result = processStandardEvent(info, &ev, draw);
|
||||||
XEvent nev;
|
if(result == STATUS_QUIT)
|
||||||
if(XCheckIfEvent(info->display, &nev, alwaysTruePredicate, NULL)) { // is there another event?
|
return STATUS_QUIT;
|
||||||
if (nev.type == KeyPress && nev.xkey.time == ev.xkey.time && nev.xkey.keycode == ev.xkey.keycode) // which is equal, but KeyPress? Then it's just auto-repeat
|
else if(result == STATUS_REDRAW)
|
||||||
return 0; // so we ignore both
|
status = STATUS_REDRAW;
|
||||||
|
|
||||||
XPutBackEvent(info->display, &nev); // otherwise put the event back, we will consider it in the next round
|
result = process(info, &ev);
|
||||||
|
if(result == STATUS_QUIT)
|
||||||
|
return STATUS_QUIT;
|
||||||
|
else if(result == STATUS_REDRAW)
|
||||||
|
status = STATUS_REDRAW;
|
||||||
}
|
}
|
||||||
} */
|
}
|
||||||
|
|
||||||
if(processStandardEvent(info, &ev, draw))
|
return status;
|
||||||
return 1;
|
|
||||||
|
|
||||||
if(process(info, &ev))
|
|
||||||
return 1; // quit event queue and application
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo-xlib.h>
|
#include <cairo-xlib.h>
|
||||||
|
|
||||||
|
#define STATUS_NOTHING 0
|
||||||
|
#define STATUS_REDRAW 1
|
||||||
|
#define STATUS_QUIT 2
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
cairo_t *cairo;
|
cairo_t *cairo;
|
||||||
cairo_matrix_t matrix;
|
cairo_matrix_t matrix;
|
||||||
@ -33,6 +37,11 @@ typedef struct {
|
|||||||
Atom wm_protocols;
|
Atom wm_protocols;
|
||||||
Atom wm_delete_window;
|
Atom wm_delete_window;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
|
cairo_t *front_context;
|
||||||
|
|
||||||
|
cairo_surface_t *buffer_surface;
|
||||||
|
unsigned char *buffer;
|
||||||
|
|
||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
unsigned long frames;
|
unsigned long frames;
|
||||||
double elapsed, frametime;
|
double elapsed, frametime;
|
||||||
|
36
limit_set.c
36
limit_set.c
@ -358,14 +358,8 @@ void drawAttractors(DrawingContext *ctx)
|
|||||||
|
|
||||||
void draw(DrawingContext *ctx)
|
void draw(DrawingContext *ctx)
|
||||||
{
|
{
|
||||||
struct timeval current_time;
|
|
||||||
gettimeofday(¤t_time, 0);
|
|
||||||
double start_time = current_time.tv_sec + current_time.tv_usec*1e-6;
|
|
||||||
|
|
||||||
cairo_t *C = ctx->cairo;
|
cairo_t *C = ctx->cairo;
|
||||||
updateDimensions(ctx);
|
|
||||||
|
|
||||||
cairo_push_group(C);
|
|
||||||
cairo_set_source_rgb(C, 1, 1, 1);
|
cairo_set_source_rgb(C, 1, 1, 1);
|
||||||
cairo_paint(C);
|
cairo_paint(C);
|
||||||
|
|
||||||
@ -378,7 +372,6 @@ void draw(DrawingContext *ctx)
|
|||||||
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||||
|
|
||||||
if(limit_curve_valid) {
|
if(limit_curve_valid) {
|
||||||
|
|
||||||
if(show_limit) {
|
if(show_limit) {
|
||||||
int last_inside = 0;
|
int last_inside = 0;
|
||||||
for(int i = 0; i < n_group_elements; i++) {
|
for(int i = 0; i < n_group_elements; i++) {
|
||||||
@ -421,13 +414,7 @@ void draw(DrawingContext *ctx)
|
|||||||
sprintf(buf, "t = %.8f", parameter);
|
sprintf(buf, "t = %.8f", parameter);
|
||||||
cairo_show_text(C, buf);
|
cairo_show_text(C, buf);
|
||||||
|
|
||||||
cairo_pop_group_to_source(C);
|
|
||||||
cairo_paint(C);
|
|
||||||
cairo_surface_flush(cairo_get_target(C));
|
cairo_surface_flush(cairo_get_target(C));
|
||||||
|
|
||||||
gettimeofday(¤t_time, 0);
|
|
||||||
double end_time = current_time.tv_sec + current_time.tv_usec*1e-6;
|
|
||||||
printf("draw() finished in %g seconds\n", end_time - start_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
@ -544,10 +531,10 @@ int processEvent(GraphicsInfo *info, XEvent *ev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(info->context);
|
return STATUS_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return STATUS_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
@ -586,7 +573,24 @@ int main()
|
|||||||
|
|
||||||
startTimer(info);
|
startTimer(info);
|
||||||
|
|
||||||
while(!checkEvents(info, processEvent, draw)) {
|
while(1) {
|
||||||
|
int result = checkEvents(info, processEvent, NULL);
|
||||||
|
if(result == STATUS_QUIT)
|
||||||
|
return 0;
|
||||||
|
else if(result == STATUS_REDRAW) {
|
||||||
|
struct timeval current_time;
|
||||||
|
gettimeofday(¤t_time, 0);
|
||||||
|
double start_time = current_time.tv_sec + current_time.tv_usec*1e-6;
|
||||||
|
|
||||||
|
updateDimensions(info->context);
|
||||||
|
draw(info->context);
|
||||||
|
cairo_set_source_surface(info->front_context, info->buffer_surface, 0, 0);
|
||||||
|
cairo_paint(info->front_context);
|
||||||
|
|
||||||
|
gettimeofday(¤t_time, 0);
|
||||||
|
double end_time = current_time.tv_sec + current_time.tv_usec*1e-6;
|
||||||
|
printf("drawing finished in %g seconds\n", end_time - start_time);
|
||||||
|
}
|
||||||
waitUpdateTimer(info);
|
waitUpdateTimer(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user