catmull-rom spline custom

This commit is contained in:
John Alanbrook 2023-12-04 19:38:37 +00:00
parent de8c8c9168
commit cb0fa34743
31 changed files with 583 additions and 9225 deletions

View file

@ -4,5 +4,14 @@ Entities are defined by creating a .jso script in your game directory. Variants
An entity which differs from its ur will have an asterisk * next to its name.
## Ur types
Entities have components. The components all do a thing. Components are placed relative to the entity.
All entities are child to Primum, once the simulation is running.
Entites can be static, kinematic, or dynamic. Static entities never move. Kinematic entities move via explicit command. Dynamic ones move under the auspices of the game world.
Components, if they have a defined transform, are relative to the entity they reside on. Components cannot have components, ensuring that components can be processed and rendered in any order.
Entities are defined via a typical scene graph system. This allows for easy reuse of components when designing levels.
When the game is run, the movement relationships are broken, and the physics system takes over. In the physics engine, each entity is a direct child of the world. Objects can still be constrained to other objects via the physics system.

View file

@ -414,10 +414,6 @@ var Game = {
sys_cmd(1);
},
get dt() {
return cmd(63);
},
wait_fns: [],
wait_exec(fn) {
@ -487,4 +483,3 @@ var Asset = {};
Asset.doc = {
doc: "Functions to manage the loading and unloading of assets, like sounds and images."
};

View file

@ -169,7 +169,6 @@ var gameobject = {
set_gravity(x) { cmd(167, this.body, x); },
set timescale(x) { cmd(168,this.body,x); },
get timescale() { return cmd(169,this.body); },
set phys(x) { console.warn(`Setting phys to ${x}`); set_body(1, this.body, x); },
get phys() { return q_body(0,this.body); },
get velocity() { return q_body(3, this.body); },
@ -513,7 +512,6 @@ var gameobject = {
}
delete this.components;
// q_body(8,this.body);
this.clear();

View file

@ -76,9 +76,14 @@ var DSP = {
return dsp_node.make(cmd(207,secs,decay));
},
allpass(secs, decay) {
var composite = {};
var fwd = DSP.fwd_delay(secs,-decay);
var fbk = DSP.delay(secs,decay);
composite.id = fwd.id;
composite.plugin = composite.plugin.bind(fbk);
composite.unplug = dsp_node.unplug.bind(fbk);
fwd.plugin(fbk);
return composite;
},
lpf(f) {
return dsp_node.make(cmd(186,f));

View file

@ -296,6 +296,7 @@ Cmdline.register_cmd("cjson", function(json) {
}, "Clean up a jso file.");
Cmdline.register_cmd("r", function(script) {
run(script);
try { run(script); } catch(e) { STD.exit(0); }
STD.exit(0);
}, "Run a script.");

View file

@ -12,8 +12,6 @@
#include "2dphysics.h"
#include "tinyspline.h"
#include "jsffi.h"
#include "script.h"
@ -39,6 +37,18 @@ 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.d = m.Columns[1].y;
t.ty = m.Columns[1].z;
return t;
}
cpShape *phys2d_query_pos(cpVect pos) {
cpShapeFilter filter;
filter.group = CP_NO_GROUP;
@ -49,62 +59,56 @@ cpShape *phys2d_query_pos(cpVect pos) {
return find;
}
int *qhits;
void querylist(cpShape *shape, cpContactPointSet *points, void *data) {
int go = shape2gameobject(shape);
int in = 0;
for (int i = 0; i < arrlen(qhits); i++) {
if (qhits[i] == go) {
in = 1;
break;
}
int sort_ids(int *a, int *b)
{
if (*a == *b) return 0;
if (*a < *b) return -1;
return 1;
}
if (!in) arrput(qhits, go);
int *clean_ids(int *ids)
{
qsort(ids, sizeof(*ids), arrlen(ids), sort_ids);
int curid = -1;
for (int i = arrlen(ids)-1; i >= 0; i--)
if (ids[i] == curid)
arrdelswap(ids, i);
else
curid = ids[i];
return ids;
}
void querylistbodies(cpBody *body, void *data) {
cpBB *bbox = data;
if (cpBBContainsVect(*bbox, cpBodyGetPosition(body))) {
int go = body2id(body);
if (go < 0) return;
int in = 0;
for (int i = 0; i < arrlen(qhits); i++) {
if (qhits[i] == go) {
in = 1;
break;
}
void querylist(cpShape *shape, cpContactPointSet *points, int *ids) {
arrput(ids,shape2gameobject(shape));
}
if (!in) arrput(qhits, go);
}
typedef struct querybox {
cpBB bb;
int *ids;
} querybox;
void querylistbodies(cpBody *body, querybox *qb) {
if (cpBBContainsVect(qb->bb, cpBodyGetPosition(body)))
arrput(qb->ids,body2id(body));
}
/* Return all points from a list of points in the given boundingbox */
int *phys2d_query_box_points(HMM_Vec2 pos, HMM_Vec2 wh, HMM_Vec2 *points, int n) {
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
cpTransform T = {0};
T.a = 1;
T.d = 1;
T.tx = pos.x;
T.ty = pos.y;
cpShapeUpdate(box, T);
cpBB bbox;
bbox = cpBBExpand(bbox, cpvadd(pos.cp, cpvmult(wh.cp,0.5)));
bbox = cpBBExpand(bbox, cpvsub(pos.cp, cpvmult(wh.cp,0.5)));
int *hits = NULL;
cpBB bbox = cpShapeGetBB(box);
if (qhits) arrfree(qhits);
for (int i = 0; i < n; i++) {
for (int i = 0; i < n; i++)
if (cpBBContainsVect(bbox, points[i].cp))
arrpush(qhits, i);
}
cpShapeFree(box);
return qhits;
arrpush(hits, i);
return hits;
}
/* Return all gameobjects within the given box */
int *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) {
cpShape *box = cpBoxShapeNew(NULL, wh.x, wh.y, 0.f);
cpTransform T = {0};
@ -116,22 +120,24 @@ int *phys2d_query_box(HMM_Vec2 pos, HMM_Vec2 wh) {
cpBB bbox = cpShapeGetBB(box);
if (qhits) arrfree(qhits);
int *ids = NULL;
cpSpaceShapeQuery(space, box, querylist, NULL);
cpSpaceEachBody(space, querylistbodies, &bbox);
querybox qb;
qb.bb = bbox;
qb.ids = ids;
cpSpaceShapeQuery(space, box, querylist, ids);
cpSpaceEachBody(space, querylistbodies, &qb);
cpShapeFree(box);
return qhits;
return clean_ids(ids);
}
int *phys2d_query_shape(struct phys2d_shape *shape) {
if (qhits) arrfree(qhits);
cpSpaceShapeQuery(space, shape->shape, querylist, NULL);
return qhits;
int *ids = NULL;
cpSpaceShapeQuery(space, shape->shape, querylist, ids);
return clean_ids(ids);
}
int cpshape_enabled(cpShape *c) {
@ -246,11 +252,12 @@ void phys2d_applycircle(struct phys2d_circle *circle) {
struct phys2d_box *Make2DBox(int go) {
struct phys2d_box *new = malloc(sizeof(struct phys2d_box));
new->w = 50.f;
new->h = 50.f;
new->t = (transform2d){
.pos = {0,0},
.angle = 0,
.scale = {0,0}
};
new->r = 0.f;
new->offset = v2zero;
new->shape.go = go;
new->shape.apply = phys2d_applybox;
phys2d_applybox(new);
@ -261,18 +268,7 @@ struct phys2d_box *Make2DBox(int go) {
}
float phys2d_box_moi(struct phys2d_box *box, float m) {
return cpMomentForBox(m, box->w, box->h);
}
cpTransform trs2cpt(HMM_Vec2 t, float r, HMM_Vec2 s) {
cpTransform T;
T.a = cos(r) * s.X;
T.b = -sin(r) * s.X;
T.c = sin(r) * s.Y;
T.d = cos(r) * s.Y;
T.tx = t.X * s.X;
T.ty = t.Y * s.Y;
return T;
return cpMomentForBox(m, box->t.scale.x, box->t.scale.y);
}
void phys2d_boxdel(struct phys2d_box *box) {
@ -282,10 +278,8 @@ void phys2d_boxdel(struct phys2d_box *box) {
void phys2d_applybox(struct phys2d_box *box) {
phys2d_boxdel(box);
struct gameobject *go = id2go(box->shape.go);
cpTransform T = trs2cpt(box->offset, box->rotation, id2go(box->shape.go)->scale.XY);
float hh = box->h / 2.f;
float hw = box->w / 2.f;
cpVect verts[4] = {{-hw, -hh}, {hw, -hh}, {hw, hh}, {-hw, hh}};
cpTransform T = m3_to_cpt(transform2d2mat(box->t));
cpVect verts[4] = {{-0.5, -0.5}, {0.5, -0.5}, {0.5, 0.5}, {-0.5, 0.5}};
box->shape.shape = cpSpaceAddShape(space, cpPolyShapeNew(go->body, 4, verts, T, box->r));
init_phys2dshape(&box->shape, box->shape.go, box);
}
@ -361,9 +355,7 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
void phys2d_applypoly(struct phys2d_poly *poly) {
if (arrlen(poly->points) <= 0) return;
struct gameobject *go = id2go(poly->shape.go);
cpTransform T = trs2cpt((HMM_Vec2){0,0}, 0, go->scale.XY);
cpTransform T = m3_to_cpt(transform2d2mat(poly->t));
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
cpSpaceReindexShapesForBody(space, cpShapeGetBody(poly->shape.shape));
@ -477,12 +469,13 @@ void phys2d_applyedge(struct phys2d_edge *edge) {
struct gameobject *go = id2go(edge->shape.go);
for (int i = 0; i < arrlen(edge->shapes); i++) {
HMM_Vec2 a = goscale(go, edge->points[i]);
HMM_Vec2 b = goscale(go, edge->points[i+1]);
/* Points must be scaled with gameobject, */
HMM_Vec2 a = HMM_MulV2(go->scale.xy, edge->points[i]);
HMM_Vec2 b = HMM_MulV2(go->scale.xy, edge->points[i+1]);
cpSegmentShapeSetEndpoints(edge->shapes[i], a.cp, b.cp);
cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness);
if (i > 0 && i < arrlen(edge->shapes) - 1)
cpSegmentShapeSetNeighbors(edge->shapes[i], goscale(go,edge->points[i-1]).cp, goscale(go,edge->points[i+2]).cp);
cpSegmentShapeSetNeighbors(edge->shapes[i], HMM_MulV2(go->scale.xy,edge->points[i-1]).cp, HMM_MulV2(go->scale.xy,edge->points[i+2]).cp);
go_shape_apply(NULL, edge->shapes[i], go);
cpShapeSetUserData(edge->shapes[i], &edge->shape);
}
@ -504,7 +497,6 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
HMM_Vec2 drawpoints[arrlen(edge->points)];
struct gameobject *go = id2go(edge->shape.go);
HMM_Mat3 g2w = t_go2world(go);
for (int i = 0; i < arrlen(edge->points); i++)
drawpoints[i] = mat_t_pos(g2w, edge->points[i]);
@ -553,9 +545,7 @@ int shape_get_sensor(struct phys2d_shape *shape) {
return cpShapeGetSensor(shape->shape);
}
void phys2d_reindex_body(cpBody *body) {
cpSpaceReindexShapesForBody(space, body);
}
void phys2d_reindex_body(cpBody *body) { cpSpaceReindexShapesForBody(space, body); }
struct postphys_cb {
struct callee c;

View file

@ -23,6 +23,7 @@ extern struct rgba sleep_color;
struct phys2d_shape {
cpShape *shape;
transform2d t;
int go;
void *data; /* The specific subtype; phys2d_circle, etc */
void (*debugdraw)(void *data);
@ -48,16 +49,14 @@ struct phys2d_segment {
/* A convex polygon; defined as the convex hull around the given set of points */
struct phys2d_poly {
HMM_Vec2 *points;
transform2d t;
float radius;
struct phys2d_shape shape;
};
/* A box shape; a type of a polygon collider */
struct phys2d_box {
float w;
float h;
HMM_Vec2 offset;
float rotation;
transform2d t; /* Scale here is used as width/height */
float r; /* radius */
struct phys2d_shape shape;
};

View file

@ -1,47 +0,0 @@
#include "3dphysics.h"
/*
btDefaultCollisionConfiguration *collisionConfig {
NULL};
btCollisionDispatcher *dispatcher {
NULL};
btBroadphaseInterface *overlappingPairCache {
NULL};
btSequentialImpulseConstraintSolver *solver {
NULL};
btDiscreteDynamicsWorld *dynamicsWorld {
NULL};
btRigidBody *worldFloor {
NULL};
void btUpdate()
{
// dynamicsWorld->stepSimulation(deltaT);
}
void btInit()
{
// collisionConfig = new btDefaultCollisionConfiguration();
// dispatcher = new btCollisionDispatcher(collisionConfig);
// overlappingPairCache = new btDbvtBroadphase();
// solver = new btSequentialImpulseConstraintSolver;
// dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfig);
// dynamicsWorld->setGravity(btVector3(0.f, -9.8f, 0.f));
// btDebugDrawer = new BulletDebugDrawer_OpenGL();
// dynamicsWorld->setDebugDrawer(btDebugDrawer);
//btDebugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb);
// Add camera and plane to world
// dynamicsWorld->addRigidBody(camera.body);
// camera.body->setGravity(btVector3(0.f, 0.f, 0.f));
// Create and add plane
// btStaticPlaneShape* floorShape = new btStaticPlaneShape(btVector3(0.f, 1.f, 0.f), 0.f);
// btDefaultMotionState* motionState = new btDefaultMotionState();
// btVector3 bodyInertia;
// btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(0.f, motionState, floorShape, bodyInertia);
// worldFloor = new btRigidBody(bodyCI);
// dynamicsWorld->addRigidBody(worldFloor);
}
*/

View file

@ -1,4 +0,0 @@
#ifndef THREEDPHYSICS_H
#define THREEDPHYSICS_H
#endif

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.
#ifndef THIRDPERSONFOLLOW_H
#define THIRDPERSONFOLLOW_H
@ -8,6 +6,7 @@
struct follow {
float distance;
HMM_Vec3 offset;
HMM_Quat target_rot;
};

View file

@ -14,7 +14,6 @@
#include "render.h"
// #define HANDMADE_MATH_USE_TURNS
#include "HandmadeMath.h"
#include "math.h"
@ -100,11 +99,11 @@ struct model *GetExistingModel(const char *path) {
return MakeModel(path);
}
cgltf_attribute *get_attr_type(cgltf_primitive p, cgltf_attribute_type t)
cgltf_attribute *get_attr_type(cgltf_primitive *p, cgltf_attribute_type t)
{
for (int i = 0; i < p.attributes_count; i++) {
if (p.attributes[i].type == t)
return &p.attributes[i];
for (int i = 0; i < p->attributes_count; i++) {
if (p->attributes[i].type == t)
return &p->attributes[i];
}
return NULL;
@ -128,7 +127,193 @@ uint32_t pack_int10_n2(float *norm)
return (ni[0] & 0x3FF) | ( (ni[1] & 0x3FF) << 10) | ( (ni[2] & 0x3FF) << 20) | ( (0 & 0x3) << 30);
}
struct model *MakeModel(const char *path) {
void mesh_add_material(mesh *mesh, cgltf_material *mat)
{
if (!mat) return;
if (mat && mat->has_pbr_metallic_roughness) {
cgltf_image *img = mat->pbr_metallic_roughness.base_color_texture.texture->image;
if (img->buffer_view) {
cgltf_buffer_view *buf = img->buffer_view;
mesh->bind.fs.images[0] = texture_fromdata(buf->buffer->data, buf->size)->id;
} else {
const char *imp = seprint("%s/%s", dirname(mesh->model->path), img->uri);
mesh->bind.fs.images[0] = texture_pullfromfile(imp)->id;
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){});
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;
}
void mesh_add_primitive(mesh *mesh, cgltf_primitive *prim)
{
uint16_t *idxs;
if (prim->indices) {
int c = prim->indices->count;
idxs = malloc(sizeof(*idxs)*c);
memcpy(idxs, cgltf_buffer_view_data(prim->indices->buffer_view), sizeof(uint16_t) * c);
mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
mesh->face_count = c;
} else {
YughWarn("Model does not have indices. Generating them.");
int c = prim->attributes[0].data->count;
mesh->face_count = c;
idxs = malloc(sizeof(*idxs)*c);
for (int z = 0; z < c; z++)
idxs[z] = z;
mesh->bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
}
free(idxs);
mesh_add_material(mesh, prim->material);
int has_norm = 0;
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);
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});
break;
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);
break;
case cgltf_attribute_type_tangent:
break;
case cgltf_attribute_type_color:
break;
case cgltf_attribute_type_weights:
break;
case cgltf_attribute_type_joints:
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);
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);
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]};
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;
}
mesh->bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = norms,
.data.size = sizeof(uint32_t) * mesh->face_count
});
}
}
void model_add_cgltf_mesh(model *model, cgltf_mesh *gltf_mesh)
{
mesh mesh = {0};
mesh.model = model;
for (int i = 0; i < gltf_mesh->primitives_count; i++)
mesh_add_primitive(&mesh, &gltf_mesh->primitives[i]);
arrput(model->meshes,mesh);
}
void model_add_cgltf_anim(model *model, cgltf_animation *anim)
{
}
void model_add_cgltf_skin(model *model, cgltf_skin *skin)
{
}
void model_process_node(model *model, cgltf_node *node)
{
if (node->has_matrix)
memcpy(model->matrix.Elements, node->matrix, sizeof(float)*16);
if (node->mesh)
model_add_cgltf_mesh(model, node->mesh);
if (node->skin)
model_add_cgltf_skin(model, node->skin);
}
void model_process_scene(model *model, cgltf_scene *scene)
{
for (int i = 0; i < scene->nodes_count; i++)
model_process_node(model, scene->nodes[i]);
}
struct model *MakeModel(const char *path)
{
YughInfo("Making the model from %s.", path);
cgltf_options options = {0};
cgltf_data *data = NULL;
@ -147,150 +332,17 @@ struct model *MakeModel(const char *path) {
}
struct model *model = calloc(1, sizeof(*model));
/* TODO: Optimize by grouping by material. One material per draw. */
YughInfo("Model has %d materials.", data->materials_count);
const char *dir = dirname(path);
float vs[65535*3];
uint16_t idxs[65535];
model->path = path;
for (int i = 0; i < data->meshes_count; i++) {
cgltf_mesh *mesh = &data->meshes[i];
struct mesh newmesh = {0};
arrput(model->meshes,newmesh);
if (data->scenes_count == 0 || data->scenes_count > 1) return NULL;
model_process_scene(model, data->scene);
YughInfo("Making mesh %d. It has %d primitives.", i, mesh->primitives_count);
for (int i = 0; i < data->meshes_count; i++)
model_add_cgltf_mesh(model, &data->meshes[i]);
for (int j = 0; j < mesh->primitives_count; j++) {
cgltf_primitive primitive = mesh->primitives[j];
if (primitive.indices) {
int c = primitive.indices->count;
memcpy(idxs, cgltf_buffer_view_data(primitive.indices->buffer_view), sizeof(uint16_t) * c);
model->meshes[j].bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
model->meshes[j].face_count = c;
} else {
YughWarn("Model does not have indices. Generating them.");
int c = primitive.attributes[0].data->count;
model->meshes[j].face_count = c;
for (int z = 0; z < c; z++)
idxs[z] = z;
model->meshes[j].bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
}
struct cgltf_material *mat = primitive.material;
if (mat && primitive.material->has_pbr_metallic_roughness) {
cgltf_image *img = primitive.material->pbr_metallic_roughness.base_color_texture.texture->image;
if (img->buffer_view) {
cgltf_buffer_view *buf = img->buffer_view;
model->meshes[j].bind.fs.images[0] = texture_fromdata(buf->buffer->data, buf->size)->id;
} else {
const char *imp = seprint("%s/%s", dir, img->uri);
model->meshes[j].bind.fs.images[0] = texture_pullfromfile(imp)->id;
free(imp);
}
} else
model->meshes[j].bind.fs.images[0] = texture_pullfromfile("k")->id;
model->meshes[j].bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
cgltf_texture *tex;
// if (tex = primitive.material->normal_texture.texture) {
// model->meshes[j].bind.fs.images[1] = texture_pullfromfile(tex->image->uri)->id;
// }// else
// model->meshes[j].bind.fs.images[1] = texture_pullfromfile("k")->id;
int has_norm = 0;
for (int k = 0; k < primitive.attributes_count; k++) {
cgltf_attribute attribute = primitive.attributes[k];
int n = cgltf_accessor_unpack_floats(attribute.data, NULL, 0); /* floats per element x num elements */
cgltf_accessor_unpack_floats(attribute.data, vs, n);
uint32_t *packed_norms;
unsigned short *packed_coords;
switch (attribute.type) {
case cgltf_attribute_type_position:
model->meshes[j].bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs,
.data.size = sizeof(float) * n});
break;
case cgltf_attribute_type_normal:
has_norm = 1;
packed_norms = malloc(model->meshes[j].face_count * sizeof(uint32_t));;
for (int i = 0; i < model->meshes[j].face_count; i++)
packed_norms[i] = pack_int10_n2(vs + i*3);
// model->meshes[j].bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
// .data.ptr = packed_norms,
// .data.size = sizeof(uint32_t) * model->meshes[j].face_count});
free (packed_norms);
break;
case cgltf_attribute_type_tangent:
break;
case cgltf_attribute_type_texcoord:
packed_coords = malloc(model->meshes[j].face_count * 2 * sizeof(unsigned short));
for (int i = 0; i < model->meshes[j].face_count*2; i++)
packed_coords[i] = pack_short_texcoord(vs[i]);
model->meshes[j].bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = packed_coords,
.data.size = sizeof(unsigned short) * 2 * model->meshes[j].face_count});
free(packed_coords);
break;
}
}
if (!has_norm) {
YughInfo("Model does not have normals. Generating them.");
uint32_t norms[model->meshes[j].face_count];
cgltf_attribute *pa = get_attr_type(primitive, cgltf_attribute_type_position);
int n = cgltf_accessor_unpack_floats(pa->data, NULL,0);
float ps[n];
cgltf_accessor_unpack_floats(pa->data,ps,n);
for (int i = 0, face=0; i < model->meshes[j].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]};
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;
}
// model->meshes[j].bind.vertex_buffers[2] = sg_make_buffer(&(sg_buffer_desc){
// .data.ptr = norms,
// .data.size = sizeof(uint32_t) * model->meshes[j].face_count
// });
}
}
}
for (int i = 0; i < data->animations_count; i++)
model_add_cgltf_anim(model, &data->animations[i]);
shput(modelhash, path, model);

View file

@ -8,16 +8,25 @@
extern HMM_Vec3 eye;
struct shader;
typedef struct material {
} material;
struct model;
/* A single mesh */
struct mesh {
sg_bindings bind;
typedef struct mesh {
sg_bindings bind; /* Encapsulates material, norms, etc */
uint32_t face_count;
};
struct model *model;
} mesh;
/* A collection of meshes which create a full figure */
struct model {
typedef struct model {
struct mesh *meshes;
};
const char *path;
HMM_Mat4 matrix;
} model;
/* A model with draw information */
struct drawmodel {

View file

@ -228,6 +228,8 @@ typedef union HMM_Vec3 {
float X, Y, Z;
};
struct { float x, y, z; };
struct
{
float U, V, W;
@ -244,6 +246,13 @@ typedef union HMM_Vec3 {
float _Ignored0;
};
struct
{
HMM_Vec2 xy;
float _Ignored4;
};
struct
{
float _Ignored1;
@ -268,6 +277,28 @@ typedef union HMM_Vec3 {
static const HMM_Vec3 v3zero = {0,0,0};
typedef union HMM_Quat {
struct
{
union {
HMM_Vec3 XYZ;
struct
{
float X, Y, Z;
};
};
float W;
};
float Elements[4];
#ifdef HANDMADE_MATH__USE_SSE
__m128 SSE;
#endif
} HMM_Quat;
typedef union HMM_Vec4 {
struct
{
@ -277,6 +308,7 @@ typedef union HMM_Vec4 {
{
float X, Y, Z;
};
HMM_Vec3 xyz;
};
float W;
@ -301,6 +333,23 @@ typedef union HMM_Vec4 {
float _Ignored1;
};
struct {
HMM_Vec2 xy;
float _ig0;
float _ig1;
};
struct {
HMM_Vec2 _2;
float _ig2;
float _ig3;
};
struct {
HMM_Vec3 _3;
float _ig4;
};
struct
{
float _Ignored2;
@ -315,6 +364,8 @@ typedef union HMM_Vec4 {
HMM_Vec2 ZW;
};
HMM_Quat quat;
float Elements[4];
#ifdef HANDMADE_MATH__USE_SSE
@ -341,26 +392,6 @@ typedef union HMM_Mat4 {
} HMM_Mat4;
typedef union HMM_Quat {
struct
{
union {
HMM_Vec3 XYZ;
struct
{
float X, Y, Z;
};
};
float W;
};
float Elements[4];
#ifdef HANDMADE_MATH__USE_SSE
__m128 SSE;
#endif
} HMM_Quat;
typedef signed int HMM_Bool;
@ -552,6 +583,7 @@ static inline HMM_Vec2 HMM_AddV2(HMM_Vec2 Left, HMM_Vec2 Right) {
return Result;
}
static inline HMM_Vec3 HMM_AddV3(HMM_Vec3 Left, HMM_Vec3 Right) {
HMM_Vec3 Result;
@ -776,6 +808,8 @@ static inline float HMM_DotV2(HMM_Vec2 Left, HMM_Vec2 Right) {
return (Left.X * Right.X) + (Left.Y * Right.Y);
}
static inline HMM_Vec2 HMM_ProjV2(HMM_Vec2 a, HMM_Vec2 b)
{
return HMM_MulV2F(b, HMM_DotV2(a,b)/HMM_DotV2(b,b));
@ -836,6 +870,11 @@ static inline float HMM_LenV2(HMM_Vec2 A) {
return HMM_SqrtF(HMM_LenSqrV2(A));
}
static inline float HMM_AngleV2(HMM_Vec2 a, HMM_Vec2 b)
{
return acos(HMM_DotV2(a,b)/(HMM_LenV2(a)*HMM_LenV2(b)));
}
static inline float HMM_DistV2(HMM_Vec2 a, HMM_Vec2 b) {
return HMM_LenV2(HMM_SubV2(a,b));
}
@ -844,10 +883,20 @@ static inline float HMM_LenV3(HMM_Vec3 A) {
return HMM_SqrtF(HMM_LenSqrV3(A));
}
static inline float HMM_AngleV3(HMM_Vec3 a, HMM_Vec3 b)
{
return acos(HMM_DotV3(a,b)/(HMM_LenV3(a)*HMM_LenV3(b)));
}
static inline float HMM_LenV4(HMM_Vec4 A) {
return HMM_SqrtF(HMM_LenSqrV4(A));
}
static inline float HMM_AngleV4(HMM_Vec4 a, HMM_Vec4 b)
{
return acos(HMM_DotV4(a,b)/(HMM_LenV4(a)*HMM_LenV4(b)));
}
static inline HMM_Vec2 HMM_NormV2(HMM_Vec2 A) {
// HMM_MulV2F(A, 1.0/HMM_LenV2(A)+FLOAT_MIN);
return HMM_MulV2F(A, HMM_InvSqrtF(HMM_DotV2(A, A)));
@ -953,6 +1002,7 @@ static inline HMM_Mat2 HMM_RotateM2(float angle)
return result;
}
static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right) {
HMM_Mat2 Result;
@ -1058,6 +1108,29 @@ static inline HMM_Mat3 HMM_M3D(float Diagonal) {
return Result;
}
static inline HMM_Mat3 HMM_Translate2D(HMM_Vec2 p)
{
HMM_Mat3 res = HMM_M3D(1);
res.Columns[2].XY = p;
return res;
}
static inline HMM_Mat3 HMM_RotateM3(float angle)
{
HMM_Mat3 r = HMM_M3D(1);
r.Columns[0] = (HMM_Vec3){cos(angle), sin(angle), 0};
r.Columns[1] = (HMM_Vec3){-sin(angle), cos(angle), 0};
return r;
}
static inline HMM_Mat3 HMM_ScaleM3(HMM_Vec2 s)
{
HMM_Mat3 sm = HMM_M3D(1);
sm.Columns[0].X = s.x;
sm.Columns[1].Y = s.y;
return sm;
}
static inline HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix) {
HMM_Mat3 Result = Matrix;
@ -1200,12 +1273,11 @@ static inline float HMM_DeterminantM3(HMM_Mat3 Matrix) {
return HMM_DotV3(Cross.Columns[2], Matrix.Columns[2]);
}
static inline HMM_Mat3 HMM_M2BasisPos(HMM_Mat2 basis, HMM_Vec2 pos)
static inline HMM_Mat3 HMM_M2Basis(HMM_Mat2 basis)
{
HMM_Mat3 m;
m.Columns[0].XY = basis.Columns[0];
m.Columns[1].XY = basis.Columns[1];
m.Columns[2].XY = pos;
m.Columns[2].Z = 1;
return m;
}

View file

@ -2,59 +2,53 @@
#include "log.h"
#include "stb_ds.h"
struct anim make_anim() {
struct anim a = {0};
a.interp = 1;
return a;
HMM_Vec4 sample_linear(sampler *sampler, float time, int prev, int next)
{
if (sampler->rotation)
return (HMM_Vec4)HMM_SLerp(sampler->data[prev].quat, time, sampler->data[next].quat);
else
return HMM_LerpV4(sampler->data[prev], time, sampler->data[next]);
}
void free_anim(struct anim a) {
arrfree(a.frames);
HMM_Vec4 sample_cubicspline(sampler *sampler, float t, int prev, int next)
{
float t2 = t*t;
float t3 = t2*t;
float td = sampler->times[next]-sampler->times[prev];
HMM_Vec4 v = HMM_MulV4F(sampler->data[prev*3+1], (2*t3-3*t2+1));
v = HMM_AddV4(v, HMM_MulV4F(sampler->data[prev*3+2], td*(t3-2*t2+t)));
v = HMM_AddV4(v, HMM_MulV4F(sampler->data[next*3+1], 3*t2-2*t3));
v = HMM_AddV4(v, HMM_MulV4F(sampler->data[next*3], td*(t3-t2)));
return v;
}
struct anim anim_add_keyframe(struct anim a, struct keyframe key) {
arrput(a.frames, key);
HMM_Vec4 sample_sampler(sampler *sampler, float time)
{
int previous_time=0;
int next_time=0;
return a;
for (int i = 1; i < arrlen(sampler->times); i++) {
if (time < sampler->times[i]) {
previous_time = sampler->times[i-1];
next_time = sampler->times[i];
break;
}
}
double interval(struct keyframe a, struct keyframe b, double t) {
return (t - a.time) / (b.time - a.time);
float td = sampler->times[next_time]-sampler->times[previous_time];
float t = (time - sampler->times[previous_time])/td;
switch(sampler->type) {
case LINEAR:
return sample_linear(sampler,t,previous_time,next_time);
break;
case STEP:
return sampler->data[previous_time];
break;
case CUBICSPLINE:
return sample_cubicspline(sampler,t, previous_time, next_time);
break;
}
double near_val(struct anim anim, double t) {
for (int i = 0; i < arrlen(anim.frames) - 1; i++) {
if (t > anim.frames[i + 1].time)
continue;
return (interval(anim.frames[i], anim.frames[i + 1], t) >= 0.5f ? anim.frames[i + 1].val : anim.frames[i].val);
}
return arrlast(anim.frames).val;
}
double lerp_val(struct anim anim, double t) {
for (int i = 0; i < arrlen(anim.frames) - 1; i++) {
if (t > anim.frames[i + 1].time)
continue;
double intv = interval(anim.frames[i], anim.frames[i + 1], t);
return ((1 - intv) * anim.frames[i].val) + (intv * anim.frames[i + 1].val);
}
return arrlast(anim.frames).val;
}
double cubic_val(struct anim anim, double t) {
return 0.0f;
}
double anim_val(struct anim anim, double t) {
if (anim.interp == 0)
return near_val(anim, t);
return lerp_val(anim, t);
}

View file

@ -1,19 +1,34 @@
#ifndef ANIM_H
#define ANIM_H
#include "HandmadeMath.h"
struct keyframe {
double time;
double val;
};
struct anim {
struct keyframe *frames;
int loop;
int interp;
#define LINEAR 0
#define STEP 1
#define CUBICSPLINE 2
typedef struct sampler {
float *times;
HMM_Vec4 *data;
int type;
int rotation;
} sampler;
struct anim_channel {
sampler *sampler;
};
struct anim make_anim();
struct anim anim_add_keyframe(struct anim a, struct keyframe f);
double anim_val(struct anim anim, double t);
struct animation {
char *name;
double time;
struct anim_channel *channels;
};
HMM_Vec4 sample_sampler(sampler *sampler, float time);
#endif

View file

@ -1,13 +1,7 @@
#include "gameobject.h"
#include "2dphysics.h"
#include "debugdraw.h"
#include "input.h"
#include "log.h"
#include "resources.h"
#include "script.h"
#include "shader.h"
#include "sprite.h"
#include <chipmunk/chipmunk.h>
#include <string.h>
#include "debugdraw.h"
@ -82,8 +76,6 @@ HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_go2w
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos) { return mat_t_pos(t_world2go(go), pos); }
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos) { return HMM_MulV2(go->scale.XY, pos); }
HMM_Mat3 t_go2world(struct gameobject *go) { return transform2d2mat(go2t(go)); }
HMM_Mat3 t_world2go(struct gameobject *go) { return HMM_InvGeneralM3(t_go2world(go)); }
@ -94,9 +86,8 @@ HMM_Mat4 t3d_world2go(struct gameobject *go) { return HMM_InvGeneralM4(t3d_go2wo
int pos2gameobject(HMM_Vec2 pos) {
cpShape *hit = phys2d_query_pos(pos.cp);
if (hit) {
if (hit)
return shape2gameobject(hit);
}
for (int i = 0; i < arrlen(gameobjects); i++) {
if (!gameobjects[i].body) continue;
@ -290,23 +281,6 @@ void gameobjects_cleanup() {
arrsetlen(go_toclean, 0);
}
void gameobject_move(struct gameobject *go, HMM_Vec2 vec) {
cpVect p = cpBodyGetPosition(go->body);
p.x += vec.x;
p.y += vec.y;
cpBodySetPosition(go->body, p);
phys2d_reindex_body(go->body);
}
void gameobject_rotate(struct gameobject *go, float as) {
cpFloat a = cpBodyGetAngle(go->body);
a += as * deltaT;
cpBodySetAngle(go->body, a);
phys2d_reindex_body(go->body);
}
void gameobject_setangle(struct gameobject *go, float angle) {
cpBodySetAngle(go->body, angle);
phys2d_reindex_body(go->body);
@ -315,7 +289,6 @@ void gameobject_setangle(struct gameobject *go, float angle) {
void gameobject_setpos(struct gameobject *go, cpVect vec) {
if (!go || !go->body) return;
cpBodySetPosition(go->body, vec);
phys2d_reindex_body(go->body);
}
@ -329,13 +302,6 @@ void gameobject_draw_debug(int go) {
if (!g || !g->body) return;
cpVect pos = cpBodyGetPosition(g->body);
struct rgba color = {
.r = 0.76*255,
.b = 0.38*255,
.g = 255,
.a = 255
};
cpBodyEachShape(g->body, body_draw_shapes_dbg, NULL);
}

View file

@ -2,10 +2,7 @@
#define GAMEOBJECT_H
#include "2dphysics.h"
#include "config.h"
#include <chipmunk/chipmunk.h>
#include <stdbool.h>
#include <stdio.h>
#include "quickjs/quickjs.h"
#include "HandmadeMath.h"
#include "transform.h"
@ -29,10 +26,6 @@
dag_rm(p->parent,p);\
}while(0)
struct shader;
struct sprite;
struct component;
typedef struct gameobject {
cpBodyType bodytype;
cpBody *body; /* NULL if this object is dead; has 2d position and rotation, relative to global 0 */
@ -49,7 +42,6 @@ typedef struct gameobject {
float damping;
unsigned int layer;
cpShapeFilter filter;
int id;
struct phys_cbs cbs;
struct shape_cb *shape_cbs;
JSValue ref;
@ -89,11 +81,6 @@ float go_worldangle(struct gameobject *go);
float go2angle(struct gameobject *go);
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos);
HMM_Vec2 gotpos(struct gameobject *go, HMM_Vec2 pos);
HMM_Mat3 mt_rst(transform2d t);
struct gameobject *id2go(int id);
int go2id(struct gameobject *go);
int body2id(cpBody *body);

View file

@ -11,8 +11,6 @@
#include <wchar.h>
#include "resources.h"
float deltaT = 0;
static int mouse_states[3] = {INPUT_UP};
static int key_states[512] = {INPUT_UP};

View file

@ -16,8 +16,6 @@ extern HMM_Vec2 mouse_delta;
#define INPUT_UP 1
#define INPUT_REPEAT 2
extern float deltaT;
void input_init();
void input_poll(double wait);

View file

@ -18,8 +18,8 @@
#include "sprite.h"
#include "stb_ds.h"
#include "string.h"
#include "tinyspline.h"
#include "window.h"
#include "spline.h"
#include "yugine.h"
#include <assert.h>
#include "resources.h"
@ -53,8 +53,8 @@ static JSValue TYPE##2js(TYPE *n) { \
QJSCLASS(dsp_node)
// gamobject2js, js2gameobject deals with gameobject*
// go2js,js2go deals with gameobject ids
// gameobject2js, js2gameobject deals with gameobject*, converted to ids
// go2js,js2go deals with gameobject*
QJSCLASS(gameobject)
@ -97,7 +97,6 @@ JSValue gos2ref(int *go)
return array;
}
JSValue js_getpropstr(JSValue v, const char *str)
{
JSValue p = JS_GetPropertyStr(js,v,str);
@ -399,42 +398,23 @@ JSValue bb2js(struct boundingbox bb)
}
JSValue duk_spline_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
// static_assert(sizeof(tsReal) * 2 == sizeof(HMM_Vec2));
tsBSpline spline;
int degrees = js2int(argv[1]);
int d = js2int(argv[2]); /* dimensions */
int degrees = js2int(argv[1]); /* not used */
int d = js2int(argv[2]); /* dimensions: 1d, 2d, 3d ...*/
/*
0: hermite-cubic
1: catmull-rom
2: b-spline
3: bezier
*/
int type = js2int(argv[3]);
HMM_Vec2 *points = js2cpvec2arr(argv[4]);
size_t nsamples = js2int(argv[5]);
tsStatus status;
ts_bspline_new(arrlen(points), d, degrees, type, &spline, &status);
if (status.code)
YughCritical("Spline creation error %d: %s", status.code, status.message);
ts_bspline_set_control_points(&spline, (tsReal*)points, &status);
if (status.code)
YughCritical("Spline creation error %d: %s", status.code, status.message);
HMM_Vec2 *samples = malloc(nsamples*sizeof(HMM_Vec2));
size_t rsamples;
/* TODO: This does not work with Clang/GCC due to UB */
ts_bspline_sample(&spline, nsamples, (tsReal **)&samples, &rsamples, &status);
if (status.code)
YughCritical("Spline creation error %d: %s", status.code, status.message);
HMM_Vec2 *samples = catmull_rom_ma_v2(points, nsamples);
JSValue arr = vecarr2js(samples, nsamples);
ts_bspline_free(&spline);
free(samples);
return arr;
return JS_UNDEFINED;
}
JSValue ints2js(int *ints) {
@ -523,6 +503,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
const char *str2 = NULL;
const void *d1 = NULL;
const void *d2 = NULL;
int *ids = NULL;
JSValue ret = JS_UNDEFINED;
switch (cmd) {
@ -754,7 +735,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 52:
ret = gos2ref(phys2d_query_box(js2vec2(argv[1]), js2vec2(argv[2])));
ids = phys2d_query_box(js2vec2(argv[1]), js2vec2(argv[2]));
ret = gos2ref(ids);
arrfree(ids);
break;
case 53:
@ -799,7 +782,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 63:
ret = JS_NewFloat64(js, deltaT);
break;
case 64:
@ -867,7 +849,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 80:
ret = gos2ref(phys2d_query_shape(js2ptr(argv[1])));
ids = phys2d_query_shape(js2ptr(argv[1]));
ret = gos2ref(ids);
arrfree(ids);
break;
case 81:
@ -891,7 +875,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 86:
ret = gos2ref(phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4])));
ids = phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4]));
ret = gos2ref(ids);
arrfree(ids);
break;
case 87:
@ -1150,6 +1136,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
break;
case 147:
YughWarn("EXITING");
exit(js2int(argv[1]));
break;
case 148:
@ -1549,7 +1536,6 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a
break;
case 3:
gameobject_move(go, js2vec2(argv[2]));
break;
case 4:
@ -1557,11 +1543,9 @@ JSValue duk_set_body(JSContext *js, JSValueConst this, int argc, JSValueConst *a
return JS_UNDEFINED;
case 5:
// go->flipx = JS_ToBool(js, argv[2]);
break;
case 6:
// go->flipy = JS_ToBool(js, argv[2]);
break;
case 7:
@ -1644,7 +1628,7 @@ JSValue duk_q_body(JSContext *js, JSValueConst this, int argc, JSValueConst *arg
JSValue duk_make_sprite(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
JSValue sprite = JS_NewObject(js);
js_setprop_str(sprite,"id",JS_NewInt64(js, make_sprite(jsgo2id(argv[0]))));
js_setprop_str(sprite,"id",JS_NewInt64(js, make_sprite(js2gameobject(argv[0]))));
return sprite;
}
@ -1666,9 +1650,8 @@ JSValue duk_make_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst
HMM_Vec2 size = js2vec2(argv[1]);
struct phys2d_box *box = Make2DBox(go);
box->w = size.x;
box->h = size.y;
box->offset = js2vec2(argv[2]);
box->t.scale = js2vec2(argv[1]);
box->t.pos = js2vec2(argv[2]);
phys2d_applybox(box);
@ -1687,17 +1670,15 @@ JSValue duk_cmd_box2d(JSContext *js, JSValueConst this, int argc, JSValueConst *
switch (cmd) {
case 0:
arg = js2vec2(argv[2]);
box->w = arg.x;
box->h = arg.y;
box->t.scale = js2vec2(argv[2]);
break;
case 1:
box->offset = js2vec2(argv[2]);
box->t.pos = js2vec2(argv[2]);
break;
case 2:
box->rotation = js2number(argv[2]);
box->t.angle = js2number(argv[2]);
break;
}
@ -1830,28 +1811,6 @@ JSValue duk_inflate_cpv(JSContext *js, JSValueConst this, int argc, JSValueConst
/* These are anims for controlling properties on an object */
JSValue duk_anim(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) {
JSValue prop = argv[0];
int keyframes = js_arrlen(argv[1]);
YughInfo("Processing %d keyframes.", keyframes);
struct anim a = make_anim();
for (int i = 0; i < keyframes; i++) {
struct keyframe k;
HMM_Vec2 v = js2vec2(js_getpropidx( argv[1], i));
k.time = v.y;
k.val = v.x;
a = anim_add_keyframe(a, k);
}
for (double i = 0; i < 3.0; i = i + 0.1) {
YughInfo("Val is now %f at time %f", anim_val(a, i), i);
JSValue vv = num2js(anim_val(a, i));
JSValue e = JS_Call(js, prop, globalThis, 1, &vv);
JS_FreeValue(js,e);
JS_FreeValue(js,vv);
}
return JS_UNDEFINED;
}

File diff suppressed because it is too large Load diff

View file

@ -1,263 +0,0 @@
/*
SPDX-License-Identifier: MIT
Parson 1.4.0 (https://github.com/kgabis/parson)
Copyright (c) 2012 - 2022 Krzysztof Gabis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef parson_parson_h
#define parson_parson_h
#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* unconfuse xcode */
#endif
#define PARSON_VERSION_MAJOR 1
#define PARSON_VERSION_MINOR 4
#define PARSON_VERSION_PATCH 0
#define PARSON_VERSION_STRING "1.4.0"
#include <stddef.h> /* size_t */
/* Types and enums */
typedef struct json_object_t JSON_Object;
typedef struct json_array_t JSON_Array;
typedef struct json_value_t JSON_Value;
enum json_value_type {
JSONError = -1,
JSONNull = 1,
JSONString = 2,
JSONNumber = 3,
JSONObject = 4,
JSONArray = 5,
JSONBoolean = 6
};
typedef int JSON_Value_Type;
enum json_result_t {
JSONSuccess = 0,
JSONFailure = -1
};
typedef int JSON_Status;
typedef void *(*JSON_Malloc_Function)(size_t);
typedef void (*JSON_Free_Function)(void *);
/* Call only once, before calling any other function from parson API. If not called, malloc and free
from stdlib will be used for all allocations */
void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun);
/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped.
This function sets a global setting and is not thread safe. */
void json_set_escape_slashes(int escape_slashes);
/* Sets float format used for serialization of numbers.
Make sure it can't serialize to a string longer than PARSON_NUM_BUF_SIZE.
If format is null then the default format is used. */
void json_set_float_serialization_format(const char *format);
/* Parses first JSON value in a file, returns NULL in case of error */
JSON_Value *json_parse_file(const char *filename);
/* Parses first JSON value in a file and ignores comments (/ * * / and //),
returns NULL in case of error */
JSON_Value *json_parse_file_with_comments(const char *filename);
/* Parses first JSON value in a string, returns NULL in case of error */
JSON_Value *json_parse_string(const char *string);
/* Parses first JSON value in a string and ignores comments (/ * * / and //),
returns NULL in case of error */
JSON_Value *json_parse_string_with_comments(const char *string);
/* Serialization */
size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */
JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename);
char *json_serialize_to_string(const JSON_Value *value);
/* Pretty serialization */
size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */
JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes);
JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename);
char *json_serialize_to_string_pretty(const JSON_Value *value);
void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */
/* Comparing */
int json_value_equals(const JSON_Value *a, const JSON_Value *b);
/* Validation
This is *NOT* JSON Schema. It validates json by checking if object have identically
named fields with matching types.
For example schema {"name":"", "age":0} will validate
{"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
In case of arrays, only first value in schema is checked against all values in tested array.
Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays,
null validates values of every type.
*/
JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value);
/*
* JSON Object
*/
JSON_Value *json_object_get_value(const JSON_Object *object, const char *name);
const char *json_object_get_string(const JSON_Object *object, const char *name);
size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object *json_object_get_object(const JSON_Object *object, const char *name);
JSON_Array *json_object_get_array(const JSON_Object *object, const char *name);
double json_object_get_number(const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
/* dotget functions enable addressing values with dot notation in nested objects,
just like in structs or c++/java/c# objects (e.g. objectA.objectB.value).
Because valid names in JSON can contain dots, some values may be inaccessible
this way. */
JSON_Value *json_object_dotget_value(const JSON_Object *object, const char *name);
const char *json_object_dotget_string(const JSON_Object *object, const char *name);
size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */
JSON_Object *json_object_dotget_object(const JSON_Object *object, const char *name);
JSON_Array *json_object_dotget_array(const JSON_Object *object, const char *name);
double json_object_dotget_number(const JSON_Object *object, const char *name); /* returns 0 on fail */
int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */
/* Functions to get available names */
size_t json_object_get_count(const JSON_Object *object);
const char *json_object_get_name(const JSON_Object *object, size_t index);
JSON_Value *json_object_get_value_at(const JSON_Object *object, size_t index);
JSON_Value *json_object_get_wrapping_value(const JSON_Object *object);
/* Functions to check if object has a value with a specific name. Returned value is 1 if object has
* a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */
int json_object_has_value(const JSON_Object *object, const char *name);
int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
int json_object_dothas_value(const JSON_Object *object, const char *name);
int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type);
/* Creates new name-value pair or frees and replaces old value with a new one.
* json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value);
JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string);
JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number);
JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean);
JSON_Status json_object_set_null(JSON_Object *object, const char *name);
/* Works like dotget functions, but creates whole hierarchy if necessary.
* json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value);
JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string);
JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number);
JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean);
JSON_Status json_object_dotset_null(JSON_Object *object, const char *name);
/* Frees and removes name-value pair */
JSON_Status json_object_remove(JSON_Object *object, const char *name);
/* Works like dotget function, but removes name-value pair only on exact match. */
JSON_Status json_object_dotremove(JSON_Object *object, const char *key);
/* Removes all name-value pairs in object */
JSON_Status json_object_clear(JSON_Object *object);
/*
*JSON Array
*/
JSON_Value *json_array_get_value(const JSON_Array *array, size_t index);
const char *json_array_get_string(const JSON_Array *array, size_t index);
size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */
JSON_Object *json_array_get_object(const JSON_Array *array, size_t index);
JSON_Array *json_array_get_array(const JSON_Array *array, size_t index);
double json_array_get_number(const JSON_Array *array, size_t index); /* returns 0 on fail */
int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */
size_t json_array_get_count(const JSON_Array *array);
JSON_Value *json_array_get_wrapping_value(const JSON_Array *array);
/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist.
* Order of values in array may change during execution. */
JSON_Status json_array_remove(JSON_Array *array, size_t i);
/* Frees and removes from array value at given index and replaces it with given one.
* Does nothing and returns JSONFailure if index doesn't exist.
* json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value);
JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char *string);
JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number);
JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean);
JSON_Status json_array_replace_null(JSON_Array *array, size_t i);
/* Frees and removes all values from array */
JSON_Status json_array_clear(JSON_Array *array);
/* Appends new value at the end of array.
* json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */
JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value);
JSON_Status json_array_append_string(JSON_Array *array, const char *string);
JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len); /* length shouldn't include last null character */
JSON_Status json_array_append_number(JSON_Array *array, double number);
JSON_Status json_array_append_boolean(JSON_Array *array, int boolean);
JSON_Status json_array_append_null(JSON_Array *array);
/*
*JSON Value
*/
JSON_Value *json_value_init_object(void);
JSON_Value *json_value_init_array(void);
JSON_Value *json_value_init_string(const char *string); /* copies passed string */
JSON_Value *json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */
JSON_Value *json_value_init_number(double number);
JSON_Value *json_value_init_boolean(int boolean);
JSON_Value *json_value_init_null(void);
JSON_Value *json_value_deep_copy(const JSON_Value *value);
void json_value_free(JSON_Value *value);
JSON_Value_Type json_value_get_type(const JSON_Value *value);
JSON_Object *json_value_get_object(const JSON_Value *value);
JSON_Array *json_value_get_array(const JSON_Value *value);
const char *json_value_get_string(const JSON_Value *value);
size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_value_get_number(const JSON_Value *value);
int json_value_get_boolean(const JSON_Value *value);
JSON_Value *json_value_get_parent(const JSON_Value *value);
/* Same as above, but shorter */
JSON_Value_Type json_type(const JSON_Value *value);
JSON_Object *json_object(const JSON_Value *value);
JSON_Array *json_array(const JSON_Value *value);
const char *json_string(const JSON_Value *value);
size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */
double json_number(const JSON_Value *value);
int json_boolean(const JSON_Value *value);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -2,6 +2,7 @@
#define PARTICLE_H
#include "HandmadeMath.h"
#include "transform.h"
struct particle {
HMM_Vec3 pos;
@ -15,12 +16,13 @@ struct particle {
};
};
struct emitter {
typedef struct emitter {
struct particle *particles;
transform3d t;
int max;
double life;
void (*seeder)(struct particle *p); /* Called to initialize each particle */
};
} emitter;
struct emitter make_emitter();
void free_emitter(struct emitter e);

View file

@ -506,7 +506,7 @@ void full_2d_pass(struct window *window)
//////////// 2D projection
cpVect pos = cam_pos();
projection = HMM_Orthographic_LH_ZO(
projection = HMM_Orthographic_LH_NO(
pos.x - zoom * window->rwidth / 2,
pos.x + zoom * window->rwidth / 2,
pos.y - zoom * window->rheight / 2,

View file

@ -435,7 +435,6 @@ dsp_node *dsp_fwd_delay(double sec, double decay)
d->ring = NULL;
d->ring = ringnew(d->ring, sec*CHANNELS*SAMPLERATE*2);
ringheader(d->ring)->write += CHANNELS*SAMPLERATE*sec;
YughWarn("FWD DELAY");
return make_node(d, filter_fwd_delay, delay_free);
}
@ -452,38 +451,31 @@ void dsp_adsr_fillbuf(struct dsp_adsr *adsr, soundbyte *out, int n)
for (int i = 0; i < n; i++) {
if (adsr->time > adsr->rls) {
// Totally decayed
adsr->out = 0.f;
goto fin;
}
if (adsr->time > adsr->sus) {
// Release phase
adsr->out = adsr->rls_t * adsr->out;
goto fin;
}
if (adsr->time > adsr->dec) {
// Sustain phase
adsr->out = adsr->sus_pwr;
goto fin;
}
if (adsr->time > adsr->atk) {
// Decay phase
adsr->out = (1 - adsr->dec_t) * adsr->sus_pwr + adsr->dec_t * adsr->out;
goto fin;
}
// Attack phase
adsr->out = (1-adsr->atk_t) + adsr->atk_t * adsr->out;
fin:
val = SHRT_MAX * adsr->out;

View file

@ -62,7 +62,6 @@ int make_sprite(int go) {
.layer = 0,
.next = -1,
.enabled = 1};
int id;
freelist_grab(id, sprites);
sprites[id] = sprite;
@ -119,21 +118,24 @@ int sprite_sort(int *a, int *b)
void sprite_draw_all() {
sg_apply_pipeline(pip_sprite);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
static int *layers;
int *layers = NULL;
if (layers) arrfree(layers);
for (int i = 0; i < freelist_len(sprites); i++)
if (sprites[i].next == -1 && sprites[i].go >= 0 && sprites[i].enabled)
arrpush(layers, i);
if (arrlen(layers) == 0) return;
if (!layers || arrlen(layers) == 0) return;
if (arrlen(layers) > 1)
qsort(layers, arrlen(layers), sizeof(*layers), sprite_sort);
for (int i = 0; i < arrlen(layers); i++)
sprite_draw(&sprites[layers[i]]);
arrfree(layers);
}
void sprite_loadtex(struct sprite *sprite, const char *path, struct glrect frame) {
if (!sprite) {
YughWarn("NO SPRITE!");
@ -201,20 +203,16 @@ void sprite_initialize() {
});
}
/* offset given in texture offset, so -0.5,-0.5 results in it being centered */
void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba emissive) {
struct sprite_vert verts[4];
float w = tex->width*st_s_w(r);
float h = tex->height*st_s_h(r);
HMM_Vec2 sposes[4] = {
{0.0,0.0},
{1.0,0.0},
{0.0,1.0},
{1.0,1.0},
};
HMM_Vec2 t_scale = {
tex->width * st_s_w(r), //*size.X;
tex->height * st_s_h(r) // * size.Y
{w,0.0},
{0.0,h},
{w,h}
};
for (int i = 0; i < 4; i++) {
@ -223,7 +221,6 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
verts[i].emissive = emissive;
}
if (!wrap) {
verts[0].uv.X = r.s0;
verts[0].uv.Y = r.t1;
verts[1].uv.X = r.s1;
@ -232,15 +229,6 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
verts[2].uv.Y = r.t0;
verts[3].uv.X = r.s1;
verts[3].uv.Y = r.t0;
} else {
// verts[0].uv = HMM_MulV2((HMM_Vec2){0,0}, size);
// verts[1].uv = HMM_MulV2((HMM_Vec2){1,0}, size);
// verts[2].uv = HMM_MulV2((HMM_Vec2){0,1}, size);
// verts[3].uv = HMM_MulV2((HMM_Vec2){1,1}, size);
for (int i = 0; i < 4; i++)
verts[i].uv = HMM_AddV2(verts[i].uv, wrapoffset);
}
bind_sprite.fs.images[0] = tex->id;
@ -256,16 +244,9 @@ void sprite_draw(struct sprite *sprite) {
if (sprite->tex) {
HMM_Mat3 m = t_go2world(go);
HMM_Mat3 sm = transform2d2mat(sprite->t);
HMM_Mat3 ss = HMM_M3D(1);
ss.Columns[0].X = sprite->t.scale.X * sprite->tex->width * st_s_w(sprite->frame);
ss.Columns[1].Y = sprite->t.scale.Y * sprite->tex->height * st_s_h(sprite->frame);
HMM_Mat3 ts = HMM_M3D(1);
ts.Columns[2] = (HMM_Vec3){sprite->t.pos.X, sprite->t.pos.Y, 1};
HMM_Mat3 sm = HMM_MulM3(ss, ts);
m = HMM_MulM3(m, sm);
tex_draw(sprite->tex, m, sprite->frame, sprite->color, 0, (HMM_Vec2){0,0}, 0, sprite->emissive);
tex_draw(sprite->tex, HMM_MulM3(m, sm), sprite->frame, sprite->color, 0, (HMM_Vec2){0,0}, 0, sprite->emissive);
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -36,9 +36,28 @@ HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir)
return mat3_t_pos(m, dir);
}
HMM_Mat3 transform2d2mat(transform2d t) {
HMM_Mat2 m = HMM_MulM2(HMM_RotateM2(t.angle), HMM_ScaleM2(t.scale));
return HMM_M2BasisPos(m, t.pos);
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)
{
transform2d t;
t.pos = m.Columns[2].xy;
t.scale = (HMM_Vec2){HMM_LenV2(m.Columns[0].xy), HMM_LenV2(m.Columns[1].xy)};
t.angle = acos(m.Columns[0].x/t.scale.x);
return t;
}
HMM_Mat4 transform3d2mat(transform3d t) { return HMM_MulM4(HMM_Translate(t.pos), HMM_MulM4(HMM_QToM4(t.rotation), HMM_Scale(t.scale))); }
transform3d mat2transform3d(HMM_Mat4 m)
{
transform3d t;
t.pos = m.Columns[3].xyz;
for (int i = 0; i < 2; i++)
t.scale.Elements[i] = HMM_LenV3(m.Columns[i].xyz);
// for (int i = 0; i < 2; i++)
// m.Columns[i].xyz = HMM_MulV3(m.Columns[i].xyz, t.scale.Elements[i]);
t.rotation = HMM_M4ToQ_RH(m);
}

View file

@ -17,6 +17,9 @@ typedef struct {
extern const transform2d t2d_unit;
#define VEC2_FMT "[%g,%g]"
#define VEC2_MEMS(s) (s).x, (s).y
HMM_Vec3 trans_forward(const transform3d *const trans);
HMM_Vec3 trans_back(const transform3d *trans);
HMM_Vec3 trans_up(const transform3d *trans);
@ -38,6 +41,8 @@ HMM_Vec3 mat3_t_pos(HMM_Mat4 m, HMM_Vec3 pos);
HMM_Vec3 mat3_t_dir(HMM_Mat4 m, HMM_Vec3 dir);
HMM_Mat3 transform2d2mat(transform2d t);
transform2d mat2transform2d(HMM_Mat3 m);
HMM_Mat4 transform3d2mat(transform3d t);
transform3d mat2transform3d(HMM_Mat4 m);
#endif

View file

@ -1,11 +1,13 @@
#include "yugine.h"
#include "font.h"
#include "transform.h"
#include "gameobject.h"
#include "input.h"
#include "render.h"
#include "window.h"
#include "sound.h"
#include "resources.h"
#include "spline.h"
#include <stdio.h>
#include "datastream.h"