Connect train tracks when inserting with the keyboard.

This commit is contained in:
Leonardo Zide 2024-11-23 18:03:54 -08:00
parent 5a2d8027af
commit 14e5e7d126
6 changed files with 274 additions and 109 deletions

View file

@ -19,6 +19,7 @@
#include <deque>
#include <functional>
#include <memory>
#include <optional>
#if _MSC_VER
#pragma warning(default : 4062) // enumerator 'identifier' in switch of enum 'enumeration' is not handled

View file

@ -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<lcMatrix44> TrainTrackTransform = CurrentTrackInfo->GetPieceInsertPosition(Last, PieceInfo);
if (TrainTrackTransform)
WorldMatrix = TrainTrackTransform.value();
}
}
else
{

View file

@ -12,46 +12,6 @@
// move config to json
// add other track types
std::pair<PieceInfo*, lcMatrix44> 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<int>(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<PieceInfo*, lcMatrix44> 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<int>(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<lcMatrix44> 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;
}

View file

@ -26,6 +26,7 @@ public:
lcTrainTrackInfo() = default;
std::pair<PieceInfo*, lcMatrix44> GetPieceInsertPosition(lcPiece* Piece, quint32 ConnectionIndex, lcTrainTrackType TrainTrackType) const;
std::optional<lcMatrix44> GetPieceInsertPosition(lcPiece* Piece, PieceInfo* Info) const;
void AddConnection(const lcTrainTrackConnection& TrainTrackConnection)
{

View file

@ -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<lcTrainTrackConnection>& 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<lcPiece*>(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<lcTrainTrackConnection>& 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<lcTrainTrackConnection>& 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)

View file

@ -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<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());