1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2003-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // startup screen
17 
18 #include "C4Include.h"
19 #include "gui/C4LoaderScreen.h"
20 
21 #include "c4group/C4Components.h"
22 #include "c4group/C4GroupSet.h"
23 #include "graphics/C4Draw.h"
24 #include "graphics/C4GraphicsResource.h"
25 #include "lib/C4LogBuf.h"
26 #include "lib/C4Random.h"
27 
28 
C4LoaderScreen()29 C4LoaderScreen::C4LoaderScreen()
30 {
31 	// zero fields
32 	szInfo=nullptr;
33 	fBlackScreen = false;
34 }
35 
~C4LoaderScreen()36 C4LoaderScreen::~C4LoaderScreen()
37 {
38 	// clear fields
39 	if (szInfo) delete [] szInfo;
40 }
41 
Init(std::string loaderSpec)42 bool C4LoaderScreen::Init(std::string loaderSpec)
43 {
44 	// Determine loader specification
45 	if (loaderSpec.empty())
46 		loaderSpec = "Loader*";
47 
48 	C4Group *pGroup = nullptr;
49 	// query groups of equal priority in set
50 	while ((pGroup=Game.GroupSet.FindGroup(C4GSCnt_Loaders, pGroup, true)))
51 	{
52 		SeekLoaderScreens(*pGroup, loaderSpec);
53 	}
54 	// nothing found? seek in main gfx grp
55 	C4Group GfxGrp;
56 	if (loaders.empty())
57 	{
58 		// open it
59 		GfxGrp.Close();
60 		if (!Reloc.Open(GfxGrp, C4CFN_Graphics))
61 		{
62 			LogFatal(FormatString(LoadResStr("IDS_PRC_NOGFXFILE"),C4CFN_Graphics,GfxGrp.GetError()).getData());
63 			return false;
64 		}
65 		// seek for loaders
66 		SeekLoaderScreens(GfxGrp, loaderSpec);
67 
68 		// Still nothing found: fall back to general loader spec in main graphics group
69 		if (loaders.empty())
70 		{
71 			SeekLoaderScreens(GfxGrp, "Loader*");
72 		}
73 		// Not even default loaders available? Fail.
74 		if (loaders.empty())
75 		{
76 			LogFatal(FormatString("No loaders found for loader specification: %s", loaderSpec.c_str()).getData());
77 			return false;
78 		}
79 	}
80 
81 	// choose random loader
82 	auto entry = loaders.begin();
83 	std::advance(entry, UnsyncedRandom(loaders.size()));
84 
85 	// load loader
86 	fctBackground.GetFace().SetBackground();
87 	if (!fctBackground.Load(*(entry->first), entry->second.c_str(), C4FCT_Full, C4FCT_Full, true, 0)) return false;
88 
89 	// load info
90 	if (szInfo) { delete [] szInfo; szInfo=nullptr; }
91 
92 	// done, success!
93 	return true;
94 }
95 
SetBlackScreen(bool fIsBlack)96 void C4LoaderScreen::SetBlackScreen(bool fIsBlack)
97 {
98 	// enabled/disables drawing of loader screen
99 	fBlackScreen = fIsBlack;
100 	// will be updated when drawn next time
101 }
102 
SeekLoaderScreens(C4Group & rFromGrp,const std::string & wildcard)103 void C4LoaderScreen::SeekLoaderScreens(C4Group &rFromGrp, const std::string &wildcard)
104 {
105 	// seek for png, jpg, jpeg, bmp
106 	char filename[_MAX_PATH + 1];
107 	for (bool found = rFromGrp.FindEntry(wildcard.c_str(), filename); found; found = rFromGrp.FindNextEntry(wildcard.c_str(), filename))
108 	{
109 		// potential candidate - check file extension
110 		std::string extension{ GetExtension(filename) };
111 		std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
112 		if (extension == "png" || extension == "jpg" || extension == "jpeg" || extension == "bmp") {
113 			loaders.emplace(&rFromGrp, std::string(filename));
114 		}
115 	}
116 }
117 
Draw(C4Facet & cgo,Flag options,int iProgress,C4LogBuffer * pLog,int Process)118 void C4LoaderScreen::Draw(C4Facet &cgo, Flag options, int iProgress, C4LogBuffer *pLog, int Process)
119 {
120 	// simple black screen loader?
121 	if (fBlackScreen || options == Flag::BLACK)
122 	{
123 		pDraw->FillBG();
124 		return;
125 	}
126 	// cgo.X/Y is assumed 0 here...
127 	// fixed positions for now
128 	int iHIndent=20;
129 	int iVIndent=20;
130 	int iLogBoxHgt=84;
131 	int iLogBoxMargin=2;
132 	int iVMargin=5;
133 	int iProgressBarHgt=15;
134 	CStdFont &LogFont=::GraphicsResource.FontTiny, &rProgressBarFont=::GraphicsResource.FontRegular;
135 	CStdFont &TitleFont = ::GraphicsResource.FontTitle;
136 	float fLogBoxFontZoom=1.0f;
137 
138 	if (options & Flag::BACKGROUND) {
139 		// Background (loader)
140 		fctBackground.DrawFullScreen(cgo);
141 	}
142 
143 	if (options & Flag::TITLE) {
144 		// draw scenario title
145 		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);
146 	}
147 
148 	if (options & Flag::PROGRESS) {
149 		// draw progress bar
150 		pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt, cgo.Wdt - iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin, 0xb0000000);
151 		int iProgressBarWdt = cgo.Wdt - iHIndent * 2 - 2;
152 		if (::GraphicsResource.fctProgressBar.Surface)
153 		{
154 			::GraphicsResource.fctProgressBar.DrawX(cgo.Surface, iHIndent + 1, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - iProgressBarHgt + 1, iProgressBarWdt*iProgress / 100, iProgressBarHgt - 2);
155 		}
156 		else
157 		{
158 			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);
159 		}
160 		pDraw->StringOut(FormatString("%i%%", iProgress).getData(), rProgressBarFont, 1.0f, cgo.Surface,
161 			cgo.Wdt / 2, cgo.Hgt - iVIndent - iLogBoxHgt - iVMargin - rProgressBarFont.GetLineHeight() / 2 - iProgressBarHgt / 2, 0xffffffff,
162 			ACenter, true);
163 	}
164 
165 	if (options & Flag::LOG) {
166 		// draw log box
167 		if (pLog)
168 		{
169 			pDraw->DrawBoxDw(cgo.Surface, iHIndent, cgo.Hgt - iVIndent - iLogBoxHgt, cgo.Wdt - iHIndent, cgo.Hgt - iVIndent, 0x7f000000);
170 			int iLineHgt = int(fLogBoxFontZoom*LogFont.GetLineHeight()); if (!iLineHgt) iLineHgt = 5;
171 			int iLinesVisible = (iLogBoxHgt - 2 * iLogBoxMargin) / iLineHgt;
172 			int iX = iHIndent + iLogBoxMargin;
173 			int iY = cgo.Hgt - iVIndent - iLogBoxHgt + iLogBoxMargin;
174 			int32_t w, h;
175 			for (int i = -iLinesVisible; i < 0; ++i)
176 			{
177 				const char *szLine = pLog->GetLine(i, nullptr, nullptr, nullptr);
178 				if (!szLine || !*szLine) continue;
179 				LogFont.GetTextExtent(szLine, w, h, true);
180 				pDraw->TextOut(szLine, LogFont, fLogBoxFontZoom, cgo.Surface, iX, iY);
181 				iY += h;
182 			}
183 
184 			if (options & Flag::PROCESS) {
185 				// append process text
186 				if (Process)
187 				{
188 					iY -= h; iX += w;
189 					pDraw->TextOut(FormatString("%i%%", (int)Process).getData(), LogFont, fLogBoxFontZoom, cgo.Surface, iX, iY);
190 				}
191 			}
192 		}
193 	}
194 }
195