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(VertexAttrib.Vertices);
142         glBindBuffer(GL_ARRAY_BUFFER, vbo);
143         glVertexAttribPointer(VertexAttrib.Vertices, 2, GL_FLOAT, GL_FALSE, 0, null);
144     
145         glEnableVertexAttribArray(VertexAttrib.Texcoords);
146         glBindBuffer(GL_ARRAY_BUFFER, tbo);
147         glVertexAttribPointer(VertexAttrib.Texcoords, 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 class ShapeBox: Mesh
175 {
176     this(Vector3f extents, Owner owner)
177     {
178         super(owner);
179         
180         vertices = New!(Vector3f[])(24);
181         normals = New!(Vector3f[])(24);
182         texcoords = New!(Vector2f[])(24);
183         indices = New!(uint[3][])(12);
184         
185         Vector3f pmax = +extents;
186         Vector3f pmin = -extents;
187         
188         texcoords[0] = Vector2f(1, 0); normals[0] = Vector3f(0,0,1); vertices[0] = Vector3f(pmax.x, pmax.y, pmax.z);
189         texcoords[1] = Vector2f(0, 0); normals[1] = Vector3f(0,0,1); vertices[1] = Vector3f(pmin.x, pmax.y, pmax.z);
190         texcoords[2] = Vector2f(0, 1); normals[2] = Vector3f(0,0,1); vertices[2] = Vector3f(pmin.x, pmin.y, pmax.z);
191         texcoords[3] = Vector2f(1, 1); normals[3] = Vector3f(0,0,1); vertices[3] = Vector3f(pmax.x, pmin.y, pmax.z);
192         indices[0][0] = 0; indices[0][1] = 1; indices[0][2] = 2;
193         indices[1][0] = 2; indices[1][1] = 3; indices[1][2] = 0;
194         
195         texcoords[4] = Vector2f(0, 0); normals[4] = Vector3f(1,0,0); vertices[4] = Vector3f(pmax.x, pmax.y, pmax.z);
196         texcoords[5] = Vector2f(0, 1); normals[5] = Vector3f(1,0,0); vertices[5] = Vector3f(pmax.x, pmin.y, pmax.z);
197         texcoords[6] = Vector2f(1, 1); normals[6] = Vector3f(1,0,0); vertices[6] = Vector3f(pmax.x, pmin.y, pmin.z);
198         texcoords[7] = Vector2f(1, 0); normals[7] = Vector3f(1,0,0); vertices[7] = Vector3f(pmax.x, pmax.y, pmin.z);
199         indices[2][0] = 4; indices[2][1] = 5; indices[2][2] = 6;
200         indices[3][0] = 6; indices[3][1] = 7; indices[3][2] = 4;
201         
202         texcoords[8] = Vector2f(1, 1); normals[8] = Vector3f(0,1,0); vertices[8] = Vector3f(pmax.x, pmax.y, pmax.z);
203         texcoords[9] = Vector2f(1, 0); normals[9] = Vector3f(0,1,0); vertices[9] = Vector3f(pmax.x, pmax.y, pmin.z);
204         texcoords[10] = Vector2f(0, 0); normals[10] = Vector3f(0,1,0); vertices[10] = Vector3f(pmin.x, pmax.y, pmin.z);
205         texcoords[11] = Vector2f(0, 1); normals[11] = Vector3f(0,1,0); vertices[11] = Vector3f(pmin.x, pmax.y, pmax.z);
206         indices[4][0] = 8; indices[4][1] = 9; indices[4][2] = 10;
207         indices[5][0] = 10; indices[5][1] = 11; indices[5][2] = 8;
208         
209         texcoords[12] = Vector2f(1, 0); normals[12] = Vector3f(-1,0,0); vertices[12] = Vector3f(pmin.x, pmax.y, pmax.z);
210         texcoords[13] = Vector2f(0, 0); normals[13] = Vector3f(-1,0,0); vertices[13] = Vector3f(pmin.x, pmax.y, pmin.z);
211         texcoords[14] = Vector2f(0, 1); normals[14] = Vector3f(-1,0,0); vertices[14] = Vector3f(pmin.x, pmin.y, pmin.z);
212         texcoords[15] = Vector2f(1, 1); normals[15] = Vector3f(-1,0,0); vertices[15] = Vector3f(pmin.x, pmin.y, pmax.z);
213         indices[6][0] = 12; indices[6][1] = 13; indices[6][2] = 14;
214         indices[7][0] = 14; indices[7][1] = 15; indices[7][2] = 12;
215         
216         texcoords[16] = Vector2f(0, 1); normals[16] = Vector3f(0,-1,0); vertices[16] = Vector3f(pmin.x, pmin.y, pmin.z);
217         texcoords[17] = Vector2f(1, 1); normals[17] = Vector3f(0,-1,0); vertices[17] = Vector3f(pmax.x, pmin.y, pmin.z);
218         texcoords[18] = Vector2f(1, 0); normals[18] = Vector3f(0,-1,0); vertices[18] = Vector3f(pmax.x, pmin.y, pmax.z);
219         texcoords[19] = Vector2f(0, 0); normals[19] = Vector3f(0,-1,0); vertices[19] = Vector3f(pmin.x, pmin.y, pmax.z);
220         indices[8][0] = 16; indices[8][1] = 17; indices[8][2] = 18;
221         indices[9][0] = 18; indices[9][1] = 19; indices[9][2] = 16;
222         
223         texcoords[20] = Vector2f(0, 1); normals[20] = Vector3f(0,0,-1); vertices[20] = Vector3f(pmax.x, pmin.y, pmin.z);
224         texcoords[21] = Vector2f(1, 1); normals[21] = Vector3f(0,0,-1); vertices[21] = Vector3f(pmin.x, pmin.y, pmin.z);
225         texcoords[22] = Vector2f(1, 0); normals[22] = Vector3f(0,0,-1); vertices[22] = Vector3f(pmin.x, pmax.y, pmin.z);
226         texcoords[23] = Vector2f(0, 0); normals[23] = Vector3f(0,0,-1); vertices[23] = Vector3f(pmax.x, pmax.y, pmin.z);
227         indices[10][0] = 20; indices[10][1] = 21; indices[10][2] = 22;
228         indices[11][0] = 22; indices[11][1] = 23; indices[11][2] = 20;
229         
230         dataReady = true;
231         prepareVAO();
232     }
233 }
234 
235 enum PI2 = PI * 2.0f;
236 enum HALF_PI = PI * 0.5f;
237 
238 Vector2f envMapEquirect(Vector3f dir)
239 {
240     //float phi = acos(dir.y);
241     //float theta = atan2(dir.x, dir.z) + PI;
242     //return Vector2f(theta / PI2, phi / PI);
243     Vector2f uv;
244     uv.y = acos(dir.y) / PI;
245     uv.x = (PI + atan2(dir.x, dir.z)) / PI2;
246     return uv;
247 }
248 
249 class ShapeSphere: Mesh
250 {
251     DynamicArray!Vector3f daVertices;
252     DynamicArray!Vector3f daNormals;
253     DynamicArray!Vector2f daTexcoords;
254     DynamicArray!(uint[3]) daIndices;
255     
256     this(float radius, int slices, int stacks, bool invNormals, Owner o)
257     {
258         super(o);
259         
260         float X1, Y1, X2, Y2, Z1, Z2;
261         float inc1, inc2, inc3, inc4, inc5, radius1, radius2;
262         uint[3] tri;
263         uint i = 0;
264         
265         float cuts = stacks;
266         float invCuts = 1.0f / cuts;
267         float heightStep = 2.0f * invCuts;
268         
269         float invSlices = 1.0f / slices;
270         float angleStep = (2.0f * PI) * invSlices;
271 
272         for(int h = 0; h < stacks; h++)
273         {
274             float h1Norm = cast(float)h * invCuts * 2.0f - 1.0f;
275             float h2Norm = cast(float)(h+1) * invCuts * 2.0f - 1.0f;
276             float y1 = sin(HALF_PI * h1Norm);
277             float y2 = sin(HALF_PI * h2Norm);
278             
279             float circleRadius1 = cos(HALF_PI * y1);
280             float circleRadius2 = cos(HALF_PI * y2);
281             
282             for(int a = 0; a < slices; a++)
283             {
284                 float x1a = sin(angleStep * a) * circleRadius1;
285                 float z1a = cos(angleStep * a) * circleRadius1;
286                 float x2a = sin(angleStep * (a + 1)) * circleRadius1;
287                 float z2a = cos(angleStep * (a + 1)) * circleRadius1;
288                 
289                 float x1b = sin(angleStep * a) * circleRadius2;
290                 float z1b = cos(angleStep * a) * circleRadius2;
291                 float x2b = sin(angleStep * (a + 1)) * circleRadius2;
292                 float z2b = cos(angleStep * (a + 1)) * circleRadius2;
293                 
294                 Vector3f v1 = Vector3f(x1a, y1, z1a);
295                 Vector3f v2 = Vector3f(x2a, y1, z2a);
296                 Vector3f v3 = Vector3f(x1b, y2, z1b);
297                 Vector3f v4 = Vector3f(x2b, y2, z2b);
298                                 
299                 Vector3f n1 = v1.normalized;
300                 Vector3f n2 = v2.normalized;
301                 Vector3f n3 = v3.normalized;
302                 Vector3f n4 = v4.normalized;
303 
304                 daVertices.append(n1 * radius);
305                 daVertices.append(n2 * radius);
306                 daVertices.append(n3 * radius);
307                 
308                 daVertices.append(n3 * radius);
309                 daVertices.append(n2 * radius);
310                 daVertices.append(n4 * radius);
311                 
312                 float sign = invNormals? -1.0f : 1.0f;
313                 
314                 daNormals.append(n1 * sign);
315                 daNormals.append(n2 * sign);
316                 daNormals.append(n3 * sign);
317                 
318                 daNormals.append(n3 * sign);
319                 daNormals.append(n2 * sign);
320                 daNormals.append(n4 * sign);
321                 
322                 auto uv1 = Vector2f(0, 1);
323                 auto uv2 = Vector2f(1, 1);
324                 auto uv3 = Vector2f(0, 0);
325                 auto uv4 = Vector2f(1, 0);
326                 
327                 daTexcoords.append(uv1); 
328                 daTexcoords.append(uv2); 
329                 daTexcoords.append(uv3);
330                 
331                 daTexcoords.append(uv3); 
332                 daTexcoords.append(uv2); 
333                 daTexcoords.append(uv4);
334                 
335                 if (invNormals)
336                 {
337                     tri[0] = i+2;
338                     tri[1] = i+1;
339                     tri[2] = i;
340                     daIndices.append(tri);
341                     
342                     tri[0] = i+5;
343                     tri[1] = i+4;
344                     tri[2] = i+3;
345                     daIndices.append(tri);
346                 }
347                 else
348                 {
349                     tri[0] = i;
350                     tri[1] = i+1;
351                     tri[2] = i+2;
352                     daIndices.append(tri);
353                     
354                     tri[0] = i+3;
355                     tri[1] = i+4;
356                     tri[2] = i+5;
357                     daIndices.append(tri);
358                 }
359                 
360                 i += 6;
361             }
362         }
363         
364         /*
365         for(int w = 0; w < resolution; w++)
366         {
367             
368         
369             for(int h = (-resolution/2); h < (resolution/2); h++)
370             {
371                 inc1 = (w/cast(float)resolution)*2*PI;
372                 inc2 = ((w+1)/cast(float)resolution)*2*PI;
373                  
374                 inc3 = (h/cast(float)resolution)*PI;
375                 inc4 = ((h+1)/cast(float)resolution)*PI;
376 
377                 X1 = sin(inc1);
378                 Y1 = cos(inc1);
379                 X2 = sin(inc2);
380                 Y2 = cos(inc2);
381 
382                 radius1 = radius*cos(inc3);
383                 radius2 = radius*cos(inc4);
384 
385                 Z1 = radius*sin(inc3); 
386                 Z2 = radius*sin(inc4);
387                 
388                 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1));
389                 daVertices.append(Vector3f(radius1*X2,Z1,radius1*Y2));
390                 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2));
391 
392                 daVertices.append(Vector3f(radius1*X1,Z1,radius1*Y1));
393                 daVertices.append(Vector3f(radius2*X2,Z2,radius2*Y2));
394                 daVertices.append(Vector3f(radius2*X1,Z2,radius2*Y1));
395                 
396                 auto uv1 = Vector2f(0, 0);
397                 auto uv2 = Vector2f(0, 1);
398                 auto uv3 = Vector2f(1, 1);
399                 auto uv4 = Vector2f(1, 0);
400 
401                 daTexcoords.append(uv1); 
402                 daTexcoords.append(uv2); 
403                 daTexcoords.append(uv3);
404 
405                 daTexcoords.append(uv1); 
406                 daTexcoords.append(uv3); 
407                 daTexcoords.append(uv4);
408                 
409                 float sign = invNormals? -1.0f : 1.0f;
410                 
411                 auto n1 = Vector3f(X1,Z1,Y1).normalized;
412                 auto n2 = Vector3f(X2,Z1,Y2).normalized;
413                 auto n3 = Vector3f(X2,Z2,Y2).normalized;
414                 auto n4 = Vector3f(X1,Z2,Y1).normalized;
415                 
416                 daNormals.append(n1 * sign);
417                 daNormals.append(n2 * sign);
418                 daNormals.append(n3 * sign);
419                 
420                 daNormals.append(n1 * sign);
421                 daNormals.append(n3 * sign);
422                 daNormals.append(n4 * sign);
423                 
424                 if (invNormals)
425                 {
426                     tri[0] = i+2;
427                     tri[1] = i+1;
428                     tri[2] = i;
429                     daIndices.append(tri);
430                     
431                     tri[0] = i+5;
432                     tri[1] = i+4;
433                     tri[2] = i+3;
434                     daIndices.append(tri);
435                 }
436                 else
437                 {
438                     tri[0] = i;
439                     tri[1] = i+1;
440                     tri[2] = i+2;
441                     daIndices.append(tri);
442                     
443                     tri[0] = i+3;
444                     tri[1] = i+4;
445                     tri[2] = i+5;
446                     daIndices.append(tri);
447                 }
448                 
449                 i += 6;
450             }
451         }
452         */
453         
454         vertices = New!(Vector3f[])(daVertices.length);
455         vertices[] = daVertices.data[];
456         
457         normals = New!(Vector3f[])(daNormals.length);
458         normals[] = daNormals.data[];
459         
460         texcoords = New!(Vector2f[])(daTexcoords.length);
461         texcoords[] = daTexcoords.data[];
462         
463         indices = New!(uint[3][])(daIndices.length);
464         indices[] = daIndices.data[];
465         
466         daVertices.free();
467         daNormals.free();
468         daTexcoords.free();
469         daIndices.free();
470         
471         dataReady = true;
472         prepareVAO();
473     }
474 }
475 
476 // TODO: other shapes from original Dagon