grid stuff

Wed, 26 Feb 2020 02:21:07 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 26 Feb 2020 02:21:07 +0200
changeset 55
cb81ecb5fb23
parent 54
a4055f67b9c7
child 56
fad4a5dd8dee

grid stuff

CMakeLists.txt file | annotate | diff | comparison | revisions
src/basics.h file | annotate | diff | comparison | revisions
src/geometry.cpp file | annotate | diff | comparison | revisions
src/geometry.h file | annotate | diff | comparison | revisions
src/gl/common.h file | annotate | diff | comparison | revisions
src/gl/gridprogram.cpp file | annotate | diff | comparison | revisions
src/gl/gridprogram.h file | annotate | diff | comparison | revisions
src/gl/partrenderer.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.h file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/maths.h file | annotate | diff | comparison | revisions
src/ui/canvas.cpp file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Thu Feb 13 15:25:01 2020 +0200
+++ b/CMakeLists.txt	Wed Feb 26 02:21:07 2020 +0200
@@ -25,6 +25,7 @@
 	src/colors.cpp
 	src/document.cpp
 	src/documentmanager.cpp
+	src/geometry.cpp
 	src/libraries.cpp
 	src/invert.cpp
 	src/main.cpp
@@ -58,6 +59,7 @@
 	src/colors.h
 	src/document.h
 	src/documentmanager.h
+	src/geometry.h
 	src/header.h
 	src/invert.h
 	src/libraries.h
--- a/src/basics.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/basics.h	Wed Feb 26 02:21:07 2020 +0200
@@ -108,30 +108,48 @@
 
 
 /**
-* @brief casts double and long double - and only those types - to float
-* @param[in] x double or long double to cast
+* @brief casts floating point values to float, converting non-floating point values causes an error
+* @param[in] x floating point value to cast
 * @returns float
 */
 template<typename T>
-auto doubleToFloat(T x)
-	-> std::enable_if_t<
-		std::is_same_v<std::decay_t<T>, double> ||
-		std::is_same_v<std::decay_t<T>, long double
-	>, float>
+auto toFloat(T x) -> std::enable_if_t<std::is_floating_point_v<T>, float>
 {
 	return static_cast<float>(x);
 }
 
 /**
-* @brief Casts float - and only float - to double
-* @param[in] x float to cast
+* @brief casts floating point values to double, converting non-floating point values causes an error
+* @param[in] x floating point value to cast
 * @returns double
 */
 template<typename T>
-auto floatToDouble(T x)
-	-> std::enable_if_t<std::is_same_v<std::decay_t<T>, float>, double>
+auto toDouble(T x) -> std::enable_if_t<std::is_floating_point_v<T>, double>
 {
 	return static_cast<double>(x);
 }
+
+template<int N, typename T, glm::qualifier Q>
+inline QPoint toQPoint(const glm::vec<N, T, Q>& vec)
+{
+	return {static_cast<int>(vec.x), static_cast<int>(vec.y)};
+}
+
+template<int N, typename T, glm::qualifier Q>
+inline QPointF toQPointF(const glm::vec<N, T, Q>& vec)
+{
+	return {toDouble(vec.x), toDouble(vec.y)};
+}
+
+inline glm::vec2 toVec2(const QPoint& point)
+{
+	return {point.x(), point.y()};
+}
+
+inline glm::vec2 toVec2(const QPointF& point)
+{
+	return {point.x(), point.y()};
+}
+
 Q_DECLARE_METATYPE(glm::vec3)
 Q_DECLARE_METATYPE(glm::mat4)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/geometry.cpp	Wed Feb 26 02:21:07 2020 +0200
@@ -0,0 +1,55 @@
+#include "geometry.h"
+
+/**
+ * @brief Computes a line from two points
+ * @param point_1
+ * @param point_2
+ * @return line
+ */
+geom::Line geom::lineFromPoints(const glm::vec3& point_1, const glm::vec3 point_2)
+{
+	return {point_2 - point_1, point_1};
+}
+
+/**
+ * @brief Computes line-plane intersection
+ * @param line
+ * @param plane
+ * @return point of intersection. Does not return a value if the line is in parallel to the plane.
+ */
+std::optional<glm::vec3> geom::linePlaneIntersection(const geom::Line& line, const geom::Plane& plane)
+{
+	const float denominator = glm::dot(line.direction, plane.normal);
+	if (std::abs(denominator) < 1e-8f)
+	{
+		return {};
+	}
+	else
+	{
+		const float d = glm::dot(plane.anchor - line.anchor, plane.normal) / denominator;
+		return line.anchor + d * line.direction;
+	}
+}
+
+/**
+ * @brief Computes the plane of a triangle
+ * @param triangle
+ * @return plane
+ */
+geom::Plane geom::planeFromTriangle(const geom::Triangle& triangle)
+{
+	return geom::Plane{triangle.points[0], normalVector(triangle)};
+}
+
+/**
+ * @brief Computes the normal vector of a triangle
+ * @param triangle
+ * @return normal vector
+ */
+glm::vec3 geom::normalVector(const geom::Triangle& triangle)
+{
+	return glm::normalize(
+		glm::cross(
+			triangle.points[1] - triangle.points[0],
+			triangle.points[2] - triangle.points[0]));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/geometry.h	Wed Feb 26 02:21:07 2020 +0200
@@ -0,0 +1,34 @@
+#pragma once
+#include "basics.h"
+
+namespace geom
+{
+	struct Plane
+	{
+		glm::vec3 normal;
+		glm::vec3 anchor;
+	};
+
+	struct Line
+	{
+		glm::vec3 direction;
+		glm::vec3 anchor;
+	};
+
+	template<int N>
+	struct Polygon
+	{
+		glm::vec3 points[N];
+	};
+
+	inline const glm::vec3 origin = {0, 0, 0};
+	inline const Plane XY = {{0, 0, 1}, origin};
+	inline const Plane XZ = {{0, 1, 0}, origin};
+	inline const Plane YZ = {{1, 0, 0}, origin};
+	using Triangle = Polygon<3>;
+
+	Line lineFromPoints(const glm::vec3& point_1, const glm::vec3 point_2);
+	Plane planeFromTriangle(const Triangle& triangle);
+	glm::vec3 normalVector(const Triangle& triangle);
+	std::optional<glm::vec3> linePlaneIntersection(const Line& line, const Plane& plane);
+}
--- a/src/gl/common.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/gl/common.h	Wed Feb 26 02:21:07 2020 +0200
@@ -37,6 +37,14 @@
 		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
@@ -50,11 +58,10 @@
 		const float (*array)[4][4] = reinterpret_cast<const float(*)[4][4]>(glm::value_ptr(value));
 		this->setUniformValue(uniformName, *array);
 	}
-	template<int N, typename Float, glm::qualifier Prec>
-	void setUniformVector(const char* uniformName, const glm::vec<N, Float, Prec>& value)
+	template<typename Float, glm::qualifier Prec>
+	void setUniformVector(const char* uniformName, const glm::vec<4, Float, Prec>& value)
 	{
-		const Float (*array)[N] = reinterpret_cast<const Float(*)[N]>(glm::value_ptr(value));
-		this->setUniformValue(uniformName, array);
+		this->setUniformValue(uniformName, value.x, value.y, value.z, value.w);
 	}
 };
 
--- a/src/gl/gridprogram.cpp	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/gl/gridprogram.cpp	Wed Feb 26 02:21:07 2020 +0200
@@ -42,7 +42,7 @@
 
 out vec4 color;
 smooth in vec2 ex_uv;
-const vec4 lineColor = vec4(1.0, 1.0, 1.0, 0.75);
+uniform vec4 gridColor;
 const float pi = 3.14159265f;
 
 void main(void)
@@ -58,7 +58,7 @@
 	/* add dashes */
 	d *= (1 + cos(ex_uv.y / 0.00001f * pi)) * 0.5f;
 	d *= (1 + cos(ex_uv.x / 0.00001f * pi)) * 0.5f;
-	color = vec4(lineColor.xyz, d);
+	color = vec4(gridColor.xyz, gridColor.w * d);
 }
 )";
 
@@ -89,6 +89,7 @@
 		this->vertexArrayObject.bind();
 		this->program->enableAttributeArray(0);
 		this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
+		this->program->setUniformVector("gridColor", this->gridColor);
 		this->vertexArrayObject.release();
 		this->buffer.release();
 		this->program->release();
@@ -123,6 +124,22 @@
 	this->checkForGLErrors();
 }
 
+void GridProgram::setGridColor(const QColor& newGridColor)
+{
+	const glm::vec4 vec = gl::colorToVector4(newGridColor);
+	if (this->isInitialized)
+	{
+		this->program->bind();
+		this->program->setUniformVector("gridColor", vec);
+		this->program->release();
+		this->checkForGLErrors();
+	}
+	else
+	{
+		this->gridColor = vec;
+	}
+}
+
 void GridProgram::draw()
 {
 	this->program->bind();
--- a/src/gl/gridprogram.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/gl/gridprogram.h	Wed Feb 26 02:21:07 2020 +0200
@@ -31,6 +31,7 @@
 	void setViewMatrix(const glm::mat4& newViewMatrix);
 	void setProjectionMatrix(const glm::mat4& newProjectionMatrix);
 	void setModelMatrix(const glm::mat4& newModelMatrix);
+	void setGridColor(const QColor& newGridColor);
 	void operator=(GridProgram) = delete;
 	void draw();
 	void teardown();
@@ -41,5 +42,6 @@
 	QOpenGLShader vertexShader;
 	QOpenGLShader fragmentShader;
 	std::optional<gl::ShaderProgram> program{std::nullopt};
+	glm::vec4 gridColor = {1.0f, 1.0f, 1.0f, 0.75f};
 	QOpenGLVertexArrayObject vertexArrayObject;
 };
--- a/src/gl/partrenderer.cpp	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/gl/partrenderer.cpp	Wed Feb 26 02:21:07 2020 +0200
@@ -22,6 +22,7 @@
 #include <QMouseEvent>
 #include <QMessageBox>
 #include <QAbstractButton>
+#include "geometry.h"
 #include "partrenderer.h"
 
 PartRenderer::PartRenderer(
@@ -62,6 +63,8 @@
 	this->initialized = true;
 	this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0});
 	this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0});
+	this->setupBackgroundColor();
+	this->updateModelMatrix();
 	this->updateViewMatrix();
 	this->update();
 }
@@ -69,6 +72,11 @@
 void PartRenderer::resizeGL(int width, int height)
 {
 	glViewport(0, 0, width, height);
+	this->viewportMatrix = {
+		{1, 0, 0},
+		{0, 1, 0},
+		{width * 0.5f, height * 0.5f, 1}
+	};
 	this->projectionMatrix = glm::perspective(
 		glm::radians(45.0f),
 		static_cast<float>(width) / static_cast<float>(height),
@@ -194,6 +202,23 @@
 	this->gridProgram->setViewMatrix(this->viewMatrix);
 }
 
+void PartRenderer::updateModelMatrix()
+{
+	const glm::mat4 modelMatrix = glm::mat4_cast(this->modelQuaternion);
+	this->compiler->setUniformMatrix("modelMatrix", modelMatrix);
+	this->gridProgram->setModelMatrix(modelMatrix);
+	this->update();
+}
+
+void PartRenderer::setupBackgroundColor()
+{
+	if (this->gridProgram.has_value())
+	{
+		const bool isDark = luma(this->renderPreferences.backgroundColor) < 0.25;
+		this->gridProgram->setGridColor(isDark ? Qt::white : Qt::black);
+	}
+}
+
 void PartRenderer::renderVao(const gl::ArrayClass arrayClass)
 {
 	this->compiler->bindVertexArray(arrayClass);
@@ -246,10 +271,7 @@
 		const glm::quat q_x = glm::angleAxis(scalar * move_x, glm::vec3{0, -1, 0});
 		const glm::quat q_y = glm::angleAxis(scalar * move_y, glm::vec3{-1, 0, 0});
 		this->modelQuaternion = q_x * q_y * this->modelQuaternion;
-		const glm::mat4 modelMatrix = glm::mat4_cast(this->modelQuaternion);
-		this->compiler->setUniformMatrix("modelMatrix", modelMatrix);
-		this->gridProgram->setModelMatrix(modelMatrix);
-		this->update();
+		this->updateModelMatrix();
 	}
 	this->lastMousePosition = pointToPointF(event->pos());
 }
@@ -263,6 +285,33 @@
 	this->update();
 }
 
+std::optional<glm::vec3> PartRenderer::cameraToGrid(const QPoint& point)
+{
+	glm::vec3 pp = {point.x(), this->height() - point.y(), 1};
+	pp = glm::inverse(this->viewportMatrix) * pp;
+	glm::mat4 matrix;
+	matrix = this->projectionMatrix * this->viewMatrix * glm::mat4_cast(this->modelQuaternion);
+	matrix = glm::transpose(glm::inverse(matrix));
+	auto p1 = matrix * glm::vec4{pp.x, pp.y, 0, 1};
+	auto p2 = matrix * glm::vec4{pp.x, pp.y, 1, 1};
+	geom::Line line = geom::lineFromPoints(p1, p2);
+	return geom::linePlaneIntersection(line, geom::XY);
+}
+
+QPointF PartRenderer::worldToCamera(const glm::vec3& point)
+{
+	glm::vec4 p = {point, 1};
+	p = glm::mat4_cast(this->modelQuaternion) * p;
+	p = this->viewMatrix * p;
+	p = this->projectionMatrix * p;
+	glm::vec2 pp = this->viewportMatrix * glm::vec3{p.x, p.y, 1};
+	return toQPointF(pp);
+	/*
+	const glm::mat4 matrix = this->projectionMatrix * this->viewMatrix * glm::mat4_cast(this->modelQuaternion);
+	return toQPointF(matrix * glm::vec4{point, 1});
+	*/
+}
+
 ldraw::Id PartRenderer::pick(const QPoint& where)
 {
 	const gl::RenderStyle oldRenderStyle = this->renderPreferences.style;
@@ -299,6 +348,8 @@
 	if (mainColorChanged or backgroundColorChanged)
 	{
 		this->compiler->build(this->model, this->documents, this->renderPreferences);
+		this->setupBackgroundColor();
+
 	}
 	this->update();
 }
--- a/src/gl/partrenderer.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/gl/partrenderer.h	Wed Feb 26 02:21:07 2020 +0200
@@ -35,15 +35,20 @@
 	const ldraw::ColorTable& colorTable;
 	gl::Compiler* const compiler;
 	ldraw::Id highlighted = ldraw::NULL_ID;
+	std::optional<glm::vec3> cameraToGrid(const QPoint& point);
+	QPointF worldToCamera(const glm::vec3& point);
 private:
 	void setFragmentStyle(gl::FragmentStyle fragStyle);
 	void renderAllArrays();
 	void renderScene();
 	void updateViewMatrix();
+	void updateModelMatrix();
+	void setupBackgroundColor();
 	QPointF lastMousePosition;
 	gl::RenderPreferences renderPreferences;
 	glm::mat4 projectionMatrix;
 	glm::mat4 viewMatrix;
+	glm::mat3 viewportMatrix;
 	glm::quat modelQuaternion;
 	std::optional<GridProgram> gridProgram;
 	static constexpr double MIN_ZOOM = 0.0;
--- a/src/main.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/main.h	Wed Feb 26 02:21:07 2020 +0200
@@ -24,6 +24,7 @@
 #include "basics.h"
 #include "utility.h"
 #include "maths.h"
+#include "geometry.h"
 
 namespace settingGroups
 {
--- a/src/maths.h	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/maths.h	Wed Feb 26 02:21:07 2020 +0200
@@ -90,6 +90,8 @@
 	{
 		return arg + sum<T>(rest...);
 	}
+
+	std::optional<glm::vec3> linePlaneIntersection();
 }
 
 inline unsigned int qHash(const glm::vec3& key)
--- a/src/ui/canvas.cpp	Thu Feb 13 15:25:01 2020 +0200
+++ b/src/ui/canvas.cpp	Wed Feb 26 02:21:07 2020 +0200
@@ -22,8 +22,21 @@
 
 void Canvas::mouseMoveEvent(QMouseEvent* event)
 {
+#if 0
+	std::optional<glm::vec3> p = this->cameraToGrid(event->pos());
+	if (p.has_value())
+	{
+		this->newStatusText("Position: (%1, %2, %3)"_q.arg(p->x).arg(p->y).arg(p->z));
+	}
+	else
+	{
+		this->newStatusText("Position: <none>"_q);
+	}
+#else
+	const QPointF originAtCamera = this->worldToCamera({1, 1, 1});
+	this->newStatusText("Origin at (%1, %2), cursor at (%3, %4)"_q.arg(originAtCamera.x()).arg(originAtCamera.y()).arg(event->pos().x()).arg(event->pos().y()));
+#endif
 	const ldraw::Id id = this->pick(event->pos());
-	this->newStatusText("Selected: %1"_q.arg(id.value));
 	this->highlighted = id;
 	this->totalMouseMove += (event->pos() - this->lastMousePosition).manhattanLength();
 	this->lastMousePosition = event->pos();

mercurial