1 /*
2 Copyright (c) 2017-2018 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.graphics.postproc;
29 
30 import std.stdio;
31 import std.conv;
32 
33 import dlib.math.vector;
34 
35 import dagon.core.libs;
36 import dagon.core.ownership;
37 import dagon.graphics.rc;
38 import dagon.graphics.framebuffer;
39 
40 class PostFilter: Owner
41 {
42     bool enabled = true;
43     Framebuffer inputBuffer;
44     Framebuffer outputBuffer;
45     
46     GLenum shaderVert;
47     GLenum shaderFrag;
48     GLenum shaderProgram;
49     
50     GLint modelViewMatrixLoc;
51     GLint prevModelViewProjMatrixLoc;
52     GLint projectionMatrixLoc;
53     GLint fbColorLoc;
54     GLint viewportSizeLoc;
55     GLint enabledLoc;
56     
57     private string vsText = 
58     q{
59         #version 330 core
60         
61         uniform mat4 modelViewMatrix;
62         uniform mat4 projectionMatrix;
63 
64         uniform vec2 viewSize;
65         
66         layout (location = 0) in vec2 va_Vertex;
67         layout (location = 1) in vec2 va_Texcoord;
68 
69         out vec2 texCoord;
70         
71         void main()
72         {
73             texCoord = va_Texcoord;
74             gl_Position = projectionMatrix * modelViewMatrix * vec4(va_Vertex * viewSize, 0.0, 1.0);
75         }
76     };
77     
78     private string fsText =
79     q{
80         #version 330 core
81         
82         uniform sampler2D fbColor;
83         uniform vec2 viewSize;
84 
85         in vec2 texCoord;
86         out vec4 frag_color;
87         
88         void main()
89         {
90             vec4 t = texture(fbColor, texCoord);
91             frag_color = t;
92             frag_color.a = 1.0;
93         }
94     };
95     
96     string vertexShader() {return vsText;}
97     string fragmentShader() {return fsText;}
98 
99     this(Framebuffer inputBuffer, Framebuffer outputBuffer, Owner o)
100     {
101         super(o);
102         
103         this.inputBuffer = inputBuffer;
104         this.outputBuffer = outputBuffer;
105         
106         const(char*)pvs = vertexShader().ptr;
107         const(char*)pfs = fragmentShader().ptr;
108         
109         char[1000] infobuffer = 0;
110         int infobufferlen = 0;
111 
112         shaderVert = glCreateShader(GL_VERTEX_SHADER);
113         glShaderSource(shaderVert, 1, &pvs, null);
114         glCompileShader(shaderVert);
115         GLint success = 0;
116         glGetShaderiv(shaderVert, GL_COMPILE_STATUS, &success);
117         if (!success)
118         {
119             GLint logSize = 0;
120             glGetShaderiv(shaderVert, GL_INFO_LOG_LENGTH, &logSize);
121             glGetShaderInfoLog(shaderVert, 999, &logSize, infobuffer.ptr);
122             writeln("Error in vertex shader:");
123             writeln(infobuffer[0..logSize]);
124         }
125 
126         shaderFrag = glCreateShader(GL_FRAGMENT_SHADER);
127         glShaderSource(shaderFrag, 1, &pfs, null);
128         glCompileShader(shaderFrag);
129         success = 0;
130         glGetShaderiv(shaderFrag, GL_COMPILE_STATUS, &success);
131         if (!success)
132         {
133             GLint logSize = 0;
134             glGetShaderiv(shaderFrag, GL_INFO_LOG_LENGTH, &logSize);
135             glGetShaderInfoLog(shaderFrag, 999, &logSize, infobuffer.ptr);
136             writeln("Error in fragment shader:");
137             writeln(infobuffer[0..logSize]);
138         }
139 
140         shaderProgram = glCreateProgram();
141         glAttachShader(shaderProgram, shaderVert);
142         glAttachShader(shaderProgram, shaderFrag);
143         glLinkProgram(shaderProgram);
144         
145         modelViewMatrixLoc = glGetUniformLocation(shaderProgram, "modelViewMatrix");
146         prevModelViewProjMatrixLoc = glGetUniformLocation(shaderProgram, "prevModelViewProjMatrix");
147         projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
148 
149         viewportSizeLoc = glGetUniformLocation(shaderProgram, "viewSize");
150         fbColorLoc = glGetUniformLocation(shaderProgram, "fbColor");
151         enabledLoc = glGetUniformLocation(shaderProgram, "enabled");
152     }
153     
154     void bind(RenderingContext* rc)
155     {
156         glUseProgram(shaderProgram);
157         
158         glUniformMatrix4fv(modelViewMatrixLoc, 1, 0, rc.viewMatrix.arrayof.ptr);
159         glUniformMatrix4fv(projectionMatrixLoc, 1, 0, rc.projectionMatrix.arrayof.ptr);
160         
161         glUniformMatrix4fv(prevModelViewProjMatrixLoc, 1, 0, rc.prevModelViewProjMatrix.arrayof.ptr);
162         
163         Vector2f viewportSize;
164         
165         auto colorTexture = inputBuffer.currentColorTexture;
166         
167         if (outputBuffer)
168             viewportSize = Vector2f(outputBuffer.width, outputBuffer.height);
169         else
170             viewportSize = Vector2f(rc.eventManager.windowWidth, rc.eventManager.windowHeight);
171         glUniform2fv(viewportSizeLoc, 1, viewportSize.arrayof.ptr);
172         
173         glActiveTexture(GL_TEXTURE0);
174         glBindTexture(GL_TEXTURE_2D, colorTexture);
175 
176         glUniform1i(fbColorLoc, 0);
177        
178         glUniform1i(enabledLoc, enabled);
179     }
180     
181     void unbind(RenderingContext* rc)
182     {
183         glActiveTexture(GL_TEXTURE0);
184         glBindTexture(GL_TEXTURE_2D, 0);
185         
186         glActiveTexture(GL_TEXTURE0);
187         
188         glUseProgram(0);
189     }
190     
191     void render(RenderingContext* rc)
192     {
193         bind(rc);
194         inputBuffer.render();
195         unbind(rc);
196     }
197 }