diff options
| author | lvntky <klevent1903@gmail.com> | 2024-11-24 00:49:27 +0300 |
|---|---|---|
| committer | lvntky <klevent1903@gmail.com> | 2024-11-24 00:49:27 +0300 |
| commit | 7a2c9657c90baa1cab5a2c9c2e8635157452cb4f (patch) | |
| tree | 27eb44a21c6384134fd6e8f9c27e96d47df3785d | |
| parent | b3471b3464a0259a5e37e53ae5b90891a95351a6 (diff) | |
[feature] texture rendering
| -rw-r--r-- | asset/393.tga | bin | 1358 -> 0 bytes | |||
| -rw-r--r-- | asset/tr.tga | bin | 0 -> 4367378 bytes | |||
| -rw-r--r-- | example/texture.c | 72 | ||||
| -rw-r--r-- | fbgl.h | 212 |
4 files changed, 257 insertions, 27 deletions
diff --git a/asset/393.tga b/asset/393.tga Binary files differdeleted file mode 100644 index 2150e42..0000000 --- a/asset/393.tga +++ /dev/null diff --git a/asset/tr.tga b/asset/tr.tga Binary files differnew file mode 100644 index 0000000..86f10ae --- /dev/null +++ b/asset/tr.tga 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; +} @@ -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 |
