const Vector3 &get_position() const { return position; }
const Vector3 &get_look_direction() const { return look_dir; }
const Vector3 &get_up_direction() const { return up_dir; }
+ const Matrix &get_matrix() const { return matrix; }
Vector3 project(const Vector4 &) const;
Vector4 unproject(const Vector4 &) const;
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2008, 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include "object.h"
#include "objectinstance.h"
#include "instancescene.h"
+#include "renderer.h"
namespace Msp {
namespace GL {
renderables.erase(&r);
}
-void InstanceScene::render(const Tag &tag) const
+void InstanceScene::render(Renderer &renderer, const Tag &tag) const
{
+ // XXX Check that the object has this pass to avoid some unnecessary function calls
for(ObjectMap::const_iterator i=objects.begin(); i!=objects.end(); ++i)
- i->first->render(i->second.begin(), i->second.end(), tag);
+ for(InstanceSet::const_iterator j=i->second.begin(); j!=i->second.end(); ++j)
+ (*j)->render(renderer, tag);
for(RenderableSet::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
- (*i)->render(tag);
+ (*i)->render(renderer, tag);
}
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2008, 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
virtual void add(const Renderable &);
virtual void remove(const Renderable &);
- virtual void render(const Tag &tag = Tag()) const;
+ using Scene::render;
+ virtual void render(Renderer &, const Tag &tag = Tag()) const;
};
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include "buffer.h"
#include "extension.h"
#include "mesh.h"
+#include "renderer.h"
using namespace std;
Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
}
+void Mesh::draw(Renderer &renderer) const
+{
+ renderer.set_vertex_array(&vertices);
+ renderer.set_element_buffer(ibuf);
+
+ for(list<Batch>::const_iterator i=batches.begin(); i!=batches.end(); ++i)
+ renderer.draw(*i);
+}
+
Mesh::Loader::Loader(Mesh &m):
DataFile::ObjectLoader<Mesh>(m)
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
namespace GL {
class Buffer;
+class Renderer;
class Mesh
{
const std::list<Batch> &get_batches() { return batches; }
void draw() const;
+ void draw(Renderer &) const;
};
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include "objectinstance.h"
#include "program.h"
#include "programdata.h"
+#include "renderer.h"
#include "technique.h"
-#include "texture.h"
-#include "texunit.h"
+#include "texturing.h"
using namespace std;
if(!pass)
return;
- Bind bind(pass);
+ Bind bind_shader(pass->get_shader_program());
+ if(pass->get_shader_data())
+ pass->get_shader_data()->apply();
+ Bind bind_material(pass->get_material());
+ Bind bind_texturing(pass->get_texturing());
+
meshes.front()->draw();
}
-void Object::render(const ObjectInstance &inst, const Tag &tag) const
+void Object::render(Renderer &renderer, const Tag &tag) const
{
const RenderPass *pass = get_pass(tag);
if(!pass)
return;
- Bind bind(pass);
- render_instance(inst, tag);
+ Renderer::Push push(renderer);
+ renderer.set_shader(pass->get_shader_program(), pass->get_shader_data());
+ renderer.set_material(pass->get_material());
+ renderer.set_texturing(pass->get_texturing());
+
+ meshes.front()->draw(renderer);
+}
+
+void Object::render(Renderer &renderer, const ObjectInstance &inst, const Tag &tag) const
+{
+ const RenderPass *pass = get_pass(tag);
+ if(!pass)
+ return;
+
+ Renderer::Push push(renderer);
+ renderer.set_shader(pass->get_shader_program(), pass->get_shader_data());
+ renderer.set_material(pass->get_material());
+ renderer.set_texturing(pass->get_texturing());
+
+ inst.setup_render(renderer, tag);
+ unsigned lod = min<unsigned>(inst.get_level_of_detail(), meshes.size()-1);
+ meshes[lod]->draw(renderer);
+ inst.finish_render(renderer, tag);
}
const RenderPass *Object::get_pass(const Tag &tag) const
return &technique->get_pass(tag);
}
-void Object::render_instance(const ObjectInstance &inst, const Tag &tag) const
-{
- inst.setup_render(tag);
- unsigned lod = min<unsigned>(inst.get_level_of_detail(), meshes.size()-1);
- meshes[lod]->draw();
- inst.finish_render(tag);
-}
-
Object::Loader::Loader(Object &o):
DataFile::CollectionObjectLoader<Object>(o, 0)
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2008, 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
*/
virtual void render(const Tag &tag = Tag()) const;
+ virtual void render(Renderer &, const Tag & = Tag()) const;
+
/**
Renders the object with an instance. The instance's hook functions are
called before and after drawing the mesh. A tag may also be given to render
a non-default pass.
*/
- virtual void render(const ObjectInstance &, const Tag &tag = Tag()) const;
+ virtual void render(Renderer &, const ObjectInstance &, const Tag & = Tag()) const;
- /**
- Renders multiple instances of the object in one go. This may improve
- performance, as the object-specific render setup only has to be done once.
- Each instance's hook functions will be called before and after drawing the
- mesh.
- */
- template<typename Iter>
- void render(Iter begin, Iter end, const Tag &tag = Tag()) const
- {
- const RenderPass *pass = get_pass(tag);
- if(!pass)
- return;
-
- Bind bind(pass);
- for(Iter i=begin; i!=end; ++i)
- render_instance(**i, tag);
- }
private:
const RenderPass *get_pass(const Tag &) const;
- void render_instance(const ObjectInstance &, const Tag &) const;
};
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include "object.h"
#include "objectinstance.h"
-#include "programdata.h"
+#include "renderer.h"
using namespace std;
void ObjectInstance::render(const Tag &tag) const
{
- object.render(*this, tag);
+ Renderer renderer(0);
+ render(renderer, tag);
+}
+
+void ObjectInstance::render(Renderer &renderer, const Tag &tag) const
+{
+ object.render(renderer, *this, tag);
}
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
Represents a single instance of an Object. An application can derive another
class from this and overload the hook functions to specify location and other
instance-specific parameters for the rendered objects.
-
-The finish_render function generally should clean up everything done by
-setup_render, unless the rendering sequence is known to allow otherwise.
*/
class ObjectInstance: public Renderable
{
const Object &get_object() const { return object; }
virtual void render(const Tag &tag = Tag()) const;
+ virtual void render(Renderer &, const Tag & = Tag()) const;
- /**
- Hook function, called from Object just before rendering the mesh.
- */
- virtual void setup_render(const Tag &) const { }
+ /** Hook function, called from Object just before rendering the mesh.
+ Renderer state will have been pushed before this is called. */
+ virtual void setup_render(Renderer &, const Tag &) const { }
- /**
- Hook function, called from Object right after rendering the mesh.
- */
- virtual void finish_render(const Tag &) const { }
+ /** Hook function, called from Object right after rendering the mesh. Since
+ Object takes care of pushing Renderer state, this rarely needs to do
+ anything. */
+ virtual void finish_render(Renderer &, const Tag &) const { }
virtual unsigned get_level_of_detail() const { return 0; }
};
/* $Id$
This file is part of libmspgl
-Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
renderables.insert(i, &r);
}
-void OrderedScene::render(const Tag &tag) const
+void OrderedScene::render(Renderer &renderer, const Tag &tag) const
{
for(RenderableList::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
- (*i)->render(tag);
+ (*i)->render(renderer, tag);
}
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
void insert(unsigned, const Renderable &);
void insert_after(const Renderable &, const Renderable &);
- virtual void render(const Tag & = Tag()) const;
+ using Scene::render;
+ virtual void render(Renderer &, const Tag & = Tag()) const;
};
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
#include "pipeline.h"
#include "postprocessor.h"
#include "renderbuffer.h"
+#include "renderer.h"
#include "tests.h"
#include "texture2d.h"
}
}
-void Pipeline::render(const Tag &tag) const
+void Pipeline::render(Renderer &renderer, const Tag &tag) const
{
const PipelinePass &pass = get_pass(tag);
for(vector<Slot>::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
if(i->passes.empty() || i->passes.count(tag))
- i->renderable->render(tag);
+ i->renderable->render(renderer, tag);
for(vector<Effect *>::const_iterator i=pass.effects.end(); i!=pass.effects.begin();)
(*--i)->cleanup();
for(vector<Effect *>::const_iterator i=effects.begin(); i!=effects.end(); ++i)
(*i)->prepare();
+ Renderer renderer(camera);
for(vector<Tag>::const_iterator i=pass_order.begin(); i!=pass_order.end(); ++i)
- render(*i);
+ render(renderer, *i);
for(vector<Effect *>::const_iterator i=effects.end(); i!=effects.begin();)
(*--i)->cleanup();
/* $Id$
This file is part of libmspgl
-Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
void add_effect(Effect &);
void add_postprocessor(PostProcessor &);
- virtual void render(const Tag &tag = Tag()) const;
+ virtual void render(Renderer &, const Tag &tag = Tag()) const;
void render_all() const;
};
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2011 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include "renderable.h"
+#include "renderer.h"
+
+namespace Msp {
+namespace GL {
+
+void Renderable::render(const Tag &) const
+{
+ throw Exception("This Renderable doesn't support rendering without a Renderer");
+}
+
+void Renderable::render(Renderer &renderer, const Tag &tag) const
+{
+ renderer.escape();
+ render(tag);
+}
+
+} // namespace Msp
+} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007, 2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
namespace Msp {
namespace GL {
+class Renderer;
+
class Renderable
{
protected:
public:
virtual ~Renderable() { }
- virtual void render(const Tag &tag = Tag()) const =0;
+ virtual void render(const Tag & = Tag()) const;
+ virtual void render(Renderer &, const Tag & = Tag()) const;
};
} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2011 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <msp/core/except.h>
+#include "batch.h"
+#include "buffer.h"
+#include "camera.h"
+#include "material.h"
+#include "program.h"
+#include "programdata.h"
+#include "renderer.h"
+#include "texture.h"
+#include "texturing.h"
+#include "vertexarray.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Renderer::Renderer(const Camera *c):
+ mtx_changed(false),
+ camera(c),
+ state_stack(1),
+ state(&state_stack.back()),
+ vertex_array(0),
+ vertex_array_changed(false),
+ element_buffer(0)
+{
+ MatrixStack::modelview().push();
+ if(camera)
+ {
+ MatrixStack::projection().push();
+ camera->apply();
+ mtx_stack = camera->get_matrix();
+ }
+ else
+ mtx_stack = MatrixStack::modelview().top();
+}
+
+Renderer::~Renderer()
+{
+ if(camera)
+ MatrixStack::projection().pop();
+ MatrixStack::modelview().pop();
+
+ Texturing::unbind();
+ Texture::unbind_from(0);
+ Material::unbind();
+ Program::unbind();
+ Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
+}
+
+MatrixStack &Renderer::matrix_stack()
+{
+ mtx_changed = true;
+ return mtx_stack;
+}
+
+void Renderer::set_texture(const Texture *t)
+{
+ state->texture = t;
+ state->texturing = 0;
+}
+
+void Renderer::set_texturing(const Texturing *t)
+{
+ state->texturing = t;
+ state->texture = 0;
+}
+
+void Renderer::set_material(const Material *m)
+{
+ state->material = m;
+}
+
+void Renderer::set_shader(const Program *p, const ProgramData *d)
+{
+ state->shprog = p;
+ if(d)
+ state->shdata.assign(1, d);
+ else
+ state->shdata.clear();
+}
+
+void Renderer::add_shader_data(const ProgramData *d)
+{
+ if(!state->shprog)
+ throw InvalidState("No shader program");
+
+ state->shdata.push_back(d);
+}
+
+void Renderer::set_vertex_array(const VertexArray *a)
+{
+ vertex_array_changed = (a!=vertex_array);
+ vertex_array = a;
+}
+
+void Renderer::set_element_buffer(const Buffer *b)
+{
+ element_buffer = b;
+}
+
+void Renderer::push_state()
+{
+ state_stack.push_back(state_stack.back());
+ state = &state_stack.back();
+ mtx_stack.push();
+}
+
+void Renderer::pop_state()
+{
+ if(state_stack.size()==1)
+ throw InvalidState("Can't pop the last state");
+
+ state_stack.pop_back();
+ state = &state_stack.back();
+ mtx_stack.pop();
+}
+
+void Renderer::escape()
+{
+ apply_state();
+ Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
+}
+
+void Renderer::draw(const Batch &batch)
+{
+ if(!vertex_array)
+ throw InvalidState("Can't draw without a vertex array");
+
+ apply_state();
+
+ // Until VertexArray acquires VAO support and becomes Bindable
+ if(vertex_array_changed)
+ vertex_array->apply();
+
+ if(element_buffer)
+ element_buffer->bind_to(ELEMENT_ARRAY_BUFFER);
+ else
+ Buffer::unbind_from(ELEMENT_ARRAY_BUFFER);
+
+ batch.draw();
+}
+
+void Renderer::apply_state()
+{
+ // We let the objects themselves figure out if the binding has changed
+
+ if(state->texturing)
+ state->texturing->bind();
+ else
+ {
+ Texturing::unbind();
+ if(state->texture)
+ state->texture->bind_to(0);
+ else
+ Texture::unbind_from(0);
+ }
+
+ if(state->material)
+ state->material->bind();
+ else
+ Material::unbind();
+
+ if(state->shprog)
+ {
+ state->shprog->bind();
+ for(vector<const ProgramData *>::const_iterator i=state->shdata.begin(); i!=state->shdata.end(); ++i)
+ (*i)->apply();
+ }
+ else
+ Program::unbind();
+
+ if(mtx_changed)
+ {
+ MatrixStack::modelview() = mtx_stack.top();
+ mtx_changed = false;
+ }
+}
+
+
+Renderer::State::State():
+ texture(0),
+ texturing(0),
+ material(0),
+ shprog(0)
+{ }
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2011 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_RENDERER_H_
+#define MSP_GL_RENDERER_H_
+
+#include <vector>
+#include "matrix.h"
+
+namespace Msp {
+namespace GL {
+
+class Batch;
+class Buffer;
+class Camera;
+class Material;
+class Program;
+class ProgramData;
+class Texture;
+class Texturing;
+class VertexArray;
+
+/**
+A class for supervising the rendering process. While many Renderables (in
+particular, Objects and Scenes) can by rendered without a Renderer, using one
+will often be more efficient. This is especially true for ObjectInstances.
+
+The Renderer works by deferring GL state changes until something is actually
+being drawn. This avoids many unnecessary GL calls. */
+class Renderer
+{
+public:
+ class Push
+ {
+ private:
+ Renderer &renderer;
+
+ public:
+ Push(Renderer &r): renderer(r) { renderer.push_state(); }
+ ~Push() { renderer.pop_state(); }
+ };
+
+private:
+ struct State
+ {
+ const Texture *texture;
+ const Texturing *texturing;
+ const Material *material;
+ const Program *shprog;
+ std::vector<const ProgramData *> shdata;
+
+ State();
+ };
+
+ MatrixStack mtx_stack;
+ bool mtx_changed;
+ const Camera *camera;
+ std::list<State> state_stack;
+ State *state;
+ const VertexArray *vertex_array;
+ bool vertex_array_changed;
+ const Buffer *element_buffer;
+
+public:
+ Renderer(const Camera *);
+ ~Renderer();
+
+ MatrixStack &matrix_stack();
+
+ const Camera *get_camera() const { return camera; }
+
+ void set_texture(const Texture *);
+ void set_texturing(const Texturing *);
+ void set_material(const Material *);
+ void set_shader(const Program *, const ProgramData *);
+ void add_shader_data(const ProgramData *);
+ void set_vertex_array(const VertexArray *);
+ void set_element_buffer(const Buffer *);
+
+ void push_state();
+ void pop_state();
+
+ /** Prepares for temporarily bypassing the Renderer. */
+ void escape();
+
+ void draw(const Batch &);
+
+private:
+ void apply_state();
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
/* $Id$
This file is part of libmspgl
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
{ }
RenderPass::RenderPass(const RenderPass &other):
- Bindable<RenderPass>(other),
shprog(other.shprog),
shdata(other.shdata ? new ProgramData(*other.shdata) : 0),
material(other.material),
texturing->attach(index, *tex);
}
-void RenderPass::bind() const
-{
- const RenderPass *old = current();
- if(!set_current(this))
- return;
-
- if(shprog)
- {
- shprog->bind();
- shdata->apply();
- }
- else if(old && old->shprog)
- Program::unbind();
-
- if(material)
- material->bind();
- else if(old && old->material)
- Material::unbind();
-
- if(texturing)
- texturing->bind();
- else if(old && old->texturing)
- Texturing::unbind();
-}
-
-void RenderPass::unbind()
-{
- const RenderPass *old = current();
- if(!set_current(0))
- return;
-
- if(old->shprog)
- Program::unbind();
-
- if(old->material)
- Material::unbind();
-
- if(old->texturing)
- Texturing::unbind();
-}
-
RenderPass::Loader::Loader(RenderPass &p):
DataFile::CollectionObjectLoader<RenderPass>(p, 0)
/* $Id$
This file is part of libmspgl
-Copyright © 2007-2008, 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2007-2008, 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
XXX Does not delete inline texture from datafiles properly
*/
-class RenderPass: public Bindable<RenderPass>
+class RenderPass
{
public:
class Loader: public DataFile::CollectionObjectLoader<RenderPass>
RenderPass(const RenderPass &);
~RenderPass();
+ const Program *get_shader_program() const { return shprog; }
+ const ProgramData *get_shader_data() const { return shdata; }
void set_material(const Material *);
+ const Material *get_material() const { return material.get(); }
void set_texture(unsigned, const Texture *);
-
- void bind() const;
-
- static void unbind();
+ const Texturing *get_texturing() const { return texturing; }
};
} // namespace GL
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2011 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "renderer.h"
+#include "scene.h"
+
+namespace Msp {
+namespace GL {
+
+void Scene::render(const Tag &tag) const
+{
+ Renderer renderer(0);
+ render(renderer, tag);
+}
+
+} // namespace GL
+} // namespace Msp
/* $Id$
This file is part of libmspgl
-Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
virtual void add(const Renderable &) = 0;
virtual void remove(const Renderable &) = 0;
+
+ using Renderable::render;
+ virtual void render(const Tag & = Tag()) const;
};
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
renderables.erase(&r);
}
-void SimpleScene::render(const Tag &tag) const
+void SimpleScene::render(Renderer &renderer, const Tag &tag) const
{
for(RenderableSet::const_iterator i=renderables.begin(); i!=renderables.end(); ++i)
- (*i)->render(tag);
+ (*i)->render(renderer, tag);
}
} // namespace GL
/* $Id$
This file is part of libmspgl
-Copyright © 2010 Mikko Rasa, Mikkosoft Productions
+Copyright © 2010-2011 Mikko Rasa, Mikkosoft Productions
Distributed under the LGPL
*/
virtual void add(const Renderable &);
virtual void remove(const Renderable &);
- virtual void render(const Tag &tag = Tag()) const;
+ using Scene::render;
+ virtual void render(Renderer &, const Tag & = Tag()) const;
};
} // namespace GL