fix camera, spline

This commit is contained in:
John Alanbrook 2023-12-19 21:34:36 +00:00
parent a1aff79d5c
commit dacad57577
16 changed files with 174 additions and 156 deletions

View file

@ -44,7 +44,7 @@ var component = {
make(go) {
var nc = Object.create(this);
// nc.gameobject = go;
nc.gameobject = go;
Object.assign(nc, this._enghook(go.body));
nc.sync();
assign_impl(nc,this.impl);
@ -61,9 +61,7 @@ var component = {
prepare_center() {},
finish_center() {},
extend(spec) {
return Object.copy(this, spec);
},
extend(spec) { return Object.copy(this, spec); },
};
component.sprite = Object.copy(component, {
@ -326,9 +324,7 @@ component.char2dimpl = {
this.timer.stop();
},
kill() {
cmd(9, this.id);
},
kill() { cmd(9, this.id); },
add_anim(anim,name) {
if (name in this) return;
@ -338,6 +334,7 @@ component.char2dimpl = {
},
post() {
/*
this.timer = timer.make(this.advance.bind(this), 1);
this.timer.loop = true;
Object.hide(this,'timer');
@ -346,7 +343,7 @@ component.char2dimpl = {
this.anims[k] = run_env(path + ".asset", path);
this.add_anim(this.anims[k], k);
}
Object.hide(this, 'acur');
Object.hide(this, 'acur');*/
},
};
@ -452,7 +449,7 @@ component.polygon2d = Object.copy(collider2d, {
flipy: false,
boundingbox() {
return points2bb(this.spoints);
return points2bb(this.spoints());
},
hides: ['id', 'shape', 'gameobject'],
@ -464,7 +461,7 @@ component.polygon2d = Object.copy(collider2d, {
},
/* EDITOR */
get spoints() {
spoints() {
var spoints = this.points.slice();
if (this.flipx) {
@ -486,13 +483,8 @@ component.polygon2d = Object.copy(collider2d, {
},
gizmo() {
this.spoints.forEach(function(x) {
Shape.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
}, this);
this.points.forEach(function(x, i) {
Debug.numbered_point(this.gameobject.this2world(x), i);
}, this);
this.spoints().forEach(x => Shape.point(this.gameobject.this2screen(x), 3, Color.green));
this.points.forEach((x,i)=>Debug.numbered_point(this.gameobject.this2screen(x), i));
},
pick(pos) {
@ -509,12 +501,8 @@ component.polygon2d = Object.copy(collider2d, {
});
component.polygon2d.impl = Object.mix(collider2d.impl, {
sync() {
cmd_poly2d(0, this.id, this.spoints);
},
query() {
return cmd(80, this.shape);
},
sync() { cmd_poly2d(0, this.id, this.spoints()); },
query() { return cmd(80, this.shape); },
});
var polygon2d = component.polygon2d;
@ -685,11 +673,55 @@ component.edge2d = Object.copy(collider2d, {
}
},
rm_node(idx) {
if (idx < 0 || idx >= this.cpoints.length) return;
if (Spline.is_catmull(this.type))
this.cpoints.splice(idx,1);
if (Spline.is_bezier(this.type)) {
Debug.assert(Spline.bezier_is_node(this.cpoints, idx), 'Attempted to delete a bezier handle.');
if (idx === 0)
this.cpoints.splice(idx,2);
else if (idx === this.cpoints.length-1)
this.cpoints.splice(this.cpoints.length-2,2);
else
this.cpoints.splice(idx-1,3);
}
},
add_node(pos) {
pos = this.gameobject.world2this(pos);
var idx = 0;
if (Spline.is_catmull(this.type)) {
if (this.cpoints.length >= 2)
idx = cmd(59, pos, this.cpoints, 400);
if (idx === this.cpoints.length)
this.cpoints.push(pos);
else
this.cpoints.splice(idx, 0, pos);
}
if (Spline.is_bezier(this.type)) {
idx = cmd(59, pos, Spline.bezier_nodes(this.cpoints),400);
idx *= 3;
if (idx < 0) return;
var adds;
if (idx === this.cpoints.length)
adds = [this.cpoints.at(-1).add([100,0]), pos.add([-100,0]), pos.slice()];
else if (idx === 0)
adds = [pos.slice(), pos.add([100,0]), this.cpoints[0].add([-100,0])];
else
adds = [pos.add([-100,0]), pos.slice(), pos.add([100,0])];
this.cpoints.splice(idx+1, 0, ...adds);
}
},
pick_all() {
var picks = [];
this.cpoints.forEach(function(x) {
picks.push(make_point_obj(this,x));
}, this);
this.cpoints.forEach(x =>picks.push(make_point_obj(this,x)));
return picks;
},
});
@ -782,32 +814,31 @@ bucket.inputs['C-o'] = function() { this.type = -1; };
bucket.inputs['C-o'].doc = "Set spline to linear.";
bucket.inputs['C-M-lm'] = function() {
var idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
if (idx === -1) return;
if (Spline.is_catmull(this.type)) {
var idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
if (idx === -1) return;
} else {
}
this.cpoints = this.cpoints.newfirst(idx);
};
bucket.inputs['C-M-lm'].doc = "Select the given point as the '0' of this spline.";
bucket.inputs['C-lm'] = function() {
var idx = 0;
if (this.cpoints.length >= 2)
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 400);
if (idx === this.cpoints.length)
this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos)));
else
this.cpoints.splice(idx, 0, this.gameobject.world2this(screen2world(Mouse.pos)));
};
bucket.inputs['C-lm'] = function() { this.add_node(Mouse.worldpos); }
bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
bucket.inputs['C-M-lm'] = function() {
var idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
var idx = -1;
if (Spline.is_catmull(this.type))
idx = Math.grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
else {
var nodes = Spline.bezier_nodes(this.cpoints);
idx = Math.grab_from_points(Mouse.worldpos, nodes.map(p => this.gameobject.this2world(p)), 25);
idx *= 3;
}
if (idx < 0 || idx > this.cpoints.length) return;
this.cpoints.splice(idx, 1);
this.rm_node(idx);
};
bucket.inputs['C-M-lm'].doc = "Remove point from the spline.";

View file

@ -1095,8 +1095,10 @@ editor.inputs.mouse = {};
editor.inputs.mouse.move = function(pos, dpos)
{
if (editor.mousejoy) {
if (editor.z_start)
if (editor.z_start) {
editor.camera.zoom -= dpos.y/500;
console.say(editor.camera.zoom);
}
else if (editor.joystart)
editor.camera.pos = editor.camera.pos.sub(Game.camera.dir_view2world(dpos));
}

View file

@ -417,6 +417,15 @@ Spline.bezier_point_handles = function(points, i)
return c;
}
Spline.bezier_nodes = function(points)
{
var c = [];
for (var i = 0; i < points.length; i+=3)
c.push(points[i].slice());
return c;
}
Spline.bezier_is_node = function(points, i) { return i%3 === 0; }
Spline.bezier_is_handle = function(points, i) { return !Spline.bezier_is_node(points,i); }

View file

@ -100,9 +100,8 @@ var gameobject = {
delay(fn, seconds) {
var t = timer.delay(fn.bind(this), seconds, false);
var killfn = function() { t.kill(); };
this.timers.push(killfn);
return killfn;
this.timers.push(t);
return t;
},
tween(prop, values, def){
@ -300,6 +299,7 @@ var gameobject = {
world2this(pos) { return cmd(70, this.body, pos); },
this2world(pos) { return cmd(71, this.body, pos); },
this2screen(pos) { return world2screen(this.this2world(pos)); },
screen2this(pos) { return this.world2this(screen2world(pos)); },
dir_world2this(dir) { return cmd(160, this.body, dir); },
dir_this2world(dir) { return cmd(161, this.body, dir); },
@ -511,6 +511,8 @@ var gameobject = {
this.level = undefined;
}
Player.do_uncontrol(this);
Register.unregister_obj(this);
@ -520,7 +522,7 @@ var gameobject = {
Register.unregister_obj(this.components[key]);
(`Destroying component ${key}`);
this.components[key].kill();
this.components.gameobject = undefined;
this.components[key].gameobject = undefined;
delete this.components[key];
}
@ -563,6 +565,7 @@ var gameobject = {
cmd(113, obj.body, obj); // set the internal obj reference to this obj
for (var [prop,p] of Object.entries(this)) {
if (!p) continue;
if (typeof p.make === 'function') {
obj[prop] = p.make(obj);
obj.components[prop] = obj[prop];
@ -589,7 +592,6 @@ var gameobject = {
make_objs(objs) {
for (var prop in objs) {
Log.warn(prop);
var newobj = this.spawn_from_instance(objs[prop]);
if (!newobj) continue;
this.rename_obj(newobj.toString(), prop);

View file

@ -37,13 +37,14 @@ void set_cat_mask(int cat, unsigned int mask) { category_masks[cat] = mask; }
cpTransform m3_to_cpt(HMM_Mat3 m)
{
cpTransform t;
t.a = m.Columns[0].x;
t.c = m.Columns[0].y;
t.tx = m.Columns[0].z;
t.b = m.Columns[1].x;
t.b = m.Columns[0].y;
t.tx = m.Columns[2].x;
t.c = m.Columns[1].x;
t.d = m.Columns[1].y;
t.ty = m.Columns[1].z;
t.ty = m.Columns[2].y;
return t;
}
@ -181,6 +182,7 @@ void phys2d_update(float deltaT) {
void init_phys2dshape(struct phys2d_shape *shape, gameobject *go, void *data) {
shape->go = go;
shape->data = data;
shape->t.scale = (HMM_Vec2){1.0,1.0};
go_shape_apply(go->body, shape->shape, go);
cpShapeSetCollisionType(shape->shape, (int)go);
cpShapeSetUserData(shape->shape, shape);
@ -336,8 +338,8 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
if (!verts) return;
if (poly->points)
arrfree(poly->points);
arrsetlen(poly->points, arrlen(verts));
for (int i = 0; i < arrlen(verts); i++) {
poly->points[i].X = verts[i].x;
poly->points[i].Y = verts[i].y;
@ -348,9 +350,10 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
void phys2d_applypoly(struct phys2d_poly *poly) {
if (arrlen(poly->points) <= 0) return;
assert(sizeof(poly->points[0]) == sizeof(cpVect));
struct gameobject *go = poly->shape.go;
cpTransform T = m3_to_cpt(transform2d2mat(poly->t));
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
// cpTransform T = m3_to_cpt(transform2d2mat(poly->t));
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, cpTransformIdentity);
cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
cpSpaceReindexShapesForBody(space, cpShapeGetBody(poly->shape.shape));
}
@ -400,9 +403,7 @@ float phys2d_edge_moi(struct phys2d_edge *edge, float m) {
return moi;
}
void phys2d_edgedel(struct phys2d_edge *edge) {
phys2d_shape_del(&edge->shape);
}
void phys2d_edgedel(struct phys2d_edge *edge) { phys2d_shape_del(&edge->shape); }
void phys2d_edgeaddvert(struct phys2d_edge *edge, HMM_Vec2 v) {
arrput(edge->points, v);
@ -567,7 +568,7 @@ void duk_call_phys_cb(HMM_Vec2 norm, struct callee c, gameobject *hit, cpArbiter
JSValue obj = JS_NewObject(js);
JS_SetPropertyStr(js, obj, "normal", vec2js(norm));
JS_SetPropertyStr(js, obj, "hit", hit->ref);
JS_SetPropertyStr(js, obj, "obj", hit->ref);
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
HMM_Vec2 srfv;
srfv.cp = cpArbiterGetSurfaceVelocity(arb);

View file

@ -30,7 +30,7 @@ struct phys2d_shape {
void (*apply)(void *data);
};
/* Circles are the fastest collier type */
/* Circles are the fastest colldier type */
struct phys2d_circle {
float radius;
HMM_Vec2 offset;

View file

@ -1,5 +1,3 @@
// odplot productions is a trademarked name. Project Yugh is a copyrighted property. This code, however, is free to be copy and extended as you see fit.
#include "3pfollow.h"
#include <math.h>

View file

@ -4,29 +4,8 @@
#include "transform.h"
#include "HandmadeMath.h"
struct follow {
float distance;
HMM_Vec3 offset;
HMM_Quat target_rot;
};
HMM_Vec3 follow_calccenter();
HMM_Vec3 follow_postoffset();
HMM_Vec3 extentsoffset();
HMM_Vec3 framebasedveclerp();
int lerpparam(float offset, float anchorwidth, float floatwidth);
HMM_Vec3 vec3lerp(HMM_Vec3 from, HMM_Vec3 to, HMM_Vec3 a);
void follow_calctargets();
HMM_Vec3 follow_removelockedrot();
void follow_targetoffset(struct follow *follow);
int float_epsilon(float a, float b, float e);
/*
//////////////////////////////////////////////////////////////////////////
// A good camera.
//////////////////////////////////////////////////////////////////////////
class ThirdPersonFollow {
public:

View file

@ -108,9 +108,12 @@ cgltf_attribute *get_attr_type(cgltf_primitive *p, cgltf_attribute_type t)
return NULL;
}
unsigned short pack_short_texcoord(float c)
unsigned short pack_short_texcoord(float x, float y)
{
return c * USHRT_MAX;
unsigned short s;
char xc = x*255;
char yc = y*255;
return (((unsigned short)yc) << 8) | xc;
}
uint32_t pack_int10_n2(float *norm)
@ -141,15 +144,42 @@ void mesh_add_material(mesh *mesh, cgltf_material *mat)
free(imp);
}
} else
// Get "no texture" tex
mesh->bind.fs.images[0] = texture_pullfromfile("k")->id;
mesh->bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
mesh->bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
/*
cgltf_texture *tex;
if (tex = mat->normal_texture.texture)
mesh->bind.fs.images[1] = texture_pullfromfile(tex->image->uri)->id;
else
mesh->bind.fs.images[1] = texture_pullfromfile("k")->id;
mesh->bind.fs.images[1] = texture_pullfromfile("k")->id;*/
}
sg_buffer texcoord_floats(float *f, int verts, int comp)
{
unsigned short packed[verts];
for (int i = 0, v = 0; v < verts; i+=comp, v++)
packed[v] = pack_short_texcoord(f[i], f[i+1]);
return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed,
.data.size = sizeof(unsigned short) * verts});
}
sg_buffer normal_floats(float *f, int verts, int comp)
{
uint32_t packed_norms[verts];
for (int v = 0, i = 0; v < verts; v++, i+= comp)
packed_norms[v] = pack_int10_n2(i);
return sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_norms,
.data.size = sizeof(uint32_t) * verts});
}
HMM_Vec3 index_to_vert(uint32_t idx, float *f)
{
return (HMM_Vec3){f[idx*3], f[idx*3+1], f[idx*3+2]};
}
void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
@ -165,11 +195,12 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
mesh->face_count = c;
mesh->idx_count = c;
} else {
YughWarn("Model does not have indices. Generating them.");
int c = prim->attributes[0].data->count;
mesh->face_count = c;
mesh->idx_count = c;
idxs = malloc(sizeof(*idxs)*c);
for (int z = 0; z < c; z++)
@ -188,17 +219,14 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
for (int k = 0; k < prim->attributes_count; k++) {
cgltf_attribute attribute = prim->attributes[k];
int n = cgltf_accessor_unpack_floats(attribute.data, NULL, 0); /* floats per element x num elements */
float *vs = malloc(sizeof(float)*n);
int n = cgltf_accessor_unpack_floats(attribute.data, NULL, 0); /* floats per vertex x num elements. In other words, total floats pulled */
int comp = cgltf_num_components(attribute.data->type);
int verts = n/comp;
float vs[n];
cgltf_accessor_unpack_floats(attribute.data, vs, n);
uint32_t *packed_norms;
unsigned short *packed_coords;
switch (attribute.type) {
case cgltf_attribute_type_position:
mesh->bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs,
.data.size = sizeof(float) * n});
@ -206,15 +234,7 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
case cgltf_attribute_type_normal:
has_norm = 1;
packed_norms = malloc(mesh->face_count * sizeof(uint32_t));
for (int i = 0; i < mesh->face_count; i++)
packed_norms[i] = pack_int10_n2(vs + i*3);
mesh->bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_norms,
.data.size = sizeof(uint32_t) * mesh->face_count});
free (packed_norms);
mesh->bind.vertex_buffers[2] = normal_floats(vs, verts, comp);
break;
case cgltf_attribute_type_tangent:
@ -230,46 +250,33 @@ void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
break;
case cgltf_attribute_type_texcoord:
packed_coords = malloc(mesh->face_count * 2 * sizeof(unsigned short));
for (int i = 0; i < mesh->face_count*2; i++)
packed_coords[i] = pack_short_texcoord(vs[i]);
mesh->bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_coords,
.data.size = sizeof(unsigned short) * 2 * mesh->face_count});
free(packed_coords);
mesh->bind.vertex_buffers[1] = texcoord_floats(vs, verts, comp);
break;
}
free(vs);
}
/*
if (!has_norm) {
uint32_t norms[mesh->face_count];
cgltf_attribute *pa = get_attr_type(prim, cgltf_attribute_type_position);
int n = cgltf_accessor_unpack_floats(pa->data, NULL,0);
int comp = 3;
int verts = n/comp;
uint32_t face_norms[verts];
float ps[n];
cgltf_accessor_unpack_floats(pa->data,ps,n);
for (int i = 0, face=0; i < mesh->face_count/3; i++, face+=9) {
int o = face;
HMM_Vec3 a = {ps[o], ps[o+1],ps[o+2]};
o += 3;
HMM_Vec3 b = {ps[o], ps[o+1],ps[o+2]};
o += 3;
HMM_Vec3 c = {ps[o], ps[o+1],ps[o+2]};
for (int i = 0; i < verts; i+=3) {
HMM_Vec3 a = index_to_vert(i,ps);
HMM_Vec3 b = index_to_vert(i+1,ps);
HMM_Vec3 c = index_to_vert(i+2,ps);
HMM_Vec3 norm = HMM_NormV3(HMM_Cross(HMM_SubV3(b,a), HMM_SubV3(c,a)));
uint32_t packed_norm = pack_int10_n2(norm.Elements);
for (int j = 0; j < 3; j++)
norms[i*3+j] = packed_norm;
face_norms[i] = face_norms[i+1] = face_norms[i+2] = packed_norm;
}
mesh->bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = norms,
.data.size = sizeof(uint32_t) * mesh->face_count
});
}
.data.ptr = face_norms,
.data.size = sizeof(uint32_t) * verts});
}*/
}
void model_add_cgltf_mesh(model *model, cgltf_mesh *gltf_mesh)
@ -373,7 +380,7 @@ void draw_model(struct model *model, HMM_Mat4 amodel) {
for (int i = 0; i < arrlen(model->meshes); i++) {
sg_apply_bindings(&model->meshes[i].bind);
sg_draw(0, model->meshes[i].face_count, 1);
sg_draw(0, model->meshes[i].idx_count, 1);
}
}

View file

@ -17,7 +17,7 @@ struct model;
/* A single mesh */
typedef struct mesh {
sg_bindings bind; /* Encapsulates material, norms, etc */
uint32_t face_count;
uint32_t idx_count;
struct model *model;
} mesh;

View file

@ -442,10 +442,8 @@ HMM_Vec2 *inflatepoints(HMM_Vec2 *p, float d, int n)
void draw_edge(HMM_Vec2 *points, int n, struct rgba color, int thickness, int closed, int flags, struct rgba line_color, float line_seg)
{
// static_assert(sizeof(HMM_Vec2) == 2*sizeof(float));
if (thickness == 0) {
if (thickness == 0)
draw_line(points,n,color,0,closed,0);
}
/* todo: should be dashed, and filled. use a texture. */
/* draw polygon outline */
@ -503,12 +501,12 @@ void draw_edge(HMM_Vec2 *points, int n, struct rgba color, int thickness, int cl
HMM_Vec2 in_p[n];
HMM_Vec2 out_p[n];
for (int i = 0, v = 0; i < n*2+1; i+=2, v++) {
for (int i = 1, v = 0; i < n*2+1; i+=2, v++) {
in_p[v].x = vertices[i].pos.x;
in_p[v].y = vertices[i].pos.y;
}
for (int i = 1, v = 0; i < n*2; i+=2,v++) {
for (int i = 0, v = 0; i < n*2; i+=2,v++) {
out_p[v].x = vertices[i].pos.x;
out_p[v].y = vertices[i].pos.y;
}

View file

@ -175,10 +175,6 @@ gameobject *MakeGameobject() {
void rm_body_shapes(cpBody *body, cpShape *shape, void *data) {
struct phys2d_shape *s = cpShapeGetUserData(shape);
if (s->data) {
free(s->data);
s->data = NULL;
}
cpSpaceRemoveShape(space, shape);
cpShapeFree(shape);
}

View file

@ -105,7 +105,7 @@ JSValue gos2ref(gameobject **go)
{
JSValue array = JS_NewArray(js);
for (int i = 0; i < arrlen(go); i++)
js_setprop_num(array,i,go[i]->ref);
js_setprop_num(array,i,JS_DupValue(js,go[i]->ref));
return array;
}
@ -1905,4 +1905,3 @@ void ffi_load() {
QJSCLASSPREP(dsp_node);
QJSCLASSPREP(gameobject);
}

View file

@ -37,7 +37,6 @@ struct TextureOptions {
int sprite;
int mips;
unsigned int gamma:1;
int animation;
int wrapx;
int wrapy;
};
@ -65,14 +64,9 @@ void texture_sync(const char *path);
char * tex_get_path(struct Texture *tex); // Get image path for texture
void texanim_fromframes(struct TexAnim *anim, int frames);
int gif_nframes(const char *path);
struct glrect tex_get_rect(struct Texture *tex);
HMM_Vec2 tex_get_dimensions(struct Texture *tex);
struct glrect anim_get_rect(struct anim2d *anim);
int anim_frames(struct TexAnim *a);
#endif

View file

@ -286,8 +286,8 @@ cpPolyShapeGetRadius(const cpShape *shape)
void
cpPolyShapeSetVerts(cpShape *shape, int count, cpVect *verts, cpTransform transform)
{
cpVect *hullVerts = (cpVect *)alloca(count*sizeof(cpVect));
cpVect hullVerts[count+1];
// Transform the verts before building the hull in case of a negative scale.
for(int i=0; i<count; i++) hullVerts[i] = cpTransformPoint(transform, verts[i]);

View file

@ -36,7 +36,9 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
return mat3_t_pos(m, dir);
}
HMM_Mat3 transform2d2mat(transform2d trn) { return HMM_MulM3(HMM_Translate2D(trn.pos), HMM_MulM3(HMM_RotateM3(trn.angle), HMM_ScaleM3(trn.scale))); }
HMM_Mat3 transform2d2mat(transform2d trn) {
return HMM_MulM3(HMM_Translate2D(trn.pos), HMM_MulM3(HMM_RotateM3(trn.angle), HMM_ScaleM3(trn.scale)));
}
transform2d mat2transform2d(HMM_Mat3 m)
{