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 }