summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLevent Kaya <42411502+lvntky@users.noreply.github.com>2024-11-27 01:33:45 +0300
committerGitHub <noreply@github.com>2024-11-27 01:33:45 +0300
commitc7b78ebc52e789f0c4d21e3351169871c2b4143f (patch)
tree487fd817ccc0e1ac6c6c5112366553bb53ee2096
parent449ea58099de8fac62aae389b4ea2808a6ef66f3 (diff)
parent19ae0e7c82275831531429c3cfabd6810c311185 (diff)
Merge pull request #9 from dario-loi/master
[FEATURE] Filled and Outlined Circle
-rw-r--r--CMakeLists.txt3
-rw-r--r--examples/circle.c32
-rw-r--r--examples/text.c44
-rw-r--r--fbgl.h268
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);
diff --git a/fbgl.h b/fbgl.h
index c511ad2..55a8845 100644
--- a/fbgl.h
+++ b/fbgl.h
@@ -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];
}