fix spline segfault

This commit is contained in:
John Alanbrook 2023-12-13 01:35:34 +00:00
parent 2083fb6e9e
commit 903ffbc607
9 changed files with 132 additions and 68 deletions

View file

@ -553,7 +553,7 @@ component.edge2d = Object.copy(collider2d, {
thickness:0, thickness:0,
type: Spline.type.catmull, type: Spline.type.catmull,
looped: false, looped: false,
angle: 5, angle: 3,
flipx: false, flipx: false,
flipy: false, flipy: false,
@ -605,10 +605,14 @@ component.edge2d = Object.copy(collider2d, {
sample(n) { sample(n) {
var spoints = this.spoints(); var spoints = this.spoints();
// n = this.samples * this.sample_calc(); if (this.looped) {
spoints.unshift(spoints[spoints.length-1]);
/* if (this.looped) spoints.push(spoints[1]);
return Spline.sample(degrees, this.dimensions, Spline.type.open, spoints.wrapped(this.degrees), n);*/ spoints.push(spoints[2]);
} else {
spoints.unshift(spoints[0].sub(spoints[1]).add(spoints[0]));
spoints.push(spoints[spoints.length-1].sub(spoints[spoints.length-2]).add(spoints[spoints.length-1]));
}
return Spline.sample_angle(this.type, spoints, this.angle); return Spline.sample_angle(this.type, spoints, this.angle);
}, },
@ -673,6 +677,7 @@ component.edge2d.impl = Object.mix({
sync() { sync() {
var sensor = this.sensor; var sensor = this.sensor;
var points = this.sample(this.samples); var points = this.sample(this.samples);
if (!points) return;
cmd_edge2d(0,this.id,points); cmd_edge2d(0,this.id,points);
this.sensor = sensor; this.sensor = sensor;
}, },

View file

@ -387,7 +387,6 @@ struct phys2d_edge *Make2DEdge(gameobject *go) {
new->shape.shape = NULL; new->shape.shape = NULL;
new->shape.apply = NULL; new->shape.apply = NULL;
new->draws = 0; new->draws = 0;
new->closed = 0;
phys2d_applyedge(new); phys2d_applyedge(new);
return new; return new;
@ -405,16 +404,14 @@ void phys2d_edgedel(struct phys2d_edge *edge) {
phys2d_shape_del(&edge->shape); phys2d_shape_del(&edge->shape);
} }
void phys2d_edgeaddvert(struct phys2d_edge *edge) { void phys2d_edgeaddvert(struct phys2d_edge *edge, HMM_Vec2 v) {
arrput(edge->points, v2zero); arrput(edge->points, v);
if (arrlen(edge->points) > 1) if (arrlen(edge->points) > 1)
arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(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);
} }
void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) { void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) {
assert(arrlen(edge->points) > index && index >= 0); if (index>arrlen(edge->points) || index < 0) return;
arrdel(edge->points, index); arrdel(edge->points, index);
@ -424,41 +421,47 @@ void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) {
cpSpaceRemoveShape(space, edge->shapes[index]); cpSpaceRemoveShape(space, edge->shapes[index]);
cpShapeFree(edge->shapes[index]); cpShapeFree(edge->shapes[index]);
arrdel(edge->shapes, index); arrdel(edge->shapes, index);
phys2d_applyedge(edge);
return; return;
} }
if (index != arrlen(edge->points)) { if (index != arrlen(edge->points))
cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1].cp, edge->points[index].cp); cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1].cp, edge->points[index].cp);
}
cpSpaceRemoveShape(space, edge->shapes[index - 1]); cpSpaceRemoveShape(space, edge->shapes[index - 1]);
cpShapeFree(edge->shapes[index - 1]); cpShapeFree(edge->shapes[index - 1]);
arrdel(edge->shapes, index - 1); arrdel(edge->shapes, index - 1);
phys2d_applyedge(edge);
} }
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) { void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) {
assert(arrlen(edge->points) > index && index >= 0); assert(arrlen(edge->points) > index && index >= 0);
edge->points[index].cp = val; edge->points[index].cp = val;
}
void phys2d_edge_update_verts(struct phys2d_edge *edge, HMM_Vec2 *verts)
{
if (arrlen(edge->points) == arrlen(verts)) {
for (int i = 0; i < arrlen(verts); i++)
phys2d_edge_setvert(edge,i,verts[i].cp);
} else {
int vertchange = arrlen(verts)-arrlen(edge->points);
phys2d_edge_clearverts(edge);
phys2d_edge_addverts(edge,verts);
}
phys2d_applyedge(edge); phys2d_applyedge(edge);
} }
void phys2d_edge_clearverts(struct phys2d_edge *edge) { void phys2d_edge_clearverts(struct phys2d_edge *edge) {
for (int i = arrlen(edge->points) - 1; i >= 0; i--) { for (int i = arrlen(edge->points) - 1; i >= 0; i--)
phys2d_edge_rmvert(edge, i); phys2d_edge_rmvert(edge, i);
} }
void phys2d_edge_addverts(struct phys2d_edge *edge, HMM_Vec2 *verts) {
for (int i = 0; i < arrlen(verts); i++)
phys2d_edgeaddvert(edge, verts[i]);
} }
void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts) { /* Calculates all true positions of verts, links them up, and so on */
for (int i = 0; i < arrlen(verts); i++) {
phys2d_edgeaddvert(edge);
phys2d_edge_setvert(edge, i, verts[i]);
}
}
void phys2d_applyedge(struct phys2d_edge *edge) { void phys2d_applyedge(struct phys2d_edge *edge) {
struct gameobject *go = edge->shape.go; struct gameobject *go = edge->shape.go;

View file

@ -65,7 +65,6 @@ struct phys2d_edge {
HMM_Vec2 *points; /* Points defined relative to the gameobject */ HMM_Vec2 *points; /* Points defined relative to the gameobject */
float thickness; float thickness;
cpShape **shapes; cpShape **shapes;
int closed; /* True if the first and last points should be connected */
struct phys2d_shape shape; struct phys2d_shape shape;
int draws; int draws;
}; };
@ -94,13 +93,15 @@ 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);
void phys2d_edgeaddvert(struct phys2d_edge *edge); void phys2d_edgeaddvert(struct phys2d_edge *edge, HMM_Vec2 v);
void phys2d_edge_rmvert(struct phys2d_edge *edge, int index); void phys2d_edge_rmvert(struct phys2d_edge *edge, int index);
float phys2d_edge_moi(struct phys2d_edge *edge, float m); float phys2d_edge_moi(struct phys2d_edge *edge, float m);
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val); void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val);
void phys2d_edge_clearverts(struct phys2d_edge *edge); void phys2d_edge_clearverts(struct phys2d_edge *edge);
void phys2d_edge_addverts(struct phys2d_edge *edge, cpVect *verts); void phys2d_edge_rmvert(struct phys2d_edge *edge, int index);
void phys2d_edge_update_verts(struct phys2d_edge *edge, HMM_Vec2 *verts);
void phys2d_edge_addverts(struct phys2d_edge *edge, HMM_Vec2 *verts);
void phys2d_edge_set_sensor(struct phys2d_edge *edge, int sensor); void phys2d_edge_set_sensor(struct phys2d_edge *edge, int sensor);
void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled); void phys2d_edge_set_enabled(struct phys2d_edge *edge, int enabled);

View file

@ -389,6 +389,7 @@ typedef union HMM_Mat3 {
typedef union HMM_Mat4 { typedef union HMM_Mat4 {
float Elements[4][4]; float Elements[4][4];
HMM_Vec4 Columns[4]; HMM_Vec4 Columns[4];
float e[4][4];
} HMM_Mat4; } HMM_Mat4;

View file

@ -256,3 +256,9 @@ void gameobject_draw_debug(gameobject *go) {
cpVect pos = cpBodyGetPosition(go->body); cpVect pos = cpBodyGetPosition(go->body);
cpBodyEachShape(go->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(gameobjects[i]);
}

View file

@ -88,4 +88,5 @@ void gameobject_rotate(gameobject *go, float as);
void gameobject_setangle(gameobject *go, float angle); void gameobject_setangle(gameobject *go, float angle);
void gameobject_setpos(gameobject *go, cpVect vec); void gameobject_setpos(gameobject *go, cpVect vec);
void gameobject_draw_debug(gameobject *go); void gameobject_draw_debug(gameobject *go);
void gameobject_draw_debugs();
#endif #endif

View file

@ -266,19 +266,14 @@ cpBitmask js2bitmask(JSValue v) {
return mask; return mask;
} }
HMM_Vec2 *cpvecarr = NULL;
/* Does not need to be freed by returning; but not reentrant */ /* Does not need to be freed by returning; but not reentrant */
HMM_Vec2 *js2cpvec2arr(JSValue v) { HMM_Vec2 *js2cpvec2arr(JSValue v) {
if (cpvecarr) HMM_Vec2 *arr = NULL;
arrfree(cpvecarr);
int n = js_arrlen(v); int n = js_arrlen(v);
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
arrput(cpvecarr, js2vec2(js_getpropidx( v, i))); arrput(arr, js2vec2(js_getpropidx( v, i)));
return cpvecarr; return arr;
} }
JSValue bitmask2js(cpBitmask mask) { JSValue bitmask2js(cpBitmask mask) {
@ -398,15 +393,13 @@ JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst
HMM_Vec2 *points = js2cpvec2arr(argv[3]); HMM_Vec2 *points = js2cpvec2arr(argv[3]);
float param = js2number(argv[4]); float param = js2number(argv[4]);
HMM_Vec2 *samples = catmull_rom_ma_v2(points, param); HMM_Vec2 *samples = catmull_rom_ma_v2(points, param);
arrfree(points);
if (!samples) if (!samples)
return JS_UNDEFINED; return JS_UNDEFINED;
// for (int i = 0; i < arrlen(samples); i++)
// YughWarn("%g,%g", samples[i].x, samples[i].y);
JSValue arr = vecarr2js(samples, arrlen(samples)); JSValue arr = vecarr2js(samples, arrlen(samples));
// arrfree(samples); arrfree(samples);
return arr; return arr;
} }
@ -497,6 +490,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
const char *str2 = NULL; const char *str2 = NULL;
const void *d1 = NULL; const void *d1 = NULL;
const void *d2 = NULL; const void *d2 = NULL;
const void *v1 = NULL;
gameobject *ids = NULL; gameobject *ids = NULL;
gameobject *go = NULL; gameobject *go = NULL;
JSValue ret = JS_UNDEFINED; JSValue ret = JS_UNDEFINED;
@ -759,7 +753,8 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 59: case 59:
ret = JS_NewInt64(js, point2segindex(js2vec2(argv[1]), js2cpvec2arr(argv[2]), js2number(argv[3]))); v1 = js2cpvec2arr(argv[2]);
ret = JS_NewInt64(js, point2segindex(js2vec2(argv[1]), v1, js2number(argv[3])));
break; break;
case 60: case 60:
@ -857,7 +852,8 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 83: case 83:
draw_edge(js2cpvec2arr(argv[1]), js_arrlen(argv[1]), js2color(argv[2]), js2number(argv[3]), 0, 0, js2color(argv[2]), 10); v1 = js2cpvec2arr(argv[1]);
draw_edge(v1, js_arrlen(argv[1]), js2color(argv[2]), js2number(argv[3]), 0, 0, js2color(argv[2]), 10);
break; break;
case 84: case 84:
@ -869,7 +865,8 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break; break;
case 86: case 86:
ids = phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4])); v1 = js2cpvec2arr(argv[3]);
ids = phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), v1, js2int(argv[4]));
ret = gos2ref(ids); ret = gos2ref(ids);
arrfree(ids); arrfree(ids);
break; break;
@ -1354,6 +1351,8 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
if (d1) free(d1); if (d1) free(d1);
if (d2) free(d2); if (d2) free(d2);
if (v1) arrfree(v1);
if (!JS_IsNull(ret)) { if (!JS_IsNull(ret)) {
return ret; return ret;
} }
@ -1750,14 +1749,17 @@ JSValue duk_make_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst
JSValue duk_cmd_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { JSValue duk_cmd_poly2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
int cmd = js2int(argv[0]); int cmd = js2int(argv[0]);
struct phys2d_poly *poly = js2ptr(argv[1]); struct phys2d_poly *poly = js2ptr(argv[1]);
HMM_Vec2 *v1 = NULL;
if (!poly) return JS_UNDEFINED; if (!poly) return JS_UNDEFINED;
switch (cmd) { switch (cmd) {
case 0: case 0:
phys2d_poly_setverts(poly, js2cpvec2arr(argv[2])); v1 = js2cpvec2arr(argv[2]);
phys2d_poly_setverts(poly, v1);
break; break;
} }
if (v1) arrfree(v1);
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@ -1765,15 +1767,9 @@ 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) {
gameobject *go = js2gameobject(argv[0]); gameobject *go = js2gameobject(argv[0]);
struct phys2d_edge *edge = Make2DEdge(go); struct phys2d_edge *edge = Make2DEdge(go);
HMM_Vec2 *points = js2cpvec2arr(argv[1]);
int n = js_arrlen(argv[1]); phys2d_edge_update_verts(edge, points);
HMM_Vec2 points[n]; arrfree(points);
for (int i = 0; i < n; i++) {
points[i] = js2vec2(js_getpropidx(argv[1],i));
phys2d_edgeaddvert(edge);
phys2d_edge_setvert(edge, i, points[i].cp);
}
JSValue edgeval = JS_NewObject(js); JSValue edgeval = JS_NewObject(js);
js_setprop_str(edgeval, "id", ptr2js(edge)); js_setprop_str(edgeval, "id", ptr2js(edge));
@ -1790,16 +1786,19 @@ JSValue duk_cmd_edge2d(JSContext *js, JSValueConst this, int argc, JSValueConst
return JS_UNDEFINED; return JS_UNDEFINED;
} }
HMM_Vec2 *v1 = NULL;
switch (cmd) { switch (cmd) {
case 0: case 0:
phys2d_edge_clearverts(edge); v1 = js2cpvec2arr(argv[2]);
phys2d_edge_addverts(edge, js2cpvec2arr(argv[2])); phys2d_edge_update_verts(edge,v1);
break; break;
case 1: case 1:
edge->thickness = js2number(argv[2]); edge->thickness = js2number(argv[2]);
break; break;
} }
if (v1) arrfree(v1);
return JS_UNDEFINED; return JS_UNDEFINED;
} }
@ -1810,7 +1809,9 @@ JSValue duk_inflate_cpv(JSContext *js, JSValueConst this, int argc, JSValueConst
double d = js2number(argv[2]); double d = js2number(argv[2]);
HMM_Vec2 *infl = inflatepoints(points,d,n); HMM_Vec2 *infl = inflatepoints(points,d,n);
JSValue arr = vecarr2js(infl,arrlen(infl)); JSValue arr = vecarr2js(infl,arrlen(infl));
arrfree(infl); arrfree(infl);
arrfree(points);
return arr; return arr;
} }

View file

@ -518,8 +518,10 @@ 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

@ -2,6 +2,7 @@
#include "stb_ds.h" #include "stb_ds.h"
#include "log.h" #include "log.h"
#include "transform.h" #include "transform.h"
#include "math.h"
static const HMM_Mat4 cubic_hermite_m = { static const HMM_Mat4 cubic_hermite_m = {
2, -2, 1, 1, 2, -2, 1, 1,
@ -121,6 +122,14 @@ static const HMM_Mat4 catmull_rom_dddm = {
-9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S -9*CAT_S, 18*CAT_S, -18*CAT_S, 6*CAT_S
}; };
/*
[t3 t2 t1 1] B [p1
p2 that is, point 1, tangent at point 1, point 2, tan and point 2
t1
t2]
*/
HMM_Vec4 spline_CT(HMM_Mat4 *C, float t) HMM_Vec4 spline_CT(HMM_Mat4 *C, float t)
{ {
float t2 = t*t; float t2 = t*t;
@ -145,6 +154,11 @@ HMM_Mat4 make_C(HMM_Vec2 p0, HMM_Vec2 p1, HMM_Vec2 p2, HMM_Vec2 p3, HMM_Mat4 *B)
return HMM_MulM4(G, *B); return HMM_MulM4(G, *B);
} }
HMM_Mat4 catmull_C(HMM_Vec2 c0, HMM_Vec2 c1, HMM_Vec2 c2, HMM_Vec2 c3)
{
return make_C(c0,c1,c2,c3,&catmull_rom_m);
}
HMM_Vec2 cubic_spline_d(HMM_Vec2 p0, HMM_Vec2 p1, HMM_Vec2 p2, HMM_Vec2 p3, HMM_Mat4 *m, float d) 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 G = make_G(p0,p1,p2,p3);
@ -193,7 +207,7 @@ HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d
HMM_Mat4 G = make_G(p0, *b, *c, p3); HMM_Mat4 G = make_G(p0, *b, *c, p3);
HMM_Mat4 C = HMM_MulM4(G, catmull_rom_m); HMM_Mat4 C = HMM_MulM4(G, catmull_rom_m);
HMM_Vec2 *ret = NULL; HMM_Vec2 *ret = NULL;
arrsetcap(ret, 100); arrsetcap(ret, 1000);
arrput(ret, *b); arrput(ret, *b);
spline2d_min_seg(0, 1, min_seg, &C, ret); spline2d_min_seg(0, 1, min_seg, &C, ret);
return ret; return ret;
@ -228,15 +242,32 @@ HMM_Vec##DIM *spline2d_min_angle_##DIM(float u0, float u1, float max_angle, HMM_
arrput(V##DIM##RET,b);\ arrput(V##DIM##RET,b);\
}\ }\
SPLINE_MIN(2) HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr)
{
float umid = (u0 + u1)/2;
HMM_Vec2 a = spline_CT(C, u0)._2;
HMM_Vec2 b = spline_CT(C, u1)._2;
HMM_Vec2 m = spline_CT(C, umid)._2;
if (fabs(HMM_AngleV2(m,b)) > max_angle) {
arr = spline2d_min_angle_2(u0, umid, max_angle, C, arr);
arr = spline2d_min_angle_2(umid, u1, max_angle, C, arr);
}
else
arrput(arr,b);
return arr;
}
//SPLINE_MIN(2)
SPLINE_MIN(3) SPLINE_MIN(3)
/* Computes non even points to give the best looking curve */ /* Computes non even points to give the best looking curve for a given catmull a,b,c,d */
HMM_Vec2 *catmull_rom_min_angle(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_angle) HMM_Vec2 *catmull_rom_min_angle(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_angle, HMM_Vec2 *arr)
{ {
HMM_Mat4 G = make_G(*a, *b, *c, *d); HMM_Mat4 C = catmull_C(*a,*b,*c,*d);
HMM_Mat4 C = HMM_MulM4(G, catmull_rom_m); arr = spline2d_min_angle_2(0,1,min_angle*M_PI/180.0,&C, arr);
return spline2d_min_angle_2(0,1,min_angle*M_PI/180.0,&C); return arr;
} }
#define CR_MA(DIM) \ #define CR_MA(DIM) \
@ -257,9 +288,22 @@ HMM_Vec##DIM *catmull_rom_ma_v##DIM(HMM_Vec##DIM *cp, float ma) \
return arrdup(V##DIM##RET);\ return arrdup(V##DIM##RET);\
}\ }\
CR_MA(2) //CR_MA(2)
CR_MA(3)
CR_MA(4) HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma)
{
if (arrlen(cp) < 4) return NULL;
HMM_Vec2 *ret = NULL;
int segments = arrlen(cp)-3;
arrput(ret, cp[1]);
for (int i = 1; i < arrlen(cp)-2; i++)
ret = catmull_rom_min_angle(&cp[i-1], &cp[i], &cp[i+1], &cp[i+2], ma, ret);
return ret;
}
//CR_MA(3)
//CR_MA(4)
HMM_Vec2 catmull_rom_query(HMM_Vec2 *cp, float d, HMM_Mat4 *G) HMM_Vec2 catmull_rom_query(HMM_Vec2 *cp, float d, HMM_Mat4 *G)
{ {