This commit is contained in:
John Alanbrook 2023-12-11 14:36:45 +00:00
parent 5ad3219379
commit 9fb36f5df3
17 changed files with 580 additions and 407 deletions

View file

@ -141,8 +141,7 @@ var gameobject = {
this.set_worldpos(this.level.this2world(x)); this.set_worldpos(this.level.this2world(x));
}, },
get pos() { return cmd get pos() {
if (!this.level) return this.worldpos(); if (!this.level) return this.worldpos();
return this.level.world2this(this.worldpos()); return this.level.world2this(this.worldpos());
}, },
@ -238,7 +237,8 @@ var gameobject = {
this.level?.remove_obj(this); this.level?.remove_obj(this);
this.level = parent; this.level = parent;
cmd(208,parent,this);
cmd(208,parent.body,this.body);
function unique_name(list, obj) { function unique_name(list, obj) {
var str = obj.toString().replaceAll('.', '_'); var str = obj.toString().replaceAll('.', '_');
@ -310,13 +310,9 @@ var gameobject = {
return bb.t-bb.b; return bb.t-bb.b;
}, },
move(vec) { move(vec) { this.pos = this.pos.add(vec); },
this.pos = this.pos.add(vec);
},
rotate(amt) { rotate(amt) { this.angle += amt; },
this.angle += amt;
},
/* Make a unique object the same as its prototype */ /* Make a unique object the same as its prototype */
revert() { revert() {

View file

@ -33,9 +33,7 @@ static const float sensor_seg = 10;
unsigned int category_masks[32]; unsigned int category_masks[32];
void set_cat_mask(int cat, unsigned int mask) { void set_cat_mask(int cat, unsigned int mask) { category_masks[cat] = mask; }
category_masks[cat] = mask;
}
cpTransform m3_to_cpt(HMM_Mat3 m) cpTransform m3_to_cpt(HMM_Mat3 m)
{ {
@ -66,7 +64,7 @@ int sort_ids(int *a, int *b)
return 1; return 1;
} }
int *clean_ids(int *ids) gameobject *clean_ids(int *ids)
{ {
qsort(ids, sizeof(*ids), arrlen(ids), sort_ids); qsort(ids, sizeof(*ids), arrlen(ids), sort_ids);
@ -80,18 +78,16 @@ int *clean_ids(int *ids)
return ids; return ids;
} }
void querylist(cpShape *shape, cpContactPointSet *points, int *ids) { void querylist(cpShape *shape, cpContactPointSet *points, int *ids) { arrput(ids,shape2go(shape)); }
arrput(ids,shape2gameobject(shape));
}
typedef struct querybox { typedef struct querybox {
cpBB bb; cpBB bb;
int *ids; gameobject **ids;
} querybox; } querybox;
void querylistbodies(cpBody *body, querybox *qb) { void querylistbodies(cpBody *body, querybox *qb) {
if (cpBBContainsVect(qb->bb, cpBodyGetPosition(body))) if (cpBBContainsVect(qb->bb, cpBodyGetPosition(body)))
arrput(qb->ids,body2id(body)); arrput(qb->ids,body2go(body));
} }
/* Return all points from a list of points in the given boundingbox */ /* Return all points from a list of points in the given boundingbox */
@ -109,7 +105,7 @@ int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n)
} }
/* Return all gameobjects within the given box */ /* Return all gameobjects within the given box */
int *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) { gameobject *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) {
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f); cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
cpTransform T = {0}; cpTransform T = {0};
T.a = 1; T.a = 1;
@ -134,8 +130,8 @@ int *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) {
return clean_ids(ids); return clean_ids(ids);
} }
int *phys2d_query_shape(struct phys2d_shape *shape) { gameobject *phys2d_query_shape(struct phys2d_shape *shape) {
int *ids = NULL; gameobject **ids = NULL;
cpSpaceShapeQuery(space, shape->shape, querylist, ids); cpSpaceShapeQuery(space, shape->shape, querylist, ids);
return clean_ids(ids); return clean_ids(ids);
} }
@ -184,10 +180,10 @@ void phys2d_update(float deltaT) {
flush_collide_cbs(); flush_collide_cbs();
} }
void init_phys2dshape(struct phys2d_shape *shape, int go, void *data) { void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
shape->go = go; shape->go = go;
shape->data = data; shape->data = data;
go_shape_apply(id2go(go)->body, shape->shape, id2go(go)); go_shape_apply(go->body, shape->shape, go);
cpShapeSetCollisionType(shape->shape, go); cpShapeSetCollisionType(shape->shape, go);
cpShapeSetUserData(shape->shape, shape); cpShapeSetUserData(shape->shape, shape);
} }
@ -199,13 +195,13 @@ void phys2d_shape_del(struct phys2d_shape *shape) {
} }
/***************** CIRCLE2D *****************/ /***************** CIRCLE2D *****************/
struct phys2d_circle *Make2DCircle(int go) { struct phys2d_circle *Make2DCircle(gameobject *go) {
struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle)); struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle));
new->radius = 10.f; new->radius = 10.f;
new->offset = v2zero; new->offset = v2zero;
new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero)); new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(go->body, new->radius, cpvzero));
new->shape.debugdraw = phys2d_dbgdrawcircle; new->shape.debugdraw = phys2d_dbgdrawcircle;
new->shape.moi = phys2d_circle_moi; new->shape.moi = phys2d_circle_moi;
new->shape.apply = phys2d_applycircle; new->shape.apply = phys2d_applycircle;
@ -240,7 +236,7 @@ void phys2d_dbgdrawcircle(struct phys2d_circle *circle) {
} }
void phys2d_applycircle(struct phys2d_circle *circle) { void phys2d_applycircle(struct phys2d_circle *circle) {
struct gameobject *go = id2go(circle->shape.go); gameobject *go = circle->shape.go;
float radius = circle->radius * HMM_MAX(HMM_ABS(go->scale.X), HMM_ABS(go->scale.Y)); float radius = circle->radius * HMM_MAX(HMM_ABS(go->scale.X), HMM_ABS(go->scale.Y));
cpCircleShapeSetRadius(circle->shape.shape, radius); cpCircleShapeSetRadius(circle->shape.shape, radius);
@ -250,7 +246,7 @@ void phys2d_applycircle(struct phys2d_circle *circle) {
/************* BOX2D ************/ /************* BOX2D ************/
struct phys2d_box *Make2DBox(int go) { struct phys2d_box *Make2DBox(gameobject *go) {
struct phys2d_box *new = malloc(sizeof(struct phys2d_box)); struct phys2d_box *new = malloc(sizeof(struct phys2d_box));
new->t = (transform2d){ new->t = (transform2d){
.pos = {0,0}, .pos = {0,0},
@ -277,7 +273,7 @@ void phys2d_boxdel(struct phys2d_box *box) {
void phys2d_applybox(struct phys2d_box *box) { void phys2d_applybox(struct phys2d_box *box) {
phys2d_boxdel(box); phys2d_boxdel(box);
struct gameobject *go = id2go(box->shape.go); struct gameobject *go = box->shape.go;
cpTransform T = m3_to_cpt(transform2d2mat(box->t)); cpTransform T = m3_to_cpt(transform2d2mat(box->t));
cpVect verts[4] = {{-0.5, -0.5}, {0.5, -0.5}, {0.5, 0.5}, {-0.5, 0.5}}; cpVect verts[4] = {{-0.5, -0.5}, {0.5, -0.5}, {0.5, 0.5}, {-0.5, 0.5}};
box->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(go->body, 4, verts, T, box->r)); box->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(go->body, 4, verts, T, box->r));
@ -304,14 +300,14 @@ void phys2d_dbgdrawbox(struct phys2d_box *box) {
} }
/************** POLYGON ************/ /************** POLYGON ************/
struct phys2d_poly *Make2DPoly(int go) { struct phys2d_poly *Make2DPoly(gameobject *go) {
struct phys2d_poly *new = malloc(sizeof(struct phys2d_poly)); struct phys2d_poly *new = malloc(sizeof(struct phys2d_poly));
new->points = NULL; new->points = NULL;
arrsetlen(new->points, 0); arrsetlen(new->points, 0);
new->radius = 0.f; new->radius = 0.f;
new->shape.shape = cpSpaceAddShape(space, cpPolyShapeNewRaw(id2go(go)->body, 0, new->points, new->radius)); new->shape.shape = cpSpaceAddShape(space, cpPolyShapeNewRaw(go->body, 0, new->points, new->radius));
new->shape.debugdraw = phys2d_dbgdrawpoly; new->shape.debugdraw = phys2d_dbgdrawpoly;
new->shape.moi = phys2d_poly_moi; new->shape.moi = phys2d_poly_moi;
new->shape.apply = phys2d_applypoly; new->shape.apply = phys2d_applypoly;
@ -354,7 +350,7 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
void phys2d_applypoly(struct phys2d_poly *poly) { void phys2d_applypoly(struct phys2d_poly *poly) {
if (arrlen(poly->points) <= 0) return; if (arrlen(poly->points) <= 0) return;
struct gameobject *go = id2go(poly->shape.go); struct gameobject *go = poly->shape.go;
cpTransform T = m3_to_cpt(transform2d2mat(poly->t)); cpTransform T = m3_to_cpt(transform2d2mat(poly->t));
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T); cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
cpPolyShapeSetRadius(poly->shape.shape, poly->radius); cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
@ -379,7 +375,7 @@ void phys2d_dbgdrawpoly(struct phys2d_poly *poly) {
} }
/****************** EDGE 2D**************/ /****************** EDGE 2D**************/
struct phys2d_edge *Make2DEdge(int go) { struct phys2d_edge *Make2DEdge(gameobject *go) {
struct phys2d_edge *new = malloc(sizeof(struct phys2d_edge)); struct phys2d_edge *new = malloc(sizeof(struct phys2d_edge));
new->points = NULL; new->points = NULL;
arrsetlen(new->points, 0); arrsetlen(new->points, 0);
@ -414,7 +410,7 @@ void phys2d_edgedel(struct phys2d_edge *edge) {
void phys2d_edgeaddvert(struct phys2d_edge *edge) { void phys2d_edgeaddvert(struct phys2d_edge *edge) {
arrput(edge->points, v2zero); arrput(edge->points, v2zero);
if (arrlen(edge->points) > 1) if (arrlen(edge->points) > 1)
arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(id2go(edge->shape.go)->body, cpvzero, cpvzero, edge->thickness))); arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(edge->shape.go->body, cpvzero, cpvzero, edge->thickness)));
phys2d_applyedge(edge); phys2d_applyedge(edge);
} }
@ -466,7 +462,7 @@ void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts) {
} }
void phys2d_applyedge(struct phys2d_edge *edge) { void phys2d_applyedge(struct phys2d_edge *edge) {
struct gameobject *go = id2go(edge->shape.go); struct gameobject *go = edge->shape.go;
for (int i = 0; i < arrlen(edge->shapes); i++) { for (int i = 0; i < arrlen(edge->shapes); i++) {
/* Points must be scaled with gameobject, */ /* Points must be scaled with gameobject, */
@ -480,7 +476,7 @@ void phys2d_applyedge(struct phys2d_edge *edge) {
cpShapeSetUserData(edge->shapes[i], &edge->shape); cpShapeSetUserData(edge->shapes[i], &edge->shape);
} }
cpSpaceReindexShapesForBody(space, id2go(edge->shape.go)->body); cpSpaceReindexShapesForBody(space, edge->shape.go->body);
} }
void phys2d_dbgdrawedge(struct phys2d_edge *edge) { void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
@ -495,7 +491,7 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
if (arrlen(edge->shapes) < 1) return; if (arrlen(edge->shapes) < 1) return;
HMM_Vec2 drawpoints[arrlen(edge->points)]; HMM_Vec2 drawpoints[arrlen(edge->points)];
struct gameobject *go = id2go(edge->shape.go); struct gameobject *go = edge->shape.go;
HMM_Mat3 g2w = t_go2world(go); HMM_Mat3 g2w = t_go2world(go);
for (int i = 0; i < arrlen(edge->points); i++) for (int i = 0; i < arrlen(edge->points); i++)
@ -563,7 +559,7 @@ void flush_collide_cbs() {
arrsetlen(begins,0); arrsetlen(begins,0);
} }
void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, int hit, cpArbiter *arb) { void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, gameobject *hit, cpArbiter *arb) {
cpShape *shape1; cpShape *shape1;
cpShape *shape2; cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2); cpArbiterGetShapes(arb, &shape1, &shape2);
@ -579,7 +575,7 @@ void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, int hit, cpArbiter *arb) {
// JS_SetPropertyStr(js, obj, "pos", vec2js(srfv)); // JS_SetPropertyStr(js, obj, "pos", vec2js(srfv));
// JS_SetPropertyStr(js,obj,"depth", num2js(cpArbiterGetDepth(arb,0))); // JS_SetPropertyStr(js,obj,"depth", num2js(cpArbiterGetDepth(arb,0)));
JS_SetPropertyStr(js, obj, "id", JS_NewInt32(js,hit)); JS_SetPropertyStr(js, obj, "id", JS_NewInt32(js,hit));
JS_SetPropertyStr(js,obj,"obj", JS_DupValue(js,id2go(hit)->ref)); JS_SetPropertyStr(js,obj,"obj", JS_DupValue(js,hit->ref));
struct postphys_cb cb; struct postphys_cb cb;
cb.c = c; cb.c = c;
@ -594,11 +590,8 @@ static cpBool handle_collision(cpArbiter *arb, int type) {
cpBody *body1; cpBody *body1;
cpBody *body2; cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2); cpArbiterGetBodies(arb, &body1, &body2);
int g1 = (int)cpBodyGetUserData(body1); gameobject *go = cpBodyGetUserData(body1);
int g2 = (int)cpBodyGetUserData(body2); gameobject *go2 = cpBodyGetUserData(body2);
struct gameobject *go = id2go(g1);
struct gameobject *go2 = id2go(g2);
cpShape *shape1; cpShape *shape1;
cpShape *shape2; cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2); cpArbiterGetShapes(arb, &shape1, &shape2);
@ -612,16 +605,16 @@ static cpBool handle_collision(cpArbiter *arb, int type) {
case CTYPE_BEGIN: case CTYPE_BEGIN:
for (int i = 0; i < arrlen(go->shape_cbs); i++) for (int i = 0; i < arrlen(go->shape_cbs); i++)
if (go->shape_cbs[i].shape == pshape1) if (go->shape_cbs[i].shape == pshape1)
duk_call_phys_cb(norm1, go->shape_cbs[i].cbs.begin, g2, arb); duk_call_phys_cb(norm1, go->shape_cbs[i].cbs.begin, go2, arb);
if (JS_IsObject(go->cbs.begin.obj)) if (JS_IsObject(go->cbs.begin.obj))
duk_call_phys_cb(norm1, go->cbs.begin, g2, arb); duk_call_phys_cb(norm1, go->cbs.begin, go2, arb);
break; break;
case CTYPE_SEP: case CTYPE_SEP:
if (JS_IsObject(go->cbs.separate.obj)) if (JS_IsObject(go->cbs.separate.obj))
duk_call_phys_cb(norm1, go->cbs.separate, g2, arb); duk_call_phys_cb(norm1, go->cbs.separate, go2, arb);
break; break;
} }
@ -637,16 +630,16 @@ static cpBool script_phys_cb_separate(cpArbiter *arb, cpSpace *space, void *data
return handle_collision(arb, CTYPE_SEP); return handle_collision(arb, CTYPE_SEP);
} }
void phys2d_rm_go_handlers(int go) { void phys2d_rm_go_handlers(gameobject *go) {
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go); cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
handler->userData = NULL; handler->userData = NULL;
handler->beginFunc = NULL; handler->beginFunc = NULL;
handler->separateFunc = NULL; handler->separateFunc = NULL;
} }
void phys2d_setup_handlers(int go) { void phys2d_setup_handlers(gameobject *go) {
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go); cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
handler->userData = (void *)go; handler->userData = go;
handler->beginFunc = script_phys_cb_begin; handler->beginFunc = script_phys_cb_begin;
handler->separateFunc = script_phys_cb_separate; handler->separateFunc = script_phys_cb_separate;
} }

View file

@ -3,11 +3,10 @@
#include "script.h" #include "script.h"
#include <chipmunk/chipmunk.h> #include <chipmunk/chipmunk.h>
#include "gameobject.h"
#include "render.h" #include "render.h"
#include "transform.h" #include "transform.h"
struct gameobject;
extern float phys2d_gravity; extern float phys2d_gravity;
extern int physOn; extern int physOn;
extern cpSpace *space; extern cpSpace *space;
@ -24,7 +23,7 @@ extern struct rgba sleep_color;
struct phys2d_shape { struct phys2d_shape {
cpShape *shape; cpShape *shape;
transform2d t; transform2d t;
int go; gameobject *go;
void *data; /* The specific subtype; phys2d_circle, etc */ void *data; /* The specific subtype; phys2d_circle, etc */
void (*debugdraw)(void *data); void (*debugdraw)(void *data);
float (*moi)(void *data, float mass); float (*moi)(void *data, float mass);
@ -71,19 +70,19 @@ struct phys2d_edge {
int draws; int draws;
}; };
struct phys2d_circle *Make2DCircle(int go); struct phys2d_circle *Make2DCircle(gameobject *go);
void phys2d_circledel(struct phys2d_circle *c); void phys2d_circledel(struct phys2d_circle *c);
void phys2d_applycircle(struct phys2d_circle *circle); void phys2d_applycircle(struct phys2d_circle *circle);
void phys2d_dbgdrawcircle(struct phys2d_circle *circle); void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
float phys2d_circle_moi(struct phys2d_circle *c, float m); float phys2d_circle_moi(struct phys2d_circle *c, float m);
struct phys2d_box *Make2DBox(int go); struct phys2d_box *Make2DBox(gameobject *go);
void phys2d_boxdel(struct phys2d_box *box); void phys2d_boxdel(struct phys2d_box *box);
void phys2d_applybox(struct phys2d_box *box); void phys2d_applybox(struct phys2d_box *box);
void phys2d_dbgdrawbox(struct phys2d_box *box); void phys2d_dbgdrawbox(struct phys2d_box *box);
float phys2d_box_moi(struct phys2d_box *box, float m); float phys2d_box_moi(struct phys2d_box *box, float m);
struct phys2d_poly *Make2DPoly(int go); struct phys2d_poly *Make2DPoly(gameobject *go);
void phys2d_polydel(struct phys2d_poly *poly); void phys2d_polydel(struct phys2d_poly *poly);
void phys2d_applypoly(struct phys2d_poly *poly); void phys2d_applypoly(struct phys2d_poly *poly);
void phys2d_dbgdrawpoly(struct phys2d_poly *poly); void phys2d_dbgdrawpoly(struct phys2d_poly *poly);
@ -91,7 +90,7 @@ void phys2d_polyaddvert(struct phys2d_poly *poly);
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts); void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts);
float phys2d_poly_moi(struct phys2d_poly *poly, float m); float phys2d_poly_moi(struct phys2d_poly *poly, float m);
struct phys2d_edge *Make2DEdge(int go); struct phys2d_edge *Make2DEdge(gameobject *go);
void phys2d_edgedel(struct phys2d_edge *edge); void phys2d_edgedel(struct phys2d_edge *edge);
void phys2d_applyedge(struct phys2d_edge *edge); void phys2d_applyedge(struct phys2d_edge *edge);
void phys2d_dbgdrawedge(struct phys2d_edge *edge); void phys2d_dbgdrawedge(struct phys2d_edge *edge);
@ -108,12 +107,8 @@ void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled);
void phys2d_init(); void phys2d_init();
void phys2d_update(float deltaT); void phys2d_update(float deltaT);
cpShape *phys2d_query_pos(cpVect pos); cpShape *phys2d_query_pos(cpVect pos);
int *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh); gameobject *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh);
struct phys_cbs {
struct callee begin;
struct callee separate;
};
struct shape_cb { struct shape_cb {
struct phys2d_shape *shape; struct phys2d_shape *shape;
@ -122,7 +117,7 @@ struct shape_cb {
void fire_hits(); void fire_hits();
void phys2d_rm_go_handlers(int go); void phys2d_rm_go_handlers(gameobject *go);
void phys2d_set_gravity(cpVect v); void phys2d_set_gravity(cpVect v);
void shape_enabled(struct phys2d_shape *shape, int enabled); void shape_enabled(struct phys2d_shape *shape, int enabled);
@ -133,8 +128,8 @@ int shape_get_sensor(struct phys2d_shape *shape);
struct rgba shape_color_s(cpShape *shape); struct rgba shape_color_s(cpShape *shape);
void shape_gui(struct phys2d_shape *shape); void shape_gui(struct phys2d_shape *shape);
void phys2d_setup_handlers(int go); void phys2d_setup_handlers(gameobject *go);
int *phys2d_query_shape(struct phys2d_shape *shape); gameobject *phys2d_query_shape(struct phys2d_shape *shape);
int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n); int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n);
void flush_collide_cbs(); void flush_collide_cbs();

View file

@ -390,7 +390,7 @@ struct drawmodel *make_drawmodel(int go)
void draw_drawmodel(struct drawmodel *dm) void draw_drawmodel(struct drawmodel *dm)
{ {
if (!dm->model) return; if (!dm->model) return;
struct gameobject *go = id2go(dm->go); struct gameobject *go = dm->go;
HMM_Mat4 rst = t3d_go2world(go); HMM_Mat4 rst = t3d_go2world(go);
draw_model(dm->model, rst); draw_model(dm->model, rst);
} }

View file

@ -4,6 +4,7 @@
#include "HandmadeMath.h" #include "HandmadeMath.h"
#include "transform.h" #include "transform.h"
#include "sokol/sokol_gfx.h" #include "sokol/sokol_gfx.h"
#include "gameobject.h"
extern HMM_Vec3 eye; extern HMM_Vec3 eye;
struct shader; struct shader;
@ -32,7 +33,7 @@ typedef struct model {
struct drawmodel { struct drawmodel {
struct model *model; struct model *model;
HMM_Mat4 amodel; HMM_Mat4 amodel;
int go; gameobject *go;
}; };
typedef struct bone { typedef struct bone {

View file

@ -1,61 +1,35 @@
#include "gameobject.h" #include "gameobject.h"
#include "2dphysics.h" #include "2dphysics.h"
#include "log.h"
#include <chipmunk/chipmunk.h> #include <chipmunk/chipmunk.h>
#include <string.h> #include <string.h>
#include "debugdraw.h" #include "debugdraw.h"
#include "freelist.h" #include "log.h"
#include "stb_ds.h" #include "stb_ds.h"
struct gameobject *gameobjects = NULL; gameobject *body2go(cpBody *body) { return cpBodyGetUserData(body); }
gameobject *shape2go(cpShape *shape)
struct gameobject *id2go(int id) {
if (id < 0) return NULL;
return &gameobjects[id];
}
int body2id(cpBody *body) { return (int)cpBodyGetUserData(body); }
cpBody *id2body(int id) {
struct gameobject *go = id2go(id);
if (go)
return go->body;
return NULL;
}
int shape2gameobject(cpShape *shape) {
struct phys2d_shape *s = cpShapeGetUserData(shape);
return s->go;
}
struct gameobject *shape2go(cpShape *shape)
{ {
return id2go(shape2gameobject(shape)); return ((struct phys2d_shape *)cpShapeGetUserData(shape))->go;
} }
HMM_Vec2 go_pos(struct gameobject *go) HMM_Vec2 go_pos(gameobject *go)
{ {
cpVect p = cpBodyGetPosition(go->body); cpVect p = cpBodyGetPosition(go->body);
return (HMM_Vec2){p.x, p.y}; return (HMM_Vec2){p.x, p.y};
} }
HMM_Vec2 go_worldpos(struct gameobject *go) HMM_Vec2 go_worldpos(gameobject *go)
{ {
HMM_Vec2 ret; HMM_Vec2 ret;
ret.cp = cpBodyGetPosition(go->body); ret.cp = cpBodyGetPosition(go->body);
return ret; return ret;
} }
float go_angle(struct gameobject *go) { return go_worldangle(go); } float go_angle(gameobject *go) { return go_worldangle(go); }
float go_worldangle(gameobject *go) { return cpBodyGetAngle(go->body); }
float go_worldangle(struct gameobject *go) { return cpBodyGetAngle(go->body); } float go2angle(gameobject *go) { return cpBodyGetAngle(go->body); }
float go2angle(struct gameobject *go) { return cpBodyGetAngle(go->body); }
transform3d go2t3(gameobject *go) transform3d go2t3(gameobject *go)
{ {
@ -72,23 +46,21 @@ transform3d go2t3(gameobject *go)
return t; return t;
} }
HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_go2world(go), pos); } HMM_Vec2 go2world(gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_go2world(go), pos); }
HMM_Vec2 world2go(gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_world2go(go), pos); }
HMM_Mat3 t_go2world(gameobject *go) { return transform2d2mat(go2t(go)); }
HMM_Mat3 t_world2go(gameobject *go) { return HMM_InvGeneralM3(t_go2world(go)); }
HMM_Mat4 t3d_go2world(gameobject *go) { return transform3d2mat(go2t3(go)); }
HMM_Mat4 t3d_world2go(gameobject *go) { return HMM_InvGeneralM4(t3d_go2world(go)); }
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_world2go(go), pos); } gameobject *pos2gameobject(HMM_Vec2 pos) {
HMM_Mat3 t_go2world(struct gameobject *go) { return transform2d2mat(go2t(go)); }
HMM_Mat3 t_world2go(struct gameobject *go) { return HMM_InvGeneralM3(t_go2world(go)); }
HMM_Mat4 t3d_go2world(struct gameobject *go) { return transform3d2mat(go2t3(go)); }
HMM_Mat4 t3d_world2go(struct gameobject *go) { return HMM_InvGeneralM4(t3d_go2world(go)); }
int pos2gameobject(HMM_Vec2 pos) {
cpShape *hit = phys2d_query_pos(pos.cp); cpShape *hit = phys2d_query_pos(pos.cp);
if (hit) if (hit)
return shape2gameobject(hit); return shape2go(hit);
return NULL;
/*
for (int i = 0; i < arrlen(gameobjects); i++) { for (int i = 0; i < arrlen(gameobjects); i++) {
if (!gameobjects[i].body) continue; if (!gameobjects[i].body) continue;
cpVect gpos = cpBodyGetPosition(gameobjects[i].body); cpVect gpos = cpBodyGetPosition(gameobjects[i].body);
@ -96,8 +68,8 @@ int pos2gameobject(HMM_Vec2 pos) {
if (dist <= 25) return i; if (dist <= 25) return i;
} }
*/
return -1; return NULL;
} }
transform2d go2t(gameobject *go) transform2d go2t(gameobject *go)
@ -111,22 +83,15 @@ transform2d go2t(gameobject *go)
return t; return t;
} }
int go2id(struct gameobject *go) {
for (int i = 0; i < arrlen(gameobjects); i++)
if (&gameobjects[i] == go) return i;
return -1;
}
unsigned int editor_cat = 1<<31; unsigned int editor_cat = 1<<31;
void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go) { void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go) {
cpShapeSetFriction(shape, go->f); cpShapeSetFriction(shape, go->f);
cpShapeSetElasticity(shape, go->e); cpShapeSetElasticity(shape, go->e);
cpShapeSetCollisionType(shape, go2id(go)); cpShapeSetCollisionType(shape, go);
cpShapeFilter filter; cpShapeFilter filter;
filter.group = go2id(go); filter.group = go;
filter.categories = 1<<go->layer | editor_cat; filter.categories = 1<<go->layer | editor_cat;
// filter.mask = CP_ALL_CATEGORIES; // filter.mask = CP_ALL_CATEGORIES;
filter.mask = category_masks[go->layer] | editor_cat; filter.mask = category_masks[go->layer] | editor_cat;
@ -138,7 +103,7 @@ void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go) {
ape->apply(ape->data); ape->apply(ape->data);
} }
void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) { void go_shape_moi(cpBody *body, cpShape *shape, gameobject *go) {
float moment = cpBodyGetMoment(go->body); float moment = cpBodyGetMoment(go->body);
struct phys2d_shape *s = cpShapeGetUserData(shape); struct phys2d_shape *s = cpShapeGetUserData(shape);
if (!s) { if (!s) {
@ -151,7 +116,7 @@ void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) {
cpBodySetMoment(go->body, 1); cpBodySetMoment(go->body, 1);
} }
void gameobject_apply(struct gameobject *go) { void gameobject_apply(gameobject *go) {
cpBodySetType(go->body, go->bodytype); cpBodySetType(go->body, go->bodytype);
cpBodyEachShape(go->body, go_shape_apply, go); cpBodyEachShape(go->body, go_shape_apply, go);
@ -169,7 +134,7 @@ void gameobject_apply(struct gameobject *go) {
static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt) static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{ {
struct gameobject *go = id2go((int)cpBodyGetUserData(body)); gameobject *go = body2go(body);
if (!go) { if (!go) {
cpBodyUpdateVelocity(body,gravity,damping,dt); cpBodyUpdateVelocity(body,gravity,damping,dt);
return; return;
@ -190,8 +155,9 @@ static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt
} }
} }
int MakeGameobject() { gameobject *MakeGameobject() {
struct gameobject go = { gameobject *ngo = malloc(sizeof(*ngo));
gameobject go = {
.scale = (HMM_Vec3){1.f,1.f,1.f}, .scale = (HMM_Vec3){1.f,1.f,1.f},
.bodytype = CP_BODY_TYPE_STATIC, .bodytype = CP_BODY_TYPE_STATIC,
.maxvelocity = INFINITY, .maxvelocity = INFINITY,
@ -206,6 +172,8 @@ int MakeGameobject() {
.damping = NAN, .damping = NAN,
.timescale = 1.0, .timescale = 1.0,
.ref = JS_UNDEFINED, .ref = JS_UNDEFINED,
.parent = NULL,
.children = NULL
}; };
go.cbs.begin.obj = JS_UNDEFINED; go.cbs.begin.obj = JS_UNDEFINED;
@ -214,16 +182,13 @@ int MakeGameobject() {
go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f)); go.body = cpSpaceAddBody(space, cpBodyNew(go.mass, 1.f));
cpBodySetVelocityUpdateFunc(go.body, velocityFn); cpBodySetVelocityUpdateFunc(go.body, velocityFn);
int id; *ngo = go;
if (!gameobjects) freelist_size(gameobjects,500); cpBodySetUserData(go.body, ngo);
freelist_grab(id, gameobjects); phys2d_setup_handlers(ngo);
cpBodySetUserData(go.body, (void*)id); return ngo;
phys2d_setup_handlers(id);
gameobjects[id] = go;
return id;
} }
void gameobject_traverse(struct gameobject *go, HMM_Mat4 p) void gameobject_traverse(gameobject *go, HMM_Mat4 p)
{ {
HMM_Mat4 local = transform3d2mat(go2t3(go)); HMM_Mat4 local = transform3d2mat(go2t3(go));
go->world = HMM_MulM4(local, p); go->world = HMM_MulM4(local, p);
@ -242,36 +207,30 @@ void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
cpShapeFree(shape); cpShapeFree(shape);
} }
int *go_toclean = NULL; gameobject **go_toclean = NULL;
/* Free this gameobject */ /* Free this gameobject */
void gameobject_clean(int id) { void gameobject_clean(gameobject *go) {
struct gameobject *go = id2go(id);
arrfree(go->shape_cbs); arrfree(go->shape_cbs);
cpBodyEachShape(go->body, rm_body_shapes, NULL); cpBodyEachShape(go->body, rm_body_shapes, NULL);
cpSpaceRemoveBody(space, go->body); cpSpaceRemoveBody(space, go->body);
cpBodyFree(go->body); cpBodyFree(go->body);
go->body = NULL; go->body = NULL;
free(go);
} }
/* Really more of a "mark for deletion" ... */ /* Really more of a "mark for deletion" ... */
void gameobject_delete(int id) { void gameobject_free(gameobject *go) {
gameobject *go = id2go(id); if (!go) return;
YughWarn("FREEING A GAMEOBJECT");
JS_FreeValue(js, go->ref); JS_FreeValue(js, go->ref);
dag_clip(go);
if (cpSpaceIsLocked(space)) if (cpSpaceIsLocked(space))
arrpush(go_toclean, id); arrpush(go_toclean, go);
else else
gameobject_clean(id); gameobject_clean(go);
dag_clip(go);
freelist_kill(gameobjects,id);
}
void gameobject_free(int id)
{
if (id >= 0)
gameobject_delete(id);
} }
void gameobjects_cleanup() { void gameobjects_cleanup() {
@ -281,12 +240,12 @@ void gameobjects_cleanup() {
arrsetlen(go_toclean, 0); arrsetlen(go_toclean, 0);
} }
void gameobject_setangle(struct gameobject *go, float angle) { void gameobject_setangle(gameobject *go, float angle) {
cpBodySetAngle(go->body, angle); cpBodySetAngle(go->body, angle);
phys2d_reindex_body(go->body); phys2d_reindex_body(go->body);
} }
void gameobject_setpos(struct gameobject *go, cpVect vec) { void gameobject_setpos(gameobject *go, cpVect vec) {
if (!go || !go->body) return; if (!go || !go->body) return;
cpBodySetPosition(go->body, vec); cpBodySetPosition(go->body, vec);
phys2d_reindex_body(go->body); phys2d_reindex_body(go->body);
@ -297,15 +256,9 @@ void body_draw_shapes_dbg(cpBody *body, cpShape *shape, void *data) {
s->debugdraw(s->data); s->debugdraw(s->data);
} }
void gameobject_draw_debug(int go) { void gameobject_draw_debug(gameobject *go) {
struct gameobject *g = id2go(go); if (!go || !go->body) return;
if (!g || !g->body) return;
cpVect pos = cpBodyGetPosition(g->body); cpVect pos = cpBodyGetPosition(go->body);
cpBodyEachShape(g->body, body_draw_shapes_dbg, NULL); cpBodyEachShape(go->body, body_draw_shapes_dbg, NULL);
}
void gameobject_draw_debugs() {
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_draw_debug(i);
} }

View file

@ -1,11 +1,11 @@
#ifndef GAMEOBJECT_H #ifndef GAMEOBJECT_H
#define GAMEOBJECT_H #define GAMEOBJECT_H
#include "2dphysics.h"
#include <chipmunk/chipmunk.h> #include <chipmunk/chipmunk.h>
#include "quickjs/quickjs.h" #include "quickjs/quickjs.h"
#include "HandmadeMath.h" #include "HandmadeMath.h"
#include "transform.h" #include "transform.h"
#include "script.h"
#define dag_rm(p,c) do{\ #define dag_rm(p,c) do{\
for (int i = arrlen(p->children)-1; i--; i >=0) {\ for (int i = arrlen(p->children)-1; i--; i >=0) {\
@ -26,7 +26,7 @@
dag_rm(p->parent,p);\ dag_rm(p->parent,p);\
}while(0) }while(0)
typedef struct gameobject { struct gameobject {
cpBodyType bodytype; cpBodyType bodytype;
cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */ cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */
HMM_Vec3 scale; /* local */ HMM_Vec3 scale; /* local */
@ -51,53 +51,46 @@ typedef struct gameobject {
float drawlayer; float drawlayer;
struct gameobject *parent; struct gameobject *parent;
struct gameobject **children; struct gameobject **children;
} gameobject; };
extern struct gameobject *gameobjects; typedef struct gameobject gameobject;
int MakeGameobject(); gameobject *MakeGameobject();
void gameobject_apply(struct gameobject *go); void gameobject_apply(gameobject *go);
void gameobject_delete(int id); void gameobject_free(gameobject *go);
void gameobject_free(int id);
void gameobjects_cleanup(); void gameobjects_cleanup();
void gameobject_traverse(struct gameobject *start, HMM_Mat4 p); void gameobject_traverse(gameobject *start, HMM_Mat4 p);
transform2d go2t(gameobject *go); transform2d go2t(gameobject *go);
transform3d go2t3(gameobject *go); transform3d go2t3(gameobject *go);
HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos); HMM_Vec2 go2world(gameobject *go, HMM_Vec2 pos);
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos); HMM_Vec2 world2go(gameobject *go, HMM_Vec2 pos);
HMM_Mat3 t_go2world(struct gameobject *go); HMM_Mat3 t_go2world(gameobject *go);
HMM_Mat3 t_world2go(struct gameobject *go); HMM_Mat3 t_world2go(gameobject *go);
HMM_Mat4 t3d_go2world(struct gameobject *go); HMM_Mat4 t3d_go2world(gameobject *go);
HMM_Mat4 t3d_world2go(struct gameobject *go); HMM_Mat4 t3d_world2go(gameobject *go);
HMM_Vec2 go_pos(struct gameobject *go); HMM_Vec2 go_pos(gameobject *go);
HMM_Vec2 go_worldpos(struct gameobject *go); HMM_Vec2 go_worldpos(gameobject *go);
//float go_angle(struct gameobject *go); //float go_angle(gameobject *go);
float go_worldangle(struct gameobject *go); float go_worldangle(gameobject *go);
float go2angle(struct gameobject *go); float go2angle(gameobject *go);
struct gameobject *id2go(int id); gameobject *body2go(cpBody *body);
int go2id(struct gameobject *go); gameobject *shape2go(cpShape *shape);
int body2id(cpBody *body);
cpBody *id2body(int id);
int shape2gameobject(cpShape *shape);
struct gameobject *shape2go(cpShape *shape);
void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go); void go_shape_apply(cpBody *body, cpShape *shape, gameobject *go);
/* Tries a few methods to select a gameobject; if none is selected returns -1 */ /* Tries a few methods to select a gameobject; if none is selected returns -1 */
int pos2gameobject(HMM_Vec2 pos); gameobject *pos2gameobject(HMM_Vec2 pos);
void gameobject_move(struct gameobject *go, HMM_Vec2 vec); void gameobject_move(gameobject *go, HMM_Vec2 vec);
void gameobject_rotate(struct gameobject *go, float as); void gameobject_rotate(gameobject *go, float as);
void gameobject_setangle(struct gameobject *go, float angle); void gameobject_setangle(gameobject *go, float angle);
void gameobject_setpos(struct gameobject *go, cpVect vec); void gameobject_setpos(gameobject *go, cpVect vec);
void gameobject_draw_debug(gameobject *go);
void gameobject_draw_debugs();
void gameobject_draw_debug(int go);
#endif #endif

View file

@ -8,7 +8,6 @@
#include "font.h" #include "font.h"
#include "gameobject.h" #include "gameobject.h"
#include "input.h" #include "input.h"
#include "level.h"
#include "log.h" #include "log.h"
#include "dsp.h" #include "dsp.h"
#include "music.h" #include "music.h"
@ -51,11 +50,8 @@ static JSValue TYPE##2js(TYPE *n) { \
JS_SetOpaque(j,n);\ JS_SetOpaque(j,n);\
return j; }\ return j; }\
QJSCLASS(dsp_node) QJSCLASS(dsp_node)
// gameobject2js, js2gameobject deals with gameobject*, converted to ids
// go2js,js2go deals with gameobject*
QJSCLASS(gameobject) QJSCLASS(gameobject)
#define QJSCLASSPREP(TYPE) \ #define QJSCLASSPREP(TYPE) \
@ -123,22 +119,13 @@ JSValue jscurtime()
return jst; return jst;
} }
void js_setprop_num(JSValue obj, uint32_t i, JSValue v) void js_setprop_num(JSValue obj, uint32_t i, JSValue v) { JS_SetPropertyUint32(js, obj, i, v); }
{
JS_SetPropertyUint32(js, obj, i, v);
}
JSValue go2ref(int id) JSValue gos2ref(gameobject **go)
{
if (id == -1) return JS_UNDEFINED;
return JS_DupValue(js,id2go(id)->ref);
}
JSValue gos2ref(int *go)
{ {
JSValue array = JS_NewArray(js); JSValue array = JS_NewArray(js);
for (int i = 0; i < arrlen(go); i++) for (int i = 0; i < arrlen(go); i++)
js_setprop_num(array,i,go2ref(go[i])); js_setprop_num(array,i,go[i]->ref);
return array; return array;
} }
@ -198,26 +185,11 @@ double js2number(JSValue v) {
return g; return g;
} }
JSValue float2js(double g) { return JS_NewFloat64(js, g);}
JSValue float2js(double g) { JSValue num2js(double g) { return float2js(g); }
return JS_NewFloat64(js, g);
}
JSValue num2js(double g) {
return float2js(g);
}
struct gameobject *js2go(JSValue v) {
return id2go(js2gameobject(v));
}
static int jsgo2id(JSValue v) { return go2id(js2go(v)); }
struct sprite *js2sprite(JSValue v) { return id2sprite(js2int(v)); } struct sprite *js2sprite(JSValue v) { return id2sprite(js2int(v)); }
void *js2ptr(JSValue v) { void *js2ptr(JSValue v) { return JS_GetOpaque(v,js_ptr_id); }
return JS_GetOpaque(v,js_ptr_id);
}
JSValue ptr2js(void *ptr) { JSValue ptr2js(void *ptr) {
JSValue obj = JS_NewObjectClass(js, js_ptr_id); JSValue obj = JS_NewObjectClass(js, js_ptr_id);
@ -225,9 +197,7 @@ JSValue ptr2js(void *ptr) {
return obj; return obj;
} }
struct timer *js2timer(JSValue v) { struct timer *js2timer(JSValue v) { return id2timer(js2int(v)); }
return id2timer(js2int(v));
}
double js_get_prop_number(JSValue v, const char *p) { double js_get_prop_number(JSValue v, const char *p) {
double num; double num;
@ -244,9 +214,7 @@ struct glrect js2glrect(JSValue v) {
return rect; return rect;
} }
JSValue js_arridx(JSValue v, int idx) { JSValue js_arridx(JSValue v, int idx) { return js_getpropidx( v, idx); }
return js_getpropidx( v, idx);
}
int js_arrlen(JSValue v) { int js_arrlen(JSValue v) {
int len; int len;
@ -541,6 +509,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
const void *d1 = NULL; const void *d1 = NULL;
const void *d2 = NULL; const void *d2 = NULL;
int *ids = NULL; int *ids = NULL;
gameobject *go = NULL;
JSValue ret = JS_UNDEFINED; JSValue ret = JS_UNDEFINED;
switch (cmd) { switch (cmd) {
@ -555,9 +524,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 2: case 2:
YughWarn("Deleting gameobject %d", js2int(argv[1])); gameobject_free(js2int(argv[1]));
gameobject_delete(js2int(argv[1]));
YughWarn("Deleted gameobject %d", js2int(argv[1]));
break; break;
case 3: case 3:
@ -699,9 +666,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 36: case 36:
js2go(argv[1])->scale.XY = js2vec2(argv[2]); js2gameobject(argv[1])->scale.XY = js2vec2(argv[2]);
gameobject_apply(js2go(argv[1])); gameobject_apply(js2gameobject(argv[1]));
cpSpaceReindexShapesForBody(space, js2go(argv[1])->body); cpSpaceReindexShapesForBody(space, js2gameobject(argv[1])->body);
break; break;
case 37: case 37:
@ -722,25 +689,26 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 40: case 40:
js2go(argv[1])->filter.categories = js2bitmask(argv[2]); js2gameobject(argv[1])->filter.categories = js2bitmask(argv[2]);
gameobject_apply(js2go(argv[1])); gameobject_apply(js2gameobject(argv[1]));
break; break;
case 41: case 41:
js2go(argv[1])->filter.mask = js2bitmask(argv[2]); js2gameobject(argv[1])->filter.mask = js2bitmask(argv[2]);
gameobject_apply(js2go(argv[1])); gameobject_apply(js2gameobject(argv[1]));
break; break;
case 42: case 42:
ret = bitmask2js(js2go(argv[1])->filter.categories); ret = bitmask2js(js2gameobject(argv[1])->filter.categories);
break; break;
case 43: case 43:
ret = bitmask2js(js2go(argv[1])->filter.mask); ret = bitmask2js(js2gameobject(argv[1])->filter.mask);
break; break;
case 44: case 44:
ret = go2ref(pos2gameobject(js2vec2(argv[1]))); go = pos2gameobject(js2vec2(argv[1]));
ret = go ? go->ref : JS_UNDEFINED;
break; break;
case 45: case 45:
@ -782,23 +750,23 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 54: case 54:
gameobject_apply(js2go(argv[1])); gameobject_apply(js2gameobject(argv[1]));
break; break;
case 55: case 55:
break; break;
// js2go(argv[1])->flipx = JS_ToBool(js, argv[2]) ? -1 : 1; // js2gameobject(argv[1])->flipx = JS_ToBool(js, argv[2]) ? -1 : 1;
case 56: case 56:
// js2go(argv[1])->flipy = JS_ToBool(js, argv[2]) ? -1 : 1; // js2gameobject(argv[1])->flipy = JS_ToBool(js, argv[2]) ? -1 : 1;
break; break;
case 57: case 57:
// ret = JS_NewBool(js, js2go(argv[1])->flipx == -1 ? 1 : 0); // ret = JS_NewBool(js, js2gameobject(argv[1])->flipx == -1 ? 1 : 0);
break; break;
case 58: case 58:
// ret = JS_NewBool(js, js2go(argv[1])->flipy == -1 ? 1 : 0); // ret = JS_NewBool(js, js2gameobject(argv[1])->flipy == -1 ? 1 : 0);
break; break;
case 59: case 59:
@ -811,7 +779,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 61: case 61:
set_cam_body(id2body(js2int(argv[1]))); set_cam_body(js2gameobject(argv[1])->body);
break; break;
case 62: case 62:
@ -847,11 +815,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 70: case 70:
ret = vec2js(world2go(js2go(argv[1]), js2vec2(argv[2]))); ret = vec2js(world2go(js2gameobject(argv[1]), js2vec2(argv[2])));
break; break;
case 71: case 71:
ret = vec2js(go2world(js2go(argv[1]), js2vec2(argv[2]))); ret = vec2js(go2world(js2gameobject(argv[1]), js2vec2(argv[2])));
break; break;
case 72: case 72:
@ -867,7 +835,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 75: case 75:
js2go(argv[1])->layer = js2int(argv[2]); js2gameobject(argv[1])->layer = js2int(argv[2]);
break; break;
case 76: case 76:
@ -875,7 +843,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 77: case 77:
ret = int2js(js2go(argv[1])->layer); ret = int2js(js2gameobject(argv[1])->layer);
break; break;
case 78: case 78:
@ -896,7 +864,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 82: case 82:
gameobject_draw_debug(js2go(argv[1])); gameobject_draw_debug(js2gameobject(argv[1]));
break; break;
case 83: case 83:
@ -989,35 +957,35 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 103: case 103:
ret = vec2js(js2go(argv[1])->scale.XY); ret = vec2js(js2gameobject(argv[1])->scale.XY);
break; break;
case 104: case 104:
// ret = bool2js(js2go(argv[1])->flipx == -1 ? 1 : 0); // ret = bool2js(js2gameobject(argv[1])->flipx == -1 ? 1 : 0);
break; break;
case 105: case 105:
// ret = bool2js(js2go(argv[1])->flipy == -1 ? 1 : 0); // ret = bool2js(js2gameobject(argv[1])->flipy == -1 ? 1 : 0);
break; break;
case 106: case 106:
js2go(argv[1])->e = js2number(argv[2]); js2gameobject(argv[1])->e = js2number(argv[2]);
break; break;
case 107: case 107:
ret = num2js(js2go(argv[1])->e); ret = num2js(js2gameobject(argv[1])->e);
break; break;
case 108: case 108:
js2go(argv[1])->f = js2number(argv[2]); js2gameobject(argv[1])->f = js2number(argv[2]);
break; break;
case 109: case 109:
ret = num2js(js2go(argv[1])->f); ret = num2js(js2gameobject(argv[1])->f);
break; break;
case 110: case 110:
ret = num2js(js2go(argv[1])->e); ret = num2js(js2gameobject(argv[1])->e);
break; break;
case 111: case 111:
@ -1029,7 +997,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 113: case 113:
js2go(argv[1])->ref = argv[2];//JS_DupValue(js,argv[2]); js2gameobject(argv[1])->ref = argv[2];//JS_DupValue(js,argv[2]);
break; break;
case 114: case 114:
@ -1188,38 +1156,38 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 151: case 151:
js2go(argv[1])->maxvelocity = js2number(argv[2]); js2gameobject(argv[1])->maxvelocity = js2number(argv[2]);
break; break;
case 152: case 152:
ret = num2js(js2go(argv[1])->maxvelocity); ret = num2js(js2gameobject(argv[1])->maxvelocity);
break; break;
case 153: case 153:
cpBodySetTorque(js2go(argv[1])->body, js2number(argv[2])); cpBodySetTorque(js2gameobject(argv[1])->body, js2number(argv[2]));
break; break;
case 154: case 154:
js2go(argv[1])->maxangularvelocity = js2number(argv[2]); js2gameobject(argv[1])->maxangularvelocity = js2number(argv[2]);
break; break;
case 155: case 155:
ret = num2js(js2go(argv[1])->maxangularvelocity); ret = num2js(js2gameobject(argv[1])->maxangularvelocity);
break; break;
case 156: case 156:
js2go(argv[1])->damping = js2number(argv[2]); js2gameobject(argv[1])->damping = js2number(argv[2]);
break; break;
case 157: case 157:
ret = num2js(js2go(argv[1])->damping); ret = num2js(js2gameobject(argv[1])->damping);
break; break;
case 158: case 158:
js2go(argv[1])->gravity = js2bool(argv[2]); js2gameobject(argv[1])->gravity = js2bool(argv[2]);
break; break;
case 159: case 159:
ret = bool2js(js2go(argv[1])->gravity); ret = bool2js(js2gameobject(argv[1])->gravity);
break; break;
case 160: case 160:
ret = vec2js(mat_t_dir(t_world2go(js2go(argv[1])), js2vec2(argv[2]))); ret = vec2js(mat_t_dir(t_world2go(js2gameobject(argv[1])), js2vec2(argv[2])));
break; break;
case 161: case 161:
ret = vec2js(mat_t_dir(t_go2world(js2go(argv[1])), js2vec2(argv[2]))); ret = vec2js(mat_t_dir(t_go2world(js2gameobject(argv[1])), js2vec2(argv[2])));
break; break;
case 162: case 162:
str = JS_ToCString(js, argv[1]); str = JS_ToCString(js, argv[1]);
@ -1242,22 +1210,22 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
ret = int2js(cp(str, str2)); ret = int2js(cp(str, str2));
break; break;
case 167: case 167:
js2go(argv[1])->cgravity = js2vec2(argv[2]); js2gameobject(argv[1])->cgravity = js2vec2(argv[2]);
break; break;
case 168: case 168:
js2go(argv[1])->timescale = js2number(argv[2]); js2gameobject(argv[1])->timescale = js2number(argv[2]);
break; break;
case 169: case 169:
ret = num2js(js2go(argv[1])->timescale); ret = num2js(js2gameobject(argv[1])->timescale);
break; break;
case 170: case 170:
id2sprite(js2int(argv[1]))->emissive = js2color(argv[2]); id2sprite(js2int(argv[1]))->emissive = js2color(argv[2]);
break; break;
case 171: case 171:
ret = num2js(js2go(argv[1])->drawlayer); ret = num2js(js2gameobject(argv[1])->drawlayer);
break; break;
case 172: case 172:
js2go(argv[1])->drawlayer = js2number(argv[2]); js2gameobject(argv[1])->drawlayer = js2number(argv[2]);
break; break;
case 173: case 173:
str = js2str(argv[1]); str = js2str(argv[1]);
@ -1373,7 +1341,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
ret = dsp_node2js(dsp_fwd_delay(js2number(argv[1]), js2number(argv[2]))); ret = dsp_node2js(dsp_fwd_delay(js2number(argv[1]), js2number(argv[2])));
break; break;
case 208: case 208:
dag_set(js2go(argv[1]), js2go(argv[2])); dag_set(js2gameobject(argv[1]), js2gameobject(argv[2]));
break; break;
case 209: case 209:
ret = unix2time(js2number(argv[1])); ret = unix2time(js2number(argv[1]));
@ -1460,23 +1428,23 @@ JSValue duk_register(JSContext *js, JSValueConst this, int argc, JSValueConst *a
return JS_UNDEFINED; return JS_UNDEFINED;
} }
void gameobject_add_shape_collider(int go, struct callee c, struct phys2d_shape *shape) { void gameobject_add_shape_collider(gameobject *go, struct callee c, struct phys2d_shape *shape) {
struct shape_cb shapecb; struct shape_cb shapecb;
shapecb.shape = shape; shapecb.shape = shape;
shapecb.cbs.begin = c; shapecb.cbs.begin = c;
arrpush(id2go(go)->shape_cbs, shapecb); arrpush(go->shape_cbs, shapecb);
} }
JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
int go = jsgo2id(argv[3]); gameobject *go = js2gameobject(argv[3]);
struct callee c; struct callee c;
c.fn = argv[1]; c.fn = argv[1];
c.obj = argv[2]; c.obj = argv[2];
switch (cmd) { switch (cmd) {
case 0: case 0:
id2go(go)->cbs.begin = c; go->cbs.begin = c;
break; break;
case 1: case 1:
@ -1488,7 +1456,7 @@ JSValue duk_register_collide(JSContext *js, JSValueConst this, int argc, JSValue
break; break;
case 3: case 3:
id2go(go)->cbs.separate = c; go->cbs.separate = c;
break; break;
} }
@ -1533,7 +1501,6 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
return JS_NewInt64(js, frame_fps()); return JS_NewInt64(js, frame_fps());
case 9: /* Clear the level out */ case 9: /* Clear the level out */
new_level();
break; break;
case 10: case 10:
@ -1545,6 +1512,7 @@ JSValue duk_sys_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
} }
JSValue duk_make_gameobject(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_make_gameobject(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
YughWarn("MAKING GAMOBJECT");
return gameobject2js(MakeGameobject()); return gameobject2js(MakeGameobject());
} }
@ -1564,7 +1532,7 @@ JSValue duk_yughlog(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
struct gameobject *go = js2go(argv[1]); gameobject *go = js2gameobject(argv[1]);
if (!go) return JS_UNDEFINED; if (!go) return JS_UNDEFINED;
@ -1638,7 +1606,7 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a
JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int q = js2int(argv[0]); int q = js2int(argv[0]);
struct gameobject *go = js2go(argv[1]); gameobject *go = js2gameobject(argv[1]);
if (!go) return JS_UNDEFINED; if (!go) return JS_UNDEFINED;
@ -1668,7 +1636,7 @@ JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *arg
return JS_NewBool(js, phys2d_in_air(go->body)); return JS_NewBool(js, phys2d_in_air(go->body));
case 8: case 8:
gameobject_delete(go2id(go)); gameobject_free(go);
break; break;
} }
@ -1695,7 +1663,7 @@ JSValue duk_make_anim2d(JSContext *js, JSValueConst this, int argc, JSValueConst
} }
JSValue duk_make_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_make_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int go = jsgo2id(argv[0]); gameobject *go = js2gameobject(argv[0]);
HMM_Vec2 size = js2vec2(argv[1]); HMM_Vec2 size = js2vec2(argv[1]);
struct phys2d_box *box = Make2DBox(go); struct phys2d_box *box = Make2DBox(go);
@ -1736,7 +1704,7 @@ JSValue duk_cmd_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *
} }
JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int go = jsgo2id(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_circle *circle = Make2DCircle(go); struct phys2d_circle *circle = Make2DCircle(go);
@ -1748,7 +1716,7 @@ JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCon
JSValue duk_make_model(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) JSValue duk_make_model(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
{ {
int go = jsgo2id(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct drawmodel *dm = make_drawmodel(go); struct drawmodel *dm = make_drawmodel(go);
JSValue ret = JS_NewObject(js); JSValue ret = JS_NewObject(js);
js_setprop_str(ret, "id", ptr2js(dm)); js_setprop_str(ret, "id", ptr2js(dm));
@ -1782,7 +1750,7 @@ JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCons
} }
JSValue duk_make_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_make_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int go = jsgo2id(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_poly *poly = Make2DPoly(go); struct phys2d_poly *poly = Make2DPoly(go);
phys2d_poly_setverts(poly, NULL); phys2d_poly_setverts(poly, NULL);
JSValue polyval = JS_NewObject(js); JSValue polyval = JS_NewObject(js);
@ -1807,7 +1775,7 @@ JSValue duk_cmd_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst
} }
JSValue duk_make_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_make_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int go = jsgo2id(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_edge *edge = Make2DEdge(go); struct phys2d_edge *edge = Make2DEdge(go);
int n = js_arrlen(argv[1]); int n = js_arrlen(argv[1]);

View file

@ -1,49 +0,0 @@
#include "level.h"
#include "gameobject.h"
#include "resources.h"
#include <stdio.h>
#include <string.h>
#include "stb_ds.h"
void save_level(char name[MAXNAME]) {
FILE *lfile = res_open(name, "wb+");
if (!lfile) return;
int objs = arrlen(gameobjects);
fwrite(&objs, sizeof(objs), 1, lfile);
fclose(lfile);
}
void load_level(char name[MAXNAME]) {
/*
FILE *lfile = fopen(name, "rb");
if (!lfile) return;
new_level();
int objs;
fread(&objs, sizeof(objs), 1, lfile);
arraddn(gameobjects, objs);
for (int i = 0; i < objs; i++) {
struct gameobject *go = &gameobjects[i];
fread(go, sizeof(struct gameobject), 1, lfile);
go->components = NULL;
gameobject_init(go, lfile);
}
fclose(lfile);
*/
}
void new_level() {
for (int i = 0; i < arrlen(gameobjects); i++)
gameobject_delete(i);
arrfree(gameobjects);
}

View file

@ -1,16 +0,0 @@
#ifndef LEVEL_H
#define LEVEL_H
#include "config.h"
// This class holds all of the entities and options for a level. Really it's nothing more than a container and access point for all the entities currently loaded into the game.
struct level {
char name[MAXNAME];
};
void save_level(char name[MAXNAME]);
void load_level(char name[MAXNAME]);
void new_level();
#endif

View file

@ -518,10 +518,9 @@ void full_2d_pass(struct window *window)
call_draw(); call_draw();
//// DEBUG //// DEBUG
if (debugDrawPhysics) { if (debugDrawPhysics)
gameobject_draw_debugs();
call_debugs(); call_debugs();
}
debug_flush(&projection); debug_flush(&projection);
text_flush(&projection); text_flush(&projection);

View file

@ -12,6 +12,12 @@ struct callee {
JSValue obj; JSValue obj;
}; };
struct phys_cbs {
struct callee begin;
struct callee separate;
};
extern struct callee stacktrace_callee; extern struct callee stacktrace_callee;
extern JSValue num_cache[100]; extern JSValue num_cache[100];

334
source/engine/spline.c Normal file
View file

@ -0,0 +1,334 @@
#include "spline.h"
#include "stb_ds.h"
#include "log.h"
#include "transform.h"
static const HMM_Mat4 cubic_hermite_m = {
2, -2, 1, 1,
-3, 3, -2, -1,
0, 0, 1, 0,
1, 0, 0, 0
};
static const HMM_Mat4 cubic_hermite_dm = {
0, 0, 0, 0,
6, -6, 3, 3,
-6, 6, -4, -2,
0, 0, 1, 0
};
static const HMM_Mat4 cubic_hermite_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6,
-6, 6, -4, -2
};
static const HMM_Mat4 cubic_hermite_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
12, -12, 6, 6
};
static const HMM_Mat4 b_spline_m = {
-1/6, 3/6, -3/6, 1,
3/6, -6/6, 3/6, 0,
-3/6, 0, 3/6, 0,
1/6, 4/6, 1/6, 0
};
static const HMM_Mat4 b_spline_dm = {
0, 0, 0, 0,
-3/6, 9/6, -9/6, 3,
6/6, -12/6, 6/6, 0,
-3/6, 0, 3/6, 0
};
static const HMM_Mat4 b_spline_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-6/6, 18/6, -18/6, 6,
6/6, -12/6, 6/6, 0
};
static const HMM_Mat4 b_spline_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6/6, 18/6, -18/6, 6
};
static const HMM_Mat4 bezier_m = {
-1, 3, -3, 1,
3, -6, 3, 0,
-3, 3, 0, 0,
1, 0, 0, 0
};
static const HMM_Mat4 bezier_dm = {
0, 0, 0, 0,
-3, 9, -9, 3,
6, -12, 6, 0,
-3, 3, 0, 0,
};
static const HMM_Mat4 bezier_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6,
6, -12, 6, 0
};
static const HMM_Mat4 bezier_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-6, 18, -18, 6
};
#define CAT_S 0.5
/* Position */
static const HMM_Mat4 catmull_rom_m = {
-CAT_S, 2-CAT_S, CAT_S-2, CAT_S,
2*CAT_S, CAT_S-3, 3-2*CAT_S, -CAT_S,
-CAT_S, 0, CAT_S, 0,
0, 1, 0, 0
};
/* Tangent */
static const HMM_Mat4 catmull_rom_dm = {
0, 0, 0, 0,
-3*CAT_S, 9*CAT_S, -9*CAT_S, 3*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S,
-CAT_S, 0, CAT_S, 0,
};
/* Curvature */
static const HMM_Mat4 catmull_rom_ddm = {
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S,
4*CAT_S, -10*CAT_S, 8*CAT_S, -2*CAT_S
};
/* Wiggle */
static const HMM_Mat4 catmull_rom_dddm = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S
};
HMM_Vec4 spline_CT(HMM_Mat4 *C, float t)
{
float t2 = t*t;
float t3 = t2*t;
HMM_Vec4 T = {t3, t2, t, 1};
return HMM_MulM4V4(*C, T);
}
HMM_Mat4 make_G(HMM_Vec2 a, HMM_Vec2 b, HMM_Vec2 c, HMM_Vec2 d)
{
HMM_Mat4 G;
G.Columns[0].xy = a;
G.Columns[1].xy = b;
G.Columns[2].xy = c;
G.Columns[3].xy = d;
return G;
}
HMM_Mat4 make_C(HMM_Vec2 p0, HMM_Vec2 p1, HMM_Vec2 p2, HMM_Vec2 p3, HMM_Mat4 *B)
{
HMM_Mat4 G = make_G(p0, p1, p2, p3);
return HMM_MulM4(G, *B);
}
HMM_Vec2 cubic_spline_d(HMM_Vec2 p0, HMM_Vec2 p1, HMM_Vec2 p2, HMM_Vec2 p3, HMM_Mat4 *m, float d)
{
HMM_Mat4 G = make_G(p0,p1,p2,p3);
HMM_Mat4 C = HMM_MulM4(G, *m);
return spline_CT(&C, d).xy;
}
HMM_Vec2 *spline_v2(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, HMM_Mat4 *m, int segs)
{
HMM_Vec2 *ret = NULL;
if (segs == 2) {
arrput(ret, *b);
arrput(ret, *c);
return ret;
}
if (segs < 2) return NULL;
HMM_Mat4 G = make_G(*a, *b, *c, *d);
HMM_Mat4 C = HMM_MulM4(G, *m);
float s = (float)1/segs;
for (float t = 0; t < 1; t += s)
arrput(ret, spline_CT(&C, t).xy);
return ret;
}
HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret)
{
HMM_Vec2 a = spline_CT(C, u0).xy;
HMM_Vec2 b = spline_CT(C, u1).xy;
if (HMM_DistV2(a,b) > min_seg) {
float umid = (u0+u1)/2;
spline2d_min_seg(u0, umid, min_seg, C, ret);
spline2d_min_seg(umid, u1, min_seg, C, ret);
}
else
arrput(ret, b);
}
HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg)
{
HMM_Vec2 p0 = HMM_MulV2F(HMM_SubV2(*c, *a), CAT_S);
HMM_Vec2 p3 = HMM_MulV2F(HMM_SubV2(*d, *b), CAT_S);
HMM_Mat4 G = make_G(p0, *b, *c, p3);
HMM_Mat4 C = HMM_MulM4(G, catmull_rom_m);
HMM_Vec2 *ret = NULL;
arrsetcap(ret, 100);
arrput(ret, *b);
spline2d_min_seg(0, 1, min_seg, &C, ret);
return ret;
}
void *stbarrdup(void *mem, size_t size, int len) {
void *out = NULL;
arrsetlen(out, len);
memcpy(out,mem,size*len);
return out;
}
#define arrconcat(a,b) do{for (int i = 0; i < arrlen(b); i++) arrput(a,b[i]);}while(0)
#define arrdup(a) (stbarrdup(a, sizeof(*a), arrlen(a)))
static HMM_Vec2 *V2RET = NULL;
static HMM_Vec3 *V3RET = NULL;
static HMM_Vec4 *V4RET = NULL;
#define SPLINE_MIN(DIM) \
HMM_Vec##DIM *spline2d_min_angle_##DIM(float u0, float u1, float max_angle, HMM_Mat4 *C) \
{ \
float umid = (u0 + u1)/2;\
HMM_Vec##DIM a = spline_CT(C, u0)._##DIM;\
HMM_Vec##DIM b = spline_CT(C, u1)._##DIM;\
HMM_Vec##DIM m = spline_CT(C, umid)._##DIM;\
if (HMM_AngleV##DIM(m,b) > max_angle) {\
spline2d_min_angle_##DIM(u0, umid, max_angle, C);\
spline2d_min_angle_##DIM(umid, u1, max_angle, C);\
}\
else\
arrput(V##DIM##RET,b);\
}\
SPLINE_MIN(2)
SPLINE_MIN(3)
/* Computes non even points to give the best looking curve */
HMM_Vec2 *catmull_rom_min_angle(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_angle)
{
HMM_Mat4 G = make_G(*a, *b, *c, *d);
HMM_Mat4 C = HMM_MulM4(G, catmull_rom_m);
return spline2d_min_angle_2(0,1,min_angle*M_PI/180.0,&C);
}
#define CR_MA(DIM) \
HMM_Vec##DIM *catmull_rom_ma_v##DIM(HMM_Vec##DIM *cp, float ma) \
{ \
if (arrlen(cp) < 4) return NULL; \
\
if (V##DIM##RET) arrfree(V##DIM##RET);\
arrsetcap(V##DIM##RET,100);\
int segments = arrlen(cp)-3;\
arrput(V##DIM##RET, cp[1]); \
for (int i = 1; i < arrlen(cp)-2; i++) { \
HMM_Vec##DIM p0 = HMM_MulV##DIM##F(HMM_SubV##DIM(cp[i+1], cp[i-1]), CAT_S);\
HMM_Vec##DIM p3 = HMM_MulV##DIM##F(HMM_SubV##DIM(cp[i+2], cp[i]), CAT_S);\
catmull_rom_min_angle(&p0, &cp[i], &cp[i+1], &p3, ma);\
}\
\
return arrdup(V##DIM##RET);\
}\
CR_MA(2)
CR_MA(3)
CR_MA(4)
HMM_Vec2 catmull_rom_query(HMM_Vec2 *cp, float d, HMM_Mat4 *G)
{
if (arrlen(cp) < 4 || d < 0 || d > 1) return HMM_V2(0,0);
int segs = arrlen(cp)-3;
float d_per_seg = (float)1/segs;
float maxi = d_per_seg;
int p1 = 2;
while (maxi < d) {
maxi += d_per_seg;
p1++;
}
HMM_Vec2 p0 = HMM_MulV2F(HMM_SubV2(cp[p1+1], cp[p1-1]), CAT_S);
HMM_Vec2 p3 = HMM_MulV2F(HMM_SubV2(cp[p1+2], cp[p1]), CAT_S);
return cubic_spline_d(p0, cp[p1], cp[p1+1], p3, G, d);
}
float catmull_rom_seglen(float t0, float t1, float max_angle, HMM_Mat4 *Cd, HMM_Mat4 *C)
{
float total = 0;
float step = 0.1;
for (float i = t0; i < t1; i += step)
total += HMM_LenV2(spline_CT(Cd, i).xy) * step;
return total;
/* Estimation via max angle */
/* float total = 0.0;
float tmid = (t0+t1)/2;
HMM_Vec2 a = spline_CT(C, t0).xy;
HMM_Vec2 b = spline_CT(C, t1).xy;
HMM_Vec2 m = spline_CT(C, tmid).xy;
if (HMM_AngleV2(m,b) > max_angle) {
total += catmull_rom_seglen(t0, tmid, max_angle, Cd, C);
total += catmull_rom_seglen(tmid, t1, max_angle, Cd, C);
} else
return HMM_LenV2(spline_CT(Cd, t0).xy)*(t1-t0);
return total;
*/
}
float catmull_rom_len(HMM_Vec2 *cp)
{
float len = 0.0;
int segs = arrlen(cp)-3;
float d_per_seg = (float)1/segs;
float maxi = d_per_seg;
for (int i = 1; i < arrlen(cp)-2; i++) {
HMM_Vec2 p0 = HMM_MulV2F(HMM_SubV2(cp[i+1], cp[i-1]), CAT_S);
HMM_Vec2 p3 = HMM_MulV2F(HMM_SubV2(cp[i+2], cp[i]), CAT_S);
HMM_Mat4 C = make_C(p0, cp[i], cp[i+1], p3, &catmull_rom_m);
HMM_Mat4 Cd = make_C(p0, cp[i], cp[i+1], p3, &catmull_rom_dm);
len += catmull_rom_seglen(0, 1, 0.1, &Cd, &C);
}
return len;
}
/* d is from 0 to 1 for the entire spline */
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_m); }
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_dm); }
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_ddm); }
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d) { return catmull_rom_query(cp,d,&catmull_rom_dddm); }
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p)
{
}

22
source/engine/spline.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef SPLINE_H
#define SPLINE_H
#include "HandmadeMath.h"
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma);
HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma);
HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma);
HMM_Vec2 catmull_rom_query(HMM_Vec2 *cp, float d, HMM_Mat4 *G);
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d);
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d);
float catmull_rom_len(HMM_Vec2 *cp);
/* Returns closest point on a curve given a point p */
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p);
#endif

View file

@ -108,8 +108,8 @@ void sprite_io(struct sprite *sprite, FILE *f, int read) {
int sprite_sort(int *a, int *b) int sprite_sort(int *a, int *b)
{ {
struct gameobject *goa = id2go(sprites[*a].go); struct gameobject *goa = sprites[*a].go;
struct gameobject *gob = id2go(sprites[*b].go); struct gameobject *gob = sprites[*b].go;
if (goa->drawlayer == gob->drawlayer) return 0; if (goa->drawlayer == gob->drawlayer) return 0;
if (goa->drawlayer > gob->drawlayer) return 1; if (goa->drawlayer > gob->drawlayer) return 1;
return -1; return -1;
@ -240,7 +240,7 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
} }
void sprite_draw(struct sprite *sprite) { void sprite_draw(struct sprite *sprite) {
struct gameobject *go = id2go(sprite->go); gameobject *go = sprite->go;
if (sprite->tex) { if (sprite->tex) {
HMM_Mat3 m = t_go2world(go); HMM_Mat3 m = t_go2world(go);

View file

@ -7,15 +7,13 @@
#include "HandmadeMath.h" #include "HandmadeMath.h"
#include "render.h" #include "render.h"
#include "transform.h" #include "transform.h"
#include "gameobject.h"
struct datastream;
struct gameobject;
struct sprite { struct sprite {
transform2d t; transform2d t;
struct rgba color; struct rgba color;
struct rgba emissive; struct rgba emissive;
int go; /* id of gameobject */ gameobject *go; /* id of gameobject */
struct Texture *tex; struct Texture *tex;
struct glrect frame; struct glrect frame;
int enabled; int enabled;

View file

@ -287,29 +287,12 @@ void c_event(const sapp_event *e)
int sim_playing() { return sim_play == SIM_PLAY; } int sim_playing() { return sim_play == SIM_PLAY; }
int sim_paused() { return sim_play == SIM_PAUSE; } int sim_paused() { return sim_play == SIM_PAUSE; }
void sim_start() { sim_play = SIM_PLAY; }
void sim_start() { void sim_pause() { sim_play = SIM_PAUSE; }
sim_play = SIM_PLAY;
}
void sim_pause() {
sim_play = SIM_PAUSE;
}
int phys_stepping() { return sim_play == SIM_STEP; } int phys_stepping() { return sim_play == SIM_STEP; }
void sim_step() { sim_play = SIM_STEP; }
void sim_step() { void set_timescale(float val) { timescale = val; }
sim_play = SIM_STEP; double get_timescale() { return timescale; }
}
void set_timescale(float val) {
timescale = val;
}
double get_timescale()
{
return timescale;
}
static sapp_desc start_desc = { static sapp_desc start_desc = {
.width = 720, .width = 720,
@ -330,10 +313,7 @@ static sapp_desc start_desc = {
.logger.func = sg_logging, .logger.func = sg_logging,
}; };
void app_name(char *name) void app_name(char *name) { start_desc.window_title = strdup(name); }
{
start_desc.window_title = strdup(name);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
#ifndef NDEBUG #ifndef NDEBUG