leocad/common/piece.cpp

1386 lines
41 KiB
C++
Raw Normal View History

#include "lc_global.h"
2012-04-14 01:41:58 +02:00
#include "lc_mesh.h"
#include "lc_colors.h"
2011-09-07 23:06:51 +02:00
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "pieceinf.h"
#include "piece.h"
#include "group.h"
#include "lc_file.h"
2011-09-07 23:06:51 +02:00
#include "lc_application.h"
2013-08-09 06:57:18 +02:00
#include "lc_library.h"
2014-11-24 00:48:56 +01:00
#include "lc_context.h"
2017-04-02 01:53:54 +02:00
#include "lc_scene.h"
#include "lc_qutils.h"
#include "lc_synth.h"
#include "lc_traintrack.h"
2011-09-07 23:06:51 +02:00
2021-11-15 03:34:24 +01:00
constexpr float LC_PIECE_CONTROL_POINT_SIZE = 10.0f;
2011-09-07 23:06:51 +02:00
lcPiece::lcPiece(PieceInfo* Info)
2020-04-19 04:45:21 +02:00
: lcObject(lcObjectType::Piece)
2011-09-07 23:06:51 +02:00
{
2017-07-23 05:54:33 +02:00
SetPieceInfo(Info, QString(), true);
mColorIndex = gDefaultColor;
mColorCode = 16;
2014-07-06 08:04:09 +02:00
mStepShow = 1;
mStepHide = LC_STEP_MAX;
mGroup = nullptr;
2015-12-14 19:01:17 +01:00
mPivotMatrix = lcMatrix44Identity();
2011-09-07 23:06:51 +02:00
}
2017-03-09 00:49:57 +01:00
lcPiece::lcPiece(const lcPiece& Other)
2020-04-19 04:45:21 +02:00
: lcObject(lcObjectType::Piece)
2017-03-09 00:49:57 +01:00
{
2017-07-23 05:54:33 +02:00
SetPieceInfo(Other.mPieceInfo, Other.mID, true);
mHidden = Other.mHidden;
mSelected = Other.mSelected;
2017-03-09 00:49:57 +01:00
mColorIndex = Other.mColorIndex;
mColorCode = Other.mColorCode;
mStepShow = Other.mStepShow;
mStepHide = Other.mStepHide;
mGroup = Other.mGroup;
2017-03-09 00:49:57 +01:00
mPivotMatrix = Other.mPivotMatrix;
mPivotPointValid = Other.mPivotPointValid;
2017-03-09 00:49:57 +01:00
2023-12-28 19:21:52 +01:00
mPosition = Other.mPosition;
mRotation = Other.mRotation;
2017-03-09 00:49:57 +01:00
mControlPoints = Other.mControlPoints;
UpdateMesh();
}
2014-05-01 20:42:11 +02:00
lcPiece::~lcPiece()
2011-09-07 23:06:51 +02:00
{
2015-12-14 19:01:17 +01:00
if (mPieceInfo)
2017-01-23 04:28:05 +01:00
{
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(mPieceInfo);
}
2016-02-19 18:53:54 +01:00
delete mMesh;
2011-09-07 23:06:51 +02:00
}
2017-07-23 05:54:33 +02:00
void lcPiece::SetPieceInfo(PieceInfo* Info, const QString& ID, bool Wait)
{
2017-01-23 04:28:05 +01:00
lcPiecesLibrary* Library = lcGetPiecesLibrary();
mPieceInfo = Info;
if (mPieceInfo)
2017-01-23 04:28:05 +01:00
Library->LoadPieceInfo(mPieceInfo, Wait, true);
2017-07-23 05:54:33 +02:00
if (!ID.isEmpty())
mID = ID;
else if (mPieceInfo)
mID = mPieceInfo->mFileName;
2017-07-23 05:54:33 +02:00
else
mID.clear();
2024-05-12 21:45:15 +02:00
mControlPoints.clear();
delete mMesh;
mMesh = nullptr;
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo ? mPieceInfo->GetSynthInfo() : nullptr;
if (SynthInfo)
{
2016-03-04 04:18:23 +01:00
SynthInfo->GetDefaultControlPoints(mControlPoints);
2016-02-19 18:53:54 +01:00
UpdateMesh();
}
}
bool lcPiece::SetPieceId(PieceInfo* Info)
{
if (mPieceInfo == Info)
return false;
lcPiecesLibrary* Library = lcGetPiecesLibrary();
Library->ReleasePieceInfo(mPieceInfo);
SetPieceInfo(Info, QString(), true);
return true;
}
2017-07-24 04:35:18 +02:00
void lcPiece::UpdateID()
{
mID = mPieceInfo->mFileName;
2017-07-24 04:35:18 +02:00
}
2014-09-05 02:24:28 +02:00
void lcPiece::SaveLDraw(QTextStream& Stream) const
{
2021-11-15 03:34:24 +01:00
const QLatin1String LineEnding("\r\n");
2014-09-08 21:42:20 +02:00
if (mStepHide != LC_STEP_MAX)
2014-09-08 21:42:20 +02:00
Stream << QLatin1String("0 !LEOCAD PIECE STEP_HIDE ") << mStepHide << LineEnding;
2014-09-08 21:42:20 +02:00
if (IsHidden())
Stream << QLatin1String("0 !LEOCAD PIECE HIDDEN") << LineEnding;
if (mPivotPointValid)
2015-12-16 23:36:42 +01:00
{
const float* PivotMatrix = mPivotMatrix;
2021-11-15 03:34:24 +01:00
const float PivotNumbers[12] = { PivotMatrix[12], -PivotMatrix[14], PivotMatrix[13], PivotMatrix[0], -PivotMatrix[8], PivotMatrix[4], -PivotMatrix[2], PivotMatrix[10], -PivotMatrix[6], PivotMatrix[1], -PivotMatrix[9], PivotMatrix[5] };
2015-12-16 23:36:42 +01:00
Stream << QLatin1String("0 !LEOCAD PIECE PIVOT ");
for (int NumberIdx = 0; NumberIdx < 12; NumberIdx++)
Stream << ' ' << lcFormatValue(PivotNumbers[NumberIdx], NumberIdx < 3 ? 4 : 6);
2015-12-16 23:36:42 +01:00
Stream << LineEnding;
}
mPosition.Save(Stream, "PIECE", "POSITION", false);
mRotation.Save(Stream, "PIECE", "ROTATION", false);
2014-09-05 02:24:28 +02:00
Stream << "1 " << mColorCode << ' ';
const float* Matrix = mModelWorld;
2021-11-15 03:34:24 +01:00
const float Numbers[12] = { Matrix[12], -Matrix[14], Matrix[13], Matrix[0], -Matrix[8], Matrix[4], -Matrix[2], Matrix[10], -Matrix[6], Matrix[1], -Matrix[9], Matrix[5] };
for (int NumberIdx = 0; NumberIdx < 12; NumberIdx++)
Stream << lcFormatValue(Numbers[NumberIdx], NumberIdx < 3 ? 4 : 6) << ' ';
2017-07-23 05:54:33 +02:00
Stream << mID << LineEnding;
}
2014-09-08 21:42:20 +02:00
bool lcPiece::ParseLDrawLine(QTextStream& Stream)
{
2014-09-08 21:42:20 +02:00
while (!Stream.atEnd())
2014-09-03 16:34:53 +02:00
{
2014-09-08 21:42:20 +02:00
QString Token;
Stream >> Token;
if (Token == QLatin1String("STEP_HIDE"))
Stream >> mStepHide;
else if (Token == QLatin1String("HIDDEN"))
SetHidden(true);
2015-12-16 23:36:42 +01:00
else if (Token == QLatin1String("PIVOT"))
{
float PivotNumbers[12];
for (int TokenIdx = 0; TokenIdx < 12; TokenIdx++)
Stream >> PivotNumbers[TokenIdx];
2021-11-15 03:34:24 +01:00
const lcMatrix44 PivotMatrix(lcVector4( PivotNumbers[3], PivotNumbers[9], -PivotNumbers[6], 0.0f), lcVector4(PivotNumbers[5], PivotNumbers[11], -PivotNumbers[8], 0.0f),
lcVector4(-PivotNumbers[4], -PivotNumbers[10], PivotNumbers[7], 0.0f), lcVector4(PivotNumbers[0], PivotNumbers[2], -PivotNumbers[1], 1.0f));
2015-12-16 23:36:42 +01:00
mPivotMatrix = PivotMatrix;
mPivotPointValid = true;
2015-12-16 23:36:42 +01:00
}
else if (mPosition.Load(Stream, Token, "POSITION"))
continue;
else if (mRotation.Load(Stream, Token, "ROTATION"))
continue;
2014-09-03 16:34:53 +02:00
}
return false;
}
2014-05-01 20:42:11 +02:00
bool lcPiece::FileLoad(lcFile& file)
2011-09-07 23:06:51 +02:00
{
2017-12-02 21:22:04 +01:00
quint8 version, ch;
2014-08-31 02:53:12 +02:00
version = file.ReadU8();
2015-12-14 19:01:17 +01:00
if (version > 12) // LeoCAD 0.80
2014-08-31 02:53:12 +02:00
return false;
2011-09-07 23:06:51 +02:00
const float PositionScale = (version < 12) ? 25.0f : 1.0f;
2014-08-31 02:53:12 +02:00
if (version > 8)
{
if (file.ReadU8() != 1)
return false;
2011-09-07 23:06:51 +02:00
2017-12-02 21:22:04 +01:00
quint16 time;
2014-08-31 02:53:12 +02:00
float param[4];
2017-12-02 21:22:04 +01:00
quint8 type;
quint32 n;
2011-09-07 23:06:51 +02:00
2014-08-31 02:53:12 +02:00
file.ReadU32(&n, 1);
while (n--)
{
file.ReadU16(&time, 1);
file.ReadFloats(param, 4);
file.ReadU8(&type, 1);
if (type == 0)
2023-12-28 19:21:52 +01:00
mPosition.ChangeKey(lcVector3(param[0], param[1], param[2]) * PositionScale, time, true);
2014-08-31 02:53:12 +02:00
else if (type == 1)
2023-12-28 19:21:52 +01:00
mRotation.ChangeKey(lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
2014-08-31 02:53:12 +02:00
}
file.ReadU32(&n, 1);
while (n--)
{
file.ReadU16(&time, 1);
file.ReadFloats(param, 4);
file.ReadU8(&type, 1);
}
}
2011-09-07 23:06:51 +02:00
if (version < 9)
{
quint16 time;
quint8 type;
if (version > 5)
{
quint32 keys;
float param[4];
file.ReadU32(&keys, 1);
while (keys--)
{
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
if (type == 0)
2023-12-28 19:21:52 +01:00
mPosition.ChangeKey(lcVector3(param[0], param[1], param[2]) * PositionScale, time, true);
else if (type == 1)
2023-12-28 19:21:52 +01:00
mRotation.ChangeKey(lcMatrix33FromAxisAngle(lcVector3(param[0], param[1], param[2]), param[3] * LC_DTOR), time, true);
}
file.ReadU32(&keys, 1);
while (keys--)
2012-10-18 20:57:21 +02:00
{
file.ReadFloats(param, 4);
file.ReadU16(&time, 1);
file.ReadU8(&type, 1);
}
}
else
{
if (version > 2)
{
file.ReadU8(&ch, 1);
while (ch--)
{
lcMatrix44 ModelWorld;
if (version > 3)
{
file.ReadFloats(ModelWorld, 16);
}
else
{
lcVector3 Translation;
float Rotation[3];
file.ReadFloats(Translation, 3);
file.ReadFloats(Rotation, 3);
ModelWorld = lcMatrix44Translation(Translation);
ModelWorld = lcMul(lcMatrix44RotationZ(Rotation[2] * LC_DTOR), lcMul(lcMatrix44RotationY(Rotation[1] * LC_DTOR), lcMul(lcMatrix44RotationX(Rotation[0] * LC_DTOR), ModelWorld)));
}
quint8 b;
file.ReadU8(&b, 1);
time = b;
2023-12-28 19:21:52 +01:00
mPosition.ChangeKey(ModelWorld.GetTranslation() * PositionScale, 1, true);
mRotation.ChangeKey(lcMatrix33(ModelWorld), time, true);
qint32 bl;
file.ReadS32(&bl, 1);
}
2012-10-18 20:57:21 +02:00
}
else
{
lcVector3 Translation;
float Rotation[3];
file.ReadFloats(Translation, 3);
file.ReadFloats(Rotation, 3);
lcMatrix44 ModelWorld = lcMatrix44Translation(Translation);
2012-10-18 20:57:21 +02:00
ModelWorld = lcMul(lcMatrix44RotationZ(Rotation[2] * LC_DTOR), lcMul(lcMatrix44RotationY(Rotation[1] * LC_DTOR), lcMul(lcMatrix44RotationX(Rotation[0] * LC_DTOR), ModelWorld)));
2023-12-28 19:21:52 +01:00
mPosition.ChangeKey(lcVector3(ModelWorld.r[3][0], ModelWorld.r[3][1], ModelWorld.r[3][2]) * PositionScale, 1, true);
mRotation.ChangeKey(lcMatrix33(ModelWorld), 1, true);
2012-10-18 20:57:21 +02:00
}
}
}
2012-10-18 20:57:21 +02:00
// Common to all versions.
2013-08-09 06:57:18 +02:00
char name[LC_PIECE_NAME_LEN];
if (version < 10)
{
memset(name, 0, LC_PIECE_NAME_LEN);
file.ReadBuffer(name, 9);
}
else
file.ReadBuffer(name, LC_PIECE_NAME_LEN);
strcat(name, ".dat");
2011-09-07 23:06:51 +02:00
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPiece(name, nullptr, true, false);
2017-07-23 05:54:33 +02:00
SetPieceInfo(pInfo, QString(), true);
2013-08-09 06:57:18 +02:00
2012-04-21 03:30:02 +02:00
// 11 (0.77)
2012-03-28 03:07:18 +02:00
if (version < 11)
{
2017-12-02 21:22:04 +01:00
quint8 Color;
2012-03-28 03:07:18 +02:00
file.ReadU8(&Color, 1);
if (version < 5)
2012-04-21 03:30:02 +02:00
mColorCode = lcGetColorCodeFromOriginalColor(Color);
else
mColorCode = lcGetColorCodeFromExtendedColor(Color);
2012-03-28 03:07:18 +02:00
}
else
file.ReadU32(&mColorCode, 1);
mColorIndex = lcGetColorIndex(mColorCode);
2011-09-07 23:06:51 +02:00
quint8 Step;
file.ReadU8(&Step, 1);
mStepShow = Step;
if (version > 1)
{
file.ReadU8(&Step, 1);
mStepHide = Step == 255 ? LC_STEP_MAX : Step;
}
else
mStepHide = LC_STEP_MAX;
if (version > 5)
{
file.ReadU16(); // m_nFrameShow
file.ReadU16(); // m_nFrameHide
if (version > 7)
{
quint8 Hidden;
file.ReadU8(&Hidden, 1);
if (Hidden & 1)
mHidden = true;
file.ReadU8(&ch, 1);
file.Seek(ch, SEEK_CUR);
}
else
{
qint32 hide;
file.ReadS32(&hide, 1);
if (hide != 0)
mHidden = true;
file.Seek(81, SEEK_CUR);
}
// 7 (0.64)
qint32 i = -1;
if (version > 6)
file.ReadS32(&i, 1);
mGroup = (lcGroup*)(quintptr)i;
}
else
{
file.ReadU8(&ch, 1);
if (ch == 0)
mGroup = (lcGroup*)-1;
else
mGroup = (lcGroup*)(quintptr)ch;
file.ReadU8(&ch, 1);
if (ch & 0x01)
mHidden = true;
2014-08-30 21:48:36 +02:00
}
return true;
2011-09-07 23:06:51 +02:00
}
void lcPiece::Initialize(const lcMatrix44& WorldMatrix, lcStep Step)
2011-09-07 23:06:51 +02:00
{
2014-07-06 08:04:09 +02:00
mStepShow = Step;
2011-09-07 23:06:51 +02:00
mPosition.SetValue(WorldMatrix.GetTranslation());
mRotation.SetValue(lcMatrix33(WorldMatrix));
2011-09-07 23:06:51 +02:00
2014-11-29 03:55:58 +01:00
UpdatePosition(Step);
2011-09-07 23:06:51 +02:00
}
2014-07-06 08:04:09 +02:00
void lcPiece::InsertTime(lcStep Start, lcStep Time)
2011-09-07 23:06:51 +02:00
{
2014-07-06 08:04:09 +02:00
if (mStepShow >= Start)
{
if (mStepShow < LC_STEP_MAX - Time)
mStepShow += Time;
else
mStepShow = LC_STEP_MAX;
}
2011-09-07 23:06:51 +02:00
2014-07-06 08:04:09 +02:00
if (mStepHide >= Start)
{
if (mStepHide < LC_STEP_MAX - Time)
mStepHide += Time;
else
mStepHide = LC_STEP_MAX;
}
2011-09-07 23:06:51 +02:00
2014-07-06 08:04:09 +02:00
if (mStepShow >= mStepHide)
{
if (mStepShow != LC_STEP_MAX)
mStepHide = mStepShow + 1;
else
{
mStepShow = LC_STEP_MAX - 1;
mStepHide = LC_STEP_MAX;
}
}
2023-12-28 19:21:52 +01:00
mPosition.InsertTime(Start, Time);
mRotation.InsertTime(Start, Time);
2011-09-07 23:06:51 +02:00
}
2014-07-06 08:04:09 +02:00
void lcPiece::RemoveTime(lcStep Start, lcStep Time)
2011-09-07 23:06:51 +02:00
{
2014-07-06 08:04:09 +02:00
if (mStepShow >= Start)
{
if (mStepShow > Time)
mStepShow -= Time;
else
mStepShow = 1;
}
2011-09-07 23:06:51 +02:00
2014-07-06 08:04:09 +02:00
if (mStepHide != LC_STEP_MAX)
{
if (mStepHide > Time)
mStepHide -= Time;
else
mStepHide = 1;
}
if (mStepShow >= mStepHide)
{
if (mStepShow != LC_STEP_MAX)
mStepHide = mStepShow + 1;
else
{
mStepShow = LC_STEP_MAX - 1;
mStepHide = LC_STEP_MAX;
}
}
2011-09-07 23:06:51 +02:00
2023-12-28 19:21:52 +01:00
mPosition.RemoveTime(Start, Time);
mRotation.RemoveTime(Start, Time);
2011-09-07 23:06:51 +02:00
}
2014-05-01 20:42:11 +02:00
void lcPiece::RayTest(lcObjectRayTest& ObjectRayTest) const
2011-09-07 23:06:51 +02:00
{
2021-11-15 03:34:24 +01:00
const lcMatrix44 InverseWorldMatrix = lcMatrix44AffineInverse(mModelWorld);
const lcVector3 Start = lcMul31(ObjectRayTest.Start, InverseWorldMatrix);
const lcVector3 End = lcMul31(ObjectRayTest.End, InverseWorldMatrix);
if (mMesh)
{
if (mMesh->MinIntersectDist(Start, End, ObjectRayTest.Distance, ObjectRayTest.PieceInfoRayTest.Plane))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcPiece*>(this);
ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_POSITION;
ObjectRayTest.PieceInfoRayTest.Transform = mModelWorld;
}
}
else
{
if (mPieceInfo->MinIntersectDist(Start, End, ObjectRayTest.Distance, ObjectRayTest.PieceInfoRayTest))
{
ObjectRayTest.ObjectSection.Object = const_cast<lcPiece*>(this);
ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_POSITION;
ObjectRayTest.PieceInfoRayTest.Transform = lcMul(ObjectRayTest.PieceInfoRayTest.Transform, mModelWorld);
}
}
if (mPieceInfo->GetSynthInfo() && AreControlPointsVisible())
{
2021-11-15 03:34:24 +01:00
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);
2024-05-12 21:45:15 +02:00
for (quint32 ControlPointIndex = 0; ControlPointIndex < mControlPoints.size(); ControlPointIndex++)
{
2024-05-12 21:45:15 +02:00
const lcMatrix44 InverseTransform = lcMatrix44AffineInverse(mControlPoints[ControlPointIndex].Transform);
2021-11-15 03:34:24 +01:00
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);
2024-05-12 21:45:15 +02:00
ObjectRayTest.ObjectSection.Section = LC_PIECE_SECTION_CONTROL_POINT_FIRST + ControlPointIndex;
ObjectRayTest.Distance = Distance;
ObjectRayTest.PieceInfoRayTest.Plane = Plane;
}
}
}
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++)
{
if (mTrainTrackConnections[ConnectionIndex])
continue;
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;
}
}
}
2011-09-07 23:06:51 +02:00
}
2014-05-01 20:42:11 +02:00
void lcPiece::BoxTest(lcObjectBoxTest& ObjectBoxTest) const
2011-09-07 23:06:51 +02:00
{
2014-12-26 16:44:46 +01:00
if (mPieceInfo->BoxTest(mModelWorld, ObjectBoxTest.Planes))
2024-05-26 22:01:34 +02:00
ObjectBoxTest.Objects.emplace_back(const_cast<lcPiece*>(this));
2011-09-07 23:06:51 +02:00
}
void lcPiece::DrawInterface(lcContext* Context, const lcScene& Scene) const
2014-11-24 00:48:56 +01:00
{
2021-11-25 00:20:08 +01:00
const lcPreferences& Preferences = lcGetPreferences();
const float LineWidth = Preferences.mLineWidth;
2014-11-24 00:48:56 +01:00
Context->SetLineWidth(2.0f * LineWidth);
2016-02-19 18:53:54 +01:00
const lcBoundingBox& BoundingBox = GetBoundingBox();
const lcVector3& Min = BoundingBox.Min;
const lcVector3& Max = BoundingBox.Max;
2014-11-24 00:48:56 +01:00
lcVector3 Edge((Max - Min) * 0.33f);
const float LineVerts[48][3] =
2014-11-24 00:48:56 +01:00
{
{ Max[0], Max[1], Max[2] }, { Max[0] - Edge[0], Max[1], Max[2] },
{ Max[0], Max[1], Max[2] }, { Max[0], Max[1] - Edge[1], Max[2] },
{ Max[0], Max[1], Max[2] }, { Max[0], Max[1], Max[2] - Edge[2] },
{ Min[0], Max[1], Max[2] }, { Min[0] + Edge[0], Max[1], Max[2] },
{ Min[0], Max[1], Max[2] }, { Min[0], Max[1] - Edge[1], Max[2] },
{ Min[0], Max[1], Max[2] }, { Min[0], Max[1], Max[2] - Edge[2] },
{ Max[0], Min[1], Max[2] }, { Max[0] - Edge[0], Min[1], Max[2] },
{ Max[0], Min[1], Max[2] }, { Max[0], Min[1] + Edge[1], Max[2] },
{ Max[0], Min[1], Max[2] }, { Max[0], Min[1], Max[2] - Edge[2] },
{ Min[0], Min[1], Max[2] }, { Min[0] + Edge[0], Min[1], Max[2] },
{ Min[0], Min[1], Max[2] }, { Min[0], Min[1] + Edge[1], Max[2] },
{ Min[0], Min[1], Max[2] }, { Min[0], Min[1], Max[2] - Edge[2] },
{ Max[0], Max[1], Min[2] }, { Max[0] - Edge[0], Max[1], Min[2] },
{ Max[0], Max[1], Min[2] }, { Max[0], Max[1] - Edge[1], Min[2] },
{ Max[0], Max[1], Min[2] }, { Max[0], Max[1], Min[2] + Edge[2] },
{ Min[0], Max[1], Min[2] }, { Min[0] + Edge[0], Max[1], Min[2] },
{ Min[0], Max[1], Min[2] }, { Min[0], Max[1] - Edge[1], Min[2] },
{ Min[0], Max[1], Min[2] }, { Min[0], Max[1], Min[2] + Edge[2] },
{ Max[0], Min[1], Min[2] }, { Max[0] - Edge[0], Min[1], Min[2] },
{ Max[0], Min[1], Min[2] }, { Max[0], Min[1] + Edge[1], Min[2] },
{ Max[0], Min[1], Min[2] }, { Max[0], Min[1], Min[2] + Edge[2] },
{ Min[0], Min[1], Min[2] }, { Min[0] + Edge[0], Min[1], Min[2] },
{ Min[0], Min[1], Min[2] }, { Min[0], Min[1] + Edge[1], Min[2] },
{ Min[0], Min[1], Min[2] }, { Min[0], Min[1], Min[2] + Edge[2] },
};
2021-11-15 03:34:24 +01:00
const lcMatrix44 WorldMatrix = Scene.ApplyActiveSubmodelTransform(mModelWorld);
2020-03-22 21:44:20 +01:00
Context->SetMaterial(lcMaterialType::UnlitColor);
Context->SetWorldMatrix(WorldMatrix);
2014-11-24 00:48:56 +01:00
if (IsFocused(LC_PIECE_SECTION_POSITION))
2021-11-25 00:20:08 +01:00
{
const lcVector4 FocusedColor = lcVector4FromColor(Preferences.mObjectFocusedColor);
Context->SetColor(FocusedColor);
}
2014-11-24 00:48:56 +01:00
else
2021-11-25 00:20:08 +01:00
{
const lcVector4 SelectedColor = lcVector4FromColor(Preferences.mObjectSelectedColor);
Context->SetColor(SelectedColor);
}
2014-11-24 00:48:56 +01:00
2017-04-03 02:15:09 +02:00
Context->SetVertexBufferPointer(LineVerts);
2017-03-24 17:34:53 +01:00
Context->SetVertexFormatPosition(3);
2015-04-19 03:10:01 +02:00
Context->DrawPrimitives(GL_LINES, 0, 48);
2015-12-14 19:01:17 +01:00
if (IsPivotPointVisible())
{
2021-11-15 03:34:24 +01:00
constexpr float Size = 5.0f;
constexpr float Verts[8 * 3] =
2015-12-14 19:01:17 +01:00
{
2015-12-15 02:57:22 +01:00
-Size, -Size, -Size, -Size, Size, -Size, Size, Size, -Size, Size, -Size, -Size,
-Size, -Size, Size, -Size, Size, Size, Size, Size, Size, Size, -Size, Size
2015-12-14 19:01:17 +01:00
};
2015-12-15 02:57:22 +01:00
const GLushort Indices[24] =
{
0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7
};
Context->SetWorldMatrix(lcMul(mPivotMatrix, WorldMatrix));
2015-12-15 02:57:22 +01:00
2015-12-14 19:01:17 +01:00
Context->SetVertexBufferPointer(Verts);
2017-03-24 17:34:53 +01:00
Context->SetVertexFormatPosition(3);
2015-12-14 19:01:17 +01:00
Context->SetIndexBufferPointer(Indices);
2015-12-15 02:57:22 +01:00
Context->DrawIndexedPrimitives(GL_LINES, 24, GL_UNSIGNED_SHORT, 0);
2015-12-14 19:01:17 +01:00
}
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] =
{
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
};
Context->EnableColorBlend(true);
Context->EnableCullFace(true);
2016-03-12 01:38:02 +01:00
const lcPreferences& Preferences = lcGetPreferences();
const lcVector4 ControlPointColor = lcVector4FromColor(Preferences.mControlPointColor);
const lcVector4 ControlPointFocusedColor = lcVector4FromColor(Preferences.mControlPointFocusedColor);
2021-11-25 00:20:08 +01:00
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);
}
2016-03-12 01:38:02 +01:00
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++)
{
if (mTrainTrackConnections[ConnectionIndex])
continue;
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();
2014-11-24 00:48:56 +01:00
}
2024-02-19 23:54:45 +01:00
QVariant lcPiece::GetPropertyValue(lcObjectPropertyId PropertyId) const
{
switch (PropertyId)
{
case lcObjectPropertyId::PieceId:
return QVariant::fromValue<void*>(mPieceInfo);
case lcObjectPropertyId::PieceColor:
return GetColorIndex();
case lcObjectPropertyId::PieceStepShow:
case lcObjectPropertyId::PieceStepHide:
case lcObjectPropertyId::CameraName:
case lcObjectPropertyId::CameraType:
case lcObjectPropertyId::CameraFOV:
case lcObjectPropertyId::CameraNear:
case lcObjectPropertyId::CameraFar:
case lcObjectPropertyId::CameraPositionX:
case lcObjectPropertyId::CameraPositionY:
case lcObjectPropertyId::CameraPositionZ:
case lcObjectPropertyId::CameraTargetX:
case lcObjectPropertyId::CameraTargetY:
case lcObjectPropertyId::CameraTargetZ:
case lcObjectPropertyId::CameraUpX:
case lcObjectPropertyId::CameraUpY:
case lcObjectPropertyId::CameraUpZ:
case lcObjectPropertyId::LightName:
case lcObjectPropertyId::LightType:
case lcObjectPropertyId::LightColor:
case lcObjectPropertyId::LightBlenderPower:
case lcObjectPropertyId::LightPOVRayPower:
case lcObjectPropertyId::LightCastShadow:
case lcObjectPropertyId::LightPOVRayFadeDistance:
case lcObjectPropertyId::LightPOVRayFadePower:
case lcObjectPropertyId::LightPointBlenderRadius:
case lcObjectPropertyId::LightSpotBlenderRadius:
case lcObjectPropertyId::LightDirectionalBlenderAngle:
case lcObjectPropertyId::LightAreaSizeX:
case lcObjectPropertyId::LightAreaSizeY:
case lcObjectPropertyId::LightSpotConeAngle:
case lcObjectPropertyId::LightSpotPenumbraAngle:
case lcObjectPropertyId::LightSpotPOVRayTightness:
case lcObjectPropertyId::LightAreaShape:
case lcObjectPropertyId::LightAreaPOVRayGridX:
case lcObjectPropertyId::LightAreaPOVRayGridY:
case lcObjectPropertyId::ObjectPositionX:
case lcObjectPropertyId::ObjectPositionY:
case lcObjectPropertyId::ObjectPositionZ:
case lcObjectPropertyId::ObjectRotationX:
case lcObjectPropertyId::ObjectRotationY:
case lcObjectPropertyId::ObjectRotationZ:
case lcObjectPropertyId::Count:
break;
}
2024-02-19 23:54:45 +01:00
return QVariant();
}
2024-02-19 23:54:45 +01:00
bool lcPiece::SetPropertyValue(lcObjectPropertyId PropertyId, lcStep Step, bool AddKey, QVariant Value)
{
2024-02-19 23:54:45 +01:00
Q_UNUSED(Step);
Q_UNUSED(AddKey);
switch (PropertyId)
{
case lcObjectPropertyId::PieceId:
return SetPieceId(static_cast<PieceInfo*>(Value.value<void*>()));
case lcObjectPropertyId::PieceColor:
return SetColorIndex(Value.toInt());
case lcObjectPropertyId::PieceStepShow:
case lcObjectPropertyId::PieceStepHide:
case lcObjectPropertyId::CameraName:
case lcObjectPropertyId::CameraType:
case lcObjectPropertyId::CameraFOV:
case lcObjectPropertyId::CameraNear:
case lcObjectPropertyId::CameraFar:
case lcObjectPropertyId::CameraPositionX:
case lcObjectPropertyId::CameraPositionY:
case lcObjectPropertyId::CameraPositionZ:
case lcObjectPropertyId::CameraTargetX:
case lcObjectPropertyId::CameraTargetY:
case lcObjectPropertyId::CameraTargetZ:
case lcObjectPropertyId::CameraUpX:
case lcObjectPropertyId::CameraUpY:
case lcObjectPropertyId::CameraUpZ:
case lcObjectPropertyId::LightName:
case lcObjectPropertyId::LightType:
case lcObjectPropertyId::LightColor:
case lcObjectPropertyId::LightBlenderPower:
case lcObjectPropertyId::LightPOVRayPower:
case lcObjectPropertyId::LightCastShadow:
case lcObjectPropertyId::LightPOVRayFadeDistance:
case lcObjectPropertyId::LightPOVRayFadePower:
case lcObjectPropertyId::LightPointBlenderRadius:
case lcObjectPropertyId::LightSpotBlenderRadius:
case lcObjectPropertyId::LightDirectionalBlenderAngle:
case lcObjectPropertyId::LightAreaSizeX:
case lcObjectPropertyId::LightAreaSizeY:
case lcObjectPropertyId::LightSpotConeAngle:
case lcObjectPropertyId::LightSpotPenumbraAngle:
case lcObjectPropertyId::LightSpotPOVRayTightness:
case lcObjectPropertyId::LightAreaShape:
case lcObjectPropertyId::LightAreaPOVRayGridX:
case lcObjectPropertyId::LightAreaPOVRayGridY:
case lcObjectPropertyId::ObjectPositionX:
case lcObjectPropertyId::ObjectPositionY:
case lcObjectPropertyId::ObjectPositionZ:
case lcObjectPropertyId::ObjectRotationX:
case lcObjectPropertyId::ObjectRotationY:
case lcObjectPropertyId::ObjectRotationZ:
case lcObjectPropertyId::Count:
break;
}
return false;
}
2024-01-15 02:41:01 +01:00
bool lcPiece::HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const
{
switch (PropertyId)
{
case lcObjectPropertyId::PieceId:
case lcObjectPropertyId::PieceColor:
case lcObjectPropertyId::PieceStepShow:
case lcObjectPropertyId::PieceStepHide:
case lcObjectPropertyId::CameraName:
case lcObjectPropertyId::CameraType:
case lcObjectPropertyId::CameraFOV:
case lcObjectPropertyId::CameraNear:
case lcObjectPropertyId::CameraFar:
case lcObjectPropertyId::CameraPositionX:
case lcObjectPropertyId::CameraPositionY:
case lcObjectPropertyId::CameraPositionZ:
case lcObjectPropertyId::CameraTargetX:
case lcObjectPropertyId::CameraTargetY:
case lcObjectPropertyId::CameraTargetZ:
case lcObjectPropertyId::CameraUpX:
case lcObjectPropertyId::CameraUpY:
case lcObjectPropertyId::CameraUpZ:
case lcObjectPropertyId::LightName:
case lcObjectPropertyId::LightType:
case lcObjectPropertyId::LightColor:
case lcObjectPropertyId::LightBlenderPower:
case lcObjectPropertyId::LightPOVRayPower:
2024-01-15 02:41:01 +01:00
case lcObjectPropertyId::LightCastShadow:
case lcObjectPropertyId::LightPOVRayFadeDistance:
case lcObjectPropertyId::LightPOVRayFadePower:
case lcObjectPropertyId::LightPointBlenderRadius:
case lcObjectPropertyId::LightSpotBlenderRadius:
case lcObjectPropertyId::LightDirectionalBlenderAngle:
2024-01-15 02:41:01 +01:00
case lcObjectPropertyId::LightAreaSizeX:
case lcObjectPropertyId::LightAreaSizeY:
case lcObjectPropertyId::LightSpotConeAngle:
case lcObjectPropertyId::LightSpotPenumbraAngle:
case lcObjectPropertyId::LightSpotPOVRayTightness:
2024-01-15 02:41:01 +01:00
case lcObjectPropertyId::LightAreaShape:
case lcObjectPropertyId::LightAreaPOVRayGridX:
case lcObjectPropertyId::LightAreaPOVRayGridY:
2024-01-15 02:41:01 +01:00
return false;
case lcObjectPropertyId::ObjectPositionX:
case lcObjectPropertyId::ObjectPositionY:
case lcObjectPropertyId::ObjectPositionZ:
return mPosition.HasKeyFrame(Time);
case lcObjectPropertyId::ObjectRotationX:
case lcObjectPropertyId::ObjectRotationY:
case lcObjectPropertyId::ObjectRotationZ:
return mRotation.HasKeyFrame(Time);
case lcObjectPropertyId::Count:
return false;
}
return false;
}
2024-01-21 21:53:18 +01:00
bool lcPiece::SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame)
{
switch (PropertyId)
{
case lcObjectPropertyId::PieceId:
case lcObjectPropertyId::PieceColor:
case lcObjectPropertyId::PieceStepShow:
case lcObjectPropertyId::PieceStepHide:
case lcObjectPropertyId::CameraName:
case lcObjectPropertyId::CameraType:
case lcObjectPropertyId::CameraFOV:
case lcObjectPropertyId::CameraNear:
case lcObjectPropertyId::CameraFar:
case lcObjectPropertyId::CameraPositionX:
case lcObjectPropertyId::CameraPositionY:
case lcObjectPropertyId::CameraPositionZ:
case lcObjectPropertyId::CameraTargetX:
case lcObjectPropertyId::CameraTargetY:
case lcObjectPropertyId::CameraTargetZ:
case lcObjectPropertyId::CameraUpX:
case lcObjectPropertyId::CameraUpY:
case lcObjectPropertyId::CameraUpZ:
case lcObjectPropertyId::LightName:
case lcObjectPropertyId::LightType:
case lcObjectPropertyId::LightColor:
case lcObjectPropertyId::LightBlenderPower:
case lcObjectPropertyId::LightPOVRayPower:
2024-01-21 21:53:18 +01:00
case lcObjectPropertyId::LightCastShadow:
case lcObjectPropertyId::LightPOVRayFadeDistance:
case lcObjectPropertyId::LightPOVRayFadePower:
case lcObjectPropertyId::LightPointBlenderRadius:
case lcObjectPropertyId::LightSpotBlenderRadius:
case lcObjectPropertyId::LightDirectionalBlenderAngle:
2024-01-21 21:53:18 +01:00
case lcObjectPropertyId::LightAreaSizeX:
case lcObjectPropertyId::LightAreaSizeY:
case lcObjectPropertyId::LightSpotConeAngle:
case lcObjectPropertyId::LightSpotPenumbraAngle:
case lcObjectPropertyId::LightSpotPOVRayTightness:
2024-01-21 21:53:18 +01:00
case lcObjectPropertyId::LightAreaShape:
case lcObjectPropertyId::LightAreaPOVRayGridX:
case lcObjectPropertyId::LightAreaPOVRayGridY:
2024-01-21 21:53:18 +01:00
return false;
case lcObjectPropertyId::ObjectPositionX:
case lcObjectPropertyId::ObjectPositionY:
case lcObjectPropertyId::ObjectPositionZ:
return mPosition.SetKeyFrame(Time, KeyFrame);
case lcObjectPropertyId::ObjectRotationX:
case lcObjectPropertyId::ObjectRotationY:
case lcObjectPropertyId::ObjectRotationZ:
return mRotation.SetKeyFrame(Time, KeyFrame);
case lcObjectPropertyId::Count:
return false;
}
return false;
}
void lcPiece::RemoveKeyFrames()
{
mPosition.RemoveAllKeys();
mRotation.RemoveAllKeys();
}
2020-12-05 20:02:10 +01:00
void lcPiece::AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const
2016-02-19 18:53:54 +01:00
{
2020-01-02 02:06:17 +01:00
lcRenderMeshState RenderMeshState = lcRenderMeshState::Default;
bool ParentActive = false;
2016-02-19 18:53:54 +01:00
if (Highlight)
RenderMeshState = lcRenderMeshState::Highlighted;
2020-01-02 02:06:17 +01:00
if (Fade)
RenderMeshState = lcRenderMeshState::Faded;
2020-12-05 20:02:10 +01:00
if (Scene->GetDrawInterface())
2016-02-19 18:53:54 +01:00
{
2021-11-15 03:34:24 +01:00
const lcPiece* ActiveSubmodelInstance = Scene->GetActiveSubmodelInstance();
2016-02-19 18:53:54 +01:00
if (!ActiveSubmodelInstance)
2020-01-02 02:06:17 +01:00
RenderMeshState = IsFocused() ? lcRenderMeshState::Focused : (IsSelected() ? lcRenderMeshState::Selected : RenderMeshState);
else if (ActiveSubmodelInstance == this)
ParentActive = true;
else
2020-01-02 02:06:17 +01:00
RenderMeshState = lcRenderMeshState::Faded;
}
2016-02-19 18:53:54 +01:00
if (!mMesh)
mPieceInfo->AddRenderMeshes(Scene, mModelWorld, mColorIndex, RenderMeshState, ParentActive);
2016-02-19 18:53:54 +01:00
else
2020-12-05 20:02:10 +01:00
Scene->AddMesh(mMesh, mModelWorld, mColorIndex, RenderMeshState);
2016-02-19 18:53:54 +01:00
2020-01-02 02:06:17 +01:00
if (RenderMeshState == lcRenderMeshState::Focused || RenderMeshState == lcRenderMeshState::Selected)
2020-12-05 20:02:10 +01:00
Scene->AddInterfaceObject(this);
2016-02-19 18:53:54 +01:00
}
2020-12-05 20:02:10 +01:00
void lcPiece::AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
{
int ColorIndex = mColorIndex;
if (ColorIndex == gDefaultColor)
ColorIndex = DefaultColorIndex;
2021-11-15 03:34:24 +01:00
const lcPiece* ActiveSubmodelInstance = Scene->GetActiveSubmodelInstance();
if (ActiveSubmodelInstance == this)
2020-01-02 02:06:17 +01:00
RenderMeshState = lcRenderMeshState::Default;
else if (ParentActive)
2020-01-02 02:06:17 +01:00
RenderMeshState = IsFocused() ? lcRenderMeshState::Focused : (IsSelected() ? lcRenderMeshState::Selected : lcRenderMeshState::Default);
if (!mMesh)
mPieceInfo->AddRenderMeshes(Scene, lcMul(mModelWorld, WorldMatrix), ColorIndex, RenderMeshState, ActiveSubmodelInstance == this);
else
2020-12-05 20:02:10 +01:00
Scene->AddMesh(mMesh, lcMul(mModelWorld, WorldMatrix), ColorIndex, RenderMeshState);
2020-01-02 02:06:17 +01:00
if (ParentActive && (RenderMeshState == lcRenderMeshState::Focused || RenderMeshState == lcRenderMeshState::Selected))
2020-12-05 20:02:10 +01:00
Scene->AddInterfaceObject(this);
}
void lcPiece::SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const
{
mPieceInfo->CompareBoundingBox(lcMul(mModelWorld, WorldMatrix), Min, Max);
}
void lcPiece::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
{
if (!mMesh)
mPieceInfo->AddSubModelBoundingBoxPoints(lcMul(mModelWorld, WorldMatrix), Points);
else
{
lcVector3 BoxPoints[8];
lcGetBoxCorners(mMesh->mBoundingBox, BoxPoints);
for (int i = 0; i < 8; i++)
Points.emplace_back(lcMul31(BoxPoints[i], mModelWorld));
}
}
void lcPiece::MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance)
2011-09-07 23:06:51 +02:00
{
2021-11-15 03:34:24 +01:00
const quint32 Section = GetFocusSection();
if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID)
{
2021-11-15 03:34:24 +01:00
const lcVector3 Position = mModelWorld.GetTranslation() + Distance;
2011-09-07 23:06:51 +02:00
2015-12-16 01:28:40 +01:00
SetPosition(Position, Step, AddKey);
2015-12-16 01:28:40 +01:00
mModelWorld.SetTranslation(Position);
}
2024-05-12 21:45:15 +02:00
else if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST)
{
2024-05-12 21:45:15 +02:00
const quint32 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
2024-05-12 21:45:15 +02:00
if (ControlPointIndex < mControlPoints.size())
{
2021-11-15 03:34:24 +01:00
const lcMatrix33 InverseWorldMatrix = lcMatrix33AffineInverse(lcMatrix33(mModelWorld));
lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform;
Transform.SetTranslation(Transform.GetTranslation() + lcMul(Distance, InverseWorldMatrix));
}
2016-02-19 18:53:54 +01:00
UpdateMesh();
}
2011-09-07 23:06:51 +02:00
}
2015-12-16 01:28:40 +01:00
void lcPiece::Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame)
2015-12-15 02:57:22 +01:00
{
2021-11-15 03:34:24 +01:00
const quint32 Section = GetFocusSection();
if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID)
{
lcVector3 Distance = mModelWorld.GetTranslation() - Center;
2021-11-15 03:34:24 +01:00
const lcMatrix33 LocalToWorldMatrix = lcMatrix33(mModelWorld);
2021-11-15 03:34:24 +01:00
const lcMatrix33 LocalToFocusMatrix = lcMul(LocalToWorldMatrix, RotationFrame);
lcMatrix33 NewLocalToWorldMatrix = lcMul(LocalToFocusMatrix, RotationMatrix);
2021-11-15 03:34:24 +01:00
const lcMatrix33 WorldToLocalMatrix = lcMatrix33AffineInverse(LocalToWorldMatrix);
Distance = lcMul(Distance, WorldToLocalMatrix);
Distance = lcMul(Distance, NewLocalToWorldMatrix);
2015-12-16 01:28:40 +01:00
NewLocalToWorldMatrix.Orthonormalize();
SetPosition(Center + Distance, Step, AddKey);
SetRotation(NewLocalToWorldMatrix, Step, AddKey);
}
2024-05-12 21:45:15 +02:00
else if (Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST)
{
2024-05-12 21:45:15 +02:00
const quint32 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
2015-12-16 01:28:40 +01:00
2024-05-12 21:45:15 +02:00
if (ControlPointIndex < mControlPoints.size())
{
lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform;
2021-11-15 03:34:24 +01:00
const lcMatrix33 PieceWorldMatrix(mModelWorld);
const lcMatrix33 LocalToWorldMatrix = lcMul(lcMatrix33(Transform), PieceWorldMatrix);
2015-12-16 01:28:40 +01:00
2021-11-15 03:34:24 +01:00
const lcMatrix33 LocalToFocusMatrix = lcMul(LocalToWorldMatrix, RotationFrame);
lcMatrix33 NewLocalToWorldMatrix = lcMul(lcMul(LocalToFocusMatrix, RotationMatrix), lcMatrix33AffineInverse(PieceWorldMatrix));
2015-12-16 01:28:40 +01:00
NewLocalToWorldMatrix.Orthonormalize();
Transform = lcMatrix44(NewLocalToWorldMatrix, Transform.GetTranslation());
}
2015-12-16 01:28:40 +01:00
UpdateMesh();
}
2015-12-16 01:28:40 +01:00
}
void lcPiece::MovePivotPoint(const lcVector3& Distance)
{
if (!IsFocused(LC_PIECE_SECTION_POSITION))
return;
mPivotMatrix.SetTranslation(mPivotMatrix.GetTranslation() + lcMul30(Distance, lcMatrix44AffineInverse(mModelWorld)));
mPivotPointValid = true;
2015-12-16 01:28:40 +01:00
}
void lcPiece::RotatePivotPoint(const lcMatrix33& RotationMatrix)
{
if (!IsFocused(LC_PIECE_SECTION_POSITION))
return;
2015-12-15 02:57:22 +01:00
lcMatrix33 NewPivotRotationMatrix = lcMul(RotationMatrix, lcMatrix33(mPivotMatrix));
NewPivotRotationMatrix.Orthonormalize();
mPivotMatrix = lcMatrix44(NewPivotRotationMatrix, mPivotMatrix.GetTranslation());
mPivotPointValid = true;
2015-12-15 02:57:22 +01:00
}
2017-12-02 21:22:04 +01:00
quint32 lcPiece::GetAllowedTransforms() const
{
2021-11-15 03:34:24 +01:00
const quint32 Section = GetFocusSection();
if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID)
2023-09-04 19:59:16 +02:00
return LC_OBJECT_TRANSFORM_MOVE_XYZ | LC_OBJECT_TRANSFORM_ROTATE_XYZ;
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo();
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
if (SynthInfo)
{
if (SynthInfo->IsUnidirectional())
return LC_OBJECT_TRANSFORM_MOVE_Z;
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
if (SynthInfo->IsCurve())
2023-09-04 19:59:16 +02:00
return LC_OBJECT_TRANSFORM_MOVE_XYZ | LC_OBJECT_TRANSFORM_ROTATE_XYZ | LC_OBJECT_TRANSFORM_SCALE_X;
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
if (SynthInfo->IsNondirectional())
2023-09-04 19:59:16 +02:00
return LC_OBJECT_TRANSFORM_MOVE_XYZ;
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
}
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
{
2024-05-12 21:45:15 +02:00
if (mControlPoints.size() >= LC_MAX_CONTROL_POINTS)
return false;
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo();
return SynthInfo && SynthInfo->CanAddControlPoints();
}
bool lcPiece::CanRemoveControlPoint() const
{
2021-11-15 03:34:24 +01:00
const quint32 Section = GetFocusSection();
2024-05-12 21:45:15 +02:00
return Section >= LC_PIECE_SECTION_CONTROL_POINT_FIRST && Section <= LC_PIECE_SECTION_CONTROL_POINT_LAST && mControlPoints.size() > 2;
}
bool lcPiece::InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd)
{
if (!CanAddControlPoint())
return false;
2021-11-15 03:34:24 +01:00
const lcMatrix44 InverseWorldMatrix = lcMatrix44AffineInverse(mModelWorld);
const lcVector3 Start = lcMul31(WorldStart, InverseWorldMatrix);
const lcVector3 End = lcMul31(WorldEnd, InverseWorldMatrix);
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo();
const int ControlPointIndex = SynthInfo->InsertControlPoint(mControlPoints, Start, End);
if (ControlPointIndex)
{
SetFocused(GetFocusSection(), false);
SetFocused(LC_PIECE_SECTION_CONTROL_POINT_FIRST + ControlPointIndex, true);
UpdateMesh();
return true;
}
return false;
}
bool lcPiece::RemoveFocusedControlPoint()
{
2024-05-12 21:45:15 +02:00
quint32 Section = GetFocusSection();
if( Section < LC_PIECE_SECTION_CONTROL_POINT_FIRST )
return false;
const quint32 ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
2024-05-12 21:45:15 +02:00
if (ControlPointIndex >= mControlPoints.size() || mControlPoints.size() <= 2)
return false;
SetFocused(GetFocusSection(), false);
SetFocused(LC_PIECE_SECTION_POSITION, true);
2024-05-12 21:45:15 +02:00
mControlPoints.erase(mControlPoints.begin() + ControlPointIndex);
UpdateMesh();
return true;
}
2024-05-12 21:45:15 +02:00
void lcPiece::VerifyControlPoints(std::vector<lcPieceControlPoint>& ControlPoints) const
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
{
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo();
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
if (!SynthInfo)
{
2024-05-12 21:45:15 +02:00
ControlPoints.clear();
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
}
else
{
2024-05-12 21:45:15 +02:00
if (ControlPoints.size() > LC_MAX_CONTROL_POINTS)
ControlPoints.resize(LC_MAX_CONTROL_POINTS);
Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints.
2020-03-30 21:17:08 +02:00
SynthInfo->VerifyControlPoints(ControlPoints);
}
}
2020-12-14 01:27:21 +01:00
QString lcPiece::GetName() const
{
2020-12-14 01:27:21 +01:00
return QString::fromLatin1(mPieceInfo->m_strDescription);
}
2019-03-13 03:51:04 +01:00
bool lcPiece::IsVisible(lcStep Step) const
2011-09-07 23:06:51 +02:00
{
return !mHidden && (mStepShow <= Step) && (mStepHide > Step || mStepHide == LC_STEP_MAX);
2011-09-07 23:06:51 +02:00
}
2019-03-13 03:51:04 +01:00
bool lcPiece::IsVisibleInSubModel() const
{
return (mStepHide == LC_STEP_MAX) && !mHidden;
2019-03-13 03:51:04 +01:00
}
2019-05-28 01:39:51 +02:00
void lcPiece::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const
{
if (!IsVisibleInSubModel())
return;
int ColorIndex = mColorIndex;
if (ColorIndex == gDefaultColor)
ColorIndex = DefaultColorIndex;
if (!mMesh)
mPieceInfo->GetModelParts(lcMul(mModelWorld, WorldMatrix), ColorIndex, ModelParts);
else
ModelParts.emplace_back(lcModelPartsEntry{ lcMul(mModelWorld, WorldMatrix), mPieceInfo, mMesh, ColorIndex });
}
2016-02-19 18:53:54 +01:00
const lcBoundingBox& lcPiece::GetBoundingBox() const
2011-09-07 23:06:51 +02:00
{
2016-02-19 18:53:54 +01:00
if (!mMesh)
return mPieceInfo->GetBoundingBox();
else
return mMesh->mBoundingBox;
}
void lcPiece::CompareBoundingBox(lcVector3& Min, lcVector3& Max) const
{
if (!mMesh)
mPieceInfo->CompareBoundingBox(mModelWorld, Min, Max);
2016-02-19 18:53:54 +01:00
else
{
lcVector3 Points[8];
2016-02-19 18:53:54 +01:00
lcGetBoxCorners(mMesh->mBoundingBox, Points);
for (int i = 0; i < 8; i++)
{
2021-11-15 03:34:24 +01:00
const lcVector3 Point = lcMul31(Points[i], mModelWorld);
Min = lcMin(Point, Min);
Max = lcMax(Point, Max);
}
2011-09-07 23:06:51 +02:00
}
}
2014-05-25 20:23:09 +02:00
lcGroup* lcPiece::GetTopGroup()
2011-09-07 23:06:51 +02:00
{
return mGroup ? mGroup->GetTopGroup() : nullptr;
2011-09-07 23:06:51 +02:00
}
2014-07-06 08:04:09 +02:00
void lcPiece::UpdatePosition(lcStep Step)
2011-09-07 23:06:51 +02:00
{
2023-12-28 19:21:52 +01:00
mPosition.Update(Step);
mRotation.Update(Step);
2023-12-28 19:21:52 +01:00
mModelWorld = lcMatrix44(mRotation, mPosition);
2011-09-07 23:06:51 +02:00
}
2016-02-19 18:53:54 +01:00
void lcPiece::UpdateMesh()
{
delete mMesh;
2021-11-15 03:34:24 +01:00
const lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo();
mMesh = SynthInfo ? SynthInfo->CreateMesh(mControlPoints) : nullptr;
2016-02-19 18:53:54 +01:00
}