prosperon/source/engine/2dphysics.c

682 lines
18 KiB
C
Raw Normal View History

2021-11-30 21:29:18 -06:00
#include "2dphysics.h"
2023-05-12 13:22:05 -05:00
#include "debug.h"
2021-11-30 21:29:18 -06:00
#include "gameobject.h"
#include "mathc.h"
2022-08-12 14:03:56 -05:00
#include "nuke.h"
2023-05-12 13:22:05 -05:00
#include <string.h>
2021-11-30 21:29:18 -06:00
2022-08-17 00:01:51 -05:00
#include "debugdraw.h"
2022-12-20 08:16:26 -06:00
#include "stb_ds.h"
2023-01-25 21:32:58 -06:00
#include <assert.h>
2023-05-12 13:22:05 -05:00
#include <chipmunk/chipmunk_unsafe.h>
#include <math.h>
2022-12-20 08:16:26 -06:00
2023-04-28 20:55:24 -05:00
#include "2dphysics.h"
2023-01-27 12:06:16 -06:00
#include "tinyspline.h"
#include "ffi.h"
2023-05-12 13:22:05 -05:00
#include "script.h"
2022-12-26 20:57:45 -06:00
2022-12-20 08:16:26 -06:00
#include "log.h"
2022-08-17 00:01:51 -05:00
2021-11-30 21:29:18 -06:00
cpSpace *space = NULL;
float phys2d_gravity = -50.f;
float dbg_color[3] = {0.836f, 1.f, 0.45f};
float trigger_color[3] = {0.278f, 0.953f, 1.f};
float disabled_color[3] = {0.58f, 0.58f, 0.58f};
2023-05-12 13:22:05 -05:00
float dynamic_color[3] = {255 / 255, 70 / 255, 46 / 255};
float kinematic_color[3] = {255 / 255, 206 / 255, 71 / 255};
float static_color[3] = {0.22f, 0.271f, 1.f};
2023-03-10 13:13:48 -06:00
unsigned int category_masks[32];
2023-05-12 13:22:05 -05:00
void set_cat_mask(int cat, unsigned int mask) {
2023-03-10 13:13:48 -06:00
category_masks[cat] = mask;
}
2023-05-12 13:22:05 -05:00
void color2float(struct color color, float *fcolor) {
fcolor[0] = (float)color.r / 255;
fcolor[1] = (float)color.g / 255;
fcolor[2] = (float)color.b / 255;
}
2023-05-12 13:22:05 -05:00
struct color float2color(float *fcolor) {
struct color new;
new.r = fcolor[0] * 255;
new.b = fcolor[1] * 255;
new.g = fcolor[2] * 255;
return new;
}
2023-05-12 13:22:05 -05:00
cpShape *phys2d_query_pos(cpVect pos) {
cpShapeFilter filter;
2023-03-17 10:25:35 -05:00
filter.group = CP_NO_GROUP;
filter.mask = CP_ALL_CATEGORIES;
filter.categories = CP_ALL_CATEGORIES;
cpShape *find = cpSpacePointQueryNearest(space, pos, 0.f, filter, NULL);
2023-05-12 13:22:05 -05:00
// cpShape *find = cpSpaceSegmentQueryFirst(space, pos, pos, 0.f, filter, NULL);
return find;
}
2023-02-05 17:42:36 -06:00
int *qhits;
2023-05-12 13:22:05 -05:00
void querylist(cpShape *shape, cpContactPointSet *points, void *data) {
2023-02-08 15:30:12 -06:00
int go = shape2gameobject(shape);
int in = 0;
for (int i = 0; i < arrlen(qhits); i++) {
if (qhits[i] == go) {
in = 1;
break;
}
}
if (!in) arrput(qhits, go);
2023-02-05 17:42:36 -06:00
}
2023-05-12 13:22:05 -05:00
void querylistbodies(cpBody *body, void *data) {
cpBB *bbox = data;
2023-02-05 17:42:36 -06:00
if (cpBBContainsVect(*bbox, cpBodyGetPosition(body))) {
int go = body2id(body);
if (go < 0) return;
2023-05-12 13:22:05 -05:00
2023-02-05 17:42:36 -06:00
int in = 0;
for (int i = 0; i < arrlen(qhits); i++) {
if (qhits[i] == go) {
in = 1;
2023-05-12 13:22:05 -05:00
break;
2023-02-05 17:42:36 -06:00
}
}
2023-05-12 13:22:05 -05:00
2023-02-05 17:42:36 -06:00
if (!in) arrput(qhits, go);
}
}
2023-05-12 13:22:05 -05:00
int *phys2d_query_box_points(cpVect pos, cpVect wh, cpVect *points, int n) {
2023-03-19 20:33:05 -05:00
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
cpTransform T = {0};
T.a = 1;
T.d = 1;
T.tx = pos.x;
T.ty = pos.y;
cpShapeUpdate(box, T);
2023-05-12 13:22:05 -05:00
2023-03-19 20:33:05 -05:00
cpBB bbox = cpShapeGetBB(box);
2023-05-12 13:22:05 -05:00
2023-03-19 20:33:05 -05:00
if (qhits) arrfree(qhits);
for (int i = 0; i < n; i++) {
if (cpBBContainsVect(bbox, points[i]))
arrpush(qhits, i);
}
2023-05-12 13:22:05 -05:00
2023-03-19 20:33:05 -05:00
return qhits;
}
2023-05-12 13:22:05 -05:00
int *phys2d_query_box(cpVect pos, cpVect wh) {
2023-02-06 16:41:47 -06:00
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
cpTransform T = {0};
T.a = 1;
T.d = 1;
T.tx = pos.x;
T.ty = pos.y;
cpShapeUpdate(box, T);
2023-05-12 13:22:05 -05:00
2023-02-06 16:41:47 -06:00
cpBB bbox = cpShapeGetBB(box);
2023-02-05 17:42:36 -06:00
if (qhits) arrfree(qhits);
2023-05-12 13:22:05 -05:00
2023-02-06 16:41:47 -06:00
cpSpaceShapeQuery(space, box, querylist, NULL);
2023-02-05 17:42:36 -06:00
cpSpaceEachBody(space, querylistbodies, &bbox);
2023-05-12 13:22:05 -05:00
2023-02-05 17:42:36 -06:00
cpShapeFree(box);
2023-05-12 13:22:05 -05:00
2023-02-05 17:42:36 -06:00
return qhits;
}
2023-05-12 13:22:05 -05:00
int *phys2d_query_shape(struct phys2d_shape *shape) {
2023-03-13 09:27:32 -05:00
if (qhits) arrfree(qhits);
2023-05-12 13:22:05 -05:00
2023-03-13 09:27:32 -05:00
cpSpaceShapeQuery(space, shape->shape, querylist, NULL);
2023-05-12 13:22:05 -05:00
2023-03-13 09:27:32 -05:00
return qhits;
}
2023-05-12 13:22:05 -05:00
int cpshape_enabled(cpShape *c) {
cpShapeFilter filter = cpShapeGetFilter(c);
if (filter.categories == ~CP_ALL_CATEGORIES && filter.mask == ~CP_ALL_CATEGORIES)
return 0;
2023-05-12 13:22:05 -05:00
return 1;
}
2023-05-12 13:22:05 -05:00
float *shape_outline_color(cpShape *shape) {
switch (cpBodyGetType(cpShapeGetBody(shape))) {
case CP_BODY_TYPE_DYNAMIC:
return dynamic_color;
2023-05-12 13:22:05 -05:00
case CP_BODY_TYPE_KINEMATIC:
return kinematic_color;
2023-05-12 13:22:05 -05:00
case CP_BODY_TYPE_STATIC:
return static_color;
2023-05-12 13:22:05 -05:00
}
return static_color;
}
2023-05-12 13:22:05 -05:00
float *shape_color(cpShape *shape) {
if (!cpshape_enabled(shape)) return disabled_color;
2023-01-16 02:16:39 -06:00
2023-05-12 13:22:05 -05:00
if (cpShapeGetSensor(shape)) return trigger_color;
2023-05-12 13:22:05 -05:00
return dbg_color;
2023-01-16 02:16:39 -06:00
}
2023-05-12 13:22:05 -05:00
struct color shape_color_s(cpShape *shape) {
2023-03-17 10:25:35 -05:00
float *c = shape_color(shape);
struct color col;
2023-05-12 13:22:05 -05:00
col.r = c[0] * 255;
col.g = c[1] * 255;
col.b = c[2] * 255;
2023-03-17 10:25:35 -05:00
return col;
}
2023-05-12 13:22:05 -05:00
void phys2d_init() {
space = cpSpaceNew();
cpVect grav = {0, phys2d_gravity};
phys2d_set_gravity(grav);
cpSpaceSetGravity(space, cpv(0, phys2d_gravity));
2021-11-30 21:29:18 -06:00
}
2023-01-10 17:23:11 -06:00
void phys2d_set_gravity(cpVect v) {
2023-05-12 13:22:05 -05:00
YughInfo("Set gravity to %g %g", v.x, v.y);
cpSpaceSetGravity(space, v);
}
2023-05-12 13:22:05 -05:00
void phys2d_update(float deltaT) {
cpSpaceStep(space, deltaT);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void init_phys2dshape(struct phys2d_shape *shape, int go, void *data) {
shape->go = go;
shape->data = data;
go_shape_apply(id2go(go)->body, shape->shape, id2go(go));
cpShapeSetCollisionType(shape->shape, go);
cpShapeSetUserData(shape->shape, shape);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_shape_del(struct phys2d_shape *shape) {
if (!shape->shape) return;
cpSpaceRemoveShape(space, shape->shape);
cpShapeFree(shape->shape);
2022-08-28 22:34:33 -05:00
}
2023-01-16 02:16:39 -06:00
/***************** CIRCLE2D *****************/
2023-05-12 13:22:05 -05:00
struct phys2d_circle *Make2DCircle(int go) {
struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle));
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
new->radius = 10.f;
new->offset = cpvzero;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero));
new->shape.debugdraw = phys2d_dbgdrawcircle;
new->shape.moi = phys2d_circle_moi;
init_phys2dshape(&new->shape, go, new);
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
return new;
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
float phys2d_circle_moi(struct phys2d_circle *c, float m) {
return cpMomentForCircle(m, 0, c->radius, c->offset);
}
2023-05-12 13:22:05 -05:00
void phys2d_circledel(struct phys2d_circle *c) {
phys2d_shape_del(&c->shape);
2022-08-28 22:34:33 -05:00
}
2023-05-12 13:22:05 -05:00
cpVect world2go(struct gameobject *go, cpVect worldpos) {
2023-02-20 16:28:07 -06:00
cpTransform T = {0};
cpVect pos = cpBodyGetPosition(go->body);
worldpos.x -= pos.x;
worldpos.y -= pos.y;
2023-05-12 13:22:05 -05:00
// worldpos.x /= go->scale;
// worldpos.y /= go->scale;
2023-02-20 16:28:07 -06:00
float angle = cpBodyGetAngle(go->body);
T.a = go->flipx * cos(-angle) / go->scale;
T.b = sin(-angle) / go->scale;
T.c = -sin(-angle) / go->scale;
T.d = go->flipy * cos(-angle) / go->scale;
2023-05-12 13:22:05 -05:00
worldpos = cpTransformPoint(T, worldpos);
2023-02-20 16:28:07 -06:00
2023-02-20 11:10:03 -06:00
return worldpos;
}
2023-05-12 13:22:05 -05:00
cpVect go2world(struct gameobject *go, cpVect gopos) {
2023-02-20 11:10:03 -06:00
cpVect pos = cpBodyGetPosition(go->body);
float angle = cpBodyGetAngle(go->body);
cpTransform T = {0};
T.a = go->scale * go->flipx * cos(angle);
2023-02-20 16:28:07 -06:00
T.b = sin(angle) * go->scale * go->flipx;
T.c = -sin(angle) * go->scale * go->flipy;
2023-02-20 11:10:03 -06:00
T.d = go->scale * go->flipy * cos(angle);
T.tx = pos.x;
T.ty = pos.y;
return cpTransformPoint(T, gopos);
}
2023-05-12 13:22:05 -05:00
cpVect gotransformpoint(struct gameobject *go, cpVect point) {
point.x *= go->scale * go->flipx;
point.y *= go->scale * go->flipy;
return point;
}
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
cpVect bodytransformpoint(cpBody *body, cpVect offset) {
cpVect pos = cpBodyGetPosition(body);
float d = sqrt(pow(offset.x, 2.f) + pow(offset.y, 2.f));
float a = atan2(offset.y, offset.x) + cpBodyGetAngle(body);
2023-05-12 13:22:05 -05:00
pos.x += d * cos(a);
pos.y += d * sin(a);
return pos;
2022-08-12 14:03:56 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_dbgdrawcpcirc(cpCircleShape *c) {
cpVect pos = bodytransformpoint(cpShapeGetBody(c), cpCircleShapeGetOffset(c));
float radius = cpCircleShapeGetRadius(c);
draw_circle(pos.x, pos.y, radius, 2, shape_color(c), 1);
2023-01-03 09:06:36 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_dbgdrawcircle(struct phys2d_circle *circle) {
phys2d_dbgdrawcpcirc((cpCircleShape *)circle->shape.shape);
2022-08-17 00:01:51 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_applycircle(struct phys2d_circle *circle) {
struct gameobject *go = id2go(circle->shape.go);
2022-08-28 22:34:33 -05:00
2023-05-12 13:22:05 -05:00
float radius = circle->radius * go->scale;
cpVect offset = gotransformpoint(go, circle->offset);
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
cpCircleShapeSetRadius(circle->shape.shape, radius);
cpCircleShapeSetOffset(circle->shape.shape, offset);
2022-08-12 14:03:56 -05:00
}
2023-01-12 17:41:54 -06:00
/************* BOX2D ************/
2023-05-12 13:22:05 -05:00
struct phys2d_box *Make2DBox(int go) {
struct phys2d_box *new = malloc(sizeof(struct phys2d_box));
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
new->w = 50.f;
new->h = 50.f;
new->r = 0.f;
new->offset[0] = 0.f;
new->offset[1] = 0.f;
new->shape.go = go;
phys2d_applybox(new);
new->shape.debugdraw = phys2d_dbgdrawbox;
new->shape.moi = phys2d_box_moi;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
return new;
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
float phys2d_box_moi(struct phys2d_box *box, float m) {
return cpMomentForBox(m, box->w, box->h);
}
2023-05-12 13:22:05 -05:00
cpTransform go2transform(struct gameobject *go, cpVect offset, float angle) {
cpTransform T = {0};
T.a = cos(angle) * go->scale * go->flipx;
T.b = -sin(angle) * go->scale * go->flipx;
T.c = sin(angle) * go->scale * go->flipy;
T.d = cos(angle) * go->scale * go->flipy;
T.tx = offset.x * go->scale;
T.ty = offset.y * go->scale;
return T;
2022-08-28 22:34:33 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_boxdel(struct phys2d_box *box) {
phys2d_shape_del(&box->shape);
}
void phys2d_applybox(struct phys2d_box *box) {
phys2d_boxdel(box);
struct gameobject *go = id2go(box->shape.go);
cpVect off;
off.x = box->offset[0];
off.y = box->offset[1];
cpTransform T = go2transform(id2go(box->shape.go), off, box->rotation);
float hh = box->h / 2.f;
float hw = box->w / 2.f;
cpVect verts[4] = {{-hw, -hh}, {hw, -hh}, {hw, hh}, {-hw, hh}};
box->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(go->body, 4, verts, T, box->r));
init_phys2dshape(&box->shape, box->shape.go, box);
}
void phys2d_dbgdrawbox(struct phys2d_box *box) {
int n = cpPolyShapeGetCount(box->shape.shape);
cpVect points[n * 2];
2023-01-25 21:32:58 -06:00
2023-05-12 13:22:05 -05:00
for (int i = 0; i < n; i++)
points[i] = bodytransformpoint(cpShapeGetBody(box->shape.shape), cpPolyShapeGetVert(box->shape.shape, i));
draw_poly(points, n, shape_color(box->shape.shape));
2023-01-25 21:32:58 -06:00
}
2023-01-12 17:41:54 -06:00
/************** POLYGON ************/
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
struct phys2d_poly *Make2DPoly(int go) {
struct phys2d_poly *new = malloc(sizeof(struct phys2d_poly));
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
new->points = NULL;
arrsetlen(new->points, 0);
new->radius = 0.f;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
new->shape.shape = cpSpaceAddShape(space, cpPolyShapeNewRaw(id2go(go)->body, 0, new->points, new->radius));
new->shape.debugdraw = phys2d_dbgdrawpoly;
new->shape.moi = phys2d_poly_moi;
init_phys2dshape(&new->shape, go, new);
return new;
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
float phys2d_poly_moi(struct phys2d_poly *poly, float m) {
2023-02-27 08:50:36 -06:00
float moi = cpMomentForPoly(m, arrlen(poly->points), poly->points, cpvzero, poly->radius);
if (moi <= 0) {
YughError("Polygon MOI is negative. Returning one;");
return 1;
}
2023-05-12 13:22:05 -05:00
2023-02-27 08:50:36 -06:00
return moi;
}
2023-05-12 13:22:05 -05:00
void phys2d_polydel(struct phys2d_poly *poly) {
arrfree(poly->points);
phys2d_shape_del(&poly->shape);
2022-08-28 22:34:33 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_polyaddvert(struct phys2d_poly *poly) {
arrput(poly->points, cpvzero);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
if (!verts) return;
arrfree(poly->points);
poly->points = verts;
phys2d_applypoly(poly);
2023-01-25 21:32:58 -06:00
}
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
void phys2d_applypoly(struct phys2d_poly *poly) {
if (arrlen(poly->points) <= 0) return;
struct gameobject *go = id2go(poly->shape.go);
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
cpTransform T = go2transform(go, cpvzero, 0);
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
cpSpaceReindexShapesForBody(space, cpShapeGetBody(poly->shape.shape));
}
void phys2d_dbgdrawpoly(struct phys2d_poly *poly) {
float *color = shape_color(poly->shape.shape);
2023-01-12 17:41:54 -06:00
2023-05-12 13:22:05 -05:00
if (arrlen(poly->points) >= 3) {
int n = cpPolyShapeGetCount(poly->shape.shape);
cpVect points[n];
2023-01-25 21:32:58 -06:00
2023-05-12 13:22:05 -05:00
for (int i = 0; i < n; i++)
points[i] = bodytransformpoint(cpShapeGetBody(poly->shape.shape), cpPolyShapeGetVert(poly->shape.shape, i));
2023-01-25 21:32:58 -06:00
2023-05-12 13:22:05 -05:00
draw_poly(points, n, color);
}
2023-01-25 21:32:58 -06:00
}
2023-01-12 17:41:54 -06:00
/****************** EDGE 2D**************/
2023-05-12 13:22:05 -05:00
struct phys2d_edge *Make2DEdge(int go) {
struct phys2d_edge *new = malloc(sizeof(struct phys2d_edge));
new->points = NULL;
arrsetlen(new->points, 0);
new->thickness = 0.f;
new->shapes = NULL;
arrsetlen(new->shapes, 0);
new->shape.go = go;
new->shape.data = new;
new->shape.debugdraw = phys2d_dbgdrawedge;
new->shape.moi = phys2d_edge_moi;
new->shape.shape = NULL;
phys2d_applyedge(new);
return new;
}
float phys2d_edge_moi(struct phys2d_edge *edge, float m) {
2023-02-28 09:40:53 -06:00
float moi = 0;
2023-05-12 13:22:05 -05:00
for (int i = 0; i < arrlen(edge->points) - 1; i++)
moi += cpMomentForSegment(m, edge->points[i], edge->points[i + 1], edge->thickness);
2023-02-28 09:40:53 -06:00
return moi;
}
2023-05-12 13:22:05 -05:00
void phys2d_edgedel(struct phys2d_edge *edge) {
phys2d_shape_del(&edge->shape);
2022-08-28 22:34:33 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_edgeaddvert(struct phys2d_edge *edge) {
arrput(edge->points, cpvzero);
if (arrlen(edge->points) > 1)
arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(id2go(edge->shape.go)->body, cpvzero, cpvzero, edge->thickness)));
2022-08-12 14:03:56 -05:00
2023-05-12 13:22:05 -05:00
phys2d_applyedge(edge);
2022-08-12 14:03:56 -05:00
}
2023-05-12 13:22:05 -05:00
void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) {
assert(arrlen(edge->points) > index && index >= 0);
2023-02-08 15:30:12 -06:00
2023-05-12 13:22:05 -05:00
arrdel(edge->points, index);
2023-02-08 15:30:12 -06:00
2023-05-12 13:22:05 -05:00
if (arrlen(edge->points) == 0) return;
2023-02-08 15:30:12 -06:00
2023-05-12 13:22:05 -05:00
if (index == 0) {
cpSpaceRemoveShape(space, edge->shapes[index]);
cpShapeFree(edge->shapes[index]);
arrdel(edge->shapes, index);
phys2d_applyedge(edge);
return;
}
2023-02-08 15:30:12 -06:00
2023-05-12 13:22:05 -05:00
if (index != arrlen(edge->points)) {
cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1], edge->points[index]);
}
2023-02-08 15:30:12 -06:00
2023-05-12 13:22:05 -05:00
cpSpaceRemoveShape(space, edge->shapes[index - 1]);
cpShapeFree(edge->shapes[index - 1]);
arrdel(edge->shapes, index - 1);
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
phys2d_applyedge(edge);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) {
assert(arrlen(edge->points) > index && index >= 0);
edge->points[index] = val;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
phys2d_applyedge(edge);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_edge_clearverts(struct phys2d_edge *edge) {
for (int i = arrlen(edge->points) - 1; i >= 0; i--) {
2023-02-08 15:30:12 -06:00
phys2d_edge_rmvert(edge, i);
}
}
2023-05-12 13:22:05 -05:00
void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts) {
2023-02-08 15:30:12 -06:00
for (int i = 0; i < arrlen(verts); i++) {
phys2d_edgeaddvert(edge);
phys2d_edge_setvert(edge, i, verts[i]);
}
}
2023-05-12 13:22:05 -05:00
void phys2d_applyedge(struct phys2d_edge *edge) {
struct gameobject *go = id2go(edge->shape.go);
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
for (int i = 0; i < arrlen(edge->shapes); i++) {
cpVect a = gotransformpoint(go, edge->points[i]);
cpVect b = gotransformpoint(go, edge->points[i + 1]);
cpSegmentShapeSetEndpoints(edge->shapes[i], a, b);
cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness);
if (i > 0 && i < arrlen(edge->shapes) - 1)
cpSegmentShapeSetNeighbors(edge->shapes[i], gotransformpoint(go, edge->points[i - 1]), gotransformpoint(go, edge->points[i + 2]));
go_shape_apply(NULL, edge->shapes[i], go);
cpShapeSetUserData(edge->shapes[i], &edge->shape);
}
cpSpaceReindexShapesForBody(space, id2go(edge->shape.go)->body);
2021-11-30 21:29:18 -06:00
}
2023-05-12 13:22:05 -05:00
void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
edge->draws++;
if (edge->draws > 1) {
if (edge->draws >= arrlen(edge->shapes))
edge->draws = 0;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
return;
}
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
if (arrlen(edge->shapes) < 1) return;
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
cpVect drawpoints[arrlen(edge->points)];
struct gameobject *go = id2go(edge->shape.go);
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
for (int i = 0; i < arrlen(edge->points); i++) {
drawpoints[i] = gotransformpoint(go, edge->points[i]);
drawpoints[i] = bodytransformpoint(cpShapeGetBody(edge->shapes[0]), drawpoints[i]);
}
2021-11-30 21:29:18 -06:00
2023-05-12 13:22:05 -05:00
draw_edge(drawpoints, arrlen(edge->points), shape_color_s(edge->shapes[0]), edge->thickness * 2);
draw_points(drawpoints, arrlen(edge->points), 2, kinematic_color);
2021-11-30 21:29:18 -06:00
}
2023-01-25 21:32:58 -06:00
/************ COLLIDER ****************/
2023-05-12 13:22:05 -05:00
void shape_enabled(struct phys2d_shape *shape, int enabled) {
if (enabled)
cpShapeSetFilter(shape->data, CP_SHAPE_FILTER_ALL);
else
cpShapeSetFilter(shape->data, CP_SHAPE_FILTER_NONE);
}
2023-05-12 13:22:05 -05:00
int shape_is_enabled(struct phys2d_shape *shape) {
if (cpshape_enabled(shape->shape))
return 1;
2023-05-12 13:22:05 -05:00
return 0;
}
2023-05-12 13:22:05 -05:00
void shape_set_sensor(struct phys2d_shape *shape, int sensor) {
if (!shape->shape) {
struct phys2d_edge *edge = shape->data;
for (int i = 0; i < arrlen(edge->shapes); i++)
cpShapeSetSensor(edge->shapes[i], sensor);
} else
cpShapeSetSensor(shape->shape, sensor);
2023-01-17 13:04:08 -06:00
}
2023-05-12 13:22:05 -05:00
int shape_get_sensor(struct phys2d_shape *shape) {
if (!shape->shape) {
return cpShapeGetSensor(((struct phys2d_edge *)(shape->data))->shapes[0]);
}
return cpShapeGetSensor(shape->shape);
}
void phys2d_reindex_body(cpBody *body) {
2023-05-12 13:22:05 -05:00
cpSpaceReindexShapesForBody(space, body);
}
2023-05-12 13:22:05 -05:00
void duk_call_phys_cb(cpVect norm, struct callee c, int hit, cpArbiter *arb) {
cpShape *shape1;
cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "normal", vec2js(norm));
JS_SetPropertyStr(js, obj, "hit", JS_NewInt32(js, hit));
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
JS_SetPropertyStr(js, obj, "velocity", vec2js(cpArbiterGetSurfaceVelocity(arb)));
script_callee(c, 1, &obj);
2023-02-17 01:16:52 -06:00
}
2023-03-17 10:25:35 -05:00
#define CTYPE_BEGIN 0
#define CTYPE_SEP 1
2023-03-10 13:13:48 -06:00
2023-05-12 13:22:05 -05:00
static cpBool handle_collision(cpArbiter *arb, int type) {
cpBody *body1;
cpBody *body2;
cpArbiterGetBodies(arb, &body1, &body2);
int g1 = (int)cpBodyGetUserData(body1);
int g2 = (int)cpBodyGetUserData(body2);
struct gameobject *go = id2go(g1);
struct gameobject *go2 = id2go(g2);
cpShape *shape1;
cpShape *shape2;
cpArbiterGetShapes(arb, &shape1, &shape2);
struct phys2d_shape *pshape1 = cpShapeGetUserData(shape1);
struct phys2d_shape *pshape2 = cpShapeGetUserData(shape2);
cpVect norm1 = cpArbiterGetNormal(arb);
switch (type) {
case CTYPE_BEGIN:
for (int i = 0; i < arrlen(go->shape_cbs); i++)
if (go->shape_cbs[i].shape == pshape1)
duk_call_phys_cb(norm1, go->shape_cbs[i].cbs.begin, g2, arb);
if (JS_IsObject(go->cbs.begin.obj))
duk_call_phys_cb(norm1, go->cbs.begin, g2, arb);
break;
case CTYPE_SEP:
if (JS_IsObject(go->cbs.separate.obj)) {
YughWarn("Made it here; separate.");
duk_call_phys_cb(norm1, go->cbs.separate, g2, arb);
2023-03-17 10:25:35 -05:00
}
2023-04-21 16:57:30 -05:00
2023-05-12 13:22:05 -05:00
break;
}
return 1;
}
2023-05-12 13:22:05 -05:00
static cpBool script_phys_cb_begin(cpArbiter *arb, cpSpace *space, void *data) {
2023-03-17 10:25:35 -05:00
return handle_collision(arb, CTYPE_BEGIN);
}
2023-05-12 13:22:05 -05:00
static cpBool script_phys_cb_separate(cpArbiter *arb, cpSpace *space, void *data) {
2023-03-17 10:25:35 -05:00
return handle_collision(arb, CTYPE_SEP);
}
2023-05-12 13:22:05 -05:00
void phys2d_rm_go_handlers(int go) {
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
handler->userData = NULL;
handler->beginFunc = NULL;
handler->separateFunc = NULL;
}
2023-05-12 13:22:05 -05:00
void phys2d_setup_handlers(int go) {
2023-03-10 13:13:48 -06:00
cpCollisionHandler *handler = cpSpaceAddWildcardHandler(space, go);
2023-05-12 13:22:05 -05:00
handler->userData = (void *)go;
2023-03-10 13:13:48 -06:00
handler->beginFunc = script_phys_cb_begin;
2023-03-17 10:25:35 -05:00
handler->separateFunc = script_phys_cb_separate;
2023-03-10 13:13:48 -06:00
}
2023-03-17 10:25:35 -05:00
static int airborne = 0;
2023-05-12 13:22:05 -05:00
void inair(cpBody *body, cpArbiter *arbiter, void *data) {
2023-03-17 10:25:35 -05:00
airborne = 0;
}
2023-05-12 13:22:05 -05:00
int phys2d_in_air(cpBody *body) {
2023-03-17 10:25:35 -05:00
airborne = 1;
cpBodyEachArbiter(body, inair, NULL);
return airborne;
}