require "opengl";
require "mspdatafile";
- require "libpng";
+ require "devil";
+ build_info
+ {
+ library "ILU";
+ };
library "mspgl"
{
namespace Msp {
namespace GL {
-class InvalidOperation: public Exception
+class IncompatibleData: public Exception
{
public:
- InvalidOperation(const std::string &w_): Exception(w_) { }
- ~InvalidOperation() throw() { }
+ IncompatibleData(const std::string &w_): Exception(w_) { }
+ ~IncompatibleData() throw() { }
};
class UnsupportedExtension: public Exception
--- /dev/null
+#include "extension.h"
+#include "ext_framebuffer_object.h"
+
+namespace Msp {
+namespace GL {
+
+PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT=0;
+PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT=0;
+PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT=0;
+PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT=0;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT=0;
+PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT=0;
+PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT=0;
+PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT=0;
+PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT=0;
+PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT=0;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT=0;
+PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT=0;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT=0;
+PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT=0;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT=0;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT=0;
+PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT=0;
+
+void init_ext_framebuffer_object()
+{
+ glIsRenderbufferEXT=reinterpret_cast<PFNGLISRENDERBUFFEREXTPROC>(get_proc_address("glIsRenderbufferEXT"));
+ glBindRenderbufferEXT=reinterpret_cast<PFNGLBINDRENDERBUFFEREXTPROC>(get_proc_address("glBindRenderbufferEXT"));
+ glDeleteRenderbuffersEXT=reinterpret_cast<PFNGLDELETERENDERBUFFERSEXTPROC>(get_proc_address("glDeleteRenderbuffersEXT"));
+ glGenRenderbuffersEXT=reinterpret_cast<PFNGLGENRENDERBUFFERSEXTPROC>(get_proc_address("glGenRenderbuffersEXT"));
+ glRenderbufferStorageEXT=reinterpret_cast<PFNGLRENDERBUFFERSTORAGEEXTPROC>(get_proc_address("glRenderbufferStorageEXT"));
+ glGetRenderbufferParameterivEXT=reinterpret_cast<PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC>(get_proc_address("glGetRenderbufferParameterivEXT"));
+ glIsFramebufferEXT=reinterpret_cast<PFNGLISFRAMEBUFFEREXTPROC>(get_proc_address("glIsFramebufferEXT"));
+ glBindFramebufferEXT=reinterpret_cast<PFNGLBINDFRAMEBUFFEREXTPROC>(get_proc_address("glBindFramebufferEXT"));
+ glDeleteFramebuffersEXT=reinterpret_cast<PFNGLDELETEFRAMEBUFFERSEXTPROC>(get_proc_address("glDeleteFramebuffersEXT"));
+ glGenFramebuffersEXT=reinterpret_cast<PFNGLGENFRAMEBUFFERSEXTPROC>(get_proc_address("glGenFramebuffersEXT"));
+ glCheckFramebufferStatusEXT=reinterpret_cast<PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC>(get_proc_address("glCheckFramebufferStatusEXT"));
+ glFramebufferTexture1DEXT=reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE1DEXTPROC>(get_proc_address("glFramebufferTexture1DEXT"));
+ glFramebufferTexture2DEXT=reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DEXTPROC>(get_proc_address("glFramebufferTexture2DEXT"));
+ glFramebufferTexture3DEXT=reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE3DEXTPROC>(get_proc_address("glFramebufferTexture3DEXT"));
+ glFramebufferRenderbufferEXT=reinterpret_cast<PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC>(get_proc_address("glFramebufferRenderbufferEXT"));
+ glGetFramebufferAttachmentParameterivEXT=reinterpret_cast<PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC>(get_proc_address("glGetFramebufferAttachmentParameterivEXT"));
+ glGenerateMipmapEXT=reinterpret_cast<PFNGLGENERATEMIPMAPEXTPROC>(get_proc_address("glGenerateMipmapEXT"));
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+#ifndef MSP_GL_EXT_FRAMEBUFFER_OBJECT_
+#define MSP_GL_EXT_FRAMEBUFFER_OBJECT_
+
+#include <GL/gl.h>
+
+namespace Msp {
+namespace GL {
+
+extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
+extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
+extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
+extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
+extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
+extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
+extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
+extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
+extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
+extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
+extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
+extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
+extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
+extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
+extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
+extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
+
+void init_ext_framebuffer_object();
+
+} // namespace GL
+} // namespace Msp
+
+#endif
#include <msp/strings/utils.h>
#include "arb_shader_objects.h"
#include "arb_vertex_shader.h"
+#include "ext_framebuffer_object.h"
#include "except.h"
#include "extension.h"
init_arb_shader_objects();
if(extensions.count("GL_ARB_vertex_shader"))
init_arb_vertex_shader();
+ if(extensions.count("GL_EXT_framebuffer_object"))
+ init_ext_framebuffer_object();
init_done=true;
}
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "extension.h"
+#include "ext_framebuffer_object.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "texture2d.h"
+
+namespace Msp {
+namespace GL {
+
+Framebuffer::Framebuffer()
+{
+ require_extension("GL_EXT_framebuffer_object");
+
+ glGenFramebuffersEXT(1, &id);
+ bind();
+}
+
+Framebuffer::~Framebuffer()
+{
+ glDeleteFramebuffersEXT(1, &id);
+}
+
+void Framebuffer::bind() const
+{
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
+ current=this;
+}
+
+void Framebuffer::attach(FramebufferAttachment attch, Renderbuffer &rbuf)
+{
+ maybe_bind();
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch, GL_RENDERBUFFER_EXT, rbuf.get_id());
+}
+
+void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, int level)
+{
+ maybe_bind();
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch, tex.get_target(), tex.get_id(), level);
+}
+
+FramebufferStatus Framebuffer::check_status() const
+{
+ maybe_bind();
+ return static_cast<FramebufferStatus>(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
+}
+
+void Framebuffer::unbind()
+{
+ if(current)
+ {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ current=0;
+ }
+}
+
+void Framebuffer::maybe_bind() const
+{
+ if(current!=this)
+ bind();
+}
+
+const Framebuffer *Framebuffer::current=0;
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_FRAMEBUFFER_H_
+#define MSP_GL_FRAMEBUFFER_H_
+
+#include "types.h"
+
+namespace Msp {
+namespace GL {
+
+class Renderbuffer;
+class Texture2D;
+
+enum FramebufferAttachment
+{
+ COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0_EXT,
+ COLOR_ATTACHMENT1 = GL_COLOR_ATTACHMENT1_EXT,
+ COLOR_ATTACHMENT2 = GL_COLOR_ATTACHMENT2_EXT,
+ COLOR_ATTACHMENT3 = GL_COLOR_ATTACHMENT3_EXT,
+ DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT_EXT,
+ STENCIL_ATTACHMENT = GL_STENCIL_ATTACHMENT_EXT
+};
+
+enum FramebufferStatus
+{
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT,
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT,
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS = GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT,
+ FRAMEBUFFER_INCOMPLETE_FORMATS = GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT,
+ FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT,
+ FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT,
+ FRAMEBUFFER_UNSUPPORTED = GL_FRAMEBUFFER_UNSUPPORTED_EXT,
+ FRAMEBUFFER_COMPLETE = GL_FRAMEBUFFER_COMPLETE_EXT
+};
+
+/**
+Framebuffer objects can be used to perform offscreen rendering. The most
+common application is rendering to a texture, which can then be used for
+fullscreen shader effects.
+
+A framebuffer consist of a number of logical buffers, such as color and depth
+buffers. Renderbuffers and Textures can be attached to the logical buffers. At
+least one image must be attached for the framebuffer to be usable.
+
+Requires the GL_EXT_framebuffer_object extension.
+*/
+class Framebuffer
+{
+private:
+ uint id;
+
+ static const Framebuffer *current;
+
+public:
+ Framebuffer();
+ ~Framebuffer();
+
+ void bind() const;
+
+ void attach(FramebufferAttachment attch, Renderbuffer &rbuf);
+ void attach(FramebufferAttachment attch, Texture2D &tex, int level);
+
+ /**
+ Checks the completeness status of the framebuffer. Returns
+ FRAMEBUFFER_COMPLETE if the framebuffer is complate and can be rendered to,
+ or one of the error status codes otherwise.
+ */
+ FramebufferStatus check_status() const;
+
+ static void unbind();
+private:
+ void maybe_bind() const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include <IL/il.h>
+#include <msp/core/except.h>
+#include "ilwrap.h"
+
+namespace Msp {
+namespace GL {
+
+Image::Image()
+{
+ if(!init_done)
+ {
+ ilInit();
+ ilEnable(IL_ORIGIN_SET);
+ ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
+ init_done=true;
+ }
+
+ ilGenImages(1, &id);
+}
+
+Image::~Image()
+{
+ ilDeleteImages(1, &id);
+}
+
+void Image::load(const std::string &fn)
+{
+ ilBindImage(id);
+ if(!ilLoadImage(const_cast<char *>(fn.c_str())))
+ throw Exception("Error loading image "+fn);
+}
+
+PixelFormat Image::get_format() const
+{
+ switch(ilGetInteger(IL_IMAGE_FORMAT))
+ {
+ case IL_COLOR_INDEX: return COLOR_INDEX;
+ case IL_LUMINANCE: return LUMINANCE;
+ case IL_LUMINANCE_ALPHA: return LUMINANCE_ALPHA;
+ case IL_RGB: return RGB;
+ case IL_RGBA: return RGBA;
+ case IL_BGR: return BGR;
+ case IL_BGRA: return BGRA;
+ default: throw InvalidParameterValue("Unknown pixel format in image");
+ }
+}
+
+unsigned Image::get_width() const
+{
+ return ilGetInteger(IL_IMAGE_WIDTH);
+}
+
+unsigned Image::get_height() const
+{
+ return ilGetInteger(IL_IMAGE_HEIGHT);
+}
+
+const void *Image::get_data() const
+{
+ return ilGetData();
+}
+
+bool Image::init_done=false;
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_ILWRAP_H_
+#define MSP_GL_ILWRAP_H_
+
+#include "pixelformat.h"
+
+namespace Msp {
+namespace GL {
+
+class Image
+{
+private:
+ unsigned id;
+
+ static bool init_done;
+
+public:
+ Image();
+ ~Image();
+
+ void load(const std::string &);
+ PixelFormat get_format() const;
+ unsigned get_width() const;
+ unsigned get_height() const;
+ const void *get_data() const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
Distributed under the LGPL
*/
+#include <msp/strings/formatter.h>
#include "except.h"
#include "material.h"
#include "mesh.h"
#include "object.h"
#include "objectinstance.h"
+#include "objectpass.h"
#include "program.h"
#include "programdata.h"
#include "texture.h"
namespace GL {
Object::Object():
- mesh(0),
- shprog(0),
- shdata(0),
+ meshes(1, static_cast<Mesh *>(0)),
material(0)
-{ }
+{
+ normal_pass=&passes[""];
+}
Object::~Object()
{
- delete shdata;
+ for(map<string, ObjectPass>::iterator i=passes.begin(); i!=passes.end(); ++i)
+ delete i->second.shdata;
}
-void Object::render(const ObjectInstance *inst) const
+bool Object::has_pass(const string &pn) const
{
- setup_render();
-
- if(inst)
- inst->setup_render();
+ return passes.count(pn);
+}
- mesh->draw();
+const ObjectPass &Object::get_pass(const string &pn) const
+{
+ map<string, ObjectPass>::const_iterator i=passes.find(pn);
+ if(i==passes.end())
+ throw KeyError("Unknown pass");
+ return i->second;
+}
- if(inst)
- inst->finish_render();
+void Object::render(const ObjectInstance *inst) const
+{
+ render(*normal_pass, inst);
+}
- finish_render();
+void Object::render(const string &pn, const ObjectInstance *inst) const
+{
+ render(get_pass(pn), inst);
}
void Object::render(const list<const ObjectInstance *> &insts) const
{
- setup_render();
-
- for(list<const ObjectInstance *>::const_iterator i=insts.begin(); i!=insts.end(); ++i)
- {
- (*i)->setup_render();
-
- mesh->draw();
-
- (*i)->finish_render();
- }
+ render(*normal_pass, insts);
+}
- finish_render();
+void Object::render(const string &pn, const list<const ObjectInstance *> &insts) const
+{
+ render(get_pass(pn), insts);
}
-void Object::setup_render() const
+void Object::setup_render(const ObjectPass &pass) const
{
- if(!mesh)
+ if(!meshes[0])
throw InvalidState("Trying to render Object without mesh");
- if(shprog)
+ if(pass.shprog)
{
- shprog->bind();
- shdata->apply();
+ pass.shprog->bind();
+ pass.shdata->apply();
for(unsigned i=0; i<textures.size(); ++i)
{
TexUnit::activate(i);
material->apply();
}
-void Object::finish_render() const
+void Object::finish_render(const ObjectPass &pass) const
{
- if(shprog)
+ if(pass.shprog)
Program::unbind();
- for(unsigned i=0; i<textures.size(); ++i)
+ for(unsigned i=textures.size(); i--;)
{
TexUnit::activate(i);
Texture::unbind();
}
}
+void Object::render(const ObjectPass &pass, const ObjectInstance *inst) const
+{
+ setup_render(pass);
+
+ unsigned lod=0;
+ if(inst)
+ {
+ inst->setup_render(pass);
+ lod=min(inst->get_level_of_detail(), meshes.size()-1);
+ }
+
+ meshes[lod]->draw();
+
+ if(inst)
+ inst->finish_render(pass);
+
+ finish_render(pass);
+}
+
+void Object::render(const ObjectPass &pass, const list<const ObjectInstance *> &insts) const
+{
+ setup_render(pass);
+
+ for(list<const ObjectInstance *>::const_iterator i=insts.begin(); i!=insts.end(); ++i)
+ {
+ (*i)->setup_render(pass);
+
+ unsigned lod=min((*i)->get_level_of_detail(), meshes.size()-1);
+ meshes[lod]->draw();
+
+ (*i)->finish_render(pass);
+ }
+
+ finish_render(pass);
+}
+
Object::Loader::Loader(Object &o, Collection &c):
obj(o),
coll(c)
{
+ add("lod_mesh", &Loader::lod_mesh);
add("material", &Object::material);
- add("mesh", &Object::mesh);
+ add("material_inline", &Loader::material_inline);
+ add("mesh", &Loader::mesh);
+ add("pass", &Loader::pass);
add("shader", &Loader::shader);
add("texture", &Loader::texture);
}
Object::Loader::~Loader()
{
- if(obj.shdata)
- {
- for(unsigned i=0; i<textures.size(); ++i)
- obj.shdata->uniform(obj.shprog->get_uniform_location(textures[i]), static_cast<int>(i));
- }
+ for(map<string, ObjectPass>::iterator i=obj.passes.begin(); i!=obj.passes.end(); ++i)
+ if(i->second.shdata)
+ {
+ for(unsigned j=0; j<textures.size(); ++j)
+ i->second.shdata->uniform(i->second.shprog->get_uniform_location(textures[j]), static_cast<int>(j));
+ }
+}
+
+void Object::Loader::lod_mesh(unsigned l, const string &n)
+{
+ obj.meshes.resize(l+1, 0);
+ obj.meshes[l]=&coll.get<Mesh>(n);
+}
+
+void Object::Loader::material_inline()
+{
+ throw Exception("material_inline not supported yet");
+ /*RefPtr<Material> mat=new Material;
+ load_sub(*mat);
+ coll.add(format("%p%p", &obj, mat.get()), mat.get());
+ obj.material=mat.release();*/
+}
+
+void Object::Loader::mesh(const string &n)
+{
+ obj.meshes[0]=&coll.get<Mesh>(n);
+}
+
+void Object::Loader::pass(const string &n)
+{
+ if(obj.passes.count(n))
+ throw KeyError("Duplicate pass name");
+ ObjectPass p;
+ load_sub(p, coll);
+ obj.passes[n]=p;
}
void Object::Loader::shader(const string &n)
{
- obj.shprog=&coll.get<Program>(n);
- if(!obj.shdata)
- obj.shdata=new ProgramData;
+ Program *shprog=&coll.get<Program>(n);
+ if(shprog) // Allow for unsupported shaders
+ {
+ RefPtr<ProgramData> shdata=new ProgramData;
+ load_sub(*shdata, *shprog);
+
+ obj.normal_pass->shprog=shprog;
+ if(obj.normal_pass->shdata)
+ delete obj.normal_pass->shdata;
+ obj.normal_pass->shdata=shdata.release();
+ }
}
void Object::Loader::texture(const string &n)
#include <vector>
#include <msp/datafile/collection.h>
+#include "objectpass.h"
namespace Msp {
namespace GL {
class Object
{
private:
- Mesh *mesh;
+ std::vector<Mesh *> meshes;
std::vector<Texture *> textures;
- Program *shprog;
- ProgramData *shdata;
+ std::map<std::string, ObjectPass> passes;
Material *material;
+ ObjectPass *normal_pass;
public:
class Loader: public DataFile::Loader
Object &get_object() const { return obj; }
Collection &get_collection() const { return coll; }
private:
+ void lod_mesh(unsigned, const std::string &);
+ void material_inline();
+ void mesh(const std::string &);
+ void pass(const std::string &);
void shader(const std::string &);
void texture(const std::string &);
};
Object();
~Object();
- Program *get_shader() const { return shprog; }
+ bool has_pass(const std::string &) const;
+ const ObjectPass &get_pass(const std::string &) const;
/**
Renders the object. If an ObjectInstance is provided, its hook functions
are called.
*/
void render(const ObjectInstance * =0) const;
+ void render(const std::string &, const ObjectInstance *) const;
/**
Renders multiple instances of the object in one go. This may be a
done once.
*/
void render(const std::list<const ObjectInstance *> &) const;
+ void render(const std::string &, const std::list<const ObjectInstance *> &) const;
private:
- void setup_render() const;
- void finish_render() const;
+ void setup_render(const ObjectPass &) const;
+ void finish_render(const ObjectPass &) const;
+ void render(const ObjectPass &, const ObjectInstance *) const;
+ void render(const ObjectPass &, const std::list<const ObjectInstance *> &) const;
};
} // namespace GL
object.render(this);
}
+void ObjectInstance::render(const std::string &pn) const
+{
+ object.render(pn, this);
+}
+
} // namespace GL
} // namespaec Msp
#ifndef MSP_GL_OBJETCINSTANCE_H_
#define MSP_GL_OBJETCINSTANCE_H_
+#include <string>
+
namespace Msp {
namespace GL {
class Object;
class ProgramData;
+class ObjectPass;
+
/**
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
public:
ObjectInstance(const Object &);
+
+ const Object &get_object() const { return object; }
+
void render() const;
+ void render(const std::string &) const;
/**
Hook function, called from Object just before rendering the mesh.
*/
- virtual void setup_render() const { }
+ virtual void setup_render(const ObjectPass &) const { }
/**
Hook function, called from Object right after rendering the mesh.
*/
- virtual void finish_render() const { }
+ virtual void finish_render(const ObjectPass &) const { }
- virtual unsigned get_detail_level() const { return 0; }
+ virtual unsigned get_level_of_detail() const { return 0; }
};
} // namespace GL
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "objectpass.h"
+#include "program.h"
+#include "programdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+ObjectPass::ObjectPass():
+ shprog(0),
+ shdata(0)
+{ }
+
+ObjectPass::~ObjectPass()
+{
+}
+
+
+ObjectPass::Loader::Loader(ObjectPass &p, Collection &c):
+ pass(p),
+ coll(c)
+{
+ add("shader", &Loader::shader);
+}
+
+void ObjectPass::Loader::shader(const string &n)
+{
+ Program *shprog=&coll.get<Program>(n);
+ if(shprog) // Allow for unsupported shaders
+ {
+ RefPtr<ProgramData> shdata=new ProgramData;
+ load_sub(*shdata, *shprog);
+
+ pass.shprog=shprog;
+ if(pass.shdata)
+ delete pass.shdata;
+ pass.shdata=shdata.release();
+ }
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_OBJECTPASS_H_
+#define MSP_GL_OBJECTPASS_H_
+
+#include <msp/datafile/collection.h>
+
+namespace Msp {
+namespace GL {
+
+class Program;
+class ProgramData;
+
+struct ObjectPass
+{
+ class Loader: public DataFile::Loader
+ {
+ public:
+ typedef DataFile::Collection Collection;
+
+ private:
+ ObjectPass &pass;
+ Collection &coll;
+
+ public:
+ Loader(ObjectPass &, Collection &);
+ ObjectPass &get_object() const { return pass; }
+ Collection &get_collection() const { return coll; }
+ private:
+ void shader(const std::string &);
+ };
+
+ Program *shprog;
+ ProgramData *shdata;
+
+ ObjectPass();
+ ~ObjectPass();
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_PIXELFORMAT_H_
+#define MSP_GL_PIXELFORMAT_H_
+
+#include <GL/gl.h>
+
+namespace Msp {
+namespace GL {
+
+enum PixelFormat
+{
+ COLOR_INDEX = GL_COLOR_INDEX,
+ STENCIL_INDEX = GL_STENCIL_INDEX,
+ DEPTH_COMPONENT = GL_DEPTH_COMPONENT,
+ RED = GL_RED,
+ GREEN = GL_GREEN,
+ BLUE = GL_BLUE,
+ ALPHA = GL_ALPHA,
+ RGB = GL_RGB,
+ RGBA = GL_RGBA,
+ BGR = GL_BGR,
+ BGRA = GL_BGRA,
+ LUMINANCE = GL_LUMINANCE,
+ LUMINANCE_ALPHA = GL_LUMINANCE_ALPHA
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
*/
#include "extension.h"
+#include "program.h"
#include "programdata.h"
#include "uniform.h"
i->second->apply(i->first);
}
+
+ProgramData::Loader::Loader(ProgramData &pd, Program &pr):
+ pdata(pd),
+ prog(pr)
+{
+ add("uniform1", &Loader::uniform1);
+ add("uniform2", &Loader::uniform2);
+ add("uniform3", &Loader::uniform3);
+ add("uniform4", &Loader::uniform4);
+}
+
+void ProgramData::Loader::uniform1(const string &n, float v)
+{
+ pdata.uniform(prog.get_uniform_location(n), v);
+}
+
+void ProgramData::Loader::uniform2(const string &n, float v0, float v1)
+{
+ pdata.uniform(prog.get_uniform_location(n), v0, v1);
+}
+
+void ProgramData::Loader::uniform3(const string &n, float v0, float v1, float v2)
+{
+ pdata.uniform(prog.get_uniform_location(n), v0, v1, v2);
+}
+
+void ProgramData::Loader::uniform4(const string &n, float v0, float v1, float v2, float v3)
+{
+ pdata.uniform(prog.get_uniform_location(n), v0, v1, v2, v3);
+}
+
} // namespace GL
} // namespace Msp
#define MSP_GL_PROGRAMDATA_H_
#include <map>
+#include <msp/datafile/loader.h>
namespace Msp {
namespace GL {
class Program;
class Uniform;
+/**
+Stores uniform variables for a shader program.
+*/
class ProgramData
{
+public:
+ class Loader: public DataFile::Loader
+ {
+ private:
+ ProgramData &pdata;
+ Program &prog;
+
+ public:
+ Loader(ProgramData &, Program &);
+ private:
+ void uniform1(const std::string &, float);
+ void uniform2(const std::string &, float, float);
+ void uniform3(const std::string &, float, float, float);
+ void uniform4(const std::string &, float, float, float, float);
+ };
+
private:
std::map<int, Uniform *> data;
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "extension.h"
+#include "ext_framebuffer_object.h"
+#include "renderbuffer.h"
+
+namespace Msp {
+namespace GL {
+
+Renderbuffer::Renderbuffer()
+{
+ require_extension("GL_EXT_framebuffer_object");
+
+ glGenRenderbuffersEXT(1, &id);
+ bind();
+}
+
+Renderbuffer::~Renderbuffer()
+{
+ glDeleteRenderbuffersEXT(1, &id);
+}
+
+void Renderbuffer::bind() const
+{
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
+}
+
+void Renderbuffer::storage(PixelFormat fmt, sizei width, sizei height)
+{
+ bind();
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, fmt, width, height);
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_RENDERBUFFER_H_
+#define MSP_GL_RENDERBUFFER_H_
+
+#include "pixelformat.h"
+#include "types.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+A Renderbuffer contains a single renderable image. It can be attached to a
+Framebuffer to provide a logical buffer that is required to render the scene
+correctly but that is not needed as a texture later.
+
+Requires the GL_EXT_framebuffer_object extension.
+*/
+class Renderbuffer
+{
+private:
+ uint id;
+
+public:
+ Renderbuffer();
+ ~Renderbuffer();
+
+ uint get_id() const { return id; }
+
+ void bind() const;
+
+ void storage(PixelFormat fmt, sizei width, sizei height);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
void _parse_internal_select_records(uint count)
{
if(!select_buf)
- throw InvalidOperation("No select buffer specified");
+ throw InvalidState("No select buffer specified");
parse_select_records(&select_buf_int[0], count, *select_buf);
}
LINEAR_MIPMAP_LINEAR = GL_LINEAR_MIPMAP_LINEAR
};
-enum TextureFormat
-{
- LUMINANCE8,
- LUMINANCE8_ALPHA8,
- RGB8,
- RGBA8,
- BGR8,
- BGRA8
-};
-
+/**
+Base class for textures. This class only defines operations common for all
+texture types and is not instantiable. For specifying images for textures, see
+one of the dimensioned texture classes.
+*/
class Texture
{
public:
Distributed under the LGPL
*/
-#include <png.h>
#include "except.h"
+#include "ilwrap.h"
#include "texture2d.h"
using namespace std;
+#include <iostream>
+
namespace Msp {
namespace GL {
-Texture2D::Texture2D()
+Texture2D::Texture2D():
+ width(0),
+ height(0)
{
target=GL_TEXTURE_2D;
+ bind();
}
-/**
-Uploads an image into the texture. Direct wrapper for glTexImage2D.
-*/
-void Texture2D::image(int level, int ifmt, sizei wd, sizei ht, int border, GLenum fmt, GLenum type, void *data)
+void Texture2D::storage(PixelFormat fmt, sizei wd, sizei ht, int brd)
+{
+ if(width>0)
+ throw InvalidState("Texture storage may only be specified once");
+ if(wd==0 || ht==0)
+ throw InvalidParameterValue("Invalid texture dimensions");
+
+ ifmt=fmt;
+ width=wd;
+ height=ht;
+ border=brd;
+}
+
+void Texture2D::image(int level, PixelFormat fmt, GLenum type, const void *data)
{
+ if(width==0)
+ throw InvalidState("Texture storage has not been specified");
+
maybe_bind();
- glTexImage2D(target, level, ifmt, wd, ht, border, fmt, type, data);
- width_=wd;
- height_=ht;
+ glTexImage2D(target, level, ifmt, width, height, border, fmt, type, data);
}
-/**
-Uploads an image into the texture, with a simpler interface.
-*/
-void Texture2D::image(int level, sizei wd, sizei ht, TextureFormat tfmt, void *data)
+void Texture2D::sub_image(int level, int x, int y, sizei wd, sizei ht, PixelFormat fmt, GLenum type, const void *data)
{
- int ifmt;
- int fmt;
- int type;
-
- switch(tfmt)
- {
- case LUMINANCE8: ifmt=GL_LUMINANCE; fmt=GL_LUMINANCE; type=GL_UNSIGNED_BYTE; break;
- case LUMINANCE8_ALPHA8: ifmt=GL_LUMINANCE_ALPHA; fmt=GL_LUMINANCE_ALPHA; type=GL_UNSIGNED_BYTE; break;
- case RGB8: ifmt=GL_RGB; fmt=GL_RGB; type=GL_UNSIGNED_BYTE; break;
- case RGBA8: ifmt=GL_RGBA; fmt=GL_RGBA; type=GL_UNSIGNED_INT_8_8_8_8_REV; break;
- case BGR8: ifmt=GL_RGB; fmt=GL_BGR; type=GL_UNSIGNED_BYTE; break;
- case BGRA8: ifmt=GL_RGBA; fmt=GL_BGRA; type=GL_UNSIGNED_INT_8_8_8_8_REV; break;
- default: throw InvalidParameterValue("Invalid texture format");
- }
-
- image(level, ifmt, wd, ht, 0, fmt, type, data);
+ if(width==0)
+ throw InvalidState("Texture storage has not been specified");
+
+ maybe_bind();
+
+ glTexSubImage2D(target, level, x, y, wd, ht, fmt, type, data);
}
-/**
-Loads an image from a file and uploads it into the texture. Currently assumes
-the file to be a PNG image.
-*/
-void Texture2D::image(const string &fn)
+void Texture2D::load_image(const string &fn)
{
- FILE *file=fopen(fn.c_str(), "r");
- if(!file) throw Exception("Couldn't open "+fn);
-
- char sig[8];
- fread(sig, 8, 1, file);
- if(png_sig_cmp((png_byte *)sig, 0, 8))
- throw Exception("Not a PNG image");
-
- png_struct *pngs=png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
- png_info *pngi=png_create_info_struct(pngs);
-
- if(setjmp(png_jmpbuf(pngs)))
- {
- png_destroy_read_struct(&pngs, &pngi, 0);
- fclose(file);
- throw Exception("PNG error");
- }
- png_init_io(pngs, file);
- png_set_sig_bytes(pngs, 8);
-
- png_read_info(pngs, pngi);
-
- unsigned wd=png_get_image_width(pngs, pngi);
- unsigned ht=png_get_image_height(pngs, pngi);
- unsigned depth=png_get_bit_depth(pngs, pngi);
- unsigned ctype=png_get_color_type(pngs, pngi);
-
- if(ctype==PNG_COLOR_TYPE_PALETTE || depth<8)
- {
- png_destroy_read_struct(&pngs, &pngi, 0);
- fclose(file);
- throw Exception("Invalid color type or bit depth");
- }
-
- if(depth==16)
- png_set_strip_16(pngs);
-
- TextureFormat fmt;
- unsigned planes;
-
- switch(ctype)
- {
- case PNG_COLOR_TYPE_GRAY: fmt=LUMINANCE8; planes=1; break;
- case PNG_COLOR_TYPE_GRAY_ALPHA: fmt=LUMINANCE8_ALPHA8; planes=2; break;
- case PNG_COLOR_TYPE_RGB: fmt=RGB8; planes=3; break;
- case PNG_COLOR_TYPE_RGB_ALPHA: fmt=RGBA8; planes=4; break;
- default: throw Exception("Invalid color type");
- }
-
- png_byte *data=new png_byte[wd*ht*planes];
- png_byte *row_ptrs[ht];
- for(unsigned i=0; i<ht; ++i)
- row_ptrs[i]=data+(ht-1-i)*wd*planes;
-
- png_read_image(pngs, row_ptrs);
-
- image(0, wd, ht, fmt, data);
- delete[] data;
-
- png_destroy_read_struct(&pngs, &pngi, 0);
- fclose(file);
+ Image img;
+ img.load(fn);
+
+ unsigned w=img.get_width();
+ unsigned h=img.get_height();
+ PixelFormat fmt=img.get_format();
+ if(width==0)
+ storage(fmt, w, h, 0);
+ else if(w!=width || h!=height)
+ throw IncompatibleData("Image does not match texture storage");
+
+ image(0, fmt, GL_UNSIGNED_BYTE, img.get_data());
}
} // namespace GL
#define MSP_GL_TEXTURE2D_H_
#include <string>
+#include "pixelformat.h"
#include "texture.h"
namespace Msp {
namespace GL {
+/**
+Two-dimensional texture class. This is the most common type of texture.
+*/
class Texture2D: public Texture
{
+private:
+ PixelFormat ifmt;
+ sizei width;
+ sizei height;
+ int border;
+
public:
Texture2D();
- void image(int, int, sizei, sizei, int, GLenum, GLenum, void *);
- void image(int, sizei, sizei, TextureFormat, void *);
- void image(const std::string &);
- sizei get_width() const { return width_; }
- sizei get_height() const { return height_; }
-private:
- sizei width_;
- sizei height_;
+
+ /**
+ Defines the texture storage. This function may only be successfully called
+ once.
+ */
+ void storage(PixelFormat fmt, sizei wd, sizei ht, int brd);
+
+ /**
+ Uploads an image to the texture. storage() must have been called prior to
+ this, and the image must have dimensions conforming to the specified
+ storage.
+ */
+ void image(int level, PixelFormat fmt, GLenum type, const void *data);
+
+ /**
+ Uploads a sub-image into the texture. Unlike full image upload, there are
+ no constraints on the size of the sub-image.
+ */
+ void sub_image(int level, int x, int y, sizei wd, sizei ht, PixelFormat fmt, GLenum type, const void *data);
+
+ /**
+ Loads an image from a file and uploads it to the texture. If storage() has
+ not been called, the storage format will be set to match the loaded image.
+ */
+ void load_image(const std::string &fn);
+
+ sizei get_width() const { return width; }
+ sizei get_height() const { return height; }
};
} // namespace GL
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#define GL_GLEXT_PROTOTYPES
+#include <cmath>
+#include "except.h"
+#include "ilwrap.h"
+#include "texture3d.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Texture3D::Texture3D():
+ width(0),
+ height(0),
+ depth(0)
+{
+ target=GL_TEXTURE_3D;
+ bind();
+}
+
+void Texture3D::storage(PixelFormat f, sizei w, sizei h, sizei d, int b)
+{
+ if(width>0)
+ throw InvalidState("Textures may only be created once");
+ if(w==0 || h==0 || d==0)
+ throw InvalidParameterValue("Invalid texture dimensions");
+
+ width=w;
+ height=h;
+ depth=d;
+ ifmt=f;
+ border=b;
+
+ image(0, ifmt, GL_UNSIGNED_BYTE, 0);
+}
+
+void Texture3D::image(int level, PixelFormat fmt, GLenum type, const void *data)
+{
+ maybe_bind();
+ glTexImage3D(target, level, ifmt, width, height, depth, border, fmt, type, data);
+}
+
+void Texture3D::load_image(const string &fn, int dp)
+{
+ Image img;
+ img.load(fn);
+
+ unsigned w=img.get_width();
+ unsigned h=img.get_height();
+ unsigned d=1;
+
+ if(dp==-1)
+ {
+ if(h%w)
+ throw IncompatibleData("Image height is not divisible by its width");
+ d=h/w;
+ h=w;
+ }
+ else if(dp==-2)
+ {
+ for(d=h; d*d>h; d>>=2);
+ for(; d*d<h; ++d);
+ if(d*d!=h)
+ throw IncompatibleData("Could not find a square root of texture height");
+ h=d;
+ }
+ else if(dp>0)
+ d=dp;
+
+ PixelFormat fmt=img.get_format();
+ if(width==0)
+ storage(fmt, w, h, d, 0);
+ else if(w!=width || h!=height || d!=depth)
+ throw IncompatibleData("Image does not match texture storage");
+
+ image(0, fmt, GL_UNSIGNED_INT, img.get_data());
+}
+
+} // namespace GL
+} // namespace Msp
--- /dev/null
+/* $Id$
+
+This file is part of libmspgl
+Copyright © 2007 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GL_TEXTURE3D_H_
+#define MSP_GL_TEXTURE3D_H_
+
+#include <string>
+#include "pixelformat.h"
+#include "texture.h"
+
+namespace Msp {
+namespace GL {
+
+class Texture3D: public Texture
+{
+private:
+ PixelFormat ifmt;
+ sizei width;
+ sizei height;
+ sizei depth;
+ int border;
+
+public:
+ Texture3D();
+ void storage(PixelFormat, sizei, sizei, sizei, int);
+ void image(int, PixelFormat, GLenum, const void *);
+ void sub_image(int, int, int, sizei, sizei, sizei, PixelFormat, GLenum, const void *);
+ void load_image(const std::string &fn, int dp=-1);
+ sizei get_width() const { return width; }
+ sizei get_height() const { return height; }
+ sizei get_depth() const { return depth; }
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif