OpenTTD Source 20260311-master-g511d3794ce
bootstrap_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "base_media_base.h"
12#include "base_media_graphics.h"
13#include "blitter/factory.hpp"
14#include "error_func.h"
15
16#if defined(WITH_FREETYPE) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA)
17
19#include "error.h"
20#include "fontcache.h"
21#include "gfx_func.h"
22#include "network/network.h"
24#include "openttd.h"
25#include "strings_func.h"
27#include "window_func.h"
28
30
31#include "table/strings.h"
32
33#include "safeguards.h"
34
36static constexpr std::initializer_list<NWidgetPart> _background_widgets = {
37 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
39};
40
45 WDP_MANUAL, {}, 0, 0,
49);
50
52class BootstrapBackground : public Window {
53public:
54 BootstrapBackground() : Window(_background_desc)
55 {
56 this->InitNested(0);
57 this->flags.Reset(WindowFlag::WhiteBorder);
58 ResizeWindow(this, _screen.width, _screen.height);
59 }
60
61 void DrawWidget(const Rect &r, WidgetID) const override
62 {
65 }
66};
67
69static constexpr std::initializer_list<NWidgetPart> _nested_bootstrap_errmsg_widgets = {
71 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BEM_CAPTION), SetStringTip(STR_MISSING_GRAPHICS_ERROR_TITLE),
75 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BEM_QUIT), SetStringTip(STR_MISSING_GRAPHICS_ERROR_QUIT), SetFill(1, 0),
77};
78
81 WDP_CENTER, {}, 0, 0,
85);
86
88class BootstrapErrorWindow : public Window {
89public:
90 BootstrapErrorWindow() : Window(_bootstrap_errmsg_desc)
91 {
92 this->InitNested(1);
93 }
94
95 void Close([[maybe_unused]] int data = 0) override
96 {
97 _exit_game = true;
98 this->Window::Close();
99 }
100
101 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
102 {
103 if (widget == WID_BEM_MESSAGE) {
104 size = GetStringBoundingBox(STR_MISSING_GRAPHICS_ERROR);
105 size.width += WidgetDimensions::scaled.frametext.Horizontal();
106 size.height += WidgetDimensions::scaled.frametext.Vertical();
107 }
108 }
109
110 void DrawWidget(const Rect &r, WidgetID widget) const override
111 {
112 if (widget == WID_BEM_MESSAGE) {
113 DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_ERROR, TC_FROMSTRING, SA_CENTER);
114 }
115 }
116
117 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
118 {
119 if (widget == WID_BEM_QUIT) {
120 _exit_game = true;
121 }
122 }
123};
124
126static constexpr std::initializer_list<NWidgetPart> _nested_bootstrap_download_status_window_widgets = {
127 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
128 NWidget(WWT_PANEL, COLOUR_GREY),
130 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_BAR), SetFill(1, 0),
131 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
132 EndContainer(),
133 EndContainer(),
134};
135
138 WDP_CENTER, {}, 0, 0,
142);
143
144
147public:
152
153 void Close([[maybe_unused]] int data = 0) override
154 {
155 /* If we are not set to exit the game, it means the bootstrap failed. */
156 if (!_exit_game) {
158 }
160 }
161
163 {
164 /* We have completed downloading. We can trigger finding the right set now. */
166
167 /* And continue going into the menu. */
168 _game_mode = GM_MENU;
169
170 /* _exit_game is used to break out of the outer video driver's MainLoop. */
171 _exit_game = true;
172 this->Close();
173 }
174};
175
177static constexpr std::initializer_list<NWidgetPart> _bootstrap_query_widgets = {
179 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
180 EndContainer(),
183 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetStringTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD),
184 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetStringTip(STR_MISSING_GRAPHICS_NO_QUIT),
185 EndContainer(),
186};
187
190 WDP_CENTER, {}, 0, 0,
194);
195
199
200public:
207
209 void Close([[maybe_unused]] int data = 0) override
210 {
211 _network_content_client.RemoveCallback(this);
212 this->Window::Close();
213 }
214
215 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
216 {
217 /* We cache the button size. This is safe as no reinit can happen here. */
218 if (this->button_size.width == 0) {
219 this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
220 this->button_size.width += WidgetDimensions::scaled.frametext.Horizontal();
221 this->button_size.height += WidgetDimensions::scaled.frametext.Vertical();
222 }
223
224 switch (widget) {
226 /* The question is twice as wide as the buttons, and determine the height based on the width. */
227 size.width = this->button_size.width * 2;
228 size.height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size.width - WidgetDimensions::scaled.frametext.Horizontal()) + WidgetDimensions::scaled.frametext.Vertical();
229 break;
230
231 case WID_BAFD_YES:
232 case WID_BAFD_NO:
233 size = this->button_size;
234 break;
235 }
236 }
237
238 void DrawWidget(const Rect &r, WidgetID widget) const override
239 {
240 if (widget != WID_BAFD_QUESTION) return;
241
242 DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER);
243 }
244
245 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
246 {
247 switch (widget) {
248 case WID_BAFD_YES:
249 /* We got permission to connect! Yay! */
250 _network_content_client.Connect();
251 break;
252
253 case WID_BAFD_NO:
254 _exit_game = true;
255 break;
256
257 default:
258 break;
259 }
260 }
261
262 void OnConnect(bool success) override
263 {
264 if (!success) {
265 UserError("Failed to connect to content server. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
266 /* _exit_game is used to break out of the outer video driver's MainLoop. */
267 _exit_game = true;
268 this->Close();
269 return;
270 }
271
272 /* Once connected, request the metadata. */
274 }
275
276 void OnReceiveContentInfo(const ContentInfo &ci) override
277 {
278 /* And once the meta data is received, start downloading it. */
279 _network_content_client.Select(ci.id);
281 this->Close();
282 }
283};
284
285#endif /* defined(WITH_FREETYPE) */
286
287#if defined(__EMSCRIPTEN__)
288# include <emscripten.h>
289# include "network/network.h"
291# include "openttd.h"
292# include "video/video_driver.hpp"
293
294class BootstrapEmscripten : public ContentCallback {
295 bool downloading = false;
296 uint total_files = 0;
297 uint total_bytes = 0;
298 uint downloaded_bytes = 0;
299
300public:
301 BootstrapEmscripten()
302 {
305 }
306
308 ~BootstrapEmscripten() override
309 {
311 }
312
313 void OnConnect(bool success) override
314 {
315 if (!success) {
316 EM_ASM({ if (window["openttd_bootstrap_failed"]) openttd_bootstrap_failed(); });
317 return;
318 }
319
320 /* Once connected, request the metadata. */
322 }
323
324 void OnReceiveContentInfo(const ContentInfo &ci) override
325 {
326 if (this->downloading) return;
327
328 /* And once the metadata is received, start downloading it. */
330 _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
331 this->downloading = true;
332
333 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
334 }
335
336 void OnDownloadProgress(const ContentInfo &, int bytes) override
337 {
338 /* A negative value means we are resetting; for example, when retrying or using a fallback. */
339 if (bytes < 0) {
340 this->downloaded_bytes = 0;
341 } else {
342 this->downloaded_bytes += bytes;
343 }
344
345 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
346 }
347
348 void OnDownloadComplete(ContentID) override
349 {
350 /* _exit_game is used to break out of the outer video driver's MainLoop. */
351 _exit_game = true;
352
353 delete this;
354 }
355};
356#endif /* __EMSCRIPTEN__ */
357
365{
366 if (BaseGraphics::GetUsedSet() != nullptr) return true;
367
368 /* No user interface, bail out with an error. */
369 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
370
371 /* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */
372#if defined(__EMSCRIPTEN__) || (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
373 if (!_network_available) goto failure;
374
375 /* First tell the game we're bootstrapping. */
376 _game_mode = GM_BOOTSTRAP;
377
378#if defined(__EMSCRIPTEN__)
379 new BootstrapEmscripten();
380#else
381 /* Initialise the font cache. */
383 /* Next "force" finding a suitable non-sprite font as the local font is missing. */
385
386 /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
387 * This way the mauve and gray colours work and we can show the user interface. */
388 GfxInitPalettes();
389 static const uint8_t offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
390 for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
391 for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
392 SetColourGradient(i, j, PixelColour(offsets[i] + j));
393 }
394 }
395
396 /* Finally ask the question. */
399#endif /* __EMSCRIPTEN__ */
400
401 /* Process the user events. */
403
404 /* _exit_game is used to get out of the video driver's main loop.
405 * In case GM_BOOTSTRAP is still set we did not exit it via the
406 * "download complete" event, so it was a manual exit. Obey it. */
407 _exit_game = _game_mode == GM_BOOTSTRAP;
408 if (_exit_game) return false;
409
410 /* Try to probe the graphics. Should work this time. */
411 if (!BaseGraphics::SetSet(nullptr)) goto failure;
412
413 /* Finally we can continue heading for the menu. */
414 _game_mode = GM_MENU;
415 return true;
416#endif
417
418 /* Failure to get enough working to get a graphics set. */
419failure:
420 UserError("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
421 return false;
422}
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base graphics data.
static constexpr std::initializer_list< NWidgetPart > _bootstrap_query_widgets
The widgets for the query.
static constexpr std::initializer_list< NWidgetPart > _nested_bootstrap_download_status_window_widgets
Nested widgets for the download window.
static WindowDesc _bootstrap_query_desc(WDP_CENTER, {}, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WindowDefaultFlag::NoClose, _bootstrap_query_widgets)
The window description for the query.
static WindowDesc _bootstrap_download_status_window_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, {WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose}, _nested_bootstrap_download_status_window_widgets)
Window description for the download window.
static constexpr std::initializer_list< NWidgetPart > _nested_bootstrap_errmsg_widgets
Nested widgets for the error window.
static constexpr std::initializer_list< NWidgetPart > _background_widgets
Widgets for the background window to prevent smearing.
static WindowDesc _background_desc(WDP_MANUAL, {}, 0, 0, WC_BOOTSTRAP, WC_NONE, WindowDefaultFlag::NoClose, _background_widgets)
Window description for the background window to prevent smearing.
bool HandleBootstrap()
Handle all procedures for bootstrapping OpenTTD without a base graphics set.
static WindowDesc _bootstrap_errmsg_desc(WDP_CENTER, {}, 0, 0, WC_BOOTSTRAP, WC_NONE, {WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose}, _nested_bootstrap_errmsg_widgets)
Window description for the error window.
Types related to the bootstrap widgets.
@ WID_BAFD_QUESTION
The question whether to download.
@ WID_BAFD_NO
An negative answer to the question.
@ WID_BAFD_YES
An affirmative answer to the question.
@ WID_BB_BACKGROUND
Background of the window.
@ WID_BEM_MESSAGE
Error message.
@ WID_BEM_QUIT
Quit button.
@ WID_BEM_CAPTION
Caption of the window.
static const GraphicsSet * GetUsedSet()
static bool SetSet(const GraphicsSet *set)
BaseNetworkContentDownloadStatusWindow(WindowDesc &desc)
Create the window with the given description.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:139
The window for the query.
void OnConnect(bool success) override
Callback for when the connection has finished.
Dimension button_size
The dimension of the button.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnReceiveContentInfo(const ContentInfo &ci) override
We received a content info.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void Close(int data=0) override
Stop listening to the content client events.
BootstrapAskForDownloadWindow()
Start listening to the content client events.
The background for the game.
void DrawWidget(const Rect &r, WidgetID) const override
Draw the contents of a nested widget.
The window for a failed bootstrap.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
void RemoveCallback(ContentCallback *cb)
Remove a callback.
void Select(ContentID cid)
Select a specific content id.
void RequestContentList(ContentType type)
Request the content list for the given type.
void AddCallback(ContentCallback *cb)
Add a callback to this class, if it doesn't already exist.
void Connect()
Connect with the content server.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
virtual void MainLoop()=0
Perform the actual drawing.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
Functions related to errors.
Error reporting related functions.
Factory to 'query' all available blitters.
Functions to read fonts from files and cache them.
void InitializeUnicodeGlyphMap()
Initialize the glyph map.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:717
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:788
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
Functions related to the gfx engine.
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:346
@ FILLRECT_OPAQUE
Fill rectangle with a single colour.
Definition gfx_type.h:345
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
#define Point
Macro that prevents name conflicts between included headers.
bool _network_available
is network mode available?
Definition network.cpp:69
Basic functions/variables used all over the place.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
Part of the network protocol handling content distribution.
User interface for downloading files.
@ WID_NCDS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NCDS_PROGRESS_BAR
Simple progress bar.
Some generic types.
void SetColourGradient(Colours colour, ColourShade shade, PixelColour palette_index)
Set colour gradient palette index.
Definition palette.cpp:404
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition strings.cpp:2397
Functions related to OTTD's strings.
Window for showing the download status of content.
BootstrapContentDownloadStatusWindow()
Simple call the constructor of the superclass.
void OnDownloadComplete(ContentID) override
We have finished downloading a file.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Callbacks for notifying others about incoming data.
virtual void OnDownloadProgress(const ContentInfo &ci, int bytes)
We have progress in the download of a file.
virtual void OnReceiveContentInfo(const ContentInfo &ci)
We received a content info.
virtual void OnDownloadComplete(ContentID cid)
We have finished downloading a file.
virtual void OnConnect(bool success)
Callback for when the connection has finished.
Container for all important information about a piece of content.
ContentID id
Unique (server side) ID for the content.
Dimensions (a width and height) of a rectangle in 2D.
Colour for pixel/line drawing.
Definition gfx_type.h:405
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
High level window description.
Definition window_gui.h:168
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1117
ResizeInfo resize
Resize information.
Definition window_gui.h:315
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1845
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1835
WindowFlags flags
Window flags.
Definition window_gui.h:301
uint32_t ContentID
Unique identifier for the content.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
Base of all video drivers.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2112
Window functions not directly related to making/drawing windows.
@ NoClose
This window can't be interactively closed.
Definition window_gui.h:156
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition window_gui.h:154
@ WhiteBorder
Window white border counter bit mask.
Definition window_gui.h:235
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
@ WDP_MANUAL
Manually align the window (so no automatic location finding).
Definition window_gui.h:143
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_CONFIRM_POPUP_QUERY_BOOTSTRAP
Query popup confirm for bootstrap.
Definition window_type.h:38
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_CONFIRM_POPUP_QUERY
Popup with confirm question; Window numbers:
@ WC_BOOTSTRAP
Bootstrap; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: