21#define GL_GLEXT_PROTOTYPES
23# define GL_SILENCE_DEPRECATION
24# include <OpenGL/gl3.h>
28#include "../3rdparty/opengl/glext.h"
48#define GL(function) static decltype(&function) _ ## function
53GL(glDebugMessageControl);
54GL(glDebugMessageCallback);
83GL(glClearBufferSubData);
92GL(glDeleteVertexArrays);
100GL(glGetProgramInfoLog);
107GL(glGetShaderInfoLog);
108GL(glGetUniformLocation);
114GL(glGetAttribLocation);
115GL(glEnableVertexAttribArray);
116GL(glDisableVertexAttribArray);
117GL(glVertexAttribPointer);
118GL(glBindFragDataLocation);
134GetOGLProcAddressProc GetOGLProcAddress;
136static std::optional<std::string_view> GlGetString(GLenum name)
138 auto str =
reinterpret_cast<const char *
>(_glGetString(name));
139 if (str ==
nullptr)
return {};
167 static PFNGLGETSTRINGIPROC glGetStringi =
nullptr;
168 static bool glGetStringi_loaded =
false;
172 if (!glGetStringi_loaded) {
174 glGetStringi_loaded =
true;
177 if (glGetStringi !=
nullptr) {
180 _glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);
182 for (GLint i = 0; i < num_exts; i++) {
183 const char *entry =
reinterpret_cast<const char *
>(glGetStringi(GL_EXTENSIONS, i));
184 if (entry !=
nullptr && entry == extension)
return true;
186 }
else if (
auto str = GlGetString(GL_EXTENSIONS); str.has_value()) {
219 f =
reinterpret_cast<F
>(GetOGLProcAddress(name));
229 if (!
BindGLProc(_glGetString,
"glGetString"))
return false;
230 if (!
BindGLProc(_glGetIntegerv,
"glGetIntegerv"))
return false;
231 if (!
BindGLProc(_glGetError,
"glGetError"))
return false;
242 if (!
BindGLProc(_glDisable,
"glDisable"))
return false;
243 if (!
BindGLProc(_glEnable,
"glEnable"))
return false;
244 if (!
BindGLProc(_glViewport,
"glViewport"))
return false;
245 if (!
BindGLProc(_glTexImage1D,
"glTexImage1D"))
return false;
246 if (!
BindGLProc(_glTexImage2D,
"glTexImage2D"))
return false;
247 if (!
BindGLProc(_glTexParameteri,
"glTexParameteri"))
return false;
248 if (!
BindGLProc(_glTexSubImage1D,
"glTexSubImage1D"))
return false;
249 if (!
BindGLProc(_glTexSubImage2D,
"glTexSubImage2D"))
return false;
250 if (!
BindGLProc(_glBindTexture,
"glBindTexture"))
return false;
251 if (!
BindGLProc(_glDeleteTextures,
"glDeleteTextures"))
return false;
252 if (!
BindGLProc(_glGenTextures,
"glGenTextures"))
return false;
253 if (!
BindGLProc(_glPixelStorei,
"glPixelStorei"))
return false;
254 if (!
BindGLProc(_glClear,
"glClear"))
return false;
255 if (!
BindGLProc(_glClearColor,
"glClearColor"))
return false;
256 if (!
BindGLProc(_glBlendFunc,
"glBlendFunc"))
return false;
257 if (!
BindGLProc(_glDrawArrays,
"glDrawArrays"))
return false;
269 if (!
BindGLProc(_glActiveTexture,
"glActiveTexture"))
return false;
271 if (!
BindGLProc(_glActiveTexture,
"glActiveTextureARB"))
return false;
284 if (!
BindGLProc(_glGenBuffers,
"glGenBuffers"))
return false;
285 if (!
BindGLProc(_glDeleteBuffers,
"glDeleteBuffers"))
return false;
286 if (!
BindGLProc(_glBindBuffer,
"glBindBuffer"))
return false;
287 if (!
BindGLProc(_glBufferData,
"glBufferData"))
return false;
288 if (!
BindGLProc(_glBufferSubData,
"glBufferSubData"))
return false;
289 if (!
BindGLProc(_glMapBuffer,
"glMapBuffer"))
return false;
290 if (!
BindGLProc(_glUnmapBuffer,
"glUnmapBuffer"))
return false;
292 if (!
BindGLProc(_glGenBuffers,
"glGenBuffersARB"))
return false;
293 if (!
BindGLProc(_glDeleteBuffers,
"glDeleteBuffersARB"))
return false;
294 if (!
BindGLProc(_glBindBuffer,
"glBindBufferARB"))
return false;
295 if (!
BindGLProc(_glBufferData,
"glBufferDataARB"))
return false;
296 if (!
BindGLProc(_glBufferSubData,
"glBufferSubDataARB"))
return false;
297 if (!
BindGLProc(_glMapBuffer,
"glMapBufferARB"))
return false;
298 if (!
BindGLProc(_glUnmapBuffer,
"glUnmapBufferARB"))
return false;
302 BindGLProc(_glClearBufferSubData,
"glClearBufferSubData");
304 _glClearBufferSubData =
nullptr;
320 if (!
BindGLProc(_glGenVertexArrays,
"glGenVertexArrays"))
return false;
321 if (!
BindGLProc(_glDeleteVertexArrays,
"glDeleteVertexArrays"))
return false;
322 if (!
BindGLProc(_glBindVertexArray,
"glBindVertexArray"))
return false;
324 if (!
BindGLProc(_glGenVertexArrays,
"glGenVertexArraysAPPLE"))
return false;
325 if (!
BindGLProc(_glDeleteVertexArrays,
"glDeleteVertexArraysAPPLE"))
return false;
326 if (!
BindGLProc(_glBindVertexArray,
"glBindVertexArrayAPPLE"))
return false;
339 if (!
BindGLProc(_glCreateProgram,
"glCreateProgram"))
return false;
340 if (!
BindGLProc(_glDeleteProgram,
"glDeleteProgram"))
return false;
341 if (!
BindGLProc(_glLinkProgram,
"glLinkProgram"))
return false;
342 if (!
BindGLProc(_glUseProgram,
"glUseProgram"))
return false;
343 if (!
BindGLProc(_glGetProgramiv,
"glGetProgramiv"))
return false;
344 if (!
BindGLProc(_glGetProgramInfoLog,
"glGetProgramInfoLog"))
return false;
345 if (!
BindGLProc(_glCreateShader,
"glCreateShader"))
return false;
346 if (!
BindGLProc(_glDeleteShader,
"glDeleteShader"))
return false;
347 if (!
BindGLProc(_glShaderSource,
"glShaderSource"))
return false;
348 if (!
BindGLProc(_glCompileShader,
"glCompileShader"))
return false;
349 if (!
BindGLProc(_glAttachShader,
"glAttachShader"))
return false;
350 if (!
BindGLProc(_glGetShaderiv,
"glGetShaderiv"))
return false;
351 if (!
BindGLProc(_glGetShaderInfoLog,
"glGetShaderInfoLog"))
return false;
352 if (!
BindGLProc(_glGetUniformLocation,
"glGetUniformLocation"))
return false;
353 if (!
BindGLProc(_glUniform1i,
"glUniform1i"))
return false;
354 if (!
BindGLProc(_glUniform1f,
"glUniform1f"))
return false;
355 if (!
BindGLProc(_glUniform2f,
"glUniform2f"))
return false;
356 if (!
BindGLProc(_glUniform4f,
"glUniform4f"))
return false;
358 if (!
BindGLProc(_glGetAttribLocation,
"glGetAttribLocation"))
return false;
359 if (!
BindGLProc(_glEnableVertexAttribArray,
"glEnableVertexAttribArray"))
return false;
360 if (!
BindGLProc(_glDisableVertexAttribArray,
"glDisableVertexAttribArray"))
return false;
361 if (!
BindGLProc(_glVertexAttribPointer,
"glVertexAttribPointer"))
return false;
364 if (!
BindGLProc(_glCreateProgram,
"glCreateProgramObjectARB"))
return false;
365 if (!
BindGLProc(_glDeleteProgram,
"glDeleteObjectARB"))
return false;
366 if (!
BindGLProc(_glLinkProgram,
"glLinkProgramARB"))
return false;
367 if (!
BindGLProc(_glUseProgram,
"glUseProgramObjectARB"))
return false;
368 if (!
BindGLProc(_glGetProgramiv,
"glGetObjectParameterivARB"))
return false;
369 if (!
BindGLProc(_glGetProgramInfoLog,
"glGetInfoLogARB"))
return false;
370 if (!
BindGLProc(_glCreateShader,
"glCreateShaderObjectARB"))
return false;
371 if (!
BindGLProc(_glDeleteShader,
"glDeleteObjectARB"))
return false;
372 if (!
BindGLProc(_glShaderSource,
"glShaderSourceARB"))
return false;
373 if (!
BindGLProc(_glCompileShader,
"glCompileShaderARB"))
return false;
374 if (!
BindGLProc(_glAttachShader,
"glAttachObjectARB"))
return false;
375 if (!
BindGLProc(_glGetShaderiv,
"glGetObjectParameterivARB"))
return false;
376 if (!
BindGLProc(_glGetShaderInfoLog,
"glGetInfoLogARB"))
return false;
377 if (!
BindGLProc(_glGetUniformLocation,
"glGetUniformLocationARB"))
return false;
378 if (!
BindGLProc(_glUniform1i,
"glUniform1iARB"))
return false;
379 if (!
BindGLProc(_glUniform1f,
"glUniform1fARB"))
return false;
380 if (!
BindGLProc(_glUniform2f,
"glUniform2fARB"))
return false;
381 if (!
BindGLProc(_glUniform4f,
"glUniform4fARB"))
return false;
383 if (!
BindGLProc(_glGetAttribLocation,
"glGetAttribLocationARB"))
return false;
384 if (!
BindGLProc(_glEnableVertexAttribArray,
"glEnableVertexAttribArrayARB"))
return false;
385 if (!
BindGLProc(_glDisableVertexAttribArray,
"glDisableVertexAttribArrayARB"))
return false;
386 if (!
BindGLProc(_glVertexAttribPointer,
"glVertexAttribPointerARB"))
return false;
391 BindGLProc(_glBindFragDataLocation,
"glBindFragDataLocation");
393 BindGLProc(_glBindFragDataLocation,
"glBindFragDataLocationEXT");
395 _glBindFragDataLocation =
nullptr;
409 if (!
BindGLProc(_glMapBufferRange,
"glMapBufferRange"))
return false;
412 if (!
BindGLProc(_glBufferStorage,
"glBufferStorage"))
return false;
414#ifndef NO_GL_BUFFER_SYNC
416 if (!
BindGLProc(_glClientWaitSync,
"glClientWaitSync"))
return false;
417 if (!
BindGLProc(_glFenceSync,
"glFenceSync"))
return false;
418 if (!
BindGLProc(_glDeleteSync,
"glDeleteSync"))
return false;
431void APIENTRY
DebugOutputCallback(GLenum, GLenum type, GLuint, GLenum severity, GLsizei,
const GLchar *message,
const void *)
434 std::string_view severity_str;
436 case GL_DEBUG_SEVERITY_HIGH: severity_str =
"high";
break;
437 case GL_DEBUG_SEVERITY_MEDIUM: severity_str =
"medium";
break;
438 case GL_DEBUG_SEVERITY_LOW: severity_str =
"low";
break;
442 std::string_view type_str =
"Other";
444 case GL_DEBUG_TYPE_ERROR: type_str =
"Error";
break;
445 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: type_str =
"Deprecated";
break;
446 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: type_str =
"Undefined behaviour";
break;
447 case GL_DEBUG_TYPE_PERFORMANCE: type_str =
"Performance";
break;
448 case GL_DEBUG_TYPE_PORTABILITY: type_str =
"Portability";
break;
457#ifndef NO_DEBUG_MESSAGES
461 BindGLProc(_glDebugMessageControl,
"glDebugMessageControl");
462 BindGLProc(_glDebugMessageCallback,
"glDebugMessageCallback");
464 BindGLProc(_glDebugMessageControl,
"glDebugMessageControlARB");
465 BindGLProc(_glDebugMessageCallback,
"glDebugMessageCallbackARB");
468 if (_glDebugMessageControl !=
nullptr && _glDebugMessageCallback !=
nullptr) {
470 _glEnable(GL_DEBUG_OUTPUT);
477 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_ERROR, GL_DONT_CARE, 0,
nullptr, GL_TRUE);
478 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DONT_CARE, 0,
nullptr, GL_TRUE);
479 _glDebugMessageControl(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0,
nullptr, GL_TRUE);
494 GetOGLProcAddress = get_proc;
521 if (_glDeleteProgram !=
nullptr) {
527 if (_glDeleteVertexArrays !=
nullptr) _glDeleteVertexArrays(1, &this->
vao_quad);
528 if (_glDeleteBuffers !=
nullptr) {
529 _glDeleteBuffers(1, &this->
vbo_quad);
530 _glDeleteBuffers(1, &this->
vid_pbo);
531 _glDeleteBuffers(1, &this->
anim_pbo);
533 if (_glDeleteTextures !=
nullptr) {
543static std::tuple<uint8_t, uint8_t> DecodeVersion(std::string_view ver)
561 auto ver = GlGetString(GL_VERSION);
562 auto vend = GlGetString(GL_VENDOR);
563 auto renderer = GlGetString(GL_RENDERER);
565 if (!ver.has_value() || !vend.has_value() || !renderer.has_value())
return "OpenGL not supported";
569#ifndef GL_ALLOW_SOFTWARE_RENDERER
572 if (renderer->starts_with(
"llvmpipe") || renderer->starts_with(
"softpipe"))
return "Software renderer detected, not using OpenGL";
605 if (
IsOpenGLVersionAtLeast(3, 2) && _glBindFragDataLocation ==
nullptr)
return "OpenGL claims to support version 3.2 but doesn't have glBindFragDataLocation";
608#ifndef NO_GL_BUFFER_SYNC
619 GLint max_tex_size = 0;
620 _glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
621 if (std::max(screen_res.width, screen_res.height) > (uint)max_tex_size)
return "Max supported texture size is too small";
624 GLint max_tex_units = 0;
625 _glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tex_units);
626 if (max_tex_units < 4)
return "Not enough simultaneous textures supported";
628 Debug(
Facility::Driver,
Severity::Warning,
"OpenGL shading language version: {}, texture units = {}", GlGetString(GL_SHADING_LANGUAGE_VERSION).value_or(
"Unknown version"), max_tex_units);
630 if (!this->
InitShaders())
return "Failed to initialize shaders";
635 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
636 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
637 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
638 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
639 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
640 _glBindTexture(GL_TEXTURE_2D, 0);
641 if (_glGetError() != GL_NO_ERROR)
return "Can't generate video buffer texture";
646 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
647 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
648 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
649 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
650 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
651 _glBindTexture(GL_TEXTURE_2D, 0);
652 if (_glGetError() != GL_NO_ERROR)
return "Can't generate animation buffer texture";
657 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
658 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
659 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
660 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
661 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
662 _glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, 256, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
nullptr);
663 _glBindTexture(GL_TEXTURE_1D, 0);
664 if (_glGetError() != GL_NO_ERROR)
return "Can't generate palette lookup texture";
667 GLint tex_location = _glGetUniformLocation(this->
vid_program,
"colour_tex");
668 GLint palette_location = _glGetUniformLocation(this->
vid_program,
"palette");
669 GLint sprite_location = _glGetUniformLocation(this->
vid_program,
"sprite");
670 GLint screen_location = _glGetUniformLocation(this->
vid_program,
"screen");
672 _glUniform1i(tex_location, 0);
673 _glUniform1i(palette_location, 1);
675 _glUniform4f(sprite_location, 0.0f, 0.0f, 1.0f, 1.0f);
676 _glUniform2f(screen_location, 1.0f, 1.0f);
679 tex_location = _glGetUniformLocation(this->
pal_program,
"colour_tex");
680 palette_location = _glGetUniformLocation(this->
pal_program,
"palette");
681 sprite_location = _glGetUniformLocation(this->
pal_program,
"sprite");
682 screen_location = _glGetUniformLocation(this->
pal_program,
"screen");
684 _glUniform1i(tex_location, 0);
685 _glUniform1i(palette_location, 1);
686 _glUniform4f(sprite_location, 0.0f, 0.0f, 1.0f, 1.0f);
687 _glUniform2f(screen_location, 1.0f, 1.0f);
690 tex_location = _glGetUniformLocation(this->
remap_program,
"colour_tex");
691 palette_location = _glGetUniformLocation(this->
remap_program,
"palette");
692 GLint remap_location = _glGetUniformLocation(this->
remap_program,
"remap_tex");
698 _glUniform1i(tex_location, 0);
699 _glUniform1i(palette_location, 1);
700 _glUniform1i(remap_location, 2);
703 tex_location = _glGetUniformLocation(this->
sprite_program,
"colour_tex");
704 palette_location = _glGetUniformLocation(this->
sprite_program,
"palette");
705 remap_location = _glGetUniformLocation(this->
sprite_program,
"remap_tex");
706 GLint pal_location = _glGetUniformLocation(this->
sprite_program,
"pal");
713 _glUniform1i(tex_location, 0);
714 _glUniform1i(palette_location, 1);
715 _glUniform1i(remap_location, 2);
716 _glUniform1i(pal_location, 3);
720 _glGenBuffers(1, &this->
vid_pbo);
721 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
723 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
724 if (_glGetError() != GL_NO_ERROR)
return "Can't allocate pixel buffer for video buffer";
730 { 1.f, -1.f, 1.f, 1.f },
731 { 1.f, 1.f, 1.f, 0.f },
732 { -1.f, -1.f, 0.f, 1.f },
733 { -1.f, 1.f, 0.f, 0.f },
737 _glGenVertexArrays(1, &this->
vao_quad);
742 _glBindBuffer(GL_ARRAY_BUFFER, this->
vbo_quad);
743 _glBufferData(GL_ARRAY_BUFFER,
sizeof(vert_array), vert_array, GL_STATIC_DRAW);
744 if (_glGetError() != GL_NO_ERROR)
return "Can't generate VBO for fullscreen quad";
747 GLint loc_position = _glGetAttribLocation(this->
vid_program,
"position");
748 GLint colour_position = _glGetAttribLocation(this->
vid_program,
"colour_uv");
749 _glEnableVertexAttribArray(loc_position);
750 _glEnableVertexAttribArray(colour_position);
753 _glBindVertexArray(0);
758 this->PrepareContext();
764void OpenGLBackend::PrepareContext()
766 _glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
767 _glDisable(GL_DEPTH_TEST);
770 _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
773std::string OpenGLBackend::GetDriverName()
775 auto renderer = GlGetString(GL_RENDERER);
776 auto version = GlGetString(GL_VERSION);
778 return fmt::format(
"{}, {}", renderer.value_or(
"Unknown renderer"), version.value_or(
"Unknown version"));
790 GLint result = GL_FALSE;
791 _glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
795 _glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
797 _glGetShaderInfoLog(shader, log_len,
nullptr, log_buf.
Allocate(log_len));
801 return result == GL_TRUE;
813 GLint result = GL_FALSE;
814 _glGetProgramiv(program, GL_LINK_STATUS, &result);
818 _glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
820 _glGetProgramInfoLog(program, log_len,
nullptr, log_buf.
Allocate(log_len));
824 return result == GL_TRUE;
833 auto ver = GlGetString(GL_SHADING_LANGUAGE_VERSION);
834 if (!ver.has_value())
return false;
836 auto [glsl_major, glsl_minor] = DecodeVersion(*ver);
838 bool glsl_150 = (
IsOpenGLVersionAtLeast(3, 2) || glsl_major > 1 || (glsl_major == 1 && glsl_minor >= 5)) && _glBindFragDataLocation !=
nullptr;
841 GLuint vert_shader = _glCreateShader(GL_VERTEX_SHADER);
843 _glCompileShader(vert_shader);
847 GLuint frag_shader_rgb = _glCreateShader(GL_FRAGMENT_SHADER);
849 _glCompileShader(frag_shader_rgb);
853 GLuint frag_shader_pal = _glCreateShader(GL_FRAGMENT_SHADER);
855 _glCompileShader(frag_shader_pal);
859 GLuint remap_shader = _glCreateShader(GL_FRAGMENT_SHADER);
861 _glCompileShader(remap_shader);
865 GLuint sprite_shader = _glCreateShader(GL_FRAGMENT_SHADER);
867 _glCompileShader(sprite_shader);
873 _glAttachShader(this->
vid_program, frag_shader_rgb);
877 _glAttachShader(this->
pal_program, frag_shader_pal);
889 _glBindFragDataLocation(this->
vid_program, 0,
"colour");
890 _glBindFragDataLocation(this->
pal_program, 0,
"colour");
907 _glDeleteShader(vert_shader);
908 _glDeleteShader(frag_shader_rgb);
909 _glDeleteShader(frag_shader_pal);
910 _glDeleteShader(remap_shader);
911 _glDeleteShader(sprite_shader);
925 T *buf =
reinterpret_cast<T *
>(_glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE));
926 for (
size_t i = 0; i < len; i++) {
929 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
941 if (!force && _screen.width == w && _screen.height == h)
return false;
944 int pitch =
Align(w, 4);
945 size_t line_pixel_count =
static_cast<size_t>(pitch) * h;
947 _glViewport(0, 0, w, h);
949 _glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
953 _glDeleteBuffers(1, &this->
vid_pbo);
954 _glGenBuffers(1, &this->
vid_pbo);
955 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
956 _glBufferStorage(GL_PIXEL_UNPACK_BUFFER, line_pixel_count * bpp / 8,
nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_CLIENT_STORAGE_BIT);
959 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
960 _glBufferData(GL_PIXEL_UNPACK_BUFFER, line_pixel_count * bpp / 8,
nullptr, GL_DYNAMIC_DRAW);
965 Colour black(0, 0, 0);
966 if (_glClearBufferSubData !=
nullptr) {
967 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_RGBA8, 0, line_pixel_count * bpp / 8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &black.data);
971 }
else if (bpp == 8) {
972 if (_glClearBufferSubData !=
nullptr) {
974 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_R8, 0, line_pixel_count, GL_RED, GL_UNSIGNED_BYTE, &b);
980 _glActiveTexture(GL_TEXTURE0);
983 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
985 _glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
nullptr);
987 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
993 _glDeleteBuffers(1, &this->
anim_pbo);
995 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
996 _glBufferStorage(GL_PIXEL_UNPACK_BUFFER, line_pixel_count,
nullptr, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_CLIENT_STORAGE_BIT);
998 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
999 _glBufferData(GL_PIXEL_UNPACK_BUFFER, line_pixel_count,
nullptr, GL_DYNAMIC_DRAW);
1003 if (_glClearBufferSubData !=
nullptr) {
1005 _glClearBufferSubData(GL_PIXEL_UNPACK_BUFFER, GL_R8, 0, line_pixel_count, GL_RED, GL_UNSIGNED_BYTE, &b);
1011 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1012 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1015 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
1016 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1017 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1023 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1025 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &dummy);
1028 _glBindTexture(GL_TEXTURE_2D, 0);
1033 _screen.pitch = pitch;
1034 _screen.dst_ptr =
nullptr;
1038 _glUniform2f(this->
remap_screen_loc, (
float)_screen.width, (
float)_screen.height);
1040 _glClear(GL_COLOR_BUFFER_BIT);
1053 assert(first + length <= 256);
1055 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1056 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1057 _glActiveTexture(GL_TEXTURE1);
1059 _glTexSubImage1D(GL_TEXTURE_1D, 0, first, length, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pal + first);
1067 _glClear(GL_COLOR_BUFFER_BIT);
1069 _glDisable(GL_BLEND);
1072 _glActiveTexture(GL_TEXTURE0);
1074 _glActiveTexture(GL_TEXTURE1);
1078 _glActiveTexture(GL_TEXTURE2);
1088 _glBindVertexArray(this->
vao_quad);
1089 _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1091 _glEnable(GL_BLEND);
1102 _cur_dpi = &_screen;
1118 OpenGLSpriteLRUCache &lru;
1121 OpenGLSpriteAllocator(OpenGLSpriteLRUCache &lru,
SpriteID sprite) : lru(lru), sprite(sprite) {}
1126void OpenGLBackend::PopulateCursorCache()
1140 for (
const auto &sc : _cursor.
sprites) {
1144 OpenGLSpriteAllocator allocator(this->
cursor_cache, sc.image.sprite);
1176#ifndef NO_GL_BUFFER_SYNC
1182 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
1183 this->
vid_buffer = _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
1185 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
1186 this->
vid_buffer = _glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
static_cast<GLsizeiptr
>(_screen.pitch) * _screen.height *
BlitterFactory::GetCurrentBlitter()->GetScreenDepth() / 8, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
1198 if (this->
anim_pbo == 0)
return nullptr;
1200#ifndef NO_GL_BUFFER_SYNC
1205 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
1206 this->
anim_buffer = _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
1208 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
1209 this->
anim_buffer = _glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0,
static_cast<GLsizeiptr
>(_screen.pitch) * _screen.height, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
1223 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
vid_pbo);
1225 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1229#ifndef NO_GL_BUFFER_SYNC
1238 _glActiveTexture(GL_TEXTURE0);
1240 _glPixelStorei(GL_UNPACK_ROW_LENGTH, _screen.pitch);
1242 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_RED, GL_UNSIGNED_BYTE, (GLvoid*)(
size_t)(update_rect.top * _screen.pitch + update_rect.left));
1244 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, (GLvoid*)(
size_t)(update_rect.top * _screen.pitch * 4 + update_rect.left * 4));
1247#ifndef NO_GL_BUFFER_SYNC
1261 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->
anim_pbo);
1263 _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
1267#ifndef NO_GL_BUFFER_SYNC
1275 if (update_rect.left != update_rect.right) {
1276 _glActiveTexture(GL_TEXTURE0);
1278 _glPixelStorei(GL_UNPACK_ROW_LENGTH, _screen.pitch);
1279 _glTexSubImage2D(GL_TEXTURE_2D, 0, update_rect.left, update_rect.top, update_rect.right - update_rect.left, update_rect.bottom - update_rect.top, GL_RED, GL_UNSIGNED_BYTE, (GLvoid *)(
size_t)(update_rect.top * _screen.pitch + update_rect.left));
1281#ifndef NO_GL_BUFFER_SYNC
1291 gl_allocator.lru.
Insert(gl_allocator.sprite, std::make_unique<OpenGLSprite>(sprite_type, sprite));
1308 _glActiveTexture(GL_TEXTURE0 + 1);
1312 _glActiveTexture(GL_TEXTURE0 + 3);
1313 if (pal != PAL_NONE) {
1318 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1321 _glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1323 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1334 _glUniform4f(this->
sprite_sprite_loc, (
float)x, (
float)y, (
float)dim.width, (
float)dim.height);
1336 _glUniform2f(this->
sprite_screen_loc, (
float)_screen.width, (
float)_screen.height);
1340 _glBindVertexArray(this->
vao_quad);
1341 _glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1361 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1362 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1363 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
1364 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1365 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1368 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1369 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1372 const Colour rgb_pixel(0, 0, 0);
1374 _glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &rgb_pixel);
1379 _glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 1, 1, 0, GL_RED, GL_UNSIGNED_BYTE, &pal);
1382 std::array<uint8_t, 256> identity_pal;
1383 std::iota(std::begin(identity_pal), std::end(identity_pal), 0);
1388 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1389 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1390 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
1391 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1392 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1393 _glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 256, 0, GL_RED, GL_UNSIGNED_BYTE, identity_pal.data());
1398 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1399 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1400 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAX_LEVEL, 0);
1401 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1402 _glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1403 _glTexImage1D(GL_TEXTURE_1D, 0, GL_R8, 256, 0, GL_RED, GL_UNSIGNED_BYTE, identity_pal.data());
1408 _glBufferData(GL_PIXEL_UNPACK_BUFFER, 256, identity_pal.data(), GL_DYNAMIC_DRAW);
1409 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1411 return _glGetError() == GL_NO_ERROR;
1430 const auto &root_sprite = sprite.Root();
1431 this->dim.
width = root_sprite.width;
1432 this->dim.height = root_sprite.height;
1433 this->
x_offs = root_sprite.x_offs;
1434 this->
y_offs = root_sprite.y_offs;
1438 (void)_glGetError();
1441 _glActiveTexture(GL_TEXTURE0);
1442 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1450 _glGenTextures(1, &this->
tex[t]);
1451 _glBindTexture(GL_TEXTURE_2D, this->
tex[t]);
1453 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
1454 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1455 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1);
1456 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1457 _glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1460 for (
int i = 0, w = this->dim.width, h = this->dim.height; i < levels; i++, w /= 2, h /= 2) {
1463 _glTexImage2D(GL_TEXTURE_2D, i, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1465 _glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
nullptr);
1472 const auto &src_sprite = sprite[zoom];
1476 assert(_glGetError() == GL_NO_ERROR);
1482 _glDeleteTextures(
static_cast<GLsizei
>(this->
tex.size()), this->tex.data());
1497 _glActiveTexture(GL_TEXTURE0);
1498 _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1499 _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1503 size_t size =
static_cast<size_t>(width) * height;
1504 Colour *rgba = buf_rgba.
Allocate(size);
1505 for (
size_t i = 0; i < size; i++) {
1506 rgba[i].r = data[i].
r;
1507 rgba[i].g = data[i].
g;
1508 rgba[i].b = data[i].
b;
1509 rgba[i].a = data[i].
a;
1513 _glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, rgba);
1518 size_t pitch =
Align(width, 4);
1520 uint8_t *pal = buf_pal.
Allocate(pitch * height);
1522 for (uint y = 0; y < height; y++, pal += pitch, row += width) {
1523 for (uint x = 0; x < width; x++) {
1529 _glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, buf_pal.
GetBuffer());
1532 assert(_glGetError() == GL_NO_ERROR);
1552 _glActiveTexture(GL_TEXTURE0);
1554 _glActiveTexture(GL_TEXTURE0 + 2);
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
Iterate a range of enum values.
void Insert(const Tkey &key, Tdata &&item)
Insert a new data item with a specified key.
Platform-independent back-end class for OpenGL video drivers.
GLint sprite_rgb_loc
Uniform location for RGB mode flag.
void * anim_buffer
Pointer to the mapped animation buffer.
GLuint remap_program
Shader program for blending and rendering a RGBA + remap texture.
bool cursor_in_window
Cursor inside this window.
void Paint()
Render video buffer to the screen.
GLuint pal_program
Shader program for rendering a paletted video buffer.
OpenGLSpriteLRUCache cursor_cache
Cache of encoded cursor sprites.
std::vector< CursorSprite > cursor_sprites
Sprites comprising cursor.
GLint remap_screen_loc
Uniform location for screen size.
~OpenGLBackend() override
Free allocated resources.
static OpenGLBackend * instance
Singleton instance pointer.
uint8_t * GetAnimBuffer()
Get a pointer to the memory for the separate animation buffer.
void * GetVideoBuffer()
Get a pointer to the memory for the video driver to draw to.
bool persistent_mapping_supported
Persistent pixel buffer mapping supported.
GLuint vid_texture
Texture handle for the video buffer texture.
GLuint vao_quad
Vertex array object storing the rendering state for the fullscreen quad.
GLint sprite_zoom_loc
Uniform location for sprite zoom.
GLint remap_zoom_loc
Uniform location for sprite zoom.
bool Resize(int w, int h, bool force=false)
Change the size of the drawing window and allocate matching resources.
OpenGLBackend()
Construct OpenGL back-end class.
static std::optional< std::string_view > Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
Create and initialize the singleton back-end class.
void * vid_buffer
Pointer to the mapped video buffer.
void UpdatePalette(const Colour *pal, uint first, uint length)
Update the stored palette.
GLuint anim_texture
Texture handle for the animation buffer texture.
void InternalClearCursorCache()
Clear all cached cursor sprites.
Sprite * Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator) override
Convert a sprite from the loader to our own format.
GLuint sprite_program
Shader program for blending and rendering a sprite to the video buffer.
void ReleaseAnimBuffer(const Rect &update_rect)
Update animation buffer texture after the animation buffer was filled.
GLuint vid_pbo
Pixel buffer object storing the memory used for the video driver to draw to.
GLsync sync_anim_mapping
Sync object for the persistently mapped animation buffer.
GLuint vbo_quad
Vertex buffer with a fullscreen quad.
bool clear_cursor_cache
A clear of the cursor cache is pending.
GLint remap_rgb_loc
Uniform location for RGB mode flag.
void ClearCursorCache()
Queue a request for cursor cache clear.
GLuint vid_program
Shader program for rendering a RGBA video buffer.
GLuint pal_texture
Palette lookup texture.
GLint remap_sprite_loc
Uniform location for sprite parameters.
bool InitShaders()
Create all needed shader programs.
void DrawMouseCursor()
Draw mouse cursor on screen.
Point cursor_pos
Cursor position.
GLint sprite_crash_loc
Uniform location for crash remap mode flag.
void ReleaseVideoBuffer(const Rect &update_rect)
Update video buffer texture after the video buffer was filled.
GLint sprite_sprite_loc
Uniform location for sprite parameters.
void RenderOglSprite(const OpenGLSprite *gl_sprite, PaletteID pal, int x, int y, ZoomLevel zoom)
Render a sprite to the back buffer.
PaletteID last_sprite_pal
Last uploaded remap palette.
GLuint anim_pbo
Pixel buffer object storing the memory used for the animation buffer.
GLsync sync_vid_mapping
Sync object for the persistently mapped video buffer.
std::optional< std::string_view > Init(const Dimension &screen_res)
Check for the needed OpenGL functionality and allocate all resources.
static void Destroy()
Free resources and destroy singleton back-end class.
GLint sprite_screen_loc
Uniform location for screen size.
void * AllocatePtr(size_t) override
Allocate memory for a sprite.
Class that encapsulates a RGBA texture together with a paletted remap texture.
bool BindTextures() const
Bind textures for rendering this sprite.
static EnumIndexArray< GLuint, Texture, Texture::End > dummy_tex
1x1 dummy textures to substitute for unused sprite components.
OpenGLSprite(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite)
Create an OpenGL sprite with a palette remap part.
Texture
Enum of all used OpenGL texture objects.
@ Remap
Remap texture part.
Dimension GetSize(ZoomLevel level) const
Query the sprite size at a certain zoom level.
static bool Create()
Create all common resources for sprite rendering.
~OpenGLSprite()
Delete the textures we allocated.
static GLuint pal_pbo
Pixel buffer object for remap upload.
static GLuint pal_identity
Identity texture mapping.
static GLuint pal_tex
Texture for palette remap.
int16_t y_offs
Number of pixels to shift the sprite downwards.
int16_t x_offs
Number of pixels to shift the sprite to the right.
void Update(uint width, uint height, uint level, const SpriteLoader::CommonPixel *data)
Update a single mip-map level with new pixel data.
EnumIndexArray< GLuint, Texture, Texture::End > tex
The texture objects.
static void Destroy()
Free all common resources for sprite rendering.
A reusable buffer that can be used for places that temporary allocate a bit of memory and do that ver...
const T * GetBuffer() const
Get the currently allocated buffer.
T * Allocate(size_t count)
Get buffer of at least count times T.
Interface for something that can allocate memory for a sprite.
SpriteCollMap< Sprite > SpriteCollection
Type defining a collection of sprites, one for each zoom level.
Parse data from a string / buffer.
@ SKIP_ALL_SEPARATORS
Read and discard all consecutive separators, do not include any in the result.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
std::string_view ReadUntil(std::string_view str, SeparatorUsage sep)
Read data until the first occurrence of 'str', and advance reader.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
T ReadIntegerBase(int base, T def=0, bool clamp=false)
Read and parse an integer in number 'base', and advance the reader.
Functions related to debugging.
bool IsVisibleSeverity(Facility facility, Severity severity)
Test if debug severity is visible for the given facility.
#define Debug(facility, severity, format_string,...)
Output a line of debugging information.
@ Driver
Driver message facility.
@ Warning
Warning, wrong but okay if you don't know.
@ Critical
Critical, user should know about this.
@ Debug2
Debug #2 - Low level debug messages.
@ Trace2
Trace information #2.
@ Error
Error, but we are recovering.
@ Trace3
Trace information #3.
#define T
Climate temperate.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Factory to 'query' all available blitters.
bool IsEmptyRect(const Rect &r)
Check if a rectangle is empty.
ZoomLevel _gui_zoom
GUI Zoom level.
Functions related to the gfx engine.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
SpriteType
Types of sprites that might be loaded.
@ Recolour
Recolour sprite.
@ Font
A sprite used for fonts.
@ Normal
The most basic (normal) sprite.
uint32_t PaletteID
The number of the palette.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
bool IsOpenGLVersionAtLeast(uint8_t major, uint8_t minor)
Check if the current OpenGL version is equal or higher than a given one.
static bool BindBasicOpenGLProcs()
Bind OpenGL 1.0 and 1.1 functions.
static void ClearPixelBuffer(size_t len, T data)
Clear the bound pixel buffer to a specific value.
static const int MAX_CACHED_CURSORS
Maximum number of cursor sprites to cache.
static bool IsOpenGLExtensionSupported(std::string_view extension)
Check if an OpenGL extension is supported by the current context.
static bool BindPersistentBufferExtensions()
Bind extension functions for persistent buffer mapping.
static bool VerifyProgram(GLuint program)
Check a program for link errors and log them if necessary.
static uint8_t _gl_major_ver
Major OpenGL version.
static bool BindGLProc(F &f, const char *name)
Try loading an OpenGL function.
static bool BindVBAExtension()
Bind vertex array object extension functions.
void SetupDebugOutput()
Enable OpenGL debug messages if supported.
static uint8_t _gl_minor_ver
Minor OpenGL version.
static bool BindShaderExtensions()
Bind extension functions for shader support.
static bool BindBasicInfoProcs()
Bind basic information functions.
bool HasStringInExtensionList(std::string_view string, std::string_view substring)
Find a substring in a string made of space delimited elements.
static bool BindTextureExtensions()
Bind texture-related extension functions.
static bool VerifyShader(GLuint shader)
Check a shader for compilation errors and log them if necessary.
void DebugOutputCallback(GLenum, GLenum type, GLuint, GLenum severity, GLsizei, const GLchar *message, const void *)
Callback to receive OpenGL debug messages.
static bool BindVBOExtension()
Bind vertex buffer object extension functions.
OpenGL video driver support.
bool IsOpenGLVersionAtLeast(uint8_t major, uint8_t minor)
Check if the current OpenGL version is equal or higher than a given one.
static const char * _vertex_shader_sprite[]
Vertex shader that positions a sprite on screen.
static const char * _frag_shader_palette_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_direct[]
Fragment shader that reads the fragment colour from a 32bpp texture.
static const char * _frag_shader_rgb_mask_blend[]
Fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_palette[]
Fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_rgb_mask_blend_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from an 8bpp texture.
static const char * _frag_shader_direct_150[]
GLSL 1.50 fragment shader that reads the fragment colour from a 32bpp texture.
static const char * _frag_shader_sprite_blend_150[]
GLSL 1.50 fragment shader that performs a palette lookup to read the colour from a sprite texture.
static const char * _frag_shader_sprite_blend[]
Fragment shader that performs a palette lookup to read the colour from a sprite texture.
static const char * _vertex_shader_sprite_150[]
GLSL 1.50 vertex shader that positions a sprite on screen.
A number of safeguards to prevent using unsafe methods.
void * GetRawSprite(SpriteID sprite, SpriteType type, SpriteAllocator *allocator, SpriteEncoder *encoder)
Reads a sprite (from disk or sprite cache).
@ Palette
Sprite has palette data.
This file contains all sprite-related enums and defines.
static constexpr uint8_t PALETTE_WIDTH
number of bits of the sprite containing the recolour palette
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
std::vector< CursorSprite > sprites
Sprites comprising cursor.
Point pos
logical mouse position
bool in_window
mouse inside this window, determines drawing logic
Dimensions (a width and height) of a rectangle in 2D.
Specification of a rectangle with absolute coordinates of all edges.
A simple 2D vertex with just position and texture.
Definition of a common pixel in OpenTTD's realm.
Data structure describing a sprite.
uint16_t width
Width of the sprite.
Functions related to zooming.
int UnScaleByZoomLower(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min).
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
ZoomLevel
All zoom levels we know.