}
}
- if(mask&PipelineState::VERTEX_SETUP)
+ if(mask&PipelineState::UNIFORMS)
{
- const VertexSetup *vertex_setup = self->vertex_setup;
- glBindVertexArray(vertex_setup ? vertex_setup->id : 0);
- if(vertex_setup)
- {
- static Require _req(MSP_primitive_restart);
-
- vertex_setup->refresh();
- unsigned ri = (vertex_setup->get_index_type()==UNSIGNED_INT ? 0xFFFFFFFF : 0xFFFF);
- if(ri!=restart_index)
+ for(const PipelineState::BoundUniformBlock &u: self->uniform_blocks)
+ if(u.changed || mask==~0U)
{
- if(!restart_index)
- glEnable(GL_PRIMITIVE_RESTART);
- glPrimitiveRestartIndex(ri);
- restart_index = ri;
- }
- }
- }
-
- if(mask&PipelineState::FACE_CULL)
- {
- glFrontFace(self->front_face==CLOCKWISE ? GL_CW : GL_CCW);
+ if(u.block)
+ {
+ if(u.binding>=0)
+ {
+ glBindBufferRange(GL_UNIFORM_BUFFER, u.binding, u.block->get_buffer()->id, u.block->get_offset(), u.block->get_data_size());
+ bound_uniform_blocks[u.binding] = 1;
+ }
+ else if(self->shprog)
+ {
+ const char *data = static_cast<const char *>(u.block->get_data_pointer());
+ for(const Program::UniformCall &call: self->shprog->uniform_calls)
+ call.func(call.location, call.size, data+call.location*16);
+ }
+ }
- if(self->face_cull!=NO_CULL && self->front_face!=NON_MANIFOLD)
- {
- glEnable(GL_CULL_FACE);
- glCullFace(self->face_cull==CULL_FRONT ? GL_FRONT : GL_BACK);
- }
- else
- glDisable(GL_CULL_FACE);
+ u.changed = false;
+ }
}
if(mask&PipelineState::TEXTURES)
}
}
- if(mask&PipelineState::UNIFORMS)
+ if(mask&PipelineState::VERTEX_SETUP)
{
- for(const PipelineState::BoundUniformBlock &u: self->uniform_blocks)
- if(u.changed || mask==~0U)
- {
- if(u.block)
- {
- if(u.binding>=0)
- {
- glBindBufferRange(GL_UNIFORM_BUFFER, u.binding, u.block->get_buffer()->id, u.block->get_offset(), u.block->get_data_size());
- bound_uniform_blocks[u.binding] = 1;
- }
- else if(self->shprog)
- {
- const char *data = static_cast<const char *>(u.block->get_data_pointer());
- for(const Program::UniformCall &call: self->shprog->uniform_calls)
- call.func(call.location, call.size, data+call.location*16);
- }
- }
+ const VertexSetup *vertex_setup = self->vertex_setup;
+ glBindVertexArray(vertex_setup ? vertex_setup->id : 0);
+ if(vertex_setup)
+ {
+ static Require _req(MSP_primitive_restart);
- u.changed = false;
+ vertex_setup->refresh();
+ unsigned ri = (vertex_setup->get_index_type()==UNSIGNED_INT ? 0xFFFFFFFF : 0xFFFF);
+ if(ri!=restart_index)
+ {
+ if(!restart_index)
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex(ri);
+ restart_index = ri;
}
+ }
+ }
+
+ if(mask&PipelineState::FACE_CULL)
+ {
+ glFrontFace(self->front_face==CLOCKWISE ? GL_CW : GL_CCW);
+
+ if(self->face_cull!=NO_CULL && self->front_face!=NON_MANIFOLD)
+ {
+ glEnable(GL_CULL_FACE);
+ glCullFace(self->face_cull==CULL_FRONT ? GL_FRONT : GL_BACK);
+ }
+ else
+ glDisable(GL_CULL_FACE);
}
if(mask&PipelineState::DEPTH_TEST)
set(shprog, p, SHPROG);
}
-void PipelineState::set_vertex_setup(const VertexSetup *s)
-{
- set(vertex_setup, s, VERTEX_SETUP);
-}
-
-void PipelineState::set_front_face(FaceWinding w)
-{
- set(front_face, w, FACE_CULL);
-}
-
-void PipelineState::set_face_cull(CullMode c)
+void PipelineState::set_uniform_block(int binding, const UniformBlock *block)
{
- set(face_cull, c, FACE_CULL);
+ auto i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
+ if(i==uniform_blocks.end() || i->binding!=binding)
+ i = uniform_blocks.insert(i, BoundUniformBlock(binding));
+ if(block!=i->block || binding<0)
+ {
+ i->block = block;
+ i->changed = true;
+ changes |= UNIFORMS;
+ }
}
void PipelineState::set_texture(unsigned binding, const Texture *tex, const Sampler *samp)
}
}
-void PipelineState::set_uniform_block(int binding, const UniformBlock *block)
+void PipelineState::set_vertex_setup(const VertexSetup *s)
{
- auto i = lower_bound_member(uniform_blocks, binding, &BoundUniformBlock::binding);
- if(i==uniform_blocks.end() || i->binding!=binding)
- i = uniform_blocks.insert(i, BoundUniformBlock(binding));
- if(block!=i->block || binding<0)
- {
- i->block = block;
- i->changed = true;
- changes |= UNIFORMS;
- }
+ set(vertex_setup, s, VERTEX_SETUP);
+}
+
+void PipelineState::set_front_face(FaceWinding w)
+{
+ set(front_face, w, FACE_CULL);
+}
+
+void PipelineState::set_face_cull(CullMode c)
+{
+ set(face_cull, c, FACE_CULL);
}
void PipelineState::set_depth_test(const DepthTest *dt)
enum ChangeMask
{
- SHPROG = 1,
- VERTEX_SETUP = 2,
- FACE_CULL = 4,
- TEXTURES = 16,
- UNIFORMS = 32,
- DEPTH_TEST = 64,
- STENCIL_TEST = 128,
- BLEND = 256,
- FRAMEBUFFER = 512,
- VIEWPORT = 1024,
- SCISSOR = 2048
+ FRAMEBUFFER = 1,
+ VIEWPORT = 2,
+ SCISSOR = 4,
+ SHPROG = 8,
+ UNIFORMS = 16,
+ TEXTURES = 32,
+ VERTEX_SETUP = 64,
+ FACE_CULL = 128,
+ DEPTH_TEST = 256,
+ STENCIL_TEST = 512,
+ BLEND = 1024
};
const Framebuffer *framebuffer = 0;
const Rect *viewport = 0;
const Rect *scissor = 0;
const Program *shprog = 0;
+ std::vector<BoundUniformBlock> uniform_blocks;
+ std::vector<BoundTexture> textures;
const VertexSetup *vertex_setup = 0;
FaceWinding front_face = COUNTERCLOCKWISE;
CullMode face_cull = NO_CULL;
- std::vector<BoundTexture> textures;
- std::vector<BoundUniformBlock> uniform_blocks;
const DepthTest *depth_test = 0;
const StencilTest *stencil_test = 0;
const Blend *blend = 0;
void set_viewport(const Rect *);
void set_scissor(const Rect *);
void set_shader_program(const Program *);
+ void set_uniform_block(int, const UniformBlock *);
+ void set_texture(unsigned, const Texture *, const Sampler *);
void set_vertex_setup(const VertexSetup *);
void set_front_face(FaceWinding);
void set_face_cull(CullMode);
- void set_texture(unsigned, const Texture *, const Sampler *);
- void set_uniform_block(int, const UniformBlock *);
void set_depth_test(const DepthTest *);
void set_stencil_test(const StencilTest *);
void set_blend(const Blend *);
end();
}
+void Renderer::end()
+{
+ if(state_stack.size()>1)
+ throw invalid_operation("Renderer::end");
+
+ *state = State();
+ shdata_stack.clear();
+ add_shader_data(standard_shdata);
+
+ commands.use_pipeline(0);
+}
+
+void Renderer::push_state()
+{
+ state_stack.push_back(state_stack.back());
+ state = &state_stack.back();
+}
+
+void Renderer::pop_state()
+{
+ if(state_stack.size()==1)
+ throw stack_underflow("Renderer::pop_state");
+
+ state_stack.pop_back();
+ state = &state_stack.back();
+ changed |= MATRIX;
+}
+
void Renderer::set_camera(const Camera &c)
{
state->camera = &c;
state->scissor = s;
}
+void Renderer::set_shader_program(const Program *p, const ProgramData *d)
+{
+ state->shprog = p;
+ if(p && d)
+ add_shader_data(*d);
+}
+
+void Renderer::add_shader_data(const ProgramData &d)
+{
+ if(state->shdata_count<shdata_stack.size())
+ {
+ const BoundProgramData &top = shdata_stack.back();
+ if(top.shdata==&d && top.generation==d.get_generation())
+ {
+ ++state->shdata_count;
+ return;
+ }
+ }
+
+ flush_shader_data();
+ shdata_stack.push_back(&d);
+ state->shdata_count = shdata_stack.size();
+ changed |= SHADER_DATA;
+}
+
void Renderer::set_texture(Tag tag, const Texture *tex, const Sampler *samp)
{
if(tex)
state->texture_count = texture_stack.size();
}
+void Renderer::flush_shader_data()
+{
+ if(shdata_stack.size()>state->shdata_count)
+ shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
+}
+
void Renderer::flush_textures()
{
for(unsigned i=0; i<state->texture_count; ++i)
texture_stack.erase(texture_stack.begin()+state->texture_count, texture_stack.end());
}
-void Renderer::set_shader_program(const Program *p, const ProgramData *d)
-{
- state->shprog = p;
- if(p && d)
- add_shader_data(*d);
-}
-
-void Renderer::add_shader_data(const ProgramData &d)
-{
- if(state->shdata_count<shdata_stack.size())
- {
- const BoundProgramData &top = shdata_stack.back();
- if(top.shdata==&d && top.generation==d.get_generation())
- {
- ++state->shdata_count;
- return;
- }
- }
-
- flush_shader_data();
- shdata_stack.push_back(&d);
- state->shdata_count = shdata_stack.size();
- changed |= SHADER_DATA;
-}
-
-void Renderer::flush_shader_data()
-{
- if(shdata_stack.size()>state->shdata_count)
- shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
-}
-
void Renderer::set_vertex_setup(const VertexSetup *vs)
{
state->vertex_setup = vs;
state->object_lod_bias = b;
}
-void Renderer::push_state()
-{
- state_stack.push_back(state_stack.back());
- state = &state_stack.back();
-}
-
-void Renderer::pop_state()
-{
- if(state_stack.size()==1)
- throw stack_underflow("Renderer::pop_state");
-
- state_stack.pop_back();
- state = &state_stack.back();
- changed |= MATRIX;
-}
-
-void Renderer::end()
-{
- if(state_stack.size()>1)
- throw invalid_operation("Renderer::end");
-
- *state = State();
- shdata_stack.clear();
- add_shader_data(standard_shdata);
-
- commands.use_pipeline(0);
-}
-
void Renderer::clear(const ClearValue *values)
{
pipeline_state.set_framebuffer(state->framebuffer);
if(!state->shprog)
throw invalid_operation("Renderer::apply_state");
+ pipeline_state.set_framebuffer(state->framebuffer);
+ pipeline_state.set_viewport(state->viewport);
+ pipeline_state.set_scissor(state->scissor);
+
+ bool shprog_changed = (state->shprog!=pipeline_state.get_shader_program());
+ pipeline_state.set_shader_program(state->shprog);
+
if(changed&MATRIX)
{
standard_shdata.uniform("world_obj_matrix", state->model_matrix);
changed &= ~MATRIX;
}
- pipeline_state.set_framebuffer(state->framebuffer);
- pipeline_state.set_viewport(state->viewport);
- pipeline_state.set_scissor(state->scissor);
+ bool shdata_changed = changed&SHADER_DATA;
+ for(auto i=shdata_stack.begin(); (!shdata_changed && i!=shdata_stack.end()); ++i)
+ shdata_changed = (i->shdata->get_generation()!=i->generation);
+ bool extra_shdata = (shdata_stack.size()>state->shdata_count);
- bool shprog_changed = (state->shprog!=pipeline_state.get_shader_program());
- pipeline_state.set_shader_program(state->shprog);
+ if(shdata_changed || shprog_changed || extra_shdata)
+ {
+ if(extra_shdata)
+ shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
+ for(const BoundProgramData &d: shdata_stack)
+ {
+ d.shdata->apply(*state->shprog, pipeline_state);
+ d.generation = d.shdata->get_generation();
+ }
+ changed &= ~SHADER_DATA;
+ }
if(state->vertex_setup)
{
pipeline_state.set_texture(t.binding, t.texture, t.sampler);
}
- bool shdata_changed = changed&SHADER_DATA;
- for(auto i=shdata_stack.begin(); (!shdata_changed && i!=shdata_stack.end()); ++i)
- shdata_changed = (i->shdata->get_generation()!=i->generation);
- bool extra_shdata = (shdata_stack.size()>state->shdata_count);
-
- if(shdata_changed || shprog_changed || extra_shdata)
- {
- if(extra_shdata)
- shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
- for(const BoundProgramData &d: shdata_stack)
- {
- d.shdata->apply(*state->shprog, pipeline_state);
- d.generation = d.shdata->get_generation();
- }
- changed &= ~SHADER_DATA;
- }
-
pipeline_state.set_depth_test(state->depth_test);
pipeline_state.set_stencil_test(state->stencil_test);
pipeline_state.set_blend(state->blend);
unsigned char changed = 0;
std::vector<State> state_stack;
State *state;
- std::vector<BoundTexture> texture_stack;
ProgramData standard_shdata;
std::vector<BoundProgramData> shdata_stack;
+ std::vector<BoundTexture> texture_stack;
PipelineState pipeline_state;
Commands commands;
Renderer();
~Renderer();
+
+ /** Unbinds all objects and resets related state. There must be no unpopped
+ state in the stack. The Renderer remains valid and may be reused for
+ further rendering. */
+ void end();
+
+ /** Saves the current state so it can be restored later. */
+ void push_state();
+
+ /** Restores a previously saved state. Must be matched with an earlier
+ push_state call. */
+ void pop_state();
+
/** Sets the camera to render from. The model matrix is reset to identity. */
void set_camera(const Camera &);
const Framebuffer *get_framebuffer() const { return state->framebuffer; }
- void set_texture(Tag, const Texture *, const Sampler * = 0);
-private:
- void flush_textures();
-
-public:
/** Sets the shader program to use. As a convenience, uniform values may be
specified at the same time. */
void set_shader_program(const Program *prog, const ProgramData *data = 0);
last will be used. */
void add_shader_data(const ProgramData &data);
+ void set_texture(Tag, const Texture *, const Sampler * = 0);
+
private:
void flush_shader_data();
+ void flush_textures();
public:
void set_vertex_setup(const VertexSetup *);
void set_object_lod_bias(unsigned);
unsigned get_object_lod_bias() const { return state->object_lod_bias; }
- /** Saves the current state so it can be restored later. */
- void push_state();
-
- /** Restores a previously saved state. Must be matched with an earlier
- push_state call. */
- void pop_state();
-
- /** Unbinds all objects and resets related state. There must be no unpopped
- state in the stack. The Renderer remains valid and may be reused for
- further rendering. */
- void end();
-
void clear(const ClearValue *);
/** Draws a batch of primitives. A shader must be active. */