# Decisiones de diseño de FnixLib Registro de las decisiones técnicas tomadas en la versión 0.1.0, con su motivo y lo que costaría revertirlas. Es un documento nuevo; no sustituye a ningún otro. ## Convenciones - **Lenguaje:** C17 estricto (`-std=c17`, sin extensiones de GNU). - **Nombres:** funciones `fnix_modulo_accion`, tipos `FnixTipo`, constantes y macros `FNIX_NOMBRE`. Los identificadores van en inglés; los comentarios y los mensajes de error, en español. - **Errores:** las funciones que crean objetos devuelven `NULL` si fallan; las de consulta no fallan (devuelven 0/false ante argumentos inválidos). El motivo se guarda por hilo y se lee con `fnix_last_error_code()` / `fnix_last_error()`. Un éxito no borra el último error (como `errno`). - **Objetos opacos:** `FnixWindow` y `FnixCanvas` solo se manejan por puntero, de modo que su contenido puede cambiar sin romper la API. ## Decisiones ### D1. Xlib (libX11) como interfaz con el sistema gráfico de Linux Se trata como interfaz nativa del sistema, igual que Win32 en Windows. Alternativas descartadas por ahora: hablar el protocolo X11 a mano sobre un socket (mucho trabajo sin beneficio en 0.1.0) y Wayland nativo (exige además implementar el protocolo y buscar una forma de dibujar). Los ejecutables se verifican bajo X11; en sesiones Wayland deberían funcionar mediante XWayland, pero **no está verificado**. *Reversible:* todo lo específico de X11 está en `src/platform/linux/` detrás de `src/platform/platform.h`. ### D2. Renderizador 2D por software y presentación con `XPutImage` Es la forma más sencilla de validar la arquitectura sin depender de la GPU. Coste: no hay aceleración ni sincronización vertical. El backend de GPU (OpenGL) queda para la fase 4 y se añadirá detrás de la misma API de dibujo. ### D3. Formato de píxel `0x00RRGGBB` y requisitos de pantalla El lienzo guarda `uint32_t 0x00RRGGBB`. Es lo que acepta X11 sin conversión en el caso habitual. Si el servidor no ofrece un visual TrueColor de 24/32 bits con esas máscaras y el mismo orden de bytes que la CPU, `fnix_window_create` falla con `FNIX_ERROR_UNSUPPORTED` y un mensaje explicativo (no se intenta convertir). ### D4. Destino de dibujo implícito, por hilo `fnix_draw_*` dibuja sobre el lienzo fijado con `fnix_set_target()`; `fnix_begin_frame()` fija el de la ventana. Mantiene la API corta (`fnix_draw_circle(x, y, r, color)`) y permite pruebas sin ventana usando `fnix_canvas_create()`. Coste: estado oculto por hilo. ### D5. Ventana de tamaño fijo Se indica con los *hints* de tamaño mínimo = máximo. Redimensionar exigiría decidir qué ocurre con el lienzo y no aporta a la primera versión. ### D6. Entrada: estado por fotograma + cola de eventos `fnix_begin_frame()` borra los *pressed/released* y la rueda, procesa los eventos del sistema y los aplica a una máquina de estados (`input.c`), que es lo que consultan `fnix_key_down`, `fnix_key_pressed`, etc. Además cada evento se guarda en una cola de 256 entradas (se descarta lo más antiguo) para quien prefiera `fnix_window_poll_event`. Detalles: - El autorepeat no vuelve a activar *pressed* (`XkbSetDetectableAutoRepeat`). - Al perder el foco, lo pulsado pasa a soltado: evita teclas pegadas. - Las teclas se identifican por el KeySym sin modificadores (índice 0) de la distribución activa; con distribuciones no QWERTY la tecla física puede cambiar de identificador. Alternativa (códigos físicos/scancodes) pospuesta. ### D7. Tiempo entre fotogramas y límite de FPS El *delta time* se mide de `begin_frame` a `begin_frame` (0 en el primero). El límite de FPS (60 por defecto) duerme en `end_frame` hasta una fecha límite que avanza un periodo por fotograma, de modo que el promedio a largo plazo es exacto. Si se va más de un fotograma tarde, se reajusta en lugar de recuperar con una ráfaga. ### D8. Geometría y recorte - Entradas limitadas a `[-2^28, 2^28]`; fuera de ese rango no se dibuja y se registra un error. Con ese límite los cálculos en `int64_t` no desbordan. - Todo se recorta antes de recorrer píxeles: el coste depende del lienzo, no del tamaño de la figura (una línea de millones de píxeles fuera de pantalla es barata). - Cada primitiva escribe cada píxel como máximo una vez, para que la mezcla con alfa no se aplique dos veces. - Líneas: Bresenham con aritmética entera; los empates se redondean hacia arriba, por lo que una línea y su inversa pueden diferir en algún píxel intermedio. - Círculos: un píxel pertenece al disco si `dx² + dy² <= r² + r`; el contorno es el disco de radio `r` menos el de `r - 1`. ### D9. Mezcla alfa "Source-over" con alfa recto y redondeo al entero más cercano; alfa 255 reemplaza y alfa 0 no dibuja. `fnix_clear` ignora el alfa. ### D10. CMake Biblioteca estática por defecto (`BUILD_SHARED_LIBS` la cambia, **sin verificar**), tipo *Release* si no se indica otro, opciones `FNIX_BUILD_EXAMPLES`, `FNIX_BUILD_TESTS`, `FNIX_WARNINGS_AS_ERRORS` y `FNIX_SANITIZE`. En sistemas que no son Linux la configuración falla con un mensaje claro en vez de compilar a medias. ### D11. Pruebas Tres ejecutables sin pantalla (núcleo, dibujo, entrada) y una prueba de integración que usa un servidor X real: una segunda conexión inyecta eventos con `XSendEvent` y lee los píxeles de la ventana con `XGetImage`. Sin `DISPLAY` termina con código 77 y `ctest` la marca como omitida. ## Pendiente (no implementado) - `cmake --install`, `find_package(FnixLib CONFIG)` y empaquetado. - Windows, y compilación cruzada desde Linux. - Imágenes y texturas, fuentes y texto, audio, matemáticas, colisiones, 3D. - Licencia: el repositorio no incluye `LICENSE`; debe elegirla el autor.