Applying C - Framebuffer Graphics |
Written by Harry Fairhead | |||||||
Monday, 10 June 2019 | |||||||
Page 3 of 3
We also need a function to get a block of pixels and a function to restore them: void saveBlock(uint32_t x, uint32_t y, uint32_t L, uint32_t block[]) { for (int i = 0; i < L; i++) { for (int j = 0; j < L; j++) { block[i+j*L] = getRawPixel(x + i, y + j); } } } void restoreBlock(uint32_t x, uint32_t y, uint32_t L, The pixel data is stored in a one-dimensional array simulating a two-dimensional array to avoid the problems of passing a variable size two-dimensional array. Now we can start on the main program. First we need the includes and some data structures: #define _POSIX_C_SOURCE 199309L #include <stdio.h> #include <stdlib.h> #include <linux/fb.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <inttypes.h> #include <time.h> #define BLOCKSIZE 10 struct fb_fix_screeninfo finfo; struct fb_var_screeninfo vinfo; uint8_t *fbp; uint32_t block[BLOCKSIZE*BLOCKSIZE]; struct color { uint32_t r; uint32_t g; uint32_t b; uint32_t a; }; The fbp variable is a global pointer to the start of the framebuffer. First we need to set up the framebuffer: int main(int argc, char** argv) { int fd = open("/dev/fb0", O_RDWR); ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); ioctl(fd, FBIOGET_FSCREENINFO, &finfo); vinfo.grayscale = 0; vinfo.bits_per_pixel = 32; ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo); ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); fbp = mmap(0, vinfo.yres * finfo.line_length, With the framebuffer set up we can write a bounce program ignoring the details of how the graphics are being created: struct color c = {0xFF, 0x00, 0x00, 0xFF}; int x = 600; int y = 400; int vx = -1; int vy = -1; struct timespec pause; pause.tv_sec = 0; pause.tv_nsec = 20 * 1000*1000; saveBlock(x, y, BLOCKSIZE,block); for (;;) { restoreBlock(x, y, BLOCKSIZE, block); x = x + vx; y = y + vy; if (x <= 0) { x = 0; vx = -vx; } if (y <= 0) { y = 0; vy = -vy; } if ((x + BLOCKSIZE) >= vinfo.xres) { x = vinfo.xres - BLOCKSIZE - 1; vx = -vx; } if ((y + BLOCKSIZE) >= vinfo.yres) { y = vinfo.yres - BLOCKSIZE - 1; vy = -vy; } saveBlock(x, y, BLOCKSIZE, block); setBlock(x, y, BLOCKSIZE, c); nanosleep(&pause, NULL); } return (EXIT_SUCCESS); } The if statements check to see if the ball is about to go off the screen and if it is then it is bounced by reversing the appropriate velocity and settings its position to be on the edge of the screen. The speed of the bounce can be determined by the time delay used in nanosleep. The ball will bounce around the screen, overwriting, but not destroying, anything else on the screen. There are various system "glitches" that can spoil the effect. In particular, the activation of any screensaver will result in the ball leaving a trail behind. If you are familiar with other graphics environments, you might be wondering how to synchronize your graphics update to the screen refresh. You can try looking up the ioctl FBIO_WAITFORVSYNC call, which waits for a vertical sync to occur. The problem is that many graphics cards do not implement it. Also included in the chapter:
Summary
Now available as a paperback or ebook from Amazon.Applying C For The IoT With Linux
Also see the companion book: Fundamental C <ASIN:1871962609> <ASIN:1871962617> Related ArticlesRemote C/C++ Development With NetBeans Getting Started With C/C++ On The Micro:bit To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.
Comments
or email your comment to: comments@i-programmer.info
|
|||||||
Last Updated ( Monday, 01 July 2019 ) |