1 /* 2 Copyright (c) 2019 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.shaders.decal; 29 30 import std.stdio; 31 import std.math; 32 33 import dlib.core.memory; 34 import dlib.math.vector; 35 import dlib.math.matrix; 36 import dlib.math.transformation; 37 import dlib.image.color; 38 39 import dagon.core.libs; 40 import dagon.core.ownership; 41 import dagon.graphics.rc; 42 import dagon.graphics.shader; 43 import dagon.graphics.gbuffer; 44 import dagon.graphics.material; 45 46 class DecalShader: Shader 47 { 48 string vs = import("Decal.vs"); 49 string fs = import("Decal.fs"); 50 51 GBuffer gbuffer; 52 53 this(GBuffer gbuffer, Owner o) 54 { 55 auto myProgram = New!ShaderProgram(vs, fs, this); 56 super(myProgram, o); 57 this.gbuffer = gbuffer; 58 } 59 60 override void bind(RenderingContext* rc) 61 { 62 auto idiffuse = "diffuse" in rc.material.inputs; 63 auto inormal = "normal" in rc.material.inputs; 64 auto iheight = "height" in rc.material.inputs; 65 auto iparallax = "parallax" in rc.material.inputs; 66 auto ipbr = "pbr" in rc.material.inputs; 67 auto iroughness = "roughness" in rc.material.inputs; 68 auto imetallic = "metallic" in rc.material.inputs; 69 auto iemission = "emission" in rc.material.inputs; 70 auto ienergy = "energy" in rc.material.inputs; 71 auto ioutputColor = "outputColor" in rc.material.inputs; 72 auto ioutputNormal = "outputNormal" in rc.material.inputs; 73 auto ioutputPBR = "outputPBR" in rc.material.inputs; 74 auto ioutputEmission = "outputEmission" in rc.material.inputs; 75 76 int parallaxMethod = iparallax.asInteger; 77 if (parallaxMethod > ParallaxOcclusionMapping) 78 parallaxMethod = ParallaxOcclusionMapping; 79 if (parallaxMethod < 0) 80 parallaxMethod = 0; 81 82 //setParameter("viewMatrix", rc.viewMatrix); 83 setParameter("modelViewMatrix", rc.modelViewMatrix); 84 setParameter("projectionMatrix", rc.projectionMatrix); 85 setParameter("invViewMatrix", rc.invViewMatrix); 86 setParameter("invModelMatrix", rc.invModelMatrix); 87 setParameter("viewSize", Vector2f(gbuffer.width, gbuffer.height)); 88 89 glActiveTexture(GL_TEXTURE0); 90 glBindTexture(GL_TEXTURE_2D, gbuffer.positionTexture); 91 setParameter("positionTexture", cast(int)0); 92 93 // Diffuse 94 if (idiffuse.texture) 95 { 96 glActiveTexture(GL_TEXTURE1); 97 idiffuse.texture.bind(); 98 setParameter("diffuseTexture", cast(int)1); 99 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture"); 100 } 101 else 102 { 103 setParameter("diffuseVector", rc.material.diffuse.asVector4f); 104 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue"); 105 } 106 107 if (!ioutputColor.asBool) 108 { 109 glColorMaski(0, 0, 0, 0, 0); 110 } 111 112 // Normal/height 113 bool haveHeightMap = inormal.texture !is null; 114 if (haveHeightMap) 115 haveHeightMap = inormal.texture.image.channels == 4; 116 117 if (!haveHeightMap) 118 { 119 if (inormal.texture is null) 120 { 121 if (iheight.texture !is null) // we have height map, but no normal map 122 { 123 Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards 124 inormal.texture = rc.material.makeTexture(color, iheight.texture); 125 haveHeightMap = true; 126 } 127 } 128 else 129 { 130 if (iheight.texture !is null) // we have both normal and height maps 131 { 132 inormal.texture = rc.material.makeTexture(inormal.texture, iheight.texture); 133 haveHeightMap = true; 134 } 135 } 136 } 137 138 if (inormal.texture) 139 { 140 setParameter("normalTexture", cast(int)2); 141 setParameterSubroutine("normal", ShaderType.Fragment, "normalMap"); 142 143 glActiveTexture(GL_TEXTURE2); 144 inormal.texture.bind(); 145 } 146 else 147 { 148 setParameter("normalVector", rc.material.normal.asVector3f); 149 setParameterSubroutine("normal", ShaderType.Fragment, "normalValue"); 150 } 151 152 if (!ioutputNormal.asBool) 153 { 154 glColorMaski(2, 0, 0, 0, 0); 155 } 156 157 // Height and parallax 158 159 // TODO: make these material properties 160 float parallaxScale = 0.03f; 161 float parallaxBias = -0.01f; 162 setParameter("parallaxScale", parallaxScale); 163 setParameter("parallaxBias", parallaxBias); 164 165 if (haveHeightMap) 166 { 167 setParameterSubroutine("height", ShaderType.Fragment, "heightMap"); 168 } 169 else 170 { 171 float h = 0.0f; //-parallaxBias / parallaxScale; 172 setParameter("heightScalar", h); 173 setParameterSubroutine("height", ShaderType.Fragment, "heightValue"); 174 parallaxMethod = ParallaxNone; 175 } 176 177 if (parallaxMethod == ParallaxSimple) 178 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple"); 179 else if (parallaxMethod == ParallaxOcclusionMapping) 180 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping"); 181 else 182 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone"); 183 184 // PBR 185 // TODO: pass solid values as uniforms, make subroutine for each mode 186 if (ipbr is null) 187 { 188 rc.material.setInput("pbr", 0.0f); 189 ipbr = "pbr" in rc.material.inputs; 190 } 191 192 if (ipbr.texture is null) 193 ipbr.texture = rc.material.makeTexture(*iroughness, *imetallic, materialInput(0.0f), materialInput(0.0f)); 194 glActiveTexture(GL_TEXTURE3); 195 ipbr.texture.bind(); 196 setParameter("pbrTexture", 3); 197 198 if (!ioutputPBR.asBool) 199 { 200 glColorMaski(1, 0, 0, 0, 0); 201 } 202 203 // Emission 204 if (iemission.texture) 205 { 206 glActiveTexture(GL_TEXTURE4); 207 iemission.texture.bind(); 208 209 setParameter("emissionTexture", 4); 210 setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap"); 211 } 212 else 213 { 214 setParameter("emissionVector", rc.material.emission.asVector4f); 215 setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue"); 216 } 217 218 setParameter("emissionEnergy", ienergy.asFloat); 219 220 if (!ioutputEmission.asBool) 221 { 222 glColorMaski(3, 0, 0, 0, 0); 223 } 224 225 glActiveTexture(GL_TEXTURE0); 226 227 super.bind(rc); 228 } 229 230 override void unbind(RenderingContext* rc) 231 { 232 super.unbind(rc); 233 234 glColorMaski(0, 1, 1, 1, 1); 235 glColorMaski(1, 1, 1, 1, 1); 236 glColorMaski(2, 1, 1, 1, 1); 237 glColorMaski(3, 1, 1, 1, 1); 238 239 glActiveTexture(GL_TEXTURE0); 240 glBindTexture(GL_TEXTURE_2D, 0); 241 242 glActiveTexture(GL_TEXTURE1); 243 glBindTexture(GL_TEXTURE_2D, 0); 244 245 glActiveTexture(GL_TEXTURE2); 246 glBindTexture(GL_TEXTURE_2D, 0); 247 248 glActiveTexture(GL_TEXTURE3); 249 glBindTexture(GL_TEXTURE_2D, 0); 250 251 glActiveTexture(GL_TEXTURE4); 252 glBindTexture(GL_TEXTURE_2D, 0); 253 254 glActiveTexture(GL_TEXTURE0); 255 } 256 }