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

Return-To-The-Roots / s25client / 20580964505

29 Dec 2025 07:24PM UTC coverage: 50.48% (-0.02%) from 50.503%
20580964505

Pull #1804

github

web-flow
Merge fa9b1433c into af2863637
Pull Request #1804: Android build

66 of 229 new or added lines in 13 files covered. (28.82%)

2 existing lines in 2 files now uncovered.

22599 of 44768 relevant lines covered (50.48%)

36851.81 hits per line

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

65.64
/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)
37✔
190
{
191
    frameLimiter_->setTargetFramerate(target);
37✔
192
    if(!setHwVSync(target == 0) && target == 0) // Fallback if no HW vsync but was requested
37✔
193
        frameLimiter_->setTargetFramerate(60);
37✔
194
}
37✔
195

196
unsigned VideoDriverWrapper::GetFPS() const
112✔
197
{
198
    return frameCtr_->getFrameRate();
112✔
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,803✔
228
{
229
    if(t != texture_current)
27,803✔
230
    {
231
        texture_current = t;
13,977✔
232
        glBindTexture(GL_TEXTURE_2D, t);
13,977✔
233
    }
234
}
27,803✔
235

236
void VideoDriverWrapper::DeleteTexture(unsigned t)
68,098✔
237
{
238
    if(!t)
68,098✔
239
        return;
68,049✔
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
    return KeyEvent();
×
255
}
256

257
void VideoDriverWrapper::SwapBuffers()
5✔
258
{
259
    if(!videodriver)
5✔
260
    {
261
        s25util::fatal_error("No video driver selected!");
×
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()
30✔
272
{
273
    glClear(GL_COLOR_BUFFER_BIT);
30✔
274
}
30✔
275

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

356
    ClearScreen();
×
357
}
358

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

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

385
    return true;
5✔
386
}
387

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

393
    return (unsigned)videodriver->GetTickCount();
326✔
394
}
395

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

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

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

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

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

432
    return videodriver->GetMouseStateL();
110✔
433
}
434

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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