1 /*
2 Copyright (c) 2019-2020 Timur Gafarov
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 Permission is hereby granted, free of charge, to any person or organization
6 obtaining a copy of the software and accompanying documentation covered by
7 this license (the "Software") to use, reproduce, display, distribute,
8 execute, and transmit the Software, and to prepare derivative works of the
9 Software, and to permit third-parties to whom the Software is furnished to
10 do so, all subject to the following:
11 
12 The copyright notices in the Software and this entire statement, including
13 the above license grant, this restriction and the following disclaimer,
14 must be included in all copies of the Software, in whole or in part, and
15 all derivative works of the Software, unless such copies or derivative
16 works are solely in the form of machine-executable object code generated by
17 a source language processor.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 */
27 
28 module dagon.render.framebuffer;
29 
30 import std.stdio;
31 import dlib.core.memory;
32 import dlib.core.ownership;
33 import dlib.image.color;
34 
35 import dagon.core.bindings;
36 
37 enum FrameBufferFormat
38 {
39     R8,
40     RGBA8,
41     RGBA16F
42 }
43 
44 class Framebuffer: Owner
45 {
46     uint width;
47     uint height;
48     FrameBufferFormat colorFormat;
49     bool hasDepthBuffer;
50     GLuint _colorTexture = 0;
51     GLuint _depthTexture = 0;
52     GLuint framebuffer;
53 
54     this(Owner owner)
55     {
56         super(owner);
57     }
58 
59     this(uint w, uint h, FrameBufferFormat format, bool depth, Owner owner)
60     {
61         super(owner);
62         init(w, h, format, depth);
63     }
64 
65     void init(uint w, uint h, FrameBufferFormat format, bool depth)
66     {
67         width = w;
68         height = h;
69         colorFormat = format;
70         hasDepthBuffer = depth;
71         createFramebuffer();
72     }
73 
74     ~this()
75     {
76         releaseFramebuffer();
77     }
78 
79     protected void createFramebuffer()
80     {
81         releaseFramebuffer();
82 
83         GLint intFormat;
84         GLenum textureFormat;
85         GLenum pixelType;
86 
87         switch (colorFormat)
88         {
89             case FrameBufferFormat.R8:      intFormat = GL_R8;      textureFormat = GL_RED;  pixelType = GL_UNSIGNED_BYTE; break;
90             case FrameBufferFormat.RGBA8:   intFormat = GL_RGBA8;   textureFormat = GL_RGBA; pixelType = GL_UNSIGNED_BYTE; break;
91             case FrameBufferFormat.RGBA16F: intFormat = GL_RGBA16F; textureFormat = GL_RGBA; pixelType = GL_FLOAT; break;
92             default: break;
93         }
94 
95         glActiveTexture(GL_TEXTURE0);
96 
97         glGenTextures(1, &_colorTexture);
98         glBindTexture(GL_TEXTURE_2D, _colorTexture);
99         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
100         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
101         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
102         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
103         glTexImage2D(GL_TEXTURE_2D, 0, intFormat, width, height, 0, textureFormat, pixelType, null);
104         glBindTexture(GL_TEXTURE_2D, 0);
105 
106         if (hasDepthBuffer)
107         {
108             glGenTextures(1, &_depthTexture);
109             glBindTexture(GL_TEXTURE_2D, _depthTexture);
110             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
111             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
112             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
113             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
114             glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, null);
115             glBindTexture(GL_TEXTURE_2D, 0);
116         }
117 
118         glGenFramebuffers(1, &framebuffer);
119         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
120         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorTexture, 0);
121         if (hasDepthBuffer)
122             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0);
123 
124         GLenum[1] drawBuffers = [GL_COLOR_ATTACHMENT0];
125         glDrawBuffers(drawBuffers.length, drawBuffers.ptr);
126 
127         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
128         if (status != GL_FRAMEBUFFER_COMPLETE)
129             writeln(status);
130 
131         glBindFramebuffer(GL_FRAMEBUFFER, 0);
132     }
133 
134     void releaseFramebuffer()
135     {
136         if (glIsFramebuffer(framebuffer))
137             glDeleteFramebuffers(1, &framebuffer);
138 
139         if (glIsTexture(_colorTexture))
140             glDeleteTextures(1, &_colorTexture);
141 
142         if (glIsTexture(_depthTexture))
143             glDeleteTextures(1, &_depthTexture);
144     }
145 
146     GLuint colorTexture()
147     {
148         return _colorTexture;
149     }
150 
151     GLuint depthTexture()
152     {
153         return _depthTexture;
154     }
155 
156     void bind()
157     {
158         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
159     }
160 
161     void unbind()
162     {
163         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
164     }
165 
166     void resize(uint w, uint h)
167     {
168         width = w;
169         height = h;
170         createFramebuffer();
171     }
172 
173     void blitColorBuffer()
174     {
175         glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
176         glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
177         glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
178     }
179 
180     void blitDepthBuffer()
181     {
182         if (hasDepthBuffer)
183         {
184             glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
185             glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
186             glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
187         }
188     }
189 }