5 Canvas::Canvas( |
5 Canvas::Canvas( |
6 Model* model, |
6 Model* model, |
7 DocumentManager* documents, |
7 DocumentManager* documents, |
8 const ldraw::ColorTable& colorTable, |
8 const ldraw::ColorTable& colorTable, |
9 QWidget* parent) : |
9 QWidget* parent) : |
10 PartRenderer{model, documents, colorTable, parent}, |
10 PartRenderer{model, documents, colorTable, parent} |
11 gridProgram{this} |
|
12 { |
11 { |
13 this->setMouseTracking(true); |
12 this->setMouseTracking(true); |
14 } |
13 } |
15 |
14 |
16 void Canvas::handleSelectionChange(const QSet<ldraw::Id>& selectedIds, const QSet<ldraw::Id>& deselectedIds) |
15 void Canvas::handleSelectionChange(const QSet<ldraw::Id>& selectedIds, const QSet<ldraw::Id>& deselectedIds) |
68 const float angle_x = std::abs(glm::dot(vector_x, cameraDirection)); |
67 const float angle_x = std::abs(glm::dot(vector_x, cameraDirection)); |
69 const float angle_y = std::abs(glm::dot(vector_y, cameraDirection)); |
68 const float angle_y = std::abs(glm::dot(vector_y, cameraDirection)); |
70 if (angle_x < angle_y) |
69 if (angle_x < angle_y) |
71 { |
70 { |
72 this->newStatusText("rotate by X axis"); |
71 this->newStatusText("rotate by X axis"); |
73 this->gridMatrix = glm::rotate(this->gridMatrix, float{M_PI} / 2, glm::vec3{1, 0, 0}); |
72 this->gridMatrix = glm::rotate(this->gridMatrix, PIf / 2, glm::vec3{1, 0, 0}); |
74 } |
73 } |
75 else |
74 else |
76 { |
75 { |
77 this->newStatusText("rotate by Y axis"); |
76 this->newStatusText("rotate by Y axis"); |
78 this->gridMatrix = glm::rotate(this->gridMatrix, float{M_PI} / 2, glm::vec3{0, 1, 0}); |
77 this->gridMatrix = glm::rotate(this->gridMatrix, PIf / 2, glm::vec3{0, 1, 0}); |
79 } |
78 } |
80 this->updateGridMatrix(); |
79 this->updateGridMatrix(); |
81 this->update(); |
80 this->update(); |
82 } |
81 } |
83 else |
82 else |
117 { |
116 { |
118 // We first create the grid program and connect everything and only then call the part renderer's initialization |
117 // We first create the grid program and connect everything and only then call the part renderer's initialization |
119 // functions so that when initialization sets up, the signals also set up the matrices on our side. |
118 // functions so that when initialization sets up, the signals also set up the matrices on our side. |
120 this->gridProgram.emplace(this); |
119 this->gridProgram.emplace(this); |
121 this->gridProgram->initialize(); |
120 this->gridProgram->initialize(); |
122 connect(this, &PartRenderer::projectionMatrixChanged, [&]() |
121 this->axesProgram.emplace(this); |
123 { |
122 this->axesProgram->initialize(); |
124 this->gridProgram->setProjectionMatrix(this->projectionMatrix); |
123 for (AbstractBasicShaderProgram* program : { |
125 }); |
124 static_cast<AbstractBasicShaderProgram*>(&*this->gridProgram), |
126 connect(this, &PartRenderer::modelMatrixChanged, [&]() |
125 static_cast<AbstractBasicShaderProgram*>(&*this->axesProgram), |
127 { |
126 }) |
128 this->gridProgram->setModelMatrix(this->modelMatrix); |
127 { |
129 }); |
128 connect(this, &PartRenderer::projectionMatrixChanged, |
130 connect(this, &PartRenderer::viewMatrixChanged, [&]() |
129 program, &AbstractBasicShaderProgram::setProjectionMatrix); |
131 { |
130 connect(this, &PartRenderer::modelMatrixChanged, |
132 this->gridProgram->setViewMatrix(this->viewMatrix); |
131 program, &AbstractBasicShaderProgram::setModelMatrix); |
133 }); |
132 connect(this, &PartRenderer::viewMatrixChanged, |
|
133 program, &AbstractBasicShaderProgram::setViewMatrix); |
|
134 } |
134 connect(this, &PartRenderer::renderPreferencesChanged, [&]() |
135 connect(this, &PartRenderer::renderPreferencesChanged, [&]() |
135 { |
136 { |
136 if (this->gridProgram.has_value()) |
137 if (this->gridProgram.has_value()) |
137 { |
138 { |
138 const bool isDark = luma(this->renderPreferences.backgroundColor) < 0.25; |
139 const bool isDark = luma(this->renderPreferences.backgroundColor) < 0.25; |
139 this->gridProgram->setGridColor(isDark ? Qt::white : Qt::black); |
140 this->gridProgram->setGridColor(isDark ? Qt::white : Qt::black); |
140 } |
141 } |
141 }); |
142 }); |
142 PartRenderer::initializeGL(); |
143 PartRenderer::initializeGL(); |
143 /* |
144 // Set up XZ grid matrix |
144 this->gridMatrix = glm::mat4{ |
|
145 {-4, 0, 0, 0}, |
|
146 {0, 6.9266, -3.6955, 0}, |
|
147 {0, -16.7222, -1.5307, 0}, |
|
148 {0, -13.273, -9.255, 1}, |
|
149 }; |
|
150 */ |
|
151 this->gridMatrix = glm::mat4{ |
145 this->gridMatrix = glm::mat4{ |
152 {1, 0, 0, 0}, |
146 {1, 0, 0, 0}, |
153 {0, 0, 1, 0}, |
147 {0, 0, 1, 0}, |
154 {0, 1, 0, 0}, |
148 {0, 1, 0, 0}, |
155 {0, 0, 0, 1} |
149 {0, 0, 0, 1} |
158 } |
152 } |
159 |
153 |
160 void Canvas::paintGL() |
154 void Canvas::paintGL() |
161 { |
155 { |
162 PartRenderer::paintGL(); |
156 PartRenderer::paintGL(); |
163 glEnable(GL_BLEND); |
157 // Render axes |
164 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
158 { |
165 this->gridProgram->draw(); |
159 glLineWidth(5); |
166 glDisable(GL_BLEND); |
160 glEnable(GL_LINE_SMOOTH); |
|
161 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); |
|
162 this->axesProgram->draw(); |
|
163 glDisable(GL_LINE_SMOOTH); |
|
164 } |
|
165 // Render grid |
|
166 { |
|
167 glEnable(GL_BLEND); |
|
168 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
|
169 this->gridProgram->draw(); |
|
170 glDisable(GL_BLEND); |
|
171 } |
167 if (this->worldPosition.has_value()) |
172 if (this->worldPosition.has_value()) |
168 { |
173 { |
169 QPainter painter{this}; |
174 QPainter painter{this}; |
170 painter.setRenderHint(QPainter::Antialiasing); |
175 painter.setRenderHint(QPainter::Antialiasing); |
171 painter.setPen(Qt::black); |
176 painter.setPen(Qt::black); |
172 painter.setBrush(Qt::green); |
177 painter.setBrush(Qt::green); |
173 const QPointF pos = this->modelToScreenCoordinates(*this->worldPosition); |
178 const QPointF pos = this->modelToScreenCoordinates(*this->worldPosition); |
174 painter.drawEllipse(pos, 5, 5); |
179 painter.drawEllipse(pos, 5, 5); |
175 painter.setPen(Qt::white); |
180 painter.setPen(Qt::white); |
176 painter.drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition)); |
181 painter.drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition)); |
177 } |
|
178 { |
|
179 QPainter axisPainter{this}; |
|
180 axisPainter.setRenderHint(QPainter::Antialiasing); |
|
181 axisPainter.setPen(Qt::red); |
|
182 axisPainter.drawLine( |
|
183 this->modelToScreenCoordinates({10, 0, 0}), |
|
184 this->modelToScreenCoordinates({-10, 0, 0})); |
|
185 axisPainter.setPen(Qt::green); |
|
186 axisPainter.drawLine( |
|
187 this->modelToScreenCoordinates({0, 10, 0}), |
|
188 this->modelToScreenCoordinates({0, -10, 0})); |
|
189 axisPainter.setPen(Qt::blue); |
|
190 axisPainter.drawLine( |
|
191 this->modelToScreenCoordinates({0, 0, 10}), |
|
192 this->modelToScreenCoordinates({0, 0, -10})); |
|
193 } |
182 } |
194 } |
183 } |
195 |
184 |
196 void Canvas::updateGridMatrix() |
185 void Canvas::updateGridMatrix() |
197 { |
186 { |