1 /*
2 Copyright (c) 2022 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 module dagon.graphics.texproc;
28 
29 import std.stdio;
30 
31 import dlib.core.memory;
32 import dlib.core.ownership;
33 import dlib.math.vector;
34 import dlib.math.matrix;
35 import dlib.math.transformation;
36 import dlib.image.color;
37 import dlib.text.str;
38 
39 import dagon.core.bindings;
40 import dagon.graphics.texture;
41 import dagon.graphics.shader;
42 import dagon.graphics.state;
43 import dagon.graphics.screensurface;
44 
45 class TextureCombinerShader: Shader
46 {
47     String vs, fs;
48     Texture[4] channels;
49     
50     this(Texture[4] channels, Owner owner)
51     {
52         vs = Shader.load("data/__internal/shaders/TextureCombiner/TextureCombiner.vert.glsl");
53         fs = Shader.load("data/__internal/shaders/TextureCombiner/TextureCombiner.frag.glsl");
54 
55         auto myProgram = New!ShaderProgram(vs, fs, this);
56         super(myProgram, owner);
57         
58         this.channels[] = channels[];
59     }
60     
61     ~this()
62     {
63         vs.free();
64         fs.free();
65     }
66     
67     override void bindParameters(GraphicsState* state)
68     {
69         // Channel0
70         glActiveTexture(GL_TEXTURE0);
71         setParameter("texChannel0", cast(int)0);
72         setParameter("valueChannel0", 0.0f);
73         if (channels[0])
74         {
75             channels[0].bind();
76             setParameterSubroutine("channel0", ShaderType.Fragment, "channel0Texture");
77         }
78         else
79         {
80             glBindTexture(GL_TEXTURE_2D, 0);
81             setParameterSubroutine("channel0", ShaderType.Fragment, "channel0Value");
82         }
83         
84         // Channel1
85         glActiveTexture(GL_TEXTURE1);
86         setParameter("texChannel1", cast(int)1);
87         setParameter("valueChannel1", 0.0f);
88         if (channels[1])
89         {
90             channels[1].bind();
91             setParameterSubroutine("channel1", ShaderType.Fragment, "channel1Texture");
92         }
93         else
94         {
95             glBindTexture(GL_TEXTURE_2D, 0);
96             setParameterSubroutine("channel1", ShaderType.Fragment, "channel1Value");
97         }
98         
99         // Channel2
100         glActiveTexture(GL_TEXTURE2);
101         setParameter("texChannel2", cast(int)2);
102         setParameter("valueChannel2", 0.0f);
103         if (channels[2])
104         {
105             channels[2].bind();
106             setParameterSubroutine("channel2", ShaderType.Fragment, "channel2Texture");
107         }
108         else
109         {
110             glBindTexture(GL_TEXTURE_2D, 0);
111             setParameterSubroutine("channel2", ShaderType.Fragment, "channel2Value");
112         }
113         
114         // Channel3
115         glActiveTexture(GL_TEXTURE3);
116         setParameter("texChannel3", cast(int)3);
117         setParameter("valueChannel3", 0.0f);
118         if (channels[3])
119         {
120             channels[3].bind();
121             setParameterSubroutine("channel3", ShaderType.Fragment, "channel3Texture");
122         }
123         else
124         {
125             glBindTexture(GL_TEXTURE_2D, 0);
126             setParameterSubroutine("channel3", ShaderType.Fragment, "channel3Value");
127         }
128         
129         glActiveTexture(GL_TEXTURE0);
130         
131         super.bindParameters(state);
132     }
133     
134     override void unbindParameters(GraphicsState* state)
135     {
136         super.unbindParameters(state);
137 
138         glActiveTexture(GL_TEXTURE0);
139         glBindTexture(GL_TEXTURE_2D, 0);
140 
141         glActiveTexture(GL_TEXTURE1);
142         glBindTexture(GL_TEXTURE_2D, 0);
143 
144         glActiveTexture(GL_TEXTURE2);
145         glBindTexture(GL_TEXTURE_2D, 0);
146 
147         glActiveTexture(GL_TEXTURE3);
148         glBindTexture(GL_TEXTURE_2D, 0);
149 
150         glActiveTexture(GL_TEXTURE0);
151     }
152 }
153 
154 /// Combine up to 4 textures to one
155 void combineTextures(Texture[4] channels, Texture output)
156 {
157     GLuint framebuffer;
158     glGenFramebuffers(1, &framebuffer);
159     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
160     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, output.texture, 0);
161     GLenum[1] drawBuffers = [GL_COLOR_ATTACHMENT0];
162     glDrawBuffers(drawBuffers.length, drawBuffers.ptr);
163     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
164     if (status != GL_FRAMEBUFFER_COMPLETE)
165     {
166         writeln(status);
167     }
168     
169     ScreenSurface screenSurface = New!ScreenSurface(null);
170     TextureCombinerShader shader = New!TextureCombinerShader(channels, null);
171     
172     GraphicsState state;
173     state.reset();
174     state.resolution = Vector2f(output.size.width, output.size.height);
175     
176     glScissor(0, 0, output.size.width, output.size.height);
177     glViewport(0, 0, output.size.width, output.size.height);
178     
179     glDisable(GL_DEPTH_TEST);
180     glDepthMask(GL_FALSE);
181     shader.bind();
182     shader.bindParameters(&state);
183     screenSurface.render(&state);
184     shader.unbindParameters(&state);
185     shader.unbind();
186     glDepthMask(GL_TRUE);
187     glEnable(GL_DEPTH_TEST);
188     
189     Delete(shader);
190     Delete(screenSurface);
191     
192     glBindFramebuffer(GL_FRAMEBUFFER, 0);
193     glDeleteFramebuffers(1, &framebuffer);
194 }
195 
196 /// ditto
197 Texture combineTextures(uint w, uint h, Texture[4] channels, Owner owner)
198 {
199     Texture output = New!Texture(owner);
200     output.createBlank(w, h, 4, 8, false, Color4f(0.0f, 0.0f, 0.0f, 1.0f));
201     combineTextures(channels, output);
202     output.generateMipmap();
203     return output;
204 }