]> git.tdb.fi Git - libs/gl.git/blob - source/render/occludedscene.cpp
Use default member initializers for simple types
[libs/gl.git] / source / render / occludedscene.cpp
1 #include <algorithm>
2 #include "camera.h"
3 #include "mesh.h"
4 #include "occludedscene.h"
5 #include "program.h"
6 #include "renderer.h"
7 #include "resources.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 OccludedScene::OccludedScene():
15         bounding_mesh(Resources::get_global().get<Mesh>("_occluder.mesh")),
16         bounding_shader(Resources::get_global().get<Program>("_occluder.glsl.shader")),
17         queries(OCCLUSION_QUERY, 0)
18 {
19         no_color_write.write_mask = WRITE_NONE;
20 }
21
22 void OccludedScene::add(Renderable &r)
23 {
24         renderables.insert(&r);
25         cache_dirty = true;
26 }
27
28 void OccludedScene::remove(Renderable &r)
29 {
30         renderables.erase(&r);
31         cache_dirty = true;
32 }
33
34 void OccludedScene::populate_cache() const
35 {
36         if(!cache_dirty)
37                 return;
38
39         if(queries.get_size()<renderables.size())
40                 queries.resize(renderables.size());
41         if(occluded_cache.size()<renderables.size())
42                 occluded_cache.resize(renderables.size());
43
44         auto j = occluded_cache.begin();
45         for(Renderable *r: renderables)
46                 j++->renderable = r;
47         for(; j!=occluded_cache.end(); ++j)
48         {
49                 j->renderable = 0;
50                 j->in_frustum = false;
51         }
52
53         cache_dirty = false;
54 }
55
56 void OccludedScene::setup_frame(Renderer &renderer)
57 {
58         populate_cache();
59         for(const OccludedRenderable &o: occluded_cache)
60                 o.renderable->setup_frame(renderer);
61 }
62
63 void OccludedScene::finish_frame()
64 {
65         for(const OccludedRenderable &o: occluded_cache)
66                 o.renderable->finish_frame();
67 }
68
69 void OccludedScene::render(Renderer &renderer, Tag tag) const
70 {
71         if(renderables.empty())
72                 return;
73
74         populate_cache();
75
76         const Camera *camera = renderer.get_camera();
77         if(!camera)
78         {
79                 for(const OccludedRenderable &o: occluded_cache)
80                         renderer.render(*o.renderable, tag);
81                 return;
82         }
83
84         const Vector3 &camera_pos = camera->get_position();
85         const Vector3 &look_dir = camera->get_look_direction();
86         float near_clip = camera->get_near_clip();
87         float frustum_h = tan(camera->get_field_of_view()/2.0f)*2.0f;
88
89         // Perform frustum culling and render any major occluders
90         bool use_frustum = setup_frustum(renderer);
91         for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
92         {
93                 i->in_frustum = (!use_frustum || !frustum_cull(*i->renderable));
94                 if(!i->in_frustum)
95                         continue;
96
97                 const Matrix *matrix = i->renderable->get_matrix();
98                 i->bounding_sphere = i->renderable->get_bounding_sphere();
99                 if(matrix && i->bounding_sphere)
100                 {
101                         float depth = dot(*matrix*i->bounding_sphere->get_center()-camera_pos, look_dir);
102                         float size = i->bounding_sphere->get_radius()*2/max(depth, near_clip);
103                         i->occluder = (size>frustum_h*occluder_min_size);
104                 }
105                 else
106                         // If the size can't be calculated, treat it as occluder
107                         i->occluder = true;
108
109                 if(i->occluder)
110                         renderer.render(*i->renderable, tag);
111         }
112
113         // Move all objects within the frustum to the beginning of the array
114         for(auto i=occluded_cache.begin(), j=i+renderables.size()-1; i!=j; )
115         {
116                 if(i->in_frustum)
117                         ++i;
118                 else if(j->in_frustum)
119                         swap(*i, *j);
120                 else
121                         --j;
122         }
123
124         {
125                 Renderer::Push push(renderer);
126                 renderer.set_shader_program(&bounding_shader);
127
128                 renderer.set_blend(&no_color_write);
129                 // XXX Preserve existing depth test predicate
130                 renderer.set_depth_test(&no_depth_write);
131
132                 // Fire off the occlusion queries
133                 for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
134                         if(!i->occluder)
135                         {
136                                 QueryPool::Activate activate_query(renderer, queries, i-occluded_cache.begin());
137                                 Renderer::Push push2(renderer);
138                                 renderer.transform(Matrix(*i->renderable->get_matrix())
139                                         .translate(i->bounding_sphere->get_center())
140                                         .scale(i->bounding_sphere->get_radius()));
141                                 bounding_mesh.draw(renderer);
142                         }
143         }
144
145         // Render anything that has a chance of being visible
146         for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
147                 if(!i->occluder && queries.get_result(i-occluded_cache.begin()))
148                         renderer.render(*i->renderable, tag);
149 }
150
151 } // namespace GL
152 } // namespace Msp