#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, void (*overrider)(Pipeline_Builder&) ) { 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; res.overrider = overrider; 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, 0); 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++ ) { auto o = [](Pipeline_Builder& pb) { pb.cull(Cull_Mode::front); }; setcam(i, l->cameras[j]); ctx.debug_push("shadow map"); drawlists[i].render(*this, dev, a, l, *shadow_passes[j], o); ctx.debug_pop(); } ctx.debug_pop(); ctx.debug_push("forward"); drawlists[FORWARD].render(*this, dev, a, l, forward_pass, 0); 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); } void Renderer::setcam(int did, Camera_Id cam) { assert(cam.index); drawlists[did].camera = cam; }