1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  *
24  *
25  * DSFML is based on SFML (Copyright Laurent Gomila)
26  */
27 
28 /**
29  * The glsl module contains types that match their equivalents in GLSL, the
30  * OpenGL shading language. These types are exclusively used by the
31  * $(SHADER_LINK) class.
32  *
33  * Types that already exist in DSFML, such as $(VECTOR2_LINK) and
34  * $(VECTOR3_LINK), are reused as aliases, so you can use the types in this
35  * module as well as the original ones.
36  * Others are newly defined, such as `Vec4` or `Mat3`. Their actual type is an
37  * implementation detail and should not be used.
38  *
39  * All vector types support a default constructor that initializes every
40  * component to zero, in addition to a constructor with one parameter for each
41  * component.
42  * The components are stored in member variables called `x`, `y`, `z`, and `w`.
43  *
44  * All matrix types support a constructor with a `float[]` parameter of the
45  * appropriate size (that is, 9 in a 3x3 matrix, 16 in a 4x4 matrix).
46  * Furthermore, they can be converted from $(TRANSFORM_LINK) objects.
47 */
48 module dsfml.graphics.glsl;
49 
50 import dsfml.graphics.color;
51 import dsfml.graphics.transform;
52 
53 import dsfml.system.vector2;
54 import dsfml.system.vector3;
55 
56 import std.traits;
57 
58 /// 2D float vector (vec2 in GLSL)
59 alias Vec2 = Vector2!(float);
60 /// 2D int vector (ivec2 in GLSL)
61 alias Ivec2 = Vector2!(int);
62 /// 2D bool vector (bvec2 in GLSL)
63 alias Bvec2 = Vector2!(bool);
64 /// 3D float vector (vec3 in GLSL)
65 alias Vec3 = Vector3!(float);
66 /// 3D int vector (ivec3 in GLSL)
67 alias Ivec3 = Vector3!(int);
68 /// 3D bool vector (bvec3 in GLSL)
69 alias Bvec3 = Vector3!(bool);
70 
71 /**
72  * 4D float vector (vec4 in GLSL)
73  *
74  * 4D float vectors can be converted from sf::Color instances. Each color
75  * channel is normalized from integers in [0, 255] to floating point values
76  * in [0, 1].
77  * ---
78  * Vec4 zeroVector;
79  * auto vector = Vec4(1.f, 2.f, 3.f, 4.f);
80  * auto color = Vec4(Color.Cyan);
81  * ---
82  */
83 alias Vec4 = Vector4!(float);
84 /**
85  * 4D int vector ( ivec4 in GLSL)
86  *
87  * 4D int vectors can be converted from sf::Color instances. Each color channel
88  * remains unchanged inside the integer interval [0, 255].
89  * $(LI test)
90  * ---
91  * Ivec4 zeroVector;
92  * auto vector = Ivec4(1, 2, 3, 4);
93  * auto color = Ivec4(Color.Cyan);
94  * ---
95  */
96 alias Ivec4 = Vector4!(int);
97 
98 /// 4D bool vector (bvec4 in GLSL)
99 alias Bvec4 = Vector4!(bool);
100 
101 /**
102  * 3x3 float matrix (mat3 in GLSL)
103  *
104  * The matrix can be constructed from an array with 3x3 elements, aligned in
105  * column-major order. For example,a translation by (x, y) looks as follows:
106  * ---
107  * float[9] array =
108  * [
109  *     1, 0, 0,
110  *     0, 1, 0,
111  *     x, y, 1
112  * ];
113  *
114  * auto matrix = Mat3(array);
115  * ---
116  *
117  * $(PARA Mat4 can also be converted from a $(TRANSFORM_LINK Transform).)
118  * ---
119  * Transform transform;
120  * auto matrix = Mat3(transform);
121  * ---
122  */
123 alias Mat3 = Matrix!(3,3);
124 
125 /**
126  * 4x4 float matrix (mat4 in GLSL)
127  *
128  * The matrix can be constructed from an array with 4x4 elements, aligned in
129  * column-major order. For example, a translation by (x, y, z) looks as follows:
130  * ---
131  * float array[16] =
132  * {
133  *     1, 0, 0, 0,
134  *     0, 1, 0, 0,
135  *     0, 0, 1, 0,
136  *     x, y, z, 1
137  * };
138  *
139  * auto matrix = Mat4(array);
140  * ---
141  *
142  * $(PARA Mat4 can also be converted from a $(TRANSFORM_LINK Transform).)
143  * ---
144  * Transform transform;
145  * auto matrix = Mat4(transform);
146  * ---
147  */
148 alias Mat4 = Matrix!(4,4);
149 
150 /**
151  * 4D vector type, used to set uniforms in GLSL.
152  */
153 struct Vector4(T)
154     if(isNumeric!(T) || is(T == bool))
155 {
156     /// 1st component (X) of the 4D vector
157     T x;
158     /// 2nd component (Y) of the 4D vector
159     T y;
160     /// 3rd component (Z) of the 4D vector
161     T z;
162     /// 4th component (W) of the 4D vector
163     T w;
164 
165     /**
166      * Construct from 4 vector components
167      *
168      * Params:
169      * X = Component of the 4D vector
170      * Y = Component of the 4D vector
171      * Z = Component of the 4D vector
172      * W = Component of the 4D vector
173      */
174     this(T X, T Y, T Z, T W)
175     {
176         x = X;
177         y = Y;
178         z = Z;
179         w = W;
180     }
181 
182     /**
183      * Conversion constructor
184      *
185      * Params:
186      * other = 4D vector of different type
187      */
188     this(U)(Vector!(U) other)
189     {
190         x = cast(T)other.x;
191         y = cast(T)other.y;
192         z = cast(T)other.z;
193         w = cast(T)other.w;
194     }
195 
196     /**
197      * Construct vector from color.
198      *
199      * The vector values are normalized to [0, 1] for floats, and left as-is for
200      * ints.
201      *
202      * Params:
203      * source = The Color instance to create the vector from
204      */
205     this(Color source)
206     {
207         static if(is(T == float))
208         {
209             x = source.r / 255f;
210             y = source.g / 255f;
211             z = source.b / 255f;
212             w = source.a / 255f;
213         }
214         else static if(is(T == int))
215         {
216             x = cast(T)source.r;
217             y = cast(T)source.g;
218             z = cast(T)source.b;
219             w = cast(T)source.a;
220         }
221     }
222 }
223 
224 /**
225  * Matrix type, used to set uniforms in GLSL.
226  */
227 struct Matrix(uint C, uint R)
228 {
229     /// Array holding matrix data.
230     float[C * R] array;
231 
232     /**
233      * Construct from DSFML transform.
234      *
235      * This constructor is only supported for 3x3 and 4x4 matrices.
236      *
237      * Params:
238      * source = A DSFML Transform
239      */
240     this(ref const(Transform) source)
241     {
242         static assert(C == R && (C == 3 || C == 4),
243         "This constructor is only supported for 3x3 and 4x4 matrices.");
244 
245         const(float)[] from = source.getMatrix();
246 
247         static if(C == 3)
248         {
249             float[] to = array;                 // 3x3
250         // Use only left-upper 3x3 block (for a 2D transform)
251         to[0] = from[ 0]; to[1] = from[ 1]; to[2] = from[ 3];
252         to[3] = from[ 4]; to[4] = from[ 5]; to[5] = from[ 7];
253         to[6] = from[12]; to[7] = from[13]; to[8] = from[15];
254         }
255         else static if(C == 4)
256         {
257             array[] = from[];
258         }
259     }
260 
261     /**
262      * Construct from raw data.
263      *
264      * The elements in source are copied to the instance.
265      *
266      * Params:
267      * source = An array that has the size of the matrix.
268      */
269     this(const(float)[] source)
270     {
271         assert(array.length == source.length);
272 
273         array[0..$] = source[0 .. $];
274     }
275 }