v4k-git-backup/tools/labs/objtests.h

390 lines
9.8 KiB
C

AUTOTEST {
test_obj_core();
}
// ----------------------------------------------------------------------------
typedef struct orc { OBJ
char name[8];
} orc;
//#pragma pack(push, 1)
typedef struct boy { OBJ
char name[8];
float hp;
} boy;
//#pragma pack(pop)
OBJTYPEDEF(orc,100)
int orc_ctor(orc* self) { strcpy(self->name, "orc!"); printf("i'm orc %p\n", self); return 0; }
int orc_tick(orc* self) { printf("%p orc tick\n", self); return 0; }
char* orc_save(orc *self) { return obj_saveini(self); } // PACKMSG("ss", "orc_v1", self->name); }
OBJTYPEDEF(boy,101)
int boy_ctor(boy* self) { strcpy(self->name, "boy!"); printf("i'm boy %p\n", self); self->hp = 0x80; return 0; }
int boy_tick(boy* self) { printf("%p boy tick, hp:%f\n", self, self->hp); return 0; }
char* boy_save(boy *self) { return obj_saveini(self); } // PACKMSG("ssf", "boy_v1", self->name, self->hp); }
AUTOTEST {
EXTEND(orc, ctor,tick,save);
EXTEND(boy, ctor,tick,save);
// instance gameobjs
boy *obj1 = obj_new(boy, "boy", 123);
orc *obj2 = obj_new(orc, "orc");
orc *obj3 = obj_new(orc, "orc");
printf("%p\n", obj_datac(obj1));
printf("%d vs %d vs %d\n", (int)sizeof(boy), obj_sizeof(obj1), obj_size(obj1));
// generics
obj_tick(obj1);
obj_tick(obj2);
obj_tick(obj3);
obj_hexdump(obj1);
obj_free(obj1); // will free
obj_ref(obj2);
obj_unref(obj2); // will free
obj_ref(obj3);
obj_free(obj3); // will do nothing
obj_unref(obj3); // will free
// make a dangling reference. this will be printed at end of program.
static int dangling;
obj1 = obj_new(boy, "boy", 123);
obj_ref(obj1);
}
// --- scene
AUTOTEST {
test_obj_scene();
}
// --- comps
struct WorldTravellerComponent {
unsigned world_source;
unsigned world_target;
};
struct TransformComponent {
vec3 position;
quat rotation;
vec3 scale;
};
struct VelocityComponent {
float speed;
};
struct LookComponent {
float sensitivity; // _and_polarity;
vec2 rotation;
};
struct PhysicsComponent {
float gravity;
vec3 velocity;
vec3 acceleration;
vec3 rotationVelocity;
vec3 rotationAcceleration;
};
struct RenderComponent {
aabb box;
mesh_t mesh;
texture_t texture;
};
AUTOTEST {
test_obj_ecs();
}
// generics
// --- example: new class
// declare new object
TYPEDEF_STRUCT(box,102,
int x,y,w,h;
);
// /* same as: */
// typedef struct box { OBJ
// int x,y,w,h;
// } box;
// OBJTYPEDEF(box,102)
// implement a few built-in interfaces
#define box(...) obj(box, __VA_ARGS__)
char* box_save(const box *b) { return obj_saveini(b); } // PACKMSG("siiii", "box_v1", b->x, b->y, b->w, b->h); }
bool box_load(box *b, const char* s) { return !!obj_loadini(b, s); } // char *header; return UNPACKMSG(s, "siiii", &header, &b->x, &b->y, &b->w, &b->h) && !strcmp(header, "box_v1"); }
int box_test(box *b) { return b->w > 0 && b->h > 0; }
void box_dtor(box *b) { puts("bye box!"); }
// create a new obj interface (not only for box! valid for every other obj that would extend on this)
obj_vtable(area, float, { return 0; });
#define obj_area(o,...) obj_method(area, o, ##__VA_ARGS__)
// implement area interface for box object
float box_area(box *b) { return b->w * b->h; }
AUTOTEST {
// reflect
STRUCT(box,int,x);
STRUCT(box,int,y);
STRUCT(box,int,w);
STRUCT(box,int,h);
// extend
obj_extend(box,save);
obj_extend(box,load);
obj_extend(box,test);
obj_extend(box,dtor);
obj_extend(box,area);
// -- example
box b = box(0,0,2,3);
box *c = obj_new(box, 1,1,3,4);
test( obj_test(&b) );
test( obj_test(c) );
test( obj_area(&b) == 6 );
test( obj_area(c) == 12 );
// serialization tests
test_obj_serialization(&b, c);
test_obj_similarity(&b, c);
char *sav = obj_save(c);
obj_load(&b, sav);
// obj_load(&b, obj_save(c)); // @fixme: this expression in mingw
test_obj_equality(&b, c);
}
// --- reflection
typedef struct MyVec3 { OBJ
float x,y,z;
} MyVec3;
OBJTYPEDEF(MyVec3,77)
typedef struct MyTransform {
MyVec3 location; ///R @todo: ideally, we would want self-reflection to inscribe these members
MyVec3 rotation; ///R @todo: ideally, we would want self-reflection to inscribe these members
float scale; ///R @todo: ideally, we would want self-reflection to inscribe these members
} MyTransform;
/*
// @todo: which is technically like doing
AUTORUN {
STRUCT(MyTransform, MyVec3, location);
STRUCT(MyTransform, MyVec3, rotation);
STRUCT(MyTransform, float, scale);
}
*/
OBJTYPEDEF(MyTransform,78);
typedef struct MyObject { OBJ
char *id;
int spawnx,spawny;
float time;
struct MyObject *next;
MyTransform tr;
} MyObject;
OBJTYPEDEF(MyObject,79);
AUTOTEST {
STRUCT( MyVec3, float, x, "Right" );
STRUCT( MyVec3, float, y, "Forward" );
STRUCT( MyVec3, float, z, "Up" );
STRUCT( MyTransform, MyVec3, location, "World location (absolute)" );
STRUCT( MyTransform, MyVec3, rotation, "Local rotation (in degrees)" );
STRUCT( MyTransform, float, scale, "Local scale (in centimeters)" );
STRUCT( MyObject, int, spawnx, "Actor Spawn X" );
STRUCT( MyObject, int, spawny, "Actor Spawn Y" );
STRUCT( MyObject, string, id, "Actor name" );
STRUCT( MyObject, MyTransform, tr, "Actor transform" );
STRUCT( MyObject, float, time, "Actor time" );
STRUCT( MyObject, MyObject *, next, "Next actor in seq" );
// reflect_print("MyVec3");
// reflect_print("MyTransform");
// reflect_print("MyObject");
// construct a type from a reflected struct
MyVec3 *o = obj_new(MyVec3, 1,2,-3);
test( 12 == obj_size(o) );
MyVec3 *o2 = obj_make("[MyVec3]\nfloat.y=2\nfloat.x=1\nfloat.z=-3");
test( !obj_comp(o,o2) ) || obj_hexdump(o), obj_hexdump(o2);
for each_objmember(o,type,name,ptr) {
/**/ if( !strcmp(type, "float") ) printf("%s %s = %f\n", type, name, *(float*)ptr );
else if( !strcmp(type, "double") ) printf("%s %s = %f\n", type, name, *(double*)ptr );
}
test_obj_console(o);
test_obj_console(o2);
// Setup objects
MyObject *root = obj_make("[MyObject]");
obj_hexdump(root);
MyObject *oo = obj_make("[MyObject]\nid=\"An identifier!\"\nx=123\ny=256\nrotation=90\nnext=root\n");
obj_hexdump(oo);
// Dump contents of our objects
obj_print(oo);
puts("---");
obj_hexdump(oo);
puts("---");
// Save to mem
char *sav = obj_savebin(oo);
test( sav && strlen(sav) > 0 );
// Clear
obj_zero(oo);
obj_hexdump(oo);
puts("---");
// Reload
obj_loadbin(oo, sav);
obj_hexdump(oo);
}
// --- Benchmarks for call overhead.
AUTOTEST {
// Here, we're using a blank ctor call as a method to test/stress call overhead.
//
// results (old i5-4300/1.90Ghz laptop):
// v1: 427 million calls/s. compiled with "cl /Ox /Os /MT /DNDEBUG /GL /GF /arch:AVX2"
// v2: 450 million calls/s. compiled with "cl /Ox /O2 /MT /DNDEBUG /GF /arch:AVX2"
double t;
enum { N = 100000000 };
t = -time_ss();
MyVec3 o = obj(MyVec3, 1,2,3); obj_setname(&o, "MyVec3");
for( unsigned i = 0; i < N; ++i ) {
obj_ctor(&o);
}
t += time_ss();
printf("Benchmark: %5.2f objcalls/s %5.2fM objcalls/s\n", N/(t), (N/1000)/(t*1000)); // ((N+N)*5) / (t) );
t = -time_ss();
MyVec3 *op = obj_new(MyVec3, 1,2,3);
for( unsigned i = 0; i < N; ++i ) {
obj_ctor(op);
}
t += time_ss();
printf("Benchmark: %5.2f objcalls/s %5.2fM objcalls/s\n", N/(t), (N/1000)/(t*1000)); // ((N+N)*5) / (t) );
}
// --- metas
AUTOTEST {
box b = box(1,2,3,4);
test( !strcmp("box", obj_type(&b)) );
test( !strcmp("box", obj_name(&b)) );
b = box(1,2,3,4);
obj_setname(&b, "MyBox1");
test( !strcmp("box", obj_type(&b)) );
test( !strcmp("MyBox1", obj_name(&b)) );
test_obj_metadatas(&b);
obj_free(&b);
}
TYPEDEF_STRUCT(test_vec3_serial, __COUNTER__,
vec3 position;
vec3 accel;
);
AUTOTEST {
STRUCT(test_vec3_serial, vec3, position);
STRUCT(test_vec3_serial, vec3, accel);
test_vec3_serial v = obj(test_vec3_serial, {1,2,3},{4,5,6}), z = obj(test_vec3_serial);
test(obj_comp(&v,&z) != 0) || obj_print(&v) & obj_print(&z);
obj_loadini(&z, obj_saveini(&v));
test(obj_comp(&v,&z) == 0) || obj_print(&z);
}
TYPEDEF_STRUCT(MyObject2, __COUNTER__,
const char* id;
int x,y;
float rotation;
struct MyObject2 *next;
);
AUTORUN {
STRUCT(MyObject2, const char *, id);
STRUCT(MyObject2, int, x);
STRUCT(MyObject2, int, y);
STRUCT(MyObject2, float, rotation);
STRUCT(MyObject2, struct MyObject2*, next);
// Construct two objects
MyObject2 *root = obj_new(MyObject2);
MyObject2 *o = obj_new(MyObject2, "An identifier!", 0x11, 0x22, 3.1415f, root );
// Copy tests
{
printf("%d vs %d vs %d\n", (int)sizeof(MyObject2), obj_size(o), (int)sizeof(obj) + obj_size(o) + (int)sizeof(array(void*)));
MyObject2 *clone = obj_clone(o);
test(obj_comp(clone,o) == 0) || obj_print(o) & obj_print(clone) & obj_hexdump(o) & obj_hexdump(clone);
test(obj_free(clone) == 0);
}
{
MyObject2 *copy = obj_new(MyObject2);
test(obj_copy(copy, o));
test(obj_comp(copy,o)==0) || obj_print(copy);
test(obj_free(copy) == 0);
}
{
MyObject2 *copy = obj_new(MyObject2, "A different identifier!", 0x33, 0x44, 0.0f, root );
test(obj_copy(copy, o));
test(obj_comp(copy,o)==0) || obj_print(copy);
test(obj_free(copy) == 0);
}
{
void *copy = obj_malloc(100); // untyped class
obj_mutate(copy, o);
obj_print(copy);
obj_copy(copy, o);
obj_print(copy);
obj_free(copy);
}
}