src/gl/common.h

Wed, 25 May 2022 20:36:34 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 25 May 2022 20:36:34 +0300
changeset 199
6988973515d2
parent 189
815fbaae9cb2
child 200
ca23936b455b
permissions
-rw-r--r--

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;
	};
}

mercurial