diff --git a/common/lc_model.cpp b/common/lc_model.cpp index 408d73b2..99a201b5 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -1572,7 +1572,7 @@ void lcModel::BoxTest(lcObjectBoxTest& ObjectBoxTest) const Light->BoxTest(ObjectBoxTest); } -bool lcModel::SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const +bool lcModel::SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance, const PieceInfo*& HitPieceInfo, lcMatrix44& HitTransform) const { bool MinIntersect = false; @@ -1582,8 +1582,14 @@ bool lcModel::SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVect const lcVector3 Start = lcMul31(WorldStart, InverseWorldMatrix); const lcVector3 End = lcMul31(WorldEnd, InverseWorldMatrix); - if (Piece->IsVisibleInSubModel() && Piece->mPieceInfo->MinIntersectDist(Start, End, MinDistance)) // todo: this should check for piece->mMesh first - MinIntersect = true; + if (Piece->IsVisibleInSubModel()) + { + if (Piece->mPieceInfo->MinIntersectDist(Start, End, MinDistance, HitPieceInfo, HitTransform)) // todo: this should check for piece->mMesh first + { + MinIntersect = true; + HitTransform = lcMul(HitTransform, Piece->mModelWorld); + } + } } return MinIntersect; diff --git a/common/lc_model.h b/common/lc_model.h index 25a13a31..9e76bd06 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -239,7 +239,7 @@ public: void RayTest(lcObjectRayTest& ObjectRayTest) const; void BoxTest(lcObjectBoxTest& ObjectBoxTest) const; - bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const; + bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance, const PieceInfo*& HitPieceInfo, lcMatrix44& HitTransform) const; bool SubModelBoxTest(const lcVector4 Planes[6]) const; void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const; void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector& Points) const; diff --git a/common/lc_view.cpp b/common/lc_view.cpp index d60bc24a..591187a4 100644 --- a/common/lc_view.cpp +++ b/common/lc_view.cpp @@ -412,19 +412,23 @@ lcVector3 lcView::GetMoveDirection(const lcVector3& Direction) const lcMatrix44 lcView::GetPieceInsertPosition(bool IgnoreSelected, PieceInfo* Info) const { - lcPiece* HitPiece = (lcPiece*)FindObjectUnderPointer(true, IgnoreSelected).Object; lcModel* ActiveModel = GetActiveModel(); - if (HitPiece) + const PieceInfo* HitPieceInfo; + lcMatrix44 HitTransform; + + std::tie(HitPieceInfo, HitTransform) = FindPieceInfoUnderPointer(IgnoreSelected); + + if (HitPieceInfo) { - lcVector3 Position(0, 0, HitPiece->GetBoundingBox().Max.z - Info->GetBoundingBox().Min.z); + lcVector3 Position(0, 0, HitPieceInfo->GetBoundingBox().Max.z - Info->GetBoundingBox().Min.z); if (gMainWindow->GetRelativeTransform()) - Position = lcMul31(ActiveModel->SnapPosition(Position), HitPiece->mModelWorld); + Position = lcMul31(ActiveModel->SnapPosition(Position), HitTransform); else - Position = ActiveModel->SnapPosition(lcMul31(Position, HitPiece->mModelWorld)); + Position = ActiveModel->SnapPosition(lcMul31(Position, HitTransform)); - lcMatrix44 WorldMatrix = HitPiece->mModelWorld; + lcMatrix44 WorldMatrix = HitTransform; WorldMatrix.SetTranslation(Position); return WorldMatrix; @@ -523,9 +527,6 @@ lcObjectSection lcView::FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelec ObjectRayTest.ViewCamera = mCamera; ObjectRayTest.Start = StartEnd[0]; ObjectRayTest.End = StartEnd[1]; - ObjectRayTest.Distance = FLT_MAX; - ObjectRayTest.ObjectSection.Object = nullptr; - ObjectRayTest.ObjectSection.Section = 0;; lcModel* ActiveModel = GetActiveModel(); @@ -542,6 +543,39 @@ lcObjectSection lcView::FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelec return ObjectRayTest.ObjectSection; } +std::pair lcView::FindPieceInfoUnderPointer(bool IgnoreSelected) const +{ + lcVector3 StartEnd[2] = + { + lcVector3((float)mMouseX, (float)mMouseY, 0.0f), + lcVector3((float)mMouseX, (float)mMouseY, 1.0f) + }; + + UnprojectPoints(StartEnd, 2); + + lcObjectRayTest ObjectRayTest; + + ObjectRayTest.PiecesOnly = true; + ObjectRayTest.IgnoreSelected = IgnoreSelected; + ObjectRayTest.ViewCamera = mCamera; + ObjectRayTest.Start = StartEnd[0]; + ObjectRayTest.End = StartEnd[1]; + + lcModel* ActiveModel = GetActiveModel(); + + if (ActiveModel != mModel) + { + lcMatrix44 InverseMatrix = lcMatrix44AffineInverse(mActiveSubmodelTransform); + + ObjectRayTest.Start = lcMul31(ObjectRayTest.Start, InverseMatrix); + ObjectRayTest.End = lcMul31(ObjectRayTest.End, InverseMatrix); + } + + ActiveModel->RayTest(ObjectRayTest); + + return { ObjectRayTest.HitPieceInfo, ObjectRayTest.HitTransform }; +} + lcArray lcView::FindObjectsInBox(float x1, float y1, float x2, float y2) const { float Left, Top, Bottom, Right; diff --git a/common/lc_view.h b/common/lc_view.h index f1a02dd6..692a63a6 100644 --- a/common/lc_view.h +++ b/common/lc_view.h @@ -256,6 +256,7 @@ public: lcVector3 GetCameraLightInsertPosition() const; void GetRayUnderPointer(lcVector3& Start, lcVector3& End) const; lcObjectSection FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelected) const; + std::pair FindPieceInfoUnderPointer(bool IgnoreSelected) const; lcArray FindObjectsInBox(float x1, float y1, float x2, float y2) const; lcVector3 ProjectPoint(const lcVector3& Point) const; diff --git a/common/object.h b/common/object.h index 1432a2c1..de42174c 100644 --- a/common/object.h +++ b/common/object.h @@ -49,8 +49,8 @@ protected: struct lcObjectSection { - lcObject* Object; - quint32 Section; + lcObject* Object = nullptr; + quint32 Section = 0; }; struct lcObjectRayTest @@ -60,8 +60,10 @@ struct lcObjectRayTest bool IgnoreSelected; lcVector3 Start; lcVector3 End; - float Distance; + float Distance = FLT_MAX; lcObjectSection ObjectSection; + const PieceInfo* HitPieceInfo = nullptr; + lcMatrix44 HitTransform; }; struct lcObjectBoxTest diff --git a/common/piece.cpp b/common/piece.cpp index a2ad945d..5c0a9401 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -475,10 +475,18 @@ void lcPiece::RayTest(lcObjectRayTest& ObjectRayTest) const ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_POSITION; } } - else if (mPieceInfo->MinIntersectDist(Start, End, ObjectRayTest.Distance)) + else { - ObjectRayTest.ObjectSection.Object = const_cast(this); - ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_POSITION; + const PieceInfo* HitPieceInfo = nullptr; + lcMatrix44 HitTransform = lcMatrix44Identity(); + + if (mPieceInfo->MinIntersectDist(Start, End, ObjectRayTest.Distance, HitPieceInfo, HitTransform)) + { + ObjectRayTest.ObjectSection.Object = const_cast(this); + ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_POSITION; + ObjectRayTest.HitPieceInfo = HitPieceInfo; + ObjectRayTest.HitTransform = lcMul(HitTransform, mModelWorld); + } } if (AreControlPointsVisible()) diff --git a/common/pieceinf.cpp b/common/pieceinf.cpp index 085f65e0..0c0d4848 100644 --- a/common/pieceinf.cpp +++ b/common/pieceinf.cpp @@ -197,31 +197,43 @@ void PieceInfo::Unload() } } -bool PieceInfo::MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance) const +bool PieceInfo::MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance, const PieceInfo*& HitPieceInfo, lcMatrix44& HitTransform) const { bool Intersect = false; if (IsPlaceholder() || IsModel() || IsProject()) { float Distance; + if (!lcBoundingBoxRayIntersectDistance(mBoundingBox.Min, mBoundingBox.Max, Start, End, &Distance, nullptr) || (Distance >= MinDistance)) return false; if (IsPlaceholder()) + { + HitPieceInfo = this; + HitTransform = lcMatrix44Identity(); return true; + } if (IsModel()) - Intersect |= mModel->SubModelMinIntersectDist(Start, End, MinDistance); + Intersect |= mModel->SubModelMinIntersectDist(Start, End, MinDistance, HitPieceInfo, HitTransform); else if (IsProject()) { const lcModel* const Model = mProject->GetMainModel(); if (Model) - Intersect |= Model->SubModelMinIntersectDist(Start, End, MinDistance); + Intersect |= Model->SubModelMinIntersectDist(Start, End, MinDistance, HitPieceInfo, HitTransform); } } if (mMesh) - Intersect = mMesh->MinIntersectDist(Start, End, MinDistance); + { + if (mMesh->MinIntersectDist(Start, End, MinDistance)) + { + HitPieceInfo = this; + HitTransform = lcMatrix44Identity(); + Intersect = true; + } + } return Intersect; } diff --git a/common/pieceinf.h b/common/pieceinf.h index a8d732e0..fa61fe0d 100644 --- a/common/pieceinf.h +++ b/common/pieceinf.h @@ -169,7 +169,7 @@ public: void CreateProject(Project* Project, const char* PieceName); bool GetPieceWorldMatrix(lcPiece* Piece, lcMatrix44& WorldMatrix) const; bool IncludesModel(const lcModel* Model) const; - bool MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance) const; + bool MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance, const PieceInfo*& HitPieceInfo, lcMatrix44& HitTransform) const; bool BoxTest(const lcMatrix44& WorldMatrix, const lcVector4 Planes[6]) const; void GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool AddSubModels, lcPartsList& PartsList) const; void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector& ModelParts) const;