| 31 QWidget* parent) : |
31 QWidget* parent) : |
| 32 QOpenGLWidget{parent}, |
32 QOpenGLWidget{parent}, |
| 33 model{model}, |
33 model{model}, |
| 34 documents{documents}, |
34 documents{documents}, |
| 35 colorTable{colorTable}, |
35 colorTable{colorTable}, |
| 36 compiler{new gl::Compiler{this->colorTable, this}} |
36 compiler{new gl::Compiler{this->colorTable, this}}, |
| |
37 gridProgram{this} |
| 37 { |
38 { |
| 38 this->setMouseTracking(true); |
39 this->setMouseTracking(true); |
| 39 } |
40 } |
| 40 |
41 |
| 41 PartRenderer::~PartRenderer() |
42 PartRenderer::~PartRenderer() |
| 42 { |
43 { |
| |
44 } |
| |
45 |
| |
46 static QVector3D vec3FromQColor(const QColor& color) |
| |
47 { |
| |
48 return {(float)color.redF(), (float)color.greenF(), (float)color.blueF()}; |
| 43 } |
49 } |
| 44 |
50 |
| 45 void PartRenderer::initializeGL() |
51 void PartRenderer::initializeGL() |
| 46 { |
52 { |
| 47 this->initializeOpenGLFunctions(); |
53 this->initializeOpenGLFunctions(); |
| 48 if (glGetError() != GL_NO_ERROR) |
54 if (glGetError() != GL_NO_ERROR) |
| 49 { |
55 { |
| 50 abort(); |
56 abort(); |
| 51 } |
57 } |
| |
58 this->gridProgram.emplace(this); |
| |
59 this->gridProgram->initialize(); |
| 52 this->compiler->initialize(); |
60 this->compiler->initialize(); |
| 53 this->compiler->build(this->model, this->documents, this->renderPreferences); |
61 this->compiler->build(this->model, this->documents, this->renderPreferences); |
| 54 this->initialized = true; |
62 this->initialized = true; |
| 55 this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0}); |
63 this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0}); |
| 56 this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0}); |
64 this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0}); |
| 65 glm::radians(45.0f), |
73 glm::radians(45.0f), |
| 66 static_cast<float>(width) / static_cast<float>(height), |
74 static_cast<float>(width) / static_cast<float>(height), |
| 67 0.1f, |
75 0.1f, |
| 68 10000.f); |
76 10000.f); |
| 69 this->compiler->setUniformMatrix("projectionMatrix", this->projectionMatrix); |
77 this->compiler->setUniformMatrix("projectionMatrix", this->projectionMatrix); |
| |
78 this->gridProgram->setProjectionMatrix(this->projectionMatrix); |
| 70 } |
79 } |
| 71 |
80 |
| 72 static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass) |
81 static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass) |
| 73 { |
82 { |
| 74 switch (vboClass) |
83 switch (vboClass) |
| 86 |
95 |
| 87 void PartRenderer::paintGL() |
96 void PartRenderer::paintGL() |
| 88 { |
97 { |
| 89 glEnable(GL_DEPTH_TEST); |
98 glEnable(GL_DEPTH_TEST); |
| 90 glShadeModel(GL_SMOOTH); |
99 glShadeModel(GL_SMOOTH); |
| 91 glEnable(GL_MULTISAMPLE); |
|
| 92 this->renderScene(); |
100 this->renderScene(); |
| 93 } |
101 } |
| 94 |
102 |
| 95 static QVector3D vec3FromQColor(const QColor& color) |
|
| 96 { |
|
| 97 return {(float)color.redF(), (float)color.greenF(), (float)color.blueF()}; |
|
| 98 } |
|
| 99 |
|
| 100 void PartRenderer::renderScene() |
103 void PartRenderer::renderScene() |
| 101 { |
104 { |
| |
105 this->checkForGLErrors(); |
| 102 if (this->renderPreferences.lineAntiAliasing && this->renderPreferences.style != gl::RenderStyle::PickScene) |
106 if (this->renderPreferences.lineAntiAliasing && this->renderPreferences.style != gl::RenderStyle::PickScene) |
| 103 { |
107 { |
| 104 glEnable(GL_LINE_SMOOTH); |
108 glEnable(GL_LINE_SMOOTH); |
| 105 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
109 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
| 106 } |
110 } |
| 120 else |
124 else |
| 121 { |
125 { |
| 122 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
126 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| 123 this->compiler->setUniform("useLighting", GL_FALSE); |
127 this->compiler->setUniform("useLighting", GL_FALSE); |
| 124 } |
128 } |
| |
129 this->checkForGLErrors(); |
| 125 this->compiler->setUniform("selectedColor", vec3FromQColor(this->renderPreferences.selectedColor)); |
130 this->compiler->setUniform("selectedColor", vec3FromQColor(this->renderPreferences.selectedColor)); |
| 126 this->compiler->setUniform("highlighted", this->highlighted.value); |
131 this->compiler->setUniform("highlighted", this->highlighted.value); |
| 127 this->checkForGLErrors(); |
132 this->checkForGLErrors(); |
| 128 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
133 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 129 glEnable(GL_DEPTH_TEST); |
134 glEnable(GL_DEPTH_TEST); |
| 162 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
167 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
| 163 this->setFragmentStyle(gl::FragmentStyle::Normal); |
168 this->setFragmentStyle(gl::FragmentStyle::Normal); |
| 164 this->renderAllArrays(); |
169 this->renderAllArrays(); |
| 165 break; |
170 break; |
| 166 } |
171 } |
| |
172 glEnable(GL_BLEND); |
| |
173 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| |
174 this->gridProgram->draw(); |
| |
175 glDisable(GL_BLEND); |
| 167 glDisable(GL_POLYGON_OFFSET_FILL); |
176 glDisable(GL_POLYGON_OFFSET_FILL); |
| 168 } |
177 } |
| 169 |
178 |
| 170 void PartRenderer::renderAllArrays() |
179 void PartRenderer::renderAllArrays() |
| 171 { |
180 { |
| 180 { |
189 { |
| 181 // I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior |
190 // I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior |
| 182 const double z = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance()); |
191 const double z = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance()); |
| 183 this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0}); |
192 this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0}); |
| 184 this->compiler->setUniformMatrix("viewMatrix", this->viewMatrix); |
193 this->compiler->setUniformMatrix("viewMatrix", this->viewMatrix); |
| |
194 this->gridProgram->setViewMatrix(this->viewMatrix); |
| 185 } |
195 } |
| 186 |
196 |
| 187 void PartRenderer::renderVao(const gl::ArrayClass arrayClass) |
197 void PartRenderer::renderVao(const gl::ArrayClass arrayClass) |
| 188 { |
198 { |
| 189 this->compiler->bindVertexArray(arrayClass); |
199 this->compiler->bindVertexArray(arrayClass); |
| 194 this->compiler->releaseVertexArray(arrayClass); |
204 this->compiler->releaseVertexArray(arrayClass); |
| 195 this->checkForGLErrors(); |
205 this->checkForGLErrors(); |
| 196 } |
206 } |
| 197 |
207 |
| 198 void PartRenderer::checkForGLErrors() |
208 void PartRenderer::checkForGLErrors() |
| |
209 { |
| |
210 gl::checkForGLErrors(this); |
| |
211 } |
| |
212 |
| |
213 void gl::checkForGLErrors(QWidget* parent) |
| 199 { |
214 { |
| 200 GLenum glError; |
215 GLenum glError; |
| 201 QStringList errors; |
216 QStringList errors; |
| 202 while ((glError = glGetError()) != GL_NO_ERROR) |
217 while ((glError = glGetError()) != GL_NO_ERROR) |
| 203 { |
218 { |
| 204 const QString glErrorString = QString::fromLatin1(reinterpret_cast<const char*>(::gluErrorString(glError))); |
219 const QString glErrorString = QString::fromLatin1(reinterpret_cast<const char*>(::gluErrorString(glError))); |
| 205 errors.append(glErrorString); |
220 errors.append(glErrorString); |
| 206 } |
221 } |
| 207 if (not errors.isEmpty()) |
222 if (not errors.isEmpty()) |
| 208 { |
223 { |
| 209 QMessageBox box{this}; |
224 QMessageBox box{parent}; |
| 210 box.setIcon(QMessageBox::Critical); |
225 box.setIcon(QMessageBox::Critical); |
| 211 box.setText(tr("Failed to render: %1").arg(errors.join("\n"))); |
226 box.setText(QObject::tr("OpenGL error: %1").arg(errors.join("\n"))); |
| 212 box.setWindowTitle(tr("Rendering error")); |
227 box.setWindowTitle(QObject::tr("OpenGL error")); |
| 213 box.setStandardButtons(QMessageBox::Close); |
228 box.setStandardButtons(QMessageBox::Close); |
| 214 box.button(QMessageBox::Close)->setText(tr("Damn it")); |
229 box.button(QMessageBox::Close)->setText(QObject::tr("Damn it")); |
| 215 box.exec(); |
230 box.exec(); |
| 216 } |
231 } |
| 217 } |
232 } |
| 218 |
233 |
| 219 void PartRenderer::mouseMoveEvent(QMouseEvent* event) |
234 void PartRenderer::mouseMoveEvent(QMouseEvent* event) |
| 229 const float move_x = static_cast<float>(move.x()); |
244 const float move_x = static_cast<float>(move.x()); |
| 230 const float move_y = static_cast<float>(move.y()); |
245 const float move_y = static_cast<float>(move.y()); |
| 231 const glm::quat q_x = glm::angleAxis(scalar * move_x, glm::vec3{0, -1, 0}); |
246 const glm::quat q_x = glm::angleAxis(scalar * move_x, glm::vec3{0, -1, 0}); |
| 232 const glm::quat q_y = glm::angleAxis(scalar * move_y, glm::vec3{-1, 0, 0}); |
247 const glm::quat q_y = glm::angleAxis(scalar * move_y, glm::vec3{-1, 0, 0}); |
| 233 this->modelQuaternion = q_x * q_y * this->modelQuaternion; |
248 this->modelQuaternion = q_x * q_y * this->modelQuaternion; |
| 234 this->compiler->setUniformMatrix("modelMatrix", glm::mat4_cast(this->modelQuaternion)); |
249 const glm::mat4 modelMatrix = glm::mat4_cast(this->modelQuaternion); |
| |
250 this->compiler->setUniformMatrix("modelMatrix", modelMatrix); |
| |
251 this->gridProgram->setModelMatrix(modelMatrix); |
| 235 this->update(); |
252 this->update(); |
| 236 } |
253 } |
| 237 this->lastMousePosition = pointToPointF(event->pos()); |
254 this->lastMousePosition = pointToPointF(event->pos()); |
| 238 } |
255 } |
| 239 |
256 |