summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--examples/player.c119
-rw-r--r--fbgl.h163
3 files changed, 276 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fad5d22..7739254 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,3 +31,4 @@ add_example(framebuf_info)
add_example(text)
add_example(texture_show_fps)
add_example(circle)
+add_example(player)
diff --git a/examples/player.c b/examples/player.c
new file mode 100644
index 0000000..6eed8e7
--- /dev/null
+++ b/examples/player.c
@@ -0,0 +1,119 @@
+#define FBGL_IMPLEMENTATION
+#include "fbgl.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define PLAYER_SPEED 1
+
+typedef struct {
+ int x;
+ int y;
+} Player;
+
+int main(int argc, char *argv[])
+{
+ // Check for font file argument
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <psf1_font_file>\n", argv[0]);
+ return 1;
+ }
+
+ // Load PSF1 font
+ fbgl_psf1_font_t *font = fbgl_load_psf1_font(argv[1]);
+ if (!font) {
+ fprintf(stderr, "Failed to load PSF1 font from %s\n", argv[1]);
+ return 1;
+ }
+
+ // Initialize framebuffer
+ fbgl_t fb;
+ if (fbgl_init(NULL, &fb) != 0) {
+ fprintf(stderr, "Failed to initialize framebuffer\n");
+ fbgl_destroy_psf1_font(font);
+ return 1;
+ }
+
+ // Initialize keyboard
+ if (fbgl_keyboard_init() != 0) {
+ fprintf(stderr, "Failed to initialize keyboard\n");
+ fbgl_destroy(&fb);
+ fbgl_destroy_psf1_font(font);
+ return 1;
+ }
+
+ // Create a player
+ Player player = { .x = fb.width / 2, .y = fb.height / 2 };
+
+ // Game loop
+ while (1) {
+ // Clear the screen
+ fbgl_set_bg(&fb, 0x000000);
+
+ // Get key input
+ fbgl_key_t key = fbgl_get_key();
+
+ // Handle player movement
+ switch (key) {
+ case FBGL_KEY_UP:
+ player.y = (player.y - PLAYER_SPEED < 0) ?
+ 0 :
+ player.y - PLAYER_SPEED;
+ break;
+ case FBGL_KEY_DOWN:
+ player.y = (player.y + PLAYER_SPEED >= fb.height) ?
+ fb.height - 1 :
+ player.y + PLAYER_SPEED;
+ break;
+ case FBGL_KEY_LEFT:
+ player.x = (player.x - PLAYER_SPEED < 0) ?
+ 0 :
+ player.x - PLAYER_SPEED;
+ break;
+ case FBGL_KEY_RIGHT:
+ player.x = (player.x + PLAYER_SPEED >= fb.width) ?
+ fb.width - 1 :
+ player.x + PLAYER_SPEED;
+ break;
+ case FBGL_KEY_ESCAPE:
+ // Exit the program
+ goto cleanup;
+ default:
+ break;
+ }
+
+ // Draw the player (as a small white rectangle)
+ fbgl_point_t top_left = { .x = player.x - 5,
+ .y = player.y - 5 };
+ fbgl_point_t bottom_right = { .x = player.x + 5,
+ .y = player.y + 5 };
+ fbgl_draw_rectangle_filled(top_left, bottom_right,
+ FBGL_RGB(255, 255, 255), &fb);
+
+ // Display debug info
+ char fps_text[32];
+ char pos_text[32];
+ float fps = fbgl_get_fps();
+
+ snprintf(fps_text, sizeof(fps_text), "FPS: %.2f", fps);
+ snprintf(pos_text, sizeof(pos_text), "POS: %d, %d", player.x,
+ player.y);
+
+ // Render text using the loaded PSF1 font
+ fbgl_render_psf1_text(&fb, font, fps_text, 10, 10,
+ FBGL_RGB(0, 255, 0));
+ fbgl_render_psf1_text(&fb, font, pos_text, 10, 30,
+ FBGL_RGB(255, 0, 0));
+
+ // Small delay to control frame rate
+ usleep(16666); // ~60 FPS
+ }
+
+cleanup:
+ // Cleanup
+
+ fbgl_destroy(&fb);
+ fbgl_destroy_psf1_font(font);
+
+ return 0;
+}
diff --git a/fbgl.h b/fbgl.h
index 8b42682..5bd95c7 100644
--- a/fbgl.h
+++ b/fbgl.h
@@ -27,7 +27,6 @@
#define VERSION "0.1.0"
#define NAME "FBGL"
#define DEFAULT_FB "/dev/fb0"
-#define FBGL_MAX_KEYS 256 // Maximum number of keys to track
#include <fcntl.h>
#include <linux/fb.h>
@@ -45,11 +44,6 @@
#include <time.h>
#include <unistd.h>
-#ifdef FBGL_USE_FREETYPE
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#endif // FBGL_USE_FREETYPE
-
/**
* Structs
*/
@@ -91,11 +85,31 @@ typedef struct fbgl_psf1_font {
uint16_t char_width; // Character width in pixels (always 8 for PSF1)
} fbgl_psf1_font_t;
+typedef enum fbgl_key {
+ FBGL_KEY_NONE = 0,
+ FBGL_KEY_UP,
+ FBGL_KEY_DOWN,
+ FBGL_KEY_LEFT,
+ FBGL_KEY_RIGHT,
+ FBGL_KEY_ESCAPE,
+ FBGL_KEY_ENTER,
+ FBGL_KEY_SPACE,
+
+} fbgl_key_t;
+
+typedef struct fbgl_keyboard_state {
+ bool is_key_down;
+ fbgl_key_t current_key;
+ bool special_key_pressed;
+} fbgl_keyboard_state_t;
+
/**
* Key state function and variables
*
*/
static struct timespec previous_frame_time = { 0 };
+static struct termios orig_termios;
+static fbgl_keyboard_state_t g_keyboard_state = { 0 };
#ifdef __cplusplus
extern "C" {
@@ -158,7 +172,10 @@ void fbgl_render_psf1_text(fbgl_t *fb, fbgl_psf1_font_t *font, const char *text,
/**
* Keyboard
*/
-// Will refactor
+int fbgl_keyboard_init(void);
+void fbgl_destroy_keyboard(void);
+fbgl_key_t fbgl_get_key(void);
+bool fbgl_is_key_pressed(fbgl_key_t key);
/**
* Color Utilities
@@ -172,6 +189,42 @@ void fbgl_render_psf1_text(fbgl_t *fb, fbgl_psf1_font_t *font, const char *text,
(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))
+// Inside functions
+static void i_fbgl_die(const char *s);
+static void i_fbgl_disable_raw_mode();
+static void i_fbgl_enable_raw_mode();
+
+static void i_fbgl_die(const char *s)
+{
+ perror(s);
+ exit(1);
+}
+
+static void i_fbgl_enable_raw_mode()
+{
+ if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) {
+ i_fbgl_die("tcgetattr");
+ }
+ atexit(i_fbgl_disable_raw_mode);
+ struct termios raw = orig_termios;
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_oflag &= ~(OPOST);
+ raw.c_cflag |= (CS8);
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ raw.c_cc[VMIN] = 0;
+ raw.c_cc[VTIME] = 1;
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) {
+ i_fbgl_die("tcsetattr");
+ }
+}
+
+static void i_fbgl_disable_raw_mode()
+{
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1) {
+ i_fbgl_die("tcesetattr");
+ }
+}
+
#ifdef FBGL_IMPLEMENTATION
char const *fbgl_name_info(void)
@@ -693,6 +746,102 @@ void fbgl_render_psf1_text(fbgl_t *fb, fbgl_psf1_font_t *font, const char *text,
}
}
+int fbgl_keyboard_init(void)
+{
+ i_fbgl_enable_raw_mode();
+
+ // Initialize keyboard state
+ g_keyboard_state.is_key_down = false;
+ g_keyboard_state.current_key = FBGL_KEY_NONE;
+ g_keyboard_state.special_key_pressed = false;
+
+ return 0;
+}
+
+void fbgl_destroy_keyboard(void)
+{
+ i_fbgl_disable_raw_mode();
+}
+fbgl_key_t fbgl_get_key(void)
+{
+ char c;
+ ssize_t bytes_read = read(STDIN_FILENO, &c, 1);
+
+ if (bytes_read <= 0) {
+ return FBGL_KEY_NONE;
+ }
+
+ // Handle escape sequences for special keys
+ if (c == 27) {
+ char seq[3];
+ if (read(STDIN_FILENO, &seq[0], 1) != 1)
+ return FBGL_KEY_ESCAPE;
+ if (read(STDIN_FILENO, &seq[1], 1) != 1)
+ return FBGL_KEY_ESCAPE;
+
+ if (seq[0] == '[') {
+ switch (seq[1]) {
+ case 'A':
+ return FBGL_KEY_UP;
+ case 'B':
+ return FBGL_KEY_DOWN;
+ case 'C':
+ return FBGL_KEY_RIGHT;
+ case 'D':
+ return FBGL_KEY_LEFT;
+ }
+ }
+
+ return FBGL_KEY_NONE;
+ }
+
+ // Handle direct key presses
+ switch (c) {
+ case 10: // Enter key
+ return FBGL_KEY_ENTER;
+ case 32: // Space key
+ return FBGL_KEY_SPACE;
+ case 'w':
+ case 'W':
+ return FBGL_KEY_UP;
+ case 's':
+ case 'S':
+ return FBGL_KEY_DOWN;
+ case 'a':
+ case 'A':
+ return FBGL_KEY_LEFT;
+ case 'd':
+ case 'D':
+ return FBGL_KEY_RIGHT;
+ case 27: // Escape key
+ return FBGL_KEY_ESCAPE;
+ }
+
+ return FBGL_KEY_NONE;
+}
+
+bool fbgl_is_key_pressed(fbgl_key_t key)
+{
+ // Use select() for non-blocking input check
+ fd_set read_fds;
+ struct timeval timeout;
+
+ FD_ZERO(&read_fds);
+ FD_SET(STDIN_FILENO, &read_fds);
+
+ // Set a very short timeout
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ // Check if there's input available
+ if (select(STDIN_FILENO + 1, &read_fds, NULL, NULL, &timeout) > 0) {
+ fbgl_key_t pressed_key = fbgl_get_key();
+ return pressed_key == key;
+ }
+
+ return false;
+}
+
#endif // FBGL_IMPLEMENTATION
#ifdef __cplusplus