src/gl/partrenderer.cpp

changeset 189
815fbaae9cb2
parent 150
b6cbba6e29a1
child 199
6988973515d2
equal deleted inserted replaced
188:64ea7282611e 189:815fbaae9cb2
26 #include "partrenderer.h" 26 #include "partrenderer.h"
27 #include "model.h" 27 #include "model.h"
28 28
29 static constexpr double MIN_ZOOM = -3.0; 29 static constexpr double MIN_ZOOM = -3.0;
30 static constexpr double MAX_ZOOM = 3.0; 30 static constexpr double MAX_ZOOM = 3.0;
31 QOpenGLFunctions glfunc;
31 32
32 PartRenderer::PartRenderer( 33 PartRenderer::PartRenderer(
33 Model* model, 34 Model* model,
34 DocumentManager* documents, 35 DocumentManager* documents,
35 const ldraw::ColorTable& colorTable, 36 const ldraw::ColorTable& colorTable,
36 QWidget* parent) : 37 QWidget* parent) :
37 QOpenGLWidget{parent}, 38 QOpenGLWidget{parent},
38 model{model}, 39 model{model},
39 documents{documents}, 40 documents{documents},
40 colorTable{colorTable}, 41 colorTable{colorTable}
41 compiler{new gl::Compiler{model, this->colorTable, this}}
42 { 42 {
43 this->setMouseTracking(true); 43 this->setMouseTracking(true);
44 connect(model, &Model::rowsInserted, [&]{ 44 connect(model, &Model::rowsInserted, [&]{
45 this->needBuild = true; 45 this->needBuild = true;
46 }); 46 });
49 49
50 PartRenderer::~PartRenderer() 50 PartRenderer::~PartRenderer()
51 { 51 {
52 } 52 }
53 53
54 static QVector3D vec3FromQColor(const QColor& color) 54 static QVector3D calcQVector3DFromQColor(const QColor& color)
55 { 55 {
56 return { 56 return {
57 toFloat(color.redF()), 57 toFloat(color.redF()),
58 toFloat(color.greenF()), 58 toFloat(color.greenF()),
59 toFloat(color.blueF()), 59 toFloat(color.blueF()),
60 }; 60 };
61 } 61 }
62 62
63 void PartRenderer::initializeGL() 63 void PartRenderer::initializeGL()
64 { 64 {
65 this->initializeOpenGLFunctions(); 65 ::glfunc.initializeOpenGLFunctions();
66 if (glGetError() != GL_NO_ERROR) 66 if (glGetError() != GL_NO_ERROR)
67 { 67 {
68 abort(); 68 abort();
69 } 69 }
70 this->compiler->initialize(); 70 gl::initializeModelShaders(&this->shaders);
71 connect(this->model, &Model::dataChanged, this, &PartRenderer::build); 71 connect(this->model, &Model::dataChanged, this, &PartRenderer::build);
72 this->initialized = true; 72 this->initialized = true;
73 this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0}); 73 this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0});
74 this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0}); 74 this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0});
75 this->setupBackgroundColor();
76 this->updateModelMatrix(); 75 this->updateModelMatrix();
77 this->updateViewMatrix(); 76 this->updateViewMatrix();
78 this->update(); 77 this->update();
79 } 78 }
80 79
85 this->projectionMatrix = glm::perspective( 84 this->projectionMatrix = glm::perspective(
86 glm::radians(45.0f), 85 glm::radians(45.0f),
87 static_cast<float>(width) / static_cast<float>(height), 86 static_cast<float>(width) / static_cast<float>(height),
88 0.1f, 87 0.1f,
89 10000.f); 88 10000.f);
90 this->compiler->setUniformMatrix("projectionMatrix", this->projectionMatrix); 89 gl::setShaderUniformMatrix(&this->shaders, "projectionMatrix", this->projectionMatrix);
91 Q_EMIT projectionMatrixChanged(this->projectionMatrix); 90 Q_EMIT projectionMatrixChanged(this->projectionMatrix);
92 } 91 }
93 92
94 static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass) 93 static constexpr GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass)
95 { 94 {
96 switch (vboClass) 95 switch (vboClass)
97 { 96 {
98 case gl::ArrayClass::Lines: 97 case gl::ArrayClass::Lines:
99 case gl::ArrayClass::ConditionalLines: 98 case gl::ArrayClass::ConditionalLines:
101 case gl::ArrayClass::Triangles: 100 case gl::ArrayClass::Triangles:
102 return GL_TRIANGLES; 101 return GL_TRIANGLES;
103 case gl::ArrayClass::Quads: 102 case gl::ArrayClass::Quads:
104 return GL_QUADS; 103 return GL_QUADS;
105 } 104 }
106 throw std::runtime_error{"Bad vbo class passed to getGlTypeForVboClass"}; 105 throw std::runtime_error{"bad value for vboClass"};
107 } 106 }
108 107
109 void PartRenderer::paintGL() 108 void PartRenderer::paintGL()
110 { 109 {
111 glEnable(GL_DEPTH_TEST); 110 glEnable(GL_DEPTH_TEST);
115 114
116 void PartRenderer::renderScene() 115 void PartRenderer::renderScene()
117 { 116 {
118 if (this->needBuild) 117 if (this->needBuild)
119 { 118 {
120 this->compiler->build(this->documents, this->renderPreferences); 119 gl::build(&this->shaders, this->model, this->colorTable, this->documents, this->renderPreferences);
120 this->boundingBox = gl::boundingBoxForModel(this->model, this->documents);
121 this->needBuild = false; 121 this->needBuild = false;
122 } 122 }
123 this->checkForGLErrors(); 123 this->checkForGLErrors();
124 if (this->renderPreferences.lineAntiAliasing && this->renderPreferences.style != gl::RenderStyle::PickScene) 124 if (true
125 { 125 and this->renderPreferences.lineAntiAliasing
126 and this->renderPreferences.style != gl::RenderStyle::PickScene
127 ) {
126 glEnable(GL_LINE_SMOOTH); 128 glEnable(GL_LINE_SMOOTH);
127 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 129 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
128 } 130 }
129 else { 131 else {
130 glDisable(GL_LINE_SMOOTH); 132 glDisable(GL_LINE_SMOOTH);
135 glClearColor( 137 glClearColor(
136 static_cast<float>(backgroundColor.redF()), 138 static_cast<float>(backgroundColor.redF()),
137 static_cast<float>(backgroundColor.greenF()), 139 static_cast<float>(backgroundColor.greenF()),
138 static_cast<float>(backgroundColor.blueF()), 140 static_cast<float>(backgroundColor.blueF()),
139 1.0f); 141 1.0f);
140 this->compiler->setUniform("useLighting", GL_TRUE); 142 gl::setShaderUniform(&this->shaders, "useLighting", GL_TRUE);
141 } 143 }
142 else 144 else
143 { 145 {
144 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 146 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
145 this->compiler->setUniform("useLighting", GL_FALSE); 147 gl::setShaderUniform(&this->shaders, "useLighting", GL_FALSE);
146 } 148 }
147 this->checkForGLErrors(); 149 this->checkForGLErrors();
148 this->compiler->setUniform("selectedColor", vec3FromQColor(this->renderPreferences.selectedColor)); 150 const QVector3D color = calcQVector3DFromQColor(this->renderPreferences.selectedColor);
149 this->compiler->setUniform("highlighted", this->highlighted.value); 151 gl::setShaderUniform(&this->shaders, "selectedColor", color);
152 gl::setShaderUniform(&this->shaders, "highlighted", this->highlighted.value);
150 this->checkForGLErrors(); 153 this->checkForGLErrors();
151 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 154 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
152 glEnable(GL_DEPTH_TEST); 155 glEnable(GL_DEPTH_TEST);
153 glEnable(GL_POLYGON_OFFSET_FILL); 156 glEnable(GL_POLYGON_OFFSET_FILL);
154 glPolygonOffset(1.0f, 1.0f); 157 glPolygonOffset(1.0f, 1.0f);
155 glLineWidth(this->renderPreferences.lineThickness); 158 glLineWidth(this->renderPreferences.lineThickness);
159 const auto renderAllArrays = [this](){
160 // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering.
161 this->renderVao(gl::ArrayClass::Triangles);
162 this->renderVao(gl::ArrayClass::Quads);
163 this->renderVao(gl::ArrayClass::Lines);
164 };
156 switch (this->renderPreferences.style) 165 switch (this->renderPreferences.style)
157 { 166 {
158 case gl::RenderStyle::Normal: 167 case gl::RenderStyle::Normal:
159 this->setFragmentStyle(gl::FragmentStyle::Normal); 168 this->setFragmentStyle(gl::FragmentStyle::Normal);
160 this->renderAllArrays(); 169 renderAllArrays();
161 break; 170 break;
162 case gl::RenderStyle::BfcRedGreen: 171 case gl::RenderStyle::BfcRedGreen:
163 glEnable(GL_CULL_FACE); 172 glEnable(GL_CULL_FACE);
164 glCullFace(GL_BACK); 173 glCullFace(GL_BACK);
165 this->setFragmentStyle(gl::FragmentStyle::BfcGreen); 174 this->setFragmentStyle(gl::FragmentStyle::BfcGreen);
170 renderVao(gl::ArrayClass::Triangles); 179 renderVao(gl::ArrayClass::Triangles);
171 renderVao(gl::ArrayClass::Quads); 180 renderVao(gl::ArrayClass::Quads);
172 glDisable(GL_CULL_FACE); 181 glDisable(GL_CULL_FACE);
173 this->setFragmentStyle(gl::FragmentStyle::Normal); 182 this->setFragmentStyle(gl::FragmentStyle::Normal);
174 renderVao(gl::ArrayClass::Lines); 183 renderVao(gl::ArrayClass::Lines);
184 break;
175 case gl::RenderStyle::RandomColors: 185 case gl::RenderStyle::RandomColors:
176 this->setFragmentStyle(gl::FragmentStyle::RandomColors); 186 this->setFragmentStyle(gl::FragmentStyle::RandomColors);
177 this->renderAllArrays(); 187 renderAllArrays();
178 break; 188 break;
179 case gl::RenderStyle::PickScene: 189 case gl::RenderStyle::PickScene:
180 glLineWidth(3.0f); 190 glLineWidth(3.0f);
181 this->setFragmentStyle(gl::FragmentStyle::Id); 191 this->setFragmentStyle(gl::FragmentStyle::Id);
182 this->renderAllArrays(); 192 renderAllArrays();
183 break; 193 break;
184 case gl::RenderStyle::VertexPickScene: 194 case gl::RenderStyle::VertexPickScene:
185 glLineWidth(1.0f); 195 glLineWidth(1.0f);
186 this->setFragmentStyle(gl::FragmentStyle::Black); 196 this->setFragmentStyle(gl::FragmentStyle::Black);
187 this->renderAllArrays(); 197 renderAllArrays();
188 break; 198 break;
189 case gl::RenderStyle::Wireframe: 199 case gl::RenderStyle::Wireframe:
190 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 200 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
191 this->setFragmentStyle(gl::FragmentStyle::Normal); 201 this->setFragmentStyle(gl::FragmentStyle::Normal);
192 this->renderAllArrays(); 202 renderAllArrays();
193 break; 203 break;
194 } 204 }
195 glDisable(GL_POLYGON_OFFSET_FILL); 205 glDisable(GL_POLYGON_OFFSET_FILL);
196 } 206 }
197 207
198 void PartRenderer::renderAllArrays()
199 {
200 // Lines need to be rendered last so that anti-aliasing does not interfere with polygon rendering.
201 renderVao(gl::ArrayClass::Triangles);
202 renderVao(gl::ArrayClass::Quads);
203 renderVao(gl::ArrayClass::Lines);
204 }
205
206 208
207 void PartRenderer::updateViewMatrix() 209 void PartRenderer::updateViewMatrix()
208 { 210 {
209 // I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior 211 // I'm not quite sure why using the exponent function on the zoom factor causes linear zoom behavior
210 const double z = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance()); 212 const float modelDistance = longestMeasure(this->boundingBox);
213 const double z = 2.0 * std::exp(this->zoom) * (1 + static_cast<double>(modelDistance));
211 this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0}); 214 this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0});
212 this->compiler->setUniformMatrix("viewMatrix", this->viewMatrix); 215 gl::setShaderUniformMatrix(&this->shaders, "viewMatrix", this->viewMatrix);
213 Q_EMIT this->viewMatrixChanged(this->viewMatrix); 216 Q_EMIT this->viewMatrixChanged(this->viewMatrix);
214 } 217 }
215 218
216 void PartRenderer::updateModelMatrix() 219 void PartRenderer::updateModelMatrix()
217 { 220 {
218 this->modelMatrix = glm::mat4_cast(this->modelQuaternion); 221 this->modelMatrix = glm::mat4_cast(this->modelQuaternion);
219 this->compiler->setUniformMatrix("modelMatrix", modelMatrix); 222 gl::setShaderUniformMatrix(&this->shaders, "modelMatrix", modelMatrix);
220 Q_EMIT this->modelMatrixChanged(this->modelMatrix); 223 Q_EMIT this->modelMatrixChanged(this->modelMatrix);
221 this->update(); 224 this->update();
222 } 225 }
223 226
224 void PartRenderer::setupBackgroundColor()
225 {
226 }
227
228 void PartRenderer::build() 227 void PartRenderer::build()
229 { 228 {
230 this->needBuild = true; 229 this->needBuild = true;
231 } 230 }
232 231
233 void PartRenderer::renderVao(const gl::ArrayClass arrayClass) 232 void PartRenderer::renderVao(const gl::ArrayClass arrayClass)
234 { 233 {
235 this->compiler->bindVertexArray(arrayClass); 234 gl::bindModelShaderVertexArray(&this->shaders, arrayClass);
236 const std::size_t vertexCount = this->compiler->vertexCount(arrayClass); 235 const std::size_t vertexCount = gl::vertexCount(&this->shaders, arrayClass);
237 this->checkForGLErrors(); 236 this->checkForGLErrors();
238 glDrawArrays(getGlTypeForArrayClass(arrayClass), 0, static_cast<GLsizei>(vertexCount)); 237 glDrawArrays(getGlTypeForArrayClass(arrayClass), 0, static_cast<GLsizei>(vertexCount));
239 this->checkForGLErrors(); 238 this->checkForGLErrors();
240 this->compiler->releaseVertexArray(arrayClass); 239 gl::releaseModelShaderVertexArray(&this->shaders, arrayClass);
241 this->checkForGLErrors(); 240 this->checkForGLErrors();
242 } 241 }
243 242
244 void PartRenderer::checkForGLErrors() 243 void PartRenderer::checkForGLErrors()
245 { 244 {
363 this->checkForGLErrors(); 362 this->checkForGLErrors();
364 glReadPixels(where.x(), this->height() - where.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &data[0]); 363 glReadPixels(where.x(), this->height() - where.y(), 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &data[0]);
365 this->checkForGLErrors(); 364 this->checkForGLErrors();
366 this->renderPreferences.style = oldRenderStyle; 365 this->renderPreferences.style = oldRenderStyle;
367 this->update(); 366 this->update();
368 return gl::Compiler::idFromColor(data); 367 return gl::idFromColor(data);
369 } 368 }
370 369
371 /** 370 /**
372 * @brief Changes the color of rendered fragments 371 * @brief Changes the color of rendered fragments
373 * @param newFragmentStyle new fragment style to use 372 * @param newFragmentStyle new fragment style to use
374 */ 373 */
375 void PartRenderer::setFragmentStyle(gl::FragmentStyle newFragmentStyle) 374 void PartRenderer::setFragmentStyle(gl::FragmentStyle newFragmentStyle)
376 { 375 {
377 this->compiler->setUniform("fragmentStyle", static_cast<int>(newFragmentStyle)); 376 gl::setShaderUniform(&this->shaders, "fragmentStyle", static_cast<int>(newFragmentStyle));
378 } 377 }
379 378
380 /** 379 /**
381 * @brief Changes the way the scene is rendered 380 * @brief Changes the way the scene is rendered
382 * @param newStyle new render style to use 381 * @param newStyle new render style to use
387 bool backgroundColorChanged = this->renderPreferences.backgroundColor != newPreferences.backgroundColor; 386 bool backgroundColorChanged = this->renderPreferences.backgroundColor != newPreferences.backgroundColor;
388 this->renderPreferences = newPreferences; 387 this->renderPreferences = newPreferences;
389 if (mainColorChanged or backgroundColorChanged) 388 if (mainColorChanged or backgroundColorChanged)
390 { 389 {
391 this->build(); 390 this->build();
392 this->setupBackgroundColor();
393 } 391 }
394 Q_EMIT this->renderPreferencesChanged(); 392 Q_EMIT this->renderPreferencesChanged();
395 this->update(); 393 this->update();
396 } 394 }
397 395

mercurial