1 /*
2 Copyright (c) 2017-2020 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.mesh;
29 
30 import std.math;
31 import std.algorithm;
32 
33 import dlib.core.memory;
34 import dlib.core.ownership;
35 import dlib.geometry.triangle;
36 import dlib.math.vector;
37 import dlib.geometry.aabb;
38 
39 import dagon.core.bindings;
40 import dagon.graphics.drawable;
41 
42 enum VertexAttrib
43 {
44     Vertices = 0,
45     Normals = 1,
46     Texcoords = 2
47 }
48 
49 interface TriangleSet
50 {
51     int opApply(scope int delegate(Triangle t) dg);
52 }
53 
54 class Mesh: Owner, Drawable, TriangleSet
55 {
56     bool dataReady = false;
57     bool canRender = false;
58     
59     // TODO: make these DynamicArrays
60     Vector3f[] vertices;
61     Vector3f[] normals;
62     Vector2f[] texcoords;
63     uint[3][] indices;
64     
65     AABB boundingBox;
66     
67     GLuint vao = 0;
68     GLuint vbo = 0;
69     GLuint nbo = 0;
70     GLuint tbo = 0;
71     GLuint eao = 0;
72     
73     this(Owner owner)
74     {
75         super(owner);
76     }
77     
78     ~this()
79     {
80         if (vertices.length) Delete(vertices);
81         if (normals.length) Delete(normals);
82         if (texcoords.length) Delete(texcoords);
83         if (indices.length) Delete(indices);
84         
85         if (canRender)
86         {
87             glDeleteVertexArrays(1, &vao);
88             glDeleteBuffers(1, &vbo);
89             glDeleteBuffers(1, &nbo);
90             glDeleteBuffers(1, &tbo);
91             glDeleteBuffers(1, &eao);
92         }
93     }
94     
95     void calcBoundingBox()
96     {
97         float maxDimension = 0.0f;
98         
99         foreach(v; vertices)
100         {
101             float ax = abs(v.x);
102             float ay = abs(v.y);
103             float az = abs(v.z);
104             if (ax > maxDimension) maxDimension = ax;
105             if (ay > maxDimension) maxDimension = ay;
106             if (az > maxDimension) maxDimension = az;
107         }
108         
109         Vector3f furthest = Vector3f(maxDimension, maxDimension, maxDimension);
110 
111         boundingBox = boxFromMinMaxPoints(-furthest, furthest);
112     }
113     
114     Triangle getTriangle(size_t faceIndex)
115     {
116         uint[3] f = indices[faceIndex];
117         Triangle tri;
118         tri.v[0] = vertices[f[0]];
119         tri.v[1] = vertices[f[1]];
120         tri.v[2] = vertices[f[2]];
121         tri.n[0] = normals[f[0]];
122         tri.n[1] = normals[f[1]];
123         tri.n[2] = normals[f[2]];
124         tri.t1[0] = texcoords[f[0]];
125         tri.t1[1] = texcoords[f[1]];
126         tri.t1[2] = texcoords[f[2]];
127         tri.normal = (tri.n[0] + tri.n[1] + tri.n[2]) / 3.0f;
128         return tri;
129     }
130     
131     int opApply(scope int delegate(Triangle t) dg)
132     {
133         int result = 0;
134 
135         foreach(i, ref f; indices)
136         {
137             Triangle tri = getTriangle(i);
138             result = dg(tri);
139             if (result)
140                 break;
141         }
142 
143         return result;
144     }
145     
146     void generateNormals()
147     {
148         if (normals.length == 0)
149             return;
150     
151         normals[] = Vector3f(0.0f, 0.0f, 0.0f);
152     
153         foreach(i, ref f; indices)
154         {
155             Vector3f v0 = vertices[f[0]];
156             Vector3f v1 = vertices[f[1]];
157             Vector3f v2 = vertices[f[2]];
158             
159             Vector3f p = cross(v1 - v0, v2 - v0);
160             
161             normals[f[0]] += p;
162             normals[f[1]] += p;
163             normals[f[2]] += p;
164         }
165         
166         foreach(i, n; normals)
167         {
168             normals[i] = n.normalized;
169         }
170     }
171     
172     void prepareVAO()
173     {
174         if (!dataReady)
175             return;
176 
177         glGenBuffers(1, &vbo);
178         glBindBuffer(GL_ARRAY_BUFFER, vbo);
179         glBufferData(GL_ARRAY_BUFFER, vertices.length * float.sizeof * 3, vertices.ptr, GL_STATIC_DRAW); 
180 
181         glGenBuffers(1, &nbo);
182         glBindBuffer(GL_ARRAY_BUFFER, nbo);
183         glBufferData(GL_ARRAY_BUFFER, normals.length * float.sizeof * 3, normals.ptr, GL_STATIC_DRAW);
184 
185         glGenBuffers(1, &tbo);
186         glBindBuffer(GL_ARRAY_BUFFER, tbo);
187         glBufferData(GL_ARRAY_BUFFER, texcoords.length * float.sizeof * 2, texcoords.ptr, GL_STATIC_DRAW);
188 
189         glGenBuffers(1, &eao);
190         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
191         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length * uint.sizeof * 3, indices.ptr, GL_STATIC_DRAW);
192 
193         glGenVertexArrays(1, &vao);
194         glBindVertexArray(vao);
195         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eao);
196     
197         glEnableVertexAttribArray(VertexAttrib.Vertices);
198         glBindBuffer(GL_ARRAY_BUFFER, vbo);
199         glVertexAttribPointer(VertexAttrib.Vertices, 3, GL_FLOAT, GL_FALSE, 0, null);
200     
201         glEnableVertexAttribArray(VertexAttrib.Normals);
202         glBindBuffer(GL_ARRAY_BUFFER, nbo);
203         glVertexAttribPointer(VertexAttrib.Normals, 3, GL_FLOAT, GL_FALSE, 0, null);
204     
205         glEnableVertexAttribArray(VertexAttrib.Texcoords);
206         glBindBuffer(GL_ARRAY_BUFFER, tbo);
207         glVertexAttribPointer(VertexAttrib.Texcoords, 2, GL_FLOAT, GL_FALSE, 0, null);
208 
209         glBindVertexArray(0);
210         
211         canRender = true;
212     }
213     
214     void render(GraphicsState* state)
215     {
216         if (canRender)
217         {
218             glBindVertexArray(vao);
219             glDrawElements(GL_TRIANGLES, cast(uint)indices.length * 3, GL_UNSIGNED_INT, cast(void*)0);
220             glBindVertexArray(0);
221         }
222     }
223 }