]> git.tdb.fi Git - libs/gl.git/blob - source/core/texture.cpp
Add support for integer vertex attributes
[libs/gl.git] / source / core / texture.cpp
1 #include <msp/gl/extensions/arb_direct_state_access.h>
2 #include <msp/gl/extensions/arb_texture_swizzle.h>
3 #include <msp/gl/extensions/ext_framebuffer_object.h>
4 #include <msp/gl/extensions/khr_debug.h>
5 #include <msp/io/memory.h>
6 #include "error.h"
7 #include "resourcemanager.h"
8 #include "resources.h"
9 #include "texture.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 int Texture::swizzle_orders[] =
17 {
18         GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA,
19         GL_RED, GL_RED, GL_RED, GL_ONE,
20         GL_RED, GL_RED, GL_RED, GL_GREEN,
21         GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA
22 };
23
24 Texture::Texture(GLenum t, ResourceManager *m):
25         id(0),
26         target(t),
27         format(RGB8),
28         storage_fmt(RGB8),
29         swizzle(NO_SWIZZLE),
30         use_srgb_format(false),
31         auto_gen_mipmap(false)
32 {
33         if(m)
34                 set_manager(m);
35         else
36                 generate_id();
37
38         static bool alignment_init = false;
39         if(!alignment_init)
40         {
41                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
42                 alignment_init = true;
43         }
44 }
45
46 Texture::~Texture()
47 {
48         if(id)
49                 glDeleteTextures(1, &id);
50 }
51
52 void Texture::generate_id()
53 {
54         if(id)
55                 throw invalid_operation("Texture::generate_id");
56         if(ARB_direct_state_access)
57                 glCreateTextures(target, 1, &id);
58         else
59                 glGenTextures(1, &id);
60
61 #ifdef DEBUG
62         if(!debug_name.empty() && KHR_debug)
63                 glObjectLabel(GL_TEXTURE, id, debug_name.size(), debug_name.c_str());
64 #endif
65 }
66
67 void Texture::set_format(PixelFormat fmt)
68 {
69         PixelComponents comp = get_components(fmt);
70         PixelComponents st_comp = comp;
71         FormatSwizzle swiz = NO_SWIZZLE;
72         switch(comp)
73         {
74         case LUMINANCE:
75                 st_comp = RED;
76                 swiz = R_TO_LUMINANCE;
77                 break;
78         case LUMINANCE_ALPHA:
79                 st_comp = RG;
80                 swiz = RG_TO_LUMINANCE_ALPHA;
81                 break;
82         case BGR:
83                 st_comp = RGB;
84                 swiz = RGB_TO_BGR;
85                 break;
86         case BGRA:
87                 st_comp = RGBA;
88                 swiz = RGB_TO_BGR;
89                 break;
90         default:;
91         }
92
93         PixelFormat st_fmt = make_pixelformat(st_comp, get_component_type(fmt), is_srgb(fmt));
94         require_pixelformat(st_fmt);
95         if(swiz!=NO_SWIZZLE)
96                 static Require _req(ARB_texture_swizzle);
97
98         format = fmt;
99         storage_fmt = st_fmt;
100         swizzle = swiz;
101 }
102
103 void Texture::apply_swizzle()
104 {
105         if(swizzle==NO_SWIZZLE)
106                 return;
107
108         if(get_gl_api()==OPENGL_ES2)
109         {
110                 set_parameter_i(GL_TEXTURE_SWIZZLE_R, swizzle_orders[swizzle*4]);
111                 set_parameter_i(GL_TEXTURE_SWIZZLE_G, swizzle_orders[swizzle*4+1]);
112                 set_parameter_i(GL_TEXTURE_SWIZZLE_B, swizzle_orders[swizzle*4+2]);
113                 set_parameter_i(GL_TEXTURE_SWIZZLE_A, swizzle_orders[swizzle*4+3]);
114         }
115         else
116         {
117                 if(ARB_direct_state_access)
118                         glTextureParameteriv(id, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
119                 else
120                         glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
121         }
122 }
123
124 void Texture::set_parameter_i(GLenum param, int value) const
125 {
126         if(ARB_direct_state_access)
127                 glTextureParameteri(id, param, value);
128         else
129                 glTexParameteri(target, param, value);
130 }
131
132 bool Texture::can_generate_mipmap()
133 {
134         return EXT_framebuffer_object;
135 }
136
137 void Texture::generate_mipmap()
138 {
139         // glGenerateMipmap is defined here
140         static Require _req(EXT_framebuffer_object);
141
142         if(!ARB_direct_state_access)
143         {
144                 glActiveTexture(GL_TEXTURE0);
145                 glBindTexture(target, id);
146         }
147         generate_mipmap_();
148         if(!ARB_direct_state_access)
149                 glBindTexture(target, 0);
150 }
151
152 void Texture::generate_mipmap_()
153 {
154         if(ARB_direct_state_access)
155                 glGenerateTextureMipmap(id);
156         else
157                 glGenerateMipmap(target);
158 }
159
160 void Texture::set_auto_generate_mipmap(bool gm)
161 {
162         if(gm)
163                 static Require _req(EXT_framebuffer_object);
164
165         auto_gen_mipmap = gm;
166 }
167
168 void Texture::load_image(const string &fn, bool)
169 {
170         load_image(fn, 0U);
171 }
172
173 void Texture::load_image(const string &fn, unsigned lv)
174 {
175         Graphics::Image img;
176         img.load_file(fn);
177
178         image(img, lv);
179 }
180
181 void Texture::image(const Graphics::Image &img, bool)
182 {
183         image(img, 0U);
184 }
185
186 void Texture::set_debug_name(const string &name)
187 {
188 #ifdef DEBUG
189         debug_name = name;
190         if(id && KHR_debug)
191                 glObjectLabel(GL_TEXTURE, id, name.size(), name.c_str());
192 #else
193         (void)name;
194 #endif
195 }
196
197
198 Texture::Loader::Loader(Texture &t):
199         DataFile::CollectionObjectLoader<Texture>(t, 0)
200 {
201         init();
202 }
203
204 Texture::Loader::Loader(Texture &t, Collection &c):
205         DataFile::CollectionObjectLoader<Texture>(t, &c)
206 {
207         init();
208 }
209
210 void Texture::Loader::init()
211 {
212         levels = 0;
213
214         add("external_image", &Loader::external_image);
215         add("external_image_srgb", &Loader::external_image_srgb);
216         add("generate_mipmap", &Loader::generate_mipmap);
217         add("image_data", &Loader::image_data);
218         add("mipmap_levels", &Loader::mipmap_levels);
219 }
220
221 void Texture::Loader::load_external_image(Graphics::Image &img, const string &fn)
222 {
223         RefPtr<IO::Seekable> io = get_collection().open_raw(fn);
224         if(!io)
225                 throw IO::file_not_found(fn);
226         img.load_io(*io);
227 }
228
229 void Texture::Loader::external_image(const string &fn)
230 {
231         obj.use_srgb_format = false;
232         external_image_common(fn);
233 }
234
235 void Texture::Loader::external_image_srgb(const string &fn)
236 {
237         obj.use_srgb_format = true;
238         external_image_common(fn);
239 }
240
241 void Texture::Loader::external_image_common(const string &fn)
242 {
243         if(obj.manager)
244                 obj.manager->set_resource_location(obj, get_collection(), fn);
245         else
246         {
247                 Graphics::Image img;
248                 load_external_image(img, fn);
249                 obj.image(img, levels);
250         }
251 }
252
253 void Texture::Loader::generate_mipmap(bool gm)
254 {
255         obj.set_auto_generate_mipmap(gm);
256 }
257
258 void Texture::Loader::image_data(const string &data)
259 {
260         if(obj.manager)
261         {
262                 obj.set_manager(0);
263                 if(!obj.id)
264                         obj.generate_id();
265         }
266
267         Graphics::Image img;
268         IO::Memory mem(data.data(), data.size());
269         img.load_io(mem);
270
271         obj.image(img, levels);
272 }
273
274 void Texture::Loader::mipmap_levels(unsigned l)
275 {
276         levels = l;
277 }
278
279 } // namespace GL
280 } // namespace Msp