diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | build.ninja | 3 | ||||
-rw-r--r-- | c2.cpp | 104 | ||||
-rw-r--r-- | configure.lua | 1 | ||||
-rw-r--r-- | hashmap.hpp | 158 | ||||
-rw-r--r-- | intermediate/surface.glsl | 22 | ||||
-rw-r--r-- | intermediate/surface_depthonly.glsl | 18 | ||||
-rw-r--r-- | lighting.cpp | 39 | ||||
-rw-r--r-- | lighting.hpp | 14 | ||||
-rw-r--r-- | model.cpp | 90 | ||||
-rw-r--r-- | model.hpp | 30 | ||||
-rw-r--r-- | pipeline.cpp | 9 | ||||
-rw-r--r-- | renderer.cpp | 169 | ||||
-rw-r--r-- | renderer.hpp | 74 | ||||
-rw-r--r-- | ui.hpp | 1 | ||||
-rw-r--r-- | video.cpp | 142 | ||||
-rw-r--r-- | video.hpp | 1 |
17 files changed, 620 insertions, 265 deletions
@@ -62,6 +62,8 @@ physics.o: physics.cpp g++ -std=c++20 $(opt_com) $(cflags) -c physics.cpp -o physics.o pipeline.o: pipeline.cpp g++ -std=c++20 $(opt_com) $(cflags) -c pipeline.cpp -o pipeline.o +renderer.o: renderer.cpp + g++ -std=c++20 $(opt_com) $(cflags) -c renderer.cpp -o renderer.o scene.o: scene.cpp g++ -std=c++20 $(opt_com) $(cflags) -c scene.cpp -o scene.o ui.o: ui.cpp @@ -70,8 +72,8 @@ video.o: video.cpp g++ -std=c++20 $(opt_com) $(cflags) -c video.cpp -o video.o world.o: world.cpp g++ -std=c++20 $(opt_com) $(cflags) -c world.cpp -o world.o -c2: app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o scene.o ui.o video.o world.o libqstd.a - g++ $(opt_lnk) $(lflags) -o c2 app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o scene.o ui.o video.o world.o libqstd.a -lX11 -lm +c2: app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o renderer.o scene.o ui.o video.o world.o libqstd.a + g++ $(opt_lnk) $(lflags) -o c2 app.o asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o renderer.o scene.o ui.o video.o world.o libqstd.a -lX11 -lm c2: pack @@ -145,10 +147,10 @@ pack: packer data/debug.csh data/mip_spec.csh data/sky.csh data/surface.csh data data: mkdir -p 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 asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d scene.d ui.d video.d world.d convtexture.d convmodel.d convmaterial.d packer.d +-include qstd/memory.d qstd/plat.d qstd/str.d qstd/pack.d cfg/cfgparse.d sc/sc.d sc/includer.d app.d asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.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 asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o scene.o ui.o video.o world.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 asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d scene.d ui.d video.d world.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/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.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 data/greybox.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 asset.o c2.o camera.o debugdraw.o editor.o lighting.o maths.o model.o physics.o pipeline.o renderer.o scene.o ui.o video.o world.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 asset.d c2.d camera.d debugdraw.d editor.d lighting.d maths.d model.d physics.d pipeline.d renderer.d scene.d ui.d video.d world.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/tonemap.csh data/triangle.csh data/ui.csh data/monkey.mdl data/cube.mdl data/scene.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 data/greybox.mat rm -f shadercompiler rmdir data rm -f c2 diff --git a/build.ninja b/build.ninja index 541cca9..0d15a5e 100644 --- a/build.ninja +++ b/build.ninja @@ -23,11 +23,12 @@ build maths.obj: cpp maths.cpp build model.obj: cpp model.cpp build physics.obj: cpp physics.cpp build pipeline.obj: cpp pipeline.cpp +build renderer.obj: cpp renderer.cpp build scene.obj: cpp scene.cpp build ui.obj: cpp ui.cpp build video.obj: cpp video.cpp build world.obj: cpp world.cpp -build c2.exe: link qstd/qstd.lib app.obj asset.obj c2.obj camera.obj debugdraw.obj editor.obj lighting.obj maths.obj model.obj physics.obj pipeline.obj scene.obj ui.obj video.obj world.obj +build c2.exe: link qstd/qstd.lib app.obj asset.obj c2.obj camera.obj debugdraw.obj editor.obj lighting.obj maths.obj model.obj physics.obj pipeline.obj renderer.obj scene.obj ui.obj video.obj world.obj libs = user32.lib build qstd/memory.obj: cpp qstd/memory.c @@ -5,6 +5,7 @@ #include "lighting.hpp" #include "model.hpp" #include "physics.hpp" +#include "renderer.hpp" #include "scene.hpp" #include "ui.hpp" #include "video.hpp" @@ -20,7 +21,7 @@ extern "C" { #define video_arena_size (1024 * 1024 * 16) #define asset_arena_size (1024 * 1024 * 4) #define ui_arena_size (1024 * 1024) -#define scene_arena_size (1024) +#define scene_arena_size (1024 * 4) #define per_frame_memory_size (1024 * 1024) static float verts[] = { @@ -94,7 +95,8 @@ static Sampler_Id create_clamped_linear(Device* dev) { return dev->create_sampler("repeated linear", s); } -struct Orbit_Cam : public Camera { +struct Orbit_Cam { + Camera* camera; bool first_frame; v3f target; int px, py; @@ -103,15 +105,16 @@ struct Orbit_Cam : public Camera { static constexpr float sense = 5.0f; static constexpr float min_dist = 0.3f; - void init() { + void init(Camera* cam) { pscroll = 0; first_frame = true; target = v3f(0.0f); - position = v3f(0.0f, 0.0f, -5.0f); - Camera::init( + camera = cam; + camera->position = v3f(0.0f, 0.0f, -5.0f); + camera->init( 90.0f, - v3f::normalised(target - position), - position + v3f::normalised(target - camera->position), + camera->position ); } @@ -122,36 +125,36 @@ struct Orbit_Cam : public Camera { if (app.mjp(mbtn_middle) || app.mjp(mbtn_right)) dx = dy = 0.0f; if (app.mp(mbtn_middle)) { - v3f left = v3f::cross(forward, v3f(0.0f, 1.0f, 0.0f)); - v3f up = v3f::cross(forward, left); - float dist = v3f::mag(position - target); - position += left * v3f(dx) * dist; - position += up * v3f(dy) * dist; - target = position + forward * dist; - forward = v3f::normalised(target - position); + v3f left = v3f::cross(camera->forward, v3f(0.0f, 1.0f, 0.0f)); + v3f up = v3f::cross(camera->forward, left); + float dist = v3f::mag(camera->position - target); + camera->position += left * v3f(dx) * dist; + camera->position += up * v3f(dy) * dist; + target = camera->position + camera->forward * dist; + camera->forward = v3f::normalised(target - camera->position); } if (app.mp(mbtn_right)) { m4f rotation = m4f::rotate( m4f::identity(), - forward.z < 0.0f? (float)dy: (float)-dy, + camera->forward.z < 0.0f? (float)dy: (float)-dy, v3f(1.0f, 0.0f, 0.0f) ) * m4f::rotate( m4f::identity(), (float)dx, v3f(0.0f, 1.0f, 0.0f) ); - v4f pos = v4f(position - target, 0.0f); + v4f pos = v4f(camera->position - target, 0.0f); yrot += dy; pos = rotation * pos; - position = target + v3f(pos.x, pos.y, pos.z); - forward = v3f::normalised(target - position); + camera->position = target + v3f(pos.x, pos.y, pos.z); + camera->forward = v3f::normalised(target - camera->position); } if (dscroll) { - v3f zp = position - forward * (float)dscroll; + v3f zp = camera->position - camera->forward * (float)dscroll; float dist = v3f::mag(zp - target); - if (dist < min_dist || v3f::dot(forward, zp - target) > 0.0f) - zp = target - forward * min_dist; - position = zp; + if (dist < min_dist || v3f::dot(camera->forward, zp - target) > 0.0f) + zp = target - camera->forward * min_dist; + camera->position = zp; } px = app.mx; py = app.my; @@ -640,8 +643,10 @@ struct C2 : public App { Texture_Id default_texture; Entity_Id monkey, monkey2, box, floor; Model_Scene scene; + Renderer renderer; Lighting lighting; - Orbit_Cam camera; + Camera_Id camera; + Orbit_Cam orbit_cam; Fullscreen_Quad quad; Sky sky; Env_Probe eprobe; @@ -710,6 +715,7 @@ struct C2 : public App { per_frame_memory_size ); clamped_linear = create_clamped_linear(dev); + renderer.init(arena, dev); world = (World*)arena_alloc(arena, sizeof *world); world->init(arena); ui = UI::create(this, &ui_arena); @@ -724,7 +730,8 @@ struct C2 : public App { sky.init(dev, &assets); eprobe.init(dev, &assets, 256); tonemap.init(dev, &assets); - camera.init(); + camera = renderer.create_camera(); + orbit_cam.init(&renderer.get_camera(camera)); { monkey = world->create_entity(); auto [_, mod] = world->add<Transform, C_Model>(monkey); @@ -732,6 +739,7 @@ struct C2 : public App { dev, (Model*)assets.load("monkey.mdl") ); + renderer.default_model(mod.i); } { monkey2 = world->create_entity(); @@ -740,6 +748,7 @@ struct C2 : public App { dev, (Model*)assets.load("monkey.mdl") ); + renderer.default_model(mod.i); } { auto sun = world->create_entity(); @@ -747,6 +756,7 @@ struct C2 : public App { light.colour = v3f(1.0f, 0.95f, 0.80f); light.dir = v3f(0.57f, 0.57f, 0.57f); light.brightness = 1.0f; + light.caster = true; } { box_col = make_box(&asset_arena, v3f(1.0f, 1.0f, 1.0f)); @@ -760,6 +770,7 @@ struct C2 : public App { dev, (Model*)assets.load("cube.mdl") ); + renderer.default_model(mod.i); floor = world->create_entity(); auto [transf, rbf, modf] = world->add<Transform, Rigidbody, C_Model>(floor); @@ -769,6 +780,7 @@ struct C2 : public App { dev, (Model*)assets.load("scene.mdl") ); + renderer.default_model(modf.i); } world->get<Transform>(monkey).mat = m4f::translate( m4f::identity(), @@ -792,10 +804,11 @@ struct C2 : public App { void on_update() override { float phys_dt = dt; Editor_Settings& es = editor_settings(); + Camera& pcam = renderer.get_camera(camera); Arena frame_arena; init_arena(&frame_arena, per_frame, per_frame_memory_size); - editor_update(*this, camera); + editor_update(*this, pcam); if (es.pause_physics) phys_dt = 0.0f; @@ -866,15 +879,6 @@ struct C2 : public App { dev->get_ctx().submit(pb.build_rp()); pb.begin_rp(); - pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); - Render_Pass& depth_prepass = pb.build_rp(); - - pb.begin_rp(); - pb.rp_target(hdr_target, Clear_Mode::restore); - pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); - Render_Pass& pass2 = pb.build_rp(); - - pb.begin_rp(); pb.rp_target(hdr_target, Clear_Mode::restore); pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); Render_Pass& sky_pass = pb.build_rp(); @@ -887,19 +891,24 @@ struct C2 : public App { eprobe.render(dev, &frame_arena, quad, sky); ctx.debug_pop(); + renderer.env_cubemap = eprobe.get_cubemap(); + renderer.clamped_linear = clamped_linear; + renderer.drawlists[FORWARD].camera = camera; + renderer.drawlists[SHADOW_MAP_START].camera = camera; + Texture& bb = dev->get_texture(hdr_target); - camera.asp = (float)bb.w / (float)bb.h; - camera.update_orbit(*this); - camera.update(); + pcam.asp = (float)bb.w / (float)bb.h; + orbit_cam.update_orbit(*this); + pcam.update(); lighting.update(dev, ctx, *world); - update_scene(scene, dev, lighting, camera, *world); + update_scene(scene, dev, lighting, pcam, *world); ctx.debug_push("scene"); - ctx.debug_push("depth prepass"); - scene.render(dev, &frame_arena, depth_prepass, &lighting, 0, clamped_linear); - ctx.debug_pop(); - ctx.debug_push("forward"); - scene.render(dev, &frame_arena, pass2, &lighting, eprobe.get_cubemap(), clamped_linear); - ctx.debug_pop(); + renderer.render( + dev, + &frame_arena, + hdr_target, + &lighting + ); ctx.debug_pop(); ctx.debug_push("sky"); @@ -909,7 +918,7 @@ struct C2 : public App { quad, sky_pass, clamped_linear, - camera, + pcam, hdr_target ); ctx.debug_pop(); @@ -966,7 +975,7 @@ struct C2 : public App { if (mjp(mbtn_left)) { auto [a, b] = scene_pick( *world, - camera, + pcam, w, h, mx, @@ -986,7 +995,7 @@ struct C2 : public App { pb.begin_rp(); pb.rp_target(dev->get_backbuffer(), Clear_Mode::restore); // pb.rp_depth_target(dev->get_depth_target(), Clear_Mode::restore); - lr.flush(camera, dev, &frame_arena, pb.build_rp()); + lr.flush(pcam, dev, &frame_arena, pb.build_rp()); ctx.debug_pop(); r += 10; @@ -1003,6 +1012,7 @@ struct C2 : public App { lr.destroy(dev); eprobe.destroy(dev); tonemap.destroy(dev); + renderer.destroy(dev); ui->destroy(); deinit_editor(); assets.destroy(); diff --git a/configure.lua b/configure.lua index d9fc7ec..c80f230 100644 --- a/configure.lua +++ b/configure.lua @@ -11,6 +11,7 @@ config = { "model", "physics", "pipeline", + "renderer", "scene", "ui", "video", diff --git a/hashmap.hpp b/hashmap.hpp new file mode 100644 index 0000000..952bf86 --- /dev/null +++ b/hashmap.hpp @@ -0,0 +1,158 @@ +#ifndef hashmap_hpp +#define hashmap_hpp + +extern "C" { +#include "plat.h" +} + +#include <tuple> +#include <stddef.h> + +template <typename T> +struct Hash_Function {}; + +template <typename Key, typename Value, int size> +struct Hash_Map { + enum { + flags_tombstone = 1 << 0, + flags_null = 1 << 1 + }; + + Key keys[size]; + Value values[size]; + uint8_t flags[size]; + + void init() { + int i; + for (i = 0; i < size; i++) flags[i] = flags_null; + } + + int find(const Key& to_find) const { + int tombstone = -1, i; + int bucket = (int)(Hash_Function<Key>{}(to_find) % (size_t)size); + for (i = 0; i < size; i++) { + const Key& k = keys[bucket]; + uint8_t flag = flags[bucket]; + if (flag & flags_null) { + if (flag & flags_tombstone) { + if (tombstone < 0) tombstone = bucket; + } else return tombstone >= 0? tombstone: bucket; + } else if (k == to_find) return bucket; + bucket = (bucket + 1) % size; + } + if (tombstone >= 0) return tombstone; + return -1; + } + + Value& set(const Key& k, const Value& v) { + int bucket = find(k); + assert(bucket >= 0); /* full */ + flags[bucket] = 0; + keys[bucket] = k; + values[bucket] = v; + return values[bucket]; + } + + Value* get(const Key& k) { + int bucket = find(k); + if (bucket < 0 || flags[bucket] & flags_null) return 0; + return &values[bucket]; + } + + Value& operator[](const Key& k) { + int bucket = find(k); + assert(bucket >= 0); + return values[bucket]; + } + + const Value& operator[](const Key& k) const { + int bucket = find(k); + assert(bucket >= 0); + return values[bucket]; + } + + Key* kaddr(const Key& k) { + int bucket = find(k); + if (bucket < 0 || flags[bucket] & flags_null) return 0; + return &keys[bucket]; + } + + void remove(const Key& k) { + int bucket = find(k); + assert(bucket >= 0); + flags[bucket] = flags_null | flags_tombstone; + } + + int has(const Key& k) { + int bucket = find(k); + return bucket >= 0 && ~flags[bucket] & flags_null; + } + + template <typename Table> + struct iterator { + Table* table; + int bucket; + + void init_begin(Table* t) { + bucket = 0; + table = t; + while ( + bucket < size && + table->flags[bucket] & flags_null + ) bucket++; + } + void init_end(Table* t) { + bucket = size; + table = t; + } + bool equals(const iterator<Table>& other) { + return bucket == other.bucket && table == other.table; + } + bool operator==(const iterator<Table>& other) { + return equals(other); + } + bool operator!=(const iterator<Table>& other) { + return !equals(other); + } + iterator<Table> operator++() { + bucket++; + while ( + bucket < size && + table->flags[bucket] & flags_null + ) bucket++; + return *this; + } + std::pair<Key&, Value&> operator*() { + return { table->keys[bucket], table->values[bucket] }; + } + std::pair<const Key&, const Value&> operator*() const { + return { table->keys[bucket], table->values[bucket] }; + } + }; + + iterator<Hash_Map<Key, Value, size>> begin() { + iterator<Hash_Map<Key, Value, size>> r; + r.init_begin(this); + return r; + } + + iterator<Hash_Map<Key, Value, size>> end() { + iterator<Hash_Map<Key, Value, size>> r; + r.init_end(this); + return r; + } + + iterator<const Hash_Map<Key, Value, size>> begin() const { + iterator<const Hash_Map<Key, Value, size>> r; + r.init_begin(this); + return r; + } + + iterator<const Hash_Map<Key, Value, size>> end() const { + iterator<const Hash_Map<Key, Value, size>> r; + r.init_end(this); + return r; + } +}; + +#endif diff --git a/intermediate/surface.glsl b/intermediate/surface.glsl index 17ddd06..9fc1c48 100644 --- a/intermediate/surface.glsl +++ b/intermediate/surface.glsl @@ -31,10 +31,13 @@ name: tbn type: mat3 [struct] -name: MVP +name: Model [variable] name: model type: mat4 + +[struct] +name: VP [variable] name: view_projection type: mat4 @@ -73,8 +76,13 @@ name: colour type: vec3 [cbuffer] -name: c_mvp -type: MVP +name: c_vp +type: VP +stage: vertex + +[cbuffer] +name: c_model +type: Model stage: vertex [cbuffer] @@ -121,15 +129,15 @@ type: vec4 #ifdef VERTEX_SHADER void main() { - vec4 pos = c_mvp.model * vec4(position, 1.0); - vec3 t = normalize((c_mvp.model * vec4(tangent, 0.0)).xyz); - vec3 n = normalize((c_mvp.model * vec4(normal, 0.0)).xyz); + vec4 pos = c_model.model * vec4(position, 1.0); + vec3 t = normalize((c_model.model * vec4(tangent, 0.0)).xyz); + vec3 n = normalize((c_model.model * vec4(normal, 0.0)).xyz); vec3 b = cross(t, n); interpolator.tbn = mat3(t, b, n); interpolator.uv = uv; interpolator.position = pos; interpolator.tbn = mat3(t, b, n); - gl_Position = c_mvp.view_projection * pos; + gl_Position = c_vp.view_projection * pos; } #endif diff --git a/intermediate/surface_depthonly.glsl b/intermediate/surface_depthonly.glsl index f53a937..2db5e96 100644 --- a/intermediate/surface_depthonly.glsl +++ b/intermediate/surface_depthonly.glsl @@ -12,17 +12,25 @@ name: position type: vec3 [struct] -name: MVP +name: Model [variable] name: model type: mat4 + +[struct] +name: VP [variable] name: view_projection type: mat4 [cbuffer] -name: c_mvp -type: MVP +name: c_vp +type: VP +stage: vertex + +[cbuffer] +name: c_model +type: Model stage: vertex #endif @@ -30,8 +38,8 @@ stage: vertex #ifdef VERTEX_SHADER void main() { - vec4 pos = c_mvp.model * vec4(position, 1.0); - gl_Position = c_mvp.view_projection * pos; + vec4 pos = c_model.model * vec4(position, 1.0); + gl_Position = c_vp.view_projection * pos; } #endif diff --git a/lighting.cpp b/lighting.cpp index d78ef6e..75ae7c2 100644 --- a/lighting.cpp +++ b/lighting.cpp @@ -1,4 +1,5 @@ #include "lighting.hpp" +#include "model.hpp" #include "world.hpp" extern "C" { @@ -15,21 +16,52 @@ struct GPU_Light { }; void Lighting::init(Device* dev) { + int i; lights.init( dev, "Light buffer", max_lights * sizeof(GPU_Light), Buffer_Flags::storage_buffer ); + shadows = dev->create_texture( + "Shadowmap Array", + texture_format_d16, + Texture_Flags::sampleable | Texture_Flags::depth_stencil_target, + shadow_res, + shadow_res, + 1, + 1, + max_shadows, + 0 + ); + for (i = 0; i < max_shadows; i++) { + shadow_slices[i] = dev->alias_texture( + shadows, + "Shadowmap Slice", + texture_format_d16, + Texture_Flags::depth_stencil_target, + shadow_res, + shadow_res, + 1, + 1, + 1, + 0, + i + ); + } } void Lighting::destroy(Device* dev) { + int i; lights.destroy(dev); + for (i = 0; i < max_shadows; i++) + dev->destroy_texture(shadow_slices[i]); + dev->destroy_texture(shadows); } void Lighting::write_buf(void* ptr, World& w) { GPU_Light* dst = (GPU_Light*)ptr; - int count = 0; + int count = 0, ccount = 0; for (auto v : w.view<Sun_Light>()) { GPU_Light gl; Sun_Light& l = v.get<Sun_Light>(); @@ -41,8 +73,13 @@ void Lighting::write_buf(void* ptr, World& w) { gl.colour = l.colour; gl.dir = l.dir; dst[count++] = gl; + if (l.caster) { + Caster& c = casters[ccount++]; + c.vp = m4f::identity(); + } } light_count = count; + caster_count = ccount; } void Lighting::update(Device* dev, Context& ctx, World& w) { diff --git a/lighting.hpp b/lighting.hpp index f7708a1..627de66 100644 --- a/lighting.hpp +++ b/lighting.hpp @@ -5,12 +5,23 @@ #include "video.hpp" struct Arena; +struct Model_Resources; +struct Model_Scene; struct World; +struct Caster { + m4f vp; +}; + struct Lighting { static constexpr int max_lights = 128; + static constexpr int max_shadows = 16; + static constexpr int shadow_res = 512; Staged_Buffer lights; - int light_count; + Texture_Id shadows; + Texture_Id shadow_slices[max_shadows]; + Caster casters[max_shadows]; + int light_count, caster_count; void init(Device* dev); void destroy(Device* dev); void update(Device* dev, Context& ctx, World& w); @@ -20,6 +31,7 @@ struct Lighting { struct Light { v3f colour; float brightness; + bool caster; }; struct Sun_Light : Light { @@ -14,9 +14,9 @@ extern "C" { #include <stdio.h> #include <algorithm> -struct MVP_Cbuffer { +struct Model_Cbuffer { m4f model; - m4f view_projection; + m4f reserved; }; struct Mat_Cbuffer { @@ -130,13 +130,18 @@ Asset* Model_Loader::load( assert(mesh.material != 0); mesh.shader = shader->id; mesh.depth_shader = depth_shader->id; - mesh.mvp_binding = shader->descriptor_binding("c_mvp"); - mesh.mvp_binding_depth = depth_shader->descriptor_binding("c_mvp"); + mesh.model_binding = shader->descriptor_binding("c_model"); + mesh.model_binding_depth = depth_shader->descriptor_binding("c_model"); + mesh.vp_binding = shader->descriptor_binding("c_vp"); + mesh.vp_binding_depth = depth_shader->descriptor_binding("c_vp"); mesh.mat_binding = shader->descriptor_binding("material"); mesh.light_binding = shader->descriptor_binding("lights"); mesh.env_cube_binding = shader->descriptor_binding("env_cube"); mesh.mesh_binding = shader->binding_index("mesh"); - assert(mesh.mvp_binding >= 0); + assert(mesh.model_binding >= 0); + assert(mesh.model_binding_depth >= 0); + assert(mesh.vp_binding >= 0); + assert(mesh.vp_binding_depth >= 0); assert(mesh.mat_binding >= 0); assert(mesh.light_binding >= 0); assert(mesh.mesh_binding >= 0); @@ -264,9 +269,9 @@ void Material_Loader::unload(Asset* a) { void Model_Instance::init(Device* dev, Heap* h, Model* model) { m = model; - mvp = dev->create_buffer( - "Model instance MVP", - sizeof(MVP_Cbuffer) * m->mesh_count, + mcb = dev->create_buffer( + "Model instance Model", + sizeof(Model_Cbuffer) * m->mesh_count, Buffer_Flags::constant_buffer | Buffer_Flags::cpu_readwrite ); @@ -284,7 +289,7 @@ void Model_Instance::init(Device* dev, Heap* h, Model* model) { void Model_Instance::destroy(Device* dev, Heap* h) { dev->destroy_buffer(mat); - dev->destroy_buffer(mvp); + dev->destroy_buffer(mcb); heap_free(h, bounds); } @@ -305,22 +310,20 @@ void Model_Instance::update_cbuffers( ) { int i, c = m->mesh_count; Mesh* meshes = m->get_meshes(); - MVP_Cbuffer* mvps = (MVP_Cbuffer*)dev->map_buffer( - mvp, + Model_Cbuffer* mcbs = (Model_Cbuffer*)dev->map_buffer( + mcb, 0, - c * sizeof *mvps + c * sizeof *mcbs ); Mat_Cbuffer* mats = (Mat_Cbuffer*)dev->map_buffer( mat, 0, c * sizeof *mats ); - m4f view_projection = cam.get_proj() * cam.get_view(); for (i = 0; i < c; i++) { Mat_Cbuffer& mat = mats[i]; Material& sm = *meshes[i].material; - mvps[i].view_projection = view_projection; - mvps[i].model = transform * meshes[i].world; + mcbs[i].model = transform * meshes[i].world; mat.albedo[0] = sm.albedo.x; mat.albedo[1] = sm.albedo.y; mat.albedo[2] = sm.albedo.z; @@ -332,7 +335,7 @@ void Model_Instance::update_cbuffers( mat.camera_pos[1] = cam.position.y; mat.camera_pos[2] = cam.position.z; } - dev->unmap_buffer(mvp); + dev->unmap_buffer(mcb); dev->unmap_buffer(mat); } @@ -341,8 +344,7 @@ void Model_Instance::render( Arena* a, Render_Pass& pass, const Lighting* lighting, - Texture_Id env_cubemap, - Sampler_Id sampler + const Model_Resources& res ) { int i, c = m->mesh_count; Mesh* meshes = m->get_meshes(); @@ -368,21 +370,25 @@ void Model_Instance::render( draw.instance_count = 1; draw.first_vertex = mesh.offset; draw.vertex_offset = mesh.vbo_offset; - pb.begin(); + pb.begin(&pass); if (depth_only) { pb.depth(true, true, Depth_Mode::less); pb.shader(mesh.depth_shader); pb.cbuffer( - mesh.mvp_binding_depth, - mvp, - i * sizeof(MVP_Cbuffer), - sizeof(MVP_Cbuffer) + mesh.model_binding_depth, + mcb, + i * sizeof(Model_Cbuffer), + sizeof(Model_Cbuffer) + ); + pb.cbuffer( + mesh.vp_binding_depth, + res.vp ); } else { pb.depth(true, false, Depth_Mode::equal); pb.shader(mesh.shader); pb.sbuffer(mesh.light_binding, lighting->lights.gpuonly); - mesh.material->use(pb, sampler, dev->get_shader(mesh.shader)); + mesh.material->use(pb, res.sampler, dev->get_shader(mesh.shader)); pb.cbuffer( mesh.mat_binding, mat, @@ -390,15 +396,19 @@ void Model_Instance::render( sizeof(Mat_Cbuffer) ); pb.cbuffer( - mesh.mvp_binding, - mvp, - i * sizeof(MVP_Cbuffer), - sizeof(MVP_Cbuffer) + mesh.model_binding, + mcb, + i * sizeof(Model_Cbuffer), + sizeof(Model_Cbuffer) + ); + pb.cbuffer( + mesh.vp_binding, + res.vp ); pb.texture( mesh.env_cube_binding, - env_cubemap, - sampler + res.env_cubemap, + res.sampler ); } pb.cull(Cull_Mode::back); @@ -417,7 +427,11 @@ void Model_Scene::init( 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); + instances = (Model_Instance*)heap_alloc( + h, + max_instances * sizeof *instances + ); + assert(instances != 0); count = 0; max = max_instances; sampler = s; @@ -457,20 +471,6 @@ void Model_Scene::update( } } -void Model_Scene::render( - Device* dev, - Arena* a, - Render_Pass& pass, - const Lighting* lighting, - Texture_Id env_cubemap, - Sampler_Id sampler -) { - int i; - Model_Instance* instance = instances; - for (i = 0; i < count; i++, instance++) - instance->render(dev, a, pass, lighting, env_cubemap, sampler); -} - void Model_Scene::destroy(Device* dev) { int i; Model_Instance* instance = instances; @@ -30,9 +30,16 @@ struct Material : public Asset { struct Model; struct Mesh { int offset, vbo_offset, count; - int parent, mesh_binding, mvp_binding, mat_binding, light_binding; + int + parent, + mesh_binding, + model_binding, + model_binding_depth, + vp_binding, + vp_binding_depth, + mat_binding, + light_binding; int env_cube_binding; - int mvp_binding_depth; bool world_dirty; m4f world, local; AABB bound; @@ -85,8 +92,14 @@ struct Material_Loader : public Asset_Loader { void unload(Asset* a) override; }; +struct Model_Resources { + Texture_Id env_cubemap; + Sampler_Id sampler; + Buffer_Id vp; +}; + struct Model_Instance { - Buffer_Id mvp; + Buffer_Id mcb; Buffer_Id mat; m4f transform; Model* m; @@ -105,8 +118,7 @@ struct Model_Instance { Arena* a, Render_Pass& pass, const Lighting* lighting, - Texture_Id env_cubemap, - Sampler_Id sampler + const Model_Resources& res ); }; @@ -126,14 +138,6 @@ struct Model_Scene { const Lighting& lighting, Device* dev ); - void render( - Device* dev, - Arena* a, - Render_Pass& pass, - const Lighting* lighting, - Texture_Id env_cubemap, - Sampler_Id sampler - ); }; #endif diff --git a/pipeline.cpp b/pipeline.cpp index b187807..0636a1c 100644 --- a/pipeline.cpp +++ b/pipeline.cpp @@ -156,6 +156,15 @@ Pipeline_Builder& Pipeline_Builder::begin(const Render_Pass* p) { return *this; } +Pipeline_Builder& Pipeline_Builder::begin( + const Pipeline_Builder& original +) { + Arena* a = arena; + *this = original; + arena = a; + return *this; +} + Pipeline_Builder& Pipeline_Builder::viewport( int x, int y, diff --git a/renderer.cpp b/renderer.cpp new file mode 100644 index 0000000..2d28ceb --- /dev/null +++ b/renderer.cpp @@ -0,0 +1,169 @@ +#include "model.hpp" +#include "renderer.hpp" + +extern "C" { +#include "memory.h" +} + +struct VP_Cbuffer { + m4f view_projection; +}; + +void init_drawlist( + Drawlist* l, + Device* d, + Arena* a, + int cap +) { + l->count = 0; + l->cap = cap; + l->camera = 0; + l->vp.init( + d, + "Drawlist cbuffer", + sizeof(VP_Cbuffer), + Buffer_Flags::constant_buffer + ); + l->models = (Model_Instance**)arena_alloc( + a, + cap * sizeof *l->models + ); +} + +void Renderer::init(Arena* arena, Device* d) { + int i; + auto id = [&](int did, int cap) { + init_drawlist(&drawlists[did], d, arena, cap); + }; + id(FORWARD, 512); + for (i = SHADOW_MAP_START; i < SHADOW_MAP_END; i++) + id(i, 512); + camera_count = 1; + cameras.init(); +} + +void Renderer::destroy(Device* d) { + int i; + for (i = 0; i < drawlist_count; i++) + drawlists[i].vp.destroy(d); +} + +void Renderer::set_camera(Camera_Id cam, int drawlist) { + drawlists[drawlist].camera = cam; +} + +void Drawlist::render( + const Renderer& r, + Device* dev, + Arena* a, + const Lighting* l, + Render_Pass& pass +) { + int i, c = count; + const Camera& cam = r.get_camera(camera); + Model_Resources res; + VP_Cbuffer* vpc = (VP_Cbuffer*)vp.map(dev); + vpc->view_projection = cam.get_proj() * cam.get_view(); + vp.unmap(dev); + vp.update(dev->get_ctx()); + res.sampler = r.clamped_linear; + res.env_cubemap = r.env_cubemap; + res.vp = vp.gpuonly; + for (i = 0; i < c; i++) { + models[i]->render(dev, a, pass, l, res); + } +} + +void Renderer::render( + Device* dev, + Arena* a, + Texture_Id hdr_target, + const Lighting* l +) { + int i, j; + Pipeline_Builder pb(a, dev); + Context& ctx = dev->get_ctx(); + + Render_Pass& depth_prepass = pb + .begin_rp() + .rp_depth_target(dev->get_depth_target(), 1.0f) + .build_rp(); + Render_Pass& forward_pass = pb + .begin_rp() + .rp_target(hdr_target, Clear_Mode::restore) + .rp_depth_target(dev->get_depth_target(), Clear_Mode::restore) + .build_rp(); + Render_Pass* shadow_passes[Lighting::max_shadows]; + for (i = 0; i < Lighting::max_shadows; i++) { + shadow_passes[i] = &pb + .begin_rp() + .rp_depth_target(l->shadow_slices[i], 1.0f) + .build_rp(); + } + + ctx.debug_push("depth prepass"); + drawlists[FORWARD].render(*this, dev, a, l, depth_prepass); + ctx.debug_pop(); + + ctx.debug_push("shadow maps"); + for ( + i = SHADOW_MAP_START, j = 0; + i < SHADOW_MAP_END && j < l->caster_count; + i++, j++ + ) { + ctx.debug_push("shadow map"); + drawlists[i].render(*this, dev, a, l, *shadow_passes[j]); + ctx.debug_pop(); + } + ctx.debug_pop(); + + ctx.debug_push("forward"); + drawlists[FORWARD].render(*this, dev, a, l, forward_pass); + ctx.debug_pop(); +} + +void Renderer::add_model(int drawlist, Model_Instance* m) { + Drawlist& d = drawlists[drawlist]; + assert(d.count < d.cap); + if (d.count >= d.cap) { + print_war("Drawlist is full.\n"); + return; + } + d.models[d.count++] = m; +} + +void Renderer::rem_model(int drawlist, Model_Instance* m) { + int i; + Drawlist& d = drawlists[drawlist]; + for (i = d.count - 1; i >= 0; i--) + if (d.models[i] == m) + d.models[i] = d.models[--d.count]; + assert(0); +} + +void Renderer::default_model(Model_Instance* m) { + int i; + for (i = 0; i < drawlist_count; i++) + add_model(i, m); +} + +Camera_Id Renderer::create_camera() { + Camera_Id id(camera_count++); + Camera cam; + cameras.set(id, cam); + return id; +} + +Camera& Renderer::get_camera(Camera_Id id) { + assert(id.index); + return cameras[id]; +} + +const Camera& Renderer::get_camera(Camera_Id id) const { + assert(id.index); + return cameras[id]; +} + +void Renderer::destroy_camera(Camera_Id cam) { + cameras.remove(cam); +} diff --git a/renderer.hpp b/renderer.hpp new file mode 100644 index 0000000..29a9dd0 --- /dev/null +++ b/renderer.hpp @@ -0,0 +1,74 @@ +#ifndef renderer_hpp +#define renderer_hpp + +#include "camera.hpp" +#include "hashmap.hpp" +#include "lighting.hpp" +#include "video.hpp" + +enum { + FORWARD, + SHADOW_MAP_START, + SHADOW_MAP_END = SHADOW_MAP_START + Lighting::max_shadows, + drawlist_count = SHADOW_MAP_END }; + +struct Camera_Id : public Primitive_Id<uint32_t> { + using Primitive_Id<uint32_t>::Primitive_Id; +}; + +template<> +struct Hash_Function<Camera_Id> { + size_t operator()(Camera_Id id) const { + return id.index; + } +}; + +struct Model_Instance; +struct Renderer; + +struct Drawlist { + Model_Instance** models; + int count; + int cap; + Camera_Id camera; + Staged_Buffer vp; + + void render( + const Renderer& r, + Device* dev, + Arena* a, + const Lighting* l, + Render_Pass& pass + ); +}; + +struct Renderer { + static constexpr int max_cameras = 16; + Hash_Map<Camera_Id, Camera, max_cameras> cameras; + Drawlist drawlists[drawlist_count]; + int camera_count; + + Sampler_Id clamped_linear; + Texture_Id env_cubemap; + + void init(Arena* arena, Device* d); + void destroy(Device* d); + void set_camera(Camera_Id cam, int drawlist); + void render( + Device* dev, + Arena* a, + Texture_Id hdr_target, + const Lighting* l + ); + + void add_model(int drawlist, Model_Instance* m); + void rem_model(int drawlist, Model_Instance* m); + void default_model(Model_Instance* m); + + Camera_Id create_camera(); + Camera& get_camera(Camera_Id cam); + const Camera& get_camera(Camera_Id cam) const; + void destroy_camera(Camera_Id cam); +}; + +#endif @@ -48,6 +48,7 @@ struct UI { enum { RECT, TEXT, + LINE, CLIP }; int type, size; @@ -1,4 +1,5 @@ #include "app.hpp" +#include "hashmap.hpp" #include "video.hpp" #define device_heap_size (1024 * 1024 * 8) @@ -61,147 +62,6 @@ void app_destroy_vk_surface( struct Device_Vk; -template <typename T> -struct Hash_Function {}; - -template <typename Key, typename Value, int size> -struct Hash_Map { - enum { - flags_tombstone = 1 << 0, - flags_null = 1 << 1 - }; - - Key keys[size]; - Value values[size]; - uint8_t flags[size]; - - void init() { - int i; - for (i = 0; i < size; i++) flags[i] = flags_null; - } - - int find(const Key& to_find) { - int tombstone = -1, i; - int bucket = (int)(Hash_Function<Key>{}(to_find) % (size_t)size); - for (i = 0; i < size; i++) { - Key& k = keys[bucket]; - uint8_t flag = flags[bucket]; - if (flag & flags_null) { - if (flag & flags_tombstone) { - if (tombstone < 0) tombstone = bucket; - } else return tombstone >= 0? tombstone: bucket; - } else if (k == to_find) return bucket; - bucket = (bucket + 1) % size; - } - if (tombstone >= 0) return tombstone; - return -1; - } - - Value& set(const Key& k, const Value& v) { - int bucket = find(k); - assert(bucket >= 0); /* full */ - flags[bucket] = 0; - keys[bucket] = k; - values[bucket] = v; - return values[bucket]; - } - - Value* get(const Key& k) { - int bucket = find(k); - if (bucket < 0 || flags[bucket] & flags_null) return 0; - return &values[bucket]; - } - - Value& operator[](const Key& k) { - int bucket = find(k); - assert(bucket >= 0); - return values[bucket]; - } - - Key* kaddr(const Key& k) { - int bucket = find(k); - if (bucket < 0 || flags[bucket] & flags_null) return 0; - return &keys[bucket]; - } - - void remove(const Key& k) { - int bucket = find(k); - assert(bucket >= 0); - flags[bucket] = flags_null | flags_tombstone; - } - - int has(const Key& k) { - int bucket = find(k); - return bucket >= 0 && ~flags[bucket] & flags_null; - } - - template <typename Table> - struct iterator { - Table* table; - int bucket; - - void init_begin(Table* t) { - bucket = 0; - table = t; - while ( - bucket < size && - table->flags[bucket] & flags_null - ) bucket++; - } - void init_end(Table* t) { - bucket = size; - table = t; - } - bool equals(const iterator<Table>& other) { - return bucket == other.bucket && table == other.table; - } - bool operator==(const iterator<Table>& other) { - return equals(other); - } - bool operator!=(const iterator<Table>& other) { - return !equals(other); - } - iterator<Table> operator++() { - bucket++; - while ( - bucket < size && - table->flags[bucket] & flags_null - ) bucket++; - return *this; - } - std::pair<Key&, Value&> operator*() { - return { table->keys[bucket], table->values[bucket] }; - } - std::pair<const Key&, const Value&> operator*() const { - return { table->keys[bucket], table->values[bucket] }; - } - }; - - iterator<Hash_Map<Key, Value, size>> begin() { - iterator<Hash_Map<Key, Value, size>> r; - r.init_begin(this); - return r; - } - - iterator<Hash_Map<Key, Value, size>> end() { - iterator<Hash_Map<Key, Value, size>> r; - r.init_end(this); - return r; - } - - iterator<const Hash_Map<Key, Value, size>> begin() const { - iterator<const Hash_Map<Key, Value, size>> r; - r.init_begin(this); - return r; - } - - iterator<const Hash_Map<Key, Value, size>> end() const { - iterator<const Hash_Map<Key, Value, size>> r; - r.init_end(this); - return r; - } -}; - struct Vram_Allocator { static constexpr int size_alignment = (1024 * 1024 * 32); struct Page; @@ -309,6 +309,7 @@ struct Pipeline_Builder { void validate_rp(); PB& begin(const Render_Pass* p = 0); + PB& begin(const Pipeline_Builder& original); PB& viewport(int x, int y, int w, int h); PB& scissor(int x, int y, int w, int h); PB& depth(bool test, bool write, Depth_Mode mode); |