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);
}
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;
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();
}
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;
}
#include <vector>
#include "bindable.h"
#include "gl.h"
+#include "texturecube.h"
namespace Msp {
namespace GL {
Texture *tex;
};
unsigned level;
+ GLenum cube_face;
Attachment(FramebufferAttachment);
void set(Renderbuffer &);
- void set(Texture &, unsigned);
+ void set(Texture &, GLenum, unsigned);
void clear();
};
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);
/**
--- /dev/null
+#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
--- /dev/null
+#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