initial box2d integration
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m12s
Build and Deploy / build-windows (CLANG64) (push) Successful in 9m33s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped

This commit is contained in:
2025-02-26 07:47:04 -06:00
parent 045c4b49ef
commit 2594c03765
9 changed files with 212 additions and 17 deletions

View File

@@ -72,6 +72,18 @@ sdl3_opts.add_cmake_defines({
'CMAKE_BUILD_TYPE': 'Release'
})
box2d_opts = cmake.subproject_options()
box2d_opts.add_cmake_defines({
'BOX2D_SAMPLES': 'OFF',
'BOX2D_BUILD_STATIC': 'ON',
'BOX2d_AVX2': 'ON',
'BOX2D_BUILD_SHARED': 'OFF',
'CMAKE_BUILD_TYPE': 'Release',
})
box2d_proj = cmake.subproject('box2d', options: box2d_opts)
deps += box2d_proj.dependency('box2d')
cc = meson.get_compiler('c')
if host_machine.system() == 'darwin'
@@ -131,14 +143,13 @@ 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)
#deps += dependency('qjs-chipmunk', static:false)
sources = []
src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c']
src += ['anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c', 'timer.c', 'transform.c','prosperon.c', 'wildmatch.c', 'sprite.c', 'rtree.c', 'qjs_dmon.c', 'qjs_nota.c', 'qjs_enet.c', 'qjs_soloud.c', 'qjs_box2d.c']
imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.cpp', 'imgui_impl_sdlgpu3.cpp']

View File

@@ -96,8 +96,6 @@
#ifndef HANDMADE_MATH_H
#define HANDMADE_MATH_H
#include <chipmunk/chipmunk.h>
#if !defined(HANDMADE_MATH_NO_SIMD)
#if defined(__ARM_NEON) || defined(__ARM_NEON__)
#define HANDMADE_MATH__USE_NEON 1
@@ -272,12 +270,6 @@ typedef union HMM_Vec3 {
HMM_Vec2 VW;
};
struct
{
HMM_Vec2 cp;
float _Ignored5;
};
float Elements[3];
float e[3];
@@ -373,12 +365,6 @@ typedef union HMM_Vec4 {
HMM_Vec2 ZW;
};
struct
{
HMM_Vec2 cp;
HMM_Vec2 wh;
};
HMM_Quat quat;
struct {float x, y, z, w; };
struct {float r, g, b, a; };

View File

@@ -7585,6 +7585,7 @@ JSValue js_imgui_use(JSContext *js);
#include "qjs_nota.h"
#include "qjs_enet.h"
#include "qjs_soloud.h"
#include "qjs_box2d.h"
#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use}
@@ -7610,6 +7611,7 @@ void ffi_load(JSContext *js, int argc, char **argv) {
arrput(module_registry, MISTLINE(dmon));
arrput(module_registry, MISTLINE(nota));
arrput(module_registry, MISTLINE(enet));
arrput(module_registry, MISTLINE(box2d));
#ifdef TRACY_ENABLE
arrput(module_registry, MISTLINE(tracy));

171
source/qjs_box2d.c Normal file
View File

@@ -0,0 +1,171 @@
#include "qjs_box2d.h"
#include "box2d/box2d.h"
#include <stdlib.h>
#define countof(a) (sizeof(a)/sizeof(*(a)))
static JSClassID box2d_world_id;
static JSClassID box2d_body_id;
static void box2d_world_finalizer(JSRuntime *rt, JSValue val)
{
b2WorldId *id = JS_GetOpaque(val, box2d_world_id);
if (!id) return;
b2DestroyWorld(*id);
}
static void box2d_body_finalizer(JSRuntime *rt, JSValue val)
{
b2BodyId *id = JS_GetOpaque(val, box2d_body_id);
if (!id) return;
if (b2Body_IsValid(*id))
b2DestroyBody(*id);
free(id);
}
static JSClassDef box2d_world = {
"Box2d World",
.finalizer = box2d_world_finalizer
};
static JSClassDef box2d_body = {
"Box2d Body",
.finalizer = box2d_body_finalizer
};
static JSValue js_box2d_body_get_position(JSContext *js, JSValueConst self) {
b2BodyId *bid = JS_GetOpaque(self, box2d_body_id);
if (!b2Body_IsValid(*bid)) return JS_ThrowReferenceError(js, "Body is invalid");
b2Vec2 pos = b2Body_GetPosition(*bid);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, pos.x));
JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, pos.y));
return obj;
}
static JSValue js_box2d_body_get_angle(JSContext *js, JSValueConst self) {
b2BodyId *bid = JS_GetOpaque(self, box2d_body_id);
if (!b2Body_IsValid(*bid)) return JS_ThrowReferenceError(js, "Body is invalid");
return JS_NewFloat64(js, b2Rot_GetAngle(b2Body_GetRotation(*bid)));
}
static const JSCFunctionListEntry js_box2d_body_funcs[] = {
JS_CFUNC_DEF("getPosition", 0, js_box2d_body_get_position),
JS_CFUNC_DEF("getAngle", 0, js_box2d_body_get_angle)
};
JSValue js_box2d_world_body(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
{
b2WorldId *wid = JS_GetOpaque(self, box2d_world_id);
if (!b2World_IsValid(*wid)) JS_ThrowReferenceError(js, "Cannot create body. World is invalid.");
b2BodyDef bdf = b2DefaultBodyDef();
b2BodyId *bid = malloc(sizeof(*bid));
*bid = b2CreateBody(*wid, &bdf);
JSValue obj = JS_NewObjectClass(js, box2d_body_id);
JS_SetOpaque(obj, bid);
return obj;
}
JSValue js_box2d_world_step(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
{
b2WorldId *wid = JS_GetOpaque(self, box2d_world_id);
if (!b2World_IsValid(*wid)) JS_ThrowReferenceError(js, "World is invalid.");
float timestep;
int substepcount;
JS_ToFloat64(js, &timestep, argv[0]);
JS_ToInt32(js, &substepcount, argv[1]);
b2World_Step(*wid, timestep, substepcount);
return JS_UNDEFINED;
}
JSValue js_box2d_world_get_gravity(JSContext *js, JSValueConst self)
{
b2WorldId *wid = JS_GetOpaque(self, box2d_world_id);
if (!b2World_IsValid(*wid)) return JS_ThrowReferenceError(js, "World is invalid");
b2Vec2 grav = b2World_GetGravity(*wid);
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "x", JS_NewFloat64(js, grav.x));
JS_SetPropertyStr(js, obj, "y", JS_NewFloat64(js, grav.y));
return obj;
}
JSValue js_box2d_world_set_gravity(JSContext *js, JSValueConst self, JSValue v)
{
b2WorldId *wid = JS_GetOpaque(self, box2d_world_id);
if (!b2World_IsValid(*wid)) return JS_ThrowReferenceError(js, "World is invalid");
JSValue x_val = JS_GetPropertyStr(js, v, "x");
JSValue y_val = JS_GetPropertyStr(js, v, "y");
double x, y;
if (JS_ToFloat64(js, &x, x_val) || JS_ToFloat64(js, &y, y_val)) {
JS_FreeValue(js, x_val);
JS_FreeValue(js, y_val);
printf("FAILED\n");
return JS_ThrowTypeError(js, "Gravity must have numeric x and y properties");
}
JS_FreeValue(js, x_val);
JS_FreeValue(js, y_val);
b2World_SetGravity(*wid, (b2Vec2){(float)x, (float)y});
return JS_UNDEFINED;
}
static const JSCFunctionListEntry js_box2d_world_funcs[] = {
JS_CFUNC_DEF("body", 0, js_box2d_world_body),
JS_CFUNC_DEF("step", 2, js_box2d_world_step),
JS_CGETSET_DEF("gravity", js_box2d_world_get_gravity, js_box2d_world_set_gravity),
};
static JSValue js_box2d_world(JSContext *js, JSValueConst self, int argc, JSValueConst *argv)
{
b2WorldDef world = b2DefaultWorldDef();
b2WorldId *wid = malloc(sizeof(*wid));
*wid = b2CreateWorld(&world);
JSValue obj = JS_NewObjectClass(js, box2d_world_id);
JS_SetOpaque(obj, wid);
return obj;
}
static const JSCFunctionListEntry js_box2d_funcs[] = {
JS_CFUNC_DEF("world", 0, js_box2d_world)
};
JSValue js_box2d_use(JSContext *ctx) {
JS_NewClassID(&box2d_world_id);
JS_NewClass(JS_GetRuntime(ctx), box2d_world_id, &box2d_world);
JSValue world_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, world_proto, js_box2d_world_funcs, countof(js_box2d_world_funcs));
JS_SetClassProto(ctx, box2d_world_id, world_proto);
JS_NewClassID(&box2d_body_id);
JS_NewClass(JS_GetRuntime(ctx), box2d_body_id, &box2d_body);
JSValue body_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, body_proto, js_box2d_body_funcs, countof(js_box2d_body_funcs));
JS_SetClassProto(ctx, box2d_body_id, body_proto);
JSValue export = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, export, js_box2d_funcs, countof(js_box2d_funcs));
return export;
}
static int js_box2d_init(JSContext *ctx, JSModuleDef *m) {
JSValue export_val = js_box2d_use(ctx);
return JS_SetModuleExport(ctx, m, "default", export_val);
}
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_box2d
#endif
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) {
JSModuleDef *m = JS_NewCModule(ctx, module_name, js_box2d_init);
if (!m) return NULL;
JS_AddModuleExport(ctx, m, "default");
return m;
}

8
source/qjs_box2d.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef QJS_BOX2D_H
#define QJS_BOX2D_H
#include "quickjs.h"
JSValue js_box2d_use(JSContext*);
#endif

View File

@@ -489,7 +489,6 @@ static int js_enet_init(JSContext *ctx, JSModuleDef *m) {
#define JS_INIT_MODULE js_init_module_enet
#endif
/* Module definition */
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) {
JSModuleDef *m = JS_NewCModule(ctx, module_name, js_enet_init);
if (!m) {

View File

@@ -2,6 +2,7 @@
#include "stb_ds.h"
#include "transform.h"
#include "math.h"
#include "float.h"
/* -------------------------------------------------------------------------
Cubic Spline Basis Matrices

4
subprojects/box2d.wrap Normal file
View File

@@ -0,0 +1,4 @@
[wrap-git]
directory=box2d
url=https://github.com/erincatto/box2d.git
revision=v3.0.0

13
tests/box2d.js Normal file
View File

@@ -0,0 +1,13 @@
var box2d = use('box2d')
var world = box2d.world()
console.log(world.gravity)
world.gravity = {x:0,y:-9.8}
console.log(world.gravity)
var body = world.body()
world.step(10, 4);
world.step(10, 4);
world.step(10, 4);
console.log(body.getPosition())