1 module gfm.opengl.textureunit; 2 3 import derelict.opengl3.gl3; 4 5 import gfm.core.log, 6 gfm.opengl.opengl; 7 8 /// Cache state of OpenGL texture units. 9 /// Use deprecated image units! 10 final class TextureUnits 11 { 12 public 13 { 14 /// Creates a TextureUnits object. 15 /// This is automatically done by loading OpenGL. 16 this(OpenGL gl) 17 { 18 _gl = gl; 19 _activeTexture = 0; // default is the first unit 0 20 21 // Use the max total image units 22 // Note: each shader stage has its own max to deal with 23 int units = gl.maxCombinedImageUnits(); 24 25 _textureUnits.length = units; 26 for (int i = 0; i < units; ++i) 27 _textureUnits[i] = new TextureUnit(gl, i); 28 } 29 30 /// Sets the "active texture" which is more precisely active texture unit. 31 /// Throws: $(D OpenGLException) on error. 32 void setActiveTexture(int texture) 33 { 34 if (_textureUnits.length == 1) 35 return; 36 37 if (glActiveTexture is null) 38 return; 39 40 glActiveTexture(GL_TEXTURE0 + texture); 41 _gl.runtimeCheck(); 42 _activeTexture = texture; 43 } 44 45 /// Gets texture unit i. 46 TextureUnit unit(int i) 47 { 48 return _textureUnits[i]; 49 } 50 51 /// Gets the active texture unit. 52 TextureUnit current() 53 { 54 return _textureUnits[_activeTexture]; 55 } 56 57 /// Clear state about a texture, called on deletion. 58 void forgetTexture(GLuint texture) 59 { 60 for (size_t i = 0; i < _textureUnits.length; ++i) 61 _textureUnits[i].forgetTexture(texture); 62 } 63 } 64 65 private 66 { 67 OpenGL _gl; 68 int _activeTexture; // index of currently active texture unit 69 TextureUnit[] _textureUnits; // all texture units 70 } 71 } 72 73 /// Cache state of a single OpenGL texture unit. 74 final class TextureUnit 75 { 76 public 77 { 78 enum UNKNOWN_BINDING = -1; 79 80 /// Binds this texture unit lazily. 81 /// Throws: $(D OpenGLException) on error. 82 void bind(GLenum target, GLuint texture) 83 { 84 size_t index = targetToIndex(cast(Target)target); 85 if(_currentBinding[index] != texture) 86 { 87 glBindTexture(target, texture); 88 _gl.runtimeCheck(); 89 _currentBinding[index] = texture; 90 } 91 } 92 } 93 94 private 95 { 96 this(OpenGL gl, int index) 97 { 98 _gl = gl; 99 _index = index; 100 101 _currentBinding[] = UNKNOWN_BINDING; // default is unknown 102 } 103 104 enum Target : GLenum 105 { 106 TEXTURE_1D = GL_TEXTURE_1D, 107 TEXTURE_2D = GL_TEXTURE_2D, 108 TEXTURE_3D = GL_TEXTURE_3D, 109 TEXTURE_1D_ARRAY = GL_TEXTURE_1D_ARRAY, 110 TEXTURE_2D_ARRAY = GL_TEXTURE_2D_ARRAY, 111 TEXTURE_RECTANGLE = GL_TEXTURE_RECTANGLE, 112 TEXTURE_BUFFER = GL_TEXTURE_BUFFER, 113 TEXTURE_CUBE_MAP = GL_TEXTURE_CUBE_MAP, 114 TEXTURE_CUBE_MAP_ARRAY = GL_TEXTURE_CUBE_MAP_ARRAY, 115 TEXTURE_2D_MULTISAMPLE = GL_TEXTURE_2D_MULTISAMPLE, 116 TEXTURE_2D_MULTISAMPLE_ARRAY = GL_TEXTURE_2D_MULTISAMPLE_ARRAY 117 } 118 119 size_t targetToIndex(Target target) 120 { 121 final switch(target) 122 { 123 case Target.TEXTURE_1D: return 0; 124 case Target.TEXTURE_2D: return 1; 125 case Target.TEXTURE_3D: return 2; 126 case Target.TEXTURE_1D_ARRAY: return 3; 127 case Target.TEXTURE_2D_ARRAY: return 4; 128 case Target.TEXTURE_RECTANGLE: return 5; 129 case Target.TEXTURE_BUFFER: return 6; 130 case Target.TEXTURE_CUBE_MAP: return 7; 131 case Target.TEXTURE_CUBE_MAP_ARRAY: return 8; 132 case Target.TEXTURE_2D_MULTISAMPLE: return 9; 133 case Target.TEXTURE_2D_MULTISAMPLE_ARRAY: return 10; 134 } 135 } 136 137 /// Clear state about a texture, called on texture deletion. 138 void forgetTexture(GLuint texture) 139 { 140 for (size_t i = 0; i < _currentBinding.length; ++i) 141 { 142 if (_currentBinding[i] == texture) 143 _currentBinding[i] = UNKNOWN_BINDING; 144 } 145 } 146 147 OpenGL _gl; 148 int _index; 149 150 GLuint[Target.max + 1] _currentBinding; 151 } 152 }