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