1 #include "lc_global.h"
2 #include "lc_view.h"
3 #include "lc_viewwidget.h"
4 #include <stdlib.h>
5 #include "lc_mainwindow.h"
6 #include "camera.h"
7 #include "texfont.h"
8 #include "lc_texture.h"
9 #include "piece.h"
10 #include "pieceinf.h"
11 #include "lc_synth.h"
12 #include "lc_scene.h"
13 #include "lc_context.h"
14 #include "lc_viewsphere.h"
15 #include "lc_findreplacewidget.h"
16
17 lcFindReplaceParams lcView::mFindReplaceParams;
18 lcFindReplaceWidget* lcView::mFindWidget;
19
20 lcView* lcView::mLastFocusedView;
21 std::vector<lcView*> lcView::mViews;
22
23 lcVertexBuffer lcView::mRotateMoveVertexBuffer;
24 lcIndexBuffer lcView::mRotateMoveIndexBuffer;
25
lcView(lcViewType ViewType,lcModel * Model)26 lcView::lcView(lcViewType ViewType, lcModel* Model)
27 : mViewType(ViewType), mScene(new lcScene()), mModel(Model)
28 {
29 mContext = new lcContext();
30 mViews.push_back(this);
31
32 mViewSphere = std::unique_ptr<lcViewSphere>(new lcViewSphere(this));
33 memset(mGridSettings, 0, sizeof(mGridSettings));
34
35 mDragState = lcDragState::None;
36 mTrackToolFromOverlay = false;
37
38 lcView* ActiveView = gMainWindow ? gMainWindow->GetActiveView() : nullptr;
39
40 if (ActiveView)
41 SetCamera(ActiveView->mCamera, false);
42 else
43 {
44 mCamera = new lcCamera(true);
45 mCamera->SetViewpoint(lcViewpoint::Home);
46 }
47 }
48
~lcView()49 lcView::~lcView()
50 {
51 mContext->DestroyVertexBuffer(mGridBuffer);
52
53 if (gMainWindow && mViewType == lcViewType::View)
54 gMainWindow->RemoveView(this);
55
56 if (mCamera && mCamera->IsSimple())
57 delete mCamera;
58
59 mViews.erase(std::find(mViews.begin(), mViews.end(), this));
60
61 if (mLastFocusedView == this)
62 mLastFocusedView = nullptr;
63
64 if (mDeleteContext)
65 delete mContext;
66 }
67
GetModelViews(const lcModel * Model)68 std::vector<lcView*> lcView::GetModelViews(const lcModel* Model)
69 {
70 std::vector<lcView*> Views;
71
72 for (lcView* View : mViews)
73 if (View->GetModel() == Model)
74 Views.push_back(View);
75
76 return Views;
77 }
78
UpdateProjectViews(const Project * Project)79 void lcView::UpdateProjectViews(const Project* Project)
80 {
81 for (lcView* View : mViews)
82 {
83 const lcModel* ViewModel = View->GetActiveModel();
84
85 if (ViewModel && ViewModel->GetProject() == Project)
86 View->Redraw();
87 }
88 }
89
UpdateAllViews()90 void lcView::UpdateAllViews()
91 {
92 for (lcView* View : mViews)
93 View->Redraw();
94 }
95
MakeCurrent()96 void lcView::MakeCurrent()
97 {
98 mContext->MakeCurrent();
99 }
100
Redraw()101 void lcView::Redraw()
102 {
103 if (mWidget)
104 mWidget->update();
105 }
106
SetOffscreenContext()107 void lcView::SetOffscreenContext()
108 {
109 mContext->SetOffscreenContext();
110 }
111
SetFocus(bool Focus)112 void lcView::SetFocus(bool Focus)
113 {
114 if (Focus)
115 {
116 if (mLastFocusedView != this)
117 {
118 delete mFindWidget;
119 mFindWidget = nullptr;
120
121 mLastFocusedView = this;
122 }
123
124 emit FocusReceived();
125 }
126 }
127
SetMousePosition(int MouseX,int MouseY)128 void lcView::SetMousePosition(int MouseX, int MouseY)
129 {
130 mMouseX = MouseX;
131 mMouseY = MouseY;
132 }
133
SetMouseModifiers(Qt::KeyboardModifiers MouseModifiers)134 void lcView::SetMouseModifiers(Qt::KeyboardModifiers MouseModifiers)
135 {
136 mMouseModifiers = MouseModifiers;
137 }
138
GetActiveModel() const139 lcModel* lcView::GetActiveModel() const
140 {
141 return !mActiveSubmodelInstance ? mModel : mActiveSubmodelInstance->mPieceInfo->GetModel();
142 }
143
SetTopSubmodelActive()144 void lcView::SetTopSubmodelActive()
145 {
146 lcModel* ActiveModel = GetActiveModel();
147
148 if (mActiveSubmodelInstance)
149 {
150 ActiveModel->SetActive(false);
151 mActiveSubmodelInstance = nullptr;
152 }
153
154 GetActiveModel()->UpdateInterface();
155 }
156
SetSelectedSubmodelActive()157 void lcView::SetSelectedSubmodelActive()
158 {
159 lcModel* ActiveModel = GetActiveModel();
160 lcObject* Object = ActiveModel->GetFocusObject();
161
162 if (mActiveSubmodelInstance)
163 {
164 ActiveModel->SetActive(false);
165 mActiveSubmodelInstance = nullptr;
166 }
167
168 if (Object && Object->IsPiece())
169 {
170 lcPiece* Piece = (lcPiece*)Object;
171
172 if (Piece->mPieceInfo->IsModel())
173 {
174 mActiveSubmodelTransform = lcMatrix44Identity();
175 mModel->GetPieceWorldMatrix(Piece, mActiveSubmodelTransform);
176 mActiveSubmodelInstance = Piece;
177 ActiveModel = mActiveSubmodelInstance->mPieceInfo->GetModel();
178 ActiveModel->SetActive(true);
179 RemoveCamera();
180 }
181 }
182
183 GetActiveModel()->UpdateInterface();
184 }
185
CreateResources(lcContext * Context)186 void lcView::CreateResources(lcContext* Context)
187 {
188 gGridTexture = new lcTexture;
189 gGridTexture->CreateGridTexture();
190
191 CreateSelectMoveOverlayMesh(Context);
192 }
193
CreateSelectMoveOverlayMesh(lcContext * Context)194 void lcView::CreateSelectMoveOverlayMesh(lcContext* Context)
195 {
196 float Verts[(51 + 138 + 10) * 3];
197 float* CurVert = Verts;
198
199 const float OverlayMovePlaneSize = 0.5f;
200 const float OverlayMoveArrowSize = 1.5f;
201 const float OverlayMoveArrowCapSize = 0.9f;
202 const float OverlayMoveArrowCapRadius = 0.1f;
203 const float OverlayMoveArrowBodySize = 1.2f;
204 const float OverlayMoveArrowBodyRadius = 0.05f;
205 const float OverlayRotateArrowStart = 1.0f;
206 const float OverlayRotateArrowEnd = 1.5f;
207 const float OverlayRotateArrowCenter = 1.2f;
208
209 *CurVert++ = OverlayMoveArrowSize; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
210
211 for (int EdgeIdx = 0; EdgeIdx < 8; EdgeIdx++)
212 {
213 *CurVert++ = OverlayMoveArrowCapSize;
214 *CurVert++ = cosf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius;
215 *CurVert++ = sinf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius;
216 }
217
218 *CurVert++ = 0.0f; *CurVert++ = -OverlayMoveArrowBodyRadius; *CurVert++ = 0.0f;
219 *CurVert++ = 0.0f; *CurVert++ = OverlayMoveArrowBodyRadius; *CurVert++ = 0.0f;
220 *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = -OverlayMoveArrowBodyRadius;
221 *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = OverlayMoveArrowBodyRadius;
222 *CurVert++ = OverlayMoveArrowBodySize; *CurVert++ = -OverlayMoveArrowBodyRadius; *CurVert++ = 0.0f;
223 *CurVert++ = OverlayMoveArrowBodySize; *CurVert++ = OverlayMoveArrowBodyRadius; *CurVert++ = 0.0f;
224 *CurVert++ = OverlayMoveArrowBodySize; *CurVert++ = 0.0f; *CurVert++ = -OverlayMoveArrowBodyRadius;
225 *CurVert++ = OverlayMoveArrowBodySize; *CurVert++ = 0.0f; *CurVert++ = OverlayMoveArrowBodyRadius;
226
227 for (int VertIdx = 0; VertIdx < 17; VertIdx++)
228 {
229 *CurVert = *(CurVert - 50); CurVert++;
230 *CurVert = *(CurVert - 52); CurVert++;
231 *CurVert = *(CurVert - 51); CurVert++;
232 }
233
234 for (int VertIdx = 0; VertIdx < 17; VertIdx++)
235 {
236 *CurVert = *(CurVert - 100); CurVert++;
237 *CurVert = *(CurVert - 102); CurVert++;
238 *CurVert = *(CurVert - 104); CurVert++;
239 }
240
241 *CurVert++ = 0.0f; *CurVert++ = OverlayRotateArrowEnd - OverlayMoveArrowCapRadius; *CurVert++ = OverlayRotateArrowStart;
242
243 for (int EdgeIdx = 0; EdgeIdx < 8; EdgeIdx++)
244 {
245 *CurVert++ = cosf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius;
246 *CurVert++ = sinf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius + OverlayRotateArrowEnd - OverlayMoveArrowCapRadius;
247 *CurVert++ = OverlayRotateArrowCenter;
248 }
249
250 *CurVert++ = 0.0f; *CurVert++ = OverlayRotateArrowStart; *CurVert++ = OverlayRotateArrowEnd - OverlayMoveArrowCapRadius;
251
252 for (int EdgeIdx = 0; EdgeIdx < 8; EdgeIdx++)
253 {
254 *CurVert++ = cosf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius;
255 *CurVert++ = OverlayRotateArrowCenter;
256 *CurVert++ = sinf(LC_2PI * EdgeIdx / 8) * OverlayMoveArrowCapRadius + OverlayRotateArrowEnd - OverlayMoveArrowCapRadius;
257 }
258
259 for (int EdgeIdx = 0; EdgeIdx < 7; EdgeIdx++)
260 {
261 const float Radius1 = OverlayRotateArrowEnd - OverlayMoveArrowCapRadius - OverlayRotateArrowCenter - OverlayMoveArrowBodyRadius;
262 const float Radius2 = OverlayRotateArrowEnd - OverlayMoveArrowCapRadius - OverlayRotateArrowCenter + OverlayMoveArrowBodyRadius;
263 float x = cosf(LC_2PI / 4 * EdgeIdx / 6);
264 float y = sinf(LC_2PI / 4 * EdgeIdx / 6);
265
266 *CurVert++ = 0.0f;
267 *CurVert++ = OverlayRotateArrowCenter + x * Radius1;
268 *CurVert++ = OverlayRotateArrowCenter + y * Radius1;
269 *CurVert++ = 0.0f;
270 *CurVert++ = OverlayRotateArrowCenter + x * Radius2;
271 *CurVert++ = OverlayRotateArrowCenter + y * Radius2;
272 }
273
274 for (int EdgeIdx = 0; EdgeIdx < 7; EdgeIdx++)
275 {
276 const float Radius = OverlayRotateArrowEnd - OverlayMoveArrowCapRadius - OverlayRotateArrowCenter;
277 float x = cosf(LC_2PI / 4 * EdgeIdx / 6);
278 float y = sinf(LC_2PI / 4 * EdgeIdx / 6);
279
280 *CurVert++ = -OverlayMoveArrowBodyRadius;
281 *CurVert++ = OverlayRotateArrowCenter + x * Radius;
282 *CurVert++ = OverlayRotateArrowCenter + y * Radius;
283 *CurVert++ = OverlayMoveArrowBodyRadius;
284 *CurVert++ = OverlayRotateArrowCenter + x * Radius;
285 *CurVert++ = OverlayRotateArrowCenter + y * Radius;
286 }
287
288 for (int VertIdx = 0; VertIdx < 46; VertIdx++)
289 {
290 *CurVert = *(CurVert - 137); CurVert++;
291 *CurVert = *(CurVert - 139); CurVert++;
292 *CurVert = *(CurVert - 138); CurVert++;
293 }
294
295 for (int VertIdx = 0; VertIdx < 46; VertIdx++)
296 {
297 *CurVert = *(CurVert - 274); CurVert++;
298 *CurVert = *(CurVert - 276); CurVert++;
299 *CurVert = *(CurVert - 278); CurVert++;
300 }
301
302 *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
303 *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f;
304 *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize; *CurVert++ = OverlayMovePlaneSize;
305 *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize;
306 *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
307 *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize;
308 *CurVert++ = 0.0f; *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize;
309 *CurVert++ = 0.0f; *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f;
310 *CurVert++ = OverlayMovePlaneSize; *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f;
311 *CurVert++ = OverlayMovePlaneSize; *CurVert++ = 0.0f; *CurVert++ = 0.0f;
312
313 const GLushort Indices[108 + 360 + 12] =
314 {
315 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8, 0, 8, 1,
316 9, 10, 14, 14, 13, 9, 11, 12, 15, 15, 16, 12,
317 17, 18, 19, 17, 19, 20, 17, 20, 21, 17, 21, 22, 17, 22, 23, 17, 23, 24, 17, 24, 25, 17, 25, 18,
318 26, 27, 31, 31, 30, 26, 28, 29, 32, 32, 33, 29,
319 34, 35, 36, 34, 36, 37, 34, 37, 38, 34, 38, 39, 34, 39, 40, 34, 40, 41, 34, 41, 42, 34, 42, 35,
320 43, 44, 48, 48, 47, 43, 45, 46, 49, 49, 50, 46,
321 51, 52, 53, 51, 53, 54, 51, 54, 55, 51, 55, 56, 51, 56, 57, 51, 57, 58, 51, 58, 59, 51, 59, 52,
322 60, 61, 62, 60, 62, 63, 60, 63, 64, 60, 64, 65, 60, 65, 66, 60, 66, 67, 60, 67, 68, 60, 68, 61,
323 69, 70, 71, 71, 72, 70, 71, 72, 73, 73, 74, 72, 73, 74, 75, 75, 76, 74, 75, 76, 77, 77, 78, 76, 77, 78, 79, 79, 80, 78, 79, 80, 81, 81, 82, 80,
324 83, 84, 85, 85, 86, 84, 85, 86, 87, 87, 88, 86, 87, 88, 89, 89, 90, 88, 89, 90, 91, 91, 92, 90, 91, 92, 93, 93, 94, 92, 93, 94, 95, 95, 96, 94,
325 97, 98, 99, 97, 99, 100, 97, 100, 101, 97, 101, 102, 97, 102, 103, 97, 103, 104, 97, 104, 105, 97, 105, 98,
326 106, 107, 108, 106, 108, 109, 106, 109, 110, 106, 110, 111, 106, 111, 112, 106, 112, 113, 106, 113, 114, 106, 114, 107,
327 115, 116, 117, 117, 118, 116, 117, 118, 119, 119, 120, 118, 119, 120, 121, 121, 122, 120, 121, 122, 123, 123, 124, 122, 123, 124, 125, 125, 126, 124, 125, 126, 127, 127, 128, 126,
328 129, 130, 131, 131, 132, 130, 131, 132, 133, 133, 134, 132, 133, 134, 135, 135, 136, 134, 135, 136, 137, 137, 138, 136, 137, 138, 139, 139, 140, 138, 139, 140, 141, 141, 142, 140,
329 143, 144, 145, 143, 145, 146, 143, 146, 147, 143, 147, 148, 143, 148, 149, 143, 149, 150, 143, 150, 151, 143, 151, 144,
330 152, 153, 154, 152, 154, 155, 152, 155, 156, 152, 156, 157, 152, 157, 158, 152, 158, 159, 152, 159, 160, 152, 160, 153,
331 161, 162, 163, 163, 164, 162, 163, 164, 165, 165, 166, 164, 165, 166, 167, 167, 168, 166, 167, 168, 169, 169, 170, 168, 169, 170, 171, 171, 172, 170, 171, 172, 173, 173, 174, 172,
332 175, 176, 177, 177, 178, 176, 177, 178, 179, 179, 180, 178, 179, 180, 181, 181, 182, 180, 181, 182, 183, 183, 184, 182, 183, 184, 185, 185, 186, 184, 185, 186, 187, 187, 188, 186,
333 189, 190, 191, 192, 189, 193, 194, 195, 189, 196, 197, 198
334 };
335
336 mRotateMoveVertexBuffer = Context->CreateVertexBuffer(sizeof(Verts), Verts);
337 mRotateMoveIndexBuffer = Context->CreateIndexBuffer(sizeof(Indices), Indices);
338 }
339
DestroyResources(lcContext * Context)340 void lcView::DestroyResources(lcContext* Context)
341 {
342 delete gGridTexture;
343 gGridTexture = nullptr;
344
345 Context->DestroyVertexBuffer(mRotateMoveVertexBuffer);
346 Context->DestroyIndexBuffer(mRotateMoveIndexBuffer);
347 }
348
RemoveCamera()349 void lcView::RemoveCamera()
350 {
351 if (mCamera && mCamera->IsSimple())
352 return;
353
354 lcCamera* Camera = mCamera;
355 mCamera = new lcCamera(true);
356
357 if (Camera)
358 mCamera->CopyPosition(Camera);
359 else
360 mCamera->SetViewpoint(lcViewpoint::Home);
361
362 emit CameraChanged();
363 Redraw();
364 }
365
ProjectPoint(const lcVector3 & Point) const366 lcVector3 lcView::ProjectPoint(const lcVector3& Point) const
367 {
368 int Viewport[4] = { 0, 0, mWidth, mHeight };
369 return lcProjectPoint(Point, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
370 }
371
UnprojectPoint(const lcVector3 & Point) const372 lcVector3 lcView::UnprojectPoint(const lcVector3& Point) const
373 {
374 int Viewport[4] = { 0, 0, mWidth, mHeight };
375 return lcUnprojectPoint(Point, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
376 }
377
UnprojectPoints(lcVector3 * Points,int NumPoints) const378 void lcView::UnprojectPoints(lcVector3* Points, int NumPoints) const
379 {
380 int Viewport[4] = { 0, 0, mWidth, mHeight };
381 lcUnprojectPoints(Points, NumPoints, mCamera->mWorldView, GetProjectionMatrix(), Viewport);
382 }
383
GetProjectionMatrix() const384 lcMatrix44 lcView::GetProjectionMatrix() const
385 {
386 float AspectRatio = (float)mWidth / (float)mHeight;
387
388 if (mCamera->IsOrtho())
389 {
390 float OrthoHeight = mCamera->GetOrthoHeight() / 2.0f;
391 float OrthoWidth = OrthoHeight * AspectRatio;
392
393 return lcMatrix44Ortho(-OrthoWidth, OrthoWidth, -OrthoHeight, OrthoHeight, mCamera->m_zNear, mCamera->m_zFar * 4);
394 }
395 else
396 return lcMatrix44Perspective(mCamera->m_fovy, AspectRatio, mCamera->m_zNear, mCamera->m_zFar);
397 }
398
GetTileProjectionMatrix(int CurrentRow,int CurrentColumn,int CurrentTileWidth,int CurrentTileHeight) const399 lcMatrix44 lcView::GetTileProjectionMatrix(int CurrentRow, int CurrentColumn, int CurrentTileWidth, int CurrentTileHeight) const
400 {
401 int ImageWidth = mRenderImage.width();
402 int ImageHeight = mRenderImage.height();
403
404 double ImageLeft, ImageRight, ImageBottom, ImageTop, Near, Far;
405 double AspectRatio = (double)ImageWidth / (double)ImageHeight;
406
407 if (mCamera->IsOrtho())
408 {
409 float OrthoHeight = mCamera->GetOrthoHeight() / 2.0f;
410 float OrthoWidth = OrthoHeight * AspectRatio;
411
412 ImageLeft = -OrthoWidth;
413 ImageRight = OrthoWidth;
414 ImageBottom = -OrthoHeight;
415 ImageTop = OrthoHeight;
416 Near = mCamera->m_zNear;
417 Far = mCamera->m_zFar * 4;
418 }
419 else
420 {
421 double xmin, xmax, ymin, ymax;
422 ymax = mCamera->m_zNear * tan(mCamera->m_fovy * 3.14159265 / 360.0);
423 ymin = -ymax;
424 xmin = ymin * AspectRatio;
425 xmax = ymax * AspectRatio;
426
427 ImageLeft = xmin;
428 ImageRight = xmax;
429 ImageBottom = ymin;
430 ImageTop = ymax;
431 Near = mCamera->m_zNear;
432 Far = mCamera->m_zFar;
433 }
434
435 double Left = ImageLeft + (ImageRight - ImageLeft) * (CurrentColumn * mWidth) / ImageWidth;
436 double Right = Left + (ImageRight - ImageLeft) * CurrentTileWidth / ImageWidth;
437 double Bottom = ImageBottom + (ImageTop - ImageBottom) * (CurrentRow * mHeight) / ImageHeight;
438 double Top = Bottom + (ImageTop - ImageBottom) * CurrentTileHeight / ImageHeight;
439
440 if (mCamera->IsOrtho())
441 return lcMatrix44Ortho(Left, Right, Bottom, Top, Near, Far);
442 else
443 return lcMatrix44Frustum(Left, Right, Bottom, Top, Near, Far);
444 }
445
ShowContextMenu() const446 void lcView::ShowContextMenu() const
447 {
448 if (mViewType != lcViewType::View)
449 return;
450
451 QAction** Actions = gMainWindow->mActions;
452
453 QMenu* Popup = new QMenu();
454
455 Popup->addAction(Actions[LC_EDIT_CUT]);
456 Popup->addAction(Actions[LC_EDIT_COPY]);
457 Popup->addAction(Actions[LC_EDIT_PASTE]);
458 Popup->addAction(Actions[LC_EDIT_PASTE_STEPS]);
459 Popup->addAction(Actions[LC_PIECE_DUPLICATE]);
460
461 Popup->addSeparator();
462
463 Popup->addAction(Actions[LC_PIECE_CONTROL_POINT_INSERT]);
464 Popup->addAction(Actions[LC_PIECE_CONTROL_POINT_REMOVE]);
465
466 Popup->addSeparator();
467
468 Popup->addAction(Actions[LC_PIECE_EDIT_SELECTED_SUBMODEL]);
469 Popup->addAction(Actions[LC_PIECE_EDIT_END_SUBMODEL]);
470 Popup->addAction(Actions[LC_PIECE_VIEW_SELECTED_MODEL]);
471 Popup->addAction(Actions[LC_PIECE_INLINE_SELECTED_MODELS]);
472 Popup->addAction(Actions[LC_PIECE_MOVE_SELECTION_TO_MODEL]);
473
474 Popup->addSeparator();
475
476 Popup->addMenu(gMainWindow->GetToolsMenu());
477 Popup->addMenu(gMainWindow->GetViewpointMenu());
478 Popup->addMenu(gMainWindow->GetCameraMenu());
479 Popup->addMenu(gMainWindow->GetProjectionMenu());
480 Popup->addMenu(gMainWindow->GetShadingMenu());
481
482 Popup->addSeparator();
483
484 Popup->addAction(Actions[LC_VIEW_SPLIT_HORIZONTAL]);
485 Popup->addAction(Actions[LC_VIEW_SPLIT_VERTICAL]);
486 Popup->addAction(Actions[LC_VIEW_REMOVE_VIEW]);
487 Popup->addAction(Actions[LC_VIEW_RESET_VIEWS]);
488
489 Popup->exec(QCursor::pos());
490 delete Popup;
491 }
492
CloseFindReplaceDialog()493 bool lcView::CloseFindReplaceDialog()
494 {
495 if (mFindWidget && (mWidget->hasFocus() || mFindWidget->focusWidget()))
496 {
497 delete mFindWidget;
498 mFindWidget = nullptr;
499
500 return true;
501 }
502
503 return false;
504 }
505
ShowFindReplaceWidget(bool Replace)506 void lcView::ShowFindReplaceWidget(bool Replace)
507 {
508 delete mFindWidget;
509 mFindReplaceParams = lcFindReplaceParams();
510 mFindWidget = new lcFindReplaceWidget(mWidget, GetActiveModel(), Replace);
511 }
512
GetMoveDirection(const lcVector3 & Direction) const513 lcVector3 lcView::GetMoveDirection(const lcVector3& Direction) const
514 {
515 if (lcGetPreferences().mFixedAxes)
516 return Direction;
517
518 // TODO: rewrite this
519 lcVector3 axis = Direction;
520
521 lcVector3 Pts[3] = { lcVector3(5.0f, 5.0f, 0.1f), lcVector3(10.0f, 5.0f, 0.1f), lcVector3(5.0f, 10.0f, 0.1f) };
522 UnprojectPoints(Pts, 3);
523
524 float ax, ay;
525 lcVector3 vx((Pts[1][0] - Pts[0][0]), (Pts[1][1] - Pts[0][1]), 0);//Pts[1][2] - Pts[0][2] };
526 vx.Normalize();
527 lcVector3 x(1, 0, 0);
528 ax = acosf(lcDot(vx, x));
529
530 lcVector3 vy((Pts[2][0] - Pts[0][0]), (Pts[2][1] - Pts[0][1]), 0);//Pts[2][2] - Pts[0][2] };
531 vy.Normalize();
532 lcVector3 y(0, -1, 0);
533 ay = acosf(lcDot(vy, y));
534
535 if (ax > 135)
536 axis[0] = -axis[0];
537
538 if (ay < 45)
539 axis[1] = -axis[1];
540
541 if (ax >= 45 && ax <= 135)
542 {
543 float tmp = axis[0];
544
545 ax = acosf(lcDot(vx, y));
546 if (ax > 90)
547 {
548 axis[0] = -axis[1];
549 axis[1] = tmp;
550 }
551 else
552 {
553 axis[0] = axis[1];
554 axis[1] = -tmp;
555 }
556 }
557
558 return axis;
559 }
560
GetPieceInsertPosition(bool IgnoreSelected,PieceInfo * Info) const561 lcMatrix44 lcView::GetPieceInsertPosition(bool IgnoreSelected, PieceInfo* Info) const
562 {
563 lcPiece* HitPiece = (lcPiece*)FindObjectUnderPointer(true, IgnoreSelected).Object;
564 lcModel* ActiveModel = GetActiveModel();
565
566 if (HitPiece)
567 {
568 lcVector3 Position(0, 0, HitPiece->GetBoundingBox().Max.z - Info->GetBoundingBox().Min.z);
569
570 if (gMainWindow->GetRelativeTransform())
571 Position = lcMul31(ActiveModel->SnapPosition(Position), HitPiece->mModelWorld);
572 else
573 Position = ActiveModel->SnapPosition(lcMul31(Position, HitPiece->mModelWorld));
574
575 lcMatrix44 WorldMatrix = HitPiece->mModelWorld;
576 WorldMatrix.SetTranslation(Position);
577
578 return WorldMatrix;
579 }
580
581 std::array<lcVector3, 2> ClickPoints = {{ lcVector3((float)mMouseX, (float)mMouseY, 0.0f), lcVector3((float)mMouseX, (float)mMouseY, 1.0f) }};
582 UnprojectPoints(ClickPoints.data(), 2);
583
584 if (ActiveModel != mModel)
585 {
586 lcMatrix44 InverseMatrix = lcMatrix44AffineInverse(mActiveSubmodelTransform);
587
588 for (lcVector3& Point : ClickPoints)
589 Point = lcMul31(Point, InverseMatrix);
590 }
591
592 const lcBoundingBox& BoundingBox = Info->GetBoundingBox();
593 lcVector3 Intersection;
594
595 if (lcLineSegmentPlaneIntersection(&Intersection, ClickPoints[0], ClickPoints[1], lcVector4(0, 0, 1, BoundingBox.Min.z)))
596 {
597 Intersection = ActiveModel->SnapPosition(Intersection);
598 return lcMatrix44Translation(Intersection);
599 }
600
601 lcVector3 Position;
602
603 if (!ActiveModel->GetFocusPosition(Position))
604 Position = ActiveModel->GetSelectionOrModelCenter();
605
606 lcVector3 FrontVector(mCamera->mTargetPosition - mCamera->mPosition);
607
608 if (lcLineSegmentPlaneIntersection(&Intersection, ClickPoints[0], ClickPoints[1], lcVector4(FrontVector, -lcDot(FrontVector, Position))))
609 {
610 Intersection = ActiveModel->SnapPosition(Intersection);
611 return lcMatrix44Translation(Intersection);
612 }
613
614 return lcMatrix44Translation(UnprojectPoint(lcVector3((float)mMouseX, (float)mMouseY, 0.9f)));
615 }
616
GetCameraLightInsertPosition() const617 lcVector3 lcView::GetCameraLightInsertPosition() const
618 {
619 lcModel* ActiveModel = GetActiveModel();
620
621 std::array<lcVector3, 2> ClickPoints = { { lcVector3((float)mMouseX, (float)mMouseY, 0.0f), lcVector3((float)mMouseX, (float)mMouseY, 1.0f) } };
622 UnprojectPoints(ClickPoints.data(), 2);
623
624 if (ActiveModel != mModel)
625 {
626 lcMatrix44 InverseMatrix = lcMatrix44AffineInverse(mActiveSubmodelTransform);
627
628 for (lcVector3& Point : ClickPoints)
629 Point = lcMul31(Point, InverseMatrix);
630 }
631
632 lcVector3 Min, Max;
633 lcVector3 Center;
634
635 if (ActiveModel->GetVisiblePiecesBoundingBox(Min, Max))
636 Center = (Min + Max) / 2.0f;
637 else
638 Center = lcVector3(0.0f, 0.0f, 0.0f);
639
640 return lcRayPointClosestPoint(Center, ClickPoints[0], ClickPoints[1]);
641 }
642
GetRayUnderPointer(lcVector3 & Start,lcVector3 & End) const643 void lcView::GetRayUnderPointer(lcVector3& Start, lcVector3& End) const
644 {
645 lcVector3 StartEnd[2] =
646 {
647 lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
648 lcVector3((float)mMouseX, (float)mMouseY, 1.0f)
649 };
650
651 UnprojectPoints(StartEnd, 2);
652
653 Start = StartEnd[0];
654 End = StartEnd[1];
655 }
656
FindObjectUnderPointer(bool PiecesOnly,bool IgnoreSelected) const657 lcObjectSection lcView::FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelected) const
658 {
659 lcVector3 StartEnd[2] =
660 {
661 lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
662 lcVector3((float)mMouseX, (float)mMouseY, 1.0f)
663 };
664
665 UnprojectPoints(StartEnd, 2);
666
667 lcObjectRayTest ObjectRayTest;
668
669 ObjectRayTest.PiecesOnly = PiecesOnly;
670 ObjectRayTest.IgnoreSelected = IgnoreSelected;
671 ObjectRayTest.ViewCamera = mCamera;
672 ObjectRayTest.Start = StartEnd[0];
673 ObjectRayTest.End = StartEnd[1];
674 ObjectRayTest.Distance = FLT_MAX;
675 ObjectRayTest.ObjectSection.Object = nullptr;
676 ObjectRayTest.ObjectSection.Section = 0;;
677
678 lcModel* ActiveModel = GetActiveModel();
679
680 if (ActiveModel != mModel)
681 {
682 lcMatrix44 InverseMatrix = lcMatrix44AffineInverse(mActiveSubmodelTransform);
683
684 ObjectRayTest.Start = lcMul31(ObjectRayTest.Start, InverseMatrix);
685 ObjectRayTest.End = lcMul31(ObjectRayTest.End, InverseMatrix);
686 }
687
688 ActiveModel->RayTest(ObjectRayTest);
689
690 return ObjectRayTest.ObjectSection;
691 }
692
FindObjectsInBox(float x1,float y1,float x2,float y2) const693 lcArray<lcObject*> lcView::FindObjectsInBox(float x1, float y1, float x2, float y2) const
694 {
695 float Left, Top, Bottom, Right;
696
697 if (x1 < x2)
698 {
699 Left = x1;
700 Right = x2;
701 }
702 else
703 {
704 Left = x2;
705 Right = x1;
706 }
707
708 if (y1 > y2)
709 {
710 Top = y1;
711 Bottom = y2;
712 }
713 else
714 {
715 Top = y2;
716 Bottom = y1;
717 }
718
719 std::array<lcVector3, 6> Corners =
720 {{
721 lcVector3(Left, Top, 0),
722 lcVector3(Left, Bottom, 0),
723 lcVector3(Right, Bottom, 0),
724 lcVector3(Right, Top, 0),
725 lcVector3(Left, Top, 1),
726 lcVector3(Right, Bottom, 1)
727 }};
728
729 UnprojectPoints(Corners.data(), (int)Corners.size());
730
731 lcModel* ActiveModel = GetActiveModel();
732
733 if (ActiveModel != mModel)
734 {
735 lcMatrix44 InverseMatrix = lcMatrix44AffineInverse(mActiveSubmodelTransform);
736
737 for (lcVector3& Point : Corners)
738 Point = lcMul31(Point, InverseMatrix);
739 }
740
741 lcVector3 PlaneNormals[6];
742 PlaneNormals[0] = lcNormalize(lcCross(Corners[4] - Corners[0], Corners[1] - Corners[0])); // Left
743 PlaneNormals[1] = lcNormalize(lcCross(Corners[5] - Corners[2], Corners[3] - Corners[2])); // Right
744 PlaneNormals[2] = lcNormalize(lcCross(Corners[3] - Corners[0], Corners[4] - Corners[0])); // Top
745 PlaneNormals[3] = lcNormalize(lcCross(Corners[1] - Corners[2], Corners[5] - Corners[2])); // Bottom
746 PlaneNormals[4] = lcNormalize(lcCross(Corners[1] - Corners[0], Corners[3] - Corners[0])); // Front
747 PlaneNormals[5] = lcNormalize(lcCross(Corners[1] - Corners[2], Corners[3] - Corners[2])); // Back
748
749 lcObjectBoxTest ObjectBoxTest;
750 ObjectBoxTest.ViewCamera = mCamera;
751 ObjectBoxTest.Planes[0] = lcVector4(PlaneNormals[0], -lcDot(PlaneNormals[0], Corners[0]));
752 ObjectBoxTest.Planes[1] = lcVector4(PlaneNormals[1], -lcDot(PlaneNormals[1], Corners[5]));
753 ObjectBoxTest.Planes[2] = lcVector4(PlaneNormals[2], -lcDot(PlaneNormals[2], Corners[0]));
754 ObjectBoxTest.Planes[3] = lcVector4(PlaneNormals[3], -lcDot(PlaneNormals[3], Corners[5]));
755 ObjectBoxTest.Planes[4] = lcVector4(PlaneNormals[4], -lcDot(PlaneNormals[4], Corners[0]));
756 ObjectBoxTest.Planes[5] = lcVector4(PlaneNormals[5], -lcDot(PlaneNormals[5], Corners[5]));
757
758 ActiveModel->BoxTest(ObjectBoxTest);
759
760 return ObjectBoxTest.Objects;
761 }
762
GetStepImages(lcStep Start,lcStep End)763 std::vector<QImage> lcView::GetStepImages(lcStep Start, lcStep End)
764 {
765 std::vector<QImage> Images;
766
767 if (!BeginRenderToImage(mWidth, mHeight))
768 {
769 QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images."));
770 return Images;
771 }
772
773 const lcStep CurrentStep = mModel->GetCurrentStep();
774
775 for (lcStep Step = Start; Step <= End; Step++)
776 {
777 mModel->SetTemporaryStep(Step);
778
779 OnDraw();
780
781 Images.emplace_back(GetRenderImage());
782 }
783
784 EndRenderToImage();
785
786 mModel->SetTemporaryStep(CurrentStep);
787
788 if (!mModel->IsActive())
789 mModel->CalculateStep(LC_STEP_MAX);
790
791 return Images;
792 }
793
SaveStepImages(const QString & BaseName,bool AddStepSuffix,lcStep Start,lcStep End,std::function<void (const QString &)> ProgressCallback)794 void lcView::SaveStepImages(const QString& BaseName, bool AddStepSuffix, lcStep Start, lcStep End, std::function<void(const QString&)> ProgressCallback)
795 {
796 std::vector<QImage> Images = GetStepImages(Start, End);
797
798 for (lcStep Step = Start; Step <= End; Step++)
799 {
800 QString FileName;
801
802 if (AddStepSuffix)
803 FileName = BaseName.arg(Step, 2, 10, QLatin1Char('0'));
804 else
805 FileName = BaseName;
806
807 QImageWriter Writer(FileName);
808
809 if (Writer.format().isEmpty())
810 Writer.setFormat("png");
811
812 if (!Writer.write(Images[Step - Start]))
813 {
814 QMessageBox::information(gMainWindow, tr("Error"), tr("Error writing to file '%1':\n%2").arg(FileName, Writer.errorString()));
815 break;
816 }
817
818 if (ProgressCallback)
819 ProgressCallback(FileName);
820 }
821 }
822
BeginRenderToImage(int Width,int Height)823 bool lcView::BeginRenderToImage(int Width, int Height)
824 {
825 GLint MaxTexture;
826 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexture);
827
828 MaxTexture = qMin(MaxTexture, 2048);
829
830 const int Samples = QSurfaceFormat::defaultFormat().samples();
831 if (Samples > 1)
832 MaxTexture /= Samples;
833
834 int TileWidth = qMin(Width, MaxTexture);
835 int TileHeight = qMin(Height, MaxTexture);
836
837 mWidth = TileWidth;
838 mHeight = TileHeight;
839 mRenderImage = QImage(Width, Height, QImage::Format_ARGB32);
840
841 QOpenGLFramebufferObjectFormat Format;
842 Format.setAttachment(QOpenGLFramebufferObject::Depth);
843
844 if (QSurfaceFormat::defaultFormat().samples() > 1)
845 Format.setSamples(QSurfaceFormat::defaultFormat().samples());
846
847 mRenderFramebuffer = std::unique_ptr<QOpenGLFramebufferObject>(new QOpenGLFramebufferObject(QSize(TileWidth, TileHeight), Format));
848
849 return mRenderFramebuffer->bind();
850 }
851
EndRenderToImage()852 void lcView::EndRenderToImage()
853 {
854 mRenderFramebuffer.reset();
855 }
856
GetRenderImage() const857 QImage lcView::GetRenderImage() const
858 {
859 return mRenderImage;
860 }
861
BindRenderFramebuffer()862 void lcView::BindRenderFramebuffer()
863 {
864 mRenderFramebuffer->bind();
865 }
866
UnbindRenderFramebuffer()867 void lcView::UnbindRenderFramebuffer()
868 {
869 mRenderFramebuffer->release();
870 }
871
GetRenderFramebufferImage() const872 QImage lcView::GetRenderFramebufferImage() const
873 {
874 return mRenderFramebuffer->toImage();
875 }
876
OnDraw()877 void lcView::OnDraw()
878 {
879 if (!mModel)
880 return;
881
882 //#define LC_PROFILE_DRAW
883 #ifdef LC_PROFILE_DRAW
884 static std::array<GLuint64, 30> QueryResults;
885 static std::array<qint64, 30> TimerResults;
886 static int FrameNumber;
887
888 QElapsedTimer Timer;
889 QOpenGLTimerQuery Query;
890
891 if (!Query.isCreated())
892 Query.create();
893
894 Query.begin();
895 Timer.start();
896 #endif
897
898 const lcPreferences& Preferences = lcGetPreferences();
899 const bool DrawOverlays = mWidget != nullptr;
900 const bool DrawInterface = mWidget != nullptr && mViewType == lcViewType::View;
901
902 lcShadingMode ShadingMode = Preferences.mShadingMode;
903 if (ShadingMode == lcShadingMode::Wireframe && !mWidget)
904 ShadingMode = lcShadingMode::Flat;
905
906 mScene->SetShadingMode(ShadingMode);
907 mScene->SetAllowLOD(Preferences.mAllowLOD && mWidget != nullptr);
908 mScene->SetLODDistance(Preferences.mMeshLODDistance);
909
910 mScene->Begin(mCamera->mWorldView);
911
912 mScene->SetActiveSubmodelInstance(mActiveSubmodelInstance, mActiveSubmodelTransform);
913 mScene->SetDrawInterface(DrawInterface);
914
915 mModel->GetScene(mScene.get(), mCamera, Preferences.mHighlightNewParts, Preferences.mFadeSteps);
916
917 if (DrawInterface && mTrackTool == lcTrackTool::Insert)
918 {
919 PieceInfo* Info = gMainWindow->GetCurrentPieceInfo();
920
921 if (Info)
922 {
923 lcMatrix44 WorldMatrix = GetPieceInsertPosition(false, Info);
924
925 if (GetActiveModel() != mModel)
926 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
927
928 Info->AddRenderMeshes(mScene.get(), WorldMatrix, gMainWindow->mColorIndex, lcRenderMeshState::Focused, false);
929 }
930 }
931
932 if (DrawInterface)
933 mScene->SetPreTranslucentCallback([this]() { DrawGrid(); });
934
935 mScene->End();
936
937 int TotalTileRows = 1;
938 int TotalTileColumns = 1;
939
940 if (!mRenderImage.isNull())
941 {
942 int ImageWidth = mRenderImage.width();
943 int ImageHeight = mRenderImage.height();
944
945 if (ImageWidth > mWidth || ImageHeight > mHeight)
946 {
947 TotalTileColumns = (mWidth + ImageWidth - 1) / mWidth;
948 TotalTileRows = (mHeight + ImageHeight - 1) / mHeight;
949 }
950 }
951
952 for (int CurrentTileRow = 0; CurrentTileRow < TotalTileRows; CurrentTileRow++)
953 {
954 for (int CurrentTileColumn = 0; CurrentTileColumn < TotalTileColumns; CurrentTileColumn++)
955 {
956 mContext->SetDefaultState();
957 mContext->SetViewport(0, 0, mWidth, mHeight);
958
959 DrawBackground();
960
961 int CurrentTileWidth, CurrentTileHeight;
962
963 if (!mRenderImage.isNull() && (TotalTileRows > 1 || TotalTileColumns > 1))
964 {
965 if (CurrentTileRow < TotalTileRows - 1)
966 CurrentTileHeight = mHeight;
967 else
968 CurrentTileHeight = mRenderImage.height() - (TotalTileRows - 1) * (mHeight);
969
970 if (CurrentTileColumn < TotalTileColumns - 1)
971 CurrentTileWidth = mWidth;
972 else
973 CurrentTileWidth = mRenderImage.width() - (TotalTileColumns - 1) * (mWidth);
974
975 mContext->SetViewport(0, 0, CurrentTileWidth, CurrentTileHeight);
976 mContext->SetProjectionMatrix(GetTileProjectionMatrix(CurrentTileRow, CurrentTileColumn, CurrentTileWidth, CurrentTileHeight));
977 }
978 else
979 {
980 CurrentTileWidth = mWidth;
981 CurrentTileHeight = mHeight;
982
983 mContext->SetProjectionMatrix(GetProjectionMatrix());
984 }
985
986 mContext->SetLineWidth(Preferences.mLineWidth);
987
988 mScene->Draw(mContext);
989
990 if (!mRenderImage.isNull())
991 {
992 UnbindRenderFramebuffer();
993 QImage TileImage = GetRenderFramebufferImage();
994 BindRenderFramebuffer();
995 quint8* Buffer = TileImage.bits();
996 uchar* ImageBuffer = mRenderImage.bits();
997
998 quint32 TileY = 0, SrcY = 0;
999 if (CurrentTileRow != TotalTileRows - 1)
1000 TileY = (TotalTileRows - CurrentTileRow - 1) * mHeight - ((mHeight - mRenderImage.height() % mHeight) % mHeight);
1001 else if (TotalTileRows > 1)
1002 SrcY = (mHeight - mRenderImage.height() % mHeight) % mHeight;
1003
1004 quint32 TileStart = ((CurrentTileColumn * mWidth) + (TileY * mRenderImage.width())) * 4;
1005
1006 for (int y = 0; y < CurrentTileHeight; y++)
1007 {
1008 quint8* src = Buffer + (SrcY + y) * mWidth * 4;
1009 quint8* dst = ImageBuffer + TileStart + y * mRenderImage.width() * 4;
1010
1011 memcpy(dst, src, CurrentTileWidth * 4);
1012 }
1013 }
1014 }
1015 }
1016
1017 if (DrawInterface)
1018 mScene->DrawInterfaceObjects(mContext);
1019
1020 if (DrawOverlays)
1021 DrawAxes();
1022
1023 if (DrawInterface)
1024 {
1025 lcTool Tool = gMainWindow->GetTool();
1026 lcModel* ActiveModel = GetActiveModel();
1027
1028 if ((Tool == lcTool::Select || Tool == lcTool::Move) && mTrackButton == lcTrackButton::None && ActiveModel->AnyObjectsSelected())
1029 DrawSelectMoveOverlay();
1030 else if (GetCurrentTool() == lcTool::Move && mTrackButton != lcTrackButton::None)
1031 DrawSelectMoveOverlay();
1032 else if ((Tool == lcTool::Rotate || (Tool == lcTool::Select && mTrackButton != lcTrackButton::None && mTrackTool >= lcTrackTool::RotateX && mTrackTool <= lcTrackTool::RotateXYZ)) && ActiveModel->AnyPiecesSelected())
1033 DrawRotateOverlay();
1034 else if ((mTrackTool == lcTrackTool::Select || mTrackTool == lcTrackTool::ZoomRegion) && mTrackButton != lcTrackButton::None)
1035 DrawSelectZoomRegionOverlay();
1036 else if (Tool == lcTool::RotateView && mTrackButton == lcTrackButton::None)
1037 DrawRotateViewOverlay();
1038 }
1039
1040 if (DrawOverlays)
1041 {
1042 mViewSphere->Draw();
1043
1044 DrawViewport();
1045 }
1046
1047 #ifdef LC_PROFILE_DRAW
1048 qint64 TimerElapsed = Timer.nsecsElapsed();
1049 Query.end();
1050
1051 GLuint64 QueryElapsed = Query.waitForResult();
1052 QueryResults[FrameNumber % QueryResults.size()] = QueryElapsed;
1053 TimerResults[FrameNumber % TimerResults.size()] = TimerElapsed;
1054 FrameNumber++;
1055
1056 GLuint64 QueryAverage = 0;
1057 for (GLuint64 Result : QueryResults)
1058 QueryAverage += Result;
1059 QueryAverage /= QueryResults.size();
1060
1061 GLuint64 TimerAverage = 0;
1062 for (GLuint64 Result : TimerResults)
1063 TimerAverage += Result;
1064 TimerAverage /= TimerResults.size();
1065
1066 mContext->SetWorldMatrix(lcMatrix44Identity());
1067 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1068 mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
1069
1070 QString Line = QString("GPU: %1 CPU: %2").arg(QString::number(QueryAverage / 1000000.0, 'f', 2), QString::number(TimerAverage / 1000000.0, 'f', 2));
1071
1072 mContext->SetMaterial(lcMaterialType::UnlitTextureModulate);
1073 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mTextColor));
1074 mContext->BindTexture2D(gTexFont.GetTexture());
1075
1076 glDisable(GL_DEPTH_TEST);
1077 glEnable(GL_BLEND);
1078
1079 gTexFont.PrintText(mContext, 3.0f, (float)mHeight - 1.0f - 6.0f, 0.0f, Line.toLatin1().constData());
1080
1081 glDisable(GL_BLEND);
1082 glEnable(GL_DEPTH_TEST);
1083
1084 Redraw();
1085 #endif
1086
1087 mContext->ClearResources();
1088 }
1089
DrawBackground() const1090 void lcView::DrawBackground() const
1091 {
1092 if (mOverrideBackgroundColor)
1093 {
1094 lcVector4 BackgroundColor(lcVector4FromColor(mBackgroundColor));
1095 mContext->ClearColorAndDepth(BackgroundColor);
1096 return;
1097 }
1098
1099 const lcPreferences& Preferences = lcGetPreferences();
1100
1101 if (!Preferences.mBackgroundGradient)
1102 {
1103 lcVector4 BackgroundColor(lcVector3FromColor(Preferences.mBackgroundSolidColor), 0.0f);
1104 mContext->ClearColorAndDepth(BackgroundColor);
1105 return;
1106 }
1107
1108 mContext->ClearDepth();
1109
1110 mContext->SetDepthWrite(false);
1111 glDisable(GL_DEPTH_TEST);
1112
1113 float ViewWidth = (float)mWidth;
1114 float ViewHeight = (float)mHeight;
1115
1116 mContext->SetWorldMatrix(lcMatrix44Identity());
1117 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1118 mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, ViewWidth, 0.0f, ViewHeight, -1.0f, 1.0f));
1119
1120 mContext->SetSmoothShading(true);
1121
1122 const quint32 Color1 = Preferences.mBackgroundGradientColorTop;
1123 const quint32 Color2 = Preferences.mBackgroundGradientColorBottom;
1124
1125 struct lcBackgroundVertex
1126 {
1127 float x, y;
1128 quint32 Color;
1129 };
1130
1131 const lcBackgroundVertex Verts[4] =
1132 {
1133 { ViewWidth, ViewHeight, Color1 }, { 0.0f, ViewHeight, Color1 }, { 0.0f, 0.0f, Color2 }, { ViewWidth, 0.0f, Color2 }
1134 };
1135
1136 mContext->SetMaterial(lcMaterialType::UnlitVertexColor);
1137 mContext->SetVertexBufferPointer(Verts);
1138 mContext->SetVertexFormat(0, 2, 0, 0, 4, false);
1139
1140 mContext->DrawPrimitives(GL_TRIANGLE_FAN, 0, 4);
1141
1142 mContext->SetSmoothShading(false);
1143
1144 glEnable(GL_DEPTH_TEST);
1145 mContext->SetDepthWrite(true);
1146 }
1147
DrawViewport() const1148 void lcView::DrawViewport() const
1149 {
1150 mContext->SetWorldMatrix(lcMatrix44Identity());
1151 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1152 mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
1153 mContext->SetLineWidth(1.0f);
1154
1155 mContext->SetDepthWrite(false);
1156 glDisable(GL_DEPTH_TEST);
1157
1158 mContext->SetMaterial(lcMaterialType::UnlitColor);
1159
1160 if (mLastFocusedView == this)
1161 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mActiveViewColor));
1162 else
1163 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mInactiveViewColor));
1164
1165 float Verts[8] = { 0.0f, 0.0f, mWidth - 1.0f, 0.0f, mWidth - 1.0f, mHeight - 1.0f, 0.0f, mHeight - 1.0f };
1166
1167 mContext->SetVertexBufferPointer(Verts);
1168 mContext->SetVertexFormatPosition(2);
1169 mContext->DrawPrimitives(GL_LINE_LOOP, 0, 4);
1170
1171 QString CameraName = mCamera->GetName();
1172
1173 if (!CameraName.isEmpty())
1174 {
1175 mContext->SetMaterial(lcMaterialType::UnlitTextureModulate);
1176 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mTextColor));
1177 mContext->BindTexture2D(gTexFont.GetTexture());
1178
1179 glEnable(GL_BLEND);
1180
1181 gTexFont.PrintText(mContext, 3.0f, (float)mHeight - 1.0f - 6.0f, 0.0f, CameraName.toLatin1().constData());
1182
1183 glDisable(GL_BLEND);
1184 }
1185
1186 mContext->SetDepthWrite(true);
1187 glEnable(GL_DEPTH_TEST);
1188 }
1189
DrawAxes() const1190 void lcView::DrawAxes() const
1191 {
1192 const lcPreferences& Preferences = lcGetPreferences();
1193
1194 switch (mViewType)
1195 {
1196 case lcViewType::View:
1197 if (!Preferences.mDrawAxes)
1198 return;
1199 break;
1200
1201 case lcViewType::Preview:
1202 if (!Preferences.mDrawPreviewAxis)
1203 return;
1204 break;
1205
1206 case lcViewType::Minifig:
1207 case lcViewType::PartsList:
1208 case lcViewType::Count:
1209 return;
1210 }
1211
1212 // mContext->ClearDepth();
1213
1214 struct lcAxisVertex
1215 {
1216 float x, y, z;
1217 quint32 Color;
1218 };
1219
1220 const quint32 Red = LC_RGBA(204, 0, 0, 255);
1221 const quint32 Green = LC_RGBA(0, 204, 0, 255);
1222 const quint32 Blue = LC_RGBA(0, 0, 204, 255);
1223
1224 const lcAxisVertex Verts[30] =
1225 {
1226 { 0.00f, 0.00f, 0.00f, Red }, { 20.00f, 0.00f, 0.00f, Red }, { 12.00f, 3.00f, 0.00f, Red }, { 12.00f, 2.12f, 2.12f, Red }, { 12.00f, 0.00f, 3.00f, Red },
1227 { 12.00f, -2.12f, 2.12f, Red }, { 12.00f, -3.00f, 0.00f, Red }, { 12.00f, -2.12f, -2.12f, Red }, { 12.00f, 0.00f, -3.00f, Red }, { 12.00f, 2.12f, -2.12f, Red },
1228 { 0.00f, 0.00f, 0.00f, Green }, { 0.00f, 20.00f, 0.00f, Green }, { 3.00f, 12.00f, 0.00f, Green }, { 2.12f, 12.00f, 2.12f, Green }, { 0.00f, 12.00f, 3.00f, Green },
1229 { -2.12f, 12.00f, 2.12f, Green }, { -3.00f, 12.00f, 0.00f, Green }, { -2.12f, 12.00f, -2.12f, Green }, { 0.00f, 12.00f, -3.00f, Green }, { 2.12f, 12.00f, -2.12f, Green },
1230 { 0.00f, 0.00f, 0.00f, Blue }, { 0.00f, 0.00f, 20.00f, Blue }, { 0.00f, 3.00f, 12.00f, Blue }, { 2.12f, 2.12f, 12.00f, Blue }, { 3.00f, 0.00f, 12.00f, Blue },
1231 { 2.12f, -2.12f, 12.00f, Blue }, { 0.00f, -3.00f, 12.00f, Blue }, { -2.12f, -2.12f, 12.00f, Blue }, { -3.00f, 0.00f, 12.00f, Blue }, { -2.12f, 2.12f, 12.00f, Blue }
1232 };
1233
1234 const GLushort Indices[78] =
1235 {
1236 0, 1, 10, 11, 20, 21,
1237 1, 2, 3, 1, 3, 4, 1, 4, 5, 1, 5, 6, 1, 6, 7, 1, 7, 8, 1, 8, 9, 1, 9, 2,
1238 11, 12, 13, 11, 13, 14, 11, 14, 15, 11, 15, 16, 11, 16, 17, 11, 17, 18, 11, 18, 19, 11, 19, 12,
1239 21, 22, 23, 21, 23, 24, 21, 24, 25, 21, 25, 26, 21, 26, 27, 21, 27, 28, 21, 28, 29, 21, 29, 22
1240 };
1241
1242 lcMatrix44 TranslationMatrix;
1243
1244 switch (Preferences.mAxisIconLocation)
1245 {
1246 default:
1247 case lcAxisIconLocation::BottomLeft:
1248 TranslationMatrix = lcMatrix44Translation(lcVector3(32, 32, 0.0f));
1249 break;
1250
1251 case lcAxisIconLocation::BottomRight:
1252 TranslationMatrix = lcMatrix44Translation(lcVector3(mWidth - 36, 32, 0.0f));
1253 break;
1254
1255 case lcAxisIconLocation::TopLeft:
1256 TranslationMatrix = lcMatrix44Translation(lcVector3(32, mHeight - 36, 0.0f));
1257 break;
1258
1259 case lcAxisIconLocation::TopRight:
1260 TranslationMatrix = lcMatrix44Translation(lcVector3(mWidth - 36, mHeight - 36, 0.0f));
1261 break;
1262 }
1263 lcMatrix44 WorldViewMatrix = mCamera->mWorldView;
1264 WorldViewMatrix.SetTranslation(lcVector3(0, 0, 0));
1265
1266 mContext->SetLineWidth(1.0f);
1267 mContext->SetMaterial(lcMaterialType::UnlitVertexColor);
1268 mContext->SetWorldMatrix(lcMatrix44Identity());
1269 mContext->SetViewMatrix(lcMul(WorldViewMatrix, TranslationMatrix));
1270 mContext->SetProjectionMatrix(lcMatrix44Ortho(0, mWidth, 0, mHeight, -50, 50));
1271
1272 mContext->SetVertexBufferPointer(Verts);
1273 mContext->SetVertexFormat(0, 3, 0, 0, 4, false);
1274 mContext->SetIndexBufferPointer(Indices);
1275
1276 mContext->DrawIndexedPrimitives(GL_LINES, 6, GL_UNSIGNED_SHORT, 0);
1277 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 72, GL_UNSIGNED_SHORT, 6 * 2);
1278
1279 mContext->SetMaterial(lcMaterialType::UnlitTextureModulate);
1280 mContext->SetViewMatrix(TranslationMatrix);
1281 mContext->BindTexture2D(gTexFont.GetTexture());
1282 glEnable(GL_BLEND);
1283
1284 float TextBuffer[6 * 5 * 3];
1285 lcVector3 PosX = lcMul30(lcVector3(25.0f, 0.0f, 0.0f), WorldViewMatrix);
1286 gTexFont.GetGlyphTriangles(PosX.x, PosX.y, PosX.z, 'X', TextBuffer);
1287 lcVector3 PosY = lcMul30(lcVector3(0.0f, 25.0f, 0.0f), WorldViewMatrix);
1288 gTexFont.GetGlyphTriangles(PosY.x, PosY.y, PosY.z, 'Y', TextBuffer + 5 * 6);
1289 lcVector3 PosZ = lcMul30(lcVector3(0.0f, 0.0f, 25.0f), WorldViewMatrix);
1290 gTexFont.GetGlyphTriangles(PosZ.x, PosZ.y, PosZ.z, 'Z', TextBuffer + 5 * 6 * 2);
1291
1292 mContext->SetVertexBufferPointer(TextBuffer);
1293 mContext->SetVertexFormat(0, 3, 0, 2, 0, false);
1294
1295 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mAxesColor));
1296 mContext->DrawPrimitives(GL_TRIANGLES, 0, 6 * 3);
1297
1298 glDisable(GL_BLEND);
1299 }
1300
DrawSelectMoveOverlay()1301 void lcView::DrawSelectMoveOverlay()
1302 {
1303 mContext->SetMaterial(lcMaterialType::UnlitColor);
1304 mContext->SetViewMatrix(mCamera->mWorldView);
1305 mContext->SetProjectionMatrix(GetProjectionMatrix());
1306
1307 glDisable(GL_DEPTH_TEST);
1308
1309 lcVector3 OverlayCenter;
1310 lcMatrix33 RelativeRotation;
1311 lcModel* ActiveModel = GetActiveModel();
1312 ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation);
1313 bool AnyPiecesSelected = ActiveModel->AnyPiecesSelected();
1314
1315 lcMatrix44 WorldMatrix = lcMatrix44(RelativeRotation, OverlayCenter);
1316
1317 if (ActiveModel != mModel)
1318 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
1319
1320 const float OverlayScale = GetOverlayScale();
1321 WorldMatrix = lcMul(lcMatrix44Scale(lcVector3(OverlayScale, OverlayScale, OverlayScale)), WorldMatrix);
1322
1323 mContext->SetWorldMatrix(WorldMatrix);
1324 mContext->SetLineWidth(1.0f);
1325
1326 mContext->SetIndexBuffer(mRotateMoveIndexBuffer);
1327 mContext->SetVertexBuffer(mRotateMoveVertexBuffer);
1328 mContext->SetVertexFormatPosition(3);
1329
1330 lcObject* Focus = ActiveModel->GetFocusObject();
1331 quint32 AllowedTransforms = Focus ? Focus->GetAllowedTransforms() : LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z | LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z;
1332
1333 if (mTrackButton == lcTrackButton::None || (mTrackTool >= lcTrackTool::MoveX && mTrackTool <= lcTrackTool::MoveXYZ))
1334 {
1335 if (AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_X)
1336 {
1337 if ((mTrackTool == lcTrackTool::MoveX) || (mTrackTool == lcTrackTool::MoveXY) || (mTrackTool == lcTrackTool::MoveXZ))
1338 {
1339 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1340 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
1341 }
1342 else if (mTrackButton == lcTrackButton::None)
1343 {
1344 mContext->SetColor(0.8f, 0.0f, 0.0f, 1.0f);
1345 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
1346 }
1347 }
1348
1349 if (AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Y)
1350 {
1351 if (((mTrackTool == lcTrackTool::MoveY) || (mTrackTool == lcTrackTool::MoveXY) || (mTrackTool == lcTrackTool::MoveYZ)) && (AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Y))
1352 {
1353 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1354 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 36 * 2);
1355 }
1356 else if (mTrackButton == lcTrackButton::None)
1357 {
1358 mContext->SetColor(0.0f, 0.8f, 0.0f, 1.0f);
1359 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 36 * 2);
1360 }
1361 }
1362
1363 if (AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Z)
1364 {
1365 if (((mTrackTool == lcTrackTool::MoveZ) || (mTrackTool == lcTrackTool::MoveXZ) || (mTrackTool == lcTrackTool::MoveYZ)) && (AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Z))
1366 {
1367 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1368 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 72 * 2);
1369 }
1370 else if (mTrackButton == lcTrackButton::None)
1371 {
1372 mContext->SetColor(0.0f, 0.0f, 0.8f, 1.0f);
1373 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 72 * 2);
1374 }
1375 }
1376 }
1377
1378 if (gMainWindow->GetTool() == lcTool::Select && mTrackButton == lcTrackButton::None && AnyPiecesSelected)
1379 {
1380 if (AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_X)
1381 {
1382 if (mTrackTool == lcTrackTool::RotateX)
1383 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1384 else
1385 mContext->SetColor(0.8f, 0.0f, 0.0f, 1.0f);
1386
1387 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 120, GL_UNSIGNED_SHORT, 108 * 2);
1388 }
1389
1390 if (AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_Y)
1391 {
1392 if (mTrackTool == lcTrackTool::RotateY)
1393 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1394 else
1395 mContext->SetColor(0.0f, 0.8f, 0.0f, 1.0f);
1396
1397 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 120, GL_UNSIGNED_SHORT, (108 + 120) * 2);
1398 }
1399
1400 if (AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_Z)
1401 {
1402 if (mTrackTool == lcTrackTool::RotateZ)
1403 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1404 else
1405 mContext->SetColor(0.0f, 0.0f, 0.8f, 1.0f);
1406
1407 mContext->DrawIndexedPrimitives(GL_TRIANGLES, 120, GL_UNSIGNED_SHORT, (108 + 240) * 2);
1408 }
1409 }
1410
1411 if ((mTrackTool == lcTrackTool::MoveXY) || (mTrackTool == lcTrackTool::MoveXZ) || (mTrackTool == lcTrackTool::MoveYZ))
1412 {
1413 glEnable(GL_BLEND);
1414
1415 mContext->SetColor(0.8f, 0.8f, 0.0f, 0.3f);
1416
1417 if (mTrackTool == lcTrackTool::MoveXY)
1418 mContext->DrawIndexedPrimitives(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, (108 + 360 + 8) * 2);
1419 else if (mTrackTool == lcTrackTool::MoveXZ)
1420 mContext->DrawIndexedPrimitives(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, (108 + 360 + 4) * 2);
1421 else if (mTrackTool == lcTrackTool::MoveYZ)
1422 mContext->DrawIndexedPrimitives(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, (108 + 360) * 2);
1423
1424 glDisable(GL_BLEND);
1425 }
1426
1427 if (Focus && Focus->IsPiece())
1428 {
1429 lcPiece* Piece = (lcPiece*)Focus;
1430 quint32 Section = Piece->GetFocusSection();
1431
1432 if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST && Section <= LC_PIECE_SECTION_CONTROL_POINT_LAST && Piece->mPieceInfo->GetSynthInfo() && Piece->mPieceInfo->GetSynthInfo()->IsCurve())
1433 {
1434 int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
1435 float Strength = Piece->GetControlPoints()[ControlPointIndex].Scale;
1436 const float ScaleStart = 2.0f;
1437 float Length = ScaleStart + Strength / OverlayScale;
1438 const float OverlayScaleInnerRadius = 0.075f;
1439 const float OverlayScaleRadius = 0.125f;
1440
1441 lcVector3 Verts[38];
1442 int NumVerts = 0;
1443
1444 Verts[NumVerts++] = lcVector3(Length - OverlayScaleRadius, 0.0f, 0.0f);
1445 Verts[NumVerts++] = lcVector3(OverlayScaleRadius - Length, 0.0f, 0.0f);
1446
1447 float SinTable[9], CosTable[9];
1448
1449 for (int Step = 0; Step <= 8; Step++)
1450 {
1451 SinTable[Step] = sinf((float)Step / 8.0f * LC_2PI);
1452 CosTable[Step] = cosf((float)Step / 8.0f * LC_2PI);
1453 }
1454
1455 for (int Step = 0; Step <= 8; Step++)
1456 {
1457 float x = CosTable[Step];
1458 float y = SinTable[Step];
1459
1460 Verts[NumVerts++] = lcVector3(Length + x * OverlayScaleInnerRadius, 0.0f, y * OverlayScaleInnerRadius);
1461 Verts[NumVerts++] = lcVector3(Length + x * OverlayScaleRadius, 0.0f, y * OverlayScaleRadius);
1462 }
1463
1464 for (int Step = 0; Step <= 8; Step++)
1465 {
1466 float x = CosTable[Step];
1467 float y = SinTable[Step];
1468
1469 Verts[NumVerts++] = lcVector3(-Length + x * OverlayScaleInnerRadius, 0.0f, y * OverlayScaleInnerRadius);
1470 Verts[NumVerts++] = lcVector3(-Length + x * OverlayScaleRadius, 0.0f, y * OverlayScaleRadius);
1471 }
1472
1473 if (mTrackTool == lcTrackTool::ScalePlus || mTrackTool == lcTrackTool::ScaleMinus)
1474 mContext->SetColor(0.8f, 0.8f, 0.0f, 0.3f);
1475 else
1476 mContext->SetColor(0.0f, 0.0f, 0.8f, 1.0f);
1477
1478 mContext->SetVertexBufferPointer(Verts);
1479 mContext->ClearIndexBuffer();
1480 mContext->SetVertexFormatPosition(3);
1481
1482 mContext->DrawPrimitives(GL_LINES, 0, 2);
1483 mContext->DrawPrimitives(GL_TRIANGLE_STRIP, 2, 18);
1484 mContext->DrawPrimitives(GL_TRIANGLE_STRIP, 20, 18);
1485 }
1486 }
1487
1488 glEnable(GL_DEPTH_TEST);
1489 }
1490
DrawRotateOverlay()1491 void lcView::DrawRotateOverlay()
1492 {
1493 const float OverlayScale = GetOverlayScale();
1494 const float OverlayRotateRadius = 2.0f;
1495
1496 mContext->SetMaterial(lcMaterialType::UnlitColor);
1497 mContext->SetViewMatrix(mCamera->mWorldView);
1498 mContext->SetProjectionMatrix(GetProjectionMatrix());
1499 mContext->SetLineWidth(1.0f);
1500
1501 glDisable(GL_DEPTH_TEST);
1502
1503 int j;
1504
1505 lcVector3 OverlayCenter;
1506 lcMatrix33 RelativeRotation;
1507 lcModel* ActiveModel = GetActiveModel();
1508 ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation);
1509 lcVector3 MouseToolDistance = ActiveModel->SnapRotation(ActiveModel->GetMouseToolDistance());
1510 bool HasAngle = false;
1511
1512 lcMatrix44 WorldMatrix = lcMatrix44(RelativeRotation, OverlayCenter);
1513
1514 if (ActiveModel != mModel)
1515 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
1516
1517 // Draw a disc showing the rotation amount.
1518 if (MouseToolDistance.LengthSquared() != 0.0f && (mTrackButton != lcTrackButton::None))
1519 {
1520 lcVector4 Rotation;
1521 float Angle, Step;
1522
1523 HasAngle = true;
1524
1525 switch (mTrackTool)
1526 {
1527 case lcTrackTool::RotateX:
1528 mContext->SetColor(0.8f, 0.0f, 0.0f, 0.3f);
1529 Angle = MouseToolDistance[0];
1530 Rotation = lcVector4(0.0f, 0.0f, 0.0f, 1.0f);
1531 break;
1532 case lcTrackTool::RotateY:
1533 mContext->SetColor(0.0f, 0.8f, 0.0f, 0.3f);
1534 Angle = MouseToolDistance[1];
1535 Rotation = lcVector4(90.0f, 0.0f, 0.0f, 1.0f);
1536 break;
1537 case lcTrackTool::RotateZ:
1538 mContext->SetColor(0.0f, 0.0f, 0.8f, 0.3f);
1539 Angle = MouseToolDistance[2];
1540 Rotation = lcVector4(90.0f, 0.0f, -1.0f, 0.0f);
1541 break;
1542 default:
1543 Rotation = lcVector4(0.0f, 0.0f, 0.0f, 1.0f);
1544 Angle = 0.0f;
1545 break;
1546 };
1547
1548 if (Angle > 0.0f)
1549 {
1550 Step = 360.0f / 32;
1551 }
1552 else
1553 {
1554 Angle = -Angle;
1555 Step = -360.0f / 32;
1556 }
1557
1558 if (fabsf(Angle) >= fabsf(Step))
1559 {
1560 lcMatrix44 RotatedWorldMatrix = lcMul(lcMatrix44FromAxisAngle(lcVector3(Rotation[1], Rotation[2], Rotation[3]), Rotation[0] * LC_DTOR), WorldMatrix);
1561
1562 mContext->SetWorldMatrix(RotatedWorldMatrix);
1563
1564 glEnable(GL_BLEND);
1565
1566 lcVector3 Verts[33];
1567 Verts[0] = lcVector3(0.0f, 0.0f, 0.0f);
1568 int NumVerts = 1;
1569
1570 mContext->SetVertexBufferPointer(Verts);
1571 mContext->SetVertexFormatPosition(3);
1572
1573 float StartAngle;
1574 int i = 0;
1575
1576 if (Step < 0)
1577 StartAngle = -Angle;
1578 else
1579 StartAngle = Angle;
1580
1581 do
1582 {
1583 float x = cosf((Step * i - StartAngle) * LC_DTOR) * OverlayRotateRadius * OverlayScale;
1584 float y = sinf((Step * i - StartAngle) * LC_DTOR) * OverlayRotateRadius * OverlayScale;
1585
1586 Verts[NumVerts++] = lcVector3(0.0f, x, y);
1587
1588 if (NumVerts == 33)
1589 {
1590 mContext->DrawPrimitives(GL_TRIANGLE_FAN, 0, NumVerts);
1591 Verts[1] = Verts[32];
1592 NumVerts = 2;
1593 }
1594
1595 i++;
1596 if (Step > 0)
1597 Angle -= Step;
1598 else
1599 Angle += Step;
1600
1601 } while (Angle >= 0.0f);
1602
1603 if (NumVerts > 2)
1604 mContext->DrawPrimitives(GL_TRIANGLE_FAN, 0, NumVerts);
1605
1606 glDisable(GL_BLEND);
1607 }
1608 }
1609
1610 // Draw the circles.
1611 if (gMainWindow->GetTool() == lcTool::Rotate && !HasAngle && mTrackButton == lcTrackButton::None)
1612 {
1613 lcMatrix44 Mat = lcMatrix44AffineInverse(mCamera->mWorldView);
1614 Mat.SetTranslation(WorldMatrix.GetTranslation());
1615
1616 lcVector3 Verts[32];
1617
1618 for (j = 0; j < 32; j++)
1619 {
1620 lcVector3 Pt;
1621
1622 Pt[0] = cosf(LC_2PI * j / 32) * OverlayRotateRadius * OverlayScale;
1623 Pt[1] = sinf(LC_2PI * j / 32) * OverlayRotateRadius * OverlayScale;
1624 Pt[2] = 0.0f;
1625
1626 Verts[j] = lcMul31(Pt, Mat);
1627 }
1628
1629 mContext->SetColor(0.1f, 0.1f, 0.1f, 1.0f);
1630 mContext->SetWorldMatrix(lcMatrix44Identity());
1631
1632 mContext->SetVertexBufferPointer(Verts);
1633 mContext->SetVertexFormatPosition(3);
1634
1635 mContext->DrawPrimitives(GL_LINE_LOOP, 0, 32);
1636 }
1637
1638 lcVector3 ViewDir = mCamera->mTargetPosition - mCamera->mPosition;
1639 ViewDir.Normalize();
1640
1641 // Transform ViewDir to local space.
1642 ViewDir = lcMul(ViewDir, lcMatrix33AffineInverse(lcMatrix33(WorldMatrix)));
1643
1644 mContext->SetWorldMatrix(WorldMatrix);
1645
1646 // Draw each axis circle.
1647 for (int i = 0; i < 3; i++)
1648 {
1649 if (static_cast<int>(mTrackTool) == static_cast<int>(lcTrackTool::RotateX) + i)
1650 {
1651 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1652 }
1653 else
1654 {
1655 if (gMainWindow->GetTool() != lcTool::Rotate || HasAngle || mTrackButton != lcTrackButton::None)
1656 continue;
1657
1658 switch (i)
1659 {
1660 case 0:
1661 mContext->SetColor(0.8f, 0.0f, 0.0f, 1.0f);
1662 break;
1663 case 1:
1664 mContext->SetColor(0.0f, 0.8f, 0.0f, 1.0f);
1665 break;
1666 case 2:
1667 mContext->SetColor(0.0f, 0.0f, 0.8f, 1.0f);
1668 break;
1669 }
1670 }
1671
1672 lcVector3 Verts[64];
1673 int NumVerts = 0;
1674
1675 for (j = 0; j < 32; j++)
1676 {
1677 lcVector3 v1, v2;
1678
1679 switch (i)
1680 {
1681 case 0:
1682 v1 = lcVector3(0.0f, cosf(LC_2PI * j / 32), sinf(LC_2PI * j / 32));
1683 v2 = lcVector3(0.0f, cosf(LC_2PI * (j + 1) / 32), sinf(LC_2PI * (j + 1) / 32));
1684 break;
1685
1686 case 1:
1687 v1 = lcVector3(cosf(LC_2PI * j / 32), 0.0f, sinf(LC_2PI * j / 32));
1688 v2 = lcVector3(cosf(LC_2PI * (j + 1) / 32), 0.0f, sinf(LC_2PI * (j + 1) / 32));
1689 break;
1690
1691 case 2:
1692 v1 = lcVector3(cosf(LC_2PI * j / 32), sinf(LC_2PI * j / 32), 0.0f);
1693 v2 = lcVector3(cosf(LC_2PI * (j + 1) / 32), sinf(LC_2PI * (j + 1) / 32), 0.0f);
1694 break;
1695 }
1696
1697 if (gMainWindow->GetTool() != lcTool::Rotate || HasAngle || mTrackButton != lcTrackButton::None || lcDot(ViewDir, v1 + v2) <= 0.0f)
1698 {
1699 Verts[NumVerts++] = v1 * (OverlayRotateRadius * OverlayScale);
1700 Verts[NumVerts++] = v2 * (OverlayRotateRadius * OverlayScale);
1701 }
1702 }
1703
1704 mContext->SetVertexBufferPointer(Verts);
1705 mContext->SetVertexFormatPosition(3);
1706
1707 mContext->DrawPrimitives(GL_LINES, 0, NumVerts);
1708 }
1709
1710 // Draw tangent vector.
1711 if (mTrackButton != lcTrackButton::None && ((mTrackTool == lcTrackTool::RotateX) || (mTrackTool == lcTrackTool::RotateY) || (mTrackTool == lcTrackTool::RotateZ)))
1712 {
1713 const float OverlayRotateArrowSize = 1.5f;
1714 const float OverlayRotateArrowCapSize = 0.25f;
1715
1716 lcVector4 Rotation;
1717 float Angle;
1718
1719 switch (mTrackTool)
1720 {
1721 case lcTrackTool::RotateX:
1722 Angle = MouseToolDistance[0];
1723 Rotation = lcVector4(0.0f, 0.0f, 0.0f, 1.0f);
1724 break;
1725 case lcTrackTool::RotateY:
1726 Angle = MouseToolDistance[1];
1727 Rotation = lcVector4(90.0f, 0.0f, 0.0f, 1.0f);
1728 break;
1729 case lcTrackTool::RotateZ:
1730 Angle = MouseToolDistance[2];
1731 Rotation = lcVector4(90.0f, 0.0f, -1.0f, 0.0f);
1732 break;
1733 default:
1734 Angle = 0.0f;
1735 Rotation = lcVector4(0.0f, 0.0f, 1.0f, 0.0f);
1736 break;
1737 };
1738
1739 lcMatrix44 RotatedWorldMatrix = lcMul(lcMatrix44FromAxisAngle(lcVector3(Rotation[1], Rotation[2], Rotation[3]), Rotation[0] * LC_DTOR), WorldMatrix);
1740 mContext->SetWorldMatrix(RotatedWorldMatrix);
1741
1742 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1743
1744 if (HasAngle)
1745 {
1746 float StartY = OverlayScale * OverlayRotateRadius;
1747 float EndZ = (Angle > 0.0f) ? OverlayScale * OverlayRotateArrowSize : -OverlayScale * OverlayRotateArrowSize;
1748 float TipZ = (Angle > 0.0f) ? -OverlayScale * OverlayRotateArrowCapSize : OverlayScale * OverlayRotateArrowCapSize;
1749
1750 lcVector3 Verts[6];
1751
1752 Verts[0] = lcVector3(0.0f, StartY, 0.0f);
1753 Verts[1] = lcVector3(0.0f, StartY, EndZ);
1754
1755 Verts[2] = lcVector3(0.0f, StartY, EndZ);
1756 Verts[3] = lcVector3(0.0f, StartY + OverlayScale * OverlayRotateArrowCapSize, EndZ + TipZ);
1757
1758 Verts[4] = lcVector3(0.0f, StartY, EndZ);
1759 Verts[5] = lcVector3(0.0f, StartY - OverlayScale * OverlayRotateArrowCapSize, EndZ + TipZ);
1760
1761 mContext->SetVertexBufferPointer(Verts);
1762 mContext->SetVertexFormatPosition(3);
1763
1764 mContext->DrawPrimitives(GL_LINES, 0, 6);
1765 }
1766
1767 // Draw text.
1768 lcVector3 ScreenPos = ProjectPoint(WorldMatrix.GetTranslation());
1769
1770 mContext->SetMaterial(lcMaterialType::UnlitTextureModulate);
1771 mContext->SetWorldMatrix(lcMatrix44Identity());
1772 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1773 mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
1774 mContext->BindTexture2D(gTexFont.GetTexture());
1775 glEnable(GL_BLEND);
1776
1777 char buf[32];
1778 sprintf(buf, "[%.2f]", fabsf(Angle));
1779
1780 int cx, cy;
1781 gTexFont.GetStringDimensions(&cx, &cy, buf);
1782
1783 mContext->SetColor(0.8f, 0.8f, 0.0f, 1.0f);
1784 gTexFont.PrintText(mContext, ScreenPos[0] - (cx / 2), ScreenPos[1] + (cy / 2), 0.0f, buf);
1785
1786 glDisable(GL_BLEND);
1787 }
1788
1789 glEnable(GL_DEPTH_TEST);
1790 }
1791
DrawSelectZoomRegionOverlay()1792 void lcView::DrawSelectZoomRegionOverlay()
1793 {
1794 mContext->SetMaterial(lcMaterialType::UnlitColor);
1795 mContext->SetWorldMatrix(lcMatrix44Identity());
1796 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1797 mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
1798 mContext->SetLineWidth(1.0f);
1799
1800 glDisable(GL_DEPTH_TEST);
1801
1802 float pt1x = (float)mMouseDownX;
1803 float pt1y = (float)mMouseDownY;
1804 float pt2x = (float)mMouseX;
1805 float pt2y = (float)mMouseY;
1806
1807 float Left, Right, Bottom, Top;
1808
1809 if (pt1x < pt2x)
1810 {
1811 Left = pt1x;
1812 Right = pt2x;
1813 }
1814 else
1815 {
1816 Left = pt2x;
1817 Right = pt1x;
1818 }
1819
1820 if (pt1y < pt2y)
1821 {
1822 Bottom = pt1y;
1823 Top = pt2y;
1824 }
1825 else
1826 {
1827 Bottom = pt2y;
1828 Top = pt1y;
1829 }
1830
1831 Left = lcMax(Left, 0.0f);
1832 Right = lcMin(Right, mWidth - 1.0f);
1833 Bottom = lcMax(Bottom, 0.0f);
1834 Top = lcMin(Top, mHeight - 1.0f);
1835
1836 float BorderX = lcMin(2.0f, Right - Left);
1837 float BorderY = lcMin(2.0f, Top - Bottom);
1838
1839 float Verts[14][2] =
1840 {
1841 { Left, Bottom },
1842 { Left + BorderX, Bottom + BorderY },
1843 { Right, Bottom },
1844 { Right - BorderX, Bottom + BorderY },
1845 { Right, Top },
1846 { Right - BorderX, Top - BorderY },
1847 { Left, Top },
1848 { Left + BorderX, Top - BorderY },
1849 { Left, Bottom },
1850 { Left + BorderX, Bottom + BorderY },
1851 { Left + BorderX, Bottom + BorderY },
1852 { Right - BorderX, Bottom + BorderY },
1853 { Left + BorderX, Top - BorderY },
1854 { Right - BorderX, Top - BorderY },
1855 };
1856
1857 mContext->SetVertexBufferPointer(Verts);
1858 mContext->SetVertexFormatPosition(2);
1859
1860 const lcPreferences& Preferences = lcGetPreferences();
1861
1862 mContext->SetColor(lcVector4FromColor(Preferences.mMarqueeBorderColor));
1863 mContext->DrawPrimitives(GL_TRIANGLE_STRIP, 0, 10);
1864
1865 if (LC_RGBA_ALPHA(Preferences.mMarqueeFillColor))
1866 {
1867 glEnable(GL_BLEND);
1868 mContext->SetColor(lcVector4FromColor(Preferences.mMarqueeFillColor));
1869 mContext->DrawPrimitives(GL_TRIANGLE_STRIP, 10, 4);
1870 glDisable(GL_BLEND);
1871 }
1872
1873 glEnable(GL_DEPTH_TEST);
1874 }
1875
DrawRotateViewOverlay()1876 void lcView::DrawRotateViewOverlay()
1877 {
1878 int x, y, w, h;
1879
1880 x = 0;
1881 y = 0;
1882 w = mWidth;
1883 h = mHeight;
1884
1885 mContext->SetMaterial(lcMaterialType::UnlitColor);
1886 mContext->SetWorldMatrix(lcMatrix44Identity());
1887 mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
1888 mContext->SetProjectionMatrix(lcMatrix44Ortho(0, w, 0, h, -1, 1));
1889 mContext->SetLineWidth(1.0f);
1890
1891 glDisable(GL_DEPTH_TEST);
1892 mContext->SetColor(lcVector4FromColor(lcGetPreferences().mOverlayColor));
1893
1894 float Verts[32 * 16 * 2];
1895 float* CurVert = Verts;
1896
1897 float r = lcMin(w, h) * 0.35f;
1898 float cx = x + w / 2.0f;
1899 float cy = y + h / 2.0f;
1900
1901 for (int i = 0; i < 32; i++)
1902 {
1903 *CurVert++ = cosf((float)i / 32.0f * (2.0f * LC_PI)) * r + cx;
1904 *CurVert++ = sinf((float)i / 32.0f * (2.0f * LC_PI)) * r + cy;
1905 }
1906
1907 const float OverlayCameraSquareSize = lcMax(8.0f, (w + h) / 200.0f);
1908
1909 *CurVert++ = cx + OverlayCameraSquareSize; *CurVert++ = cy + r + OverlayCameraSquareSize;
1910 *CurVert++ = cx - OverlayCameraSquareSize; *CurVert++ = cy + r + OverlayCameraSquareSize;
1911 *CurVert++ = cx - OverlayCameraSquareSize; *CurVert++ = cy + r - OverlayCameraSquareSize;
1912 *CurVert++ = cx + OverlayCameraSquareSize; *CurVert++ = cy + r - OverlayCameraSquareSize;
1913 *CurVert++ = cx + OverlayCameraSquareSize; *CurVert++ = cy - r + OverlayCameraSquareSize;
1914 *CurVert++ = cx - OverlayCameraSquareSize; *CurVert++ = cy - r + OverlayCameraSquareSize;
1915 *CurVert++ = cx - OverlayCameraSquareSize; *CurVert++ = cy - r - OverlayCameraSquareSize;
1916 *CurVert++ = cx + OverlayCameraSquareSize; *CurVert++ = cy - r - OverlayCameraSquareSize;
1917 *CurVert++ = cx + r + OverlayCameraSquareSize; *CurVert++ = cy + OverlayCameraSquareSize;
1918 *CurVert++ = cx + r - OverlayCameraSquareSize; *CurVert++ = cy + OverlayCameraSquareSize;
1919 *CurVert++ = cx + r - OverlayCameraSquareSize; *CurVert++ = cy - OverlayCameraSquareSize;
1920 *CurVert++ = cx + r + OverlayCameraSquareSize; *CurVert++ = cy - OverlayCameraSquareSize;
1921 *CurVert++ = cx - r + OverlayCameraSquareSize; *CurVert++ = cy + OverlayCameraSquareSize;
1922 *CurVert++ = cx - r - OverlayCameraSquareSize; *CurVert++ = cy + OverlayCameraSquareSize;
1923 *CurVert++ = cx - r - OverlayCameraSquareSize; *CurVert++ = cy - OverlayCameraSquareSize;
1924 *CurVert++ = cx - r + OverlayCameraSquareSize; *CurVert++ = cy - OverlayCameraSquareSize;
1925
1926 mContext->SetVertexBufferPointer(Verts);
1927 mContext->SetVertexFormatPosition(2);
1928
1929 GLushort Indices[64 + 32] =
1930 {
1931 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
1932 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 0,
1933 32, 33, 33, 34, 34, 35, 35, 32, 36, 37, 37, 38, 38, 39, 39, 36,
1934 40, 41, 41, 42, 42, 43, 43, 40, 44, 45, 45, 46, 46, 47, 47, 44
1935 };
1936
1937 mContext->SetIndexBufferPointer(Indices);
1938 mContext->DrawIndexedPrimitives(GL_LINES, 96, GL_UNSIGNED_SHORT, 0);
1939
1940 glEnable(GL_DEPTH_TEST);
1941 }
1942
DrawGrid()1943 void lcView::DrawGrid()
1944 {
1945 const lcPreferences& Preferences = lcGetPreferences();
1946
1947 if (!Preferences.mDrawGridStuds && !Preferences.mDrawGridLines && !Preferences.mDrawGridOrigin)
1948 return;
1949
1950 if (!Preferences.mGridEnabled)
1951 return;
1952
1953 const int Spacing = lcMax(Preferences.mGridLineSpacing, 1);
1954 int MinX, MaxX, MinY, MaxY;
1955 lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
1956
1957 bool GridSizeValid = mModel->GetVisiblePiecesBoundingBox(Min, Max);
1958
1959 if (mTrackTool == lcTrackTool::Insert)
1960 {
1961 PieceInfo* CurPiece = gMainWindow->GetCurrentPieceInfo();
1962
1963 if (CurPiece)
1964 {
1965 lcVector3 Points[8];
1966 lcGetBoxCorners(CurPiece->GetBoundingBox(), Points);
1967
1968 lcMatrix44 WorldMatrix = GetPieceInsertPosition(false, CurPiece);
1969
1970 for (int i = 0; i < 8; i++)
1971 {
1972 lcVector3 Point = lcMul31(Points[i], WorldMatrix);
1973
1974 Min = lcMin(Point, Min);
1975 Max = lcMax(Point, Max);
1976 }
1977
1978 GridSizeValid = true;
1979 }
1980 }
1981
1982 if (GridSizeValid)
1983 {
1984 MinX = (int)(floorf(Min[0] / (20.0f * Spacing))) - 1;
1985 MinY = (int)(floorf(Min[1] / (20.0f * Spacing))) - 1;
1986 MaxX = (int)(ceilf(Max[0] / (20.0f * Spacing))) + 1;
1987 MaxY = (int)(ceilf(Max[1] / (20.0f * Spacing))) + 1;
1988
1989 MinX = lcMin(MinX, -2);
1990 MinY = lcMin(MinY, -2);
1991 MaxX = lcMax(MaxX, 2);
1992 MaxY = lcMax(MaxY, 2);
1993 }
1994 else
1995 {
1996 MinX = -2;
1997 MinY = -2;
1998 MaxX = 2;
1999 MaxY = 2;
2000 }
2001
2002 if (!mGridBuffer.IsValid() || MinX != mGridSettings[0] || MinY != mGridSettings[1] || MaxX != mGridSettings[2] || MaxY != mGridSettings[3] ||
2003 Spacing != mGridSettings[4] || (Preferences.mDrawGridStuds ? 1 : 0) != mGridSettings[5] || (Preferences.mDrawGridLines ? 1 : 0) != mGridSettings[6])
2004 {
2005 int VertexBufferSize = 0;
2006
2007 if (Preferences.mDrawGridStuds)
2008 VertexBufferSize += 4 * 5 * sizeof(float);
2009
2010 if (Preferences.mDrawGridLines)
2011 VertexBufferSize += 2 * (MaxX - MinX + MaxY - MinY + 2) * 3 * sizeof(float);
2012
2013 float* Verts = (float*)malloc(VertexBufferSize);
2014 if (!Verts)
2015 return;
2016 float* CurVert = Verts;
2017
2018 if (Preferences.mDrawGridStuds)
2019 {
2020 float Left = MinX * 20.0f * Spacing;
2021 float Right = MaxX * 20.0f * Spacing;
2022 float Top = MinY * 20.0f * Spacing;
2023 float Bottom = MaxY * 20.0f * Spacing;
2024 float Z = 0;
2025 float U = (MaxX - MinX) * Spacing;
2026 float V = (MaxY - MinY) * Spacing;
2027
2028 *CurVert++ = Left;
2029 *CurVert++ = Top;
2030 *CurVert++ = Z;
2031 *CurVert++ = 0.0f;
2032 *CurVert++ = V;
2033
2034 *CurVert++ = Right;
2035 *CurVert++ = Top;
2036 *CurVert++ = Z;
2037 *CurVert++ = U;
2038 *CurVert++ = V;
2039
2040 *CurVert++ = Left;
2041 *CurVert++ = Bottom;
2042 *CurVert++ = Z;
2043 *CurVert++ = 0.0f;
2044 *CurVert++ = 0.0f;
2045
2046 *CurVert++ = Right;
2047 *CurVert++ = Bottom;
2048 *CurVert++ = Z;
2049 *CurVert++ = U;
2050 *CurVert++ = 0.0f;
2051 }
2052
2053 if (Preferences.mDrawGridLines)
2054 {
2055 float LineSpacing = Spacing * 20.0f;
2056
2057 for (int Step = MinX; Step < MaxX + 1; Step++)
2058 {
2059 *CurVert++ = Step * LineSpacing;
2060 *CurVert++ = MinY * LineSpacing;
2061 *CurVert++ = 0.0f;
2062 *CurVert++ = Step * LineSpacing;
2063 *CurVert++ = MaxY * LineSpacing;
2064 *CurVert++ = 0.0f;
2065 }
2066
2067 for (int Step = MinY; Step < MaxY + 1; Step++)
2068 {
2069 *CurVert++ = MinX * LineSpacing;
2070 *CurVert++ = Step * LineSpacing;
2071 *CurVert++ = 0.0f;
2072 *CurVert++ = MaxX * LineSpacing;
2073 *CurVert++ = Step * LineSpacing;
2074 *CurVert++ = 0.0f;
2075 }
2076 }
2077
2078 mGridSettings[0] = MinX;
2079 mGridSettings[1] = MinY;
2080 mGridSettings[2] = MaxX;
2081 mGridSettings[3] = MaxY;
2082 mGridSettings[4] = Spacing;
2083 mGridSettings[5] = (Preferences.mDrawGridStuds ? 1 : 0);
2084 mGridSettings[6] = (Preferences.mDrawGridLines ? 1 : 0);
2085
2086 mContext->DestroyVertexBuffer(mGridBuffer);
2087 mGridBuffer = mContext->CreateVertexBuffer(VertexBufferSize, Verts);
2088 free(Verts);
2089 }
2090
2091 int BufferOffset = 0;
2092 mContext->SetVertexBuffer(mGridBuffer);
2093 mContext->SetWorldMatrix(lcMatrix44Identity());
2094
2095 if (Preferences.mDrawGridStuds)
2096 {
2097 mContext->BindTexture2D(gGridTexture->mTexture);
2098 mContext->SetDepthWrite(false);
2099 glEnable(GL_BLEND);
2100
2101 mContext->SetMaterial(lcMaterialType::UnlitTextureModulate);
2102 mContext->SetColor(lcVector4FromColor(Preferences.mGridStudColor));
2103
2104 mContext->SetVertexFormat(0, 3, 0, 2, 0, false);
2105 mContext->DrawPrimitives(GL_TRIANGLE_STRIP, 0, 4);
2106
2107 glDisable(GL_BLEND);
2108 mContext->SetDepthWrite(true);
2109
2110 BufferOffset = 4 * 5 * sizeof(float);
2111 }
2112
2113 if (Preferences.mDrawGridLines)
2114 {
2115 mContext->SetLineWidth(1.0f);
2116 mContext->SetMaterial(lcMaterialType::UnlitColor);
2117 mContext->SetColor(lcVector4FromColor(Preferences.mGridLineColor));
2118
2119 int NumVerts = 2 * (MaxX - MinX + MaxY - MinY + 2);
2120
2121 mContext->SetVertexFormat(BufferOffset, 3, 0, 0, 0, false);
2122 mContext->DrawPrimitives(GL_LINES, 0, NumVerts);
2123 }
2124
2125 if (Preferences.mDrawGridOrigin)
2126 {
2127 struct lcGridVertex
2128 {
2129 float x, y;
2130 quint32 Color;
2131 };
2132
2133 const quint32 Red = LC_RGBA(204, 0, 0, 255);
2134 const quint32 Green = LC_RGBA(0, 204, 0, 255);
2135 const float Scale = 20.0f * Spacing;
2136
2137 const lcGridVertex Verts[4] =
2138 {
2139 { 0.0f, MinY * Scale, Green }, { 0.0f, MaxY * Scale, Green }, { MinX * Scale, 0.0f, Red }, { MaxX * Scale, 0.0f, Red }
2140 };
2141
2142 mContext->SetMaterial(lcMaterialType::UnlitVertexColor);
2143 mContext->SetVertexBufferPointer(Verts);
2144 mContext->SetVertexFormat(0, 2, 0, 0, 4, false);
2145
2146 mContext->DrawPrimitives(GL_LINES, 0, 4);
2147 }
2148 }
2149
GetOverrideTrackTool(Qt::MouseButton Button) const2150 lcTrackTool lcView::GetOverrideTrackTool(Qt::MouseButton Button) const
2151 {
2152 if (mTrackToolFromOverlay)
2153 return lcTrackTool::None;
2154
2155 lcTool OverrideTool = gMouseShortcuts.GetTool(Button, mMouseModifiers);
2156
2157 if (OverrideTool == lcTool::Count)
2158 return lcTrackTool::None;
2159
2160 constexpr lcTrackTool TrackToolFromTool[] =
2161 {
2162 lcTrackTool::Insert, // lcTool::Insert
2163 lcTrackTool::PointLight, // lcTool::Light
2164 lcTrackTool::SpotLight, // lcTool::SpotLight
2165 lcTrackTool::Camera, // lcTool::Camera
2166 lcTrackTool::Select, // lcTool::Select
2167 lcTrackTool::MoveXYZ, // lcTool::Move
2168 lcTrackTool::RotateXYZ, // lcTool::Rotate
2169 lcTrackTool::Eraser, // lcTool::Eraser
2170 lcTrackTool::Paint, // lcTool::Paint
2171 lcTrackTool::ColorPicker, // lcTool::ColorPicker
2172 lcTrackTool::Zoom, // lcTool::Zoom
2173 lcTrackTool::Pan, // lcTool::Pan
2174 lcTrackTool::OrbitXY, // lcTool::RotateView
2175 lcTrackTool::Roll, // lcTool::Roll
2176 lcTrackTool::ZoomRegion // lcTool::ZoomRegion
2177 };
2178
2179 LC_ARRAY_SIZE_CHECK(TrackToolFromTool, lcTool::Count);
2180
2181 return TrackToolFromTool[static_cast<int>(OverrideTool)];
2182 }
2183
GetOverlayScale() const2184 float lcView::GetOverlayScale() const
2185 {
2186 lcVector3 OverlayCenter;
2187 lcMatrix33 RelativeRotation;
2188 lcModel* ActiveModel = GetActiveModel();
2189 ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation);
2190
2191 lcMatrix44 WorldMatrix = lcMatrix44(RelativeRotation, OverlayCenter);
2192
2193 if (ActiveModel != mModel)
2194 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
2195
2196 lcVector3 ScreenPos = ProjectPoint(WorldMatrix.GetTranslation());
2197 ScreenPos[0] += 10.0f;
2198 lcVector3 Point = UnprojectPoint(ScreenPos);
2199
2200 lcVector3 Dist(Point - WorldMatrix.GetTranslation());
2201 return Dist.Length() * 5.0f;
2202 }
2203
BeginDrag(lcDragState DragState)2204 void lcView::BeginDrag(lcDragState DragState)
2205 {
2206 mDragState = DragState;
2207 UpdateTrackTool();
2208 }
2209
EndDrag(bool Accept)2210 void lcView::EndDrag(bool Accept)
2211 {
2212 lcModel* ActiveModel = GetActiveModel();
2213
2214 if (Accept)
2215 {
2216 switch (mDragState)
2217 {
2218 case lcDragState::None:
2219 break;
2220
2221 case lcDragState::Piece:
2222 {
2223 PieceInfo* Info = gMainWindow->GetCurrentPieceInfo();
2224 if (Info)
2225 ActiveModel->InsertPieceToolClicked(GetPieceInsertPosition(false, Info));
2226 } break;
2227
2228 case lcDragState::Color:
2229 ActiveModel->PaintToolClicked(FindObjectUnderPointer(true, false).Object);
2230 break;
2231 }
2232 }
2233
2234 mDragState = lcDragState::None;
2235 UpdateTrackTool();
2236 ActiveModel->UpdateAllViews();
2237 }
2238
SetViewpoint(lcViewpoint Viewpoint)2239 void lcView::SetViewpoint(lcViewpoint Viewpoint)
2240 {
2241 if (!mCamera || !mCamera->IsSimple())
2242 {
2243 lcCamera* OldCamera = mCamera;
2244
2245 mCamera = new lcCamera(true);
2246
2247 if (OldCamera)
2248 mCamera->CopySettings(OldCamera);
2249 }
2250
2251 mCamera->SetViewpoint(Viewpoint);
2252 ZoomExtents();
2253 Redraw();
2254
2255 emit CameraChanged();
2256 }
2257
SetViewpoint(const lcVector3 & Position)2258 void lcView::SetViewpoint(const lcVector3& Position)
2259 {
2260 if (!mCamera || !mCamera->IsSimple())
2261 {
2262 lcCamera* OldCamera = mCamera;
2263
2264 mCamera = new lcCamera(true);
2265
2266 if (OldCamera)
2267 mCamera->CopySettings(OldCamera);
2268 }
2269
2270 mCamera->SetViewpoint(Position);
2271 ZoomExtents();
2272 Redraw();
2273
2274 emit CameraChanged();
2275 }
2276
SetViewpoint(const lcVector3 & Position,const lcVector3 & Target,const lcVector3 & Up)2277 void lcView::SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up)
2278 {
2279 if (!mCamera || !mCamera->IsSimple())
2280 {
2281 lcCamera* OldCamera = mCamera;
2282
2283 mCamera = new lcCamera(true);
2284
2285 if (OldCamera)
2286 mCamera->CopySettings(OldCamera);
2287 }
2288
2289 mCamera->SetViewpoint(Position, Target, Up);
2290 Redraw();
2291
2292 emit CameraChanged();
2293 }
2294
SetCameraAngles(float Latitude,float Longitude)2295 void lcView::SetCameraAngles(float Latitude, float Longitude)
2296 {
2297 if (!mCamera || !mCamera->IsSimple())
2298 {
2299 lcCamera* OldCamera = mCamera;
2300
2301 mCamera = new lcCamera(true);
2302
2303 if (OldCamera)
2304 mCamera->CopySettings(OldCamera);
2305 }
2306
2307 mCamera->SetAngles(Latitude, Longitude, 1.0f);
2308 ZoomExtents();
2309 Redraw();
2310 }
2311
SetDefaultCamera()2312 void lcView::SetDefaultCamera()
2313 {
2314 if (!mCamera || !mCamera->IsSimple())
2315 mCamera = new lcCamera(true);
2316
2317 mCamera->SetViewpoint(lcViewpoint::Home);
2318 ZoomExtents();
2319 Redraw();
2320
2321 emit CameraChanged();
2322 }
2323
SetCamera(lcCamera * Camera,bool ForceCopy)2324 void lcView::SetCamera(lcCamera* Camera, bool ForceCopy)
2325 {
2326 if (Camera->IsSimple() || ForceCopy)
2327 {
2328 if (!mCamera || !mCamera->IsSimple())
2329 mCamera = new lcCamera(true);
2330
2331 mCamera->CopyPosition(Camera);
2332 }
2333 else
2334 {
2335 if (mCamera && mCamera->IsSimple())
2336 delete mCamera;
2337
2338 mCamera = Camera;
2339 }
2340 }
2341
SetCamera(const QString & CameraName)2342 void lcView::SetCamera(const QString& CameraName)
2343 {
2344 const lcArray<lcCamera*>& Cameras = mModel->GetCameras();
2345
2346 for (int CameraIdx = 0; CameraIdx < Cameras.GetSize(); CameraIdx++)
2347 {
2348 if (CameraName.compare(Cameras[CameraIdx]->GetName(), Qt::CaseInsensitive) == 0)
2349 {
2350 SetCameraIndex(CameraIdx);
2351 return;
2352 }
2353 }
2354 }
2355
SetCameraIndex(int Index)2356 void lcView::SetCameraIndex(int Index)
2357 {
2358 const lcArray<lcCamera*>& Cameras = mModel->GetCameras();
2359
2360 if (Index >= Cameras.GetSize())
2361 return;
2362
2363 lcCamera* Camera = Cameras[Index];
2364 SetCamera(Camera, false);
2365
2366 emit CameraChanged();
2367 Redraw();
2368 }
2369
SetProjection(bool Ortho)2370 void lcView::SetProjection(bool Ortho)
2371 {
2372 if (mCamera->IsSimple())
2373 {
2374 mCamera->SetOrtho(Ortho);
2375 Redraw();
2376
2377 if (gMainWindow)
2378 gMainWindow->UpdatePerspective();
2379 }
2380 else
2381 {
2382 lcModel* ActiveModel = GetActiveModel();
2383 if (ActiveModel)
2384 ActiveModel->SetCameraOrthographic(mCamera, Ortho);
2385 }
2386 }
2387
LookAt()2388 void lcView::LookAt()
2389 {
2390 lcModel* ActiveModel = GetActiveModel();
2391 if (ActiveModel)
2392 ActiveModel->LookAt(mCamera);
2393 }
2394
MoveCamera(const lcVector3 & Direction)2395 void lcView::MoveCamera(const lcVector3& Direction)
2396 {
2397 lcModel* ActiveModel = GetActiveModel();
2398 if (ActiveModel)
2399 ActiveModel->MoveCamera(mCamera, Direction);
2400 }
2401
Zoom(float Amount)2402 void lcView::Zoom(float Amount)
2403 {
2404 lcModel* ActiveModel = GetActiveModel();
2405 if (ActiveModel)
2406 ActiveModel->Zoom(mCamera, Amount);
2407 }
2408
ZoomExtents()2409 void lcView::ZoomExtents()
2410 {
2411 lcModel* ActiveModel = GetActiveModel();
2412 if (ActiveModel)
2413 ActiveModel->ZoomExtents(mCamera, (float)mWidth / (float)mHeight);
2414 }
2415
GetCursor() const2416 lcCursor lcView::GetCursor() const
2417 {
2418 if (mTrackButton != lcTrackButton::None)
2419 return lcCursor::Hidden;
2420
2421 if (mTrackTool == lcTrackTool::Select)
2422 {
2423 if (mMouseModifiers & Qt::ControlModifier)
2424 return lcCursor::SelectAdd;
2425
2426 if (mMouseModifiers & Qt::ShiftModifier)
2427 return lcCursor::SelectRemove;
2428 }
2429
2430 constexpr lcCursor CursorFromTrackTool[] =
2431 {
2432 lcCursor::Select, // lcTrackTool::None
2433 lcCursor::Brick, // lcTrackTool::Insert
2434 lcCursor::Light, // lcTrackTool::PointLight
2435 lcCursor::Spotlight, // lcTrackTool::SpotLight
2436 lcCursor::Camera, // lcTrackTool::Camera
2437 lcCursor::Select, // lcTrackTool::Select
2438 lcCursor::Move, // lcTrackTool::MoveX
2439 lcCursor::Move, // lcTrackTool::MoveY
2440 lcCursor::Move, // lcTrackTool::MoveZ
2441 lcCursor::Move, // lcTrackTool::MoveXY
2442 lcCursor::Move, // lcTrackTool::MoveXZ
2443 lcCursor::Move, // lcTrackTool::MoveYZ
2444 lcCursor::Move, // lcTrackTool::MoveXYZ
2445 lcCursor::Rotate, // lcTrackTool::RotateX
2446 lcCursor::Rotate, // lcTrackTool::RotateY
2447 lcCursor::Rotate, // lcTrackTool::RotateZ
2448 lcCursor::Rotate, // lcTrackTool::RotateXY
2449 lcCursor::Rotate, // lcTrackTool::RotateXYZ
2450 lcCursor::Move, // lcTrackTool::ScalePlus
2451 lcCursor::Move, // lcTrackTool::ScaleMinus
2452 lcCursor::Delete, // lcTrackTool::Eraser
2453 lcCursor::Paint, // lcTrackTool::Paint
2454 lcCursor::ColorPicker, // lcTrackTool::ColorPicker
2455 lcCursor::Zoom, // lcTrackTool::Zoom
2456 lcCursor::Pan, // lcTrackTool::Pan
2457 lcCursor::RotateX, // lcTrackTool::OrbitX
2458 lcCursor::RotateY, // lcTrackTool::OrbitY
2459 lcCursor::RotateView, // lcTrackTool::OrbitXY
2460 lcCursor::Roll, // lcTrackTool::Roll
2461 lcCursor::ZoomRegion // lcTrackTool::ZoomRegion
2462 };
2463
2464 LC_ARRAY_SIZE_CHECK(CursorFromTrackTool, lcTrackTool::Count);
2465
2466 if (mTrackTool >= lcTrackTool::None && mTrackTool < lcTrackTool::Count)
2467 return CursorFromTrackTool[static_cast<int>(mTrackTool)];
2468
2469 return lcCursor::Select;
2470 }
2471
SetCursor(lcCursor CursorType)2472 void lcView::SetCursor(lcCursor CursorType)
2473 {
2474 if (mCursor == CursorType)
2475 return;
2476
2477 struct lcCursorInfo
2478 {
2479 int x, y;
2480 const char* Name;
2481 };
2482
2483 constexpr lcCursorInfo Cursors[] =
2484 {
2485 { 0, 0, "" }, // lcCursor::Hidden
2486 { 0, 0, "" }, // lcCursor::Default
2487 { 8, 3, ":/resources/cursor_insert" }, // lcCursor::Brick
2488 { 15, 15, ":/resources/cursor_light" }, // lcCursor::Light
2489 { 7, 10, ":/resources/cursor_spotlight" }, // lcCursor::Spotlight
2490 { 15, 9, ":/resources/cursor_camera" }, // lcCursor::Camera
2491 { 0, 2, ":/resources/cursor_select" }, // lcCursor::Select
2492 { 0, 2, ":/resources/cursor_select_add" }, // lcCursor::SelectAdd
2493 { 0, 2, ":/resources/cursor_select_remove" }, // lcCursor::SelectRemove
2494 { 15, 15, ":/resources/cursor_move" }, // lcCursor::Move
2495 { 15, 15, ":/resources/cursor_rotate" }, // lcCursor::Rotate
2496 { 15, 15, ":/resources/cursor_rotatex" }, // lcCursor::RotateX
2497 { 15, 15, ":/resources/cursor_rotatey" }, // lcCursor::RotateY
2498 { 0, 10, ":/resources/cursor_delete" }, // lcCursor::Delete
2499 { 14, 14, ":/resources/cursor_paint" }, // lcCursor::Paint
2500 { 1, 13, ":/resources/cursor_color_picker" }, // lcCursor::ColorPicker
2501 { 15, 15, ":/resources/cursor_zoom" }, // lcCursor::Zoom
2502 { 9, 9, ":/resources/cursor_zoom_region" }, // lcCursor::ZoomRegion
2503 { 15, 15, ":/resources/cursor_pan" }, // lcCursor::Pan
2504 { 15, 15, ":/resources/cursor_roll" }, // lcCursor::Roll
2505 { 15, 15, ":/resources/cursor_rotate_view" }, // lcCursor::RotateView
2506 };
2507
2508 LC_ARRAY_SIZE_CHECK(Cursors, lcCursor::Count);
2509
2510 if (CursorType == lcCursor::Hidden)
2511 {
2512 mWidget->setCursor(Qt::BlankCursor);
2513 mCursor = CursorType;
2514 }
2515 else if (CursorType >= lcCursor::First && CursorType < lcCursor::Count)
2516 {
2517 const lcCursorInfo& Cursor = Cursors[static_cast<int>(CursorType)];
2518 mWidget->setCursor(QCursor(QPixmap(Cursor.Name), Cursor.x, Cursor.y));
2519 mCursor = CursorType;
2520 }
2521 else
2522 {
2523 mWidget->unsetCursor();
2524 mCursor = lcCursor::Default;
2525 }
2526 }
2527
UpdateCursor()2528 void lcView::UpdateCursor()
2529 {
2530 SetCursor(GetCursor());
2531 }
2532
GetCurrentTool() const2533 lcTool lcView::GetCurrentTool() const
2534 {
2535 constexpr lcTool ToolFromTrackTool[] =
2536 {
2537 lcTool::Select, // lcTrackTool::None
2538 lcTool::Insert, // lcTrackTool::Insert
2539 lcTool::Light, // lcTrackTool::PointLight
2540 lcTool::SpotLight, // lcTrackTool::SpotLight
2541 lcTool::Camera, // lcTrackTool::Camera
2542 lcTool::Select, // lcTrackTool::Select
2543 lcTool::Move, // lcTrackTool::MoveX
2544 lcTool::Move, // lcTrackTool::MoveY
2545 lcTool::Move, // lcTrackTool::MoveZ
2546 lcTool::Move, // lcTrackTool::MoveXY
2547 lcTool::Move, // lcTrackTool::MoveXZ
2548 lcTool::Move, // lcTrackTool::MoveYZ
2549 lcTool::Move, // lcTrackTool::MoveXYZ
2550 lcTool::Rotate, // lcTrackTool::RotateX
2551 lcTool::Rotate, // lcTrackTool::RotateY
2552 lcTool::Rotate, // lcTrackTool::RotateZ
2553 lcTool::Rotate, // lcTrackTool::RotateXY
2554 lcTool::Rotate, // lcTrackTool::RotateXYZ
2555 lcTool::Move, // lcTrackTool::ScalePlus
2556 lcTool::Move, // lcTrackTool::ScaleMinus
2557 lcTool::Eraser, // lcTrackTool::Eraser
2558 lcTool::Paint, // lcTrackTool::Paint
2559 lcTool::ColorPicker, // lcTrackTool::ColorPicker
2560 lcTool::Zoom, // lcTrackTool::Zoom
2561 lcTool::Pan, // lcTrackTool::Pan
2562 lcTool::RotateView, // lcTrackTool::OrbitX
2563 lcTool::RotateView, // lcTrackTool::OrbitY
2564 lcTool::RotateView, // lcTrackTool::OrbitXY
2565 lcTool::Roll, // lcTrackTool::Roll
2566 lcTool::ZoomRegion // lcTrackTool::ZoomRegion
2567 };
2568
2569 LC_ARRAY_SIZE_CHECK(ToolFromTrackTool, lcTrackTool::Count);
2570
2571 if (mTrackTool >= lcTrackTool::None && mTrackTool < lcTrackTool::Count)
2572 return ToolFromTrackTool[static_cast<int>(mTrackTool)];
2573
2574 return lcTool::Select;
2575 }
2576
UpdateTrackTool()2577 void lcView::UpdateTrackTool()
2578 {
2579 if (mViewType != lcViewType::View)
2580 {
2581 mTrackTool = lcTrackTool::None;
2582 UpdateCursor();
2583 return;
2584 }
2585
2586 lcTool CurrentTool = gMainWindow->GetTool();
2587 lcTrackTool NewTrackTool = mTrackTool;
2588 int x = mMouseX;
2589 int y = mMouseY;
2590 bool Redraw = false;
2591 mTrackToolFromOverlay = false;
2592 lcModel* ActiveModel = GetActiveModel();
2593
2594 switch (CurrentTool)
2595 {
2596 case lcTool::Insert:
2597 NewTrackTool = lcTrackTool::Insert;
2598 break;
2599
2600 case lcTool::Light:
2601 NewTrackTool = lcTrackTool::PointLight;
2602 break;
2603
2604 case lcTool::SpotLight:
2605 NewTrackTool = lcTrackTool::SpotLight;
2606 break;
2607
2608 case lcTool::Camera:
2609 NewTrackTool = lcTrackTool::Camera;
2610 break;
2611
2612 case lcTool::Select:
2613 case lcTool::Move:
2614 {
2615 const float OverlayScale = GetOverlayScale();
2616 const float OverlayMovePlaneSize = 0.5f * OverlayScale;
2617 const float OverlayMoveArrowSize = 1.5f * OverlayScale;
2618 const float OverlayMoveArrowCapRadius = 0.1f * OverlayScale;
2619 const float OverlayRotateArrowStart = 1.0f * OverlayScale;
2620 const float OverlayRotateArrowEnd = 1.5f * OverlayScale;
2621 const float OverlayScaleRadius = 0.125f;
2622
2623 NewTrackTool = (CurrentTool == lcTool::Move) ? lcTrackTool::MoveXYZ : lcTrackTool::Select;
2624 mMouseDownPiece = nullptr;
2625
2626 lcVector3 OverlayCenter;
2627 lcMatrix33 RelativeRotation;
2628 if (!ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation))
2629 break;
2630
2631 lcMatrix44 WorldMatrix = lcMatrix44(RelativeRotation, OverlayCenter);
2632
2633 if (ActiveModel != mModel)
2634 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
2635 OverlayCenter = WorldMatrix.GetTranslation();
2636
2637 lcVector3 PlaneNormals[3] =
2638 {
2639 lcVector3(1.0f, 0.0f, 0.0f),
2640 lcVector3(0.0f, 1.0f, 0.0f),
2641 lcVector3(0.0f, 0.0f, 1.0f),
2642 };
2643
2644 for (int i = 0; i < 3; i++)
2645 PlaneNormals[i] = lcMul30(PlaneNormals[i], WorldMatrix);
2646
2647 lcVector3 StartEnd[2] = { lcVector3((float)x, (float)y, 0.0f), lcVector3((float)x, (float)y, 1.0f) };
2648 UnprojectPoints(StartEnd, 2);
2649 const lcVector3& Start = StartEnd[0];
2650 const lcVector3& End = StartEnd[1];
2651 float ClosestIntersectionDistance = FLT_MAX;
2652
2653 lcObject* Focus = ActiveModel->GetFocusObject();
2654 int ControlPointIndex = -1;
2655 if (Focus && Focus->IsPiece())
2656 {
2657 lcPiece* Piece = (lcPiece*)Focus;
2658 quint32 Section = Piece->GetFocusSection();
2659
2660 if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST && Section <= LC_PIECE_SECTION_CONTROL_POINT_LAST)
2661 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_1;
2662 }
2663
2664 quint32 AllowedTransforms = Focus ? Focus->GetAllowedTransforms() : LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z | LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z;
2665
2666 for (int AxisIndex = 0; AxisIndex < 3; AxisIndex++)
2667 {
2668 lcVector4 Plane(PlaneNormals[AxisIndex], -lcDot(PlaneNormals[AxisIndex], OverlayCenter));
2669 lcVector3 Intersection;
2670
2671 if (!lcLineSegmentPlaneIntersection(&Intersection, Start, End, Plane))
2672 continue;
2673
2674 float IntersectionDistance = lcLengthSquared(Intersection - Start);
2675
2676 if (IntersectionDistance > ClosestIntersectionDistance)
2677 continue;
2678
2679 lcVector3 Dir(Intersection - OverlayCenter);
2680
2681 float Proj1 = lcDot(Dir, PlaneNormals[(AxisIndex + 1) % 3]);
2682 float Proj2 = lcDot(Dir, PlaneNormals[(AxisIndex + 2) % 3]);
2683
2684 if (Proj1 > 0.0f && Proj1 < OverlayMovePlaneSize && Proj2 > 0.0f && Proj2 < OverlayMovePlaneSize)
2685 {
2686 lcTrackTool PlaneModes[] = { lcTrackTool::MoveYZ, lcTrackTool::MoveXZ, lcTrackTool::MoveXY };
2687
2688 if (IsTrackToolAllowed(PlaneModes[AxisIndex], AllowedTransforms))
2689 {
2690 NewTrackTool = PlaneModes[AxisIndex];
2691 ClosestIntersectionDistance = IntersectionDistance;
2692 }
2693 }
2694
2695 if (CurrentTool == lcTool::Select && Proj1 > OverlayRotateArrowStart && Proj1 < OverlayRotateArrowEnd && Proj2 > OverlayRotateArrowStart && Proj2 < OverlayRotateArrowEnd && ActiveModel->AnyPiecesSelected())
2696 {
2697 lcTrackTool PlaneModes[] = { lcTrackTool::RotateX, lcTrackTool::RotateY, lcTrackTool::RotateZ };
2698
2699 if (IsTrackToolAllowed(PlaneModes[AxisIndex], AllowedTransforms))
2700 {
2701 NewTrackTool = PlaneModes[AxisIndex];
2702 ClosestIntersectionDistance = IntersectionDistance;
2703 }
2704 }
2705
2706 if (fabs(Proj1) < OverlayMoveArrowCapRadius && Proj2 > 0.0f && Proj2 < OverlayMoveArrowSize)
2707 {
2708 lcTrackTool DirModes[] = { lcTrackTool::MoveZ, lcTrackTool::MoveX, lcTrackTool::MoveY };
2709
2710 if (IsTrackToolAllowed(DirModes[AxisIndex], AllowedTransforms))
2711 {
2712 NewTrackTool = DirModes[AxisIndex];
2713 ClosestIntersectionDistance = IntersectionDistance;
2714 }
2715 }
2716
2717 if (fabs(Proj2) < OverlayMoveArrowCapRadius && Proj1 > 0.0f && Proj1 < OverlayMoveArrowSize)
2718 {
2719 lcTrackTool DirModes[] = { lcTrackTool::MoveY, lcTrackTool::MoveZ, lcTrackTool::MoveX };
2720
2721 if (IsTrackToolAllowed(DirModes[AxisIndex], AllowedTransforms))
2722 {
2723 NewTrackTool = DirModes[AxisIndex];
2724 ClosestIntersectionDistance = IntersectionDistance;
2725 }
2726 }
2727
2728 lcPiece* Piece = (lcPiece*)Focus;
2729
2730 if (ControlPointIndex != -1 && Piece->mPieceInfo->GetSynthInfo() && Piece->mPieceInfo->GetSynthInfo()->IsCurve())
2731 {
2732 float Strength = Piece->GetControlPoints()[ControlPointIndex].Scale;
2733 const float ScaleStart = (2.0f - OverlayScaleRadius) * OverlayScale + Strength;
2734 const float ScaleEnd = (2.0f + OverlayScaleRadius) * OverlayScale + Strength;
2735
2736 if (AxisIndex == 1 && fabs(Proj1) < OverlayScaleRadius * OverlayScale)
2737 {
2738 if (Proj2 > ScaleStart && Proj2 < ScaleEnd)
2739 {
2740 if (IsTrackToolAllowed(lcTrackTool::ScalePlus, AllowedTransforms))
2741 {
2742 NewTrackTool = lcTrackTool::ScalePlus;
2743 ClosestIntersectionDistance = IntersectionDistance;
2744 }
2745 }
2746 else if (Proj2 < -ScaleStart && Proj2 > -ScaleEnd)
2747 {
2748 if (IsTrackToolAllowed(lcTrackTool::ScaleMinus, AllowedTransforms))
2749 {
2750 NewTrackTool = lcTrackTool::ScaleMinus;
2751 ClosestIntersectionDistance = IntersectionDistance;
2752 }
2753 }
2754 }
2755 else if (AxisIndex == 2 && fabs(Proj2) < OverlayScaleRadius * OverlayScale)
2756 {
2757 if (Proj1 > ScaleStart && Proj1 < ScaleEnd)
2758 {
2759 if (IsTrackToolAllowed(lcTrackTool::ScalePlus, AllowedTransforms))
2760 {
2761 NewTrackTool = lcTrackTool::ScalePlus;
2762 ClosestIntersectionDistance = IntersectionDistance;
2763 }
2764 }
2765 else if (Proj1 < -ScaleStart && Proj1 > -ScaleEnd)
2766 {
2767 if (IsTrackToolAllowed(lcTrackTool::ScaleMinus, AllowedTransforms))
2768 {
2769 NewTrackTool = lcTrackTool::ScaleMinus;
2770 ClosestIntersectionDistance = IntersectionDistance;
2771 }
2772 }
2773 }
2774 }
2775 }
2776
2777 if (CurrentTool == lcTool::Select && NewTrackTool == lcTrackTool::Select && mMouseModifiers == Qt::NoModifier)
2778 {
2779 lcObjectSection ObjectSection = FindObjectUnderPointer(false, false);
2780 lcObject* Object = ObjectSection.Object;
2781
2782 if (Object && Object->IsPiece() && ObjectSection.Section == LC_PIECE_SECTION_POSITION && Object->IsSelected())
2783 {
2784 lcPiece* Piece = (lcPiece*)Object;
2785 mMouseDownPosition = Piece->mModelWorld.GetTranslation();
2786 mMouseDownPiece = Piece->mPieceInfo;
2787 NewTrackTool = lcTrackTool::MoveXYZ;
2788 }
2789 }
2790
2791 mTrackToolFromOverlay = NewTrackTool != lcTrackTool::MoveXYZ && NewTrackTool != lcTrackTool::Select;
2792 Redraw = true;
2793 }
2794 break;
2795
2796 case lcTool::Rotate:
2797 {
2798 const float OverlayScale = GetOverlayScale();
2799 const float OverlayRotateRadius = 2.0f;
2800
2801 NewTrackTool = lcTrackTool::RotateXYZ;
2802
2803 lcVector3 OverlayCenter;
2804 lcMatrix33 RelativeRotation;
2805 if (!ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation))
2806 break;
2807
2808 // Calculate the distance from the mouse pointer to the center of the sphere.
2809 lcVector3 StartEnd[2] = { lcVector3((float)x, (float)y, 0.0f), lcVector3((float)x, (float)y, 1.0f) };
2810 UnprojectPoints(StartEnd, 2);
2811 const lcVector3& SegStart = StartEnd[0];
2812 const lcVector3& SegEnd = StartEnd[1];
2813
2814 lcVector3 Line = SegEnd - SegStart;
2815 lcVector3 Vec = OverlayCenter - SegStart;
2816
2817 float u = lcDot(Vec, Line) / Line.LengthSquared();
2818
2819 // Closest point in the line to the mouse.
2820 lcVector3 Closest = SegStart + Line * u;
2821
2822 float Distance = (Closest - OverlayCenter).Length();
2823 const float Epsilon = 0.25f * OverlayScale;
2824
2825 if (Distance > (OverlayRotateRadius * OverlayScale + Epsilon))
2826 {
2827 NewTrackTool = lcTrackTool::RotateXYZ;
2828 }
2829 else if (Distance < (OverlayRotateRadius * OverlayScale + Epsilon))
2830 {
2831 // 3D rotation unless we're over one of the axis circles.
2832 NewTrackTool = lcTrackTool::RotateXYZ;
2833
2834 // Point P on a line defined by two points P1 and P2 is described by P = P1 + u (P2 - P1)
2835 // A sphere centered at P3 with radius r is described by (x - x3)^2 + (y - y3)^2 + (z - z3)^2 = r^2
2836 // Substituting the equation of the line into the sphere gives a quadratic equation where:
2837 // a = (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2
2838 // b = 2[ (x2 - x1) (x1 - x3) + (y2 - y1) (y1 - y3) + (z2 - z1) (z1 - z3) ]
2839 // c = x32 + y32 + z32 + x12 + y12 + z12 - 2[x3 x1 + y3 y1 + z3 z1] - r2
2840 // The solutions to this quadratic are described by: (-b +- sqrt(b^2 - 4 a c) / 2 a
2841 // The exact behavior is determined by b^2 - 4 a c:
2842 // If this is less than 0 then the line does not intersect the sphere.
2843 // If it equals 0 then the line is a tangent to the sphere intersecting it at one point
2844 // If it is greater then 0 the line intersects the sphere at two points.
2845
2846 float x1 = SegStart[0], y1 = SegStart[1], z1 = SegStart[2];
2847 float x2 = SegEnd[0], y2 = SegEnd[1], z2 = SegEnd[2];
2848 float x3 = OverlayCenter[0], y3 = OverlayCenter[1], z3 = OverlayCenter[2];
2849 float r = OverlayRotateRadius * OverlayScale;
2850
2851 // TODO: rewrite using vectors.
2852 float a = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) + (z2 - z1)*(z2 - z1);
2853 float b = 2 * ((x2 - x1)*(x1 - x3) + (y2 - y1)*(y1 - y3) + (z2 - z1)*(z1 - z3));
2854 float c = x3*x3 + y3*y3 + z3*z3 + x1*x1 + y1*y1 + z1*z1 - 2*(x3*x1 + y3*y1 + z3*z1) - r*r;
2855 float f = b * b - 4 * a * c;
2856
2857 if (f >= 0.0f)
2858 {
2859 lcVector3 ViewDir(mCamera->mTargetPosition - mCamera->mPosition);
2860
2861 float u1 = (-b + sqrtf(f)) / (2*a);
2862 float u2 = (-b - sqrtf(f)) / (2*a);
2863
2864 lcVector3 Intersections[2] =
2865 {
2866 lcVector3(x1 + u1*(x2-x1), y1 + u1*(y2-y1), z1 + u1*(z2-z1)),
2867 lcVector3(x1 + u2*(x2-x1), y1 + u2*(y2-y1), z1 + u2*(z2-z1))
2868 };
2869
2870 for (int i = 0; i < 2; i++)
2871 {
2872 lcVector3 Dist = Intersections[i] - OverlayCenter;
2873
2874 if (lcDot(ViewDir, Dist) > 0.0f)
2875 continue;
2876
2877 Dist = lcMul(Dist, RelativeRotation);
2878
2879 // Check if we're close enough to one of the axis.
2880 Dist.Normalize();
2881
2882 float dx = fabsf(Dist[0]);
2883 float dy = fabsf(Dist[1]);
2884 float dz = fabsf(Dist[2]);
2885
2886 if (dx < dy)
2887 {
2888 if (dx < dz)
2889 {
2890 if (dx < Epsilon)
2891 NewTrackTool = lcTrackTool::RotateX;
2892 }
2893 else
2894 {
2895 if (dz < Epsilon)
2896 NewTrackTool = lcTrackTool::RotateZ;
2897 }
2898 }
2899 else
2900 {
2901 if (dy < dz)
2902 {
2903 if (dy < Epsilon)
2904 NewTrackTool = lcTrackTool::RotateY;
2905 }
2906 else
2907 {
2908 if (dz < Epsilon)
2909 NewTrackTool = lcTrackTool::RotateZ;
2910 }
2911 }
2912
2913 if (NewTrackTool != lcTrackTool::RotateXYZ)
2914 {
2915 switch (NewTrackTool)
2916 {
2917 case lcTrackTool::RotateX:
2918 Dist[0] = 0.0f;
2919 break;
2920 case lcTrackTool::RotateY:
2921 Dist[1] = 0.0f;
2922 break;
2923 case lcTrackTool::RotateZ:
2924 Dist[2] = 0.0f;
2925 break;
2926 default:
2927 break;
2928 }
2929
2930 mTrackToolFromOverlay = true;
2931 Dist *= r;
2932 break;
2933 }
2934 }
2935 }
2936 }
2937
2938 Redraw = true;
2939 }
2940 break;
2941
2942 case lcTool::Eraser:
2943 NewTrackTool = lcTrackTool::Eraser;
2944 break;
2945
2946 case lcTool::Paint:
2947 NewTrackTool = lcTrackTool::Paint;
2948 break;
2949
2950 case lcTool::ColorPicker:
2951 NewTrackTool = lcTrackTool::ColorPicker;
2952 break;
2953
2954 case lcTool::Zoom:
2955 NewTrackTool = lcTrackTool::Zoom;
2956 break;
2957
2958 case lcTool::Pan:
2959 NewTrackTool = lcTrackTool::Pan;
2960 break;
2961
2962 case lcTool::RotateView:
2963 {
2964 int vx, vy, vw, vh;
2965
2966 vx = 0;
2967 vy = 0;
2968 vw = mWidth;
2969 vh = mHeight;
2970
2971 int cx = vx + vw / 2;
2972 int cy = vy + vh / 2;
2973
2974 float d = sqrtf((float)((cx - x) * (cx - x) + (cy - y) * (cy - y)));
2975 float r = lcMin(vw, vh) * 0.35f;
2976
2977 const float SquareSize = lcMax(8.0f, (vw + vh) / 200.0f);
2978
2979 if ((d < r + SquareSize) && (d > r - SquareSize))
2980 {
2981 if ((cx - x < SquareSize) && (cx - x > -SquareSize))
2982 {
2983 NewTrackTool = lcTrackTool::OrbitY;
2984 mTrackToolFromOverlay = true;
2985 }
2986
2987 if ((cy - y < SquareSize) && (cy - y > -SquareSize))
2988 {
2989 NewTrackTool = lcTrackTool::OrbitX;
2990 mTrackToolFromOverlay = true;
2991 }
2992 }
2993 else
2994 {
2995 if (d < r)
2996 NewTrackTool = lcTrackTool::OrbitXY;
2997 else
2998 NewTrackTool = lcTrackTool::Roll;
2999 }
3000 }
3001 break;
3002
3003 case lcTool::Roll:
3004 NewTrackTool = lcTrackTool::Roll;
3005 break;
3006
3007 case lcTool::ZoomRegion:
3008 NewTrackTool = lcTrackTool::ZoomRegion;
3009 break;
3010
3011 case lcTool::Count:
3012 break;
3013 }
3014
3015 switch (mDragState)
3016 {
3017 case lcDragState::None:
3018 break;
3019
3020 case lcDragState::Piece:
3021 NewTrackTool = lcTrackTool::Insert;
3022 Redraw = true;
3023 break;
3024
3025 case lcDragState::Color:
3026 NewTrackTool = lcTrackTool::Paint;
3027 break;
3028 }
3029
3030 mTrackTool = NewTrackTool;
3031 UpdateCursor();
3032
3033 if (Redraw)
3034 ActiveModel->UpdateAllViews();
3035 }
3036
IsTrackToolAllowed(lcTrackTool TrackTool,quint32 AllowedTransforms) const3037 bool lcView::IsTrackToolAllowed(lcTrackTool TrackTool, quint32 AllowedTransforms) const
3038 {
3039 switch (TrackTool)
3040 {
3041 case lcTrackTool::None:
3042 case lcTrackTool::Insert:
3043 case lcTrackTool::PointLight:
3044 case lcTrackTool::SpotLight:
3045 case lcTrackTool::Camera:
3046 case lcTrackTool::Select:
3047 return true;
3048
3049 case lcTrackTool::MoveX:
3050 return AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_X;
3051
3052 case lcTrackTool::MoveY:
3053 return AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Y;
3054
3055 case lcTrackTool::MoveZ:
3056 return AllowedTransforms & LC_OBJECT_TRANSFORM_MOVE_Z;
3057
3058 case lcTrackTool::MoveXY:
3059 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y)) == (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y);
3060
3061 case lcTrackTool::MoveXZ:
3062 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Z)) == (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Z);
3063
3064 case lcTrackTool::MoveYZ:
3065 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z)) == (LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z);
3066
3067 case lcTrackTool::MoveXYZ:
3068 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z)) == (LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z);
3069
3070 case lcTrackTool::RotateX:
3071 return AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_X;
3072
3073 case lcTrackTool::RotateY:
3074 return AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_Y;
3075
3076 case lcTrackTool::RotateZ:
3077 return AllowedTransforms & LC_OBJECT_TRANSFORM_ROTATE_Z;
3078
3079 case lcTrackTool::RotateXY:
3080 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y)) == (LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y);
3081
3082 case lcTrackTool::RotateXYZ:
3083 return (AllowedTransforms & (LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z)) == (LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z);
3084
3085 case lcTrackTool::ScalePlus:
3086 case lcTrackTool::ScaleMinus:
3087 return AllowedTransforms & (LC_OBJECT_TRANSFORM_SCALE_X | LC_OBJECT_TRANSFORM_SCALE_Y | LC_OBJECT_TRANSFORM_SCALE_Z);
3088
3089 case lcTrackTool::Eraser:
3090 case lcTrackTool::Paint:
3091 case lcTrackTool::ColorPicker:
3092 case lcTrackTool::Zoom:
3093 case lcTrackTool::Pan:
3094 case lcTrackTool::OrbitX:
3095 case lcTrackTool::OrbitY:
3096 case lcTrackTool::OrbitXY:
3097 case lcTrackTool::Roll:
3098 case lcTrackTool::ZoomRegion:
3099 return true;
3100
3101 case lcTrackTool::Count:
3102 return false;
3103 }
3104
3105 return false;
3106 }
3107
StartOrbitTracking()3108 void lcView::StartOrbitTracking()
3109 {
3110 mTrackTool = lcTrackTool::OrbitXY;
3111 UpdateCursor();
3112 OnButtonDown(lcTrackButton::Left);
3113 }
3114
3115
StartTracking(lcTrackButton TrackButton)3116 void lcView::StartTracking(lcTrackButton TrackButton)
3117 {
3118 mTrackButton = TrackButton;
3119 mTrackUpdated = false;
3120 mMouseDownX = mMouseX;
3121 mMouseDownY = mMouseY;
3122 lcTool Tool = GetCurrentTool();
3123 lcModel* ActiveModel = GetActiveModel();
3124
3125 switch (Tool)
3126 {
3127 case lcTool::Insert:
3128 case lcTool::Light:
3129 break;
3130
3131 case lcTool::SpotLight:
3132 {
3133 lcVector3 Position = GetCameraLightInsertPosition();
3134 lcVector3 Target = Position + lcVector3(0.1f, 0.1f, 0.1f);
3135 ActiveModel->BeginSpotLightTool(Position, Target);
3136 }
3137 break;
3138
3139 case lcTool::Camera:
3140 {
3141 lcVector3 Position = GetCameraLightInsertPosition();
3142 lcVector3 Target = Position + lcVector3(0.1f, 0.1f, 0.1f);
3143 ActiveModel->BeginCameraTool(Position, Target);
3144 }
3145 break;
3146
3147 case lcTool::Select:
3148 break;
3149
3150 case lcTool::Move:
3151 case lcTool::Rotate:
3152 ActiveModel->BeginMouseTool();
3153 break;
3154
3155 case lcTool::Eraser:
3156 case lcTool::Paint:
3157 case lcTool::ColorPicker:
3158 break;
3159
3160 case lcTool::Zoom:
3161 case lcTool::Pan:
3162 case lcTool::RotateView:
3163 case lcTool::Roll:
3164 ActiveModel->BeginMouseTool();
3165 break;
3166
3167 case lcTool::ZoomRegion:
3168 break;
3169
3170 case lcTool::Count:
3171 break;
3172 }
3173
3174 UpdateCursor();
3175 }
3176
StopTracking(bool Accept)3177 void lcView::StopTracking(bool Accept)
3178 {
3179 if (mTrackButton == lcTrackButton::None)
3180 return;
3181
3182 lcTool Tool = GetCurrentTool();
3183 lcModel* ActiveModel = GetActiveModel();
3184
3185 switch (Tool)
3186 {
3187 case lcTool::Insert:
3188 case lcTool::Light:
3189 break;
3190
3191 case lcTool::SpotLight:
3192 case lcTool::Camera:
3193 ActiveModel->EndMouseTool(Tool, Accept);
3194 break;
3195
3196 case lcTool::Select:
3197 if (Accept && mMouseDownX != mMouseX && mMouseDownY != mMouseY)
3198 {
3199 lcArray<lcObject*> Objects = FindObjectsInBox(mMouseDownX, mMouseDownY, mMouseX, mMouseY);
3200
3201 if (mMouseModifiers & Qt::ControlModifier)
3202 ActiveModel->AddToSelection(Objects, true, true);
3203 else if (mMouseModifiers & Qt::ShiftModifier)
3204 ActiveModel->RemoveFromSelection(Objects);
3205 else
3206 ActiveModel->SetSelectionAndFocus(Objects, nullptr, 0, true);
3207 }
3208 break;
3209
3210 case lcTool::Move:
3211 case lcTool::Rotate:
3212 ActiveModel->EndMouseTool(Tool, Accept);
3213 break;
3214
3215 case lcTool::Eraser:
3216 case lcTool::Paint:
3217 case lcTool::ColorPicker:
3218 break;
3219
3220 case lcTool::Zoom:
3221 case lcTool::Pan:
3222 case lcTool::RotateView:
3223 case lcTool::Roll:
3224 ActiveModel->EndMouseTool(Tool, Accept);
3225 break;
3226
3227 case lcTool::ZoomRegion:
3228 {
3229 if (mMouseX == mMouseDownX || mMouseY == mMouseDownY)
3230 break;
3231
3232 lcVector3 Points[6] =
3233 {
3234 lcVector3((mMouseDownX + lcMin(mMouseX, mWidth - 1)) / 2, (mMouseDownY + lcMin(mMouseY, mHeight - 1)) / 2, 0.0f),
3235 lcVector3((mMouseDownX + lcMin(mMouseX, mWidth - 1)) / 2, (mMouseDownY + lcMin(mMouseY, mHeight - 1)) / 2, 1.0f),
3236 lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
3237 lcVector3((float)mMouseX, (float)mMouseY, 1.0f),
3238 lcVector3(mMouseDownX, mMouseDownY, 0.0f),
3239 lcVector3(mMouseDownX, mMouseDownY, 1.0f)
3240 };
3241
3242 UnprojectPoints(Points, 5);
3243
3244 lcVector3 Center = ActiveModel->GetSelectionOrModelCenter();
3245
3246 lcVector3 PlaneNormal(mCamera->mPosition - mCamera->mTargetPosition);
3247 lcVector4 Plane(PlaneNormal, -lcDot(PlaneNormal, Center));
3248 lcVector3 Target, Corners[2];
3249
3250 if (lcLineSegmentPlaneIntersection(&Target, Points[0], Points[1], Plane) && lcLineSegmentPlaneIntersection(&Corners[0], Points[2], Points[3], Plane) && lcLineSegmentPlaneIntersection(&Corners[1], Points[3], Points[4], Plane))
3251 {
3252 float AspectRatio = (float)mWidth / (float)mHeight;
3253 ActiveModel->ZoomRegionToolClicked(mCamera, AspectRatio, Points[0], Target, Corners);
3254 }
3255 }
3256 break;
3257
3258 case lcTool::Count:
3259 break;
3260 }
3261
3262 mTrackButton = lcTrackButton::None;
3263 UpdateTrackTool();
3264 ActiveModel->UpdateAllViews();
3265 }
3266
CancelTrackingOrClearSelection()3267 void lcView::CancelTrackingOrClearSelection()
3268 {
3269 if (mTrackButton != lcTrackButton::None)
3270 StopTracking(false);
3271 else
3272 {
3273 lcModel* ActiveModel = GetActiveModel();
3274 if (ActiveModel)
3275 ActiveModel->ClearSelection(true);
3276 }
3277 }
3278
OnButtonDown(lcTrackButton TrackButton)3279 void lcView::OnButtonDown(lcTrackButton TrackButton)
3280 {
3281 lcModel* ActiveModel = GetActiveModel();
3282 mToolClicked = false;
3283
3284 switch (mTrackTool)
3285 {
3286 case lcTrackTool::None:
3287 break;
3288
3289 case lcTrackTool::Insert:
3290 {
3291 PieceInfo* CurPiece = gMainWindow->GetCurrentPieceInfo();
3292
3293 if (!CurPiece)
3294 break;
3295
3296 ActiveModel->InsertPieceToolClicked(GetPieceInsertPosition(false, gMainWindow->GetCurrentPieceInfo()));
3297
3298 if ((mMouseModifiers & Qt::ControlModifier) == 0)
3299 gMainWindow->SetTool(lcTool::Select);
3300
3301 mToolClicked = true;
3302 UpdateTrackTool();
3303 }
3304 break;
3305
3306 case lcTrackTool::PointLight:
3307 {
3308 ActiveModel->PointLightToolClicked(GetCameraLightInsertPosition());
3309
3310 if ((mMouseModifiers & Qt::ControlModifier) == 0)
3311 gMainWindow->SetTool(lcTool::Select);
3312
3313 mToolClicked = true;
3314 UpdateTrackTool();
3315 }
3316 break;
3317
3318 case lcTrackTool::SpotLight:
3319 case lcTrackTool::Camera:
3320 StartTracking(TrackButton);
3321 break;
3322
3323 case lcTrackTool::Select:
3324 {
3325 lcObjectSection ObjectSection = FindObjectUnderPointer(false, false);
3326
3327 if (mMouseModifiers & Qt::ControlModifier)
3328 ActiveModel->FocusOrDeselectObject(ObjectSection);
3329 else if (mMouseModifiers & Qt::ShiftModifier)
3330 ActiveModel->RemoveFromSelection(ObjectSection);
3331 else
3332 ActiveModel->ClearSelectionAndSetFocus(ObjectSection, true);
3333
3334 StartTracking(TrackButton);
3335 }
3336 break;
3337
3338 case lcTrackTool::MoveX:
3339 case lcTrackTool::MoveY:
3340 case lcTrackTool::MoveZ:
3341 case lcTrackTool::MoveXY:
3342 case lcTrackTool::MoveXZ:
3343 case lcTrackTool::MoveYZ:
3344 case lcTrackTool::MoveXYZ:
3345 if (ActiveModel->AnyObjectsSelected())
3346 StartTracking(TrackButton);
3347 break;
3348
3349 case lcTrackTool::RotateX:
3350 case lcTrackTool::RotateY:
3351 case lcTrackTool::RotateZ:
3352 case lcTrackTool::RotateXY:
3353 case lcTrackTool::RotateXYZ:
3354 if (ActiveModel->AnyPiecesSelected())
3355 StartTracking(TrackButton);
3356 break;
3357
3358 case lcTrackTool::ScalePlus:
3359 case lcTrackTool::ScaleMinus:
3360 if (ActiveModel->AnyPiecesSelected())
3361 StartTracking(TrackButton);
3362 break;
3363
3364 case lcTrackTool::Eraser:
3365 ActiveModel->EraserToolClicked(FindObjectUnderPointer(false, false).Object);
3366 mToolClicked = true;
3367 break;
3368
3369 case lcTrackTool::Paint:
3370 ActiveModel->PaintToolClicked(FindObjectUnderPointer(true, false).Object);
3371 mToolClicked = true;
3372 break;
3373
3374 case lcTrackTool::ColorPicker:
3375 ActiveModel->ColorPickerToolClicked(FindObjectUnderPointer(true, false).Object);
3376 mToolClicked = true;
3377 break;
3378
3379 case lcTrackTool::Zoom:
3380 case lcTrackTool::Pan:
3381 case lcTrackTool::OrbitX:
3382 case lcTrackTool::OrbitY:
3383 case lcTrackTool::OrbitXY:
3384 case lcTrackTool::Roll:
3385 case lcTrackTool::ZoomRegion:
3386 StartTracking(TrackButton);
3387 break;
3388
3389 case lcTrackTool::Count:
3390 break;
3391 }
3392 }
3393
OnLeftButtonDown()3394 void lcView::OnLeftButtonDown()
3395 {
3396 if (mTrackButton != lcTrackButton::None)
3397 {
3398 StopTracking(false);
3399 return;
3400 }
3401
3402 if (mViewSphere->OnLeftButtonDown())
3403 return;
3404
3405 lcTrackTool OverrideTool = GetOverrideTrackTool(Qt::LeftButton);
3406
3407 if (OverrideTool != lcTrackTool::None)
3408 {
3409 mTrackTool = OverrideTool;
3410 UpdateCursor();
3411 }
3412
3413 OnButtonDown(lcTrackButton::Left);
3414 }
3415
OnLeftButtonUp()3416 void lcView::OnLeftButtonUp()
3417 {
3418 StopTracking(mTrackButton == lcTrackButton::Left);
3419
3420 if (mViewSphere->OnLeftButtonUp())
3421 return;
3422 }
3423
OnLeftButtonDoubleClick()3424 void lcView::OnLeftButtonDoubleClick()
3425 {
3426 if (mViewType != lcViewType::View)
3427 {
3428 ZoomExtents();
3429 return;
3430 }
3431
3432 lcObjectSection ObjectSection = FindObjectUnderPointer(false, false);
3433 lcModel* ActiveModel = GetActiveModel();
3434
3435 if (mMouseModifiers & Qt::ControlModifier)
3436 ActiveModel->FocusOrDeselectObject(ObjectSection);
3437 else if (mMouseModifiers & Qt::ShiftModifier)
3438 ActiveModel->RemoveFromSelection(ObjectSection);
3439 else
3440 ActiveModel->ClearSelectionAndSetFocus(ObjectSection, true);
3441 }
3442
OnMiddleButtonDown()3443 void lcView::OnMiddleButtonDown()
3444 {
3445 if (mTrackButton != lcTrackButton::None)
3446 {
3447 StopTracking(false);
3448 return;
3449 }
3450
3451 lcTrackTool OverrideTool = GetOverrideTrackTool(Qt::MiddleButton);
3452
3453 if (OverrideTool != lcTrackTool::None)
3454 {
3455 mTrackTool = OverrideTool;
3456 UpdateCursor();
3457 }
3458
3459 OnButtonDown(lcTrackButton::Middle);
3460 }
3461
OnMiddleButtonUp()3462 void lcView::OnMiddleButtonUp()
3463 {
3464 StopTracking(mTrackButton == lcTrackButton::Middle);
3465 }
3466
OnRightButtonDown()3467 void lcView::OnRightButtonDown()
3468 {
3469 if (mTrackButton != lcTrackButton::None)
3470 {
3471 StopTracking(false);
3472 return;
3473 }
3474
3475 lcTrackTool OverrideTool = GetOverrideTrackTool(Qt::RightButton);
3476
3477 if (OverrideTool != lcTrackTool::None)
3478 {
3479 mTrackTool = OverrideTool;
3480 UpdateCursor();
3481 }
3482
3483 OnButtonDown(lcTrackButton::Right);
3484 }
3485
OnRightButtonUp()3486 void lcView::OnRightButtonUp()
3487 {
3488 bool ShowMenu = !mToolClicked && (mTrackButton == lcTrackButton::None || !mTrackUpdated);
3489
3490 if (mTrackButton != lcTrackButton::None)
3491 StopTracking(mTrackButton == lcTrackButton::Right);
3492
3493 if (ShowMenu)
3494 ShowContextMenu();
3495 }
3496
OnBackButtonDown()3497 void lcView::OnBackButtonDown()
3498 {
3499 }
3500
OnBackButtonUp()3501 void lcView::OnBackButtonUp()
3502 {
3503 gMainWindow->HandleCommand(LC_VIEW_TIME_PREVIOUS);
3504 }
3505
OnForwardButtonDown()3506 void lcView::OnForwardButtonDown()
3507 {
3508 }
3509
OnForwardButtonUp()3510 void lcView::OnForwardButtonUp()
3511 {
3512 gMainWindow->HandleCommand(LC_VIEW_TIME_NEXT);
3513 }
3514
OnMouseMove()3515 void lcView::OnMouseMove()
3516 {
3517 lcModel* ActiveModel = GetActiveModel();
3518
3519 if (!ActiveModel)
3520 return;
3521
3522 if (mTrackButton == lcTrackButton::None)
3523 {
3524 if (mViewSphere->OnMouseMove())
3525 {
3526 lcTrackTool NewTrackTool = mViewSphere->IsDragging() ? lcTrackTool::OrbitXY : lcTrackTool::None;
3527
3528 if (NewTrackTool != mTrackTool)
3529 {
3530 mTrackTool = NewTrackTool;
3531 UpdateCursor();
3532 }
3533
3534 return;
3535 }
3536
3537 UpdateTrackTool();
3538
3539 if (mTrackTool == lcTrackTool::Insert)
3540 ActiveModel->UpdateAllViews();
3541
3542 return;
3543 }
3544
3545 mTrackUpdated = true;
3546 const float MouseSensitivity = 0.5f / (21.0f - lcGetPreferences().mMouseSensitivity);
3547
3548 switch (mTrackTool)
3549 {
3550 case lcTrackTool::None:
3551 case lcTrackTool::Insert:
3552 case lcTrackTool::PointLight:
3553 break;
3554
3555 case lcTrackTool::SpotLight:
3556 ActiveModel->UpdateSpotLightTool(GetCameraLightInsertPosition());
3557 break;
3558
3559 case lcTrackTool::Camera:
3560 ActiveModel->UpdateCameraTool(GetCameraLightInsertPosition());
3561 break;
3562
3563 case lcTrackTool::Select:
3564 Redraw();
3565 break;
3566
3567 case lcTrackTool::MoveX:
3568 case lcTrackTool::MoveY:
3569 case lcTrackTool::MoveZ:
3570 case lcTrackTool::MoveXY:
3571 case lcTrackTool::MoveXZ:
3572 case lcTrackTool::MoveYZ:
3573 case lcTrackTool::MoveXYZ:
3574 case lcTrackTool::ScalePlus:
3575 case lcTrackTool::ScaleMinus:
3576 {
3577 lcVector3 Points[4] =
3578 {
3579 lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
3580 lcVector3((float)mMouseX, (float)mMouseY, 1.0f),
3581 lcVector3(mMouseDownX, mMouseDownY, 0.0f),
3582 lcVector3(mMouseDownX, mMouseDownY, 1.0f)
3583 };
3584
3585 UnprojectPoints(Points, 4);
3586
3587 const lcVector3& CurrentStart = Points[0];
3588 const lcVector3& CurrentEnd = Points[1];
3589 const lcVector3& MouseDownStart = Points[2];
3590 const lcVector3& MouseDownEnd = Points[3];
3591
3592 lcVector3 OverlayCenter;
3593 lcMatrix33 RelativeRotation;
3594 ActiveModel->GetMoveRotateTransform(OverlayCenter, RelativeRotation);
3595
3596 lcMatrix44 WorldMatrix = lcMatrix44(RelativeRotation, OverlayCenter);
3597
3598 if (ActiveModel != mModel)
3599 WorldMatrix = lcMul(WorldMatrix, mActiveSubmodelTransform);
3600
3601 const lcVector3 Center = WorldMatrix.GetTranslation();
3602
3603 if (mTrackTool == lcTrackTool::MoveX || mTrackTool == lcTrackTool::MoveY || mTrackTool == lcTrackTool::MoveZ)
3604 {
3605 lcVector3 Direction;
3606 if (mTrackTool == lcTrackTool::MoveX)
3607 Direction = lcVector3(1.0f, 0.0f, 0.0f);
3608 else if (mTrackTool == lcTrackTool::MoveY)
3609 Direction = lcVector3(0.0f, 1.0f, 0.0f);
3610 else
3611 Direction = lcVector3(0.0f, 0.0f, 1.0f);
3612
3613 Direction = lcMul30(Direction, WorldMatrix);
3614
3615 lcVector3 Intersection;
3616 lcClosestPointsBetweenLines(Center, Center + Direction, CurrentStart, CurrentEnd, &Intersection, nullptr);
3617
3618 lcVector3 MoveStart;
3619 lcClosestPointsBetweenLines(Center, Center + Direction, MouseDownStart, MouseDownEnd, &MoveStart, nullptr);
3620
3621 lcVector3 Distance = Intersection - MoveStart;
3622 Distance = lcMul(Distance, lcMatrix33AffineInverse(lcMatrix33(WorldMatrix)));
3623 ActiveModel->UpdateMoveTool(Distance, true, mTrackButton != lcTrackButton::Left);
3624 }
3625 else if (mTrackTool == lcTrackTool::MoveXY || mTrackTool == lcTrackTool::MoveXZ || mTrackTool == lcTrackTool::MoveYZ)
3626 {
3627 lcVector3 PlaneNormal;
3628
3629 if (mTrackTool == lcTrackTool::MoveXY)
3630 PlaneNormal = lcVector3(0.0f, 0.0f, 1.0f);
3631 else if (mTrackTool == lcTrackTool::MoveXZ)
3632 PlaneNormal = lcVector3(0.0f, 1.0f, 0.0f);
3633 else
3634 PlaneNormal = lcVector3(1.0f, 0.0f, 0.0f);
3635
3636 PlaneNormal = lcMul30(PlaneNormal, WorldMatrix);
3637 lcVector4 Plane(PlaneNormal, -lcDot(PlaneNormal, Center));
3638 lcVector3 Intersection;
3639
3640 if (lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane))
3641 {
3642 lcVector3 MoveStart;
3643
3644 if (lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
3645 {
3646 lcVector3 Distance = Intersection - MoveStart;
3647 Distance = lcMul(Distance, lcMatrix33AffineInverse(lcMatrix33(WorldMatrix)));
3648 ActiveModel->UpdateMoveTool(Distance, true, mTrackButton != lcTrackButton::Left);
3649 }
3650 }
3651 }
3652 else if (mTrackTool == lcTrackTool::MoveXYZ && mMouseDownPiece)
3653 {
3654 lcMatrix44 NewPosition = GetPieceInsertPosition(true, mMouseDownPiece);
3655 lcVector3 Distance = NewPosition.GetTranslation() - mMouseDownPosition;
3656 ActiveModel->UpdateMoveTool(Distance, false, mTrackButton != lcTrackButton::Left);
3657 }
3658 else if (mTrackTool == lcTrackTool::ScalePlus || mTrackTool == lcTrackTool::ScaleMinus)
3659 {
3660 lcVector3 Direction;
3661 if (mTrackTool == lcTrackTool::ScalePlus)
3662 Direction = lcVector3(1.0f, 0.0f, 0.0f);
3663 else
3664 Direction = lcVector3(-1.0f, 0.0f, 0.0f);
3665
3666 Direction = lcMul30(Direction, WorldMatrix);
3667
3668 lcVector3 Intersection;
3669 lcClosestPointsBetweenLines(Center, Center + Direction, CurrentStart, CurrentEnd, &Intersection, nullptr);
3670
3671 lcObject* Focus = ActiveModel->GetFocusObject();
3672 if (Focus && Focus->IsPiece())
3673 {
3674 lcPiece* Piece = (lcPiece*)Focus;
3675 quint32 Section = Piece->GetFocusSection();
3676
3677 if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST && Section <= LC_PIECE_SECTION_CONTROL_POINT_LAST)
3678 {
3679 const float ScaleMax = 200.0f;
3680 const float OverlayScale = GetOverlayScale();
3681 const float ScaleStart = 2.0f * OverlayScale;
3682
3683 lcVector3 Position = Piece->GetSectionPosition(Section);
3684 lcVector3 Start = Position + Direction * ScaleStart;
3685
3686 float Distance = lcLength(Intersection - Start);
3687 if (lcDot(Direction, Intersection - Start) < 0.0f)
3688 Distance = 0.0f;
3689
3690 float Scale = lcClamp(Distance, 0.1f, ScaleMax);
3691
3692 ActiveModel->UpdateScaleTool(Scale);
3693 }
3694 }
3695 }
3696 else
3697 {
3698 lcVector3 PlaneNormal = lcNormalize(mCamera->mTargetPosition - mCamera->mPosition);
3699 lcVector4 Plane(PlaneNormal, -lcDot(PlaneNormal, Center));
3700 lcVector3 Intersection;
3701
3702 if (lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane))
3703 {
3704 lcVector3 MoveStart;
3705
3706 if (lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
3707 {
3708 lcVector3 Distance = Intersection - MoveStart;
3709 ActiveModel->UpdateMoveTool(Distance, true, mTrackButton != lcTrackButton::Left);
3710 }
3711 }
3712 }
3713 }
3714 break;
3715
3716 case lcTrackTool::RotateX:
3717 case lcTrackTool::RotateY:
3718 case lcTrackTool::RotateZ:
3719 {
3720 lcVector3 ScreenX = lcNormalize(lcCross(mCamera->mTargetPosition - mCamera->mPosition, mCamera->mUpVector));
3721 lcVector3 ScreenY = mCamera->mUpVector;
3722 lcVector3 Dir1;
3723
3724 switch (mTrackTool)
3725 {
3726 case lcTrackTool::RotateX:
3727 Dir1 = lcVector3(1.0f, 0.0f, 0.0f);
3728 break;
3729 case lcTrackTool::RotateY:
3730 Dir1 = lcVector3(0.0f, 1.0f, 0.0f);
3731 break;
3732 case lcTrackTool::RotateZ:
3733 Dir1 = lcVector3(0.0f, 0.0f, 1.0f);
3734 break;
3735 default:
3736 Dir1 = lcVector3(0.0f, 0.0f, 1.0f);
3737 break;
3738 }
3739
3740 lcVector3 MoveX, MoveY;
3741
3742 float dx1 = lcDot(ScreenX, Dir1);
3743 float dy1 = lcDot(ScreenY, Dir1);
3744
3745 if (fabsf(dx1) > fabsf(dy1))
3746 {
3747 if (dx1 >= 0.0f)
3748 MoveX = Dir1;
3749 else
3750 MoveX = -Dir1;
3751
3752 MoveY = lcVector3(0, 0, 0);
3753 }
3754 else
3755 {
3756 MoveX = lcVector3(0, 0, 0);
3757
3758 if (dy1 > 0.0f)
3759 MoveY = Dir1;
3760 else
3761 MoveY = -Dir1;
3762 }
3763
3764 MoveX *= 36.0f * (float)(mMouseX - mMouseDownX) * MouseSensitivity;
3765 MoveY *= 36.0f * (float)(mMouseY - mMouseDownY) * MouseSensitivity;
3766
3767 ActiveModel->UpdateRotateTool(MoveX + MoveY, mTrackButton != lcTrackButton::Left);
3768 }
3769 break;
3770
3771 case lcTrackTool::RotateXY:
3772 {
3773 lcVector3 ScreenZ = lcNormalize(mCamera->mTargetPosition - mCamera->mPosition);
3774 lcVector3 ScreenX = lcCross(ScreenZ, mCamera->mUpVector);
3775 lcVector3 ScreenY = mCamera->mUpVector;
3776
3777 lcVector3 MoveX = 36.0f * (float)(mMouseX - mMouseDownX) * MouseSensitivity * ScreenX;
3778 lcVector3 MoveY = 36.0f * (float)(mMouseY - mMouseDownY) * MouseSensitivity * ScreenY;
3779 ActiveModel->UpdateRotateTool(MoveX + MoveY, mTrackButton != lcTrackButton::Left);
3780 }
3781 break;
3782
3783 case lcTrackTool::RotateXYZ:
3784 {
3785 lcVector3 ScreenZ = lcNormalize(mCamera->mTargetPosition - mCamera->mPosition);
3786
3787 ActiveModel->UpdateRotateTool(36.0f * (float)(mMouseY - mMouseDownY) * MouseSensitivity * ScreenZ, mTrackButton != lcTrackButton::Left);
3788 }
3789 break;
3790
3791 case lcTrackTool::Eraser:
3792 case lcTrackTool::Paint:
3793 case lcTrackTool::ColorPicker:
3794 break;
3795
3796 case lcTrackTool::Zoom:
3797 ActiveModel->UpdateZoomTool(mCamera, 2.0f * MouseSensitivity * (mMouseY - mMouseDownY));
3798 break;
3799
3800 case lcTrackTool::Pan:
3801 {
3802 lcVector3 Points[4] =
3803 {
3804 lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
3805 lcVector3((float)mMouseX, (float)mMouseY, 1.0f),
3806 lcVector3(mMouseDownX, mMouseDownY, 0.0f),
3807 lcVector3(mMouseDownX, mMouseDownY, 1.0f)
3808 };
3809
3810 UnprojectPoints(Points, 4);
3811
3812 const lcVector3& CurrentStart = Points[0];
3813 const lcVector3& CurrentEnd = Points[1];
3814 const lcVector3& MouseDownStart = Points[2];
3815 const lcVector3& MouseDownEnd = Points[3];
3816 lcVector3 Center = ActiveModel->GetSelectionOrModelCenter();
3817
3818 lcVector3 PlaneNormal(mCamera->mPosition - mCamera->mTargetPosition);
3819 lcVector4 Plane(PlaneNormal, -lcDot(PlaneNormal, Center));
3820 lcVector3 Intersection, MoveStart;
3821
3822 if (!lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane) || !lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
3823 {
3824 Center = MouseDownStart + lcNormalize(MouseDownEnd - MouseDownStart) * 10.0f;
3825 Plane = lcVector4(PlaneNormal, -lcDot(PlaneNormal, Center));
3826
3827 if (!lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane) || !lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
3828 break;
3829 }
3830
3831 ActiveModel->UpdatePanTool(mCamera, MoveStart - Intersection);
3832 }
3833 break;
3834
3835 case lcTrackTool::OrbitX:
3836 ActiveModel->UpdateOrbitTool(mCamera, 0.1f * MouseSensitivity * (mMouseX - mMouseDownX), 0.0f);
3837 break;
3838
3839 case lcTrackTool::OrbitY:
3840 ActiveModel->UpdateOrbitTool(mCamera, 0.0f, 0.1f * MouseSensitivity * (mMouseY - mMouseDownY));
3841 break;
3842
3843 case lcTrackTool::OrbitXY:
3844 ActiveModel->UpdateOrbitTool(mCamera, 0.1f * MouseSensitivity * (mMouseX - mMouseDownX), 0.1f * MouseSensitivity * (mMouseY - mMouseDownY));
3845 break;
3846
3847 case lcTrackTool::Roll:
3848 ActiveModel->UpdateRollTool(mCamera, 2.0f * MouseSensitivity * (mMouseX - mMouseDownX) * LC_DTOR);
3849 break;
3850
3851 case lcTrackTool::ZoomRegion:
3852 Redraw();
3853 break;
3854
3855 case lcTrackTool::Count:
3856 break;
3857 }
3858 }
3859
OnMouseWheel(float Direction)3860 void lcView::OnMouseWheel(float Direction)
3861 {
3862 mModel->Zoom(mCamera, (int)(((mMouseModifiers & Qt::ControlModifier) ? 100 : 10) * Direction));
3863 }
3864