--- a/src/gl/compiler.cpp Tue May 24 16:11:10 2022 +0300 +++ b/src/gl/compiler.cpp Wed May 25 12:01:58 2022 +0300 @@ -125,17 +125,6 @@ } )"; -gl::Compiler::Compiler(Model *model, const ldraw::ColorTable& colorTable, QObject* parent) : - QObject{parent}, - model{model}, - colorTable{colorTable} -{ -} - -gl::Compiler::~Compiler() -{ -} - void gl::buildShaders( QOpenGLShaderProgram* shaderProgram, const char* vertexShaderSource, @@ -174,69 +163,40 @@ } } -void gl::Compiler::initialize() +void gl::initializeModelShaders(gl::ModelShaders *modelShaders) { - if (not this->initialized) + if (not modelShaders->initialized) { - this->initializeOpenGLFunctions(); - for (auto& object : this->glObjects) + for (auto& shader : modelShaders->shaderObjects) { - object.program = new QOpenGLShaderProgram; - gl::buildShaders(object.program, ::vertexShaderSource, ::fragmentShaderSource); - object.program->bind(); - object.buffer.create(); - object.buffer.bind(); - object.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); - object.vertexArray.create(); - object.vertexArray.bind(); + shader.program = std::make_unique<QOpenGLShaderProgram>(); + gl::buildShaders(shader.program.get(), ::vertexShaderSource, ::fragmentShaderSource); + shader.program->bind(); + shader.buffer.create(); + shader.buffer.bind(); + shader.buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw); + shader.vertexArray.create(); + shader.vertexArray.bind(); for (int k : {0, 1, 2, 3, 4}) { - object.program->enableAttributeArray(k); + shader.program->enableAttributeArray(k); } + using Vertex = ModelShaders::Vertex; constexpr int stride = sizeof(Vertex); - object.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride); - object.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride); - object.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride); + shader.program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 3, stride); + shader.program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, color), 4, stride); + shader.program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, normal), 3, stride); glVertexAttribIPointer(3, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, id))); glVertexAttribIPointer(4, 1, GL_INT, stride, reinterpret_cast<void*>(offsetof(Vertex, selected))); - object.vertexArray.release(); - object.buffer.release(); - object.program->release(); + shader.vertexArray.release(); + shader.buffer.release(); + shader.program->release(); } - this->initialized = true; + modelShaders->initialized = true; } } -void gl::Compiler::build(DocumentManager* context, const gl::RenderPreferences& preferences) -{ - this->boundingBox = {}; - std::vector<Vertex> vboData[gl::NUM_POLYGON_TYPES]; - std::optional<ModelId> modelId = context->findIdForModel(this->model); - if (modelId.has_value()) - { - PolygonCache* polygonBuilder = context->getPolygonCacheForModel(modelId.value()); - if (polygonBuilder != nullptr) - { - const std::vector<gl::Polygon> polygons = polygonBuilder->getPolygons(context); - for (const gl::Polygon& polygon : polygons) - { - this->buildPolygon(polygon, vboData, preferences); - } - for (int arrayId = 0; arrayId < gl::NUM_POLYGON_TYPES; arrayId += 1) - { - auto& buffer = this->glObjects[arrayId].buffer; - auto& vector = vboData[arrayId]; - this->storedVertexCounts[arrayId] = vector.size(); - this->glObjects[arrayId].cachedData = vector; // todo: get rid of this copy - buffer.bind(); - buffer.allocate(vector.data(), static_cast<int>(vector.size() * sizeof vector[0])); - buffer.release(); - } - } - } -} - -gl::ArrayClass classifyPolygon(const gl::Polygon& polygon) +static gl::ArrayClass classifyPolygon(const gl::Polygon& polygon) { switch (polygon.type) { @@ -252,36 +212,27 @@ return gl::ArrayClass::Lines; } -ldraw::id_t gl::Compiler::idFromColor(const std::array<GLubyte, 3>& data) -{ - return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]}; -} - -void gl::Compiler::buildPolygon( - gl::Polygon polygon, - std::vector<Vertex>* vboData, - const gl::RenderPreferences& preferences) +template<typename Fn> +void iterateModelPolygons(Model* model, DocumentManager* context, Fn&& fn) { - const gl::ArrayClass vboClass = classifyPolygon(polygon); - std::vector<Vertex>& vertexBuffer = vboData[static_cast<int>(vboClass)]; - auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); - reserveMore(vertexBuffer, polygon.numPolygonVertices()); - const QColor color = this->getColorForPolygon(polygon, preferences); - for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) + std::optional<ModelId> modelId = context->findIdForModel(model); + if (modelId.has_value()) { - const glm::vec3& v1 = vertexRing[i - 1]; - const glm::vec3& v2 = vertexRing[i]; - const glm::vec3& v3 = vertexRing[i + 1]; - this->boundingBox.consider(polygon.vertices[i]); - Vertex& vertex = vertexBuffer.emplace_back(); - vertex.position = polygon.vertices[i]; - vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2)); - vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()}; - vertex.id = polygon.id.value; + PolygonCache* polygonCache= context->getPolygonCacheForModel(modelId.value()); + if (polygonCache != nullptr) + { + for (const gl::Polygon& polygon : polygonCache->getPolygons(context)) + { + fn(polygon); + } + } } } -QColor gl::Compiler::getColorForPolygon(const gl::Polygon& polygon, const gl::RenderPreferences& preferences) +static QColor getColorForPolygon( + const gl::Polygon& polygon, + const gl::RenderPreferences& preferences, + const ldraw::ColorTable& colorTable) { QColor color; // For normal colors, use the polygon's color. @@ -297,41 +248,94 @@ else { // Not main or edge color, use the polygon's color as is. - color = this->colorTable[polygon.color].faceColor; + color = colorTable[polygon.color].faceColor; } return color; } -glm::vec3 gl::Compiler::modelCenter() const +/** + * @brief Computes the minimum bounding box for a model + */ +BoundingBox gl::boundingBoxForModel(Model* model, DocumentManager* context) { - return boxCenter(this->boundingBox); -} - -double gl::Compiler::modelDistance() const -{ - return static_cast<double>(longestMeasure(this->boundingBox)); + BoundingBox result = emptyBoundingBox; + iterateModelPolygons(model, context, [&](const gl::Polygon& polygon) + { + for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + addPointToBox(result, polygon.vertices[i]); + } + }); + return result; } -void gl::Compiler::bindVertexArray(gl::ArrayClass arrayClass) +/** + * @brief gl::build Creates GL vertices for objects in the model and buffers them to shaders. + */ +void gl::build( + gl::ModelShaders* shaders, + Model* model, + const ldraw::ColorTable& colorTable, + DocumentManager* context, + const gl::RenderPreferences& preferences) { - auto& object = this->glObjects[static_cast<int>(arrayClass)]; - object.vertexArray.bind(); - object.program->bind(); + for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects) { + shader.cachedData.clear(); + } + iterateModelPolygons(model, context, [&](const Polygon& polygon) + { + const int index = static_cast<int>(classifyPolygon(polygon)); + std::vector<gl::ModelShaders::Vertex>& vertexBuffer = shaders->shaderObjects[index].cachedData; + auto vertexRing = iter::ring(polygon.vertices, polygon.numPolygonVertices()); + reserveMore(vertexBuffer, polygon.numPolygonVertices()); + const QColor color = getColorForPolygon(polygon, preferences, colorTable); + for (unsigned int i = 0; i < polygon.numPolygonVertices(); i += 1) + { + const glm::vec3& v1 = vertexRing[i - 1]; + const glm::vec3& v2 = vertexRing[i]; + const glm::vec3& v3 = vertexRing[i + 1]; + gl::ModelShaders::Vertex& vertex = vertexBuffer.emplace_back(); + vertex.position = polygon.vertices[i]; + vertex.normal = glm::normalize(glm::cross(v1 - v2, v3 - v2)); + vertex.color = glm::vec4{color.redF(), color.greenF(), color.blueF(), color.alphaF()}; + vertex.id = polygon.id.value; + } + }); + for (gl::ModelShaders::ShaderObject& shader : shaders->shaderObjects) + { + shader.vertexCount = shader.cachedData.size(); + shader.buffer.bind(); + const int bytes = static_cast<int>(shader.cachedData.size() * sizeof shader.cachedData[0]); + shader.buffer.allocate(shader.cachedData.data(), bytes); + shader.buffer.release(); + } } -void gl::Compiler::releaseVertexArray(gl::ArrayClass arrayClass) +ldraw::id_t gl::idFromColor(const std::array<GLubyte, 3>& data) { - auto& object = this->glObjects[static_cast<int>(arrayClass)]; - object.program->release(); - object.vertexArray.release(); + return {data[0] * std::int32_t{0x10000} + data[1] * std::int32_t{0x100} + data[2]}; +} + +void gl::bindModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass) +{ + ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)]; + shaderObject.vertexArray.bind(); + shaderObject.program->bind(); } -void gl::Compiler::setSelectedObjects(const QSet<ldraw::id_t> ids) +void gl::releaseModelShaderVertexArray(gl::ModelShaders* shaders, gl::ArrayClass arrayClass) { - for (auto& object : this->glObjects) + ModelShaders::ShaderObject& shaderObject = shaders->shaderObjects[static_cast<int>(arrayClass)]; + shaderObject.program->release(); + shaderObject.vertexArray.release(); +} + +void gl::setModelShaderSelectedObjects(gl::ModelShaders* shaders, const QSet<ldraw::id_t>& ids) +{ + for (ModelShaders::ShaderObject& object : shaders->shaderObjects) { - std::vector<Vertex>& vector = object.cachedData; - for (Vertex& vertex : vector) + std::vector<ModelShaders::Vertex>& vector = object.cachedData; + for (ModelShaders::Vertex& vertex : vector) { vertex.selected = (ids.contains({vertex.id})) ? 1 : 0; } @@ -342,7 +346,7 @@ } } -std::size_t gl::Compiler::vertexCount(const gl::ArrayClass arrayClass) const +std::size_t gl::vertexCount(const gl::ModelShaders* shaders, const gl::ArrayClass arrayClass) { - return this->storedVertexCounts[static_cast<int>(arrayClass)]; + return shaders->shaderObjects[static_cast<int>(arrayClass)].vertexCount; }