From 4c824098eed32b9f825745670fc018c84394ceb4 Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Mon, 1 Jul 2019 21:00:33 -0400 Subject: [PATCH] Major refactoring, got working with color changes --- blit_xcb.c | 264 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 169 insertions(+), 95 deletions(-) diff --git a/blit_xcb.c b/blit_xcb.c index ef5a2b2..26303e7 100644 --- a/blit_xcb.c +++ b/blit_xcb.c @@ -1,5 +1,3 @@ -#include -#include #include /* for XGetXCBConnection, link with libX11-xcb */ #include #include @@ -8,14 +6,18 @@ #include #include #include -#include + +typedef struct { + unsigned short r; + unsigned short g; + unsigned short b; +} color_t; xcb_alloc_color_reply_t* -getColor(xcb_connection_t*, - xcb_colormap_t, - unsigned short, - unsigned short, - unsigned short); +getColorFromCmap(xcb_connection_t*, + xcb_colormap_t, + color_t); + /* Macro definition to parse X server events * 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 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 how to resize dynamically (See handmade hero videos for tips) * Figure out good strategy for only copying changed pixels to window * 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* -getColor(xcb_connection_t *display, - xcb_colormap_t colormap, - unsigned short red, - unsigned short green, - unsigned short blue) { - /* Return a new xcb color structure */ +getColorFromCmap(xcb_connection_t *display, + xcb_colormap_t colormap, + color_t color) { + /* Allocate a color in the color map */ /* Initialize it with RGB */ xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(display, xcb_alloc_color(display, colormap, - red, - green, - blue), + color.r, + color.g, + color.b), NULL); /* TODO, make sure colors get free'd after they're used? @@ -149,19 +148,15 @@ static xcb_gcontext_t getGC(xcb_connection_t *display, xcb_screen_t *screen, xcb_colormap_t colormap, - unsigned short r, - unsigned short g, - unsigned short b) { + color_t color) { xcb_drawable_t window = screen->root; xcb_gcontext_t foreground = xcb_generate_id(display); - xcb_alloc_color_reply_t *xcolor = getColor(display, - colormap, - r, - g, - b); + xcb_alloc_color_reply_t *xcolor = getColorFromCmap(display, + colormap, + color); uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; uint32_t values[2] = {xcolor->pixel, 0}; @@ -175,35 +170,36 @@ getGC(xcb_connection_t *display, return foreground; } -static xcb_pixmap_t -allocatePixmap(xcb_connection_t *display, - xcb_screen_t *screen, - xcb_window_t window, - uint32_t width, - uint32_t height) { - xcb_pixmap_t pixmapId = xcb_generate_id(display); - - xcb_create_pixmap(display, - screen->root_depth, - pixmapId, - window, - width, - height); +static xcb_void_cookie_t +updateGCColor(xcb_connection_t *display, + xcb_gcontext_t gc, + xcb_colormap_t colormap, + color_t color) { + /* https://www.x.org/releases/X11R7.6/doc/libxcb/tutorial/index.html#changegc */ - return pixmapId; + xcb_alloc_color_reply_t *xcolor = getColorFromCmap(display, + colormap, + color); + + 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* genPoints(uint16_t width, uint16_t height) { + /* Fills the entire screen with pixels */ xcb_point_t *points = malloc( sizeof(xcb_point_t) * height * width); xcb_point_t point; int i = 0; - printf("width = %d, height = %d\n", width, height); - for (uint16_t x = 0; x < width; x++) { for(uint16_t y = 0; y < height; y++) { point.x = x; @@ -218,17 +214,101 @@ genPoints(uint16_t width, 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 main(void) { - uint16_t window_width = 500; - uint16_t window_height = 500; - /* Open up the display */ xcb_connection_t *display = getDisplay(); /* Get a handle to the screen */ 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 */ xcb_window_t window = getWindow(display, screen, @@ -248,15 +328,25 @@ main(void) { struct timespec req = genSleep(0, 20000000); struct timespec rem = genSleep(0, 0); + color_t draw_color = color(0, 0, 0); + xcb_generic_event_t *event; xcb_expose_event_t *expose; xcb_gcontext_t gc = getGC(display, screen, colormap, - 0, - 0xffff, - 0); + draw_color); + + /* 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) { event = xcb_poll_for_event(display); @@ -267,59 +357,24 @@ main(void) { case XCB_EXPOSE: { 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", expose->window, expose->x, expose->y, expose->width, 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_poly_point (display, /* The connection to the X server */ - XCB_COORD_MODE_ORIGIN, /* Coordinate mode, usually set to XCB_COORD_MODE_ORIGIN */ - pixmap, /* The drawable on which we want to draw the point(s) */ - 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, - 0, /* top left x coord */ - 0, /* top left y coord */ - 0, /* top left x coord of dest*/ - 0, /* top left y coord of dest*/ - window_width, /* pixel width of source */ - window_height /* pixel height of source */ - ); - - xcb_flush(display); - free(points); - xcb_free_pixmap(display, pixmap); + writePixmap(pixmap_buffer, + draw_color, + colormap, + points, + gc, + display, + window, + expose); + was_exposed = 1; break; } @@ -331,10 +386,29 @@ main(void) { 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); } + xcb_free_pixmap(display, pixmap_buffer); xcb_disconnect(display); return 0;