Add initial FnixLib development implementation

This commit is contained in:
Clinv committed 2026-10-13 20:36:51 -03:00
commit 84742ae38e
33 files changed
+3340

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
/*
* FnixLib - lienzo (búfer de píxeles en memoria).
*
* Un FnixCanvas es la superficie sobre la que dibuja el renderizador 2D por
* software. Cada ventana tiene uno (fnix_window_canvas), pero también se
* pueden crear lienzos independientes, por ejemplo para pruebas sin pantalla.
*
* Formato de píxel: uint32_t 0x00RRGGBB, filas consecutivas sin relleno,
* origen (0,0) arriba a la izquierda.
*/
#ifndef FNIX_CANVAS_H
#define FNIX_CANVAS_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
/* Lado máximo de un lienzo, en píxeles. */
#define FNIX_CANVAS_MAX_SIZE 16384
/* Crea un lienzo negro de width x height. Devuelve NULL si el tamaño no está
* entre 1 y FNIX_CANVAS_MAX_SIZE o si falta memoria (ver fnix_last_error). */
FnixCanvas *fnix_canvas_create(int width, int height);
/* Libera el lienzo. Acepta NULL. Si era el destino de dibujo del hilo actual,
* el destino pasa a ser NULL. */
void fnix_canvas_destroy(FnixCanvas *canvas);
int fnix_canvas_width(const FnixCanvas *canvas);
int fnix_canvas_height(const FnixCanvas *canvas);
/* Acceso de solo lectura a los píxeles (0x00RRGGBB). NULL si canvas es NULL. */
const uint32_t *fnix_canvas_pixels(const FnixCanvas *canvas);
/* Color del píxel (x, y) con alfa 255. Fuera del lienzo devuelve FNIX_TRANSPARENT. */
FnixColor fnix_canvas_get_pixel(const FnixCanvas *canvas, int x, int y);
/* Lienzo sobre el que dibujan las funciones fnix_draw_*. Es un valor por hilo.
* fnix_begin_frame() lo establece al lienzo de la ventana. */
void fnix_set_target(FnixCanvas *canvas);
FnixCanvas *fnix_get_target(void);
FNIX_END_DECLS
#endif /* FNIX_CANVAS_H */
+47
View File
@@ -0,0 +1,47 @@
/*
* FnixLib - dibujo 2D por software.
*
* Todas las funciones dibujan sobre el lienzo de destino (fnix_get_target()).
* Sin destino no hacen nada y dejan un error en fnix_last_error().
*
* Reglas comunes:
* - Se recorta al lienzo: dibujar parcial o totalmente fuera es seguro.
* - Color con alfa 255 reemplaza el píxel; alfa 0 no dibuja; los valores
* intermedios se mezclan con el fondo (alfa "source-over").
* - Cada píxel se modifica como máximo una vez por llamada, así que la mezcla
* con alfa nunca se aplica dos veces sobre el mismo píxel.
* - Coordenadas, anchos, altos y radios deben estar en [-2^28, 2^28]; fuera
* de ese rango no se dibuja nada y se registra un error.
*/
#ifndef FNIX_DRAW2D_H
#define FNIX_DRAW2D_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
/* Rellena todo el lienzo. Ignora el alfa del color (escribe color opaco). */
void fnix_clear(FnixColor color);
void fnix_draw_pixel(int x, int y, FnixColor color);
/* Línea de 1 píxel de grosor; incluye ambos extremos. */
void fnix_draw_line(int x_start, int y_start, int x_end, int y_end,
FnixColor color);
/* Rectángulo con esquina superior izquierda (x, y). width o height <= 0
* no dibujan nada. */
void fnix_draw_rect(int x, int y, int width, int height, FnixColor color);
void fnix_draw_rect_outline(int x, int y, int width, int height,
FnixColor color);
/* Círculo de centro (cx, cy). Un píxel (dx, dy) pertenece al disco si
* dx*dx + dy*dy <= radius*radius + radius. radius 0 dibuja un píxel;
* radius < 0 no dibuja nada. El contorno es el disco de radio `radius`
* menos el de radio `radius - 1` (1 píxel de grosor). */
void fnix_draw_circle(int cx, int cy, int radius, FnixColor color);
void fnix_draw_circle_outline(int cx, int cy, int radius, FnixColor color);
FNIX_END_DECLS
#endif /* FNIX_DRAW2D_H */
+42
View File
@@ -0,0 +1,42 @@
/*
* FnixLib - manejo de errores.
*
* Convención general de la API:
* - Las funciones que crean un objeto devuelven un puntero; NULL indica fallo.
* - Las funciones de consulta no fallan: con un puntero NULL o un argumento
* fuera de rango devuelven 0 / false.
* - Cuando algo falla, FnixLib guarda un código y un mensaje legibles
* (por hilo), que se consultan con fnix_last_error_code() y
* fnix_last_error(). Un éxito NO borra el último error (como errno).
*/
#ifndef FNIX_ERRORS_H
#define FNIX_ERRORS_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
typedef enum FnixError {
FNIX_OK = 0,
FNIX_ERROR_INVALID_ARGUMENT, /* argumento nulo o fuera de rango */
FNIX_ERROR_OUT_OF_MEMORY, /* no se pudo reservar memoria */
FNIX_ERROR_PLATFORM, /* fallo del sistema (pantalla, ventana) */
FNIX_ERROR_UNSUPPORTED /* el sistema no ofrece lo que se necesita */
} FnixError;
/* Descripción corta y fija de un código. Nunca devuelve NULL. */
const char *fnix_error_string(FnixError error);
/* Código del último error ocurrido en este hilo (FNIX_OK si no hubo ninguno). */
FnixError fnix_last_error_code(void);
/* Mensaje detallado del último error. Nunca devuelve NULL; es "" si no hubo
* errores. El puntero es válido hasta el siguiente error en este hilo. */
const char *fnix_last_error(void);
/* Olvida el último error de este hilo. */
void fnix_clear_error(void);
FNIX_END_DECLS
#endif /* FNIX_ERRORS_H */
+45
View File
@@ -0,0 +1,45 @@
/*
* FnixLib - cola de eventos.
*
* Además de las consultas de estado de input.h, cada ventana guarda los
* eventos recibidos en una cola que el programa puede vaciar con
* fnix_window_poll_event(). La cola conserva como máximo los 256 eventos más
* recientes: si el programa no la consulta, los más antiguos se descartan.
*/
#ifndef FNIX_EVENTS_H
#define FNIX_EVENTS_H
#include "fnix/input.h"
#include "fnix/types.h"
FNIX_BEGIN_DECLS
typedef enum FnixEventType {
FNIX_EVENT_NONE = 0,
FNIX_EVENT_WINDOW_CLOSE, /* el usuario pidió cerrar la ventana */
FNIX_EVENT_FOCUS_GAINED,
FNIX_EVENT_FOCUS_LOST,
FNIX_EVENT_KEY_DOWN, /* usa key y repeat */
FNIX_EVENT_KEY_UP, /* usa key */
FNIX_EVENT_MOUSE_BUTTON_DOWN, /* usa button, x, y */
FNIX_EVENT_MOUSE_BUTTON_UP, /* usa button, x, y */
FNIX_EVENT_MOUSE_MOVE, /* usa x, y */
FNIX_EVENT_MOUSE_WHEEL /* usa wheel, x, y */
} FnixEventType;
/* Solo son significativos los campos indicados para cada tipo; el resto vale 0. */
typedef struct FnixEvent {
FnixEventType type;
FnixKey key;
bool repeat; /* KEY_DOWN generado por autorepeat */
FnixMouseButton button;
int x, y;
int wheel; /* +1 arriba, -1 abajo */
} FnixEvent;
/* Saca el evento más antiguo de la cola. Devuelve false si está vacía. */
bool fnix_window_poll_event(FnixWindow *window, FnixEvent *event);
FNIX_END_DECLS
#endif /* FNIX_EVENTS_H */
+21
View File
@@ -0,0 +1,21 @@
/*
* FnixLib - cabecera general: incluye toda la API pública.
*/
#ifndef FNIX_FNIX_H
#define FNIX_FNIX_H
#define FNIX_VERSION_MAJOR 0
#define FNIX_VERSION_MINOR 1
#define FNIX_VERSION_PATCH 0
#define FNIX_VERSION_STRING "0.1.0"
#include "fnix/canvas.h"
#include "fnix/draw2d.h"
#include "fnix/errors.h"
#include "fnix/events.h"
#include "fnix/input.h"
#include "fnix/time.h"
#include "fnix/types.h"
#include "fnix/window.h"
#endif /* FNIX_FNIX_H */
+72
View File
@@ -0,0 +1,72 @@
/*
* FnixLib - estado del teclado y del ratón.
*
* Las consultas se refieren al estado tras el último fnix_begin_frame():
* - down: la tecla/botón está mantenida ahora mismo.
* - pressed: pasó de suelta a pulsada en este fotograma (el autorepeat del
* teclado NO la vuelve a activar).
* - released: pasó de pulsada a suelta en este fotograma. También se activa
* para todo lo que estaba pulsado cuando la ventana pierde el foco.
*
* Las teclas se identifican por el símbolo que produce cada una SIN modificadores
* en la distribución de teclado activa: con una distribución no QWERTY, la tecla
* física que antes era "A" puede cambiar de identificador.
*
* Todas las funciones aceptan window == NULL o valores inválidos y devuelven 0/false.
*/
#ifndef FNIX_INPUT_H
#define FNIX_INPUT_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
typedef enum FnixKey {
FNIX_KEY_UNKNOWN = 0,
/* Las letras, los dígitos y F1..F12 son contiguos: no reordenar. */
FNIX_KEY_A, FNIX_KEY_B, FNIX_KEY_C, FNIX_KEY_D, FNIX_KEY_E, FNIX_KEY_F,
FNIX_KEY_G, FNIX_KEY_H, FNIX_KEY_I, FNIX_KEY_J, FNIX_KEY_K, FNIX_KEY_L,
FNIX_KEY_M, FNIX_KEY_N, FNIX_KEY_O, FNIX_KEY_P, FNIX_KEY_Q, FNIX_KEY_R,
FNIX_KEY_S, FNIX_KEY_T, FNIX_KEY_U, FNIX_KEY_V, FNIX_KEY_W, FNIX_KEY_X,
FNIX_KEY_Y, FNIX_KEY_Z,
FNIX_KEY_0, FNIX_KEY_1, FNIX_KEY_2, FNIX_KEY_3, FNIX_KEY_4,
FNIX_KEY_5, FNIX_KEY_6, FNIX_KEY_7, FNIX_KEY_8, FNIX_KEY_9,
FNIX_KEY_F1, FNIX_KEY_F2, FNIX_KEY_F3, FNIX_KEY_F4, FNIX_KEY_F5,
FNIX_KEY_F6, FNIX_KEY_F7, FNIX_KEY_F8, FNIX_KEY_F9, FNIX_KEY_F10,
FNIX_KEY_F11, FNIX_KEY_F12,
FNIX_KEY_SPACE, FNIX_KEY_ENTER, FNIX_KEY_ESCAPE, FNIX_KEY_TAB,
FNIX_KEY_BACKSPACE,
FNIX_KEY_LEFT, FNIX_KEY_RIGHT, FNIX_KEY_UP, FNIX_KEY_DOWN,
FNIX_KEY_LEFT_SHIFT, FNIX_KEY_RIGHT_SHIFT,
FNIX_KEY_LEFT_CTRL, FNIX_KEY_RIGHT_CTRL,
FNIX_KEY_LEFT_ALT, FNIX_KEY_RIGHT_ALT,
FNIX_KEY_COUNT
} FnixKey;
typedef enum FnixMouseButton {
FNIX_MOUSE_LEFT = 0,
FNIX_MOUSE_MIDDLE,
FNIX_MOUSE_RIGHT,
FNIX_MOUSE_BUTTON_COUNT
} FnixMouseButton;
bool fnix_key_down(const FnixWindow *window, FnixKey key);
bool fnix_key_pressed(const FnixWindow *window, FnixKey key);
bool fnix_key_released(const FnixWindow *window, FnixKey key);
bool fnix_mouse_down(const FnixWindow *window, FnixMouseButton button);
bool fnix_mouse_pressed(const FnixWindow *window, FnixMouseButton button);
bool fnix_mouse_released(const FnixWindow *window, FnixMouseButton button);
/* Posición del cursor en píxeles de la ventana (origen arriba a la izquierda).
* Puede quedar fuera de la ventana mientras se arrastra con un botón pulsado. */
int fnix_mouse_x(const FnixWindow *window);
int fnix_mouse_y(const FnixWindow *window);
/* Desplazamiento de la rueda acumulado en este fotograma: positivo hacia
* arriba (alejándose del usuario), negativo hacia abajo. */
int fnix_mouse_wheel(const FnixWindow *window);
FNIX_END_DECLS
#endif /* FNIX_INPUT_H */
+20
View File
@@ -0,0 +1,20 @@
/*
* FnixLib - tiempo.
*/
#ifndef FNIX_TIME_H
#define FNIX_TIME_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
/* Segundos desde un origen arbitrario, con un reloj monótono (nunca retrocede).
* Sirve para medir intervalos, no para conocer la hora del día. */
double fnix_time_now(void);
/* Duerme el hilo actual al menos `seconds` segundos. Valores <= 0 no hacen nada. */
void fnix_time_sleep(double seconds);
FNIX_END_DECLS
#endif /* FNIX_TIME_H */
+47
View File
@@ -0,0 +1,47 @@
/*
* FnixLib - tipos públicos comunes.
*/
#ifndef FNIX_TYPES_H
#define FNIX_TYPES_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
#define FNIX_BEGIN_DECLS extern "C" {
#define FNIX_END_DECLS }
#else
#define FNIX_BEGIN_DECLS
#define FNIX_END_DECLS
#endif
FNIX_BEGIN_DECLS
/* Tipos opacos: su contenido es privado y puede cambiar entre versiones. */
typedef struct FnixWindow FnixWindow;
typedef struct FnixCanvas FnixCanvas;
/* Color RGBA con 8 bits por canal. a = 255 es opaco, a = 0 es invisible. */
typedef struct FnixColor {
uint8_t r, g, b, a;
} FnixColor;
#define FNIX_RGBA(red, green, blue, alpha) \
((FnixColor){(red), (green), (blue), (alpha)})
#define FNIX_RGB(red, green, blue) FNIX_RGBA((red), (green), (blue), 255)
#define FNIX_BLACK FNIX_RGB(0, 0, 0)
#define FNIX_WHITE FNIX_RGB(255, 255, 255)
#define FNIX_RED FNIX_RGB(255, 0, 0)
#define FNIX_GREEN FNIX_RGB(0, 255, 0)
#define FNIX_BLUE FNIX_RGB(0, 0, 255)
#define FNIX_YELLOW FNIX_RGB(255, 255, 0)
#define FNIX_CYAN FNIX_RGB(0, 255, 255)
#define FNIX_MAGENTA FNIX_RGB(255, 0, 255)
#define FNIX_GRAY FNIX_RGB(128, 128, 128)
#define FNIX_TRANSPARENT FNIX_RGBA(0, 0, 0, 0)
FNIX_END_DECLS
#endif /* FNIX_TYPES_H */
+65
View File
@@ -0,0 +1,65 @@
/*
* FnixLib - ventanas.
*
* Uso típico:
*
* FnixWindow *window = fnix_window_create("Mi juego", 800, 600);
* while (!fnix_window_should_close(window)) {
* fnix_begin_frame(window); // lee eventos, fija el destino
* fnix_clear(FNIX_BLACK);
* fnix_draw_circle(400, 300, 50, FNIX_RED);
* fnix_end_frame(window); // muestra y limita los FPS
* }
* fnix_window_destroy(window);
*
* Limitaciones de la versión 0.1.0: la ventana tiene tamaño fijo y solo existe
* la implementación para Linux/X11 (ver README.md).
*
* Todas las funciones aceptan window == NULL (no hacen nada o devuelven 0).
*/
#ifndef FNIX_WINDOW_H
#define FNIX_WINDOW_H
#include "fnix/types.h"
FNIX_BEGIN_DECLS
/* Crea y muestra una ventana de width x height píxeles (cada lado entre 1 y
* FNIX_CANVAS_MAX_SIZE) y su lienzo. Devuelve NULL si falla; el motivo está
* en fnix_last_error(). Límite inicial de FPS: 60. */
FnixWindow *fnix_window_create(const char *title, int width, int height);
/* Cierra la ventana y libera todos sus recursos. Acepta NULL. */
void fnix_window_destroy(FnixWindow *window);
/* true cuando el usuario cerró la ventana o se llamó a fnix_window_request_close. */
bool fnix_window_should_close(const FnixWindow *window);
void fnix_window_request_close(FnixWindow *window);
int fnix_window_width(const FnixWindow *window);
int fnix_window_height(const FnixWindow *window);
/* Lienzo de la ventana; lo que se dibuje en él se muestra en fnix_end_frame().
* Pertenece a la ventana: no se debe destruir por separado. */
FnixCanvas *fnix_window_canvas(FnixWindow *window);
/* Limita los fotogramas por segundo durmiendo en fnix_end_frame().
* 0 desactiva el límite (el bucle usará toda la CPU). Valores negativos = 0. */
void fnix_window_set_target_fps(FnixWindow *window, int fps);
/* Segundos entre el inicio del fotograma anterior y el del actual (medidos en
* fnix_begin_frame). Vale 0 en el primer fotograma. */
double fnix_window_delta_time(const FnixWindow *window);
/* Inicio de fotograma: borra los "pressed/released" y la rueda del fotograma
* anterior, procesa los eventos pendientes del sistema, calcula el delta time
* y fija el lienzo de la ventana como destino de dibujo. NO borra el lienzo. */
void fnix_begin_frame(FnixWindow *window);
/* Fin de fotograma: muestra el lienzo en la ventana y espera lo necesario para
* respetar el límite de FPS. */
void fnix_end_frame(FnixWindow *window);
FNIX_END_DECLS
#endif /* FNIX_WINDOW_H */