From c1d7e986b3071f25e324bcd2780be651c1b02f66 Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Mon, 18 Jan 2021 12:09:33 -0800 Subject: [PATCH] Added stud logo primitives. --- common/lc_library.cpp | 108 +++++++++++++++++++++++---------------- common/lc_library.h | 13 ++--- common/pieceinf.cpp | 2 +- common/pieceinf.h | 5 +- leocad.qrc | 1 + resources/primitives.zip | Bin 0 -> 8933 bytes 6 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 resources/primitives.zip diff --git a/common/lc_library.cpp b/common/lc_library.cpp index f547d072..43d17342 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -69,8 +69,9 @@ void lcPiecesLibrary::Unload() mTextures.clear(); mNumOfficialPieces = 0; - mZipFiles[LC_ZIPFILE_OFFICIAL] = nullptr; - mZipFiles[LC_ZIPFILE_UNOFFICIAL] = nullptr; + + for (std::unique_ptr& ZipFile : mZipFiles) + ZipFile.reset(); } void lcPiecesLibrary::RemoveTemporaryPieces() @@ -250,18 +251,23 @@ bool lcPiecesLibrary::Load(const QString& LibraryPath, bool ShowProgress) return ColorFile.Open(QIODevice::ReadOnly) && lcLoadColorFile(ColorFile); }; - if (OpenArchive(LibraryPath, LC_ZIPFILE_OFFICIAL)) + if (OpenArchive(LibraryPath, lcZipFileType::Official)) { lcMemFile ColorFile; if (!LoadCustomColors()) - if (!mZipFiles[LC_ZIPFILE_OFFICIAL]->ExtractFile("ldraw/ldconfig.ldr", ColorFile) || !lcLoadColorFile(ColorFile)) + if (!mZipFiles[static_cast(lcZipFileType::Official)]->ExtractFile("ldraw/ldconfig.ldr", ColorFile) || !lcLoadColorFile(ColorFile)) lcLoadDefaultColors(); + std::unique_ptr PrimitivesFile(new lcDiskFile(":/resources/primitives.zip")); + + if (PrimitivesFile->Open(QIODevice::ReadOnly)) + OpenArchive(std::move(PrimitivesFile), lcZipFileType::Primitives); + mLibraryDir = QFileInfo(LibraryPath).absoluteDir(); QString UnofficialFileName = mLibraryDir.absoluteFilePath(QLatin1String("ldrawunf.zip")); - if (!OpenArchive(UnofficialFileName, LC_ZIPFILE_UNOFFICIAL)) + if (!OpenArchive(UnofficialFileName, lcZipFileType::Unofficial)) UnofficialFileName.clear(); ReadArchiveDescriptions(LibraryPath, UnofficialFileName); @@ -284,6 +290,11 @@ bool lcPiecesLibrary::Load(const QString& LibraryPath, bool ShowProgress) lcLoadDefaultColors(); } } + + std::unique_ptr PrimitivesFile(new lcDiskFile(":/resources/primitives.zip")); + + if (PrimitivesFile->Open(QIODevice::ReadOnly)) + OpenArchive(std::move(PrimitivesFile), lcZipFileType::Primitives); } else return false; @@ -343,14 +354,14 @@ bool lcPiecesLibrary::OpenArchive(std::unique_ptr File, lcZipFileType Zi { if (!memcmp(Dst, ".PNG", 4)) { - if ((ZipFileType == LC_ZIPFILE_OFFICIAL && !memcmp(Name, "LDRAW/PARTS/TEXTURES/", 21)) || - (ZipFileType == LC_ZIPFILE_UNOFFICIAL && !memcmp(Name, "PARTS/TEXTURES/", 15))) + if ((ZipFileType == lcZipFileType::Official && !memcmp(Name, "LDRAW/PARTS/TEXTURES/", 21)) || + (ZipFileType == lcZipFileType::Unofficial && !memcmp(Name, "PARTS/TEXTURES/", 15))) { lcTexture* Texture = new lcTexture(); mTextures.push_back(Texture); *Dst = 0; - strncpy(Texture->mName, Name + (ZipFileType == LC_ZIPFILE_OFFICIAL ? 21 : 15), sizeof(Texture->mName)-1); + strncpy(Texture->mName, Name + (ZipFileType == lcZipFileType::Official ? 21 : 15), sizeof(Texture->mName)-1); Texture->mName[sizeof(Texture->mName) - 1] = 0; } } @@ -358,7 +369,7 @@ bool lcPiecesLibrary::OpenArchive(std::unique_ptr File, lcZipFileType Zi continue; } - if (ZipFileType == LC_ZIPFILE_OFFICIAL) + if (ZipFileType == lcZipFileType::Official) { if (memcmp(Name, "LDRAW/", 6)) continue; @@ -409,7 +420,7 @@ bool lcPiecesLibrary::OpenArchive(std::unique_ptr File, lcZipFileType Zi } } - mZipFiles[ZipFileType] = std::move(ZipFile); + mZipFiles[static_cast(ZipFileType)] = std::move(ZipFile); return true; } @@ -443,7 +454,7 @@ void lcPiecesLibrary::ReadArchiveDescriptions(const QString& OfficialFileName, c { PieceInfo* Info = PieceIt.second; - mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile, 256); + mZipFiles[static_cast(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile, 256); PieceFile.Seek(0, SEEK_END); PieceFile.WriteU8(0); @@ -534,7 +545,7 @@ bool lcPiecesLibrary::OpenDirectory(const QDir& LibraryDir, bool ShowProgress) mHasUnofficial = true; const bool SubFile = SubFileDirectories[DirectoryIdx]; - mPrimitives[Name] = new lcLibraryPrimitive(std::move(FileName), strchr(FileString, '/') + 1, LC_NUM_ZIPFILES, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile); + mPrimitives[Name] = new lcLibraryPrimitive(std::move(FileName), strchr(FileString, '/') + 1, lcZipFileType::Count, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile); } } } @@ -1182,17 +1193,17 @@ bool lcPiecesLibrary::LoadPieceData(PieceInfo* Info) bool Loaded = false; bool SaveCache = false; - if (Info->mZipFileType != LC_NUM_ZIPFILES && mZipFiles[Info->mZipFileType]) + if (Info->mZipFileType != lcZipFileType::Count && mZipFiles[static_cast(Info->mZipFileType)]) { if (LoadCachePiece(Info)) return true; lcMemFile PieceFile; - if (mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile)) + if (mZipFiles[static_cast(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile)) Loaded = MeshLoader.LoadMesh(PieceFile, LC_MESHDATA_SHARED); - SaveCache = Loaded && (Info->mZipFileType == LC_ZIPFILE_OFFICIAL); + SaveCache = Loaded && (Info->mZipFileType == lcZipFileType::Official); } else { @@ -1239,11 +1250,11 @@ bool lcPiecesLibrary::LoadPieceData(PieceInfo* Info) void lcPiecesLibrary::GetPrimitiveFile(lcLibraryPrimitive* Primitive, std::function Callback) { - if (mZipFiles[LC_ZIPFILE_OFFICIAL]) + if (mZipFiles[static_cast(lcZipFileType::Official)]) { lcMemFile IncludeFile; - if (mZipFiles[Primitive->mZipFileType]->ExtractFile(Primitive->mZipFileIndex, IncludeFile)) + if (mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, IncludeFile)) Callback(IncludeFile); } else @@ -1263,11 +1274,11 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::functionsecond; - if (mZipFiles[LC_ZIPFILE_OFFICIAL] && Info->mZipFileType != LC_NUM_ZIPFILES) + if (mZipFiles[static_cast(lcZipFileType::Official)] && Info->mZipFileType != lcZipFileType::Count) { lcMemFile IncludeFile; - if (mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, IncludeFile)) + if (mZipFiles[static_cast(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, IncludeFile)) Callback(IncludeFile); } else @@ -1298,31 +1309,31 @@ void lcPiecesLibrary::GetPieceFile(const char* PieceName, std::function(lcZipFileType::Official)]) { lcMemFile IncludeFile; - auto LoadIncludeFile = [&IncludeFile, PieceName, this](const char* Folder, int ZipFileIndex) + auto LoadIncludeFile = [&IncludeFile, PieceName, this](const char* Folder, lcZipFileType ZipFileType) { char IncludeFileName[LC_MAXPATH]; sprintf(IncludeFileName, Folder, PieceName); - return mZipFiles[ZipFileIndex]->ExtractFile(IncludeFileName, IncludeFile); + return mZipFiles[static_cast(ZipFileType)]->ExtractFile(IncludeFileName, IncludeFile); }; if (mHasUnofficial) { - Found = LoadIncludeFile("parts/%s", LC_ZIPFILE_UNOFFICIAL); + Found = LoadIncludeFile("parts/%s", lcZipFileType::Unofficial); if (!Found) - Found = LoadIncludeFile("p/%s", LC_ZIPFILE_UNOFFICIAL); + Found = LoadIncludeFile("p/%s", lcZipFileType::Unofficial); } if (!Found) { - Found = LoadIncludeFile("ldraw/parts/%s", LC_ZIPFILE_OFFICIAL); + Found = LoadIncludeFile("ldraw/parts/%s", lcZipFileType::Official); if (!Found) - Found = LoadIncludeFile("ldraw/p/%s", LC_ZIPFILE_OFFICIAL); + Found = LoadIncludeFile("ldraw/p/%s", lcZipFileType::Official); } if (Found) @@ -1451,17 +1462,17 @@ bool lcPiecesLibrary::LoadTexture(lcTexture* Texture) { char FileName[2*LC_MAXPATH]; - if (mZipFiles[LC_ZIPFILE_OFFICIAL]) + if (mZipFiles[static_cast(lcZipFileType::Official)]) { lcMemFile TextureFile; sprintf(FileName, "parts/textures/%s.png", Texture->mName); - if (!mZipFiles[LC_ZIPFILE_UNOFFICIAL] || !mZipFiles[LC_ZIPFILE_UNOFFICIAL]->ExtractFile(FileName, TextureFile)) + if (!mZipFiles[static_cast(lcZipFileType::Unofficial)] || !mZipFiles[static_cast(lcZipFileType::Unofficial)]->ExtractFile(FileName, TextureFile)) { sprintf(FileName, "ldraw/parts/textures/%s.png", Texture->mName); - if (!mZipFiles[LC_ZIPFILE_OFFICIAL]->ExtractFile(FileName, TextureFile)) + if (!mZipFiles[static_cast(lcZipFileType::Official)]->ExtractFile(FileName, TextureFile)) return false; } @@ -1502,7 +1513,7 @@ void lcPiecesLibrary::UploadTextures(lcContext* Context) bool lcPiecesLibrary::SupportsStudLogo() const { - return mZipFiles[LC_ZIPFILE_UNOFFICIAL] || mHasUnofficial; + return mZipFiles[static_cast(lcZipFileType::Primitives)] != nullptr || mHasUnofficial; } void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload) @@ -1587,7 +1598,7 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) bool SetStudLogo = false; - if (mZipFiles[LC_ZIPFILE_OFFICIAL]) + if (mZipFiles[static_cast(lcZipFileType::Official)]) { lcLibraryPrimitive* LowPrimitive = nullptr; @@ -1615,7 +1626,7 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) } } - if (!SetStudLogo && !mZipFiles[Primitive->mZipFileType]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) + if (!SetStudLogo && !mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) return false; if (!LowPrimitive) @@ -1628,7 +1639,7 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_HIGH)) return false; - if (!mZipFiles[LowPrimitive->mZipFileType]->ExtractFile(LowPrimitive->mZipFileIndex, PrimFile)) + if (!mZipFiles[static_cast(LowPrimitive->mZipFileType)]->ExtractFile(LowPrimitive->mZipFileIndex, PrimFile)) return false; if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_LOW)) @@ -1656,10 +1667,23 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) if (!SetStudLogo) { - lcDiskFile PrimFile(Primitive->mFileName); + if (Primitive->mZipFileType == lcZipFileType::Count) + { + lcDiskFile PrimFile(Primitive->mFileName); - if (!PrimFile.Open(QIODevice::ReadOnly) || !MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) // todo: LOD like the zip files - return false; + if (!PrimFile.Open(QIODevice::ReadOnly) || !MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) // todo: LOD like the zip files + return false; + } + else + { + lcMemFile PrimFile; + + if (!mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) + return false; + + if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) + return false; + } } } @@ -1824,15 +1848,9 @@ std::string lcPiecesLibrary::GetPartId(const PieceInfo* Info) const bool lcPiecesLibrary::LoadBuiltinPieces() { - QResource Resource(":/resources/library.zip"); + std::unique_ptr File(new lcDiskFile(":/resources/library.zip")); - if (!Resource.isValid()) - return false; - - std::unique_ptr File(new lcMemFile()); - File->WriteBuffer(Resource.data(), Resource.size()); - - if (!OpenArchive(std::move(File), LC_ZIPFILE_OFFICIAL)) + if (!OpenArchive(std::move(File), lcZipFileType::Official)) return false; lcMemFile PieceFile; @@ -1841,7 +1859,7 @@ bool lcPiecesLibrary::LoadBuiltinPieces() { PieceInfo* Info = PieceIt.second; - mZipFiles[Info->mZipFileType]->ExtractFile(Info->mZipFileIndex, PieceFile, 256); + mZipFiles[static_cast(Info->mZipFileType)]->ExtractFile(Info->mZipFileIndex, PieceFile, 256); PieceFile.Seek(0, SEEK_END); PieceFile.WriteU8(0); diff --git a/common/lc_library.h b/common/lc_library.h index 0e889203..e18363aa 100644 --- a/common/lc_library.h +++ b/common/lc_library.h @@ -10,11 +10,12 @@ class PieceInfo; class lcZipFile; class lcLibraryMeshData; -enum lcZipFileType +enum class lcZipFileType { - LC_ZIPFILE_OFFICIAL, - LC_ZIPFILE_UNOFFICIAL, - LC_NUM_ZIPFILES + Official, + Unofficial, + Primitives, + Count }; enum lcLibraryFolderType @@ -137,7 +138,7 @@ public: void SetOfficialPieces() { - if (mZipFiles[LC_ZIPFILE_OFFICIAL]) + if (mZipFiles[static_cast(lcZipFileType::Official)]) mNumOfficialPieces = (int)mPieces.size(); } @@ -194,7 +195,7 @@ protected: QString mCachePath; qint64 mArchiveCheckSum[4]; - std::unique_ptr mZipFiles[LC_NUM_ZIPFILES]; + std::unique_ptr mZipFiles[static_cast(lcZipFileType::Count)]; bool mHasUnofficial; bool mCancelLoading; }; diff --git a/common/pieceinf.cpp b/common/pieceinf.cpp index a512c410..85e8ca44 100644 --- a/common/pieceinf.cpp +++ b/common/pieceinf.cpp @@ -16,7 +16,7 @@ PieceInfo::PieceInfo() { - mZipFileType = LC_NUM_ZIPFILES; + mZipFileType = lcZipFileType::Count; mZipFileIndex = -1; mState = LC_PIECEINFO_UNLOADED; mRefCount = 0; diff --git a/common/pieceinf.h b/common/pieceinf.h index 68829eb9..b38c10f6 100644 --- a/common/pieceinf.h +++ b/common/pieceinf.h @@ -30,6 +30,7 @@ struct lcModelPartsEntry }; class lcSynthInfo; +enum class lcZipFileType; class PieceInfo { @@ -117,7 +118,7 @@ public: return mType != lcPieceInfoType::Part; } - void SetZipFile(int ZipFileType, int ZipFileIndex) + void SetZipFile(lcZipFileType ZipFileType, int ZipFileIndex) { mZipFileType = ZipFileType; mZipFileIndex = ZipFileIndex; @@ -182,7 +183,7 @@ public: public: char mFileName[LC_PIECE_NAME_LEN]; char m_strDescription[128]; - int mZipFileType; + lcZipFileType mZipFileType; int mZipFileIndex; lcPieceInfoState mState; int mFolderType; diff --git a/leocad.qrc b/leocad.qrc index 354a7fd0..1da3a222 100644 --- a/leocad.qrc +++ b/leocad.qrc @@ -96,6 +96,7 @@ resources/parts_cancel.png resources/archive.png resources/library.zip + resources/primitives.zip resources/ldconfig.ldr resources/minifig.ini resources/ldraw.xml diff --git a/resources/primitives.zip b/resources/primitives.zip new file mode 100644 index 0000000000000000000000000000000000000000..27b0ba7d27bd4c4b48948cf2ccf88769ff663139 GIT binary patch literal 8933 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 F@P9PIA=Cf> literal 0 HcmV?d00001