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 <http://www.gnu.org/licenses/>.
8 /** @file sdl2_opengl_v.cpp Implementation of the OpenGL backend for SDL2 video driver. */
10 /* XXX -- Temporary hack for Windows compile */
14 #include "../stdafx.h"
15 #include "../openttd.h"
16 #include "../gfx_func.h"
18 #include "../blitter/factory.hpp"
19 #include "../network/network.h"
20 #include "../thread.h"
21 #include "../progress.h"
22 #include "../core/random_func.hpp"
23 #include "../core/math_func.hpp"
24 #include "../core/mem_func.hpp"
25 #include "../core/geometry_func.hpp"
26 #include "../fileio_func.h"
27 #include "../framerate_type.h"
28 #include "../window_func.h"
29 #include "sdl2_opengl_v.h"
32 #include <condition_variable>
34 #include "../3rdparty/opengl/glext.h"
37 # include <emscripten.h>
38 # include <emscripten/html5.h>
41 #include "../safeguards.h"
43 static FVideoDriver_SDL_OpenGL iFVideoDriver_SDL_OpenGL
;
45 /** Platform-specific callback to get an OpenGL funtion pointer. */
46 static OGLProc
GetOGLProcAddressCallback(const char *proc
)
48 return reinterpret_cast<OGLProc
>(SDL_GL_GetProcAddress(proc
));
51 bool VideoDriver_SDL_OpenGL::CreateMainWindow(uint w
, uint h
, uint flags
)
53 return this->VideoDriver_SDL_Base::CreateMainWindow(w
, h
, flags
| SDL_WINDOW_OPENGL
);
56 const char *VideoDriver_SDL_OpenGL::Start(const StringList
¶m
)
58 const char *error
= VideoDriver_SDL_Base::Start(param
);
59 if (error
!= nullptr) return error
;
61 error
= this->AllocateContext();
62 if (error
!= nullptr) {
67 this->driver_info
+= " (";
68 this->driver_info
+= OpenGLBackend::Get()->GetDriverName();
69 this->driver_info
+= ")";
71 /* Now we have a OpenGL context, force a client-size-changed event,
72 * so all buffers are allocated correctly. */
74 SDL_GetWindowSize(this->sdl_window
, &w
, &h
);
75 this->ClientSizeChanged(w
, h
, true);
76 /* We should have a valid screen buffer now. If not, something went wrong and we should abort. */
77 if (_screen
.dst_ptr
== nullptr) {
79 return "Can't get pointer to screen buffer";
81 /* Main loop expects to start with the buffer unmapped. */
82 this->ReleaseVideoPointer();
87 void VideoDriver_SDL_OpenGL::Stop()
89 this->DestroyContext();
90 this->VideoDriver_SDL_Base::Stop();
93 void VideoDriver_SDL_OpenGL::DestroyContext()
95 OpenGLBackend::Destroy();
97 if (this->gl_context
!= nullptr) {
98 SDL_GL_DeleteContext(this->gl_context
);
99 this->gl_context
= nullptr;
103 void VideoDriver_SDL_OpenGL::ToggleVsync(bool vsync
)
105 SDL_GL_SetSwapInterval(vsync
);
108 const char *VideoDriver_SDL_OpenGL::AllocateContext()
110 SDL_GL_SetAttribute(SDL_GL_RED_SIZE
, 8);
111 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE
, 8);
112 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE
, 8);
113 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE
, 0);
114 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL
, 1);
115 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK
, SDL_GL_CONTEXT_PROFILE_CORE
);
117 if (_debug_driver_level
>= 8) {
118 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS
, SDL_GL_CONTEXT_DEBUG_FLAG
);
121 this->gl_context
= SDL_GL_CreateContext(this->sdl_window
);
122 if (this->gl_context
== nullptr) return "SDL2: Can't active GL context";
124 ToggleVsync(_video_vsync
);
126 return OpenGLBackend::Create(&GetOGLProcAddressCallback
, this->GetScreenSize());
129 void VideoDriver_SDL_OpenGL::PopulateSystemSprites()
131 OpenGLBackend::Get()->PopulateCursorCache();
134 void VideoDriver_SDL_OpenGL::ClearSystemSprites()
136 OpenGLBackend::Get()->ClearCursorCache();
139 bool VideoDriver_SDL_OpenGL::AllocateBackingStore(int w
, int h
, bool force
)
141 if (this->gl_context
== nullptr) return false;
143 if (_screen
.dst_ptr
!= nullptr) this->ReleaseVideoPointer();
147 MemSetT(&this->dirty_rect
, 0);
149 bool res
= OpenGLBackend::Get()->Resize(w
, h
, force
);
150 SDL_GL_SwapWindow(this->sdl_window
);
151 _screen
.dst_ptr
= this->GetVideoPointer();
153 CopyPalette(this->local_palette
, true);
158 void *VideoDriver_SDL_OpenGL::GetVideoPointer()
160 if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
161 this->anim_buffer
= OpenGLBackend::Get()->GetAnimBuffer();
163 return OpenGLBackend::Get()->GetVideoBuffer();
166 void VideoDriver_SDL_OpenGL::ReleaseVideoPointer()
168 if (this->anim_buffer
!= nullptr) OpenGLBackend::Get()->ReleaseAnimBuffer(this->dirty_rect
);
169 OpenGLBackend::Get()->ReleaseVideoBuffer(this->dirty_rect
);
170 MemSetT(&this->dirty_rect
, 0);
171 this->anim_buffer
= nullptr;
174 void VideoDriver_SDL_OpenGL::Paint()
176 PerformanceMeasurer
framerate(PFE_VIDEO
);
178 if (this->local_palette
.count_dirty
!= 0) {
179 Blitter
*blitter
= BlitterFactory::GetCurrentBlitter();
181 /* Always push a changed palette to OpenGL. */
182 OpenGLBackend::Get()->UpdatePalette(this->local_palette
.palette
, this->local_palette
.first_dirty
, this->local_palette
.count_dirty
);
183 if (blitter
->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_BLITTER
) {
184 blitter
->PaletteAnimate(this->local_palette
);
187 this->local_palette
.count_dirty
= 0;
190 OpenGLBackend::Get()->Paint();
191 OpenGLBackend::Get()->DrawMouseCursor();
193 SDL_GL_SwapWindow(this->sdl_window
);