1 /// This module defines one texture type for each sort of OpenGL texture.
2 module gfm.opengl.texture;
3 
4 import std.string;
5 
6 import derelict.opengl3.gl3;
7 
8 import gfm.core.log,
9        gfm.opengl.opengl, 
10        gfm.opengl.textureunit;
11 
12 /// OpenGL Texture wrapper.
13 ///
14 /// TODO:
15 /// $(UL
16 ///     $(LI Support partial updates.)
17 ///     $(LI Support glStorage through pseudo-code given in OpenGL specification.)
18 ///  )
19 class GLTexture
20 {
21     public
22     {
23         /// Creates a texture. You should create a child class instead of calling
24         /// this constructor directly.
25         /// Throws: $(D OpenGLException) on error.
26         this(OpenGL gl, GLuint target)
27         {
28             _gl = gl;
29             _target = target;
30             glGenTextures(1, &_handle);
31             _gl.runtimeCheck();
32             _initialized = true;
33             _textureUnit = -1;
34         }
35 
36         ~this()
37         {
38             close();
39         }
40 
41          /// Releases the OpenGL texture resource.
42         final void close()
43         {
44             if (_initialized)
45             {
46                 _gl.textureUnits().forgetTexture(_handle);
47                 glDeleteTextures(1, &_handle);
48                 _initialized = false;
49             }
50         }
51 
52         /// Use this texture, binding it to a texture unit.
53         /// Params:
54         ///     textureUnit = Index of the texture unit to use.
55         final void use(int textureUnit = 0)
56         {
57             _gl.textureUnits().setActiveTexture(textureUnit);
58             bind();
59         }
60 
61         /// Unuse this texture.
62         final void unuse()
63         {
64           // do nothing: texture unit binding is as needed
65         }
66         
67         /// Returns: Requested texture parameter.
68         /// Throws: $(D OpenGLException) on error.
69         /// Warning: Calling $(D glGetTexParameteriv) is generally not recommended
70         ///          since it could stall the OpenGL pipeline.
71         final int getParam(GLenum paramName)
72         {
73             int res;
74             bind();
75             glGetTexParameteriv(_target, paramName, &res);
76             _gl.runtimeCheck();
77             return res;
78         }
79 
80         /// Returns: Requested texture level parameter.
81         /// Throws: $(D OpenGLException) on error.
82         /// Warning: Calling $(D glGetTexLevelParameteriv) is generally not recommended
83         ///          since it could stall the OpenGL pipeline.
84         final int getLevelParam(GLenum paramName, int level)
85         {
86             int res;
87             bind();
88             glGetTexLevelParameteriv(_target, level, paramName, &res);
89             _gl.runtimeCheck();
90             return res;
91         }
92 
93         /// Sets the texture base level.
94         /// Throws: $(D OpenGLException) on error.
95         final void setBaseLevel(int level)
96         {
97             bind();
98             glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, level);
99             _gl.runtimeCheck();
100         }
101 
102         /// Sets the texture maximum level.
103         /// Throws: $(D OpenGLException) on error.
104         final void setMaxLevel(int level)
105         {
106             bind();
107             glTexParameteri(_target, GL_TEXTURE_MAX_LEVEL, level);
108             _gl.runtimeCheck();
109         }
110 
111         // Texture "sampler" parameters which are now in Sampler Objects too
112         // but are also here for legacy cards.
113 
114         /// Sets the texture minimum LOD.
115         /// Throws: $(D OpenGLException) on error.
116         final void setMinLOD(float lod)
117         {
118             bind();
119             glTexParameterf(_target, GL_TEXTURE_MIN_LOD, lod);
120             _gl.runtimeCheck();
121         }
122 
123         /// Sets the texture maximum LOD.
124         /// Throws: $(D OpenGLException) on error.
125         final void setMaxLOD(float lod)
126         {
127             bind();
128             glTexParameterf(_target, GL_TEXTURE_MAX_LOD, lod);
129             _gl.runtimeCheck();
130         }
131 
132         /// Sets the texture LOD bias.
133         /// Throws: $(D OpenGLException) on error.
134         final void setLODBias(float lodBias)
135         {
136             bind();
137             glTexParameterf(_target, GL_TEXTURE_LOD_BIAS, lodBias);
138             _gl.runtimeCheck();
139         }
140 
141         /// Sets the wrap mode for 1st texture coordinate.
142         /// Throws: $(D OpenGLException) on error.
143         final void setWrapS(GLenum wrapS)
144         {
145             bind();
146             glTexParameteri(_target, GL_TEXTURE_WRAP_S, wrapS);
147             _gl.runtimeCheck();
148         }
149 
150         /// Sets the wrap mode for 2nd texture coordinate.
151         /// Throws: $(D OpenGLException) on error.
152         final void setWrapT(GLenum wrapT)
153         {
154             bind();
155             glTexParameteri(_target, GL_TEXTURE_WRAP_T, wrapT);
156             _gl.runtimeCheck();
157         }
158 
159         /// Sets the wrap mode for 3rd texture coordinate.
160         /// Throws: $(D OpenGLException) on error.
161         final void setWrapR(GLenum wrapR)
162         {
163             bind();
164             glTexParameteri(_target, GL_TEXTURE_WRAP_R, wrapR);
165             _gl.runtimeCheck();
166         }
167 
168         /// Sets the texture minification filter mode.
169         /// Throws: $(D OpenGLException) on error.
170         final void setMinFilter(GLenum minFilter)
171         {
172             bind();
173             glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, minFilter);
174             _gl.runtimeCheck();
175         }
176 
177         /// Sets the texture magnification filter mode.
178         /// Throws: $(D OpenGLException) on error.
179         final void setMagFilter(GLenum magFilter)
180         {
181             bind();
182             glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, magFilter);
183             _gl.runtimeCheck();
184         }
185 
186         /// Sets the texture anisotropic filter level.
187         /// If texture anisotropy isn't supported, fail silently.
188         /// Throws: $(D OpenGLException) on error.
189         final void setMaxAnisotropy(float f)
190         {
191             assert(f >= 1.0f);
192             if (!EXT_texture_filter_anisotropic())
193                 return;
194 
195             auto maxAniso = _gl.maxTextureMaxAnisotropy();
196 
197             if (f >= maxAniso)
198                 f = maxAniso;
199 
200             glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, f);
201             _gl.runtimeCheck();
202         }
203 
204         /// Gets the texture data.
205         /// Throws: $(D OpenGLException) on error.
206         final void getTexImage(int level, GLenum format, GLenum type, void* data)
207         {
208             bind();
209             glGetTexImage(_target, level, format, type, data);
210             _gl.runtimeCheck();
211         }
212 
213         /// Returns: Wrapped OpenGL resource handle.
214         GLuint handle() pure const nothrow
215         {
216           return _handle;
217         }
218 
219         GLuint target() pure const nothrow
220         {
221             return _target;
222         }
223 		
224         /// Regenerates the mipmapped levels.
225         /// Throws: $(D OpenGLException) on error.
226         void generateMipmap()
227         {
228             bind();
229             glGenerateMipmap(_target);
230             _gl.runtimeCheck();
231         }
232     }
233 
234     package
235     {
236         GLuint _target;
237     }
238 
239     private
240     {
241         OpenGL _gl;
242         GLuint _handle;
243         bool _initialized;
244         int _textureUnit;
245 
246         void bind()
247         {
248             // Bind on whatever the current texture unit is!
249             // consequently, do not ever change texture parameters if you want 
250             // to rely on a texture being bound to a texture unit
251             _gl.textureUnits().current().bind(_target, _handle);
252         }
253     }
254 }
255 
256 /// Wrapper for 1D texture.
257 final class GLTexture1D : GLTexture
258 {
259     public
260     {
261         /// Creates a 1D texture.
262         /// Throws: $(D OpenGLException) on error.
263         this(OpenGL gl)
264         {
265             super(gl, GL_TEXTURE_1D);
266         }
267 
268         /// Sets texture content.
269         /// Throws: $(D OpenGLException) on error.
270         void setImage(int level, GLint internalFormat, int width, int border, GLenum format, GLenum type, void* data)
271         {
272             glTexImage1D(_target, level, internalFormat, width, border, format, type, data);
273             _gl.runtimeCheck();
274         }
275     }
276 
277 }
278 
279 /// Wrapper for 2D texture.
280 final class GLTexture2D : GLTexture
281 {
282     public
283     {
284         /// Creates a 2D texture.
285         /// Throws: $(D OpenGLException) on error.
286         this(OpenGL gl)
287         {
288             super(gl, GL_TEXTURE_2D);
289         }
290 
291         /// Sets texture content.
292         /// Throws: $(D OpenGLException) on error.
293         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
294         {
295             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, data);
296             _gl.runtimeCheck();
297         }
298     }
299 
300 }
301 
302 /// Wrapper for 3D texture.
303 final class GLTexture3D : GLTexture
304 {
305     public
306     {
307         /// Creates a 3D texture.
308         /// Throws: $(D OpenGLException) on error.
309         this(OpenGL gl)
310         {
311             super(gl, GL_TEXTURE_3D);
312         }
313 
314         /// Sets texture content.
315         /// Throws: $(D OpenGLException) on error.
316         void setImage(int level, GLint internalFormat, int width, int height, int depth, int border, GLenum format, GLenum type, void* data)
317         {
318             glTexImage3D(_target, level, internalFormat, width, height, depth, border, format, type, data);
319             _gl.runtimeCheck();
320         }
321     }
322 }
323 
324 /// Wrapper for 1D texture array.
325 final class GLTexture1DArray : GLTexture
326 {
327     public
328     {
329         /// Creates a 1D texture array.
330         /// Throws: $(D OpenGLException) on error.
331         this(OpenGL gl)
332         {
333             super(gl, GL_TEXTURE_1D_ARRAY);
334         }
335 
336         /// Sets texture content.
337         /// Throws: $(D OpenGLException) on error.
338         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
339         {
340             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, null);
341             _gl.runtimeCheck();
342         }
343     }
344 }
345 
346 /// Wrapper for 2D texture array.
347 final class GLTexture2DArray : GLTexture
348 {
349     public
350     {
351         /// Creates a 2D texture array.
352         /// Throws: $(D OpenGLException) on error.
353         this(OpenGL gl)
354         {
355             super(gl, GL_TEXTURE_2D_ARRAY);
356         }
357 
358         /// Sets texture content.
359         /// Throws: $(D OpenGLException) on error.
360         void setImage(int level, GLint internalFormat, int width, int height, int depth, int border, GLenum format, GLenum type, void* data)
361         {
362             glTexImage3D(_target, level, internalFormat, width, height, depth, border, format, type, data);
363             _gl.runtimeCheck();
364         }
365 
366         /// Sets partial texture content.
367         /// Throws: $(D OpenGLException) on error.
368         void setSubImage(int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, GLenum format, GLenum type, void* data)
369         {
370             glTexSubImage3D(_target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
371             _gl.runtimeCheck();
372         }
373     }
374 }
375 
376 /// Wrapper for texture rectangle.
377 final class GLTextureRectangle : GLTexture
378 {
379     public
380     {
381         /// Creates a texture rectangle.
382         /// Throws: $(D OpenGLException) on error.        
383         this(OpenGL gl)
384         {
385             super(gl, GL_TEXTURE_RECTANGLE);
386         }
387 
388         /// Sets texture content.
389         /// Throws: $(D OpenGLException) on error.
390         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
391         {
392             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, null);
393             _gl.runtimeCheck();
394         }
395     }
396 }
397 
398 /// Wrapper for 2D multisampled texture.
399 final class GLTexture2DMultisample : GLTexture
400 {
401     public
402     {
403         /// Creates a 2D multisampled texture.
404         /// Throws: $(D OpenGLException) on error.
405         this(OpenGL gl)
406         {
407             super(gl, GL_TEXTURE_2D_MULTISAMPLE);
408         }
409 
410         /// Sets texture content.
411         /// Throws: $(D OpenGLException) on error.
412         void setImage(int level, int samples, GLint internalFormat, int width, int height, bool fixedsamplelocations)
413         {
414             glTexImage2DMultisample(_target, samples, internalFormat, width, height, fixedsamplelocations ? GL_TRUE : GL_FALSE);
415             _gl.runtimeCheck();
416         }
417     }
418 }
419 
420 /// Wrapper for 2D multisampled texture array.
421 final class GLTexture2DMultisampleArray : GLTexture
422 {
423     public
424     {
425         /// Creates a 2D multisampled texture array.
426         /// Throws: $(D OpenGLException) on error.
427         this(OpenGL gl)
428         {
429             super(gl, GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
430         }
431 
432         /// Sets texture content.
433         /// Throws: $(D OpenGLException) on error.
434         void setImage(int level, int samples, GLint internalFormat, int width, int height, int depth, bool fixedsamplelocations)
435         {
436             glTexImage3DMultisample(_target, samples, internalFormat, width, height, depth, fixedsamplelocations ? GL_TRUE : GL_FALSE);
437             _gl.runtimeCheck();
438         }
439     }
440 }
441 
442