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