1 module gfm.opengl.renderbuffer;
2 
3 import std.string;
4 
5 import derelict.opengl3.gl3;
6 
7 import gfm.core.log,
8        gfm.math.funcs,
9        gfm.opengl.opengl;
10 
11 /// OpenGL Renderbuffer wrapper.
12 final class GLRenderBuffer
13 {
14     public
15     {
16         /// <p>Creates an OpenGL renderbuffer.</p>
17         /// <p>If asking for a multisampled render buffer fails, 
18         /// a non multisampled buffer will be created instead.</p>
19         /// Throws: $(D OpenGLException) if creation failed.
20         this(OpenGL gl, GLenum internalFormat, int width, int height, int samples = 0)
21         {
22             _gl = gl;
23             glGenRenderbuffers(1, &_handle);
24             gl.runtimeCheck();
25             
26             use();
27             scope(exit) unuse();
28             if (samples > 1)
29             {
30                 // fallback to non multisampled
31                 if (glRenderbufferStorageMultisample is null)
32                 {
33                     gl._logger.warningf("render-buffer multisampling is not supported, fallback to non-multisampled");
34                     goto non_mutisampled;
35                 }
36                 
37                 int maxSamples;
38                 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
39                 if (maxSamples < 1)
40                     maxSamples = 1;
41 
42                 // limit samples to what is supported on this machine
43                 if (samples >= maxSamples)
44                 {
45                     int newSamples = clamp(samples, 0, maxSamples - 1);
46                     gl._logger.warningf(format("implementation does not support %s samples, fallback to %s samples", samples, newSamples));
47                     samples = newSamples;
48                 }
49 
50                 try
51                 {
52                     glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalFormat, width, height);
53                 }
54                 catch(OpenGLException e)
55                 {
56                     _gl._logger.warning(e.msg);
57                     goto non_mutisampled; // fallback to non multisampled
58                 }
59             }
60             else
61             {
62             non_mutisampled:
63                 glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height);
64                 gl.runtimeCheck();
65             }
66 
67             _initialized = true;
68         }
69 
70         ~this()
71         {
72             close();
73         }
74 
75         /// Releases the OpenGL renderbuffer resource.
76         void close()
77         {
78             if (_initialized)
79             {
80                 _initialized = false;
81                 glDeleteRenderbuffers(1, &_handle);
82             }
83         }
84 
85         /// Binds this renderbuffer.
86         /// Throws: $(D OpenGLException) on error.
87         void use()
88         {
89             glBindRenderbuffer(GL_RENDERBUFFER, _handle);
90             _gl.runtimeCheck();
91         }
92 
93         /// Unbinds this renderbuffer.
94         /// Throws: $(D OpenGLException) on error.
95         void unuse()
96         {
97             glBindRenderbuffer(GL_RENDERBUFFER, 0);
98             _gl.runtimeCheck();
99         }
100 
101         /// Returns: Wrapped OpenGL resource handle.
102         GLuint handle() pure const nothrow
103         {
104             return _handle;
105         }
106     }
107 
108     package
109     {
110         GLuint _handle;
111     }
112 
113     private
114     {
115         OpenGL _gl;
116         GLenum _format;
117         GLenum _type;
118         bool _initialized;
119     }
120 }