Files
FnixLib/docs/DECISIONS.md
T

102 lines
5.6 KiB
Markdown

# 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.