From a8d757c0c4344dcbbcc8fb0541c8fe50dc2458ef Mon Sep 17 00:00:00 2001 From: Leonardo Zide Date: Mon, 18 Jan 2021 15:23:13 -0800 Subject: [PATCH] Added a system to override primitives and updated the stud logos to use it. --- common/lc_library.cpp | 161 +++++++++++++++++---------------------- common/lc_library.h | 38 +++++---- leocad.qrc | 6 +- resources/primitives.zip | Bin 8933 -> 0 bytes resources/studlogo1.zip | Bin 0 -> 483 bytes resources/studlogo2.zip | Bin 0 -> 484 bytes resources/studlogo3.zip | Bin 0 -> 485 bytes resources/studlogo4.zip | Bin 0 -> 485 bytes resources/studlogo5.zip | Bin 0 -> 485 bytes 9 files changed, 101 insertions(+), 104 deletions(-) delete mode 100644 resources/primitives.zip create mode 100644 resources/studlogo1.zip create mode 100644 resources/studlogo2.zip create mode 100644 resources/studlogo3.zip create mode 100644 resources/studlogo4.zip create mode 100644 resources/studlogo5.zip diff --git a/common/lc_library.cpp b/common/lc_library.cpp index f643567e..eefadbee 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -60,9 +60,7 @@ void lcPiecesLibrary::Unload() delete PieceIt.second; mPieces.clear(); - for (const auto& PrimitiveIt : mPrimitives) - delete PrimitiveIt.second; - mPrimitives.clear(); + mSources.clear(); for (lcTexture* Texture : mTextures) delete Texture; @@ -259,11 +257,6 @@ bool lcPiecesLibrary::Load(const QString& LibraryPath, bool ShowProgress) 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")); @@ -290,22 +283,34 @@ 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; } + UpdateStudLogoSource(); lcLoadDefaultCategories(); lcSynthInit(); return true; } +void lcPiecesLibrary::UpdateStudLogoSource() +{ + if (!mSources.empty() && mSources.front()->Type == lcLibrarySourceType::StudLogo) + mSources.erase(mSources.begin()); + + mZipFiles[static_cast(lcZipFileType::StudLogo)].reset(); + + if (!mStudLogo) + return; + + std::unique_ptr StudLogoFile(new lcDiskFile(QString(":/resources/studlogo%1.zip").arg(QString::number(mStudLogo)))); + + if (StudLogoFile->Open(QIODevice::ReadOnly)) + OpenArchive(std::move(StudLogoFile), lcZipFileType::StudLogo); +} + bool lcPiecesLibrary::OpenArchive(const QString& FileName, lcZipFileType ZipFileType) { std::unique_ptr File(new lcDiskFile(FileName)); @@ -323,6 +328,9 @@ bool lcPiecesLibrary::OpenArchive(std::unique_ptr File, lcZipFileType Zi if (!ZipFile->OpenRead(std::move(File))) return false; + std::unique_ptr Source(new lcLibrarySource); + Source->Type = ZipFileType != lcZipFileType::StudLogo ? lcLibrarySourceType::Library : lcLibrarySourceType::StudLogo; + for (int FileIdx = 0; FileIdx < ZipFile->mFiles.GetSize(); FileIdx++) { lcZipFileInfo& FileInfo = ZipFile->mFiles[FileIdx]; @@ -398,29 +406,18 @@ bool lcPiecesLibrary::OpenArchive(std::unique_ptr File, lcZipFileType Zi Info->SetZipFile(ZipFileType, FileIdx); } else - { - lcLibraryPrimitive* Primitive = FindPrimitive(Name); - - if (!Primitive) - mPrimitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, false, true); - else - Primitive->SetZipFile(ZipFileType, FileIdx); - } + Source->Primitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, false, true); } else if (!memcmp(Name, "P/", 2)) { Name += 2; - lcLibraryPrimitive* Primitive = FindPrimitive(Name); - - if (!Primitive) - mPrimitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, (memcmp(Name, "STU", 3) == 0), false); - else - Primitive->SetZipFile(ZipFileType, FileIdx); + Source->Primitives[Name] = new lcLibraryPrimitive(QString(), FileInfo.file_name + (Name - NameBuffer), ZipFileType, FileIdx, (memcmp(Name, "STU", 3) == 0), false); } } mZipFiles[static_cast(ZipFileType)] = std::move(ZipFile); + mSources.insert(mSources.begin(), std::move(Source)); return true; } @@ -500,6 +497,9 @@ bool lcPiecesLibrary::OpenDirectory(const QDir& LibraryDir, bool ShowProgress) for (unsigned int BaseFolderIdx = 0; BaseFolderIdx < LC_ARRAY_COUNT(BaseFolders); BaseFolderIdx++) { + std::unique_ptr Source(new lcLibrarySource); + Source->Type = lcLibrarySourceType::Library; + const char* PrimitiveDirectories[] = { "p/", "parts/s/" }; bool SubFileDirectories[] = { false, false, true }; QDir BaseDir(LibraryDir.absoluteFilePath(QLatin1String(BaseFolders[BaseFolderIdx]))); @@ -545,9 +545,11 @@ 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, lcZipFileType::Count, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile); + Source->Primitives[Name] = new lcLibraryPrimitive(std::move(FileName), strchr(FileString, '/') + 1, lcZipFileType::Count, 0, !SubFile && (memcmp(Name, "STU", 3) == 0), SubFile); } } + + mSources.push_back(std::move(Source)); } for (unsigned int BaseFolderIdx = 0; BaseFolderIdx < LC_ARRAY_COUNT(BaseFolders); BaseFolderIdx++) @@ -1513,20 +1515,25 @@ void lcPiecesLibrary::UploadTextures(lcContext* Context) bool lcPiecesLibrary::SupportsStudLogo() const { - return mZipFiles[static_cast(lcZipFileType::Primitives)] != nullptr || mHasUnofficial; + return true; } void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload) { mStudLogo = StudLogo; + UpdateStudLogoSource(); + mLoadMutex.lock(); - for (const auto& PrimitiveIt : mPrimitives) + for (const std::unique_ptr& Source : mSources) { - lcLibraryPrimitive* Primitive = PrimitiveIt.second; - if (Primitive->mMeshData.mHasLogoStud) - Primitive->Unload(); + for (const auto& PrimitiveIt : Source->Primitives) + { + lcLibraryPrimitive* Primitive = PrimitiveIt.second; + if (Primitive->mMeshData.mHasLogoStud) + Primitive->Unload(); + } } mLoadMutex.unlock(); @@ -1553,27 +1560,26 @@ void lcPiecesLibrary::SetStudLogo(int StudLogo, bool Reload) } } -bool lcPiecesLibrary::GetStudLogoFile(lcMemFile& PrimFile, int StudLogo, bool OpenStud) +bool lcPiecesLibrary::IsPrimitive(const char* Name) const { - if (!StudLogo || !SupportsStudLogo()) - return false; + for (const std::unique_ptr& Source : mSources) + if (Source->Primitives.find(Name) != Source->Primitives.end()) + return true; - const QLatin1String LineEnding("\r\n"); - QByteArray FileData; - QTextStream TextStream(&FileData); + return false; +} - TextStream << (OpenStud ? QLatin1String("0 Stud Open") : QLatin1String("0 Stud")) << LineEnding; - TextStream << (OpenStud ? QLatin1String("0 Name: stud2.dat") : QLatin1String("0 Name: stud.dat")) << LineEnding; - TextStream << QLatin1String("0 Author: James Jessiman") << LineEnding; - TextStream << QLatin1String("0 !LDRAW_ORG Primitive") << LineEnding; - TextStream << QLatin1String("0 BFC CERTIFY CCW") << LineEnding; - TextStream << QString("1 16 0 0 0 1 0 0 0 1 0 0 0 1 stud%1-logo%2.dat").arg(OpenStud ? "2" : QString(), StudLogo > 1 ? QString::number(StudLogo) : QString()) << LineEnding; - TextStream.flush(); +lcLibraryPrimitive* lcPiecesLibrary::FindPrimitive(const char* Name) const +{ + for (const std::unique_ptr& Source : mSources) + { + const auto PrimitiveIt = Source->Primitives.find(Name); - PrimFile.WriteBuffer(FileData.constData(), size_t(FileData.size())); - PrimFile.Seek(0, SEEK_SET); + if (PrimitiveIt != Source->Primitives.end()) + return PrimitiveIt->second; + } - return true; + return nullptr; } bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) @@ -1596,8 +1602,6 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) lcMeshLoader MeshLoader(Primitive->mMeshData, true, nullptr, false); - bool SetStudLogo = false; - if (mZipFiles[static_cast(lcZipFileType::Official)]) { lcLibraryPrimitive* LowPrimitive = nullptr; @@ -1606,27 +1610,20 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) if (Primitive->mStud) { - const bool OpenStud = !strcmp(Primitive->mName,"stud2.dat"); - if (OpenStud || !strcmp(Primitive->mName,"stud.dat")) - { + if (!strcmp(Primitive->mName, "stud.dat") || !strcmp(Primitive->mName, "stud2.dat")) Primitive->mMeshData.mHasLogoStud = true; - - if (mStudLogo) - SetStudLogo = GetStudLogoFile(PrimFile, mStudLogo, OpenStud); - } - - if (!SetStudLogo && strncmp(Primitive->mName, "8/", 2)) // todo: this is currently the only place that uses mName so use mFileName instead. this should also be done for the loose file libraries. + else if (strncmp(Primitive->mName, "8/", 2)) // todo: this is currently the only place that uses mName so use mFileName instead. this should also be done for the loose file libraries. { char Name[LC_PIECE_NAME_LEN]; strcpy(Name, "8/"); strcat(Name, Primitive->mName); strupr(Name); - LowPrimitive = FindPrimitive(Name); + LowPrimitive = FindPrimitive(Name); // todo: low primitives don't work with studlogo, because the low stud gets added as shared } } - if (!SetStudLogo && !mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) + if (!mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) return false; if (!LowPrimitive) @@ -1650,40 +1647,26 @@ bool lcPiecesLibrary::LoadPrimitive(lcLibraryPrimitive* Primitive) { if (Primitive->mStud) { - const bool OpenStud = !strcmp(Primitive->mName,"stud2.dat"); - if (OpenStud || !strcmp(Primitive->mName,"stud.dat")) - { + if (!strcmp(Primitive->mName,"stud.dat") || !strcmp(Primitive->mName, "stud2.dat")) Primitive->mMeshData.mHasLogoStud = true; - - if (mStudLogo) - { - lcMemFile PrimFile; - - if (GetStudLogoFile(PrimFile, mStudLogo, OpenStud)) - SetStudLogo = MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED); - } - } } - if (!SetStudLogo) + if (Primitive->mZipFileType == lcZipFileType::Count) { - if (Primitive->mZipFileType == lcZipFileType::Count) - { - lcDiskFile PrimFile(Primitive->mFileName); + lcDiskFile PrimFile(Primitive->mFileName); - if (!PrimFile.Open(QIODevice::ReadOnly) || !MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) // todo: LOD like the zip files - return false; - } - else - { - lcMemFile PrimFile; + 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 (!mZipFiles[static_cast(Primitive->mZipFileType)]->ExtractFile(Primitive->mZipFileIndex, PrimFile)) + return false; - if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) - return false; - } + if (!MeshLoader.LoadMesh(PrimFile, LC_MESHDATA_SHARED)) + return false; } } diff --git a/common/lc_library.h b/common/lc_library.h index c96942ce..d7c70bd9 100644 --- a/common/lc_library.h +++ b/common/lc_library.h @@ -14,7 +14,7 @@ enum class lcZipFileType { Official, Unofficial, - Primitives, + StudLogo, Count }; @@ -70,6 +70,24 @@ public: lcLibraryMeshData mMeshData; }; +enum class lcLibrarySourceType +{ + Library, + StudLogo +}; + +struct lcLibrarySource +{ + ~lcLibrarySource() + { + for (const auto& PrimitiveIt : Primitives) + delete PrimitiveIt.second; + } + + lcLibrarySourceType Type; + std::map Primitives; +}; + class lcPiecesLibrary : public QObject { Q_OBJECT @@ -115,17 +133,8 @@ public: void GetPrimitiveFile(lcLibraryPrimitive* Primitive, std::function Callback); void GetPieceFile(const char* FileName, std::function Callback); - bool IsPrimitive(const char* Name) const - { - return mPrimitives.find(Name) != mPrimitives.end(); - } - - lcLibraryPrimitive* FindPrimitive(const char* Name) const - { - const auto PrimitiveIt = mPrimitives.find(Name); - return PrimitiveIt != mPrimitives.end() ? PrimitiveIt->second : nullptr; - } - + bool IsPrimitive(const char* Name) const; + lcLibraryPrimitive* FindPrimitive(const char* Name) const; bool LoadPrimitive(lcLibraryPrimitive* Primitive); bool SupportsStudLogo() const; @@ -152,7 +161,6 @@ public: void UnloadUnusedParts(); std::map mPieces; - std::map mPrimitives; int mNumOfficialPieces; std::vector mTextures; @@ -182,7 +190,9 @@ protected: bool ReadDirectoryCacheFile(const QString& FileName, lcMemFile& CacheFile); bool WriteDirectoryCacheFile(const QString& FileName, lcMemFile& CacheFile); - bool GetStudLogoFile(lcMemFile& PrimFile, int StudLogo, bool OpenStud); + void UpdateStudLogoSource(); + + std::vector> mSources; QMutex mLoadMutex; QList> mLoadFutures; diff --git a/leocad.qrc b/leocad.qrc index 1da3a222..f9a05af1 100644 --- a/leocad.qrc +++ b/leocad.qrc @@ -96,7 +96,11 @@ resources/parts_cancel.png resources/archive.png resources/library.zip - resources/primitives.zip + resources/studlogo1.zip + resources/studlogo2.zip + resources/studlogo3.zip + resources/studlogo4.zip + resources/studlogo5.zip resources/ldconfig.ldr resources/minifig.ini resources/ldraw.xml diff --git a/resources/primitives.zip b/resources/primitives.zip deleted file mode 100644 index 27b0ba7d27bd4c4b48948cf2ccf88769ff663139..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8933 zcmaJ`1yq#X+8r9CJ4CvXP9=mP1f-E}Dd`@%O9Y0Hj-k6#8tD>{mK+)>=@jutzWdz^ z*YE!CT5x8qS!?fi_I}P2=P15{gU18>eqi)CmG3_M>mTgxs>r7JukVoom};ELN70px zB`^R$9vlGh=w@fgcmi1y)tSNOS4V9+q?PJ3p zLF>GQxT>BgD-J~v8|(k|`d8SU=Tsi4tUF($zZWh9iAU!n~Bf*omIb!*yhWZrP9Jx^=H zM2X>kQ9=$u+ZyGyy(v8pvA%(qK}IpH_U)n$;g`w1P&$VFxV49Q9gf&_jSV?ZPM|H< z2hj5DeDOhkbW_G}n?XA)ORn(t^Y^Pg5vF!aIBu{{=Fb8eX0%>_3)0T^cZ``+e1r%r zMJ#yiE39)l{jcnptA4Ry>8`+=LbjeYZ?aq7(s=v9Ist^)h(* zIn-S-P<|pOAX*V%WpA>wJrSU3sON!7Ep8Cl4x>OJgdUK&1vD<}d{EZG#}vk+H)7@= z8ul@BHyh(Hay`;-NW-oQ3lfg-^Dte#%&e(6?XS@vdWx+!H`;S+_8Bq&fckGwIe(j) zt2!q?CxYema)mq?vtlM?n%A}vC6-C1DDV+wU{w3#3KFX|{+jfW#pa!P8VX>CfB@Gf z=?F2L|LB1OZ1z<{u-n3?5?%aP$Oby3T=o#NV}kHmhHL7`=3|J7!PP>qswxj11;;>I+`m3`|$CK!X??27*^- zu=27P60B8(%Vw|bDGgNdv;3Yu4qwvc9;_b47LOdU-0h^^?WLg1Hek#aup)Z?DXJC^c7!<%XLL2XsTlCY8O zY=!R(Z)2y|EKP15dn3*WJc?k&8B-ux(HpEpm~%R_nUfwNl<>kcH7g#jYyfJ+7c@B2 z!fTJ@%2=?{zCV0rL`x=dq~Uf}5)E>2%4GX$u-7X9pZFzz8o}ADs&$~Nq-v<4wxQ-Y zu6`Dc3lOvIOIuUjgUH*oSB&%poO~1OxUfIsCmo}Ev+~+2OPQ4Ni#hTY)vhM}3%|?; zw0G(&aA^zYw0%(N8lMr+2kJoOAqXc}m2xGT@=d+bN57%(xxGhXy{?<-QBKFGhXRr) z)QwDeg${u|3{xB(_O=U};!QAint6Ci0+wVm&-1Az%$dmTW4o9@wB9KAw&HQdG0LmX zK+x2;K8%kaFBalZ=I5H8q?MEsp^SHeUc-{sXLGM1?H6=iOo7i@rr5uFlcF+?T8quhGT2_zR(wwg09)|nXQS~cE1OVXb$^CHW z`W^128e2BF99TDzT>^am;>9MkA&|Y|AJ&(#EujS1O|1?3Hs8M{6y4k~ZKkKT)q9>D&dm*~@BTFP@X(&e z8$A8!Vscnr@Ls>cKb1wEtxSH#q?HMzs_6+;AKc$b-Qz26HV*5qc06NdbLj?kt{{I^ zsT*{xb5+|IoE#A>xYlcGeU91tHsME7XaZ^c2yu!((?r`!ng_(q@_y|^31JY_X|@_( zqtNQk37eDt$d|Kp=4V+u;IH_0c>;WdQ@D+?J!^5E(`9a_1{K__z97RhQwXl7u*3c$ z6cH$+#|+oeStgVpz&_q}YOrJwo?=60H(ocL^m3PrfloBg=y@Q!9lN+RTcqvUAFJl z(q>0fvvKf^W3LJNlkS-E??)Ih`~uIG9VNKZO^;oRk}52fddEVSO@Usbj0}|F1o?W< zVOHUHg!N(L3e#|645t1Rb?-^5(dQ?gMxnoY^Gv4$MLP75d*KcHuFb?xU6HTRo^NUb zu;IYr2jpv`HADoG&u|f|@q^Cea`ySa?2*o>I>3l5&0NIE`odrgNB8y zdE308$H;5FqkM!ORPr{=k<5&5m8xlCgD%?3bi|8cs9^CM9WW#CMdAGX+Y13FtI3|+ z=A+)7au|G(BJI6?O`QQ3?{XEa=1+5w8dRxaQ=QDy@~pa&sK}$_SkXwscQx>z0Mg6b zGaW|LvfptGa#^RI%IWwL%$P135bbt+q3;-@Lc|j>{{{$5Z5_|k*20lPA_Qs2ysSKl zXNUxy46XBtl#_z%QF8dOOwnhF{vzBMeN8q+PQfAiJF>i^TwoG&r zl`w&CSNv+pj#Me(LfCZ9HZzS$l1Z#76p!MF;T$kR$rFc0bBoJbJSO9acOZ&s$-s~) zQrp*vJhgFd8IsBY3^?4fg}XsKZW+LmalhrmjHT625r&uyYZ&lEE&;%OF~21dzt}2y zMe1j&1`9!MV-VOgo0riUhB6Bx!=IAJ263)1A7)hNh$`tePheDxn*7Fe_+CSGCRee3>RN z4x*vXN;8R#lvnT1uE~_iq4qCv`h#$b#Nx*yvYwRQ3p|bLJr1alh-$9XOHRIdY z^I6Uqu{fBSbD8E-uVxd$l7x8==dbMrAb*eaww9FD45kBy>fp4IF@EsPF*@kHn2GS_ zEmQr-jwz~K+K3N9EowIng*4K0=p^aK;mb4c&StH>smFcl%oo}dlLTZ(?kYAmaci3+ zhF2#jh@{7R|LQo5wQr10UyIQgbg$H5v8@5Rfm5vG1sNvox~Wbqbe!>DkP z=qQNm_c`m@DcI>$GDqCtT0#k3g1pFzxAYdsTVFd&QQDu^zWbySkSdXj&>yEoVDoZt z+`50Q*02%O?l)-zr517CJ87jDrz?dEZ&XUJorx=4 zro?lN43gE8;#NyvU_T`bLaPuI7ZC|HLb3N@bIf!xj zN7amdy)Mkh{_(JQhyeIIjLcYe(GU2+g%f>xt8SvFGjdz3{5$T&yKqSPt@K`)ZrRdy z1yvD61vDR?#4D@pIKLcuPKfX-gSY%Z^J&0rU7R4Mj?CxRtu%qYqgYN7-|A8Y{lsRK zY1BgZP8gO~2h>PT^>wa$uz^W6kV>MRi5xTztCAfsPlyLNZ=|xgqrIBC@E#fRWdS++3*4s} z56hy3_U4D>2G9!Sn>_F{7cV|1&gL;HaMn0MpT5OnWc-E8`aC2Dhvp@f>bXB0-FWSr z8(f8TtM^onH5W3(>RDI4!}RE#F>-;(N`*^@70@QT8Oz0rK0+z_3-n3pb~eb5L$*r# z)Hw`ZiI|^Xr+$jWyK>n+J~~6|k9c-I6#k-%*y>5!9{uPkZ@&(Ky(f{7QfL9hII_!* zy%)7?e{w;~tuamng>S;qq-&4z{7TW^D|dwM9fP$|_p0dDOwOi}yB0V4FV%gE{lpLK z0_E}c{#=&C=&RM1#G6E_gN;0*V+Pu|Ya5B>bO$wtmj2I2V`p@RJSwjWR@Nz|Ohl{l ztu>=AeXILSh$`jnj>xrLO%&PozD$ZKJEX{rP*%E4oL)qE>fF$i@s;-mZ-m#_6v3g` z<3t)>BK;>bBIt7}KjPP9U%nlw_-;pL%)8Ob(aG7E<=-=N>eq>4FZp~!aM=Jg{JgPRLee){&QMuK!Jf!J<`2<0|Q@q(K7 zWE)?dOBAcJ4$tUBX_1l*Pmq-ME9>KUOB~GvtWCd4O=m}C(*{gqN~oL@ylZmM+x*el zsJEiIH6Hpn{->dltHGezm4sSWK^=mHgD(fBD*RRF z19+&0K((Eh;H?rox5FmZLpAQEP3ve|%MNy|9w_G76Nr~@Y!1lgVtDd}<2&#+7IyU4 zR1&qv(kctBKebHuVxtLN8m=MpolknZ)*sRDfrvmqjL?Rrd<~72r@k4aHi_rweBbAn zbWmV1Mi`EPJrbhT)wJETF|$Io)%#{hvTxkj-I2Ch<>^BN$~v>+0bgB64Vh*ev3!_p zn)KK^iDvDi*ag$+isv|Ol;~~Bm*D~-OjXF8XIL+*l6Vu7acbNl{Y+JY?_2-$5nH@TAp@8~mN=Ck3C8Gb7pT3^(6VI`*Apg*wD_de zjstq^`S*}=@hs)kCcITJo4=(r`c&oY{fhiM?v`6tPXun2=KE9WyFte~dfCRG9n1F@ z+l;_GSw@cP2Ei{5@lBu;41rNNM;zH08Y82`$B*Pvh~rOx+V7qIa8F<%oI>O53Q)igG$Q`Tz=2n=;yNr(ec5U! ziZi1s23#0$0g`W#(Xn+nkz>rDJX`t%^ zKou059%Qk>9YB8aiHVOmO{eT~&}R(MEO zd1q|W!SO!{!EIbKok9n1oh93>LBX67>4{#je zjyB?Np`ZOJ^j-gB9X)z0G+yw2!tN6=rs5ctW0(utXakn6Z#R*VY)}BNn1#&f-rh^v z0CP0L{8VrKADgkjoMOCT;6CL6y(99PJgnbM!B$Weld>#jd~Yw(BQEbxl(DtIBNC^Q zSj%x2=9UBt)0PX>D|t<(z9JjjbM zPh<}KT(vja=B-26vH%3gCZZis^^vBpwNil*h5shg+7=AUPhBLA&1SIB!8JPsoKRcy zHo4`aIo?Po?blc(AX1m9wXiQSBy-3iOdyaGXssbZQjHeI^SW2ZfeVjixi5}Ylo{fg z$?3vj0GE-lUtV%w#4=WWjDycPSuatF`vM)NkJWjcRHG-_+-C4eP#=k-~+ z=^jz6+;fw6eSOJ01aBWpm8(D(jmM|@`yzE%p)L(HXlfIT7hh^Zo+hzSatXk}gy%)6 z#UMX^J*|#LP}PG{14d_h87@ZKzqtxN>yg*NfBMR5X^-CZJcVzDJ90Y3L^vR!CpMS0 zri52PZ94e`MxjrKCQKFf8Ph_{GC7k`Fzt@#qK@shg;JhpahQBRbx zE@A7i5t9hb<*}fb^Vlr?vjYKx-a~<7?=nfb8AuEs!ew57t0EXi)bm)I#5^#G)JFDQG@%UCIl?O4&`R}R|5z{Uo zAc7UVPuJRc0l*R&6SI{v7XxNwzUArRp5qLXHZYIR-JWaG7N4jY{cH%LgI*siR1uUI zCx|(SV3gCmdgm_ztE9qhATn>a3PRMBCZ$^Ws;94sRZWurrHHY&0MBegcDr@DzY1GL zqpHl`w-yIMkenZ)$Cg|lYFhYlk!B0_yIVDM9IR2R`KU;G4BLa|B)}D4XiwPvQrp`LIShDCfk9S%>@mOZ0oupco#o2JU~r8cgZI(q%}LLhVV4k}f9_^MMB?=#cvG^Sk1uj3()VXDR(J|jPyJ4H zTek^zO9N^JBIeDx7A~`e7Xz!u4J#sR`UMH&_um)r)Yg@mk={gspy&7xLmY(giPrqq z8N`2Z=B~iS#Vp7NuoDH3$Tf#dqcWHiXB}EmZGY}SThb5baQ2)dA*R(m-25JtX*Eu4 z!79X zNPmts?^Rryxnm$Iya1}*>JVn&bh4H<-?)p9 zbkqKids+JTj`20dXZ-C8@;~@;R}bT2pzx4Qf{m5Tz307g|=wswb z%99-v0J(+*m8NdZw&koJ|Ac+GU$WC^)R}L6iMcHa|DDP1%I9xi0{-R8Dx8P`9Cwo# zA}R_@XWlqbb;aqYL!+l}!nY(wwk})C+vp|@`X9rN3dA3XUXsDOV2di6 z;4`qN1tid?8ilT1$po-7+9B4m%f{+R$;Q#>VC)9(GxOqVCgxFXooY1qFUzqr80>HB*@6( zc2>bCjEd{&{=kiS4-9^r=A#xuL#;uvCr+p}AmU!#eGf5?C}W0n`%J;Tt3q;BrXFbK zlMm#=C`Dhq^deFsGTqMO#s@v}ig@wfA-lf^TO-)HUS3q1>k>OnbO?WiQmuf9_9C=$o2?8arX%ZKm-W) zL!KDhn}Yf8^*@;Zbj|uV=5L(ee~N5>50LkjAd4jdbB`4{*<$nxi?eji-nc5+u_ zdoZ})Cx{|OJs-c-`|lO-dV3v?{NdaGCU`jg-Y3w#4VHTZe~7L?vCN_^?xxu9Cz+Bu;V^p_``%y3hVw~iifrQKE(@?hZKL9 zJp+1tM-kOJ@c&XgEKBz(rXN3~_`~gLaqK$^r0d21qCh~rO_8^!ZI}Sa?JY0I?JX|= F@P9PIA=Cf> diff --git a/resources/studlogo1.zip b/resources/studlogo1.zip new file mode 100644 index 0000000000000000000000000000000000000000..8d4d55e22a6f30acf018d1f40c91ff56b1aed14a GIT binary patch literal 483 zcmWIWW@Zs#00G|uqaZK?N-zQG0Q~@{JO_g|P(Dh?xJDf)t_8$gVEN*b(iFXv#FEsb z8#x&aI9LvZ#waM>Pmy=rAgFWYFKhJ9M-D%}uw9#|dOYSYS2{DoI4huW$E_wm&;S~v z4aD4Vb8+?OZ5nOHM@){STKtO4GPO!f@8e4qj}6a)ky z6wp6h3<_X2BZCBkWX#!FPv2f+gwdD94@?8`5oTiZHOx$qIUpRM4+{fivyVRRE&-YK zZFa#!5dG>@J(!PdHf9hYo1G6g8yq0WhA+9q-G*$q%bV&-h{IXgfVvo%fsmJxf#Cp% G!vFxuV0J+O literal 0 HcmV?d00001 diff --git a/resources/studlogo2.zip b/resources/studlogo2.zip new file mode 100644 index 0000000000000000000000000000000000000000..10f31b72ffbfcc6ca8e6754572f2ae5149ad0bfb GIT binary patch literal 484 zcmWIWW@Zs#0D+_eqaZK?N-zQG0Q~@{JO^05)I2{=11PQy#9Uzc;*!!7y_Cd~)T0|Y z84NgB4ur-iD9%^<&B7vm(CKdchN;?oE$+(`-%Q+d<;c5d@~jB+5`p$DsqlROGEWDH zx#8v+VHlV{v6jh63T~h`$iPG1Z>94q0|UGnnd}*Gc|iqeCV97!<&4Mg|Fn zO~3DLc>4AlV~WWGFg^ch!yFJFVJ0?j!^{Mk1Hu9Nus}dId+%C^*{uJW?t{#15N^aU w8#4%y%`SkO4Gs`w!`+O`zz+Ve$_zH#R;3AQI4c`a7Xvd8@-i|o90YL~0J|`D8~^|S literal 0 HcmV?d00001 diff --git a/resources/studlogo3.zip b/resources/studlogo3.zip new file mode 100644 index 0000000000000000000000000000000000000000..a0d522a9c2f5fd6bdbb5aa61de17aa0f68924f3e GIT binary patch literal 485 zcmWIWW@Zs#0D+tWqaZK?N-zQG0Q~@{JO^0*s2qQ=22flZh`GS>#U-UFdMSw|sYf?* zG8k~M90-k3Q1n;$&B7vm(CKdchN;?oE$+(`-%Q+d<;c5d@~jB+vVr!A1nS<^1e&7* z#N2T6j35Rc78X-(F*65w!u+{ogC+g7^qCvH2TjCdeER z4$y~%0;kyi;1EGJyp{35Zjhlc!&|?@3}SAC9LS9A&hC?6@0|1qob^-tZ literal 0 HcmV?d00001 diff --git a/resources/studlogo4.zip b/resources/studlogo4.zip new file mode 100644 index 0000000000000000000000000000000000000000..1c37cad4733c8e528ec2995a57a04a7b7b49c60a GIT binary patch literal 485 zcmWIWW@Zs#0D;m1qaZK?N-zQG0Q~@{JO^0*>LLAy8bEPvAm#$g7nhW#=%plVXWwYV=&d^2&+l_T$-$+IHND*@Wa(#xB#2{cCs zh`HhB89@v@$jP9hE&d86f;KCDbH_cEmE)Km=6Kttg8$=|(RK?P_k2nawZppUp16u@jo1__2FamV9N-(F+9HKP+uN8eVk~Gn|zT RsEdIa2zeP97!H9r3;>7Ebk+a> literal 0 HcmV?d00001 diff --git a/resources/studlogo5.zip b/resources/studlogo5.zip new file mode 100644 index 0000000000000000000000000000000000000000..3eb7ac776f0c7d8fff7e40b2ebf56bf7a90301e2 GIT binary patch literal 485 zcmWIWW@Zs#0D+nUqaZK?N-zQG0Q~@{JO@J+P(Jmw{~ZmWxHb@Tf#r)!N>lVw5=&B# zZscSz;9xlr8l#{XukxFPMf#xA-S`btwfS1ymnXiNxaZ1|chBTm5$1vH+p;7#NE2v| z4iIz0%`<`+c#xApfrIrzXv~5a>|6a6N(60I{N|2(Dl5k^J*JJbinOak6w0n0DXHHV?!{n2F8bFf&2s zfN+35EEJH