From f06a231816ca58e3fabc9e7d74786cae87dcbcaf Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Thu, 11 Jul 2024 15:04:07 -0700 Subject: [PATCH] Added thumbnail manager. --- common/lc_library.cpp | 3 + common/lc_library.h | 7 + common/lc_mainwindow.cpp | 2 +- common/lc_partselectionwidget.cpp | 219 +++++++++--------------------- common/lc_partselectionwidget.h | 29 ++-- common/lc_thumbnailmanager.cpp | 148 ++++++++++++++++++++ common/lc_thumbnailmanager.h | 45 ++++++ leocad.pro | 46 ++++--- 8 files changed, 307 insertions(+), 192 deletions(-) create mode 100644 common/lc_thumbnailmanager.cpp create mode 100644 common/lc_thumbnailmanager.h diff --git a/common/lc_library.cpp b/common/lc_library.cpp index 37ecbe06..ecfe142a 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -1,5 +1,6 @@ #include "lc_global.h" #include "lc_library.h" +#include "lc_thumbnailmanager.h" #include "lc_zipfile.h" #include "lc_file.h" #include "pieceinf.h" @@ -33,6 +34,7 @@ lcPiecesLibrary::lcPiecesLibrary() : mLoadMutex(QMutex::Recursive) #endif { + mThumbnailManager = std::unique_ptr(new lcThumbnailManager(this)); QStringList cachePathList = QStandardPaths::standardLocations(QStandardPaths::CacheLocation); mCachePath = cachePathList.first(); @@ -49,6 +51,7 @@ lcPiecesLibrary::lcPiecesLibrary() lcPiecesLibrary::~lcPiecesLibrary() { + mThumbnailManager.reset(); mLoadMutex.lock(); mLoadQueue.clear(); mLoadMutex.unlock(); diff --git a/common/lc_library.h b/common/lc_library.h index b626fbc4..a1d90c84 100644 --- a/common/lc_library.h +++ b/common/lc_library.h @@ -7,6 +7,7 @@ class PieceInfo; class lcZipFile; class lcLibraryMeshData; +class lcThumbnailManager; enum class lcStudStyle { @@ -126,6 +127,11 @@ public: lcPiecesLibrary& operator=(const lcPiecesLibrary&) = delete; lcPiecesLibrary& operator=(lcPiecesLibrary&&) = delete; + lcThumbnailManager* GetThumbnailManager() const + { + return mThumbnailManager.get(); + } + bool Load(const QString& LibraryPath, bool ShowProgress); void LoadColors(); void Unload(); @@ -234,6 +240,7 @@ protected: lcStudStyle mStudStyle; bool mStudCylinderColorEnabled; + std::unique_ptr mThumbnailManager; QString mCachePath; qint64 mArchiveCheckSum[4]; std::unique_ptr mZipFiles[static_cast(lcZipFileType::Count)]; diff --git a/common/lc_mainwindow.cpp b/common/lc_mainwindow.cpp index fbfdcdd2..9fb3b7e9 100644 --- a/common/lc_mainwindow.cpp +++ b/common/lc_mainwindow.cpp @@ -1341,7 +1341,7 @@ void lcMainWindow::SetShadingMode(lcShadingMode ShadingMode) lcView::UpdateAllViews(); if (mPartSelectionWidget) - mPartSelectionWidget->Redraw(); + mPartSelectionWidget->UpdateThumbnails(); } void lcMainWindow::SetSelectionMode(lcSelectionMode SelectionMode) diff --git a/common/lc_partselectionwidget.cpp b/common/lc_partselectionwidget.cpp index 6200354a..3fe31817 100644 --- a/common/lc_partselectionwidget.cpp +++ b/common/lc_partselectionwidget.cpp @@ -5,12 +5,9 @@ #include "lc_application.h" #include "lc_mainwindow.h" #include "lc_library.h" -#include "lc_model.h" +#include "lc_thumbnailmanager.h" #include "project.h" #include "pieceinf.h" -#include "camera.h" -#include "lc_scene.h" -#include "lc_view.h" #include "lc_glextensions.h" #include "lc_category.h" @@ -18,7 +15,7 @@ Q_DECLARE_METATYPE(QList) void lcPartSelectionItemDelegate::paint(QPainter* Painter, const QStyleOptionViewItem& Option, const QModelIndex& Index) const { - mListModel->RequestPreview(Index.row()); + mListModel->RequestThumbnail(Index.row()); QStyledItemDelegate::paint(Painter, Option, Index); } @@ -60,38 +57,19 @@ lcPartSelectionListModel::lcPartSelectionListModel(QObject* Parent) mColorLocked = true; } - connect(lcGetPiecesLibrary(), &lcPiecesLibrary::PartLoaded, this, &lcPartSelectionListModel::PartLoaded); + connect(lcGetPiecesLibrary()->GetThumbnailManager(), &lcThumbnailManager::ThumbnailReady, this, &lcPartSelectionListModel::ThumbnailReady); } lcPartSelectionListModel::~lcPartSelectionListModel() { - ClearRequests(); - - mView.reset(); - mModel.reset(); + ReleaseThumbnails(); } -void lcPartSelectionListModel::ClearRequests() +void lcPartSelectionListModel::UpdateThumbnails() { - lcPiecesLibrary* Library = lcGetPiecesLibrary(); - - for (int RequestIdx : mRequestedPreviews) - { - PieceInfo* Info = mParts[RequestIdx].first; - Library->ReleasePieceInfo(Info); - } - - mRequestedPreviews.clear(); -} - -void lcPartSelectionListModel::Redraw() -{ - ClearRequests(); - beginResetModel(); - for (size_t PartIdx = 0; PartIdx < mParts.size(); PartIdx++) - mParts[PartIdx].second = QPixmap(); + ReleaseThumbnails(); endResetModel(); @@ -103,8 +81,9 @@ void lcPartSelectionListModel::SetColorIndex(int ColorIndex) if (mColorLocked || ColorIndex == mColorIndex) return; + UpdateThumbnails(); + mColorIndex = ColorIndex; - Redraw(); } void lcPartSelectionListModel::ToggleColorLocked() @@ -125,10 +104,10 @@ void lcPartSelectionListModel::ToggleListMode() void lcPartSelectionListModel::SetCategory(int CategoryIndex) { - ClearRequests(); - beginResetModel(); + ReleaseThumbnails(); + lcPiecesLibrary* Library = lcGetPiecesLibrary(); std::vector SingleParts, GroupedParts; @@ -160,8 +139,8 @@ void lcPartSelectionListModel::SetCategory(int CategoryIndex) mParts.resize(SingleParts.size()); - for (size_t PartIdx = 0; PartIdx < SingleParts.size(); PartIdx++) - mParts[PartIdx] = std::pair(SingleParts[PartIdx], QPixmap()); + for (size_t PartIndex = 0; PartIndex < SingleParts.size(); PartIndex++) + mParts[PartIndex].Info = SingleParts[PartIndex]; endResetModel(); @@ -170,10 +149,9 @@ void lcPartSelectionListModel::SetCategory(int CategoryIndex) void lcPartSelectionListModel::SetModelsCategory() { - ClearRequests(); - beginResetModel(); + ReleaseThumbnails(); mParts.clear(); const std::vector>& Models = lcGetActiveProject()->GetModels(); @@ -181,11 +159,11 @@ void lcPartSelectionListModel::SetModelsCategory() for (const std::unique_ptr& Model : Models) if (!Model->IncludesModel(ActiveModel)) - mParts.emplace_back(std::pair(Model->GetPieceInfo(), QPixmap())); + mParts.emplace_back().Info = Model->GetPieceInfo(); - auto lcPartSortFunc = [](const std::pair& a, const std::pair& b) + auto lcPartSortFunc = [](const lcPartSelectionListModelEntry& a, const lcPartSelectionListModelEntry& b) { - return strcmp(a.first->m_strDescription, b.first->m_strDescription) < 0; + return strcmp(a.Info->m_strDescription, b.Info->m_strDescription) < 0; }; std::sort(mParts.begin(), mParts.end(), lcPartSortFunc); @@ -197,10 +175,9 @@ void lcPartSelectionListModel::SetModelsCategory() void lcPartSelectionListModel::SetPaletteCategory(int SetIndex) { - ClearRequests(); - beginResetModel(); + ReleaseThumbnails(); mParts.clear(); lcPartSelectionWidget* PartSelectionWidget = mListView->GetPartSelectionWidget(); @@ -216,8 +193,8 @@ void lcPartSelectionListModel::SetPaletteCategory(int SetIndex) mParts.reserve(PartsList.size()); - for (PieceInfo* Favorite : PartsList) - mParts.emplace_back(std::pair(Favorite, QPixmap())); + for (PieceInfo* Info : PartsList) + mParts.emplace_back().Info = Info; endResetModel(); @@ -226,10 +203,9 @@ void lcPartSelectionListModel::SetPaletteCategory(int SetIndex) void lcPartSelectionListModel::SetCurrentModelCategory() { - ClearRequests(); - beginResetModel(); + ReleaseThumbnails(); mParts.clear(); lcModel* ActiveModel = gMainWindow->GetActiveModel(); @@ -239,11 +215,11 @@ void lcPartSelectionListModel::SetCurrentModelCategory() ActiveModel->GetPartsList(gDefaultColor, true, true, PartsList); for (const auto& PartIt : PartsList) - mParts.emplace_back(std::pair((PieceInfo*)PartIt.first, QPixmap())); + mParts.emplace_back().Info = (PieceInfo*)PartIt.first; - auto lcPartSortFunc = [](const std::pair& a, const std::pair& b) + auto lcPartSortFunc = [](const lcPartSelectionListModelEntry& a, const lcPartSelectionListModelEntry& b) { - return strcmp(a.first->m_strDescription, b.first->m_strDescription) < 0; + return strcmp(a.Info->m_strDescription, b.Info->m_strDescription) < 0; }; std::sort(mParts.begin(), mParts.end(), lcPartSortFunc); @@ -259,7 +235,7 @@ void lcPartSelectionListModel::SetFilter(const QString& Filter) for (size_t PartIdx = 0; PartIdx < mParts.size(); PartIdx++) { - PieceInfo* Info = mParts[PartIdx].first; + PieceInfo* Info = mParts[PartIdx].Info; bool Visible; if (!mShowDecoratedParts && Info->IsPatterned() && !Info->IsProjectPiece()) @@ -307,7 +283,7 @@ QVariant lcPartSelectionListModel::data(const QModelIndex& Index, int Role) cons if (Index.isValid() && InfoIndex < mParts.size()) { - PieceInfo* Info = mParts[InfoIndex].first; + PieceInfo* Info = mParts[InfoIndex].Info; switch (Role) { @@ -320,8 +296,8 @@ QVariant lcPartSelectionListModel::data(const QModelIndex& Index, int Role) cons return QVariant(QString("%1 (%2)").arg(QString::fromLatin1(Info->m_strDescription), QString::fromLatin1(Info->mFileName))); case Qt::DecorationRole: - if (!mParts[InfoIndex].second.isNull() && mIconSize) - return QVariant(mParts[InfoIndex].second); + if (mIconSize && !mParts[InfoIndex].Pixmap.isNull()) + return QVariant(mParts[InfoIndex].Pixmap); else return QVariant(QColor(0, 0, 0, 0)); @@ -351,119 +327,51 @@ Qt::ItemFlags lcPartSelectionListModel::flags(const QModelIndex& Index) const return DefaultFlags; } -void lcPartSelectionListModel::RequestPreview(int InfoIndex) +void lcPartSelectionListModel::ReleaseThumbnails() { - if (!mIconSize || !mParts[InfoIndex].second.isNull()) - return; + lcThumbnailManager* ThumbnailManager = lcGetPiecesLibrary()->GetThumbnailManager(); - if (std::find(mRequestedPreviews.begin(), mRequestedPreviews.end(), InfoIndex) != mRequestedPreviews.end()) - return; - - PieceInfo* Info = mParts[InfoIndex].first; - lcGetPiecesLibrary()->LoadPieceInfo(Info, false, false); - - if (Info->mState == lcPieceInfoState::Loaded) - DrawPreview(InfoIndex); - else - mRequestedPreviews.push_back(InfoIndex); + for (lcPartSelectionListModelEntry& Part : mParts) + { + ThumbnailManager->ReleaseThumbnail(Part.ThumbnailId); + Part.ThumbnailId = lcPartThumbnailId::Invalid; + Part.Pixmap = QPixmap(); + } } -void lcPartSelectionListModel::PartLoaded(PieceInfo* Info) +void lcPartSelectionListModel::RequestThumbnail(int PartIndex) { - for (size_t PartIdx = 0; PartIdx < mParts.size(); PartIdx++) + if (!mIconSize || !mParts[PartIndex].Pixmap.isNull() || mParts[PartIndex].ThumbnailId != lcPartThumbnailId::Invalid) + return; + + PieceInfo* Info = mParts[PartIndex].Info; + auto [ThumbnailId, Thumbnail] = lcGetPiecesLibrary()->GetThumbnailManager()->RequestThumbnail(Info, mColorIndex, mIconSize); + + mParts[PartIndex].ThumbnailId = ThumbnailId; + + if (!Thumbnail.isNull()) { - if (mParts[PartIdx].first == Info) + mParts[PartIndex].Pixmap = Thumbnail; + + emit dataChanged(index(PartIndex, 0), index(PartIndex, 0), { Qt::DecorationRole }); + } +} + +void lcPartSelectionListModel::ThumbnailReady(lcPartThumbnailId ThumbnailId, QPixmap Pixmap) +{ + for (int PartIndex = 0; PartIndex < static_cast(mParts.size()); PartIndex++) + { + if (mParts[PartIndex].ThumbnailId == ThumbnailId) { - auto PreviewIt = std::find(mRequestedPreviews.begin(), mRequestedPreviews.end(), static_cast(PartIdx)); - if (PreviewIt != mRequestedPreviews.end()) - { - mRequestedPreviews.erase(PreviewIt); - DrawPreview((int)PartIdx); - } + mParts[PartIndex].Pixmap = Pixmap; + + emit dataChanged(index(PartIndex, 0), index(PartIndex, 0), { Qt::DecorationRole }); + break; } } } -void lcPartSelectionListModel::DrawPreview(int InfoIndex) -{ - const int Width = mIconSize * 2; - const int Height = mIconSize * 2; - - if (mView && (mView->GetWidth() != Width || mView->GetHeight() != Height)) - mView.reset(); - - if (!mView) - { - if (!mModel) - mModel = std::unique_ptr(new lcModel(QString(), nullptr, true)); - mView = std::unique_ptr(new lcView(lcViewType::PartsList, mModel.get())); - - mView->SetOffscreenContext(); - mView->MakeCurrent(); - mView->SetSize(Width, Height); - - if (!mView->BeginRenderToImage(Width, Height)) - { - mView.reset(); - return; - } - } - - mView->MakeCurrent(); - mView->BindRenderFramebuffer(); - - const uint BackgroundColor = mListView->palette().color(QPalette::Base).rgba(); - mView->SetBackgroundColorOverride(LC_RGBA(qRed(BackgroundColor), qGreen(BackgroundColor), qBlue(BackgroundColor), 0)); - - PieceInfo* Info = mParts[InfoIndex].first; - mModel->SetPreviewPieceInfo(Info, mColorIndex); - - const lcVector3 Center = (Info->GetBoundingBox().Min + Info->GetBoundingBox().Max) / 2.0f; - const lcVector3 Position = Center + lcVector3(100.0f, -100.0f, 75.0f); - - mView->GetCamera()->SetViewpoint(Position, Center, lcVector3(0, 0, 1)); - mView->GetCamera()->m_fovy = 20.0f; - mView->ZoomExtents(); - - mView->OnDraw(); - - mView->UnbindRenderFramebuffer(); - - QImage Image = mView->GetRenderFramebufferImage().convertToFormat(QImage::Format_ARGB32); - - if (Info->GetSynthInfo()) - { - QPainter Painter(&Image); - QImage Icon = QImage(":/resources/flexible.png"); - uchar* ImageBits = Icon.bits(); - QRgb TextColor = mListView->palette().color(QPalette::WindowText).rgba(); - int Red = qRed(TextColor); - int Green = qGreen(TextColor); - int Blue = qBlue(TextColor); - - for (int y = 0; y < Icon.height(); y++) - { - for (int x = 0; x < Icon.width(); x++) - { - QRgb& Pixel = ((QRgb*)ImageBits)[x]; - Pixel = qRgba(Red, Green, Blue, qAlpha(Pixel)); - } - - ImageBits += Icon.bytesPerLine(); - } - - Painter.drawImage(QPoint(0, 0), Icon); - Painter.end(); - } - - mParts[InfoIndex].second = QPixmap::fromImage(Image).scaled(mIconSize, mIconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - - lcGetPiecesLibrary()->ReleasePieceInfo(Info); - - emit dataChanged(index(InfoIndex, 0), index(InfoIndex, 0), QVector() << Qt::DecorationRole); -} - void lcPartSelectionListModel::SetShowDecoratedParts(bool Show) { if (Show == mShowDecoratedParts) @@ -493,8 +401,7 @@ void lcPartSelectionListModel::SetIconSize(int Size) beginResetModel(); - for (size_t PartIdx = 0; PartIdx < mParts.size(); PartIdx++) - mParts[PartIdx].second = QPixmap(); + ReleaseThumbnails(); endResetModel(); @@ -1036,9 +943,9 @@ void lcPartSelectionWidget::EditPartPalettes() UpdateCategories(); } -void lcPartSelectionWidget::Redraw() +void lcPartSelectionWidget::UpdateThumbnails() { - mPartsWidget->GetListModel()->Redraw(); + mPartsWidget->GetListModel()->UpdateThumbnails(); } void lcPartSelectionWidget::SetDefaultPart() diff --git a/common/lc_partselectionwidget.h b/common/lc_partselectionwidget.h index bda09014..f1f1ba3e 100644 --- a/common/lc_partselectionwidget.h +++ b/common/lc_partselectionwidget.h @@ -1,6 +1,6 @@ #pragma once -#include "lc_context.h" +#include "lc_thumbnailmanager.h" class lcPartSelectionListModel; class lcPartSelectionListView; @@ -45,6 +45,13 @@ protected: lcPartSelectionListModel* mListModel; }; +struct lcPartSelectionListModelEntry +{ + PieceInfo* Info = nullptr; + QPixmap Pixmap; + lcPartThumbnailId ThumbnailId = lcPartThumbnailId::Invalid; +}; + class lcPartSelectionListModel : public QAbstractListModel { Q_OBJECT @@ -60,12 +67,12 @@ public: PieceInfo* GetPieceInfo(const QModelIndex& Index) const { - return Index.isValid() ? mParts[Index.row()].first : nullptr; + return Index.isValid() ? mParts[Index.row()].Info : nullptr; } PieceInfo* GetPieceInfo(int Row) const { - return mParts[Row].first; + return mParts[Row].Info; } bool GetShowDecoratedParts() const @@ -103,7 +110,7 @@ public: return mListMode; } - void Redraw(); + void UpdateThumbnails(); void SetColorIndex(int ColorIndex); void ToggleColorLocked(); void ToggleListMode(); @@ -112,22 +119,20 @@ public: void SetPaletteCategory(int SetIndex); void SetCurrentModelCategory(); void SetFilter(const QString& Filter); - void RequestPreview(int InfoIndex); + void RequestThumbnail(int PartIndex); void SetShowDecoratedParts(bool Show); void SetShowPartAliases(bool Show); void SetIconSize(int Size); void SetShowPartNames(bool Show); protected slots: - void PartLoaded(PieceInfo* Info); + void ThumbnailReady(lcPartThumbnailId ThumbnailId, QPixmap Pixmap); protected: - void ClearRequests(); - void DrawPreview(int InfoIndex); + void ReleaseThumbnails(); lcPartSelectionListView* mListView; - std::vector> mParts; - std::vector mRequestedPreviews; + std::vector mParts; int mIconSize; bool mColorLocked; int mColorIndex; @@ -136,8 +141,6 @@ protected: bool mShowDecoratedParts; bool mShowPartAliases; QByteArray mFilter; - std::unique_ptr mView; - std::unique_ptr mModel; }; class lcPartSelectionListView : public QListView @@ -205,7 +208,7 @@ class lcPartSelectionWidget : public QWidget public: lcPartSelectionWidget(QWidget* Parent); - void Redraw(); + void UpdateThumbnails(); void SetDefaultPart(); void UpdateModels(); void UpdateCategories(); diff --git a/common/lc_thumbnailmanager.cpp b/common/lc_thumbnailmanager.cpp new file mode 100644 index 00000000..50ef7e44 --- /dev/null +++ b/common/lc_thumbnailmanager.cpp @@ -0,0 +1,148 @@ +#include "lc_global.h" +#include "lc_thumbnailmanager.h" +#include "lc_library.h" +#include "pieceinf.h" +#include "lc_view.h" +#include "lc_model.h" +#include "camera.h" + +lcThumbnailManager::lcThumbnailManager(lcPiecesLibrary* Library) + : QObject(Library), mLibrary(Library) +{ + connect(mLibrary, &lcPiecesLibrary::PartLoaded, this, &lcThumbnailManager::PartLoaded); +} + +lcThumbnailManager::~lcThumbnailManager() +{ + for (auto &[ThumbnailId, Thumbnail] : mThumbnails) + if (Thumbnail.Pixmap.isNull()) + mLibrary->ReleasePieceInfo(Thumbnail.Info); +} + +std::pair lcThumbnailManager::RequestThumbnail(PieceInfo* Info, int ColorIndex, int Size) +{ + for (auto &[ThumbnailId, Thumbnail] : mThumbnails) + if (Thumbnail.Info == Info && Thumbnail.ColorIndex == ColorIndex && Thumbnail.Size == Size) + return { ThumbnailId, Thumbnail.Pixmap }; + + lcPartThumbnailId ThumbnailId = static_cast(mNextThumbnailId++); + lcPartThumbnail& Thumbnail = mThumbnails[ThumbnailId]; + + Thumbnail.Info = Info; + Thumbnail.ColorIndex = ColorIndex; + Thumbnail.Size = Size; + Thumbnail.ReferenceCount = 1; + + mLibrary->LoadPieceInfo(Info, false, false); + + if (Info->mState == lcPieceInfoState::Loaded) + DrawThumbnail(ThumbnailId, Thumbnail); + + return { ThumbnailId, Thumbnail.Pixmap }; +} + +void lcThumbnailManager::ReleaseThumbnail(lcPartThumbnailId ThumbnailId) +{ + auto ThumbnailIt = mThumbnails.find(ThumbnailId); + + if (ThumbnailIt == mThumbnails.end()) + return; + + lcPartThumbnail& Thumbnail = ThumbnailIt->second; + + Thumbnail.ReferenceCount--; + + if (Thumbnail.ReferenceCount == 0) + { + if (Thumbnail.Pixmap.isNull()) + mLibrary->ReleasePieceInfo(Thumbnail.Info); + + mThumbnails.erase(ThumbnailIt); + } +} + +void lcThumbnailManager::PartLoaded(PieceInfo* Info) +{ + for (auto& [ThumbnailId, Thumbnail] : mThumbnails) + if (Thumbnail.Info == Info && Thumbnail.Pixmap.isNull()) + DrawThumbnail(ThumbnailId, Thumbnail); +} + +void lcThumbnailManager::DrawThumbnail(lcPartThumbnailId ThumbnailId, lcPartThumbnail& Thumbnail) +{ + const int Width = Thumbnail.Size * 2; + const int Height = Thumbnail.Size * 2; + + if (mView && (mView->GetWidth() != Width || mView->GetHeight() != Height)) + mView.reset(); + + if (!mView) + { + if (!mModel) + mModel = std::unique_ptr(new lcModel(QString(), nullptr, true)); + mView = std::unique_ptr(new lcView(lcViewType::PartsList, mModel.get())); + + mView->SetOffscreenContext(); + mView->MakeCurrent(); + mView->SetSize(Width, Height); + + if (!mView->BeginRenderToImage(Width, Height)) + { + mView.reset(); + return; + } + } + + mView->MakeCurrent(); + mView->BindRenderFramebuffer(); + + const uint BackgroundColor = QApplication::palette().color(QPalette::Base).rgba(); + mView->SetBackgroundColorOverride(LC_RGBA(qRed(BackgroundColor), qGreen(BackgroundColor), qBlue(BackgroundColor), 0)); + + PieceInfo* Info = Thumbnail.Info; + mModel->SetPreviewPieceInfo(Info, Thumbnail.ColorIndex); + + const lcVector3 Center = (Info->GetBoundingBox().Min + Info->GetBoundingBox().Max) / 2.0f; + const lcVector3 Position = Center + lcVector3(100.0f, -100.0f, 75.0f); + + mView->GetCamera()->SetViewpoint(Position, Center, lcVector3(0, 0, 1)); + mView->GetCamera()->m_fovy = 20.0f; + mView->ZoomExtents(); + + mView->OnDraw(); + + mView->UnbindRenderFramebuffer(); + + QImage Image = mView->GetRenderFramebufferImage().convertToFormat(QImage::Format_ARGB32); + + if (Info->GetSynthInfo()) + { + QPainter Painter(&Image); + QImage Icon = QImage(":/resources/flexible.png"); + uchar* ImageBits = Icon.bits(); + QRgb TextColor = QApplication::palette().color(QPalette::WindowText).rgba(); + int Red = qRed(TextColor); + int Green = qGreen(TextColor); + int Blue = qBlue(TextColor); + + for (int y = 0; y < Icon.height(); y++) + { + for (int x = 0; x < Icon.width(); x++) + { + QRgb& Pixel = ((QRgb*)ImageBits)[x]; + Pixel = qRgba(Red, Green, Blue, qAlpha(Pixel)); + } + + ImageBits += Icon.bytesPerLine(); + } + + Painter.drawImage(QPoint(0, 0), Icon); + Painter.end(); + } + + Thumbnail.Pixmap = QPixmap::fromImage(Image).scaled(Thumbnail.Size, Thumbnail.Size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + mLibrary->ReleasePieceInfo(Info); + + emit ThumbnailReady(ThumbnailId, Thumbnail.Pixmap); +} diff --git a/common/lc_thumbnailmanager.h b/common/lc_thumbnailmanager.h new file mode 100644 index 00000000..6d94f36e --- /dev/null +++ b/common/lc_thumbnailmanager.h @@ -0,0 +1,45 @@ +#pragma once + +class lcPiecesLibrary; + +struct lcPartThumbnail +{ + QPixmap Pixmap; + PieceInfo* Info; + int ColorIndex; + int Size; + int ReferenceCount; +}; + +enum class lcPartThumbnailId : uint64_t +{ + Invalid = 0 +}; + +class lcThumbnailManager : public QObject +{ + Q_OBJECT + +public: + lcThumbnailManager(lcPiecesLibrary* Library); + ~lcThumbnailManager(); + + std::pair RequestThumbnail(PieceInfo* Info, int ColorIndex, int Size); + void ReleaseThumbnail(lcPartThumbnailId ThumbnailId); + +signals: + void ThumbnailReady(lcPartThumbnailId ThumbnailId, QPixmap Pixmap); + +protected slots: + void PartLoaded(PieceInfo* Info); + +protected: + void DrawThumbnail(lcPartThumbnailId ThumbnailId, lcPartThumbnail& Thumbnail); + + lcPiecesLibrary* mLibrary = nullptr; + std::map mThumbnails; + int mNextThumbnailId = 1; + + std::unique_ptr mView; + std::unique_ptr mModel; +}; diff --git a/leocad.pro b/leocad.pro index 0c5b6dcf..6aac24a6 100644 --- a/leocad.pro +++ b/leocad.pro @@ -165,13 +165,16 @@ macx { } SOURCES += \ - common/texfont.cpp \ - common/project.cpp \ - common/pieceinf.cpp \ - common/piece.cpp \ - common/object.cpp \ - common/minifig.cpp \ + common/camera.cpp \ + common/group.cpp \ + common/image.cpp \ common/light.cpp \ + common/minifig.cpp \ + common/object.cpp \ + common/piece.cpp \ + common/pieceinf.cpp \ + common/project.cpp \ + common/texfont.cpp \ common/lc_aboutdialog.cpp \ common/lc_application.cpp \ common/lc_arraydialog.cpp \ @@ -204,6 +207,7 @@ SOURCES += \ common/lc_modellistdialog.cpp \ common/lc_objectproperty.cpp \ common/lc_pagesetupdialog.cpp \ + common/lc_partpalettedialog.cpp \ common/lc_partselectionwidget.cpp \ common/lc_previewwidget.cpp \ common/lc_profile.cpp \ @@ -213,15 +217,13 @@ SOURCES += \ common/lc_stringcache.cpp \ common/lc_synth.cpp \ common/lc_texture.cpp \ + common/lc_thumbnailmanager.cpp \ common/lc_timelinewidget.cpp \ common/lc_view.cpp \ common/lc_viewmanipulator.cpp \ common/lc_viewsphere.cpp \ common/lc_viewwidget.cpp \ common/lc_zipfile.cpp \ - common/image.cpp \ - common/group.cpp \ - common/camera.cpp \ qt/system.cpp \ qt/qtmain.cpp \ qt/lc_qeditgroupsdialog.cpp \ @@ -233,16 +235,18 @@ SOURCES += \ qt/lc_qupdatedialog.cpp \ qt/lc_qutils.cpp \ qt/lc_renderdialog.cpp \ - qt/lc_setsdatabasedialog.cpp \ - common/lc_partpalettedialog.cpp + qt/lc_setsdatabasedialog.cpp HEADERS += \ - common/texfont.h \ - common/project.h \ - common/pieceinf.h \ - common/piece.h \ - common/object.h \ - common/minifig.h \ + common/camera.h \ + common/group.h \ + common/image.h \ common/light.h \ + common/minifig.h \ + common/object.h \ + common/piece.h \ + common/pieceinf.h \ + common/project.h \ + common/texfont.h \ common/lc_aboutdialog.h \ common/lc_application.h \ common/lc_arraydialog.h \ @@ -277,6 +281,7 @@ HEADERS += \ common/lc_modellistdialog.h \ common/lc_objectproperty.h \ common/lc_pagesetupdialog.h \ + common/lc_partselectionwidget.h \ common/lc_previewwidget.h \ common/lc_profile.h \ common/lc_propertieswidget.h \ @@ -285,16 +290,13 @@ HEADERS += \ common/lc_stringcache.h \ common/lc_synth.h \ common/lc_texture.h \ + common/lc_thumbnailmanager.h \ + common/lc_timelinewidget.h \ common/lc_view.h \ common/lc_viewmanipulator.h \ common/lc_viewsphere.h \ common/lc_viewwidget.h \ common/lc_zipfile.h \ - common/lc_partselectionwidget.h \ - common/lc_timelinewidget.h \ - common/image.h \ - common/group.h \ - common/camera.h \ qt/lc_qeditgroupsdialog.h \ qt/lc_qselectdialog.h \ qt/lc_qpropertiesdialog.h \