| 172 QObject::tr("Could not link shaders: %1").arg(shaderProgram->log()) |
161 QObject::tr("Could not link shaders: %1").arg(shaderProgram->log()) |
| 173 ); |
162 ); |
| 174 } |
163 } |
| 175 } |
164 } |
| 176 |
165 |
| 177 void gl::Compiler::initialize() |
166 void gl::initializeModelShaders(gl::ModelShaders *modelShaders) |
| 178 { |
167 { |
| 179 if (not this->initialized) |
168 if (not modelShaders->initialized) |
| 180 { |
169 { |
| 181 this->initializeOpenGLFunctions(); |
170 for (auto& shader : modelShaders->shaderObjects) |
| 182 for (auto& object : this->glObjects) |
171 { |
| 183 { |
172 shader.program = std::make_unique<QOpenGLShaderProgram>(); |
| 184 object.program = new QOpenGLShaderProgram; |
173 gl::buildShaders(shader.program.get(), ::vertexShaderSource, ::fragmentShaderSource); |
| 185 gl::buildShaders(object.program, ::vertexShaderSource, ::fragmentShaderSource); |
174 shader.program->bind(); |
| 186 object.program->bind(); |
175 shader.buffer.create(); |
| 187 object.buffer.create(); |
176 shader.buffer.bind(); |
| 188 object.buffer.bind(); |
177 shader.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); |
| 189 object.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); |
178 shader.vertexArray.create(); |
| 190 object.vertexArray.create(); |
179 shader.vertexArray.bind(); |
| 191 object.vertexArray.bind(); |
|
| 192 for (int k : {0, 1, 2, 3, 4}) |
180 for (int k : {0, 1, 2, 3, 4}) |
| 193 { |
181 { |
| 194 object.program->enableAttributeArray(k); |
182 shader.program->enableAttributeArray(k); |
| 195 } |
183 } |
| |
184 using Vertex = ModelShaders::Vertex; |
| 196 constexpr int stride = sizeof(Vertex); |
185 constexpr int stride = sizeof(Vertex); |
| 197 object.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride); |
186 shader.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride); |
| 198 object.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride); |
187 shader.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride); |
| 199 object.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride); |
188 shader.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride); |
| 200 glVertexAttribIPointer(3, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, id))); |
189 glVertexAttribIPointer(3, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, id))); |
| 201 glVertexAttribIPointer(4, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, selected))); |
190 glVertexAttribIPointer(4, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, selected))); |
| 202 object.vertexArray.release(); |
191 shader.vertexArray.release(); |
| 203 object.buffer.release(); |
192 shader.buffer.release(); |
| 204 object.program->release(); |
193 shader.program->release(); |
| 205 } |
194 } |
| 206 this->initialized = true; |
195 modelShaders->initialized = true; |
| 207 } |
196 } |
| 208 } |
197 } |
| 209 |
198 |
| 210 void gl::Compiler::build(DocumentManager* context, const gl::RenderPreferences& preferences) |
199 static gl::ArrayClass classifyPolygon(const gl::Polygon& polygon) |
| 211 { |
|
| 212 this->boundingBox = {}; |
|
| 213 std::vector<Vertex> vboData[gl::NUM_POLYGON_TYPES]; |
|
| 214 std::optional<ModelId> modelId = context->findIdForModel(this->model); |
|
| 215 if (modelId.has_value()) |
|
| 216 { |
|
| 217 PolygonCache* polygonBuilder = context->getPolygonCacheForModel(modelId.value()); |
|
| 218 if (polygonBuilder != nullptr) |
|
| 219 { |
|
| 220 const std::vector<gl::Polygon> polygons = polygonBuilder->getPolygons(context); |
|
| 221 for (const gl::Polygon& polygon : polygons) |
|
| 222 { |
|
| 223 this->buildPolygon(polygon, vboData, preferences); |
|
| 224 } |
|
| 225 for (int arrayId = 0; arrayId < gl::NUM_POLYGON_TYPES; arrayId += 1) |
|
| 226 { |
|
| 227 auto& buffer = this->glObjects[arrayId].buffer; |
|
| 228 auto& vector = vboData[arrayId]; |
|
| 229 this->storedVertexCounts[arrayId] = vector.size(); |
|
| 230 this->glObjects[arrayId].cachedData = vector; // todo: get rid of this copy |
|
| 231 buffer.bind(); |
|
| 232 buffer.allocate(vector.data(), static_cast<int>(vector.size() * sizeof vector[0])); |
|
| 233 buffer.release(); |
|
| 234 } |
|
| 235 } |
|
| 236 } |
|
| 237 } |
|
| 238 |
|
| 239 gl::ArrayClass classifyPolygon(const gl::Polygon& polygon) |
|
| 240 { |
200 { |
| 241 switch (polygon.type) |
201 switch (polygon.type) |
| 242 { |
202 { |
| 243 case gl::Polygon::EdgeLine: |
203 case gl::Polygon::EdgeLine: |
| 244 return gl::ArrayClass::Lines; |
204 return gl::ArrayClass::Lines; |
| 250 return gl::ArrayClass::ConditionalLines; |
210 return gl::ArrayClass::ConditionalLines; |
| 251 } |
211 } |
| 252 return gl::ArrayClass::Lines; |
212 return gl::ArrayClass::Lines; |
| 253 } |
213 } |
| 254 |
214 |
| 255 ldraw::id_t gl::Compiler::idFromColor(const std::array<GLubyte, 3>& data) |
215 template<typename Fn> |
| 256 { |
216 void iterateModelPolygons(Model* model, DocumentManager* context, Fn&& fn) |
| 257 return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]}; |
217 { |
| 258 } |
218 std::optional<ModelId> modelId = context->findIdForModel(model); |
| 259 |
219 if (modelId.has_value()) |
| 260 void gl::Compiler::buildPolygon( |
220 { |
| 261 gl::Polygon polygon, |
221 PolygonCache* polygonCache= context->getPolygonCacheForModel(modelId.value()); |
| 262 std::vector<Vertex>* vboData, |
222 if (polygonCache != nullptr) |
| 263 const gl::RenderPreferences& preferences) |
223 { |
| 264 { |
224 for (const gl::Polygon& polygon : polygonCache->getPolygons(context)) |
| 265 const gl::ArrayClass vboClass = classifyPolygon(polygon); |
225 { |
| 266 std::vector<Vertex>& vertexBuffer = vboData[static_cast<int>(vboClass)]; |
226 fn(polygon); |
| 267 auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); |
227 } |
| 268 reserveMore(vertexBuffer, polygon.numPolygonVertices()); |
228 } |
| 269 const QColor color = this->getColorForPolygon(polygon, preferences); |
229 } |
| 270 for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) |
230 } |
| 271 { |
231 |
| 272 const glm::vec3& v1 = vertexRing[i - 1]; |
232 static QColor getColorForPolygon( |
| 273 const glm::vec3& v2 = vertexRing[i]; |
233 const gl::Polygon& polygon, |
| 274 const glm::vec3& v3 = vertexRing[i + 1]; |
234 const gl::RenderPreferences& preferences, |
| 275 this->boundingBox.consider(polygon.vertices[i]); |
235 const ldraw::ColorTable& colorTable) |
| 276 Vertex& vertex = vertexBuffer.emplace_back(); |
|
| 277 vertex.position = polygon.vertices[i]; |
|
| 278 vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2)); |
|
| 279 vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()}; |
|
| 280 vertex.id = polygon.id.value; |
|
| 281 } |
|
| 282 } |
|
| 283 |
|
| 284 QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, const gl::RenderPreferences& preferences) |
|
| 285 { |
236 { |
| 286 QColor color; |
237 QColor color; |
| 287 // For normal colors, use the polygon's color. |
238 // For normal colors, use the polygon's color. |
| 288 if (polygon.color == ldraw::MAIN_COLOR) |
239 if (polygon.color == ldraw::MAIN_COLOR) |
| 289 { |
240 { |
| 295 color = luma(preferences.backgroundColor) > (40.0 / 256.0) ? Qt::black : Qt::white; |
246 color = luma(preferences.backgroundColor) > (40.0 / 256.0) ? Qt::black : Qt::white; |
| 296 } |
247 } |
| 297 else |
248 else |
| 298 { |
249 { |
| 299 // Not main or edge color, use the polygon's color as is. |
250 // Not main or edge color, use the polygon's color as is. |
| 300 color = this->colorTable[polygon.color].faceColor; |
251 color = colorTable[polygon.color].faceColor; |
| 301 } |
252 } |
| 302 return color; |
253 return color; |
| 303 } |
254 } |
| 304 |
255 |
| 305 glm::vec3 gl::Compiler::modelCenter() const |
256 /** |
| 306 { |
257 * @brief Computes the minimum bounding box for a model |
| 307 return boxCenter(this->boundingBox); |
258 */ |
| 308 } |
259 BoundingBox gl::boundingBoxForModel(Model* model, DocumentManager* context) |
| 309 |
260 { |
| 310 double gl::Compiler::modelDistance() const |
261 BoundingBox result = emptyBoundingBox; |
| 311 { |
262 iterateModelPolygons(model, context, [&](const gl::Polygon& polygon) |
| 312 return static_cast<double>(longestMeasure(this->boundingBox)); |
263 { |
| 313 } |
264 for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) |
| 314 |
265 { |
| 315 void gl::Compiler::bindVertexArray(gl::ArrayClass arrayClass) |
266 addPointToBox(result, polygon.vertices[i]); |
| 316 { |
267 } |
| 317 auto& object = this->glObjects[static_cast<int>(arrayClass)]; |
268 }); |
| 318 object.vertexArray.bind(); |
269 return result; |
| 319 object.program->bind(); |
270 } |
| 320 } |
271 |
| 321 |
272 /** |
| 322 void gl::Compiler::releaseVertexArray(gl::ArrayClass arrayClass) |
273 * @brief gl::build Creates GL vertices for objects in the model and buffers them to shaders. |
| 323 { |
274 */ |
| 324 auto& object = this->glObjects[static_cast<int>(arrayClass)]; |
275 void gl::build( |
| 325 object.program->release(); |
276 gl::ModelShaders* shaders, |
| 326 object.vertexArray.release(); |
277 Model* model, |
| 327 } |
278 const ldraw::ColorTable& colorTable, |
| 328 |
279 DocumentManager* context, |
| 329 void gl::Compiler::setSelectedObjects(const QSet<ldraw::id_t> ids) |
280 const gl::RenderPreferences& preferences) |
| 330 { |
281 { |
| 331 for (auto& object : this->glObjects) |
282 for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects) { |
| 332 { |
283 shader.cachedData.clear(); |
| 333 std::vector<Vertex>& vector = object.cachedData; |
284 } |
| 334 for (Vertex& vertex : vector) |
285 iterateModelPolygons(model, context, [&](const Polygon& polygon) |
| |
286 { |
| |
287 const int index = static_cast<int>(classifyPolygon(polygon)); |
| |
288 std::vector<gl::ModelShaders::Vertex>& vertexBuffer = shaders->shaderObjects[index].cachedData; |
| |
289 auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); |
| |
290 reserveMore(vertexBuffer, polygon.numPolygonVertices()); |
| |
291 const QColor color = getColorForPolygon(polygon, preferences, colorTable); |
| |
292 for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) |
| |
293 { |
| |
294 const glm::vec3& v1 = vertexRing[i - 1]; |
| |
295 const glm::vec3& v2 = vertexRing[i]; |
| |
296 const glm::vec3& v3 = vertexRing[i + 1]; |
| |
297 gl::ModelShaders::Vertex& vertex = vertexBuffer.emplace_back(); |
| |
298 vertex.position = polygon.vertices[i]; |
| |
299 vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2)); |
| |
300 vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()}; |
| |
301 vertex.id = polygon.id.value; |
| |
302 } |
| |
303 }); |
| |
304 for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects) |
| |
305 { |
| |
306 shader.vertexCount = shader.cachedData.size(); |
| |
307 shader.buffer.bind(); |
| |
308 const int bytes = static_cast<int>(shader.cachedData.size() * sizeof shader.cachedData[0]); |
| |
309 shader.buffer.allocate(shader.cachedData.data(), bytes); |
| |
310 shader.buffer.release(); |
| |
311 } |
| |
312 } |
| |
313 |
| |
314 ldraw::id_t gl::idFromColor(const std::array<GLubyte, 3>& data) |
| |
315 { |
| |
316 return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]}; |
| |
317 } |
| |
318 |
| |
319 void gl::bindModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass) |
| |
320 { |
| |
321 ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)]; |
| |
322 shaderObject.vertexArray.bind(); |
| |
323 shaderObject.program->bind(); |
| |
324 } |
| |
325 |
| |
326 void gl::releaseModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass) |
| |
327 { |
| |
328 ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)]; |
| |
329 shaderObject.program->release(); |
| |
330 shaderObject.vertexArray.release(); |
| |
331 } |
| |
332 |
| |
333 void gl::setModelShaderSelectedObjects(gl::ModelShaders* shaders, const QSet<ldraw::id_t>& ids) |
| |
334 { |
| |
335 for (ModelShaders::ShaderObject& object : shaders->shaderObjects) |
| |
336 { |
| |
337 std::vector<ModelShaders::Vertex>& vector = object.cachedData; |
| |
338 for (ModelShaders::Vertex& vertex : vector) |
| 335 { |
339 { |
| 336 vertex.selected = (ids.contains({vertex.id})) ? 1 : 0; |
340 vertex.selected = (ids.contains({vertex.id})) ? 1 : 0; |
| 337 } |
341 } |
| 338 const GLsizeiptr size = static_cast<int>(vector.size() * sizeof vector[0]); |
342 const GLsizeiptr size = static_cast<int>(vector.size() * sizeof vector[0]); |
| 339 object.buffer.bind(); |
343 object.buffer.bind(); |
| 340 glBufferSubData(GL_ARRAY_BUFFER, 0, size, vector.data()); |
344 glBufferSubData(GL_ARRAY_BUFFER, 0, size, vector.data()); |
| 341 object.buffer.release(); |
345 object.buffer.release(); |
| 342 } |
346 } |
| 343 } |
347 } |
| 344 |
348 |
| 345 std::size_t gl::Compiler::vertexCount(const gl::ArrayClass arrayClass) const |
349 std::size_t gl::vertexCount(const gl::ModelShaders* shaders, const gl::ArrayClass arrayClass) |
| 346 { |
350 { |
| 347 return this->storedVertexCounts[static_cast<int>(arrayClass)]; |
351 return shaders->shaderObjects[static_cast<int>(arrayClass)].vertexCount; |
| 348 } |
352 } |