247 lines
6.9 KiB
C
247 lines
6.9 KiB
C
#include "qjs_transform.h"
|
|
#include "jsffi.h"
|
|
#include "qjs_macros.h"
|
|
#include "stb_ds.h"
|
|
|
|
#include "transform.h"
|
|
#include "HandmadeMath.h"
|
|
#include "cell.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;
|
|
}
|