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