From 366a20e7ed0152a37e3db612e69408c546967987 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Fri, 3 Nov 2023 13:31:06 +0000 Subject: [PATCH] 3d rendering --- scripts/components.js | 9 ++ source/engine/3d/model.c | 118 ++++++++++++++------- source/engine/3d/model.h | 15 ++- source/engine/HandmadeMath.h | 5 + source/engine/ffi.c | 19 ++++ source/engine/gameobject.c | 1 + source/engine/gameobject.h | 2 + source/engine/thirdparty/sokol/sokol_app.h | 44 ++++++++ source/shaders/diffuse.sglsl | 1 - 9 files changed, 173 insertions(+), 41 deletions(-) diff --git a/scripts/components.js b/scripts/components.js index 4dd2249..cdc3dcf 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -104,6 +104,15 @@ component.sprite.impl = { Object.freeze(sprite); +component.model = Object.copy(component, { + path:"", + _enghook: make_model, +}); +component.model.impl = { + set path(x) { cmd(149, this.id, x); }, + draw() { cmd(150, this.id); }, +}; + var sprite = component.sprite; sprite.doc = { diff --git a/source/engine/3d/model.c b/source/engine/3d/model.c index 390dcb7..e29395c 100644 --- a/source/engine/3d/model.c +++ b/source/engine/3d/model.c @@ -6,8 +6,11 @@ #include "stb_ds.h" #include "font.h" #include "window.h" +#include "gameobject.h" +#include "libgen.h" -#include "diffuse.sglsl.h" +//#include "diffuse.sglsl.h" +#include "unlit.sglsl.h" #include "render.h" @@ -39,18 +42,14 @@ static sg_shader model_shader; static sg_pipeline model_pipe; void model_init() { - model_shader = sg_make_shader(diffuse_shader_desc(sg_query_backend())); +/* model_shader = sg_make_shader(diffuse_shader_desc(sg_query_backend())); model_pipe = sg_make_pipeline(&(sg_pipeline_desc){ .shader = model_shader, .layout = { .attrs = { [0].format = SG_VERTEXFORMAT_FLOAT3, - [0].buffer_index = 0, /* position */ [1].format = SG_VERTEXFORMAT_USHORT2N, - [1].buffer_index = 1, /* tex coords */ - [2].format = SG_VERTEXFORMAT_UINT10_N2, - [2].buffer_index = 2, /* normal */ }, }, .index_type = SG_INDEXTYPE_UINT16, @@ -58,6 +57,24 @@ void model_init() { .depth.write_enabled = true, .depth.compare = SG_COMPAREFUNC_LESS_EQUAL }); +*/ + + model_shader = sg_make_shader(unlit_shader_desc(sg_query_backend())); + + model_pipe = sg_make_pipeline(&(sg_pipeline_desc){ + .shader = model_shader, + .layout = { + .attrs = { + [0].format = SG_VERTEXFORMAT_FLOAT3, + [1].format = SG_VERTEXFORMAT_USHORT2N, + [1].buffer_index = 1, + }, + }, + .index_type = SG_INDEXTYPE_UINT16, + .cull_mode = SG_CULLMODE_FRONT, + .depth.write_enabled = true, + .depth.compare = SG_COMPAREFUNC_LESS_EQUAL + }); } struct model *GetExistingModel(const char *path) { @@ -118,6 +135,7 @@ struct model *MakeModel(const char *path) { struct model *model = calloc(1, sizeof(*model)); /* TODO: Optimize by grouping by material. One material per draw. */ YughWarn("Model has %d materials.", data->materials_count); + const char *dir = dirname(path); float vs[65535*3]; uint16_t idxs[65535]; @@ -156,19 +174,21 @@ struct model *MakeModel(const char *path) { } if (primitive.material->has_pbr_metallic_roughness && primitive.material->pbr_metallic_roughness.base_color_texture.texture) { -// YughWarn("Texture is %s.", primitive.material->pbr_metallic_roughness.base_color_texture.texture->image->uri); + const char *imp = seprint("%s/%s", dir, primitive.material->pbr_metallic_roughness.base_color_texture.texture->image->uri); + YughInfo("Texture is %s.", imp); - model->meshes[j].bind.fs.images[0] = texture_pullfromfile(primitive.material->pbr_metallic_roughness.base_color_texture.texture->image->uri)->id; + 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; - 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; + model->meshes[j].bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){}); - model->meshes[j].bind.fs.images[2] = ddimg; + 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; @@ -184,6 +204,7 @@ struct model *MakeModel(const char *path) { 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}); @@ -194,10 +215,10 @@ struct model *MakeModel(const char *path) { 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}); + +// 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; @@ -209,7 +230,7 @@ struct model *MakeModel(const char *path) { 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 = vs, .data.size = sizeof(unsigned short) * 2 * model->meshes[j].face_count}); @@ -243,10 +264,10 @@ struct model *MakeModel(const char *path) { 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 - }); +// 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 +// }); } } } @@ -256,7 +277,7 @@ struct model *MakeModel(const char *path) { HMM_Vec3 eye = {50,10,5}; -void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm) { +void draw_model(struct model *model, HMM_Mat4 amodel) { HMM_Mat4 proj = HMM_Perspective_RH_ZO(45, (float)mainwin.width / mainwin.height, 0.1, 10000); HMM_Vec3 center = {0.f, 0.f, 0.f}; HMM_Vec3 up = {0.f, 1.f, 0.f}; @@ -268,23 +289,13 @@ void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm) { HMM_Vec3 lp = {1, 1, 1}; HMM_Vec3 dir_dir = HMM_NormV3(HMM_SubV3(center, dirl_pos)); - HMM_Mat4 m2[4]; - m2[0] = view; - m2[1] = amodel; - m2[2] = proj; - m2[3] = lsm; - - HMM_Vec3 f_ubo[5]; - f_ubo[0] = lp; - f_ubo[1] = dir_dir; - f_ubo[2] = eye; - f_ubo[3] = eye; - f_ubo[4] = eye; + vs_p_t vs_p; + memcpy(vs_p.vp, view.Elements, sizeof(float)*16); + memcpy(vs_p.model, amodel.Elements, sizeof(float)*16); + memcpy(vs_p.proj, proj.Elements, sizeof(float)*16); sg_apply_pipeline(model_pipe); - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(m2)); - sg_apply_uniforms(SG_SHADERSTAGE_FS, 0, SG_RANGE_REF(f_ubo)); - + sg_apply_uniforms(SG_SHADERSTAGE_VS, SLOT_vs_p, SG_RANGE_REF(vs_p)); for (int i = 0; i < arrlen(model->meshes); i++) { sg_apply_bindings(&model->meshes[i].bind); @@ -292,3 +303,32 @@ void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm) { } } +struct drawmodel *make_drawmodel(int go) +{ + struct drawmodel *dm = malloc(sizeof(struct drawmodel)); + dm->model = NULL; + dm->amodel = HMM_M4D(1.f); + dm->go = go; + return dm; +} + +void draw_drawmodel(struct drawmodel *dm) +{ + if (!dm->model) return; + struct gameobject *go = id2go(dm->go); + cpVect pos = cpBodyGetPosition(go->body); + HMM_Mat4 scale = HMM_Scale(id2go(dm->go)->scale3); + HMM_Mat4 trans = HMM_M4D(1.f); + trans.Elements[3][2] = -pos.x; + trans.Elements[3][1] = pos.y; + HMM_Mat4 rot = HMM_Rotate_RH(cpBodyGetAngle(go->body), vUP); + /* model matrix = trans * rot * scale */ + + draw_model(dm->model, HMM_MulM4(trans, HMM_MulM4(rot, scale))); +} + +void free_drawmodel(struct drawmodel *dm) +{ + free(dm); +} + diff --git a/source/engine/3d/model.h b/source/engine/3d/model.h index 2a91b5f..11f575c 100644 --- a/source/engine/3d/model.h +++ b/source/engine/3d/model.h @@ -8,15 +8,24 @@ extern HMM_Vec3 eye; struct shader; +/* A single mesh */ struct mesh { sg_bindings bind; uint32_t face_count; }; +/* A collection of meshes which create a full figure */ struct model { struct mesh *meshes; }; +/* A model with draw information */ +struct drawmodel { + struct model *model; + HMM_Mat4 amodel; + int go; +}; + /* Get the model at a path, or create and return if it doesn't exist */ struct model *GetExistingModel(const char *path); @@ -28,7 +37,11 @@ void loadmodel(struct model *model); void model_init(); -void draw_model(struct model *model, HMM_Mat4 amodel, HMM_Mat4 lsm); +void draw_model(struct model *model, HMM_Mat4 amodel); void draw_models(struct model *model, struct shader *shader); +struct drawmodel *make_drawmodel(int go); +void draw_drawmodel(struct drawmodel *dm); +void free_drawmodel(struct drawmodel *dm); + #endif diff --git a/source/engine/HandmadeMath.h b/source/engine/HandmadeMath.h index 2291be0..d31586c 100644 --- a/source/engine/HandmadeMath.h +++ b/source/engine/HandmadeMath.h @@ -542,6 +542,11 @@ static inline HMM_Vec3 HMM_V3(float X, float Y, float Z) { return Result; } +static inline HMM_Vec3 HMM_V3i(float i) +{ + return (HMM_Vec3){i,i,i}; +} + static inline HMM_Vec4 HMM_V4(float X, float Y, float Z, float W) { HMM_Vec4 Result; diff --git a/source/engine/ffi.c b/source/engine/ffi.c index c26cf7d..05a0fe8 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -650,6 +650,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 36: id2go(js2int(argv[1]))->scale = js2number(argv[2]); + id2go(js2int(argv[1]))->scale3 = HMM_V3i(js2number(argv[2])); gameobject_apply(id2go(js2int(argv[1]))); cpSpaceReindexShapesForBody(space, id2go(js2int(argv[1]))->body); break; @@ -1123,6 +1124,14 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 148: ret = color2js(id2sprite(js2int(argv[1]))->color); break; + case 149: + ((struct drawmodel *)js2ptr(argv[1]))->model = GetExistingModel(js2str(argv[2])); + break; + + case 150: + draw_drawmodel(js2ptr(argv[1])); + break; + } if (str) @@ -1491,6 +1500,15 @@ JSValue duk_make_circle2d(JSContext *js, JSValueConst this, int argc, JSValueCon return circleval; } +JSValue duk_make_model(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) +{ + int go = js2int(argv[0]); + struct drawmodel *dm = make_drawmodel(go); + JSValue ret = JS_NewObject(js); + js_setprop_str(ret, "id", ptr2js(dm)); + return ret; +} + JSValue duk_cmd_circle2d(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) { int cmd = js2int(argv[0]); struct phys2d_circle *circle = js2ptr(argv[1]); @@ -1675,6 +1693,7 @@ void ffi_load() { DUK_FUNC(cmd_poly2d, 6) DUK_FUNC(make_edge2d, 3) DUK_FUNC(cmd_edge2d, 6) + DUK_FUNC(make_model,2); DUK_FUNC(make_timer, 3) DUK_FUNC(cmd_points, 5); diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 54c6ad0..9683e20 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -144,6 +144,7 @@ static void gameobject_setpickcolor(struct gameobject *go) { int MakeGameobject() { struct gameobject go = { .scale = 1.f, + .scale3 = (HMM_Vec3){1.f,1.f,1.f}, .bodytype = CP_BODY_TYPE_STATIC, .mass = 1.f, .next = -1, diff --git a/source/engine/gameobject.h b/source/engine/gameobject.h index b9c0abd..161708a 100644 --- a/source/engine/gameobject.h +++ b/source/engine/gameobject.h @@ -7,6 +7,7 @@ #include #include #include "quickjs/quickjs.h" +#include "HandmadeMath.h" struct shader; struct sprite; @@ -16,6 +17,7 @@ struct gameobject { cpBodyType bodytype; int next; float scale; + HMM_Vec3 scale3; float mass; float f; /* friction */ float e; /* elasticity */ diff --git a/source/engine/thirdparty/sokol/sokol_app.h b/source/engine/thirdparty/sokol/sokol_app.h index 3b81160..0ec18c9 100644 --- a/source/engine/thirdparty/sokol/sokol_app.h +++ b/source/engine/thirdparty/sokol/sokol_app.h @@ -3471,6 +3471,50 @@ _SOKOL_PRIVATE void _sapp_macos_run(const sapp_desc* desc) { // set the application dock icon as early as possible, otherwise // the dummy icon will be visible for a short time sapp_set_icon(&_sapp.desc.icon); + +NSMenu* menu_bar = [[NSMenu alloc] init]; + NSMenuItem* app_menu_item = [[NSMenuItem alloc] init]; + [menu_bar addItem:app_menu_item]; + NSApp.mainMenu = menu_bar; + NSMenu* app_menu = [[NSMenu alloc] init]; + NSString* window_title_as_nsstring = [NSString stringWithUTF8String:desc->window_title]; + + NSString* quit_title = [@"Quit " stringByAppendingString:window_title_as_nsstring]; + NSMenuItem* quit_menu_item = [[NSMenuItem alloc] + initWithTitle:quit_title + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSString* hide_title = [@"Hide " stringByAppendingString:window_title_as_nsstring]; + NSMenuItem* hide_menu_item = [[NSMenuItem alloc] + initWithTitle:hide_title + action:@selector(hide:) + keyEquivalent:@"h"]; + + NSMenuItem* hide_others_item = [[NSMenuItem alloc] + initWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"]; + + [hide_others_item setKeyEquivalentModifierMask: NSEventModifierFlagOption]; + + NSMenuItem* show_all_item = [[NSMenuItem alloc] + initWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + + [app_menu addItem:hide_menu_item]; + [app_menu addItem:hide_others_item]; + [app_menu addItem:show_all_item]; + [app_menu addItem:[NSMenuItem separatorItem]]; + [app_menu addItem:quit_menu_item]; + app_menu_item.submenu = app_menu; + + _SAPP_OBJC_RELEASE(window_title_as_nsstring); + _SAPP_OBJC_RELEASE(app_menu); + _SAPP_OBJC_RELEASE(app_menu_item); + _SAPP_OBJC_RELEASE(menu_bar); + _sapp.macos.app_dlg = [[_sapp_macos_app_delegate alloc] init]; NSApp.delegate = _sapp.macos.app_dlg; diff --git a/source/shaders/diffuse.sglsl b/source/shaders/diffuse.sglsl index 685b190..7808cb1 100644 --- a/source/shaders/diffuse.sglsl +++ b/source/shaders/diffuse.sglsl @@ -8,7 +8,6 @@ out vec3 normal; out vec3 frag_pos; out vec4 frag_pos_light; - uniform vs_p { uniform mat4 vp; uniform mat4 model;