1 /*
2 Copyright (c) 2017-2018 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.shapes;
29 
30 import std.math;
31 
32 import dlib.core.memory;
33 import dlib.math.vector;
34 import dlib.container.array;
35 
36 import dagon.core.libs;
37 import dagon.core.interfaces;
38 import dagon.core.ownership;
39 import dagon.graphics.mesh;
40 
41 class ShapePlane: Mesh
42 {
43     this(float sx, float sz, uint numTiles, Owner owner)
44     {
45         super(owner);
46         
47         float px = -sx * 0.5f;
48         float py = -sz * 0.5f;
49         
50         float tileWidth = sx / numTiles;
51         float tileHeight = sz / numTiles;
52         
53         Vector3f start = Vector3f(px, 0.0f, py);
54         
55         uint gridSize = numTiles + 1;
56         
57         vertices = New!(Vector3f[])(gridSize * gridSize);
58         normals = New!(Vector3f[])(gridSize * gridSize);
59         texcoords = New!(Vector2f[])(gridSize * gridSize);
60 
61         for (uint i = 0, y = 0; y < gridSize; y++)
62         for (uint x = 0; x < gridSize; x++, i++)
63         {
64             vertices[i] = start + Vector3f(x * tileWidth, 0, y * tileHeight);
65             normals[i] = Vector3f(0, 1, 0);
66             texcoords[i] = Vector2f(x, y);
67         }     
68         
69         indices = New!(uint[3][])(gridSize * gridSize * 2);
70         
71         uint index = 0;
72         for (uint y = 0; y < gridSize - 1; y++)
73         for (uint x = 0; x < gridSize - 1; x++)
74         {
75             uint offset = y * gridSize + x;
76             indices[index][2] = (offset + 0);
77             indices[index][1] = (offset + 1);
78             indices[index][0] = (offset + gridSize);
79             
80             indices[index+1][2] = (offset + 1);
81             indices[index+1][1] = (offset + gridSize + 1);
82             indices[index+1][0] = (offset + gridSize);
83             
84             index += 2;
85         }
86 
87         dataReady = true;
88         prepareVAO();
89     }
90 }
91 
92 class ShapeQuad: Owner, Drawable
93 {
94     Vector2f[4] vertices;
95     Vector2f[4] texcoords;
96     uint[3][2] indices;
97     
98     GLuint vao = 0;
99     GLuint vbo = 0;
100     GLuint tbo = 0;
101     GLuint eao = 0;
102     
103     this(Owner o)
104     {
105         super(o);
106 
107         vertices[0] = Vector2f(0, 1);
108         vertices[1] = Vector2f(0, 0);
109         vertices[2] = Vector2f(1, 0);
110         vertices[3] = Vector2f(1, 1);
111         
112         texcoords[0] = Vector2f(0, 1);
113         texcoords[1] = Vector2f(0, 0);
114         texcoords[2] = Vector2f(1, 0);
115         texcoords[3] = Vector2f(1, 1);
116         
117         indices[0][0] = 0;
118         indices[0][1] = 1;
119         indices[0][2] = 2;
120         
121         indices[1][0] = 0;
122         indices[1][1] = 2;
123         indices[1][2] = 3;
124         
125         glGenBuffers(1, &vbo);
126         glBindBuffer(GL_ARRAY_BUFFER, vbo);
127         glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof * 2, vertices.ptr, GL_STATIC_DRAW); 
128 
129         glGenBuffers(1, &tbo);
130         glBindBuffer(GL_ARRAY_BUFFER, tbo);
131         glBufferData(GL_ARRAY_BUFFER, texcoords.length * float.sizeof * 2, texcoords.ptr, GL_STATIC_DRAW);
132 
133         glGenBuffers(1, &eao);
134         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
135         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length * uint.sizeof * 3, indices.ptr, GL_STATIC_DRAW);
136 
137         glGenVertexArrays(1, &vao);
138         glBindVertexArray(vao);
139         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
140     
141         glEnableVertexAttribArray(0);
142         glBindBuffer(GL_ARRAY_BUFFER, vbo);
143         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, null);
144     
145         glEnableVertexAttribArray(1);
146         glBindBuffer(GL_ARRAY_BUFFER, tbo);
147         glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, null);
148 
149         glBindVertexArray(0);
150     }
151     
152     ~this()
153     {            
154         glDeleteVertexArrays(1, &vao);
155         glDeleteBuffers(1, &vbo);
156         glDeleteBuffers(1, &tbo);
157         glDeleteBuffers(1, &eao);
158     }
159     
160     void update(double dt)
161     {
162     }
163     
164     void render(RenderingContext* rc)
165     {        
166         glDepthMask(0);
167         glBindVertexArray(vao);
168         glDrawElements(GL_TRIANGLES, cast(uint)indices.length * 3, GL_UNSIGNED_INT, cast(void*)0);
169         glBindVertexArray(0);
170         glDepthMask(1);
171     }
172 }
173 
174 enum PI2 = PI * 2.0f;
175 enum HALF_PI = PI * 0.5f;
176 
177 Vector2f envMapEquirect(Vector3f dir)
178 {
179     //float phi = acos(dir.y);
180     //float theta = atan2(dir.x, dir.z) + PI;
181     //return Vector2f(theta / PI2, phi / PI);
182     Vector2f uv;
183     uv.y = acos(dir.y) / PI;
184     uv.x = (PI + atan2(dir.x, dir.z)) / PI2;
185     return uv;
186 }
187 
188 class ShapeSphere: Mesh
189 {
190     DynamicArray!Vector3f daVertices;
191     DynamicArray!Vector3f daNormals;
192     DynamicArray!Vector2f daTexcoords;
193     DynamicArray!(uint[3]) daIndices;
194     
195     this(float radius, int slices, int stacks, bool invNormals, Owner o)
196     {
197         super(o);
198         
199         float X1, Y1, X2, Y2, Z1, Z2;
200         float inc1, inc2, inc3, inc4, inc5, radius1, radius2;
201         uint[3] tri;
202         uint i = 0;
203         
204         float cuts = stacks;
205         float invCuts = 1.0f / cuts;
206         float heightStep = 2.0f * invCuts;
207         
208         float invSlices = 1.0f / slices;
209         float angleStep = (2.0f * PI) * invSlices;
210 
211         for(int h = 0; h < stacks; h++)
212         {
213             float h1Norm = cast(float)h * invCuts * 2.0f - 1.0f;
214             float h2Norm = cast(float)(h+1) * invCuts * 2.0f - 1.0f;
215             float y1 = sin(HALF_PI * h1Norm);
216             float y2 = sin(HALF_PI * h2Norm);
217             
218             float circleRadius1 = cos(HALF_PI * y1);
219             float circleRadius2 = cos(HALF_PI * y2);
220             
221             for(int a = 0; a < slices; a++)
222             {
223                 float x1a = sin(angleStep * a) * circleRadius1;
224                 float z1a = cos(angleStep * a) * circleRadius1;
225                 float x2a = sin(angleStep * (a + 1)) * circleRadius1;
226                 float z2a = cos(angleStep * (a + 1)) * circleRadius1;
227                 
228                 float x1b = sin(angleStep * a) * circleRadius2;
229                 float z1b = cos(angleStep * a) * circleRadius2;
230                 float x2b = sin(angleStep * (a + 1)) * circleRadius2;
231                 float z2b = cos(angleStep * (a + 1)) * circleRadius2;
232                 
233                 Vector3f v1 = Vector3f(x1a, y1, z1a);
234                 Vector3f v2 = Vector3f(x2a, y1, z2a);
235                 Vector3f v3 = Vector3f(x1b, y2, z1b);
236                 Vector3f v4 = Vector3f(x2b, y2, z2b);
237                                 
238                 Vector3f n1 = v1.normalized;
239                 Vector3f n2 = v2.normalized;
240                 Vector3f n3 = v3.normalized;
241                 Vector3f n4 = v4.normalized;
242 
243                 daVertices.append(n1 * radius);
244                 daVertices.append(n2 * radius);
245                 daVertices.append(n3 * radius);
246                 
247                 daVertices.append(n3 * radius);
248                 daVertices.append(n2 * radius);
249                 daVertices.append(n4 * radius);
250                 
251                 float sign = invNormals? -1.0f : 1.0f;
252                 
253                 daNormals.append(n1 * sign);
254                 daNormals.append(n2 * sign);
255                 daNormals.append(n3 * sign);
256                 
257                 daNormals.append(n3 * sign);
258                 daNormals.append(n2 * sign);
259                 daNormals.append(n4 * sign);
260                 
261                 auto uv1 = Vector2f(0, 1);
262                 auto uv2 = Vector2f(1, 1);
263                 auto uv3 = Vector2f(0, 0);
264                 auto uv4 = Vector2f(1, 0);
265                 
266                 daTexcoords.append(uv1); 
267                 daTexcoords.append(uv2); 
268                 daTexcoords.append(uv3);
269                 
270                 daTexcoords.append(uv3); 
271                 daTexcoords.append(uv2); 
272                 daTexcoords.append(uv4);
273                 
274                 if (invNormals)
275                 {
276                     tri[0] = i+2;
277                     tri[1] = i+1;
278                     tri[2] = i;
279                     daIndices.append(tri);
280                     
281                     tri[0] = i+5;
282                     tri[1] = i+4;
283                     tri[2] = i+3;
284                     daIndices.append(tri);
285                 }
286                 else
287                 {
288                     tri[0] = i;
289                     tri[1] = i+1;
290                     tri[2] = i+2;
291                     daIndices.append(tri);
292                     
293                     tri[0] = i+3;
294                     tri[1] = i+4;
295                     tri[2] = i+5;
296                     daIndices.append(tri);
297                 }
298                 
299                 i += 6;
300             }
301         }
302         
303         /*
304         for(int w = 0; w < resolution; w++)
305         {
306             
307         
308             for(int h = (-resolution/2); h < (resolution/2); h++)
309             {
310                 inc1 = (w/cast(float)resolution)*2*PI;
311                 inc2 = ((w+1)/cast(float)resolution)*2*PI;
312                  
313                 inc3 = (h/cast(float)resolution)*PI;
314                 inc4 = ((h+1)/cast(float)resolution)*PI;
315 
316                 X1 = sin(inc1);
317                 Y1 = cos(inc1);
318                 X2 = sin(inc2);
319                 Y2 = cos(inc2);
320 
321                 radius1 = radius*cos(inc3);
322                 radius2 = radius*cos(inc4);
323 
324                 Z1 = radius*sin(inc3); 
325                 Z2 = radius*sin(inc4);
326                 
327                 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1));
328                 daVertices.append(Vector3f(radius1*X2,Z1,radius1*Y2));
329                 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2));
330 
331                 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1));
332                 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2));
333                 daVertices.append(Vector3f(radius2*X1,Z2,radius2*Y1));
334                 
335                 auto uv1 = Vector2f(0, 0);
336                 auto uv2 = Vector2f(0, 1);
337                 auto uv3 = Vector2f(1, 1);
338                 auto uv4 = Vector2f(1, 0);
339 
340                 daTexcoords.append(uv1); 
341                 daTexcoords.append(uv2); 
342                 daTexcoords.append(uv3);
343 
344                 daTexcoords.append(uv1); 
345                 daTexcoords.append(uv3); 
346                 daTexcoords.append(uv4);
347                 
348                 float sign = invNormals? -1.0f : 1.0f;
349                 
350                 auto n1 = Vector3f(X1,Z1,Y1).normalized;
351                 auto n2 = Vector3f(X2,Z1,Y2).normalized;
352                 auto n3 = Vector3f(X2,Z2,Y2).normalized;
353                 auto n4 = Vector3f(X1,Z2,Y1).normalized;
354                 
355                 daNormals.append(n1 * sign);
356                 daNormals.append(n2 * sign);
357                 daNormals.append(n3 * sign);
358                 
359                 daNormals.append(n1 * sign);
360                 daNormals.append(n3 * sign);
361                 daNormals.append(n4 * sign);
362                 
363                 if (invNormals)
364                 {
365                     tri[0] = i+2;
366                     tri[1] = i+1;
367                     tri[2] = i;
368                     daIndices.append(tri);
369                     
370                     tri[0] = i+5;
371                     tri[1] = i+4;
372                     tri[2] = i+3;
373                     daIndices.append(tri);
374                 }
375                 else
376                 {
377                     tri[0] = i;
378                     tri[1] = i+1;
379                     tri[2] = i+2;
380                     daIndices.append(tri);
381                     
382                     tri[0] = i+3;
383                     tri[1] = i+4;
384                     tri[2] = i+5;
385                     daIndices.append(tri);
386                 }
387                 
388                 i += 6;
389             }
390         }
391         */
392         
393         vertices = New!(Vector3f[])(daVertices.length);
394         vertices[] = daVertices.data[];
395         
396         normals = New!(Vector3f[])(daNormals.length);
397         normals[] = daNormals.data[];
398         
399         texcoords = New!(Vector2f[])(daTexcoords.length);
400         texcoords[] = daTexcoords.data[];
401         
402         indices = New!(uint[3][])(daIndices.length);
403         indices[] = daIndices.data[];
404         
405         daVertices.free();
406         daNormals.free();
407         daTexcoords.free();
408         daIndices.free();
409         
410         dataReady = true;
411         prepareVAO();
412     }
413 }
414 
415 // TODO: other shapes from original Dagon