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