mirror of
https://github.com/leozide/leocad
synced 2024-12-27 21:58:37 +01:00
600 lines
13 KiB
C++
600 lines
13 KiB
C++
#include "lc_global.h"
|
|
#include "lc_previewwidget.h"
|
|
#include "pieceinf.h"
|
|
#include "piece.h"
|
|
#include "project.h"
|
|
#include "lc_model.h"
|
|
#include "camera.h"
|
|
#include "lc_library.h"
|
|
|
|
#include "lc_qglwidget.h"
|
|
|
|
lcPreviewDockWidget::lcPreviewDockWidget(QMainWindow* Parent)
|
|
: QMainWindow(Parent)
|
|
{
|
|
mPreview = new lcPreviewWidget();
|
|
mViewWidget = new lcQGLWidget(nullptr, mPreview);
|
|
setCentralWidget(mViewWidget);
|
|
setMinimumSize(200, 200);
|
|
|
|
mLockAction = new QAction(QIcon(":/resources/action_preview_unlocked.png"),tr("Lock Preview"), this);
|
|
mLockAction->setCheckable(true);
|
|
mLockAction->setChecked(false);
|
|
mLockAction->setShortcut(tr("Ctrl+L"));
|
|
connect(mLockAction, SIGNAL(triggered()), this, SLOT(SetPreviewLock()));
|
|
SetPreviewLock();
|
|
|
|
mLabel = new QLabel(QString());
|
|
|
|
mToolBar = addToolBar(tr("Toolbar"));
|
|
mToolBar->setObjectName("Toolbar");
|
|
mToolBar->setStatusTip(tr("Preview Toolbar"));
|
|
mToolBar->setMovable(false);
|
|
mToolBar->addAction(mLockAction);
|
|
mToolBar->addSeparator();
|
|
mToolBar->addWidget(mLabel);
|
|
if (mToolBar->isHidden())
|
|
mToolBar->show();
|
|
}
|
|
|
|
bool lcPreviewDockWidget::SetCurrentPiece(const QString& PartType, int ColorCode)
|
|
{
|
|
if (mLockAction->isChecked())
|
|
return true;
|
|
|
|
mLabel->setText(tr("Loading..."));
|
|
if (mPreview->SetCurrentPiece(PartType, ColorCode))
|
|
{
|
|
mLabel->setText(mPreview->GetDescription());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void lcPreviewDockWidget::UpdatePreview()
|
|
{
|
|
mPreview->UpdatePreview();
|
|
}
|
|
|
|
void lcPreviewDockWidget::ClearPreview()
|
|
{
|
|
if (mPreview->GetActiveModel()->GetPieces().GetSize())
|
|
mPreview->ClearPreview();
|
|
mLabel->setText(QString());
|
|
}
|
|
|
|
void lcPreviewDockWidget::SetPreviewLock()
|
|
{
|
|
bool Locked = mLockAction->isChecked();
|
|
if (Locked && mPreview->GetActiveModel()->GetPieces().IsEmpty())
|
|
{
|
|
mLockAction->setChecked(false);
|
|
return;
|
|
}
|
|
QIcon LockIcon(Locked ? ":/resources/action_preview_locked.png" : ":/resources/action_preview_unlocked.png");
|
|
QString State(Locked ? tr("Unlock") : tr("Lock"));
|
|
QString StatusTip(tr("%1 the preview display to %2 updates").arg(State).arg(Locked ? "enable" : "disable"));
|
|
mLockAction->setToolTip(tr("%1 Preview").arg(State));
|
|
mLockAction->setIcon(LockIcon);
|
|
mLockAction->setStatusTip(StatusTip);
|
|
}
|
|
|
|
lcPreviewWidget::lcPreviewWidget()
|
|
: mLoader(new Project(true)), mViewSphere(this)
|
|
{
|
|
mTrackTool = lcTrackTool::None;
|
|
mTrackButton = lcTrackButton::None;
|
|
|
|
mLoader->SetActiveModel(0);
|
|
mModel = mLoader->GetActiveModel();
|
|
|
|
SetDefaultCamera();
|
|
}
|
|
|
|
lcPreviewWidget::~lcPreviewWidget()
|
|
{
|
|
if (mCamera && mCamera->IsSimple())
|
|
delete mCamera;
|
|
|
|
delete mLoader;
|
|
}
|
|
|
|
bool lcPreviewWidget::SetCurrentPiece(const QString& PartType, int ColorCode)
|
|
{
|
|
lcPiecesLibrary* Library = lcGetPiecesLibrary();
|
|
PieceInfo* Info = Library->FindPiece(PartType.toLatin1().constData(), nullptr, false, false);
|
|
|
|
if (Info)
|
|
{
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
for (lcPiece* ModelPiece : ActiveModel->GetPieces())
|
|
{
|
|
if (Info == ModelPiece->mPieceInfo)
|
|
{
|
|
int ModelColorCode = ModelPiece->mColorCode;
|
|
if (ModelColorCode == ColorCode)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
mIsModel = Info->IsModel();
|
|
mDescription = Info->m_strDescription;
|
|
|
|
ActiveModel->SelectAllPieces();
|
|
ActiveModel->DeleteSelectedObjects();
|
|
|
|
Library->LoadPieceInfo(Info, false, true);
|
|
Library->WaitForLoadQueue();
|
|
|
|
lcStep CurrentStep = 1;
|
|
lcPiece* Piece = new lcPiece(nullptr);
|
|
|
|
Piece->SetPieceInfo(Info, PartType, false);
|
|
Piece->Initialize(lcMatrix44Identity(), CurrentStep);
|
|
Piece->SetColorCode(ColorCode);
|
|
|
|
ActiveModel->SetPreviewPiece(Piece);
|
|
}
|
|
else
|
|
{
|
|
QString ModelPath = QString("%1/%2").arg(QDir::currentPath()).arg(PartType);
|
|
|
|
if (!mLoader->Load(ModelPath))
|
|
{
|
|
QMessageBox::warning(nullptr, QMessageBox::tr("Error"), QMessageBox::tr("Failed to load '%1'.").arg(ModelPath));
|
|
return false;
|
|
}
|
|
|
|
mLoader->SetActiveModel(0);
|
|
lcGetPiecesLibrary()->RemoveTemporaryPieces();
|
|
mModel = mLoader->GetActiveModel();
|
|
if (!mModel->GetProperties().mDescription.isEmpty())
|
|
mDescription = mModel->GetProperties().mDescription;
|
|
else
|
|
mDescription = PartType;
|
|
mIsModel = true;
|
|
}
|
|
|
|
ZoomExtents();
|
|
|
|
return true;
|
|
}
|
|
|
|
void lcPreviewWidget::ClearPreview()
|
|
{
|
|
delete mLoader;
|
|
mLoader = new Project(true/*IsPreview*/);
|
|
mLoader->SetActiveModel(0);
|
|
mModel = mLoader->GetActiveModel();
|
|
lcGetPiecesLibrary()->UnloadUnusedParts();
|
|
Redraw();
|
|
}
|
|
|
|
void lcPreviewWidget::UpdatePreview()
|
|
{
|
|
QString PartType;
|
|
int ColorCode = -1;
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
for (lcPiece* ModelPiece : ActiveModel->GetPieces())
|
|
{
|
|
if (ModelPiece->mPieceInfo)
|
|
{
|
|
PartType = ModelPiece->mPieceInfo->mFileName;
|
|
ColorCode = ModelPiece->mColorCode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ClearPreview();
|
|
|
|
if (!PartType.isEmpty() && ColorCode > -1)
|
|
SetCurrentPiece(PartType, ColorCode);
|
|
}
|
|
|
|
void lcPreviewWidget::SetDefaultCamera()
|
|
{
|
|
if (!mCamera || !mCamera->IsSimple())
|
|
mCamera = new lcCamera(true);
|
|
mCamera->SetViewpoint(LC_VIEWPOINT_HOME);
|
|
}
|
|
|
|
void lcPreviewWidget::SetCamera(lcCamera* Camera) // called by lcModel::DeleteModel()
|
|
{
|
|
if (!mCamera || !mCamera->IsSimple())
|
|
mCamera = new lcCamera(true);
|
|
|
|
mCamera->CopyPosition(Camera);
|
|
}
|
|
|
|
lcModel* lcPreviewWidget::GetActiveModel() const
|
|
{
|
|
return mModel;
|
|
}
|
|
|
|
void lcPreviewWidget::ZoomExtents()
|
|
{
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
if (ActiveModel)
|
|
{
|
|
ActiveModel->ZoomExtents(mCamera, float(mWidth) / float(mHeight));
|
|
Redraw();
|
|
}
|
|
}
|
|
|
|
void lcPreviewWidget::StartOrbitTracking() // called by viewSphere
|
|
{
|
|
mTrackTool = lcTrackTool::OrbitXY;
|
|
|
|
OnUpdateCursor();
|
|
|
|
OnButtonDown(lcTrackButton::Left);
|
|
}
|
|
|
|
void lcPreviewWidget::SetViewpoint(const lcVector3& Position)
|
|
{
|
|
if (!mCamera || !mCamera->IsSimple())
|
|
{
|
|
lcCamera* OldCamera = mCamera;
|
|
|
|
mCamera = new lcCamera(true);
|
|
|
|
if (OldCamera)
|
|
mCamera->CopySettings(OldCamera);
|
|
}
|
|
|
|
mCamera->SetViewpoint(Position);
|
|
|
|
Redraw();
|
|
}
|
|
|
|
void lcPreviewWidget::DrawViewport()
|
|
{
|
|
mContext->SetWorldMatrix(lcMatrix44Identity());
|
|
mContext->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0)));
|
|
mContext->SetProjectionMatrix(lcMatrix44Ortho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f));
|
|
|
|
mContext->SetDepthWrite(false);
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
if (true/*we have an active view*/)
|
|
{
|
|
mContext->SetMaterial(lcMaterialType::UnlitColor);
|
|
mContext->SetColor(lcVector4FromColor(lcGetPreferences().mPreviewActiveColor));
|
|
float Verts[8] = { 0.0f, 0.0f, mWidth - 1.0f, 0.0f, mWidth - 1.0f, mHeight - 1.0f, 0.0f, mHeight - 1.0f };
|
|
|
|
mContext->SetVertexBufferPointer(Verts);
|
|
mContext->SetVertexFormatPosition(2);
|
|
mContext->DrawPrimitives(GL_LINE_LOOP, 0, 4);
|
|
}
|
|
|
|
mContext->SetDepthWrite(true);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
lcTool lcPreviewWidget::GetCurrentTool() const
|
|
{
|
|
const lcTool ToolFromTrackTool[] =
|
|
{
|
|
lcTool::Select, // lcTrackTool::None
|
|
lcTool::Pan, // lcTrackTool::Pan
|
|
lcTool::RotateView, // lcTrackTool::OrbitXY
|
|
};
|
|
|
|
return ToolFromTrackTool[static_cast<int>(mTrackTool)];
|
|
}
|
|
|
|
void lcPreviewWidget::StartTracking(lcTrackButton TrackButton)
|
|
{
|
|
mTrackButton = TrackButton;
|
|
mMouseDownX = mMouseX;
|
|
mMouseDownY = mMouseY;
|
|
lcTool Tool = GetCurrentTool(); // Either lcTrackTool::None (LC_TOOL_SELECT) or lcTrackTool::OrbitXY (LC_TOOL_ROTATE_VIEW)
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
|
|
switch (Tool)
|
|
{
|
|
case lcTool::Select:
|
|
break;
|
|
|
|
case lcTool::Pan:
|
|
case lcTool::RotateView:
|
|
ActiveModel->BeginMouseTool();
|
|
break;
|
|
|
|
case lcTool::Count:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
OnUpdateCursor();
|
|
}
|
|
|
|
void lcPreviewWidget::StopTracking(bool Accept)
|
|
{
|
|
if (mTrackButton == lcTrackButton::None)
|
|
return;
|
|
|
|
lcTool Tool = GetCurrentTool(); // Either lcTrackTool::None (LC_TOOL_SELECT) or lcTrackTool::OrbitXY (LC_TOOL_ROTATE_VIEW)
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
|
|
switch (Tool)
|
|
{
|
|
case lcTool::Select:
|
|
break;
|
|
|
|
case lcTool::Pan:
|
|
case lcTool::RotateView:
|
|
ActiveModel->EndMouseTool(Tool, Accept);
|
|
break;
|
|
|
|
case lcTool::Count:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
mTrackButton = lcTrackButton::None;
|
|
|
|
mTrackTool = lcTrackTool::None;
|
|
|
|
OnUpdateCursor();
|
|
}
|
|
|
|
void lcPreviewWidget::OnButtonDown(lcTrackButton TrackButton)
|
|
{
|
|
switch (mTrackTool)
|
|
{
|
|
case lcTrackTool::None:
|
|
break;
|
|
|
|
case lcTrackTool::Pan:
|
|
StartTracking(TrackButton);
|
|
break;
|
|
|
|
case lcTrackTool::OrbitXY:
|
|
StartTracking(TrackButton);
|
|
break;
|
|
|
|
case lcTrackTool::Count:
|
|
break;
|
|
}
|
|
}
|
|
|
|
lcCursor lcPreviewWidget::GetCursor() const
|
|
{
|
|
const lcCursor CursorFromTrackTool[] =
|
|
{
|
|
lcCursor::Select, // lcTrackTool::None
|
|
lcCursor::Pan, // lcTrackTool::Pan
|
|
lcCursor::RotateView, // lcTrackTool::OrbitXY
|
|
};
|
|
|
|
static_assert(LC_ARRAY_COUNT(CursorFromTrackTool) == static_cast<int>(lcTrackTool::Count), "Tracktool array size mismatch.");
|
|
|
|
if (mTrackTool < lcTrackTool::Count)
|
|
return CursorFromTrackTool[static_cast<int>(mTrackTool)];
|
|
|
|
return lcCursor::Select;
|
|
}
|
|
|
|
void lcPreviewWidget::OnDraw()
|
|
{
|
|
if (!mModel)
|
|
return;
|
|
|
|
lcPreferences& Preferences = lcGetPreferences();
|
|
const bool DrawInterface = mWidget != nullptr;
|
|
|
|
mScene->SetAllowLOD(Preferences.mAllowLOD && mWidget != nullptr);
|
|
mScene->SetLODDistance(Preferences.mMeshLODDistance);
|
|
|
|
mScene->Begin(mCamera->mWorldView);
|
|
|
|
mScene->SetDrawInterface(DrawInterface);
|
|
|
|
mModel->GetScene(mScene.get(), mCamera, false /*HighlightNewParts*/, false/*mFadeSteps*/);
|
|
|
|
mScene->End();
|
|
|
|
mContext->SetDefaultState();
|
|
|
|
mContext->SetViewport(0, 0, mWidth, mHeight);
|
|
|
|
DrawBackground();
|
|
|
|
mContext->SetProjectionMatrix(GetProjectionMatrix());
|
|
|
|
mContext->SetLineWidth(Preferences.mLineWidth);
|
|
|
|
mScene->Draw(mContext);
|
|
|
|
if (DrawInterface)
|
|
{
|
|
mContext->SetLineWidth(1.0f);
|
|
|
|
if (Preferences.mDrawPreviewAxis)
|
|
DrawAxes();
|
|
|
|
if (Preferences.mDrawPreviewViewSphere)
|
|
mViewSphere.Draw();
|
|
DrawViewport();
|
|
}
|
|
|
|
mContext->ClearResources();
|
|
}
|
|
|
|
void lcPreviewWidget::OnUpdateCursor()
|
|
{
|
|
SetCursor(GetCursor());
|
|
}
|
|
|
|
void lcPreviewWidget::OnLeftButtonDown()
|
|
{
|
|
if (mTrackButton != lcTrackButton::None)
|
|
{
|
|
StopTracking(false);
|
|
return;
|
|
}
|
|
|
|
if (mViewSphere.OnLeftButtonDown())
|
|
return;
|
|
|
|
lcTrackTool OverrideTool = lcTrackTool::OrbitXY;
|
|
|
|
if (OverrideTool != lcTrackTool::None)
|
|
{
|
|
mTrackTool = OverrideTool;
|
|
OnUpdateCursor();
|
|
}
|
|
|
|
OnButtonDown(lcTrackButton::Left);
|
|
}
|
|
|
|
void lcPreviewWidget::OnLeftButtonUp()
|
|
{
|
|
StopTracking(mTrackButton == lcTrackButton::Left);
|
|
|
|
if (mViewSphere.OnLeftButtonUp()) {
|
|
ZoomExtents();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void lcPreviewWidget::OnMiddleButtonDown()
|
|
{
|
|
if (mTrackButton != lcTrackButton::None)
|
|
{
|
|
StopTracking(false);
|
|
return;
|
|
}
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
|
|
lcTrackTool OverrideTool = lcTrackTool::None;
|
|
|
|
if (OverrideTool != lcTrackTool::None)
|
|
{
|
|
mTrackTool = OverrideTool;
|
|
OnUpdateCursor();
|
|
}
|
|
#endif
|
|
OnButtonDown(lcTrackButton::Middle);
|
|
}
|
|
|
|
void lcPreviewWidget::OnMiddleButtonUp()
|
|
{
|
|
StopTracking(mTrackButton == lcTrackButton::Middle);
|
|
}
|
|
|
|
void lcPreviewWidget::OnLeftButtonDoubleClick()
|
|
{
|
|
ZoomExtents();
|
|
Redraw();
|
|
}
|
|
|
|
void lcPreviewWidget::OnRightButtonDown()
|
|
{
|
|
if (mTrackButton != lcTrackButton::None)
|
|
{
|
|
StopTracking(false);
|
|
return;
|
|
}
|
|
|
|
lcTrackTool OverrideTool = lcTrackTool::Pan;
|
|
|
|
if (OverrideTool != lcTrackTool::None)
|
|
{
|
|
mTrackTool = OverrideTool;
|
|
OnUpdateCursor();
|
|
}
|
|
|
|
OnButtonDown(lcTrackButton::Middle);
|
|
}
|
|
|
|
void lcPreviewWidget::OnRightButtonUp()
|
|
{
|
|
if (mTrackButton != lcTrackButton::None)
|
|
StopTracking(mTrackButton == lcTrackButton::Right);
|
|
}
|
|
|
|
void lcPreviewWidget::OnMouseMove()
|
|
{
|
|
lcModel* ActiveModel = GetActiveModel();
|
|
|
|
if (!ActiveModel)
|
|
return;
|
|
|
|
if (mTrackButton == lcTrackButton::None)
|
|
{
|
|
if (mViewSphere.OnMouseMove())
|
|
{
|
|
lcTrackTool NewTrackTool = mViewSphere.IsDragging() ? lcTrackTool::OrbitXY : lcTrackTool::None;
|
|
|
|
if (NewTrackTool != mTrackTool)
|
|
{
|
|
mTrackTool = NewTrackTool;
|
|
OnUpdateCursor();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
const float MouseSensitivity = 0.5f / (21.0f - lcGetPreferences().mMouseSensitivity);
|
|
|
|
switch (mTrackTool)
|
|
{
|
|
case lcTrackTool::None:
|
|
break;
|
|
|
|
case lcTrackTool::Pan:
|
|
{
|
|
lcVector3 Points[4] =
|
|
{
|
|
lcVector3((float)mMouseX, (float)mMouseY, 0.0f),
|
|
lcVector3((float)mMouseX, (float)mMouseY, 1.0f),
|
|
lcVector3(mMouseDownX, mMouseDownY, 0.0f),
|
|
lcVector3(mMouseDownX, mMouseDownY, 1.0f)
|
|
};
|
|
|
|
UnprojectPoints(Points, 4);
|
|
|
|
const lcVector3& CurrentStart = Points[0];
|
|
const lcVector3& CurrentEnd = Points[1];
|
|
const lcVector3& MouseDownStart = Points[2];
|
|
const lcVector3& MouseDownEnd = Points[3];
|
|
lcVector3 Center = ActiveModel->GetSelectionOrModelCenter();
|
|
|
|
lcVector3 PlaneNormal(mCamera->mPosition - mCamera->mTargetPosition);
|
|
lcVector4 Plane(PlaneNormal, -lcDot(PlaneNormal, Center));
|
|
lcVector3 Intersection, MoveStart;
|
|
|
|
if (!lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane) || !lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
|
|
{
|
|
Center = MouseDownStart + lcNormalize(MouseDownEnd - MouseDownStart) * 10.0f;
|
|
Plane = lcVector4(PlaneNormal, -lcDot(PlaneNormal, Center));
|
|
|
|
if (!lcLineSegmentPlaneIntersection(&Intersection, CurrentStart, CurrentEnd, Plane) || !lcLineSegmentPlaneIntersection(&MoveStart, MouseDownStart, MouseDownEnd, Plane))
|
|
break;
|
|
}
|
|
|
|
ActiveModel->UpdatePanTool(mCamera, MoveStart - Intersection);
|
|
Redraw();
|
|
}
|
|
break;
|
|
|
|
case lcTrackTool::OrbitXY:
|
|
ActiveModel->UpdateOrbitTool(mCamera, 0.1f * MouseSensitivity * (mMouseX - mMouseDownX), 0.1f * MouseSensitivity * (mMouseY - mMouseDownY));
|
|
Redraw();
|
|
break;
|
|
|
|
case lcTrackTool::Count:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void lcPreviewWidget::OnMouseWheel(float Direction)
|
|
{
|
|
mModel->Zoom(mCamera, (int)(((mMouseModifiers & Qt::ControlModifier) ? 100 : 10) * Direction));
|
|
Redraw();
|
|
}
|