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