From 384472f183bbe44578143aa3f409777c9e474064 Mon Sep 17 00:00:00 2001 From: Kanibal Date: Sun, 27 Aug 2017 01:12:56 +0200 Subject: [PATCH] Modernize loader loading code (#1748) --- src/gui/C4Gui.cpp | 2 +- src/gui/C4LoaderScreen.cpp | 169 +++++++++++++++++++------------------ src/gui/C4LoaderScreen.h | 30 +++++-- src/gui/C4MessageBoard.cpp | 2 +- 4 files changed, 110 insertions(+), 93 deletions(-) diff --git a/src/gui/C4Gui.cpp b/src/gui/C4Gui.cpp index bf85235a9..e0f1ed9c7 100644 --- a/src/gui/C4Gui.cpp +++ b/src/gui/C4Gui.cpp @@ -752,7 +752,7 @@ namespace C4GUI if (!pFSDlg || !pFSDlg->HasBackground()) { if (::GraphicsSystem.pLoaderScreen) - ::GraphicsSystem.pLoaderScreen->fctBackground.DrawFullScreen(cgo); + ::GraphicsSystem.pLoaderScreen->Draw(cgo, C4LoaderScreen::Flag::BACKGROUND); else // loader not yet loaded: black BG pDraw->DrawBoxDw(cgo.Surface, 0,0, cgo.Wdt+1, cgo.Hgt+1, 0x00000000); diff --git a/src/gui/C4LoaderScreen.cpp b/src/gui/C4LoaderScreen.cpp index bd2fff4fc..e1c1c00fc 100644 --- a/src/gui/C4LoaderScreen.cpp +++ b/src/gui/C4LoaderScreen.cpp @@ -25,6 +25,11 @@ #include "lib/C4LogBuf.h" #include "lib/C4Random.h" +// allow combination of loader flags +inline C4LoaderScreen::Flag operator|(C4LoaderScreen::Flag a, C4LoaderScreen::Flag b) { + return static_cast(static_cast(a) | static_cast(b)); +} + C4LoaderScreen::C4LoaderScreen() { // zero fields @@ -38,33 +43,21 @@ C4LoaderScreen::~C4LoaderScreen() if (szInfo) delete [] szInfo; } -bool C4LoaderScreen::Init(const char *szLoaderSpec) +bool C4LoaderScreen::Init(std::string loaderSpec) { // Determine loader specification - if (!szLoaderSpec || !szLoaderSpec[0]) - szLoaderSpec = "Loader*"; - char szLoaderSpecPng[128 + 1 + 4], szLoaderSpecBmp[128 + 1 + 4]; - char szLoaderSpecJpg[128 + 1 + 4], szLoaderSpecJpeg[128 + 1 + 5]; - SCopy(szLoaderSpec, szLoaderSpecPng); DefaultExtension(szLoaderSpecPng, "png"); - SCopy(szLoaderSpec, szLoaderSpecBmp); DefaultExtension(szLoaderSpecBmp, "bmp"); - SCopy(szLoaderSpec, szLoaderSpecJpg); DefaultExtension(szLoaderSpecJpg, "jpg"); - SCopy(szLoaderSpec, szLoaderSpecJpeg); DefaultExtension(szLoaderSpecJpeg, "jpeg"); - int iLoaders=0; - C4Group *pGroup=nullptr,*pChosenGrp=nullptr; - char ChosenFilename[_MAX_PATH+1]; + if (loaderSpec.empty()) + loaderSpec = "Loader*"; + + C4Group *pGroup = nullptr; // query groups of equal priority in set while ((pGroup=Game.GroupSet.FindGroup(C4GSCnt_Loaders, pGroup, true))) { - iLoaders+=SeekLoaderScreens(*pGroup, szLoaderSpecPng, iLoaders, ChosenFilename, &pChosenGrp); - iLoaders+=SeekLoaderScreens(*pGroup, szLoaderSpecJpeg, iLoaders, ChosenFilename, &pChosenGrp); - iLoaders+=SeekLoaderScreens(*pGroup, szLoaderSpecJpg, iLoaders, ChosenFilename, &pChosenGrp); - // lower the chance for any loader other than png - iLoaders*=2; - iLoaders+=SeekLoaderScreens(*pGroup, szLoaderSpecBmp, iLoaders, ChosenFilename, &pChosenGrp); + SeekLoaderScreens(*pGroup, loaderSpec); } // nothing found? seek in main gfx grp C4Group GfxGrp; - if (!iLoaders) + if (loaders.empty()) { // open it GfxGrp.Close(); @@ -73,31 +66,29 @@ bool C4LoaderScreen::Init(const char *szLoaderSpec) LogFatal(FormatString(LoadResStr("IDS_PRC_NOGFXFILE"),C4CFN_Graphics,GfxGrp.GetError()).getData()); return false; } - // seek for png-loaders - iLoaders=SeekLoaderScreens(GfxGrp, szLoaderSpecPng, iLoaders, ChosenFilename, &pChosenGrp); - iLoaders+=SeekLoaderScreens(GfxGrp, szLoaderSpecJpg, iLoaders, ChosenFilename, &pChosenGrp); - iLoaders+=SeekLoaderScreens(GfxGrp, szLoaderSpecJpeg, iLoaders, ChosenFilename, &pChosenGrp); - iLoaders*=2; - // seek for bmp-loaders - iLoaders+=SeekLoaderScreens(GfxGrp, szLoaderSpecBmp, iLoaders, ChosenFilename, &pChosenGrp); + // seek for loaders + SeekLoaderScreens(GfxGrp, loaderSpec); + // Still nothing found: fall back to general loader spec in main graphics group - if (!iLoaders) + if (loaders.empty()) { - iLoaders = SeekLoaderScreens(GfxGrp, "Loader*.png", 0, ChosenFilename, &pChosenGrp); - iLoaders += SeekLoaderScreens(GfxGrp, "Loader*.jpg", iLoaders, ChosenFilename, &pChosenGrp); - iLoaders += SeekLoaderScreens(GfxGrp, "Loader*.jpeg", iLoaders, ChosenFilename, &pChosenGrp); + SeekLoaderScreens(GfxGrp, "Loader*"); } // Not even default loaders available? Fail. - if (!iLoaders) + if (loaders.empty()) { - LogFatal(FormatString("No loaders found for loader specification: %s/%s/%s/%s", szLoaderSpecPng, szLoaderSpecBmp, szLoaderSpecJpg, szLoaderSpecJpeg).getData()); + LogFatal(FormatString("No loaders found for loader specification: %s", loaderSpec.c_str()).getData()); return false; } } + // choose random loader + auto entry = loaders.begin(); + std::advance(entry, UnsyncedRandom(loaders.size())); + // load loader fctBackground.GetFace().SetBackground(); - if (!fctBackground.Load(*pChosenGrp,ChosenFilename, C4FCT_Full,C4FCT_Full,true,0)) return false; + if (!fctBackground.Load(*(entry->first), entry->second.c_str(), C4FCT_Full, C4FCT_Full, true, 0)) return false; // load info if (szInfo) { delete [] szInfo; szInfo=nullptr; } @@ -113,29 +104,25 @@ void C4LoaderScreen::SetBlackScreen(bool fIsBlack) // will be updated when drawn next time } -int C4LoaderScreen::SeekLoaderScreens(C4Group &rFromGrp, const char *szWildcard, int iLoaderCount, char *szDstName, C4Group **ppDestGrp) +void C4LoaderScreen::SeekLoaderScreens(C4Group &rFromGrp, const std::string wildcard) { - bool fFound; - int iLocalLoaders=0; - char Filename[_MAX_PATH+1]; - for (fFound=rFromGrp.FindEntry(szWildcard, Filename); fFound; fFound=rFromGrp.FindNextEntry(szWildcard, Filename)) + // seek for png, jpg, jpeg, bmp + char filename[_MAX_PATH + 1]; + for (bool found = rFromGrp.FindEntry(wildcard.c_str(), filename); found; found = rFromGrp.FindNextEntry(wildcard.c_str(), filename)) { - // loader found; choose it, if Daniel wants it that way - ++iLocalLoaders; - if (!UnsyncedRandom(++iLoaderCount)) - { - // copy group and path - *ppDestGrp=&rFromGrp; - SCopy(Filename, szDstName, _MAX_PATH); + // potential candidate - check file extension + std::string extension{ GetExtension(filename) }; + if (extension == "png" || extension == "jpg" || extension == "jpeg" || extension == "bmp") { + auto loader = std::pair{ &rFromGrp, std::string(filename) }; + loaders.emplace(loader); } } - return iLocalLoaders; } -void C4LoaderScreen::Draw(C4Facet &cgo, int iProgress, C4LogBuffer *pLog, int Process) +void C4LoaderScreen::Draw(C4Facet &cgo, Flag options, int iProgress, C4LogBuffer *pLog, int Process) { // simple black screen loader? - if (fBlackScreen) + if (fBlackScreen || options == Flag::BLACK) { pDraw->FillBG(); return; @@ -151,47 +138,61 @@ void C4LoaderScreen::Draw(C4Facet &cgo, int iProgress, C4LogBuffer *pLog, int Pr CStdFont &LogFont=::GraphicsResource.FontTiny, &rProgressBarFont=::GraphicsResource.FontRegular; CStdFont &TitleFont = ::GraphicsResource.FontTitle; float fLogBoxFontZoom=1.0f; - // Background (loader) - fctBackground.DrawFullScreen(cgo); - // draw scenario title - pDraw->StringOut(Game.ScenarioTitle.getData(), TitleFont, 1.0f, cgo.Surface, cgo.Wdt-iHIndent, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-iProgressBarHgt-iVMargin-TitleFont.GetLineHeight(), 0xdddddddd, ARight, false); - // - // draw progress bar - pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-iProgressBarHgt, cgo.Wdt-iHIndent, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin, 0xb0000000); - int iProgressBarWdt=cgo.Wdt-iHIndent*2-2; - if (::GraphicsResource.fctProgressBar.Surface) - { - ::GraphicsResource.fctProgressBar.DrawX(cgo.Surface, iHIndent+1, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-iProgressBarHgt+1, iProgressBarWdt*iProgress/100, iProgressBarHgt-2); + + if (options & Flag::BACKGROUND) { + // Background (loader) + fctBackground.DrawFullScreen(cgo); } - else - { - pDraw->DrawBoxDw(cgo.Surface, iHIndent+1, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-iProgressBarHgt+1, iHIndent+1+iProgressBarWdt*iProgress/100, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-1, 0xb0ff0000); + + if (options & Flag::TITLE) { + // draw scenario title + pDraw->StringOut(Game.ScenarioTitle.getData(), TitleFont, 1.0f, cgo.Surface, cgo.Wdt - iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt - iVMargin - TitleFont.GetLineHeight(), 0xdddddddd, ARight, false); } - pDraw->StringOut(FormatString("%i%%", iProgress).getData(), rProgressBarFont, 1.0f, cgo.Surface, - cgo.Wdt/2, cgo.Hgt-iVIndent-iLogBoxHgt-iVMargin-rProgressBarFont.GetLineHeight()/2-iProgressBarHgt/2, 0xffffffff, - ACenter, true); - // draw log box - if (pLog) - { - pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt-iVIndent-iLogBoxHgt, cgo.Wdt-iHIndent, cgo.Hgt-iVIndent, 0x7f000000); - int iLineHgt=int(fLogBoxFontZoom*LogFont.GetLineHeight()); if (!iLineHgt) iLineHgt=5; - int iLinesVisible = (iLogBoxHgt-2*iLogBoxMargin)/iLineHgt; - int iX = iHIndent+iLogBoxMargin; - int iY = cgo.Hgt-iVIndent-iLogBoxHgt+iLogBoxMargin; - int32_t w,h; - for (int i = -iLinesVisible; i < 0; ++i) + + if (options & Flag::PROGRESS) { + // draw progress bar + pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt, cgo.Wdt - iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin, 0xb0000000); + int iProgressBarWdt = cgo.Wdt - iHIndent * 2 - 2; + if (::GraphicsResource.fctProgressBar.Surface) { - const char *szLine = pLog->GetLine(i, nullptr, nullptr, nullptr); - if (!szLine || !*szLine) continue; - LogFont.GetTextExtent(szLine, w,h, true); - pDraw->TextOut(szLine,LogFont,fLogBoxFontZoom,cgo.Surface,iX,iY); - iY += h; + ::GraphicsResource.fctProgressBar.DrawX(cgo.Surface, iHIndent + 1, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt + 1, iProgressBarWdt*iProgress / 100, iProgressBarHgt - 2); } - // append process text - if (Process) + else { - iY -= h; iX += w; - pDraw->TextOut(FormatString("%i%%", (int) Process).getData(),LogFont,fLogBoxFontZoom,cgo.Surface,iX,iY); + pDraw->DrawBoxDw(cgo.Surface, iHIndent + 1, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt + 1, iHIndent + 1 + iProgressBarWdt*iProgress / 100, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - 1, 0xb0ff0000); + } + pDraw->StringOut(FormatString("%i%%", iProgress).getData(), rProgressBarFont, 1.0f, cgo.Surface, + cgo.Wdt / 2, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - rProgressBarFont.GetLineHeight() / 2 - iProgressBarHgt / 2, 0xffffffff, + ACenter, true); + } + + if (options & Flag::LOG) { + // draw log box + if (pLog) + { + pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt, cgo.Wdt - iHIndent, cgo.Hgt - iVIndent, 0x7f000000); + int iLineHgt = int(fLogBoxFontZoom*LogFont.GetLineHeight()); if (!iLineHgt) iLineHgt = 5; + int iLinesVisible = (iLogBoxHgt - 2 * iLogBoxMargin) / iLineHgt; + int iX = iHIndent + iLogBoxMargin; + int iY = cgo.Hgt - iVIndent - iLogBoxHgt + iLogBoxMargin; + int32_t w, h; + for (int i = -iLinesVisible; i < 0; ++i) + { + const char *szLine = pLog->GetLine(i, nullptr, nullptr, nullptr); + if (!szLine || !*szLine) continue; + LogFont.GetTextExtent(szLine, w, h, true); + pDraw->TextOut(szLine, LogFont, fLogBoxFontZoom, cgo.Surface, iX, iY); + iY += h; + } + + if (options & Flag::PROCESS) { + // append process text + if (Process) + { + iY -= h; iX += w; + pDraw->TextOut(FormatString("%i%%", (int)Process).getData(), LogFont, fLogBoxFontZoom, cgo.Surface, iX, iY); + } + } } } } diff --git a/src/gui/C4LoaderScreen.h b/src/gui/C4LoaderScreen.h index a805be1a3..2fb732a28 100644 --- a/src/gui/C4LoaderScreen.h +++ b/src/gui/C4LoaderScreen.h @@ -13,29 +13,45 @@ * To redistribute this file separately, substitute the full license texts * for the above references. */ -// startup screen + // startup screen #ifndef INC_C4LoaderScreen #define INC_C4LoaderScreen #include "graphics/C4FacetEx.h" + class C4LoaderScreen { public: + enum Flag { + BLACK = 0x00, + BACKGROUND = 0x01, + TITLE = 0x02, + PROGRESS = 0x04, + LOG = 0x08, + PROCESS = 0x0f, + + // All of the above + ALL = 0xFF + }; + +protected: C4FacetSurface fctBackground; // background image char *szInfo; // info text to be drawn on loader screen bool fBlackScreen; // if set, a black screen is drawn instead of a loader + std::map loaders; + void SeekLoaderScreens(C4Group &rFromGrp, const std::string wildcard); + public: - C4LoaderScreen(); // ctor - ~C4LoaderScreen(); // dtor + C4LoaderScreen(); + ~C4LoaderScreen(); - bool Init(const char *szLoaderSpec); // inits and loads from global C4Game-class + bool Init(std::string szLoaderSpec); // inits and loads from global C4Game-class void SetBlackScreen(bool fIsBlack); // enabled/disables drawing of loader screen - int SeekLoaderScreens(C4Group &rFromGrp, const char *szWildcard, int iLoaderCount, char *szDstName, C4Group **ppDestGrp); - - void Draw(C4Facet &cgo, int iProgress=0, class C4LogBuffer *pLog=nullptr, int Process=0); // draw loader screen (does not page flip!) + // draw loader screen (does not page flip!) + void Draw(C4Facet &cgo, Flag options = Flag::ALL, int iProgress = 0, class C4LogBuffer *pLog = nullptr, int Process = 0); }; #endif //INC_C4LoaderScreen diff --git a/src/gui/C4MessageBoard.cpp b/src/gui/C4MessageBoard.cpp index 6c33ca770..bae3b3ba0 100644 --- a/src/gui/C4MessageBoard.cpp +++ b/src/gui/C4MessageBoard.cpp @@ -136,7 +136,7 @@ void C4MessageBoard::Draw(C4Facet &cgo) if (Startup) { if (::GraphicsSystem.pLoaderScreen) - ::GraphicsSystem.pLoaderScreen->Draw(cgo, Game.InitProgress, &LogBuffer); + ::GraphicsSystem.pLoaderScreen->Draw(cgo, C4LoaderScreen::Flag::ALL, Game.InitProgress, &LogBuffer); else // loader not yet loaded: black BG pDraw->DrawBoxDw(cgo.Surface, 0,0, cgo.Wdt, cgo.Hgt, 0x00000000);