1 /*
2 Copyright (c) 2017-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 
28 module dagon.graphics.material;
29 
30 import std.traits;
31 import std.math;
32 import std.algorithm;
33 
34 import dlib.core.memory;
35 import dlib.core.ownership;
36 import dlib.math.vector;
37 import dlib.image.color;
38 import dlib.image.image;
39 import dlib.image.unmanaged;
40 import dlib.container.dict;
41 
42 import dagon.core.bindings;
43 import dagon.graphics.texture;
44 import dagon.graphics.state;
45 import dagon.graphics.shader;
46 import dagon.graphics.light;
47 
48 enum
49 {
50     CBlack = Color4f(0.0f, 0.0f, 0.0f, 1.0f),
51     CWhite = Color4f(1.0f, 1.0f, 1.0f, 1.0f),
52     CRed = Color4f(1.0f, 0.0f, 0.0f, 1.0f),
53     COrange = Color4f(1.0f, 0.5f, 0.0f, 1.0f),
54     CYellow = Color4f(1.0f, 1.0f, 0.0f, 1.0f),
55     CGreen = Color4f(0.0f, 1.0f, 0.0f, 1.0f),
56     CCyan = Color4f(0.0f, 1.0f, 1.0f, 1.0f),
57     CBlue = Color4f(0.0f, 0.0f, 1.0f, 1.0f),
58     CPurple = Color4f(0.5f, 0.0f, 1.0f, 1.0f),
59     CMagenta = Color4f(1.0f, 0.0f, 1.0f, 1.0f)
60 }
61 
62 enum int None = 0;
63 
64 enum int ShadowFilterNone = 0;
65 enum int ShadowFilterPCF = 1;
66 
67 enum int ParallaxNone = 0;
68 enum int ParallaxSimple = 1;
69 enum int ParallaxOcclusionMapping = 2;
70 
71 enum int Opaque = 0;
72 enum int Transparent = 1;
73 enum int Additive = 2;
74 
75 class Material: Owner
76 {
77     Shader shader;
78     Light sun;
79     Texture baseColorTexture;
80     Texture roughnessMetallicTexture;
81     Texture emissionTexture;
82     Texture normalTexture;
83     Texture heightTexture;
84     Texture maskTexture;
85     Color4f baseColorFactor = Color4f(1.0f, 1.0f, 1.0f, 1.0f);
86     Color4f emissionFactor = Color4f(0.0f, 0.0f, 0.0f, 1.0f);
87     Vector3f normalFactor = Vector3f(0.0f, 0.0f, 1.0f);
88     Vector2f textureScale = Vector2f(1.0f, 1.0f); // TODO: textureTransformation matrix instead
89     float heightFactor = 0.0f;
90     float emissionEnergy = 1.0f;
91     float opacity = 1.0f;
92     float alphaTestThreshold = 0.5f;
93     float roughnessFactor = 0.5f;
94     float metallicFactor = 0.0f;
95     float specularity = 1.0f;
96     float translucency = 0.0f;
97     float parallaxScale = 0.03f;
98     float parallaxBias = -0.01f;
99     float maskFactor = 1.0f;
100     int parallaxMode = ParallaxNone;
101     int shadowFilter = ShadowFilterPCF;
102     int blendMode = Opaque;
103     bool shadeless = false;
104     bool invertNormalY = true;
105     bool useShadows = true;
106     bool useFog = true;
107     bool useCulling = true;
108     bool sphericalNormal = false;
109     bool colorWrite = true;
110     bool depthWrite = true;
111     bool outputColor = true;
112     bool outputNormal = true;
113     bool outputPBR = true;
114     bool outputEmission = true;
115     
116     this(Owner o)
117     {
118         super(o);
119     }
120     
121     ~this()
122     {
123     }
124     
125     bool isTransparent()
126     {
127         return (blendMode != Opaque);
128     }
129     
130     void bind(GraphicsState* state)
131     {
132         if (blendMode == Transparent)
133         {
134             glEnablei(GL_BLEND, 0);
135             glEnablei(GL_BLEND, 1);
136             glEnablei(GL_BLEND, 2);
137             glEnablei(GL_BLEND, 3);
138             glEnablei(GL_BLEND, 4);
139             glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
140             glBlendFuncSeparatei(1, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
141             glBlendFuncSeparatei(2, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
142             glBlendFuncSeparatei(3, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
143             glBlendFuncSeparatei(4, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
144         }
145         else if (blendMode == Additive)
146         {
147             glEnablei(GL_BLEND, 0);
148             glEnablei(GL_BLEND, 1);
149             glEnablei(GL_BLEND, 2);
150             glEnablei(GL_BLEND, 3);
151             glEnablei(GL_BLEND, 4);
152             glBlendFunci(0, GL_SRC_ALPHA, GL_ONE);
153             glBlendFunci(1, GL_SRC_ALPHA, GL_ONE);
154             glBlendFunci(2, GL_SRC_ALPHA, GL_ONE);
155             glBlendFunci(3, GL_SRC_ALPHA, GL_ONE);
156             glBlendFunci(4, GL_SRC_ALPHA, GL_ONE);
157         }
158 
159         if (useCulling && state.culling)
160         {
161             glEnable(GL_CULL_FACE);
162         }
163         else
164         {
165             glDisable(GL_CULL_FACE);
166         }
167 
168         if (!colorWrite || !state.colorMask)
169         {
170             glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
171         }
172 
173         if (!depthWrite || !state.depthMask)
174         {
175             glDepthMask(GL_FALSE);
176         }
177 
178         state.material = this;
179     }
180 
181     void unbind(GraphicsState* state)
182     {
183         state.material = null;
184 
185         glDepthMask(GL_TRUE);
186         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
187 
188         glDisable(GL_CULL_FACE);
189 
190         glDisablei(GL_BLEND, 0);
191         glDisablei(GL_BLEND, 1);
192         glDisablei(GL_BLEND, 2);
193         glDisablei(GL_BLEND, 3);
194         glDisablei(GL_BLEND, 4);
195     }
196 }