MatrixStack::MatrixStack(GLenum m):
mode(m)
{
+ matrices.reserve(mode==GL_MODELVIEW ? 32 : 4);
matrices.push_back(Matrix());
}
MatrixStack::MatrixStack():
mode(0)
{
+ matrices.reserve(32);
matrices.push_back(Matrix());
}
#ifndef MSP_GL_MATRIX_H_
#define MSP_GL_MATRIX_H_
-#include <list>
+#include <vector>
#include "gl.h"
#include "vector.h"
private:
GLenum mode;
- std::list<Matrix> matrices;
+ std::vector<Matrix> matrices;
static GLenum current_mode;
mtx_changed(false),
camera(c),
state_stack(1),
- state(&state_stack.back()),
vertex_array(0),
vertex_array_changed(false),
element_buffer(0)
{
+ state_stack.reserve(16);
+ shdata_stack.reserve(32);
+ state = &state_stack.back();
+
MatrixStack::modelview().push();
if(camera)
{
state->shprog = p;
if(p && d)
add_shader_data(*d);
+
+ /* Even if we have no new shdata, the existing ones need to be re-applied
+ to the new program */
shdata_changed = true;
}
void Renderer::add_shader_data(const ProgramData &d)
{
- state->shdata.push_back(&d);
+ shdata_stack.push_back(&d);
+ state->shdata_count = shdata_stack.size();
shdata_changed = true;
}
state_stack.pop_back();
state = &state_stack.back();
+ if(shdata_stack.size()>state->shdata_count)
+ shdata_stack.erase(shdata_stack.begin()+state->shdata_count, shdata_stack.end());
mtx_stack.pop();
mtx_changed = true;
shdata_changed = true;
state->shprog->bind();
if(shdata_changed)
{
- for(vector<const ProgramData *>::const_iterator i=state->shdata.begin(); i!=state->shdata.end(); ++i)
+ for(vector<const ProgramData *>::const_iterator i=shdata_stack.begin(); i!=shdata_stack.end(); ++i)
(*i)->apply();
shdata_changed = false;
}
The Renderer works by deferring GL state changes until something is actually
being drawn. This avoids many unnecessary GL calls if consecutive renderables
use the same resources.
+
+A state stack is provided to help with state scoping. Typically a Renderable
+will push the current state on entry, set whatever state it requires, render
+itself, and pop the state when it's done. An RAII helper class is provided for
+the push/pop operation.
*/
class Renderer
{
const Texturing *texturing;
const Material *material;
const Program *shprog;
- std::vector<const ProgramData *> shdata;
+ unsigned shdata_count;
const WindingTest *winding_test;
State();
MtxStack mtx_stack;
bool mtx_changed;
const Camera *camera;
- std::list<State> state_stack;
+ std::vector<State> state_stack;
State *state;
+ std::vector<const ProgramData *> shdata_stack;
+ bool shdata_changed;
const VertexArray *vertex_array;
bool vertex_array_changed;
const Buffer *element_buffer;
- bool shdata_changed;
public:
Renderer(const Camera *);
void set_element_buffer(const Buffer *);
void set_winding_test(const WindingTest *);
+ /** 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();
/** Prepares for temporarily bypassing the Renderer by synchronizing the