#include <msp/game/entity.h>
#include <msp/game/light.h>
#include <msp/game/meshsource.h>
+#include <msp/game/shadowtarget.h>
#include <msp/game/stage.h>
#include <msp/game/transform.h>
#include <msp/gl/colorcurve.h>
stage.synthesize_initial_events(event_observer);
+ content_slot.set(&scene);
view.set_camera(&gl_camera);
}
re.light_emitter = Game::Owned<LightEmitter>(re.entity, light->get_type());
re.light_emitter->set_intensity(light->get_intensity());
re.light_emitter->set_lighting(&lighting);
+ if(light->casts_shadows())
+ shadows_changed = true;
}
}
}
{
if(dynamic_handle_cast<Game::MeshSource>(event.component))
i->mesh_renderer = nullptr;
- if(dynamic_handle_cast<Game::Light>(event.component))
+ if(auto light = dynamic_handle_cast<Game::Light>(event.component))
+ {
i->light_emitter = nullptr;
+ if(light->casts_shadows())
+ shadows_changed = true;
+ }
}
}
sequence->set_clear_enabled(true);
sequence->set_clear_colors({ GL::Color(0.0f) });
- GL::Sequence::Step &opaque = sequence->add_step(GL::Tag(), scene);
+ GL::Sequence::Step &opaque = sequence->add_step(GL::Tag(), content_slot);
opaque.set_depth_test(GL::LEQUAL);
opaque.set_lighting(&lighting);
void Renderer::tick(Time::TimeDelta)
{
+ if(shadows_changed)
+ {
+ shadows_changed = false;
+
+ vector<ShadowedLight> lights;
+
+ unsigned total_area = 0;
+ stage.iterate_objects<LightEmitter>([&lights, &total_area, this](LightEmitter &e){
+ if(Game::Handle<Game::Light> light = e.get_entity()->get_component<Game::Light>())
+ {
+ unsigned size = light->get_shadow_map_size(shadow_base_size);;
+ total_area += size*size;
+ lights.emplace_back(&e, size);
+ }
+ });
+
+ unsigned width = 1;
+ while(width*width<total_area)
+ width <<= 1;
+ unsigned height = (width*width>=total_area*2 ? width/2 : width);
+
+ if(lights.empty())
+ {
+ shadow_map = nullptr;
+ content_slot.set(&scene);
+ }
+ else
+ {
+ sort(lights);
+
+ if(!shadow_seq)
+ {
+ shadow_seq = make_unique<GL::Sequence>();
+ shadow_seq->set_clear_enabled(true);
+ GL::Sequence::Step &step = shadow_seq->add_step("shadow", scene);
+ step.set_depth_test(GL::LEQUAL);
+ }
+
+ shadow_map = make_unique<GL::ShadowMap>(width, height, scene, lighting);
+ for(const ShadowedLight &l: lights)
+ l.light->set_shadow_map(shadow_map.get(), l.shadow_size, *shadow_seq);
+
+ content_slot.set(shadow_map.get());
+ }
+ }
+
+ if(shadow_map)
+ {
+ Geometry::BoundingSphere<float, 3> shadow_bounds;
+ stage.iterate_objects<Game::ShadowTarget>([&shadow_bounds](Game::ShadowTarget &s){
+ LinAl::Vector<float, 3> pos = s.get_entity()->get_transform()->get_position();
+ shadow_bounds = shadow_bounds | Geometry::BoundingSphere<float, 3>(pos, s.get_radius());
+ });
+
+ shadow_map->set_target(shadow_bounds.get_center(), shadow_bounds.get_radius());
+ }
+
if(active_camera)
{
Game::Handle<Game::Transform> transform = active_camera->get_entity()->get_transform();
#include <msp/gl/light.h>
#include <msp/gl/lighting.h>
#include <msp/gl/sequence.h>
+#include <msp/gl/shadowmap.h>
#include <msp/gl/simplescene.h>
+#include <msp/gl/slot.h>
#include <msp/gl/view.h>
#include "mspgameview_api.h"
RenderedEntity(Game::Handle<Game::Entity>);
};
+ struct ShadowedLight
+ {
+ LightEmitter *light;
+ unsigned shadow_size;
+
+ bool operator<(const ShadowedLight &other) const { return shadow_size>other.shadow_size; }
+ };
+
GL::View &view;
Game::EventObserver event_observer;
std::vector<RenderedEntity> entities;
GL::SimpleScene scene;
GL::Lighting lighting;
+ std::unique_ptr<GL::ShadowMap> shadow_map;
+ std::unique_ptr<GL::Sequence> shadow_seq;
Game::Handle<Game::Camera> active_camera;
GL::Camera gl_camera;
std::unique_ptr<GL::Sequence> sequence;
+ GL::Slot content_slot;
+ unsigned shadow_base_size = 4096;
+ bool shadows_changed = false;
public:
Renderer(Game::Stage &, GL::View &);