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