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.render.shaders.decal; 29 30 import std.stdio; 31 import std.math; 32 33 import dlib.core.memory; 34 import dlib.core.ownership; 35 import dlib.math.vector; 36 import dlib.math.matrix; 37 import dlib.math.transformation; 38 import dlib.math.interpolation; 39 import dlib.image.color; 40 import dlib.text.str; 41 42 import dagon.core.bindings; 43 import dagon.graphics.material; 44 import dagon.graphics.shader; 45 import dagon.graphics.state; 46 import dagon.render.gbuffer; 47 48 class DecalShader: Shader 49 { 50 String vs, fs; 51 52 GBuffer gbuffer; 53 54 this(GBuffer gbuffer, Owner owner) 55 { 56 vs = Shader.load("data/__internal/shaders/Decal/Decal.vert.glsl"); 57 fs = Shader.load("data/__internal/shaders/Decal/Decal.frag.glsl"); 58 59 auto prog = New!ShaderProgram(vs, fs, this); 60 super(prog, owner); 61 62 this.gbuffer = gbuffer; 63 } 64 65 ~this() 66 { 67 vs.free(); 68 fs.free(); 69 } 70 71 override void bindParameters(GraphicsState* state) 72 { 73 auto idiffuse = "diffuse" in state.material.inputs; 74 auto inormal = "normal" in state.material.inputs; 75 auto iheight = "height" in state.material.inputs; 76 auto iparallax = "parallax" in state.material.inputs; 77 auto ipbr = "pbr" in state.material.inputs; 78 auto iroughness = "roughness" in state.material.inputs; 79 auto imetallic = "metallic" in state.material.inputs; 80 auto ispecularity = "specularity" in state.material.inputs; 81 auto itextureScale = "textureScale" in state.material.inputs; 82 auto iemission = "emission" in state.material.inputs; 83 auto ienergy = "energy" in state.material.inputs; 84 auto ioutputColor = "outputColor" in state.material.inputs; 85 auto ioutputNormal = "outputNormal" in state.material.inputs; 86 auto ioutputPBR = "outputPBR" in state.material.inputs; 87 auto ioutputEmission = "outputEmission" in state.material.inputs; 88 89 int parallaxMethod = iparallax.asInteger; 90 if (parallaxMethod > ParallaxOcclusionMapping) 91 parallaxMethod = ParallaxOcclusionMapping; 92 if (parallaxMethod < 0) 93 parallaxMethod = 0; 94 95 setParameter("modelViewMatrix", state.modelViewMatrix); 96 setParameter("projectionMatrix", state.projectionMatrix); 97 setParameter("invProjectionMatrix", state.invProjectionMatrix); 98 setParameter("normalMatrix", state.normalMatrix); 99 setParameter("viewMatrix", state.viewMatrix); 100 setParameter("invViewMatrix", state.invViewMatrix); 101 setParameter("invModelMatrix", state.invModelMatrix); 102 setParameter("resolution", state.resolution); 103 104 setParameter("opacity", state.opacity); 105 setParameter("textureScale", itextureScale.asVector2f); 106 107 glActiveTexture(GL_TEXTURE0); 108 glBindTexture(GL_TEXTURE_2D, gbuffer.depthTexture); 109 setParameter("depthTexture", cast(int)0); 110 111 // Diffuse 112 if (idiffuse.texture) 113 { 114 glActiveTexture(GL_TEXTURE1); 115 idiffuse.texture.bind(); 116 setParameter("diffuseTexture", cast(int)1); 117 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorTexture"); 118 } 119 else 120 { 121 setParameter("diffuseVector", idiffuse.asVector4f); 122 setParameterSubroutine("diffuse", ShaderType.Fragment, "diffuseColorValue"); 123 } 124 125 if (!ioutputColor.asBool) 126 { 127 glColorMaski(0, 0, 0, 0, 0); 128 } 129 130 // Normal/height 131 bool haveHeightMap = inormal.texture !is null; 132 if (haveHeightMap) 133 haveHeightMap = inormal.texture.image.channels == 4; 134 135 if (!haveHeightMap) 136 { 137 if (inormal.texture is null) 138 { 139 if (iheight.texture !is null) // we have height map, but no normal map 140 { 141 Color4f color = Color4f(0.5f, 0.5f, 1.0f, 0.0f); // default normal pointing upwards 142 inormal.texture = state.material.makeTexture(color, iheight.texture); 143 haveHeightMap = true; 144 } 145 } 146 else 147 { 148 if (iheight.texture !is null) // we have both normal and height maps 149 { 150 inormal.texture = state.material.makeTexture(inormal.texture, iheight.texture); 151 haveHeightMap = true; 152 } 153 } 154 } 155 156 if (inormal.texture) 157 { 158 setParameter("normalTexture", 2); 159 setParameterSubroutine("normal", ShaderType.Fragment, "normalMap"); 160 161 glActiveTexture(GL_TEXTURE2); 162 inormal.texture.bind(); 163 } 164 else 165 { 166 setParameter("normalVector", state.material.normal.asVector3f); 167 setParameterSubroutine("normal", ShaderType.Fragment, "normalValue"); 168 } 169 170 if (!ioutputNormal.asBool) 171 { 172 glColorMaski(1, 0, 0, 0, 0); 173 } 174 175 // Height and parallax 176 // TODO: make these material properties 177 float parallaxScale = 0.03f; 178 float parallaxBias = -0.01f; 179 setParameter("parallaxScale", parallaxScale); 180 setParameter("parallaxBias", parallaxBias); 181 182 if (haveHeightMap) 183 { 184 setParameterSubroutine("height", ShaderType.Fragment, "heightMap"); 185 } 186 else 187 { 188 float h = 0.0f; //-parallaxBias / parallaxScale; 189 setParameter("heightScalar", h); 190 setParameterSubroutine("height", ShaderType.Fragment, "heightValue"); 191 parallaxMethod = ParallaxNone; 192 } 193 194 if (parallaxMethod == ParallaxSimple) 195 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxSimple"); 196 else if (parallaxMethod == ParallaxOcclusionMapping) 197 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxOcclusionMapping"); 198 else 199 setParameterSubroutine("parallax", ShaderType.Fragment, "parallaxNone"); 200 201 // PBR 202 if (ipbr is null) 203 { 204 state.material.setInput("pbr", 0.0f); 205 ipbr = "pbr" in state.material.inputs; 206 } 207 if (ipbr.texture is null) 208 { 209 ipbr.texture = state.material.makeTexture(*iroughness, *imetallic, *ispecularity, materialInput(0.0f)); 210 } 211 glActiveTexture(GL_TEXTURE3); 212 ipbr.texture.bind(); 213 setParameter("pbrTexture", 3); 214 215 if (iroughness.texture is null) 216 { 217 setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessValue"); 218 219 if (iroughness.type == MaterialInputType.Float) 220 setParameter("roughnessScalar", iroughness.asFloat); 221 else if (iroughness.type == MaterialInputType.Bool) 222 setParameter("roughnessScalar", cast(float)iroughness.asBool); 223 else if (iroughness.type == MaterialInputType.Integer) 224 setParameter("roughnessScalar", cast(float)iroughness.asInteger); 225 else if (iroughness.type == MaterialInputType.Vec2) 226 setParameter("roughnessScalar", iroughness.asVector2f.r); 227 else if (iroughness.type == MaterialInputType.Vec3) 228 setParameter("roughnessScalar", iroughness.asVector3f.r); 229 else if (iroughness.type == MaterialInputType.Vec4) 230 setParameter("roughnessScalar", iroughness.asVector4f.r); 231 } 232 else 233 { 234 setParameterSubroutine("roughness", ShaderType.Fragment, "roughnessMap"); 235 } 236 237 if (imetallic.texture is null) 238 { 239 setParameterSubroutine("metallic", ShaderType.Fragment, "metallicValue"); 240 241 if (imetallic.type == MaterialInputType.Float) 242 setParameter("metallicScalar", imetallic.asFloat); 243 else if (imetallic.type == MaterialInputType.Bool) 244 setParameter("metallicScalar", cast(float)imetallic.asBool); 245 else if (imetallic.type == MaterialInputType.Integer) 246 setParameter("metallicScalar", cast(float)imetallic.asInteger); 247 else if (imetallic.type == MaterialInputType.Vec2) 248 setParameter("metallicScalar", imetallic.asVector2f.r); 249 else if (imetallic.type == MaterialInputType.Vec3) 250 setParameter("metallicScalar", imetallic.asVector3f.r); 251 else if (imetallic.type == MaterialInputType.Vec4) 252 setParameter("metallicScalar", imetallic.asVector4f.r); 253 } 254 else 255 { 256 setParameterSubroutine("metallic", ShaderType.Fragment, "metallicMap"); 257 } 258 259 if (ispecularity.texture is null) 260 { 261 setParameterSubroutine("specularity", ShaderType.Fragment, "specularityValue"); 262 263 if (ispecularity.type == MaterialInputType.Float) 264 setParameter("specularityScalar", ispecularity.asFloat); 265 else if (ispecularity.type == MaterialInputType.Bool) 266 setParameter("specularityScalar", cast(float)ispecularity.asBool); 267 else if (ispecularity.type == MaterialInputType.Integer) 268 setParameter("specularityScalar", cast(float)ispecularity.asInteger); 269 else if (ispecularity.type == MaterialInputType.Vec2) 270 setParameter("specularityScalar", ispecularity.asVector2f.r); 271 else if (ispecularity.type == MaterialInputType.Vec3) 272 setParameter("specularityScalar", ispecularity.asVector3f.r); 273 else if (ispecularity.type == MaterialInputType.Vec4) 274 setParameter("specularityScalar", ispecularity.asVector4f.r); 275 } 276 else 277 { 278 setParameterSubroutine("specularity", ShaderType.Fragment, "specularityMap"); 279 } 280 281 if (!ioutputPBR.asBool) 282 { 283 glColorMaski(2, 0, 0, 0, 0); 284 } 285 286 // Emission 287 if (iemission.texture) 288 { 289 glActiveTexture(GL_TEXTURE4); 290 iemission.texture.bind(); 291 setParameter("emissionTexture", cast(int)4); 292 setParameterSubroutine("emission", ShaderType.Fragment, "emissionMap"); 293 } 294 else 295 { 296 setParameter("emissionVector", iemission.asVector4f); 297 setParameterSubroutine("emission", ShaderType.Fragment, "emissionValue"); 298 } 299 setParameter("energy", ienergy.asFloat); 300 301 if (!ioutputEmission.asBool) 302 { 303 glColorMaski(3, 0, 0, 0, 0); 304 } 305 306 glActiveTexture(GL_TEXTURE0); 307 308 super.bindParameters(state); 309 } 310 311 override void unbindParameters(GraphicsState* state) 312 { 313 super.unbindParameters(state); 314 315 glColorMaski(0, 1, 1, 1, 1); 316 glColorMaski(1, 1, 1, 1, 1); 317 glColorMaski(2, 1, 1, 1, 1); 318 glColorMaski(3, 1, 1, 1, 1); 319 320 glActiveTexture(GL_TEXTURE0); 321 glBindTexture(GL_TEXTURE_2D, 0); 322 323 glActiveTexture(GL_TEXTURE1); 324 glBindTexture(GL_TEXTURE_2D, 0); 325 326 glActiveTexture(GL_TEXTURE2); 327 glBindTexture(GL_TEXTURE_2D, 0); 328 329 glActiveTexture(GL_TEXTURE3); 330 glBindTexture(GL_TEXTURE_2D, 0); 331 332 glActiveTexture(GL_TEXTURE4); 333 glBindTexture(GL_TEXTURE_2D, 0); 334 335 glActiveTexture(GL_TEXTURE0); 336 } 337 }