Inital commit
This commit is contained in:
226
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL2.cpp
vendored
Normal file
226
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL2.cpp
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "../RmlUi_Backend.h"
|
||||
#include "../RmlUi_Platform_GLFW.h"
|
||||
#include "RmlUi_Renderer_BackwardCompatible_GL2.h"
|
||||
#include <RmlUi/Core/Context.h>
|
||||
#include <RmlUi/Core/Input.h>
|
||||
#include <RmlUi/Core/Profiling.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
static void SetupCallbacks(GLFWwindow* window);
|
||||
|
||||
static void LogErrorFromGLFW(int error, const char* description)
|
||||
{
|
||||
Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW error (0x%x): %s", error, description);
|
||||
}
|
||||
|
||||
/**
|
||||
Global data used by this backend.
|
||||
|
||||
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||
*/
|
||||
struct BackendData {
|
||||
SystemInterface_GLFW system_interface;
|
||||
RenderInterface_BackwardCompatible_GL2 render_interface;
|
||||
GLFWwindow* window = nullptr;
|
||||
int glfw_active_modifiers = 0;
|
||||
bool context_dimensions_dirty = true;
|
||||
|
||||
// Arguments set during event processing and nulled otherwise.
|
||||
Rml::Context* context = nullptr;
|
||||
KeyDownCallback key_down_callback = nullptr;
|
||||
};
|
||||
static Rml::UniquePtr<BackendData> data;
|
||||
|
||||
bool Backend::Initialize(const char* name, int width, int height, bool allow_resize)
|
||||
{
|
||||
RMLUI_ASSERT(!data);
|
||||
|
||||
glfwSetErrorCallback(LogErrorFromGLFW);
|
||||
|
||||
if (!glfwInit())
|
||||
return false;
|
||||
|
||||
// Set window hints for OpenGL 2 context creation.
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
|
||||
|
||||
// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, 8);
|
||||
|
||||
// Enable MSAA for better-looking visuals, especially when transforms are applied.
|
||||
glfwWindowHint(GLFW_SAMPLES, 2);
|
||||
|
||||
// Apply window properties and create it.
|
||||
glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(width, height, name, nullptr, nullptr);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
data = Rml::MakeUnique<BackendData>();
|
||||
data->window = window;
|
||||
data->system_interface.SetWindow(window);
|
||||
|
||||
// The window size may have been scaled by DPI settings, get the actual pixel size.
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
data->render_interface.SetViewport(width, height);
|
||||
|
||||
// Receive num lock and caps lock modifiers for proper handling of numpad inputs in text fields.
|
||||
glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
|
||||
|
||||
// Setup the input and window event callback functions.
|
||||
SetupCallbacks(window);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Backend::Shutdown()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
glfwDestroyWindow(data->window);
|
||||
data.reset();
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
return &data->system_interface;
|
||||
}
|
||||
|
||||
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
return data->render_interface.GetAdaptedInterface();
|
||||
}
|
||||
|
||||
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||
{
|
||||
RMLUI_ASSERT(data && context);
|
||||
|
||||
// The initial window size may have been affected by system DPI settings, apply the actual pixel size and dp-ratio to the context.
|
||||
if (data->context_dimensions_dirty)
|
||||
{
|
||||
data->context_dimensions_dirty = false;
|
||||
|
||||
Rml::Vector2i window_size;
|
||||
float dp_ratio = 1.f;
|
||||
glfwGetFramebufferSize(data->window, &window_size.x, &window_size.y);
|
||||
glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
|
||||
|
||||
context->SetDimensions(window_size);
|
||||
context->SetDensityIndependentPixelRatio(dp_ratio);
|
||||
}
|
||||
|
||||
data->context = context;
|
||||
data->key_down_callback = key_down_callback;
|
||||
|
||||
if (power_save)
|
||||
glfwWaitEventsTimeout(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0));
|
||||
else
|
||||
glfwPollEvents();
|
||||
|
||||
data->context = nullptr;
|
||||
data->key_down_callback = nullptr;
|
||||
|
||||
const bool result = !glfwWindowShouldClose(data->window);
|
||||
glfwSetWindowShouldClose(data->window, GLFW_FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Backend::RequestExit()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
glfwSetWindowShouldClose(data->window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
void Backend::BeginFrame()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
data->render_interface.BeginFrame();
|
||||
data->render_interface.Clear();
|
||||
}
|
||||
|
||||
void Backend::PresentFrame()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
data->render_interface.EndFrame();
|
||||
glfwSwapBuffers(data->window);
|
||||
|
||||
// Optional, used to mark frames during performance profiling.
|
||||
RMLUI_FrameMark;
|
||||
}
|
||||
|
||||
static void SetupCallbacks(GLFWwindow* window)
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
|
||||
// Key input
|
||||
glfwSetKeyCallback(window, [](GLFWwindow* /*window*/, int glfw_key, int /*scancode*/, int glfw_action, int glfw_mods) {
|
||||
if (!data->context)
|
||||
return;
|
||||
|
||||
// Store the active modifiers for later because GLFW doesn't provide them in the callbacks to the mouse input events.
|
||||
data->glfw_active_modifiers = glfw_mods;
|
||||
|
||||
// Override the default key event callback to add global shortcuts for the samples.
|
||||
Rml::Context* context = data->context;
|
||||
KeyDownCallback key_down_callback = data->key_down_callback;
|
||||
|
||||
switch (glfw_action)
|
||||
{
|
||||
case GLFW_PRESS:
|
||||
case GLFW_REPEAT:
|
||||
{
|
||||
const Rml::Input::KeyIdentifier key = RmlGLFW::ConvertKey(glfw_key);
|
||||
const int key_modifier = RmlGLFW::ConvertKeyModifiers(glfw_mods);
|
||||
float dp_ratio = 1.f;
|
||||
glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
|
||||
|
||||
// See if we have any global shortcuts that take priority over the context.
|
||||
if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, true))
|
||||
break;
|
||||
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||
if (!RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods))
|
||||
break;
|
||||
// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
|
||||
if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, false))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GLFW_RELEASE: RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods); break;
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetCharCallback(window, [](GLFWwindow* /*window*/, unsigned int codepoint) { RmlGLFW::ProcessCharCallback(data->context, codepoint); });
|
||||
|
||||
glfwSetCursorEnterCallback(window, [](GLFWwindow* /*window*/, int entered) { RmlGLFW::ProcessCursorEnterCallback(data->context, entered); });
|
||||
|
||||
// Mouse input
|
||||
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) {
|
||||
RmlGLFW::ProcessCursorPosCallback(data->context, window, xpos, ypos, data->glfw_active_modifiers);
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, [](GLFWwindow* /*window*/, int button, int action, int mods) {
|
||||
data->glfw_active_modifiers = mods;
|
||||
RmlGLFW::ProcessMouseButtonCallback(data->context, button, action, mods);
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, [](GLFWwindow* /*window*/, double /*xoffset*/, double yoffset) {
|
||||
RmlGLFW::ProcessScrollCallback(data->context, yoffset, data->glfw_active_modifiers);
|
||||
});
|
||||
|
||||
// Window events
|
||||
glfwSetFramebufferSizeCallback(window, [](GLFWwindow* /*window*/, int width, int height) {
|
||||
data->render_interface.SetViewport(width, height);
|
||||
RmlGLFW::ProcessFramebufferSizeCallback(data->context, width, height);
|
||||
});
|
||||
|
||||
glfwSetWindowContentScaleCallback(window,
|
||||
[](GLFWwindow* /*window*/, float xscale, float /*yscale*/) { RmlGLFW::ProcessContentScaleCallback(data->context, xscale); });
|
||||
}
|
||||
240
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL3.cpp
vendored
Normal file
240
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL3.cpp
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
#include "../RmlUi_Backend.h"
|
||||
#include "../RmlUi_Platform_GLFW.h"
|
||||
#include "RmlUi_Renderer_BackwardCompatible_GL3.h"
|
||||
#include <RmlUi/Core/Context.h>
|
||||
#include <RmlUi/Core/Input.h>
|
||||
#include <RmlUi/Core/Profiling.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
static void SetupCallbacks(GLFWwindow* window);
|
||||
|
||||
static void LogErrorFromGLFW(int error, const char* description)
|
||||
{
|
||||
Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW error (0x%x): %s", error, description);
|
||||
}
|
||||
|
||||
/**
|
||||
Global data used by this backend.
|
||||
|
||||
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||
*/
|
||||
struct BackendData {
|
||||
SystemInterface_GLFW system_interface;
|
||||
RenderInterface_BackwardCompatible_GL3 render_interface;
|
||||
GLFWwindow* window = nullptr;
|
||||
int glfw_active_modifiers = 0;
|
||||
bool context_dimensions_dirty = true;
|
||||
|
||||
// Arguments set during event processing and nulled otherwise.
|
||||
Rml::Context* context = nullptr;
|
||||
KeyDownCallback key_down_callback = nullptr;
|
||||
};
|
||||
static Rml::UniquePtr<BackendData> data;
|
||||
|
||||
bool Backend::Initialize(const char* name, int width, int height, bool allow_resize)
|
||||
{
|
||||
RMLUI_ASSERT(!data);
|
||||
|
||||
glfwSetErrorCallback(LogErrorFromGLFW);
|
||||
|
||||
if (!glfwInit())
|
||||
return false;
|
||||
|
||||
// Set window hints for OpenGL 3.3 Core context creation.
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
|
||||
|
||||
// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
|
||||
glfwWindowHint(GLFW_STENCIL_BITS, 8);
|
||||
|
||||
// Enable MSAA for better-looking visuals, especially when transforms are applied.
|
||||
glfwWindowHint(GLFW_SAMPLES, 2);
|
||||
|
||||
// Apply window properties and create it.
|
||||
glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(width, height, name, nullptr, nullptr);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
|
||||
// Load the OpenGL functions.
|
||||
Rml::String renderer_message;
|
||||
if (!RmlGL3::Initialize(&renderer_message))
|
||||
return false;
|
||||
|
||||
// Construct the system and render interface, this includes compiling all the shaders. If this fails, it is likely an error in the shader code.
|
||||
data = Rml::MakeUnique<BackendData>();
|
||||
if (!data || !data->render_interface)
|
||||
return false;
|
||||
|
||||
data->window = window;
|
||||
data->system_interface.SetWindow(window);
|
||||
data->system_interface.LogMessage(Rml::Log::LT_INFO, renderer_message);
|
||||
|
||||
// The window size may have been scaled by DPI settings, get the actual pixel size.
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
data->render_interface.SetViewport(width, height);
|
||||
|
||||
// Receive num lock and caps lock modifiers for proper handling of numpad inputs in text fields.
|
||||
glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
|
||||
|
||||
// Setup the input and window event callback functions.
|
||||
SetupCallbacks(window);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Backend::Shutdown()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
glfwDestroyWindow(data->window);
|
||||
data.reset();
|
||||
RmlGL3::Shutdown();
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
return &data->system_interface;
|
||||
}
|
||||
|
||||
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
return data->render_interface.GetAdaptedInterface();
|
||||
}
|
||||
|
||||
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||
{
|
||||
RMLUI_ASSERT(data && context);
|
||||
|
||||
// The initial window size may have been affected by system DPI settings, apply the actual pixel size and dp-ratio to the context.
|
||||
if (data->context_dimensions_dirty)
|
||||
{
|
||||
data->context_dimensions_dirty = false;
|
||||
|
||||
Rml::Vector2i window_size;
|
||||
float dp_ratio = 1.f;
|
||||
glfwGetFramebufferSize(data->window, &window_size.x, &window_size.y);
|
||||
glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
|
||||
|
||||
context->SetDimensions(window_size);
|
||||
context->SetDensityIndependentPixelRatio(dp_ratio);
|
||||
}
|
||||
|
||||
data->context = context;
|
||||
data->key_down_callback = key_down_callback;
|
||||
|
||||
if (power_save)
|
||||
glfwWaitEventsTimeout(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0));
|
||||
else
|
||||
glfwPollEvents();
|
||||
|
||||
data->context = nullptr;
|
||||
data->key_down_callback = nullptr;
|
||||
|
||||
const bool result = !glfwWindowShouldClose(data->window);
|
||||
glfwSetWindowShouldClose(data->window, GLFW_FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Backend::RequestExit()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
glfwSetWindowShouldClose(data->window, GLFW_TRUE);
|
||||
}
|
||||
|
||||
void Backend::BeginFrame()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
data->render_interface.BeginFrame();
|
||||
data->render_interface.Clear();
|
||||
}
|
||||
|
||||
void Backend::PresentFrame()
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
data->render_interface.EndFrame();
|
||||
glfwSwapBuffers(data->window);
|
||||
|
||||
// Optional, used to mark frames during performance profiling.
|
||||
RMLUI_FrameMark;
|
||||
}
|
||||
|
||||
static void SetupCallbacks(GLFWwindow* window)
|
||||
{
|
||||
RMLUI_ASSERT(data);
|
||||
|
||||
// Key input
|
||||
glfwSetKeyCallback(window, [](GLFWwindow* /*window*/, int glfw_key, int /*scancode*/, int glfw_action, int glfw_mods) {
|
||||
if (!data->context)
|
||||
return;
|
||||
|
||||
// Store the active modifiers for later because GLFW doesn't provide them in the callbacks to the mouse input events.
|
||||
data->glfw_active_modifiers = glfw_mods;
|
||||
|
||||
// Override the default key event callback to add global shortcuts for the samples.
|
||||
Rml::Context* context = data->context;
|
||||
KeyDownCallback key_down_callback = data->key_down_callback;
|
||||
|
||||
switch (glfw_action)
|
||||
{
|
||||
case GLFW_PRESS:
|
||||
case GLFW_REPEAT:
|
||||
{
|
||||
const Rml::Input::KeyIdentifier key = RmlGLFW::ConvertKey(glfw_key);
|
||||
const int key_modifier = RmlGLFW::ConvertKeyModifiers(glfw_mods);
|
||||
float dp_ratio = 1.f;
|
||||
glfwGetWindowContentScale(data->window, &dp_ratio, nullptr);
|
||||
|
||||
// See if we have any global shortcuts that take priority over the context.
|
||||
if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, true))
|
||||
break;
|
||||
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||
if (!RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods))
|
||||
break;
|
||||
// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
|
||||
if (key_down_callback && !key_down_callback(context, key, key_modifier, dp_ratio, false))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GLFW_RELEASE: RmlGLFW::ProcessKeyCallback(context, glfw_key, glfw_action, glfw_mods); break;
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetCharCallback(window, [](GLFWwindow* /*window*/, unsigned int codepoint) { RmlGLFW::ProcessCharCallback(data->context, codepoint); });
|
||||
|
||||
glfwSetCursorEnterCallback(window, [](GLFWwindow* /*window*/, int entered) { RmlGLFW::ProcessCursorEnterCallback(data->context, entered); });
|
||||
|
||||
// Mouse input
|
||||
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) {
|
||||
RmlGLFW::ProcessCursorPosCallback(data->context, window, xpos, ypos, data->glfw_active_modifiers);
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, [](GLFWwindow* /*window*/, int button, int action, int mods) {
|
||||
data->glfw_active_modifiers = mods;
|
||||
RmlGLFW::ProcessMouseButtonCallback(data->context, button, action, mods);
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, [](GLFWwindow* /*window*/, double /*xoffset*/, double yoffset) {
|
||||
RmlGLFW::ProcessScrollCallback(data->context, yoffset, data->glfw_active_modifiers);
|
||||
});
|
||||
|
||||
// Window events
|
||||
glfwSetFramebufferSizeCallback(window, [](GLFWwindow* /*window*/, int width, int height) {
|
||||
data->render_interface.SetViewport(width, height);
|
||||
RmlGLFW::ProcessFramebufferSizeCallback(data->context, width, height);
|
||||
});
|
||||
|
||||
glfwSetWindowContentScaleCallback(window,
|
||||
[](GLFWwindow* /*window*/, float xscale, float /*yscale*/) { RmlGLFW::ProcessContentScaleCallback(data->context, xscale); });
|
||||
}
|
||||
300
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.cpp
vendored
Normal file
300
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.cpp
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
#include "RmlUi_Renderer_BackwardCompatible_GL2.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
|
||||
#include "RmlUi_Include_Windows.h"
|
||||
#include <gl/Gl.h>
|
||||
#include <gl/Glu.h>
|
||||
#elif defined RMLUI_PLATFORM_MACOSX
|
||||
#include <AGL/agl.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#elif defined RMLUI_PLATFORM_UNIX
|
||||
#include "RmlUi_Include_Xlib.h"
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
|
||||
RenderInterface_BackwardCompatible_GL2::RenderInterface_BackwardCompatible_GL2() {}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::SetViewport(int in_viewport_width, int in_viewport_height)
|
||||
{
|
||||
viewport_width = in_viewport_width;
|
||||
viewport_height = in_viewport_height;
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::BeginFrame()
|
||||
{
|
||||
RMLUI_ASSERT(viewport_width >= 0 && viewport_height >= 0);
|
||||
glViewport(0, 0, viewport_width, viewport_height);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Rml::Matrix4f projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf(projection.data());
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
transform_enabled = false;
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::EndFrame() {}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::Clear()
|
||||
{
|
||||
glClearStencil(0);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::RenderGeometry(Rml::Vertex* vertices, int /*num_vertices*/, int* indices, int num_indices,
|
||||
const Rml::TextureHandle texture, const Rml::Vector2f& translation)
|
||||
{
|
||||
glPushMatrix();
|
||||
glTranslatef(translation.x, translation.y, 0);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].position);
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Rml::Vertex), &vertices[0].colour);
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (texture != TextureEnableWithoutBinding)
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)texture);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].tex_coord);
|
||||
}
|
||||
|
||||
glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::EnableScissorRegion(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
if (!transform_enabled)
|
||||
{
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::SetScissorRegion(int x, int y, int width, int height)
|
||||
{
|
||||
if (!transform_enabled)
|
||||
{
|
||||
glScissor(x, viewport_height - (y + height), width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear the stencil buffer
|
||||
glStencilMask(GLuint(-1));
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// fill the stencil buffer
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
glDepthMask(GL_FALSE);
|
||||
glStencilFunc(GL_NEVER, 1, GLuint(-1));
|
||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
||||
|
||||
float fx = (float)x;
|
||||
float fy = (float)y;
|
||||
float fwidth = (float)width;
|
||||
float fheight = (float)height;
|
||||
|
||||
// draw transformed quad
|
||||
GLfloat vertices[] = {fx, fy, 0, fx, fy + fheight, 0, fx + fwidth, fy + fheight, 0, fx + fwidth, fy, 0};
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vertices);
|
||||
GLushort indices[] = {1, 2, 0, 3};
|
||||
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// prepare for drawing the real thing
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDepthMask(GL_TRUE);
|
||||
glStencilMask(0);
|
||||
glStencilFunc(GL_EQUAL, 1, GLuint(-1));
|
||||
}
|
||||
}
|
||||
|
||||
// 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_GL2::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;
|
||||
}
|
||||
|
||||
char* buffer = new char[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 char* image_src = buffer + sizeof(TGAHeader);
|
||||
unsigned char* image_dest = new unsigned char[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 * color_mode;
|
||||
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)
|
||||
image_dest[write_index + 3] = image_src[read_index + 3];
|
||||
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_GL2::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);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::ReleaseTexture(Rml::TextureHandle texture_handle)
|
||||
{
|
||||
glDeleteTextures(1, (GLuint*)&texture_handle);
|
||||
}
|
||||
|
||||
void RenderInterface_BackwardCompatible_GL2::SetTransform(const Rml::Matrix4f* transform)
|
||||
{
|
||||
transform_enabled = (transform != nullptr);
|
||||
|
||||
if (transform)
|
||||
{
|
||||
if (std::is_same<Rml::Matrix4f, Rml::ColumnMajorMatrix4f>::value)
|
||||
glLoadMatrixf(transform->data());
|
||||
else if (std::is_same<Rml::Matrix4f, Rml::RowMajorMatrix4f>::value)
|
||||
glLoadMatrixf(transform->Transpose().data());
|
||||
}
|
||||
else
|
||||
glLoadIdentity();
|
||||
}
|
||||
46
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.h
vendored
Normal file
46
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/RenderInterfaceCompatibility.h>
|
||||
|
||||
/*
|
||||
The GL2 renderer from RmlUi 5, only modified to derive from the compatibility interface.
|
||||
|
||||
Implemented for testing and demonstration purposes, not recommended for production use.
|
||||
*/
|
||||
|
||||
class RenderInterface_BackwardCompatible_GL2 : public Rml::RenderInterfaceCompatibility {
|
||||
public:
|
||||
RenderInterface_BackwardCompatible_GL2();
|
||||
|
||||
// The viewport should be updated whenever the window size changes.
|
||||
void SetViewport(int viewport_width, int viewport_height);
|
||||
|
||||
// Sets up OpenGL states for taking rendering commands from RmlUi.
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
// Optional, can be used to clear the framebuffer.
|
||||
void Clear();
|
||||
|
||||
// -- Inherited from Rml::RenderInterface --
|
||||
|
||||
void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
|
||||
const Rml::Vector2f& translation) override;
|
||||
|
||||
void EnableScissorRegion(bool enable) override;
|
||||
void SetScissorRegion(int x, int y, int width, int height) override;
|
||||
|
||||
bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||
bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
|
||||
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||
|
||||
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||
|
||||
// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
|
||||
static const Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
|
||||
|
||||
private:
|
||||
int viewport_width = 0;
|
||||
int viewport_height = 0;
|
||||
bool transform_enabled = false;
|
||||
};
|
||||
765
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.cpp
vendored
Normal file
765
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.cpp
vendored
Normal file
@@ -0,0 +1,765 @@
|
||||
#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
|
||||
}
|
||||
117
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.h
vendored
Normal file
117
vendor/rmlui_backend/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.h
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/RenderInterfaceCompatibility.h>
|
||||
#include <RmlUi/Core/Types.h>
|
||||
|
||||
namespace Gfx {
|
||||
struct ShadersData;
|
||||
}
|
||||
|
||||
/*
|
||||
The GL3 renderer from RmlUi 5, only modified to derive from the compatibility interface.
|
||||
|
||||
Implemented for testing and demonstration purposes, not recommended for production use.
|
||||
*/
|
||||
|
||||
class RenderInterface_BackwardCompatible_GL3 : public Rml::RenderInterfaceCompatibility {
|
||||
public:
|
||||
RenderInterface_BackwardCompatible_GL3();
|
||||
~RenderInterface_BackwardCompatible_GL3();
|
||||
|
||||
// Returns true if the renderer was successfully constructed.
|
||||
explicit operator bool() const { return static_cast<bool>(shaders); }
|
||||
|
||||
// The viewport should be updated whenever the window size changes.
|
||||
void SetViewport(int viewport_width, int viewport_height);
|
||||
|
||||
// Sets up OpenGL states for taking rendering commands from RmlUi.
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
|
||||
// Optional, can be used to clear the framebuffer.
|
||||
void Clear();
|
||||
|
||||
// -- Inherited from Rml::RenderInterface --
|
||||
|
||||
void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
|
||||
const Rml::Vector2f& translation) override;
|
||||
|
||||
Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices,
|
||||
Rml::TextureHandle texture) override;
|
||||
void RenderCompiledGeometry(Rml::CompiledGeometryHandle geometry, const Rml::Vector2f& translation) override;
|
||||
void ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||
|
||||
void EnableScissorRegion(bool enable) override;
|
||||
void SetScissorRegion(int x, int y, int width, int height) override;
|
||||
|
||||
bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||
bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
|
||||
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||
|
||||
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||
|
||||
// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
|
||||
static const Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
|
||||
|
||||
private:
|
||||
enum class ProgramId { None, Texture = 1, Color = 2, All = (Texture | Color) };
|
||||
void SubmitTransformUniform(ProgramId program_id, int uniform_location);
|
||||
|
||||
Rml::Matrix4f transform, projection;
|
||||
ProgramId transform_dirty_state = ProgramId::All;
|
||||
bool transform_active = false;
|
||||
|
||||
enum class ScissoringState { Disable, Scissor, Stencil };
|
||||
ScissoringState scissoring_state = ScissoringState::Disable;
|
||||
|
||||
int viewport_width = 0;
|
||||
int viewport_height = 0;
|
||||
|
||||
Rml::UniquePtr<Gfx::ShadersData> shaders;
|
||||
|
||||
struct GLStateBackup {
|
||||
bool enable_cull_face;
|
||||
bool enable_blend;
|
||||
bool enable_stencil_test;
|
||||
bool enable_scissor_test;
|
||||
|
||||
int viewport[4];
|
||||
int scissor[4];
|
||||
|
||||
int stencil_clear_value;
|
||||
float color_clear_value[4];
|
||||
|
||||
int blend_equation_rgb;
|
||||
int blend_equation_alpha;
|
||||
int blend_src_rgb;
|
||||
int blend_dst_rgb;
|
||||
int blend_src_alpha;
|
||||
int blend_dst_alpha;
|
||||
|
||||
struct Stencil {
|
||||
int func;
|
||||
int ref;
|
||||
int value_mask;
|
||||
int writemask;
|
||||
int fail;
|
||||
int pass_depth_fail;
|
||||
int pass_depth_pass;
|
||||
};
|
||||
Stencil stencil_front;
|
||||
Stencil stencil_back;
|
||||
};
|
||||
GLStateBackup glstate_backup = {};
|
||||
};
|
||||
|
||||
/**
|
||||
Helper functions for the OpenGL 3 renderer.
|
||||
*/
|
||||
namespace RmlGL3 {
|
||||
|
||||
// Loads OpenGL functions. Optionally, the out message describes the loaded GL version or an error message on failure.
|
||||
bool Initialize(Rml::String* out_message = nullptr);
|
||||
|
||||
// Unloads OpenGL functions.
|
||||
void Shutdown();
|
||||
|
||||
} // namespace RmlGL3
|
||||
Reference in New Issue
Block a user