31 #include "src/gl/partrenderer.h" |
31 #include "src/gl/partrenderer.h" |
32 #include "src/gl/compiler.h" |
32 #include "src/gl/compiler.h" |
33 |
33 |
34 static constexpr double MIN_ZOOM = -3.0; |
34 static constexpr double MIN_ZOOM = -3.0; |
35 static constexpr double MAX_ZOOM = 3.0; |
35 static constexpr double MAX_ZOOM = 3.0; |
|
36 const gl::RenderPreferences PartRenderer::default_render_preferences{}; |
|
37 const gl::build_preferences PartRenderer::default_build_preferences{}; |
36 |
38 |
37 PartRenderer::PartRenderer( |
39 PartRenderer::PartRenderer( |
38 QTextDocument* model, |
40 QTextDocument* model, |
39 DocumentManager* documents, |
41 DocumentManager* documents, |
40 const ColorTable& colorTable, |
42 const ColorTable& colorTable, |
118 |
120 |
119 void PartRenderer::renderScene() |
121 void PartRenderer::renderScene() |
120 { |
122 { |
121 if (this->needBuild) |
123 if (this->needBuild) |
122 { |
124 { |
123 gl::build(&this->shaders, this->model, this->colorTable, this->documents, this->renderPreferences); |
125 gl::build(&this->shaders, this->model, this->colorTable, this->documents, this->build_preferences); |
124 this->boundingBox = gl::boundingBoxForModel(this->model, this->documents); |
126 this->boundingBox = gl::boundingBoxForModel(this->model, this->documents); |
125 this->needBuild = false; |
127 this->needBuild = false; |
126 } |
128 } |
127 this->checkForGLErrors(); |
129 this->checkForGLErrors(); |
128 if (true |
130 if (this->render_preferences->lineAntiAliasing) |
129 and this->renderPreferences.lineAntiAliasing |
131 { |
130 and this->renderPreferences.style != gl::RenderStyle::PickScene |
|
131 ) { |
|
132 glEnable(GL_LINE_SMOOTH); |
132 glEnable(GL_LINE_SMOOTH); |
133 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
133 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
134 } |
134 } |
135 else { |
135 else { |
136 glDisable(GL_LINE_SMOOTH); |
136 glDisable(GL_LINE_SMOOTH); |
137 } |
137 } |
138 if (this->renderPreferences.style != gl::RenderStyle::PickScene) |
138 if (this->render_preferences->style != gl::RenderStyle::PickScene) |
139 { |
139 { |
140 const QColor& backgroundColor = this->renderPreferences.backgroundColor; |
140 const QColor& backgroundColor = this->build_preferences->backgroundColor; |
141 glClearColor( |
141 glClearColor( |
142 static_cast<float>(backgroundColor.redF()), |
142 static_cast<float>(backgroundColor.redF()), |
143 static_cast<float>(backgroundColor.greenF()), |
143 static_cast<float>(backgroundColor.greenF()), |
144 static_cast<float>(backgroundColor.blueF()), |
144 static_cast<float>(backgroundColor.blueF()), |
145 1.0f); |
145 1.0f); |
149 { |
149 { |
150 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
150 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); |
151 gl::setShaderUniform(&this->shaders, "useLighting", GL_FALSE); |
151 gl::setShaderUniform(&this->shaders, "useLighting", GL_FALSE); |
152 } |
152 } |
153 this->checkForGLErrors(); |
153 this->checkForGLErrors(); |
154 const QColor qs = this->renderPreferences.selectedColor; |
154 const QColor qs = this->render_preferences->selectedColor; |
155 const glm::vec4 selectedColor{qs.redF(), qs.greenF(), qs.blueF(), 1.0f}; |
155 const glm::vec4 selectedColor{qs.redF(), qs.greenF(), qs.blueF(), 1.0f}; |
156 gl::setShaderUniformVector(&this->shaders, "selectedColor", selectedColor); |
156 gl::setShaderUniformVector(&this->shaders, "selectedColor", selectedColor); |
157 gl::setShaderUniform(&this->shaders, "highlighted", this->highlighted.value); |
157 gl::setShaderUniform(&this->shaders, "highlighted", this->highlighted.value); |
158 this->checkForGLErrors(); |
158 this->checkForGLErrors(); |
159 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
159 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
160 glEnable(GL_DEPTH_TEST); |
160 glEnable(GL_DEPTH_TEST); |
161 glEnable(GL_POLYGON_OFFSET_FILL); |
161 glEnable(GL_POLYGON_OFFSET_FILL); |
162 glPolygonOffset(1.0f, 1.0f); |
162 glPolygonOffset(1.0f, 1.0f); |
163 glLineWidth(this->renderPreferences.lineThickness); |
163 glLineWidth(this->render_preferences->lineThickness); |
164 const auto renderAllArrays = [this](){ |
164 const auto renderAllArrays = [this](){ |
165 // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering. |
165 // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering. |
166 this->renderVao<gl::ArrayClass::Triangles>(); |
166 this->renderVao<gl::ArrayClass::Triangles>(); |
167 this->renderVao<gl::ArrayClass::Quads>(); |
167 this->renderVao<gl::ArrayClass::Quads>(); |
168 this->renderVao<gl::ArrayClass::Lines>(); |
168 this->renderVao<gl::ArrayClass::Lines>(); |
169 }; |
169 }; |
170 if (this->renderPreferences.wireframe and this->renderPreferences.style != gl::RenderStyle::PickScene) { |
170 if (this->render_preferences->wireframe) |
|
171 { |
171 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
172 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
172 } |
173 } |
173 switch (this->renderPreferences.style) |
174 switch (this->render_preferences->style) |
174 { |
175 { |
175 case gl::RenderStyle::Normal: |
176 case gl::RenderStyle::Normal: |
176 this->setFragmentStyle(gl::FragmentStyle::Normal); |
177 this->setFragmentStyle(gl::FragmentStyle::Normal); |
177 renderAllArrays(); |
178 renderAllArrays(); |
178 break; |
179 break; |
393 return toQPointF(glm::vec2{projected.x, static_cast<float>(this->height()) - projected.y}); |
393 return toQPointF(glm::vec2{projected.x, static_cast<float>(this->height()) - projected.y}); |
394 } |
394 } |
395 |
395 |
396 bool PartRenderer::isDark() const |
396 bool PartRenderer::isDark() const |
397 { |
397 { |
398 return luma(this->renderPreferences.backgroundColor) < 0.25; |
398 return luma(this->build_preferences->backgroundColor) < 0.25; |
399 } |
399 } |
400 |
400 |
401 Line<3> PartRenderer::cameraLine(const QPointF& point) const |
401 Line<3> PartRenderer::cameraLine(const QPointF& point) const |
402 { |
402 { |
403 const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0}); |
403 const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0}); |
431 where.setY(this->height() - where.y()); |
431 where.setY(this->height() - where.y()); |
432 // Since we are dealing with pixel data right from the framebuffer, its size |
432 // Since we are dealing with pixel data right from the framebuffer, its size |
433 // will be affected by High DPI scaling. We need to take this into account |
433 // will be affected by High DPI scaling. We need to take this into account |
434 // and multiply the pixel positions by the screen pixel scaling factor. |
434 // and multiply the pixel positions by the screen pixel scaling factor. |
435 where *= this->devicePixelRatioF(); |
435 where *= this->devicePixelRatioF(); |
436 const gl::RenderStyle oldRenderStyle = this->renderPreferences.style; |
436 static const gl::RenderPreferences pick_scene_preferences { |
437 this->renderPreferences.style = gl::RenderStyle::PickScene; |
437 .style = gl::RenderStyle::PickScene, |
|
438 .selectedColor = {}, |
|
439 .lineThickness = 3.0f, |
|
440 .lineAntiAliasing = false, |
|
441 .drawAxes = false, |
|
442 .wireframe = false, |
|
443 }; |
|
444 const gl::RenderPreferences* old_render_preferences = this->render_preferences; |
|
445 this->render_preferences = &pick_scene_preferences; |
438 this->makeCurrent(); |
446 this->makeCurrent(); |
439 QOpenGLFramebufferObject fbo{this->width(), this->height(), QOpenGLFramebufferObject::CombinedDepthStencil}; |
447 QOpenGLFramebufferObject fbo{this->width(), this->height(), QOpenGLFramebufferObject::CombinedDepthStencil}; |
440 fbo.bind(); |
448 fbo.bind(); |
441 this->renderScene(); |
449 this->renderScene(); |
442 std::array<GLubyte, 3> data; |
450 std::array<GLubyte, 3> data; |
443 this->checkForGLErrors(); |
451 this->checkForGLErrors(); |
444 glReadPixels(where.x(), where.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &data[0]); |
452 glReadPixels(where.x(), where.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &data[0]); |
445 this->checkForGLErrors(); |
453 this->checkForGLErrors(); |
446 fbo.release(); |
454 fbo.release(); |
447 this->renderPreferences.style = oldRenderStyle; |
455 this->render_preferences = old_render_preferences; |
448 return gl::idFromUcharColor(data); |
456 return gl::idFromUcharColor(data); |
449 } |
457 } |
450 |
458 |
451 /** |
459 /** |
452 * @brief Changes the color of rendered fragments |
460 * @brief Changes the color of rendered fragments |
453 * @param newFragmentStyle new fragment style to use |
461 * @param newFragmentStyle new fragment style to use |
454 */ |
462 */ |
455 void PartRenderer::setFragmentStyle(gl::FragmentStyle newFragmentStyle) |
463 void PartRenderer::setFragmentStyle(gl::FragmentStyle newFragmentStyle) |
456 { |
464 { |
457 gl::setShaderUniform(&this->shaders, "fragmentStyle", static_cast<int>(newFragmentStyle)); |
465 gl::setShaderUniform(&this->shaders, "fragmentStyle", static_cast<int>(newFragmentStyle)); |
458 } |
|
459 |
|
460 /** |
|
461 * @brief Changes the way the scene is rendered |
|
462 * @param newStyle new render style to use |
|
463 */ |
|
464 void PartRenderer::setRenderPreferences(const gl::RenderPreferences& newPreferences) |
|
465 { |
|
466 bool mainColorChanged = this->renderPreferences.mainColor != newPreferences.mainColor; |
|
467 bool backgroundColorChanged = this->renderPreferences.backgroundColor != newPreferences.backgroundColor; |
|
468 this->renderPreferences = newPreferences; |
|
469 if (mainColorChanged or backgroundColorChanged) |
|
470 { |
|
471 this->build(); |
|
472 } |
|
473 Q_EMIT this->renderPreferencesChanged(); |
|
474 this->update(); |
|
475 } |
466 } |
476 |
467 |
477 /** |
468 /** |
478 * @return the currently highlighted object |
469 * @return the currently highlighted object |
479 */ |
470 */ |