Create buffers and a pixmap

To let the application process a frame while the windowing system updates the frame buffer with earlier changes, the sample uses a double-buffered window.

Using a double-buffered window has the added advantage of preventing flickering if an alpha-blended window is placed on top of the application window.

The default buffer size is usually fullscreen, but you can confirm that by querying the buffer size.

int rect[4] = { 0, 0 };
screen_create_window_buffers(screen_win, 2);
screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);
        

The sample stores the hourglass bitmap in a pixmap letting you use the screen_blit() function to copy the bitmap to the window. This technique is faster than moving the pixels manually in a for loop or with memcopy.

screen_pixmap_t screen_pix;
screen_create_pixmap(&screen_pix, screen_ctx);
        

The sample blends the hourglass on top of the yellow background and blue bar letting the bar show through the areas of the bitmap that are not covered by the hourglass. To do this, the pixmap must have an alpha channel — RGBA8888.

int format = SCREEN_FORMAT_RGBA8888;
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_FORMAT, &format);
        

Unlike the window buffers, to load the hourglass image you must use a pointer to the pixmap buffer. Later, when you copy the contents of the pixmap to the window using the screen_blit() function, you'll need a combined usage property of SCREEN_USAGE_WRITE and SCREEN_USAGE_NATIVE.

usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_NATIVE;
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_USAGE, &usage);
        

Specify the size of the hourglass — 100px x 100px.

int size[2] = { 100, 100 };
screen_set_pixmap_property_iv(screen_pix, SCREEN_PROPERTY_BUFFER_SIZE, size);
        

Pixmaps can have only a single buffer, but you must use screen_create_pixmap_buffer() to create that buffer explicitly. This lets you change several key properties, such as usage and buffer size, before creating the pixmap buffer. When you've created the buffer, you can get a handle to it by querying the pixmap's SCREEN_PROPERTY_RENDER_BUFFERS property.

screen_buffer_t screen_pbuf;
screen_create_pixmap_buffer(screen_pix);
screen_get_pixmap_property_pv(screen_pix, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_pbuf);
        

To fill in the hourglass shape, get a pointer to the pixmap buffer by querying the pointer property of the handle you obtained in the previous step. If you forgot to add read or write to the usage, this operation returns NULL.

unsigned char *ptr = NULL;
screen_get_buffer_property_pv(screen_pbuf, SCREEN_PROPERTY_POINTER, (void **)&ptr);
        

The stride is the number of bytes between pixels on different rows, represented by the stride variable. If a pixel at position (x,y) is at ptr, the pixel at location (x, y+1) will be at (ptr + stride). Because you set write and native usage, there's no guarantee that each line is 400 bytes in this case. Drivers often have constraints that require the stride to be larger than width * bytes per pixel.

int stride = 0;
screen_get_buffer_property_iv(screen_pbuf, SCREEN_PROPERTY_STRIDE, &stride);
        

Rather than load an image, as a real application might at this stage, the hourglass is simple enough to calculate. The calculation adjusts the alpha channel to be transparent or opaque based on a test that determines whether a pixel is inside or outside the hourglass.

for (i = 0; i < size[1]; i++, ptr += stride) {
    for (j = 0; j < size[0]; j++) {
        ptr[j*4] = 0xa0;
        ptr[j*4+1] = 0xa0;
        ptr[j*4+2] = 0xa0;
        ptr[j*4+3] = ((j >= i && j <= size[1]-i) || (j <= i && j >= size[1]-i)) ? 0xff : 0;
    }
}