]> git.tdb.fi Git - libs/gl.git/commitdiff
Use DevIL for loading images
authorMikko Rasa <tdb@tdb.fi>
Fri, 2 Nov 2007 19:11:28 +0000 (19:11 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 2 Nov 2007 19:11:28 +0000 (19:11 +0000)
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

26 files changed:
Build
source/except.h
source/ext_framebuffer_object.cpp [new file with mode: 0644]
source/ext_framebuffer_object.h [new file with mode: 0644]
source/extension.cpp
source/framebuffer.cpp [new file with mode: 0644]
source/framebuffer.h [new file with mode: 0644]
source/ilwrap.cpp [new file with mode: 0644]
source/ilwrap.h [new file with mode: 0644]
source/object.cpp
source/object.h
source/objectinstance.cpp
source/objectinstance.h
source/objectpass.cpp [new file with mode: 0644]
source/objectpass.h [new file with mode: 0644]
source/pixelformat.h [new file with mode: 0644]
source/programdata.cpp
source/programdata.h
source/renderbuffer.cpp [new file with mode: 0644]
source/renderbuffer.h [new file with mode: 0644]
source/select.cpp
source/texture.h
source/texture2d.cpp
source/texture2d.h
source/texture3d.cpp [new file with mode: 0644]
source/texture3d.h [new file with mode: 0644]

diff --git a/Build b/Build
index a70e9ac90bb1d5871c9cdcf5ec9edd21868db08d..b83b3c7c12c37f67140ce45ed70e2c13de3ce958 100644 (file)
--- a/Build
+++ b/Build
@@ -7,7 +7,11 @@ package "mspgl"
 
        require "opengl";
        require "mspdatafile";
-       require "libpng";
+       require "devil";
+       build_info
+       {
+               library "ILU";
+       };
 
        library "mspgl"
        {
index 7bcf59f4336cd3bda9ffb4669a939be73972d6dd..2d8f979e7f86182b5a0effae9a768e4d06f1b607 100644 (file)
@@ -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 (file)
index 0000000..80da828
--- /dev/null
@@ -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<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
diff --git a/source/ext_framebuffer_object.h b/source/ext_framebuffer_object.h
new file mode 100644 (file)
index 0000000..f541c2f
--- /dev/null
@@ -0,0 +1,32 @@
+#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
index 2d57d1d12224155e8b9ade1f3e488c2d35c8e7c7..e250bb249c9f04fd9fce24ebd3a42762ded9657d 100644 (file)
@@ -13,6 +13,7 @@ Distributed under the LGPL
 #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"
 
@@ -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 (file)
index 0000000..d9d873b
--- /dev/null
@@ -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<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
diff --git a/source/framebuffer.h b/source/framebuffer.h
new file mode 100644 (file)
index 0000000..0dd8f5d
--- /dev/null
@@ -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 (file)
index 0000000..be8442b
--- /dev/null
@@ -0,0 +1,73 @@
+/* $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
diff --git a/source/ilwrap.h b/source/ilwrap.h
new file mode 100644 (file)
index 0000000..7b3766a
--- /dev/null
@@ -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
index 0469c31a99629187f17ce7d5dde803823636bb2e..7250caf8f9bc22272c4e859882ee17229298f97a 100644 (file)
@@ -5,11 +5,13 @@ Copyright © 2007  Mikko Rasa, Mikkosoft Productions
 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"
@@ -21,57 +23,60 @@ namespace Msp {
 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);
@@ -85,42 +90,119 @@ void Object::setup_render() const
                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)
index 7a40a40ba24bc71ff40af47c46af642a229e0249..e38afb5c4c1b16fb92946785143bed0fb4824a6d 100644 (file)
@@ -10,6 +10,7 @@ Distributed under the LGPL
 
 #include <vector>
 #include <msp/datafile/collection.h>
+#include "objectpass.h"
 
 namespace Msp {
 namespace GL {
@@ -31,11 +32,11 @@ See also class ObjectInstance.
 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
@@ -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 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
index 80f44cd48ea35e45528d1f0b4f7b54c6dc0c3a6b..78042bd1a8182de436d6963bf4d7e4dc512381b9 100644 (file)
@@ -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
index 955ad1ddd7f0d9ac2f9ee2508c8bad3bdd49d88b..151e316c9e2e91faaff22fa31337f9bc9fa3d1ea 100644 (file)
@@ -8,12 +8,16 @@ Distributed under the LGPL
 #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
@@ -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 (file)
index 0000000..57e7b27
--- /dev/null
@@ -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<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
diff --git a/source/objectpass.h b/source/objectpass.h
new file mode 100644 (file)
index 0000000..59a1dfb
--- /dev/null
@@ -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 <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
diff --git a/source/pixelformat.h b/source/pixelformat.h
new file mode 100644 (file)
index 0000000..87cbe75
--- /dev/null
@@ -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 <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
index 6d657d8a9354ba64d915ca6770318608d17d8ae9..af2679a5965bbd932082b679ffe88f135ff47434 100644 (file)
@@ -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
index 495ea22f3a5be143fe498c1d9ce8ae7ee5bb91d3..986bd7b1f444cda423f878557efc3a4bb907e268 100644 (file)
@@ -9,6 +9,7 @@ Distributed under the LGPL
 #define MSP_GL_PROGRAMDATA_H_
 
 #include <map>
+#include <msp/datafile/loader.h>
 
 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<int, Uniform *> data;
 
diff --git a/source/renderbuffer.cpp b/source/renderbuffer.cpp
new file mode 100644 (file)
index 0000000..49e0b74
--- /dev/null
@@ -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 (file)
index 0000000..a9c25ad
--- /dev/null
@@ -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
index 486ffbeddd2f483cfe4e93a33a0de4fc100533a1..67420977323597738ebfac564c8c9514ce637799 100644 (file)
@@ -52,7 +52,7 @@ void parse_select_records(const uint *buf, uint count, vector<SelectRecord> &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);
 }
 
index 55eda001a79ec0b12dc3c1e52628327653733365..6c3541d446ef01d817ae88e3611d3dccb0a05f9e 100644 (file)
@@ -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:
index c6137d73b60f41c0adeb62f5d6547406a64b9cf2..455c7314cb4d2a04676b1ac6e6612884e95ef212 100644 (file)
@@ -5,122 +5,72 @@ Copyright © 2007  Mikko Rasa, Mikkosoft Productions
 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
index e06ea920a1aff896f7c1c50ed1f87fac75e7b007..251561b99490c5ca93166bd9679e121a3fbc92d2 100644 (file)
@@ -9,23 +9,53 @@ Distributed under the LGPL
 #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
diff --git a/source/texture3d.cpp b/source/texture3d.cpp
new file mode 100644 (file)
index 0000000..858ca47
--- /dev/null
@@ -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 <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
diff --git a/source/texture3d.h b/source/texture3d.h
new file mode 100644 (file)
index 0000000..b4260e8
--- /dev/null
@@ -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 <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