main
Dominik Madarász 2023-10-21 11:18:13 +02:00
parent 25224c6db1
commit 2fddd84946
30 changed files with 5628 additions and 528 deletions

@ -1 +1 @@
Subproject commit e838bef9bea402b1fa3ecb66b74addcb4256b687 Subproject commit f7cf64ed703b21981c5c5e600bd55c43e0b9e66e

View File

@ -1143,6 +1143,15 @@ ffi.cdef([[
//lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 font_highlight(const char *text, const void *colors); //lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 font_highlight(const char *text, const void *colors);
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 font_highlight(const char *text, const void *colors); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 font_highlight(const char *text, const void *colors);
//lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 font_highlight(const char *text, const void *colors); //lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 font_highlight(const char *text, const void *colors);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API char* ftoa2(vec2 v);
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC char* ftoa2(vec2 v);
//lcpp INF [0000] vec2: macro name but used as C declaration in: char* ftoa2(vec2 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:API char* ftoa3(vec3 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC char* ftoa3(vec3 v);
//lcpp INF [0000] vec3: macro name but used as C declaration in: char* ftoa3(vec3 v);
//lcpp INF [0000] vec4: macro name but used as C declaration in:API char* ftoa4(vec4 v);
//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC char* ftoa4(vec4 v);
//lcpp INF [0000] vec4: macro name but used as C declaration in: char* ftoa4(vec4 v);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 atof2(const char *s); //lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 atof2(const char *s);
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 atof2(const char *s); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 atof2(const char *s);
//lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 atof2(const char *s); //lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 atof2(const char *s);
@ -1152,15 +1161,18 @@ ffi.cdef([[
//lcpp INF [0000] vec4: macro name but used as C declaration in:API vec4 atof4(const char *s); //lcpp INF [0000] vec4: macro name but used as C declaration in:API vec4 atof4(const char *s);
//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC vec4 atof4(const char *s); //lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC vec4 atof4(const char *s);
//lcpp INF [0000] vec4: macro name but used as C declaration in: vec4 atof4(const char *s); //lcpp INF [0000] vec4: macro name but used as C declaration in: vec4 atof4(const char *s);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API char* ftoa2(vec2 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in:API char* itoa2(vec2i v);
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC char* ftoa2(vec2 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in:STATIC char* itoa2(vec2i v);
//lcpp INF [0000] vec2: macro name but used as C declaration in: char* ftoa2(vec2 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in: char* itoa2(vec2i v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:API char* ftoa3(vec3 v); //lcpp INF [0000] vec3i: macro name but used as C declaration in:API char* itoa3(vec3i v);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC char* ftoa3(vec3 v); //lcpp INF [0000] vec3i: macro name but used as C declaration in:STATIC char* itoa3(vec3i v);
//lcpp INF [0000] vec3: macro name but used as C declaration in: char* ftoa3(vec3 v); //lcpp INF [0000] vec3i: macro name but used as C declaration in: char* itoa3(vec3i v);
//lcpp INF [0000] vec4: macro name but used as C declaration in:API char* ftoa4(vec4 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in:API vec2i atoi2(const char *s);
//lcpp INF [0000] vec4: macro name but used as C declaration in:STATIC char* ftoa4(vec4 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in:STATIC vec2i atoi2(const char *s);
//lcpp INF [0000] vec4: macro name but used as C declaration in: char* ftoa4(vec4 v); //lcpp INF [0000] vec2i: macro name but used as C declaration in: vec2i atoi2(const char *s);
//lcpp INF [0000] vec3i: macro name but used as C declaration in:API vec3i atoi3(const char *s);
//lcpp INF [0000] vec3i: macro name but used as C declaration in:STATIC vec3i atoi3(const char *s);
//lcpp INF [0000] vec3i: macro name but used as C declaration in: vec3i atoi3(const char *s);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API void swapf2(vec2 *a, vec2 *b); //lcpp INF [0000] vec2: macro name but used as C declaration in:API void swapf2(vec2 *a, vec2 *b);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API void swapf2(vec2 *a, vec2 *b); //lcpp INF [0000] vec2: macro name but used as C declaration in:API void swapf2(vec2 *a, vec2 *b);
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC void swapf2(vec2 *a, vec2 *b); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC void swapf2(vec2 *a, vec2 *b);
@ -1641,9 +1653,10 @@ EASE_IN,
EASE_INOUT = EASE_IN * 2, EASE_INOUT = EASE_IN * 2,
EASE_OUT = 0, EASE_OUT = 0,
}; };
float ease(float t01, unsigned mode); float ease(float t01, unsigned fn);
float ease_ping_pong(float t, float(*fn1)(float), float(*fn2)(float)); float ease_pong(float t01, unsigned fn);
float ease_pong_ping(float t, float(*fn1)(float), float(*fn2)(float)); float ease_ping_pong(float t, unsigned fn1, unsigned fn2);
float ease_pong_ping(float t, unsigned fn1, unsigned fn2);
float deg (float radians); float deg (float radians);
float rad (float degrees); float rad (float degrees);
int mini (int a, int b); int mini (int a, int b);
@ -2190,6 +2203,23 @@ uintptr_t id_make(void *ptr);
void * id_handle(uintptr_t id); void * id_handle(uintptr_t id);
void id_dispose(uintptr_t id); void id_dispose(uintptr_t id);
bool id_valid(uintptr_t id); bool id_valid(uintptr_t id);
int semver( int major, int minor, int patch );
int semvercmp( int v1, int v2 );
typedef struct byte2 { uint8_t x,y; } byte2;
typedef struct byte3 { uint8_t x,y,z; } byte3;
typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2;
typedef struct int3 { int x,y,z; } int3;
typedef struct int4 { int x,y,z,w; } int4;
typedef struct uint2 { unsigned int x,y; } uint2;
typedef struct uint3 { unsigned int x,y,z; } uint3;
typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2;
typedef struct float3 { float x,y,z; } float3;
typedef struct float4 { float x,y,z,w; } float4;
typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
char *cc4str(unsigned cc); char *cc4str(unsigned cc);
char *cc8str(uint64_t cc); char *cc8str(uint64_t cc);
enum { enum {
@ -2197,13 +2227,20 @@ cc__1 = '1', cc__2, cc__3, cc__4, cc__5, cc__6,cc__7, cc__8, cc__9, cc__0, cc___
cc__A = 'A', cc__B, cc__C, cc__D, cc__E, cc__F,cc__G, cc__H, cc__I, cc__J, cc__K,cc__L, cc__M, cc__N, cc__O, cc__P,cc__Q, cc__R, cc__S, cc__T, cc__U,cc__V, cc__W, cc__X, cc__Y, cc__Z, cc__A = 'A', cc__B, cc__C, cc__D, cc__E, cc__F,cc__G, cc__H, cc__I, cc__J, cc__K,cc__L, cc__M, cc__N, cc__O, cc__P,cc__Q, cc__R, cc__S, cc__T, cc__U,cc__V, cc__W, cc__X, cc__Y, cc__Z,
cc__a = 'a', cc__b, cc__c, cc__d, cc__e, cc__f,cc__g, cc__h, cc__i, cc__j, cc__k,cc__l, cc__m, cc__n, cc__o, cc__p,cc__q, cc__r, cc__s, cc__t, cc__u,cc__v, cc__w, cc__x, cc__y, cc__z, cc__a = 'a', cc__b, cc__c, cc__d, cc__e, cc__f,cc__g, cc__h, cc__i, cc__j, cc__k,cc__l, cc__m, cc__n, cc__o, cc__p,cc__q, cc__r, cc__s, cc__t, cc__u,cc__v, cc__w, cc__x, cc__y, cc__z,
}; };
char* ftoa1(float v);
char* ftoa2(vec2 v);
char* ftoa3(vec3 v);
char* ftoa4(vec4 v);
float atof1(const char *s);
vec2 atof2(const char *s); vec2 atof2(const char *s);
vec3 atof3(const char *s); vec3 atof3(const char *s);
vec4 atof4(const char *s); vec4 atof4(const char *s);
char* ftoa(float f); char* itoa1(int v);
char* ftoa2(vec2 v); char* itoa2(vec2i v);
char* ftoa3(vec3 v); char* itoa3(vec3i v);
char* ftoa4(vec4 v); int atoi1(const char *s);
vec2i atoi2(const char *s);
vec3i atoi3(const char *s);
int is_big(); int is_big();
int is_little(); int is_little();
uint16_t swap16( uint16_t x ); uint16_t swap16( uint16_t x );
@ -2416,23 +2453,95 @@ enum { NETWORK_USERID = 7, NETWORK_COUNT , NETWORK_CAPACITY };
void server_send_bin(int64_t handle, const void *ptr, int len); void server_send_bin(int64_t handle, const void *ptr, int len);
void server_drop(int64_t handle); void server_drop(int64_t handle);
int64_t client_join(const char *ip, int port); int64_t client_join(const char *ip, int port);
int semver( int major, int minor, int patch ); typedef struct obj { struct { union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objheap:1; uintptr_t objsizew:7; uintptr_t objrefs:8; uintptr_t objcomps:1; uintptr_t objnameid:16; uintptr_t objid:16+3; uintptr_t objunused:64-8-7-1-1-8-16-16-3; }; }; }; } obj;
int semvercmp( int v1, int v2 ); typedef struct entity { struct { union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objheap:1; uintptr_t objsizew:7; uintptr_t objrefs:8; uintptr_t objcomps:1; uintptr_t objnameid:16; uintptr_t objid:16+3; uintptr_t objunused:64-8-7-1-1-8-16-16-3; }; }; union { struct { uintptr_t objenabled:32, objflagged:32; }; uintptr_t cflags; }; void *c[32]; }; } entity;
typedef struct byte2 { uint8_t x,y; } byte2; obj *objtmp;
typedef struct byte3 { uint8_t x,y,z; } byte3; void* obj_malloc(unsigned sz);
typedef struct byte4 { uint8_t x,y,z,w; } byte4; void* obj_free(void *o);
typedef struct int2 { int x,y; } int2; extern void (*obj_ctor[256])();
typedef struct int3 { int x,y,z; } int3; extern void (*obj_dtor[256])();
typedef struct int4 { int x,y,z,w; } int4; extern char* (*obj_save[256])();
typedef struct uint2 { unsigned int x,y; } uint2; extern bool (*obj_load[256])();
typedef struct uint3 { unsigned int x,y,z; } uint3; extern int (*obj_test[256])();
typedef struct uint4 { unsigned int x,y,z,w; } uint4; extern int (*obj_init[256])();
typedef struct float2 { float x,y; } float2; extern int (*obj_quit[256])();
typedef struct float3 { float x,y,z; } float3; extern int (*obj_tick[256])();
typedef struct float4 { float x,y,z,w; } float4; extern int (*obj_draw[256])();
typedef struct double2 { double x,y; } double2; extern int (*obj_lerp[256])();
typedef struct double3 { double x,y,z; } double3; extern int (*obj_edit[256])();
typedef struct double4 { double x,y,z,w; } double4; uintptr_t obj_header(const void *o);
uintptr_t obj_id(const void *o);
const char* obj_name(const void *o);
unsigned obj_typeid(const void *o);
const char* obj_type(const void *o);
int obj_sizeof(const void *o);
int obj_size(const void *o);
char* obj_data(void *o);
const char* obj_datac(const void *o);
void* obj_payload(const void *o);
void* obj_zero(void *o);
void* obj_ref(void *oo);
void* obj_unref(void *oo);
obj* obj_detach(void *c);
obj* obj_attach(void *o, void *c);
obj* obj_root(const void *o);
obj* obj_parent(const void *o);
obj***obj_children(const void *o);
obj***obj_siblings(const void *o);
int obj_dumptree(const void *o);
const char* obj_metaset(const void *o, const char *key, const char *value);
const char* obj_metaget(const void *o, const char *key);
void* obj_swap(void *dst, void *src);
void* obj_copy_fast(void *dst, const void *src);
void* obj_copy(void *dst, const void *src);
int obj_comp_fast(const void *a, const void *b);
int obj_comp(const void *a, const void *b);
int obj_lesser(const void *a, const void *b);
int obj_greater(const void *a, const void *b);
int obj_equal(const void *a, const void *b);
uint64_t obj_hash(const void *o);
bool obj_hexdump(const void *oo);
int obj_print(const void *o);
int obj_printf(const void *o, const char *text);
int obj_console(const void *o);
char* obj_saveini(const void *o);
obj* obj_mergeini(void *o, const char *ini);
obj* obj_loadini(void *o, const char *ini);
char* obj_savejson(const void *o);
obj* obj_mergejson(void *o, const char *json);
obj* obj_loadjson(void *o, const char *json);
char* obj_savebin(const void *o);
obj* obj_mergebin(void *o, const char *sav);
obj* obj_loadbin(void *o, const char *sav);
char* obj_savempack(const void *o);
obj* obj_mergempack(void *o, const char *sav);
obj* obj_loadmpack(void *o, const char *sav);
int obj_push(const void *o);
int obj_pop(void *o);
bool obj_addcomponent(void *object, unsigned c, void *ptr);
bool obj_hascomponent(void *object, unsigned c);
void* obj_getcomponent(void *object, unsigned c);
bool obj_delcomponent(void *object, unsigned c);
bool obj_usecomponent(void *object, unsigned c);
bool obj_offcomponent(void *object, unsigned c);
char* entity_save(entity *self);
void* obj_clone(const void *src);
void* obj_merge(void *dst, const void *src);
void* obj_mutate(void **dst, const void *src);
void* obj_make(const char *str);
typedef enum OBJTYPE_BUILTINS {
OBJTYPE_obj = 0,
OBJTYPE_entity = 1,
OBJTYPE_vec2 = 2,
OBJTYPE_vec3 = 3,
OBJTYPE_vec4 = 4,
OBJTYPE_quat = 5,
OBJTYPE_mat33 = 6,
OBJTYPE_mat34 = 7,
OBJTYPE_mat44 = 8,
OBJTYPE_vec2i = 9,
OBJTYPE_vec3i = 10,
} OBJTYPE_BUILTINS;
int profiler_enable(bool on); int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; }; struct profile_t { double stat; int32_t cost, avg; };
typedef struct { map base; struct { pair p; char * key; struct profile_t val; } tmp, *ptr; struct profile_t* tmpval; int (*typed_cmp)(char *, char *); uint64_t (*typed_hash)(char *); } * profiler_t; typedef struct { map base; struct { pair p; char * key; struct profile_t val; } tmp, *ptr; struct profile_t* tmpval; int (*typed_cmp)(char *, char *); uint64_t (*typed_hash)(char *); } * profiler_t;
@ -2456,7 +2565,7 @@ unsigned bytes;
void * function_find(const char *F); void * function_find(const char *F);
reflect_t member_find(const char *T, const char *M); reflect_t member_find(const char *T, const char *M);
void * member_findptr(void *obj, const char *T, const char *M); void * member_findptr(void *obj, const char *T, const char *M);
reflect_t* members_find(const char *T); reflect_t** members_find(const char *T);
void type_inscribe(const char *TY,unsigned TYsz,const char *infos); void type_inscribe(const char *TY,unsigned TYsz,const char *infos);
void enum_inscribe(const char *E,unsigned Eval,const char *infos); void enum_inscribe(const char *E,unsigned Eval,const char *infos);
void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos); void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos);
@ -2470,7 +2579,7 @@ typedef unsigned handle;
unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ); unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a );
unsigned rgbaf( float r, float g, float b, float a ); unsigned rgbaf( float r, float g, float b, float a );
unsigned bgraf( float b, float g, float r, float a ); unsigned bgraf( float b, float g, float r, float a );
float alpha( unsigned rgba ); unsigned alpha( unsigned rgba );
enum IMAGE_FLAGS { enum IMAGE_FLAGS {
IMAGE_R =4096, IMAGE_R =4096,
IMAGE_RG =8192, IMAGE_RG =8192,
@ -3031,14 +3140,14 @@ int u_coefficients_sh;
char* strjoin(char** list, const char *separator); char* strjoin(char** list, const char *separator);
char * string8(const wchar_t *str); char * string8(const wchar_t *str);
uint32_t* string32( const char *utf8 ); uint32_t* string32( const char *utf8 );
unsigned intern( const char *string ); unsigned intern( const char *string );
const char *quark( unsigned key ); const char *quark( unsigned key );
typedef struct quarks_db { typedef struct quarks_db {
char* blob; char* blob;
vec2i* entries; vec2i* entries;
} quarks_db; } quarks_db;
unsigned quark_intern( quarks_db*, const char *string ); unsigned quark_intern( quarks_db*, const char *string );
const char *quark_string( quarks_db*, unsigned key ); const char *quark_string( quarks_db*, unsigned key );
uint64_t date(); uint64_t date();
uint64_t date_epoch(); uint64_t date_epoch();
char* date_string(); char* date_string();
@ -3090,7 +3199,7 @@ typedef vec3i guid;
void alert(const char *message); void alert(const char *message);
void hexdump( const void *ptr, unsigned len ); void hexdump( const void *ptr, unsigned len );
void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width ); void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width );
void breakpoint(const char *optional_reason); void breakpoint();
bool has_debugger(); bool has_debugger();
void trap_install(void); void trap_install(void);
const char *trap_name(int signal); const char *trap_name(int signal);

2
depot

@ -1 +1 @@
Subproject commit 80c739fc0ce8381e2200f347654b23b646f12fba Subproject commit ea89db8ecd2b32fca2a21f67f486601de5c6a93c

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,490 @@
/* A mathematical expression evaluator.
* It uses a recursive descent parser internally.
* Author: Werner Stoop
* This is free and unencumbered software released into the public domain.
* http://unlicense.org/
*/
#include <assert.h>
#include <ctype.h>
#include <math.h> /* remember to compile with -lm */
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
/* Special tokens used by the lexer function lex()
* they've been chosen as non-printable characters
* so that printable characters can be used for other
* purposes
*/
#define TOK_END 0 /* end of text */
#define TOK_INI 1 /* Initial state */
#define TOK_ID 2 /* identifier */
#define TOK_NUM 3 /* number */
/* Types of errors */
// 0 /* "no error" */
#define ERR_MEMORY 1 /* "out of memory" */
#define ERR_LEXER 2 /* "unknown token" */
#define ERR_LONGID 3 /* "identifier too long" */
#define ERR_VALUE 4 /* "value expected" */
#define ERR_BRACKET 5 /* "missing ')'" */
#define ERR_FUNC 6 /* "unknown function" */
#define ERR_ARGS 7 /* "wrong number of arguments" */
#define ERR_CONST 8 /* "unknown constant" */
/* Other definitions */
#define MAX_ID_LEN 11 /* Max length of an identifier */
#define OPERATORS "+-*/%(),^" /* Valid operators */
#define EVAL_PI 3.141592654
#define EVAL_E 2.718281828
#define EVAL_DEG (EVAL_PI/180)
/* Internal structure for the parser/evaluator */
struct eval {
jmp_buf j; /* For error handling */
const char *p; /* Position in the text being parsed */
double *st; /* Stack */
int st_size; /* Stack size */
int sp; /* Stack pointer */
/* The current and next tokens identified by the lexer */
struct {
int type; /* Type of the token */
double n_val; /* Numeric value of the previous lexed token */
char s_val[MAX_ID_LEN]; /* String (identifier) value of the previous lexed token */
} token[2];
int cur_tok; /* Current token, either 0 or 1 (see the comments of lex()) */
};
/* Prototypes */
static double pop(struct eval *ev);
static void push(struct eval *ev, double d);
static int lex(struct eval *ev);
/* Prototypes for the recursive descent parser */
static void expr(struct eval *ev);
static void add_expr(struct eval *ev);
static void mul_expr(struct eval *ev);
static void pow_expr(struct eval *ev);
static void uni_expr(struct eval *ev);
static void bra_expr(struct eval *ev);
static void id_expr(struct eval *ev);
static void num_expr(struct eval *ev);
/*
* Evaluates a mathemeatical expression
*/
double eval(const char *exp/*, int *ep*/) {
int _ep, *ep = &_ep;
struct eval ev;
double ans = 0.0;
assert(ep != NULL);
/* Allocate a stack */
ev.st_size = 10;
ev.st = CALLOC(ev.st_size, sizeof *ev.st);
if(!ev.st)
{
*ep = ERR_MEMORY;
return NAN; //0.0;
}
ev.sp = 0;
/* Manage errors */
*ep = setjmp(ev.j);
if(*ep != 0)
{
FREE(ev.st);
return NAN; //0.0;
}
/* Initialize the lexer */
ev.token[0].type = TOK_INI;
ev.token[0].s_val[0] = '\0';
ev.token[1].type = TOK_INI;
ev.token[1].s_val[0] = '\0';
ev.cur_tok = 0;
/* Initialize the parser */
ev.p = exp;
/* lex once to initialize the lexer */
if(lex(&ev) != TOK_END)
{
expr(&ev);
ans = pop(&ev);
}
FREE(ev.st);
return ans;
}
/*
* Pushes a value onto the stack, increases the stack size if necessary
*/
static void push(struct eval *ev, double d) {
if(ev->sp == ev->st_size) {
/* Resize the stack by 1.5 */
double *old = ev->st;
int new_size = ev->st_size + (ev->st_size >> 1);
ev->st = REALLOC(ev->st, new_size);
if(!ev->st) {
ev->st = old;
longjmp(ev->j, ERR_MEMORY);
}
ev->st_size = new_size;
}
ev->st[ev->sp++] = d;
}
// Pops a value from the top of the stack
static double pop(struct eval *ev) {
assert(ev->sp > 0);
return ev->st[--ev->sp];
}
// stricmp() is common, but not standard, so I provide my own
static int istrcmp(const char *p, const char *q) {
for(; tolower(p[0]) == tolower(q[0]) && p[0]; p++, q++);
return tolower(p[0]) - tolower(q[0]);
}
/*
* Lexical analyzer function
*
* In order to implement LL(1), struct eval has an array of two token structures,
* and its cur_tok member is used to point to the _current_ token, while the other
* element contains the _next_ token. This implements a 2 element ring buffer where
* the lexer always writes to the _next_ token so that the recursive descent parser can
* _peek_ at the next token.
*/
static int lex(struct eval *ev) {
int next_tok;
start:
/* Cycle the tokens */
next_tok = ev->cur_tok;
ev->cur_tok = ev->cur_tok?0:1;
while(isspace(ev->p[0])) ev->p++;
if(!ev->p[0]) {
/* End of the expression */
ev->token[next_tok].type = TOK_END;
goto end;
}
else if(isdigit(ev->p[0]) || ev->p[0] == '.') {
/* Number */
char *endp;
ev->token[next_tok].type = TOK_NUM;
ev->token[next_tok].n_val = strtod(ev->p, &endp);
ev->p = endp;
goto end;
}
else if(isalpha(ev->p[0])) {
/* Identifier */
int i;
for(i = 0; isalnum(ev->p[0]) && i < MAX_ID_LEN - 1; i++, ev->p++)
ev->token[next_tok].s_val[i] = ev->p[0];
if(isalpha(ev->p[0])) longjmp(ev->j, ERR_LONGID);
ev->token[next_tok].s_val[i] = '\0';
ev->token[next_tok].type = TOK_ID;
goto end;
}
else if(strchr(OPERATORS, ev->p[0])) {
/* Operator */
ev->token[next_tok].type = ev->p[0];
ev->p++;
goto end;
}
else /* Unknown token */
longjmp(ev->j, ERR_LEXER);
end:
/* If this was the first call, cycle the tokens again */
if(ev->token[ev->cur_tok].type == TOK_INI)
goto start;
return ev->token[ev->cur_tok].type;
}
#define EVAL_TYPE(e) (e->token[e->cur_tok].type)
#define EVAL_ERROR(c) longjmp(ev->j, (c))
// num_expr ::= NUMBER
static void num_expr(struct eval *ev) {
if(EVAL_TYPE(ev) != TOK_NUM)
EVAL_ERROR(ERR_VALUE);
push(ev, ev->token[ev->cur_tok].n_val);
lex(ev);
}
// expr ::= add_expr
static void expr(struct eval *ev) {
add_expr(ev);
}
// add_expr ::= mul_expr [('+'|'-') mul_expr]
static void add_expr(struct eval *ev) {
int t;
mul_expr(ev);
while((t =EVAL_TYPE(ev)) == '+' || t == '-') {
double a,b;
lex(ev);
mul_expr(ev);
b = pop(ev);
a = pop(ev);
if(t == '+')
push(ev, a + b);
else
push(ev, a - b);
}
}
// mul_expr ::= pow_expr [('*'|'/'|'%') pow_expr]
static void mul_expr(struct eval *ev) {
int t;
pow_expr(ev);
while((t = EVAL_TYPE(ev)) == '*' || t == '/' || t == '%') {
double a,b;
lex(ev);
pow_expr(ev);
b = pop(ev);
a = pop(ev);
if(t == '*')
push(ev, a * b);
else if(t == '/')
push(ev, a / b);
else
push(ev, fmod(a, b));
}
}
// pow_expr ::= uni_expr ['^' pow_expr]
static void pow_expr(struct eval *ev) {
/* Note that exponentiation is right associative:
2^3^4 is 2^(3^4), not (2^3)^4 */
uni_expr(ev);
if(EVAL_TYPE(ev) == '^') {
double a,b;
lex(ev);
pow_expr(ev);
b = pop(ev);
a = pop(ev);
push(ev, pow(a,b));
}
}
// uni_expr ::= ['+'|'-'] bra_expr
static void uni_expr(struct eval *ev) {
int t = '+';
if(EVAL_TYPE(ev) == '-' || EVAL_TYPE(ev) == '+') {
t = EVAL_TYPE(ev);
lex(ev);
}
bra_expr(ev);
if(t == '-') {
double a = pop(ev);
push(ev, -a);
}
}
// bra_expr ::= '(' add_expr ')' | id_expr
static void bra_expr(struct eval *ev) {
if(EVAL_TYPE(ev) == '(') {
lex(ev);
add_expr(ev);
if(EVAL_TYPE(ev) != ')')
EVAL_ERROR(ERR_BRACKET);
lex(ev);
}
else
id_expr(ev);
}
// id_expr ::= ID '(' add_expr [',' add_expr]* ')' | ID | num_expr
static void id_expr(struct eval *ev) {
int nargs = 0;
char id[MAX_ID_LEN];
if(EVAL_TYPE(ev) != TOK_ID) {
num_expr(ev);
} else {
strcpy(id, ev->token[ev->cur_tok].s_val);
lex(ev);
if(EVAL_TYPE(ev) != '(') {
/**/ if(!istrcmp(id, "true")) push(ev, 1.0);
else if(!istrcmp(id, "false")) push(ev, 0.0);
else if(!istrcmp(id, "on")) push(ev, 1.0);
else if(!istrcmp(id, "off")) push(ev, 0.0);
// pi - 3.141592654
else if(!istrcmp(id, "pi"))
push(ev, EVAL_PI);
// e - base of natural logarithms, 2.718281828
else if(!istrcmp(id, "e"))
push(ev, EVAL_E);
// deg - deg2rad, allows to degree conversion `sin(90*deg) = 1`
else if(!istrcmp(id, "deg"))
push(ev, EVAL_DEG);
else
EVAL_ERROR(ERR_CONST);
} else {
lex(ev);
while(EVAL_TYPE(ev) != ')') {
add_expr(ev);
nargs++;
if(EVAL_TYPE(ev) == ')') break;
if(EVAL_TYPE(ev) != ',')
EVAL_ERROR(ERR_BRACKET);
lex(ev);
}
lex(ev);
// abs(x) - absolute value of x
if(!istrcmp(id, "abs")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, fabs(pop(ev)));
}
// ceil(x) - smallest integer greater than x
else if(!istrcmp(id, "ceil")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, ceil(pop(ev)));
}
// floor(x) - largest integer smaller than x
else if(!istrcmp(id, "floor")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, floor(pop(ev)));
}
// sin(x) - sine of x, in radians
else if(!istrcmp(id, "sin")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sin(pop(ev)));
}
// asin(x) - arcsine of x, in radians
else if(!istrcmp(id, "asin")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, asin(pop(ev)));
}
// cos(x) - cosine of x, in radians
else if(!istrcmp(id, "cos")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, cos(pop(ev)));
}
// acos(x) - arccosine of x, in radians
else if(!istrcmp(id, "acos")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, acos(pop(ev)));
}
// tan(x) - tangent of x, in radians
else if(!istrcmp(id, "tan")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, tan(pop(ev)));
}
// atan(x) - arctangent of x, in radians
else if(!istrcmp(id, "atan")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, atan(pop(ev)));
}
// atan(y,x) - arctangent of y/x, in radians.
else if(!istrcmp(id, "atan2")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, atan2(a,b));
}
// sinh(x) - hyperbolic sine of x, in radians
else if(!istrcmp(id, "sinh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sinh(pop(ev)));
}
// cosh(x) - hyperbolic cosine of x, in radians
else if(!istrcmp(id, "cosh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, cosh(pop(ev)));
}
// tanh(x) - hyperbolic tangent of x, in radians
else if(!istrcmp(id, "tanh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, tanh(pop(ev)));
}
// log(x) - natural logarithm of x
else if(!istrcmp(id, "log")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, log(pop(ev)));
}
// log10(x) - logarithm of x, base-10
else if(!istrcmp(id, "log10")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, log10(pop(ev)));
}
// exp(x) - computes e^x
else if(!istrcmp(id, "exp")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, exp(pop(ev)));
}
// sqrt(x) - square root of x
else if(!istrcmp(id, "sqrt")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sqrt(pop(ev)));
}
// rad(x) - converts x from degrees to radians
else if(!istrcmp(id, "rad")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, pop(ev)*EVAL_PI/180);
}
// deg(x) - converts x from radians to degrees
else if(!istrcmp(id, "deg")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, pop(ev)*180/EVAL_PI);
}
// pow(x,y) - computes x^y
else if(!istrcmp(id, "pow")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, pow(a,b));
}
// hypot(x,y) - computes sqrt(x*x + y*y)
else if(!istrcmp(id, "hypot")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, sqrt(a*a + b*b));
}
else
EVAL_ERROR(ERR_FUNC);
}
}
}
//
#ifdef EVALDEMO
#include <stdio.h>
int main() {
assert( eval("1+1") == 2 ); // common path
assert( eval("1+") != eval("1+") ); // check that errors return NAN
assert(~puts("Ok") );
}
#endif

View File

@ -8020,7 +8020,7 @@ nk_utf_decode(const char *c, nk_rune *u, int clen)
*u = NK_UTF_INVALID; *u = NK_UTF_INVALID;
udecoded = nk_utf_decode_byte(c[0], &len); udecoded = nk_utf_decode_byte(c[0], &len);
if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) if (!NK_BETWEEN(len, 1, NK_UTF_SIZE+1)) //< @r-lyeh: add +1 for len<=4
return 1; return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
@ -20155,7 +20155,12 @@ window->is_window_resizing |= layout->flags & NK_WINDOW_SCALE_TOP ? NK_WINDOW_SC
} }
} }
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; int icon = //< @r-lyeh
((layout->flags & NK_WINDOW_SCALE_TOP) && !(layout->flags & NK_WINDOW_SCALE_LEFT))
||
((layout->flags & NK_WINDOW_SCALE_LEFT) && !(layout->flags & NK_WINDOW_SCALE_TOP))
? NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT : NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT;
ctx->style.cursor_active = ctx->style.cursors[icon]; //< @r-lyeh
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;
} }

View File

@ -169,6 +169,8 @@ errno_t fopen_s(
{{FILE:3rd_xml.h}} {{FILE:3rd_xml.h}}
#undef g #undef g
{{FILE:3rd_polychop.h}} {{FILE:3rd_polychop.h}}
#define expr expr2 // 3rd_lua.h
{{FILE:3rd_eval.h}}
// #define SQLITE_OMIT_LOAD_EXTENSION // #define SQLITE_OMIT_LOAD_EXTENSION
// #define SQLITE_CORE 1 // #define SQLITE_CORE 1
// #define SQLITE_DEBUG 1 // #define SQLITE_DEBUG 1

View File

@ -169,7 +169,7 @@
#define conc4t(a,b) a##b ///- #define conc4t(a,b) a##b ///-
#define macro(name) concat(name, __LINE__) #define macro(name) concat(name, __LINE__)
#define unique(name) concat(concat(name, L##__LINE__), __COUNTER__) #define unique(name) concat(concat(concat(name,concat(_L,__LINE__)),_),__COUNTER__)
#define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1)) #define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1))
#define scope(end) defer((void)0, end) #define scope(end) defer((void)0, end)
#define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 )) #define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 ))
@ -194,8 +194,8 @@
#define ASSERT(expr, ...) (void)0 #define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0 #define ASSERT_ONCE(expr, ...) (void)0
#else #else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#endif #endif
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L)
@ -274,6 +274,7 @@
// note: based on code by Joe Lowe (public domain). // note: based on code by Joe Lowe (public domain).
// note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers // note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers
#define AUTORUN AUTORUN_( unique(fn) )
#ifdef __cplusplus #ifdef __cplusplus
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
static void fn(void); \ static void fn(void); \
@ -297,8 +298,6 @@
static void fn(void) static void fn(void)
#endif #endif
#define AUTORUN AUTORUN_( concat(concat(concat(fn_L,__LINE__),_),__COUNTER__) )
#if 0 // autorun demo #if 0 // autorun demo
void byebye(void) { puts("seen after main()"); } void byebye(void) { puts("seen after main()"); }
AUTORUN { puts("seen before main()"); } AUTORUN { puts("seen before main()"); }
@ -315,7 +314,7 @@ AUTORUN { puts("seen before main() too"); atexit( byebye ); }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// visibility // visibility
// win32 users would need to -DAPI=IMPORT/EXPORT as needed when using/building V4K as DLL. // win32 users would need to -DAPI=EXPORT/IMPORT as needed when building/using V4K as DLL.
#define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport))) #define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport)))
#define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport))) #define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport)))

View File

@ -74,7 +74,7 @@ static __thread unsigned array_n_;
#define array_vlen_(t) ( vlen(t) - 0 ) #define array_vlen_(t) ( vlen(t) - 0 )
#define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) ) #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) )
#define array_free(t) array_clear(t) #define array_free(t) array_clear(t)
#else // new: with reserve support (bugs?) #else // new: with reserve support (@todo: check for bugs?)
#define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) ) #define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) )
#define array_clear(t) ( array_realloc_((t),0) ) // -1 #define array_clear(t) ( array_realloc_((t),0) ) // -1
#define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1 #define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1
@ -121,7 +121,7 @@ static __thread unsigned array_n_;
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_erase_fast(t, i) do { /*may alter ordering*/ \ #define array_erase_fast(t, i) do { /*alters ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)

View File

@ -1634,7 +1634,7 @@ void font_color(const char *tag, uint32_t color) {
if( f->initialized ) { if( f->initialized ) {
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_1D, f->texture_colors); glBindTexture(GL_TEXTURE_1D, f->texture_colors);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, FONT_MAX_COLORS, GL_BGRA, GL_UNSIGNED_BYTE, font_palette); glTexSubImage1D(GL_TEXTURE_1D, 0, 0, FONT_MAX_COLORS, GL_RGBA, GL_UNSIGNED_BYTE, font_palette);
} }
} }
} }
@ -1832,7 +1832,7 @@ void font_face_from_mem(const char *tag, const void *ttf_bufferv, unsigned ttf_l
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// last chance to inspect the font atlases // last chance to inspect the font atlases
if( flag("--debug-font-atlas") ) if( flag("--font-debug") )
stbi_write_png(va("debug_font_atlas%d.png", index), f->width, f->height, 1, bitmap, 0); stbi_write_png(va("debug_font_atlas%d.png", index), f->width, f->height, 1, bitmap, 0);
FREE(bitmap); FREE(bitmap);
@ -1880,7 +1880,7 @@ void font_face_from_mem(const char *tag, const void *ttf_bufferv, unsigned ttf_l
glGenTextures(1, &f->texture_colors); glGenTextures(1, &f->texture_colors);
glActiveTexture(GL_TEXTURE2); glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_1D, f->texture_colors); glBindTexture(GL_TEXTURE_1D, f->texture_colors);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, FONT_MAX_COLORS, 0, GL_BGRA, GL_UNSIGNED_BYTE, font_palette); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, FONT_MAX_COLORS, 0, GL_RGBA, GL_UNSIGNED_BYTE, font_palette);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);

View File

@ -60,9 +60,6 @@ void v4k_quit(void) {
void v4k_init() { void v4k_init() {
do_once { do_once {
// abort run if any test suite failed
if( test_errs ) exit(-1);
// install signal handlers // install signal handlers
ifdef(debug, trap_install()); ifdef(debug, trap_install());

View File

@ -112,9 +112,6 @@ float ease_inout_bounce(float t) { return t < 0.5f ? 0.5f*ease_in_bounce(t*2) :
float ease_inout_perlin(float t) { float t3=t*t*t,t4=t3*t,t5=t4*t; return 6*t5-15*t4+10*t3; } float ease_inout_perlin(float t) { float t3=t*t*t,t4=t3*t,t5=t4*t; return 6*t5-15*t4+10*t3; }
float ease_ping_pong(float t, float(*fn1)(float), float(*fn2)(float)) { return t < 0.5 ? fn1(t*2) : fn2(1-(t-0.5)*2); }
float ease_pong_ping(float t, float(*fn1)(float), float(*fn2)(float)) { return 1 - ease_ping_pong(t,fn1,fn2); }
float ease(float t01, unsigned mode) { float ease(float t01, unsigned mode) {
typedef float (*easing)(float); typedef float (*easing)(float);
easing modes[] = { easing modes[] = {
@ -159,6 +156,10 @@ float ease(float t01, unsigned mode) {
return modes[clampi(mode, 0, countof(modes))](clampf(t01,0,1)); return modes[clampi(mode, 0, countof(modes))](clampf(t01,0,1));
} }
float ease_pong(float t, unsigned fn) { return 1 - ease(t, fn); }
float ease_ping_pong(float t, unsigned fn1, unsigned fn2) { return t < 0.5 ? ease(t*2,fn1) : ease(1-(t-0.5)*2,fn2); }
float ease_pong_ping(float t, unsigned fn1, unsigned fn2) { return 1 - ease_ping_pong(t,fn1,fn2); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
float deg (float radians) { return radians / C_PI * 180.0f; } float deg (float radians) { return radians / C_PI * 180.0f; }
@ -953,3 +954,11 @@ void printq( quat q ) { print_(&q.x,4,1); }
void print33( float *m ) { print_(m,3,3); } void print33( float *m ) { print_(m,3,3); }
void print34( float *m ) { print_(m,3,4); } void print34( float *m ) { print_(m,3,4); }
void print44( float *m ) { print_(m,4,4); } void print44( float *m ) { print_(m,4,4); }
// -----------
AUTORUN {
STRUCT( vec3, float, x );
STRUCT( vec3, float, y );
STRUCT( vec3, float, z, "Up" );
}

View File

@ -5,9 +5,9 @@
// Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense). // Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense).
#define C_EPSILON (1e-6) #define C_EPSILON (1e-6)
#define C_PI (3.141592654f) // (3.14159265358979323846f) #define C_PI (3.14159265358979323846f) // (3.141592654f)
#define TO_RAD (C_PI/180.f) #define TO_RAD (C_PI/180)
#define TO_DEG (180.f/C_PI) #define TO_DEG (180/C_PI)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -39,7 +39,6 @@ API void randset(uint64_t state);
API uint64_t rand64(void); API uint64_t rand64(void);
API double randf(void); // [0, 1) interval API double randf(void); // [0, 1) interval
API int randi(int mini, int maxi); // [mini, maxi) interval API int randi(int mini, int maxi); // [mini, maxi) interval
//API double rng(void); // [0..1) Lehmer RNG "minimal standard"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -105,10 +104,10 @@ enum EASE_FLAGS {
EASE_OUT = 0, EASE_OUT = 0,
}; };
API float ease(float t01, unsigned mode); // 0=linear,1=out_sine...31=inout_perlin API float ease(float t01, unsigned fn); // / 0-to-1
API float ease_pong(float t01, unsigned fn); // \ 1-to-0
API float ease_ping_pong(float t, float(*fn1)(float), float(*fn2)(float)); API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0
API float ease_pong_ping(float t, float(*fn1)(float), float(*fn2)(float)); API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -1,44 +1,801 @@
// ----------------------------------------------------------------------------- // C objects framework
// semantic versioning in a single byte (octal)
// - rlyeh, public domain. // - rlyeh, public domain.
//
// - single octal byte that represents semantic versioning (major.minor.patch).
// - allowed range [0000..0377] ( <-> [0..255] decimal )
// - comparison checks only major.minor tuple as per convention.
int semver( int major, int minor, int patch ) { // --- implement new vtables
return SEMVER(major, minor, patch);
obj_vtable(ctor, void, {} );
obj_vtable(dtor, void, {} );
obj_vtable_null(save, char* );
obj_vtable_null(load, bool );
obj_vtable_null(test, int );
obj_vtable_null(init, int );
obj_vtable_null(quit, int );
obj_vtable_null(tick, int );
obj_vtable_null(draw, int );
obj_vtable_null(lerp, int );
obj_vtable_null(edit, int ); // OSC cmds: argc,argv "undo","redo","cut","copy","paste","edit","view","menu"
// ----------------------------------------------------------------------------
const char *OBJTYPES[256] = { 0 }; // = { REPEAT256("") };
// ----------------------------------------------------------------------------
// heap/stack ctor/dtor
void *obj_malloc(unsigned sz) {
//sz = sizeof(obj) + sz + sizeof(array(obj*))); // useful?
obj *ptr = CALLOC(1, sz);
OBJ_CTOR_HDR(ptr,1,intern("obj"),sz,OBJTYPE_obj);
return ptr;
} }
int semvercmp( int v1, int v2 ) { void *obj_free(void *o) {
return SEMVERCMP(v1, v2); if( !((obj*)o)->objrefs ) {
obj_dtor(o);
//obj_zero(o);
if( ((obj*)o)->objheap ) {
FREE(o);
}
return 0;
}
return o; // cannot destroy: object is still referenced
} }
#if 0 // ----------------------------------------------------------------------------
AUTORUN { // core
for( int i= 0; i <= 255; ++i) printf(SEMVERFMT ",", i);
puts("");
printf(SEMVERFMT "\n", semver(3,7,7)); uintptr_t obj_header(const void *o) {
printf(SEMVERFMT "\n", semver(2,7,7)); return ((obj*)o)->objheader;
printf(SEMVERFMT "\n", semver(1,7,7));
printf(SEMVERFMT "\n", semver(0,7,7));
printf(SEMVERFMT "\n", semver(3,7,1));
printf(SEMVERFMT "\n", semver(2,5,3));
printf(SEMVERFMT "\n", semver(1,3,5));
printf(SEMVERFMT "\n", semver(0,1,7));
assert( semvercmp( 0357, 0300 ) > 0 );
assert( semvercmp( 0277, 0300 ) < 0 );
assert( semvercmp( 0277, 0200 ) > 0 );
assert( semvercmp( 0277, 0100 ) < 0 );
assert( semvercmp( 0076, 0070 ) == 0 );
assert( semvercmp( 0076, 0077 ) == 0 );
assert( semvercmp( 0176, 0170 ) == 0 );
assert( semvercmp( 0176, 0177 ) == 0 );
assert( semvercmp( 0276, 0270 ) == 0 );
assert( semvercmp( 0276, 0277 ) == 0 );
assert( semvercmp( 0376, 0370 ) == 0 );
assert( semvercmp( 0376, 0377 ) == 0 );
} }
uintptr_t obj_id(const void *o) {
return ((obj*)o)->objid;
}
unsigned obj_typeid(const void *o) {
return ((obj*)o)->objtype;
}
const char *obj_type(const void *o) {
return OBJTYPES[ (((obj*)o)->objtype) ];
}
const char *obj_name(const void *o) {
return quark(((obj*)o)->objnameid);
}
int obj_sizeof(const void *o) {
return (int)( ((const obj*)o)->objsizew << OBJ_MIN_PRAGMAPACK_BITS );
}
int obj_size(const void *o) { // size of all members together in struct. may include padding bytes.
static int obj_sizes[256] = {0};
unsigned objtypeid = ((obj*)o)->objtype;
if( objtypeid > 1 && !obj_sizes[objtypeid] ) { // check reflection for a more accurate objsize (without padding bits)
reflect_init();
array(reflect_t) *found = map_find(members, intern(obj_type(o)));
if(!found)
obj_sizes[objtypeid] = obj_sizeof(o) - sizeof(obj); // @fixme: -= sizeof(entity);
else
for each_array_ptr(*found, reflect_t, it)
obj_sizes[objtypeid] += it->bytes;
}
return obj_sizes[objtypeid];
}
char *obj_data(void *o) { // pointer to the first member in struct
return (char*)o + sizeof(obj);
}
const char *obj_datac(const void *o) { // const pointer to the first struct member
return (const char*)o + sizeof(obj);
}
void* obj_payload(const void *o) { // pointer right after last member in struct
return (char*)o + (((obj*)o)->objsizew<<OBJ_MIN_PRAGMAPACK_BITS);
}
void *obj_zero(void *o) { // reset all object members
return memset(obj_data(o), 0, obj_size(o)), o;
}
static
void test_obj_core() {
obj *r = obj_new_ext(obj, "root");
obj *s = obj_new_ext(obj, "root");
test(r);
test( 0 == strcmp(obj_type(r), "obj") );
test( 0 == strcmp(obj_name(r), "root") );
test( OBJTYPE_obj == obj_typeid(r) );
test(s);
test( 0 == strcmp(obj_type(s), "obj") );
test( 0 == strcmp(obj_name(s), "root") );
test( OBJTYPE_obj == obj_typeid(s) );
test( obj_id(r) != 0 );
test( obj_id(s) != 0 );
test( obj_id(r) != obj_id(s) );
obj t = obj_ext(obj, "root");
obj u = obj_ext(obj, "root");
test(&t);
test( 0 == strcmp(obj_type(&t), "obj") );
test( 0 == strcmp(obj_name(&t), "root") );
test( OBJTYPE_obj == obj_typeid(&t) );
test(&u);
test( 0 == strcmp(obj_type(&u), "obj") );
test( 0 == strcmp(obj_name(&u), "root") );
test( OBJTYPE_obj == obj_typeid(&u) );
test( obj_id(&t) == 0 );
test( obj_id(&u) == 0 );
test( obj_id(&t) == obj_id(&u) );
}
// ----------------------------------------------------------------------------
// refcounting
// static int __thread global_ref_count; // @fixme: make it atomic
// static void objref_check_atexit(void) {
// if(global_ref_count) tty_color(YELLOW), fprintf(stderr, "Warn! obj_refs not zero (%d)\n", global_ref_count), tty_color(0);
// }
// AUTORUN { (atexit)(objref_check_atexit); }
void *obj_ref(void *oo) {
obj* o = (obj*)oo;
int num = o->objrefs;
++o->objrefs;
assert( num < o->objrefs && "Object referenced too many times");
//++global_ref_count;
return o;
}
void *obj_unref(void *oo) {
obj* o = (obj*)oo;
if( o->objrefs ) --o->objrefs;
if( o->objrefs ) return o;
obj_free(o);
//--global_ref_count;
return 0;
}
// ----------------------------------------------------------------------------
// scene tree
array(obj*)* obj_children(const void *o) {
array(obj*) *c = obj_payload(o);
if(!(*c)) array_push((*c), NULL); // default parenting: none. @todo: optimize & move this at construction time
return c;
}
obj* obj_parent(const void *o) {
array(obj*) *c = obj_children(o);
return (*c) ? 0[*c] : NULL;
}
obj* obj_root(const void *o) {
while( obj_parent(o) ) o = obj_parent(o);
return (obj*)o;
}
array(obj*)* obj_siblings(const void *o) {
return obj_children(obj_parent(o));
}
static
obj* obj_reparent(obj *o, const void *p) {
array(obj*) *c = obj_children(o);
0[*c] = (void*)p;
return o;
}
obj* obj_detach(void *c) {
obj *p = obj_parent(c);
if( p ) {
uintptr_t id = obj_id(c);
array(obj*) *oo = obj_children(p);
for( int i = 1, end = array_count(*oo); i < end; ++i) {
obj *v = (*oo)[i];
{
if( obj_id(v) == id ) {
obj_reparent(c, 0);
return c;
}
}
}
}
return 0;
}
obj* obj_attach(void *o, void *c) {
// reattach
obj_detach(c);
obj_reparent(c, o);
// insert into children
array(obj*) *p = obj_children(o);
array_push(*p, c);
return o;
}
int obj_dumptree(const void *o) {
static int tabs = 0;
printf("%*s" "+- %s\n", tabs++, "", obj_name(o));
for each_objchild(o, obj, v) {
obj_dumptree(v);
}
--tabs;
return 0;
}
static
void test_obj_scene() {
obj *r = obj_new_ext(obj, "root"); // root
obj *c1 = obj_new_ext(obj, "child1"); // child1
obj *c2 = obj_new_ext(obj, "child2"); // child2
obj *gc1 = obj_new_ext(obj, "grandchild1"); // grandchild1
obj *gc2 = obj_new_ext(obj, "grandchild2"); // grandchild2
obj *gc3 = obj_new_ext(obj, "grandchild3"); // grandchild3
test( !obj_parent(r) );
test( !obj_parent(c1) );
test( !obj_parent(c2) );
test( !obj_parent(gc1) );
test( !obj_parent(gc2) );
test( !obj_parent(gc3) );
test( obj_root(r) == r );
test( obj_root(c1) == c1 );
test( obj_root(c2) == c2 );
test( obj_root(gc1) == gc1 );
test( obj_root(gc2) == gc2 );
test( obj_root(gc3) == gc3 );
// r
obj_attach(r, c1); // +- c1
obj_attach(c1, gc1); // +- gc1
obj_attach(r, c2); // +- c2
obj_attach(c2, gc2); // +- gc2
obj_attach(c2, gc3); // +- gc3
// obj_dumptree(r);
// puts("---");
test( obj_parent(r) == 0 );
test( obj_parent(c1) == r );
test( obj_parent(c2) == r );
test( obj_parent(gc1) == c1 );
test( obj_parent(gc2) == c2 );
test( obj_parent(gc3) == c2 );
test( obj_root(r) == r );
test( obj_root(c1) == r );
test( obj_root(c2) == r );
test( obj_root(gc1) == r );
test( obj_root(gc2) == r );
test( obj_root(gc3) == r );
for each_objchild(r, obj, o) test( o == c1 || o == c2 );
for each_objchild(c1, obj, o) test( o == gc1 );
for each_objchild(c2, obj, o) test( o == gc2 || o == gc3 );
obj_detach(c1);
test( !obj_parent(c1) );
for each_objchild(r, obj, o) test( o != c1 );
for each_objchild(c1, obj, o) test( o == gc1 );
obj_detach(c2);
test( !obj_parent(c2) );
for each_objchild(r, obj, o) test( o != c2 );
for each_objchild(c2, obj, o) test( o == gc2 || o == gc3 );
}
// ----------------------------------------------------------------------------
// metadata
static map(int,int) oms;
static thread_mutex_t *oms_lock;
const char *obj_metaset(const void *o, const char *key, const char *value) {
do_threadlock(oms_lock) {
if(!oms) map_init_int(oms);
int *q = map_find_or_add(oms, intern(va("%llu-%s",obj_id((obj*)o),key)), 0);
if(!*q && !value[0]) {} else *q = intern(value);
return quark(*q);
}
return 0; // unreachable
}
const char* obj_metaget(const void *o, const char *key) {
do_threadlock(oms_lock) {
if(!oms) map_init_int(oms);
int *q = map_find_or_add(oms, intern(va("%llu-%s",obj_id((obj*)o),key)), 0);
return quark(*q);
}
return 0; // unreachable
}
static
void test_obj_metadatas( void *o1 ) {
obj *o = (obj *)o1;
test( !strcmp("", obj_metaget(o, "has_passed_test")) );
test( !strcmp("yes", obj_metaset(o, "has_passed_test", "yes")) );
test( !strcmp("yes", obj_metaget(o, "has_passed_test")) );
}
// ----------------------------------------------------------------------------
// stl
void* obj_swap(void *dst, void *src) { // @testme
int len = obj_size(dst);
char *buffer = ALLOCA(len);
memcpy(buffer, obj_datac(dst), len);
memcpy(obj_data(dst), obj_datac(src), len);
memcpy(obj_data(src), buffer, len);
return dst;
}
void* obj_copy_fast(void *dst, const void *src) {
// note: prefer obj_copy() as it should handle pointers and guids as well
return memcpy(obj_data(dst), obj_datac(src), obj_size(dst));
}
void* obj_copy(void *dst, const void *src) { // @testme
// @todo: use obj_copy_fast() silently if the object does not contain any pointers/guids
return obj_loadini(dst, obj_saveini(src));
// return obj_load(dst, obj_save(src));
// return obj_loadbin(dst, obj_savebin(src));
// return obj_loadini(dst, obj_saveini(src));
// return obj_loadjson(dst, obj_savejson(src));
// return obj_loadmpack(dst, obj_savempack(src));
}
int obj_comp_fast(const void *a, const void *b) {
// note: prefer obj_comp() as it should handle pointers and guids as well
return memcmp(obj_datac(a), obj_datac(b), obj_size(a));
}
int obj_comp(const void *a, const void *b) {
// @todo: use obj_comp_fast() silently if the object does not contain any pointers/guids
return strcmp(obj_saveini(a),obj_saveini(b));
}
int obj_lesser(const void *a, const void *b) {
return obj_comp(a,b) < 0;
}
int obj_greater(const void *a, const void *b) {
return obj_comp(a,b) > 0;
}
int obj_equal(const void *a, const void *b) {
return obj_comp(a,b) == 0;
}
uint64_t obj_hash(const void *o) {
return hash_bin(obj_datac(o), obj_size(o));
}
static
void test_obj_similarity(void *o1, void *o2) {
obj *b = (obj*)o1;
obj *c = (obj*)o2;
test( 0 == strcmp(obj_name(b),obj_name(c)) );
test( 0 == strcmp(obj_type(b),obj_type(c)) );
}
static
void test_obj_equality(void *o1, void *o2) {
obj *b = (obj*)o1;
obj *c = (obj*)o2;
test_obj_similarity(b, c);
test( obj_size(b) == obj_size(c) );
test( obj_hash(b) == obj_hash(c) );
test( 0 == obj_comp(b,c) );
test( obj_equal(b,c) );
test( !obj_lesser(b,c) );
test( !obj_greater(b,c) );
}
static
void test_obj_exact(void *o1, void *o2) {
obj *b = (obj*)o1;
obj *c = (obj*)o2;
test_obj_equality(b, c);
test( obj_header(b) == obj_header(c) );
test( 0 == memcmp(b, c, obj_sizeof(b)) );
}
// ----------------------------------------------------------------------------
// debug
bool obj_hexdump(const void *oo) {
const obj *o = (const obj *)oo;
int header = 1 * sizeof(obj);
printf("; name[%s] type[%s] id[%d..%d] unused[%08x] sizeof[%02d] %llx\n",
obj_name(o), obj_type(o),
(int)o->objid>>16, (int)o->objid&0xffff, (int)o->objunused,
obj_sizeof(o), o->objheader);
return hexdump(obj_datac(o) - header, obj_size(o) + header), 1;
}
int obj_print(const void *o) {
char *sav = obj_saveini(o); // obj_savejson(o)
return puts(sav);
}
static char *obj_tempname = 0;
static FILE *obj_filelog = 0;
int (obj_printf)(const void *o, const char *text) {
if( !obj_tempname ) {
obj_tempname = stringf("%s.log", app_name());
unlink(obj_tempname);
obj_filelog = fopen(obj_tempname, "w+b");
if( obj_filelog ) fseek(obj_filelog, 0L, SEEK_SET);
}
int rc = 0;
for( char *end; (end = strchr(text, '\n')) != NULL; ) {
rc |= fprintf(obj_filelog, "[%p] %.*s\n", o, (int)(end - text), text );
text = end + 1;
}
if( text[0] ) rc |= fprintf(obj_filelog, "[%p] %s\n", o, text);
return rc;
}
int obj_console(const void *o) { // obj_output() ?
if( obj_filelog ) fflush(obj_filelog);
return obj_tempname && !system(va(ifdef(win32,"type \"%s\" | find \"[%p]\"", "cat %s | grep \"[%p]\""), obj_tempname, o));
}
static
void test_obj_console(void *o1) {
obj *o = (obj *)o1;
obj_printf(o, "this is [%s], line 1\n", obj_name(o));
obj_printf(NULL, "this line does not belong to any object\n");
obj_printf(o, "this is [%s], line 2\n", obj_name(o));
obj_console(o);
}
// ----------------------------------------------------------------------------
// serialization
const char *p2s(const char *type, void *p) {
// @todo: p2s(int interned_type, void *p)
/**/ if( !strcmp(type, "int") ) return itoa1(*(int*)p);
else if( !strcmp(type, "unsigned") ) return itoa1(*(unsigned*)p);
else if( !strcmp(type, "float") ) return ftoa1(*(float*)p);
else if( !strcmp(type, "double") ) return ftoa1(*(double*)p);
else if( !strcmp(type, "uintptr_t") ) return va("%08llx", *(uintptr_t*)p);
else if( !strcmp(type, "vec2i") ) return itoa2(*(vec2i*)p);
else if( !strcmp(type, "vec3i") ) return itoa3(*(vec3i*)p);
else if( !strcmp(type, "vec2") ) return ftoa2(*(vec2*)p);
else if( !strcmp(type, "vec3") ) return ftoa3(*(vec3*)p);
else if( !strcmp(type, "vec4") ) return ftoa4(*(vec4*)p);
else if( !strcmp(type, "char*") || !strcmp(type, "string") ) return va("%s", *(char**)p);
// @todo: if strchr('*') assume obj, if reflected save guid: obj_id();
return tty_color(YELLOW), printf("p2s: cannot serialize `%s` type\n", type), tty_color(0), "";
}
bool s2p(void *P, const char *type, const char *str) {
int i; unsigned u; float f; double g; char *s = 0; uintptr_t p;
vec2 v2; vec3 v3; vec4 v4; vec2i v2i; vec3i v3i;
/**/ if( !strcmp(type, "int") ) return !!memcpy(P, (i = atoi1(str), &i), sizeof(i));
else if( !strcmp(type, "unsigned") ) return !!memcpy(P, (u = atoi1(str), &u), sizeof(u));
else if( !strcmp(type, "vec2i") ) return !!memcpy(P, (v2i = atoi2(str), &v2i), sizeof(v2i));
else if( !strcmp(type, "vec3i") ) return !!memcpy(P, (v3i = atoi3(str), &v3i), sizeof(v3i));
else if( !strcmp(type, "float") ) return !!memcpy(P, (f = atof1(str), &f), sizeof(f));
else if( !strcmp(type, "double") ) return !!memcpy(P, (g = atof1(str), &g), sizeof(g));
else if( !strcmp(type, "vec2") ) return !!memcpy(P, (v2 = atof2(str), &v2), sizeof(v2));
else if( !strcmp(type, "vec3") ) return !!memcpy(P, (v3 = atof3(str), &v3), sizeof(v3));
else if( !strcmp(type, "vec4") ) return !!memcpy(P, (v4 = atof4(str), &v4), sizeof(v4));
else if( !strcmp(type, "uintptr_t") ) return !!memcpy(P, (p = strtol(str, NULL, 16), &p), sizeof(p));
else if( !strcmp(type, "char*") || !strcmp(type, "string") ) {
char substring[128] = {0};
sscanf(str, "%[^\r\n]", substring);
strcatf(&s, "%s", substring);
*(uintptr_t*)(P) = (uintptr_t)s;
return 1;
}
// @todo: if strchr('*') assume obj, if reflected load guid: obj_id();
return tty_color(YELLOW), printf("s2p: cannot deserialize `%s` type\n", type), tty_color(0), 0;
}
char *obj_saveini(const void *o) { // @testme
char *out = 0;
const char *T = obj_type(o);
strcatf(&out, "[%s] ; v100\n", T);
for each_member(T,R) {
const char *sav = p2s(R->type,(char*)(o)+R->sz);
if(!sav) return FREE(out), NULL;
strcatf(&out,"%s.%s=%s\n", R->type,R->name,sav );
}
char *cpy = va("%s", out);
FREE(out);
return cpy;
}
obj *obj_mergeini(void *o, const char *ini) { // @testme
const char *sqr = strchr(ini, '[');
if( !sqr ) return 0;
ini = sqr+1;
char T[64] = {0};
if( sscanf(ini, "%64[^]]", &T) != 1 ) return 0; // @todo: parse version as well
ini += strlen(T);
for each_member(T,R) {
char *lookup = va("\n%s.%s=", R->type,R->name), *found = 0;
// type needed? /*
if(!found) { found = strstr(ini, lookup); if (found) found += strlen(lookup); }
if(!found) { *lookup = '\r'; }
if(!found) { found = strstr(ini, lookup); if (found) found += strlen(lookup); }
// */
if(!found) lookup = va("\n%s=", R->name);
if(!found) { found = strstr(ini, lookup); if (found) found += strlen(lookup); }
if(!found) { *lookup = '\r'; }
if(!found) { found = strstr(ini, lookup); if (found) found += strlen(lookup); }
if( found) {
if(!s2p((char*)(o)+R->sz, R->type, found))
return 0;
}
}
return o;
}
obj *obj_loadini(void *o, const char *ini) { // @testme
return obj_mergeini(obj_zero(o), ini);
}
char *obj_savejson(const void *o) {
char *j = 0;
const char *T = obj_type(o);
for each_member(T,R) {
const char *sav = p2s(R->type,(char*)(o)+R->sz);
if(!sav) return FREE(j), NULL;
char is_string = !strcmp(R->type,"char*") || !strcmp(R->type,"string");
strcatf(&j," %s: %s%s%s,\n", R->name,is_string?"\"":"",sav,is_string?"\"":"" );
}
char *out = va("%s: { // v100\n%s}\n", T,j);
FREE(j);
#if is(debug)
json5 root = { 0 };
char *error = json5_parse(&root, va("%s", out), 0);
assert( !error );
json5_free(&root);
#endif #endif
return out;
}
obj *obj_mergejson(void *o, const char *json) {
// @fixme: va() call below could be optimized out since we could figure it out if json was internally provided (via va or strdup), or user-provided
json5 root = { 0 };
char *error = json5_parse(&root, va("%s", json), 0); // @todo: parse version comment
if( !error && root.type == JSON5_OBJECT && root.count == 1 ) {
json5 *n = &root.nodes[0];
char *T = n->name;
for each_member(T,R) {
for( int i = 0; i < n->count; ++i ) {
if( !strcmp(R->name, n->nodes[i].name) ) {
void *p = (char*)o + R->sz;
/**/ if( n->nodes[i].type == JSON5_UNDEFINED ) {}
else if( n->nodes[i].type == JSON5_NULL ) {
*(uintptr_t*)(p) = (uintptr_t)0;
}
else if( n->nodes[i].type == JSON5_BOOL ) {
*(bool*)p = n->nodes[i].boolean;
}
else if( n->nodes[i].type == JSON5_INTEGER ) {
if( strstr(R->type, "64" ) )
*(int64_t*)p = n->nodes[i].integer;
else
*(int*)p = n->nodes[i].integer;
}
else if( n->nodes[i].type == JSON5_STRING ) {
char *s = 0;
strcatf(&s, "%s", n->nodes[i].string);
*(uintptr_t*)(p) = (uintptr_t)s;
}
else if( n->nodes[i].type == JSON5_REAL ) {
if( R->type[0] == 'f' )
*(float*)(p) = n->nodes[i].real;
else
*(double*)(p) = n->nodes[i].real;
}
else if( n->nodes[i].type == JSON5_OBJECT ) {}
else if( n->nodes[i].type == JSON5_ARRAY ) {}
break;
}
}
}
}
json5_free(&root);
return error ? 0 : o;
}
obj *obj_loadjson(void *o, const char *json) { // @testme
return obj_mergejson(obj_zero(o), json);
}
char *obj_savebin(const void *o) { // PACKMSG("ss", "entity_v1", quark(self->objnameid)); // = PACKMSG("p", obj_data(&b), (uint64_t)obj_size(&b));
int len = cobs_bounds(obj_size(o));
char *sav = va("%*.s", len, "");
len = cobs_encode(obj_datac(o), obj_size(o), sav, len);
sav[len] = '\0';
return sav;
}
obj *obj_mergebin(void *o, const char *sav) { // UNPACKMSG(sav, "p", obj_data(c), (uint64_t)obj_size(c));
int outlen = cobs_decode(sav, strlen(sav), obj_data(o), obj_size(o));
return outlen != obj_size(o) ? NULL : o;
}
obj *obj_loadbin(void *o, const char *sav) {
return obj_mergebin(obj_zero(o), sav);
}
char *obj_savempack(const void *o) { // @todo
return "";
}
obj *obj_mergempack(void *o, const char *sav) { // @todo
return 0;
}
obj *obj_loadmpack(void *o, const char *sav) { // @todo
return obj_mergempack(obj_zero(o), sav);
}
static __thread array(char*) obj_stack;
int obj_push(const void *o) {
char *bin = STRDUP(obj_savebin(o));
array_push(obj_stack, bin);
return 1;
}
int obj_pop(void *o) {
char *bin = *array_pop(obj_stack);
int rc = !!obj_loadbin(o, bin);
return FREE(bin), rc;
}
static
void test_obj_serialization(void *o1, void *o2) {
obj* b = (obj*)o1;
obj* c = (obj*)o2;
char *json = obj_savejson(b); // puts(json);
test( json[0] );
char *ini = obj_saveini(b); // puts(ini);
test( ini[0] );
char *bin = obj_savebin(b); // puts(bin);
test( bin[0] );
obj_push(c);
test( obj_copy(c,b) );
test( obj_comp(b,c) == 0 ) || obj_hexdump(b) & obj_hexdump(c);
test( obj_zero(c) );
test( obj_comp(c,b) != 0 ) || obj_hexdump(c);
test( obj_loadbin(c, bin) );
test( obj_comp(c,b) == 0 ) || obj_hexdump(c) & obj_hexdump(b);
test( obj_zero(c) );
test( obj_comp(c,b) != 0 ) || obj_hexdump(c);
test( obj_loadini(c, ini) );
test( obj_comp(c,b) == 0 ) || obj_hexdump(c) & obj_hexdump(b);
test( obj_zero(c) );
test( obj_comp(c,b) != 0 ) || obj_hexdump(c);
test( obj_loadjson(c, json) );
test( obj_comp(c,b) == 0 ) || obj_hexdump(c) & obj_hexdump(b);
obj_pop(c);
obj_hexdump(c);
}
// ----------------------------------------------------------------------------
// components
bool obj_addcomponent(void *object, unsigned c, void *ptr) {
entity *e = (entity*)object;
e->cflags |= (3ULL << c);
e->c[c & (OBJCOMPONENTS_MAX-1)] = ptr;
return 1;
}
bool obj_hascomponent(void *object, unsigned c) {
entity *e = (entity*)object;
return !!(e->cflags & (3ULL << c));
}
void* obj_getcomponent(void *object, unsigned c) {
entity *e = (entity*)object;
return e->c[c & (OBJCOMPONENTS_MAX-1)];
}
bool obj_delcomponent(void *object, unsigned c) {
entity *e = (entity*)object;
e->cflags &= ~(3ULL << c);
e->c[c & (OBJCOMPONENTS_MAX-1)] = NULL;
return 1;
}
bool obj_usecomponent(void *object, unsigned c) {
entity *e = (entity*)object;
e->cflags |= (1ULL << c);
return 1;
}
bool obj_offcomponent(void *object, unsigned c) {
entity *e = (entity*)object;
e->cflags &= ~(1ULL << c);
return 0;
}
char *entity_save(entity *self) {
char *sav = obj_saveini(self);
return sav;
}
AUTORUN {
STRUCT(entity, uintptr_t, cflags);
// struct { OBJHEADER union { struct { uintptr_t objenabled : 32, objflagged : 32; }; uintptr_t cflags; }; void* c[32]; };
obj_extend(entity, save);
}
static
void test_obj_ecs() {
entity *e = obj_new(entity);
puts(obj_save(e));
for( int i = 0; i < 32; ++i) test(0 == obj_hascomponent(e, i));
for( int i = 0; i < 32; ++i) test(1 == obj_addcomponent(e, i, NULL));
for( int i = 0; i < 32; ++i) test(1 == obj_hascomponent(e, i));
for( int i = 0; i < 32; ++i) test(1 == obj_delcomponent(e, i));
for( int i = 0; i < 32; ++i) test(0 == obj_hascomponent(e, i));
}
// ----------------------------------------------------------------------------
// reflection
void *obj_clone(const void *src) {
obj *ptr = obj_malloc( sizeof(obj) + obj_size(src) + sizeof(array(obj*)) );
ptr->objheader = ((const obj *)src)->objheader;
obj_loadini(ptr, obj_saveini(src));
return ptr;
}
void* obj_merge(void *dst, const void *src) { // @testme
char *bin = obj_savebin(src);
return obj_mergebin(dst, bin);
}
void* obj_mutate(void **dst, const void *src) {
#if 0
// mutate a class. ie, convert a given object class into a different one,
// while preserving the original metas, components and references as much as possible.
// @todo iterate per field
if(!*dst_) return *dst_ = obj_clone(src);
void *dst = *dst_;
dtor(dst);
unsigned src_sz = obj_sizeof(src);
unsigned src_id = obj_id(src);
void *dst_ptr = *((void**)dst - 1);
unsigned payload = (OBJPAYLOAD16(dst_ptr) & 255) | src_id << 8;
FREE( OBJUNBOX(dst_ptr) );
*((void**)dst - 1) = OBJBOX( STRDUP( OBJUNBOX(*((void**)src - 1)) ), payload);
void *base = (void*)((void**)dst - 1);
base = REALLOC(base, src_sz + sizeof(void*));
*dst_ = (char*)base + sizeof(void*);
dst = (char*)base + sizeof(void*);
memcpy(dst, src, src_sz);
ctor(dst);
#endif
return dst;
}
void *obj_make(const char *str) {
const char *T;
const char *I = strchr(str, '['); // is_ini
const char *J = strchr(str, '{'); // is_json
if( !I && !J ) return 0;
else if( I && !J ) T = I;
else if( !I && J ) T = J;
else T = I < J ? I : J;
char name[64] = {0};
if( sscanf(T+1, T == I ? "%64[^]]" : "%64[^:=]", &name) != 1 ) return 0;
int has_components = 0; // @todo: support entities too
unsigned Tid = intern(name);
reflect_init();
reflect_t *found = map_find(reflects, Tid);
if(!found) return 0;
obj *ptr = CALLOC(1, found->sz + has_components * sizeof(array(obj*)));
void *ret = (T == I ? obj_mergeini : obj_mergejson)(ptr, str);
OBJTYPES[ found->objtype ] = found->name;
OBJ_CTOR_PTR(ptr,1,found->id,found->sz,found->objtype);
return ptr; // returns partial construction as well. @todo: just return `ret` for a more strict built/failed policy
}

View File

@ -1,57 +1,306 @@
// ----------------------------------------------------------------------------- // C objects framework
// semantic versioning in a single byte (octal)
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// - single octal byte that represents semantic versioning (major.minor.patch). // ## object limitations
// - allowed range [0000..0377] ( <-> [0..255] decimal ) // - 8-byte overhead per object
// - comparison checks only major.minor tuple as per convention. // - XX-byte overhead per object-entity
// - 32 components max per object-entity
// - 256 classes max per game
// - 256 references max per object
// - 1024K bytes max per object
// - 8 generations + 64K IDs per running instance (19-bit IDs)
// - support for pragma pack(1) structs not enabled by default.
API int semver( int major, int minor, int patch ); /* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */
API int semvercmp( int v1, int v2 ); #ifndef OBJ_MIN_PRAGMAPACK_BITS
//#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 7<<3, so 1024 bytes max per class (default)
#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 7<<1, so 256 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 7<<0, so 128 bytes max per class
#endif
#define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch)) #define OBJHEADER \
#define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110)) union { \
#define SEMVERFMT "%03o" uintptr_t objheader; \
struct { \
uintptr_t objtype:8; \
uintptr_t objheap:1; \
uintptr_t objsizew:7; \
uintptr_t objrefs:8; \
uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \
uintptr_t objnameid:16; \
uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \
uintptr_t objunused:64-8-7-1-1-8-16-ID_INDEX_BITS-ID_COUNT_BITS; /*4*/ \
}; \
};
// ----------------------------------------------------------------------------- #define OBJ \
// storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations struct { OBJHEADER };
typedef struct byte2 { uint8_t x,y; } byte2; // ----------------------------------------------------------------------------
typedef struct byte3 { uint8_t x,y,z; } byte3; // syntax sugars
typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2; #ifdef OBJTYPE
typedef struct int3 { int x,y,z; } int3; #undef OBJTYPE
typedef struct int4 { int x,y,z,w; } int4; #endif
typedef struct uint2 { unsigned int x,y; } uint2; #define OBJTYPE(T) \
typedef struct uint3 { unsigned int x,y,z; } uint3; OBJTYPE_##T
typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2; #define OBJTYPEDEF(NAME,N) \
typedef struct float3 { float x,y,z; } float3; enum { OBJTYPE(NAME) = N }; \
typedef struct float4 { float x,y,z,w; } float4; STATIC_ASSERT( N <= 255 ); \
STATIC_ASSERT( (sizeof(NAME) & ((1<<OBJ_MIN_PRAGMAPACK_BITS)-1)) == 0 );
typedef struct double2 { double x,y; } double2; // ----------------------------------------------------------------------------
typedef struct double3 { double x,y,z; } double3; // objects
typedef struct double4 { double x,y,z,w; } double4;
#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) ) #define TYPEDEF_STRUCT(NAME,N,...) \
#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) ) typedef struct NAME { OBJ \
#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) ) __VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) ) // TYPEDEF_STRUCT(obj,0);
#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) ) typedef struct obj { OBJ } obj;
#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) ) // ----------------------------------------------------------------------------
#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) ) // entities
#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) ) #define OBJCOMPONENTS_MAX 32
#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) ) #define OBJCOMPONENTS_ALL_ENABLED 0xAAAAAAAAAAAAAAAAULL
#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) ) #define OBJCOMPONENTS_ALL_FLAGGED 0x5555555555555555ULL
#define COMPONENTS_ONLY(x) ((x) & ~OBJCOMPONENTS_ALL_FLAGGED)
#define ENTITY \
struct { OBJHEADER union { struct { uintptr_t objenabled:OBJCOMPONENTS_MAX, objflagged:OBJCOMPONENTS_MAX; }; uintptr_t cflags; }; void *c[OBJCOMPONENTS_MAX]; };
#define TYPEDEF_ENTITY(NAME,N,...) \
typedef struct NAME { ENTITY \
__VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
// OBJTYPEDEF(entity,1)
typedef struct entity { ENTITY } entity;
// ----------------------------------------------------------------------------
// heap/stack ctor/dtor
static __thread obj *objtmp;
#define OBJ_CTOR_HDR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE) ( \
(PTR)->objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \
(PTR)->objnameid = (OBJ_NAMEID), \
(PTR)->objtype = (OBJ_TYPE), \
(PTR)->objheap = (HEAP), \
(PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS))
#define OBJ_CTOR_PTR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE) ( \
OBJ_CTOR_HDR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE), \
obj_ctor(PTR))
#define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \
objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \
*(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \
((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \
( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \
OBJ_CTOR_PTR(objtmp, HEAP,intern(NAME),sizeof(TYPE),OBJTYPE(TYPE)), \
ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \
objtmp)
#define obj(TYPE, ...) obj_ext(TYPE, #TYPE, __VA_ARGS__)
#define obj_ext(TYPE, NAME, ...) *OBJ_CTOR(TYPE, NAME, 0, sizeof(array(obj*)), __VA_ARGS__)
#define obj_new(TYPE, ...) obj_new_ext(TYPE, #TYPE, __VA_ARGS__)
#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__)
void* obj_malloc(unsigned sz);
void* obj_free(void *o);
// ----------------------------------------------------------------------------
// obj generics. can be extended.
#define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__)
#define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__)
#define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__)
#define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__)
#define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__)
#define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__)
#define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__)
#define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__)
#define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__)
#define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__)
#define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__)
// --- syntax sugars
#define obj_extend(T,func) (obj_##func[OBJTYPE(T)] = (void*)T##_##func)
#define obj_method(method,o,...) (obj_##method[((obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_vtable(func,RC,...) RC macro(obj_##func)(){ __VA_ARGS__ }; RC (*obj_##func[256])() = { REPEAT256(macro(obj_##func)) };
#define obj_vtable_null(func,RC) RC (*obj_##func[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed
#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f
#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f)
#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f)
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
API extern void (*obj_dtor[256])(); ///-
API extern char* (*obj_save[256])(); ///-
API extern bool (*obj_load[256])(); ///-
API extern int (*obj_test[256])(); ///-
API extern int (*obj_init[256])(); ///-
API extern int (*obj_quit[256])(); ///-
API extern int (*obj_tick[256])(); ///-
API extern int (*obj_draw[256])(); ///-
API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
// ----------------------------------------------------------------------------
// core
API uintptr_t obj_header(const void *o);
API uintptr_t obj_id(const void *o);
API const char* obj_name(const void *o);
API unsigned obj_typeid(const void *o);
API const char* obj_type(const void *o);
API int obj_sizeof(const void *o);
API int obj_size(const void *o); // size of all members together in struct. may include padding bytes.
API char* obj_data(void *o); // pointer to the first member in struct
API const char* obj_datac(const void *o); // const pointer to the first struct member
API void* obj_payload(const void *o); // pointer right after last member in struct
API void* obj_zero(void *o); // reset all object members
// ----------------------------------------------------------------------------
// refcounting
API void* obj_ref(void *oo);
API void* obj_unref(void *oo);
// ----------------------------------------------------------------------------
// scene tree
// non-recursive
#define each_objchild(p,t,o) \
(array(obj*)* children = obj_children(p); children; children = 0) \
for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \
for(t *o = (t *)((*children)[_i]); o && 0[*children]; o = 0)
API obj* obj_detach(void *c);
API obj* obj_attach(void *o, void *c);
API obj* obj_root(const void *o);
API obj* obj_parent(const void *o);
API array(obj*)*obj_children(const void *o);
API array(obj*)*obj_siblings(const void *o);
API int obj_dumptree(const void *o);
// ----------------------------------------------------------------------------
// metadata
API const char* obj_metaset(const void *o, const char *key, const char *value);
API const char* obj_metaget(const void *o, const char *key);
// ----------------------------------------------------------------------------
// stl
API void* obj_swap(void *dst, void *src);
API void* obj_copy_fast(void *dst, const void *src);
API void* obj_copy(void *dst, const void *src);
API int obj_comp_fast(const void *a, const void *b);
API int obj_comp(const void *a, const void *b);
API int obj_lesser(const void *a, const void *b);
API int obj_greater(const void *a, const void *b);
API int obj_equal(const void *a, const void *b);
API uint64_t obj_hash(const void *o);
// ----------------------------------------------------------------------------
// debug
API bool obj_hexdump(const void *oo);
API int obj_print(const void *o);
API int obj_printf(const void *o, const char *text);
API int obj_console(const void *o); // obj_output() ?
#define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__))
// ----------------------------------------------------------------------------
// serialization
API char* obj_saveini(const void *o);
API obj* obj_mergeini(void *o, const char *ini);
API obj* obj_loadini(void *o, const char *ini);
API char* obj_savejson(const void *o);
API obj* obj_mergejson(void *o, const char *json);
API obj* obj_loadjson(void *o, const char *json);
API char* obj_savebin(const void *o);
API obj* obj_mergebin(void *o, const char *sav);
API obj* obj_loadbin(void *o, const char *sav);
API char* obj_savempack(const void *o); // @todo
API obj* obj_mergempack(void *o, const char *sav); // @todo
API obj* obj_loadmpack(void *o, const char *sav); // @todo
API int obj_push(const void *o);
API int obj_pop(void *o);
// ----------------------------------------------------------------------------
// components
API bool obj_addcomponent(void *object, unsigned c, void *ptr);
API bool obj_hascomponent(void *object, unsigned c);
API void* obj_getcomponent(void *object, unsigned c);
API bool obj_delcomponent(void *object, unsigned c);
API bool obj_usecomponent(void *object, unsigned c);
API bool obj_offcomponent(void *object, unsigned c);
API char* entity_save(entity *self);
// ----------------------------------------------------------------------------
// reflection
#define each_objmember(oo,TYPE,NAME,PTR) \
(array(reflect_t) *found_ = members_find(quark(((obj*)oo)->objnameid)); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \
for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \
for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 )
API void* obj_clone(const void *src);
API void* obj_merge(void *dst, const void *src); // @testme
API void* obj_mutate(void **dst, const void *src);
API void* obj_make(const char *str);
// built-ins
typedef enum OBJTYPE_BUILTINS {
OBJTYPE_obj = 0,
OBJTYPE_entity = 1,
OBJTYPE_vec2 = 2,
OBJTYPE_vec3 = 3,
OBJTYPE_vec4 = 4,
OBJTYPE_quat = 5,
OBJTYPE_mat33 = 6,
OBJTYPE_mat34 = 7,
OBJTYPE_mat44 = 8,
OBJTYPE_vec2i = 9,
OBJTYPE_vec3i = 10,
} OBJTYPE_BUILTINS;
#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )

View File

@ -1,3 +1,48 @@
// -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal)
// - rlyeh, public domain.
//
// - single octal byte that represents semantic versioning (major.minor.patch).
// - allowed range [0000..0377] ( <-> [0..255] decimal )
// - comparison checks only major.minor tuple as per convention.
int semver( int major, int minor, int patch ) {
return SEMVER(major, minor, patch);
}
int semvercmp( int v1, int v2 ) {
return SEMVERCMP(v1, v2);
}
#if 0
AUTORUN {
for( int i= 0; i <= 255; ++i) printf(SEMVERFMT ",", i);
puts("");
printf(SEMVERFMT "\n", semver(3,7,7));
printf(SEMVERFMT "\n", semver(2,7,7));
printf(SEMVERFMT "\n", semver(1,7,7));
printf(SEMVERFMT "\n", semver(0,7,7));
printf(SEMVERFMT "\n", semver(3,7,1));
printf(SEMVERFMT "\n", semver(2,5,3));
printf(SEMVERFMT "\n", semver(1,3,5));
printf(SEMVERFMT "\n", semver(0,1,7));
assert( semvercmp( 0357, 0300 ) > 0 );
assert( semvercmp( 0277, 0300 ) < 0 );
assert( semvercmp( 0277, 0200 ) > 0 );
assert( semvercmp( 0277, 0100 ) < 0 );
assert( semvercmp( 0076, 0070 ) == 0 );
assert( semvercmp( 0076, 0077 ) == 0 );
assert( semvercmp( 0176, 0170 ) == 0 );
assert( semvercmp( 0176, 0177 ) == 0 );
assert( semvercmp( 0276, 0270 ) == 0 );
assert( semvercmp( 0276, 0277 ) == 0 );
assert( semvercmp( 0376, 0370 ) == 0 );
assert( semvercmp( 0376, 0377 ) == 0 );
}
#endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// compile-time fourcc, eightcc // compile-time fourcc, eightcc
@ -25,24 +70,18 @@ char *cc8str(uint64_t x) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// float conversion (text) // float conversion (text)
vec2 atof2(const char *s) { char* itoa1(int v) {
vec2 v = {0}; return va("%d", v);
sscanf(s, "%f,%f", &v.x, &v.y);
return v;
} }
vec3 atof3(const char *s) { char* itoa2(vec2i v) {
vec3 v = {0}; return va("%d,%d", v.x,v.y);
sscanf(s, "%f,%f,%f", &v.x, &v.y, &v.z);
return v;
} }
vec4 atof4(const char *s) { char* itoa3(vec3i v) {
vec4 v = {0}; return va("%d,%d,%d", v.x,v.y,v.z);
sscanf(s, "%f,%f,%f,%f", &v.x, &v.y, &v.z, &v.w);
return v;
} }
char* ftoa(float f) { char* ftoa1(float v) {
return va("%f", f); return va("%f", v);
} }
char* ftoa2(vec2 v) { char* ftoa2(vec2 v) {
return va("%f,%f", v.x, v.y); return va("%f,%f", v.x, v.y);
@ -54,6 +93,51 @@ char* ftoa4(vec4 v) {
return va("%f,%f,%f,%f", v.x, v.y, v.z, v.w); return va("%f,%f,%f,%f", v.x, v.y, v.z, v.w);
} }
float atof1(const char *s) {
char buf[64];
return sscanf(s, "%64[^]\r\n,}]", buf) == 1 ? (float)eval(buf) : (float)NAN;
}
vec2 atof2(const char *s) {
vec2 v = { 0 };
char buf1[64],buf2[64];
int num = sscanf(s, "%64[^]\r\n,}],%64[^]\r\n,}]", buf1, buf2);
if( num > 0 ) v.x = eval(buf1);
if( num > 1 ) v.y = eval(buf2);
return v;
}
vec3 atof3(const char *s) {
vec3 v = {0};
char buf1[64],buf2[64],buf3[64];
int num = sscanf(s, "%64[^]\r\n,}],%64[^]\r\n,}],%64[^]\r\n,}]", buf1, buf2, buf3);
if( num > 0 ) v.x = eval(buf1);
if( num > 1 ) v.y = eval(buf2);
if( num > 2 ) v.z = eval(buf3);
return v;
}
vec4 atof4(const char *s) {
vec4 v = {0};
char buf1[64],buf2[64],buf3[64],buf4[64];
int num = sscanf(s, "%64[^]\r\n,}],%64[^]\r\n,}],%64[^]\r\n,}],%64[^]\r\n,}]", buf1, buf2, buf3, buf4);
if( num > 0 ) v.x = eval(buf1);
if( num > 1 ) v.y = eval(buf2);
if( num > 2 ) v.z = eval(buf3);
if( num > 3 ) v.w = eval(buf4);
return v;
}
// @todo: expand this to proper int parsers
int atoi1(const char *s) {
return (int)atof1(s);
}
vec2i atoi2(const char *s) {
vec2 v = atof2(s);
return vec2i( v.x, v.y );
}
vec3i atoi3(const char *s) {
vec3 v = atof3(s);
return vec3i( v.x, v.y, v.z );
}
// endianness ----------------------------------------------------------------- // endianness -----------------------------------------------------------------
// - rlyeh, public domain // - rlyeh, public domain

View File

@ -1,3 +1,61 @@
// -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal)
// - rlyeh, public domain.
//
// - single octal byte that represents semantic versioning (major.minor.patch).
// - allowed range [0000..0377] ( <-> [0..255] decimal )
// - comparison checks only major.minor tuple as per convention.
API int semver( int major, int minor, int patch );
API int semvercmp( int v1, int v2 );
#define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch))
#define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110))
#define SEMVERFMT "%03o"
// -----------------------------------------------------------------------------
// storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations
typedef struct byte2 { uint8_t x,y; } byte2;
typedef struct byte3 { uint8_t x,y,z; } byte3;
typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2;
typedef struct int3 { int x,y,z; } int3;
typedef struct int4 { int x,y,z,w; } int4;
typedef struct uint2 { unsigned int x,y; } uint2;
typedef struct uint3 { unsigned int x,y,z; } uint3;
typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2;
typedef struct float3 { float x,y,z; } float3;
typedef struct float4 { float x,y,z,w; } float4;
typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) )
#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) )
#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) )
#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) )
#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) )
#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// compile-time fourcc, eightcc // compile-time fourcc, eightcc
@ -26,16 +84,25 @@ enum {
#define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g) #define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// float conversion (text) // text conversions
API char* ftoa1(float v);
API char* ftoa2(vec2 v);
API char* ftoa3(vec3 v);
API char* ftoa4(vec4 v);
API float atof1(const char *s);
API vec2 atof2(const char *s); API vec2 atof2(const char *s);
API vec3 atof3(const char *s); API vec3 atof3(const char *s);
API vec4 atof4(const char *s); API vec4 atof4(const char *s);
API char* ftoa(float f); API char* itoa1(int v);
API char* ftoa2(vec2 v); API char* itoa2(vec2i v);
API char* ftoa3(vec3 v); API char* itoa3(vec3i v);
API char* ftoa4(vec4 v);
API int atoi1(const char *s);
API vec2i atoi2(const char *s);
API vec3i atoi3(const char *s);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// endianness // endianness

View File

@ -79,10 +79,10 @@ void *member_findptr(void *obj, const char *T, const char *M) {
M = symbol(M); M = symbol(M);
return (char*)obj + member_find(T,M).sz; return (char*)obj + member_find(T,M).sz;
} }
array(reflect_t) members_find(const char *T) { array(reflect_t)* members_find(const char *T) {
reflect_init(); reflect_init();
T = symbol(T); T = symbol(T);
return *map_find(members, intern(T)); return map_find(members, intern(T));
} }

View File

@ -43,14 +43,14 @@ API void * function_find(const char *F);
API reflect_t member_find(const char *T, const char *M); /// find specific member API reflect_t member_find(const char *T, const char *M); /// find specific member
API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate
API array(reflect_t) members_find(const char *T); API array(reflect_t)* members_find(const char *T);
// iterate members in a struct // iterate members in a struct
#define each_member(T,R) \ #define each_member(T,R) \
(array(reflect_t)*found_ = map_find(members, intern(T)); found_; found_ = 0) \ (array(reflect_t) *found_ = members_find(T); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = (*found_)+it_; R; R = 0 ) for(reflect_t *R = &(*found_)[it_]; R; R = 0 )
// private api, still exposed // private api, still exposed

View File

@ -533,13 +533,13 @@ void shader_colormap(const char *name, colormap_t c ) {
// colors // colors
unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a ) { unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a ) {
return (unsigned)r << 24 | g << 16 | b << 8 | a; return (unsigned)a << 24 | b << 16 | g << 8 | r;
} }
unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ) { unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ) {
return rgba(r,g,b,a); return rgba(r,g,b,a);
} }
float alpha( unsigned rgba ) { unsigned alpha( unsigned rgba ) {
return ( rgba >> 24 ) / 255.f; return rgba >> 24;
} }
unsigned rgbaf(float r, float g, float b, float a) { unsigned rgbaf(float r, float g, float b, float a) {

View File

@ -15,7 +15,7 @@ API unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a );
API unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ); API unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a );
API unsigned rgbaf( float r, float g, float b, float a ); API unsigned rgbaf( float r, float g, float b, float a );
API unsigned bgraf( float b, float g, float r, float a ); API unsigned bgraf( float b, float g, float r, float a );
API float alpha( unsigned rgba ); API unsigned alpha( unsigned rgba );
#define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) ) #define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) )
#define RGB3(r,g,b) ( (255<<24) | ((r)<<16) | ((g)<<8) | (b) ) #define RGB3(r,g,b) ( (255<<24) | ((r)<<16) | ((g)<<8) | (b) )

View File

@ -79,13 +79,13 @@ API array(uint32_t) string32( const char *utf8 ); /// convert from utf8 to utf32
// ## string interning (quarks) // ## string interning (quarks)
// - rlyeh, public domain. // - rlyeh, public domain.
unsigned intern( const char *string ); API unsigned intern( const char *string );
const char *quark( unsigned key ); API const char *quark( unsigned key );
typedef struct quarks_db { typedef struct quarks_db {
array(char) blob; array(char) blob;
array(vec2i) entries; array(vec2i) entries;
} quarks_db; } quarks_db;
unsigned quark_intern( quarks_db*, const char *string ); API unsigned quark_intern( quarks_db*, const char *string );
const char *quark_string( quarks_db*, unsigned key ); API const char *quark_string( quarks_db*, unsigned key );

View File

@ -279,7 +279,7 @@ void trap_on_abort(int signal) {
exit(-1); exit(-1);
} }
void trap_on_debug(int signal) { void trap_on_debug(int signal) {
breakpoint("Error: unexpected signal"); alert("Error: unexpected signal"), breakpoint();
fprintf(stderr, "Error: unexpected signal %s (%d)\n%s\n", trap_name(signal), signal, callstack(16)); fprintf(stderr, "Error: unexpected signal %s (%d)\n%s\n", trap_name(signal), signal, callstack(16));
exit(-1); exit(-1);
} }
@ -549,7 +549,7 @@ void tty_color(unsigned color) {
} }
#endif #endif
if( color ) { if( color ) {
// if( color == RED ) breakpoint("break on RED"); // debug // if( color == RED ) alert("break on error message (RED)"), breakpoint(); // debug
unsigned r = (color >> 16) & 255; unsigned r = (color >> 16) & 255;
unsigned g = (color >> 8) & 255; unsigned g = (color >> 8) & 255;
unsigned b = (color >> 0) & 255; unsigned b = (color >> 0) & 255;
@ -668,6 +668,9 @@ static void debugbreak(void) { // break if debugger present
#endif #endif
void alert(const char *message) { // @todo: move to app_, besides die() void alert(const char *message) { // @todo: move to app_, besides die()
window_visible(false);
message = message[0] == '!' ? (const char*)va("%s\n%s", message+1, callstack(+48)) : message;
#if is(win32) #if is(win32)
MessageBoxA(0, message, 0,0); MessageBoxA(0, message, 0,0);
#elif is(ems) #elif is(ems)
@ -678,18 +681,12 @@ void alert(const char *message) { // @todo: move to app_, besides die()
#elif is(osx) #elif is(osx)
system(va("osascript -e 'display alert \"Alert\" message \"%s\"'", message)); system(va("osascript -e 'display alert \"Alert\" message \"%s\"'", message));
#endif #endif
}
void breakpoint(const char *reason) {
window_visible(false);
if( reason ) {
const char *fulltext = reason[0] == '!' ? va("%s\n%s", reason+1, callstack(+48)) : reason;
PRINTF("%s", fulltext);
(alert)(fulltext);
}
debugbreak();
window_visible(true); window_visible(true);
}
void breakpoint() {
debugbreak();
} }
bool has_debugger() { bool has_debugger() {
@ -752,7 +749,9 @@ int (PANIC)(const char *error, const char *file, int line) {
tty_color(0); tty_color(0);
breakpoint(error); alert(error);
breakpoint();
exit(-line); exit(-line);
return 1; return 1;
} }
@ -904,10 +903,12 @@ const char* app_savefile() {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// tests // tests
static __thread int test_oks, test_errs, test_once; static __thread int test_oks, test_errors, test_once;
static void test_exit(void) { fprintf(stderr, "%d/%d tests passed\n", test_oks, test_oks+test_errs); } static void test_exit(void) { fprintf(stderr, "%d/%d tests passed\n", test_oks, test_oks+test_errors); }
int (test)(const char *file, int line, const char *expr, bool result) { int (test)(const char *file, int line, const char *expr, bool result) {
static int breakon = -1; if(breakon<0) breakon = optioni("--test-break", 0);
if( breakon == (test_oks+test_errors+1) ) alert("user requested to break on this test"), breakpoint();
test_once = test_once || !(atexit)(test_exit); test_once = test_once || !(atexit)(test_exit);
test_oks += result, test_errs += !result; test_oks += result, test_errors += !result;
return (result || (tty_color(RED), fprintf(stderr, "(Test `%s` failed %s:%d)\n", expr, file, line), tty_color(0), 0) ); return (result || (tty_color(RED), fprintf(stderr, "(Test `%s` failed %s:%d)\n", expr, file, line), tty_color(0), 0) );
} }

View File

@ -49,7 +49,7 @@ API void die(const char *message);
API void alert(const char *message); API void alert(const char *message);
API void hexdump( const void *ptr, unsigned len ); API void hexdump( const void *ptr, unsigned len );
API void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width ); API void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width );
API void breakpoint(const char *optional_reason); API void breakpoint();
API bool has_debugger(); API bool has_debugger();
API void trap_install(void); API void trap_install(void);

View File

@ -24,7 +24,7 @@ API void timer_destroy(unsigned timer_handle);
// //
// also similar to a mongo object id, 12 bytes as follows: // also similar to a mongo object id, 12 bytes as follows:
// - 4-byte timestamp (ss). epoch: Tuesday, 12 September 2023 6:06:56 // - 4-byte timestamp (ss). epoch: Tuesday, 12 September 2023 6:06:56
// - 2-byte (machine or app hash) // - 2-byte (machine, hash or app id)
// - 2-byte (thread-id) // - 2-byte (thread-id)
// - 4-byte (rand counter, that gets increased at every id creation) // - 4-byte (rand counter, that gets increased at every id creation)

View File

@ -5,7 +5,6 @@
#define UI_FONT_ENUM(carlito,b612) b612 // carlito #define UI_FONT_ENUM(carlito,b612) b612 // carlito
#define UI_FONT_ICONS "MaterialIconsSharp-Regular.otf" // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf" //
#define UI_FONT_REGULAR UI_FONT_ENUM("Carlito", "B612") "-Regular.ttf" #define UI_FONT_REGULAR UI_FONT_ENUM("Carlito", "B612") "-Regular.ttf"
#define UI_FONT_HEADING UI_FONT_ENUM("Carlito", "B612") "-BoldItalic.ttf" #define UI_FONT_HEADING UI_FONT_ENUM("Carlito", "B612") "-BoldItalic.ttf"
#define UI_FONT_TERMINAL UI_FONT_ENUM("Inconsolata", "B612Mono") "-Regular.ttf" #define UI_FONT_TERMINAL UI_FONT_ENUM("Inconsolata", "B612Mono") "-Regular.ttf"
@ -76,12 +75,16 @@ static void nk_config_custom_fonts() {
} }
// ...with icons embedded on it. // ...with icons embedded on it.
static struct icon_font {
for( char *data = vfs_load(UI_FONT_ICONS, &datalen); data; data = 0 ) { const char *file; nk_rune range[3];
static const nk_rune icon_range[] = {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}; } icons[] = {
{"MaterialIconsSharp-Regular.otf", {UI_ICON_MIN, UI_ICON_MED /*MAX*/, 0}}, // "MaterialIconsOutlined-Regular.otf" "MaterialIcons-Regular.ttf"
{"materialdesignicons-webfont.ttf", {0xF68C /*ICON_MIN_MDI*/, 0xF1C80/*ICON_MAX_MDI*/, 0}},
};
for( int f = 0; f < countof(icons); ++f )
for( char *data = vfs_load(icons[f].file, &datalen); data; data = 0 ) {
struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE); struct nk_font_config cfg = nk_font_config(UI_ICON_FONTSIZE);
cfg.range = icon_range; // nk_font_default_glyph_ranges(); cfg.range = icons[f].range; // nk_font_default_glyph_ranges();
cfg.merge_mode = 1; cfg.merge_mode = 1;
cfg.spacing.x += UI_ICON_SPACING_X; cfg.spacing.x += UI_ICON_SPACING_X;

View File

@ -271,7 +271,8 @@ void glNewFrame() {
} }
bool window_create_from_handle(void *handle, float scale, unsigned flags) { bool window_create_from_handle(void *handle, float scale, unsigned flags) {
ifdef(debug, if( flag("--tests") ) exit(0)); // abort run if any test suite failed in unit-test mode
ifdef(debug, if( flag("--test-only") ) exit( test_errors ? -test_errors : 0 ));
glfw_init(); glfw_init();
v4k_init(); v4k_init();

View File

@ -199014,7 +199014,7 @@ nk_utf_decode(const char *c, nk_rune *u, int clen)
*u = NK_UTF_INVALID; *u = NK_UTF_INVALID;
udecoded = nk_utf_decode_byte(c[0], &len); udecoded = nk_utf_decode_byte(c[0], &len);
if (!NK_BETWEEN(len, 1, NK_UTF_SIZE)) if (!NK_BETWEEN(len, 1, NK_UTF_SIZE+1)) //< @r-lyeh: add +1 for len<=4
return 1; return 1;
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
@ -211149,7 +211149,12 @@ window->is_window_resizing |= layout->flags & NK_WINDOW_SCALE_TOP ? NK_WINDOW_SC
} }
} }
ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT]; int icon = //< @r-lyeh
((layout->flags & NK_WINDOW_SCALE_TOP) && !(layout->flags & NK_WINDOW_SCALE_LEFT))
||
((layout->flags & NK_WINDOW_SCALE_LEFT) && !(layout->flags & NK_WINDOW_SCALE_TOP))
? NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT : NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT;
ctx->style.cursor_active = ctx->style.cursors[icon]; //< @r-lyeh
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f; in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;
in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f; in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;
} }
@ -312982,6 +312987,499 @@ API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n,
* SOFTWARE. * SOFTWARE.
*/ */
#line 0 #line 0
#define expr expr2 // 3rd_lua.h
#line 1 "engine/split/3rd_eval.h"
/* A mathematical expression evaluator.
* It uses a recursive descent parser internally.
* Author: Werner Stoop
* This is free and unencumbered software released into the public domain.
* http://unlicense.org/
*/
#include <assert.h>
#include <ctype.h>
#include <math.h> /* remember to compile with -lm */
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
/* Special tokens used by the lexer function lex()
* they've been chosen as non-printable characters
* so that printable characters can be used for other
* purposes
*/
#define TOK_END 0 /* end of text */
#define TOK_INI 1 /* Initial state */
#define TOK_ID 2 /* identifier */
#define TOK_NUM 3 /* number */
/* Types of errors */
// 0 /* "no error" */
#define ERR_MEMORY 1 /* "out of memory" */
#define ERR_LEXER 2 /* "unknown token" */
#define ERR_LONGID 3 /* "identifier too long" */
#define ERR_VALUE 4 /* "value expected" */
#define ERR_BRACKET 5 /* "missing ')'" */
#define ERR_FUNC 6 /* "unknown function" */
#define ERR_ARGS 7 /* "wrong number of arguments" */
#define ERR_CONST 8 /* "unknown constant" */
/* Other definitions */
#define MAX_ID_LEN 11 /* Max length of an identifier */
#define OPERATORS "+-*/%(),^" /* Valid operators */
#define EVAL_PI 3.141592654
#define EVAL_E 2.718281828
#define EVAL_DEG (EVAL_PI/180)
/* Internal structure for the parser/evaluator */
struct eval {
jmp_buf j; /* For error handling */
const char *p; /* Position in the text being parsed */
double *st; /* Stack */
int st_size; /* Stack size */
int sp; /* Stack pointer */
/* The current and next tokens identified by the lexer */
struct {
int type; /* Type of the token */
double n_val; /* Numeric value of the previous lexed token */
char s_val[MAX_ID_LEN]; /* String (identifier) value of the previous lexed token */
} token[2];
int cur_tok; /* Current token, either 0 or 1 (see the comments of lex()) */
};
/* Prototypes */
static double pop(struct eval *ev);
static void push(struct eval *ev, double d);
static int lex(struct eval *ev);
/* Prototypes for the recursive descent parser */
static void expr(struct eval *ev);
static void add_expr(struct eval *ev);
static void mul_expr(struct eval *ev);
static void pow_expr(struct eval *ev);
static void uni_expr(struct eval *ev);
static void bra_expr(struct eval *ev);
static void id_expr(struct eval *ev);
static void num_expr(struct eval *ev);
/*
* Evaluates a mathemeatical expression
*/
double eval(const char *exp/*, int *ep*/) {
int _ep, *ep = &_ep;
struct eval ev;
double ans = 0.0;
assert(ep != NULL);
/* Allocate a stack */
ev.st_size = 10;
ev.st = CALLOC(ev.st_size, sizeof *ev.st);
if(!ev.st)
{
*ep = ERR_MEMORY;
return NAN; //0.0;
}
ev.sp = 0;
/* Manage errors */
*ep = setjmp(ev.j);
if(*ep != 0)
{
FREE(ev.st);
return NAN; //0.0;
}
/* Initialize the lexer */
ev.token[0].type = TOK_INI;
ev.token[0].s_val[0] = '\0';
ev.token[1].type = TOK_INI;
ev.token[1].s_val[0] = '\0';
ev.cur_tok = 0;
/* Initialize the parser */
ev.p = exp;
/* lex once to initialize the lexer */
if(lex(&ev) != TOK_END)
{
expr(&ev);
ans = pop(&ev);
}
FREE(ev.st);
return ans;
}
/*
* Pushes a value onto the stack, increases the stack size if necessary
*/
static void push(struct eval *ev, double d) {
if(ev->sp == ev->st_size) {
/* Resize the stack by 1.5 */
double *old = ev->st;
int new_size = ev->st_size + (ev->st_size >> 1);
ev->st = REALLOC(ev->st, new_size);
if(!ev->st) {
ev->st = old;
longjmp(ev->j, ERR_MEMORY);
}
ev->st_size = new_size;
}
ev->st[ev->sp++] = d;
}
// Pops a value from the top of the stack
static double pop(struct eval *ev) {
assert(ev->sp > 0);
return ev->st[--ev->sp];
}
// stricmp() is common, but not standard, so I provide my own
static int istrcmp(const char *p, const char *q) {
for(; tolower(p[0]) == tolower(q[0]) && p[0]; p++, q++);
return tolower(p[0]) - tolower(q[0]);
}
/*
* Lexical analyzer function
*
* In order to implement LL(1), struct eval has an array of two token structures,
* and its cur_tok member is used to point to the _current_ token, while the other
* element contains the _next_ token. This implements a 2 element ring buffer where
* the lexer always writes to the _next_ token so that the recursive descent parser can
* _peek_ at the next token.
*/
static int lex(struct eval *ev) {
int next_tok;
start:
/* Cycle the tokens */
next_tok = ev->cur_tok;
ev->cur_tok = ev->cur_tok?0:1;
while(isspace(ev->p[0])) ev->p++;
if(!ev->p[0]) {
/* End of the expression */
ev->token[next_tok].type = TOK_END;
goto end;
}
else if(isdigit(ev->p[0]) || ev->p[0] == '.') {
/* Number */
char *endp;
ev->token[next_tok].type = TOK_NUM;
ev->token[next_tok].n_val = strtod(ev->p, &endp);
ev->p = endp;
goto end;
}
else if(isalpha(ev->p[0])) {
/* Identifier */
int i;
for(i = 0; isalnum(ev->p[0]) && i < MAX_ID_LEN - 1; i++, ev->p++)
ev->token[next_tok].s_val[i] = ev->p[0];
if(isalpha(ev->p[0])) longjmp(ev->j, ERR_LONGID);
ev->token[next_tok].s_val[i] = '\0';
ev->token[next_tok].type = TOK_ID;
goto end;
}
else if(strchr(OPERATORS, ev->p[0])) {
/* Operator */
ev->token[next_tok].type = ev->p[0];
ev->p++;
goto end;
}
else /* Unknown token */
longjmp(ev->j, ERR_LEXER);
end:
/* If this was the first call, cycle the tokens again */
if(ev->token[ev->cur_tok].type == TOK_INI)
goto start;
return ev->token[ev->cur_tok].type;
}
#define EVAL_TYPE(e) (e->token[e->cur_tok].type)
#define EVAL_ERROR(c) longjmp(ev->j, (c))
// num_expr ::= NUMBER
static void num_expr(struct eval *ev) {
if(EVAL_TYPE(ev) != TOK_NUM)
EVAL_ERROR(ERR_VALUE);
push(ev, ev->token[ev->cur_tok].n_val);
lex(ev);
}
// expr ::= add_expr
static void expr(struct eval *ev) {
add_expr(ev);
}
// add_expr ::= mul_expr [('+'|'-') mul_expr]
static void add_expr(struct eval *ev) {
int t;
mul_expr(ev);
while((t =EVAL_TYPE(ev)) == '+' || t == '-') {
double a,b;
lex(ev);
mul_expr(ev);
b = pop(ev);
a = pop(ev);
if(t == '+')
push(ev, a + b);
else
push(ev, a - b);
}
}
// mul_expr ::= pow_expr [('*'|'/'|'%') pow_expr]
static void mul_expr(struct eval *ev) {
int t;
pow_expr(ev);
while((t = EVAL_TYPE(ev)) == '*' || t == '/' || t == '%') {
double a,b;
lex(ev);
pow_expr(ev);
b = pop(ev);
a = pop(ev);
if(t == '*')
push(ev, a * b);
else if(t == '/')
push(ev, a / b);
else
push(ev, fmod(a, b));
}
}
// pow_expr ::= uni_expr ['^' pow_expr]
static void pow_expr(struct eval *ev) {
/* Note that exponentiation is right associative:
2^3^4 is 2^(3^4), not (2^3)^4 */
uni_expr(ev);
if(EVAL_TYPE(ev) == '^') {
double a,b;
lex(ev);
pow_expr(ev);
b = pop(ev);
a = pop(ev);
push(ev, pow(a,b));
}
}
// uni_expr ::= ['+'|'-'] bra_expr
static void uni_expr(struct eval *ev) {
int t = '+';
if(EVAL_TYPE(ev) == '-' || EVAL_TYPE(ev) == '+') {
t = EVAL_TYPE(ev);
lex(ev);
}
bra_expr(ev);
if(t == '-') {
double a = pop(ev);
push(ev, -a);
}
}
// bra_expr ::= '(' add_expr ')' | id_expr
static void bra_expr(struct eval *ev) {
if(EVAL_TYPE(ev) == '(') {
lex(ev);
add_expr(ev);
if(EVAL_TYPE(ev) != ')')
EVAL_ERROR(ERR_BRACKET);
lex(ev);
}
else
id_expr(ev);
}
// id_expr ::= ID '(' add_expr [',' add_expr]* ')' | ID | num_expr
static void id_expr(struct eval *ev) {
int nargs = 0;
char id[MAX_ID_LEN];
if(EVAL_TYPE(ev) != TOK_ID) {
num_expr(ev);
} else {
strcpy(id, ev->token[ev->cur_tok].s_val);
lex(ev);
if(EVAL_TYPE(ev) != '(') {
/**/ if(!istrcmp(id, "true")) push(ev, 1.0);
else if(!istrcmp(id, "false")) push(ev, 0.0);
else if(!istrcmp(id, "on")) push(ev, 1.0);
else if(!istrcmp(id, "off")) push(ev, 0.0);
// pi - 3.141592654
else if(!istrcmp(id, "pi"))
push(ev, EVAL_PI);
// e - base of natural logarithms, 2.718281828
else if(!istrcmp(id, "e"))
push(ev, EVAL_E);
// deg - deg2rad, allows to degree conversion `sin(90*deg) = 1`
else if(!istrcmp(id, "deg"))
push(ev, EVAL_DEG);
else
EVAL_ERROR(ERR_CONST);
} else {
lex(ev);
while(EVAL_TYPE(ev) != ')') {
add_expr(ev);
nargs++;
if(EVAL_TYPE(ev) == ')') break;
if(EVAL_TYPE(ev) != ',')
EVAL_ERROR(ERR_BRACKET);
lex(ev);
}
lex(ev);
// abs(x) - absolute value of x
if(!istrcmp(id, "abs")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, fabs(pop(ev)));
}
// ceil(x) - smallest integer greater than x
else if(!istrcmp(id, "ceil")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, ceil(pop(ev)));
}
// floor(x) - largest integer smaller than x
else if(!istrcmp(id, "floor")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, floor(pop(ev)));
}
// sin(x) - sine of x, in radians
else if(!istrcmp(id, "sin")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sin(pop(ev)));
}
// asin(x) - arcsine of x, in radians
else if(!istrcmp(id, "asin")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, asin(pop(ev)));
}
// cos(x) - cosine of x, in radians
else if(!istrcmp(id, "cos")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, cos(pop(ev)));
}
// acos(x) - arccosine of x, in radians
else if(!istrcmp(id, "acos")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, acos(pop(ev)));
}
// tan(x) - tangent of x, in radians
else if(!istrcmp(id, "tan")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, tan(pop(ev)));
}
// atan(x) - arctangent of x, in radians
else if(!istrcmp(id, "atan")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, atan(pop(ev)));
}
// atan(y,x) - arctangent of y/x, in radians.
else if(!istrcmp(id, "atan2")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, atan2(a,b));
}
// sinh(x) - hyperbolic sine of x, in radians
else if(!istrcmp(id, "sinh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sinh(pop(ev)));
}
// cosh(x) - hyperbolic cosine of x, in radians
else if(!istrcmp(id, "cosh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, cosh(pop(ev)));
}
// tanh(x) - hyperbolic tangent of x, in radians
else if(!istrcmp(id, "tanh")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, tanh(pop(ev)));
}
// log(x) - natural logarithm of x
else if(!istrcmp(id, "log")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, log(pop(ev)));
}
// log10(x) - logarithm of x, base-10
else if(!istrcmp(id, "log10")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, log10(pop(ev)));
}
// exp(x) - computes e^x
else if(!istrcmp(id, "exp")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, exp(pop(ev)));
}
// sqrt(x) - square root of x
else if(!istrcmp(id, "sqrt")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, sqrt(pop(ev)));
}
// rad(x) - converts x from degrees to radians
else if(!istrcmp(id, "rad")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, pop(ev)*EVAL_PI/180);
}
// deg(x) - converts x from radians to degrees
else if(!istrcmp(id, "deg")) {
if(nargs != 1) EVAL_ERROR(ERR_ARGS);
push(ev, pop(ev)*180/EVAL_PI);
}
// pow(x,y) - computes x^y
else if(!istrcmp(id, "pow")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, pow(a,b));
}
// hypot(x,y) - computes sqrt(x*x + y*y)
else if(!istrcmp(id, "hypot")) {
double a, b;
if(nargs != 2) EVAL_ERROR(ERR_ARGS);
b = pop(ev);
a = pop(ev);
push(ev, sqrt(a*a + b*b));
}
else
EVAL_ERROR(ERR_FUNC);
}
}
}
//
#ifdef EVALDEMO
#include <stdio.h>
int main() {
assert( eval("1+1") == 2 ); // common path
assert( eval("1+") != eval("1+") ); // check that errors return NAN
assert(~puts("Ok") );
}
#endif
#line 0
// #define SQLITE_OMIT_LOAD_EXTENSION // #define SQLITE_OMIT_LOAD_EXTENSION
// #define SQLITE_CORE 1 // #define SQLITE_CORE 1
// #define SQLITE_DEBUG 1 // #define SQLITE_DEBUG 1

File diff suppressed because it is too large Load Diff

View File

@ -267,7 +267,7 @@ extern "C" {
#define conc4t(a,b) a##b ///- #define conc4t(a,b) a##b ///-
#define macro(name) concat(name, __LINE__) #define macro(name) concat(name, __LINE__)
#define unique(name) concat(concat(name, L##__LINE__), __COUNTER__) #define unique(name) concat(concat(concat(name,concat(_L,__LINE__)),_),__COUNTER__)
#define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1)) #define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1))
#define scope(end) defer((void)0, end) #define scope(end) defer((void)0, end)
#define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 )) #define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 ))
@ -292,8 +292,8 @@ extern "C" {
#define ASSERT(expr, ...) (void)0 #define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0 #define ASSERT_ONCE(expr, ...) (void)0
#else #else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, breakpoint(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)); } } while(0) #define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#endif #endif
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L)
@ -372,6 +372,7 @@ extern "C" {
// note: based on code by Joe Lowe (public domain). // note: based on code by Joe Lowe (public domain).
// note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers // note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers
#define AUTORUN AUTORUN_( unique(fn) )
#ifdef __cplusplus #ifdef __cplusplus
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
static void fn(void); \ static void fn(void); \
@ -395,8 +396,6 @@ extern "C" {
static void fn(void) static void fn(void)
#endif #endif
#define AUTORUN AUTORUN_( concat(concat(concat(fn_L,__LINE__),_),__COUNTER__) )
#if 0 // autorun demo #if 0 // autorun demo
void byebye(void) { puts("seen after main()"); } void byebye(void) { puts("seen after main()"); }
AUTORUN { puts("seen before main()"); } AUTORUN { puts("seen before main()"); }
@ -413,7 +412,7 @@ AUTORUN { puts("seen before main() too"); atexit( byebye ); }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// visibility // visibility
// win32 users would need to -DAPI=IMPORT/EXPORT as needed when using/building V4K as DLL. // win32 users would need to -DAPI=EXPORT/IMPORT as needed when building/using V4K as DLL.
#define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport))) #define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport)))
#define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport))) #define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport)))
@ -586,7 +585,7 @@ static __thread unsigned array_n_;
#define array_vlen_(t) ( vlen(t) - 0 ) #define array_vlen_(t) ( vlen(t) - 0 )
#define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) ) #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) )
#define array_free(t) array_clear(t) #define array_free(t) array_clear(t)
#else // new: with reserve support (bugs?) #else // new: with reserve support (@todo: check for bugs?)
#define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) ) #define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) )
#define array_clear(t) ( array_realloc_((t),0) ) // -1 #define array_clear(t) ( array_realloc_((t),0) ) // -1
#define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1 #define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1
@ -633,7 +632,7 @@ static __thread unsigned array_n_;
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_erase_fast(t, i) do { /*may alter ordering*/ \ #define array_erase_fast(t, i) do { /*alters ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
@ -955,9 +954,9 @@ API void (map_clear)(map* m);
// Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense). // Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense).
#define C_EPSILON (1e-6) #define C_EPSILON (1e-6)
#define C_PI (3.141592654f) // (3.14159265358979323846f) #define C_PI (3.14159265358979323846f) // (3.141592654f)
#define TO_RAD (C_PI/180.f) #define TO_RAD (C_PI/180)
#define TO_DEG (180.f/C_PI) #define TO_DEG (180/C_PI)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -989,7 +988,6 @@ API void randset(uint64_t state);
API uint64_t rand64(void); API uint64_t rand64(void);
API double randf(void); // [0, 1) interval API double randf(void); // [0, 1) interval
API int randi(int mini, int maxi); // [mini, maxi) interval API int randi(int mini, int maxi); // [mini, maxi) interval
//API double rng(void); // [0..1) Lehmer RNG "minimal standard"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -1055,10 +1053,10 @@ enum EASE_FLAGS {
EASE_OUT = 0, EASE_OUT = 0,
}; };
API float ease(float t01, unsigned mode); // 0=linear,1=out_sine...31=inout_perlin API float ease(float t01, unsigned fn); // / 0-to-1
API float ease_pong(float t01, unsigned fn); // \ 1-to-0
API float ease_ping_pong(float t, float(*fn1)(float), float(*fn2)(float)); API float ease_ping_pong(float t, unsigned fn1, unsigned fn2); // /\ 0-to-1-to-0
API float ease_pong_ping(float t, float(*fn1)(float), float(*fn2)(float)); API float ease_pong_ping(float t, unsigned fn1, unsigned fn2); // \/ 1-to-0-to-1
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -2047,6 +2045,64 @@ bool id_valid(uintptr_t id);
#line 0 #line 0
#line 1 "engine/split/v4k_pack.h" #line 1 "engine/split/v4k_pack.h"
// -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal)
// - rlyeh, public domain.
//
// - single octal byte that represents semantic versioning (major.minor.patch).
// - allowed range [0000..0377] ( <-> [0..255] decimal )
// - comparison checks only major.minor tuple as per convention.
API int semver( int major, int minor, int patch );
API int semvercmp( int v1, int v2 );
#define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch))
#define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110))
#define SEMVERFMT "%03o"
// -----------------------------------------------------------------------------
// storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations
typedef struct byte2 { uint8_t x,y; } byte2;
typedef struct byte3 { uint8_t x,y,z; } byte3;
typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2;
typedef struct int3 { int x,y,z; } int3;
typedef struct int4 { int x,y,z,w; } int4;
typedef struct uint2 { unsigned int x,y; } uint2;
typedef struct uint3 { unsigned int x,y,z; } uint3;
typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2;
typedef struct float3 { float x,y,z; } float3;
typedef struct float4 { float x,y,z,w; } float4;
typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) )
#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) )
#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) )
#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) )
#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) )
#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// compile-time fourcc, eightcc // compile-time fourcc, eightcc
@ -2075,16 +2131,25 @@ enum {
#define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g) #define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// float conversion (text) // text conversions
API char* ftoa1(float v);
API char* ftoa2(vec2 v);
API char* ftoa3(vec3 v);
API char* ftoa4(vec4 v);
API float atof1(const char *s);
API vec2 atof2(const char *s); API vec2 atof2(const char *s);
API vec3 atof3(const char *s); API vec3 atof3(const char *s);
API vec4 atof4(const char *s); API vec4 atof4(const char *s);
API char* ftoa(float f); API char* itoa1(int v);
API char* ftoa2(vec2 v); API char* itoa2(vec2i v);
API char* ftoa3(vec3 v); API char* itoa3(vec3i v);
API char* ftoa4(vec4 v);
API int atoi1(const char *s);
API vec2i atoi2(const char *s);
API vec3i atoi3(const char *s);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// endianness // endianness
@ -2579,63 +2644,312 @@ API int64_t client_join(const char *ip, int port);
#line 0 #line 0
#line 1 "engine/split/v4k_obj.h" #line 1 "engine/split/v4k_obj.h"
// ----------------------------------------------------------------------------- // C objects framework
// semantic versioning in a single byte (octal)
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// - single octal byte that represents semantic versioning (major.minor.patch). // ## object limitations
// - allowed range [0000..0377] ( <-> [0..255] decimal ) // - 8-byte overhead per object
// - comparison checks only major.minor tuple as per convention. // - XX-byte overhead per object-entity
// - 32 components max per object-entity
// - 256 classes max per game
// - 256 references max per object
// - 1024K bytes max per object
// - 8 generations + 64K IDs per running instance (19-bit IDs)
// - support for pragma pack(1) structs not enabled by default.
API int semver( int major, int minor, int patch ); /* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */
API int semvercmp( int v1, int v2 ); #ifndef OBJ_MIN_PRAGMAPACK_BITS
//#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 7<<3, so 1024 bytes max per class (default)
#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 7<<1, so 256 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 7<<0, so 128 bytes max per class
#endif
#define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch)) #define OBJHEADER \
#define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110)) union { \
#define SEMVERFMT "%03o" uintptr_t objheader; \
struct { \
uintptr_t objtype:8; \
uintptr_t objheap:1; \
uintptr_t objsizew:7; \
uintptr_t objrefs:8; \
uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \
uintptr_t objnameid:16; \
uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \
uintptr_t objunused:64-8-7-1-1-8-16-ID_INDEX_BITS-ID_COUNT_BITS; /*4*/ \
}; \
};
// ----------------------------------------------------------------------------- #define OBJ \
// storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations struct { OBJHEADER };
typedef struct byte2 { uint8_t x,y; } byte2; // ----------------------------------------------------------------------------
typedef struct byte3 { uint8_t x,y,z; } byte3; // syntax sugars
typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2; #ifdef OBJTYPE
typedef struct int3 { int x,y,z; } int3; #undef OBJTYPE
typedef struct int4 { int x,y,z,w; } int4; #endif
typedef struct uint2 { unsigned int x,y; } uint2; #define OBJTYPE(T) \
typedef struct uint3 { unsigned int x,y,z; } uint3; OBJTYPE_##T
typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2; #define OBJTYPEDEF(NAME,N) \
typedef struct float3 { float x,y,z; } float3; enum { OBJTYPE(NAME) = N }; \
typedef struct float4 { float x,y,z,w; } float4; STATIC_ASSERT( N <= 255 ); \
STATIC_ASSERT( (sizeof(NAME) & ((1<<OBJ_MIN_PRAGMAPACK_BITS)-1)) == 0 );
typedef struct double2 { double x,y; } double2; // ----------------------------------------------------------------------------
typedef struct double3 { double x,y,z; } double3; // objects
typedef struct double4 { double x,y,z,w; } double4;
#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) ) #define TYPEDEF_STRUCT(NAME,N,...) \
#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) ) typedef struct NAME { OBJ \
#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) ) __VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) ) // TYPEDEF_STRUCT(obj,0);
#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) ) typedef struct obj { OBJ } obj;
#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) ) // ----------------------------------------------------------------------------
#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) ) // entities
#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) ) #define OBJCOMPONENTS_MAX 32
#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) ) #define OBJCOMPONENTS_ALL_ENABLED 0xAAAAAAAAAAAAAAAAULL
#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) ) #define OBJCOMPONENTS_ALL_FLAGGED 0x5555555555555555ULL
#define COMPONENTS_ONLY(x) ((x) & ~OBJCOMPONENTS_ALL_FLAGGED)
#define ENTITY \
struct { OBJHEADER union { struct { uintptr_t objenabled:OBJCOMPONENTS_MAX, objflagged:OBJCOMPONENTS_MAX; }; uintptr_t cflags; }; void *c[OBJCOMPONENTS_MAX]; };
#define TYPEDEF_ENTITY(NAME,N,...) \
typedef struct NAME { ENTITY \
__VA_ARGS__ \
char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N);
// OBJTYPEDEF(entity,1)
typedef struct entity { ENTITY } entity;
// ----------------------------------------------------------------------------
// heap/stack ctor/dtor
static __thread obj *objtmp;
#define OBJ_CTOR_HDR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE) ( \
(PTR)->objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \
(PTR)->objnameid = (OBJ_NAMEID), \
(PTR)->objtype = (OBJ_TYPE), \
(PTR)->objheap = (HEAP), \
(PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS))
#define OBJ_CTOR_PTR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE) ( \
OBJ_CTOR_HDR(PTR,HEAP,OBJ_NAMEID,SIZEOF_OBJ,OBJ_TYPE), \
obj_ctor(PTR))
#define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \
objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \
*(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \
((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \
( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \
OBJ_CTOR_PTR(objtmp, HEAP,intern(NAME),sizeof(TYPE),OBJTYPE(TYPE)), \
ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \
objtmp)
#define obj(TYPE, ...) obj_ext(TYPE, #TYPE, __VA_ARGS__)
#define obj_ext(TYPE, NAME, ...) *OBJ_CTOR(TYPE, NAME, 0, sizeof(array(obj*)), __VA_ARGS__)
#define obj_new(TYPE, ...) obj_new_ext(TYPE, #TYPE, __VA_ARGS__)
#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__)
void* obj_malloc(unsigned sz);
void* obj_free(void *o);
// ----------------------------------------------------------------------------
// obj generics. can be extended.
#define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__)
#define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__)
#define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__)
#define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__)
#define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__)
#define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__)
#define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__)
#define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__)
#define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__)
#define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__)
#define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__)
// --- syntax sugars
#define obj_extend(T,func) (obj_##func[OBJTYPE(T)] = (void*)T##_##func)
#define obj_method(method,o,...) (obj_##method[((obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_vtable(func,RC,...) RC macro(obj_##func)(){ __VA_ARGS__ }; RC (*obj_##func[256])() = { REPEAT256(macro(obj_##func)) };
#define obj_vtable_null(func,RC) RC (*obj_##func[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed
#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f
#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f)
#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f)
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
API extern void (*obj_dtor[256])(); ///-
API extern char* (*obj_save[256])(); ///-
API extern bool (*obj_load[256])(); ///-
API extern int (*obj_test[256])(); ///-
API extern int (*obj_init[256])(); ///-
API extern int (*obj_quit[256])(); ///-
API extern int (*obj_tick[256])(); ///-
API extern int (*obj_draw[256])(); ///-
API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
// ----------------------------------------------------------------------------
// core
API uintptr_t obj_header(const void *o);
API uintptr_t obj_id(const void *o);
API const char* obj_name(const void *o);
API unsigned obj_typeid(const void *o);
API const char* obj_type(const void *o);
API int obj_sizeof(const void *o);
API int obj_size(const void *o); // size of all members together in struct. may include padding bytes.
API char* obj_data(void *o); // pointer to the first member in struct
API const char* obj_datac(const void *o); // const pointer to the first struct member
API void* obj_payload(const void *o); // pointer right after last member in struct
API void* obj_zero(void *o); // reset all object members
// ----------------------------------------------------------------------------
// refcounting
API void* obj_ref(void *oo);
API void* obj_unref(void *oo);
// ----------------------------------------------------------------------------
// scene tree
// non-recursive
#define each_objchild(p,t,o) \
(array(obj*)* children = obj_children(p); children; children = 0) \
for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \
for(t *o = (t *)((*children)[_i]); o && 0[*children]; o = 0)
API obj* obj_detach(void *c);
API obj* obj_attach(void *o, void *c);
API obj* obj_root(const void *o);
API obj* obj_parent(const void *o);
API array(obj*)*obj_children(const void *o);
API array(obj*)*obj_siblings(const void *o);
API int obj_dumptree(const void *o);
// ----------------------------------------------------------------------------
// metadata
API const char* obj_metaset(const void *o, const char *key, const char *value);
API const char* obj_metaget(const void *o, const char *key);
// ----------------------------------------------------------------------------
// stl
API void* obj_swap(void *dst, void *src);
API void* obj_copy_fast(void *dst, const void *src);
API void* obj_copy(void *dst, const void *src);
API int obj_comp_fast(const void *a, const void *b);
API int obj_comp(const void *a, const void *b);
API int obj_lesser(const void *a, const void *b);
API int obj_greater(const void *a, const void *b);
API int obj_equal(const void *a, const void *b);
API uint64_t obj_hash(const void *o);
// ----------------------------------------------------------------------------
// debug
API bool obj_hexdump(const void *oo);
API int obj_print(const void *o);
API int obj_printf(const void *o, const char *text);
API int obj_console(const void *o); // obj_output() ?
#define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__))
// ----------------------------------------------------------------------------
// serialization
API char* obj_saveini(const void *o);
API obj* obj_mergeini(void *o, const char *ini);
API obj* obj_loadini(void *o, const char *ini);
API char* obj_savejson(const void *o);
API obj* obj_mergejson(void *o, const char *json);
API obj* obj_loadjson(void *o, const char *json);
API char* obj_savebin(const void *o);
API obj* obj_mergebin(void *o, const char *sav);
API obj* obj_loadbin(void *o, const char *sav);
API char* obj_savempack(const void *o); // @todo
API obj* obj_mergempack(void *o, const char *sav); // @todo
API obj* obj_loadmpack(void *o, const char *sav); // @todo
API int obj_push(const void *o);
API int obj_pop(void *o);
// ----------------------------------------------------------------------------
// components
API bool obj_addcomponent(void *object, unsigned c, void *ptr);
API bool obj_hascomponent(void *object, unsigned c);
API void* obj_getcomponent(void *object, unsigned c);
API bool obj_delcomponent(void *object, unsigned c);
API bool obj_usecomponent(void *object, unsigned c);
API bool obj_offcomponent(void *object, unsigned c);
API char* entity_save(entity *self);
// ----------------------------------------------------------------------------
// reflection
#define each_objmember(oo,TYPE,NAME,PTR) \
(array(reflect_t) *found_ = members_find(quark(((obj*)oo)->objnameid)); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \
for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \
for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 )
API void* obj_clone(const void *src);
API void* obj_merge(void *dst, const void *src); // @testme
API void* obj_mutate(void **dst, const void *src);
API void* obj_make(const char *str);
// built-ins
typedef enum OBJTYPE_BUILTINS {
OBJTYPE_obj = 0,
OBJTYPE_entity = 1,
OBJTYPE_vec2 = 2,
OBJTYPE_vec3 = 3,
OBJTYPE_vec4 = 4,
OBJTYPE_quat = 5,
OBJTYPE_mat33 = 6,
OBJTYPE_mat34 = 7,
OBJTYPE_mat44 = 8,
OBJTYPE_vec2i = 9,
OBJTYPE_vec3i = 10,
} OBJTYPE_BUILTINS;
#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
#line 0 #line 0
#line 1 "engine/split/v4k_profile.h" #line 1 "engine/split/v4k_profile.h"
@ -2716,14 +3030,14 @@ API void * function_find(const char *F);
API reflect_t member_find(const char *T, const char *M); /// find specific member API reflect_t member_find(const char *T, const char *M); /// find specific member
API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate
API array(reflect_t) members_find(const char *T); API array(reflect_t)* members_find(const char *T);
// iterate members in a struct // iterate members in a struct
#define each_member(T,R) \ #define each_member(T,R) \
(array(reflect_t)*found_ = map_find(members, intern(T)); found_; found_ = 0) \ (array(reflect_t) *found_ = members_find(T); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = (*found_)+it_; R; R = 0 ) for(reflect_t *R = &(*found_)[it_]; R; R = 0 )
// private api, still exposed // private api, still exposed
@ -2756,7 +3070,7 @@ API unsigned rgba( uint8_t r, uint8_t g, uint8_t b, uint8_t a );
API unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a ); API unsigned bgra( uint8_t b, uint8_t g, uint8_t r, uint8_t a );
API unsigned rgbaf( float r, float g, float b, float a ); API unsigned rgbaf( float r, float g, float b, float a );
API unsigned bgraf( float b, float g, float r, float a ); API unsigned bgraf( float b, float g, float r, float a );
API float alpha( unsigned rgba ); API unsigned alpha( unsigned rgba );
#define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) ) #define RGBX(rgb,x) ( ((rgb)&0xFFFFFF) | (((unsigned)(x))<<24) )
#define RGB3(r,g,b) ( (255<<24) | ((r)<<16) | ((g)<<8) | (b) ) #define RGB3(r,g,b) ( (255<<24) | ((r)<<16) | ((g)<<8) | (b) )
@ -3742,16 +4056,16 @@ API array(uint32_t) string32( const char *utf8 ); /// convert from utf8 to utf32
// ## string interning (quarks) // ## string interning (quarks)
// - rlyeh, public domain. // - rlyeh, public domain.
unsigned intern( const char *string ); API unsigned intern( const char *string );
const char *quark( unsigned key ); API const char *quark( unsigned key );
typedef struct quarks_db { typedef struct quarks_db {
array(char) blob; array(char) blob;
array(vec2i) entries; array(vec2i) entries;
} quarks_db; } quarks_db;
unsigned quark_intern( quarks_db*, const char *string ); API unsigned quark_intern( quarks_db*, const char *string );
const char *quark_string( quarks_db*, unsigned key ); API const char *quark_string( quarks_db*, unsigned key );
#line 0 #line 0
#line 1 "engine/split/v4k_time.h" #line 1 "engine/split/v4k_time.h"
@ -3781,7 +4095,7 @@ API void timer_destroy(unsigned timer_handle);
// //
// also similar to a mongo object id, 12 bytes as follows: // also similar to a mongo object id, 12 bytes as follows:
// - 4-byte timestamp (ss). epoch: Tuesday, 12 September 2023 6:06:56 // - 4-byte timestamp (ss). epoch: Tuesday, 12 September 2023 6:06:56
// - 2-byte (machine or app hash) // - 2-byte (machine, hash or app id)
// - 2-byte (thread-id) // - 2-byte (thread-id)
// - 4-byte (rand counter, that gets increased at every id creation) // - 4-byte (rand counter, that gets increased at every id creation)
@ -3853,7 +4167,7 @@ API void die(const char *message);
API void alert(const char *message); API void alert(const char *message);
API void hexdump( const void *ptr, unsigned len ); API void hexdump( const void *ptr, unsigned len );
API void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width ); API void hexdumpf( FILE *fp, const void *ptr, unsigned len, int width );
API void breakpoint(const char *optional_reason); API void breakpoint();
API bool has_debugger(); API bool has_debugger();
API void trap_install(void); API void trap_install(void);