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.opengl.opengl;
9 
10 /// OpenGL Texture wrapper.
11 ///
12 /// TODO:
13 /// $(UL
14 ///     $(LI Support partial updates.)
15 ///     $(LI Support glStorage through pseudo-code given in OpenGL specification.)
16 ///  )
17 class GLTexture
18 {
19     public
20     {
21         /// Creates a texture. You should create a child class instead of calling
22         /// this constructor directly.
23         /// Throws: $(D OpenGLException) on error.
24         this(OpenGL gl, GLuint target)
25         {
26             _gl = gl;
27             _target = target;
28             glGenTextures(1, &_handle);
29             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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             _gl.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, f);
186             _gl.runtimeCheck();
187         }
188 
189         /// Gets the texture data.
190         /// Throws: $(D OpenGLException) on error.
191         final void getTexImage(int level, GLenum format, GLenum type, void* data)
192         {
193             bind();
194             glGetTexImage(_target, level, format, type, data);
195             _gl.runtimeCheck();
196         }
197 
198         /// Returns: Wrapped OpenGL resource handle.
199         GLuint handle() pure const nothrow
200         {
201           return _handle;
202         }
203 
204         GLuint target() pure const nothrow
205         {
206             return _target;
207         }
208 
209         /// Regenerates the mipmapped levels.
210         /// Throws: $(D OpenGLException) on error.
211         void generateMipmap()
212         {
213             bind();
214             glGenerateMipmap(_target);
215             _gl.runtimeCheck();
216         }
217     }
218 
219     package
220     {
221         GLuint _target;
222     }
223 
224     private
225     {
226         OpenGL _gl;
227         GLuint _handle;
228         bool _initialized;
229         int _textureUnit;
230 
231         void bind()
232         {
233             // Bind on whatever the current texture unit is!
234             glBindTexture(target, _handle);
235             _gl.runtimeCheck();
236         }
237     }
238 }
239 
240 /// Wrapper for 1D texture.
241 final class GLTexture1D : GLTexture
242 {
243     public
244     {
245         /// Creates a 1D texture.
246         /// Throws: $(D OpenGLException) on error.
247         this(OpenGL gl)
248         {
249             super(gl, GL_TEXTURE_1D);
250         }
251 
252         /// Sets texture content.
253         /// Throws: $(D OpenGLException) on error.
254         void setImage(int level, GLint internalFormat, int width, int border, GLenum format, GLenum type, void* data)
255         {
256             glTexImage1D(_target, level, internalFormat, width, border, format, type, data);
257             _gl.runtimeCheck();
258         }
259     }
260 
261 }
262 
263 /// Wrapper for 2D texture.
264 final class GLTexture2D : GLTexture
265 {
266     public
267     {
268         /// Creates a 2D texture.
269         /// Throws: $(D OpenGLException) on error.
270         this(OpenGL gl)
271         {
272             super(gl, GL_TEXTURE_2D);
273         }
274 
275         /// Sets texture content.
276         /// Throws: $(D OpenGLException) on error.
277         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
278         {
279             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, data);
280             _gl.runtimeCheck();
281         }
282     }
283 
284 }
285 
286 /// Wrapper for 3D texture.
287 final class GLTexture3D : GLTexture
288 {
289     public
290     {
291         /// Creates a 3D texture.
292         /// Throws: $(D OpenGLException) on error.
293         this(OpenGL gl)
294         {
295             super(gl, GL_TEXTURE_3D);
296         }
297 
298         /// Sets texture content.
299         /// Throws: $(D OpenGLException) on error.
300         void setImage(int level, GLint internalFormat, int width, int height, int depth, int border, GLenum format, GLenum type, void* data)
301         {
302             glTexImage3D(_target, level, internalFormat, width, height, depth, border, format, type, data);
303             _gl.runtimeCheck();
304         }
305     }
306 }
307 
308 /// Wrapper for 1D texture array.
309 final class GLTexture1DArray : GLTexture
310 {
311     public
312     {
313         /// Creates a 1D texture array.
314         /// Throws: $(D OpenGLException) on error.
315         this(OpenGL gl)
316         {
317             super(gl, GL_TEXTURE_1D_ARRAY);
318         }
319 
320         /// Sets texture content.
321         /// Throws: $(D OpenGLException) on error.
322         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
323         {
324             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, null);
325             _gl.runtimeCheck();
326         }
327     }
328 }
329 
330 /// Wrapper for 2D texture array.
331 final class GLTexture2DArray : GLTexture
332 {
333     public
334     {
335         /// Creates a 2D texture array.
336         /// Throws: $(D OpenGLException) on error.
337         this(OpenGL gl)
338         {
339             super(gl, GL_TEXTURE_2D_ARRAY);
340         }
341 
342         /// Sets texture content.
343         /// Throws: $(D OpenGLException) on error.
344         void setImage(int level, GLint internalFormat, int width, int height, int depth, int border, GLenum format, GLenum type, void* data)
345         {
346             glTexImage3D(_target, level, internalFormat, width, height, depth, border, format, type, data);
347             _gl.runtimeCheck();
348         }
349 
350         /// Sets partial texture content.
351         /// Throws: $(D OpenGLException) on error.
352         void setSubImage(int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, GLenum format, GLenum type, void* data)
353         {
354             glTexSubImage3D(_target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
355             _gl.runtimeCheck();
356         }
357     }
358 }
359 
360 /// Wrapper for texture rectangle.
361 final class GLTextureRectangle : GLTexture
362 {
363     public
364     {
365         /// Creates a texture rectangle.
366         /// Throws: $(D OpenGLException) on error.
367         this(OpenGL gl)
368         {
369             super(gl, GL_TEXTURE_RECTANGLE);
370         }
371 
372         /// Sets texture content.
373         /// Throws: $(D OpenGLException) on error.
374         void setImage(int level, GLint internalFormat, int width, int height, int border, GLenum format, GLenum type, void* data)
375         {
376             glTexImage2D(_target, level, internalFormat, width, height, border, format, type, null);
377             _gl.runtimeCheck();
378         }
379     }
380 }
381 
382 /// Wrapper for 2D multisampled texture.
383 final class GLTexture2DMultisample : GLTexture
384 {
385     public
386     {
387         /// Creates a 2D multisampled texture.
388         /// Throws: $(D OpenGLException) on error.
389         this(OpenGL gl)
390         {
391             super(gl, GL_TEXTURE_2D_MULTISAMPLE);
392         }
393 
394         /// Sets texture content.
395         /// Throws: $(D OpenGLException) on error.
396         void setImage(int level, int samples, GLint internalFormat, int width, int height, bool fixedsamplelocations)
397         {
398             glTexImage2DMultisample(_target, samples, internalFormat, width, height, fixedsamplelocations ? GL_TRUE : GL_FALSE);
399             _gl.runtimeCheck();
400         }
401     }
402 }
403 
404 /// Wrapper for 2D multisampled texture array.
405 final class GLTexture2DMultisampleArray : GLTexture
406 {
407     public
408     {
409         /// Creates a 2D multisampled texture array.
410         /// Throws: $(D OpenGLException) on error.
411         this(OpenGL gl)
412         {
413             super(gl, GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
414         }
415 
416         /// Sets texture content.
417         /// Throws: $(D OpenGLException) on error.
418         void setImage(int level, int samples, GLint internalFormat, int width, int height, int depth, bool fixedsamplelocations)
419         {
420             glTexImage3DMultisample(_target, samples, internalFormat, width, height, depth, fixedsamplelocations ? GL_TRUE : GL_FALSE);
421             _gl.runtimeCheck();
422         }
423     }
424 }
425 
426