render to image surface
This commit is contained in:
parent
c3deff6d64
commit
000d8a53b9
114
initcairo.c
114
initcairo.c
@ -54,9 +54,17 @@ GraphicsInfo *initCairo(int screen, int mask, int width, int height, const char
|
||||
|
||||
XMapWindow(info->display, info->win);
|
||||
|
||||
// create xlib surface
|
||||
info->surface = cairo_xlib_surface_create(info->display, info->win, visual, 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);
|
||||
info->context->width = width;
|
||||
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);
|
||||
XSetWMProtocols(info->display, info->win, &info->wm_delete_window, 1);
|
||||
|
||||
XFlush(info->display);
|
||||
|
||||
return 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);
|
||||
XFreeColormap(info->display, info->cmap);
|
||||
XCloseDisplay(info->display);
|
||||
@ -107,26 +122,35 @@ int processStandardEvent(GraphicsInfo *info, XEvent *ev, void (*draw)(DrawingCon
|
||||
{
|
||||
int state;
|
||||
static int last_x, last_y;
|
||||
int stride;
|
||||
int status = STATUS_NOTHING;
|
||||
|
||||
switch(ev->type) {
|
||||
|
||||
case Expose:
|
||||
draw(info->context);
|
||||
break;
|
||||
return STATUS_REDRAW;
|
||||
|
||||
case ConfigureNotify:
|
||||
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->height = ev->xconfigure.height;
|
||||
cairo_xlib_surface_set_size(info->surface, ev->xconfigure.width, ev->xconfigure.height);
|
||||
draw(info->context);
|
||||
break;
|
||||
cairo_xlib_surface_set_size(info->surface, info->context->width, info->context->height);
|
||||
|
||||
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:
|
||||
state = ev->xkey.state & (ShiftMask | LockMask | ControlMask);
|
||||
if(state == 0 && ev->xkey.keycode == 24)
|
||||
return true;
|
||||
break;
|
||||
return STATUS_QUIT;
|
||||
return STATUS_NOTHING;
|
||||
|
||||
case ButtonPress:
|
||||
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_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||
draw(info->context);
|
||||
status = STATUS_REDRAW;
|
||||
} else if(ev->xbutton.button == 5) {
|
||||
cairo_matrix_t 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_translate(&transform, -ev->xbutton.x, -ev->xbutton.y);
|
||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||
draw(info->context);
|
||||
status = STATUS_REDRAW;
|
||||
}
|
||||
|
||||
last_x = ev->xbutton.x;
|
||||
last_y = ev->xbutton.y;
|
||||
break;
|
||||
return status;
|
||||
|
||||
case MotionNotify:
|
||||
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_translate(&transform, dx, dy);
|
||||
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) {
|
||||
double width = (double) cairo_xlib_surface_get_width(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_translate(&transform, -width/2, -height/2);
|
||||
cairo_matrix_multiply(&info->context->matrix, &info->context->matrix, &transform);
|
||||
draw(info->context);
|
||||
status = STATUS_REDRAW;
|
||||
}
|
||||
|
||||
last_x = ev->xmotion.x;
|
||||
last_y = ev->xmotion.y;
|
||||
break;
|
||||
|
||||
return status;
|
||||
|
||||
case ClientMessage:
|
||||
if((Atom)ev->xclient.message_type == info->wm_protocols && (Atom)ev->xclient.data.l[0] == info->wm_delete_window) {
|
||||
// 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
|
||||
{
|
||||
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;
|
||||
|
||||
XNextEvent(info->display, &ev);
|
||||
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);
|
||||
|
||||
if(ev.xany.window != info->win)
|
||||
return 0;
|
||||
select(x11_fd + 1, &fds, NULL, NULL, NULL);
|
||||
|
||||
/* if(ev.type == KeyRelease) { // deal with autorepeat
|
||||
XEvent nev;
|
||||
if(XCheckIfEvent(info->display, &nev, alwaysTruePredicate, NULL)) { // is there another event?
|
||||
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
|
||||
return 0; // so we ignore both
|
||||
if(FD_ISSET(x11_fd, &fds))
|
||||
x11_event = 1;
|
||||
}
|
||||
|
||||
XPutBackEvent(info->display, &nev); // otherwise put the event back, we will consider it in the next round
|
||||
if(x11_event) {
|
||||
while(XPending(info->display)) {
|
||||
XNextEvent(info->display, &ev);
|
||||
|
||||
if(ev.xany.window != info->win)
|
||||
continue;
|
||||
|
||||
result = processStandardEvent(info, &ev, draw);
|
||||
if(result == STATUS_QUIT)
|
||||
return STATUS_QUIT;
|
||||
else if(result == STATUS_REDRAW)
|
||||
status = STATUS_REDRAW;
|
||||
|
||||
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 1;
|
||||
|
||||
if(process(info, &ev))
|
||||
return 1; // quit event queue and application
|
||||
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <cairo.h>
|
||||
#include <cairo-xlib.h>
|
||||
|
||||
#define STATUS_NOTHING 0
|
||||
#define STATUS_REDRAW 1
|
||||
#define STATUS_QUIT 2
|
||||
|
||||
typedef struct {
|
||||
cairo_t *cairo;
|
||||
cairo_matrix_t matrix;
|
||||
@ -33,6 +37,11 @@ typedef struct {
|
||||
Atom wm_protocols;
|
||||
Atom wm_delete_window;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *front_context;
|
||||
|
||||
cairo_surface_t *buffer_surface;
|
||||
unsigned char *buffer;
|
||||
|
||||
struct timeval start_time;
|
||||
unsigned long frames;
|
||||
double elapsed, frametime;
|
||||
|
36
limit_set.c
36
limit_set.c
@ -358,14 +358,8 @@ void drawAttractors(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;
|
||||
updateDimensions(ctx);
|
||||
|
||||
cairo_push_group(C);
|
||||
cairo_set_source_rgb(C, 1, 1, 1);
|
||||
cairo_paint(C);
|
||||
|
||||
@ -378,7 +372,6 @@ void draw(DrawingContext *ctx)
|
||||
cairo_set_line_cap(C, CAIRO_LINE_CAP_ROUND);
|
||||
|
||||
if(limit_curve_valid) {
|
||||
|
||||
if(show_limit) {
|
||||
int last_inside = 0;
|
||||
for(int i = 0; i < n_group_elements; i++) {
|
||||
@ -421,13 +414,7 @@ void draw(DrawingContext *ctx)
|
||||
sprintf(buf, "t = %.8f", parameter);
|
||||
cairo_show_text(C, buf);
|
||||
|
||||
cairo_pop_group_to_source(C);
|
||||
cairo_paint(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()
|
||||
@ -544,10 +531,10 @@ int processEvent(GraphicsInfo *info, XEvent *ev)
|
||||
break;
|
||||
}
|
||||
|
||||
draw(info->context);
|
||||
return STATUS_REDRAW;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return STATUS_NOTHING;
|
||||
}
|
||||
|
||||
int main()
|
||||
@ -586,7 +573,24 @@ int main()
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user