• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 4217246446

pending completion
4217246446

Pull #1529

github

GitHub
Merge 11c6faa50 into 57f3a3451
Pull Request #1529: Added a popup when gamefiles are missing.

9 of 9 new or added lines in 3 files covered. (100.0%)

22052 of 42824 relevant lines covered (51.49%)

32707.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.82
/libs/s25main/drivers/VideoDriverWrapper.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "VideoDriverWrapper.h"
6
#include "FrameCounter.h"
7
#include "RTTR_Version.h"
8
#include "WindowManager.h"
9
#include "driver/VideoInterface.h"
10
#include "helpers/containerUtils.h"
11
#include "helpers/roundToNextPow2.h"
12
#include "mygettext/mygettext.h"
13
#include "ogl/DummyRenderer.h"
14
#include "ogl/OpenGLRenderer.h"
15
#include "openglCfg.hpp"
16
#include "s25util/Log.h"
17
#include "s25util/error.h"
18
#include <glad/glad.h>
19
#include <ctime>
20
#if !defined(NDEBUG) && defined(HAVE_MEMCHECK_H)
21
#    include <valgrind/memcheck.h>
22
#endif
23

24
#ifdef _WIN32
25
using SwapIntervalExt_t = BOOL APIENTRY(int);
26
#else
27
using SwapIntervalExt_t = int(int);
28
#endif
29

30
SwapIntervalExt_t* wglSwapIntervalEXT = nullptr;
31

32
VideoDriverWrapper::VideoDriverWrapper()
6✔
33
    : videodriver(nullptr, nullptr), renderer_(nullptr), enableMouseWarping(true), texture_current(0)
6✔
34
{}
6✔
35

36
VideoDriverWrapper::~VideoDriverWrapper()
12✔
37
{
38
    CleanUp();
6✔
39
    UnloadDriver();
6✔
40
}
6✔
41

42
bool VideoDriverWrapper::Initialize()
4✔
43
{
44
    if(!videodriver || !videodriver->Initialize())
4✔
45
    {
46
        UnloadDriver();
×
47
        return false;
×
48
    }
49

50
    LOG.write(_("Loaded video driver \"%1%\"\n")) % GetName();
4✔
51

52
    frameCtr_ = std::make_unique<FrameCounter>();
4✔
53
    frameLimiter_ = std::make_unique<FrameLimiter>();
4✔
54

55
    return true;
4✔
56
}
57

58
bool VideoDriverWrapper::LoadDriver(IVideoDriver* existingDriver)
3✔
59
{
60
    UnloadDriver();
3✔
61
    videodriver = Handle(existingDriver, [](IVideoDriver* p) { delete p; });
12✔
62
    return Initialize();
3✔
63
}
64

65
bool VideoDriverWrapper::LoadDriver(std::string& preference)
1✔
66
{
67
    UnloadDriver();
1✔
68
    // DLL laden
69
    if(!driver_wrapper.Load(drivers::DriverType::Video, preference))
1✔
70
        return false;
×
71

72
    auto createVideoInstance = driver_wrapper.GetFunction<CreateVideoInstance_t>("CreateVideoInstance");
1✔
73
    auto freeVideoInstance = driver_wrapper.GetFunction<FreeVideoInstance_t>("FreeVideoInstance");
1✔
74
    RTTR_Assert(createVideoInstance && freeVideoInstance);
1✔
75

76
    videodriver = Handle(createVideoInstance(&WINDOWMANAGER), freeVideoInstance);
1✔
77
    return Initialize();
1✔
78
}
79

80
void VideoDriverWrapper::UnloadDriver()
11✔
81
{
82
    videodriver.reset();
11✔
83
    driver_wrapper.Unload();
11✔
84
    renderer_.reset();
11✔
85
}
11✔
86

87
/**
88
 *  Erstellt das Fenster.
89
 *
90
 *  @param[in] width  Breite des Fensters
91
 *  @param[in] height Höhe des Fensters
92
 *
93
 *  @return Bei Erfolg @p true ansonsten @p false
94
 */
95
bool VideoDriverWrapper::CreateScreen(const VideoMode size, const bool fullscreen)
5✔
96
{
97
    if(!videodriver)
5✔
98
    {
99
        s25util::fatal_error("No video driver selected!\n");
×
100
        return false;
×
101
    }
102

103
    if(!videodriver->CreateScreen(rttr::version::GetTitle(), size, fullscreen))
5✔
104
    {
105
        s25util::fatal_error("Could not create window!\n");
×
106
        return false;
×
107
    }
108

109
    // DriverWrapper Initialisieren
110
    // Extensions laden
111
    if(!LoadAllExtensions())
5✔
112
    {
113
        s25util::fatal_error("Failed to initialize the OpenGL context!\n");
×
114
        return false;
×
115
    }
116

117
    RenewViewport();
5✔
118

119
    // Buffer swappen um den leeren Buffer darzustellen
120
    SwapBuffers();
5✔
121

122
    // WindowManager informieren
123
    WINDOWMANAGER.Msg_ScreenResize(GetRenderSize());
5✔
124

125
    return true;
5✔
126
}
127

128
/**
129
 *  Verändert Auflösung, Fenster/Fullscreen
130
 *
131
 *  @param[in] screenWidth neue Breite des Fensters
132
 *  @param[in] screenHeight neue Höhe des Fensters
133
 *  @param[in] fullscreen Vollbild oder nicht
134
 *
135
 *  @return Bei Erfolg @p true ansonsten @p false
136
 */
137
bool VideoDriverWrapper::ResizeScreen(const VideoMode size, const bool fullscreen)
1✔
138
{
139
    if(!videodriver)
1✔
140
    {
141
        s25util::fatal_error("No video driver selected!\n");
×
142
        return false;
×
143
    }
144

145
    const bool result = videodriver->ResizeScreen(size, fullscreen);
1✔
146
#ifdef _WIN32
147
    if(!videodriver->IsFullscreen())
148
    {
149
        // We cannot change the size of a maximized window. So restore it here
150
        WINDOWPLACEMENT wp;
151
        wp.length = sizeof(WINDOWPLACEMENT);
152

153
        if(GetWindowPlacement((HWND)GetMapPointer(), &wp) && ((wp.showCmd & SW_MAXIMIZE) == SW_MAXIMIZE))
154
            ShowWindow((HWND)GetMapPointer(), SW_RESTORE);
155
    }
156
#endif
157
    WINDOWMANAGER.WindowResized();
1✔
158
    return result;
1✔
159
}
160

161
/**
162
 *  Zerstört den DriverWrapper-Bildschirm.
163
 */
164
bool VideoDriverWrapper::DestroyScreen()
2✔
165
{
166
    if(!videodriver)
2✔
167
    {
168
        s25util::fatal_error("No video driver selected!\n");
×
169
        return false;
×
170
    }
171

172
    LOG.write("Clearing textures: ");
2✔
173
    unsigned ladezeit = GetTickCount();
2✔
174
    CleanUp();
2✔
175
    LOG.write("Finished in %dms\n") % (GetTickCount() - ladezeit);
2✔
176

177
    // Videotreiber zurücksetzen
178
    videodriver->DestroyScreen();
2✔
179

180
    return true;
2✔
181
}
182

183
void VideoDriverWrapper::ShowErrorMessage(const char* title, const char* message)
×
184
{
185
    videodriver->ShowErrorMessage(title, message);
×
186
}
×
187

188
void VideoDriverWrapper::setTargetFramerate(int target)
31✔
189
{
190
    frameLimiter_->setTargetFramerate(target);
31✔
191
    if(!setHwVSync(target == 0) && target == 0) // Fallback if no HW vsync but was requested
31✔
192
        frameLimiter_->setTargetFramerate(60);
31✔
193
}
31✔
194

195
unsigned VideoDriverWrapper::GetFPS() const
97✔
196
{
197
    return frameCtr_->getFrameRate();
97✔
198
}
199

200
/**
201
 *  Löscht alle herausgegebenen Texturen aus dem Speicher.
202
 */
203
void VideoDriverWrapper::CleanUp()
11✔
204
{
205
    if(!texture_list.empty())
11✔
206
    {
207
        glDeleteTextures(texture_list.size(), static_cast<const GLuint*>(texture_list.data()));
3✔
208
        texture_list.clear();
3✔
209
    }
210
}
11✔
211

212
unsigned VideoDriverWrapper::GenerateTexture()
48✔
213
{
214
    GLuint newTexture = 0;
48✔
215
    glGenTextures(1, &newTexture);
48✔
216
#if !defined(NDEBUG) && defined(HAVE_MEMCHECK_H)
217
    VALGRIND_MAKE_MEM_DEFINED(&newTexture, sizeof(newTexture));
218
#endif
219

220
    static_assert(sizeof(newTexture) == sizeof(texture_list[0]), "Unexpected texture size");
221
    if(newTexture)
48✔
222
        texture_list.push_back(newTexture);
48✔
223
    return newTexture;
48✔
224
}
225

226
void VideoDriverWrapper::BindTexture(unsigned t)
2,278✔
227
{
228
    if(t != texture_current)
2,278✔
229
    {
230
        texture_current = t;
981✔
231
        glBindTexture(GL_TEXTURE_2D, t);
981✔
232
    }
233
}
2,278✔
234

235
void VideoDriverWrapper::DeleteTexture(unsigned t)
3,987✔
236
{
237
    if(!t)
3,987✔
238
        return;
3,949✔
239
    if(t == texture_current)
38✔
240
        texture_current = 0;
4✔
241
    auto it = helpers::find(texture_list, t);
38✔
242
    if(it != texture_list.end())
38✔
243
    {
244
        glDeleteTextures(1, &t);
25✔
245
        texture_list.erase(it);
25✔
246
    }
247
}
248

249
KeyEvent VideoDriverWrapper::GetModKeyState() const
3✔
250
{
251
    if(videodriver)
3✔
252
        return videodriver->GetModKeyState();
3✔
253
    const KeyEvent ke = {KeyType::Invalid, 0, false, false, false};
×
254
    return ke;
×
255
}
256

257
void VideoDriverWrapper::SwapBuffers()
5✔
258
{
259
    if(!videodriver)
5✔
260
    {
261
        s25util::fatal_error("No video driver selected!\n");
×
262
        return;
×
263
    }
264
    frameLimiter_->sleepTillNextFrame(FrameCounter::clock::now());
5✔
265
    videodriver->SwapBuffers();
5✔
266
    FrameCounter::clock::time_point now = FrameCounter::clock::now();
5✔
267
    frameLimiter_->update(now);
5✔
268
    frameCtr_->update(now);
5✔
269
}
270

271
void VideoDriverWrapper::ClearScreen()
25✔
272
{
273
    glClear(GL_COLOR_BUFFER_BIT);
25✔
274
}
25✔
275

276
bool VideoDriverWrapper::Run()
×
277
{
278
    if(!videodriver)
×
279
    {
280
        s25util::fatal_error("No video driver selected!\n");
×
281
        return false;
×
282
    }
283

284
    return videodriver->MessageLoop();
×
285
}
286

287
Extent VideoDriverWrapper::calcPreferredTextureSize(const Extent& minSize) const
38✔
288
{
289
    return Extent(helpers::roundToNextPowerOfTwo(minSize.x), helpers::roundToNextPowerOfTwo(minSize.y));
38✔
290
}
291

292
bool VideoDriverWrapper::setHwVSync(bool enabled)
31✔
293
{
294
    if(!wglSwapIntervalEXT)
31✔
295
        return false;
31✔
296
    return wglSwapIntervalEXT(enabled ? 1 : 0) != 0;
×
297
}
298

299
/**
300
 *  Viewport (neu) setzen
301
 */
302
void VideoDriverWrapper::RenewViewport()
6✔
303
{
304
    if(!videodriver->IsOpenGL() || !renderer_)
6✔
305
        return;
6✔
306

307
    const Extent renderSize = videodriver->GetRenderSize();
×
308

309
    // Viewport mit widthxheight setzen
310
    glViewport(0, 0, renderSize.x, renderSize.y);
×
311
    glScissor(0, 0, renderSize.x, renderSize.y);
×
312

313
    // Orthogonale Matrix erstellen
314
    glMatrixMode(GL_PROJECTION);
×
315
    glLoadIdentity();
×
316

317
    // 0,0 should be top left corner
318
    glOrtho(0, renderSize.x, renderSize.y, 0, -100, 100);
×
319

320
    glMatrixMode(GL_MODELVIEW);
×
321
    glLoadIdentity();
×
322

323
    // Depthbuffer und Colorbuffer einstellen
324
    glClearColor(0.0, 0.0, 0.0, 1.0);
×
325

326
    // Smooth - Shading aktivieren
327
    glShadeModel(GL_SMOOTH);
×
328

329
    glEnable(GL_ALPHA_TEST);
×
330
    glAlphaFunc(GL_GREATER, 0.0f);
×
331

332
    // Alphablending an
333
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
×
334
    glEnable(GL_BLEND);
×
335

336
    // Depthbuffer abschalten
337
    glDisable(GL_DEPTH_TEST);
×
338
    glDepthMask(GL_FALSE);
×
339

340
    // Texturen anstellen
341
    glEnable(GL_TEXTURE_2D);
×
342

343
    // Dither abstellen
344
    glDisable(GL_DITHER);
×
345

346
    // Scissoring aktivieren
347
    glEnable(GL_SCISSOR_TEST);
×
348

349
    // Nur obere Seite von Dreiecke rendern --> Performance
350
    glEnable(GL_CULL_FACE);
×
351

352
    glEnableClientState(GL_VERTEX_ARRAY);
×
353
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
×
354

355
    ClearScreen();
×
356
}
357

358
/**
359
 *  lädt die driverwrapper-extensions.
360
 */
361
bool VideoDriverWrapper::LoadAllExtensions()
5✔
362
{
363
    if(videodriver->IsOpenGL())
5✔
364
        renderer_ = std::make_unique<OpenGLRenderer>();
×
365
    else
366
        renderer_ = std::make_unique<DummyRenderer>();
5✔
367
    if(!renderer_->initOpenGL(videodriver->GetLoaderFunction()))
5✔
368
        return false;
×
369
    LOG.write(_("OpenGL %1%.%2% supported\n")) % GLVersion.major % GLVersion.minor;
5✔
370
    if(GLVersion.major < RTTR_OGL_MAJOR || (GLVersion.major == RTTR_OGL_MAJOR && GLVersion.minor < RTTR_OGL_MINOR))
5✔
371
    {
372
        LOG.write(_("OpenGL %1% %2%.%3% is not supported. Try updating your GPU drivers or hardware!"))
×
373
          % ((RTTR_OGL_ES) ? "ES" : "") % RTTR_OGL_MAJOR % RTTR_OGL_MINOR;
×
374
        return false;
×
375
    }
376

377
// auf VSync-Extension testen
378
#ifdef _WIN32
379
    wglSwapIntervalEXT = reinterpret_cast<SwapIntervalExt_t*>(loadExtension("wglSwapIntervalEXT"));
380
#else
381
    wglSwapIntervalEXT = reinterpret_cast<SwapIntervalExt_t*>(loadExtension("glXSwapIntervalSGI"));
5✔
382
#endif
383

384
    return true;
5✔
385
}
386

387
unsigned VideoDriverWrapper::GetTickCount()
300✔
388
{
389
    if(!videodriver)
300✔
390
        return (unsigned)time(nullptr);
×
391

392
    return (unsigned)videodriver->GetTickCount();
300✔
393
}
394

395
std::string VideoDriverWrapper::GetName() const
10✔
396
{
397
    const char* name = (videodriver) ? videodriver->GetName() : nullptr;
10✔
398
    return (name) ? name : "";
10✔
399
}
400

401
/**
402
 *  lädt eine bestimmte DriverWrapper Extension-Funktion.
403
 *
404
 *  @param[in] extension Die Extension-Funktion
405
 *
406
 *  @return @p nullptr bei Fehler, Adresse der gewünschten Funktion bei Erfolg.
407
 */
408
void* VideoDriverWrapper::loadExtension(const std::string& extension)
5✔
409
{
410
    if(!videodriver)
5✔
411
    {
412
        s25util::fatal_error("Kein Videotreiber ausgewaehlt!\n");
×
413
        return (nullptr);
×
414
    }
415

416
    return videodriver->GetLoaderFunction()(extension.c_str());
5✔
417
}
418

419
Position VideoDriverWrapper::GetMousePos() const
229✔
420
{
421
    if(!videodriver)
229✔
422
        return Position::Invalid();
×
423
    return videodriver->GetMousePos();
229✔
424
}
425

426
bool VideoDriverWrapper::IsLeftDown()
95✔
427
{
428
    if(!videodriver)
95✔
429
        return false;
×
430

431
    return videodriver->GetMouseStateL();
95✔
432
}
433

434
bool VideoDriverWrapper::IsRightDown()
×
435
{
436
    if(!videodriver)
×
437
        return false;
×
438

439
    return videodriver->GetMouseStateR();
×
440
}
441

442
void VideoDriverWrapper::SetMousePos(const Position& newPos)
18✔
443
{
444
    if(!videodriver || !enableMouseWarping)
18✔
445
        return;
×
446

447
    videodriver->SetMousePos(newPos);
18✔
448
}
449

450
/**
451
 *  Listet verfügbare Videomodi auf.
452
 */
453
void VideoDriverWrapper::ListVideoModes(std::vector<VideoMode>& video_modes) const
×
454
{
455
    if(!videodriver)
×
456
        return;
×
457

458
    videodriver->ListVideoModes(video_modes);
×
459
}
460

461
bool VideoDriverWrapper::HasVSync() const
×
462
{
463
    return wglSwapIntervalEXT != nullptr;
×
464
}
465

466
/**
467
 *  Gibt Pointer auf ein Fenster zurück (device-dependent!), HWND unter Windows.
468
 */
469
void* VideoDriverWrapper::GetMapPointer() const
1✔
470
{
471
    if(!videodriver)
1✔
472
        return nullptr;
1✔
473

474
    return videodriver->GetMapPointer();
×
475
}
476

477
VideoMode VideoDriverWrapper::GetWindowSize() const
8✔
478
{
479
    // Always return at least 800x600 even if real window is smaller
480
    VideoMode windowSize = videodriver->GetWindowSize();
8✔
481
    windowSize.width = std::max<unsigned>(800, windowSize.width);
8✔
482
    windowSize.height = std::max<unsigned>(600, windowSize.height);
8✔
483
    return windowSize;
8✔
484
}
485

486
Extent VideoDriverWrapper::GetRenderSize() const
296✔
487
{
488
    return videodriver->GetRenderSize();
296✔
489
}
490

491
bool VideoDriverWrapper::IsFullscreen() const
6✔
492
{
493
    return videodriver->IsFullscreen();
6✔
494
}
36✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc