summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asset/393.tgabin1358 -> 0 bytes
-rw-r--r--asset/tr.tgabin0 -> 4367378 bytes
-rw-r--r--example/texture.c72
-rw-r--r--fbgl.h212
4 files changed, 257 insertions, 27 deletions
diff --git a/asset/393.tga b/asset/393.tga
deleted file mode 100644
index 2150e42..0000000
--- a/asset/393.tga
+++ /dev/null
Binary files differ
diff --git a/asset/tr.tga b/asset/tr.tga
new file mode 100644
index 0000000..86f10ae
--- /dev/null
+++ b/asset/tr.tga
Binary files differ
diff --git a/example/texture.c b/example/texture.c
new file mode 100644
index 0000000..da614d4
--- /dev/null
+++ b/example/texture.c
@@ -0,0 +1,72 @@
+#define FBGL_IMPLEMENTATION
+#include "../fbgl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> // for usleep
+
+int main(int argc, char **argv)
+{
+ // Initialize framebuffer
+ fbgl_t framebuffer;
+ if (fbgl_init(NULL, &framebuffer) != 0) {
+ fprintf(stderr, "Failed to initialize framebuffer.\n");
+ return EXIT_FAILURE;
+ }
+
+ // Load a TGA texture
+ const char *texture_path = argv[1];
+ fbgl_tga_texture_t *texture = fbgl_load_tga_texture(texture_path);
+ if (!texture) {
+ fprintf(stderr, "Failed to load texture.\n");
+ fbgl_destroy(&framebuffer);
+ return EXIT_FAILURE;
+ }
+
+ // Set a background color (e.g., black)
+ fbgl_set_bg(&framebuffer, 0x000000); // Clear the framebuffer to black
+
+ // Texture movement parameters
+ int texture_x = 0; // Initial horizontal position of the texture
+ int texture_y = 100; // Initial vertical position of the texture
+ int dx = 5; // Horizontal speed (adjust for desired marquee speed)
+ int dy = 3; // Vertical speed (adjust for desired marquee speed)
+
+ // Main rendering loop
+ while (1) {
+ // Clear the framebuffer (set background)
+ fbgl_set_bg(&framebuffer, 0x000000);
+
+ // Draw the texture at the current position
+ fbgl_draw_texture(&framebuffer, texture, texture_x, texture_y);
+
+ // Move the texture by updating its position
+ texture_x += dx;
+ texture_y += dy;
+
+ // Reverse direction if the texture hits the screen boundary (X-axis)
+ if (texture_x <= 0 ||
+ texture_x + texture->width >= framebuffer.width) {
+ dx = -dx; // Reverse horizontal direction when hitting the left or right edge
+ }
+
+ // Reverse direction if the texture hits the screen boundary (Y-axis)
+ if (texture_y <= 0 ||
+ texture_y + texture->height >= framebuffer.height) {
+ dy = -dy; // Reverse vertical direction when hitting the top or bottom edge
+ }
+
+ usleep(50000); // Delay to make the marquee effect visible (adjust as needed)
+ }
+
+ // Wait for the user to press the escape key before exiting
+ printf("Press ESC to exit...\n");
+ while (!fbgl_check_esc_key()) {
+ // You can add additional rendering logic here if needed
+ }
+
+ // Clean up
+ fbgl_destroy_texture(texture);
+ fbgl_destroy(&framebuffer);
+
+ return EXIT_SUCCESS;
+}
diff --git a/fbgl.h b/fbgl.h
index 00a8f11..219009a 100644
--- a/fbgl.h
+++ b/fbgl.h
@@ -17,6 +17,7 @@
#include <stdio.h>
#include <termios.h>
#include <signal.h>
+#include <stdbool.h>
#ifdef FBGL_USE_FREETYPE
#include <ft2build.h>
@@ -63,6 +64,12 @@ typedef struct fbgl_point {
size_t y;
} fbgl_point_t;
+typedef struct fbgl_tga_texture {
+ uint16_t width;
+ uint16_t height;
+ uint32_t *data;
+} fbgl_tga_texture_t;
+
#ifdef FBGL_HIDE_CURSOR
#include <linux/kd.h>
int fbgl_hide_cursor(int fd)
@@ -142,6 +149,13 @@ void fbgl_draw_rectangle_filled(fbgl_point_t top_left,
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);
+
#ifdef FBGL_IMPLEMENTATION
char const *fbgl_name_info(void)
@@ -406,37 +420,181 @@ void fbgl_draw_line(fbgl_point_t x, fbgl_point_t y, uint32_t color,
}
}
}
-void fbgl_draw_rectangle_outline(fbgl_point_t top_left, 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);
- }
+void fbgl_draw_rectangle_outline(fbgl_point_t top_left,
+ 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);
+ }
}
-void fbgl_draw_rectangle_filled(fbgl_point_t top_left, 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);
- }
- }
+void fbgl_draw_rectangle_filled(fbgl_point_t top_left,
+ 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);
+ }
+ }
}
+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;
+}
+
+void fbgl_destroy_texture(fbgl_tga_texture_t *texture)
+{
+ if (texture) {
+ free(texture->data);
+ free(texture);
+ }
+}
+
+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);
+ }
+ }
+ }
+}
#ifdef __cplusplus
} // extern "C"
#endif