clean up 3d model creation

This commit is contained in:
John Alanbrook 2024-08-08 17:32:58 -05:00
parent ceccd032c2
commit 57c2285019
8 changed files with 159 additions and 524 deletions

View file

@ -209,6 +209,8 @@ debug.api.print_doc = function(name)
return mdoc; return mdoc;
} }
debug.frozen = false;
return { return {
debug, debug,
Gizmos, Gizmos,

View file

@ -44,6 +44,8 @@ function set_model(t)
render.setunim4(0, cur.shader.vs.unimap.model.slot, t); render.setunim4(0, cur.shader.vs.unimap.model.slot, t);
} }
render.set_model = set_model;
var shaderlang = { var shaderlang = {
macos: "metal_macos", macos: "metal_macos",
windows: "hlsl5", windows: "hlsl5",

15
scripts/repl.js Normal file
View file

@ -0,0 +1,15 @@
var repl = {};
var file = "repl.jj";
var last = 0;
repl.hotreload = function() {
if (io.mod(file) > last) {
say("REPL:::");
last = io.mod(file);
var script = io.slurp(file);
eval(script);
}
}
return {repl:repl};

View file

@ -25,12 +25,11 @@ struct anim_channel {
sampler *sampler; sampler *sampler;
}; };
struct animation { typedef struct animation {
char *name;
double time; double time;
struct anim_channel *channels; struct anim_channel *channels;
sampler *samplers; sampler *samplers;
}; } animation;
void animation_run(struct animation *anim, float now); void animation_run(struct animation *anim, float now);
HMM_Vec4 sample_sampler(sampler *sampler, float time); HMM_Vec4 sample_sampler(sampler *sampler, float time);

View file

@ -48,8 +48,6 @@ static JSValue globalThis;
static JSClassID js_ptr_id; static JSClassID js_ptr_id;
static JSClassDef js_ptr_class = { "POINTER" }; static JSClassDef js_ptr_class = { "POINTER" };
static JSValue JSUNDEF;
JSValue str2js(const char *c, ...) { JSValue str2js(const char *c, ...) {
if (!c) return JS_UNDEFINED; if (!c) return JS_UNDEFINED;
char *result = NULL; char *result = NULL;
@ -95,6 +93,11 @@ void cpConstraint_free(cpConstraint *c)
cpConstraintFree(c); cpConstraintFree(c);
} }
void skin_free(skin *sk) {
arrfree(sk->invbind);
free(sk);
}
void jsfreestr(const char *s) { JS_FreeCString(js, s); } void jsfreestr(const char *s) { JS_FreeCString(js, s); }
QJSCLASS(gameobject) QJSCLASS(gameobject)
QJSCLASS(transform) QJSCLASS(transform)
@ -109,6 +112,7 @@ QJSCLASS(datastream)
QJSCLASS(cpShape) QJSCLASS(cpShape)
QJSCLASS(cpConstraint) QJSCLASS(cpConstraint)
QJSCLASS(timer) QJSCLASS(timer)
QJSCLASS(skin);
static JSValue js_circle2d; static JSValue js_circle2d;
static JSValue js_poly2d; static JSValue js_poly2d;
@ -205,6 +209,7 @@ uint64_t js2uint64(JSValue v)
JSValue angle2js(double g) { JSValue angle2js(double g) {
return number2js(g*HMM_RadToTurn); return number2js(g*HMM_RadToTurn);
} }
double js2angle(JSValue v) { double js2angle(JSValue v) {
double n = js2number(v); double n = js2number(v);
return n * HMM_TurnToRad; return n * HMM_TurnToRad;
@ -532,6 +537,7 @@ int js_print_exception(JSValue v)
JS_FreeCString(js, msg); JS_FreeCString(js, msg);
JS_FreeCString(js, stack); JS_FreeCString(js, stack);
JS_FreeValue(js,ex); JS_FreeValue(js,ex);
return 1; return 1;
#endif #endif
return 0; return 0;
@ -864,6 +870,45 @@ sg_shader js2shader(JSValue v)
return sh; return sh;
} }
#define MAT_POS 0
#define MAT_UV 1
#define MAT_NORM 2
#define MAT_BONE 3
#define MAT_WEIGHT 4
#define MAT_COLOR 5
#define MAT_TAN 6
#define MAT_ANGLE 7
#define MAT_WH 8
#define MAT_ST 9
#define MAT_PPOS 10
#define MAT_SCALE 11
static int mat2type(int mat)
{
switch(mat) {
case MAT_POS:
case MAT_NORM:
return SG_VERTEXFORMAT_FLOAT3;
case MAT_PPOS:
case MAT_WH:
case MAT_ST:
return SG_VERTEXFORMAT_FLOAT2;
case MAT_UV:
case MAT_TAN:
return SG_VERTEXFORMAT_USHORT2N;
return SG_VERTEXFORMAT_UINT10_N2;
case MAT_BONE:
return SG_VERTEXFORMAT_UBYTE4;
case MAT_WEIGHT:
case MAT_COLOR:
return SG_VERTEXFORMAT_UBYTE4N;
case MAT_ANGLE:
case MAT_SCALE:
return SG_VERTEXFORMAT_FLOAT;
};
return 0;
}
sg_vertex_layout_state js2layout(JSValue v) sg_vertex_layout_state js2layout(JSValue v)
{ {
sg_vertex_layout_state st = {0}; sg_vertex_layout_state st = {0};
@ -1892,6 +1937,7 @@ JSC_CCALL(transform_rotate,
transform *t = js2transform(self); transform *t = js2transform(self);
HMM_Quat rot = HMM_QFromAxisAngle_LH(axis, js2angle(argv[1])); HMM_Quat rot = HMM_QFromAxisAngle_LH(axis, js2angle(argv[1]));
t->rotation = HMM_MulQ(t->rotation,rot); t->rotation = HMM_MulQ(t->rotation,rot);
printf("rotation is now %g,%g,%g,%g\n", t->rotation.e[0], t->rotation.e[1], t->rotation.e[2], t->rotation.e[3]);
t->dirty = true; t->dirty = true;
) )
@ -2890,42 +2936,34 @@ JSC_CCALL(os_make_transform, return transform2js(make_transform()))
JSC_SCALL(os_system, return number2js(system(str)); ) JSC_SCALL(os_system, return number2js(system(str)); )
#define PRIMCHECK(VAR, JS, VAL) \ JSC_SCALL(os_gltf_buffer,
if (VAR->VAL.id) js_setpropstr(JS, #VAL, sg_buffer2js(&VAR->VAL)); \ int buffer_idx = js2number(argv[1]);
int type = js2number(argv[2]);
cgltf_options options = {0};
cgltf_data *data = NULL;
cgltf_result result = cgltf_parse_file(&options, str, &data);
result = cgltf_load_buffers(&options, data, str);
JSValue primitive2js(primitive *p) sg_buffer *b = malloc(sizeof(*b));
{ *b = accessor2buffer(&data->accessors[buffer_idx], type);
JSValue v = JS_NewObject(js); cgltf_free(data);
PRIMCHECK(p, v, pos)
PRIMCHECK(p,v,norm)
PRIMCHECK(p,v,uv)
PRIMCHECK(p,v,bone)
PRIMCHECK(p,v,weight)
PRIMCHECK(p,v,color)
PRIMCHECK(p,v,index)
js_setpropstr(v, "count", number2js(p->idx_count));
return v; ret = sg_buffer2js(b);
} )
JSValue material2js(material *m) JSC_SCALL(os_gltf_skin,
{ cgltf_options options = {0};
JSValue v = JS_NewObject(js); cgltf_data *data = NULL;
if (m->diffuse) cgltf_parse_file(&options,str,&data);
js_setpropstr(v, "diffuse", texture2js(m->diffuse)); cgltf_load_buffers(&options,data,str);
return v; if (data->skins_count <= 0) {
} ret = (JS_UNDEFINED);
goto CLEANUP;
}
JSC_SCALL(os_make_model, CLEANUP:
model *m = model_make(str); cgltf_free(data);
if (arrlen(m->meshes) != 1) return JSUNDEF;
mesh *me = m->meshes+0;
JSValue v = JS_NewObject(js);
js_setpropstr(v, "mesh", primitive2js(me->primitives+0));
js_setpropstr(v, "material", material2js(me->primitives[0].mat));
return v;
) )
JSC_CCALL(os_make_buffer, JSC_CCALL(os_make_buffer,
@ -3088,6 +3126,11 @@ JSC_SCALL(os_make_video,
js_setpropstr(ret, "texture", texture2js(t)); js_setpropstr(ret, "texture", texture2js(t));
) )
JSC_CCALL(os_skin_calculate,
skin *sk = js2skin(argv[0]);
skin_calculate(sk);
)
static const JSCFunctionListEntry js_os_funcs[] = { static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, cwd, 0), MIST_FUNC_DEF(os, cwd, 0),
MIST_FUNC_DEF(os, env, 1), MIST_FUNC_DEF(os, env, 1),
@ -3105,7 +3148,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, make_texture, 1), MIST_FUNC_DEF(os, make_texture, 1),
MIST_FUNC_DEF(os, make_tex_data, 3), MIST_FUNC_DEF(os, make_tex_data, 3),
MIST_FUNC_DEF(os, make_font, 2), MIST_FUNC_DEF(os, make_font, 2),
MIST_FUNC_DEF(os, make_model, 1),
MIST_FUNC_DEF(os, make_transform, 0), MIST_FUNC_DEF(os, make_transform, 0),
MIST_FUNC_DEF(os, make_buffer, 1), MIST_FUNC_DEF(os, make_buffer, 1),
MIST_FUNC_DEF(os, make_line_prim, 4), MIST_FUNC_DEF(os, make_line_prim, 4),
@ -3133,7 +3175,10 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, check_gc, 0), MIST_FUNC_DEF(os, check_gc, 0),
MIST_FUNC_DEF(os, check_cycles, 0), MIST_FUNC_DEF(os, check_cycles, 0),
MIST_FUNC_DEF(os, memstate, 0), MIST_FUNC_DEF(os, memstate, 0),
MIST_FUNC_DEF(os, value_id, 1) MIST_FUNC_DEF(os, value_id, 1),
MIST_FUNC_DEF(os, gltf_buffer, 3),
MIST_FUNC_DEF(os, gltf_skin, 1),
MIST_FUNC_DEF(os, skin_calculate, 1),
}; };
#include "steam.h" #include "steam.h"
@ -3147,7 +3192,6 @@ void ffi_load() {
cycles = tmpfile(); cycles = tmpfile();
quickjs_set_cycleout(cycles); quickjs_set_cycleout(cycles);
JSUNDEF = JS_UNDEFINED;
globalThis = JS_GetGlobalObject(js); globalThis = JS_GetGlobalObject(js);
QJSCLASSPREP(ptr); QJSCLASSPREP(ptr);

View file

@ -23,7 +23,7 @@ extern JSValue cpShape2js(cpShape *s);
#define JSC_SCALL(NAME, FN) JSC_CCALL(NAME, \ #define JSC_SCALL(NAME, FN) JSC_CCALL(NAME, \
const char *str = js2str(argv[0]); \ const char *str = js2str(argv[0]); \
FN ; \ {FN;} ; \
JS_FreeCString(js,str); \ JS_FreeCString(js,str); \
) \ ) \

View file

@ -25,47 +25,10 @@
#include "sokol/sokol_gfx.h" #include "sokol/sokol_gfx.h"
static void processnode(); #include "jsffi.h"
static void processmesh();
static void processtexture();
static cgltf_data *cdata;
static char *cpath;
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];
}
return NULL;
}
unsigned short pack_short_tex(float c) { return c * USHRT_MAX; } unsigned short pack_short_tex(float c) { return c * USHRT_MAX; }
void mesh_add_material(primitive *prim, cgltf_material *mat)
{
if (!mat) return;
prim->mat = calloc(sizeof(*prim->mat), 1);
material *pmat = prim->mat;
if (mat->has_pbr_metallic_roughness && mat->pbr_metallic_roughness.base_color_texture.texture) {
cgltf_image *img = mat->pbr_metallic_roughness.base_color_texture.texture->image;
if (img->buffer_view) {
cgltf_buffer_view *buf = img->buffer_view;
pmat->diffuse = texture_fromdata(buf->buffer->data, buf->size);
} else {
// char *path = makepath(dirname(cpath), img->uri);
// pmat->diffuse = texture_from_file(path);
// free(path);
}
} else
pmat->diffuse = texture_from_file("icons/moon.gif");
}
sg_buffer texcoord_floats(float *f, int n) sg_buffer texcoord_floats(float *f, int n)
{ {
unsigned short packed[n]; unsigned short packed[n];
@ -156,196 +119,57 @@ sg_buffer ubyte_buffer(float *f, int v)
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)}); return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
} }
sg_buffer joint_buf(float *f, int v) sg_buffer accessor2buffer(cgltf_accessor *a, int type)
{ {
char joints[v]; int n = cgltf_accessor_unpack_floats(a, NULL, 0);
for (int i = 0; i < (v); i++) float vs[n];
joints[i] = f[i]; cgltf_accessor_unpack_floats(a, vs, n);
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(joints)}); switch(type) {
} case cgltf_attribute_type_position:
return sg_make_buffer(&(sg_buffer_desc){
sg_buffer weight_buf(float *f, int v)
{
unsigned char weights[v];
for (int i = 0; i < (v); i++)
weights[i] = f[i]*255;
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(weights)});
}
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 primitive_gen_indices(primitive *prim)
{
if (prim->idx_count != 0) return;
uint16_t *idxs = malloc(sizeof(*idxs)*prim->idx_count);
for (int z = 0; z < prim->idx_count; z++)
idxs[z] = z;
prim->index = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * prim->idx_count,
.type = SG_BUFFERTYPE_INDEXBUFFER});
free(idxs);
}
struct primitive mesh_add_primitive(cgltf_primitive *prim)
{
primitive retp = (primitive){0};
uint16_t *idxs;
if (prim->indices) {
int n = cgltf_accessor_unpack_floats(prim->indices, NULL, 0);
float fidx[n];
cgltf_accessor_unpack_floats(prim->indices, fidx, n);
idxs = malloc(sizeof(*idxs)*n);
for (int i = 0; i < n; i++)
idxs[i] = fidx[i];
retp.index = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(*idxs) * n,
.type = SG_BUFFERTYPE_INDEXBUFFER,
.label = "mesh index buffer",
});
retp.idx_count = n;
free(idxs);
} else {
retp.idx_count = cgltf_accessor_unpack_floats(prim->attributes[0].data, NULL, 0);
primitive_gen_indices(&retp);
}
printf("adding material\n");
mesh_add_material(&retp, prim->material);
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 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);
switch (attribute.type) {
case cgltf_attribute_type_position:
retp.pos = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = vs, .data.ptr = vs,
.data.size = sizeof(float) * n, .data.size = sizeof(float)*n
.label = "mesh vert buffer" });
});
break;
case cgltf_attribute_type_normal: case cgltf_attribute_type_normal:
retp.norm = normal_floats(vs, n); return normal_floats(vs,n);
break;
case cgltf_attribute_type_tangent: case cgltf_attribute_type_tangent:
return normal_floats(vs,n); // TODO: MAKE A TANGENT READER
break; break;
case cgltf_attribute_type_color: case cgltf_attribute_type_color:
retp.color = ubyten_buffer(vs,n); return ubyten_buffer(vs,n);
break;
case cgltf_attribute_type_weights: case cgltf_attribute_type_weights:
retp.weight = ubyten_buffer(vs, n); return ubyten_buffer(vs,n);
break;
case cgltf_attribute_type_joints: case cgltf_attribute_type_joints:
retp.bone = ubyte_buffer(vs, n); return ubyte_buffer(vs,n);
break;
case cgltf_attribute_type_texcoord: case cgltf_attribute_type_texcoord:
retp.uv = texcoord_floats(vs, n); return texcoord_floats(vs,n);
break;
case cgltf_attribute_type_invalid: case cgltf_attribute_type_invalid:
YughWarn("Invalid type.");
break; break;
case 100:
case cgltf_attribute_type_custom: return index_buffer(vs,n);
break;
case cgltf_attribute_type_max_enum:
break;
}
} }
if (!retp.bone.id) { return sg_make_buffer(&(sg_buffer_desc) {
char joints[retp.idx_count*4]; .data.size = 4,
memset(joints, 0, retp.idx_count*4); .usage = SG_USAGE_STREAM
retp.bone = sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(joints)}); });
}
if (!retp.weight.id) {
char weights[retp.idx_count*4];
memset(weights,0,retp.idx_count*4);
retp.weight = sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(weights)});
}
if (!retp.color.id) {
char colors[retp.idx_count*4];
memset(colors,0,retp.idx_count*4);
retp.color = sg_make_buffer(&(sg_buffer_desc) { .data = SG_RANGE(colors) });
}
if (!retp.norm.id) {
YughInfo("Making normals.");
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; 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);
face_norms[i] = face_norms[i+1] = face_norms[i+2] = packed_norm;
}
retp.norm = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = face_norms,
.data.size = sizeof(uint32_t) * verts});
}
return retp;
}
void model_add_cgltf_mesh(mesh *m, cgltf_mesh *gltf_mesh)
{
for (int i = 0; i < gltf_mesh->primitives_count; i++)
arrput(m->primitives, mesh_add_primitive(gltf_mesh->primitives+i));
} }
void packFloats(float *src, float *dest, int srcLength) { void packFloats(float *src, float *dest, int srcLength) {
int i, j; int i, j;
for (i = 0, j = 0; i < srcLength; i += 3, j += 4) { for (i = 0, j = 0; i < srcLength; i += 3, j += 4) {
dest[j] = src[i]; dest[j] = src[i];
dest[j + 1] = src[i + 1]; dest[j + 1] = src[i + 1];
dest[j + 2] = src[i + 2]; dest[j + 2] = src[i + 2];
dest[j + 3] = 0.0f; dest[j + 3] = 0.0f;
} }
} }
void model_add_cgltf_anim(model *model, cgltf_animation *anim) animation *gltf_anim(cgltf_animation *anim)
{ {
YughInfo("FOUND ANIM, using %d channels and %d samplers", anim->channels_count, anim->samplers_count); animation *ret = calloc(sizeof(*ret), 1);
animation an = *ret;
struct animation an = (struct animation){0};
arrsetlen(an.samplers, anim->samplers_count); arrsetlen(an.samplers, anim->samplers_count);
for (int i = 0; i < anim->samplers_count; i++) { for (int i = 0; i < anim->samplers_count; i++) {
@ -378,7 +202,7 @@ void model_add_cgltf_anim(model *model, cgltf_animation *anim)
for (int i = 0; i < anim->channels_count; i++) { for (int i = 0; i < anim->channels_count; i++) {
cgltf_animation_channel ch = anim->channels[i]; cgltf_animation_channel ch = anim->channels[i];
struct anim_channel ach = (struct anim_channel){0}; struct anim_channel ach = (struct anim_channel){0};
md5joint *md = model->nodes+(ch.target_node-cdata->nodes); md5joint *md = NULL;
switch(ch.target_path) { switch(ch.target_path) {
case cgltf_animation_path_type_translation: case cgltf_animation_path_type_translation:
ach.target = &md->pos; ach.target = &md->pos;
@ -396,31 +220,28 @@ void model_add_cgltf_anim(model *model, cgltf_animation *anim)
arrput(an.channels, ach); arrput(an.channels, ach);
} }
model->anim = an; *ret = an;
model->anim.time = apptime();
} }
void model_add_cgltf_skin(model *model, cgltf_skin *skin) skin *make_gltf_skin(cgltf_skin *skin)
{ {
int n = cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, NULL, 0); int n = cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, NULL, 0);
struct skin sk = (struct skin){0}; struct skin *sk = NULL;
arrsetlen(sk.invbind, n/16); sk = calloc(sizeof(*sk),1);
cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, sk.invbind, n); arrsetlen(sk->invbind, n/16);
YughInfo("FOUND SKIN, of %d bones, and %d vert comps", skin->joints_count, n); cgltf_accessor_unpack_floats(skin->inverse_bind_matrices, sk->invbind, n);
cgltf_node *root = skin->skeleton; arrsetlen(sk->joints, skin->joints_count);
arrsetlen(sk.joints, skin->joints_count);
sk.root = model->nodes+(skin->skeleton-cdata->nodes);
for (int i = 0; i < 50; i++) for (int i = 0; i < 50; i++)
sk.binds[i] = MAT1; sk->binds[i] = MAT1;
for (int i = 0; i < skin->joints_count; i++) { for (int i = 0; i < skin->joints_count; i++) {
int offset = skin->joints[i]-cdata->nodes;
sk.joints[i] = model->nodes+offset;
md5joint *j = sk.joints[i];
cgltf_node *n = skin->joints[i]; cgltf_node *n = skin->joints[i];
int idx = n-skin->skeleton;
int parent_idx = n->parent-skin->skeleton;
md5joint *j = sk->joints+idx;
j->parent = sk->joints+parent_idx;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
j->pos.e[i] = n->translation[i]; j->pos.e[i] = n->translation[i];
j->scale.e[i] = n->scale[i]; j->scale.e[i] = n->scale[i];
@ -429,196 +250,17 @@ void model_add_cgltf_skin(model *model, cgltf_skin *skin)
j->rot.e[i] = n->rotation[i]; j->rot.e[i] = n->rotation[i];
} }
model->skin = sk; return sk;
} }
void model_process_node(model *model, cgltf_node *node) void skin_calculate(skin *sk)
{ {
int n = node-cdata->nodes;
cgltf_node_transform_world(node, model->nodes[n].t.e);
model->nodes[n].parent = model->nodes+(node->parent-cdata->nodes);
if (node->mesh) {
int meshn = node->mesh-cdata->meshes;
arrsetlen(model->meshes, meshn+1);
model->meshes[meshn].m = &model->nodes[n].t;
model_add_cgltf_mesh(model->meshes+meshn, node->mesh);
}
}
struct model *model_make(const char *path)
{
YughInfo("Making the model from %s.", path);
cpath = path;
cgltf_options options = {0};
cgltf_data *data = NULL;
cgltf_result result = cgltf_parse_file(&options, path, &data);
struct model *model = NULL;
if (result) {
YughError("CGLTF could not parse file %s, err %d.", path, result);
goto CLEAN;
}
result = cgltf_load_buffers(&options, data, path);
if (result) {
YughError("CGLTF could not load buffers for file %s, err %d.", path, result);
goto CLEAN;
}
cdata = data;
model = calloc(1, sizeof(*model));
arrsetlen(model->nodes, data->nodes_count);
for (int i = 0; i < data->nodes_count; i++)
model_process_node(model, data->nodes+i);
for (int i = 0; i < data->animations_count; i++)
model_add_cgltf_anim(model, data->animations+i);
for (int i = 0; i < data->skins_count; i++)
model_add_cgltf_skin(model, data->skins+i);
CLEAN:
cgltf_free(data);
return model;
}
void model_free(model *m)
{
}
sg_bindings primitive_bind(primitive *p)
{
sg_bindings b = {0};
b.vertex_buffers[MAT_POS] = p->pos;
b.vertex_buffers[MAT_UV] = p->uv;
b.vertex_buffers[MAT_NORM] = p->norm;
b.vertex_buffers[MAT_BONE] = p->bone;
b.vertex_buffers[MAT_WEIGHT] = p->weight;
b.vertex_buffers[MAT_COLOR] = p->color;
b.index_buffer = p->index;
b.fs.images[0] = p->mat->diffuse->id;
b.fs.samplers[0] = tex_sampler;
return b;
}
void model_draw_go(model *model, transform *go)
{
HMM_Mat4 gom = transform2mat(go);
animation_run(&model->anim, apptime());
skin *sk = &model->skin;
for (int i = 0; i < arrlen(sk->joints); i++) { for (int i = 0; i < arrlen(sk->joints); i++) {
md5joint *md = sk->joints[i]; md5joint *md = sk->joints+i;
HMM_Mat4 local = HMM_M4TRS(md->pos.xyz, md->rot, md->scale.xyz); HMM_Mat4 local = HMM_M4TRS(md->pos.xyz, md->rot, md->scale.xyz);
if (md->parent) if (md->parent)
local = HMM_MulM4(md->parent->t, local); local = HMM_MulM4(md->parent->t, local);
md->t = local; md->t = local;
sk->binds[i] = HMM_MulM4(md->t, sk->invbind[i]); sk->binds[i] = HMM_MulM4(md->t, sk->invbind[i]);
} }
/*sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_skinv, &(sg_range){
.ptr = sk->binds,
.size = sizeof(*sk->binds)*50
});
*/
for (int i = 0; i < arrlen(model->meshes); i++) {
HMM_Mat4 mod = *model->meshes[i].m;
mod = HMM_MulM4(mod, gom);
mesh msh = model->meshes[i];
for (int j = 0; j < arrlen(msh.primitives); j++) {
sg_bindings b = primitive_bind(msh.primitives+j);
sg_apply_bindings(&b);
sg_draw(0, msh.primitives[j].idx_count, 1);
}
}
}
int mat2type(int mat)
{
switch(mat) {
case MAT_POS:
case MAT_NORM:
return SG_VERTEXFORMAT_FLOAT3;
case MAT_PPOS:
case MAT_WH:
case MAT_ST:
return SG_VERTEXFORMAT_FLOAT2;
case MAT_UV:
case MAT_TAN:
return SG_VERTEXFORMAT_USHORT2N;
return SG_VERTEXFORMAT_UINT10_N2;
case MAT_BONE:
return SG_VERTEXFORMAT_UBYTE4;
case MAT_WEIGHT:
case MAT_COLOR:
return SG_VERTEXFORMAT_UBYTE4N;
case MAT_ANGLE:
case MAT_SCALE:
return SG_VERTEXFORMAT_FLOAT;
};
return 0;
}
int mat2step(int mat)
{
switch(mat) {
case MAT_POS:
case MAT_UV:
case MAT_TAN:
case MAT_NORM:
case MAT_BONE:
case MAT_WEIGHT:
return SG_VERTEXSTEP_PER_VERTEX;
};
return SG_VERTEXSTEP_PER_INSTANCE;
}
sg_buffer mat2buffer(int mat, primitive *p)
{
switch(mat) {
case MAT_POS: return p->pos;
case MAT_NORM: return p->norm;
case MAT_UV: return p->uv;
case MAT_BONE: return p->bone;
case MAT_WEIGHT: return p->weight;
case MAT_COLOR: return p->color;
};
return p->pos;
}
sg_bindings primitive_bindings(primitive *p, JSValue v)
{
sg_bindings b = {0};
JSValue inputs = js_getpropstr(js_getpropstr(v, "vs"), "inputs");
for (int i = 0; i < js_arrlen(inputs); i++) {
JSValue attr = js_getpropidx(inputs, i);
int mat = js2number(js_getpropstr(attr, "mat"));
int slot = js2number(js_getpropstr(attr, "slot"));
sg_buffer buf = mat2buffer(mat,p);
if (!buf.id) {
// ERROR
}
b.vertex_buffers[slot] = buf;
}
b.index_buffer = p->index;
return b;
}
void primitive_free(primitive *prim)
{
}
void material_free(material *mat)
{
} }

View file

@ -7,57 +7,7 @@
#include "gameobject.h" #include "gameobject.h"
#include "anim.h" #include "anim.h"
#include "texture.h" #include "texture.h"
#include "cgltf.h"
#define MAT_POS 0
#define MAT_UV 1
#define MAT_NORM 2
#define MAT_BONE 3
#define MAT_WEIGHT 4
#define MAT_COLOR 5
#define MAT_TAN 6
#define MAT_ANGLE 7
#define MAT_WH 8
#define MAT_ST 9
#define MAT_PPOS 10
#define MAT_SCALE 11
typedef struct material {
struct texture *diffuse;
struct texture *metalrough;
float metal;
float rough;
struct texture *normal;
float nrm;
struct texture *occlusion;
float occl;
struct texture *emissive;
HMM_Vec3 emis;
} material;
struct model;
typedef struct primitive {
sg_buffer pos;
sg_buffer norm;
sg_buffer uv;
sg_buffer bone;
sg_buffer weight;
sg_buffer color;
sg_buffer index;
material *mat;
uint32_t idx_count;
} primitive;
/* A single mesh */
typedef struct mesh {
primitive *primitives;
HMM_Mat4 *m;
} mesh;
typedef struct joint {
int me;
struct joint *children;
} joint_t;
typedef struct md5joint { typedef struct md5joint {
struct md5joint *parent; struct md5joint *parent;
@ -68,29 +18,14 @@ typedef struct md5joint {
} md5joint; } md5joint;
typedef struct skin { typedef struct skin {
md5joint **joints; md5joint *joints;
HMM_Mat4 *invbind; HMM_Mat4 *invbind;
HMM_Mat4 binds[50]; /* binds = joint * invbind */ HMM_Mat4 binds[50]; /* binds = joint * invbind */
md5joint *root;
} skin; } skin;
/* A collection of meshes which create a full figure */ sg_buffer accessor2buffer(cgltf_accessor *a, int type);
typedef struct model { skin *make_gltf_skin(cgltf_skin *skin);
struct mesh *meshes; void skin_calculate(skin *sk);
md5joint *nodes;
material *mats;
skin skin;
struct animation anim;
} model;
/* Make a Model struct */
struct model *model_make(const char *path);
void model_free(model *m);
void model_draw_go(model *m, transform *go);
sg_bindings primitive_bindings(primitive *p, JSValue pipe);
void primitive_gen_indices(primitive *prim);
int mat2type(int mat);
sg_buffer float_buffer(float *f, int v); sg_buffer float_buffer(float *f, int v);
sg_buffer index_buffer(float *f, int verts); sg_buffer index_buffer(float *f, int verts);
@ -101,9 +36,5 @@ sg_buffer ubyten_buffer(float *f, int v);
sg_buffer ubyte_buffer(float *f, int v); sg_buffer ubyte_buffer(float *f, int v);
sg_buffer joint_buf(float *f, int v); sg_buffer joint_buf(float *f, int v);
sg_buffer weight_buf(float *f, int v); sg_buffer weight_buf(float *f, int v);
void primitive_free(primitive *prim);
material *material_make();
void material_free(material *mat);
#endif #endif