|
1 /* |
|
2 * LDForge: LDraw parts authoring CAD |
|
3 * Copyright (C) 2013 - 2018 Teemu Piippo |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include "vertexcompiler.h" |
|
20 #include "vertexselection.h" |
|
21 #include "model.h" |
|
22 |
|
23 static const Vertex sphere[] = { |
|
24 {1, 0, 0}, {0.7071, 0.7071, 0}, {0.7071, 0, 0.7071}, |
|
25 {0, 0.7071, 0.7071}, {0, 0, 1}, {0.7071, 0, 0.7071}, |
|
26 {0.7071, 0.7071, 0}, {0, 0.7071, 0.7071}, {0.7071, 0, 0.7071}, |
|
27 {0, 1, 0}, {0, 0.7071, 0.7071}, {0.7071, 0.7071, 0}, |
|
28 {0.7071, 0, -0.7071}, {0.7071, 0.7071, 0}, {1, 0, 0}, |
|
29 {0.7071, 0, -0.7071}, {0, 0, -1}, {0, 0.7071, -0.7071}, |
|
30 {0.7071, 0, -0.7071}, {0, 0.7071, -0.7071}, {0.7071, 0.7071, 0}, |
|
31 {0.7071, 0.7071, 0}, {0, 0.7071, -0.7071}, {0, 1, 0}, |
|
32 {-0.7071, 0, 0.7071}, {-0.7071, 0.7071, 0}, {-1, 0, 0}, |
|
33 {-0.7071, 0, 0.7071}, {0, 0, 1}, {0, 0.7071, 0.7071}, |
|
34 {-0.7071, 0, 0.7071}, {0, 0.7071, 0.7071}, {-0.7071, 0.7071, 0}, |
|
35 {-0.7071, 0.7071, 0}, {0, 0.7071, 0.7071}, {0, 1, 0}, |
|
36 {-1, 0, 0}, {-0.7071, 0.7071, 0}, {-0.7071, 0, -0.7071}, |
|
37 {0, 0.7071, -0.7071}, {0, 0, -1}, {-0.7071, 0, -0.7071}, |
|
38 {-0.7071, 0.7071, 0}, {0, 0.7071, -0.7071}, {-0.7071, 0, -0.7071}, |
|
39 {0, 1, 0}, {0, 0.7071, -0.7071}, {-0.7071, 0.7071, 0}, |
|
40 {-0.7071, 0, -0.7071}, {0, 0, -1}, {0, -0.7071, -0.7071}, |
|
41 {0, -1, 0}, {0, -0.7071, 0.7071}, {-0.7071, -0.7071, 0}, |
|
42 {0.7071, -0.7071, 0}, {0, -0.7071, -0.7071}, {0.7071, 0, -0.7071}, |
|
43 {-1, 0, 0}, {-0.7071, -0.7071, 0}, {-0.7071, 0, 0.7071}, |
|
44 {-0.7071, -0.7071, 0}, {0, -0.7071, -0.7071}, {0, -1, 0}, |
|
45 {0, -1, 0}, {0, -0.7071, -0.7071}, {0.7071, -0.7071, 0}, |
|
46 {0.7071, 0, 0.7071}, {0, -0.7071, 0.7071}, {0.7071, -0.7071, 0}, |
|
47 {-0.7071, 0, -0.7071}, {-0.7071, -0.7071, 0}, {-1, 0, 0}, |
|
48 {1, 0, 0}, {0.7071, -0.7071, 0}, {0.7071, 0, -0.7071}, |
|
49 {0.7071, 0, 0.7071}, {0, 0, 1}, {0, -0.7071, 0.7071}, |
|
50 {-0.7071, 0, -0.7071}, {0, -0.7071, -0.7071}, {-0.7071, -0.7071, 0}, |
|
51 {0.7071, -0.7071, 0}, {0, -0.7071, 0.7071}, {0, -1, 0}, |
|
52 {0.7071, 0, 0.7071}, {0.7071, -0.7071, 0}, {1, 0, 0}, |
|
53 {-0.7071, -0.7071, 0}, {0, -0.7071, 0.7071}, {-0.7071, 0, 0.7071}, |
|
54 {0, -0.7071, -0.7071}, {0, 0, -1}, {0.7071, 0, -0.7071}, |
|
55 {0, -0.7071, 0.7071}, {0, 0, 1}, {-0.7071, 0, 0.7071}, |
|
56 }; |
|
57 |
|
58 static const float sphereSize = 0.5; |
|
59 static const QColor sphereColor {192, 192, 255}; |
|
60 |
|
61 VertexCompiler::VertexCompiler(Model* model, VertexSelection* selection, QObject* parent) : |
|
62 QObject {parent}, |
|
63 model {model} |
|
64 { |
|
65 connect(model, &Model::objectAdded, this, &VertexCompiler::handleNewObject); |
|
66 connect(model, &Model::aboutToRemoveObject, this, &VertexCompiler::handleRemovedObject); |
|
67 |
|
68 if (selection != nullptr) |
|
69 { |
|
70 this->connect( |
|
71 selection, |
|
72 &VertexSelection::vertexSelected, |
|
73 this, |
|
74 &VertexCompiler::updateVertex |
|
75 ); |
|
76 this->connect( |
|
77 selection, |
|
78 &VertexSelection::vertexDeselected, |
|
79 this, |
|
80 &VertexCompiler::updateVertex |
|
81 ); |
|
82 } |
|
83 } |
|
84 |
|
85 VertexCompiler::~VertexCompiler() |
|
86 { |
|
87 if (this->initialized) |
|
88 { |
|
89 GLuint buffers[NumVbos]; |
|
90 |
|
91 for (int i = 0; i < countof(this->vbos); i += 1) |
|
92 buffers[i] = this->vbos[i].buffer; |
|
93 |
|
94 this->glDeleteBuffers(countof(buffers), &buffers[0]); |
|
95 } |
|
96 } |
|
97 |
|
98 void VertexCompiler::handleNewObject(const QModelIndex &index) |
|
99 { |
|
100 LDObject* object = this->model->lookup(index); |
|
101 this->addVerticesFromObject(object); |
|
102 connect(object, &LDObject::aboutToBeModified, this, &VertexCompiler::handlePreModifiedObject); |
|
103 connect(object, &LDObject::modified, this, &VertexCompiler::handleModifiedObject); |
|
104 } |
|
105 |
|
106 void VertexCompiler::handleRemovedObject(const QModelIndex &index) |
|
107 { |
|
108 LDObject* object = this->model->lookup(index); |
|
109 this->removeVerticesFromObject(object); |
|
110 } |
|
111 |
|
112 void VertexCompiler::handlePreModifiedObject() |
|
113 { |
|
114 removeVerticesFromObject(qobject_cast<LDObject*>(this->sender())); |
|
115 } |
|
116 |
|
117 void VertexCompiler::handleModifiedObject() |
|
118 { |
|
119 addVerticesFromObject(qobject_cast<LDObject*>(this->sender())); |
|
120 } |
|
121 |
|
122 void VertexCompiler::initialize() |
|
123 { |
|
124 if (not this->initialized) |
|
125 { |
|
126 this->initializeOpenGLFunctions(); |
|
127 this->initialized = true; |
|
128 GLuint buffers[NumVbos]; |
|
129 this->glGenBuffers(countof(buffers), &buffers[0]); |
|
130 |
|
131 for (int i = 0; i < countof(this->vbos); i += 1) |
|
132 this->vbos[i].buffer = buffers[i]; |
|
133 } |
|
134 } |
|
135 |
|
136 void VertexCompiler::addVerticesFromObject(LDObject* object) |
|
137 { |
|
138 for (int i = 0; i < object->numPolygonVertices(); i += 1) |
|
139 this->addVertex(object->vertex(i)); |
|
140 |
|
141 this->needCompile = true; |
|
142 } |
|
143 |
|
144 void VertexCompiler::removeVerticesFromObject(LDObject* object) |
|
145 { |
|
146 for (int i = 0; i < object->numPolygonVertices(); i += 1) |
|
147 this->removeVertex(object->vertex(i)); |
|
148 |
|
149 this->needCompile = true; |
|
150 } |
|
151 |
|
152 void VertexCompiler::addVertex(const Vertex& vertex) |
|
153 { |
|
154 auto iterator = this->vertices.find(vertex); |
|
155 |
|
156 if (iterator == this->vertices.end()) |
|
157 this->vertices.insert(vertex, 1); |
|
158 else |
|
159 iterator.value() += 1; |
|
160 } |
|
161 |
|
162 void VertexCompiler::removeVertex(const Vertex& vertex) |
|
163 { |
|
164 auto iterator = this->vertices.find(vertex); |
|
165 |
|
166 if (iterator != this->vertices.end()) |
|
167 { |
|
168 if (iterator.value() > 1) |
|
169 iterator.value() -= 1; |
|
170 else |
|
171 this->vertices.erase(iterator); |
|
172 } |
|
173 } |
|
174 |
|
175 void VertexCompiler::updateVertex(const Vertex&) |
|
176 { |
|
177 this->needCompile = true; |
|
178 } |
|
179 |
|
180 /* |
|
181 * Returns the GL buffer for the given vbo. |
|
182 */ |
|
183 GLuint VertexCompiler::vbo(Vbo vboIndex) |
|
184 { |
|
185 if (this->needCompile) |
|
186 { |
|
187 this->compile(); |
|
188 this->upload(); |
|
189 this->needCompile = false; |
|
190 } |
|
191 |
|
192 return this->vbos[vboIndex].buffer; |
|
193 } |
|
194 |
|
195 /* |
|
196 * Returns the size of the given vbo. |
|
197 */ |
|
198 size_t VertexCompiler::vboSize(Vbo vboIndex) const |
|
199 { |
|
200 return this->vbos[vboIndex].data.size(); |
|
201 } |
|
202 |
|
203 /* |
|
204 * Clears the vertex scene. |
|
205 */ |
|
206 void VertexCompiler::clear() |
|
207 { |
|
208 for (auto& vbo : this->vbos) |
|
209 vbo.data.clear(); |
|
210 } |
|
211 |
|
212 /* |
|
213 * Builds the vertex scene |
|
214 */ |
|
215 void VertexCompiler::compile() |
|
216 { |
|
217 this->clear(); |
|
218 QMapIterator<Vertex, unsigned int> iterator {this->vertices}; |
|
219 |
|
220 while (iterator.hasNext()) |
|
221 { |
|
222 iterator.next(); |
|
223 this->compileVertex(iterator.key()); |
|
224 } |
|
225 } |
|
226 |
|
227 /* |
|
228 * Adds a little sphere into the scene to represent the given vertex. |
|
229 */ |
|
230 void VertexCompiler::compileVertex(const Vertex& vertex) |
|
231 { |
|
232 for (int i = 0; i < countof(::sphere); i += 1) |
|
233 { |
|
234 // Y and Z inverted like the rest of the scene |
|
235 Vertex spherePoint = { |
|
236 ::sphere[i][X] * ::sphereSize + vertex.x, |
|
237 ::sphere[i][Y] * ::sphereSize - vertex.y, |
|
238 ::sphere[i][Z] * ::sphereSize - vertex.z |
|
239 }; |
|
240 this->vbos[Surfaces].data << spherePoint.x << spherePoint.y << spherePoint.z; |
|
241 // The points of the sphere are position vectors, which in this case are also unit normals. |
|
242 this->vbos[Normals].data << ::sphere[i][X] << ::sphere[i][Y] << ::sphere[i][Z]; |
|
243 this->vbos[Colors].data |
|
244 << ::sphereColor.redF() |
|
245 << ::sphereColor.greenF() |
|
246 << ::sphereColor.blueF() |
|
247 << ::sphereColor.alphaF(); |
|
248 } |
|
249 } |
|
250 |
|
251 /* |
|
252 * Uploads VBO data to the graphics card. |
|
253 */ |
|
254 void VertexCompiler::upload() |
|
255 { |
|
256 for (const auto& vbo : this->vbos) |
|
257 { |
|
258 glBindBuffer(GL_ARRAY_BUFFER, vbo.buffer); |
|
259 glBufferData( |
|
260 GL_ARRAY_BUFFER, |
|
261 countof(vbo.data) * sizeof(GLfloat), |
|
262 vbo.data.constData(), |
|
263 GL_STATIC_DRAW |
|
264 ); |
|
265 } |
|
266 glBindBuffer(GL_ARRAY_BUFFER, 0); |
|
267 } |