From a361efc05fcad11b2918f3cd7abdebe794b131d8 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 2 Nov 2007 19:11:28 +0000 Subject: [PATCH] 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 --- Build | 6 +- source/except.h | 6 +- source/ext_framebuffer_object.cpp | 47 +++++++++ source/ext_framebuffer_object.h | 32 ++++++ source/extension.cpp | 3 + source/framebuffer.cpp | 72 +++++++++++++ source/framebuffer.h | 83 +++++++++++++++ source/ilwrap.cpp | 73 +++++++++++++ source/ilwrap.h | 37 +++++++ source/object.cpp | 166 ++++++++++++++++++++++-------- source/object.h | 22 ++-- source/objectinstance.cpp | 5 + source/objectinstance.h | 14 ++- source/objectpass.cpp | 50 +++++++++ source/objectpass.h | 48 +++++++++ source/pixelformat.h | 36 +++++++ source/programdata.cpp | 32 ++++++ source/programdata.h | 20 ++++ source/renderbuffer.cpp | 40 +++++++ source/renderbuffer.h | 43 ++++++++ source/select.cpp | 2 +- source/texture.h | 15 +-- source/texture2d.cpp | 140 ++++++++----------------- source/texture2d.h | 46 +++++++-- source/texture3d.cpp | 87 ++++++++++++++++ source/texture3d.h | 41 ++++++++ 26 files changed, 997 insertions(+), 169 deletions(-) create mode 100644 source/ext_framebuffer_object.cpp create mode 100644 source/ext_framebuffer_object.h create mode 100644 source/framebuffer.cpp create mode 100644 source/framebuffer.h create mode 100644 source/ilwrap.cpp create mode 100644 source/ilwrap.h create mode 100644 source/objectpass.cpp create mode 100644 source/objectpass.h create mode 100644 source/pixelformat.h create mode 100644 source/renderbuffer.cpp create mode 100644 source/renderbuffer.h create mode 100644 source/texture3d.cpp create mode 100644 source/texture3d.h 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 -- 2.45.2