1 module dlangui.graphics.scene.material; 2 3 public import dlangui.core.config; 4 static if (ENABLE_OPENGL): 5 static if (BACKEND_GUI): 6 7 import dlangui.core.types; 8 import dlangui.core.logger; 9 import dlangui.graphics.glsupport; 10 import dlangui.graphics.gldrawbuf; 11 import dlangui.graphics.scene.effect; 12 import dlangui.graphics.scene.node; 13 import dlangui.graphics.scene.mesh; 14 import dlangui.graphics.scene.light; 15 16 /// Reference counted Material object 17 alias MaterialRef = Ref!Material; 18 19 class Material : RefCountedObject { 20 // effect 21 protected EffectRef _effect; 22 protected EffectId _effectId; 23 protected string _autoEffectParams; 24 protected EffectId _autoEffectId; 25 26 // textures 27 protected TextureRef _texture; 28 protected string _textureId; 29 protected bool _textureLinear = true; 30 31 protected TextureRef _bumpTexture; 32 protected string _bumpTextureId; 33 34 // colors 35 protected vec4 _diffuseColor = vec4(1, 1, 1, 1); 36 protected vec3 _ambientColor = vec3(0.2, 0.2, 0.2); 37 protected vec4 _modulateColor = vec4(1, 1, 1, 1); 38 protected float _modulateAlpha = 1; 39 40 /// 0 - specular is disabled, 1 .. 256 - specular exponent 41 protected float _specular = 0; 42 43 // TODO: more material properties 44 45 this() { 46 } 47 48 this(EffectId effectId, string textureId, string bumpTextureId = null) { 49 _effectId = effectId; 50 _autoEffectParams = null; 51 _autoEffectId = effectId; 52 _textureId = textureId; 53 _bumpTextureId = bumpTextureId; 54 } 55 56 @property vec4 diffuseColor() { return _diffuseColor; } 57 @property Material diffuseColor(vec4 color) { _diffuseColor = color; return this; } 58 @property vec3 ambientColor() { return _ambientColor; } 59 @property Material ambientColor(vec3 color) { _ambientColor = color; return this; } 60 @property vec4 modulateColor() { return _modulateColor; } 61 @property Material modulateColor(vec4 color) { _modulateColor = color; return this; } 62 @property float modulateAlpha() { return _modulateAlpha; } 63 @property Material modulateColor(float a) { _modulateAlpha = a; return this; } 64 @property float specular() { return _specular; } 65 @property Material specular(float a) { _specular = a; return this; } 66 67 @property EffectRef effect() { 68 if (_effect.isNull && !_autoEffectId.empty) 69 _effect = EffectCache.instance.get(_autoEffectId); 70 return _effect; 71 } 72 /// set as effect instance 73 @property Material effect(EffectRef e) { 74 _effect = e; 75 return this; 76 } 77 /// set as effect id 78 @property Material effect(EffectId effectId) { 79 if (_effectId == effectId) 80 return this; // no change 81 _effectId = effectId; 82 _autoEffectId = EffectId(_effectId, _autoEffectParams); 83 _effect.clear(); 84 return this; 85 } 86 87 protected @property Material autoEffectParams(string params) { 88 if (_autoEffectParams != params && !_effectId.empty) { 89 _autoEffectId = EffectId(_effectId, params); 90 _autoEffectParams = params; 91 _effect.clear(); 92 } 93 return this; 94 } 95 96 @property TextureRef texture() { 97 if (_texture.isNull && _textureId.length) { 98 _texture = GLTextureCache.instance.get(_textureId); 99 } 100 return _texture; 101 } 102 /// set texture 103 @property Material texture(TextureRef e) { 104 _texture = e; 105 return this; 106 } 107 /// set texture from resourceId 108 @property Material texture(string resourceId) { 109 if (_textureId == resourceId) 110 return this; // no change 111 _texture.clear(); 112 _textureId = resourceId; 113 return this; 114 } 115 @property bool textureLinear() { return _textureLinear; } 116 @property Material textureLinear(bool v) { _textureLinear = v; return this; } 117 118 119 @property TextureRef bumpTexture() { 120 if (_bumpTexture.isNull && _bumpTextureId.length) { 121 _bumpTexture = GLTextureCache.instance.get(_bumpTextureId); 122 } 123 return _bumpTexture; 124 } 125 /// set texture 126 @property Material bumpTexture(TextureRef e) { 127 _bumpTexture = e; 128 return this; 129 } 130 /// set texture from resourceId 131 @property Material bumpTexture(string resourceId) { 132 if (_bumpTextureId == resourceId) 133 return this; // no change 134 _bumpTexture.clear(); 135 _bumpTextureId = resourceId; 136 return this; 137 } 138 139 FogParams _fogParams; 140 @property FogParams fogParams() { return _fogParams; } 141 @property Material fogParams(FogParams fogParams) { _fogParams = fogParams; return this; } 142 143 private AutoParams _lastParams; 144 private string _lastDefs; 145 string calcAutoEffectParams(Mesh mesh, LightParams * lights) { 146 AutoParams newParams = AutoParams(mesh, lights, _specular, !bumpTexture.isNull, _fogParams); 147 if (newParams != _lastParams) { 148 _lastParams = newParams; 149 _lastDefs = _lastParams.defs; 150 } 151 return _lastDefs; 152 } 153 154 void bind(Node3d node, Mesh mesh, LightParams * lights = null) { 155 autoEffectParams = calcAutoEffectParams(mesh, lights); 156 assert(!effect.isNull); 157 effect.bind(); 158 if (!texture.isNull) { 159 texture.texture.setup(); 160 texture.texture.setSamplerParams(_textureLinear, true, true); 161 } 162 if (!bumpTexture.isNull) { 163 bumpTexture.texture.setup(1); 164 bumpTexture.texture.setSamplerParams(true, true, false); 165 } 166 // matrixes, positions uniforms 167 if (_effect.hasUniform(DefaultUniform.u_worldViewProjectionMatrix)) 168 _effect.setUniform(DefaultUniform.u_worldViewProjectionMatrix, node.projectionViewModelMatrix); 169 if (_effect.hasUniform(DefaultUniform.u_cameraPosition)) 170 _effect.setUniform(DefaultUniform.u_cameraPosition, node.cameraPosition); 171 if (_effect.hasUniform(DefaultUniform.u_worldViewMatrix)) 172 _effect.setUniform(DefaultUniform.u_worldViewMatrix, node.worldViewMatrix); 173 if (_effect.hasUniform(DefaultUniform.u_inverseTransposeWorldViewMatrix)) 174 _effect.setUniform(DefaultUniform.u_inverseTransposeWorldViewMatrix, node.inverseTransposeWorldViewMatrix); 175 176 // color uniforms 177 if (_effect.hasUniform(DefaultUniform.u_ambientColor)) 178 _effect.setUniform(DefaultUniform.u_ambientColor, _ambientColor); 179 if (_effect.hasUniform(DefaultUniform.u_diffuseColor)) 180 _effect.setUniform(DefaultUniform.u_diffuseColor, _diffuseColor); 181 if (_effect.hasUniform(DefaultUniform.u_modulateColor)) 182 _effect.setUniform(DefaultUniform.u_modulateColor, _modulateColor); 183 if (_effect.hasUniform(DefaultUniform.u_modulateAlpha)) 184 _effect.setUniform(DefaultUniform.u_modulateAlpha, _modulateAlpha); 185 if (_effect.hasUniform(DefaultUniform.u_specularExponent)) 186 _effect.setUniform(DefaultUniform.u_specularExponent, _specular); 187 188 // fog uniforms 189 if (_fogParams) { 190 if (_effect.hasUniform(DefaultUniform.u_fogColor)) 191 _effect.setUniform(DefaultUniform.u_fogColor, _fogParams.fogColor); 192 if (_effect.hasUniform(DefaultUniform.u_fogMinDistance)) 193 _effect.setUniform(DefaultUniform.u_fogMinDistance, _fogParams.fogMinDistance); 194 if (_effect.hasUniform(DefaultUniform.u_fogMaxDistance)) 195 _effect.setUniform(DefaultUniform.u_fogMaxDistance, _fogParams.fogMaxDistance); 196 } 197 198 // lighting uniforms 199 if (lights && !lights.empty) { 200 if (lights.u_directionalLightDirection.length) { 201 if (_effect.hasUniform(DefaultUniform.u_directionalLightDirection)) { 202 _effect.setUniform(DefaultUniform.u_directionalLightDirection, lights.u_directionalLightDirection); 203 //Log.d("DefaultUniform.u_directionalLightDirection: ", lights.u_directionalLightDirection); 204 } 205 if (_effect.hasUniform(DefaultUniform.u_directionalLightColor)) 206 _effect.setUniform(DefaultUniform.u_directionalLightColor, lights.u_directionalLightColor); 207 } 208 if (lights.u_pointLightPosition.length) { 209 if (_effect.hasUniform(DefaultUniform.u_pointLightPosition)) 210 _effect.setUniform(DefaultUniform.u_pointLightPosition, lights.u_pointLightPosition); 211 if (_effect.hasUniform(DefaultUniform.u_pointLightColor)) 212 _effect.setUniform(DefaultUniform.u_pointLightColor, lights.u_pointLightColor); 213 if (_effect.hasUniform(DefaultUniform.u_pointLightRangeInverse)) 214 _effect.setUniform(DefaultUniform.u_pointLightRangeInverse, lights.u_pointLightRangeInverse); 215 } 216 if (lights.u_spotLightPosition.length) { 217 if (_effect.hasUniform(DefaultUniform.u_spotLightPosition)) 218 _effect.setUniform(DefaultUniform.u_spotLightPosition, lights.u_spotLightPosition); 219 if (_effect.hasUniform(DefaultUniform.u_spotLightDirection)) 220 _effect.setUniform(DefaultUniform.u_spotLightDirection, lights.u_spotLightDirection); 221 if (_effect.hasUniform(DefaultUniform.u_spotLightColor)) 222 _effect.setUniform(DefaultUniform.u_spotLightColor, lights.u_spotLightColor); 223 if (_effect.hasUniform(DefaultUniform.u_spotLightRangeInverse)) 224 _effect.setUniform(DefaultUniform.u_spotLightRangeInverse, lights.u_spotLightRangeInverse); 225 if (_effect.hasUniform(DefaultUniform.u_spotLightInnerAngleCos)) 226 _effect.setUniform(DefaultUniform.u_spotLightInnerAngleCos, lights.u_spotLightInnerAngleCos); 227 if (_effect.hasUniform(DefaultUniform.u_spotLightOuterAngleCos)) 228 _effect.setUniform(DefaultUniform.u_spotLightOuterAngleCos, lights.u_spotLightOuterAngleCos); 229 } 230 } 231 } 232 233 void drawMesh(Mesh mesh) { 234 effect.draw(mesh); 235 } 236 237 void unbind() { 238 if (!texture.isNull) { 239 texture.texture.unbind(); 240 } 241 if (!bumpTexture.isNull) { 242 bumpTexture.texture.unbind(); 243 } 244 effect.unbind(); 245 } 246 } 247 248 struct AutoParams { 249 ubyte directionalLightCount = 0; 250 ubyte pointLightCount = 0; 251 ubyte spotLightCount = 0; 252 bool vertexColor = false; 253 bool specular = false; 254 bool bumpMapping = false; 255 FogParams fogParams; 256 this(Mesh mesh, LightParams * lights, float specular, bool bumpMapping, FogParams fogParams) { 257 if (mesh) 258 vertexColor = mesh.hasElement(VertexElementType.COLOR); 259 if (lights) { 260 directionalLightCount = cast(ubyte)lights.u_directionalLightDirection.length; 261 pointLightCount = cast(ubyte)lights.u_pointLightPosition.length; 262 spotLightCount = cast(ubyte)lights.u_spotLightPosition.length; 263 } 264 this.specular = specular > 0.01; 265 this.bumpMapping = bumpMapping; 266 this.fogParams = fogParams; 267 } 268 string defs() { 269 import std.conv : to; 270 char[] buf; 271 if (fogParams) { 272 buf ~= "FOG"; 273 } 274 if (directionalLightCount) { 275 if (buf.length) 276 buf ~= ";"; 277 buf ~= "DIRECTIONAL_LIGHT_COUNT "; 278 buf ~= directionalLightCount.to!string; 279 } 280 if (pointLightCount) { 281 if (buf.length) 282 buf ~= ";"; 283 buf ~= "POINT_LIGHT_COUNT "; 284 buf ~= pointLightCount.to!string; 285 } 286 if (spotLightCount) { 287 if (buf.length) 288 buf ~= ";"; 289 buf ~= "SPOT_LIGHT_COUNT "; 290 buf ~= spotLightCount.to!string; 291 } 292 if (vertexColor) { 293 if (buf.length) 294 buf ~= ";"; 295 buf ~= "VERTEX_COLOR"; 296 } 297 if (specular) { 298 if (buf.length) 299 buf ~= ";"; 300 buf ~= "SPECULAR"; 301 } 302 if (bumpMapping) { 303 if (buf.length) 304 buf ~= ";"; 305 buf ~= "BUMPED"; 306 } 307 return buf.dup; 308 } 309 } 310 311 class FogParams { 312 immutable vec4 fogColor; 313 immutable float fogMinDistance; 314 immutable float fogMaxDistance; 315 this(vec4 fogColor, float fogMinDistance, float fogMaxDistance) { 316 this.fogColor = fogColor; 317 this.fogMinDistance = fogMinDistance; 318 this.fogMaxDistance = fogMaxDistance; 319 } 320 }