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