src/gl/compiler.cpp

changeset 189
815fbaae9cb2
parent 150
b6cbba6e29a1
child 193
b4beff48bb7a
equal deleted inserted replaced
188:64ea7282611e 189:815fbaae9cb2
123 fColor = vColor; 123 fColor = vColor;
124 } 124 }
125 } 125 }
126 )"; 126 )";
127 127
128 gl::Compiler::Compiler(Model *model, const ldraw::ColorTable& colorTable, QObject* parent) :
129 QObject{parent},
130 model{model},
131 colorTable{colorTable}
132 {
133 }
134
135 gl::Compiler::~Compiler()
136 {
137 }
138
139 void gl::buildShaders( 128 void gl::buildShaders(
140 QOpenGLShaderProgram* shaderProgram, 129 QOpenGLShaderProgram* shaderProgram,
141 const char* vertexShaderSource, 130 const char* vertexShaderSource,
142 const char* fragmentShaderSource) 131 const char* fragmentShaderSource)
143 { 132 {
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 }

mercurial