|
@ -1,5 +1,3 @@ |
|
|
#include <GL/gl.h> |
|
|
|
|
|
#include <GL/glx.h> |
|
|
|
|
|
#include <X11/Xlib-xcb.h> /* for XGetXCBConnection, link with libX11-xcb */ |
|
|
#include <X11/Xlib-xcb.h> /* for XGetXCBConnection, link with libX11-xcb */ |
|
|
#include <X11/Xlib.h> |
|
|
#include <X11/Xlib.h> |
|
|
#include <assert.h> |
|
|
#include <assert.h> |
|
@ -8,14 +6,18 @@ |
|
|
#include <time.h> |
|
|
#include <time.h> |
|
|
#include <unistd.h> |
|
|
#include <unistd.h> |
|
|
#include <xcb/xcb.h> |
|
|
#include <xcb/xcb.h> |
|
|
#include <xcb/xcb.h> |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
unsigned short r; |
|
|
|
|
|
unsigned short g; |
|
|
|
|
|
unsigned short b; |
|
|
|
|
|
} color_t; |
|
|
|
|
|
|
|
|
xcb_alloc_color_reply_t* |
|
|
xcb_alloc_color_reply_t* |
|
|
getColor(xcb_connection_t*, |
|
|
getColorFromCmap(xcb_connection_t*, |
|
|
xcb_colormap_t, |
|
|
xcb_colormap_t, |
|
|
unsigned short, |
|
|
color_t); |
|
|
unsigned short, |
|
|
|
|
|
unsigned short); |
|
|
|
|
|
|
|
|
|
|
|
/* Macro definition to parse X server events
|
|
|
/* Macro definition to parse X server events
|
|
|
* The ~0x80 is needed to get the lower 7 bits |
|
|
* The ~0x80 is needed to get the lower 7 bits |
|
@ -33,7 +35,6 @@ getColor(xcb_connection_t*, |
|
|
* Figure out what resources need to be free'd and figure out a strategy for allocating things better |
|
|
* Figure out what resources need to be free'd and figure out a strategy for allocating things better |
|
|
* Figure out a better way of managing the event loop than nanosleep? (clock_nanosleep maybe) |
|
|
* Figure out a better way of managing the event loop than nanosleep? (clock_nanosleep maybe) |
|
|
* Figure out which events we need to actually be handling |
|
|
* Figure out which events we need to actually be handling |
|
|
* Figure out how to resize dynamically (See handmade hero videos for tips) |
|
|
|
|
|
* Figure out good strategy for only copying changed pixels to window |
|
|
* Figure out good strategy for only copying changed pixels to window |
|
|
* Figure out what allocations can fail and what to do if they fail |
|
|
* Figure out what allocations can fail and what to do if they fail |
|
|
*/ |
|
|
*/ |
|
@ -111,20 +112,18 @@ allocateColorMap(xcb_connection_t *display, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
xcb_alloc_color_reply_t* |
|
|
xcb_alloc_color_reply_t* |
|
|
getColor(xcb_connection_t *display, |
|
|
getColorFromCmap(xcb_connection_t *display, |
|
|
xcb_colormap_t colormap, |
|
|
xcb_colormap_t colormap, |
|
|
unsigned short red, |
|
|
color_t color) { |
|
|
unsigned short green, |
|
|
/* Allocate a color in the color map */ |
|
|
unsigned short blue) { |
|
|
|
|
|
/* Return a new xcb color structure */ |
|
|
|
|
|
/* Initialize it with RGB */ |
|
|
/* Initialize it with RGB */ |
|
|
|
|
|
|
|
|
xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(display, |
|
|
xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(display, |
|
|
xcb_alloc_color(display, |
|
|
xcb_alloc_color(display, |
|
|
colormap, |
|
|
colormap, |
|
|
red, |
|
|
color.r, |
|
|
green, |
|
|
color.g, |
|
|
blue), |
|
|
color.b), |
|
|
NULL); |
|
|
NULL); |
|
|
|
|
|
|
|
|
/* TODO, make sure colors get free'd after they're used?
|
|
|
/* TODO, make sure colors get free'd after they're used?
|
|
@ -149,19 +148,15 @@ static xcb_gcontext_t |
|
|
getGC(xcb_connection_t *display, |
|
|
getGC(xcb_connection_t *display, |
|
|
xcb_screen_t *screen, |
|
|
xcb_screen_t *screen, |
|
|
xcb_colormap_t colormap, |
|
|
xcb_colormap_t colormap, |
|
|
unsigned short r, |
|
|
color_t color) { |
|
|
unsigned short g, |
|
|
|
|
|
unsigned short b) { |
|
|
|
|
|
|
|
|
|
|
|
xcb_drawable_t window = screen->root; |
|
|
xcb_drawable_t window = screen->root; |
|
|
|
|
|
|
|
|
xcb_gcontext_t foreground = xcb_generate_id(display); |
|
|
xcb_gcontext_t foreground = xcb_generate_id(display); |
|
|
|
|
|
|
|
|
xcb_alloc_color_reply_t *xcolor = getColor(display, |
|
|
xcb_alloc_color_reply_t *xcolor = getColorFromCmap(display, |
|
|
colormap, |
|
|
colormap, |
|
|
r, |
|
|
color); |
|
|
g, |
|
|
|
|
|
b); |
|
|
|
|
|
|
|
|
|
|
|
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; |
|
|
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; |
|
|
uint32_t values[2] = {xcolor->pixel, 0}; |
|
|
uint32_t values[2] = {xcolor->pixel, 0}; |
|
@ -175,35 +170,36 @@ getGC(xcb_connection_t *display, |
|
|
return foreground; |
|
|
return foreground; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static xcb_pixmap_t |
|
|
static xcb_void_cookie_t |
|
|
allocatePixmap(xcb_connection_t *display, |
|
|
updateGCColor(xcb_connection_t *display, |
|
|
xcb_screen_t *screen, |
|
|
xcb_gcontext_t gc, |
|
|
xcb_window_t window, |
|
|
xcb_colormap_t colormap, |
|
|
uint32_t width, |
|
|
color_t color) { |
|
|
uint32_t height) { |
|
|
/* https://www.x.org/releases/X11R7.6/doc/libxcb/tutorial/index.html#changegc */ |
|
|
xcb_pixmap_t pixmapId = xcb_generate_id(display); |
|
|
|
|
|
|
|
|
|
|
|
xcb_create_pixmap(display, |
|
|
xcb_alloc_color_reply_t *xcolor = getColorFromCmap(display, |
|
|
screen->root_depth, |
|
|
colormap, |
|
|
pixmapId, |
|
|
color); |
|
|
window, |
|
|
|
|
|
width, |
|
|
|
|
|
height); |
|
|
|
|
|
|
|
|
|
|
|
return pixmapId; |
|
|
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; |
|
|
|
|
|
uint32_t values[2] = {xcolor->pixel, 0}; |
|
|
|
|
|
|
|
|
|
|
|
return xcb_change_gc(display, |
|
|
|
|
|
gc, |
|
|
|
|
|
mask, |
|
|
|
|
|
values); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
xcb_point_t* |
|
|
xcb_point_t* |
|
|
genPoints(uint16_t width, |
|
|
genPoints(uint16_t width, |
|
|
uint16_t height) { |
|
|
uint16_t height) { |
|
|
|
|
|
/* Fills the entire screen with pixels */ |
|
|
xcb_point_t *points = malloc( sizeof(xcb_point_t) * height * width); |
|
|
xcb_point_t *points = malloc( sizeof(xcb_point_t) * height * width); |
|
|
|
|
|
|
|
|
xcb_point_t point; |
|
|
xcb_point_t point; |
|
|
|
|
|
|
|
|
int i = 0; |
|
|
int i = 0; |
|
|
|
|
|
|
|
|
printf("width = %d, height = %d\n", width, height); |
|
|
|
|
|
|
|
|
|
|
|
for (uint16_t x = 0; x < width; x++) { |
|
|
for (uint16_t x = 0; x < width; x++) { |
|
|
for(uint16_t y = 0; y < height; y++) { |
|
|
for(uint16_t y = 0; y < height; y++) { |
|
|
point.x = x; |
|
|
point.x = x; |
|
@ -218,17 +214,101 @@ genPoints(uint16_t width, |
|
|
return points; |
|
|
return points; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
displayBuffer(xcb_pixmap_t pixmap_buffer, |
|
|
|
|
|
xcb_connection_t *display, |
|
|
|
|
|
xcb_window_t window, |
|
|
|
|
|
xcb_gcontext_t gc, |
|
|
|
|
|
xcb_expose_event_t *event) { |
|
|
|
|
|
/* Note that x = 0, y = 0, is the top left of the screen */ |
|
|
|
|
|
xcb_copy_area(display, |
|
|
|
|
|
pixmap_buffer, |
|
|
|
|
|
window, |
|
|
|
|
|
gc, |
|
|
|
|
|
0, /* top left x coord */ |
|
|
|
|
|
0, /* top left y coord */ |
|
|
|
|
|
event->x, /* top left x coord of dest*/ |
|
|
|
|
|
event->y, /* top left y coord of dest*/ |
|
|
|
|
|
event->width, /* pixel width of source */ |
|
|
|
|
|
event->height /* pixel height of source */ |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
xcb_flush(display); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
writePixmap(xcb_pixmap_t pixmap_buffer, |
|
|
|
|
|
color_t color, |
|
|
|
|
|
xcb_colormap_t colormap, |
|
|
|
|
|
xcb_point_t *points, |
|
|
|
|
|
xcb_gcontext_t gc, |
|
|
|
|
|
xcb_connection_t *display, |
|
|
|
|
|
xcb_window_t window, |
|
|
|
|
|
xcb_expose_event_t *event) { |
|
|
|
|
|
|
|
|
|
|
|
printf("Drawing pixmap\nr = %u, g = %u, b = %u\n", color.r, color.g, color.b); |
|
|
|
|
|
updateGCColor(display, |
|
|
|
|
|
gc, |
|
|
|
|
|
colormap, |
|
|
|
|
|
color); |
|
|
|
|
|
|
|
|
|
|
|
xcb_poly_point(display, |
|
|
|
|
|
XCB_COORD_MODE_ORIGIN, /* Coordinate mode, usually set to XCB_COORD_MODE_ORIGIN */ |
|
|
|
|
|
pixmap_buffer, |
|
|
|
|
|
gc, |
|
|
|
|
|
event->width*event->height, |
|
|
|
|
|
points); |
|
|
|
|
|
|
|
|
|
|
|
displayBuffer(pixmap_buffer, |
|
|
|
|
|
display, |
|
|
|
|
|
window, |
|
|
|
|
|
gc, |
|
|
|
|
|
event); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xcb_pixmap_t |
|
|
|
|
|
getPixmap(xcb_connection_t *display, |
|
|
|
|
|
xcb_screen_t *screen, |
|
|
|
|
|
xcb_window_t window, |
|
|
|
|
|
uint16_t window_width, |
|
|
|
|
|
uint16_t window_height) { |
|
|
|
|
|
/* Allocate a pixmap we will be blitting to the window */ |
|
|
|
|
|
xcb_pixmap_t pixmapId = xcb_generate_id(display); |
|
|
|
|
|
|
|
|
|
|
|
xcb_create_pixmap(display, |
|
|
|
|
|
screen->root_depth, |
|
|
|
|
|
pixmapId, |
|
|
|
|
|
window, |
|
|
|
|
|
window_width, |
|
|
|
|
|
window_height); |
|
|
|
|
|
|
|
|
|
|
|
return pixmapId; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static color_t |
|
|
|
|
|
color(unsigned short r, |
|
|
|
|
|
unsigned short g, |
|
|
|
|
|
unsigned short b) { |
|
|
|
|
|
/* Initialize an RGB color struct */ |
|
|
|
|
|
color_t color; |
|
|
|
|
|
color.r = r; |
|
|
|
|
|
color.g = g; |
|
|
|
|
|
color.b = b; |
|
|
|
|
|
return color; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
int |
|
|
int |
|
|
main(void) { |
|
|
main(void) { |
|
|
uint16_t window_width = 500; |
|
|
|
|
|
uint16_t window_height = 500; |
|
|
|
|
|
|
|
|
|
|
|
/* Open up the display */ |
|
|
/* Open up the display */ |
|
|
xcb_connection_t *display = getDisplay(); |
|
|
xcb_connection_t *display = getDisplay(); |
|
|
|
|
|
|
|
|
/* Get a handle to the screen */ |
|
|
/* Get a handle to the screen */ |
|
|
xcb_screen_t *screen = getScreen(display); |
|
|
xcb_screen_t *screen = getScreen(display); |
|
|
|
|
|
|
|
|
|
|
|
uint16_t window_height = screen->height_in_pixels; |
|
|
|
|
|
uint16_t window_width = screen->width_in_pixels; |
|
|
|
|
|
|
|
|
/* Create a window */ |
|
|
/* Create a window */ |
|
|
xcb_window_t window = getWindow(display, |
|
|
xcb_window_t window = getWindow(display, |
|
|
screen, |
|
|
screen, |
|
@ -248,15 +328,25 @@ main(void) { |
|
|
struct timespec req = genSleep(0, 20000000); |
|
|
struct timespec req = genSleep(0, 20000000); |
|
|
struct timespec rem = genSleep(0, 0); |
|
|
struct timespec rem = genSleep(0, 0); |
|
|
|
|
|
|
|
|
|
|
|
color_t draw_color = color(0, 0, 0); |
|
|
|
|
|
|
|
|
xcb_generic_event_t *event; |
|
|
xcb_generic_event_t *event; |
|
|
xcb_expose_event_t *expose; |
|
|
xcb_expose_event_t *expose; |
|
|
|
|
|
|
|
|
xcb_gcontext_t gc = getGC(display, |
|
|
xcb_gcontext_t gc = getGC(display, |
|
|
screen, |
|
|
screen, |
|
|
colormap, |
|
|
colormap, |
|
|
0, |
|
|
draw_color); |
|
|
0xffff, |
|
|
|
|
|
0); |
|
|
/* The pixmap that acts as our backbuffer */ |
|
|
|
|
|
xcb_pixmap_t pixmap_buffer = getPixmap(display, |
|
|
|
|
|
screen, |
|
|
|
|
|
window, |
|
|
|
|
|
window_width, |
|
|
|
|
|
window_height); |
|
|
|
|
|
|
|
|
|
|
|
int was_exposed = 0; |
|
|
|
|
|
|
|
|
while (1) { |
|
|
while (1) { |
|
|
event = xcb_poll_for_event(display); |
|
|
event = xcb_poll_for_event(display); |
|
|
|
|
|
|
|
@ -267,59 +357,24 @@ main(void) { |
|
|
|
|
|
|
|
|
case XCB_EXPOSE: { |
|
|
case XCB_EXPOSE: { |
|
|
expose = (xcb_expose_event_t *)event; |
|
|
expose = (xcb_expose_event_t *)event; |
|
|
|
|
|
window_width = expose->width; |
|
|
|
|
|
window_height = expose->height; |
|
|
printf("Window %u exposed. Region to be redrawn at location (%u,%u), with dimension (%u,%u)\n", |
|
|
printf("Window %u exposed. Region to be redrawn at location (%u,%u), with dimension (%u,%u)\n", |
|
|
expose->window, expose->x, |
|
|
expose->window, expose->x, |
|
|
expose->y, |
|
|
expose->y, |
|
|
expose->width, |
|
|
expose->width, |
|
|
expose->height); |
|
|
expose->height); |
|
|
|
|
|
|
|
|
window_width = expose->width; |
|
|
|
|
|
window_height = expose->height; |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* One important note should be made: |
|
|
|
|
|
* it is possible to create pixmaps with different depths on the same screen. |
|
|
|
|
|
* When we perform copy operations (a pixmap onto a window, etc), |
|
|
|
|
|
* we should make sure that both source and target have the same depth. |
|
|
|
|
|
* If they have a different depth, the operation will fail. |
|
|
|
|
|
* The exception to this is if we copy a specific bit plane of the source pixmap using xcb_copy_plane(). |
|
|
|
|
|
* In such an event, we can copy a specific plane to the target window |
|
|
|
|
|
* (in actuality, setting a specific bit in the color of each pixel copied). |
|
|
|
|
|
* This can be used to generate strange graphic effects in a window, but that is beyond the scope of this tutorial. |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate a pixmap we will be blitting to the window */ |
|
|
|
|
|
xcb_pixmap_t pixmap = allocatePixmap(display, |
|
|
|
|
|
screen, |
|
|
|
|
|
window, |
|
|
|
|
|
window_width, |
|
|
|
|
|
window_height); |
|
|
|
|
|
|
|
|
|
|
|
xcb_point_t *points = genPoints(window_width, window_height); |
|
|
xcb_point_t *points = genPoints(window_width, window_height); |
|
|
|
|
|
writePixmap(pixmap_buffer, |
|
|
xcb_poly_point (display, /* The connection to the X server */ |
|
|
draw_color, |
|
|
XCB_COORD_MODE_ORIGIN, /* Coordinate mode, usually set to XCB_COORD_MODE_ORIGIN */ |
|
|
colormap, |
|
|
pixmap, /* The drawable on which we want to draw the point(s) */ |
|
|
points, |
|
|
gc, /* The Graphic Context we use to draw the point(s) */ |
|
|
|
|
|
window_width*window_height, /* The number of points */ |
|
|
|
|
|
points); /* An array of points */ |
|
|
|
|
|
|
|
|
|
|
|
xcb_copy_area(display, |
|
|
|
|
|
pixmap, |
|
|
|
|
|
window, |
|
|
|
|
|
gc, |
|
|
gc, |
|
|
0, /* top left x coord */ |
|
|
display, |
|
|
0, /* top left y coord */ |
|
|
window, |
|
|
0, /* top left x coord of dest*/ |
|
|
expose); |
|
|
0, /* top left y coord of dest*/ |
|
|
was_exposed = 1; |
|
|
window_width, /* pixel width of source */ |
|
|
|
|
|
window_height /* pixel height of source */ |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
xcb_flush(display); |
|
|
|
|
|
free(points); |
|
|
|
|
|
xcb_free_pixmap(display, pixmap); |
|
|
|
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -331,10 +386,29 @@ main(void) { |
|
|
free(event); |
|
|
free(event); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if (was_exposed) { |
|
|
|
|
|
xcb_point_t *points = genPoints(window_width, window_height); |
|
|
|
|
|
|
|
|
|
|
|
writePixmap(pixmap_buffer, |
|
|
|
|
|
draw_color, |
|
|
|
|
|
colormap, |
|
|
|
|
|
points, |
|
|
|
|
|
gc, |
|
|
|
|
|
display, |
|
|
|
|
|
window, |
|
|
|
|
|
expose); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
draw_color.r += 100; |
|
|
|
|
|
|
|
|
|
|
|
/* General strategy for writing to buffer
|
|
|
|
|
|
* Function should take point(s), color, and write it |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
nanosleep(&req, &rem); |
|
|
nanosleep(&req, &rem); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xcb_free_pixmap(display, pixmap_buffer); |
|
|
xcb_disconnect(display); |
|
|
xcb_disconnect(display); |
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|