src/gl/partrenderer.cpp

changeset 26
3a9e761e4faa
parent 24
1a0faaaceb84
child 27
c57fb7a5ffa3
--- a/src/gl/partrenderer.cpp	Sun Jan 19 14:25:57 2020 +0200
+++ b/src/gl/partrenderer.cpp	Wed Jan 22 00:23:29 2020 +0200
@@ -16,19 +16,54 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <GL/glut.h>
 #include <QMouseEvent>
-#include <GL/glut.h>
+#include <QMessageBox>
 #include "partrenderer.h"
 
-PartRenderer::PartRenderer(Model* model, DocumentManager* documents, QWidget* parent) :
+
+static const char* vertexShaderSource = R"(
+#version 330 core
+
+layout(location=0) in vec3 position;
+layout(location=1) in vec4 color;
+out vec4 vColor;
+uniform mat4 CameraTransformation;
+
+void main()
+{
+	vColor = color;
+	gl_Position = CameraTransformation * vec4(position, 1.0);
+}
+)";
+
+static const char* fragmentShaderSource = R"(
+#version 330 core
+
+in vec4 vColor;
+out vec4 fColor;
+
+void main()
+{
+	fColor = vColor;
+}
+)";
+
+PartRenderer::PartRenderer(Model* model, DocumentManager* documents, const ColorTable& colorTable, QWidget* parent) :
 	QOpenGLWidget{parent},
 	model{model},
 	documents{documents},
-	compiler{new gl::Compiler{this}}
+	colorTable{colorTable},
+	compiler{new gl::Compiler{this->colorTable, this}}
 {
 	this->setMouseTracking(true);
 }
 
+PartRenderer::~PartRenderer()
+{
+	delete this->objects.program;
+}
+
 void PartRenderer::initializeGL()
 {
 	this->initializeOpenGLFunctions();
@@ -36,12 +71,64 @@
 	{
 		abort();
 	}
+	glEnableClientState(GL_NORMAL_ARRAY);
+	glEnableClientState(GL_VERTEX_ARRAY);
+	//this->compiler->initialize();
+	//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->compiler->build(this->model, this->documents);
 	glLineWidth(2.0);
+	this->objects.program = new QOpenGLShaderProgram;
+	this->objects.program->create();
+	this->checkForGLErrors();
+	this->objects.program->addShaderFromSourceCode(QOpenGLShader::Vertex, ::vertexShaderSource);
+	this->checkForGLErrors();
+	this->objects.program->addShaderFromSourceCode(QOpenGLShader::Fragment, ::fragmentShaderSource);
+	this->checkForGLErrors();
+	this->objects.program->link();
+	this->checkForGLErrors();
+	this->objects.program->bind();
+	this->checkForGLErrors();
+	this->objects.buffer.create();
+	this->checkForGLErrors();
+	this->objects.buffer.bind();
+	this->checkForGLErrors();
+	this->objects.buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+	this->checkForGLErrors();
+	/*
+	GLfloat data[] = {
+		20.0f, 20.0f, 6.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+		30.0f, 20.0f, 6.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+		30.0f, 30.0f, 6.0f, 0.0f, 0.0f, 1.0f, 1.0f,
+	};
+	*/
+	GLfloat data[] = {
+		0.00f, 0.75f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+		-0.75f, -0.75f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+		0.75f, -0.75f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f
+	};
+	this->objects.buffer.allocate(data, sizeof data);
+	this->checkForGLErrors();
+	this->objects.vertexArray.create();
+	this->checkForGLErrors();
+	this->objects.vertexArray.bind();
+	this->checkForGLErrors();
+	this->objects.program->enableAttributeArray(0);
+	this->checkForGLErrors();
+	this->objects.program->enableAttributeArray(1);
+	this->checkForGLErrors();
+	this->objects.program->setAttributeBuffer(0, GL_FLOAT, 0, 3);
+	this->checkForGLErrors();
+	this->objects.program->setAttributeBuffer(1, GL_FLOAT, 3, 4);
+	this->checkForGLErrors();
+	this->objects.vertexArray.release();
+	this->checkForGLErrors();
+	this->objects.buffer.release();
+	this->checkForGLErrors();
+	this->objects.program->release();
+	this->checkForGLErrors();
 }
 
 /*
@@ -85,29 +172,27 @@
 	glMatrixMode(GL_MODELVIEW);
 }
 
-static GLenum getGlTypeForVboClass(const gl::VboClass vboClass)
+static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass)
 {
 	switch (vboClass)
 	{
-	case gl::VboClass::Lines:
-	case gl::VboClass::ConditionalLines:
+	case gl::ArrayClass::Lines:
+	case gl::ArrayClass::ConditionalLines:
 		return GL_LINES;
-	case gl::VboClass::Triangles:
+	case gl::ArrayClass::Triangles:
 		return GL_TRIANGLES;
-	case gl::VboClass::Quads:
+	case gl::ArrayClass::Quads:
 		return GL_QUADS;
 	}
 	throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"};
 }
 
-// https://www.codemiles.com/c-opengl-examples/drawing-teapot-using-opengl-t9010.html?mobile=on
-#include <QMessageBox>
 void PartRenderer::paintGL()
 {
+	/*
 	glEnable (GL_BLEND);
 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	glEnable (GL_POLYGON_OFFSET_FILL);
-	glPolygonOffset (1.0f, 1.0f);
+	*/
 	glEnable (GL_DEPTH_TEST);
 	glShadeModel (GL_SMOOTH);
 	glEnable (GL_MULTISAMPLE);
@@ -118,6 +203,20 @@
 
 void PartRenderer::renderScene()
 {
+	glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	glMatrixMode(GL_MODELVIEW);
+	glEnable(GL_DEPTH_TEST);
+	glEnable(GL_LIGHTING);
+	glLoadIdentity();
+	//glTranslated(0.0, 0.0, -4.5 * this->compiler->modelDistance());
+	//glTranslated(0.0, 0.0, -4.5);
+	//glMultMatrixf(padMatrix(this->rotation.toRotationMatrix()).constData());
+	//xyz(glTranslatef, -this->compiler->modelCenter());
+	auto rotationMatrix = padMatrix(this->rotation.toRotationMatrix());
+	rotationMatrix(2, 3) = 0;
+	glEnable(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(1.0f, 1.0f);
 	switch (this->renderStyle)
 	{
 	case gl::RenderStyle::Normal:
@@ -128,60 +227,58 @@
 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 		break;
 	}
-	glMatrixMode(GL_MODELVIEW);
-	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	glEnable(GL_DEPTH_TEST);
-	glEnable(GL_LIGHTING);
-	glLoadIdentity();
-	glTranslatef(0.0, 0.0, -4.5 * this->compiler->modelDistance());
-	glMultMatrixf(padMatrix(this->rotation.toRotationMatrix()).constData());
-	xyz(glTranslatef, -this->compiler->modelCenter());
-	glEnableClientState(GL_NORMAL_ARRAY);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnableClientState(GL_COLOR_ARRAY);
-	for (const gl::VboClass vboClass : {gl::VboClass::Lines, gl::VboClass::Triangles, gl::VboClass::Quads})
-	{
-		const GLuint vboSurfaces = this->compiler->vbo({vboClass, gl::VboSubclass::Surfaces});
-		const GLuint vboColors = this->compiler->vbo({vboClass, gl::VboSubclass::RegularColors});
-		const GLuint vboNormals = this->compiler->vbo({vboClass, gl::VboSubclass::Normals});
-		const std::size_t count = this->compiler->vboSize({vboClass, gl::VboSubclass::Surfaces}) / 3_z;
-		glBindBuffer(GL_ARRAY_BUFFER, vboSurfaces);
-		glVertexPointer(3, GL_FLOAT, 0, nullptr);
-		glBindBuffer(GL_ARRAY_BUFFER, vboColors);
-		glColorPointer(4, GL_FLOAT, 0, nullptr);
-		glBindBuffer(GL_ARRAY_BUFFER, vboNormals);
-		glNormalPointer(GL_FLOAT, 0, nullptr);
-		glDrawArrays(getGlTypeForVboClass(vboClass), 0, static_cast<GLsizei>(count));
-	}
-	glBindBuffer(GL_ARRAY_BUFFER, 0);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-	const GLenum glError = this->glGetError();
-	if (glError != GL_NO_ERROR)
+	this->objects.program->bind();
+	this->checkForGLErrors();
+	const int cameraTransformationUniform = glGetUniformLocation(this->objects.program->programId(), "CameraTransformation");
+	this->checkForGLErrors();
+	this->objects.program->setUniformValue(cameraTransformationUniform, rotationMatrix);
+	this->checkForGLErrors();
+	this->objects.vertexArray.bind();
+	this->checkForGLErrors();
+	glDrawArrays(GL_TRIANGLES, 0, 3);
+	this->checkForGLErrors();
+	this->objects.vertexArray.release();
+	this->checkForGLErrors();
+	this->objects.program->release();
+	this->checkForGLErrors();
+#if 0
+	// Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering.
+	renderVao(gl::ArrayClass::Triangles);
+	renderVao(gl::ArrayClass::Quads);
+	renderVao(gl::ArrayClass::Lines);
+#endif
+	glDisable(GL_POLYGON_OFFSET_FILL);
+}
+
+void PartRenderer::renderVao(const gl::ArrayClass /*arrayClass*/)
+{
+	/*
+	this->compiler->bindVertexArray(arrayClass);
+	const std::size_t vertexCount = this->compiler->vboSize({arrayClass, gl::VboSubclass::VertexData}) / gl::FLOATS_PER_VERTEX;
+	glDrawArrays(getGlTypeForArrayClass(arrayClass), 0, static_cast<GLsizei>(vertexCount));
+	this->compiler->releaseVertexArray(arrayClass);
+	this->checkForGLErrors();
+	*/
+}
+
+void PartRenderer::checkForGLErrors()
+{
+	GLenum glError;
+	QStringList errors;
+	while ((glError = glGetError()) != GL_NO_ERROR)
 	{
 		const QString glErrorString = QString::fromLatin1(reinterpret_cast<const char*>(::gluErrorString(glError)));
+		errors.append(glErrorString);
+	}
+	if (not errors.isEmpty())
+	{
 		QMessageBox::critical(
 			this,
 			tr("Rendering error"),
-			QString{"Failed to render: %1"}.arg(glErrorString));
+			QString{"Failed to render.\n%1"}.arg(errors.join("\n")));
 	}
-	glDisable(GL_CULL_FACE);
 }
 
-static QPointF pointToPointF(const QPoint& point)
-{
-	return {static_cast<qreal>(point.x()), static_cast<qreal>(point.y())};
-}
-
-/*
-static QPoint pointFToPoint(const QPointF& point)
-{
-	return {static_cast<int>(std::round(point.x())), static_cast<int>(std::round(point.y()))};
-}
-*/
-
 void PartRenderer::mouseMoveEvent(QMouseEvent* event)
 {
 	const bool left = event->buttons() & Qt::LeftButton;

mercurial