sync fwk
parent
25224c6db1
commit
2fddd84946
2
_mirror
2
_mirror
|
@ -1 +1 @@
|
||||||
Subproject commit e838bef9bea402b1fa3ecb66b74addcb4256b687
|
Subproject commit f7cf64ed703b21981c5c5e600bd55c43e0b9e66e
|
189
bind/v4k.lua
189
bind/v4k.lua
|
@ -1143,15 +1143,6 @@ 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 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] vec3: macro name but used as C declaration in:API vec3 atof3(const char *s);
|
|
||||||
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC vec3 atof3(const char *s);
|
|
||||||
//lcpp INF [0000] vec3: macro name but used as C declaration in: vec3 atof3(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: 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] 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:STATIC char* ftoa2(vec2 v);
|
||||||
//lcpp INF [0000] vec2: macro name but used as C declaration in: char* ftoa2(vec2 v);
|
//lcpp INF [0000] vec2: macro name but used as C declaration in: char* ftoa2(vec2 v);
|
||||||
|
@ -1161,6 +1152,27 @@ ffi.cdef([[
|
||||||
//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: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:STATIC char* ftoa4(vec4 v);
|
||||||
//lcpp INF [0000] vec4: macro name but used as C declaration in: 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: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] vec3: macro name but used as C declaration in:API vec3 atof3(const char *s);
|
||||||
|
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC vec3 atof3(const char *s);
|
||||||
|
//lcpp INF [0000] vec3: macro name but used as C declaration in: vec3 atof3(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: vec4 atof4(const char *s);
|
||||||
|
//lcpp INF [0000] vec2i: macro name but used as C declaration in:API char* itoa2(vec2i v);
|
||||||
|
//lcpp INF [0000] vec2i: macro name but used as C declaration in:STATIC char* itoa2(vec2i v);
|
||||||
|
//lcpp INF [0000] vec2i: macro name but used as C declaration in: char* itoa2(vec2i v);
|
||||||
|
//lcpp INF [0000] vec3i: macro name but used as C declaration in:API char* itoa3(vec3i v);
|
||||||
|
//lcpp INF [0000] vec3i: macro name but used as C declaration in:STATIC char* itoa3(vec3i v);
|
||||||
|
//lcpp INF [0000] vec3i: macro name but used as C declaration in: char* itoa3(vec3i v);
|
||||||
|
//lcpp INF [0000] vec2i: macro name but used as C declaration in:API vec2i atoi2(const char *s);
|
||||||
|
//lcpp INF [0000] vec2i: macro name but used as C declaration in:STATIC vec2i atoi2(const char *s);
|
||||||
|
//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,
|
||||||
};
|
};
|
||||||
vec2 atof2(const char *s);
|
char* ftoa1(float v);
|
||||||
vec3 atof3(const char *s);
|
|
||||||
vec4 atof4(const char *s);
|
|
||||||
char* ftoa(float f);
|
|
||||||
char* ftoa2(vec2 v);
|
char* ftoa2(vec2 v);
|
||||||
char* ftoa3(vec3 v);
|
char* ftoa3(vec3 v);
|
||||||
char* ftoa4(vec4 v);
|
char* ftoa4(vec4 v);
|
||||||
|
float atof1(const char *s);
|
||||||
|
vec2 atof2(const char *s);
|
||||||
|
vec3 atof3(const char *s);
|
||||||
|
vec4 atof4(const char *s);
|
||||||
|
char* itoa1(int v);
|
||||||
|
char* itoa2(vec2i v);
|
||||||
|
char* itoa3(vec3i 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
2
depot
|
@ -1 +1 @@
|
||||||
Subproject commit 80c739fc0ce8381e2200f347654b23b646f12fba
|
Subproject commit ea89db8ecd2b32fca2a21f67f486601de5c6a93c
|
1988
engine/joint/v4k.h
1988
engine/joint/v4k.h
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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" );
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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) )
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) )
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
502
engine/v4k
502
engine/v4k
|
@ -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
|
||||||
|
|
1026
engine/v4k.c
1026
engine/v4k.c
File diff suppressed because it is too large
Load Diff
460
engine/v4k.h
460
engine/v4k.h
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue