Allow outputs with missing geometry and fit available meshes

This commit is contained in:
Leonardo Zide committed 2026-10-04 13:57:35 -07:00
1 parent dcd2ef5a3b
commit 8ceceb95ba
14 files changed
+192 -237

No files matched your search

+2 -9
View File
@@ -1139,14 +1139,7 @@ lcStartupMode lcApplication::Initialize(const QList<QPair<QString, bool>>& Libra
if (Options.SetHighlightColor)
mPreferences.mHighlightNewPartsColor = Options.HighlightColor;
const lcResult<void> Ready = ActiveModel->EnsureAssetsReady();
if (!Ready)
{
StdErr << Ready.error() << '\n';
return lcStartupMode::Error;
}
ActiveModel->WaitForAssets();
const bool UsesCameraPosition = Options.SetCameraPosition && Options.Viewpoint == lcViewpoint::Count && !Options.SetCameraAngles;
@@ -1154,7 +1147,7 @@ lcStartupMode lcApplication::Initialize(const QList<QPair<QString, bool>>& Libra
{
const lcStep FitStep = Options.ImageStart == Options.ImageEnd ? Options.ImageStart : ActiveModel->GetLastStep();
ActiveModel->ZoomExtentsAtStep(ActiveView->GetCamera(), (float)ActiveView->GetWidth() / (float)ActiveView->GetHeight(), FitStep);
ActiveModel->ZoomExtentsAtStep(ActiveView->GetCamera(), (float)ActiveView->GetWidth() / (float)ActiveView->GetHeight(), FitStep, lcGeometryBoundsMode::AvailableGeometryOnly);
}
auto ProgressCallback = [&StdOut](const QString& FileName)
+6
View File
@@ -63,6 +63,12 @@ class QPrinter;
typedef quint32 lcStep;
#define LC_STEP_MAX 0xffffffff
enum class lcGeometryBoundsMode
{
IncludeFallbackGeometry,
AvailableGeometryOnly
};
// Version number.
#define LC_VERSION_MAJOR 26
#define LC_VERSION_MINOR 9
+1 -1
View File
@@ -65,7 +65,7 @@ void lcInstructionsPartsListItem::Update()
QFont Font = mInstructions->GetFontProperty(lcInstructionsPropertyType::PLIFont, mModel, mStep);
QColor TextColor = mInstructions->GetColorProperty(lcInstructionsPropertyType::PLITextColor, mModel, mStep);
QImage PartsImage = mModel->GetPartsListImage(300, mStep, lcRGBAFromQColor(BackgroundColor), Font, TextColor);
QImage PartsImage = mModel->GetPartsListImage(300, mStep, lcRGBAFromQColor(BackgroundColor), Font, TextColor, false);
setPixmap(QPixmap::fromImage(PartsImage));
}
+3 -21
View File
@@ -1347,13 +1347,7 @@ void lcMainWindow::ProjectFileChanged(const QString& Path)
void lcMainWindow::Print(QPrinter* Printer)
{
#ifndef QT_NO_PRINTER
const lcResult<void> Ready = lcGetActiveProject()->EnsureAssetsReady();
if (!Ready)
{
QMessageBox::warning(this, tr("LeoCAD"), Ready.error());
return;
}
lcGetActiveProject()->GetMainModel()->WaitForAssets();
int DocCopies;
int PageCopies;
@@ -1521,13 +1515,7 @@ void lcMainWindow::ShowRenderDialog(lcRenderDialogMode RenderDialogMode)
void lcMainWindow::ShowInstructionsDialog()
{
const lcResult<void> Ready = lcGetActiveProject()->EnsureAssetsReady();
if (!Ready)
{
QMessageBox::warning(this, tr("LeoCAD"), Ready.error());
return;
}
lcGetActiveProject()->GetMainModel()->WaitForAssets();
lcInstructionsDialog* Dialog = new lcInstructionsDialog(this, lcGetActiveProject());
Dialog->setWindowModality(Qt::ApplicationModal);
@@ -1537,13 +1525,7 @@ void lcMainWindow::ShowInstructionsDialog()
void lcMainWindow::ShowPrintDialog()
{
const lcResult<void> Ready = lcGetActiveProject()->EnsureAssetsReady();
if (!Ready)
{
QMessageBox::warning(this, tr("LeoCAD"), Ready.error());
return;
}
lcGetActiveProject()->GetMainModel()->WaitForAssets();
#ifndef QT_NO_PRINTER
int PageCount = static_cast<int>(lcGetActiveProject()->GetInstructions()->mPages.size());
+94 -86
View File
@@ -513,42 +513,13 @@ std::vector<lcPiece*> lcModel::GetRequiredSynthPieces() const
return Required;
}
lcResult<void> lcModel::EnsureAssetsReady() const
void lcModel::WaitForAssets() const
{
const std::vector<PieceInfo*> Required = GetRequiredPieces();
lcPiecesLibrary* Library = lcGetPiecesLibrary();
if (!Library->EnsurePiecesReady(Required))
{
for (const PieceInfo* Info : Required)
{
if (Info->mState != lcPieceInfoState::Failed)
continue;
const QString Error = Library->GetPieceLoadError(Info);
if (!Error.isEmpty())
return lcUnexpected(Error);
}
return lcUnexpected(tr("Could not load all required pieces."));
}
const std::vector<lcPiece*> GeneratedPieces = GetRequiredSynthPieces();
if (!Library->EnsureSynthMeshesReady(GeneratedPieces))
{
for (const lcPiece* Piece : GeneratedPieces)
if (!Piece->HasGeneratedMesh())
{
QString Error = Library->GetSynthMeshError(Piece);
if (Error.isEmpty())
Error = tr("Could not generate geometry for piece '%1'.").arg(QString::fromLatin1(Piece->mPieceInfo->mFileName));
return lcUnexpected(Error);
}
}
Library->EnsurePiecesReady(Required);
Library->EnsureSynthMeshesReady(GetRequiredSynthPieces());
// Temporary minifigure and thumbnail models have no container piece to update.
if (mPieceInfo)
@@ -556,6 +527,40 @@ lcResult<void> lcModel::EnsureAssetsReady() const
std::vector<lcModel*> UpdatedModels;
const_cast<lcModel*>(this)->UpdatePieceInfo(UpdatedModels);
}
}
lcResult<void> lcModel::EnsureAssetsReady() const
{
WaitForAssets();
const std::vector<PieceInfo*> Required = GetRequiredPieces();
lcPiecesLibrary* Library = lcGetPiecesLibrary();
for (const PieceInfo* Info : Required)
{
if (Info->mState == lcPieceInfoState::Loaded)
continue;
const QString Error = Library->GetPieceLoadError(Info);
if (!Error.isEmpty())
return lcUnexpected(Error);
return lcUnexpected(tr("Could not load all required pieces."));
}
const std::vector<lcPiece*> GeneratedPieces = GetRequiredSynthPieces();
for (const lcPiece* Piece : GeneratedPieces)
if (!Piece->HasGeneratedMesh())
{
QString Error = Library->GetSynthMeshError(Piece);
if (Error.isEmpty())
Error = tr("Could not generate geometry for piece '%1'.").arg(QString::fromLatin1(Piece->mPieceInfo->mFileName));
return lcUnexpected(Error);
}
return lcResult<void>();
}
@@ -1690,15 +1695,7 @@ void lcModel::AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMat
QImage lcModel::GetStepImage(bool Zoom, int Width, int Height, lcStep Step)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
{
if (gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), Ready.error());
return QImage();
}
WaitForAssets();
const lcResult<QImage> Image = RenderStepImageWithReadyAssets(Zoom, Width, Height, Step, nullptr);
@@ -1729,12 +1726,12 @@ lcResult<QImage> lcModel::RenderStepImageWithReadyAssets(bool Zoom, int Width, i
View.MakeCurrent();
if (!OutputCamera && !ActiveView)
ZoomExtentsAtStep(View.GetCamera(), (float)Width / (float)Height, GetLastStep());
ZoomExtentsAtStep(View.GetCamera(), (float)Width / (float)Height, GetLastStep(), lcGeometryBoundsMode::AvailableGeometryOnly);
SetTemporaryStep(Step);
if (Zoom && ActiveView && !OutputCamera)
ZoomExtents(View.GetCamera(), (float)Width / (float)Height, lcMatrix44Identity());
ZoomExtents(View.GetCamera(), (float)Width / (float)Height, lcMatrix44Identity(), lcGeometryBoundsMode::AvailableGeometryOnly);
if (!View.BeginRenderToImage(Width, Height))
{
@@ -1748,12 +1745,7 @@ lcResult<QImage> lcModel::RenderStepImageWithReadyAssets(bool Zoom, int Width, i
View.OnDraw();
QImage Image;
const bool MissingAssets = View.HasMissingAssets();
if (!MissingAssets)
Image = View.GetRenderImage();
QImage Image = View.GetRenderImage();
View.EndRenderToImage();
@@ -1762,23 +1754,15 @@ lcResult<QImage> lcModel::RenderStepImageWithReadyAssets(bool Zoom, int Width, i
if (!mActive)
CalculateStep(LC_STEP_MAX);
if (MissingAssets || Image.isNull())
return lcUnexpected(tr("Could not render all required pieces."));
if (Image.isNull())
return lcUnexpected(tr("Error creating images."));
return Image;
}
QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundColor, QFont Font, QColor TextColor) const
QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundColor, QFont Font, QColor TextColor, bool KeepMissingParts) const
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
{
if (gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), Ready.error());
return QImage();
}
WaitForAssets();
lcPartsList PartsList;
@@ -1804,6 +1788,11 @@ QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundC
for (const auto& PartIt : PartsList)
{
const PieceInfo* Info = PartIt.first;
if (!KeepMissingParts && !Info->IsModel() && !Info->IsProject() && (Info->mState != lcPieceInfoState::Loaded || !Info->GetMesh()))
continue;
for (const auto& ColorIt : PartIt.second)
{
Images.push_back(lcPartsListImage());
@@ -1814,6 +1803,13 @@ QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundC
}
}
if (Images.empty())
{
QImage Image(1, 1, QImage::Format_ARGB32);
Image.fill(lcQColorFromRGBA(BackgroundColor));
return Image;
}
auto ImageCompare = [](const lcPartsListImage& Image1, const lcPartsListImage& Image2)
{
if (Image1.ColorIndex != Image2.ColorIndex)
@@ -1898,18 +1894,6 @@ QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundC
Scene.End();
if (Scene.HasMissingAssets())
{
View.UnbindRenderFramebuffer();
View.EndRenderToImage();
Context->ClearResources();
if (gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not render all required pieces."));
return QImage();
}
Scene.Draw(Context);
View.UnbindRenderFramebuffer();
@@ -1949,6 +1933,27 @@ QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundC
QtConcurrent::blockingMap(Images, CalculateImageBounds);
if (KeepMissingParts)
{
for (lcPartsListImage& Image : Images)
if (Image.Bounds.isEmpty())
Image.Bounds = QRect(0, 0, qMin(64, ThumbnailSize), qMin(64, ThumbnailSize));
}
else
{
Images.erase(std::remove_if(Images.begin(), Images.end(), [](const lcPartsListImage& Image)
{
return Image.Bounds.isEmpty();
}), Images.end());
}
if (Images.empty())
{
QImage Image(1, 1, QImage::Format_ARGB32);
Image.fill(lcQColorFromRGBA(BackgroundColor));
return Image;
}
QImage DummyImage(16, 16, QImage::Format_ARGB32);
QPainter DummyPainter(&DummyImage);
@@ -2019,10 +2024,7 @@ QImage lcModel::GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundC
lcResult<void> lcModel::SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, int Width, int Height, lcStep Start, lcStep End)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
return Ready;
WaitForAssets();
lcCamera OutputCamera(true);
lcCamera* Camera = nullptr;
@@ -2030,7 +2032,7 @@ lcResult<void> lcModel::SaveStepImages(const QString& BaseName, bool AddStepSuff
if (!gMainWindow || !gMainWindow->GetActiveView())
{
OutputCamera.SetViewpoint(lcViewpoint::Home);
ZoomExtentsAtStep(&OutputCamera, (float)Width / (float)Height, GetLastStep());
ZoomExtentsAtStep(&OutputCamera, (float)Width / (float)Height, GetLastStep(), lcGeometryBoundsMode::AvailableGeometryOnly);
Camera = &OutputCamera;
}
@@ -2147,10 +2149,13 @@ void lcModel::SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector
Piece->SubModelCompareBoundingBox(WorldMatrix, Min, Max);
}
void lcModel::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
void lcModel::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const
{
const lcMesh* Mesh = mPieceInfo ? mPieceInfo->GetDisplayMesh() : nullptr;
if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded)
Mesh = nullptr;
if (Mesh)
{
lcVector3 Box[8];
@@ -2162,7 +2167,7 @@ void lcModel::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::v
for (const std::unique_ptr<lcPiece>& Piece : mPieces)
if (Piece->IsVisibleInSubModel())
Piece->SubModelAddBoundingBoxPoints(WorldMatrix, Points);
Piece->SubModelAddBoundingBoxPoints(WorldMatrix, Points, Mode);
}
void lcModel::AddSelectionHistory(std::function<void()> Callback)
@@ -4819,11 +4824,14 @@ bool lcModel::GetVisiblePiecesBoundingBox(lcVector3& Min, lcVector3& Max) const
return Valid;
}
std::vector<lcVector3> lcModel::GetPiecesBoundingBoxPoints() const
std::vector<lcVector3> lcModel::GetPiecesBoundingBoxPoints(lcGeometryBoundsMode Mode) const
{
std::vector<lcVector3> Points;
const lcMesh* Mesh = mPieceInfo ? mPieceInfo->GetDisplayMesh() : nullptr;
if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo && mPieceInfo->mState != lcPieceInfoState::Loaded)
Mesh = nullptr;
if (Mesh)
{
lcVector3 Box[8];
@@ -4835,7 +4843,7 @@ std::vector<lcVector3> lcModel::GetPiecesBoundingBoxPoints() const
for (const std::unique_ptr<lcPiece>& Piece : mPieces)
if (Piece->IsSelected() || Piece->IsVisible(mCurrentStep))
Piece->SubModelAddBoundingBoxPoints(lcMatrix44Identity(), Points);
Piece->SubModelAddBoundingBoxPoints(lcMatrix44Identity(), Points, Mode);
return Points;
}
@@ -5995,9 +6003,9 @@ void lcModel::MoveCamera(lcCamera* Camera, const lcVector3& Direction)
}
}
void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix)
void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode)
{
std::vector<lcVector3> Points = GetPiecesBoundingBoxPoints();
std::vector<lcVector3> Points = GetPiecesBoundingBoxPoints(Mode);
if (Points.empty())
return;
@@ -6034,12 +6042,12 @@ void lcModel::ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& Worl
}
}
void lcModel::ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step)
void lcModel::ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step, lcGeometryBoundsMode Mode)
{
const lcStep CurrentStep = mCurrentStep;
SetTemporaryStep(Step);
ZoomExtents(Camera, Aspect, lcMatrix44Identity());
ZoomExtents(Camera, Aspect, lcMatrix44Identity(), Mode);
SetTemporaryStep(CurrentStep);
if (!mActive)
+6 -5
View File
@@ -183,6 +183,7 @@ public:
void RefreshPreview() const;
std::vector<PieceInfo*> GetRequiredPieces() const;
std::vector<lcPiece*> GetRequiredSynthPieces() const;
void WaitForAssets() const;
lcResult<void> EnsureAssetsReady() const;
PieceInfo* GetPieceInfo() const
@@ -331,7 +332,7 @@ public:
void GetScene(lcScene* Scene, const lcCamera* ViewCamera, bool AllowHighlight, bool AllowFade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
QImage GetStepImage(bool Zoom, int Width, int Height, lcStep Step);
QImage GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundColor, QFont Font, QColor TextColor) const;
QImage GetPartsListImage(int MaxWidth, lcStep Step, quint32 BackgroundColor, QFont Font, QColor TextColor, bool KeepMissingParts) const;
lcResult<void> SaveStepImages(const QString& BaseName, bool AddStepSuffix, bool Zoom, int Width, int Height, lcStep Start, lcStep End);
void RayTest(lcObjectRayTest& ObjectRayTest) const;
@@ -339,7 +340,7 @@ public:
bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance, lcPieceInfoRayTest& PieceInfoRayTest) const;
bool SubModelBoxTest(const lcVector4 Planes[6]) const;
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const;
bool HasPieces() const
{
@@ -359,7 +360,7 @@ public:
bool GetSelectionCenter(lcVector3& Center) const;
lcBoundingBox GetAllPiecesBoundingBox() const;
bool GetVisiblePiecesBoundingBox(lcVector3& Min, lcVector3& Max) const;
std::vector<lcVector3> GetPiecesBoundingBoxPoints() const;
std::vector<lcVector3> GetPiecesBoundingBoxPoints(lcGeometryBoundsMode Mode) const;
void GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool AddSubModels, lcPartsList& PartsList) const;
void GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcPartsList& PartsList, bool Cumulative) const;
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
@@ -423,8 +424,8 @@ public:
void ZoomRegionToolClicked(lcView* View, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners);
void LookAt(lcCamera* Camera);
void MoveCamera(lcCamera* Camera, const lcVector3& Direction);
void ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix);
void ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step);
void ZoomExtents(lcCamera* Camera, float Aspect, const lcMatrix44& WorldMatrix, lcGeometryBoundsMode Mode);
void ZoomExtentsAtStep(lcCamera* Camera, float Aspect, lcStep Step, lcGeometryBoundsMode Mode);
void Zoom(lcCamera* Camera, float Amount);
void MoveSelectedObjects(const lcVector3& Distance, lcModelTransformFlags Flags, lcModelHistoryEditMerge ModelHistoryEditMerge)
+7 -22
View File
@@ -722,15 +722,7 @@ std::vector<lcObject*> lcView::FindObjectsInBox(float x1, float y1, float x2, fl
std::vector<QImage> lcView::GetStepImages(lcStep Start, lcStep End)
{
std::vector<QImage> Images;
const lcResult<void> Ready = mModel->EnsureAssetsReady();
if (!Ready)
{
if (gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), Ready.error());
return Images;
}
mModel->WaitForAssets();
if (!BeginRenderToImage(mWidth, mHeight))
{
@@ -741,7 +733,7 @@ std::vector<QImage> lcView::GetStepImages(lcStep Start, lcStep End)
}
const lcStep CurrentStep = mModel->GetCurrentStep();
bool MissingAssets = false;
bool RenderFailed = false;
for (lcStep Step = Start; Step <= End; Step++)
{
@@ -749,18 +741,11 @@ std::vector<QImage> lcView::GetStepImages(lcStep Start, lcStep End)
OnDraw();
if (HasMissingAssets())
{
MissingAssets = true;
Images.clear();
break;
}
QImage Image = GetRenderImage();
if (Image.isNull())
{
MissingAssets = true;
RenderFailed = true;
Images.clear();
break;
}
@@ -775,8 +760,8 @@ std::vector<QImage> lcView::GetStepImages(lcStep Start, lcStep End)
if (!mModel->IsActive())
mModel->CalculateStep(LC_STEP_MAX);
if (MissingAssets && gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Could not render all required pieces."));
if (RenderFailed && gMainWindow)
QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images."));
return Images;
}
@@ -786,7 +771,7 @@ lcResult<void> lcView::SaveStepImages(const QString& BaseName, bool AddStepSuffi
std::vector<QImage> Images = GetStepImages(Start, End);
if (Images.size() != static_cast<size_t>(End - Start + 1))
return lcUnexpected(tr("Could not render all required pieces."));
return lcUnexpected(tr("Error creating images."));
for (lcStep Step = Start; Step <= End; Step++)
{
@@ -1959,7 +1944,7 @@ void lcView::ZoomExtents()
{
const lcMatrix44 WorldMatrix = mActiveSubmodelInstance ? mActiveSubmodelTransform : lcMatrix44Identity();
ActiveModel->ZoomExtents(mCamera, (float)mWidth / (float)mHeight, WorldMatrix);
ActiveModel->ZoomExtents(mCamera, (float)mWidth / (float)mHeight, WorldMatrix, lcGeometryBoundsMode::IncludeFallbackGeometry);
}
}
+11 -2
View File
@@ -1074,7 +1074,10 @@ void lcPiece::AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade
}
if (mPieceInfo->GetSynthInfo() && !HasGeneratedMesh() && Scene->GetRequireGeneratedMeshes())
{
Scene->MarkMissingAssets();
return;
}
if (mSynthPending && Scene->GetRequireCompleteAssets())
Scene->MarkMissingAssets();
@@ -1102,7 +1105,10 @@ void lcPiece::AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMat
RenderMeshState = IsFocused() ? lcRenderMeshState::Focused : (IsSelected() ? lcRenderMeshState::Selected : lcRenderMeshState::Default);
if (mPieceInfo->GetSynthInfo() && !HasGeneratedMesh() && Scene->GetRequireGeneratedMeshes())
{
Scene->MarkMissingAssets();
return;
}
if (mSynthPending && Scene->GetRequireCompleteAssets())
Scene->MarkMissingAssets();
@@ -1137,12 +1143,15 @@ void lcPiece::SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector
}
}
void lcPiece::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
void lcPiece::SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const
{
if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly && mPieceInfo->GetSynthInfo() && !HasGeneratedMesh())
return;
lcMesh* Mesh = GetDisplayMesh();
if (!Mesh || mPieceInfo->IsLoading())
mPieceInfo->AddSubModelBoundingBoxPoints(lcMul(mModelWorld, WorldMatrix), Points);
mPieceInfo->AddSubModelBoundingBoxPoints(lcMul(mModelWorld, WorldMatrix), Points, Mode);
else
{
lcVector3 BoxPoints[8];
+1 -1
View File
@@ -99,7 +99,7 @@ public:
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const;
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
+22 -2
View File
@@ -420,8 +420,28 @@ void PieceInfo::CompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min
}
}
void PieceInfo::AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const
void PieceInfo::AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const
{
if (Mode == lcGeometryBoundsMode::AvailableGeometryOnly)
{
if (IsModel())
{
mModel->SubModelAddBoundingBoxPoints(WorldMatrix, Points, Mode);
return;
}
if (IsProject())
{
if (const lcModel* Model = mProject->GetMainModel())
Model->SubModelAddBoundingBoxPoints(WorldMatrix, Points, Mode);
return;
}
if (mState != lcPieceInfoState::Loaded || !mMesh)
return;
}
if (!IsModel())
{
lcVector3 BoxPoints[8];
@@ -436,7 +456,7 @@ void PieceInfo::AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std:
}
else
{
mModel->SubModelAddBoundingBoxPoints(WorldMatrix, Points);
mModel->SubModelAddBoundingBoxPoints(WorldMatrix, Points, Mode);
}
}
+1 -1
View File
@@ -194,7 +194,7 @@ public:
void GetPartsList(int DefaultColorIndex, bool ScanSubModels, bool AddSubModels, lcPartsList& PartsList) const;
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
void CompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
void AddSubModelBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const;
void UpdateBoundingBox(std::vector<lcModel*>& UpdatedModels);
void Unload();
+36 -77
View File
@@ -1123,13 +1123,15 @@ bool Project::ImportInventory(const std::vector<lcSetInventoryItem>& SetInventor
return true;
}
lcResult<std::vector<lcModelPartsEntry>> Project::GetModelParts()
std::vector<lcModelPartsEntry> Project::GetModelParts()
{
std::vector<lcModelPartsEntry> ModelParts;
if (mModels.empty())
return ModelParts;
mModels[0]->WaitForAssets();
for (const std::unique_ptr<lcModel>& Model : mModels)
Model->CalculateStep(LC_STEP_MAX);
@@ -1137,13 +1139,14 @@ lcResult<std::vector<lcModelPartsEntry>> Project::GetModelParts()
SetActiveModel(mActiveModel, false);
for (const lcModelPartsEntry& ModelPart : ModelParts)
ModelParts.erase(std::remove_if(ModelParts.begin(), ModelParts.end(), [](const lcModelPartsEntry& ModelPart)
{
if (ModelPart.Info->GetSynthInfo() && !ModelPart.Mesh)
return lcUnexpected(tr("Could not generate geometry for piece '%1'.").arg(QString::fromLatin1(ModelPart.Info->mFileName)));
}
return ModelPart.Info->mState != lcPieceInfoState::Loaded ||
(ModelPart.Info->GetSynthInfo() && !ModelPart.Mesh) ||
(!ModelPart.Mesh && !ModelPart.Info->GetMesh());
}), ModelParts.end());
return std::move(ModelParts);
return ModelParts;
}
std::vector<PieceInfo*> Project::GetRequiredPieces() const
@@ -1379,20 +1382,7 @@ QString Project::GetExportFileName(const QString& FileName, const QString& Defau
lcResult<void> Project::Export3DStudio(const QString& FileName)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
return Ready;
const lcResult<std::vector<lcModelPartsEntry>> ModelPartsResult = GetModelParts();
if (!ModelPartsResult)
return lcUnexpected(ModelPartsResult.error());
const std::vector<lcModelPartsEntry>& ModelParts = ModelPartsResult.value();
if (ModelParts.empty())
return lcUnexpected(tr("Nothing to export."));
const std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
QString SaveFileName = GetExportFileName(FileName, "3ds", tr("Export 3D Studio"), tr("3DS Files (*.3ds);;All Files (*.*)"));
@@ -1842,20 +1832,7 @@ lcResult<void> Project::ExportBrickLink()
lcResult<void> Project::ExportCOLLADA(const QString& FileName)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
return Ready;
const lcResult<std::vector<lcModelPartsEntry>> ModelPartsResult = GetModelParts();
if (!ModelPartsResult)
return lcUnexpected(ModelPartsResult.error());
const std::vector<lcModelPartsEntry>& ModelParts = ModelPartsResult.value();
if (ModelParts.empty())
return lcUnexpected(tr("Nothing to export."));
const std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
QString SaveFileName = GetExportFileName(FileName, "dae", tr("Export COLLADA"), tr("COLLADA Files (*.dae);;All Files (*.*)"));
@@ -2209,12 +2186,7 @@ lcResult<void> Project::ExportHTML(const lcHTMLExportOptions& Options)
}
for (const lcModel* Model : Models)
{
const lcResult<void> Ready = Model->EnsureAssetsReady();
if (!Ready)
return Ready;
}
Model->WaitForAssets();
QDir Dir(Options.PathName);
Dir.mkpath(QLatin1String("."));
@@ -2285,7 +2257,7 @@ lcResult<void> Project::ExportHTML(const lcHTMLExportOptions& Options)
if (PartsList.empty())
return lcResult<void>();
QImage Image = Model->GetPartsListImage(1024, Step, LC_RGBA(255, 255, 255, 0), QFont("Arial", 16, QFont::Bold), Qt::black);
QImage Image = Model->GetPartsListImage(1024, Step, LC_RGBA(255, 255, 255, 0), QFont("Arial", 16, QFont::Bold), Qt::black, true);
if (Image.isNull())
return lcUnexpected(tr("Could not render the pieces list image."));
@@ -2493,20 +2465,7 @@ lcResult<void> Project::ExportHTML(const lcHTMLExportOptions& Options)
lcResult<void> Project::ExportPOVRay(const QString& FileName)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
return Ready;
const lcResult<std::vector<lcModelPartsEntry>> ModelPartsResult = GetModelParts();
if (!ModelPartsResult)
return lcUnexpected(ModelPartsResult.error());
const std::vector<lcModelPartsEntry>& ModelParts = ModelPartsResult.value();
if (ModelParts.empty())
return lcUnexpected(tr("Nothing to export."));
const std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
QString SaveFileName = GetExportFileName(FileName, QLatin1String("pov"), tr("Export POV-Ray"), tr("POV-Ray Files (*.pov);;All Files (*.*)"));
@@ -2588,11 +2547,18 @@ lcResult<void> Project::ExportPOVRay(const QString& FileName)
lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX);
lcVector3 Max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
if (ModelParts.empty())
{
Min = lcVector3(-10.0f, -10.0f, -10.0f);
Max = lcVector3(10.0f, 10.0f, 10.0f);
}
for (const lcModelPartsEntry& ModelPart : ModelParts)
{
lcVector3 Points[8];
lcGetBoxCorners(ModelPart.Info->GetBoundingBox(), Points);
const lcMesh* Mesh = ModelPart.Mesh ? ModelPart.Mesh : ModelPart.Info->GetMesh();
lcGetBoxCorners(Mesh->mBoundingBox, Points);
for (int PointIdx = 0; PointIdx < 8; PointIdx++)
{
@@ -3150,8 +3116,11 @@ lcResult<void> Project::ExportPOVRay(const QString& FileName)
POVFile.WriteLine(Line);
}
snprintf(Line, sizeof(Line), "#declare %s = union {\n", TopModelName.toLatin1().constData());
POVFile.WriteLine(Line);
if (!ModelParts.empty())
{
snprintf(Line, sizeof(Line), "#declare %s = union {\n", TopModelName.toLatin1().constData());
POVFile.WriteLine(Line);
}
for (const lcModelPartsEntry& ModelPart : ModelParts)
{
@@ -3205,12 +3174,15 @@ lcResult<void> Project::ExportPOVRay(const QString& FileName)
POVFile.WriteLine(Line);
}
snprintf(Line, sizeof(Line), "\n #if (ModelReflection = 0)\n no_reflection\n #end\n #if (ModelShadow = 0)\n no_shadow\n #end\n}\n\n");
POVFile.WriteLine(Line);
if (!ModelParts.empty())
{
snprintf(Line, sizeof(Line), "\n #if (ModelReflection = 0)\n no_reflection\n #end\n #if (ModelShadow = 0)\n no_shadow\n #end\n}\n\n");
POVFile.WriteLine(Line);
snprintf(Line, sizeof(Line), "object {\n %s\n %s { %s }\n}\n\n",
TopModelName.toLatin1().constData(), (UseLGEO ? "material" : "texture"), ColorTable[lcGetColorIndex(TopModelColorCode)].data());
POVFile.WriteLine(Line);
snprintf(Line, sizeof(Line), "object {\n %s\n %s { %s }\n}\n\n",
TopModelName.toLatin1().constData(), (UseLGEO ? "material" : "texture"), ColorTable[lcGetColorIndex(TopModelColorCode)].data());
POVFile.WriteLine(Line);
}
snprintf(Line, sizeof(Line), "#if (Floor)\n object {\n plane { FloorAxis, FloorLocation hollow }\n texture {\n pigment { color srgb FloorColor }\n finish { emission 0 ambient FloorAmbient diffuse FloorDiffuse }\n }\n }\n#end\n");
POVFile.WriteLine(Line);
@@ -3226,20 +3198,7 @@ lcResult<void> Project::ExportPOVRay(const QString& FileName)
lcResult<void> Project::ExportWavefront(const QString& FileName)
{
const lcResult<void> Ready = EnsureAssetsReady();
if (!Ready)
return Ready;
const lcResult<std::vector<lcModelPartsEntry>> ModelPartsResult = GetModelParts();
if (!ModelPartsResult)
return lcUnexpected(ModelPartsResult.error());
const std::vector<lcModelPartsEntry>& ModelParts = ModelPartsResult.value();
if (ModelParts.empty())
return lcUnexpected(tr("Nothing to export."));
const std::vector<lcModelPartsEntry> ModelParts = GetModelParts();
QString SaveFileName = GetExportFileName(FileName, QLatin1String("obj"), tr("Export Wavefront"), tr("Wavefront Files (*.obj);;All Files (*.*)"));
+1 -1
View File
@@ -144,7 +144,7 @@ protected:
static bool CanShareMergePiece(const PieceInfo* Existing, const PieceInfo* Incoming);
QString GetExportFileName(const QString& FileName, const QString& DefaultExtension, const QString& DialogTitle, const QString& DialogFilter) const;
lcResult<std::vector<lcModelPartsEntry>> GetModelParts();
std::vector<lcModelPartsEntry> GetModelParts();
void SetFileName(const QString& FileName);
bool mIsPreview;
+1 -9
View File
@@ -234,22 +234,14 @@ void lcRenderDialog::RenderPOVRay()
ui->RenderProgress->setValue(ui->RenderProgress->minimum());
ui->RenderProgress->setFormat(tr("Exporting Model"));
QFuture<lcResult<void>> ExportThread = QtConcurrent::run([FileName]()
{
return lcGetActiveProject()->ExportPOVRay(FileName);
});
QApplication::setOverrideCursor(Qt::WaitCursor);
while (!ExportThread.isFinished())
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
lcResult<void> ExportResult = lcGetActiveProject()->ExportPOVRay(FileName);
QGuiApplication::restoreOverrideCursor();
ui->RenderProgress->setFormat("%p%");
lcResult<void> ExportResult = ExportThread.result();
if (!ExportResult)
{
if (!ExportResult.error().isEmpty())