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

Return-To-The-Roots / s25client / 18856213349

27 Oct 2025 09:18PM UTC coverage: 50.471% (-0.02%) from 50.491%
18856213349

Pull #1804

github

web-flow
Merge 1556dcccf into 2d6849772
Pull Request #1804: Android build

75 of 242 new or added lines in 14 files covered. (30.99%)

3 existing lines in 3 files now uncovered.

22552 of 44683 relevant lines covered (50.47%)

35157.57 hits per line

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

65.35
/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()
6✔
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; });
6✔
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!");
×
100
        return false;
×
101
    }
102

103
    if(!videodriver->CreateScreen(rttr::version::GetTitle(), size, fullscreen))
5✔
104
    {
105
        s25util::fatal_error("Could not create window!");
×
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!");
×
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)
3✔
138
{
139
    if(!videodriver)
3✔
140
    {
141
        s25util::fatal_error("No video driver selected!");
×
142
        return false;
×
143
    }
144

145
    const bool result = videodriver->ResizeScreen(size, fullscreen);
3✔
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();
3✔
158
    return result;
3✔
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!");
×
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 std::string& title, const std::string& message)
×
184
{
185
    if(videodriver)
×
186
        videodriver->ShowErrorMessage(title, message);
×
187
}
×
188

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

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

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

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

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

227
void VideoDriverWrapper::BindTexture(unsigned t)
27,795✔
228
{
229
    if(t != texture_current)
27,795✔
230
    {
231
        texture_current = t;
13,969✔
232
        glBindTexture(GL_TEXTURE_2D, t);
13,969✔
233
    }
234
}
27,795✔
235

236
void VideoDriverWrapper::DeleteTexture(unsigned t)
68,092✔
237
{
238
    if(!t)
68,092✔
239
        return;
68,043✔
240
    if(t == texture_current)
49✔
241
        texture_current = 0;
10✔
242
    auto it = helpers::find(texture_list, t);
49✔
243
    if(it != texture_list.end())
49✔
244
    {
245
        glDeleteTextures(1, &t);
35✔
246
        texture_list.erase(it);
35✔
247
    }
248
}
249

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

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

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

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

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

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

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

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

308
    const Extent renderSize = videodriver->GetRenderSize();
×
309
    const VideoMode windowSize = videodriver->GetWindowSize();
×
310

311
    // Set the viewport and scissor area to the entire window
312
    glViewport(0, 0, windowSize.width, windowSize.height);
×
313
    glScissor(0, 0, windowSize.width, windowSize.height);
×
314

315
    // Orthogonale Matrix erstellen
316
    glMatrixMode(GL_PROJECTION);
×
317
    glLoadIdentity();
×
318

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

322
    glMatrixMode(GL_MODELVIEW);
×
323
    glLoadIdentity();
×
324

325
    // Depthbuffer und Colorbuffer einstellen
326
    glClearColor(0.0, 0.0, 0.0, 1.0);
×
327

328
    // Smooth - Shading aktivieren
329
    glShadeModel(GL_SMOOTH);
×
330

331
    glEnable(GL_ALPHA_TEST);
×
332
    glAlphaFunc(GL_GREATER, 0.0f);
×
333

334
    // Alphablending an
335
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
×
336
    glEnable(GL_BLEND);
×
337

338
    // Depthbuffer abschalten
339
    glDisable(GL_DEPTH_TEST);
×
340
    glDepthMask(GL_FALSE);
×
341

342
    // Texturen anstellen
343
    glEnable(GL_TEXTURE_2D);
×
344

345
    // Dither abstellen
346
    glDisable(GL_DITHER);
×
347

348
    // Scissoring aktivieren
349
    glEnable(GL_SCISSOR_TEST);
×
350

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

354
    glEnableClientState(GL_VERTEX_ARRAY);
×
355
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
×
356

357
    ClearScreen();
×
358
}
359

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

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

386
    return true;
5✔
387
}
388

389
unsigned VideoDriverWrapper::GetTickCount()
324✔
390
{
391
    if(!videodriver)
324✔
392
        return (unsigned)time(nullptr);
×
393

394
    return (unsigned)videodriver->GetTickCount();
324✔
395
}
396

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

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

418
    return videodriver->GetLoaderFunction()(extension.c_str());
5✔
419
}
420

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

428
bool VideoDriverWrapper::IsLeftDown()
106✔
429
{
430
    if(!videodriver)
106✔
431
        return false;
×
432

433
    return videodriver->GetMouseStateL();
106✔
434
}
435

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

441
    return videodriver->GetMouseStateR();
×
442
}
443

444
bool VideoDriverWrapper::IsTouch()
25✔
445
{
446
    if(!videodriver)
25✔
NEW
447
        return false;
×
448

449
    return videodriver->IsTouchEvent();
25✔
450
}
451

452
void VideoDriverWrapper::SetMousePos(const Position& newPos)
26✔
453
{
454
    if(!videodriver || !enableMouseWarping)
26✔
455
        return;
×
456

457
    videodriver->SetMousePos(newPos);
26✔
458
}
459

460
/**
461
 *  Listet verfügbare Videomodi auf.
462
 */
463
void VideoDriverWrapper::ListVideoModes(std::vector<VideoMode>& video_modes) const
×
464
{
465
    if(!videodriver)
×
466
        return;
×
467

468
    videodriver->ListVideoModes(video_modes);
×
469
}
470

471
bool VideoDriverWrapper::HasVSync() const
×
472
{
473
    return wglSwapIntervalEXT != nullptr;
×
474
}
475

476
/**
477
 *  Gibt Pointer auf ein Fenster zurück (device-dependent!), HWND unter Windows.
478
 */
479
void* VideoDriverWrapper::GetMapPointer() const
1✔
480
{
481
    if(!videodriver)
1✔
482
        return nullptr;
1✔
483

484
    return videodriver->GetMapPointer();
×
485
}
486

487
VideoMode VideoDriverWrapper::GetWindowSize() const
14✔
488
{
489
    // Always return at least 800x600 even if real window is smaller
490
    VideoMode windowSize = videodriver->GetWindowSize();
14✔
491
    windowSize.width = std::max<unsigned>(800, windowSize.width);
14✔
492
    windowSize.height = std::max<unsigned>(600, windowSize.height);
14✔
493
    return windowSize;
14✔
494
}
495

496
Extent VideoDriverWrapper::GetRenderSize() const
462✔
497
{
498
    return videodriver->GetRenderSize();
462✔
499
}
500

501
bool VideoDriverWrapper::IsFullscreen() const
6✔
502
{
503
    return videodriver->IsFullscreen();
6✔
504
}
505

506
float VideoDriverWrapper::getDpiScale() const
8✔
507
{
508
    return videodriver->getDpiScale();
8✔
509
}
510

511
const GuiScale& VideoDriverWrapper::getGuiScale() const
8✔
512
{
513
    return videodriver->getGuiScale();
8✔
514
}
515

516
void VideoDriverWrapper::setGuiScalePercent(unsigned percent)
×
517
{
518
    videodriver->setGuiScalePercent(percent);
×
519
}
×
520

521
GuiScaleRange VideoDriverWrapper::getGuiScaleRange() const
×
522
{
523
    return videodriver->getGuiScaleRange();
×
524
}
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