src/gl/partrenderer.cpp

changeset 31
b6df269a2c6b
parent 30
1536f23cfab7
child 32
767592024ec5
--- a/src/gl/partrenderer.cpp	Thu Jan 23 00:29:10 2020 +0200
+++ b/src/gl/partrenderer.cpp	Sun Jan 26 00:55:36 2020 +0200
@@ -48,8 +48,9 @@
 	this->compiler->build(this->model, this->documents);
 	this->initializeLighting();
 	this->initialized = true;
-	this->rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30);
-	this->rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330);
+	this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{1, 0, 0});
+	this->modelQuaternion *= glm::angleAxis(glm::radians(330.0f), glm::vec3{0, 1, 0});
+	this->updateViewMatrix();
 	glLineWidth(2.0);
 	this->update();
 }
@@ -74,10 +75,10 @@
 {
 	glViewport(0, 0, width, height);
 	this->projectionMatrix = glm::perspective(
-		glm::radians(90.0f),
+		glm::radians(45.0f),
 		static_cast<float>(width) / static_cast<float>(height),
 		0.1f,
-		100.f);
+		10000.f);
 }
 
 static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass)
@@ -127,7 +128,7 @@
 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 		break;
 	}
-	this->compiler->setUniformMatrix("CameraTransformation", this->projectionMatrix * this->viewMatrix);
+	this->compiler->setUniformMatrix("CameraTransformation", this->projectionMatrix * this->viewMatrix * glm::mat4_cast(this->modelQuaternion));
 	// Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering.
 	renderVao(gl::ArrayClass::Triangles);
 	renderVao(gl::ArrayClass::Quads);
@@ -135,6 +136,13 @@
 	glDisable(GL_POLYGON_OFFSET_FILL);
 }
 
+void PartRenderer::updateViewMatrix()
+{
+	// I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior
+	const double z  = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance());
+	this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0});
+}
+
 void PartRenderer::renderVao(const gl::ArrayClass arrayClass)
 {
 	this->compiler->bindVertexArray(arrayClass);
@@ -168,20 +176,29 @@
 	const QPointF move = pointToPointF(event->pos()) - this->lastMousePosition;
 	if (left and not move.isNull())
 	{
-		// FIXME: find a more elegant way to do this
-		const QQuaternion versor = QQuaternion::fromAxisAndAngle(
-			QVector3D{static_cast<float>(-move.y()), static_cast<float>(move.x()), 0.0f},
-			0.6f * static_cast<float>(std::hypot(move.x(), move.y()))
-		);
-		this->rotation = versor * this->rotation;
-		QVector3D cameraPosition = this->rotation.rotatedVector({0, 0, static_cast<float>(2 + 2 * this->compiler->modelDistance())});
-		glm::vec3 cameraPosition_glm = {cameraPosition.x(), cameraPosition.y(), cameraPosition.z()};
-		this->viewMatrix = glm::lookAt(cameraPosition_glm, {0, 0, 0}, {0, -1, 0});
+		// q_x is the rotation of the brick along the vertical y-axis, because turning the
+		// vertical axis causes horizontal (=x) rotation. Likewise q_y is the rotation of the
+		// brick along the horizontal x-axis, which causes vertical rotation.
+		const auto scalar = 0.006f;
+		const float move_x = static_cast<float>(move.x());
+		const float move_y = static_cast<float>(move.y());
+		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;
 		this->update();
 	}
 	this->lastMousePosition = pointToPointF(event->pos());
 }
 
+void PartRenderer::wheelEvent(QWheelEvent* event)
+{
+	static constexpr double WHEEL_STEP = 1 / 1000.0;
+	const double move = (-event->angleDelta().y()) * WHEEL_STEP;
+	this->zoom = std::clamp(this->zoom + move, MIN_ZOOM, MAX_ZOOM);
+	this->updateViewMatrix();
+	this->update();
+}
+
 void PartRenderer::setRenderStyle(const gl::RenderStyle newStyle)
 {
 	this->renderStyle = newStyle;

mercurial