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