V2.0.0
This commit is contained in:
1 parent
7f7fcd545d
commit
4d9a339421
114 files changed
+11383
-1837
No files matched your search
@@ -0,0 +1,59 @@
|
||||
/* Composición, Onion Skin y reproducción. */
|
||||
#ifndef TAHGIBU_ANIMATION_H
|
||||
#define TAHGIBU_ANIMATION_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct tgb_onion_settings {
|
||||
bool enabled;
|
||||
int frames_before; /* 0..8 */
|
||||
int frames_after; /* 0..8 */
|
||||
float opacity_before; /* 0..1 opacidad del fotograma más cercano */
|
||||
float opacity_after;
|
||||
float falloff; /* 0..1: cuánto se atenúa cada fotograma más lejano */
|
||||
bool tint; /* teñir anteriores/posteriores */
|
||||
tgb_color tint_before; /* por defecto rojizo */
|
||||
tgb_color tint_after; /* por defecto azulado */
|
||||
} tgb_onion_settings;
|
||||
|
||||
void tgb_onion_defaults(tgb_onion_settings *s);
|
||||
tgb_status tgb_onion_validate(tgb_onion_settings *s); /* recorta a rangos válidos */
|
||||
|
||||
/* Aplana las capas visibles (con su opacidad) del fotograma en 'out'
|
||||
* (mismas dimensiones que el documento; se sobrescribe). */
|
||||
tgb_status tgb_render_flatten(const tgb_document *doc, size_t frame_index, tgb_canvas *out);
|
||||
|
||||
/* Vista de edición: fondo + Onion Skin + fotograma actual.
|
||||
* background.a == 0 deja el fondo transparente. */
|
||||
tgb_status tgb_render_view(const tgb_document *doc, size_t frame_index,
|
||||
const tgb_onion_settings *onion, tgb_color background,
|
||||
tgb_canvas *out);
|
||||
|
||||
typedef enum tgb_play_mode { TGB_PLAY_ONCE = 0, TGB_PLAY_LOOP, TGB_PLAY_PINGPONG } tgb_play_mode;
|
||||
|
||||
/* Reproductor: lógica pura de tiempo, respeta la duración de cada fotograma.
|
||||
* El documento debe sobrevivir al reproductor. */
|
||||
typedef struct tgb_player tgb_player;
|
||||
tgb_player *tgb_player_create(const tgb_document *doc);
|
||||
void tgb_player_destroy(tgb_player *p);
|
||||
void tgb_player_play(tgb_player *p);
|
||||
void tgb_player_pause(tgb_player *p);
|
||||
void tgb_player_stop(tgb_player *p); /* pausa y vuelve al inicio del rango */
|
||||
bool tgb_player_is_playing(const tgb_player *p);
|
||||
void tgb_player_set_mode(tgb_player *p, tgb_play_mode mode);
|
||||
void tgb_player_set_speed(tgb_player *p, float speed); /* 0.1 .. 8 */
|
||||
tgb_status tgb_player_set_range(tgb_player *p, size_t first, size_t last);
|
||||
void tgb_player_clear_range(tgb_player *p);
|
||||
tgb_status tgb_player_seek(tgb_player *p, size_t frame_index);
|
||||
size_t tgb_player_frame(const tgb_player *p);
|
||||
/* Avanza dt_ms milisegundos; devuelve el fotograma actual. */
|
||||
size_t tgb_player_update(tgb_player *p, double dt_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Lienzo de píxeles RGBA de 8 bits (NO premultiplicado), sin dependencias
|
||||
* de raylib ni del sistema operativo.
|
||||
* Propiedad: tgb_canvas_create/clone devuelven un objeto con 1 referencia;
|
||||
* quien lo recibe debe llamar a tgb_canvas_release una vez. */
|
||||
#ifndef TAHGIBU_CANVAS_H
|
||||
#define TAHGIBU_CANVAS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "tahgibu/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TGB_MAX_DIMENSION 4096 /* ancho/alto máximos de un lienzo */
|
||||
|
||||
typedef struct tgb_color { uint8_t r, g, b, a; } tgb_color;
|
||||
typedef struct tgb_rect { int x, y, w, h; } tgb_rect;
|
||||
|
||||
typedef struct tgb_canvas tgb_canvas;
|
||||
|
||||
tgb_canvas *tgb_canvas_create(int width, int height); /* transparente; NULL si falla */
|
||||
tgb_canvas *tgb_canvas_clone(const tgb_canvas *src); /* copia profunda */
|
||||
tgb_canvas *tgb_canvas_retain(tgb_canvas *c); /* +1 referencia */
|
||||
void tgb_canvas_release(tgb_canvas *c); /* -1; libera al llegar a 0; acepta NULL */
|
||||
int tgb_canvas_refs(const tgb_canvas *c);
|
||||
|
||||
int tgb_canvas_width(const tgb_canvas *c);
|
||||
int tgb_canvas_height(const tgb_canvas *c);
|
||||
size_t tgb_canvas_bytes(const tgb_canvas *c);
|
||||
/* Lectura directa (filas contiguas, 4 bytes por píxel: R,G,B,A). */
|
||||
const uint8_t *tgb_canvas_pixels(const tgb_canvas *c);
|
||||
|
||||
tgb_color tgb_canvas_get(const tgb_canvas *c, int x, int y); /* transparente fuera del lienzo */
|
||||
void tgb_canvas_set(tgb_canvas *c, int x, int y, tgb_color col); /* reemplaza */
|
||||
void tgb_canvas_blend(tgb_canvas *c, int x, int y, tgb_color col); /* "source-over" */
|
||||
void tgb_canvas_erase_px(tgb_canvas *c, int x, int y, uint8_t amount);/* resta opacidad */
|
||||
|
||||
void tgb_canvas_clear(tgb_canvas *c);
|
||||
void tgb_canvas_fill_rect(tgb_canvas *c, tgb_rect r, tgb_color col, bool blend);
|
||||
/* Copia src sobre dst en (dx,dy). opacity 0..255. blend=false reemplaza. */
|
||||
void tgb_canvas_blit(tgb_canvas *dst, const tgb_canvas *src, int dx, int dy,
|
||||
uint8_t opacity, bool blend);
|
||||
tgb_status tgb_canvas_crop(const tgb_canvas *src, tgb_rect r, tgb_canvas **out);
|
||||
bool tgb_canvas_is_empty(const tgb_canvas *c); /* todo alfa = 0 */
|
||||
bool tgb_canvas_equal(const tgb_canvas *a, const tgb_canvas *b);
|
||||
tgb_status tgb_canvas_copy_pixels(tgb_canvas *dst, const tgb_canvas *src); /* mismas dimensiones */
|
||||
|
||||
/* Seguimiento de la zona modificada (lo usan las sesiones de edición). */
|
||||
tgb_rect tgb_canvas_dirty(const tgb_canvas *c); /* w==0 si no hay cambios */
|
||||
void tgb_canvas_reset_dirty(tgb_canvas *c);
|
||||
void tgb_canvas_mark_dirty(tgb_canvas *c, tgb_rect r);
|
||||
|
||||
tgb_rect tgb_rect_intersect(tgb_rect a, tgb_rect b);
|
||||
tgb_rect tgb_rect_union(tgb_rect a, tgb_rect b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Contexto de la aplicación: dueño de la configuración, rutas de usuario,
|
||||
* bus de eventos y portapapeles de fotogramas.
|
||||
* Orden de destrucción: destruye primero todos los tgb_document y
|
||||
* gestores (recuperación, extensiones) y al final el contexto. */
|
||||
#ifndef TAHGIBU_CONTEXT_H
|
||||
#define TAHGIBU_CONTEXT_H
|
||||
|
||||
#include "tahgibu/error.h"
|
||||
#include "tahgibu/events.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct tgb_context_config {
|
||||
/* NULL = ubicación estándar del sistema (ver docs/ARCHITECTURE.md). */
|
||||
const char *config_dir; /* configuración y registro de extensiones */
|
||||
const char *data_dir; /* datos del usuario (extensiones instaladas, paletas) */
|
||||
const char *cache_dir; /* caché y temporales de historial */
|
||||
const char *state_dir; /* registros y archivos de recuperación */
|
||||
} tgb_context_config;
|
||||
|
||||
/* config puede ser NULL. Crea las carpetas si no existen. */
|
||||
tgb_status tgb_context_create(const tgb_context_config *config, tgb_context **out);
|
||||
void tgb_context_destroy(tgb_context *ctx); /* acepta NULL */
|
||||
|
||||
const char *tgb_context_config_dir(const tgb_context *ctx);
|
||||
const char *tgb_context_data_dir(const tgb_context *ctx);
|
||||
const char *tgb_context_cache_dir(const tgb_context *ctx);
|
||||
const char *tgb_context_state_dir(const tgb_context *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Documento de animación: dimensiones, fps, capas y fotogramas.
|
||||
* Modelo: las CAPAS son del documento; cada FOTOGRAMA tiene una "celda"
|
||||
* (lienzo) por capa. Las celdas vacías no ocupan memoria. Los índices
|
||||
* empiezan en 0; la capa 0 es la de más abajo.
|
||||
* Propiedad: tgb_document_create devuelve un objeto que debes destruir
|
||||
* con tgb_document_destroy ANTES de destruir el contexto. */
|
||||
#ifndef TAHGIBU_DOCUMENT_H
|
||||
#define TAHGIBU_DOCUMENT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "tahgibu/canvas.h"
|
||||
#include "tahgibu/context.h"
|
||||
#include "tahgibu/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TGB_MAX_FRAMES 5000
|
||||
#define TGB_MAX_LAYERS 64
|
||||
#define TGB_NAME_MAX 64 /* bytes, incluye el NUL; UTF-8 */
|
||||
#define TGB_MIN_FPS 1
|
||||
#define TGB_MAX_FPS 60
|
||||
#define TGB_MIN_FRAME_MS 16
|
||||
#define TGB_MAX_FRAME_MS 60000
|
||||
|
||||
/* Crea un documento con 1 capa ("Capa 1") y 1 fotograma vacío. */
|
||||
tgb_status tgb_document_create(tgb_context *ctx, int width, int height, int fps,
|
||||
tgb_document **out);
|
||||
void tgb_document_destroy(tgb_document *doc); /* acepta NULL */
|
||||
|
||||
tgb_context *tgb_document_context(const tgb_document *doc);
|
||||
int tgb_document_width(const tgb_document *doc);
|
||||
int tgb_document_height(const tgb_document *doc);
|
||||
int tgb_document_fps(const tgb_document *doc);
|
||||
/* Cambia el fps por defecto (y, si apply_to_all, la duración de todos los
|
||||
* fotogramas). Se puede deshacer. */
|
||||
tgb_status tgb_document_set_fps(tgb_document *doc, int fps, bool apply_to_all);
|
||||
|
||||
/* Cada cambio incrementa la revisión. "Sucio" = revisión distinta de la guardada. */
|
||||
uint64_t tgb_document_revision(const tgb_document *doc);
|
||||
bool tgb_document_dirty(const tgb_document *doc);
|
||||
void tgb_document_mark_saved(tgb_document *doc);
|
||||
|
||||
/* Ruta asociada (de la última carga/guardado). Puede ser NULL. */
|
||||
const char *tgb_document_path(const tgb_document *doc);
|
||||
tgb_status tgb_document_set_path(tgb_document *doc, const char *path);
|
||||
|
||||
/* false si una operación falló a medias y no se pudo restaurar el estado. */
|
||||
bool tgb_document_is_consistent(const tgb_document *doc);
|
||||
|
||||
/* Campo desconocido conservado de un archivo .tgb (JSON crudo) o NULL. */
|
||||
const char *tgb_document_extra_field(const tgb_document *doc, const char *key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Herramientas de dibujo.
|
||||
* Capa 1 (primitivas): funciones sobre un tgb_canvas, sin historial.
|
||||
* Capa 2 (sesión de edición): tgb_edit_* conecta una celda del documento
|
||||
* con el historial: todo lo dibujado entre begin y end es UNA operación
|
||||
* que se puede deshacer. Solo puede haber una sesión abierta por documento. */
|
||||
#ifndef TAHGIBU_DRAWING_H
|
||||
#define TAHGIBU_DRAWING_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum tgb_brush_mode { TGB_BRUSH_PAINT = 0, TGB_BRUSH_ERASE = 1 } tgb_brush_mode;
|
||||
|
||||
typedef struct tgb_brush {
|
||||
float size; /* diámetro en píxeles (1..512) */
|
||||
float hardness; /* 0 (muy suave) .. 1 (borde duro) */
|
||||
bool antialias; /* false = lápiz de píxeles exactos */
|
||||
tgb_color color;
|
||||
tgb_brush_mode mode;
|
||||
} tgb_brush;
|
||||
|
||||
tgb_brush tgb_brush_pencil(tgb_color color, int size); /* sin suavizado */
|
||||
tgb_brush tgb_brush_soft(tgb_color color, float size, float hardness);
|
||||
tgb_brush tgb_brush_eraser(float size, float hardness);
|
||||
|
||||
/* ---- Primitivas (marcan la zona modificada del lienzo) ---- */
|
||||
void tgb_draw_dab(tgb_canvas *c, const tgb_brush *b, float x, float y);
|
||||
void tgb_draw_line(tgb_canvas *c, const tgb_brush *b, float x0, float y0, float x1, float y1);
|
||||
void tgb_draw_rect(tgb_canvas *c, const tgb_brush *b, tgb_rect r, bool filled);
|
||||
void tgb_draw_ellipse(tgb_canvas *c, const tgb_brush *b, tgb_rect bounds, bool filled);
|
||||
/* Curva de Bézier cúbica con puntos de control p1 y p2. */
|
||||
void tgb_draw_bezier(tgb_canvas *c, const tgb_brush *b, float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, float x3, float y3);
|
||||
/* Relleno por inundación; tolerance 0..255 (por canal). Devuelve píxeles cambiados. */
|
||||
size_t tgb_flood_fill(tgb_canvas *c, int x, int y, tgb_color fill, int tolerance);
|
||||
tgb_color tgb_eyedropper(const tgb_canvas *c, int x, int y);
|
||||
|
||||
/* Transformaciones de una región (selección rectangular). */
|
||||
tgb_status tgb_region_move(tgb_canvas *c, tgb_rect src, int dx, int dy); /* mueve y deja hueco */
|
||||
tgb_status tgb_region_flip(tgb_canvas *c, tgb_rect r, bool horizontal);
|
||||
tgb_status tgb_region_scale(tgb_canvas *c, tgb_rect r, int new_w, int new_h); /* vecino más cercano, ancla arriba-izquierda */
|
||||
tgb_status tgb_region_clear(tgb_canvas *c, tgb_rect r);
|
||||
|
||||
/* ---- Sesión de edición ligada al documento ---- */
|
||||
|
||||
/* Abre la sesión sobre la celda (frame_id, layer_id). Crea la celda si estaba
|
||||
* vacía. Errores: TGB_ERR_LOCKED (capa bloqueada), TGB_ERR_STATE (ya hay
|
||||
* sesión), TGB_ERR_NOT_FOUND. */
|
||||
tgb_status tgb_edit_begin(tgb_document *doc, uint32_t frame_id, uint32_t layer_id,
|
||||
const char *label);
|
||||
/* Lienzo editable de la sesión (NULL si no hay sesión). NO lo liberes. */
|
||||
tgb_canvas *tgb_edit_canvas(tgb_document *doc);
|
||||
/* Vuelve al estado del principio de la sesión (útil para previsualizar formas). */
|
||||
tgb_status tgb_edit_reset(tgb_document *doc);
|
||||
/* Cierra y registra UNA operación en el historial si hubo cambios reales.
|
||||
* Devuelve TGB_WARN_HISTORY_LOST si el cambio se aplicó pero no cabe en el
|
||||
* historial. Si falla por memoria, deja la celda como estaba. */
|
||||
tgb_status tgb_edit_end(tgb_document *doc);
|
||||
tgb_status tgb_edit_cancel(tgb_document *doc); /* descarta los cambios */
|
||||
bool tgb_edit_active(const tgb_document *doc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Códigos de error comunes de toda la API pública.
|
||||
* Regla: valor < 0 = fallo, 0 = éxito, > 0 = éxito con aviso. */
|
||||
#ifndef TAHGIBU_ERROR_H
|
||||
#define TAHGIBU_ERROR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum tgb_status {
|
||||
TGB_WARN_HISTORY_LOST = 1, /* la operación se hizo pero no se pudo guardar para deshacer */
|
||||
TGB_OK = 0,
|
||||
TGB_ERR_INVALID_ARG = -1, /* argumento NULL o inválido */
|
||||
TGB_ERR_NOMEM = -2, /* sin memoria */
|
||||
TGB_ERR_RANGE = -3, /* índice o valor fuera de rango */
|
||||
TGB_ERR_NOT_FOUND = -4, /* id/archivo/elemento inexistente */
|
||||
TGB_ERR_EXISTS = -5, /* ya existe (p. ej. nombre repetido) */
|
||||
TGB_ERR_IO = -6, /* error de lectura/escritura del sistema */
|
||||
TGB_ERR_FORMAT = -7, /* el archivo no tiene el formato esperado */
|
||||
TGB_ERR_CORRUPT = -8, /* datos dañados (Base64, PNG, CRC...) */
|
||||
TGB_ERR_UNSUPPORTED = -9, /* válido pero no soportado todavía */
|
||||
TGB_ERR_LIMIT = -10, /* supera un límite de seguridad */
|
||||
TGB_ERR_STATE = -11, /* operación no permitida en el estado actual */
|
||||
TGB_ERR_LOCKED = -12, /* capa bloqueada */
|
||||
TGB_ERR_NOTHING = -13, /* nada que deshacer/rehacer */
|
||||
TGB_ERR_PLUGIN = -14, /* fallo de una extensión */
|
||||
TGB_ERR_INCOMPATIBLE = -15 /* versión de formato más nueva o desconocida */
|
||||
} tgb_status;
|
||||
|
||||
#define TGB_FAILED(s) ((s) < 0)
|
||||
#define TGB_SUCCEEDED(s) ((s) >= 0)
|
||||
|
||||
/* Nombre corto del código (para registros), p. ej. "TGB_ERR_IO". */
|
||||
const char *tgb_status_name(tgb_status status);
|
||||
|
||||
/* Mensaje detallado en español del último fallo en ESTE hilo.
|
||||
* Nunca devuelve NULL. El puntero es válido hasta la siguiente llamada
|
||||
* a la API desde el mismo hilo; copia el texto si lo necesitas más tiempo. */
|
||||
const char *tgb_last_error(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Bus de eventos sencillo. Las llamadas a los suscriptores son SÍNCRONAS,
|
||||
* en el mismo hilo que provocó el cambio. Un suscriptor no debe
|
||||
* suscribirse/desuscribirse ni modificar el documento dentro de su
|
||||
* callback. */
|
||||
#ifndef TAHGIBU_EVENTS_H
|
||||
#define TAHGIBU_EVENTS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tahgibu/canvas.h"
|
||||
#include "tahgibu/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct tgb_context tgb_context;
|
||||
typedef struct tgb_document tgb_document;
|
||||
|
||||
typedef enum tgb_event_type {
|
||||
TGB_EVENT_DOCUMENT_CHANGED = 1, /* cualquier cambio del documento */
|
||||
TGB_EVENT_PIXELS_CHANGED, /* cambian píxeles (rect, frame_id, layer_id) */
|
||||
TGB_EVENT_FRAMES_CHANGED, /* altas/bajas/orden/duración de fotogramas */
|
||||
TGB_EVENT_LAYERS_CHANGED, /* altas/bajas/propiedades de capas */
|
||||
TGB_EVENT_HISTORY_CHANGED, /* undo/redo disponible o modificado */
|
||||
TGB_EVENT_HISTORY_TRUNCATED, /* se descartó historial por límites */
|
||||
TGB_EVENT_RECOVERY_POINTS_CHANGED,
|
||||
TGB_EVENT_DOCUMENT_SAVED,
|
||||
TGB_EVENT_AUTOSAVED,
|
||||
TGB_EVENT_PLUGIN_LOADED,
|
||||
TGB_EVENT_PLUGIN_UNLOADED
|
||||
} tgb_event_type;
|
||||
|
||||
typedef struct tgb_event {
|
||||
tgb_event_type type;
|
||||
tgb_document *document; /* puede ser NULL (eventos globales) */
|
||||
uint32_t frame_id, layer_id;
|
||||
tgb_rect rect;
|
||||
const char *text; /* nombre/etiqueta; válido solo durante el callback */
|
||||
} tgb_event;
|
||||
|
||||
typedef void (*tgb_event_fn)(const tgb_event *event, void *user);
|
||||
|
||||
/* Devuelve un identificador >0 en *out_id. Máximo 64 suscriptores. */
|
||||
tgb_status tgb_events_subscribe(tgb_context *ctx, tgb_event_fn fn, void *user, uint32_t *out_id);
|
||||
tgb_status tgb_events_unsubscribe(tgb_context *ctx, uint32_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Fotogramas. Todas las operaciones que modifican se pueden deshacer y
|
||||
* fallan con TGB_ERR_STATE si hay una sesión de edición abierta. */
|
||||
#ifndef TAHGIBU_FRAME_H
|
||||
#define TAHGIBU_FRAME_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
size_t tgb_frame_count(const tgb_document *doc);
|
||||
uint32_t tgb_frame_id(const tgb_document *doc, size_t index); /* 0 si fuera de rango */
|
||||
tgb_status tgb_frame_index_of(const tgb_document *doc, uint32_t id, size_t *out_index);
|
||||
uint32_t tgb_frame_duration_ms(const tgb_document *doc, size_t index);
|
||||
|
||||
/* index == count añade al final. Devuelve el id del nuevo fotograma. */
|
||||
tgb_status tgb_frame_add(tgb_document *doc, size_t index, uint32_t *out_id);
|
||||
/* Duplica y coloca la copia justo después (comparte memoria hasta editarla). */
|
||||
tgb_status tgb_frame_duplicate(tgb_document *doc, size_t index, uint32_t *out_id);
|
||||
tgb_status tgb_frame_delete(tgb_document *doc, size_t index); /* nunca el último */
|
||||
tgb_status tgb_frame_move(tgb_document *doc, size_t from, size_t to);
|
||||
tgb_status tgb_frame_set_duration(tgb_document *doc, size_t index, uint32_t ms);
|
||||
|
||||
/* Portapapeles de fotogramas (vive en el contexto). Pegar exige mismas
|
||||
* dimensiones; las capas se emparejan por posición (las sobrantes se ignoran). */
|
||||
tgb_status tgb_frame_copy(tgb_document *doc, size_t index);
|
||||
tgb_status tgb_frame_paste(tgb_document *doc, size_t index, uint32_t *out_id);
|
||||
|
||||
/* Celda de un fotograma/capa. NULL = celda vacía (transparente). Solo lectura. */
|
||||
const tgb_canvas *tgb_frame_cel(const tgb_document *doc, size_t frame_index, size_t layer_index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Historial unificado (deshacer/rehacer) de un documento.
|
||||
* - Edición de píxeles, fotogramas, capas y propiedades usan el mismo historial.
|
||||
* - Operaciones agrupadas: begin_group ... end_group = UNA entrada.
|
||||
* - Límites adaptativos: memoria, nº de operaciones y almacenamiento temporal.
|
||||
* Al superarlos, las operaciones más antiguas de píxeles se pasan a disco
|
||||
* (si hay carpeta temporal y espacio) o, si no, se descartan (la más
|
||||
* antigua primero). Nunca se descarta lo ya aplicado al documento. */
|
||||
#ifndef TAHGIBU_HISTORY_H
|
||||
#define TAHGIBU_HISTORY_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
tgb_status tgb_history_undo(tgb_document *doc); /* TGB_ERR_NOTHING si no hay nada */
|
||||
tgb_status tgb_history_redo(tgb_document *doc);
|
||||
bool tgb_history_can_undo(const tgb_document *doc);
|
||||
bool tgb_history_can_redo(const tgb_document *doc);
|
||||
const char *tgb_history_undo_label(const tgb_document *doc); /* NULL si no hay */
|
||||
const char *tgb_history_redo_label(const tgb_document *doc);
|
||||
|
||||
/* Grupos anidables (hasta 8 niveles). Mientras hay un grupo abierto no se
|
||||
* puede deshacer/rehacer. abort_group deshace lo hecho dentro del grupo y
|
||||
* lo descarta (lo usan las extensiones al fallar). */
|
||||
tgb_status tgb_history_begin_group(tgb_document *doc, const char *label);
|
||||
tgb_status tgb_history_end_group(tgb_document *doc);
|
||||
tgb_status tgb_history_abort_group(tgb_document *doc);
|
||||
|
||||
typedef struct tgb_history_limits {
|
||||
size_t max_memory_bytes; /* memoria para datos del historial */
|
||||
uint32_t max_operations; /* nº máximo de operaciones deshacibles */
|
||||
size_t max_temp_bytes; /* disco temporal permitido (0 = no usar disco) */
|
||||
char temp_dir[512]; /* carpeta temporal ("" = no usar disco) */
|
||||
} tgb_history_limits;
|
||||
|
||||
tgb_status tgb_history_set_limits(tgb_document *doc, const tgb_history_limits *limits);
|
||||
void tgb_history_get_limits(const tgb_document *doc, tgb_history_limits *out);
|
||||
/* Recalcula los límites según la RAM libre, el tamaño del documento y el
|
||||
* espacio en disco. Llámalo de vez en cuando (p. ej. cada minuto). */
|
||||
tgb_status tgb_history_adapt(tgb_document *doc);
|
||||
|
||||
typedef struct tgb_history_stats {
|
||||
size_t undo_count, redo_count;
|
||||
size_t memory_bytes, temp_bytes;
|
||||
uint64_t dropped_ops, spilled_ops;
|
||||
} tgb_history_stats;
|
||||
void tgb_history_get_stats(const tgb_document *doc, tgb_history_stats *out);
|
||||
void tgb_history_clear(tgb_document *doc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Archivos: proyectos .tgb, importación de imágenes y exportación.
|
||||
* Toda lectura valida el contenido y devuelve errores con mensaje claro
|
||||
* (tgb_last_error). Todo guardado es atómico: se escribe un temporal en la
|
||||
* misma carpeta y se reemplaza el destino solo si todo salió bien. */
|
||||
#ifndef TAHGIBU_IO_H
|
||||
#define TAHGIBU_IO_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TGB_MAX_FILE_BYTES (512u * 1024u * 1024u) /* tamaño máximo de un .tgb */
|
||||
#define TGB_MAX_PIXEL_MEMORY ((size_t)2048u * 1024u * 1024u) /* memoria máxima de píxeles al cargar */
|
||||
|
||||
tgb_status tgb_document_load(tgb_context *ctx, const char *path, tgb_document **out);
|
||||
tgb_status tgb_document_load_memory(tgb_context *ctx, const uint8_t *data, size_t len,
|
||||
tgb_document **out);
|
||||
|
||||
typedef struct tgb_save_options {
|
||||
bool include_flat_frames; /* true: añade "frames" aplanados para lectores del formato 2 */
|
||||
bool legacy_v2; /* true: escribe formato 2 (una imagen por fotograma, SIN capas
|
||||
ni puntos de recuperación: se pierde información) */
|
||||
} tgb_save_options;
|
||||
void tgb_save_options_defaults(tgb_save_options *opts); /* include_flat_frames=true */
|
||||
|
||||
/* path NULL = usar la ruta asociada al documento. Tras guardar bien, asocia
|
||||
* la ruta y marca el documento como guardado (salvo en modo legacy_v2). */
|
||||
tgb_status tgb_document_save(tgb_document *doc, const char *path, const tgb_save_options *opts);
|
||||
/* Serializa a memoria; libera *out_data con tgb_free. No cambia el estado del documento. */
|
||||
tgb_status tgb_document_save_memory(const tgb_document *doc, const tgb_save_options *opts,
|
||||
uint8_t **out_data, size_t *out_len);
|
||||
void tgb_free(void *p);
|
||||
|
||||
/* PNG (8 bits RGBA al escribir; al leer: 8/16 bits, gris/RGB/paleta/+alfa,
|
||||
* sin entrelazado). */
|
||||
tgb_status tgb_png_decode_memory(const uint8_t *data, size_t len, tgb_canvas **out);
|
||||
tgb_status tgb_png_encode_memory(const tgb_canvas *canvas, uint8_t **out_data, size_t *out_len);
|
||||
|
||||
/* Importa un PNG como NUEVO fotograma en frame_index, dibujado en la capa
|
||||
* layer_index (centrado; se recorta si es mayor que el documento). Una sola
|
||||
* operación deshacible. */
|
||||
tgb_status tgb_import_png(tgb_document *doc, const char *path, size_t frame_index,
|
||||
size_t layer_index, uint32_t *out_frame_id);
|
||||
/* Exporta un fotograma aplanado a PNG. */
|
||||
tgb_status tgb_export_png(const tgb_document *doc, size_t frame_index, const char *path);
|
||||
/* Exporta todos los fotogramas: <dir>/<prefix>_0001.png ... */
|
||||
tgb_status tgb_export_png_sequence(const tgb_document *doc, const char *dir, const char *prefix);
|
||||
/* Exporta una animación APNG (PNG animado) respetando la duración de cada fotograma. */
|
||||
tgb_status tgb_export_apng(const tgb_document *doc, const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Capas. Opacidad 0..255. Una capa bloqueada rechaza ediciones de píxeles. */
|
||||
#ifndef TAHGIBU_LAYER_H
|
||||
#define TAHGIBU_LAYER_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
size_t tgb_layer_count(const tgb_document *doc);
|
||||
uint32_t tgb_layer_id(const tgb_document *doc, size_t index); /* 0 si fuera de rango */
|
||||
tgb_status tgb_layer_index_of(const tgb_document *doc, uint32_t id, size_t *out_index);
|
||||
/* El puntero devuelto es válido hasta el siguiente cambio de capas. */
|
||||
const char *tgb_layer_name(const tgb_document *doc, size_t index);
|
||||
bool tgb_layer_visible(const tgb_document *doc, size_t index);
|
||||
bool tgb_layer_locked(const tgb_document *doc, size_t index);
|
||||
uint8_t tgb_layer_opacity(const tgb_document *doc, size_t index);
|
||||
|
||||
tgb_status tgb_layer_add(tgb_document *doc, size_t index, const char *name, uint32_t *out_id);
|
||||
tgb_status tgb_layer_delete(tgb_document *doc, size_t index); /* nunca la última */
|
||||
tgb_status tgb_layer_move(tgb_document *doc, size_t from, size_t to);
|
||||
tgb_status tgb_layer_rename(tgb_document *doc, size_t index, const char *name);
|
||||
tgb_status tgb_layer_set_visible(tgb_document *doc, size_t index, bool visible);
|
||||
tgb_status tgb_layer_set_locked(tgb_document *doc, size_t index, bool locked);
|
||||
tgb_status tgb_layer_set_opacity(tgb_document *doc, size_t index, uint8_t opacity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
/* Extensiones nativas en C (y base de las de Lua).
|
||||
*
|
||||
* ADVERTENCIA DE SEGURIDAD: una extensión nativa es código que se ejecuta
|
||||
* DENTRO del proceso de Tahgibu con sus mismos permisos. Los permisos
|
||||
* (capabilities) de abajo controlan qué funciones del host se le ofrecen,
|
||||
* pero NO pueden impedir que el código nativo lea/escriba memoria o
|
||||
* archivos por su cuenta. Instala solo extensiones de origen confiable.
|
||||
*
|
||||
* Una extensión nativa es una biblioteca compartida (.so/.dll) que exporta:
|
||||
* const uint32_t tgb_plugin_api_version; (usa TGB_PLUGIN_DECLARE_API_VERSION)
|
||||
* tgb_status tgb_plugin_init(const tgb_host_api *host, tgb_plugin_handle *self,
|
||||
* tgb_plugin_info *info);
|
||||
* void tgb_plugin_shutdown(tgb_plugin_handle *self); (opcional)
|
||||
*
|
||||
* Las funciones de lectura/edición del host solo funcionan DENTRO de un
|
||||
* comando (mientras Tahgibu ejecuta tgb_plugin_command_fn), nunca en init. */
|
||||
#ifndef TAHGIBU_PLUGIN_H
|
||||
#define TAHGIBU_PLUGIN_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TGB_PLUGIN_API_VERSION 1
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define TGB_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define TGB_PLUGIN_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
/* Declara la versión de API con la que se compiló la extensión. Sin ella (o con otra) no se carga. */
|
||||
#define TGB_PLUGIN_DECLARE_API_VERSION TGB_PLUGIN_EXPORT const uint32_t tgb_plugin_api_version = TGB_PLUGIN_API_VERSION
|
||||
|
||||
typedef enum tgb_capability {
|
||||
TGB_CAP_READ_DOCUMENT = 1u << 0, /* leer dimensiones, fotogramas, píxeles */
|
||||
TGB_CAP_EDIT_DOCUMENT = 1u << 1, /* modificar el documento (siempre con historial) */
|
||||
TGB_CAP_EVENTS = 1u << 2 /* recibir eventos */
|
||||
} tgb_capability;
|
||||
|
||||
typedef struct tgb_plugin_handle tgb_plugin_handle; /* identidad de la extensión (opaco) */
|
||||
|
||||
typedef struct tgb_plugin_info {
|
||||
const char *name; /* nombre legible */
|
||||
const char *version; /* p. ej. "1.0.0" */
|
||||
uint32_t required_caps; /* combinación de tgb_capability */
|
||||
} tgb_plugin_info;
|
||||
|
||||
/* Un comando recibe el documento activo a través del host (no directamente). */
|
||||
typedef tgb_status (*tgb_plugin_command_fn)(tgb_plugin_handle *self, void *user);
|
||||
|
||||
typedef struct tgb_host_api {
|
||||
uint32_t api_version; /* = TGB_PLUGIN_API_VERSION */
|
||||
uint32_t struct_size; /* sizeof(tgb_host_api) del host */
|
||||
uint32_t (*granted_caps)(tgb_plugin_handle *self);
|
||||
void (*log)(tgb_plugin_handle *self, const char *message);
|
||||
tgb_status (*register_command)(tgb_plugin_handle *self, const char *name,
|
||||
tgb_plugin_command_fn fn, void *user);
|
||||
/* TGB_CAP_EVENTS */
|
||||
tgb_status (*subscribe)(tgb_plugin_handle *self, tgb_event_fn fn, void *user);
|
||||
/* TGB_CAP_READ_DOCUMENT */
|
||||
int (*doc_width)(tgb_plugin_handle *self);
|
||||
int (*doc_height)(tgb_plugin_handle *self);
|
||||
size_t (*doc_frame_count)(tgb_plugin_handle *self);
|
||||
size_t (*doc_layer_count)(tgb_plugin_handle *self);
|
||||
tgb_color (*get_pixel)(tgb_plugin_handle *self, size_t frame, size_t layer, int x, int y);
|
||||
/* TGB_CAP_EDIT_DOCUMENT: todo lo editado entre begin y end es una operación deshacible */
|
||||
tgb_status (*edit_begin)(tgb_plugin_handle *self, size_t frame, size_t layer);
|
||||
tgb_status (*put_pixel)(tgb_plugin_handle *self, int x, int y, tgb_color color);
|
||||
tgb_status (*fill_rect)(tgb_plugin_handle *self, tgb_rect r, tgb_color color);
|
||||
tgb_status (*edit_end)(tgb_plugin_handle *self);
|
||||
tgb_status (*add_frame)(tgb_plugin_handle *self, size_t index);
|
||||
} tgb_host_api;
|
||||
|
||||
/* ---------------- Gestor de extensiones (lado de la aplicación) ---------------- */
|
||||
typedef struct tgb_plugin_manager tgb_plugin_manager;
|
||||
|
||||
typedef struct tgb_plugin_entry_info {
|
||||
char id[64];
|
||||
char kind[8]; /* "native" o "lua" */
|
||||
char file[256];
|
||||
char name[64];
|
||||
char version[32];
|
||||
bool enabled;
|
||||
bool loaded;
|
||||
uint32_t granted_caps;
|
||||
uint32_t required_caps;
|
||||
char last_error[160];
|
||||
} tgb_plugin_entry_info;
|
||||
|
||||
/* El registro vive en <config_dir>/extensions.json; los archivos instalados
|
||||
* en <data_dir>/extensions/. NUNCA se carga nada que no esté en el registro
|
||||
* y habilitado explícitamente. */
|
||||
tgb_status tgb_plugin_manager_create(tgb_context *ctx, tgb_plugin_manager **out);
|
||||
void tgb_plugin_manager_destroy(tgb_plugin_manager *mgr); /* descarga todo */
|
||||
/* Copia el archivo a la carpeta de extensiones y lo registra DESHABILITADO. */
|
||||
tgb_status tgb_plugin_install(tgb_plugin_manager *mgr, const char *source_path,
|
||||
const char *id, size_t *out_index); /* id: [a-z0-9_-], 1..48; .lua = Lua */
|
||||
/* granted_caps = permisos que el usuario concede. Falla si no cubren los requeridos. */
|
||||
tgb_status tgb_plugin_enable(tgb_plugin_manager *mgr, size_t index, uint32_t granted_caps);
|
||||
tgb_status tgb_plugin_disable(tgb_plugin_manager *mgr, size_t index);
|
||||
tgb_status tgb_plugin_remove(tgb_plugin_manager *mgr, size_t index); /* borra archivo y registro */
|
||||
size_t tgb_plugin_count(const tgb_plugin_manager *mgr);
|
||||
tgb_status tgb_plugin_info_at(const tgb_plugin_manager *mgr, size_t index, tgb_plugin_entry_info *out);
|
||||
/* OJO: los índices de comandos CAMBIAN al habilitar, deshabilitar o eliminar extensiones.
|
||||
* Una interfaz debe guardar el NOMBRE ("id:comando") y ejecutar con tgb_plugin_run_command_named. */
|
||||
size_t tgb_plugin_command_count(const tgb_plugin_manager *mgr);
|
||||
tgb_status tgb_plugin_command_name(const tgb_plugin_manager *mgr, size_t cmd_index,
|
||||
char *buf, size_t buf_size);
|
||||
/* Ejecuta un comando sobre un documento como UNA operación deshacible.
|
||||
* Si el comando falla, se deshace todo lo que hizo (el documento queda como estaba). */
|
||||
tgb_status tgb_plugin_run_command(tgb_plugin_manager *mgr, size_t cmd_index, tgb_document *doc);
|
||||
/* Igual, pero identificando el comando por su nombre estable "id:comando". TGB_ERR_NOT_FOUND si no existe. */
|
||||
tgb_status tgb_plugin_run_command_named(tgb_plugin_manager *mgr, const char *full_name, tgb_document *doc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Recuperación. Hay CUATRO cosas distintas (ver docs/RECOVERY.md):
|
||||
* 1. El proyecto guardado por el usuario (.tgb).
|
||||
* 2. El autoguardado: copia temporal en la carpeta de estado.
|
||||
* 3. La sesión: marcador que permite detectar un cierre inesperado.
|
||||
* 4. Los puntos de recuperación NOMBRADOS: viven dentro del proyecto. */
|
||||
#ifndef TAHGIBU_RECOVERY_H
|
||||
#define TAHGIBU_RECOVERY_H
|
||||
|
||||
#include "tahgibu/document.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ---------- Puntos de recuperación nombrados ---------- */
|
||||
#define TGB_MAX_RECOVERY_POINTS 64
|
||||
#define TGB_RECOVERY_POINT_NAME_MAX 128
|
||||
|
||||
typedef struct tgb_recovery_point_info {
|
||||
uint32_t id;
|
||||
char name[TGB_RECOVERY_POINT_NAME_MAX];
|
||||
int64_t created_unix;
|
||||
bool compatible; /* false: guardado con un formato que no se puede restaurar */
|
||||
} tgb_recovery_point_info;
|
||||
|
||||
size_t tgb_recovery_point_count(const tgb_document *doc);
|
||||
tgb_status tgb_recovery_point_info_at(const tgb_document *doc, size_t index,
|
||||
tgb_recovery_point_info *out);
|
||||
/* Nombre único, no vacío, UTF-8 válido. Comparte memoria con el documento
|
||||
* (copy-on-write): solo cuesta lo que luego se edite. */
|
||||
tgb_status tgb_recovery_point_create(tgb_document *doc, const char *name, uint32_t *out_id);
|
||||
/* Antes de restaurar crea el punto "Antes de restaurar «nombre»" y vacía el
|
||||
* historial ordinario (queda el punto automático para volver). */
|
||||
tgb_status tgb_recovery_point_restore(tgb_document *doc, uint32_t id);
|
||||
tgb_status tgb_recovery_point_delete(tgb_document *doc, uint32_t id);
|
||||
/* Memoria extra retenida por los puntos (celdas que ya no están en el documento). */
|
||||
size_t tgb_recovery_points_extra_bytes(const tgb_document *doc);
|
||||
|
||||
/* ---------- Autoguardado y recuperación de sesión ---------- */
|
||||
typedef struct tgb_recovery tgb_recovery;
|
||||
|
||||
typedef struct tgb_recovery_candidate {
|
||||
char autosave_path[512];
|
||||
char original_path[512]; /* "" si el documento nunca se guardó */
|
||||
char title[128];
|
||||
int64_t saved_unix;
|
||||
} tgb_recovery_candidate;
|
||||
|
||||
/* Abre la gestión de sesión: busca restos de sesiones que terminaron mal y
|
||||
* registra la sesión actual. Los archivos originales nunca se tocan. */
|
||||
tgb_status tgb_recovery_open(tgb_context *ctx, tgb_recovery **out);
|
||||
/* clean_exit=true: borra marcador y autoguardados de esta sesión.
|
||||
* clean_exit=false: libera memoria pero deja los archivos (simula un cierre inesperado en pruebas). */
|
||||
void tgb_recovery_close(tgb_recovery *rec, bool clean_exit);
|
||||
|
||||
size_t tgb_recovery_candidate_count(const tgb_recovery *rec);
|
||||
tgb_status tgb_recovery_candidate_at(const tgb_recovery *rec, size_t index,
|
||||
tgb_recovery_candidate *out);
|
||||
/* Carga el autoguardado en un documento NUEVO (el original no se modifica). */
|
||||
tgb_status tgb_recovery_candidate_load(tgb_recovery *rec, size_t index, tgb_document **out);
|
||||
/* Borra el autoguardado (solo si el usuario lo decide). */
|
||||
tgb_status tgb_recovery_candidate_discard(tgb_recovery *rec, size_t index);
|
||||
|
||||
tgb_status tgb_recovery_attach(tgb_recovery *rec, tgb_document *doc, const char *title);
|
||||
tgb_status tgb_recovery_detach(tgb_recovery *rec, tgb_document *doc); /* borra su autoguardado */
|
||||
void tgb_recovery_set_interval(tgb_recovery *rec, double seconds); /* por defecto 300 (5 min) */
|
||||
/* Llamar a menudo con un reloj monotónico en segundos. Autoguarda los
|
||||
* documentos con cambios cuando toca. Si falla (p. ej. disco lleno) devuelve
|
||||
* el error y CONSERVA el autoguardado anterior. */
|
||||
tgb_status tgb_recovery_tick(tgb_recovery *rec, double now_seconds);
|
||||
tgb_status tgb_recovery_save_now(tgb_recovery *rec, tgb_document *doc);
|
||||
/* Avisa de que el usuario guardó el proyecto: el autoguardado ya no hace falta. */
|
||||
void tgb_recovery_notify_saved(tgb_recovery *rec, tgb_document *doc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Cabecera "paraguas" de la API pública de Tahgibu. */
|
||||
#ifndef TAHGIBU_H
|
||||
#define TAHGIBU_H
|
||||
|
||||
#include "tahgibu/version.h"
|
||||
#include "tahgibu/error.h"
|
||||
#include "tahgibu/canvas.h"
|
||||
#include "tahgibu/events.h"
|
||||
#include "tahgibu/context.h"
|
||||
#include "tahgibu/document.h"
|
||||
#include "tahgibu/frame.h"
|
||||
#include "tahgibu/layer.h"
|
||||
#include "tahgibu/drawing.h"
|
||||
#include "tahgibu/animation.h"
|
||||
#include "tahgibu/history.h"
|
||||
#include "tahgibu/recovery.h"
|
||||
#include "tahgibu/io.h"
|
||||
#include "tahgibu/plugin.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/* Versiones de Tahgibu. Son TRES cosas distintas, no las confundas:
|
||||
* - versión de la aplicación (2.0.0)
|
||||
* - versión de la API pública en C (TGB_API_VERSION)
|
||||
* - versión del formato de archivo .tgb (TGB_FORMAT_VERSION_*) */
|
||||
#ifndef TAHGIBU_VERSION_H
|
||||
#define TAHGIBU_VERSION_H
|
||||
|
||||
#define TGB_VERSION_MAJOR 2
|
||||
#define TGB_VERSION_MINOR 0
|
||||
#define TGB_VERSION_PATCH 0
|
||||
#define TGB_VERSION_STRING "2.0.0"
|
||||
#define TGB_APP_NAME "Tahgibu"
|
||||
|
||||
/* API pública: sube cuando cambian los contratos. NO es estable todavía
|
||||
* (ver docs/API.md): no hay política de compatibilidad de ABI. */
|
||||
#define TGB_API_VERSION 1
|
||||
|
||||
/* Formato .tgb: 2 = formato histórico (un PNG por fotograma, sin capas),
|
||||
* 3 = formato de Tahgibu 2.0.0 (capas, duraciones, puntos). */
|
||||
#define TGB_FORMAT_VERSION_LEGACY 2
|
||||
#define TGB_FORMAT_VERSION_CURRENT 3
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user