]> git.tdb.fi Git - libs/gl.git/blob - source/texture3d.cpp
Add some utility functions for textures
[libs/gl.git] / source / texture3d.cpp
1 #include <cmath>
2 #include <msp/gl/extensions/ext_texture3d.h>
3 #include <msp/graphics/image.h>
4 #include "bindable.h"
5 #include "error.h"
6 #include "pixelstore.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         ifmt(RGB),
17         width(0),
18         height(0),
19         depth(0),
20         allocated(0)
21 { }
22
23 Texture3D::Texture3D():
24         Texture(GL_TEXTURE_3D),
25         ifmt(RGB),
26         width(0),
27         height(0),
28         depth(0),
29         allocated(0)
30 {
31         static Require _req(EXT_texture3D);
32 }
33
34 void Texture3D::storage(PixelFormat fmt, unsigned wd, unsigned ht, unsigned dp)
35 {
36         if(width>0)
37                 throw invalid_operation("Texture3D::storage");
38         if(wd==0 || ht==0 || dp==0)
39                 throw invalid_argument("Texture3D::storage");
40
41         if(MSP_sized_internal_formats)
42                 fmt = get_sized_pixelformat(fmt);
43         require_pixelformat(fmt);
44
45         ifmt = fmt;
46         width = wd;
47         height = ht;
48         depth = dp;
49 }
50
51 void Texture3D::allocate(unsigned level)
52 {
53         if(allocated&(1<<level))
54                 return;
55
56         PixelFormat base_fmt = get_base_pixelformat(ifmt);
57         image(level, base_fmt, get_alloc_type(base_fmt), 0);
58 }
59
60 void Texture3D::image(unsigned level, PixelFormat fmt, DataType type, const void *data)
61 {
62         if(width==0 || height==0 || depth==0)
63                 throw invalid_operation("Texture3D::image");
64
65         unsigned w = width;
66         unsigned h = height;
67         unsigned d = depth;
68         get_level_size(level, w, h, d);
69
70         BindRestore _bind(this);
71         glTexImage3D(target, level, ifmt, width, height, depth, 0, fmt, type, data);
72
73         allocated |= 1<<level;
74         if(gen_mipmap && level==0)
75         {
76                 auto_generate_mipmap();
77                 allocated |= (1<<get_n_levels())-1;
78         }
79 }
80
81 void Texture3D::sub_image(unsigned level, int x, int y, int z, unsigned wd, unsigned ht, unsigned dp, PixelFormat fmt, DataType type, const void *data)
82 {
83         if(width==0 || height==0 || depth==0)
84                 throw invalid_operation("Texture3D::image");
85
86         allocate(level);
87
88         BindRestore _bind(this);
89         glTexSubImage3D(target, level, x, y, z, wd, ht, dp, fmt, type, data);
90 }
91
92 void Texture3D::load_image(const string &fn, int dp)
93 {
94         Graphics::Image img;
95         img.load_file(fn);
96
97         unsigned w = img.get_width();
98         unsigned h = img.get_height();
99         unsigned d = 1;
100
101         if(dp==-1)
102         {
103                 if(h%w)
104                         throw incompatible_data("Texture3D::load_image");
105                 d = h/w;
106                 h = w;
107         }
108         else if(dp==-2)
109         {
110                 for(d=h; d*d>h; d>>=2) ;
111                 for(; d*d<h; ++d) ;
112                 if(d*d!=h)
113                         throw incompatible_data("Texture3D::load_image");
114                 h = d;
115         }
116         else if(dp>0)
117         {
118                 d = dp;
119                 if(h%d)
120                         throw incompatible_data("Texture3D::load_image");
121                 h /= d;
122         }
123         else
124                 throw invalid_argument("Texture3D::load_image");
125
126         PixelFormat fmt = pixelformat_from_graphics(img.get_format());
127         if(width==0)
128                 storage(storage_pixelformat_from_graphics(img.get_format()), w, h, d);
129         else if(w!=width || h!=height || d!=depth)
130                 throw incompatible_data("Texture3D::load_image");
131
132         PixelStore pstore = PixelStore::from_image(img);
133         BindRestore _bind_ps(pstore);
134
135         image(0, fmt, UNSIGNED_BYTE, img.get_data());
136 }
137
138 void Texture3D::image(const Graphics::Image &img, bool srgb)
139 {
140         unsigned w = img.get_width();
141         unsigned h = img.get_height();
142         unsigned d = 1;
143
144         if(depth)
145         {
146                 if(h%depth)
147                         throw incompatible_data("Texture3D::load_image");
148                 h /= depth;
149                 d = depth;
150         }
151         else
152         {
153                 if(h%w)
154                         throw incompatible_data("Texture3D::load_image");
155                 d = h/w;
156                 h = w;
157         }
158
159         PixelFormat fmt = pixelformat_from_graphics(img.get_format());
160         if(width==0)
161                 storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, h, d);
162         else if(w!=width || h!=height || d!=depth)
163                 throw incompatible_data("Texture3D::load_image");
164
165         PixelStore pstore = PixelStore::from_image(img);
166         BindRestore _bind_ps(pstore);
167
168         image(0, fmt, UNSIGNED_BYTE, img.get_data());
169 }
170
171 unsigned Texture3D::get_n_levels() const
172 {
173         unsigned s = max(width, height);
174         if(target!=GL_TEXTURE_2D_ARRAY)
175                 s = max(s, depth);
176         unsigned n = 0;
177         for(; s; s>>=1, ++n) ;
178         return n;
179 }
180
181 void Texture3D::get_level_size(unsigned level, unsigned &w, unsigned &h, unsigned &d) const
182 {
183         w >>= level;
184         h >>= level;
185         if(target!=GL_TEXTURE_2D_ARRAY)
186                 d >>= level;
187
188         if(!w && (h || d))
189                 w = 1;
190         if(!h && (w || d))
191                 h = 1;
192         if(!d && (w || h))
193                 d = 1;
194 }
195
196 UInt64 Texture3D::get_data_size() const
197 {
198         return id ? width*height*depth*get_pixel_size(ifmt) : 0;
199 }
200
201
202 Texture3D::Loader::Loader(Texture3D &t):
203         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t)
204 {
205         init();
206 }
207
208 Texture3D::Loader::Loader(Texture3D &t, Collection &c):
209         DataFile::DerivedObjectLoader<Texture3D, Texture::Loader>(t, c)
210 {
211         init();
212 }
213
214 void Texture3D::Loader::init()
215 {
216         add("raw_data", &Loader::raw_data);
217         add("storage", &Loader::storage);
218 }
219
220 void Texture3D::Loader::raw_data(const string &data)
221 {
222         obj.image(0, get_base_pixelformat(obj.ifmt), UNSIGNED_BYTE, data.data());
223 }
224
225 void Texture3D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h, unsigned d)
226 {
227         if(srgb)
228                 fmt = get_srgb_pixelformat(fmt);
229         obj.storage(fmt, w, h, d);
230 }
231
232 } // namespace GL
233 } // namespace Msp