1 #include <msp/datafile/collection.h>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_seamless_cube_map.h>
4 #include <msp/gl/extensions/arb_texture_cube_map.h>
5 #include <msp/gl/extensions/arb_texture_storage.h>
6 #include <msp/io/memory.h>
7 #include <msp/strings/format.h>
9 #include "texturecube.h"
16 TextureCubeFace TextureCube::face_order[6] =
26 Vector3 TextureCube::directions[6] =
36 unsigned TextureCube::orientations[12] =
46 TextureCube::TextureCube():
47 Texture(GL_TEXTURE_CUBE_MAP),
50 static Require _req(ARB_texture_cube_map);
51 if(ARB_seamless_cube_map)
52 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
55 void TextureCube::storage(PixelFormat fmt, unsigned sz, unsigned lv)
59 if(fmt!=format || sz!=size || (lv && lv!=levels))
60 throw incompatible_data("TextureCube::storage");
64 throw invalid_argument("TextureCube::storage");
68 levels = get_n_levels();
70 levels = min(levels, lv);
72 GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
73 if(ARB_texture_storage)
75 if(ARB_direct_state_access)
76 glTextureStorage2D(id, levels, gl_fmt, size, size);
80 glTexStorage2D(target, levels, gl_fmt, size, size);
86 GLenum comp = get_gl_components(get_components(storage_fmt));
87 GLenum type = get_gl_type(get_component_type(storage_fmt));
88 for(unsigned i=0; i<levels; ++i)
90 unsigned lv_size = get_level_size(i);
91 for(unsigned j=0; j<6; ++j)
92 glTexImage2D(enumerate_faces(j), i, gl_fmt, lv_size, lv_size, 0, comp, type, 0);
94 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
100 void TextureCube::image(TextureCubeFace face, unsigned level, const void *data)
102 unsigned lsz = get_level_size(level);
103 return sub_image(face, level, 0, 0, lsz, lsz, data);
106 void TextureCube::sub_image(TextureCubeFace face, unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
109 throw invalid_operation("TextureCube::sub_image");
111 throw out_of_range("TextureCube::sub_image");
113 GLenum comp = get_gl_components(get_components(storage_fmt));
114 GLenum type = get_gl_type(get_component_type(storage_fmt));
115 if(ARB_direct_state_access)
116 glTextureSubImage3D(id, level, x, y, get_face_index(face), wd, ht, 1, comp, type, data);
120 glTexSubImage2D(face, level, x, y, wd, ht, comp, type, data);
124 void TextureCube::image(TextureCubeFace face, const Graphics::Image &img)
126 unsigned w = img.get_width();
127 unsigned h = img.get_height();
129 throw incompatible_data("TextureCube::image");
131 PixelFormat fmt = pixelformat_from_image(img);
132 storage(make_pixelformat(get_components(fmt), get_component_type(fmt), use_srgb_format), w);
134 image(face, 0, img.get_pixels());
137 void TextureCube::image(const Graphics::Image &img, unsigned lv)
139 unsigned w = img.get_width();
140 unsigned h = img.get_height();
143 throw incompatible_data("TextureCube::image");
146 PixelFormat fmt = pixelformat_from_image(img);
148 storage(make_pixelformat(get_components(fmt), get_component_type(fmt), use_srgb_format), w, lv);
149 else if(w!=size || h!=size)
150 throw incompatible_data("TextureCube::image");
152 const char *pixels = reinterpret_cast<const char *>(img.get_pixels());
153 unsigned face_size = img.get_stride()*size;
154 for(unsigned i=0; i<6; ++i)
155 image(enumerate_faces(i), 0, pixels+i*face_size);
158 unsigned TextureCube::get_n_levels() const
161 for(unsigned s=size; s; s>>=1, ++n) ;
165 unsigned TextureCube::get_level_size(unsigned level) const
170 TextureCubeFace TextureCube::enumerate_faces(unsigned i)
173 throw out_of_range("TextureCube::enumerate_faces");
174 return face_order[i];
177 unsigned TextureCube::get_face_index(TextureCubeFace face)
181 case POSITIVE_X: return 0;
182 case NEGATIVE_X: return 1;
183 case POSITIVE_Y: return 2;
184 case NEGATIVE_Y: return 3;
185 case POSITIVE_Z: return 4;
186 case NEGATIVE_Z: return 5;
187 default: throw invalid_argument("TextureCube::get_face_index");
191 const Vector3 &TextureCube::get_face_direction(TextureCubeFace face)
193 return directions[get_face_index(face)];
196 const Vector3 &TextureCube::get_s_direction(TextureCubeFace face)
198 return directions[orientations[get_face_index(face)*2]];
201 const Vector3 &TextureCube::get_t_direction(TextureCubeFace face)
203 return directions[orientations[get_face_index(face)*2+1]];
206 Vector3 TextureCube::get_texel_direction(TextureCubeFace face, unsigned u, unsigned v)
208 float s = (u+0.5f)*2.0f/size-1.0f;
209 float t = (v+0.5f)*2.0f/size-1.0f;
210 const Vector3 &fv = get_face_direction(face);
211 const Vector3 &sv = get_s_direction(face);
212 const Vector3 &tv = get_t_direction(face);
216 uint64_t TextureCube::get_data_size() const
218 return id ? size*size*6*get_pixel_size(storage_fmt) : 0;
222 TextureCube::Loader::Loader(TextureCube &t):
223 DataFile::DerivedObjectLoader<TextureCube, Texture::Loader>(t)
228 TextureCube::Loader::Loader(TextureCube &t, Collection &c):
229 DataFile::DerivedObjectLoader<TextureCube, Texture::Loader>(t, c)
234 void TextureCube::Loader::init()
236 add("external_image", &Loader::external_image);
237 add("image_data", &Loader::image_data);
238 add("raw_data", &Loader::raw_data);
239 add("storage", &Loader::storage);
240 add("storage", &Loader::storage_levels);
243 void TextureCube::Loader::external_image(TextureCubeFace face, const string &fn)
246 RefPtr<IO::Seekable> io = get_collection().open_raw(fn);
249 obj.image(face, img);
252 void TextureCube::Loader::image_data(TextureCubeFace face, const string &data)
255 IO::Memory mem(data.data(), data.size());
258 obj.image(face, img);
261 void TextureCube::Loader::raw_data(TextureCubeFace face, const string &data)
263 obj.image(face, 0, data.data());
266 void TextureCube::Loader::storage(PixelFormat fmt, unsigned s)
271 void TextureCube::Loader::storage_levels(PixelFormat fmt, unsigned s, unsigned l)
273 obj.storage(fmt, s, l);
277 void operator>>(const LexicalConverter &conv, TextureCubeFace &face)
279 const string &str = conv.get();
280 if(str=="POSITIVE_X")
282 else if(str=="NEGATIVE_X")
284 else if(str=="POSITIVE_Y")
286 else if(str=="NEGATIVE_Y")
288 else if(str=="POSITIVE_Z")
290 else if(str=="NEGATIVE_Z")
293 throw lexical_error(format("conversion of '%s' to TextureCubeFace", str));