Wed, 25 May 2022 20:36:34 +0300
Fix pick() picking from weird places on the screen with high DPI scaling
glReadPixels reads data from the frame buffer, which contains data after
high DPI scaling, so any reads to that need to take this scaling into account
/* * LDForge: LDraw parts authoring CAD * Copyright (C) 2013 - 2018 Teemu Piippo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <QWidget> #include <QColor> #include <QOpenGLBuffer> #include <QOpenGLFunctions> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QOpenGLVertexArrayObject> #include <glm/gtc/type_ptr.hpp> #include "basics.h" #include "colors.h" namespace gl { struct Polygon; class ShaderProgram; void buildShaders( QOpenGLShaderProgram* shaderProgram, const char* vertexShaderSource, const char* fragmentShaderSource); void checkForGLErrors(QWidget* parent); inline glm::vec3 colorToVector3(const QColor& color) { return {toFloat(color.redF()), toFloat(color.greenF()), toFloat(color.blueF())}; } inline glm::vec4 colorToVector4(const QColor& color) { return {gl::colorToVector3(color), toFloat(color.alphaF())}; } } class gl::ShaderProgram : public QOpenGLShaderProgram { public: using QOpenGLShaderProgram::QOpenGLShaderProgram; // for some reason I cannot overload setUniformValue properly with this template thing template<typename Float, glm::qualifier Prec> void setUniformMatrix(const char* uniformName, const glm::mat<4, 4, Float, Prec>& value) { const float (*array)[4][4] = reinterpret_cast<const float(*)[4][4]>(glm::value_ptr(value)); this->setUniformValue(uniformName, *array); } template<typename Float, glm::qualifier Prec> void setUniformVector(const char* uniformName, const glm::vec<4, Float, Prec>& value) { this->setUniformValue(uniformName, value.x, value.y, value.z, value.w); } }; struct gl::Polygon { enum Type : qint8 { EdgeLine, Triangle, Quadrilateral, ConditionalEdge } type; glm::vec3 vertices[4]; ldraw::Color color; ldraw::id_t id; /** * @return amount of vertices used for geometry */ inline unsigned int numPolygonVertices() const { if (type == Type::ConditionalEdge) return 2; else return numVertices(); } /** * @return amount of vertices */ inline unsigned int numVertices() const { switch (type) { case Type::EdgeLine: return 2; case Type::Triangle: return 3; case Type::ConditionalEdge: case Type::Quadrilateral: return 4; } return 0; } }; Q_DECLARE_METATYPE(gl::Polygon) extern QOpenGLFunctions glfunc; namespace gl { constexpr Polygon::Type POLYGON_TYPES[] = { Polygon::Type::EdgeLine, Polygon::Type::Triangle, Polygon::Type::Quadrilateral, Polygon::Type::ConditionalEdge }; constexpr int NUM_POLYGON_TYPES = countof(POLYGON_TYPES); inline Polygon edgeLine(const glm::vec3& v_1, const glm::vec3& v_2, ldraw::Color color, ldraw::id_t id) { return {Polygon::EdgeLine, {v_1, v_2}, color, id}; } inline Polygon triangle( const glm::vec3& v_1, const glm::vec3& v_2, const glm::vec3& v_3, ldraw::Color color, ldraw::id_t id) { return {Polygon::Triangle, {v_1, v_2, v_3}, color, id}; } inline Polygon quadrilateral( const glm::vec3& v_1, const glm::vec3& v_2, const glm::vec3& v_3, const glm::vec3& v_4, ldraw::Color color, ldraw::id_t id) { return {Polygon::Quadrilateral, {v_1, v_2, v_3, v_4}, color, id}; } inline Polygon conditionalEdge( const glm::vec3& v_1, const glm::vec3& v_2, const glm::vec3& control_1, const glm::vec3& control_2, ldraw::Color color, ldraw::id_t id) { return {Polygon::ConditionalEdge, {v_1, v_2, control_1, control_2}, color, id}; } // Vbo names enum class ArrayClass : std::uint8_t { Lines, Triangles, Quads, ConditionalLines }; constexpr ArrayClass ARRAY_CLASSES[] = { ArrayClass::Lines, ArrayClass::Triangles, ArrayClass::Quads, ArrayClass::ConditionalLines, }; constexpr int NUM_ARRAY_CLASSES = countof(ARRAY_CLASSES); // Different ways to render the scene enum class RenderStyle { // Normal rendering style Normal, // Render all polygons as lines Wireframe, // Use green colour for front faces and red colour for back faces BfcRedGreen, // Use a different colour for each object RandomColors, // Render so that the colour of an object has an one to one correspondence with its id PickScene, // Render a scene where vertices can be picked VertexPickScene, }; // Different ways to render fragments. // These are also defined in shaders enum class FragmentStyle { // Use normal colours Normal = 0, // Use a distinctive green colour for BFC red/green view BfcGreen = 1, // Use a distinctive red colour for BFC red/green view BfcRed = 2, // Use a colour based on the object to distinguish objects RandomColors = 3, // Use a colour that codes the object's id Id = 4, // Render everything black Black = 5, }; // User options for rendering struct RenderPreferences { gl::RenderStyle style = gl::RenderStyle::Normal; QColor mainColor{255, 255, 64}; QColor backgroundColor{48, 48, 48}; QColor selectedColor{32, 32, 255}; GLfloat lineThickness = 2.0f; bool lineAntiAliasing = true; bool drawAxes = true; }; }