src/gl/partrenderer.cpp

changeset 26
3a9e761e4faa
parent 24
1a0faaaceb84
child 27
c57fb7a5ffa3
equal deleted inserted replaced
25:6de5ac1fb471 26:3a9e761e4faa
14 * 14 *
15 * You should have received a copy of the GNU General Public License 15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19 #include <GL/glut.h>
19 #include <QMouseEvent> 20 #include <QMouseEvent>
20 #include <GL/glut.h> 21 #include <QMessageBox>
21 #include "partrenderer.h" 22 #include "partrenderer.h"
22 23
23 PartRenderer::PartRenderer(Model* model, DocumentManager* documents, QWidget* parent) : 24
25 static const char* vertexShaderSource = R"(
26 #version 330 core
27
28 layout(location=0) in vec3 position;
29 layout(location=1) in vec4 color;
30 out vec4 vColor;
31 uniform mat4 CameraTransformation;
32
33 void main()
34 {
35 vColor = color;
36 gl_Position = CameraTransformation * vec4(position, 1.0);
37 }
38 )";
39
40 static const char* fragmentShaderSource = R"(
41 #version 330 core
42
43 in vec4 vColor;
44 out vec4 fColor;
45
46 void main()
47 {
48 fColor = vColor;
49 }
50 )";
51
52 PartRenderer::PartRenderer(Model* model, DocumentManager* documents, const ColorTable& colorTable, QWidget* parent) :
24 QOpenGLWidget{parent}, 53 QOpenGLWidget{parent},
25 model{model}, 54 model{model},
26 documents{documents}, 55 documents{documents},
27 compiler{new gl::Compiler{this}} 56 colorTable{colorTable},
57 compiler{new gl::Compiler{this->colorTable, this}}
28 { 58 {
29 this->setMouseTracking(true); 59 this->setMouseTracking(true);
60 }
61
62 PartRenderer::~PartRenderer()
63 {
64 delete this->objects.program;
30 } 65 }
31 66
32 void PartRenderer::initializeGL() 67 void PartRenderer::initializeGL()
33 { 68 {
34 this->initializeOpenGLFunctions(); 69 this->initializeOpenGLFunctions();
35 if (glGetError() != GL_NO_ERROR) 70 if (glGetError() != GL_NO_ERROR)
36 { 71 {
37 abort(); 72 abort();
38 } 73 }
74 glEnableClientState(GL_NORMAL_ARRAY);
75 glEnableClientState(GL_VERTEX_ARRAY);
76 //this->compiler->initialize();
77 //this->compiler->build(this->model, this->documents);
39 this->initializeLighting(); 78 this->initializeLighting();
40 this->initialized = true; 79 this->initialized = true;
41 this->rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30); 80 this->rotation = QQuaternion::fromAxisAndAngle({1, 0, 0}, 30);
42 this->rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330); 81 this->rotation *= QQuaternion::fromAxisAndAngle({0, 1, 0}, 330);
43 this->compiler->build(this->model, this->documents);
44 glLineWidth(2.0); 82 glLineWidth(2.0);
83 this->objects.program = new QOpenGLShaderProgram;
84 this->objects.program->create();
85 this->checkForGLErrors();
86 this->objects.program->addShaderFromSourceCode(QOpenGLShader::Vertex, ::vertexShaderSource);
87 this->checkForGLErrors();
88 this->objects.program->addShaderFromSourceCode(QOpenGLShader::Fragment, ::fragmentShaderSource);
89 this->checkForGLErrors();
90 this->objects.program->link();
91 this->checkForGLErrors();
92 this->objects.program->bind();
93 this->checkForGLErrors();
94 this->objects.buffer.create();
95 this->checkForGLErrors();
96 this->objects.buffer.bind();
97 this->checkForGLErrors();
98 this->objects.buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
99 this->checkForGLErrors();
100 /*
101 GLfloat data[] = {
102 20.0f, 20.0f, 6.0f, 1.0f, 0.0f, 0.0f, 1.0f,
103 30.0f, 20.0f, 6.0f, 0.0f, 1.0f, 0.0f, 1.0f,
104 30.0f, 30.0f, 6.0f, 0.0f, 0.0f, 1.0f, 1.0f,
105 };
106 */
107 GLfloat data[] = {
108 0.00f, 0.75f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
109 -0.75f, -0.75f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
110 0.75f, -0.75f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f
111 };
112 this->objects.buffer.allocate(data, sizeof data);
113 this->checkForGLErrors();
114 this->objects.vertexArray.create();
115 this->checkForGLErrors();
116 this->objects.vertexArray.bind();
117 this->checkForGLErrors();
118 this->objects.program->enableAttributeArray(0);
119 this->checkForGLErrors();
120 this->objects.program->enableAttributeArray(1);
121 this->checkForGLErrors();
122 this->objects.program->setAttributeBuffer(0, GL_FLOAT, 0, 3);
123 this->checkForGLErrors();
124 this->objects.program->setAttributeBuffer(1, GL_FLOAT, 3, 4);
125 this->checkForGLErrors();
126 this->objects.vertexArray.release();
127 this->checkForGLErrors();
128 this->objects.buffer.release();
129 this->checkForGLErrors();
130 this->objects.program->release();
131 this->checkForGLErrors();
45 } 132 }
46 133
47 /* 134 /*
48 * Pads a 3×3 matrix into a 4×4 one by adding cells from the identity matrix. 135 * Pads a 3×3 matrix into a 4×4 one by adding cells from the identity matrix.
49 */ 136 */
83 glLoadIdentity(); 170 glLoadIdentity();
84 gluPerspective(45.0, static_cast<double>(width) / static_cast<double>(height), near, far); 171 gluPerspective(45.0, static_cast<double>(width) / static_cast<double>(height), near, far);
85 glMatrixMode(GL_MODELVIEW); 172 glMatrixMode(GL_MODELVIEW);
86 } 173 }
87 174
88 static GLenum getGlTypeForVboClass(const gl::VboClass vboClass) 175 static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass)
89 { 176 {
90 switch (vboClass) 177 switch (vboClass)
91 { 178 {
92 case gl::VboClass::Lines: 179 case gl::ArrayClass::Lines:
93 case gl::VboClass::ConditionalLines: 180 case gl::ArrayClass::ConditionalLines:
94 return GL_LINES; 181 return GL_LINES;
95 case gl::VboClass::Triangles: 182 case gl::ArrayClass::Triangles:
96 return GL_TRIANGLES; 183 return GL_TRIANGLES;
97 case gl::VboClass::Quads: 184 case gl::ArrayClass::Quads:
98 return GL_QUADS; 185 return GL_QUADS;
99 } 186 }
100 throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"}; 187 throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"};
101 } 188 }
102 189
103 // https://www.codemiles.com/c-opengl-examples/drawing-teapot-using-opengl-t9010.html?mobile=on
104 #include <QMessageBox>
105 void PartRenderer::paintGL() 190 void PartRenderer::paintGL()
106 { 191 {
192 /*
107 glEnable (GL_BLEND); 193 glEnable (GL_BLEND);
108 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 194 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
109 glEnable (GL_POLYGON_OFFSET_FILL); 195 */
110 glPolygonOffset (1.0f, 1.0f);
111 glEnable (GL_DEPTH_TEST); 196 glEnable (GL_DEPTH_TEST);
112 glShadeModel (GL_SMOOTH); 197 glShadeModel (GL_SMOOTH);
113 glEnable (GL_MULTISAMPLE); 198 glEnable (GL_MULTISAMPLE);
114 glEnable (GL_LINE_SMOOTH); 199 glEnable (GL_LINE_SMOOTH);
115 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); 200 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
116 this->renderScene(); 201 this->renderScene();
117 } 202 }
118 203
119 void PartRenderer::renderScene() 204 void PartRenderer::renderScene()
120 { 205 {
206 glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
208 glMatrixMode(GL_MODELVIEW);
209 glEnable(GL_DEPTH_TEST);
210 glEnable(GL_LIGHTING);
211 glLoadIdentity();
212 //glTranslated(0.0, 0.0, -4.5 * this->compiler->modelDistance());
213 //glTranslated(0.0, 0.0, -4.5);
214 //glMultMatrixf(padMatrix(this->rotation.toRotationMatrix()).constData());
215 //xyz(glTranslatef, -this->compiler->modelCenter());
216 auto rotationMatrix = padMatrix(this->rotation.toRotationMatrix());
217 rotationMatrix(2, 3) = 0;
218 glEnable(GL_POLYGON_OFFSET_FILL);
219 glPolygonOffset(1.0f, 1.0f);
121 switch (this->renderStyle) 220 switch (this->renderStyle)
122 { 221 {
123 case gl::RenderStyle::Normal: 222 case gl::RenderStyle::Normal:
124 case gl::RenderStyle::BfcRedGreen: 223 case gl::RenderStyle::BfcRedGreen:
125 case gl::RenderStyle::RandomColors: 224 case gl::RenderStyle::RandomColors:
126 break; 225 break;
127 case gl::RenderStyle::Wireframe: 226 case gl::RenderStyle::Wireframe:
128 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 227 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
129 break; 228 break;
130 } 229 }
131 glMatrixMode(GL_MODELVIEW); 230 this->objects.program->bind();
132 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 231 this->checkForGLErrors();
133 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 232 const int cameraTransformationUniform = glGetUniformLocation(this->objects.program->programId(), "CameraTransformation");
134 glEnable(GL_DEPTH_TEST); 233 this->checkForGLErrors();
135 glEnable(GL_LIGHTING); 234 this->objects.program->setUniformValue(cameraTransformationUniform, rotationMatrix);
136 glLoadIdentity(); 235 this->checkForGLErrors();
137 glTranslatef(0.0, 0.0, -4.5 * this->compiler->modelDistance()); 236 this->objects.vertexArray.bind();
138 glMultMatrixf(padMatrix(this->rotation.toRotationMatrix()).constData()); 237 this->checkForGLErrors();
139 xyz(glTranslatef, -this->compiler->modelCenter()); 238 glDrawArrays(GL_TRIANGLES, 0, 3);
140 glEnableClientState(GL_NORMAL_ARRAY); 239 this->checkForGLErrors();
141 glEnableClientState(GL_VERTEX_ARRAY); 240 this->objects.vertexArray.release();
142 glEnableClientState(GL_COLOR_ARRAY); 241 this->checkForGLErrors();
143 for (const gl::VboClass vboClass : {gl::VboClass::Lines, gl::VboClass::Triangles, gl::VboClass::Quads}) 242 this->objects.program->release();
144 { 243 this->checkForGLErrors();
145 const GLuint vboSurfaces = this->compiler->vbo({vboClass, gl::VboSubclass::Surfaces}); 244 #if 0
146 const GLuint vboColors = this->compiler->vbo({vboClass, gl::VboSubclass::RegularColors}); 245 // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering.
147 const GLuint vboNormals = this->compiler->vbo({vboClass, gl::VboSubclass::Normals}); 246 renderVao(gl::ArrayClass::Triangles);
148 const std::size_t count = this->compiler->vboSize({vboClass, gl::VboSubclass::Surfaces}) / 3_z; 247 renderVao(gl::ArrayClass::Quads);
149 glBindBuffer(GL_ARRAY_BUFFER, vboSurfaces); 248 renderVao(gl::ArrayClass::Lines);
150 glVertexPointer(3, GL_FLOAT, 0, nullptr); 249 #endif
151 glBindBuffer(GL_ARRAY_BUFFER, vboColors); 250 glDisable(GL_POLYGON_OFFSET_FILL);
152 glColorPointer(4, GL_FLOAT, 0, nullptr); 251 }
153 glBindBuffer(GL_ARRAY_BUFFER, vboNormals); 252
154 glNormalPointer(GL_FLOAT, 0, nullptr); 253 void PartRenderer::renderVao(const gl::ArrayClass /*arrayClass*/)
155 glDrawArrays(getGlTypeForVboClass(vboClass), 0, static_cast<GLsizei>(count)); 254 {
156 } 255 /*
157 glBindBuffer(GL_ARRAY_BUFFER, 0); 256 this->compiler->bindVertexArray(arrayClass);
158 glDisableClientState(GL_NORMAL_ARRAY); 257 const std::size_t vertexCount = this->compiler->vboSize({arrayClass, gl::VboSubclass::VertexData}) / gl::FLOATS_PER_VERTEX;
159 glDisableClientState(GL_VERTEX_ARRAY); 258 glDrawArrays(getGlTypeForArrayClass(arrayClass), 0, static_cast<GLsizei>(vertexCount));
160 glDisableClientState(GL_COLOR_ARRAY); 259 this->compiler->releaseVertexArray(arrayClass);
161 const GLenum glError = this->glGetError(); 260 this->checkForGLErrors();
162 if (glError != GL_NO_ERROR) 261 */
262 }
263
264 void PartRenderer::checkForGLErrors()
265 {
266 GLenum glError;
267 QStringList errors;
268 while ((glError = glGetError()) != GL_NO_ERROR)
163 { 269 {
164 const QString glErrorString = QString::fromLatin1(reinterpret_cast<const char*>(::gluErrorString(glError))); 270 const QString glErrorString = QString::fromLatin1(reinterpret_cast<const char*>(::gluErrorString(glError)));
271 errors.append(glErrorString);
272 }
273 if (not errors.isEmpty())
274 {
165 QMessageBox::critical( 275 QMessageBox::critical(
166 this, 276 this,
167 tr("Rendering error"), 277 tr("Rendering error"),
168 QString{"Failed to render: %1"}.arg(glErrorString)); 278 QString{"Failed to render.\n%1"}.arg(errors.join("\n")));
169 } 279 }
170 glDisable(GL_CULL_FACE); 280 }
171 }
172
173 static QPointF pointToPointF(const QPoint& point)
174 {
175 return {static_cast<qreal>(point.x()), static_cast<qreal>(point.y())};
176 }
177
178 /*
179 static QPoint pointFToPoint(const QPointF& point)
180 {
181 return {static_cast<int>(std::round(point.x())), static_cast<int>(std::round(point.y()))};
182 }
183 */
184 281
185 void PartRenderer::mouseMoveEvent(QMouseEvent* event) 282 void PartRenderer::mouseMoveEvent(QMouseEvent* event)
186 { 283 {
187 const bool left = event->buttons() & Qt::LeftButton; 284 const bool left = event->buttons() & Qt::LeftButton;
188 const QPointF move = pointToPointF(event->pos()) - this->lastMousePosition; 285 const QPointF move = pointToPointF(event->pos()) - this->lastMousePosition;

mercurial