+#include <msp/gl/extensions/arb_direct_state_access.h>
+#include <msp/gl/extensions/arb_seamless_cube_map.h>
+#include <msp/gl/extensions/arb_texture_cube_map.h>
+#include <msp/gl/extensions/arb_texture_storage.h>
+#include "gl.h"
+#include "texturecube.h"
+#include "texturecube_backend.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+OpenGLTextureCube::OpenGLTextureCube():
+ Texture(GL_TEXTURE_CUBE_MAP)
+{
+ static Require _req(ARB_texture_cube_map);
+ if(ARB_seamless_cube_map)
+ {
+ static bool seamless_init = false;
+ if(!seamless_init)
+ {
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ seamless_init = true;
+ }
+ }
+}
+
+void OpenGLTextureCube::allocate()
+{
+ unsigned size = static_cast<const TextureCube *>(this)->size;
+ unsigned levels = static_cast<const TextureCube *>(this)->levels;
+
+ GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
+ if(ARB_texture_storage)
+ {
+ if(ARB_direct_state_access)
+ glTextureStorage2D(id, levels, gl_fmt, size, size);
+ else
+ {
+ bind_scratch();
+ glTexStorage2D(target, levels, gl_fmt, size, size);
+ }
+ }
+ else
+ {
+ bind_scratch();
+ GLenum comp = get_gl_components(get_components(storage_fmt));
+ GLenum type = get_gl_type(get_component_type(storage_fmt));
+ for(unsigned i=0; i<levels; ++i)
+ {
+ unsigned lv_size = static_cast<const TextureCube *>(this)->get_level_size(i);
+ for(unsigned j=0; j<6; ++j)
+ glTexImage2D(get_gl_cube_face(j), i, gl_fmt, lv_size, lv_size, 0, comp, type, 0);
+ }
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
+ }
+
+ apply_swizzle();
+}
+
+void OpenGLTextureCube::sub_image(unsigned face, unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
+{
+ GLenum comp = get_gl_components(get_components(storage_fmt));
+ GLenum type = get_gl_type(get_component_type(storage_fmt));
+ if(ARB_direct_state_access)
+ glTextureSubImage3D(id, level, x, y, face, wd, ht, 1, comp, type, data);
+ else
+ {
+ bind_scratch();
+ glTexSubImage2D(get_gl_cube_face(face), level, x, y, wd, ht, comp, type, data);
+ }
+}
+
+unsigned get_gl_cube_face(unsigned face)
+{
+ switch(static_cast<TextureCubeFace>(face))
+ {
+ case POSITIVE_X: return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ case NEGATIVE_X: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
+ case POSITIVE_Y: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+ case NEGATIVE_Y: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ case POSITIVE_Z: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+ case NEGATIVE_Z: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ default: throw invalid_argument("get_gl_cube_face");
+ }
+}
+
+} // namespace GL
+} // namespace Msp