From: Mikko Rasa Date: Fri, 2 Nov 2007 19:11:28 +0000 (+0000) Subject: Use DevIL for loading images X-Git-Tag: 0.9~25 X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=a361efc05fcad11b2918f3cd7abdebe794b131d8 Use DevIL for loading images Rework the texture interface Add framebuffer objects Add Loader for ProgramData Support for multiple rendering passes and levels of detail in Object Add 3D textures --- diff --git a/Build b/Build index a70e9ac9..b83b3c7c 100644 --- a/Build +++ b/Build @@ -7,7 +7,11 @@ package "mspgl" require "opengl"; require "mspdatafile"; - require "libpng"; + require "devil"; + build_info + { + library "ILU"; + }; library "mspgl" { diff --git a/source/except.h b/source/except.h index 7bcf59f4..2d8f979e 100644 --- a/source/except.h +++ b/source/except.h @@ -13,11 +13,11 @@ Distributed under the LGPL 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 diff --git a/source/ext_framebuffer_object.cpp b/source/ext_framebuffer_object.cpp new file mode 100644 index 00000000..80da8283 --- /dev/null +++ b/source/ext_framebuffer_object.cpp @@ -0,0 +1,47 @@ +#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(get_proc_address("glIsRenderbufferEXT")); + glBindRenderbufferEXT=reinterpret_cast(get_proc_address("glBindRenderbufferEXT")); + glDeleteRenderbuffersEXT=reinterpret_cast(get_proc_address("glDeleteRenderbuffersEXT")); + glGenRenderbuffersEXT=reinterpret_cast(get_proc_address("glGenRenderbuffersEXT")); + glRenderbufferStorageEXT=reinterpret_cast(get_proc_address("glRenderbufferStorageEXT")); + glGetRenderbufferParameterivEXT=reinterpret_cast(get_proc_address("glGetRenderbufferParameterivEXT")); + glIsFramebufferEXT=reinterpret_cast(get_proc_address("glIsFramebufferEXT")); + glBindFramebufferEXT=reinterpret_cast(get_proc_address("glBindFramebufferEXT")); + glDeleteFramebuffersEXT=reinterpret_cast(get_proc_address("glDeleteFramebuffersEXT")); + glGenFramebuffersEXT=reinterpret_cast(get_proc_address("glGenFramebuffersEXT")); + glCheckFramebufferStatusEXT=reinterpret_cast(get_proc_address("glCheckFramebufferStatusEXT")); + glFramebufferTexture1DEXT=reinterpret_cast(get_proc_address("glFramebufferTexture1DEXT")); + glFramebufferTexture2DEXT=reinterpret_cast(get_proc_address("glFramebufferTexture2DEXT")); + glFramebufferTexture3DEXT=reinterpret_cast(get_proc_address("glFramebufferTexture3DEXT")); + glFramebufferRenderbufferEXT=reinterpret_cast(get_proc_address("glFramebufferRenderbufferEXT")); + glGetFramebufferAttachmentParameterivEXT=reinterpret_cast(get_proc_address("glGetFramebufferAttachmentParameterivEXT")); + glGenerateMipmapEXT=reinterpret_cast(get_proc_address("glGenerateMipmapEXT")); +} + +} // namespace GL +} // namespace Msp diff --git a/source/ext_framebuffer_object.h b/source/ext_framebuffer_object.h new file mode 100644 index 00000000..f541c2ff --- /dev/null +++ b/source/ext_framebuffer_object.h @@ -0,0 +1,32 @@ +#ifndef MSP_GL_EXT_FRAMEBUFFER_OBJECT_ +#define MSP_GL_EXT_FRAMEBUFFER_OBJECT_ + +#include + +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 diff --git a/source/extension.cpp b/source/extension.cpp index 2d57d1d1..e250bb24 100644 --- a/source/extension.cpp +++ b/source/extension.cpp @@ -13,6 +13,7 @@ Distributed under the LGPL #include #include "arb_shader_objects.h" #include "arb_vertex_shader.h" +#include "ext_framebuffer_object.h" #include "except.h" #include "extension.h" @@ -40,6 +41,8 @@ bool is_supported(const string &ext) 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; } diff --git a/source/framebuffer.cpp b/source/framebuffer.cpp new file mode 100644 index 00000000..d9d873bb --- /dev/null +++ b/source/framebuffer.cpp @@ -0,0 +1,72 @@ +/* $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(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 diff --git a/source/framebuffer.h b/source/framebuffer.h new file mode 100644 index 00000000..0dd8f5d7 --- /dev/null +++ b/source/framebuffer.h @@ -0,0 +1,83 @@ +/* $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 diff --git a/source/ilwrap.cpp b/source/ilwrap.cpp new file mode 100644 index 00000000..be8442be --- /dev/null +++ b/source/ilwrap.cpp @@ -0,0 +1,73 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#include +#include +#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(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 diff --git a/source/ilwrap.h b/source/ilwrap.h new file mode 100644 index 00000000..7b3766a4 --- /dev/null +++ b/source/ilwrap.h @@ -0,0 +1,37 @@ +/* $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 diff --git a/source/object.cpp b/source/object.cpp index 0469c31a..7250caf8 100644 --- a/source/object.cpp +++ b/source/object.cpp @@ -5,11 +5,13 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ +#include #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" @@ -21,57 +23,60 @@ namespace Msp { namespace GL { Object::Object(): - mesh(0), - shprog(0), - shdata(0), + meshes(1, static_cast(0)), material(0) -{ } +{ + normal_pass=&passes[""]; +} Object::~Object() { - delete shdata; + for(map::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::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 &insts) const { - setup_render(); - - for(list::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 &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; iapply(); } -void Object::finish_render() const +void Object::finish_render(const ObjectPass &pass) const { - if(shprog) + if(pass.shprog) Program::unbind(); - for(unsigned i=0; isetup_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 &insts) const +{ + setup_render(pass); + + for(list::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; iuniform(obj.shprog->get_uniform_location(textures[i]), static_cast(i)); - } + for(map::iterator i=obj.passes.begin(); i!=obj.passes.end(); ++i) + if(i->second.shdata) + { + for(unsigned j=0; jsecond.shdata->uniform(i->second.shprog->get_uniform_location(textures[j]), static_cast(j)); + } +} + +void Object::Loader::lod_mesh(unsigned l, const string &n) +{ + obj.meshes.resize(l+1, 0); + obj.meshes[l]=&coll.get(n); +} + +void Object::Loader::material_inline() +{ + throw Exception("material_inline not supported yet"); + /*RefPtr 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(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(n); - if(!obj.shdata) - obj.shdata=new ProgramData; + Program *shprog=&coll.get(n); + if(shprog) // Allow for unsupported shaders + { + RefPtr 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) diff --git a/source/object.h b/source/object.h index 7a40a40b..e38afb5c 100644 --- a/source/object.h +++ b/source/object.h @@ -10,6 +10,7 @@ Distributed under the LGPL #include #include +#include "objectpass.h" namespace Msp { namespace GL { @@ -31,11 +32,11 @@ See also class ObjectInstance. class Object { private: - Mesh *mesh; + std::vector meshes; std::vector textures; - Program *shprog; - ProgramData *shdata; + std::map passes; Material *material; + ObjectPass *normal_pass; public: class Loader: public DataFile::Loader @@ -56,6 +57,10 @@ public: 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 &); }; @@ -63,13 +68,15 @@ public: 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 @@ -77,9 +84,12 @@ public: done once. */ void render(const std::list &) const; + void render(const std::string &, const std::list &) 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; }; } // namespace GL diff --git a/source/objectinstance.cpp b/source/objectinstance.cpp index 80f44cd4..78042bd1 100644 --- a/source/objectinstance.cpp +++ b/source/objectinstance.cpp @@ -21,5 +21,10 @@ void ObjectInstance::render() const object.render(this); } +void ObjectInstance::render(const std::string &pn) const +{ + object.render(pn, this); +} + } // namespace GL } // namespaec Msp diff --git a/source/objectinstance.h b/source/objectinstance.h index 955ad1dd..151e316c 100644 --- a/source/objectinstance.h +++ b/source/objectinstance.h @@ -8,12 +8,16 @@ Distributed under the LGPL #ifndef MSP_GL_OBJETCINSTANCE_H_ #define MSP_GL_OBJETCINSTANCE_H_ +#include + 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 @@ -26,19 +30,23 @@ protected: 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 diff --git a/source/objectpass.cpp b/source/objectpass.cpp new file mode 100644 index 00000000..57e7b278 --- /dev/null +++ b/source/objectpass.cpp @@ -0,0 +1,50 @@ +/* $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(n); + if(shprog) // Allow for unsupported shaders + { + RefPtr shdata=new ProgramData; + load_sub(*shdata, *shprog); + + pass.shprog=shprog; + if(pass.shdata) + delete pass.shdata; + pass.shdata=shdata.release(); + } +} + +} // namespace GL +} // namespace Msp diff --git a/source/objectpass.h b/source/objectpass.h new file mode 100644 index 00000000..59a1dfb4 --- /dev/null +++ b/source/objectpass.h @@ -0,0 +1,48 @@ +/* $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 + +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 diff --git a/source/pixelformat.h b/source/pixelformat.h new file mode 100644 index 00000000..87cbe754 --- /dev/null +++ b/source/pixelformat.h @@ -0,0 +1,36 @@ +/* $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 + +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 diff --git a/source/programdata.cpp b/source/programdata.cpp index 6d657d8a..af2679a5 100644 --- a/source/programdata.cpp +++ b/source/programdata.cpp @@ -6,6 +6,7 @@ Distributed under the LGPL */ #include "extension.h" +#include "program.h" #include "programdata.h" #include "uniform.h" @@ -86,5 +87,36 @@ void ProgramData::apply() const 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 diff --git a/source/programdata.h b/source/programdata.h index 495ea22f..986bd7b1 100644 --- a/source/programdata.h +++ b/source/programdata.h @@ -9,6 +9,7 @@ Distributed under the LGPL #define MSP_GL_PROGRAMDATA_H_ #include +#include namespace Msp { namespace GL { @@ -16,8 +17,27 @@ 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 data; diff --git a/source/renderbuffer.cpp b/source/renderbuffer.cpp new file mode 100644 index 00000000..49e0b74f --- /dev/null +++ b/source/renderbuffer.cpp @@ -0,0 +1,40 @@ +/* $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 diff --git a/source/renderbuffer.h b/source/renderbuffer.h new file mode 100644 index 00000000..a9c25ad7 --- /dev/null +++ b/source/renderbuffer.h @@ -0,0 +1,43 @@ +/* $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 diff --git a/source/select.cpp b/source/select.cpp index 486ffbed..67420977 100644 --- a/source/select.cpp +++ b/source/select.cpp @@ -52,7 +52,7 @@ void parse_select_records(const uint *buf, uint count, vector &tbu 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); } diff --git a/source/texture.h b/source/texture.h index 55eda001..6c3541d4 100644 --- a/source/texture.h +++ b/source/texture.h @@ -24,16 +24,11 @@ enum TextureFilter 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: diff --git a/source/texture2d.cpp b/source/texture2d.cpp index c6137d73..455c7314 100644 --- a/source/texture2d.cpp +++ b/source/texture2d.cpp @@ -5,122 +5,72 @@ Copyright © 2007 Mikko Rasa, Mikkosoft Productions Distributed under the LGPL */ -#include #include "except.h" +#include "ilwrap.h" #include "texture2d.h" using namespace std; +#include + 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 +#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 diff --git a/source/texture3d.cpp b/source/texture3d.cpp new file mode 100644 index 00000000..858ca478 --- /dev/null +++ b/source/texture3d.cpp @@ -0,0 +1,87 @@ +/* $Id$ + +This file is part of libmspgl +Copyright © 2007 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ + +#define GL_GLEXT_PROTOTYPES +#include +#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*d0) + 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 diff --git a/source/texture3d.h b/source/texture3d.h new file mode 100644 index 00000000..b4260e88 --- /dev/null +++ b/source/texture3d.h @@ -0,0 +1,41 @@ +/* $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 +#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