summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--build.ninja3
-rw-r--r--c2.cpp104
-rw-r--r--configure.lua1
-rw-r--r--hashmap.hpp158
-rw-r--r--intermediate/surface.glsl22
-rw-r--r--intermediate/surface_depthonly.glsl18
-rw-r--r--lighting.cpp39
-rw-r--r--lighting.hpp14
-rw-r--r--model.cpp90
-rw-r--r--model.hpp30
-rw-r--r--pipeline.cpp9
-rw-r--r--renderer.cpp169
-rw-r--r--renderer.hpp74
-rw-r--r--ui.hpp1
-rw-r--r--video.cpp142
-rw-r--r--video.hpp1
17 files changed, 620 insertions, 265 deletions
diff --git a/Makefile b/Makefile
index 2a44434..0250cc1 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/c2.cpp b/c2.cpp
index 06c31c5..2832131 100644
--- a/c2.cpp
+++ b/c2.cpp
@@ -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 {
diff --git a/model.cpp b/model.cpp
index e864ff5..caa1422 100644
--- a/model.cpp
+++ b/model.cpp
@@ -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;
diff --git a/model.hpp b/model.hpp
index d1b9449..23f3825 100644
--- a/model.hpp
+++ b/model.hpp
@@ -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
diff --git a/ui.hpp b/ui.hpp
index 056e69a..2779183 100644
--- a/ui.hpp
+++ b/ui.hpp
@@ -48,6 +48,7 @@ struct UI {
enum {
RECT,
TEXT,
+ LINE,
CLIP
};
int type, size;
diff --git a/video.cpp b/video.cpp
index f1fb512..9a4cc74 100644
--- a/video.cpp
+++ b/video.cpp
@@ -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;
diff --git a/video.hpp b/video.hpp
index b8293fa..3bd756f 100644
--- a/video.hpp
+++ b/video.hpp
@@ -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);