| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- /*
- * This source file is part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
- #include "RmlUi_Renderer_BackwardCompatible_GL3.h"
- #include <RmlUi/Core/Core.h>
- #include <RmlUi/Core/FileInterface.h>
- #include <RmlUi/Core/Log.h>
- #include <RmlUi/Core/Platform.h>
- #include <string.h>
- #if defined RMLUI_PLATFORM_WIN32_NATIVE
- // function call missing argument list
- #pragma warning(disable : 4551)
- // unreferenced local function has been removed
- #pragma warning(disable : 4505)
- #endif
- #if defined RMLUI_PLATFORM_EMSCRIPTEN
- #define RMLUI_SHADER_HEADER "#version 300 es\nprecision highp float;\n"
- #include <GLES3/gl3.h>
- #elif defined RMLUI_GL3_CUSTOM_LOADER
- #define RMLUI_SHADER_HEADER "#version 330\n"
- #include RMLUI_GL3_CUSTOM_LOADER
- #else
- #define RMLUI_SHADER_HEADER "#version 330\n"
- #define GLAD_GL_IMPLEMENTATION
- #include "../RmlUi_Include_GL3.h"
- #endif
- static const char* shader_main_vertex = RMLUI_SHADER_HEADER R"(
- uniform vec2 _translate;
- uniform mat4 _transform;
- in vec2 inPosition;
- in vec4 inColor0;
- in vec2 inTexCoord0;
- out vec2 fragTexCoord;
- out vec4 fragColor;
- void main() {
- fragTexCoord = inTexCoord0;
- fragColor = inColor0;
- vec2 translatedPos = inPosition + _translate.xy;
- vec4 outPos = _transform * vec4(translatedPos, 0, 1);
- gl_Position = outPos;
- }
- )";
- static const char* shader_main_fragment_texture = RMLUI_SHADER_HEADER R"(
- uniform sampler2D _tex;
- in vec2 fragTexCoord;
- in vec4 fragColor;
- out vec4 finalColor;
- void main() {
- vec4 texColor = texture(_tex, fragTexCoord);
- finalColor = fragColor * texColor;
- }
- )";
- static const char* shader_main_fragment_color = RMLUI_SHADER_HEADER R"(
- in vec2 fragTexCoord;
- in vec4 fragColor;
- out vec4 finalColor;
- void main() {
- finalColor = fragColor;
- }
- )";
- namespace Gfx {
- enum class ProgramUniform { Translate, Transform, Tex, Count };
- static const char* const program_uniform_names[(size_t)ProgramUniform::Count] = {"_translate", "_transform", "_tex"};
- enum class VertexAttribute { Position, Color0, TexCoord0, Count };
- static const char* const vertex_attribute_names[(size_t)VertexAttribute::Count] = {"inPosition", "inColor0", "inTexCoord0"};
- struct CompiledGeometryData {
- Rml::TextureHandle texture;
- GLuint vao;
- GLuint vbo;
- GLuint ibo;
- GLsizei draw_count;
- };
- struct ProgramData {
- GLuint id;
- GLint uniform_locations[(size_t)ProgramUniform::Count];
- };
- struct ShadersData {
- ProgramData program_color;
- ProgramData program_texture;
- GLuint shader_main_vertex;
- GLuint shader_main_fragment_color;
- GLuint shader_main_fragment_texture;
- };
- static void CheckGLError(const char* operation_name)
- {
- #ifdef RMLUI_DEBUG
- GLenum error_code = glGetError();
- if (error_code != GL_NO_ERROR)
- {
- static const Rml::Pair<GLenum, const char*> error_names[] = {{GL_INVALID_ENUM, "GL_INVALID_ENUM"}, {GL_INVALID_VALUE, "GL_INVALID_VALUE"},
- {GL_INVALID_OPERATION, "GL_INVALID_OPERATION"}, {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY"}};
- const char* error_str = "''";
- for (auto& err : error_names)
- {
- if (err.first == error_code)
- {
- error_str = err.second;
- break;
- }
- }
- Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL error during %s. Error code 0x%x (%s).", operation_name, error_code, error_str);
- }
- #endif
- (void)operation_name;
- }
- // Create the shader, 'shader_type' is either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
- static GLuint CreateShader(GLenum shader_type, const char* code_string)
- {
- GLuint id = glCreateShader(shader_type);
- glShaderSource(id, 1, (const GLchar**)&code_string, NULL);
- glCompileShader(id);
- GLint status = 0;
- glGetShaderiv(id, GL_COMPILE_STATUS, &status);
- if (status == GL_FALSE)
- {
- GLint info_log_length = 0;
- glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
- char* info_log_string = new char[info_log_length + 1];
- glGetShaderInfoLog(id, info_log_length, NULL, info_log_string);
- Rml::Log::Message(Rml::Log::LT_ERROR, "Compile failure in OpenGL shader: %s", info_log_string);
- delete[] info_log_string;
- glDeleteShader(id);
- return 0;
- }
- CheckGLError("CreateShader");
- return id;
- }
- static void BindAttribLocations(GLuint program)
- {
- for (GLuint i = 0; i < (GLuint)VertexAttribute::Count; i++)
- {
- glBindAttribLocation(program, i, vertex_attribute_names[i]);
- }
- CheckGLError("BindAttribLocations");
- }
- static bool CreateProgram(GLuint vertex_shader, GLuint fragment_shader, ProgramData& out_program)
- {
- GLuint id = glCreateProgram();
- RMLUI_ASSERT(id);
- BindAttribLocations(id);
- glAttachShader(id, vertex_shader);
- glAttachShader(id, fragment_shader);
- glLinkProgram(id);
- glDetachShader(id, vertex_shader);
- glDetachShader(id, fragment_shader);
- GLint status = 0;
- glGetProgramiv(id, GL_LINK_STATUS, &status);
- if (status == GL_FALSE)
- {
- GLint info_log_length = 0;
- glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
- char* info_log_string = new char[info_log_length + 1];
- glGetProgramInfoLog(id, info_log_length, NULL, info_log_string);
- Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program linking failure: %s", info_log_string);
- delete[] info_log_string;
- glDeleteProgram(id);
- return false;
- }
- out_program = {};
- out_program.id = id;
- // Make a lookup table for the uniform locations.
- GLint num_active_uniforms = 0;
- glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
- constexpr size_t name_size = 64;
- GLchar name_buf[name_size] = "";
- for (int unif = 0; unif < num_active_uniforms; ++unif)
- {
- GLint array_size = 0;
- GLenum type = 0;
- GLsizei actual_length = 0;
- glGetActiveUniform(id, unif, name_size, &actual_length, &array_size, &type, name_buf);
- GLint location = glGetUniformLocation(id, name_buf);
- // See if we have the name in our pre-defined name list.
- ProgramUniform program_uniform = ProgramUniform::Count;
- for (int i = 0; i < (int)ProgramUniform::Count; i++)
- {
- const char* uniform_name = program_uniform_names[i];
- if (strcmp(name_buf, uniform_name) == 0)
- {
- program_uniform = (ProgramUniform)i;
- break;
- }
- }
- if ((size_t)program_uniform < (size_t)ProgramUniform::Count)
- {
- out_program.uniform_locations[(size_t)program_uniform] = location;
- }
- else
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program uses unknown uniform '%s'.", name_buf);
- return false;
- }
- }
- CheckGLError("CreateProgram");
- return true;
- }
- static bool CreateShaders(ShadersData& out_shaders)
- {
- out_shaders = {};
- GLuint& main_vertex = out_shaders.shader_main_vertex;
- GLuint& main_fragment_color = out_shaders.shader_main_fragment_color;
- GLuint& main_fragment_texture = out_shaders.shader_main_fragment_texture;
- main_vertex = CreateShader(GL_VERTEX_SHADER, shader_main_vertex);
- if (!main_vertex)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_vertex'.");
- return false;
- }
- main_fragment_color = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_color);
- if (!main_fragment_color)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_color'.");
- return false;
- }
- main_fragment_texture = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_texture);
- if (!main_fragment_texture)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_texture'.");
- return false;
- }
- if (!CreateProgram(main_vertex, main_fragment_color, out_shaders.program_color))
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_color'.");
- return false;
- }
- if (!CreateProgram(main_vertex, main_fragment_texture, out_shaders.program_texture))
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_texture'.");
- return false;
- }
- return true;
- }
- static void DestroyShaders(ShadersData& shaders)
- {
- glDeleteProgram(shaders.program_color.id);
- glDeleteProgram(shaders.program_texture.id);
- glDeleteShader(shaders.shader_main_vertex);
- glDeleteShader(shaders.shader_main_fragment_color);
- glDeleteShader(shaders.shader_main_fragment_texture);
- shaders = {};
- }
- } // namespace Gfx
- RenderInterface_BackwardCompatible_GL3::RenderInterface_BackwardCompatible_GL3()
- {
- shaders = Rml::MakeUnique<Gfx::ShadersData>();
- if (!Gfx::CreateShaders(*shaders))
- shaders.reset();
- }
- RenderInterface_BackwardCompatible_GL3::~RenderInterface_BackwardCompatible_GL3()
- {
- if (shaders)
- Gfx::DestroyShaders(*shaders);
- }
- void RenderInterface_BackwardCompatible_GL3::SetViewport(int width, int height)
- {
- viewport_width = width;
- viewport_height = height;
- }
- void RenderInterface_BackwardCompatible_GL3::BeginFrame()
- {
- RMLUI_ASSERT(viewport_width >= 0 && viewport_height >= 0);
- // Backup GL state.
- glstate_backup.enable_cull_face = glIsEnabled(GL_CULL_FACE);
- glstate_backup.enable_blend = glIsEnabled(GL_BLEND);
- glstate_backup.enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
- glstate_backup.enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
- glGetIntegerv(GL_VIEWPORT, glstate_backup.viewport);
- glGetIntegerv(GL_SCISSOR_BOX, glstate_backup.scissor);
- glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &glstate_backup.stencil_clear_value);
- glGetFloatv(GL_COLOR_CLEAR_VALUE, glstate_backup.color_clear_value);
- glGetIntegerv(GL_BLEND_EQUATION_RGB, &glstate_backup.blend_equation_rgb);
- glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &glstate_backup.blend_equation_alpha);
- glGetIntegerv(GL_BLEND_SRC_RGB, &glstate_backup.blend_src_rgb);
- glGetIntegerv(GL_BLEND_DST_RGB, &glstate_backup.blend_dst_rgb);
- glGetIntegerv(GL_BLEND_SRC_ALPHA, &glstate_backup.blend_src_alpha);
- glGetIntegerv(GL_BLEND_DST_ALPHA, &glstate_backup.blend_dst_alpha);
- glGetIntegerv(GL_STENCIL_FUNC, &glstate_backup.stencil_front.func);
- glGetIntegerv(GL_STENCIL_REF, &glstate_backup.stencil_front.ref);
- glGetIntegerv(GL_STENCIL_VALUE_MASK, &glstate_backup.stencil_front.value_mask);
- glGetIntegerv(GL_STENCIL_WRITEMASK, &glstate_backup.stencil_front.writemask);
- glGetIntegerv(GL_STENCIL_FAIL, &glstate_backup.stencil_front.fail);
- glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &glstate_backup.stencil_front.pass_depth_fail);
- glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &glstate_backup.stencil_front.pass_depth_pass);
- glGetIntegerv(GL_STENCIL_BACK_FUNC, &glstate_backup.stencil_back.func);
- glGetIntegerv(GL_STENCIL_BACK_REF, &glstate_backup.stencil_back.ref);
- glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &glstate_backup.stencil_back.value_mask);
- glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &glstate_backup.stencil_back.writemask);
- glGetIntegerv(GL_STENCIL_BACK_FAIL, &glstate_backup.stencil_back.fail);
- glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &glstate_backup.stencil_back.pass_depth_fail);
- glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &glstate_backup.stencil_back.pass_depth_pass);
- // Setup expected GL state.
- glViewport(0, 0, viewport_width, viewport_height);
- glClearStencil(0);
- glClearColor(0, 0, 0, 1);
- glDisable(GL_CULL_FACE);
- glEnable(GL_BLEND);
- glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
- glStencilMask(GLuint(-1));
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
- SetTransform(nullptr);
- }
- void RenderInterface_BackwardCompatible_GL3::EndFrame()
- {
- // Restore GL state.
- if (glstate_backup.enable_cull_face)
- glEnable(GL_CULL_FACE);
- else
- glDisable(GL_CULL_FACE);
- if (glstate_backup.enable_blend)
- glEnable(GL_BLEND);
- else
- glDisable(GL_BLEND);
- if (glstate_backup.enable_stencil_test)
- glEnable(GL_STENCIL_TEST);
- else
- glDisable(GL_STENCIL_TEST);
- if (glstate_backup.enable_scissor_test)
- glEnable(GL_SCISSOR_TEST);
- else
- glDisable(GL_SCISSOR_TEST);
- glViewport(glstate_backup.viewport[0], glstate_backup.viewport[1], glstate_backup.viewport[2], glstate_backup.viewport[3]);
- glScissor(glstate_backup.scissor[0], glstate_backup.scissor[1], glstate_backup.scissor[2], glstate_backup.scissor[3]);
- glClearStencil(glstate_backup.stencil_clear_value);
- glClearColor(glstate_backup.color_clear_value[0], glstate_backup.color_clear_value[1], glstate_backup.color_clear_value[2],
- glstate_backup.color_clear_value[3]);
- glBlendEquationSeparate(glstate_backup.blend_equation_rgb, glstate_backup.blend_equation_alpha);
- glBlendFuncSeparate(glstate_backup.blend_src_rgb, glstate_backup.blend_dst_rgb, glstate_backup.blend_src_alpha, glstate_backup.blend_dst_alpha);
- glStencilFuncSeparate(GL_FRONT, glstate_backup.stencil_front.func, glstate_backup.stencil_front.ref, glstate_backup.stencil_front.value_mask);
- glStencilMaskSeparate(GL_FRONT, glstate_backup.stencil_front.writemask);
- glStencilOpSeparate(GL_FRONT, glstate_backup.stencil_front.fail, glstate_backup.stencil_front.pass_depth_fail,
- glstate_backup.stencil_front.pass_depth_pass);
- glStencilFuncSeparate(GL_BACK, glstate_backup.stencil_back.func, glstate_backup.stencil_back.ref, glstate_backup.stencil_back.value_mask);
- glStencilMaskSeparate(GL_BACK, glstate_backup.stencil_back.writemask);
- glStencilOpSeparate(GL_BACK, glstate_backup.stencil_back.fail, glstate_backup.stencil_back.pass_depth_fail,
- glstate_backup.stencil_back.pass_depth_pass);
- }
- void RenderInterface_BackwardCompatible_GL3::Clear()
- {
- glClearStencil(0);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
- void RenderInterface_BackwardCompatible_GL3::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices,
- const Rml::TextureHandle texture, const Rml::Vector2f& translation)
- {
- Rml::CompiledGeometryHandle geometry = CompileGeometry(vertices, num_vertices, indices, num_indices, texture);
- if (geometry)
- {
- RenderCompiledGeometry(geometry, translation);
- ReleaseCompiledGeometry(geometry);
- }
- }
- Rml::CompiledGeometryHandle RenderInterface_BackwardCompatible_GL3::CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices,
- int num_indices, Rml::TextureHandle texture)
- {
- constexpr GLenum draw_usage = GL_STATIC_DRAW;
- GLuint vao = 0;
- GLuint vbo = 0;
- GLuint ibo = 0;
- glGenVertexArrays(1, &vao);
- glGenBuffers(1, &vbo);
- glGenBuffers(1, &ibo);
- glBindVertexArray(vao);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof(Rml::Vertex) * num_vertices, (const void*)vertices, draw_usage);
- glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Position);
- glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
- (const GLvoid*)(offsetof(Rml::Vertex, position)));
- glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Color0);
- glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Rml::Vertex),
- (const GLvoid*)(offsetof(Rml::Vertex, colour)));
- glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::TexCoord0);
- glVertexAttribPointer((GLuint)Gfx::VertexAttribute::TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
- (const GLvoid*)(offsetof(Rml::Vertex, tex_coord)));
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, (const void*)indices, draw_usage);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- Gfx::CheckGLError("CompileGeometry");
- Gfx::CompiledGeometryData* geometry = new Gfx::CompiledGeometryData;
- geometry->texture = texture;
- geometry->vao = vao;
- geometry->vbo = vbo;
- geometry->ibo = ibo;
- geometry->draw_count = num_indices;
- return (Rml::CompiledGeometryHandle)geometry;
- }
- void RenderInterface_BackwardCompatible_GL3::RenderCompiledGeometry(Rml::CompiledGeometryHandle handle, const Rml::Vector2f& translation)
- {
- Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
- if (geometry->texture)
- {
- glUseProgram(shaders->program_texture.id);
- if (geometry->texture != TextureEnableWithoutBinding)
- glBindTexture(GL_TEXTURE_2D, (GLuint)geometry->texture);
- SubmitTransformUniform(ProgramId::Texture, shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
- glUniform2fv(shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
- }
- else
- {
- glUseProgram(shaders->program_color.id);
- glBindTexture(GL_TEXTURE_2D, 0);
- SubmitTransformUniform(ProgramId::Color, shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
- glUniform2fv(shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
- }
- glBindVertexArray(geometry->vao);
- glDrawElements(GL_TRIANGLES, geometry->draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
- glBindVertexArray(0);
- glUseProgram(0);
- glBindTexture(GL_TEXTURE_2D, 0);
- Gfx::CheckGLError("RenderCompiledGeometry");
- }
- void RenderInterface_BackwardCompatible_GL3::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle handle)
- {
- Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
- glDeleteVertexArrays(1, &geometry->vao);
- glDeleteBuffers(1, &geometry->vbo);
- glDeleteBuffers(1, &geometry->ibo);
- delete geometry;
- }
- void RenderInterface_BackwardCompatible_GL3::EnableScissorRegion(bool enable)
- {
- ScissoringState new_state = ScissoringState::Disable;
- if (enable)
- new_state = (transform_active ? ScissoringState::Stencil : ScissoringState::Scissor);
- if (new_state != scissoring_state)
- {
- // Disable old
- if (scissoring_state == ScissoringState::Scissor)
- glDisable(GL_SCISSOR_TEST);
- else if (scissoring_state == ScissoringState::Stencil)
- glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
- // Enable new
- if (new_state == ScissoringState::Scissor)
- glEnable(GL_SCISSOR_TEST);
- else if (new_state == ScissoringState::Stencil)
- glStencilFunc(GL_EQUAL, 1, GLuint(-1));
- scissoring_state = new_state;
- }
- }
- void RenderInterface_BackwardCompatible_GL3::SetScissorRegion(int x, int y, int width, int height)
- {
- if (transform_active)
- {
- const float left = float(x);
- const float right = float(x + width);
- const float top = float(y);
- const float bottom = float(y + height);
- Rml::Vertex vertices[4];
- vertices[0].position = {left, top};
- vertices[1].position = {right, top};
- vertices[2].position = {right, bottom};
- vertices[3].position = {left, bottom};
- int indices[6] = {0, 2, 1, 0, 3, 2};
- glClear(GL_STENCIL_BUFFER_BIT);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- RenderGeometry(vertices, 4, indices, 6, 0, Rml::Vector2f(0, 0));
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_EQUAL, 1, GLuint(-1));
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- }
- else
- {
- glScissor(x, viewport_height - (y + height), width, height);
- }
- }
- // Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
- #pragma pack(1)
- struct TGAHeader {
- char idLength;
- char colourMapType;
- char dataType;
- short int colourMapOrigin;
- short int colourMapLength;
- char colourMapDepth;
- short int xOrigin;
- short int yOrigin;
- short int width;
- short int height;
- char bitsPerPixel;
- char imageDescriptor;
- };
- // Restore packing
- #pragma pack()
- bool RenderInterface_BackwardCompatible_GL3::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions,
- const Rml::String& source)
- {
- Rml::FileInterface* file_interface = Rml::GetFileInterface();
- Rml::FileHandle file_handle = file_interface->Open(source);
- if (!file_handle)
- {
- return false;
- }
- file_interface->Seek(file_handle, 0, SEEK_END);
- size_t buffer_size = file_interface->Tell(file_handle);
- file_interface->Seek(file_handle, 0, SEEK_SET);
- if (buffer_size <= sizeof(TGAHeader))
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
- file_interface->Close(file_handle);
- return false;
- }
- using Rml::byte;
- byte* buffer = new byte[buffer_size];
- file_interface->Read(buffer, buffer_size, file_handle);
- file_interface->Close(file_handle);
- TGAHeader header;
- memcpy(&header, buffer, sizeof(TGAHeader));
- int color_mode = header.bitsPerPixel / 8;
- int image_size = header.width * header.height * 4; // We always make 32bit textures
- if (header.dataType != 2)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
- delete[] buffer;
- return false;
- }
- // Ensure we have at least 3 colors
- if (color_mode < 3)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
- delete[] buffer;
- return false;
- }
- const byte* image_src = buffer + sizeof(TGAHeader);
- byte* image_dest = new byte[image_size];
- // Targa is BGR, swap to RGB and flip Y axis
- for (long y = 0; y < header.height; y++)
- {
- long read_index = y * header.width * color_mode;
- long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * 4;
- for (long x = 0; x < header.width; x++)
- {
- image_dest[write_index] = image_src[read_index + 2];
- image_dest[write_index + 1] = image_src[read_index + 1];
- image_dest[write_index + 2] = image_src[read_index];
- if (color_mode == 4)
- {
- const int alpha = image_src[read_index + 3];
- #ifdef RMLUI_SRGB_PREMULTIPLIED_ALPHA
- image_dest[write_index + 0] = (image_dest[write_index + 0] * alpha) / 255;
- image_dest[write_index + 1] = (image_dest[write_index + 1] * alpha) / 255;
- image_dest[write_index + 2] = (image_dest[write_index + 2] * alpha) / 255;
- #endif
- image_dest[write_index + 3] = (byte)alpha;
- }
- else
- {
- image_dest[write_index + 3] = 255;
- }
- write_index += 4;
- read_index += color_mode;
- }
- }
- texture_dimensions.x = header.width;
- texture_dimensions.y = header.height;
- bool success = GenerateTexture(texture_handle, image_dest, texture_dimensions);
- delete[] image_dest;
- delete[] buffer;
- return success;
- }
- bool RenderInterface_BackwardCompatible_GL3::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source,
- const Rml::Vector2i& source_dimensions)
- {
- GLuint texture_id = 0;
- glGenTextures(1, &texture_id);
- if (texture_id == 0)
- {
- Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
- return false;
- }
- glBindTexture(GL_TEXTURE_2D, texture_id);
- GLint internal_format = GL_RGBA8;
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- texture_handle = (Rml::TextureHandle)texture_id;
- glBindTexture(GL_TEXTURE_2D, 0);
- return true;
- }
- void RenderInterface_BackwardCompatible_GL3::ReleaseTexture(Rml::TextureHandle texture_handle)
- {
- glDeleteTextures(1, (GLuint*)&texture_handle);
- }
- void RenderInterface_BackwardCompatible_GL3::SetTransform(const Rml::Matrix4f* new_transform)
- {
- transform_active = (new_transform != nullptr);
- transform = projection * (new_transform ? *new_transform : Rml::Matrix4f::Identity());
- transform_dirty_state = ProgramId::All;
- }
- void RenderInterface_BackwardCompatible_GL3::SubmitTransformUniform(ProgramId program_id, int uniform_location)
- {
- if ((int)program_id & (int)transform_dirty_state)
- {
- glUniformMatrix4fv(uniform_location, 1, false, transform.data());
- transform_dirty_state = ProgramId((int)transform_dirty_state & ~(int)program_id);
- }
- }
- bool RmlGL3::Initialize(Rml::String* out_message)
- {
- #if defined RMLUI_PLATFORM_EMSCRIPTEN
- if (out_message)
- *out_message = "Started Emscripten WebGL renderer.";
- #elif !defined RMLUI_GL3_CUSTOM_LOADER
- const int gl_version = gladLoaderLoadGL();
- if (gl_version == 0)
- {
- if (out_message)
- *out_message = "Failed to initialize OpenGL context.";
- return false;
- }
- if (out_message)
- *out_message = Rml::CreateString("Loaded OpenGL %d.%d.", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
- #endif
- return true;
- }
- void RmlGL3::Shutdown()
- {
- #if !defined RMLUI_PLATFORM_EMSCRIPTEN && !defined RMLUI_GL3_CUSTOM_LOADER
- gladLoaderUnloadGL();
- #endif
- }
|