diff options
| author | Levent Kaya <42411502+lvntky@users.noreply.github.com> | 2024-11-27 01:33:45 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-27 01:33:45 +0300 |
| commit | c7b78ebc52e789f0c4d21e3351169871c2b4143f (patch) | |
| tree | 487fd817ccc0e1ac6c6c5112366553bb53ee2096 | |
| parent | 449ea58099de8fac62aae389b4ea2808a6ef66f3 (diff) | |
| parent | 19ae0e7c82275831531429c3cfabd6810c311185 (diff) | |
Merge pull request #9 from dario-loi/master
[FEATURE] Filled and Outlined Circle
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | examples/circle.c | 32 | ||||
| -rw-r--r-- | examples/text.c | 44 | ||||
| -rw-r--r-- | fbgl.h | 268 |
4 files changed, 219 insertions, 128 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 69efb9d..50a4e39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ function(add_example NAME) target_compile_features("${NAME}" PRIVATE c_std_99) target_compile_options("${NAME}" PRIVATE -Wall -Wextra -Wpedantic) target_include_directories("${NAME}" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") - target_link_libraries("${NAME}" PRIVATE ${FREETYPE2_LIBRARIES}) + target_link_libraries("${NAME}" PRIVATE ${FREETYPE2_LIBRARIES} m) add_custom_target("run_${NAME}" COMMAND "${NAME}" VERBATIM) add_dependencies("run_${NAME}" "${NAME}") add_dependencies(run-examples "run_${NAME}") @@ -32,3 +32,4 @@ add_example(framebuf_info) add_example(text) add_example(texture_show_fps) add_example(keyboard) +add_example(circle)
\ No newline at end of file diff --git a/examples/circle.c b/examples/circle.c new file mode 100644 index 0000000..40ad800 --- /dev/null +++ b/examples/circle.c @@ -0,0 +1,32 @@ +#define FBGL_IMPLEMENTATION +#include "fbgl.h" + +int main(void) +{ + fbgl_t buffer; + if (fbgl_init("/dev/fb0", &buffer) == -1) { + fprintf(stdout, "Error: could not open framebuffer device\n"); + return -1; + } + + fbgl_point_t circ_center = { 960, 540 }; + + fbgl_set_bg(&buffer, 0x00FF0000); + uint32_t i = 0; + while (true) { + circ_center.x = 960 + 200 * cos(i * M_PI / 180); + circ_center.y = 540 + 200 * sin(i * M_PI / 180); + + fbgl_draw_circle_outline(circ_center.x - 240, + circ_center.y - 240, 40, 0xFFFFFF, + &buffer); + i = (i + 1) % 360; + fbgl_draw_circle_filled(480, 540, 40, 0xFFFFFF, &buffer); + usleep(10000); + } + + while (1) { + } + + return 0; +} diff --git a/examples/text.c b/examples/text.c index 7cbf3ff..9003e3c 100644 --- a/examples/text.c +++ b/examples/text.c @@ -16,35 +16,35 @@ int save_framebuffer_as_ppm(fbgl_t *fb, const char *filename) } // Write PPM header (P6 format - binary RGB) - fprintf(fp, "P6\n%zu %zu\n255\n", fb->width, fb->height); + fprintf(fp, "P6\n%u %u\n255\n", fb->width, fb->height); - // Allocate buffer for pixel data - uint8_t *pixel_buffer = malloc(fb->width * fb->height * 3); - if (!pixel_buffer) { + // Allocate buffer for pixel data + uint8_t* pixel_buffer = malloc(fb->width * fb->height * 3); + if (!pixel_buffer) { perror("Memory allocation error"); fclose(fp); return -1; } // Convert framebuffer to RGB - for (size_t y = 0; y < fb->height; y++) { - for (size_t x = 0; x < fb->width; x++) { - uint32_t pixel = fb->pixels[y * fb->width + x]; - - // Extract RGB components (assuming 32-bit ARGB or RGB) - uint8_t r = (pixel >> 16) & 0xFF; - uint8_t g = (pixel >> 8) & 0xFF; - uint8_t b = pixel & 0xFF; - - // Store in buffer for PPM - pixel_buffer[(y * fb->width + x) * 3] = r; - pixel_buffer[(y * fb->width + x) * 3 + 1] = g; - pixel_buffer[(y * fb->width + x) * 3 + 2] = b; - } - } - - // Write pixel data - fwrite(pixel_buffer, 1, fb->width * fb->height * 3, fp); + for (int32_t y = 0; y < fb->height; y++) { + for (int32_t x = 0; x < fb->width; x++) { + uint32_t pixel = fb->pixels[y * fb->width + x]; + + // Extract RGB components (assuming 32-bit ARGB or RGB) + uint8_t r = (pixel >> 16) & 0xFF; + uint8_t g = (pixel >> 8) & 0xFF; + uint8_t b = pixel & 0xFF; + + // Store in buffer for PPM + pixel_buffer[(y * fb->width + x) * 3] = r; + pixel_buffer[(y * fb->width + x) * 3 + 1] = g; + pixel_buffer[(y * fb->width + x) * 3 + 2] = b; + } + } + + // Write pixel data + fwrite(pixel_buffer, 1, fb->width * fb->height * 3, fp); // Cleanup free(pixel_buffer); @@ -31,6 +31,7 @@ #include <fcntl.h> #include <linux/fb.h> +#include <math.h> #include <signal.h> #include <stdbool.h> #include <stddef.h> @@ -41,8 +42,8 @@ #include <sys/ioctl.h> #include <sys/mman.h> #include <termios.h> -#include <unistd.h> #include <time.h> +#include <unistd.h> #ifdef FBGL_USE_FREETYPE #include <ft2build.h> @@ -168,6 +169,10 @@ void fbgl_draw_rectangle_outline(fbgl_point_t top_left, void fbgl_draw_rectangle_filled(fbgl_point_t top_left, fbgl_point_t bottom_right, uint32_t color, fbgl_t *fb); +void fbgl_draw_circle_outline(int x, int y, int radius, uint32_t color, + fbgl_t* fb); +void fbgl_draw_circle_filled(int x, int y, int radius, uint32_t color, + fbgl_t* fb); /** * texture @@ -194,6 +199,15 @@ bool fbgl_key_down(unsigned char key); bool fbgl_key_pressed(unsigned char key); bool fbgl_key_released(unsigned char key); +/** + * Color Utilities + * + */ +#define FBGL_RGB(r, g, b) ((uint32_t)(((r) << 16) | ((g) << 8) | (b))) +#define FBGL_RGBA(r, g, b, a) ((uint32_t)(((a) << 24) | ((r) << 16) | ((g) << 8) | (b))) +#define FBGL_F32RGB_TO_U32(r, g, b) ((uint32_t)(((uint8_t)(r * 255) << 16) | ((uint8_t)(g * 255) << 8) | (uint8_t)(b * 255))) +#define FBGL_F32RGBA_TO_U32(r, g, b, a) ((uint32_t)(((uint8_t)(a * 255) << 24) | ((uint8_t)(r * 255) << 16) | ((uint8_t)(g * 255) << 8) | (uint8_t)(b * 255)) + #ifdef FBGL_IMPLEMENTATION char const *fbgl_name_info(void) @@ -443,109 +457,163 @@ void fbgl_draw_rectangle_filled(fbgl_point_t top_left, } } } -fbgl_tga_texture_t *fbgl_load_tga_texture(const char *path) + +void fbgl_draw_circle_outline(int x, int y, int radius, uint32_t color, + fbgl_t* fb) { - FILE *file = fopen(path, "rb"); - if (!file) { - perror("Unable to open texture file"); - return NULL; - } + int f = 1 - radius; + int ddF_x = 1; + int ddF_y = -2 * radius; + int xx = 0; + int yy = radius; + + fbgl_put_pixel(x, y + radius, color, fb); + fbgl_put_pixel(x, y - radius, color, fb); + fbgl_put_pixel(x + radius, y, color, fb); + fbgl_put_pixel(x - radius, y, color, fb); + + while (xx < yy) { + if (f >= 0) { + yy--; + ddF_y += 2; + f += ddF_y; + } + xx++; + ddF_x += 2; + f += ddF_x; + + fbgl_put_pixel(x + xx, y + yy, color, fb); + fbgl_put_pixel(x - xx, y + yy, color, fb); + fbgl_put_pixel(x + xx, y - yy, color, fb); + fbgl_put_pixel(x - xx, y - yy, color, fb); + fbgl_put_pixel(x + yy, y + xx, color, fb); + fbgl_put_pixel(x - yy, y + xx, color, fb); + fbgl_put_pixel(x + yy, y - xx, color, fb); + fbgl_put_pixel(x - yy, y - xx, color, fb); + } +} - // 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; - } +void fbgl_draw_circle_filled(int x, int y, int radius, uint32_t color, fbgl_t* fb) +{ + for (int yy = -radius; yy <= radius; ++yy) { + int half_width = (int)sqrt(radius * radius - yy * yy); - // 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; - } + int row_start = x - half_width; + int row_end = x + half_width; - // 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]; + if (y + yy < 0 || y + yy >= fb->height) + continue; + if (row_start < 0) + row_start = 0; + if (row_end >= fb->width) + row_end = fb->width - 1; - // 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; - } + int pixel_offset = (y + yy) * fb->width + row_start; + int num_pixels = row_end - row_start + 1; - // Skip image ID field - if (header[0]) { - fseek(file, header[0], SEEK_CUR); - } + uint32_t* row_start_ptr = fb->pixels + pixel_offset; + for (int i = 0; i < num_pixels; ++i) { + row_start_ptr[i] = color; + } + } +} - // 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; - } +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; + } - // 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; - } + // 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; + } - // 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; - } + // 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; + } - // 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 - } + // 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; + } - texture->data[pixel_index] = pixel; - } + // Skip image ID field + if (header[0]) { + fseek(file, header[0], SEEK_CUR); + } - free(pixel_buffer); - fclose(file); - return texture; + // 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) @@ -781,11 +849,10 @@ void fbgl_keyboard_update(void) // Copy current state to previous state memcpy(keyboard.prev_keys, keyboard.keys, sizeof(keyboard.keys)); - char c; + unsigned char c; while (read(STDIN_FILENO, &c, 1) > 0) { - if (c >= 0 && c < FBGL_MAX_KEYS) { - keyboard.keys[(unsigned char)c] = true; - } + + keyboard.keys[(unsigned char)c] = true; } // Reset keys that are not pressed @@ -799,25 +866,16 @@ void fbgl_keyboard_update(void) bool fbgl_key_down(unsigned char key) { - if (key >= FBGL_MAX_KEYS) { - return false; - } return keyboard.keys[key]; } bool fbgl_key_pressed(unsigned char key) { - if (key >= FBGL_MAX_KEYS) { - return false; - } return keyboard.keys[key] && !keyboard.prev_keys[key]; } bool fbgl_key_released(unsigned char key) { - if (key >= FBGL_MAX_KEYS) { - return false; - } return !keyboard.keys[key] && keyboard.prev_keys[key]; } |
