diff --git a/common/lc_global.h b/common/lc_global.h index 655df052..04966a76 100644 --- a/common/lc_global.h +++ b/common/lc_global.h @@ -19,6 +19,7 @@ #include #include #include +#include #if _MSC_VER #pragma warning(default : 4062) // enumerator 'identifier' in switch of enum 'enumeration' is not handled diff --git a/common/lc_model.cpp b/common/lc_model.cpp index e44fa172..7a624a92 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -11,6 +11,7 @@ #include "lc_scene.h" #include "lc_texture.h" #include "lc_synth.h" +#include "lc_traintrack.h" #include "lc_file.h" #include "pieceinf.h" #include "lc_view.h" @@ -2288,12 +2289,23 @@ void lcModel::AddPiece() if (Last) { - const lcBoundingBox& LastBoundingBox = Last->GetBoundingBox(); - lcVector3 Dist(0, 0, LastBoundingBox.Max.z - PieceInfoBoundingBox.Min.z); - Dist = SnapPosition(Dist); + if (!PieceInfo->GetTrainTrackInfo() || !Last->mPieceInfo->GetTrainTrackInfo()) + { + const lcBoundingBox& LastBoundingBox = Last->GetBoundingBox(); + lcVector3 Dist(0, 0, LastBoundingBox.Max.z - PieceInfoBoundingBox.Min.z); + Dist = SnapPosition(Dist); - WorldMatrix = Last->mModelWorld; - WorldMatrix.SetTranslation(lcMul31(Dist, Last->mModelWorld)); + WorldMatrix = Last->mModelWorld; + WorldMatrix.SetTranslation(lcMul31(Dist, Last->mModelWorld)); + } + else + { + lcTrainTrackInfo* CurrentTrackInfo = Last->mPieceInfo->GetTrainTrackInfo(); + std::optional TrainTrackTransform = CurrentTrackInfo->GetPieceInsertPosition(Last, PieceInfo); + + if (TrainTrackTransform) + WorldMatrix = TrainTrackTransform.value(); + } } else { diff --git a/common/lc_traintrack.cpp b/common/lc_traintrack.cpp index 0a138406..5a1c4845 100644 --- a/common/lc_traintrack.cpp +++ b/common/lc_traintrack.cpp @@ -12,46 +12,6 @@ // move config to json // add other track types -std::pair lcTrainTrackInfo::GetPieceInsertPosition(lcPiece* Piece, quint32 ConnectionIndex, lcTrainTrackType TrainTrackType) const -{ - if (ConnectionIndex >= mConnections.size()) - return { nullptr, lcMatrix44Identity() }; - - const char* PieceNames[] = - { - "74746.dat", - "74747.dat", - "74747.dat", - "2861c04.dat", - "2859c04.dat" - }; - - PieceInfo* Info = lcGetPiecesLibrary()->FindPiece(PieceNames[static_cast(TrainTrackType)], nullptr, false, false); - - if (!Info) - return { nullptr, lcMatrix44Identity() }; - - lcTrainTrackInfo* TrainTrackInfo = Info->GetTrainTrackInfo(); - - if (!TrainTrackInfo || TrainTrackInfo->mConnections.empty()) - return { nullptr, lcMatrix44Identity() }; - - lcMatrix44 Transform; - - if (TrainTrackType != lcTrainTrackType::Left) - Transform = TrainTrackInfo->mConnections[0].Transform; - else - { - Transform = lcMatrix44AffineInverse(TrainTrackInfo->mConnections[0].Transform); - Transform = lcMul(Transform, lcMatrix44RotationZ(LC_PI)); - } - - Transform = lcMul(Transform, mConnections[ConnectionIndex].Transform); - Transform = lcMul(Transform, Piece->mModelWorld); - - return { Info, Transform }; -} - void lcTrainTrackInit(lcPiecesLibrary* Library) { PieceInfo* Info = Library->FindPiece("74746.dat", nullptr, false, false); @@ -110,3 +70,77 @@ void lcTrainTrackInit(lcPiecesLibrary* Library) Info->SetTrainTrackInfo(TrainTrackInfo); } } + +std::pair lcTrainTrackInfo::GetPieceInsertPosition(lcPiece* Piece, quint32 ConnectionIndex, lcTrainTrackType TrainTrackType) const +{ + if (ConnectionIndex >= mConnections.size()) + return { nullptr, lcMatrix44Identity() }; + + const char* PieceNames[] = + { + "74746.dat", + "74747.dat", + "74747.dat", + "2861c04.dat", + "2859c04.dat" + }; + + PieceInfo* Info = lcGetPiecesLibrary()->FindPiece(PieceNames[static_cast(TrainTrackType)], nullptr, false, false); + + if (!Info) + return { nullptr, lcMatrix44Identity() }; + + lcTrainTrackInfo* TrainTrackInfo = Info->GetTrainTrackInfo(); + + if (!TrainTrackInfo || TrainTrackInfo->mConnections.empty()) + return { nullptr, lcMatrix44Identity() }; + + lcMatrix44 Transform; + + if (TrainTrackType != lcTrainTrackType::Left) + Transform = TrainTrackInfo->mConnections[0].Transform; + else + { + Transform = lcMatrix44AffineInverse(TrainTrackInfo->mConnections[0].Transform); + Transform = lcMul(Transform, lcMatrix44RotationZ(LC_PI)); + } + + Transform = lcMul(Transform, mConnections[ConnectionIndex].Transform); + Transform = lcMul(Transform, Piece->mModelWorld); + + return { Info, Transform }; +} + +std::optional lcTrainTrackInfo::GetPieceInsertPosition(lcPiece* Piece, PieceInfo* Info) const +{ + quint32 FocusSection = Piece->GetFocusSection(); + quint32 ConnectionIndex = 0; + + if (FocusSection > LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST) + { + ConnectionIndex = FocusSection - LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST; + + if (ConnectionIndex >= mConnections.size()) + ConnectionIndex = 0; + } + + lcTrainTrackInfo* TrainTrackInfo = Info->GetTrainTrackInfo(); + + if (!TrainTrackInfo || TrainTrackInfo->mConnections.empty()) + return std::nullopt; + + lcMatrix44 Transform; + +// if (TrainTrackType != lcTrainTrackType::Left) + Transform = TrainTrackInfo->mConnections[0].Transform; +// else +// { +// Transform = lcMatrix44AffineInverse(TrainTrackInfo->mConnections[0].Transform); +// Transform = lcMul(Transform, lcMatrix44RotationZ(LC_PI)); +// } + + Transform = lcMul(Transform, mConnections[ConnectionIndex].Transform); + Transform = lcMul(Transform, Piece->mModelWorld); + + return Transform; +} diff --git a/common/lc_traintrack.h b/common/lc_traintrack.h index 7a12d86d..b7ff5a47 100644 --- a/common/lc_traintrack.h +++ b/common/lc_traintrack.h @@ -26,6 +26,7 @@ public: lcTrainTrackInfo() = default; std::pair GetPieceInsertPosition(lcPiece* Piece, quint32 ConnectionIndex, lcTrainTrackType TrainTrackType) const; + std::optional GetPieceInsertPosition(lcPiece* Piece, PieceInfo* Info) const; void AddConnection(const lcTrainTrackConnection& TrainTrackConnection) { diff --git a/common/piece.cpp b/common/piece.cpp index d3b26e30..720e257b 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -14,6 +14,7 @@ #include "lc_scene.h" #include "lc_qutils.h" #include "lc_synth.h" +#include "lc_traintrack.h" constexpr float LC_PIECE_CONTROL_POINT_SIZE = 10.0f; @@ -487,7 +488,7 @@ void lcPiece::RayTest(lcObjectRayTest& ObjectRayTest) const } } - if (AreControlPointsVisible()) + if (mPieceInfo->GetSynthInfo() && AreControlPointsVisible()) { const lcVector3 Min(-LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE); const lcVector3 Max(LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE); @@ -510,6 +511,31 @@ void lcPiece::RayTest(lcObjectRayTest& ObjectRayTest) const } } } + + if (mPieceInfo->GetTrainTrackInfo() && AreTrainTrackConnectionsVisible()) + { + const lcVector3 Min(-LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE); + const lcVector3 Max(LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE); + const std::vector& Connections = mPieceInfo->GetTrainTrackInfo()->GetConnections(); + + for (quint32 ConnectionIndex = 0; ConnectionIndex < Connections.size(); ConnectionIndex++) + { + const lcMatrix44 InverseTransform = lcMatrix44AffineInverse(Connections[ConnectionIndex].Transform); + const lcVector3 PointStart = lcMul31(Start, InverseTransform); + const lcVector3 PointEnd = lcMul31(End, InverseTransform); + + float Distance; + lcVector3 Plane; + + if (lcBoundingBoxRayIntersectDistance(Min, Max, PointStart, PointEnd, &Distance, nullptr, &Plane)) + { + ObjectRayTest.ObjectSection.Object = const_cast(this); + ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST + ConnectionIndex; + ObjectRayTest.Distance = Distance; + ObjectRayTest.PieceInfoRayTest.Plane = Plane; + } + } + } } void lcPiece::BoxTest(lcObjectBoxTest& ObjectBoxTest) const @@ -608,54 +634,115 @@ void lcPiece::DrawInterface(lcContext* Context, const lcScene& Scene) const Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, 0); } - if (!mControlPoints.empty() && AreControlPointsVisible()) + if (mPieceInfo->GetSynthInfo()) + DrawSynthInterface(Context, WorldMatrix); + else if (mPieceInfo->GetTrainTrackInfo()) + DrawTrainTrackInterface(Context, WorldMatrix); +} + +void lcPiece::DrawSynthInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const +{ + if (mControlPoints.empty() || !AreControlPointsVisible()) + return; + + float Verts[8 * 3]; + float* CurVert = Verts; + + lcVector3 CubeMin(-LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE); + lcVector3 CubeMax(LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE); + + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; + + const GLushort Indices[36] = { - float Verts[8 * 3]; - float* CurVert = Verts; + 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 5, 1, 0, 4, 5, 0, + 7, 3, 2, 6, 7, 2, 0, 3, 7, 0, 7, 4, 6, 2, 1, 5, 6, 1 + }; - lcVector3 CubeMin(-LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE); - lcVector3 CubeMax(LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE); + Context->EnableColorBlend(true); + Context->EnableCullFace(true); - *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; - *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; - *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; - *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; - *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; - *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; - *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; - *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; + const lcPreferences& Preferences = lcGetPreferences(); + const lcVector4 ControlPointColor = lcVector4FromColor(Preferences.mControlPointColor); + const lcVector4 ControlPointFocusedColor = lcVector4FromColor(Preferences.mControlPointFocusedColor); - const GLushort Indices[36] = - { - 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 5, 1, 0, 4, 5, 0, - 7, 3, 2, 6, 7, 2, 0, 3, 7, 0, 7, 4, 6, 2, 1, 5, 6, 1 - }; + for (quint32 ControlPointIndex = 0; ControlPointIndex < mControlPoints.size(); ControlPointIndex++) + { + Context->SetWorldMatrix(lcMul(mControlPoints[ControlPointIndex].Transform, WorldMatrix)); - Context->EnableColorBlend(true); - Context->EnableCullFace(true); + Context->SetVertexBufferPointer(Verts); + Context->SetVertexFormatPosition(3); + Context->SetIndexBufferPointer(Indices); - const lcVector4 ControlPointColor = lcVector4FromColor(Preferences.mControlPointColor); - const lcVector4 ControlPointFocusedColor = lcVector4FromColor(Preferences.mControlPointFocusedColor); + if (IsFocused(LC_PIECE_SECTION_CONTROL_POINT_FIRST + ControlPointIndex)) + Context->SetColor(ControlPointFocusedColor); + else + Context->SetColor(ControlPointColor); - for (quint32 ControlPointIndex = 0; ControlPointIndex < mControlPoints.size(); ControlPointIndex++) - { - Context->SetWorldMatrix(lcMul(mControlPoints[ControlPointIndex].Transform, WorldMatrix)); - - Context->SetVertexBufferPointer(Verts); - Context->SetVertexFormatPosition(3); - Context->SetIndexBufferPointer(Indices); - - if (IsFocused(LC_PIECE_SECTION_CONTROL_POINT_FIRST + ControlPointIndex)) - Context->SetColor(ControlPointFocusedColor); - else - Context->SetColor(ControlPointColor); - - Context->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0); - } - - Context->EnableCullFace(false); - Context->EnableColorBlend(false); + Context->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0); } + + Context->EnableCullFace(false); + Context->EnableColorBlend(false); +} + +void lcPiece::DrawTrainTrackInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const +{ + if (!AreTrainTrackConnectionsVisible()) + return; + + float Verts[8 * 3]; + float* CurVert = Verts; + + lcVector3 CubeMin(-LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE, -LC_PIECE_CONTROL_POINT_SIZE); + lcVector3 CubeMax(LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE, LC_PIECE_CONTROL_POINT_SIZE); + + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMin[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMin[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMax[1]; *CurVert++ = CubeMax[2]; + *CurVert++ = CubeMax[0]; *CurVert++ = CubeMin[1]; *CurVert++ = CubeMax[2]; + + const GLushort Indices[36] = + { + 0, 1, 2, 0, 2, 3, 7, 6, 5, 7, 5, 4, 5, 1, 0, 4, 5, 0, + 7, 3, 2, 6, 7, 2, 0, 3, 7, 0, 7, 4, 6, 2, 1, 5, 6, 1 + }; + + const lcPreferences& Preferences = lcGetPreferences(); + const lcVector4 ConnectionColor = lcVector4FromColor(Preferences.mControlPointColor); + const lcVector4 ConnectionFocusedColor = lcVector4FromColor(Preferences.mControlPointFocusedColor); + + const lcTrainTrackInfo* TrainTrackInfo = mPieceInfo->GetTrainTrackInfo(); + const std::vector& Connections = TrainTrackInfo->GetConnections(); + + for (quint32 ConnectionIndex = 0; ConnectionIndex < Connections.size(); ConnectionIndex++) + { + Context->SetWorldMatrix(lcMul(Connections[ConnectionIndex].Transform, WorldMatrix)); + + Context->SetVertexBufferPointer(Verts); + Context->SetVertexFormatPosition(3); + Context->SetIndexBufferPointer(Indices); + + if (IsFocused(LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST + ConnectionIndex)) + Context->SetColor(ConnectionFocusedColor); + else + Context->SetColor(ConnectionColor); + + Context->DrawIndexedPrimitives(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0); + } + + mPieceInfo->GetTrainTrackInfo()->GetConnections(); } QVariant lcPiece::GetPropertyValue(lcObjectPropertyId PropertyId) const @@ -1094,6 +1181,48 @@ quint32 lcPiece::GetAllowedTransforms() const return 0; } +lcVector3 lcPiece::GetSectionPosition(quint32 Section) const +{ + if (Section == LC_PIECE_SECTION_POSITION) + { + if (mPivotPointValid) + return lcMul(mPivotMatrix, mModelWorld).GetTranslation(); + else + return mModelWorld.GetTranslation(); + } + + if (mPieceInfo->GetSynthInfo()) + { + if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST) + { + const quint32 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST; + + if (ControlPointIndex < mControlPoints.size()) + { + const lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform; + return lcMul(Transform, mModelWorld).GetTranslation(); + } + } + } + + if (mPieceInfo->GetTrainTrackInfo()) + { + if (Section >= LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST) + { + const quint32 ConnectionIndex = Section - LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST; + const std::vector& Connections = mPieceInfo->GetTrainTrackInfo()->GetConnections(); + + if (ConnectionIndex < Connections.size()) + { + const lcMatrix44& Transform = Connections[ConnectionIndex].Transform; + return lcMul(Transform, mModelWorld).GetTranslation(); + } + } + } + + return lcVector3(0.0f, 0.0f, 0.0f); +} + bool lcPiece::CanAddControlPoint() const { if (mControlPoints.size() >= LC_MAX_CONTROL_POINTS) diff --git a/common/piece.h b/common/piece.h index e1db7371..66dc3ef1 100644 --- a/common/piece.h +++ b/common/piece.h @@ -14,6 +14,7 @@ enum lcPieceSection : quint32 LC_PIECE_SECTION_POSITION = 0, LC_PIECE_SECTION_CONTROL_POINT_FIRST, LC_PIECE_SECTION_CONTROL_POINT_LAST = LC_PIECE_SECTION_CONTROL_POINT_FIRST + LC_MAX_CONTROL_POINTS - 1, + LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST = 1 }; struct lcPieceControlPoint @@ -90,29 +91,7 @@ public: } quint32 GetAllowedTransforms() const override; - - lcVector3 GetSectionPosition(quint32 Section) const override - { - if (Section == LC_PIECE_SECTION_POSITION) - { - if (mPivotPointValid) - return lcMul(mPivotMatrix, mModelWorld).GetTranslation(); - else - return mModelWorld.GetTranslation(); - } - else if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST) - { - const quint32 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST; - - if (ControlPointIndex < mControlPoints.size()) - { - const lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform; - return lcMul(Transform, mModelWorld).GetTranslation(); - } - } - - return lcVector3(0.0f, 0.0f, 0.0f); - } + lcVector3 GetSectionPosition(quint32 Section) const override; void SaveLDraw(QTextStream& Stream) const; bool ParseLDrawLine(QTextStream& Stream); @@ -360,6 +339,15 @@ protected: return IsSelected(); } + void DrawSynthInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const; + + bool AreTrainTrackConnectionsVisible() const + { + return IsSelected(); + } + + void DrawTrainTrackInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const; + lcObjectProperty mPosition = lcObjectProperty(lcVector3(0.0f, 0.0f, 0.0f)); lcObjectProperty mRotation = lcObjectProperty(lcMatrix33Identity());