diff options
| -rw-r--r-- | example/.gitignore | 3 | ||||
| -rw-r--r-- | example/CMakeLists.txt | 39 | ||||
| -rw-r--r-- | example/empty_example.c | 74 | ||||
| -rw-r--r-- | example/line.c | 7 | ||||
| -rw-r--r-- | example/raw_mode.c | 21 | ||||
| -rw-r--r-- | example/rectangle.c | 102 | ||||
| -rw-r--r-- | example/red.c | 13 | ||||
| -rw-r--r-- | fbgl.h | 798 |
8 files changed, 540 insertions, 517 deletions
diff --git a/example/.gitignore b/example/.gitignore index 07ac165..4b44f82 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,2 +1 @@ -build/ -core.* +build / core.* diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 411945a..837e6e8 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,24 +1,31 @@ cmake_minimum_required(VERSION 3.21) -project(fbglExamples C) + project(fbglExamples C) -include(../cmake/folders.cmake) + include(../ cmake / folders.cmake) -if(PROJECT_IS_TOP_LEVEL) - find_package(fbgl REQUIRED) -endif() + if (PROJECT_IS_TOP_LEVEL) find_package( + fbgl REQUIRED) endif() -add_custom_target(run-examples) + add_custom_target(run - examples) -function(add_example NAME) - add_executable("${NAME}" "${NAME}.c") - target_link_libraries("${NAME}" PRIVATE fbgl::fbgl) - target_compile_features("${NAME}" PRIVATE c_std_99) - add_custom_target("run_${NAME}" COMMAND "${NAME}" VERBATIM) - add_dependencies("run_${NAME}" "${NAME}") - add_dependencies(run-examples "run_${NAME}") -endfunction() + function(add_example NAME) add_executable( + "${NAME}" + "${NAME}.c") target_link_libraries("${NAME}" PRIVATE + fbgl::fbgl) + target_compile_features("${NAME}" PRIVATE c_std_99) add_custom_target( + "run_${NAME}" COMMAND + "${NAME}" VERBATIM) + add_dependencies( + "run_${NAME}" + "${NAME}") + add_dependencies( + run - + examples + "run_${NAME}") endfunction() -add_example(empty_example) + add_example( + empty_example) -add_folders(Example) + add_folders( + Example) diff --git a/example/empty_example.c b/example/empty_example.c index aee9232..cbb69c4 100644 --- a/example/empty_example.c +++ b/example/empty_example.c @@ -8,46 +8,46 @@ int main() { - printf("version %s\n", fbgl_version_info()); - printf("name %s\n", fbgl_name_info()); + printf("version %s\n", fbgl_version_info()); + printf("name %s\n", fbgl_name_info()); - fbgl_t buffer; - if (fbgl_init("/dev/fb0", &buffer) == -1) { - fprintf(stdout, "Error: could not open framebuffer device\n"); - return -1; - } - int color = 0x00000000; - - - FT_Library library = fbgl_freetype_init(); - if (!library) { - fbgl_destroy(&buffer); - return -1; - } + fbgl_t buffer; + if (fbgl_init("/dev/fb0", &buffer) == -1) { + fprintf(stdout, "Error: could not open framebuffer device\n"); + return -1; + } + int color = 0x00000000; - FT_Face face = fbgl_load_font(library, "../asset/font_2.ttf", 24); // Adjust path and size - if (!face) { - fbgl_freetype_cleanup(library); - fbgl_destroy(&buffer); - return -1; - } + FT_Library library = fbgl_freetype_init(); + if (!library) { + fbgl_destroy(&buffer); + return -1; + } - // Render text to framebuffer - fbgl_render_freetype_text(&buffer, library, face, "Hello, World!", 50, 50); + FT_Face face = fbgl_load_font(library, "../asset/font_2.ttf", + 24); // Adjust path and size + if (!face) { + fbgl_freetype_cleanup(library); + fbgl_destroy(&buffer); + return -1; + } - // Main loop checking for ESC key - int l = 0; - while (1) { - - if (fbgl_check_esc_key()) { - fprintf(stdout, "ESC pressed\n"); - break; - } - //fbgl_set_bg(&buffer, i++); // Set background color to - for(int i = 0x000000; i <= 0xFFFFFF; i++) { - fbgl_set_bg(&buffer, i); + // Render text to framebuffer + fbgl_render_freetype_text(&buffer, library, face, "Hello, World!", 50, + 50); + + // Main loop checking for ESC key + int l = 0; + while (1) { + if (fbgl_check_esc_key()) { + fprintf(stdout, "ESC pressed\n"); + break; + } + //fbgl_set_bg(&buffer, i++); // Set background color to + for (int i = 0x000000; i <= 0xFFFFFF; i++) { + fbgl_set_bg(&buffer, i); + } } - } - fbgl_destroy(&buffer); - return 0; + fbgl_destroy(&buffer); + return 0; } diff --git a/example/line.c b/example/line.c index 9d937cd..f20ec7e 100644 --- a/example/line.c +++ b/example/line.c @@ -11,11 +11,12 @@ int main(int argc, char *argv[]) fbgl_set_bg(&buffer, 0xFF0000); fbgl_point_t start = { 0, 0 }; - fbgl_point_t end = { 1020, 1020}; - for(int i = 0; i < 1890; i++) { + fbgl_point_t end = { 1020, 1020 }; + for (int i = 0; i < 1890; i++) { start.x = i; fbgl_draw_line(start, end, 0xFFFFFF, &buffer); - for(int j = 0; j < 10000000; j++){} + for (int j = 0; j < 10000000; j++) { + } } fbgl_draw_line(start, end, 0x000000, &buffer); diff --git a/example/raw_mode.c b/example/raw_mode.c index 12127af..449a824 100644 --- a/example/raw_mode.c +++ b/example/raw_mode.c @@ -4,18 +4,17 @@ int main(int argc, char *argv[]) { - fbgl_t fb; - fbgl_init("/dev/fb0", &fb); + fbgl_t fb; + fbgl_init("/dev/fb0", &fb); - fbgl_set_bg(&fb, 0xFFFFFF); + fbgl_set_bg(&fb, 0xFFFFFF); - while(1) { - if(fbgl_check_esc_key()) { - printf("pressed"); - fbgl_set_bg(&fb, 0x000000); + while (1) { + if (fbgl_check_esc_key()) { + printf("pressed"); + fbgl_set_bg(&fb, 0x000000); + } } - } - - return 0; -} + return 0; +} diff --git a/example/rectangle.c b/example/rectangle.c index 73f9c4b..ecc1afd 100644 --- a/example/rectangle.c +++ b/example/rectangle.c @@ -3,57 +3,59 @@ int main(int argc, char *argv[]) { - fbgl_t buffer; - if (fbgl_init("/dev/fb0", &buffer) == -1) { - fprintf(stdout, "Error: could not open framebuffer device\n"); - return -1; - } - - fbgl_set_bg(&buffer, 0xFFFFFF); // Set the background to white - - fbgl_point_t start = {100, 100}; - fbgl_point_t end = {200, 200}; - fbgl_draw_rectangle_outline(start, end, 0xFF0000, &buffer); // Draw red rectangle outline - - fbgl_point_t start2 = {600, 400}; - fbgl_point_t end2 = {800, 800}; - uint32_t colors[] = {0xFFC00, 0x00FF00, 0x0000FF, 0xFF00FF}; // Yellow, Green, Blue, Magenta - size_t color_index = 0; - - // Initial position of the marquee rectangle - int dx = 15; // Horizontal speed - int dy = 8; // Vertical speed - - while (1) { - // Clear the framebuffer (set background) - fbgl_set_bg(&buffer, 0xFFFFFF); - - - // Draw the moving filled rectangle - fbgl_draw_rectangle_filled(start2, end2, colors[color_index], &buffer); - - // Move the filled rectangle by updating its position - start2.x += dx; - end2.x += dx; - start2.y += dy; - end2.y += dy; - - // Reverse direction if the rectangle hits the screen boundary - if (start2.x <= 0 || end2.x >= buffer.width) { - dx = -dx; - color_index++; - } - if (start2.y <= 0 || end2.y >= buffer.height) { - dy = -dy; - color_index++; - } - if (color_index >= 4) { - color_index = 0; + fbgl_t buffer; + if (fbgl_init("/dev/fb0", &buffer) == -1) { + fprintf(stdout, "Error: could not open framebuffer device\n"); + return -1; } - usleep(50000); // Delay to make the animation visible (adjust as needed) - } + fbgl_set_bg(&buffer, 0xFFFFFF); // Set the background to white + + fbgl_point_t start = { 100, 100 }; + fbgl_point_t end = { 200, 200 }; + fbgl_draw_rectangle_outline(start, end, 0xFF0000, + &buffer); // Draw red rectangle outline + + fbgl_point_t start2 = { 600, 400 }; + fbgl_point_t end2 = { 800, 800 }; + uint32_t colors[] = { 0xFFC00, 0x00FF00, 0x0000FF, + 0xFF00FF }; // Yellow, Green, Blue, Magenta + size_t color_index = 0; + + // Initial position of the marquee rectangle + int dx = 15; // Horizontal speed + int dy = 8; // Vertical speed + + while (1) { + // Clear the framebuffer (set background) + fbgl_set_bg(&buffer, 0xFFFFFF); + + // Draw the moving filled rectangle + fbgl_draw_rectangle_filled(start2, end2, colors[color_index], + &buffer); + + // Move the filled rectangle by updating its position + start2.x += dx; + end2.x += dx; + start2.y += dy; + end2.y += dy; + + // Reverse direction if the rectangle hits the screen boundary + if (start2.x <= 0 || end2.x >= buffer.width) { + dx = -dx; + color_index++; + } + if (start2.y <= 0 || end2.y >= buffer.height) { + dy = -dy; + color_index++; + } + if (color_index >= 4) { + color_index = 0; + } + + usleep(50000); // Delay to make the animation visible (adjust as needed) + } - fbgl_destroy(&buffer); - return 0; + fbgl_destroy(&buffer); + return 0; } diff --git a/example/red.c b/example/red.c index 274bc31..7f64dbd 100644 --- a/example/red.c +++ b/example/red.c @@ -4,10 +4,11 @@ int main(int argc, char *argv[]) { - fbgl_t fb; - fbgl_init("/dev/fb0", &fb); - fbgl_set_bg(&fb, 0xFF0000); - while(1){} - - return 0; + fbgl_t fb; + fbgl_init("/dev/fb0", &fb); + fbgl_set_bg(&fb, 0xFF0000); + while (1) { + } + + return 0; } @@ -52,50 +52,50 @@ * Structs */ typedef struct fbgl { - int width; - int height; - int fd; - size_t screen_size; - uint32_t* pixels; - struct fb_var_screeninfo vinfo; // Variable screen information - struct fb_fix_screeninfo finfo; // Fixed screen information + int width; + int height; + int fd; + size_t screen_size; + uint32_t *pixels; + struct fb_var_screeninfo vinfo; // Variable screen information + struct fb_fix_screeninfo finfo; // Fixed screen information } fbgl_t; typedef struct fbgl_window { - int x; // Top-left x-coordinate of the window - int y; // Top-left y-coordinate of the window - int width; // Width of the window - int height; // Height of the window - fbgl_t* fb; // Pointer to the framebuffer context + int x; // Top-left x-coordinate of the window + int y; // Top-left y-coordinate of the window + int width; // Width of the window + int height; // Height of the window + fbgl_t *fb; // Pointer to the framebuffer context } fbgl_window_t; typedef struct fbgl_psf2_header { - uint8_t magic[2]; // Magic number, should be {0x72, 0xB5} - uint8_t version; // Version of PSF2 (usually 0) - uint8_t header_size; // Size of the header (usually 32 bytes) - uint16_t flags; // Flags (usually 0) - uint16_t numglyphs; // Number of glyphs (characters) - uint16_t bytes_per_glyph; // Number of bytes per glyph (depends on font size) - uint16_t height; // Height of each character in pixels - uint16_t width; // Width of each character in pixels - uint8_t* glyphs; // Pointer to the glyph data + uint8_t magic[2]; // Magic number, should be {0x72, 0xB5} + uint8_t version; // Version of PSF2 (usually 0) + uint8_t header_size; // Size of the header (usually 32 bytes) + uint16_t flags; // Flags (usually 0) + uint16_t numglyphs; // Number of glyphs (characters) + uint16_t bytes_per_glyph; // Number of bytes per glyph (depends on font size) + uint16_t height; // Height of each character in pixels + uint16_t width; // Width of each character in pixels + uint8_t *glyphs; // Pointer to the glyph data } fbgl_psf2_header_t; typedef struct fbgl_point { - size_t x; - size_t y; + size_t x; + size_t y; } fbgl_point_t; typedef struct fbgl_tga_texture { - uint16_t width; - uint16_t height; - uint32_t* data; + uint16_t width; + uint16_t height; + uint32_t *data; } fbgl_tga_texture_t; typedef struct fbgl_keyboard { - bool keys[FBGL_MAX_KEYS]; // Current state of each key - bool prev_keys[FBGL_MAX_KEYS]; // Previous state of each key - bool is_initialized; // Track if keyboard is initialized + bool keys[FBGL_MAX_KEYS]; // Current state of each key + bool prev_keys[FBGL_MAX_KEYS]; // Previous state of each key + bool is_initialized; // Track if keyboard is initialized } fbgl_keyboard_t; /** @@ -109,30 +109,30 @@ static fbgl_keyboard_t keyboard = { 0 }; #include <linux/kd.h> int fbgl_hide_cursor(int fd) { - int tty_fd = open("/dev/tty0", O_RDWR); - if (tty_fd == -1) { - perror("Error opening /dev/tty0"); - return -1; - } - - if (ioctl(tty_fd, KDSETMODE, KD_GRAPHICS) == -1) { - perror("Error setting graphics mode"); - close(tty_fd); - return -1; - } - - close(tty_fd); - return 0; + int tty_fd = open("/dev/tty0", O_RDWR); + if (tty_fd == -1) { + perror("Error opening /dev/tty0"); + return -1; + } + + if (ioctl(tty_fd, KDSETMODE, KD_GRAPHICS) == -1) { + perror("Error setting graphics mode"); + close(tty_fd); + return -1; + } + + close(tty_fd); + return 0; } #endif // FBGL_HIDE_CURSOR #ifdef FBGL_USE_FREETYPE FT_Library fbgl_freetype_init(); void fbgl_freetype_cleanup(FT_Library library); -FT_Face fbgl_load_font(FT_Library library, const char* font_path, - int font_size); -void fbgl_render_freetype_text(fbgl_t* fb, FT_Library library, FT_Face face, - const char* text, int x, int y); +FT_Face fbgl_load_font(FT_Library library, const char *font_path, + int font_size); +void fbgl_render_freetype_text(fbgl_t *fb, FT_Library library, FT_Face face, + const char *text, int x, int y); #endif // FBGL_USE_FREETYPE #ifdef __cplusplus @@ -142,8 +142,8 @@ extern "C" { /** * General purpose methods */ -char const* fbgl_name_info(void); -char const* fbgl_version_info(void); +char const *fbgl_name_info(void); +char const *fbgl_version_info(void); void fbgl_enable_raw_mode(); void fbgl_disable_raw_mode(); void fbgl_cleanup(int sig); @@ -151,15 +151,15 @@ int fbgl_check_esc_key(); void fbgl_set_signal_handlers(); /*Create and destroy methods*/ -int fbgl_init(const char* device, fbgl_t* fb); -void fbgl_destroy(fbgl_t* fb); +int fbgl_init(const char *device, fbgl_t *fb); +void fbgl_destroy(fbgl_t *fb); /** * Drawing functions */ void fbgl_clear(uint32_t color); -void fbgl_put_pixel(int x, int y, uint32_t color, fbgl_t* fb); -void fbgl_draw_line(fbgl_point_t x, fbgl_point_t y, uint32_t color, fbgl_t* fb); +void fbgl_put_pixel(int x, int y, uint32_t color, fbgl_t *fb); +void fbgl_draw_line(fbgl_point_t x, fbgl_point_t y, uint32_t color, fbgl_t *fb); void fbgl_set_bg(); /** @@ -170,7 +170,7 @@ void fbgl_display(); /** * Access framebuffer data methods */ -uint32_t* fb_get_data(void); +uint32_t *fb_get_data(void); int fb_get_width(void); int fb_get_height(void); @@ -178,18 +178,18 @@ int fb_get_height(void); * Shapes */ void fbgl_draw_rectangle_outline(fbgl_point_t top_left, - fbgl_point_t bottom_right, uint32_t color, - fbgl_t* fb); + fbgl_point_t bottom_right, uint32_t color, + fbgl_t *fb); void fbgl_draw_rectangle_filled(fbgl_point_t top_left, - fbgl_point_t bottom_right, uint32_t color, - fbgl_t* fb); + fbgl_point_t bottom_right, uint32_t color, + fbgl_t *fb); /** * texture */ -fbgl_tga_texture_t* fbgl_load_tga_texture(const char* path); -void fbgl_destroy_texture(fbgl_tga_texture_t* texture); -void fbgl_draw_texture(fbgl_t* fb, fbgl_tga_texture_t* texture, int x, int y); +fbgl_tga_texture_t *fbgl_load_tga_texture(const char *path); +void fbgl_destroy_texture(fbgl_tga_texture_t *texture); +void fbgl_draw_texture(fbgl_t *fb, fbgl_tga_texture_t *texture, int x, int y); /** * Keyboard @@ -203,177 +203,179 @@ bool fbgl_key_down(unsigned char key); #ifdef FBGL_IMPLEMENTATION -char const* fbgl_name_info(void) +char const *fbgl_name_info(void) { - return NAME; + return NAME; } -char const* fbgl_version_info(void) +char const *fbgl_version_info(void) { - return VERSION; + return VERSION; } -int fbgl_init(const char* device, fbgl_t* fb) +int fbgl_init(const char *device, fbgl_t *fb) { - if (!fb) { - fprintf(stderr, "Error: fbgl_t pointer is NULL."); - return -1; - } - - fb->fd = device == NULL ? open(DEFAULT_FB, O_RDWR) : open(device, O_RDWR); - if (fb->fd == -1) { - perror("Error openning framebuffer device"); - return -1; - } - - if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo) == -1) { - perror("Error: Reading fixed information."); - close(fb->fd); - return -1; - } - if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) == -1) { - perror("Error reading variable information"); - close(fb->fd); - return -1; - } + if (!fb) { + fprintf(stderr, "Error: fbgl_t pointer is NULL."); + return -1; + } + + fb->fd = device == NULL ? open(DEFAULT_FB, O_RDWR) : + open(device, O_RDWR); + if (fb->fd == -1) { + perror("Error openning framebuffer device"); + return -1; + } + + if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo) == -1) { + perror("Error: Reading fixed information."); + close(fb->fd); + return -1; + } + if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) == -1) { + perror("Error reading variable information"); + close(fb->fd); + return -1; + } #ifdef FBGL_HIDE_CURSOR - fbgl_hide_cursor(fb->fd); - fbgl_set_signal_handlers(); - fbgl_enable_raw_mode(); + fbgl_hide_cursor(fb->fd); + fbgl_set_signal_handlers(); + fbgl_enable_raw_mode(); #endif // FBGL_HIDE_CURSOR - fb->width = fb->vinfo.xres; - fb->height = fb->vinfo.yres; - fb->screen_size = fb->finfo.smem_len; - - // Map framebuffer to memory - fb->pixels = (uint32_t*)mmap(NULL, fb->screen_size, - PROT_READ | PROT_WRITE, MAP_SHARED, - fb->fd, 0); - if (fb->pixels == MAP_FAILED) { - perror("Error mapping framebuffer device to memory"); - close(fb->fd); - return -1; - } - - return 0; + fb->width = fb->vinfo.xres; + fb->height = fb->vinfo.yres; + fb->screen_size = fb->finfo.smem_len; + + // Map framebuffer to memory + fb->pixels = (uint32_t *)mmap(NULL, fb->screen_size, + PROT_READ | PROT_WRITE, MAP_SHARED, + fb->fd, 0); + if (fb->pixels == MAP_FAILED) { + perror("Error mapping framebuffer device to memory"); + close(fb->fd); + return -1; + } + + return 0; } -void fbgl_destroy(fbgl_t* fb) +void fbgl_destroy(fbgl_t *fb) { - if (!fb || fb->fd == -1) { - fprintf(stderr, - "Error: framebuffer not initialized or already destroyed.\n"); - return; - } + if (!fb || fb->fd == -1) { + fprintf(stderr, + "Error: framebuffer not initialized or already destroyed.\n"); + return; + } - if (fb->pixels && fb->pixels != MAP_FAILED) { - munmap(fb->pixels, fb->screen_size); - } + if (fb->pixels && fb->pixels != MAP_FAILED) { + munmap(fb->pixels, fb->screen_size); + } - close(fb->fd); - fb->fd = -1; + close(fb->fd); + fb->fd = -1; #ifdef FBGL_HIDE_CURSOR - fbgl_disable_raw_mode(); + fbgl_disable_raw_mode(); #endif // FBGL_HIDE_CURSOR } -void fbgl_set_bg(fbgl_t* fb, uint32_t color) +void fbgl_set_bg(fbgl_t *fb, uint32_t color) { - if (!fb || fb->fd == -1) { - fprintf(stderr, "Error: framebuffer not initialized.\n"); - return; - } - - // Fill the entire framebuffer with the specified color - for (size_t i = 0; i < (fb->width * fb->height); ++i) { - fb->pixels[i] = color; - } + if (!fb || fb->fd == -1) { + fprintf(stderr, "Error: framebuffer not initialized.\n"); + return; + } + + // Fill the entire framebuffer with the specified color + for (size_t i = 0; i < (fb->width * fb->height); ++i) { + fb->pixels[i] = color; + } } -void fbgl_put_pixel(int x, int y, uint32_t color, fbgl_t* fb) +void fbgl_put_pixel(int x, int y, uint32_t color, fbgl_t *fb) { - if (!fb || !fb->pixels) { - fprintf(stderr, "Error: framebuffer not initialized.\n"); - return; - } + if (!fb || !fb->pixels) { + fprintf(stderr, "Error: framebuffer not initialized.\n"); + return; + } - if (x < 0 || x >= fb->width || y < 0 || y >= fb->height) { - return; // Ignore out-of-bound coordinates - } + if (x < 0 || x >= fb->width || y < 0 || y >= fb->height) { + return; // Ignore out-of-bound coordinates + } - size_t index = y * fb->width + x; - fb->pixels[index] = color; + size_t index = y * fb->width + x; + fb->pixels[index] = color; } void fbgl_enable_raw_mode() { - struct termios raw; - - if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) { - perror("tcgetattr"); - exit(EXIT_FAILURE); - } - raw = orig_termios; - raw.c_lflag &= ~(ECHO | ICANON); - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { - perror("tcsetattr"); - exit(EXIT_FAILURE); - } + struct termios raw; + + if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) { + perror("tcgetattr"); + exit(EXIT_FAILURE); + } + raw = orig_termios; + raw.c_lflag &= ~(ECHO | ICANON); + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) { + perror("tcsetattr"); + exit(EXIT_FAILURE); + } } void fbgl_disable_raw_mode() { - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1) { - perror("tcsetattr"); - } + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1) { + perror("tcsetattr"); + } } void fbgl_cleanup(int sig) { - fbgl_disable_raw_mode(); - printf("\033[2J\033[H"); // Clear the terminal screen and move the cursor to top-left - exit(sig); + fbgl_disable_raw_mode(); + printf("\033[2J\033[H"); // Clear the terminal screen and move the cursor to top-left + exit(sig); } int fbgl_check_esc_key() { - char c; - struct timeval tv = { 0, 0 }; // Timeout of 0, to poll immediately - fd_set fds; - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - - // Check if there's input available - if (select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) == -1) { - perror("select"); - return 0; - } - - if (FD_ISSET(STDIN_FILENO, &fds)) { - if (read(STDIN_FILENO, &c, 1) == -1) { - perror("read"); - return 0; - } - return c == 27; // ASCII value of the `Esc` key - } - - return 0; + char c; + struct timeval tv = { 0, 0 }; // Timeout of 0, to poll immediately + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + + // Check if there's input available + if (select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv) == -1) { + perror("select"); + return 0; + } + + if (FD_ISSET(STDIN_FILENO, &fds)) { + if (read(STDIN_FILENO, &c, 1) == -1) { + perror("read"); + return 0; + } + return c == 27; // ASCII value of the `Esc` key + } + + return 0; } void fbgl_set_signal_handlers() { - struct sigaction sa; - sa.sa_handler = fbgl_cleanup; - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - - if (sigaction(SIGINT, &sa, NULL) == -1 || sigaction(SIGTERM, &sa, NULL) == -1) { - perror("sigaction"); - exit(EXIT_FAILURE); - } + struct sigaction sa; + sa.sa_handler = fbgl_cleanup; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + + if (sigaction(SIGINT, &sa, NULL) == -1 || + sigaction(SIGTERM, &sa, NULL) == -1) { + perror("sigaction"); + exit(EXIT_FAILURE); + } } #endif @@ -381,250 +383,262 @@ void fbgl_set_signal_handlers() #ifdef FBGL_USE_FREETYPE FT_Library fbgl_freetype_init() { - FT_Library library; - if (FT_Init_FreeType(&library)) { - fprintf(stderr, "Could not init FreeType Library\n"); - return NULL; - } - return library; + FT_Library library; + if (FT_Init_FreeType(&library)) { + fprintf(stderr, "Could not init FreeType Library\n"); + return NULL; + } + return library; } void fbgl_freetype_cleanup(FT_Library library) { - if (library) { - FT_Done_FreeType(library); - } + if (library) { + FT_Done_FreeType(library); + } } -FT_Face fbgl_load_font(FT_Library library, const char* font_path, int font_size) +FT_Face fbgl_load_font(FT_Library library, const char *font_path, int font_size) { - FT_Face face; - if (FT_New_Face(library, font_path, 0, &face)) { - fprintf(stderr, "Could not open font: %s\n", font_path); - return NULL; - } - FT_Set_Pixel_Sizes(face, 0, font_size); // Set font size - return face; + FT_Face face; + if (FT_New_Face(library, font_path, 0, &face)) { + fprintf(stderr, "Could not open font: %s\n", font_path); + return NULL; + } + FT_Set_Pixel_Sizes(face, 0, font_size); // Set font size + return face; } -void fbgl_render_freetype_text(fbgl_t* fb, FT_Library library, FT_Face face, - const char* text, int x, int y) +void fbgl_render_freetype_text(fbgl_t *fb, FT_Library library, FT_Face face, + const char *text, int x, int y) { - while (*text) { - FT_Load_Char(face, *text, FT_LOAD_RENDER); - FT_Bitmap bitmap = face->glyph->bitmap; - - // Draw the bitmap to framebuffer - for (int j = 0; j < bitmap.rows; j++) { - for (int i = 0; i < bitmap.width; i++) { - if (bitmap.buffer[j * bitmap.width + i]) { // Check pixel is not empty - fbgl_put_pixel(x + i, y + j, 0xFF0000, - fb); // Draw white pixel - } - } - } - x += face->glyph->advance.x >> 6; // Move to the next character position - ++text; - } + while (*text) { + FT_Load_Char(face, *text, FT_LOAD_RENDER); + FT_Bitmap bitmap = face->glyph->bitmap; + + // Draw the bitmap to framebuffer + for (int j = 0; j < bitmap.rows; j++) { + for (int i = 0; i < bitmap.width; i++) { + if (bitmap.buffer[j * bitmap.width + + i]) { // Check pixel is not empty + fbgl_put_pixel(x + i, y + j, 0xFF0000, + fb); // Draw white pixel + } + } + } + x += face->glyph->advance.x >> + 6; // Move to the next character position + ++text; + } } #endif // FBGL_USE_FREETYPE void fbgl_draw_line(fbgl_point_t x, fbgl_point_t y, uint32_t color, - fbgl_t* buffer) + fbgl_t *buffer) { - int dx = abs(y.x - x.x); - int dy = abs(y.y - x.y); + int dx = abs(y.x - x.x); + int dy = abs(y.y - x.y); - int sx = (x.x < y.x) ? 1 : -1; - int sy = (x.y < y.y) ? 1 : -1; + int sx = (x.x < y.x) ? 1 : -1; + int sy = (x.y < y.y) ? 1 : -1; - int err = dx - dy; + int err = dx - dy; - while (1) { - // Set the pixel at the current position - fbgl_put_pixel(x.x, x.y, color, buffer); + while (1) { + // Set the pixel at the current position + fbgl_put_pixel(x.x, x.y, color, buffer); - // If we've reached the end point, break - if (x.x == y.x && x.y == y.y) - break; + // If we've reached the end point, break + if (x.x == y.x && x.y == y.y) + break; - int e2 = 2 * err; + int e2 = 2 * err; - if (e2 > -dy) { - err -= dy; - x.x += sx; - } + if (e2 > -dy) { + err -= dy; + x.x += sx; + } - if (e2 < dx) { - err += dx; - x.y += sy; - } - } + if (e2 < dx) { + err += dx; + x.y += sy; + } + } } void fbgl_draw_rectangle_outline(fbgl_point_t top_left, - fbgl_point_t bottom_right, uint32_t color, - fbgl_t* fb) + fbgl_point_t bottom_right, uint32_t color, + fbgl_t *fb) { - // Top horizontal line - for (int x = top_left.x; x < bottom_right.x; x++) { - fbgl_put_pixel(x, top_left.y, color, fb); - } - - // Bottom horizontal line - for (int x = top_left.x; x < bottom_right.x; x++) { - fbgl_put_pixel(x, bottom_right.y - 1, color, fb); - } - - // Left vertical line - for (int y = top_left.y; y < bottom_right.y; y++) { - fbgl_put_pixel(top_left.x, y, color, fb); - } - - // Right vertical line - for (int y = top_left.y; y < bottom_right.y; y++) { - fbgl_put_pixel(bottom_right.x - 1, y, color, fb); - } + // Top horizontal line + for (int x = top_left.x; x < bottom_right.x; x++) { + fbgl_put_pixel(x, top_left.y, color, fb); + } + + // Bottom horizontal line + for (int x = top_left.x; x < bottom_right.x; x++) { + fbgl_put_pixel(x, bottom_right.y - 1, color, fb); + } + + // Left vertical line + for (int y = top_left.y; y < bottom_right.y; y++) { + fbgl_put_pixel(top_left.x, y, color, fb); + } + + // Right vertical line + for (int y = top_left.y; y < bottom_right.y; y++) { + fbgl_put_pixel(bottom_right.x - 1, y, color, fb); + } } void fbgl_draw_rectangle_filled(fbgl_point_t top_left, - fbgl_point_t bottom_right, uint32_t color, - fbgl_t* fb) + fbgl_point_t bottom_right, uint32_t color, + fbgl_t *fb) { - for (int y = top_left.y; y < bottom_right.y; y++) { - // Manually set each pixel in the row - for (int x = top_left.x; x < bottom_right.x; x++) { - fbgl_put_pixel(x, y, color, fb); - } - } + for (int y = top_left.y; y < bottom_right.y; y++) { + // Manually set each pixel in the row + for (int x = top_left.x; x < bottom_right.x; x++) { + fbgl_put_pixel(x, y, color, fb); + } + } } -fbgl_tga_texture_t* fbgl_load_tga_texture(const char* path) +fbgl_tga_texture_t *fbgl_load_tga_texture(const char *path) { - FILE* file = fopen(path, "rb"); - if (!file) { - perror("Unable to open texture file"); - return NULL; - } - - // TGA header structure - uint8_t header[18]; - if (fread(header, 1, sizeof(header), file) != sizeof(header)) { - perror("Error reading TGA header"); - fclose(file); - return NULL; - } - - // Allocate texture structure - fbgl_tga_texture_t* texture = (fbgl_tga_texture_t*)malloc(sizeof(fbgl_tga_texture_t)); - if (!texture) { - perror("Failed to allocate texture structure"); - fclose(file); - return NULL; - } - - // Extract dimensions from header - texture->width = header[12] | (header[13] << 8); - texture->height = header[14] | (header[15] << 8); - uint8_t bits_per_pixel = header[16]; - uint8_t image_descriptor = header[17]; - - // Verify format support - if (bits_per_pixel != 24 && bits_per_pixel != 32) { - fprintf(stderr, - "Unsupported TGA bit depth: %d (only 24 and 32-bit supported)\n", - bits_per_pixel); - free(texture); - fclose(file); - return NULL; - } - - // Skip image ID field - if (header[0]) { - fseek(file, header[0], SEEK_CUR); - } - - // Allocate pixel data - size_t pixel_count = texture->width * texture->height; - texture->data = (uint32_t*)malloc(pixel_count * sizeof(uint32_t)); - if (!texture->data) { - perror("Failed to allocate pixel data"); - free(texture); - fclose(file); - return NULL; - } - - // Read pixel data - uint8_t* pixel_buffer = (uint8_t*)malloc(bits_per_pixel / 8); - if (!pixel_buffer) { - perror("Failed to allocate pixel buffer"); - free(texture->data); - free(texture); - fclose(file); - return NULL; - } - - // Determine if image is flipped (based on image descriptor) - bool bottom_up = !(image_descriptor & 0x20); - - for (size_t i = 0; i < pixel_count; i++) { - size_t pixel_index = bottom_up ? (texture->height - 1 - (i / texture->width)) * texture->width + (i % texture->width) : i; - - if (fread(pixel_buffer, 1, bits_per_pixel / 8, file) != bits_per_pixel / 8) { - perror("Error reading pixel data"); - free(pixel_buffer); - free(texture->data); - free(texture); - fclose(file); - return NULL; - } - - // Convert BGR(A) to RGBA - uint32_t pixel = 0xFF000000; // Default alpha to 255 - pixel |= pixel_buffer[2] << 16; // R - pixel |= pixel_buffer[1] << 8; // G - pixel |= pixel_buffer[0]; // B - if (bits_per_pixel == 32) { - pixel = (pixel & 0x00FFFFFF) | (pixel_buffer[3] << 24); // A - } - - texture->data[pixel_index] = pixel; - } - - free(pixel_buffer); - fclose(file); - return texture; + FILE *file = fopen(path, "rb"); + if (!file) { + perror("Unable to open texture file"); + return NULL; + } + + // TGA header structure + uint8_t header[18]; + if (fread(header, 1, sizeof(header), file) != sizeof(header)) { + perror("Error reading TGA header"); + fclose(file); + return NULL; + } + + // Allocate texture structure + fbgl_tga_texture_t *texture = + (fbgl_tga_texture_t *)malloc(sizeof(fbgl_tga_texture_t)); + if (!texture) { + perror("Failed to allocate texture structure"); + fclose(file); + return NULL; + } + + // Extract dimensions from header + texture->width = header[12] | (header[13] << 8); + texture->height = header[14] | (header[15] << 8); + uint8_t bits_per_pixel = header[16]; + uint8_t image_descriptor = header[17]; + + // Verify format support + if (bits_per_pixel != 24 && bits_per_pixel != 32) { + fprintf(stderr, + "Unsupported TGA bit depth: %d (only 24 and 32-bit supported)\n", + bits_per_pixel); + free(texture); + fclose(file); + return NULL; + } + + // Skip image ID field + if (header[0]) { + fseek(file, header[0], SEEK_CUR); + } + + // Allocate pixel data + size_t pixel_count = texture->width * texture->height; + texture->data = (uint32_t *)malloc(pixel_count * sizeof(uint32_t)); + if (!texture->data) { + perror("Failed to allocate pixel data"); + free(texture); + fclose(file); + return NULL; + } + + // Read pixel data + uint8_t *pixel_buffer = (uint8_t *)malloc(bits_per_pixel / 8); + if (!pixel_buffer) { + perror("Failed to allocate pixel buffer"); + free(texture->data); + free(texture); + fclose(file); + return NULL; + } + + // Determine if image is flipped (based on image descriptor) + bool bottom_up = !(image_descriptor & 0x20); + + for (size_t i = 0; i < pixel_count; i++) { + size_t pixel_index = + bottom_up ? + (texture->height - 1 - (i / texture->width)) * + texture->width + + (i % texture->width) : + i; + + if (fread(pixel_buffer, 1, bits_per_pixel / 8, file) != + bits_per_pixel / 8) { + perror("Error reading pixel data"); + free(pixel_buffer); + free(texture->data); + free(texture); + fclose(file); + return NULL; + } + + // Convert BGR(A) to RGBA + uint32_t pixel = 0xFF000000; // Default alpha to 255 + pixel |= pixel_buffer[2] << 16; // R + pixel |= pixel_buffer[1] << 8; // G + pixel |= pixel_buffer[0]; // B + if (bits_per_pixel == 32) { + pixel = (pixel & 0x00FFFFFF) | + (pixel_buffer[3] << 24); // A + } + + texture->data[pixel_index] = pixel; + } + + free(pixel_buffer); + fclose(file); + return texture; } -void fbgl_destroy_texture(fbgl_tga_texture_t* texture) +void fbgl_destroy_texture(fbgl_tga_texture_t *texture) { - if (texture) { - free(texture->data); - free(texture); - } + if (texture) { + free(texture->data); + free(texture); + } } -void fbgl_draw_texture(fbgl_t* fb, fbgl_tga_texture_t* texture, int x, int y) +void fbgl_draw_texture(fbgl_t *fb, fbgl_tga_texture_t *texture, int x, int y) { - if (!fb || !texture || !texture->data) { - return; - } - - for (int ty = 0; ty < texture->height; ty++) { - for (int tx = 0; tx < texture->width; tx++) { - int screen_x = x + tx; - int screen_y = y + ty; - - // Skip if outside screen bounds - if (screen_x < 0 || screen_x >= fb->width || screen_y < 0 || screen_y >= fb->height) { - continue; - } - - uint32_t pixel = texture->data[ty * texture->width + tx]; - // Only draw if pixel is not fully transparent - if ((pixel & 0xFF000000) != 0) { - fbgl_put_pixel(screen_x, screen_y, pixel, fb); - } - } - } + if (!fb || !texture || !texture->data) { + return; + } + + for (int ty = 0; ty < texture->height; ty++) { + for (int tx = 0; tx < texture->width; tx++) { + int screen_x = x + tx; + int screen_y = y + ty; + + // Skip if outside screen bounds + if (screen_x < 0 || screen_x >= fb->width || + screen_y < 0 || screen_y >= fb->height) { + continue; + } + + uint32_t pixel = + texture->data[ty * texture->width + tx]; + // Only draw if pixel is not fully transparent + if ((pixel & 0xFF000000) != 0) { + fbgl_put_pixel(screen_x, screen_y, pixel, fb); + } + } + } } #ifdef __cplusplus } // extern "C" |
