src/gl/common.h

Wed, 08 Jun 2022 23:02:04 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 08 Jun 2022 23:02:04 +0300
changeset 207
5315358a7d91
parent 206
654661eab7f3
child 210
232e7634cc8a
permissions
-rw-r--r--

well that's embarrassing

/*
 *  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"
#include "model.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 {float_cast(color.redF()), float_cast(color.greenF()), float_cast(color.blueF())};
	}
	inline glm::vec4 colorToVector4(const QColor& color)
	{
		return {gl::colorToVector3(color), float_cast(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;
	ModelId 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 Colored<LineSegment>& seg, ModelId id)
	{
		return Polygon{
			.type = Polygon::EdgeLine,
			.vertices = {seg.p1, seg.p2},
			.color = seg.color,
			.id = id,
		};
	}

	inline Polygon triangle(const Colored<Triangle>& tri, ModelId id)
	{
		return Polygon{
			.type = Polygon::Triangle,
			.vertices = {tri.p1, tri.p2, tri.p3},
			.color = tri.color,
			.id = id,
		};
	}

	inline Polygon quadrilateral(const Colored<Quadrilateral>& quad, ModelId id)
	{
		return Polygon{
			.type = Polygon::Quadrilateral,
			.vertices = {quad.p1, quad.p2, quad.p3, quad.p4},
			.color = quad.color,
			.id = id,
		};
	}

	inline Polygon conditionalEdge(const Colored<ConditionalEdge>& cedge, ModelId id)
	{
		return Polygon{
			.type = Polygon::ConditionalEdge,
			.vertices = {cedge.p1, cedge.p2, cedge.c1, cedge.c2},
			.color = cedge.color,
			.id = 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