diff options
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | c2.cpp | 161 | ||||
-rw-r--r-- | configure.lua | 9 | ||||
-rw-r--r-- | intermediate/debug.glsl | 53 | ||||
-rw-r--r-- | model.cpp | 78 | ||||
-rw-r--r-- | model.hpp | 17 | ||||
-rw-r--r-- | pipeline.cpp | 5 | ||||
-rw-r--r-- | ui.cpp | 2 | ||||
-rw-r--r-- | video.cpp | 17 | ||||
-rw-r--r-- | video.hpp | 9 |
10 files changed, 346 insertions, 31 deletions
@@ -81,20 +81,22 @@ packer.o: packer.c packer: packer.o libqstd.a gcc $(opt_lnk) $(lflags) -o packer packer.o libqstd.a -data/triangle.csh: intermediate/triangle.glsl shadercompiler | data - ./shadercompiler intermediate/triangle.glsl data/triangle.csh -data/ui.csh: intermediate/ui.glsl shadercompiler | data - ./shadercompiler intermediate/ui.glsl data/ui.csh +data/debug.csh: intermediate/debug.glsl shadercompiler | data + ./shadercompiler intermediate/debug.glsl data/debug.csh +data/mip_spec.csh: intermediate/mip_spec.glsl shadercompiler | data + ./shadercompiler intermediate/mip_spec.glsl data/mip_spec.csh +data/sky.csh: intermediate/sky.glsl shadercompiler | data + ./shadercompiler intermediate/sky.glsl data/sky.csh data/surface.csh: intermediate/surface.glsl shadercompiler | data ./shadercompiler intermediate/surface.glsl data/surface.csh data/surface_depthonly.csh: intermediate/surface_depthonly.glsl shadercompiler | data ./shadercompiler intermediate/surface_depthonly.glsl data/surface_depthonly.csh -data/sky.csh: intermediate/sky.glsl shadercompiler | data - ./shadercompiler intermediate/sky.glsl data/sky.csh -data/mip_spec.csh: intermediate/mip_spec.glsl shadercompiler | data - ./shadercompiler intermediate/mip_spec.glsl data/mip_spec.csh +data/triangle.csh: intermediate/triangle.glsl shadercompiler | data + ./shadercompiler intermediate/triangle.glsl data/triangle.csh +data/ui.csh: intermediate/ui.glsl shadercompiler | data + ./shadercompiler intermediate/ui.glsl data/ui.csh -data/monkey.mdl: convmodel intermediate/monkey.glb data/triangle.csh data/ui.csh data/surface.csh data/surface_depthonly.csh data/sky.csh data/mip_spec.csh | data +data/monkey.mdl: convmodel intermediate/monkey.glb data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh | data ./convmodel data intermediate/monkey.glb data/monkey.mdl data/22.tex: convtexture intermediate/22.bmp | data @@ -115,8 +117,8 @@ data/bricks.mat: convmaterial intermediate/bricks.mat | data data/plastic.mat: convmaterial intermediate/plastic.mat | data ./convmaterial intermediate/plastic.mat data/plastic.mat -pack: packer data/triangle.csh data/ui.csh data/surface.csh data/surface_depthonly.csh data/sky.csh data/mip_spec.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat - ./packer pack data triangle.csh ui.csh surface.csh surface_depthonly.csh sky.csh mip_spec.csh monkey.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat +pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat + ./packer pack data debug.csh mip_spec.csh sky.csh surface.csh surface_depthonly.csh triangle.csh ui.csh monkey.mdl 22.tex kita.tex brick_albedo.tex brick_ao.tex brick_normal.tex sky.tex bricks.mat plastic.mat data: mkdir -p data @@ -124,7 +126,7 @@ data: -include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d c2.d video.d pipeline.d asset.d ui.d maths.d model.d convtexture.d convmodel.d convmaterial.d packer.d clean: - rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o c2.o video.o pipeline.o asset.o ui.o maths.o model.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d c2.d video.d pipeline.d asset.d ui.d maths.d model.d convtexture.d convmodel.d convmaterial.d packer.d data/triangle.csh data/ui.csh data/surface.csh data/surface_depthonly.csh data/sky.csh data/mip_spec.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat + rm -f qstd/memory.o qstd/plat.o qstd/str.o qstd/pack.o cfg/cfgparse.o sc/sc.o sc/includer.o app.o c2.o video.o pipeline.o asset.o ui.o maths.o model.o convtexture.o convmodel.o convmaterial.o packer.o qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d c2.d video.d pipeline.d asset.d ui.d maths.d model.d convtexture.d convmodel.d convmaterial.d packer.d data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data/surface_depthonly.csh data/triangle.csh data/ui.csh data/monkey.mdl data/22.tex data/kita.tex data/brick_albedo.tex data/brick_ao.tex data/brick_normal.tex data/sky.tex data/bricks.mat data/plastic.mat rm -f shadercompiler rmdir data rm -f c2 @@ -13,6 +13,7 @@ extern "C" { #define video_arena_size (1024 * 1024 * 16) #define asset_arena_size (1024 * 1024 * 4) #define ui_arena_size (1024 * 16) +#define scene_arena_size (1024) #define per_frame_memory_size (1024 * 1024) static float verts[] = { @@ -533,6 +534,134 @@ struct Env_Probe { } }; +struct Line_Renderer { + static constexpr int max_lines = 1024; + Staged_Buffer vb, cb; + Shader* shader; + int vert_binding, cbuffer_binding; + int cur; + int w, h; + v3f cur_col; + + struct Vertex { + float x, y, z; + float r, g, b; + }* verts; + + struct CBuffer { + m4f vp; + }; + + void init(Device* dev, Asset_Arena* assets) { + vb.init( + dev, + "Line Renderer mesh", + max_lines * sizeof(Vertex) * 2, + Buffer_Flags::vertex_buffer + ); + cb.init( + dev, + "Line Renderer cbuffer", + sizeof(CBuffer), + Buffer_Flags::constant_buffer + ); + shader = (Shader*)assets->load("debug.csh"); + vert_binding = shader->binding_index("verts"); + cbuffer_binding = shader->descriptor_binding("cbuf"); + assert(vert_binding >= 0); + assert(cbuffer_binding >= 0); + verts = (Vertex*)vb.map(dev); + cur = 0; + } + + void destroy(Device* dev) { + vb.unmap(dev); + vb.destroy(dev); + cb.destroy(dev); + } + + void begin(int wi, int he) { + cur = 0; + w = wi; + h = he; + cur_col = v3f(1.0f, 1.0f, 1.0f); + } + + void colour(const v3f& c) { + cur_col = c; + } + + void add_line(const v3f& s, const v3f& e) { + if (cur >= max_lines) { + assert(0); + return; + } + Vertex& a = verts[cur * 2]; + Vertex& b = verts[cur * 2 + 1]; + a.x = s.x; + a.y = s.y; + a.z = s.z; + b.x = e.x; + b.y = e.y; + b.z = e.z; + a.r = cur_col.x; + a.g = cur_col.y; + a.b = cur_col.z; + b.r = cur_col.x; + b.g = cur_col.y; + b.b = cur_col.z; + cur++; + } + + void add_box(const AABB& b) { + add_line(v3f(b.max.x, b.max.y, b.max.z), v3f(b.max.x, b.max.y, b.min.z)); + add_line(v3f(b.max.x, b.max.y, b.max.z), v3f(b.max.x, b.min.y, b.max.z)); + add_line(v3f(b.max.x, b.max.y, b.max.z), v3f(b.min.x, b.max.y, b.max.z)); + add_line(v3f(b.max.x, b.min.y, b.min.z), v3f(b.max.x, b.max.y, b.min.z)); + add_line(v3f(b.max.x, b.min.y, b.min.z), v3f(b.max.x, b.min.y, b.max.z)); + add_line(v3f(b.min.x, b.max.y, b.max.z), v3f(b.min.x, b.min.y, b.max.z)); + add_line(v3f(b.min.x, b.max.y, b.min.z), v3f(b.max.x, b.max.y, b.min.z)); + add_line(v3f(b.min.x, b.max.y, b.min.z), v3f(b.min.x, b.max.y, b.max.z)); + add_line(v3f(b.min.x, b.min.y, b.max.z), v3f(b.max.x, b.min.y, b.max.z)); + add_line(v3f(b.min.x, b.min.y, b.min.z), v3f(b.max.x, b.min.y, b.min.z)); + add_line(v3f(b.min.x, b.min.y, b.min.z), v3f(b.min.x, b.max.y, b.min.z)); + add_line(v3f(b.min.x, b.min.y, b.min.z), v3f(b.min.x, b.min.y, b.max.z)); + } + + void flush( + const Camera& cam, + Device* dev, + Arena* a, + Render_Pass& rp + ) { + if (!cur) return; + CBuffer* c = (CBuffer*)cb.map(dev); + c->vp = cam.get_proj() * cam.get_view(); + cb.unmap(dev); + Pipeline_Builder pb(a, dev); + Context& ctx = dev->get_ctx(); + cb.update(ctx); + vb.update(ctx); + pb.begin(); + pb.shader(shader->id); + pb.cbuffer(cbuffer_binding, cb.gpuonly); + pb.vertex_format(shader->vf); + pb.geo(Geo_Type::lines); + Pipeline& pip = pb.build(); + Vertex_Buffer_Binding binding[] = {{ + .id = vb.gpuonly, + .offset = 0, + .target = vert_binding + }, {}}; + Draw d{}; + d.verts = binding; + d.vertex_count = cur * 2; + d.instance_count = 1; + ctx.submit(d, pip, rp); + cur = 0; + } +}; + struct Config_Buffer { float offset[2]; }; @@ -543,7 +672,7 @@ struct Config_Buffer2 { }; struct C2 : public App { - Arena video_arena, asset_arena, ui_arena; + Arena video_arena, asset_arena, ui_arena, scene_arena; Model_Loader model_loader; Material_Loader mat_loader; Asset_Arena assets; @@ -559,6 +688,7 @@ struct C2 : public App { Env_Probe eprobe; Buffer_Id vbo, cbuf; Sampler_Id clamped_linear; + Line_Renderer lr; UI* ui; UI::Label* fps_label; void* per_frame; @@ -566,6 +696,8 @@ struct C2 : public App { uint8_t r = 0; float rot = 0.0f; v3f raxis = v3f(0.0f, 1.0f, 0.0); + Model_Instance* selected_model; + int selected_mesh; void on_init() override { running = 1; @@ -584,6 +716,11 @@ struct C2 : public App { arena_alloc(arena, ui_arena_size), ui_arena_size ); + init_arena( + &scene_arena, + arena_alloc(arena, scene_arena_size), + scene_arena_size + ); assets.init(&asset_arena, "pack", 128); dev = Device::create(&video_arena, this); default_texture = make_default_texture(dev); @@ -607,11 +744,12 @@ struct C2 : public App { ); clamped_linear = create_clamped_linear(dev); ui = UI::create(dev, this, &ui_arena, ui_shader->id); + lr.init(dev, &assets); assert(per_frame != 0); vbo = upload_verts(dev); ui->layout(w, h); fps_label = ui->create_element<UI::Label>(ui->root, ""); - scene.init(arena, 32, clamped_linear); + scene.init(&scene_arena, 32, clamped_linear); monkey = scene.instantiate( dev, (Model*)assets.load("monkey.mdl") @@ -630,6 +768,7 @@ struct C2 : public App { init_arena(&frame_arena, per_frame, per_frame_memory_size); dev->begin_frame(); + lr.begin(w, h); if (frame % 10 == 0) { char buf[32]; @@ -748,6 +887,23 @@ struct C2 : public App { ui->render(&frame_arena, dev->get_backbuffer()); ctx.debug_pop(); + if (mjp(mbtn_left)) { + std::tie(selected_model, selected_mesh) = + scene.pick(camera, w, h, mx, my); + } + + lr.colour(v3f(1.0f, 0.0f, 0.0f)); + + if (selected_model) { + lr.add_box(selected_model->bounds[selected_mesh]); + } + + ctx.debug_push("debug"); + pb.begin_rp(); + pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore); + lr.flush(camera, dev, &frame_arena, pb.build_rp()); + ctx.debug_pop(); + r += 10; rot += 1.0f * dt; frame++; @@ -757,6 +913,7 @@ struct C2 : public App { void on_destroy() override { scene.destroy(dev); sky.destroy(dev); + lr.destroy(dev); eprobe.destroy(dev); ui->destroy(); assets.destroy(); diff --git a/configure.lua b/configure.lua index 0509346..2c5672b 100644 --- a/configure.lua +++ b/configure.lua @@ -35,12 +35,13 @@ config = { "convmaterial" }, shaders = { - "triangle", - "ui", + "debug", + "mip_spec", + "sky", "surface", "surface_depthonly", - "sky", - "mip_spec" + "triangle", + "ui", }, materials = { "bricks", diff --git a/intermediate/debug.glsl b/intermediate/debug.glsl new file mode 100644 index 0000000..135511b --- /dev/null +++ b/intermediate/debug.glsl @@ -0,0 +1,53 @@ +#ifdef DESC +[program] +type: graphics +vertex: main +fragment: main + +[binding] +name: verts +rate: vertex +[attribute] +name: position +type: vec3 +[attribute] +name: colour +type: vec3 + +[struct] +name: CBuffer +[variable] +name: view_proj +type: mat4 + +[cbuffer] +type: CBuffer +name: cbuf +stage: vertex + +[interpolator] +name: colour +type: vec3 + +[target] +name: colour +type: vec4 + +#endif + +#ifdef VERTEX_SHADER + +void main() { + interpolator.colour = colour; + gl_Position = cbuf.view_proj * vec4(position, 1.0); +} + +#endif + +#ifdef FRAGMENT_SHADER + +void main() { + colour = vec4(interpolator.colour, 1.0); +} + +#endif @@ -9,6 +9,8 @@ extern "C" { } #include <string.h> +#include <stdio.h> +#include <algorithm> struct MVP_Cbuffer { m4f model; @@ -273,7 +275,7 @@ m4f Camera::get_proj() const { return m4f::pers(fov, asp, near, far); } -void Model_Instance::init(Device* dev, Model* model) { +void Model_Instance::init(Device* dev, Heap* h, Model* model) { m = model; mvp = dev->create_buffer( "Model instance MVP", @@ -287,11 +289,26 @@ void Model_Instance::init(Device* dev, Model* model) { Buffer_Flags::constant_buffer | Buffer_Flags::cpu_readwrite ); + bounds = (AABB*)heap_alloc( + h, + sizeof *bounds * model->mesh_count + ); } -void Model_Instance::destroy(Device* dev) { +void Model_Instance::destroy(Device* dev, Heap* h) { dev->destroy_buffer(mat); dev->destroy_buffer(mvp); + heap_free(h, bounds); +} + +void Model_Instance::update() { + Mesh* meshes = m->get_meshes(); + int i, c = m->mesh_count; + for (i = 0; i < c; i++) + bounds[i] = m4f::transform( + transform * meshes[i].world, + meshes[i].bound + ); } void Model_Instance::update_cbuffers( @@ -400,12 +417,34 @@ void Model_Instance::render( } } +int Model_Instance::pick(const v3f& o, const v3f& d) { + int i, c = m->mesh_count; + for (i = 0; i < c; i++) { + AABB& b = bounds[i]; + v3f id = 1.0f / d; + v3f t1 = (b.min - o) * id; + v3f t2 = (b.max - o) * id; + float tmin = std::max(std::max(std::min(t1.x, t2.x), std::min(t1.y, t2.y)), std::min(t1.z, t2.z)); + float tmax = std::min(std::min(std::max(t1.x, t2.x), std::max(t1.y, t2.y)), std::max(t1.z, t2.z)); + if (tmax < 0.0f || tmin > tmax) + { + continue; + } + return i; + } + return -1; +} + void Model_Scene::init( Arena* arena, int max_instances, Sampler_Id s ) { - instances = (Model_Instance*)arena_alloc(arena, max_instances); + int hs; + h = (Heap*)arena_alloc(arena, sizeof *h); + hs = arena->size - arena->ptr - allocation_default_alignment - 1; + init_heap(h, arena_alloc(arena, hs), hs); + instances = (Model_Instance*)heap_alloc(h, max_instances); count = 0; max = max_instances; sampler = s; @@ -417,7 +456,7 @@ Model_Instance* Model_Scene::instantiate( ) { Model_Instance* instance = &instances[count++]; assert(count <= max); - instance->init(dev, model); + instance->init(dev, h, model); return instance; } @@ -427,7 +466,7 @@ void Model_Scene::uninstantiate( ) { int idx = model - instances; int last = count - 1; - model->destroy(dev); + model->destroy(dev, h); instances[idx] = instances[last]; count = last; } @@ -435,8 +474,10 @@ void Model_Scene::uninstantiate( void Model_Scene::update(const Camera& cam, Device* dev) { int i; Model_Instance* instance = instances; - for (i = 0; i < count; i++, instance++) + for (i = 0; i < count; i++, instance++) { + instance->update(); instance->update_cbuffers(dev, cam); + } } void Model_Scene::render( @@ -456,5 +497,28 @@ void Model_Scene::destroy(Device* dev) { int i; Model_Instance* instance = instances; for (i = 0; i < count; i++, instance++) - instance->destroy(dev); + instance->destroy(dev, h); +} + +std::pair<Model_Instance*, int> Model_Scene::pick( + const Camera& cam, + int w, + int h, + int mx, + int my +) { + int i, c = count; + v2f uv = (2.0f * v2f(mx, my) - v2f(w, h)) / (float)h; + v4f e = + cam.get_proj().inverse() * + v4f(uv.x, uv.y, -1.0f, 1.0f); + e.z = -1.0f; e.w = 0.0f; + v4f d4 = cam.get_view().inverse() * e; + v3f d = v3f::normalised(v3f(d4.x, d4.y, d4.z)); + for (i = 0; i < c; i++) { + int m = instances[i].pick(cam.position, d); + if (m >= 0) return { &instances[i], m }; + } + return { 0, -1 }; } + @@ -5,6 +5,8 @@ #include "maths.hpp" #include "video.hpp" +#include <tuple> + struct Material : public Asset { float metalness, roughness, ao; v3f albedo; @@ -93,9 +95,11 @@ struct Model_Instance { Buffer_Id mat; m4f transform; Model* m; + AABB* bounds; - void init(Device* dev, Model* model); - void destroy(Device* dev); + void init(Device* dev, Heap* h, Model* model); + void destroy(Device* dev, Heap* h); + void update(); void update_cbuffers(Device* dev, const Camera& cam); void render( Device* dev, @@ -104,9 +108,11 @@ struct Model_Instance { Texture_Id env_cubemap, Sampler_Id sampler ); + int pick(const v3f& o, const v3f& d); }; struct Model_Scene { + Heap* h; Model_Instance* instances; int count, max; Sampler_Id sampler; @@ -124,6 +130,13 @@ struct Model_Scene { Texture_Id env_cubemap, Sampler_Id sampler ); + std::pair<Model_Instance*, int> pick( + const Camera& cam, + int w, + int h, + int mx, + int my + ); }; #endif diff --git a/pipeline.cpp b/pipeline.cpp index 1b55966..30c110c 100644 --- a/pipeline.cpp +++ b/pipeline.cpp @@ -165,6 +165,10 @@ void Pipeline_Builder::depth(bool test, bool write, Depth_Mode mode) { pip->depth_mode = mode; } +void Pipeline_Builder::geo(Geo_Type type) { + pip->geo = type; +} + void Pipeline_Builder::blend( Blend_Mode mode, Blend_Factor src, @@ -267,6 +271,7 @@ void Pipeline::hash() { h(pipeline_hash, depth_test); h(pipeline_hash, depth_write); h(pipeline_hash, depth_mode); + h(pipeline_hash, geo); h(pipeline_hash, blend_enable); h(pipeline_hash, blend_mode); h(pipeline_hash, blend_mode_alpha); @@ -515,9 +515,9 @@ void UI::render(Arena* s, Texture_Id target) { pb.texture(shader_info.atlas_binding, atlas, sampler); pipeline = &pb.build(); - mesh.reset(Rect(0, 0, t.w, t.h)); root->render(); mesh.draw(this, ctx, *pipeline, *render_pass); + mesh.reset(Rect(0, 0, t.w, t.h)); } void UI::draw_container(const Rect& bound, Colour c) { @@ -274,6 +274,19 @@ static VkCullModeFlags get_vk_cull_mode(Cull_Mode mode) { return VK_CULL_MODE_NONE; } +static VkPrimitiveTopology get_topology(Geo_Type type) { + switch (type) { + case Geo_Type::triangles: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case Geo_Type::lines: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case Geo_Type::points: + return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + } + assert(0); + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; +} + static VkFormat get_vk_format(Texture_Format fmt) { switch (fmt) { case texture_format_r8i: return VK_FORMAT_R8_UNORM; @@ -2847,11 +2860,9 @@ void Pipeline_Vk::init_input_assembly( sizeof ia ); (void)dev; - (void)desc; - (void)info; zero(&ia, sizeof ia); ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + ia.topology = get_topology(desc.geo); info.pInputAssemblyState = &ia; } @@ -110,6 +110,12 @@ enum class Cull_Mode { front }; +enum class Geo_Type { + triangles, + lines, + points +}; + struct Pipeline { uint64_t pipeline_hash; uint64_t descriptor_resource_hash; @@ -118,6 +124,7 @@ struct Pipeline { bool depth_test, depth_write; bool blend_enable; Depth_Mode depth_mode; + Geo_Type geo; Blend_Factor blend_src, blend_dst; Blend_Mode blend_mode; Blend_Factor blend_src_alpha, blend_dst_alpha; @@ -145,6 +152,7 @@ struct Pipeline { depth_test == other.depth_test && depth_write == other.depth_write && depth_mode == other.depth_mode && + geo == other.geo && blend_enable == other.blend_enable && blend_src == other.blend_src && blend_dst == other.blend_dst && @@ -300,6 +308,7 @@ struct Pipeline_Builder { void viewport(int x, int y, int w, int h); void scissor(int x, int y, int w, int h); void depth(bool test, bool write, Depth_Mode mode); + void geo(Geo_Type type); void blend(Blend_Mode mode, Blend_Factor src, Blend_Factor dst); void blend( Blend_Mode mode_col, |