-#include <algorithm>
-#include <msp/gl/extensions/arb_occlusion_query.h>
-#include <msp/gl/extensions/arb_occlusion_query2.h>
+#include <msp/core/algorithm.h>
#include "camera.h"
+#include "mesh.h"
#include "occludedscene.h"
+#include "program.h"
#include "renderer.h"
#include "resources.h"
-#include "sphere.h"
using namespace std;
namespace Msp {
namespace GL {
-OccludedScene::OccludedScene(Resources &resources):
- bounding_mesh(resources.get<Mesh>("_occluder.mesh")),
- bounding_shader(resources.get<Program>("_occluder.glsl")),
- occluder_min_size(0.25f),
- cache_dirty(false)
+OccludedScene::OccludedScene():
+ bounding_mesh(Resources::get_global().get<Mesh>("_occluder.mesh")),
+ bounding_shader(Resources::get_global().get<Program>("occluder.glsl.shader")),
+ queries(OCCLUSION_QUERY, 0)
{
- static Require req(ARB_occlusion_query);
- static Require req2(ARB_occlusion_query2);
-}
-
-OccludedScene::~OccludedScene()
-{
- vector<unsigned> queries;
- queries.reserve(occluded_cache.size());
- for(OccludedArray::iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
- queries.push_back(i->query);
- glDeleteQueries(queries.size(), &queries[0]);
+ no_color_write.write_mask = WRITE_NONE;
}
void OccludedScene::add(Renderable &r)
{
- renderables.insert(&r);
- cache_dirty = true;
+ auto i = lower_bound(content, &r);
+ if(i==content.end() || *i!=&r)
+ {
+ content.insert(i, &r);
+ cache_dirty = true;
+ }
}
void OccludedScene::remove(Renderable &r)
{
- renderables.erase(&r);
- cache_dirty = true;
+ auto i = lower_bound(content, &r);
+ if(i!=content.end() && *i==&r)
+ {
+ content.erase(i);
+ cache_dirty = true;
+ }
}
void OccludedScene::populate_cache() const
if(!cache_dirty)
return;
- if(occluded_cache.size()<renderables.size())
- {
- unsigned old_size = occluded_cache.size();
- occluded_cache.resize(renderables.size());
- vector<unsigned> new_queries(occluded_cache.size()-old_size);
- glGenQueries(new_queries.size(), &new_queries[0]);
- for(unsigned i=0; i<new_queries.size(); ++i)
- occluded_cache[old_size+i].query = new_queries[i];
- }
+ if(queries.get_size()<content.size())
+ queries.resize(content.size());
+ if(occluded_cache.size()<content.size())
+ occluded_cache.resize(content.size());
- OccludedArray::iterator j = occluded_cache.begin();
- for(RenderableSet::iterator i=renderables.begin(); i!=renderables.end(); ++i, ++j)
- j->renderable = *i;
+ auto j = occluded_cache.begin();
+ for(Renderable *r: content)
+ j++->renderable = r;
for(; j!=occluded_cache.end(); ++j)
{
j->renderable = 0;
void OccludedScene::setup_frame(Renderer &renderer)
{
populate_cache();
- for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
- i->renderable->setup_frame(renderer);
+ for(const OccludedRenderable &o: occluded_cache)
+ o.renderable->setup_frame(renderer);
}
void OccludedScene::finish_frame()
{
- for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
- i->renderable->finish_frame();
+ for(const OccludedRenderable &o: occluded_cache)
+ o.renderable->finish_frame();
}
-void OccludedScene::render(Renderer &renderer, const Tag &tag) const
+void OccludedScene::render(Renderer &renderer, Tag tag) const
{
- if(renderables.empty())
+ if(content.empty())
return;
populate_cache();
const Camera *camera = renderer.get_camera();
if(!camera)
{
- for(OccludedArray::const_iterator i=occluded_cache.begin(); i!=occluded_cache.end(); ++i)
- renderer.render(*i->renderable, tag);
+ for(const OccludedRenderable &o: occluded_cache)
+ o.renderable->render(renderer, tag);
return;
}
// Perform frustum culling and render any major occluders
bool use_frustum = setup_frustum(renderer);
- for(OccludedArray::iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
+ for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->renderable); ++i)
{
i->in_frustum = (!use_frustum || !frustum_cull(*i->renderable));
if(!i->in_frustum)
i->occluder = true;
if(i->occluder)
- renderer.render(*i->renderable, tag);
+ i->renderable->render(renderer, tag);
}
// Move all objects within the frustum to the beginning of the array
- for(OccludedArray::iterator i=occluded_cache.begin(), j=i+renderables.size()-1; i!=j; )
+ for(auto i=occluded_cache.begin(), j=i+content.size()-1; i!=j; )
{
if(i->in_frustum)
++i;
Renderer::Push push(renderer);
renderer.set_shader_program(&bounding_shader);
- glColorMask(false, false, false, false);
- glDepthMask(false);
+ renderer.set_blend(&no_color_write);
+ // XXX Preserve existing depth test predicate
+ renderer.set_depth_test(&no_depth_write);
// Fire off the occlusion queries
- for(OccludedArray::const_iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
+ for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
if(!i->occluder)
{
- glBeginQuery(GL_ANY_SAMPLES_PASSED, i->query);
+ QueryPool::Activate activate_query(renderer, queries, i-occluded_cache.begin());
Renderer::Push push2(renderer);
- renderer.transform(Matrix(*i->renderable->get_matrix())
+ renderer.set_matrix(Matrix(*i->renderable->get_matrix())
.translate(i->bounding_sphere->get_center())
.scale(i->bounding_sphere->get_radius()));
bounding_mesh.draw(renderer);
- glEndQuery(GL_ANY_SAMPLES_PASSED);
}
-
- glColorMask(true, true, true, true);
- glDepthMask(true);
}
// Render anything that has a chance of being visible
- for(OccludedArray::const_iterator i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
- if(!i->occluder)
- {
- unsigned any_passed = 0;
- glGetQueryObjectuiv(i->query, GL_QUERY_RESULT, &any_passed);
- if(any_passed)
- renderer.render(*i->renderable, tag);
- }
+ for(auto i=occluded_cache.begin(); (i!=occluded_cache.end() && i->in_frustum); ++i)
+ if(!i->occluder && queries.get_result(i-occluded_cache.begin()))
+ i->renderable->render(renderer, tag);
}
-
-OccludedScene::OccludedRenderable::OccludedRenderable():
- renderable(0),
- bounding_sphere(0),
- in_frustum(false),
- occluder(false),
- query(0)
-{ }
-
} // namespace GL
} // namespace Msp