]> git.tdb.fi Git - libs/gl.git/blob - source/core/texture3d.cpp
Add an srgb flag to pixelformat_from_image
[libs/gl.git] / source / core / texture3d.cpp
1 #include <cmath>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_texture_storage.h>
4 #include <msp/gl/extensions/ext_texture3d.h>
5 #include <msp/gl/extensions/ext_texture_array.h>
6 #include <msp/graphics/image.h>
7 #include "error.h"
8 #include "texture3d.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 Texture3D::Texture3D(GLenum t):
16         Texture(t),
17         width(0),
18         height(0),
19         depth(0)
20 { }
21
22 Texture3D::Texture3D():
23         Texture(GL_TEXTURE_3D),
24         width(0),
25         height(0),
26         depth(0)
27 {
28         static Require _req(EXT_texture3D);
29 }
30
31 void Texture3D::storage(PixelFormat fmt, unsigned wd, unsigned ht, unsigned dp, unsigned lv)
32 {
33         if(width>0)
34         {
35                 if(fmt!=format || wd!=width || ht!=height || dp!=depth || (lv && lv!=levels))
36                         throw incompatible_data("Texture3D::storage");
37                 return;
38         }
39         if(wd==0 || ht==0 || dp==0)
40                 throw invalid_argument("Texture3D::storage");
41
42         set_format(fmt);
43         width = wd;
44         height = ht;
45         depth = dp;
46         levels = get_n_levels();
47         if(lv>0)
48                 levels = min(levels, lv);
49
50         GLenum gl_fmt = get_gl_pixelformat(storage_fmt);
51         if(ARB_texture_storage)
52         {
53                 if(ARB_direct_state_access)
54                         glTextureStorage3D(id, levels, gl_fmt, width, height, depth);
55                 else
56                 {
57                         bind_scratch();
58                         glTexStorage3D(target, levels, gl_fmt, width, height, depth);
59                 }
60         }
61         else
62         {
63                 bind_scratch();
64                 GLenum comp = get_gl_components(get_components(storage_fmt));
65                 GLenum type = get_gl_type(get_component_type(storage_fmt));
66                 for(unsigned i=0; i<levels; ++i)
67                 {
68                         LinAl::Vector<unsigned, 3> lv_size = get_level_size(i);
69                         glTexImage3D(target, i, gl_fmt, lv_size.x, lv_size.y, lv_size.z, 0, comp, type, 0);
70                 }
71                 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
72         }
73
74         apply_swizzle();
75 }
76
77 void Texture3D::image(unsigned level, const void *data)
78 {
79         LinAl::Vector<unsigned, 3> size = get_level_size(level);
80         return sub_image(level, 0, 0, 0, size.x, size.y, size.z, data);
81 }
82
83 void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, const void *data)
84 {
85         if(width==0 || height==0 || depth==0)
86                 throw invalid_operation("Texture3D::sub_image");
87         if(level>=levels)
88                 throw out_of_range("Texture3D::sub_image");
89
90         GLenum comp = get_gl_components(get_components(storage_fmt));
91         GLenum type = get_gl_type(get_component_type(storage_fmt));
92         if(ARB_direct_state_access)
93                 glTextureSubImage3D(id, level, x, y, z, wd, ht, dp, comp, type, data);
94         else
95         {
96                 bind_scratch();
97                 glTexSubImage3D(target, level, x, y, z, wd, ht, dp, comp, type, data);
98         }
99 }
100
101 void Texture3D::image(const Graphics::Image &img, unsigned lv)
102 {
103         unsigned w = img.get_width();
104         unsigned h = img.get_height();
105
106         if(h%w)
107                 throw incompatible_data("Texture3D::load_image");
108         unsigned d = h/w;
109         h = w;
110
111         storage(pixelformat_from_image(img, use_srgb_format), w, h, d, lv);
112         image(0, img.get_pixels());
113 }
114
115 unsigned Texture3D::get_n_levels() const
116 {
117         unsigned s = max(width, height);
118         if(target!=GL_TEXTURE_2D_ARRAY)
119                 s = max(s, depth);
120         unsigned n = 0;
121         for(; s; s>>=1, ++n) ;
122         return n;
123 }
124
125 LinAl::Vector<unsigned, 3> Texture3D::get_level_size(unsigned level) const
126 {
127         unsigned w = width>>level;
128         unsigned h = height>>level;
129         unsigned d = depth;
130         if(target!=GL_TEXTURE_2D_ARRAY)
131                 d >>= level;
132
133         if(!w && (h || d))
134                 w = 1;
135         if(!h && (w || d))
136                 h = 1;
137         if(!d && (w || h))
138                 d = 1;
139
140         return LinAl::Vector<unsigned, 3>(w, h, d);
141 }
142
143 uint64_t Texture3D::get_data_size() const
144 {
145         return id ? width*height*depth*get_pixel_size(storage_fmt) : 0;
146 }
147
148
149 Texture3D::Loader::Loader(Texture3D &t):
150         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t)
151 {
152         init();
153 }
154
155 Texture3D::Loader::Loader(Texture3D &t, Collection &c):
156         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t, c)
157 {
158         init();
159 }
160
161 void Texture3D::Loader::init()
162 {
163         add("raw_data", &Loader::raw_data);
164         add("storage", &Loader::storage);
165         add("storage", &Loader::storage_levels);
166 }
167
168 void Texture3D::Loader::raw_data(const string &data)
169 {
170         obj.image(0, data.data());
171 }
172
173 void Texture3D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h, unsigned d)
174 {
175         obj.storage(fmt, w, h, d);
176 }
177
178 void Texture3D::Loader::storage_levels(PixelFormat fmt, unsigned w, unsigned h, unsigned d, unsigned l)
179 {
180         obj.storage(fmt, w, h, d, l);
181 }
182
183 } // namespace GL
184 } // namespace Msp