]> git.tdb.fi Git - libs/gl.git/blob - source/core/texture2d.cpp
Remove remaining deprecated things from the core classes
[libs/gl.git] / source / core / texture2d.cpp
1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_texture_storage.h>
3 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
4 #include <msp/graphics/imageloader.h>
5 #include "buffer.h"
6 #include "error.h"
7 #include "resources.h"
8 #include "texture2d.h"
9
10 using namespace std;
11
12 namespace Msp {
13 namespace GL {
14
15 class Texture2D::AsyncLoader: public Resource::AsyncLoader
16 {
17 private:
18         Texture2D &texture;
19         IO::Seekable &io;
20         Buffer pixel_buffer;
21         char *mapped_address;
22         Graphics::Image image;
23         Graphics::ImageLoader *img_loader;
24         unsigned n_bytes;
25         int phase;
26
27 public:
28         AsyncLoader(Texture2D &, IO::Seekable &);
29         ~AsyncLoader();
30
31         virtual bool needs_sync() const;
32         virtual bool process();
33 };
34
35
36 Texture2D::Texture2D(ResourceManager *m):
37         Texture(GL_TEXTURE_2D, m),
38         width(0),
39         height(0),
40         allocated(0)
41 { }
42
43 Texture2D::~Texture2D()
44 {
45         set_manager(0);
46 }
47
48 void Texture2D::storage(PixelFormat fmt, unsigned wd, unsigned ht, unsigned lv)
49 {
50         if(width>0)
51         {
52                 if(fmt!=format || wd!=width || ht!=height || (lv && lv!=levels))
53                         throw incompatible_data("Texture2D::storage");
54                 return;
55         }
56         if(wd==0 || ht==0)
57                 throw invalid_argument("Texture2D::storage");
58
59         set_format(fmt);
60         width = wd;
61         height = ht;
62         levels = get_n_levels();
63         if(lv>0)
64                 levels = min(levels, lv);
65 }
66
67 void Texture2D::allocate(unsigned level)
68 {
69         if(width==0 || height==0)
70                 throw invalid_operation("Texture2D::allocate");
71         if(level>=levels)
72                 throw invalid_argument("Texture2D::allocate");
73         if(allocated&(1<<level))
74                 return;
75
76         if(ARB_texture_storage)
77         {
78                 GLenum fmt = get_gl_pixelformat(storage_fmt);
79                 if(ARB_direct_state_access)
80                         glTextureStorage2D(id, levels, fmt, width, height);
81                 else
82                 {
83                         bind_scratch();
84                         glTexStorage2D(target, levels, fmt, width, height);
85                 }
86                 apply_swizzle();
87                 allocated |= (1<<levels)-1;
88         }
89         else
90                 image(level, 0);
91 }
92
93 void Texture2D::image(unsigned level, const void *data)
94 {
95         if(width==0 || height==0)
96                 throw invalid_operation("Texture2D::image");
97         if(level>=levels)
98                 throw out_of_range("Texture2D::image");
99
100         LinAl::Vector<unsigned, 2> size = get_level_size(level);
101
102         if(ARB_texture_storage)
103                 return sub_image(level, 0, 0, size.x, size.y, data);
104
105         bind_scratch();
106
107         if(!allocated)
108         {
109                 glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
110                 apply_swizzle();
111         }
112
113         GLenum fmt = get_gl_pixelformat(storage_fmt);
114         GLenum comp = get_gl_components(get_components(storage_fmt));
115         GLenum type = get_gl_type(get_component_type(storage_fmt));
116         glTexImage2D(target, level, fmt, size.x, size.y, 0, comp, type, data);
117
118         allocated |= 1<<level;
119 }
120
121 void Texture2D::sub_image(unsigned level, int x, int y, unsigned wd, unsigned ht, const void *data)
122 {
123         if(width==0 || height==0)
124                 throw invalid_operation("Texture2D::sub_image");
125         if(level>=levels)
126                 throw out_of_range("Texture2D::sub_image");
127
128         allocate(level);
129
130         GLenum comp = get_gl_components(get_components(storage_fmt));
131         GLenum type = get_gl_type(get_component_type(storage_fmt));
132         if(ARB_direct_state_access)
133                 glTextureSubImage2D(id, level, x, y, wd, ht, comp, type, data);
134         else
135         {
136                 bind_scratch();
137                 glTexSubImage2D(target, level, x, y, wd, ht, comp, type, data);
138         }
139 }
140
141 void Texture2D::image(const Graphics::Image &img, unsigned lv)
142 {
143         image(img, lv, false);
144 }
145
146 void Texture2D::image(const Graphics::Image &img, unsigned lv, bool from_buffer)
147 {
148         unsigned w = img.get_width();
149         unsigned h = img.get_height();
150         PixelFormat fmt = pixelformat_from_image(img);
151         storage(make_pixelformat(get_components(fmt), get_component_type(fmt), use_srgb_format), w, h, lv);
152
153         image(0, from_buffer ? 0 : img.get_pixels());
154 }
155
156 unsigned Texture2D::get_n_levels() const
157 {
158         unsigned n = 0;
159         for(unsigned s=max(width, height); s; s>>=1, ++n) ;
160         return n;
161 }
162
163 LinAl::Vector<unsigned, 2> Texture2D::get_level_size(unsigned level) const
164 {
165         unsigned w = width>>level;
166         unsigned h = height>>level;
167
168         if(!w && h)
169                 w = 1;
170         else if(!h && w)
171                 h = 1;
172
173         return LinAl::Vector<unsigned, 2>(w, h);
174 }
175
176 Resource::AsyncLoader *Texture2D::load(IO::Seekable &io, const Resources *)
177 {
178         AsyncLoader *ldr = new AsyncLoader(*this, io);
179         return ldr;
180 }
181
182 uint64_t Texture2D::get_data_size() const
183 {
184         return id ? width*height*get_pixel_size(format) : 0;
185 }
186
187 void Texture2D::unload()
188 {
189         glDeleteTextures(1, &id);
190         id = 0;
191         allocated = 0;
192 }
193
194
195 Texture2D::Loader::Loader(Texture2D &t):
196         DataFile::DerivedObjectLoader<Texture2D, Texture::Loader>(t)
197 {
198         init();
199 }
200
201 Texture2D::Loader::Loader(Texture2D &t, Collection &c):
202         DataFile::DerivedObjectLoader<Texture2D, Texture::Loader>(t, c)
203 {
204         init();
205 }
206
207 void Texture2D::Loader::init()
208 {
209         add("raw_data", &Loader::raw_data);
210         add("storage", &Loader::storage);
211         add("storage", &Loader::storage_levels);
212 }
213
214 void Texture2D::Loader::raw_data(const string &data)
215 {
216         if(obj.manager)
217         {
218                 obj.set_manager(0);
219                 if(!obj.id)
220                         obj.generate_id();
221         }
222         obj.image(0, data.data());
223 }
224
225 void Texture2D::Loader::storage(PixelFormat fmt, unsigned w, unsigned h)
226 {
227         obj.storage(fmt, w, h);
228 }
229
230 void Texture2D::Loader::storage_levels(PixelFormat fmt, unsigned w, unsigned h, unsigned l)
231 {
232         obj.storage(fmt, w, h, l);
233 }
234
235
236 Texture2D::AsyncLoader::AsyncLoader(Texture2D &t, IO::Seekable &i):
237         texture(t),
238         io(i),
239         mapped_address(0),
240         img_loader(Graphics::ImageLoader::open_io(io)),
241         phase(0)
242 { }
243
244 Texture2D::AsyncLoader::~AsyncLoader()
245 {
246         if(mapped_address)
247                 pixel_buffer.unmap();
248         delete img_loader;
249 }
250
251 bool Texture2D::AsyncLoader::needs_sync() const
252 {
253         return phase%2;
254 }
255
256 bool Texture2D::AsyncLoader::process()
257 {
258         if(phase==0)
259         {
260                 image.load_headers(*img_loader);
261                 n_bytes = image.get_stride()*image.get_height();
262         }
263         else if(phase==1)
264         {
265                 pixel_buffer.storage(n_bytes);
266                 mapped_address = reinterpret_cast<char *>(pixel_buffer.map());
267         }
268         else if(phase==2)
269                 image.load_into(*img_loader, mapped_address);
270         else if(phase==3)
271         {
272                 mapped_address = 0;
273                 if(!pixel_buffer.unmap())
274                 {
275                         phase = 1;
276                         return false;
277                 }
278
279                 if(!texture.id)
280                         texture.generate_id();
281                 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixel_buffer.get_id());
282                 texture.image(image, 0, true);
283                 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
284                 if(texture.auto_gen_mipmap)
285                         texture.generate_mipmap();
286         }
287
288         ++phase;
289         return phase>3;
290 }
291
292 } // namespace GL
293 } // namespace Msp