]> git.tdb.fi Git - libs/gl.git/commitdiff
Add support for cube map textures
authorMikko Rasa <tdb@tdb.fi>
Thu, 9 Aug 2012 18:07:43 +0000 (21:07 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 9 Aug 2012 18:07:43 +0000 (21:07 +0300)
source/framebuffer.cpp
source/framebuffer.h
source/texturecube.cpp [new file with mode: 0644]
source/texturecube.h [new file with mode: 0644]

index 6877f4808b7402c7f1660097c3860bb7fcbbe5bc..8806ea6c4956d980dafd2b72419050e78813c2d8 100644 (file)
@@ -60,6 +60,11 @@ void Framebuffer::update_attachment(unsigned mask) const
                                        static_cast<Texture2D *>(attch.tex)->allocate(attch.level);
                                        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch.attachment, attch.type, attch.tex->get_id(), attch.level);
                                }
+                               else if(attch.type==GL_TEXTURE_CUBE_MAP)
+                               {
+                                       static_cast<TextureCube *>(attch.tex)->allocate(attch.level);
+                                       glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attch.attachment, attch.cube_face, attch.tex->get_id(), attch.level);
+                               }
                                else
                                        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attch.attachment, 0, 0);
                        }
@@ -90,6 +95,11 @@ void Framebuffer::check_size()
                                width = tex->get_width();
                                height = tex->get_height();
                        }
+                       else if(i->type==GL_TEXTURE_CUBE_MAP)
+                       {
+                               width = static_cast<TextureCube *>(i->tex)->get_size();
+                               height = width;
+                       }
                        if(current()==this)
                                glViewport(0, 0, width, height);
                        break;
@@ -113,7 +123,18 @@ void Framebuffer::attach(FramebufferAttachment attch, Texture2D &tex, unsigned l
                throw invalid_operation("Framebuffer::attach");
 
        unsigned i = get_attachment_index(attch);
-       attachments[i].set(tex, level);
+       attachments[i].set(tex, 0, level);
+       update_attachment(1<<i);
+       check_size();
+}
+
+void Framebuffer::attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level)
+{
+       if(!id)
+               throw invalid_operation("Framebuffer::attach");
+
+       unsigned i = get_attachment_index(attch);
+       attachments[i].set(tex, face, level);
        update_attachment(1<<i);
        check_size();
 }
@@ -230,10 +251,11 @@ void Framebuffer::Attachment::set(Renderbuffer &r)
        level = 0;
 }
 
-void Framebuffer::Attachment::set(Texture &t, unsigned l)
+void Framebuffer::Attachment::set(Texture &t, GLenum f, unsigned l)
 {
        type = t.get_target();
        tex = &t;
+       cube_face = f;
        level = l;
 }
 
index 3d3ec088138f9d4b50d675ead1d0b73807277212..e33deda9218d9bf3afea690b44fc1e9dd6329bc1 100644 (file)
@@ -4,6 +4,7 @@
 #include <vector>
 #include "bindable.h"
 #include "gl.h"
+#include "texturecube.h"
 
 namespace Msp {
 namespace GL {
@@ -80,10 +81,11 @@ private:
                        Texture *tex;
                };
                unsigned level;
+               GLenum cube_face;
 
                Attachment(FramebufferAttachment);
                void set(Renderbuffer &);
-               void set(Texture &, unsigned);
+               void set(Texture &, GLenum, unsigned);
                void clear();
        };
 
@@ -107,6 +109,7 @@ private:
 public:
        void attach(FramebufferAttachment attch, Renderbuffer &rbuf);
        void attach(FramebufferAttachment attch, Texture2D &tex, unsigned level = 0);
+       void attach(FramebufferAttachment attch, TextureCube &tex, TextureCubeFace face, unsigned level = 0);
        void detach(FramebufferAttachment attch);
 
        /**
diff --git a/source/texturecube.cpp b/source/texturecube.cpp
new file mode 100644 (file)
index 0000000..4a613a3
--- /dev/null
@@ -0,0 +1,82 @@
+#include "bindable.h"
+#include "error.h"
+#include "extension.h"
+#include "texturecube.h"
+
+using namespace std;
+
+namespace {
+
+// An array to facilitate looping through the cube faces
+Msp::GL::TextureCubeFace faces[6] =
+{
+       Msp::GL::POSITIVE_X,
+       Msp::GL::NEGATIVE_X,
+       Msp::GL::POSITIVE_Y,
+       Msp::GL::NEGATIVE_Y,
+       Msp::GL::POSITIVE_Z,
+       Msp::GL::NEGATIVE_Z
+};
+
+}
+
+
+namespace Msp {
+namespace GL {
+
+TextureCube::TextureCube():
+       Texture(GL_TEXTURE_CUBE_MAP),
+       size(0),
+       allocated(0)
+{
+       static RequireVersion _ver(1, 3);
+}
+
+void TextureCube::storage(PixelFormat fmt, unsigned sz)
+{
+       if(size>0)
+               throw invalid_operation("TextureCube::storage");
+       if(sz==0)
+               throw invalid_argument("TextureCube::storage");
+
+       ifmt = fmt;
+       size = sz;
+}
+
+void TextureCube::allocate(unsigned level)
+{
+       if(allocated&(1<<level))
+               return;
+
+       for(unsigned i=0; i<6; ++i)
+               image(faces[i], level, get_base_pixelformat(ifmt), UNSIGNED_BYTE, 0);
+}
+
+void TextureCube::image(TextureCubeFace face, unsigned level, PixelFormat fmt, DataType type, const void *data)
+{
+       if(size==0)
+               throw invalid_operation("TextureCube::image");
+
+       unsigned s = get_level_size(level);
+       if(s==0)
+               throw invalid_argument("TextureCube::image");
+
+       Bind _bind(this, true);
+       glTexImage2D(face, level, ifmt, s, s, 0, fmt, type, data);
+
+       // XXX Allocation should be tracked per-face, but we'll run out of bits
+       allocated |= 1<<level;
+       if(gen_mipmap && level==0)
+       {
+               for(; s; s>>=1, ++level) ;
+               allocated |= (1<<level)-1;
+       }
+}
+
+unsigned TextureCube::get_level_size(unsigned level)
+{
+       return size>>level;
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/texturecube.h b/source/texturecube.h
new file mode 100644 (file)
index 0000000..c8e18a1
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef MSP_GL_TEXTURECUBE_H_
+#define MSP_GL_TEXTURECUBE_H_
+
+#include "datatype.h"
+#include "pixelformat.h"
+#include "texture.h"
+
+namespace Msp {
+namespace GL {
+
+enum TextureCubeFace
+{
+       POSITIVE_X = GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+       NEGATIVE_X = GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+       POSITIVE_Y = GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+       NEGATIVE_Y = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+       POSITIVE_Z = GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+       NEGATIVE_Z = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+};
+
+/**
+Cube map texture, consisting of six square faces.  All of the faces must be of
+the same size.  A cube map texture is addressed by three-dimensional texture
+coordinates.  The face is first selected according to the largest coordinate,
+and the remaining two coordinates are used to sample the face image.
+
+All faces of a cube map texture must be allocated for it to be usable.
+
+Requires OpenGL version 1.3.
+*/
+class TextureCube: public Texture
+{
+private:
+       PixelFormat ifmt;
+       unsigned size;
+       unsigned allocated;
+
+public:
+       TextureCube();
+
+       /** Defines storage structure for the texture.  Must be called before an
+       image can be uploaded.  Once storage is defined, it can't be changed. */
+       void storage(PixelFormat fmt, unsigned size);
+
+       /** Allocates storage for the cube faces.  The contents are initially
+       undefined.  If storage has already been allocated, does nothing. */
+       void allocate(unsigned level);
+
+       /** Uploads image data to a face.  Storage must be defined beforehand.  The
+       image data must have dimensions and format compatible with the defined
+       storage. */
+       void image(TextureCubeFace face, unsigned level,
+               PixelFormat fmt, DataType type, const void *data);
+
+       /** Updates a rectangular region of a face.  Storage must be defined and
+       allocated beforehand.  The update region must be fully inside the texture.
+       The data format must be compatible with the defined storage. */
+       void sub_image(TextureCubeFace face, unsigned level,
+               int x, int y, unsigned w, unsigned h,
+               PixelFormat fmt, DataType type, const void *data);
+
+       unsigned get_size() const { return size; }
+private:
+       unsigned get_level_size(unsigned);
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif