mirror of
https://github.com/leozide/leocad.git
synced 2026-10-26 22:10:32 +00:00
Initialize stud settings and simplify loader bookkeeping
Pass effective startup stud settings into the library and apply color preferences before loading. Replace the reload toggle with UpdateStudStyleAndColors, preserve configured settings in the fallback library, and save the selected color config before combined preferences updates. Remove temporary consumer references from synchronous piece waits, the redundant drain mutex, and worker-start queues. Derive loading states from current requests and use explicit piece names for request, queue, and notification storage. Document the updated ownership and settings contracts. Validated with a Debug build, startup style and color exports, 14 asset export checks, and temporary lifecycle checks covering owned waits, failed and duplicate requirements, regeneration, cancellation, pause/resume, reference cleanup, and shutdown.
This commit is contained in:
1 parent
3ec8b274b1
commit
6a8c05acc5
7 files changed
+150
-170
No files matched your search
+23
-29
@@ -333,10 +333,10 @@ void lcApplication::ExportClipboard(const QByteArray& Clipboard)
|
|||||||
SetClipboard(Clipboard);
|
SetClipboard(Clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lcApplication::LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths)
|
bool lcApplication::LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths, lcStudStyle StudStyle, bool StudCylinderColorEnabled)
|
||||||
{
|
{
|
||||||
if (mLibrary == nullptr)
|
if (mLibrary == nullptr)
|
||||||
mLibrary = new lcPiecesLibrary();
|
mLibrary = new lcPiecesLibrary(StudStyle, StudCylinderColorEnabled);
|
||||||
|
|
||||||
const bool ShowProgress = gMainWindow != nullptr;
|
const bool ShowProgress = gMainWindow != nullptr;
|
||||||
|
|
||||||
@@ -985,7 +985,21 @@ lcStartupMode lcApplication::Initialize(const QList<QPair<QString, bool>>& Libra
|
|||||||
lcLoadDefaultMouseShortcuts();
|
lcLoadDefaultMouseShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoadPartsLibrary(Options.LibraryPaths.isEmpty() ? LibraryPaths : Options.LibraryPaths, !Options.LibraryPaths.isEmpty()))
|
mPreferences.mShadingMode = Options.ShadingMode;
|
||||||
|
mPreferences.mLineWidth = Options.LineWidth;
|
||||||
|
mPreferences.mStudCylinderColorEnabled = Options.StudCylinderColorEnabled;
|
||||||
|
mPreferences.mStudCylinderColor = Options.StudCylinderColor;
|
||||||
|
mPreferences.mPartEdgeColorEnabled = Options.PartEdgeColorEnabled;
|
||||||
|
mPreferences.mPartEdgeColor = Options.PartEdgeColor;
|
||||||
|
mPreferences.mBlackEdgeColorEnabled = Options.BlackEdgeColorEnabled;
|
||||||
|
mPreferences.mBlackEdgeColor = Options.BlackEdgeColor;
|
||||||
|
mPreferences.mDarkEdgeColorEnabled = Options.DarkEdgeColorEnabled;
|
||||||
|
mPreferences.mDarkEdgeColor = Options.DarkEdgeColor;
|
||||||
|
mPreferences.mPartEdgeContrast = Options.PartEdgeContrast;
|
||||||
|
mPreferences.mPartColorValueLDIndex = Options.PartColorValueLDIndex;
|
||||||
|
mPreferences.mAutomateEdgeColor = Options.AutomateEdgeColor;
|
||||||
|
|
||||||
|
if (!LoadPartsLibrary(Options.LibraryPaths.isEmpty() ? LibraryPaths : Options.LibraryPaths, !Options.LibraryPaths.isEmpty(), Options.StudStyle, Options.StudCylinderColorEnabled))
|
||||||
{
|
{
|
||||||
QString Message;
|
QString Message;
|
||||||
|
|
||||||
@@ -1003,22 +1017,6 @@ lcStartupMode lcApplication::Initialize(const QList<QPair<QString, bool>>& Libra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mPreferences.mShadingMode = Options.ShadingMode;
|
|
||||||
mPreferences.mLineWidth = Options.LineWidth;
|
|
||||||
mPreferences.mStudCylinderColorEnabled = Options.StudCylinderColorEnabled;
|
|
||||||
mPreferences.mStudCylinderColor = Options.StudCylinderColor;
|
|
||||||
mPreferences.mPartEdgeColorEnabled = Options.PartEdgeColorEnabled;
|
|
||||||
mPreferences.mPartEdgeColor = Options.PartEdgeColor;
|
|
||||||
mPreferences.mBlackEdgeColorEnabled = Options.BlackEdgeColorEnabled;
|
|
||||||
mPreferences.mBlackEdgeColor = Options.BlackEdgeColor;
|
|
||||||
mPreferences.mDarkEdgeColorEnabled = Options.DarkEdgeColorEnabled;
|
|
||||||
mPreferences.mDarkEdgeColor = Options.DarkEdgeColor;
|
|
||||||
mPreferences.mPartEdgeContrast = Options.PartEdgeContrast;
|
|
||||||
mPreferences.mPartColorValueLDIndex = Options.PartColorValueLDIndex;
|
|
||||||
mPreferences.mAutomateEdgeColor = Options.AutomateEdgeColor;
|
|
||||||
|
|
||||||
lcGetPiecesLibrary()->SetStudStyle(Options.StudStyle, false, Options.StudCylinderColorEnabled);
|
|
||||||
|
|
||||||
if (!SaveAndExit)
|
if (!SaveAndExit)
|
||||||
gMainWindow->CreateWidgets();
|
gMainWindow->CreateWidgets();
|
||||||
|
|
||||||
@@ -1492,18 +1490,14 @@ void lcApplication::ShowPreferencesDialog()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StudStyleChanged || StudCylinderColorEnabledChanged)
|
// UpdateStudStyleAndColors() reloads colors too; both paths must see the newly selected config.
|
||||||
{
|
if (ColorConfigChanged)
|
||||||
lcSetProfileStudStyle(Options.StudStyle);
|
lcSetProfileString(LC_PROFILE_COLOR_CONFIG, Options.ColorConfigPath);
|
||||||
lcGetPiecesLibrary()->SetStudStyle(Options.StudStyle, true, Options.Preferences.mStudCylinderColorEnabled);
|
|
||||||
}
|
|
||||||
else if (ColorConfigChanged || EdgeColorSettingsChanged)
|
|
||||||
{
|
|
||||||
if (ColorConfigChanged)
|
|
||||||
lcSetProfileString(LC_PROFILE_COLOR_CONFIG, Options.ColorConfigPath);
|
|
||||||
|
|
||||||
|
if (StudStyleChanged || StudCylinderColorEnabledChanged)
|
||||||
|
lcGetPiecesLibrary()->UpdateStudStyleAndColors(Options.StudStyle, Options.Preferences.mStudCylinderColorEnabled);
|
||||||
|
else if (ColorConfigChanged || EdgeColorSettingsChanged)
|
||||||
lcGetPiecesLibrary()->LoadColors();
|
lcGetPiecesLibrary()->LoadColors();
|
||||||
}
|
|
||||||
|
|
||||||
gMainWindow->SetShadingMode(Options.Preferences.mShadingMode);
|
gMainWindow->SetShadingMode(Options.Preferences.mShadingMode);
|
||||||
lcView::UpdateAllViews();
|
lcView::UpdateAllViews();
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ public:
|
|||||||
void ShowPreferencesDialog();
|
void ShowPreferencesDialog();
|
||||||
void SaveTabLayout() const;
|
void SaveTabLayout() const;
|
||||||
|
|
||||||
bool LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths);
|
bool LoadPartsLibrary(const QList<QPair<QString, bool>>& LibraryPaths, bool OnlyUsePaths, lcStudStyle StudStyle, bool StudCylinderColorEnabled);
|
||||||
|
|
||||||
void SetClipboard(const QByteArray& Clipboard);
|
void SetClipboard(const QByteArray& Clipboard);
|
||||||
void ExportClipboard(const QByteArray& Clipboard);
|
void ExportClipboard(const QByteArray& Clipboard);
|
||||||
|
|||||||
+67
-81
@@ -37,8 +37,8 @@ bool lcAssetLoader::LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPrior
|
|||||||
else if (LoadPriority != lcPieceLoadPriority::Low)
|
else if (LoadPriority != lcPieceLoadPriority::Low)
|
||||||
{
|
{
|
||||||
mQueueMutex.lock();
|
mQueueMutex.lock();
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
if (It != mRequests.end())
|
if (It != mPieceRequests.end())
|
||||||
PromoteRequestPriorityLocked(It->second, LoadPriority);
|
PromoteRequestPriorityLocked(It->second, LoadPriority);
|
||||||
mQueueMutex.unlock();
|
mQueueMutex.unlock();
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,9 @@ void lcAssetLoader::EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriori
|
|||||||
if (mStopping)
|
if (mStopping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto Existing = mRequests.find(Info);
|
const auto Existing = mPieceRequests.find(Info);
|
||||||
|
|
||||||
if (Existing != mRequests.end())
|
if (Existing != mPieceRequests.end())
|
||||||
{
|
{
|
||||||
PromoteRequestPriorityLocked(Existing->second, LoadPriority);
|
PromoteRequestPriorityLocked(Existing->second, LoadPriority);
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@ void lcAssetLoader::EnqueuePiece(PieceInfo* Info, lcPieceLoadPriority LoadPriori
|
|||||||
RequestedPiece->LoadPriority = LoadPriority;
|
RequestedPiece->LoadPriority = LoadPriority;
|
||||||
RequestedPiece->EnqueuedAt = QDateTime::currentMSecsSinceEpoch();
|
RequestedPiece->EnqueuedAt = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
|
||||||
mRequests.emplace(Info, RequestedPiece);
|
mPieceRequests.emplace(Info, RequestedPiece);
|
||||||
|
|
||||||
mQueue.push_back(RequestedPiece);
|
mPieceQueue.push_back(RequestedPiece);
|
||||||
StartWorkersLocked();
|
StartWorkersLocked();
|
||||||
|
|
||||||
emit mLibrary->AssetRequestsChanged();
|
emit mLibrary->AssetRequestsChanged();
|
||||||
@@ -191,7 +191,7 @@ void lcAssetLoader::StartWorkersLocked()
|
|||||||
}), mFutures.end());
|
}), mFutures.end());
|
||||||
|
|
||||||
const int MaxWorkers = qMax(1, qMin(4, QThread::idealThreadCount()));
|
const int MaxWorkers = qMax(1, qMin(4, QThread::idealThreadCount()));
|
||||||
const int Queued = static_cast<int>(mQueue.size() + mTextureQueue.size() + mSynthQueue.size());
|
const int Queued = static_cast<int>(mPieceQueue.size() + mTextureQueue.size() + mSynthQueue.size());
|
||||||
const int Additional = mPaused || mStopping ? 0 : qMin(MaxWorkers - mActiveWorkers, Queued);
|
const int Additional = mPaused || mStopping ? 0 : qMin(MaxWorkers - mActiveWorkers, Queued);
|
||||||
|
|
||||||
for (int Worker = 0; Worker < Additional; Worker++)
|
for (int Worker = 0; Worker < Additional; Worker++)
|
||||||
@@ -212,7 +212,7 @@ void lcAssetLoader::RunWorker()
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
if (mStopping || mPaused || (mQueue.empty() && mTextureQueue.empty() && mSynthQueue.empty()))
|
if (mStopping || mPaused || (mPieceQueue.empty() && mTextureQueue.empty() && mSynthQueue.empty()))
|
||||||
{
|
{
|
||||||
mActiveWorkers--;
|
mActiveWorkers--;
|
||||||
mResultReady.wakeAll();
|
mResultReady.wakeAll();
|
||||||
@@ -234,19 +234,18 @@ void lcAssetLoader::RunWorker()
|
|||||||
return Score(Left) < Score(Right) || (Score(Left) == Score(Right) && Left->EnqueuedAt > Right->EnqueuedAt);
|
return Score(Left) < Score(Right) || (Score(Left) == Score(Right) && Left->EnqueuedAt > Right->EnqueuedAt);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto PartBest = std::max_element(mQueue.begin(), mQueue.end(), Less);
|
auto PartBest = std::max_element(mPieceQueue.begin(), mPieceQueue.end(), Less);
|
||||||
auto TextureBest = std::max_element(mTextureQueue.begin(), mTextureQueue.end(), Less);
|
auto TextureBest = std::max_element(mTextureQueue.begin(), mTextureQueue.end(), Less);
|
||||||
auto SynthBest = std::max_element(mSynthQueue.begin(), mSynthQueue.end(), Less);
|
auto SynthBest = std::max_element(mSynthQueue.begin(), mSynthQueue.end(), Less);
|
||||||
|
|
||||||
if (TextureBest != mTextureQueue.end() && (PartBest == mQueue.end() || !Less(*TextureBest, *PartBest)) &&
|
if (TextureBest != mTextureQueue.end() && (PartBest == mPieceQueue.end() || !Less(*TextureBest, *PartBest)) &&
|
||||||
(SynthBest == mSynthQueue.end() || !Less(*TextureBest, *SynthBest)))
|
(SynthBest == mSynthQueue.end() || !Less(*TextureBest, *SynthBest)))
|
||||||
{
|
{
|
||||||
RequestedTexture = *TextureBest;
|
RequestedTexture = *TextureBest;
|
||||||
mTextureQueue.erase(TextureBest);
|
mTextureQueue.erase(TextureBest);
|
||||||
RequestedTexture->Running = true;
|
RequestedTexture->Running = true;
|
||||||
mStartedTextures.push_back(RequestedTexture);
|
|
||||||
}
|
}
|
||||||
else if (SynthBest != mSynthQueue.end() && (PartBest == mQueue.end() || !Less(*SynthBest, *PartBest)))
|
else if (SynthBest != mSynthQueue.end() && (PartBest == mPieceQueue.end() || !Less(*SynthBest, *PartBest)))
|
||||||
{
|
{
|
||||||
RequestedSynth = *SynthBest;
|
RequestedSynth = *SynthBest;
|
||||||
mSynthQueue.erase(SynthBest);
|
mSynthQueue.erase(SynthBest);
|
||||||
@@ -255,9 +254,8 @@ void lcAssetLoader::RunWorker()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
RequestedPiece = *PartBest;
|
RequestedPiece = *PartBest;
|
||||||
mQueue.erase(PartBest);
|
mPieceQueue.erase(PartBest);
|
||||||
RequestedPiece->Running = true;
|
RequestedPiece->Running = true;
|
||||||
mStarted.push_back(RequestedPiece);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,30 +331,25 @@ bool lcAssetLoader::ProcessCompletions()
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
while (!mStarted.empty())
|
// Reflect worker starts in asset states on the UI thread.
|
||||||
|
if (!mStopping)
|
||||||
{
|
{
|
||||||
const std::shared_ptr<PieceRequest> RequestedPiece = mStarted.front();
|
for (const PieceRequestMap::value_type& Entry : mPieceRequests)
|
||||||
|
{
|
||||||
|
const std::shared_ptr<PieceRequest>& RequestedPiece = Entry.second;
|
||||||
|
|
||||||
mStarted.pop_front();
|
if (RequestedPiece->Running && RequestedPiece->Info->mState == lcPieceInfoState::Queued)
|
||||||
|
RequestedPiece->Info->mState = lcPieceInfoState::Loading;
|
||||||
|
}
|
||||||
|
|
||||||
const auto It = mRequests.find(RequestedPiece->Info);
|
for (const TextureRequestMap::value_type& Entry : mTextureRequests)
|
||||||
|
{
|
||||||
|
const std::shared_ptr<TextureRequest>& RequestedTexture = Entry.second;
|
||||||
|
|
||||||
if (!mStopping && It != mRequests.end() && It->second == RequestedPiece && RequestedPiece->Info->mState == lcPieceInfoState::Queued)
|
if (RequestedTexture->Running && RequestedTexture->Texture->mState == lcTextureState::Queued)
|
||||||
RequestedPiece->Info->mState = lcPieceInfoState::Loading;
|
RequestedTexture->Texture->mState = lcTextureState::Decoding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!mStartedTextures.empty())
|
|
||||||
{
|
|
||||||
const std::shared_ptr<TextureRequest> RequestedTexture = mStartedTextures.front();
|
|
||||||
|
|
||||||
mStartedTextures.pop_front();
|
|
||||||
|
|
||||||
const auto It = mTextureRequests.find(RequestedTexture->Texture);
|
|
||||||
|
|
||||||
if (!mStopping && It != mTextureRequests.end() && It->second == RequestedTexture && RequestedTexture->Texture->mState == lcTextureState::Queued)
|
|
||||||
RequestedTexture->Texture->mState = lcTextureState::Decoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int MaxCompletionsPerPump = 16;
|
constexpr int MaxCompletionsPerPump = 16;
|
||||||
@@ -446,10 +439,10 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
|||||||
bool Stale;
|
bool Stale;
|
||||||
|
|
||||||
mQueueMutex.lock();
|
mQueueMutex.lock();
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
Stale = mStopping || RequestedPiece->Obsolete || Completed.Result.Generation != mGeneration || It == mRequests.end() || It->second != RequestedPiece;
|
Stale = mStopping || RequestedPiece->Obsolete || Completed.Result.Generation != mGeneration || It == mPieceRequests.end() || It->second != RequestedPiece;
|
||||||
if (Stale && It != mRequests.end() && It->second == RequestedPiece)
|
if (Stale && It != mPieceRequests.end() && It->second == RequestedPiece)
|
||||||
mRequests.erase(It);
|
mPieceRequests.erase(It);
|
||||||
mQueueMutex.unlock();
|
mQueueMutex.unlock();
|
||||||
|
|
||||||
RequestedPiece->Running = false;
|
RequestedPiece->Running = false;
|
||||||
@@ -461,7 +454,7 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
|||||||
if (!Stale)
|
if (!Stale)
|
||||||
{
|
{
|
||||||
mQueueMutex.lock();
|
mQueueMutex.lock();
|
||||||
mRequests.erase(Info);
|
mPieceRequests.erase(Info);
|
||||||
mQueueMutex.unlock();
|
mQueueMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,7 +484,7 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
|||||||
|
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
mQueue.push_back(RequestedPiece);
|
mPieceQueue.push_back(RequestedPiece);
|
||||||
StartWorkersLocked();
|
StartWorkersLocked();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -506,7 +499,7 @@ void lcAssetLoader::CompletePiece(Completion& Completed)
|
|||||||
|
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
mQueue.push_back(RequestedPiece);
|
mPieceQueue.push_back(RequestedPiece);
|
||||||
StartWorkersLocked();
|
StartWorkersLocked();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -810,7 +803,7 @@ void lcAssetLoader::FinishPiecesWithSettledTextures()
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
for (const PieceRequestMap::value_type& Entry : mRequests)
|
for (const PieceRequestMap::value_type& Entry : mPieceRequests)
|
||||||
if (Entry.second->StagedMesh)
|
if (Entry.second->StagedMesh)
|
||||||
Waiting.push_back(Entry.second);
|
Waiting.push_back(Entry.second);
|
||||||
}
|
}
|
||||||
@@ -878,16 +871,16 @@ void lcAssetLoader::FinishPiece(const std::shared_ptr<PieceRequest>& RequestedPi
|
|||||||
}
|
}
|
||||||
|
|
||||||
mQueueMutex.lock();
|
mQueueMutex.lock();
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
if (It != mRequests.end() && It->second == RequestedPiece)
|
if (It != mPieceRequests.end() && It->second == RequestedPiece)
|
||||||
mRequests.erase(It);
|
mPieceRequests.erase(It);
|
||||||
RequestedPiece->Terminal = true;
|
RequestedPiece->Terminal = true;
|
||||||
RequestedPiece->Succeeded = Loaded;
|
RequestedPiece->Succeeded = Loaded;
|
||||||
mResultReady.wakeAll();
|
mResultReady.wakeAll();
|
||||||
mQueueMutex.unlock();
|
mQueueMutex.unlock();
|
||||||
|
|
||||||
mLibrary->ScheduleBufferRepack();
|
mLibrary->ScheduleBufferRepack();
|
||||||
mNotifications.push_back({ RequestedPiece, Loaded, std::move(LoadError) });
|
mPieceNotifications.push_back({ RequestedPiece, Loaded, std::move(LoadError) });
|
||||||
|
|
||||||
QCoreApplication::postEvent(this, new QEvent(lcAssetLoaderCompletionEvent));
|
QCoreApplication::postEvent(this, new QEvent(lcAssetLoaderCompletionEvent));
|
||||||
}
|
}
|
||||||
@@ -934,11 +927,11 @@ void lcAssetLoader::DispatchNotifications()
|
|||||||
|
|
||||||
constexpr int MaxNotificationsPerPump = 32;
|
constexpr int MaxNotificationsPerPump = 32;
|
||||||
|
|
||||||
for (int Delivered = 0; Delivered < MaxNotificationsPerPump && !mNotifications.empty(); Delivered++)
|
for (int Delivered = 0; Delivered < MaxNotificationsPerPump && !mPieceNotifications.empty(); Delivered++)
|
||||||
{
|
{
|
||||||
Notification Notification = std::move(mNotifications.front());
|
PieceNotification Notification = std::move(mPieceNotifications.front());
|
||||||
|
|
||||||
mNotifications.pop_front();
|
mPieceNotifications.pop_front();
|
||||||
|
|
||||||
PieceInfo* Info = Notification.RequestedPiece->Info;
|
PieceInfo* Info = Notification.RequestedPiece->Info;
|
||||||
|
|
||||||
@@ -987,7 +980,7 @@ void lcAssetLoader::DispatchNotifications()
|
|||||||
mLibrary->ReleasePieceLoadHold(Info);
|
mLibrary->ReleasePieceLoadHold(Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mNotifications.empty() || !mSynthNotifications.empty())
|
if (!mPieceNotifications.empty() || !mSynthNotifications.empty())
|
||||||
QCoreApplication::postEvent(this, new QEvent(lcAssetLoaderCompletionEvent));
|
QCoreApplication::postEvent(this, new QEvent(lcAssetLoaderCompletionEvent));
|
||||||
|
|
||||||
if (!SettledSynths.empty())
|
if (!SettledSynths.empty())
|
||||||
@@ -1006,6 +999,7 @@ bool lcAssetLoader::event(QEvent* Event)
|
|||||||
|
|
||||||
return QObject::event(Event);
|
return QObject::event(Event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcAssetLoader::WaitForResultsLocked()
|
void lcAssetLoader::WaitForResultsLocked()
|
||||||
{
|
{
|
||||||
if (!mCompletions.empty())
|
if (!mCompletions.empty())
|
||||||
@@ -1041,9 +1035,9 @@ bool lcAssetLoader::WaitForRequest(PieceInfo* Info)
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
|
|
||||||
if (It != mRequests.end())
|
if (It != mPieceRequests.end())
|
||||||
{
|
{
|
||||||
RequestedPiece = It->second;
|
RequestedPiece = It->second;
|
||||||
|
|
||||||
@@ -1088,9 +1082,6 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
|||||||
|
|
||||||
Required.erase(std::unique(Required.begin(), Required.end()), Required.end());
|
Required.erase(std::unique(Required.begin(), Required.end()), Required.end());
|
||||||
|
|
||||||
for (PieceInfo* Info : Required)
|
|
||||||
mLibrary->AddPieceReference(Info);
|
|
||||||
|
|
||||||
for (PieceInfo* Info : Required)
|
for (PieceInfo* Info : Required)
|
||||||
{
|
{
|
||||||
if (Info->mState != lcPieceInfoState::Unloaded)
|
if (Info->mState != lcPieceInfoState::Unloaded)
|
||||||
@@ -1107,9 +1098,9 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
|||||||
|
|
||||||
for (PieceInfo* Info : Required)
|
for (PieceInfo* Info : Required)
|
||||||
{
|
{
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
|
|
||||||
if (It == mRequests.end())
|
if (It == mPieceRequests.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PromoteRequestPriorityLocked(It->second, lcPieceLoadPriority::Blocking);
|
PromoteRequestPriorityLocked(It->second, lcPieceLoadPriority::Blocking);
|
||||||
@@ -1123,9 +1114,6 @@ bool lcAssetLoader::WaitForPieces(const std::vector<PieceInfo*>& Pieces)
|
|||||||
for (PieceInfo* Info : Required)
|
for (PieceInfo* Info : Required)
|
||||||
Ready = WaitForRequest(Info) && Ready;
|
Ready = WaitForRequest(Info) && Ready;
|
||||||
|
|
||||||
for (PieceInfo* Info : Required)
|
|
||||||
mLibrary->ReleasePieceInfo(Info);
|
|
||||||
|
|
||||||
return Ready;
|
return Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1225,15 +1213,13 @@ void lcAssetLoader::WaitForLoadQueue()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(QThread::currentThread() == thread());
|
Q_ASSERT(QThread::currentThread() == thread());
|
||||||
|
|
||||||
QMutexLocker DrainLock(&mDrainMutex);
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
ProcessCompletions();
|
ProcessCompletions();
|
||||||
|
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
if (mRequests.empty() && mTextureRequests.empty() && mSynthRequests.empty() && mActiveWorkers == 0 && mCompletions.empty())
|
if (mPieceRequests.empty() && mTextureRequests.empty() && mSynthRequests.empty() && mActiveWorkers == 0 && mCompletions.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
WaitForResultsLocked();
|
WaitForResultsLocked();
|
||||||
@@ -1248,7 +1234,7 @@ void lcAssetLoader::WaitForLoadQueue()
|
|||||||
bool lcAssetLoader::HasPendingWork()
|
bool lcAssetLoader::HasPendingWork()
|
||||||
{
|
{
|
||||||
mQueueMutex.lock();
|
mQueueMutex.lock();
|
||||||
const bool Pending = !mRequests.empty() || !mTextureRequests.empty() || !mSynthRequests.empty() || !mCompletions.empty();
|
const bool Pending = !mPieceRequests.empty() || !mTextureRequests.empty() || !mSynthRequests.empty() || !mCompletions.empty();
|
||||||
mQueueMutex.unlock();
|
mQueueMutex.unlock();
|
||||||
|
|
||||||
return Pending;
|
return Pending;
|
||||||
@@ -1294,21 +1280,21 @@ void lcAssetLoader::InvalidatePiece(PieceInfo* Info)
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
|
|
||||||
if (It != mRequests.end())
|
if (It != mPieceRequests.end())
|
||||||
{
|
{
|
||||||
Removed = It->second;
|
Removed = It->second;
|
||||||
Removed->Obsolete = true;
|
Removed->Obsolete = true;
|
||||||
Removed->Terminal = true;
|
Removed->Terminal = true;
|
||||||
Removed->Succeeded = false;
|
Removed->Succeeded = false;
|
||||||
ReleaseHold = !Removed->Running;
|
ReleaseHold = !Removed->Running;
|
||||||
mRequests.erase(It);
|
mPieceRequests.erase(It);
|
||||||
|
|
||||||
mQueue.erase(std::remove(mQueue.begin(), mQueue.end(), Removed), mQueue.end());
|
mPieceQueue.erase(std::remove(mPieceQueue.begin(), mPieceQueue.end(), Removed), mPieceQueue.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Notification& Pending : mNotifications)
|
for (PieceNotification& Pending : mPieceNotifications)
|
||||||
if (Pending.RequestedPiece->Info == Info)
|
if (Pending.RequestedPiece->Info == Info)
|
||||||
Pending.RequestedPiece->Obsolete = true;
|
Pending.RequestedPiece->Obsolete = true;
|
||||||
|
|
||||||
@@ -1343,9 +1329,9 @@ void lcAssetLoader::OnConsumerReleased(PieceInfo* Info)
|
|||||||
{
|
{
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
const auto It = mRequests.find(Info);
|
const auto It = mPieceRequests.find(Info);
|
||||||
|
|
||||||
if (It == mRequests.end())
|
if (It == mPieceRequests.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::shared_ptr<PieceRequest>& RequestedPiece = It->second;
|
const std::shared_ptr<PieceRequest>& RequestedPiece = It->second;
|
||||||
@@ -1361,9 +1347,9 @@ void lcAssetLoader::OnConsumerReleased(PieceInfo* Info)
|
|||||||
|
|
||||||
Info->mState = lcPieceInfoState::Cancelled;
|
Info->mState = lcPieceInfoState::Cancelled;
|
||||||
|
|
||||||
mRequests.erase(It);
|
mPieceRequests.erase(It);
|
||||||
|
|
||||||
mQueue.erase(std::remove(mQueue.begin(), mQueue.end(), Removed), mQueue.end());
|
mPieceQueue.erase(std::remove(mPieceQueue.begin(), mPieceQueue.end(), Removed), mPieceQueue.end());
|
||||||
|
|
||||||
mResultReady.wakeAll();
|
mResultReady.wakeAll();
|
||||||
}
|
}
|
||||||
@@ -1487,7 +1473,7 @@ void lcAssetLoader::PauseQueuedWork()
|
|||||||
|
|
||||||
// A mesh awaiting textures was built with the previous stud settings.
|
// A mesh awaiting textures was built with the previous stud settings.
|
||||||
// Rebuild it after the settings change instead of publishing stale geometry.
|
// Rebuild it after the settings change instead of publishing stale geometry.
|
||||||
for (const PieceRequestMap::value_type& Entry : mRequests)
|
for (const PieceRequestMap::value_type& Entry : mPieceRequests)
|
||||||
{
|
{
|
||||||
const std::shared_ptr<PieceRequest>& RequestedPiece = Entry.second;
|
const std::shared_ptr<PieceRequest>& RequestedPiece = Entry.second;
|
||||||
|
|
||||||
@@ -1505,7 +1491,7 @@ void lcAssetLoader::PauseQueuedWork()
|
|||||||
RequestedPiece->StagedMesh.reset();
|
RequestedPiece->StagedMesh.reset();
|
||||||
RequestedPiece->Info->mState = lcPieceInfoState::Queued;
|
RequestedPiece->Info->mState = lcPieceInfoState::Queued;
|
||||||
RequestedPiece->Running = false;
|
RequestedPiece->Running = false;
|
||||||
mQueue.push_back(RequestedPiece);
|
mPieceQueue.push_back(RequestedPiece);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pending generated meshes are restarted after the new stud style is installed.
|
// Pending generated meshes are restarted after the new stud style is installed.
|
||||||
@@ -1532,7 +1518,7 @@ void lcAssetLoader::ResumeQueuedWork()
|
|||||||
|
|
||||||
QMutexLocker QueueLock(&mQueueMutex);
|
QMutexLocker QueueLock(&mQueueMutex);
|
||||||
|
|
||||||
for (const std::shared_ptr<PieceRequest>& RequestedPiece : mQueue)
|
for (const std::shared_ptr<PieceRequest>& RequestedPiece : mPieceQueue)
|
||||||
{
|
{
|
||||||
const bool SkipCache = RequestedPiece->Source.SkipCache;
|
const bool SkipCache = RequestedPiece->Source.SkipCache;
|
||||||
|
|
||||||
@@ -1560,13 +1546,13 @@ void lcAssetLoader::CancelAndDrain()
|
|||||||
|
|
||||||
mStopping = true;
|
mStopping = true;
|
||||||
mGeneration++;
|
mGeneration++;
|
||||||
mQueue.clear();
|
mPieceQueue.clear();
|
||||||
mTextureQueue.clear();
|
mTextureQueue.clear();
|
||||||
mSynthQueue.clear();
|
mSynthQueue.clear();
|
||||||
mSynthPieces.clear();
|
mSynthPieces.clear();
|
||||||
mFailedSynthErrors.clear();
|
mFailedSynthErrors.clear();
|
||||||
|
|
||||||
for (auto It = mRequests.begin(); It != mRequests.end();)
|
for (auto It = mPieceRequests.begin(); It != mPieceRequests.end();)
|
||||||
{
|
{
|
||||||
if (It->second->Running)
|
if (It->second->Running)
|
||||||
{
|
{
|
||||||
@@ -1581,7 +1567,7 @@ void lcAssetLoader::CancelAndDrain()
|
|||||||
|
|
||||||
Cancelled.push_back(It->second);
|
Cancelled.push_back(It->second);
|
||||||
|
|
||||||
It = mRequests.erase(It);
|
It = mPieceRequests.erase(It);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1622,11 +1608,11 @@ void lcAssetLoader::CancelAndDrain()
|
|||||||
|
|
||||||
WaitForLoadQueue();
|
WaitForLoadQueue();
|
||||||
|
|
||||||
while (!mNotifications.empty())
|
while (!mPieceNotifications.empty())
|
||||||
{
|
{
|
||||||
Notification Notification = std::move(mNotifications.front());
|
PieceNotification Notification = std::move(mPieceNotifications.front());
|
||||||
|
|
||||||
mNotifications.pop_front();
|
mPieceNotifications.pop_front();
|
||||||
|
|
||||||
mLibrary->ReleasePieceLoadHold(Notification.RequestedPiece->Info);
|
mLibrary->ReleasePieceLoadHold(Notification.RequestedPiece->Info);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-10
@@ -35,6 +35,7 @@ struct lcPieceBuildResult
|
|||||||
{
|
{
|
||||||
lcPieceBuildResult() = default;
|
lcPieceBuildResult() = default;
|
||||||
~lcPieceBuildResult();
|
~lcPieceBuildResult();
|
||||||
|
|
||||||
lcPieceBuildResult(lcPieceBuildResult&&) = default;
|
lcPieceBuildResult(lcPieceBuildResult&&) = default;
|
||||||
lcPieceBuildResult& operator=(lcPieceBuildResult&&) = default;
|
lcPieceBuildResult& operator=(lcPieceBuildResult&&) = default;
|
||||||
lcPieceBuildResult(const lcPieceBuildResult&) = delete;
|
lcPieceBuildResult(const lcPieceBuildResult&) = delete;
|
||||||
@@ -59,7 +60,7 @@ public:
|
|||||||
lcAssetLoader(lcPiecesLibrary* Library);
|
lcAssetLoader(lcPiecesLibrary* Library);
|
||||||
~lcAssetLoader() override;
|
~lcAssetLoader() override;
|
||||||
|
|
||||||
// Load a piece the library has already acquired for the caller; this adds no consumer reference.
|
// Load a piece the library has already acquired for the caller. Adds no consumer reference.
|
||||||
// Low and Normal return immediately; true does not mean the piece is ready yet.
|
// Low and Normal return immediately; true does not mean the piece is ready yet.
|
||||||
// Blocking promotes urgent work, waits until loading settles, and returns whether it succeeded.
|
// Blocking promotes urgent work, waits until loading settles, and returns whether it succeeded.
|
||||||
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||||
@@ -68,7 +69,7 @@ public:
|
|||||||
// Cancel any older request and keep the previous mesh visible while the replacement is built.
|
// Cancel any older request and keep the previous mesh visible while the replacement is built.
|
||||||
void QueueSynthMesh(lcPiece* Piece);
|
void QueueSynthMesh(lcPiece* Piece);
|
||||||
|
|
||||||
// Start or promote loading as needed, then wait. Returns true if all pieces are ready.
|
// Start or promote loading, then wait and returns true if all pieces are ready. Adds no consumer references.
|
||||||
// Waits for these identities only, without traversing container children or generated meshes.
|
// Waits for these identities only, without traversing container children or generated meshes.
|
||||||
bool WaitForPieces(const std::vector<PieceInfo*>& Pieces);
|
bool WaitForPieces(const std::vector<PieceInfo*>& Pieces);
|
||||||
|
|
||||||
@@ -174,7 +175,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// UI-thread delivery retains the load hold after publication, until callbacks finish.
|
// UI-thread delivery retains the load hold after publication, until callbacks finish.
|
||||||
struct Notification
|
struct PieceNotification
|
||||||
{
|
{
|
||||||
std::shared_ptr<PieceRequest> RequestedPiece;
|
std::shared_ptr<PieceRequest> RequestedPiece;
|
||||||
bool Loaded;
|
bool Loaded;
|
||||||
@@ -229,23 +230,19 @@ private:
|
|||||||
// Private build data passes between worker and UI phases through completions.
|
// Private build data passes between worker and UI phases through completions.
|
||||||
QMutex mQueueMutex;
|
QMutex mQueueMutex;
|
||||||
QWaitCondition mResultReady;
|
QWaitCondition mResultReady;
|
||||||
// Serializes full queue drains; scoped readiness waits do not acquire this mutex.
|
PieceRequestMap mPieceRequests;
|
||||||
QMutex mDrainMutex;
|
|
||||||
PieceRequestMap mRequests;
|
|
||||||
TextureRequestMap mTextureRequests;
|
TextureRequestMap mTextureRequests;
|
||||||
SynthRequestMap mSynthRequests;
|
SynthRequestMap mSynthRequests;
|
||||||
// UI-thread diagnostics and instance tracking; these do not own the pieces.
|
// UI-thread diagnostics and instance tracking; these do not own the pieces.
|
||||||
std::unordered_map<const lcPiece*, QString> mFailedSynthErrors;
|
std::unordered_map<const lcPiece*, QString> mFailedSynthErrors;
|
||||||
std::unordered_set<lcPiece*> mSynthPieces;
|
std::unordered_set<lcPiece*> mSynthPieces;
|
||||||
// Pending worker phases remain here while paused; mPaused prevents dispatch.
|
// Pending worker phases remain here while paused; mPaused prevents dispatch.
|
||||||
std::deque<std::shared_ptr<PieceRequest>> mQueue;
|
std::deque<std::shared_ptr<PieceRequest>> mPieceQueue;
|
||||||
std::deque<std::shared_ptr<TextureRequest>> mTextureQueue;
|
std::deque<std::shared_ptr<TextureRequest>> mTextureQueue;
|
||||||
std::deque<std::shared_ptr<SynthRequest>> mSynthQueue;
|
std::deque<std::shared_ptr<SynthRequest>> mSynthQueue;
|
||||||
std::deque<Completion> mCompletions;
|
std::deque<Completion> mCompletions;
|
||||||
std::deque<std::shared_ptr<PieceRequest>> mStarted;
|
|
||||||
std::deque<std::shared_ptr<TextureRequest>> mStartedTextures;
|
|
||||||
// UI-thread only; public signals are deferred until outside synchronous waits.
|
// UI-thread only; public signals are deferred until outside synchronous waits.
|
||||||
std::deque<Notification> mNotifications;
|
std::deque<PieceNotification> mPieceNotifications;
|
||||||
std::deque<SynthNotification> mSynthNotifications;
|
std::deque<SynthNotification> mSynthNotifications;
|
||||||
std::vector<QFuture<void>> mFutures;
|
std::vector<QFuture<void>> mFutures;
|
||||||
int mActiveWorkers = 0;
|
int mActiveWorkers = 0;
|
||||||
|
|||||||
+34
-42
@@ -37,7 +37,8 @@ enum class lcLibraryCacheFlag : quint32
|
|||||||
Directory = 0x0002
|
Directory = 0x0002
|
||||||
};
|
};
|
||||||
|
|
||||||
lcPiecesLibrary::lcPiecesLibrary()
|
lcPiecesLibrary::lcPiecesLibrary(lcStudStyle StudStyle, bool StudCylinderColorEnabled)
|
||||||
|
: mStudStyle(StudStyle), mStudCylinderColorEnabled(StudCylinderColorEnabled)
|
||||||
{
|
{
|
||||||
mTextureManager = std::make_unique<lcTextureManager>();
|
mTextureManager = std::make_unique<lcTextureManager>();
|
||||||
mAssetLoader = std::unique_ptr<lcAssetLoader>(new lcAssetLoader(this));
|
mAssetLoader = std::unique_ptr<lcAssetLoader>(new lcAssetLoader(this));
|
||||||
@@ -53,8 +54,6 @@ lcPiecesLibrary::lcPiecesLibrary()
|
|||||||
mNumOfficialPieces = 0;
|
mNumOfficialPieces = 0;
|
||||||
mBuffersDirty = false;
|
mBuffersDirty = false;
|
||||||
mHasUnofficial = false;
|
mHasUnofficial = false;
|
||||||
mStudStyle = lcGetProfileStudStyle();
|
|
||||||
mStudCylinderColorEnabled = lcGetProfileInt(LC_PROFILE_STUD_CYLINDER_COLOR_ENABLED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lcPiecesLibrary::~lcPiecesLibrary()
|
lcPiecesLibrary::~lcPiecesLibrary()
|
||||||
@@ -2279,7 +2278,7 @@ bool lcPiecesLibrary::SupportsStudStyle() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcPiecesLibrary::SetStudStyle(lcStudStyle StudStyle, bool Reload, bool StudCylinderColorEnabled)
|
void lcPiecesLibrary::UpdateStudStyleAndColors(lcStudStyle StudStyle, bool StudCylinderColorEnabled)
|
||||||
{
|
{
|
||||||
if (mStudStyle == StudStyle && mStudCylinderColorEnabled == StudCylinderColorEnabled)
|
if (mStudStyle == StudStyle && mStudCylinderColorEnabled == StudCylinderColorEnabled)
|
||||||
return;
|
return;
|
||||||
@@ -2289,7 +2288,6 @@ void lcPiecesLibrary::SetStudStyle(lcStudStyle StudStyle, bool Reload, bool Stud
|
|||||||
mAssetLoader->PauseQueuedWork();
|
mAssetLoader->PauseQueuedWork();
|
||||||
|
|
||||||
mStudStyle = StudStyle;
|
mStudStyle = StudStyle;
|
||||||
|
|
||||||
mStudCylinderColorEnabled = StudCylinderColorEnabled;
|
mStudCylinderColorEnabled = StudCylinderColorEnabled;
|
||||||
|
|
||||||
LoadColors();
|
LoadColors();
|
||||||
@@ -2308,47 +2306,40 @@ void lcPiecesLibrary::SetStudStyle(lcStudStyle StudStyle, bool Reload, bool Stud
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto ReloadPiece = [this](PieceInfo* Info)
|
||||||
|
{
|
||||||
|
if (Info->mState != lcPieceInfoState::Loaded || !Info->GetMesh() || !(Info->GetMesh()->mFlags & lcMeshFlag::HasStyleStud))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Info->IsModel())
|
||||||
|
{
|
||||||
|
Info->ReleaseMesh();
|
||||||
|
Info->mState = lcPieceInfoState::Unloaded;
|
||||||
|
|
||||||
|
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
||||||
|
}
|
||||||
|
else if (!Info->IsProject())
|
||||||
|
{
|
||||||
|
Info->Unload();
|
||||||
|
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
||||||
|
}
|
||||||
|
|
||||||
|
mBuffersDirty = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const std::map<std::string, PieceInfo*>::value_type& PieceIt : mPieces)
|
||||||
|
ReloadPiece(PieceIt.second);
|
||||||
|
|
||||||
|
for (const std::unordered_map<PieceInfo*, Project*>::value_type& Local : mProjectPieces)
|
||||||
|
ReloadPiece(Local.first);
|
||||||
|
|
||||||
mLoadMutex.unlock();
|
mLoadMutex.unlock();
|
||||||
|
|
||||||
if (Reload)
|
mAssetLoader->ReloadSynthMeshes();
|
||||||
{
|
|
||||||
mLoadMutex.lock();
|
|
||||||
|
|
||||||
const auto ReloadPiece = [this](PieceInfo* Info)
|
|
||||||
{
|
|
||||||
if (Info->mState != lcPieceInfoState::Loaded || !Info->GetMesh() || !(Info->GetMesh()->mFlags & lcMeshFlag::HasStyleStud))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Info->IsModel())
|
|
||||||
{
|
|
||||||
Info->ReleaseMesh();
|
|
||||||
Info->mState = lcPieceInfoState::Unloaded;
|
|
||||||
|
|
||||||
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
|
||||||
}
|
|
||||||
else if (!Info->IsProject())
|
|
||||||
{
|
|
||||||
Info->Unload();
|
|
||||||
mAssetLoader->LoadPieceInfo(Info, lcPieceLoadPriority::Low);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBuffersDirty = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const std::map<std::string, PieceInfo*>::value_type& PieceIt : mPieces)
|
|
||||||
ReloadPiece(PieceIt.second);
|
|
||||||
|
|
||||||
for (const std::unordered_map<PieceInfo*, Project*>::value_type& Local : mProjectPieces)
|
|
||||||
ReloadPiece(Local.first);
|
|
||||||
|
|
||||||
mLoadMutex.unlock();
|
|
||||||
mAssetLoader->ReloadSynthMeshes();
|
|
||||||
}
|
|
||||||
|
|
||||||
mAssetLoader->ResumeQueuedWork();
|
mAssetLoader->ResumeQueuedWork();
|
||||||
|
|
||||||
if (Reload)
|
WaitForLoadQueue();
|
||||||
WaitForLoadQueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lcPiecesLibrary::IsPrimitive(const char* Name) const
|
bool lcPiecesLibrary::IsPrimitive(const char* Name) const
|
||||||
@@ -2720,8 +2711,9 @@ bool lcPiecesLibrary::LoadBuiltinPieces()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lcLoadDefaultColors(lcStudStyle::Plain);
|
lcLoadDefaultColors(mStudStyle);
|
||||||
UpdateLoadingMeshColors();
|
UpdateLoadingMeshColors();
|
||||||
|
UpdateStudStyleSource();
|
||||||
lcLoadDefaultCategories(true);
|
lcLoadDefaultCategories(true);
|
||||||
lcSynthInit();
|
lcSynthInit();
|
||||||
lcTrainTrackInfo::Initialize(this);
|
lcTrainTrackInfo::Initialize(this);
|
||||||
|
|||||||
+4
-3
@@ -159,7 +159,7 @@ class lcPiecesLibrary : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
lcPiecesLibrary();
|
lcPiecesLibrary(lcStudStyle StudStyle, bool StudCylinderColorEnabled);
|
||||||
~lcPiecesLibrary();
|
~lcPiecesLibrary();
|
||||||
|
|
||||||
lcPiecesLibrary(const lcPiecesLibrary&) = delete;
|
lcPiecesLibrary(const lcPiecesLibrary&) = delete;
|
||||||
@@ -193,7 +193,8 @@ public:
|
|||||||
// Blocking waits and reports success; Low and Normal return immediately. See docs/asset-loading.md.
|
// Blocking waits and reports success; Low and Normal return immediately. See docs/asset-loading.md.
|
||||||
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
bool LoadPieceInfo(PieceInfo* Info, lcPieceLoadPriority LoadPriority);
|
||||||
void NotifyConsumersChanged();
|
void NotifyConsumersChanged();
|
||||||
// Start or promote loading as needed, then wait with temporary holds; false means failure/cancellation.
|
// Start or promote loading, then wait. Adds no consumer references.
|
||||||
|
// Returns false for failed or cancelled pieces.
|
||||||
// Does not traverse container children or wait for per-instance synth geometry.
|
// Does not traverse container children or wait for per-instance synth geometry.
|
||||||
bool WaitForPieces(const std::vector<PieceInfo*>& Pieces);
|
bool WaitForPieces(const std::vector<PieceInfo*>& Pieces);
|
||||||
// Also settles container children/synths and updates bounds; caller retains the identity.
|
// Also settles container children/synths and updates bounds; caller retains the identity.
|
||||||
@@ -254,7 +255,7 @@ public:
|
|||||||
lcResult<void> LoadPrimitive(lcLibraryPrimitive* Primitive);
|
lcResult<void> LoadPrimitive(lcLibraryPrimitive* Primitive);
|
||||||
|
|
||||||
bool SupportsStudStyle() const;
|
bool SupportsStudStyle() const;
|
||||||
void SetStudStyle(lcStudStyle StudStyle, bool Reload, bool StudCylinderColorEnabled);
|
void UpdateStudStyleAndColors(lcStudStyle StudStyle, bool StudCylinderColorEnabled);
|
||||||
|
|
||||||
lcStudStyle GetStudStyle() const
|
lcStudStyle GetStudStyle() const
|
||||||
{
|
{
|
||||||
|
|||||||
+14
-4
@@ -339,8 +339,8 @@ buffer upload is not part of asset readiness.
|
|||||||
`LoadPieceInfo()` acquires one reference even if loading fails. Always pair it
|
`LoadPieceInfo()` acquires one reference even if loading fails. Always pair it
|
||||||
with `ReleasePieceInfo()`. Its asynchronous return value means the call did not
|
with `ReleasePieceInfo()`. Its asynchronous return value means the call did not
|
||||||
wait, not that the asset loaded. `AddPieceReference()` retains an identity without
|
wait, not that the asset loaded. `AddPieceReference()` retains an identity without
|
||||||
starting work. `WaitForPieces()` deduplicates its input, temporarily holds
|
starting work. `WaitForPieces()` deduplicates its input without acquiring consumer
|
||||||
each part, and releases those holds before returning.
|
references; callers retain every required identity and its owner through the wait.
|
||||||
|
|
||||||
A part request owns an additional in-flight reference. Removing one instance
|
A part request owns an additional in-flight reference. Removing one instance
|
||||||
cannot destroy an asset still used by another instance or pending work. On the
|
cannot destroy an asset still used by another instance or pending work. On the
|
||||||
@@ -404,7 +404,9 @@ shares its request rather than submitting another build.
|
|||||||
|
|
||||||
`WaitForPieces()` starts or promotes loading as needed, then waits for the supplied
|
`WaitForPieces()` starts or promotes loading as needed, then waits for the supplied
|
||||||
identities, not the entire library. It returns false for failed or cancelled
|
identities, not the entire library. It returns false for failed or cancelled
|
||||||
requirements and does not expand model containers itself. `WaitForSynthMeshes()`
|
requirements and does not expand model containers itself. Callers retain every
|
||||||
|
required identity through the wait; it does not acquire consumer references.
|
||||||
|
`WaitForSynthMeshes()`
|
||||||
promotes and waits for queued generations of the specified instances; callers
|
promotes and waits for queued generations of the specified instances; callers
|
||||||
start generations with `QueueSynthMesh()`. The loader's `WaitForTexture()` starts
|
start generations with `QueueSynthMesh()`. The loader's `WaitForTexture()` starts
|
||||||
or promotes decoding as needed and waits through upload and retries.
|
or promotes decoding as needed and waits through upload and retries.
|
||||||
@@ -421,7 +423,7 @@ workers, including unrelated assets; it is not a scoped success check.
|
|||||||
| Retain and start ordinary asynchronous work | `LoadPieceInfo()` with `lcPieceLoadPriority::Low` for background work or `Normal` for model/view work. Pair every acquisition with `ReleasePieceInfo()`, including failures. |
|
| Retain and start ordinary asynchronous work | `LoadPieceInfo()` with `lcPieceLoadPriority::Low` for background work or `Normal` for model/view work. Pair every acquisition with `ReleasePieceInfo()`, including failures. |
|
||||||
| Retain and synchronously load one identity | `LoadPieceInfo()` with `lcPieceLoadPriority::Blocking`; check its return value and pair the acquisition with `ReleasePieceInfo()`, including failures. |
|
| Retain and synchronously load one identity | `LoadPieceInfo()` with `lcPieceLoadPriority::Blocking`; check its return value and pair the acquisition with `ReleasePieceInfo()`, including failures. |
|
||||||
| Retain without starting work | `AddPieceReference()`, paired with `ReleasePieceInfo()`. This does not make geometry ready. |
|
| Retain without starting work | `AddPieceReference()`, paired with `ReleasePieceInfo()`. This does not make geometry ready. |
|
||||||
| Wait for an explicit part set | `WaitForPieces()` (use `{ Info }` for one identity), check the boolean for strict consumers. Temporary holds end before return, so the caller still needs ownership if it will use the assets afterward. |
|
| Wait for an explicit part set | `WaitForPieces()` (use `{ Info }` for one identity), check the boolean for strict consumers. Retain every identity and its owner throughout the wait; this call acquires no consumer references. |
|
||||||
| Wait for one identity and its container geometry | `EnsurePieceAssetsReady()` settles the identity, then delegates recursive children, synths, and bounds to the model/project API. Retain the identity and its owner throughout. |
|
| Wait for one identity and its container geometry | `EnsurePieceAssetsReady()` settles the identity, then delegates recursive children, synths, and bounds to the model/project API. Retain the identity and its owner throughout. |
|
||||||
| Wait for a model, including nested synths | `WaitForAssets()` for permissive output; `EnsureAssetsReady()` for strict preview-style failure reporting. Keep the model and its pieces alive throughout. |
|
| Wait for a model, including nested synths | `WaitForAssets()` for permissive output; `EnsureAssetsReady()` for strict preview-style failure reporting. Keep the model and its pieces alive throughout. |
|
||||||
| Replace/wait for generated geometry | `QueueSynthMesh()` / `WaitForSynthMeshes()`. Supply live `lcPiece` instances; a shared part mesh or a retained previous generated mesh is not readiness for the replacement. |
|
| Replace/wait for generated geometry | `QueueSynthMesh()` / `WaitForSynthMeshes()`. Supply live `lcPiece` instances; a shared part mesh or a retained previous generated mesh is not readiness for the replacement. |
|
||||||
@@ -522,6 +524,14 @@ Pending jobs remain in the normal piece, texture, and synth queues while paused;
|
|||||||
`mPaused` prevents dispatch. Resume refreshes queued piece source snapshots before
|
`mPaused` prevents dispatch. Resume refreshes queued piece source snapshots before
|
||||||
allowing workers to take jobs again.
|
allowing workers to take jobs again.
|
||||||
|
|
||||||
|
The library constructor receives the effective startup stud settings; application
|
||||||
|
color preferences are applied before loading sources and colors, including the
|
||||||
|
built-in fallback library. `UpdateStudStyleAndColors()` handles runtime changes and always
|
||||||
|
rebuilds affected geometry and drains the resulting work when settings change.
|
||||||
|
The preferences dialog saves a changed color-config path before this setter runs,
|
||||||
|
so simultaneous stud/color changes load the new configuration once. Color-only
|
||||||
|
changes call `LoadColors()` directly.
|
||||||
|
|
||||||
Stud-style changes pause dispatch, finish running phases, discard staging built
|
Stud-style changes pause dispatch, finish running phases, discard staging built
|
||||||
with old settings, refresh sources, and rebuild affected published meshes and
|
with old settings, refresh sources, and rebuild affected published meshes and
|
||||||
generated geometry. The existing style-change path resumes and drains work.
|
generated geometry. The existing style-change path resumes and drains work.
|
||||||
|
|||||||
Reference in new issue
Block a user