Vectors are better than lists, since they don't need to allocate new
memory for every element. A suitably sized reserve() does away with any
initial reallocations in most cases.
ProgramData in Renderer can be stored in a semi-independent stack as
well, since it can only be removed with a pop. State is now devoid of
dynamically allocated memory, making the stack operations even faster.
MatrixStack::MatrixStack(GLenum m):
mode(m)
{
MatrixStack::MatrixStack(GLenum m):
mode(m)
{
+ matrices.reserve(mode==GL_MODELVIEW ? 32 : 4);
matrices.push_back(Matrix());
}
MatrixStack::MatrixStack():
mode(0)
{
matrices.push_back(Matrix());
}
MatrixStack::MatrixStack():
mode(0)
{
matrices.push_back(Matrix());
}
matrices.push_back(Matrix());
}
#ifndef MSP_GL_MATRIX_H_
#define MSP_GL_MATRIX_H_
#ifndef MSP_GL_MATRIX_H_
#define MSP_GL_MATRIX_H_
#include "gl.h"
#include "vector.h"
#include "gl.h"
#include "vector.h"
- std::list<Matrix> matrices;
+ std::vector<Matrix> matrices;
static GLenum current_mode;
static GLenum current_mode;
mtx_changed(false),
camera(c),
state_stack(1),
mtx_changed(false),
camera(c),
state_stack(1),
- state(&state_stack.back()),
vertex_array(0),
vertex_array_changed(false),
element_buffer(0)
{
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)
{
MatrixStack::modelview().push();
if(camera)
{
state->shprog = p;
if(p && d)
add_shader_data(*d);
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)
{
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();
state_stack.pop_back();
state = &state_stack.back();
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;
mtx_stack.pop();
mtx_changed = true;
shdata_changed = true;
state->shprog->bind();
if(shdata_changed)
{
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;
}
(*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.
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.
const Texturing *texturing;
const Material *material;
const Program *shprog;
const Texturing *texturing;
const Material *material;
const Program *shprog;
- std::vector<const ProgramData *> shdata;
const WindingTest *winding_test;
State();
const WindingTest *winding_test;
State();
MtxStack mtx_stack;
bool mtx_changed;
const Camera *camera;
MtxStack mtx_stack;
bool mtx_changed;
const Camera *camera;
- std::list<State> state_stack;
+ std::vector<State> state_stack;
+ std::vector<const ProgramData *> shdata_stack;
+ bool shdata_changed;
const VertexArray *vertex_array;
bool vertex_array_changed;
const Buffer *element_buffer;
const VertexArray *vertex_array;
bool vertex_array_changed;
const Buffer *element_buffer;
public:
Renderer(const Camera *);
public:
Renderer(const Camera *);
void set_element_buffer(const Buffer *);
void set_winding_test(const WindingTest *);
void set_element_buffer(const Buffer *);
void set_winding_test(const WindingTest *);
+ /** Saves the current state so it can be restored later. */
+
+ /** 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
void pop_state();
/** Prepares for temporarily bypassing the Renderer by synchronizing the