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