diff --git a/meson.build b/meson.build index 3649a0ef..74478ca3 100644 --- a/meson.build +++ b/meson.build @@ -72,6 +72,18 @@ sdl3_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': 'Release' }) +chipmunk_opts = cmake.subproject_options() +chipmunk_opts.add_cmake_defines({ + 'BUILD_DEMOS': 'OFF', + 'BUILD_SHARED': 'OFF', + 'BUILD_STATIC': 'ON', + 'CMAKE_BUILD_TYPE': 'Release', +# uncomment to use floats instead of doubles +# 'CP_USE_DOUBLES': 'OFF', +}) +chipmunk_proj = cmake.subproject('chipmunk', options: chipmunk_opts) +deps += chipmunk_proj.dependency('chipmunk_static') + cc = meson.get_compiler('c') if host_machine.system() == 'darwin' @@ -131,7 +143,6 @@ deps += dependency('physfs', static:true) #deps += cc.find_library('opencv') deps += dependency('threads') -deps += dependency('chipmunk', static:true) deps += dependency('enet', static:true) deps += dependency('soloud', static:true) diff --git a/source/qjs_chipmunk.c b/source/qjs_chipmunk.c index 94d38ec6..92e80d03 100644 --- a/source/qjs_chipmunk.c +++ b/source/qjs_chipmunk.c @@ -3,10 +3,14 @@ #include #include #include +#include /* Items are automatically reclaimed when they go out of scope in your quickjs program. Each chipmunk type's userdata is a pointer to the underlying JSValue it's associated with. + Constraints and shapes are create and forget. They can't be changed between bodies. Just delete and make anew. + Memory for the underlying C types are only freed when the object is out of scope in javascript. + If a body is freed, all of its shapes and constraints are invalid and issue a warning if you try to use them. */ #define countof(x) (sizeof(x)/sizeof((x)[0])) @@ -42,6 +46,9 @@ static void PostBodyFree(cpBody *body, cpSpace *space) { } static void ShapeFreeWrap(cpSpace *space, cpShape *shape, void *unused) { + printf("Removing shape %p from space\n", shape); + cpSpace *myspace = cpShapeGetSpace(shape); + printf("i'm currently in %p, removing out of %p\n", myspace, space); cpSpaceRemoveShape(space, shape); } @@ -61,27 +68,39 @@ static void js_cpSpace_finalizer(JSRuntime *rt, JSValue val) { printf("freeing space\n"); cpSpace *space = JS_GetOpaque(val, js_cpSpace_class_id); - cpSpaceEachShape(space, PostShapeFree, NULL); - cpSpaceEachConstraint(space, PostConstraintFree, NULL); - cpSpaceEachBody(space, PostBodyFree, NULL); + cpSpaceEachShape(space, PostShapeFree, space); + cpSpaceEachConstraint(space, PostConstraintFree, space); + cpSpaceEachBody(space, PostBodyFree, space); JSValue *cb = (JSValue*)cpShapeGetUserData(space); JS_FreeValueRT(rt, *cb); free(cb); + cpShapeSetUserData(space, NULL); // required to not crash on space free cpSpaceFree(space); } +static void body_rm_shape(cpBody *body, cpShape *shape, cpSpace *space) +{ + cpSpaceRemoveShape(space, shape); +} + +static void body_rm_constraint(cpBody *body, cpConstraint *constraint, cpSpace *space) +{ + cpSpaceRemoveConstraint(space, constraint); +} + static void js_cpBody_finalizer(JSRuntime *rt, JSValue val) { printf("freeing body\n"); cpBody *body = JS_GetOpaque(val, js_cpBody_class_id); - + cpSpace *space = cpBodyGetSpace(body); - if (space) + + if (space) { + cpBodyEachShape(body, body_rm_shape, space); + cpBodyEachConstraint(body, PostConstraintFree, space); cpSpaceRemoveBody(space,body); - - cpBodyEachShape(body, PostShapeFree, space); - cpBodyEachConstraint(body, PostConstraintFree, space); + } JSValue *cb = (JSValue *)cpBodyGetUserData(body); JS_FreeValueRT(rt, *cb); @@ -94,7 +113,7 @@ static void js_cpShape_finalizer(JSRuntime *rt, JSValue val) { printf("freeing shape\n"); cpShape *shape = JS_GetOpaque(val, js_cpShape_class_id); - + cpSpace *space = cpShapeGetSpace(shape); if (space) cpSpaceRemoveShape(space, shape); @@ -205,17 +224,16 @@ static JSValue js_##CP##_get_##ENTRY (JSContext *js, JSValueConst this_val) { \ return TYPE##2js(js, CP##Get##ENTRY(cp)); \ } -// Basic space creation - static JSValue js_make_cpSpace(JSContext *js, JSValueConst this_val, int argc, JSValueConst *argv) { cpSpace *space = cpSpaceNew(); JSValue obj = JS_NewObjectClass(js, js_cpSpace_class_id); JS_SetOpaque(obj, space); - // Link the JS object to the Chipmunk space JSValue *cb = malloc(sizeof(*cb)); - *cb = JS_DupValue(js,obj); + *cb = obj;//JS_DupValue(js,obj); cpSpaceSetUserData(space, cb); + + printf("new space is %p\n", space); return obj; } @@ -322,9 +340,9 @@ static JSValue js_cpSpace_add_body (JSContext *js, JSValueConst this_val, int ar JS_SetOpaque(obj, body); JSValue *cb = malloc(sizeof(*cb)); - *cb = JS_DupValue(js,obj); + *cb = obj;//JS_DupValue(js,obj); cpBodySetUserData(body, cb); - + printf("adding body to space %p\n", space); cpSpaceAddBody(space, body); printf("finished adding body at %p\n", body); return obj; @@ -464,22 +482,38 @@ static JSValue js_body_each_arbiter(JSContext *js, JSValueConst this_val, int ar return JS_UNDEFINED; } -// Shape creation from body static JSValue js_body_add_circle_shape(JSContext *js, JSValueConst this_val, int argc, JSValueConst *argv) { - cpBody *body = js2cpBody(js, this_val); if (!body) return JS_EXCEPTION; - double radius = js2number(js, argv[0]); - cpVect offset = js2cpvect(js, argv[1]); - cpShape *shape = cpCircleShapeNew(body, (cpFloat)radius, offset); + cpBody *body = js2cpBody(js, this_val); + if (!body) return JS_ThrowReferenceError(js, "Shape must be added to a body."); + + cpSpace *space = cpBodyGetSpace(body); + printf("adding circle shape to space %p\n", space); + + double radius = 10; + cpVect offset = {0,0}; + if (argc > 0 && JS_IsObject(argv[0])) { + JSValue r = JS_GetPropertyStr(js, argv[0], "radius"); + if (!JS_IsUndefined(r)) radius = js2number(js, r); + JS_FreeValue(js, r); + + printf("RADIUS IS %g\n", radius); + + JSValue o = JS_GetPropertyStr(js, argv[0], "offset"); + if (!JS_IsUndefined(o)) offset = js2cpvect(js, o); + JS_FreeValue(js, o); + } + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, offset)); JSValue obj = JS_NewObjectClass(js, js_cpShape_class_id); JS_SetOpaque(obj, shape); - // Set the circle prototype chain JS_SetPrototype(js, obj, circle_proto); JSValue *cb = malloc(sizeof(*cb)); - *cb = JS_DupValue(js,obj); + *cb = obj;//JS_DupValue(js,obj); cpShapeSetUserData(shape, cb); - // We do not call cpSpaceAddShape here. Typically you'd do that explicitly: space.addShape(...) + + printf("MADE CIRCLE SHAPE\n"); return obj; } @@ -496,7 +530,7 @@ static JSValue js_body_add_segment_shape(JSContext *js, JSValueConst this_val, i JS_SetPrototype(js, obj, segment_proto); JSValue *cb = malloc(sizeof(*cb)); - *cb = JS_DupValue(js,obj); + *cb = obj;//JS_DupValue(js,obj); cpShapeSetUserData(shape, cb); return obj; @@ -544,9 +578,9 @@ static const JSCFunctionListEntry js_cpBody_funcs[] = { JS_CFUNC_DEF("eachShape", 1, js_body_each_shape), JS_CFUNC_DEF("eachConstraint", 1, js_body_each_constraint), JS_CFUNC_DEF("eachArbiter", 1, js_body_each_arbiter), - JS_CFUNC_DEF("add_circle_shape", 2, js_body_add_circle_shape), - JS_CFUNC_DEF("add_segment_shape", 3, js_body_add_segment_shape), - JS_CFUNC_DEF("add_poly_shape", 1, js_body_add_poly_shape), + JS_CFUNC_DEF("circle", 1, js_body_add_circle_shape), + JS_CFUNC_DEF("segment", 1, js_body_add_segment_shape), + JS_CFUNC_DEF("poly", 1, js_body_add_poly_shape), }; // Shape-specific get/set @@ -1222,10 +1256,6 @@ JSValue js_chipmunk2d_use(JSContext *js) { JSValue export_obj = JS_NewObject(js); JS_SetPropertyFunctionList(js, export_obj, js_chipmunk2d_funcs, countof(js_chipmunk2d_funcs)); - // Add a "Space" constructor - JSValue space_constructor = JS_NewCFunction2(js, js_make_cpSpace, "Space", 0, JS_CFUNC_constructor, 0); - JS_SetPropertyStr(js, export_obj, "Space", space_constructor); - return export_obj; } diff --git a/subprojects/chipmunk.wrap b/subprojects/chipmunk.wrap index d111cfa5..8f23818e 100644 --- a/subprojects/chipmunk.wrap +++ b/subprojects/chipmunk.wrap @@ -1,8 +1,5 @@ [wrap-git] -url = https://github.com/johnbrethauer/Chipmunk2D.git -revision = head +url = https://github.com/slembcke/Chipmunk2D.git +revision = Chipmunk-7.0.3 depth = 1 -[provide] -chipmunk = chipmunk_dep - diff --git a/tests/chipmunk2d.js b/tests/chipmunk2d.js index c22c4b2d..7d77809b 100644 --- a/tests/chipmunk2d.js +++ b/tests/chipmunk2d.js @@ -112,7 +112,7 @@ var testCases = [ name: "Body creation and position", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); + const body = space.body(); body.position = vec(10, 20); return deepCompare(vec(10, 20), body.position); } @@ -121,7 +121,7 @@ var testCases = [ name: "Body mass and moment", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); + const body = space.body(); body.type = 0 body.mass = 10; body.moment = 100; @@ -138,7 +138,7 @@ var testCases = [ name: "Body velocity", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); + const body = space.body(); body.velocity = vec(5, -5); return deepCompare(vec(5, -5), body.velocity); } @@ -147,7 +147,7 @@ var testCases = [ name: "Body force application", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); + const body = space.body(); body.type = 0 body.mass = 1; body.moment = 1 @@ -163,8 +163,8 @@ var testCases = [ name: "Circle shape creation", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); - const shape = body.add_circle_shape(5, vec(0, 0)); + const body = space.body(); + const shape = body.circle({radius:5, offset:vec(0, 0)}); const radiusResult = deepCompare(5, shape.radius); const offsetResult = deepCompare(vec(0, 0), shape.offset); return { @@ -177,7 +177,7 @@ var testCases = [ name: "Segment shape creation", run: () => { const space = chipmunk.make_space(); - const body = space.add_body(); + const body = space.body(); const shape = body.add_segment_shape(vec(0, 0), vec(10, 10), 2); for (var i in shape) console.log(i) shape.setEndpoints(vec(1, 1), vec(11, 11)); @@ -192,8 +192,8 @@ var testCases = [ name: "Pin joint", run: () => { const space = chipmunk.make_space(); - const body1 = space.add_body(); - const body2 = space.add_body(); + const body1 = space.body(); + const body2 = space.body(); body1.position = vec(0, 0); body2.position = vec(10, 0); const joint = space.pin(body1, body2); @@ -205,8 +205,8 @@ var testCases = [ name: "Pivot joint", run: () => { const space = chipmunk.make_space(); - const body1 = space.add_body(); - const body2 = space.add_body(); + const body1 = space.body(); + const body2 = space.body(); const joint = space.pivot(body1, body2, vec(5, 5)); const anchorAResult = deepCompare(vec(5, 5), joint.anchor_a); const anchorBResult = deepCompare(vec(5, 5), joint.anchor_b); @@ -225,12 +225,12 @@ var testCases = [ console.log(space.gravity) space.gravity = vec(0, -9.81); console.log(space.gravity) - const body = space.add_body(); - body.add_circle_shape(5); + const body = space.body(); + body.circle(5); body.mass = 1; body.moment = 1; body.position = vec(0, 100); - space.step(1); // 1 second + for (var i = 0; i < 61; i++) space.step(1/60) const expectedPos = vec(0, 100 - (9.81/2)); // s = ut + (1/2)at^2 return deepCompare(expectedPos, body.position); }