This commit is contained in:
2025-11-30 00:17:04 -06:00
parent 36930ef007
commit 5fd83c6928
26 changed files with 379 additions and 553 deletions

View File

@@ -275,16 +275,10 @@ static const JSCFunctionListEntry js_SDL_Camera_funcs[] =
MIST_FUNC_DEF(camera, get_format, 0),
};
JSValue js_camera_use(JSContext *js) {
CELL_USE_INIT(
SDL_Init(SDL_INIT_CAMERA);
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_camera_funcs,countof(js_camera_funcs));
QJSCLASSPREP_FUNCS(SDL_Camera)
return mod;
}
JSValue js_sdl_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyStr(js, mod, "camera", js_camera_use(js));
return mod;
}
)

View File

@@ -105,8 +105,4 @@ static const JSCFunctionListEntry js_video_funcs[] = {
MIST_FUNC_DEF(os, make_video, 1),
};
JSValue js_video_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_video_funcs,countof(js_video_funcs));
return mod;
}
CELL_USE_FUNCS(js_video_funcs)

View File

@@ -13,6 +13,7 @@ extern void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t
// GEOMETRY FUNCTIONS
JSC_CCALL(geometry_rect_intersection,
rect a = js2rect(js,argv[0]);
rect b = js2rect(js,argv[1]);
@@ -1185,8 +1186,4 @@ static const JSCFunctionListEntry js_geometry_funcs[] = {
MIST_FUNC_DEF(geometry, make_rect_quad, 3),
};
JSValue js_geometry_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_geometry_funcs,countof(js_geometry_funcs));
return mod;
}
CELL_USE_FUNCS(js_geometry_funcs)

View File

@@ -280,8 +280,4 @@ const JSCFunctionListEntry js_graphics_funcs[] = {
MIST_FUNC_DEF(graphics, hsl_to_rgb, 3),
};
JSValue js_graphics_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_graphics_funcs,countof(js_graphics_funcs));
return mod;
}
CELL_USE_FUNCS(js_graphics_funcs)

View File

@@ -1,4 +1,4 @@
#include "quickjs.h"
#include "cell.h"
#include <stdint.h>
#include <math.h>
@@ -188,8 +188,7 @@ static const JSCFunctionListEntry js_layout_funcs[] = {
JS_CFUNC_DEF("make_context", 0, js_layout_context_new)
};
JSValue js_layout_use(JSContext *js)
{
CELL_USE_INIT(
JS_NewClassID(&js_layout_class_id);
JS_NewClass(JS_GetRuntime(js), js_layout_class_id, &js_layout_class);
@@ -229,4 +228,4 @@ JSValue js_layout_use(JSContext *js)
JS_SetPropertyStr(js, export, "contain", contain);
return export;
}
)

View File

@@ -505,8 +505,4 @@ static const JSCFunctionListEntry js_math_funcs[] = {
MIST_FUNC_DEF(math, from_to, 5),
};
JSValue js_math_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_math_funcs,countof(js_math_funcs));
return mod;
}
CELL_USE_FUNCS(js_math_funcs)

View File

@@ -31,7 +31,6 @@ SDL_Window *js2SDL_Window(JSContext *js, JSValue v);
JSValue SDL_Window2js(JSContext *js, SDL_Window *w);
void *get_gpu_buffer(JSContext *js, JSValue argv, size_t *stride, size_t *size);
double js_getnum_str(JSContext *js, JSValue v, const char *str);
sprite *js2sprite(JSContext *js, JSValue v);
HMM_Vec3 js2vec3(JSContext *js, JSValue v);
JSValue vec32js(JSContext *js, HMM_Vec3 v);
HMM_Vec4 js2vec4(JSContext *js, JSValue v);

View File

@@ -122,12 +122,11 @@ static const JSCFunctionListEntry js_dmon_funcs[] = {
JS_CFUNC_DEF("poll", 1, js_dmon_poll)
};
JSValue js_dmon_use(JSContext *js)
{
CELL_USE_INIT(
JSValue export = JS_NewObject(js);
JS_SetPropertyFunctionList(js, export, js_dmon_funcs, sizeof(js_dmon_funcs)/sizeof(JSCFunctionListEntry));
dmon_init();
return export;
}
)

View File

@@ -505,8 +505,7 @@ static const JSCFunctionListEntry js_mod_funcs[] = {
JS_CFUNC_DEF("create", 1, js_mod_create)
};
JSValue js_renderer_use(JSContext *ctx) {
// Create an object that will hold all the "renderer" methods
CELL_USE_INIT(
JSValue obj = JS_NewObject(ctx);
// Add all the above C functions as properties of that object
@@ -514,4 +513,4 @@ JSValue js_renderer_use(JSContext *ctx) {
js_renderer_funcs,
sizeof(js_renderer_funcs)/sizeof(JSCFunctionListEntry));
return obj;
}
)

View File

@@ -4,11 +4,6 @@
#include <SDL3/SDL.h>
#include "cell.h"
JSValue js_input_use(JSContext *ctx);
JSValue js_camera_use(JSContext *ctx);
JSValue js_sdl_audio_use(JSContext *ctx);
JSValue js_sdl_use(JSContext *js);
SDL_PixelFormat str2pixelformat(const char *str);
SDL_PixelFormat js2pixelformat(JSContext *js, JSValue v);
JSValue pixelformat2js(JSContext *js, SDL_PixelFormat format);
@@ -31,4 +26,4 @@ typedef struct SDL_Surface SDL_Surface;
SDL_Surface *js2SDL_Surface(JSContext *js, JSValue v);
JSValue SDL_Surface2js(JSContext *js, SDL_Surface *s);
#endif /* QJS_SDL_H */
#endif

View File

@@ -1,15 +0,0 @@
#ifndef QJS_SDL_GPU_H
#define QJS_SDL_GPU_H
#include "cell.h"
#include "sprite.h"
// Forward declarations for sprite sorting functions
int sort_sprite(const sprite *a, const sprite *b);
int sort_sprite_backtofront(const sprite *a, const sprite *b);
int sort_sprite_fronttoback(const sprite *a, const sprite *b);
int sort_sprite_texture(const sprite *a, const sprite *b);
JSValue js_sdl_gpu_use(JSContext *js);
#endif

View File

@@ -1,12 +0,0 @@
#ifndef QJS_SDL_INPUT_H
#define QJS_SDL_INPUT_H
#include <quickjs.h>
const char* event_type_to_string(uint32_t event_type);
const char* mouse_button_to_string(int mouse);
// JavaScript module entry point
JSValue js_input_use(JSContext *js);
#endif // QJS_SDL_INPUT_H

View File

@@ -4,8 +4,6 @@
#include "cell.h"
#include <SDL3/SDL_surface.h>
JSValue js_sdl_surface_use(JSContext *js);
// Functions generated by QJSCLASS macro
JSValue SDL_Surface2js(JSContext *js, SDL_Surface *s);
SDL_Surface *js2SDL_Surface(JSContext *js, JSValue val);

View File

@@ -1,107 +0,0 @@
#include "qjs_sprite.h"
#include "prosperon.h"
#include "qjs_macros.h"
#include "sprite.h"
#include "HandmadeMath.h"
// Sprite class definitions
static JSClassID js_sprite_id;
static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
sprite *sp = JS_GetOpaque(val, js_sprite_id);
if (!sp) return;
JS_MarkValue(rt, sp->image, mark_func);
}
// Class definition for sprite with mark function for GC
QJSCLASSMARK(sprite,)
// SPRITE GETTER/SETTER FUNCTIONS
JSC_GETSET(sprite, pos, vec2)
JSC_GETSET(sprite, center, vec2)
JSC_GETSET(sprite, layer, number)
JSC_GETSET(sprite, color, color)
JSC_GETSET(sprite, skew, vec2)
JSC_GETSET(sprite, scale, vec2)
JSC_GETSET(sprite, rotation, number)
// SPRITE ACTION FUNCTIONS
JSC_CCALL(sprite_move,
sprite *sp = js2sprite(js,self);
HMM_Vec2 mv = js2vec2(js,argv[0]);
sp->pos.x += mv.x;
sp->pos.y += mv.y;
)
JSC_CCALL(sprite_set_affine,
sprite *sp = js2sprite(js,self);
sprite_apply(sp);
)
JSC_CCALL(sprite_set_image,
sprite *sp = js2sprite(js,self);
if (!JS_IsNull(sp->image))
JS_FreeValue(js,sp->image);
sp->image = JS_DupValue(js, argv[0]);
)
static const JSCFunctionListEntry js_sprite_funcs[] = {
MIST_FUNC_DEF(sprite, set_affine, 0),
MIST_FUNC_DEF(sprite, set_image, 1),
MIST_FUNC_DEF(sprite, move, 1),
JS_CGETSET_DEF("pos", js_sprite_get_pos, js_sprite_set_pos),
JS_CGETSET_DEF("scale", js_sprite_get_scale, js_sprite_set_scale),
JS_CGETSET_DEF("skew", js_sprite_get_skew, js_sprite_set_skew),
JS_CGETSET_DEF("layer", js_sprite_get_layer, js_sprite_set_layer),
JS_CGETSET_DEF("color", js_sprite_get_color, js_sprite_set_color),
JS_CGETSET_DEF("center", js_sprite_get_center, js_sprite_set_center),
JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation),
};
// Constructor function for sprite
static JSValue js_sprite_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) {
sprite *sp = make_sprite();
if (!sp) return JS_ThrowOutOfMemory(js);
// If an options object is provided, initialize the sprite with it
if (argc > 0 && JS_IsObject(argv[0])) {
JS_GETATOM(js, sp->pos, argv[0], pos, vec2)
JS_GETATOM(js, sp->center, argv[0], center, vec2)
JS_GETATOM(js, sp->skew, argv[0], skew, vec2)
JS_GETATOM(js, sp->scale, argv[0], scale, vec2)
JS_GETATOM(js, sp->rotation, argv[0], rotation, number)
JS_GETATOM(js, sp->layer, argv[0], layer, number)
JS_GETATOM(js, sp->color, argv[0], color, color)
JSValue image = JS_GetProperty(js, argv[0], JS_NewAtom(js, "image"));
if (!JS_IsNull(image)) {
sp->image = image; // Transfer ownership, no need to dup
}
}
// Default values if not provided
if (sp->scale.x == 0 && sp->scale.y == 0) {
sp->scale.x = 1;
sp->scale.y = 1;
}
if (sp->color.w == 0) sp->color.w = 1; // Default alpha to 1
sprite_apply(sp);
return sprite2js(js, sp);
}
JSValue js_sprite_use(JSContext *js) {
// Register the sprite class
QJSCLASSPREP_FUNCS(sprite);
// Create the constructor function
JSValue ctor = JS_NewCFunction2(js, js_sprite_constructor, "sprite", 1, JS_CFUNC_constructor, 0);
// Set the prototype on the constructor
JSValue proto = JS_GetClassProto(js, js_sprite_id);
JS_SetConstructor(js, ctor, proto);
JS_FreeValue(js, proto);
return ctor;
}

View File

@@ -1,12 +0,0 @@
#ifndef QJS_SPRITE_H
#define QJS_SPRITE_H
#include "cell.h"
#include "sprite.h"
JSValue js_sprite_use(JSContext *ctx);
sprite *js2sprite(JSContext *js, JSValue v);
#endif /* QJS_SPRITE_H */

View File

@@ -1,245 +0,0 @@
#include "cell.h"
#include "prosperon.h"
#include "qjs_macros.h"
#include "stb_ds.h"
#include "transform.h"
#include "HandmadeMath.h"
// Transform class definitions
JSClassID js_transform_id;
static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
transform *t = JS_GetOpaque(val, js_transform_id);
if (!t) return;
// Mark the JSValue references stored in your struct
JS_MarkValue(rt, t->change_hook, mark_func);
JS_MarkValue(rt, t->jsparent, mark_func);
// Mark the array elements
for (int i = 0; i < arrlen(t->jschildren); i++)
JS_MarkValue(rt, t->jschildren[i], mark_func);
}
QJSCLASSMARK_EXTERN(transform,)
// TRANSFORM GETTER/SETTER FUNCTIONS
JSC_GETSET_APPLY(transform, pos, vec3)
JSC_GETSET_APPLY(transform, scale, vec3)
JSC_GETSET_APPLY(transform, rotation, quat)
static JSValue js_transform_get_change_hook(JSContext *js, JSValueConst self)
{
transform *t = js2transform(js,self);
return JS_DupValue(js,t->change_hook);
}
static JSValue js_transform_set_change_hook(JSContext *js, JSValueConst self, JSValue v)
{
transform *t = js2transform(js,self);
if (!JS_IsNull(v) && !JS_IsFunction(js,v)) return JS_ThrowReferenceError(js, "Hook must be a function.");
JS_FreeValue(js,t->change_hook);
t->change_hook = JS_DupValue(js,v);
return JS_NULL;
}
static JSValue js_transform_get_parent(JSContext *js, JSValueConst self)
{
transform *t = js2transform(js,self);
if (t->parent) return JS_DupValue(js,t->jsparent);
return JS_NULL;
}
static JSValue js_transform_set_parent(JSContext *js, JSValueConst self, JSValue v)
{
transform *p = js2transform(js,v);
if (!JS_IsNull(v) && !p)
return JS_ThrowReferenceError(js,"Parent must be another transform.");
transform *t = js2transform(js,self);
if (t == p)
return JS_ThrowReferenceError(js, "A transform cannot be its own parent.");
if (t->parent) {
transform *cur_parent = t->parent;
JS_FreeValue(js,t->jsparent);
t->jsparent = JS_NULL;
for (int i = 0; i < arrlen(cur_parent->children); i++) {
if (cur_parent->children[i] == t) {
arrdelswap(cur_parent->children,i);
break;
}
}
for (int i = 0; i < arrlen(cur_parent->jschildren); i++) {
if (JS_SameValue(js,cur_parent->jschildren[i],self)) {
JS_FreeValue(js,cur_parent->jschildren[i]);
arrdelswap(cur_parent->jschildren,i);
break;
}
}
}
t->parent = p;
t->jsparent = JS_DupValue(js,v);
if (p) {
arrput(p->children, t);
JSValue child = JS_DupValue(js,self);
arrput(p->jschildren,child);
}
transform_apply(t);
return JS_NULL;
}
// TRANSFORM ACTION FUNCTIONS
JSC_CCALL(transform_move,
transform *t = js2transform(js,self);
transform_move(t, js2vec3(js,argv[0]));
)
JSC_CCALL(transform_lookat,
HMM_Vec3 point = js2vec3(js,argv[0]);
transform *go = js2transform(js,self);
HMM_Mat4 m = HMM_LookAt_RH(go->pos, point, vUP);
go->rotation = HMM_M4ToQ_RH(m);
transform_apply(go);
)
JSC_CCALL(transform_rotate,
HMM_Vec3 axis = js2vec3(js,argv[0]);
transform *t = js2transform(js,self);
HMM_Quat rot = HMM_QFromAxisAngle_RH(axis, js2angle(js,argv[1]));
t->rotation = HMM_MulQ(t->rotation,rot);
transform_apply(t);
)
JSC_CCALL(transform_angle,
HMM_Vec3 axis = js2vec3(js,argv[0]);
transform *t = js2transform(js,self);
if (axis.x) return angle2js(js,HMM_Q_Roll(t->rotation));
if (axis.y) return angle2js(js,HMM_Q_Pitch(t->rotation));
if (axis.z) return angle2js(js,HMM_Q_Yaw(t->rotation));
return angle2js(js,0);
)
JSC_CCALL(transform_direction,
transform *t = js2transform(js,self);
return vec32js(js, HMM_QVRot(js2vec3(js,argv[0]), t->rotation));
)
JSC_CCALL(transform_phys2d,
transform *t = js2transform(js,self);
HMM_Vec2 v = js2vec2(js,argv[0]);
float av = js2number(js,argv[1]);
float dt = js2number(js,argv[2]);
transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0});
HMM_Quat rot = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,1}, av*dt);
t->rotation = HMM_MulQ(t->rotation, rot);
transform_apply(t);
)
JSC_CCALL(transform_unit,
transform *t = js2transform(js,self);
t->pos = v3zero;
t->rotation = QUAT1;
t->scale = v3one;
transform_apply(t);
)
JSC_CCALL(transform_trs,
transform *t = js2transform(js,self);
t->pos = JS_IsNull(argv[0]) ? v3zero : js2vec3(js,argv[0]);
t->rotation = JS_IsNull(argv[1]) ? QUAT1 : js2quat(js,argv[1]);
t->scale = JS_IsNull(argv[2]) ? v3one : js2vec3(js,argv[2]);
transform_apply(t);
)
JSC_CCALL(transform_rect,
transform *t = js2transform(js,self);
rect r = js2rect(js,argv[0]);
t->pos = (HMM_Vec3){r.x,r.y,0};
t->scale = (HMM_Vec3){r.w,r.h,1};
t->rotation = QUAT1;
transform_apply(t);
)
JSC_CCALL(transform_array,
transform *t = js2transform(js,self);
HMM_Mat4 m= transform2mat(t);
ret = JS_NewArray(js);
for (int i = 0; i < 16; i++)
JS_SetPropertyUint32(js,ret,i, number2js(js,m.em[i]));
)
JSC_CCALL(transform_torect,
transform *t = js2transform(js,self);
return rect2js(js,transform2rect(t));
)
JSC_CCALL(transform_children,
transform *t = js2transform(js,self);
ret = JS_NewArray(js);
for (int i = 0; i < arrlen(t->jschildren); i++)
JS_SetPropertyUint32(js,ret,i,JS_DupValue(js,t->jschildren[i]));
)
static const JSCFunctionListEntry js_transform_funcs[] = {
CGETSET_ADD(transform, pos),
CGETSET_ADD(transform, scale),
CGETSET_ADD(transform, rotation),
CGETSET_ADD(transform, parent),
CGETSET_ADD(transform, change_hook),
MIST_FUNC_DEF(transform, trs, 3),
MIST_FUNC_DEF(transform, phys2d, 3),
MIST_FUNC_DEF(transform, move, 1),
MIST_FUNC_DEF(transform, rotate, 2),
MIST_FUNC_DEF(transform, angle, 1),
MIST_FUNC_DEF(transform, lookat, 1),
MIST_FUNC_DEF(transform, direction, 1),
MIST_FUNC_DEF(transform, unit, 0),
MIST_FUNC_DEF(transform, rect, 1),
MIST_FUNC_DEF(transform, array, 0),
MIST_FUNC_DEF(transform, torect, 0),
MIST_FUNC_DEF(transform, children, 0),
};
// Constructor function for transform
static JSValue js_transform_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) {
transform *t = make_transform();
if (!t) return JS_ThrowOutOfMemory(js);
JSValue ret = transform2js(js, t);
t->self = ret;
return ret;
}
JSC_CCALL(transform_clean,
clean_all(js);
)
static const JSCFunctionListEntry js_transform_ctor_funcs[] = {
MIST_FUNC_DEF(transform, clean, 0),
};
JSValue js_transform_use(JSContext *js) {
// Register the transform class
QJSCLASSPREP_FUNCS(transform);
// Create the constructor function
JSValue ctor = JS_NewCFunction2(js, js_transform_constructor, "transform", 0, JS_CFUNC_constructor, 0);
// Set the prototype on the constructor
JSValue proto = JS_GetClassProto(js, js_transform_id);
JS_SetConstructor(js, ctor, proto);
JS_FreeValue(js, proto);
// Add static methods to the constructor
JS_SetPropertyFunctionList(js, ctor, js_transform_ctor_funcs, countof(js_transform_ctor_funcs));
return ctor;
}

View File

@@ -172,9 +172,4 @@ static const JSCFunctionListEntry js_qoi_funcs[] = {
MIST_FUNC_DEF(qoi, decode, 1)
};
JSValue js_qoi_use(JSContext *js)
{
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js, mod, js_qoi_funcs, countof(js_qoi_funcs));
return mod;
}
CELL_USE_FUNCS(js_qoi_funcs)

View File

@@ -1,6 +1,3 @@
#include "qjs_macros.h"
#include "quickjs.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_audio.h>
#include "cell.h"
@@ -359,8 +356,7 @@ static const JSCFunctionListEntry js_sdl_audio_funcs[] = {
JS_CFUNC_DEF("mix_audio", 4, js_mix_audio),
};
// Use function
JSValue js_sdl_audio_use(JSContext *js) {
CELL_USE_INIT(
JS_NewClassID(&js_SDL_AudioStream_id);
JS_NewClass(JS_GetRuntime(js), js_SDL_AudioStream_id, &js_SDL_AudioStream_class);
JSValue proto = JS_NewObject(js);
@@ -370,4 +366,4 @@ JSValue js_sdl_audio_use(JSContext *js) {
JSValue export = JS_NewObject(js);
JS_SetPropertyFunctionList(js, export, js_sdl_audio_funcs, countof(js_sdl_audio_funcs));
return export;
}
)

View File

@@ -1656,8 +1656,7 @@ static JSValue js_gpu_constructor(JSContext *js, JSValueConst new_target, int ar
}
// Function to register module
JSValue js_sdl_gpu_use(JSContext *js)
{
CELL_USE_INIT(
JSValue ret = JS_NewObject(js);
// Initialize classes
@@ -1708,4 +1707,4 @@ JSValue js_sdl_gpu_use(JSContext *js)
JS_SetPropertyStr(js, ret, "texture", texture_ctor);
return ret;
}
)

View File

@@ -783,8 +783,4 @@ static const JSCFunctionListEntry js_input_funcs[] = {
MIST_FUNC_DEF(input, gamepad_id_to_type, 1),
};
JSValue js_input_use(JSContext *js) {
JSValue mod = JS_NewObject(js);
JS_SetPropertyFunctionList(js,mod,js_input_funcs,countof(js_input_funcs));
return mod;
}
CELL_USE_FUNCS(js_input_funcs)

View File

@@ -1056,8 +1056,7 @@ JSC_CCALL(surface_convert_generic,
return result;
)
JSValue js_sdl_surface_use(JSContext *js)
{
CELL_USE_INIT(
QJSCLASSPREP_FUNCS(SDL_Surface)
// Add the surface constructor
@@ -1084,4 +1083,4 @@ JSValue js_sdl_surface_use(JSContext *js)
JS_SetPropertyStr(js, ctor, "dup", JS_NewCFunction(js, js_surface_dup_img, "dup", 1));
return ctor;
}
)

View File

@@ -749,7 +749,7 @@ JSC_CCALL(sdl_set_cursor,
SDL_SetCursor(cursor);
)
JSValue js_sdl_video_use(JSContext *js) {
CELL_USE_INIT(
if (!SDL_Init(SDL_INIT_VIDEO))
return JS_ThrowInternalError(js, "Unable to initialize video subsystem: %s", SDL_GetError());
@@ -775,4 +775,4 @@ JSValue js_sdl_video_use(JSContext *js) {
JS_NewCFunction(js, js_sdl_set_cursor, "setCursor", 1));
return ret;
}
)

View File

@@ -1,85 +0,0 @@
#ifndef SPLINE_H
#define SPLINE_H
#include "HandmadeMath.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
These were already in your original header:
*/
// Adaptive CatmullRom in 2D / 3D / 4D (by minimum angle):
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma);
HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma); /* not yet implemented in .c, placeholder */
HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma); /* not yet implemented in .c, placeholder */
// Adaptive Bezier in 2D (by minimum angle):
HMM_Vec2 *bezier_cb_ma_v2(HMM_Vec2 *cp, float ma);
// Generic “single-segment” query for 2D control points + basis matrix:
HMM_Vec2 spline_query(HMM_Vec2 *cp, float d, HMM_Mat4 *basis);
// CatmullRom “entire spline” queries:
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d); // position
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d); // tangent
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d); // curvature
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d); // 3rd derivative (“wiggle”)
// Computes approximate length of a 2D CatmullRom spline:
float catmull_rom_len(HMM_Vec2 *cp);
// Returns closest point on a 2D CatmullRom curve given an external 2D point `p`:
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p);
/*
Additional convenience functions for *single-segment* cubic splines:
Each of these expects exactly 4 control points in `p[0..3]`,
and a parameter t in [0..1]. They pick the appropriate matrix internally.
*/
// Hermite:
HMM_Vec2 cubic_hermite_pos(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_tan(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_curv(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_wig(HMM_Vec2 *p, float d);
// B-spline:
HMM_Vec2 b_spline_pos(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_tan(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_curv(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_wig(HMM_Vec2 *p, float d);
// Bezier:
HMM_Vec2 bezier_pos(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_tan(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_curv(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_wig(HMM_Vec2 *p, float d);
/*
Uniform sampling of a *single* 4-point segment in 2D:
Returns an array of points (stb_ds dynamic array).
*/
HMM_Vec2 *spline_v2(HMM_Vec2 *p, HMM_Mat4 *m, int segs);
/*
Adaptive subdivision routines (single-segment) in 2D:
- Subdivide by min segment length
- Subdivide by “max angle” proxy
*/
HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret);
HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg);
HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr);
HMM_Vec2 *spline_min_angle(HMM_Vec2 *p, const HMM_Mat4 *B, float min_angle, HMM_Vec2 *arr);
#ifdef __cplusplus
}
#endif
#endif /* SPLINE_H */

107
sprite.c
View File

@@ -1,4 +1,9 @@
#include "qjs_sprite.h"
#include "prosperon.h"
#include "qjs_macros.h"
#include "sprite.h"
#include "HandmadeMath.h"
sprite *make_sprite(void)
{
@@ -27,3 +32,105 @@ void sprite_apply(sprite *sp)
.y = -k.y * s + c };
}
// Sprite class definitions
static JSClassID js_sprite_id;
static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
sprite *sp = JS_GetOpaque(val, js_sprite_id);
if (!sp) return;
JS_MarkValue(rt, sp->image, mark_func);
}
// Class definition for sprite with mark function for GC
QJSCLASSMARK(sprite,)
// SPRITE GETTER/SETTER FUNCTIONS
JSC_GETSET(sprite, pos, vec2)
JSC_GETSET(sprite, center, vec2)
JSC_GETSET(sprite, layer, number)
JSC_GETSET(sprite, color, color)
JSC_GETSET(sprite, skew, vec2)
JSC_GETSET(sprite, scale, vec2)
JSC_GETSET(sprite, rotation, number)
// SPRITE ACTION FUNCTIONS
JSC_CCALL(sprite_move,
sprite *sp = js2sprite(js,self);
HMM_Vec2 mv = js2vec2(js,argv[0]);
sp->pos.x += mv.x;
sp->pos.y += mv.y;
)
JSC_CCALL(sprite_set_affine,
sprite *sp = js2sprite(js,self);
sprite_apply(sp);
)
JSC_CCALL(sprite_set_image,
sprite *sp = js2sprite(js,self);
if (!JS_IsNull(sp->image))
JS_FreeValue(js,sp->image);
sp->image = JS_DupValue(js, argv[0]);
)
static const JSCFunctionListEntry js_sprite_funcs[] = {
MIST_FUNC_DEF(sprite, set_affine, 0),
MIST_FUNC_DEF(sprite, set_image, 1),
MIST_FUNC_DEF(sprite, move, 1),
JS_CGETSET_DEF("pos", js_sprite_get_pos, js_sprite_set_pos),
JS_CGETSET_DEF("scale", js_sprite_get_scale, js_sprite_set_scale),
JS_CGETSET_DEF("skew", js_sprite_get_skew, js_sprite_set_skew),
JS_CGETSET_DEF("layer", js_sprite_get_layer, js_sprite_set_layer),
JS_CGETSET_DEF("color", js_sprite_get_color, js_sprite_set_color),
JS_CGETSET_DEF("center", js_sprite_get_center, js_sprite_set_center),
JS_CGETSET_DEF("rotation", js_sprite_get_rotation, js_sprite_set_rotation),
};
// Constructor function for sprite
static JSValue js_sprite_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) {
sprite *sp = make_sprite();
if (!sp) return JS_ThrowOutOfMemory(js);
// If an options object is provided, initialize the sprite with it
if (argc > 0 && JS_IsObject(argv[0])) {
JS_GETATOM(js, sp->pos, argv[0], pos, vec2)
JS_GETATOM(js, sp->center, argv[0], center, vec2)
JS_GETATOM(js, sp->skew, argv[0], skew, vec2)
JS_GETATOM(js, sp->scale, argv[0], scale, vec2)
JS_GETATOM(js, sp->rotation, argv[0], rotation, number)
JS_GETATOM(js, sp->layer, argv[0], layer, number)
JS_GETATOM(js, sp->color, argv[0], color, color)
JSValue image = JS_GetProperty(js, argv[0], JS_NewAtom(js, "image"));
if (!JS_IsNull(image)) {
sp->image = image; // Transfer ownership, no need to dup
}
}
// Default values if not provided
if (sp->scale.x == 0 && sp->scale.y == 0) {
sp->scale.x = 1;
sp->scale.y = 1;
}
if (sp->color.w == 0) sp->color.w = 1; // Default alpha to 1
sprite_apply(sp);
return sprite2js(js, sp);
}
CELL_USE_INIT(
// Register the sprite class
QJSCLASSPREP_FUNCS(sprite);
// Create the constructor function
JSValue ctor = JS_NewCFunction2(js, js_sprite_constructor, "sprite", 1, JS_CFUNC_constructor, 0);
// Set the prototype on the constructor
JSValue proto = JS_GetClassProto(js, js_sprite_id);
JS_SetConstructor(js, ctor, proto);
JS_FreeValue(js, proto);
return ctor;
)

View File

@@ -124,8 +124,7 @@ static JSValue js_font_constructor(JSContext *ctx, JSValueConst new_target, int
}
// Initialize the staef module
JSValue js_staef_use(JSContext *js)
{
CELL_USE_INIT(
JSValue mod = JS_NewObject(js);
JSValue proto;
@@ -144,4 +143,4 @@ JSValue js_staef_use(JSContext *js)
JS_SetPropertyStr(js, mod, "font", font_ctor);
return mod;
}
)

View File

@@ -1,7 +1,12 @@
#include "transform.h"
#include "cell.h"
#include "prosperon.h"
#include "qjs_macros.h"
#include "stb_ds.h"
#include <string.h>
#include <stdio.h>
#include "stb_ds.h"
#include "transform.h"
#include "HandmadeMath.h"
static transform **dirties;
@@ -154,3 +159,241 @@ transform mat2transform(HMM_Mat4 m)
t.rotation = HMM_M4ToQ_RH(m);
return t;
}
// Transform class definitions
JSClassID js_transform_id;
static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
transform *t = JS_GetOpaque(val, js_transform_id);
if (!t) return;
// Mark the JSValue references stored in your struct
JS_MarkValue(rt, t->change_hook, mark_func);
JS_MarkValue(rt, t->jsparent, mark_func);
// Mark the array elements
for (int i = 0; i < arrlen(t->jschildren); i++)
JS_MarkValue(rt, t->jschildren[i], mark_func);
}
QJSCLASSMARK_EXTERN(transform,)
// TRANSFORM GETTER/SETTER FUNCTIONS
JSC_GETSET_APPLY(transform, pos, vec3)
JSC_GETSET_APPLY(transform, scale, vec3)
JSC_GETSET_APPLY(transform, rotation, quat)
static JSValue js_transform_get_change_hook(JSContext *js, JSValueConst self)
{
transform *t = js2transform(js,self);
return JS_DupValue(js,t->change_hook);
}
static JSValue js_transform_set_change_hook(JSContext *js, JSValueConst self, JSValue v)
{
transform *t = js2transform(js,self);
if (!JS_IsNull(v) && !JS_IsFunction(js,v)) return JS_ThrowReferenceError(js, "Hook must be a function.");
JS_FreeValue(js,t->change_hook);
t->change_hook = JS_DupValue(js,v);
return JS_NULL;
}
static JSValue js_transform_get_parent(JSContext *js, JSValueConst self)
{
transform *t = js2transform(js,self);
if (t->parent) return JS_DupValue(js,t->jsparent);
return JS_NULL;
}
static JSValue js_transform_set_parent(JSContext *js, JSValueConst self, JSValue v)
{
transform *p = js2transform(js,v);
if (!JS_IsNull(v) && !p)
return JS_ThrowReferenceError(js,"Parent must be another transform.");
transform *t = js2transform(js,self);
if (t == p)
return JS_ThrowReferenceError(js, "A transform cannot be its own parent.");
if (t->parent) {
transform *cur_parent = t->parent;
JS_FreeValue(js,t->jsparent);
t->jsparent = JS_NULL;
for (int i = 0; i < arrlen(cur_parent->children); i++) {
if (cur_parent->children[i] == t) {
arrdelswap(cur_parent->children,i);
break;
}
}
for (int i = 0; i < arrlen(cur_parent->jschildren); i++) {
if (JS_SameValue(js,cur_parent->jschildren[i],self)) {
JS_FreeValue(js,cur_parent->jschildren[i]);
arrdelswap(cur_parent->jschildren,i);
break;
}
}
}
t->parent = p;
t->jsparent = JS_DupValue(js,v);
if (p) {
arrput(p->children, t);
JSValue child = JS_DupValue(js,self);
arrput(p->jschildren,child);
}
transform_apply(t);
return JS_NULL;
}
// TRANSFORM ACTION FUNCTIONS
JSC_CCALL(transform_move,
transform *t = js2transform(js,self);
transform_move(t, js2vec3(js,argv[0]));
)
JSC_CCALL(transform_lookat,
HMM_Vec3 point = js2vec3(js,argv[0]);
transform *go = js2transform(js,self);
HMM_Mat4 m = HMM_LookAt_RH(go->pos, point, vUP);
go->rotation = HMM_M4ToQ_RH(m);
transform_apply(go);
)
JSC_CCALL(transform_rotate,
HMM_Vec3 axis = js2vec3(js,argv[0]);
transform *t = js2transform(js,self);
HMM_Quat rot = HMM_QFromAxisAngle_RH(axis, js2angle(js,argv[1]));
t->rotation = HMM_MulQ(t->rotation,rot);
transform_apply(t);
)
JSC_CCALL(transform_angle,
HMM_Vec3 axis = js2vec3(js,argv[0]);
transform *t = js2transform(js,self);
if (axis.x) return angle2js(js,HMM_Q_Roll(t->rotation));
if (axis.y) return angle2js(js,HMM_Q_Pitch(t->rotation));
if (axis.z) return angle2js(js,HMM_Q_Yaw(t->rotation));
return angle2js(js,0);
)
JSC_CCALL(transform_direction,
transform *t = js2transform(js,self);
return vec32js(js, HMM_QVRot(js2vec3(js,argv[0]), t->rotation));
)
JSC_CCALL(transform_phys2d,
transform *t = js2transform(js,self);
HMM_Vec2 v = js2vec2(js,argv[0]);
float av = js2number(js,argv[1]);
float dt = js2number(js,argv[2]);
transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0});
HMM_Quat rot = HMM_QFromAxisAngle_RH((HMM_Vec3){0,0,1}, av*dt);
t->rotation = HMM_MulQ(t->rotation, rot);
transform_apply(t);
)
JSC_CCALL(transform_unit,
transform *t = js2transform(js,self);
t->pos = v3zero;
t->rotation = QUAT1;
t->scale = v3one;
transform_apply(t);
)
JSC_CCALL(transform_trs,
transform *t = js2transform(js,self);
t->pos = JS_IsNull(argv[0]) ? v3zero : js2vec3(js,argv[0]);
t->rotation = JS_IsNull(argv[1]) ? QUAT1 : js2quat(js,argv[1]);
t->scale = JS_IsNull(argv[2]) ? v3one : js2vec3(js,argv[2]);
transform_apply(t);
)
JSC_CCALL(transform_rect,
transform *t = js2transform(js,self);
rect r = js2rect(js,argv[0]);
t->pos = (HMM_Vec3){r.x,r.y,0};
t->scale = (HMM_Vec3){r.w,r.h,1};
t->rotation = QUAT1;
transform_apply(t);
)
JSC_CCALL(transform_array,
transform *t = js2transform(js,self);
HMM_Mat4 m= transform2mat(t);
ret = JS_NewArray(js);
for (int i = 0; i < 16; i++)
JS_SetPropertyUint32(js,ret,i, number2js(js,m.em[i]));
)
JSC_CCALL(transform_torect,
transform *t = js2transform(js,self);
return rect2js(js,transform2rect(t));
)
JSC_CCALL(transform_children,
transform *t = js2transform(js,self);
ret = JS_NewArray(js);
for (int i = 0; i < arrlen(t->jschildren); i++)
JS_SetPropertyUint32(js,ret,i,JS_DupValue(js,t->jschildren[i]));
)
static const JSCFunctionListEntry js_transform_funcs[] = {
CGETSET_ADD(transform, pos),
CGETSET_ADD(transform, scale),
CGETSET_ADD(transform, rotation),
CGETSET_ADD(transform, parent),
CGETSET_ADD(transform, change_hook),
MIST_FUNC_DEF(transform, trs, 3),
MIST_FUNC_DEF(transform, phys2d, 3),
MIST_FUNC_DEF(transform, move, 1),
MIST_FUNC_DEF(transform, rotate, 2),
MIST_FUNC_DEF(transform, angle, 1),
MIST_FUNC_DEF(transform, lookat, 1),
MIST_FUNC_DEF(transform, direction, 1),
MIST_FUNC_DEF(transform, unit, 0),
MIST_FUNC_DEF(transform, rect, 1),
MIST_FUNC_DEF(transform, array, 0),
MIST_FUNC_DEF(transform, torect, 0),
MIST_FUNC_DEF(transform, children, 0),
};
// Constructor function for transform
static JSValue js_transform_constructor(JSContext *js, JSValueConst new_target, int argc, JSValueConst *argv) {
transform *t = make_transform();
if (!t) return JS_ThrowOutOfMemory(js);
JSValue ret = transform2js(js, t);
t->self = ret;
return ret;
}
JSC_CCALL(transform_clean,
clean_all(js);
)
static const JSCFunctionListEntry js_transform_ctor_funcs[] = {
MIST_FUNC_DEF(transform, clean, 0),
};
CELL_USE_INIT(
// Register the transform class
QJSCLASSPREP_FUNCS(transform);
// Create the constructor function
JSValue ctor = JS_NewCFunction2(js, js_transform_constructor, "transform", 0, JS_CFUNC_constructor, 0);
// Set the prototype on the constructor
JSValue proto = JS_GetClassProto(js, js_transform_id);
JS_SetConstructor(js, ctor, proto);
JS_FreeValue(js, proto);
// Add static methods to the constructor
JS_SetPropertyFunctionList(js, ctor, js_transform_ctor_funcs, countof(js_transform_ctor_funcs));
return ctor;
)