Adding template project and correct name
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.direnv/
|
||||||
|
result
|
||||||
|
build/
|
||||||
|
.vscode/
|
||||||
|
.cache/
|
||||||
62
CMakeLists.txt
Normal file
62
CMakeLists.txt
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(init-tracker LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
find_package(Freetype REQUIRED)
|
||||||
|
find_package(glfw3 CONFIG REQUIRED)
|
||||||
|
find_package(Lua REQUIRED)
|
||||||
|
|
||||||
|
pkg_check_modules(LUNASVG REQUIRED IMPORTED_TARGET lunasvg)
|
||||||
|
add_library(lunasvg::lunasvg ALIAS PkgConfig::LUNASVG)
|
||||||
|
|
||||||
|
find_package(RmlUi CONFIG REQUIRED)
|
||||||
|
|
||||||
|
add_library(rmlui_backend STATIC
|
||||||
|
vendor/rmlui_backend/RmlUi_Backend_GLFW_GL3.cpp
|
||||||
|
vendor/rmlui_backend/RmlUi_Platform_GLFW.cpp
|
||||||
|
vendor/rmlui_backend/RmlUi_Renderer_GL3.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE PAGE_SOURCES CONFIGURE_DEPENDS "src/pages/*.cpp")
|
||||||
|
file(GLOB_RECURSE ELEMENT_SOURCES CONFIGURE_DEPENDS "src/elements/*.cpp")
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
src/main.cpp
|
||||||
|
src/app.cpp
|
||||||
|
src/lua_app_api.cpp
|
||||||
|
src/page.cpp
|
||||||
|
|
||||||
|
${PAGE_SOURCES}
|
||||||
|
${ELEMENT_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
|
src
|
||||||
|
src/elements
|
||||||
|
vendor/rmlui_backend
|
||||||
|
${FREETYPE_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
|
rmlui_backend
|
||||||
|
RmlUi::RmlUi
|
||||||
|
RmlUi::Debugger
|
||||||
|
RmlUi::Lua
|
||||||
|
${LUA_LIBRARIES}
|
||||||
|
Freetype::Freetype
|
||||||
|
lunasvg::lunasvg
|
||||||
|
glfw
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||||
|
install(DIRECTORY assets DESTINATION bin)
|
||||||
|
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||||
|
ASSETS_DIR="${CMAKE_SOURCE_DIR}/bin/assets"
|
||||||
|
)
|
||||||
|
|
||||||
15
assets/main.rml
Normal file
15
assets/main.rml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<rml>
|
||||||
|
<head>
|
||||||
|
<title>RmlUi Temaplate</title>
|
||||||
|
<link type="text/rcss" href="styles/main.rcss" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="navbar">
|
||||||
|
<h1>RmlUi App Template</h1>
|
||||||
|
<div class="nav-buttons">
|
||||||
|
<!-- <button id="nav-lua-test" onclick="NavigateTo('lua-test')">Lua Test</button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="page-content"></div>
|
||||||
|
</body>
|
||||||
|
</rml>
|
||||||
3
assets/pages/home.rml
Normal file
3
assets/pages/home.rml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<div id="page-root" class="page">
|
||||||
|
|
||||||
|
</div>
|
||||||
314
assets/styles/main.rcss
Normal file
314
assets/styles/main.rcss
Normal file
@@ -0,0 +1,314 @@
|
|||||||
|
/* ==========================================================================
|
||||||
|
RCSS User Agent Defaults (Plain HTML Style)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/* Core Application Window Foundation */
|
||||||
|
body {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
font-family: "rmlui-debugger-font";
|
||||||
|
font-size: 16px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic Structural Layout Defaults */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
div, section, article, header, footer, main, nav, aside {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
span, em, strong, a {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typographic Defaults */
|
||||||
|
p {
|
||||||
|
display: block;
|
||||||
|
margin: 1em 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
display: block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0.83em 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 { font-size: 2em; }
|
||||||
|
h2 { font-size: 1.5em; }
|
||||||
|
h3 { font-size: 1.17em; }
|
||||||
|
h4 { font-size: 1em; }
|
||||||
|
h5 { font-size: 0.83em; }
|
||||||
|
h6 { font-size: 0.67em; }
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #0000ee;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #551a8b;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
display: block;
|
||||||
|
margin: 1em 40px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 2px #cccccc;
|
||||||
|
color: #555555;
|
||||||
|
}
|
||||||
|
|
||||||
|
code, pre {
|
||||||
|
font-family: "rmlui-debugger-font";
|
||||||
|
background-color: #606060;
|
||||||
|
color: #000000;
|
||||||
|
padding: 3px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
display: block;
|
||||||
|
white-space: pre;
|
||||||
|
margin: 1em 0px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
ul, ol {
|
||||||
|
display: block;
|
||||||
|
margin: 1em 0px;
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Tables
|
||||||
|
========================================================================== */
|
||||||
|
table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
display: table-cell;
|
||||||
|
padding: 4px 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #eaeaea;
|
||||||
|
}
|
||||||
|
|
||||||
|
col {
|
||||||
|
display: table-column;
|
||||||
|
}
|
||||||
|
|
||||||
|
colgroup {
|
||||||
|
display: table-column-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead, tbody, tfoot {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Form Inputs & Interactive UI Components
|
||||||
|
========================================================================== */
|
||||||
|
button, input, select, textarea {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: "rmlui-debugger-font";
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 2px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traditional gray bevel button style */
|
||||||
|
button, input[type="submit"], input[type="button"] {
|
||||||
|
padding: 4px 12px;
|
||||||
|
min-width: 40px;
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
color: #000000;
|
||||||
|
border: 1px #767676;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
|
||||||
|
background-color: #d0d0d0;
|
||||||
|
border: 1px #4f4f4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active, input[type="submit"]:active, input[type="button"]:active {
|
||||||
|
background-color: #b5b5b5;
|
||||||
|
border: 1px #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard text field styling */
|
||||||
|
input[type="text"], input[type="password"], textarea {
|
||||||
|
padding: 4px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
border: 1px #767676;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus, input[type="password"]:focus, textarea:focus {
|
||||||
|
border: 1px #005aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
display: block;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
width: 300px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select Box & Dropdowns */
|
||||||
|
select {
|
||||||
|
padding: 4px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #000000;
|
||||||
|
border: 1px #767676;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
RmlUi Specific Elements (Tabsets, Progress Bars, etc.)
|
||||||
|
========================================================================== */
|
||||||
|
tabset {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabset tabs {
|
||||||
|
display: block;
|
||||||
|
border-bottom: 1px #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple default layout style for built-in tabs */
|
||||||
|
tab {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 1px #cccccc;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab:selected {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-bottom: 1px #ffffff; /* Overlap the bottom border line */
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel {
|
||||||
|
display: block;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard HTML5 / RmlUi Progress Bar Fallback */
|
||||||
|
progress {
|
||||||
|
display: inline-block;
|
||||||
|
width: 160px;
|
||||||
|
height: 20px;
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
border: 1px #b0b0b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
progress-value {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #0078d7; /* Classic Windows Blue fill */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Utility & Modern Layout Helpers
|
||||||
|
========================================================================== */
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#navbar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0px 20px;
|
||||||
|
background-color: #2b2baa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar h1 {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 24px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar .nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
color: #e0e0e0;
|
||||||
|
border: 1px #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
#navbar button:hover {
|
||||||
|
background-color: #55555a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page Content Base */
|
||||||
|
#page-content {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #f0f0f0;
|
||||||
|
}
|
||||||
1
compile_commands.json
Symbolic link
1
compile_commands.json
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
build/compile_commands.json
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1783224372,
|
||||||
|
"narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d407951447dcd00442e97087bf374aad70c04cea",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
106
flake.nix
Normal file
106
flake.nix
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
description = "C++ RmlUI + Raylib development environemt";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils }:
|
||||||
|
utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
rmlui = pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "rmlui";
|
||||||
|
version = "master";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "mikke89";
|
||||||
|
repo = "RmlUi";
|
||||||
|
rev = "9c74c4fadc2ad7f1496239e560bab19ca2fe5072";
|
||||||
|
hash = "sha256-YZz41ViE3+a0VPypnbJ1Orlf5Hyxd65se5yzyHIY7ZI=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.freetype
|
||||||
|
pkgs.lunasvg
|
||||||
|
pkgs.lua
|
||||||
|
];
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
"-DRMLUI_LUA_BINDINGS=ON"
|
||||||
|
"-DRMLUI_LUA_BINDINGS_LIBRARY=lua"
|
||||||
|
"-DRMLUI_SVG_PLUGIN=ON"
|
||||||
|
"-DBUILD_SHARED_LIBS=ON"
|
||||||
|
"-DBUILD_SAMPLES=OFF"
|
||||||
|
"-DBUILD_TESTING=OFF"
|
||||||
|
"-DNO_FONT_INTERFACE_DEFAULT=OFF"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
buildDeps = with pkgs; [
|
||||||
|
cmake
|
||||||
|
pkg-config
|
||||||
|
gcc
|
||||||
|
clang-tools
|
||||||
|
lua-language-server
|
||||||
|
];
|
||||||
|
|
||||||
|
runtimeDeps = with pkgs; [
|
||||||
|
raylib
|
||||||
|
glfw
|
||||||
|
libGL
|
||||||
|
clang-tools
|
||||||
|
libX11
|
||||||
|
libXcursor
|
||||||
|
libXrandr
|
||||||
|
libXinerama
|
||||||
|
libXi
|
||||||
|
wayland
|
||||||
|
libxkbcommon
|
||||||
|
rmlui
|
||||||
|
freetype
|
||||||
|
lunasvg
|
||||||
|
lua
|
||||||
|
lua-language-server
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = buildDeps;
|
||||||
|
buildInputs = runtimeDeps;
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export CP_PATH="${pkgs.raylib}/include:${pkgs.glfw}/include:${rmlui}/include"
|
||||||
|
export LIBRARY_PATH="${pkgs.raylib}/lib:${pkgs.glfw}/lib:${pkgs.libGL}/lib:${rmlui}/lib"
|
||||||
|
export LD_LIBRARY_PATH="$LIBRARY_PATH:$LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
echo "Env ready"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.default = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "init-tracker";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = buildDeps ++ [ pkgs.makeWrapper ];
|
||||||
|
buildInputs = runtimeDeps;
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
wrapProgram $out/bin/''$pname \
|
||||||
|
--prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath runtimeDeps}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
18
src/ButtonClickListener.hpp
Normal file
18
src/ButtonClickListener.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include <RmlUi/Core/Event.h>
|
||||||
|
#include <RmlUi/Core/EventListener.h>
|
||||||
|
|
||||||
|
|
||||||
|
class ButtonClickListener : public Rml::EventListener {
|
||||||
|
public:
|
||||||
|
using ClickCallback = std::function<void(Rml::Event &event)>;
|
||||||
|
ButtonClickListener(ClickCallback callback) : callback(callback) {}
|
||||||
|
|
||||||
|
void ProcessEvent(Rml::Event &event) override {
|
||||||
|
if (event.GetId() == Rml::EventId::Click) {
|
||||||
|
if (callback) callback(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClickCallback callback;
|
||||||
|
};
|
||||||
217
src/app.cpp
Normal file
217
src/app.cpp
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
#include "app.hpp"
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Factory.h>
|
||||||
|
#include <RmlUi/Lua/Interpreter.h>
|
||||||
|
#include <RmlUi/Core/StyleSheetContainer.h>
|
||||||
|
#include <RmlUi/Lua.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
#include <lua.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
App::App(Rml::Context *ctx, ApplicationData *appData)
|
||||||
|
: ctx(ctx), appData(appData), doc(nullptr) {}
|
||||||
|
|
||||||
|
|
||||||
|
App::~App() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::SetupListeners(std::function<void(Rml::ElementDocument*)> bindCallback) {
|
||||||
|
onBindListeners = bindCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::RegisterListener(Rml::Element* element, std::unique_ptr<Rml::EventListener> listener) {
|
||||||
|
if (element && listener) {
|
||||||
|
element->AddEventListener(Rml::EventId::Click, listener.get());
|
||||||
|
listeners.push_back(std::move(listener));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PageBase* App::GetOrCreatePage(const std::string& pageName) {
|
||||||
|
if (auto it = pages.find(pageName); it != pages.end()) {
|
||||||
|
return it->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = GetAssetsPath() + "/pages/" + pageName + ".rml";
|
||||||
|
if (!std::filesystem::exists(path)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto page = std::make_unique<PageBase>(pageName, this);
|
||||||
|
PageBase* raw = page.get();
|
||||||
|
pages.emplace(pageName, std::move(page));
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::ReadFile(const std::string& path, std::string& outContent) {
|
||||||
|
std::ifstream file(path, std::ios::in | std::ios::binary);
|
||||||
|
if (!file) return false;
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << file.rdbuf();
|
||||||
|
outContent = ss.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::NavigateTo(const std::string &pageName) {
|
||||||
|
|
||||||
|
if (!pageOutlet) {
|
||||||
|
std::cout << "[ERROR] no page outlet - is main.rml missing id=\"page-content\"?\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageBase* page = GetOrCreatePage(pageName);
|
||||||
|
if (!page) {
|
||||||
|
std::cout << "[ERROR] no page registered or found on disk for '" << pageName << "'\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TeardownCurrentPage();
|
||||||
|
|
||||||
|
std::string luaPath = GetAssetsPath() + "/pages/" + pageName + ".lua";
|
||||||
|
if (std::filesystem::exists(luaPath)) {
|
||||||
|
std::string luaContent;
|
||||||
|
if (ReadFile(luaPath, luaContent)) {
|
||||||
|
lua_State *L = Rml::Lua::Interpreter::GetLuaState();
|
||||||
|
|
||||||
|
if (luaL_dostring(L, luaContent.c_str()) != LUA_OK) {
|
||||||
|
std::cout << "[LUA ERROR] Failed to run page script " << pageName << ".lua: "
|
||||||
|
<< lua_tostring(L, -1) << "\n";
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = GetAssetsPath() + "/pages/" + pageName + ".rml";
|
||||||
|
std::string content;
|
||||||
|
if (!ReadFile(path, content)) {
|
||||||
|
std::cout << "[ERROR] could not read page file: " << path << "\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Rml::DataModelConstructor constructor = ctx->CreateDataModel(pageName)) {
|
||||||
|
page->SetupDataModel(constructor);
|
||||||
|
page->model = constructor.GetModelHandle();
|
||||||
|
page->hasModel = true;
|
||||||
|
} else {
|
||||||
|
std::cout << "[WARN] failed to create data model for page '" << pageName << "'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string rcssPath = GetAssetsPath() + "/pages/" + pageName + ".rcss";
|
||||||
|
if (std::filesystem::exists(rcssPath)) {
|
||||||
|
auto pageStyleSheet = Rml::Factory::InstanceStyleSheetFile(rcssPath);
|
||||||
|
if (pageStyleSheet && baseStyleSheet) {
|
||||||
|
auto combined = baseStyleSheet->CombineStyleSheetContainer(*pageStyleSheet);
|
||||||
|
doc->SetStyleSheetContainer(combined);
|
||||||
|
}
|
||||||
|
} else if (doc && baseStyleSheet) {
|
||||||
|
doc->SetStyleSheetContainer(baseStyleSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageOutlet->SetInnerRML(content);
|
||||||
|
|
||||||
|
page->root = pageOutlet->GetElementById("page-root");
|
||||||
|
if (!page->root) {
|
||||||
|
std::cout << "[WARN] page '" << pageName << "' has no element with id=\"page-root\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage = page;
|
||||||
|
page->OnEnter(page->root);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool App::LoadUi() {
|
||||||
|
if (!ctx) return false;
|
||||||
|
|
||||||
|
doc = ctx->LoadDocument(GetAssetsPath() + "/main.rml");
|
||||||
|
if (!doc) return false;
|
||||||
|
|
||||||
|
doc->Show();
|
||||||
|
|
||||||
|
pageOutlet = doc->GetElementById("page-content");
|
||||||
|
if (!pageOutlet) {
|
||||||
|
std::cout << "[WARN] main.rml has no element with id=\"page-content\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
baseStyleSheet = Rml::Factory::InstanceStyleSheetFile(GetAssetsPath() + "/styles/main.rcss");
|
||||||
|
|
||||||
|
listeners.clear();
|
||||||
|
if (onBindListeners) {
|
||||||
|
onBindListeners(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::Reload() {
|
||||||
|
Rml::Factory::ClearStyleSheetCache();
|
||||||
|
Rml::Factory::ClearTemplateCache();
|
||||||
|
|
||||||
|
std::string previousPage = currentPage ? currentPage->GetName() : "";
|
||||||
|
|
||||||
|
TeardownCurrentPage();
|
||||||
|
|
||||||
|
if (doc) {
|
||||||
|
doc->Close();
|
||||||
|
doc = nullptr;
|
||||||
|
pageOutlet = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadUi();
|
||||||
|
|
||||||
|
if (!previousPage.empty()) {
|
||||||
|
NavigateTo(previousPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string App::GetAssetsPath() {
|
||||||
|
std::string install_path = std::string(ASSETS_DIR) + "/main.rml";
|
||||||
|
if (std::filesystem::exists(install_path)) {
|
||||||
|
return std::string(ASSETS_DIR);
|
||||||
|
}
|
||||||
|
if (std::filesystem::exists("./assets/main.rml")) {
|
||||||
|
return "./assets";
|
||||||
|
}
|
||||||
|
return ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::TeardownCurrentPage() {
|
||||||
|
if (!currentPage) return;
|
||||||
|
|
||||||
|
lua_State* L = Rml::Lua::Interpreter::GetLuaState();
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_setglobal(L, currentPage->GetName().c_str());
|
||||||
|
|
||||||
|
currentPage->OnExit();
|
||||||
|
|
||||||
|
if (currentPage->hasModel) {
|
||||||
|
ctx->RemoveDataModel(currentPage->GetName());
|
||||||
|
currentPage->hasModel = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage->root = nullptr;
|
||||||
|
|
||||||
|
if (pageOutlet) {
|
||||||
|
pageOutlet->SetInnerRML("");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage->pageListeners.clear();
|
||||||
|
currentPage = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::Shutdown() {
|
||||||
|
if (hasShutdown) return;
|
||||||
|
hasShutdown = true;
|
||||||
|
|
||||||
|
TeardownCurrentPage(); // uses ctx->RemoveDataModel - must run while ctx is still valid
|
||||||
|
|
||||||
|
if (doc) {
|
||||||
|
doc->Close(); // deferred destruction, but marks it for cleanup on next Update/Shutdown
|
||||||
|
doc = nullptr;
|
||||||
|
pageOutlet = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/app.hpp
Normal file
58
src/app.hpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/ElementDocument.h>
|
||||||
|
#include <RmlUi/Core/EventListener.h>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "page.hpp"
|
||||||
|
|
||||||
|
struct ApplicationData {};
|
||||||
|
|
||||||
|
class App {
|
||||||
|
public:
|
||||||
|
App(Rml::Context* ctx, ApplicationData* appData);
|
||||||
|
~App();
|
||||||
|
|
||||||
|
void SetupListeners(std::function<void(Rml::ElementDocument*)> bindCallback);
|
||||||
|
void RegisterListener(Rml::Element* element, std::unique_ptr<Rml::EventListener> listener);
|
||||||
|
|
||||||
|
template <typename T = PageBase>
|
||||||
|
void RegisterPage(const std::string &pageName) {
|
||||||
|
static_assert(std::is_base_of<PageBase, T>::value, "T must derive from PageBase");
|
||||||
|
pages[pageName] = std::make_unique<T>(pageName, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NavigateTo(const std::string &pageName);
|
||||||
|
|
||||||
|
bool LoadUi();
|
||||||
|
void Reload();
|
||||||
|
|
||||||
|
static std::string GetAssetsPath();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ApplicationData *appData;
|
||||||
|
Rml::Context* ctx;
|
||||||
|
Rml::ElementDocument* doc;
|
||||||
|
Rml::Element* pageOutlet = nullptr;
|
||||||
|
|
||||||
|
Rml::SharedPtr<Rml::StyleSheetContainer> baseStyleSheet;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Rml::EventListener>> listeners;
|
||||||
|
std::function<void(Rml::ElementDocument*)> onBindListeners;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<PageBase>> pages;
|
||||||
|
PageBase* currentPage = nullptr;
|
||||||
|
|
||||||
|
PageBase* GetOrCreatePage(const std::string& pageName);
|
||||||
|
static bool ReadFile(const std::string& path, std::string& outContent);
|
||||||
|
void TeardownCurrentPage();
|
||||||
|
|
||||||
|
bool hasShutdown = false;
|
||||||
|
};
|
||||||
22
src/element_registry.hpp
Normal file
22
src/element_registry.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/ElementInstancer.h>
|
||||||
|
#include <RmlUi/Core/Factory.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ElementRegistry {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
void Register(const std::string& tag) {
|
||||||
|
static_assert(std::is_base_of<Rml::Element, T>::value, "T must derive from Rml::Element");
|
||||||
|
auto instancer = std::make_unique<Rml::ElementInstancerGeneric<T>>();
|
||||||
|
Rml::Factory::RegisterElementInstancer(tag, instancer.get());
|
||||||
|
instancers.push_back(std::move(instancer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<Rml::ElementInstancer>> instancers;
|
||||||
|
};
|
||||||
35
src/lua_app_api.cpp
Normal file
35
src/lua_app_api.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "lui_app_api.hpp"
|
||||||
|
#include <RmlUi/Lua/Interpreter.h>
|
||||||
|
#include <RmlUi/Lua/Lua.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "lua.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
int AppLuaApi::Lua_NavigateTo(lua_State *L) {
|
||||||
|
AppLuaApi* apiInstance = static_cast<AppLuaApi*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||||
|
|
||||||
|
if (!apiInstance || !apiInstance->app) {
|
||||||
|
std::cout << "[LUA ERROR] API context or App pointer is invalid.\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_isstring(L, 1)) {
|
||||||
|
std::string pageName = lua_tostring(L, 1);
|
||||||
|
apiInstance->app->NavigateTo(pageName);
|
||||||
|
} else {
|
||||||
|
std::cout << "[LUA ERROR] NavigateTo expects a string argument for pageName.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppLuaApi::RegisterLuaBindings() {
|
||||||
|
if (!L) return;
|
||||||
|
|
||||||
|
lua_pushlightuserdata(L, this);
|
||||||
|
|
||||||
|
lua_pushcclosure(L, Lua_NavigateTo, 1);
|
||||||
|
lua_setglobal(L, "NavigateTo");
|
||||||
|
}
|
||||||
16
src/lui_app_api.hpp
Normal file
16
src/lui_app_api.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <RmlUi/Lua/Lua.h>
|
||||||
|
#include "app.hpp"
|
||||||
|
|
||||||
|
class AppLuaApi {
|
||||||
|
public:
|
||||||
|
|
||||||
|
AppLuaApi(App *app, lua_State *L) : app(app), L(L) {}
|
||||||
|
|
||||||
|
void RegisterLuaBindings();
|
||||||
|
|
||||||
|
static int Lua_NavigateTo(lua_State *L);
|
||||||
|
|
||||||
|
private:
|
||||||
|
App *app;
|
||||||
|
lua_State *L;
|
||||||
|
};
|
||||||
130
src/main.cpp
Normal file
130
src/main.cpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <RmlUi/Core/ElementDocument.h>
|
||||||
|
#include <RmlUi/Core/Event.h>
|
||||||
|
#include <RmlUi/Debugger/Debugger.h>
|
||||||
|
#include <RmlUi/Lua/Interpreter.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Math.h>
|
||||||
|
#include <RmlUi/Core.h>
|
||||||
|
#include <RmlUi_Backend.h>
|
||||||
|
#include <RmlUi/Debugger.h>
|
||||||
|
#include <RmlUi/Lua/Lua.h>
|
||||||
|
#include "app.hpp"
|
||||||
|
#include "element_registry.hpp"
|
||||||
|
#include "ButtonClickListener.hpp"
|
||||||
|
#include "lui_app_api.hpp"
|
||||||
|
|
||||||
|
static bool is_initalized = false;
|
||||||
|
static bool is_running = false;
|
||||||
|
static Rml::Context *ctx;
|
||||||
|
static App *app;
|
||||||
|
static ElementRegistry elementRegistry;
|
||||||
|
|
||||||
|
void RegisterElements() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InitalizeApplication() {
|
||||||
|
if (!Backend::Initialize("RmlUi App Template", 800, 600, true)) {
|
||||||
|
std::cout << "[ERROR] backend was not initalized successfully.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SetSystemInterface(Backend::GetSystemInterface());
|
||||||
|
Rml::SetRenderInterface(Backend::GetRenderInterface());
|
||||||
|
Rml::Initialise();
|
||||||
|
Rml::Lua::Initialise();
|
||||||
|
|
||||||
|
ctx = Rml::CreateContext("main", Rml::Vector2i(800,600));
|
||||||
|
if (!ctx) {
|
||||||
|
std::cout << "[ERROR] context was null.\n";
|
||||||
|
Rml::Shutdown();
|
||||||
|
Backend::Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Debugger::Initialise(ctx);
|
||||||
|
|
||||||
|
app = new App(ctx, nullptr);
|
||||||
|
if (!app) {
|
||||||
|
std::cout << "[ERROR] app was null.\n";
|
||||||
|
Rml::Shutdown();
|
||||||
|
Backend::Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* L = Rml::Lua::Interpreter::GetLuaState();
|
||||||
|
AppLuaApi *lua_app_api = new AppLuaApi(app, L);
|
||||||
|
lua_app_api->RegisterLuaBindings();
|
||||||
|
|
||||||
|
RegisterElements();
|
||||||
|
|
||||||
|
std::cout << "Application initalized...\n";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool f5_was_pressed = false;
|
||||||
|
bool f8_was_pressed = false;
|
||||||
|
|
||||||
|
void handle_input() {
|
||||||
|
GLFWwindow *window = glfwGetCurrentContext();
|
||||||
|
if(window) {
|
||||||
|
// Reload ui
|
||||||
|
bool f5_state = glfwGetKey(window, GLFW_KEY_F5);
|
||||||
|
if (f5_state == GLFW_PRESS && !f5_was_pressed) {
|
||||||
|
f5_was_pressed = true;
|
||||||
|
app->Reload();
|
||||||
|
} else if (f5_state == GLFW_RELEASE) {
|
||||||
|
f5_was_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle debugger window
|
||||||
|
bool f8_state = glfwGetKey(window, GLFW_KEY_F8);
|
||||||
|
if (f8_state == GLFW_PRESS && !f8_was_pressed) {
|
||||||
|
f8_was_pressed = true;
|
||||||
|
bool is_visible = Rml::Debugger::IsVisible();
|
||||||
|
Rml::Debugger::SetVisible(!is_visible);
|
||||||
|
} else if (f8_state == GLFW_RELEASE) {
|
||||||
|
f8_was_pressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::cout << "Application starting...\n";
|
||||||
|
is_initalized = InitalizeApplication();
|
||||||
|
if (!is_initalized) return 1;
|
||||||
|
|
||||||
|
is_running = true;
|
||||||
|
|
||||||
|
std::cout << "Loading UI...\n";
|
||||||
|
|
||||||
|
app->SetupListeners([](Rml::ElementDocument *doc) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app->LoadUi();
|
||||||
|
app->NavigateTo("home");
|
||||||
|
std::cout << "UI Loaded\n";
|
||||||
|
|
||||||
|
while (is_running) {
|
||||||
|
is_running = Backend::ProcessEvents(ctx);
|
||||||
|
|
||||||
|
handle_input();
|
||||||
|
|
||||||
|
ctx->Update();
|
||||||
|
Backend::BeginFrame();
|
||||||
|
ctx->Render();
|
||||||
|
Backend::PresentFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
app->Shutdown();
|
||||||
|
Rml::Shutdown();
|
||||||
|
delete app;
|
||||||
|
Backend::Shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
0
src/page.cpp
Normal file
0
src/page.cpp
Normal file
49
src/page.hpp
Normal file
49
src/page.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/DataModelHandle.h>
|
||||||
|
#include <RmlUi/Core/Element.h>
|
||||||
|
#include <RmlUi/Core/ElementDocument.h>
|
||||||
|
#include <RmlUi/Core/Factory.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class App;
|
||||||
|
|
||||||
|
class PageBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PageBase(std::string pageName, App* app) : pageName(std::move(pageName)), app(app) {}
|
||||||
|
virtual ~PageBase() = default;
|
||||||
|
|
||||||
|
const std::string& GetName() const { return pageName; }
|
||||||
|
bool TryLoadRmlPage(std::string path = "");
|
||||||
|
|
||||||
|
virtual void SetupDataModel(Rml::DataModelConstructor constructor) {}
|
||||||
|
virtual void OnEnter(Rml::Element *root) {}
|
||||||
|
virtual void OnExit() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
App* GetApp() const {return app;}
|
||||||
|
void RegisterListener(Rml::Element* element, std::unique_ptr<Rml::EventListener> listener) {
|
||||||
|
if (element && listener) {
|
||||||
|
element->AddEventListener(Rml::EventId::Click, listener.get());
|
||||||
|
pageListeners.push_back(std::move(listener));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DirtyVariable(const std::string& name) {
|
||||||
|
if (hasModel) model.DirtyVariable(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class App;
|
||||||
|
|
||||||
|
std::string pageName;
|
||||||
|
App *app;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Rml::EventListener>> pageListeners;
|
||||||
|
|
||||||
|
Rml::Element *root = nullptr;
|
||||||
|
Rml::DataModelHandle model;
|
||||||
|
bool hasModel = false;
|
||||||
|
};
|
||||||
253
vendor/rmlui_backend/CMakeLists.txt
vendored
Normal file
253
vendor/rmlui_backend/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
#[[
|
||||||
|
Interface libraries for each backend, including their source files and linking requirements.
|
||||||
|
|
||||||
|
Every time a new backend gets added or its target name is modified, please update
|
||||||
|
the list of available backends found in OptionsLists.cmake
|
||||||
|
]]
|
||||||
|
|
||||||
|
add_library(rmlui_backend_common_headers INTERFACE)
|
||||||
|
target_include_directories(rmlui_backend_common_headers INTERFACE "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
target_sources(rmlui_backend_common_headers INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(RMLUI_BACKEND_SIMULATE_TOUCH)
|
||||||
|
set(RMLUI_BACKEND_SIMULATE_TOUCH_SUPPORTED
|
||||||
|
"SDL_GL2"
|
||||||
|
"SDL_GL3"
|
||||||
|
"SDL_VK"
|
||||||
|
"SDL_SDLrenderer"
|
||||||
|
"SDL_GPU"
|
||||||
|
)
|
||||||
|
if(NOT RMLUI_BACKEND IN_LIST RMLUI_BACKEND_SIMULATE_TOUCH_SUPPORTED)
|
||||||
|
message(WARNING "RMLUI_BACKEND_SIMULATE_TOUCH enabled but not supported on selected backend ${RMLUI_BACKEND}")
|
||||||
|
else()
|
||||||
|
target_compile_definitions(rmlui_backend_common_headers INTERFACE "RMLUI_BACKEND_SIMULATE_TOUCH")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(rmlui_backend_Win32_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_Win32_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_Win32_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_Windows.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_Win32_GL2 INTERFACE rmlui_backend_common_headers OpenGL::GL)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_Win32_VK INTERFACE)
|
||||||
|
target_sources(rmlui_backend_Win32_VK INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_Win32_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_Vulkan.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Vulkan/ShadersCompiledSPV.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_Win32_VK INTERFACE rmlui_backend_common_headers)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_Win32_DX12 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_Win32_DX12 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_Win32_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_Win32.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_DirectX_12.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_Win32_DX12 INTERFACE rmlui_backend_common_headers)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_X11_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_X11_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_X11.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_X11_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_X11.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_Xlib.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# RMLUI_CMAKE_MINIMUM_VERSION_RAISE_NOTICE:
|
||||||
|
# Once the minimum CMake version is CMake >= 3.14, "${X11_LIBRARIES}" should
|
||||||
|
# be substituted by "X11:X11" in addition to any of the other imported that might
|
||||||
|
# be required. More info:
|
||||||
|
# https://cmake.org/cmake/help/latest/module/FindX11.html
|
||||||
|
target_link_libraries(rmlui_backend_X11_GL2 INTERFACE rmlui_backend_common_headers OpenGL::GL ${X11_LIBRARIES})
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_GL2 INTERFACE rmlui_backend_common_headers OpenGL::GL SDL::SDL SDL_image::SDL_image)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_GL3 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_GL3 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL3.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_GL3.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL3.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_GL3.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_GL3 INTERFACE rmlui_backend_common_headers SDL::SDL SDL_image::SDL_image)
|
||||||
|
if(UNIX)
|
||||||
|
# The OpenGL 3 renderer implementation uses dlopen/dlclose
|
||||||
|
# This is required in some UNIX and UNIX-like operating systems to load shared object files at runtime
|
||||||
|
target_link_libraries(rmlui_backend_SDL_GL3 INTERFACE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
if(EMSCRIPTEN)
|
||||||
|
# Only Emscripten requires linking to OpenGL::GL, for other platforms we use 'glad' as an OpenGL loader.
|
||||||
|
target_link_libraries(rmlui_backend_SDL_GL3 INTERFACE OpenGL::GL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_VK INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_VK INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_Vulkan.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Vulkan/ShadersCompiledSPV.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_VK INTERFACE rmlui_backend_common_headers SDL::SDL)
|
||||||
|
if(UNIX)
|
||||||
|
# The Vulkan renderer implementation uses dlopen/dlclose
|
||||||
|
# This is required in some UNIX and UNIX-like operating systems to load shared object files at runtime
|
||||||
|
target_link_libraries(rmlui_backend_SDL_VK INTERFACE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_DX12 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_DX12 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_DirectX_12.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_DX12 INTERFACE rmlui_backend_common_headers SDL::SDL SDL_image::SDL_image)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_SDLrenderer INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_SDLrenderer INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_SDLrenderer.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_SDL.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_SDLrenderer INTERFACE rmlui_backend_common_headers SDL::SDL SDL_image::SDL_image)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SDL_GPU INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SDL_GPU INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_SDL_GPU.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SDL_GPU.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SDL.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_SDL_GPU.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SDL_GPU INTERFACE rmlui_backend_common_headers SDL::SDL SDL_image::SDL_image)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_SFML_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_SFML_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SFML.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_SFML_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_SFML.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_SFML_GL2 INTERFACE
|
||||||
|
rmlui_backend_common_headers OpenGL::GL SFML::Graphics SFML::Window SFML::System
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_GLFW_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_GLFW_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_GLFW_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL2.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_GL2 INTERFACE rmlui_backend_common_headers OpenGL::GL glfw)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_GLFW_GL3 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_GLFW_GL3 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL3.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_GLFW_GL3.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_GL3.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_GL3.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_GL3 INTERFACE rmlui_backend_common_headers glfw)
|
||||||
|
if(UNIX)
|
||||||
|
# The OpenGL 3 renderer implementation uses dlopen/dlclose
|
||||||
|
# This is required in some UNIX and UNIX-like operating systems to load shared object files at runtime
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_GL3 INTERFACE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(rmlui_backend_GLFW_VK INTERFACE)
|
||||||
|
target_sources(rmlui_backend_GLFW_VK INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_GLFW_VK.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_VK.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_Vulkan.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Vulkan/ShadersCompiledSPV.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_VK INTERFACE rmlui_backend_common_headers glfw)
|
||||||
|
if(UNIX)
|
||||||
|
# The Vulkan renderer implementation uses dlopen/dlclose
|
||||||
|
# This is required in some UNIX and UNIX-like operating systems to load shared object files at runtime
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_VK INTERFACE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(rmlui_backend_GLFW_DX12 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_GLFW_DX12 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Backend_GLFW_DX12.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Renderer_DX12.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Include_DirectX_12.h"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_GLFW_DX12 INTERFACE rmlui_backend_common_headers glfw)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_BackwardCompatible_GLFW_GL2 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_BackwardCompatible_GLFW_GL2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL2.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL2.cpp"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_BackwardCompatible_GLFW_GL2 INTERFACE rmlui_backend_common_headers OpenGL::GL glfw)
|
||||||
|
|
||||||
|
add_library(rmlui_backend_BackwardCompatible_GLFW_GL3 INTERFACE)
|
||||||
|
target_sources(rmlui_backend_BackwardCompatible_GLFW_GL3 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_Platform_GLFW.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.cpp"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Renderer_BackwardCompatible_GL3.h"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/RmlUi_BackwardCompatible/RmlUi_Backend_BackwardCompatible_GLFW_GL3.cpp"
|
||||||
|
)
|
||||||
|
target_link_libraries(rmlui_backend_BackwardCompatible_GLFW_GL3 INTERFACE rmlui_backend_common_headers glfw)
|
||||||
|
if(UNIX)
|
||||||
|
# The OpenGL 3 renderer implementation uses dlopen/dlclose
|
||||||
|
# This is required in some UNIX and UNIX-like operating systems to load shared object files at runtime
|
||||||
|
target_link_libraries(rmlui_backend_BackwardCompatible_GLFW_GL3 INTERFACE ${CMAKE_DL_LIBS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(RMLUI_IS_ROOT_PROJECT)
|
||||||
|
install(DIRECTORY "./"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_DATADIR}/Backends"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
41
vendor/rmlui_backend/RmlUi_Backend.h
vendored
Normal file
41
vendor/rmlui_backend/RmlUi_Backend.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
|
||||||
|
using KeyDownCallback = bool (*)(Rml::Context* context, Rml::Input::KeyIdentifier key, int key_modifier, float native_dp_ratio, bool priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
This interface serves as a basic abstraction over the various backends included with RmlUi. It is mainly intended as an example to get something
|
||||||
|
simple up and running, and provides just enough functionality for the included samples.
|
||||||
|
|
||||||
|
This interface may be used directly for simple applications and testing. However, for anything more advanced we recommend to use the backend as a
|
||||||
|
starting point and copy relevant parts into the main loop of your application. On the other hand, the underlying platform and renderer used by the
|
||||||
|
backend are intended to be re-usable as is.
|
||||||
|
*/
|
||||||
|
namespace Backend {
|
||||||
|
|
||||||
|
// Initializes the backend, including the custom system and render interfaces, and opens a window for rendering the RmlUi context.
|
||||||
|
bool Initialize(const char* window_name, int width, int height, bool allow_resize);
|
||||||
|
// Closes the window and release all resources owned by the backend, including the system and render interfaces.
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Returns a pointer to the custom system interface which should be provided to RmlUi.
|
||||||
|
Rml::SystemInterface* GetSystemInterface();
|
||||||
|
// Returns a pointer to the custom render interface which should be provided to RmlUi.
|
||||||
|
Rml::RenderInterface* GetRenderInterface();
|
||||||
|
|
||||||
|
// Polls and processes events from the current platform, and applies any relevant events to the provided RmlUi context and the key down callback.
|
||||||
|
// @return False to indicate that the application should be closed.
|
||||||
|
bool ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback = nullptr, bool power_save = false);
|
||||||
|
// Request application closure during the next event processing call.
|
||||||
|
void RequestExit();
|
||||||
|
|
||||||
|
// Prepares the render state to accept rendering commands from RmlUi, call before rendering the RmlUi context.
|
||||||
|
void BeginFrame();
|
||||||
|
// Presents the rendered frame to the screen, call after rendering the RmlUi context.
|
||||||
|
void PresentFrame();
|
||||||
|
|
||||||
|
} // namespace Backend
|
||||||
280
vendor/rmlui_backend/RmlUi_Backend_GLFW_DX12.cpp
vendored
Normal file
280
vendor/rmlui_backend/RmlUi_Backend_GLFW_DX12.cpp
vendored
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_GLFW.h"
|
||||||
|
#include "RmlUi_Renderer_DX12.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
#include <GLFW/glfw3native.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 {
|
||||||
|
BackendData(GLFWwindow* window) : system_interface(window), window(window) {}
|
||||||
|
|
||||||
|
SystemInterface_GLFW system_interface;
|
||||||
|
Rml::UniquePtr<RenderInterface_DX12> render_interface;
|
||||||
|
|
||||||
|
GLFWwindow* window;
|
||||||
|
Rml::Context* context = nullptr;
|
||||||
|
KeyDownCallback key_down_callback = nullptr;
|
||||||
|
|
||||||
|
int glfw_active_modifiers = 0;
|
||||||
|
bool running = true;
|
||||||
|
bool context_dimensions_dirty = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
glfwSetErrorCallback(LogErrorFromGLFW);
|
||||||
|
|
||||||
|
if (!glfwInit())
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
|
||||||
|
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||||
|
|
||||||
|
GLFWwindow* window = glfwCreateWindow(width, height, window_name, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW failed to create window");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND window_handle = glfwGetWin32Window(window);
|
||||||
|
if (!window_handle)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Could not retrieve native window handle from GLFW");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
|
||||||
|
RmlRendererSettings settings = {};
|
||||||
|
settings.vsync = true;
|
||||||
|
settings.msaa_sample_count = RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT;
|
||||||
|
|
||||||
|
data->render_interface = Rml::MakeUnique<RenderInterface_DX12>(window_handle, settings);
|
||||||
|
|
||||||
|
if (!data->render_interface || !(*data->render_interface))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize DirectX 12 render interface");
|
||||||
|
data.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
SetupCallbacks(window);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.reset();
|
||||||
|
|
||||||
|
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.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WaitForValidSwapchain()
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any render
|
||||||
|
// calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead, we keep the
|
||||||
|
// application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
while (!data->render_interface->IsSwapchainValid())
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
if (glfwWindowShouldClose(data->window))
|
||||||
|
{
|
||||||
|
glfwRestoreWindow(data->window);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwPollEvents();
|
||||||
|
data->render_interface->RecreateSwapchain();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
if (!WaitForValidSwapchain())
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
data->context = nullptr;
|
||||||
|
data->key_down_callback = nullptr;
|
||||||
|
|
||||||
|
result = !glfwWindowShouldClose(data->window);
|
||||||
|
glfwSetWindowShouldClose(data->window, GLFW_FALSE);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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); });
|
||||||
|
}
|
||||||
227
vendor/rmlui_backend/RmlUi_Backend_GLFW_GL2.cpp
vendored
Normal file
227
vendor/rmlui_backend/RmlUi_Backend_GLFW_GL2.cpp
vendored
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_GLFW.h"
|
||||||
|
#include "RmlUi_Renderer_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 {
|
||||||
|
BackendData(GLFWwindow* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_GLFW system_interface;
|
||||||
|
RenderInterface_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>(window);
|
||||||
|
data->window = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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); });
|
||||||
|
}
|
||||||
235
vendor/rmlui_backend/RmlUi_Backend_GLFW_GL3.cpp
vendored
Normal file
235
vendor/rmlui_backend/RmlUi_Backend_GLFW_GL3.cpp
vendored
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_GLFW.h"
|
||||||
|
#include "RmlUi_Renderer_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 {
|
||||||
|
BackendData(GLFWwindow* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_GLFW system_interface;
|
||||||
|
RenderInterface_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);
|
||||||
|
|
||||||
|
// 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>(window);
|
||||||
|
if (!data || !data->render_interface)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data->window = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.Clear();
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
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); });
|
||||||
|
}
|
||||||
268
vendor/rmlui_backend/RmlUi_Backend_GLFW_VK.cpp
vendored
Normal file
268
vendor/rmlui_backend/RmlUi_Backend_GLFW_VK.cpp
vendored
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Renderer_VK.h"
|
||||||
|
// This space is intentional to prevent autoformat from reordering RmlUi_Renderer_VK behind RmlUi_Platform_GLFW
|
||||||
|
#include "RmlUi_Platform_GLFW.h"
|
||||||
|
#include <RmlUi/Config/Config.h>
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
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 {
|
||||||
|
BackendData(GLFWwindow* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_GLFW system_interface;
|
||||||
|
RenderInterface_VK render_interface;
|
||||||
|
|
||||||
|
GLFWwindow* window = nullptr;
|
||||||
|
Rml::Context* context = nullptr;
|
||||||
|
KeyDownCallback key_down_callback = nullptr;
|
||||||
|
|
||||||
|
int glfw_active_modifiers = 0;
|
||||||
|
bool running = true;
|
||||||
|
bool context_dimensions_dirty = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
glfwSetErrorCallback(LogErrorFromGLFW);
|
||||||
|
|
||||||
|
if (!glfwInit())
|
||||||
|
{
|
||||||
|
glfwTerminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, allow_resize ? GLFW_TRUE : GLFW_FALSE);
|
||||||
|
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
|
||||||
|
|
||||||
|
GLFWwindow* window = glfwCreateWindow(width, height, window_name, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "GLFW failed to create window");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
data->window = window;
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
const char** extensions = glfwGetRequiredInstanceExtensions(&count);
|
||||||
|
RMLUI_VK_ASSERTMSG(extensions != nullptr, "Failed to query GLFW Vulkan extensions");
|
||||||
|
if (!data->render_interface.Initialize(Rml::Vector<const char*>(extensions, extensions + count),
|
||||||
|
[](VkInstance instance, VkSurfaceKHR* out_surface) {
|
||||||
|
return glfwCreateWindowSurface(instance, data->window, nullptr, out_surface) == VkResult::VK_SUCCESS;
|
||||||
|
;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize Vulkan render interface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
SetupCallbacks(window);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.Shutdown();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WaitForValidSwapchain()
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any render
|
||||||
|
// calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead, we keep the
|
||||||
|
// application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
|
||||||
|
while (!data->render_interface.IsSwapchainValid())
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
|
||||||
|
if (glfwWindowShouldClose(data->window))
|
||||||
|
{
|
||||||
|
glfwRestoreWindow(data->window);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwPollEvents();
|
||||||
|
data->render_interface.RecreateSwapchain();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
if (!WaitForValidSwapchain())
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
data->context = nullptr;
|
||||||
|
data->key_down_callback = nullptr;
|
||||||
|
|
||||||
|
result = !glfwWindowShouldClose(data->window);
|
||||||
|
glfwSetWindowShouldClose(data->window, GLFW_FALSE);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
glfwSetWindowShouldClose(data->window, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
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); });
|
||||||
|
}
|
||||||
394
vendor/rmlui_backend/RmlUi_Backend_SDL_DX12.cpp
vendored
Normal file
394
vendor/rmlui_backend/RmlUi_Backend_SDL_DX12.cpp
vendored
Normal file
@@ -0,0 +1,394 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_DX12.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
#else
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#include <SDL_syswm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom render interface example for the SDL/DX12 backend.
|
||||||
|
|
||||||
|
Overloads the DirectX 12 render interface to load textures through SDL_image's built-in texture loading functionality.
|
||||||
|
*/
|
||||||
|
class RenderInterface_DX12_SDL : public RenderInterface_DX12 {
|
||||||
|
public:
|
||||||
|
RenderInterface_DX12_SDL(void* p_window_handle, const Backend::RmlRendererSettings& settings) : RenderInterface_DX12(p_window_handle, settings) {}
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override
|
||||||
|
{
|
||||||
|
Rml::FileInterface* file_interface = Rml::GetFileInterface();
|
||||||
|
Rml::FileHandle file_handle = file_interface->Open(source);
|
||||||
|
if (!file_handle)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_END);
|
||||||
|
const size_t buffer_size = file_interface->Tell(file_handle);
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_SET);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
const size_t i_ext = source.rfind('.');
|
||||||
|
Rml::String extension = (i_ext == Rml::String::npos ? Rml::String() : source.substr(i_ext + 1));
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_IO(SDL_IOFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, SDL_PixelFormat format) { return SDL_ConvertSurface(surface, format); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_DestroySurface(surface); };
|
||||||
|
#else
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_RW(SDL_RWFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, Uint32 format) { return SDL_ConvertSurfaceFormat(surface, format, 0); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_FreeSurface(surface); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* surface = CreateSurface();
|
||||||
|
if (!surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
if (GetSurfaceFormat(surface) != SDL_PIXELFORMAT_RGBA32)
|
||||||
|
{
|
||||||
|
// Ensure correct format for premultiplied alpha conversion and GenerateTexture below.
|
||||||
|
SDL_Surface* converted_surface = ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
DestroySurface(surface);
|
||||||
|
if (!converted_surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
surface = converted_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
const size_t pixels_byte_size = surface->w * surface->h * 4;
|
||||||
|
byte* pixels = static_cast<byte*>(surface->pixels);
|
||||||
|
for (size_t i = 0; i < pixels_byte_size; i += 4)
|
||||||
|
{
|
||||||
|
const byte alpha = pixels[i + 3];
|
||||||
|
for (size_t j = 0; j < 3; ++j)
|
||||||
|
pixels[i + j] = byte(int(pixels[i + j]) * int(alpha) / 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle texture_handle = RenderInterface_DX12::GenerateTexture({pixels, pixels_byte_size}, texture_dimensions);
|
||||||
|
|
||||||
|
DestroySurface(surface);
|
||||||
|
|
||||||
|
return texture_handle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window) : system_interface(window), window(window) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
Rml::UniquePtr<RenderInterface_DX12_SDL> render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
#else
|
||||||
|
const Uint32 window_flags = (allow_resize ? SDL_WINDOW_RESIZABLE : 0);
|
||||||
|
SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
|
||||||
|
// SDL2 implicitly activates text input on window creation. Turn it off for now, it will be activated again e.g. when focusing a text input field.
|
||||||
|
SDL_StopTextInput();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
HWND window_handle = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
||||||
|
#else
|
||||||
|
SDL_SysWMinfo wm_info = {};
|
||||||
|
SDL_VERSION(&wm_info.version);
|
||||||
|
if (!SDL_GetWindowWMInfo(window, &wm_info))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error getting window info: %s", SDL_GetError());
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
HWND window_handle = wm_info.info.win.window;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window_handle)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Could not retrieve native window handle from SDL");
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the actual window size (may differ due to DPI scaling).
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_GetWindowSizeInPixels(window, &width, &height);
|
||||||
|
#else
|
||||||
|
SDL_GetWindowSize(window, &width, &height);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
|
||||||
|
RmlRendererSettings settings = {};
|
||||||
|
settings.vsync = true;
|
||||||
|
settings.msaa_sample_count = RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT;
|
||||||
|
|
||||||
|
data->render_interface = Rml::MakeUnique<RenderInterface_DX12_SDL>(window_handle, settings);
|
||||||
|
|
||||||
|
if (!data->render_interface || !(*data->render_interface))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize DirectX 12 render interface");
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
data.reset();
|
||||||
|
SDL_Quit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->render_interface->SetViewport(width, height);
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.reset();
|
||||||
|
|
||||||
|
SDL_DestroyWindow(data->window);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return data->render_interface.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WaitForValidSwapchain()
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
#else
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any render
|
||||||
|
// calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead, we keep the
|
||||||
|
// application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
while (!data->render_interface->IsSwapchainValid())
|
||||||
|
{
|
||||||
|
SDL_Event ev;
|
||||||
|
while (SDL_PollEvent(&ev))
|
||||||
|
{
|
||||||
|
if (ev.type == event_quit)
|
||||||
|
{
|
||||||
|
// Restore the window so that we can recreate the swapchain, and then properly release all resource and shutdown cleanly.
|
||||||
|
SDL_RestoreWindow(data->window);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_Delay(10);
|
||||||
|
data->render_interface->RecreateSwapchain();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
|
||||||
|
bool has_event = false;
|
||||||
|
#else
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN \
|
||||||
|
case SDL_WINDOWEVENT: \
|
||||||
|
{ \
|
||||||
|
switch (ev.window.event) \
|
||||||
|
{
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetDisplayScale = []() { return 1.f; };
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_TEXTEDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_WINDOWEVENT_SIZE_CHANGED;
|
||||||
|
int has_event = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
|
||||||
|
case event_window_size_changed:
|
||||||
|
{
|
||||||
|
Rml::Vector2i dimensions = {ev.window.data1, ev.window.data2};
|
||||||
|
data->render_interface->SetViewport(dimensions.x, dimensions.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_END
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WaitForValidSwapchain())
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface->BeginFrame();
|
||||||
|
data->render_interface->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface->EndFrame();
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
353
vendor/rmlui_backend/RmlUi_Backend_SDL_GL2.cpp
vendored
Normal file
353
vendor/rmlui_backend/RmlUi_Backend_SDL_GL2.cpp
vendored
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_GL2.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
#else
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION == 2 && !(SDL_VIDEO_RENDER_OGL)
|
||||||
|
#error "Only the OpenGL SDL backend is supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom render interface example for the SDL/GL2 backend.
|
||||||
|
|
||||||
|
Overloads the OpenGL2 render interface to load textures through SDL_image's built-in texture loading functionality.
|
||||||
|
*/
|
||||||
|
class RenderInterface_GL2_SDL : public RenderInterface_GL2 {
|
||||||
|
public:
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override
|
||||||
|
{
|
||||||
|
Rml::FileInterface* file_interface = Rml::GetFileInterface();
|
||||||
|
Rml::FileHandle file_handle = file_interface->Open(source);
|
||||||
|
if (!file_handle)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_END);
|
||||||
|
const size_t buffer_size = file_interface->Tell(file_handle);
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_SET);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
const size_t i_ext = source.rfind('.');
|
||||||
|
Rml::String extension = (i_ext == Rml::String::npos ? Rml::String() : source.substr(i_ext + 1));
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_IO(SDL_IOFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, SDL_PixelFormat format) { return SDL_ConvertSurface(surface, format); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_DestroySurface(surface); };
|
||||||
|
#else
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_RW(SDL_RWFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, Uint32 format) { return SDL_ConvertSurfaceFormat(surface, format, 0); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_FreeSurface(surface); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* surface = CreateSurface();
|
||||||
|
if (!surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
if (GetSurfaceFormat(surface) != SDL_PIXELFORMAT_RGBA32)
|
||||||
|
{
|
||||||
|
// Ensure correct format for premultiplied alpha conversion and GenerateTexture below.
|
||||||
|
SDL_Surface* converted_surface = ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
DestroySurface(surface);
|
||||||
|
if (!converted_surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
surface = converted_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
const size_t pixels_byte_size = surface->w * surface->h * 4;
|
||||||
|
byte* pixels = static_cast<byte*>(surface->pixels);
|
||||||
|
for (size_t i = 0; i < pixels_byte_size; i += 4)
|
||||||
|
{
|
||||||
|
const byte alpha = pixels[i + 3];
|
||||||
|
for (size_t j = 0; j < 3; ++j)
|
||||||
|
pixels[i + j] = byte(int(pixels[i + j]) * int(alpha) / 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle texture_handle = RenderInterface_GL2::GenerateTexture({pixels, pixels_byte_size}, texture_dimensions);
|
||||||
|
|
||||||
|
DestroySurface(surface);
|
||||||
|
|
||||||
|
return texture_handle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
RenderInterface_GL2_SDL render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
SDL_GLContext glcontext = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Request stencil buffer of at least 8-bit size to supporting clipping on transformed elements.
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
|
||||||
|
// Enable MSAA for better-looking visuals, especially when transforms are applied.
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateWindow = [&]() {
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
return window;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
auto CreateWindow = [&]() {
|
||||||
|
const Uint32 window_flags = (SDL_WINDOW_OPENGL | (allow_resize ? SDL_WINDOW_RESIZABLE : 0));
|
||||||
|
SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
|
||||||
|
// SDL2 implicitly activates text input on window creation. Turn it off for now, it will be activated again e.g. when focusing a text input
|
||||||
|
// field.
|
||||||
|
SDL_StopTextInput();
|
||||||
|
return window;
|
||||||
|
};
|
||||||
|
// Enable linear filtering, SDL 3 already defaults to it.
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Window* window = CreateWindow();
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
// Try again on low-quality settings.
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
|
||||||
|
window = CreateWindow();
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
|
||||||
|
SDL_GL_MakeCurrent(window, glcontext);
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
|
||||||
|
data->window = window;
|
||||||
|
data->glcontext = glcontext;
|
||||||
|
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_GL_DestroyContext(data->glcontext);
|
||||||
|
#else
|
||||||
|
SDL_GL_DeleteContext(data->glcontext);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_DestroyWindow(data->window);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
|
||||||
|
bool has_event = false;
|
||||||
|
#else
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN \
|
||||||
|
case SDL_WINDOWEVENT: \
|
||||||
|
{ \
|
||||||
|
switch (ev.window.event) \
|
||||||
|
{
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetDisplayScale = []() { return 1.f; };
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_TEXTEDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_WINDOWEVENT_SIZE_CHANGED;
|
||||||
|
int has_event = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
|
||||||
|
case event_window_size_changed:
|
||||||
|
{
|
||||||
|
Rml::Vector2i dimensions = {ev.window.data1, ev.window.data2};
|
||||||
|
data->render_interface.SetViewport(dimensions.x, dimensions.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_END
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.Clear();
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
SDL_GL_SwapWindow(data->window);
|
||||||
|
}
|
||||||
388
vendor/rmlui_backend/RmlUi_Backend_SDL_GL3.cpp
vendored
Normal file
388
vendor/rmlui_backend/RmlUi_Backend_SDL_GL3.cpp
vendored
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_GL3.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
#else
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined RMLUI_PLATFORM_EMSCRIPTEN
|
||||||
|
#include <emscripten.h>
|
||||||
|
#elif SDL_MAJOR_VERSION == 2 && !(SDL_VIDEO_RENDER_OGL)
|
||||||
|
#error "Only the OpenGL SDL backend is supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom render interface example for the SDL/GL3 backend.
|
||||||
|
|
||||||
|
Overloads the OpenGL3 render interface to load textures through SDL_image's built-in texture loading functionality.
|
||||||
|
*/
|
||||||
|
class RenderInterface_GL3_SDL : public RenderInterface_GL3 {
|
||||||
|
public:
|
||||||
|
RenderInterface_GL3_SDL() {}
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override
|
||||||
|
{
|
||||||
|
Rml::FileInterface* file_interface = Rml::GetFileInterface();
|
||||||
|
Rml::FileHandle file_handle = file_interface->Open(source);
|
||||||
|
if (!file_handle)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_END);
|
||||||
|
const size_t buffer_size = file_interface->Tell(file_handle);
|
||||||
|
file_interface->Seek(file_handle, 0, SEEK_SET);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
const size_t i_ext = source.rfind('.');
|
||||||
|
Rml::String extension = (i_ext == Rml::String::npos ? Rml::String() : source.substr(i_ext + 1));
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_IO(SDL_IOFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, SDL_PixelFormat format) { return SDL_ConvertSurface(surface, format); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_DestroySurface(surface); };
|
||||||
|
#else
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_RW(SDL_RWFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, Uint32 format) { return SDL_ConvertSurfaceFormat(surface, format, 0); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_FreeSurface(surface); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* surface = CreateSurface();
|
||||||
|
if (!surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
if (GetSurfaceFormat(surface) != SDL_PIXELFORMAT_RGBA32)
|
||||||
|
{
|
||||||
|
// Ensure correct format for premultiplied alpha conversion and GenerateTexture below.
|
||||||
|
SDL_Surface* converted_surface = ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
DestroySurface(surface);
|
||||||
|
if (!converted_surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
surface = converted_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
const size_t pixels_byte_size = surface->w * surface->h * 4;
|
||||||
|
byte* pixels = static_cast<byte*>(surface->pixels);
|
||||||
|
for (size_t i = 0; i < pixels_byte_size; i += 4)
|
||||||
|
{
|
||||||
|
const byte alpha = pixels[i + 3];
|
||||||
|
for (size_t j = 0; j < 3; ++j)
|
||||||
|
pixels[i + j] = byte(int(pixels[i + j]) * int(alpha) / 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle texture_handle = RenderInterface_GL3::GenerateTexture({pixels, pixels_byte_size}, texture_dimensions);
|
||||||
|
|
||||||
|
DestroySurface(surface);
|
||||||
|
|
||||||
|
return texture_handle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
RenderInterface_GL3_SDL render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
SDL_GLContext glcontext = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(RMLUI_PLATFORM_EMSCRIPTEN)
|
||||||
|
// GLES 3.0 (WebGL 2.0)
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
// GLES 3.2 on Android
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||||
|
#else
|
||||||
|
// GL 3.3 Core
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
#else
|
||||||
|
const Uint32 window_flags = (SDL_WINDOW_OPENGL | (allow_resize ? SDL_WINDOW_RESIZABLE : 0));
|
||||||
|
SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
|
||||||
|
// SDL2 implicitly activates text input on window creation. Turn it off for now, it will be activated again e.g. when focusing a text input field.
|
||||||
|
SDL_StopTextInput();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
|
||||||
|
SDL_GL_MakeCurrent(window, glcontext);
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
|
||||||
|
if (!RmlGL3::Initialize())
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize OpenGL renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
|
||||||
|
if (!data->render_interface)
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize OpenGL3 render interface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->window = window;
|
||||||
|
data->glcontext = glcontext;
|
||||||
|
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
SDL_Window* window = data->window;
|
||||||
|
SDL_GLContext glcontext = data->glcontext;
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_GL_DestroyContext(glcontext);
|
||||||
|
#else
|
||||||
|
SDL_GL_DeleteContext(glcontext);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
#if defined RMLUI_PLATFORM_EMSCRIPTEN
|
||||||
|
|
||||||
|
// Ideally we would hand over control of the main loop to emscripten:
|
||||||
|
//
|
||||||
|
// // Hand over control of the main loop to the WebAssembly runtime.
|
||||||
|
// emscripten_set_main_loop_arg(EventLoopIteration, (void*)user_data_handle, 0, true);
|
||||||
|
//
|
||||||
|
// The above is the recommended approach. However, as we don't control the main loop here we have to make due with another approach. Instead, use
|
||||||
|
// Asyncify to yield by sleeping.
|
||||||
|
// Important: Must be linked with option -sASYNCIFY
|
||||||
|
emscripten_sleep(1);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
|
||||||
|
bool has_event = false;
|
||||||
|
#else
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN \
|
||||||
|
case SDL_WINDOWEVENT: \
|
||||||
|
{ \
|
||||||
|
switch (ev.window.event) \
|
||||||
|
{
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetDisplayScale = []() { return 1.f; };
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_TEXTEDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_WINDOWEVENT_SIZE_CHANGED;
|
||||||
|
int has_event = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
|
||||||
|
case event_window_size_changed:
|
||||||
|
{
|
||||||
|
Rml::Vector2i dimensions = {ev.window.data1, ev.window.data2};
|
||||||
|
data->render_interface.SetViewport(dimensions.x, dimensions.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_END
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.Clear();
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
SDL_GL_SwapWindow(data->window);
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
246
vendor/rmlui_backend/RmlUi_Backend_SDL_GPU.cpp
vendored
Normal file
246
vendor/rmlui_backend/RmlUi_Backend_SDL_GPU.cpp
vendored
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_SDL_GPU.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
|
||||||
|
#ifndef RMLUI_BACKEND_SDL_GPU_DEBUG
|
||||||
|
#define RMLUI_BACKEND_SDL_GPU_DEBUG false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window, SDL_GPUDevice* device) : system_interface(window), render_interface(device, window) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
RenderInterface_SDL_GPU render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
SDL_GPUDevice* device = nullptr;
|
||||||
|
SDL_GPUCommandBuffer* command_buffer = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
props = SDL_CreateProperties();
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, RMLUI_BACKEND_SDL_GPU_DEBUG);
|
||||||
|
SDL_GPUDevice* device = SDL_CreateGPUDeviceWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create GPU device: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SDL_ClaimWindowForGPUDevice(device, window))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on claiming window for GPU device: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window, device);
|
||||||
|
data->window = window;
|
||||||
|
data->device = device;
|
||||||
|
|
||||||
|
const char* renderer_name = SDL_GetGPUDeviceDriver(device);
|
||||||
|
data->system_interface.LogMessage(Rml::Log::LT_INFO, Rml::CreateString("Using SDL device driver: %s", renderer_name));
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.Shutdown();
|
||||||
|
|
||||||
|
SDL_ReleaseWindowFromGPUDevice(data->device, data->window);
|
||||||
|
SDL_DestroyGPUDevice(data->device);
|
||||||
|
SDL_DestroyWindow(data->window);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
bool has_event = false;
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->command_buffer = SDL_AcquireGPUCommandBuffer(data->device);
|
||||||
|
if (!data->command_buffer)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to acquire command buffer: %s", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUTexture* swapchain_texture;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
if (!SDL_WaitAndAcquireGPUSwapchainTexture(data->command_buffer, data->window, &swapchain_texture, &width, &height))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to acquire swapchain texture: %s", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!swapchain_texture || !width || !height)
|
||||||
|
{
|
||||||
|
// Not an error. Happens on minimize
|
||||||
|
SDL_CancelGPUCommandBuffer(data->command_buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do your normal draw operations (make sure you clear the swapchain texture)
|
||||||
|
SDL_GPUColorTargetInfo color_info{};
|
||||||
|
color_info.texture = swapchain_texture;
|
||||||
|
color_info.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
color_info.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(data->command_buffer, &color_info, 1, nullptr);
|
||||||
|
SDL_EndGPURenderPass(render_pass);
|
||||||
|
|
||||||
|
data->render_interface.BeginFrame(data->command_buffer, swapchain_texture, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
|
||||||
|
SDL_SubmitGPUCommandBuffer(data->command_buffer);
|
||||||
|
data->command_buffer = nullptr;
|
||||||
|
}
|
||||||
242
vendor/rmlui_backend/RmlUi_Backend_SDL_SDLrenderer.cpp
vendored
Normal file
242
vendor/rmlui_backend/RmlUi_Backend_SDL_SDLrenderer.cpp
vendored
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_SDL.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window, SDL_Renderer* renderer) : system_interface(window), render_interface(renderer) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
RenderInterface_SDL render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
SDL_Renderer* renderer = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
#else
|
||||||
|
const Uint32 window_flags = (allow_resize ? SDL_WINDOW_RESIZABLE : 0);
|
||||||
|
SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
|
||||||
|
// SDL2 implicitly activates text input on window creation. Turn it off for now, it will be activated again e.g. when focusing a text input field.
|
||||||
|
SDL_StopTextInput();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s\n", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force a specific SDL renderer
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengles2");
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d");
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d12");
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
|
||||||
|
// SDL_SetHint(SDL_HINT_RENDER_DRIVER, "vulkan");
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_Renderer* renderer = SDL_CreateRenderer(window, nullptr);
|
||||||
|
#else
|
||||||
|
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!renderer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window, renderer);
|
||||||
|
data->window = window;
|
||||||
|
data->renderer = renderer;
|
||||||
|
|
||||||
|
const char* renderer_name = nullptr;
|
||||||
|
Rml::String available_renderers;
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetRenderVSync(renderer, 1);
|
||||||
|
renderer_name = SDL_GetRendererName(renderer);
|
||||||
|
for (int i = 0; i < SDL_GetNumRenderDrivers(); i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
available_renderers += ", ";
|
||||||
|
available_renderers += SDL_GetRenderDriver(i);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
SDL_RendererInfo renderer_info;
|
||||||
|
if (SDL_GetRendererInfo(renderer, &renderer_info) == 0)
|
||||||
|
renderer_name = renderer_info.name;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!available_renderers.empty())
|
||||||
|
data->system_interface.LogMessage(Rml::Log::LT_INFO, Rml::CreateString("Available SDL renderers: %s", available_renderers.c_str()));
|
||||||
|
if (renderer_name)
|
||||||
|
data->system_interface.LogMessage(Rml::Log::LT_INFO, Rml::CreateString("Using SDL renderer: %s", renderer_name));
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
SDL_DestroyRenderer(data->renderer);
|
||||||
|
SDL_DestroyWindow(data->window);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
bool has_event = false;
|
||||||
|
#else
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetDisplayScale = []() { return 1.f; };
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_TEXTEDITING;
|
||||||
|
int has_event = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
SDL_RenderPresent(data->renderer);
|
||||||
|
}
|
||||||
319
vendor/rmlui_backend/RmlUi_Backend_SDL_VK.cpp
vendored
Normal file
319
vendor/rmlui_backend/RmlUi_Backend_SDL_VK.cpp
vendored
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include "RmlUi_Renderer_VK.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION == 2 && !(SDL_VIDEO_VULKAN)
|
||||||
|
#error "Only the Vulkan SDL backend is supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#include <SDL3/SDL_vulkan.h>
|
||||||
|
#else
|
||||||
|
#include <SDL2/SDL_vulkan.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(SDL_Window* window) : system_interface(window) {}
|
||||||
|
|
||||||
|
SystemInterface_SDL system_interface;
|
||||||
|
RenderInterface_VK render_interface;
|
||||||
|
TextInputMethodEditor_SDL text_input_method_editor;
|
||||||
|
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "composition");
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Submit click events when focusing the window.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||||
|
// Touch events are handled natively, no need to generate synthetic mouse events for touch devices.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
|
||||||
|
#if defined RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
// Simulate touch events from mouse events for testing touch behavior on a desktop machine.
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const float window_size_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_name);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, int(width * window_size_scale));
|
||||||
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, int(height * window_size_scale));
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, true);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, allow_resize);
|
||||||
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
|
||||||
|
SDL_Window* window = SDL_CreateWindowWithProperties(props);
|
||||||
|
SDL_DestroyProperties(props);
|
||||||
|
auto CreateSurface = [](VkInstance instance, VkSurfaceKHR* out_surface) {
|
||||||
|
return SDL_Vulkan_CreateSurface(data->window, instance, nullptr, out_surface);
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const Uint32 window_flags = (SDL_WINDOW_VULKAN | (allow_resize ? SDL_WINDOW_RESIZABLE : 0));
|
||||||
|
SDL_Window* window = SDL_CreateWindow(window_name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
|
||||||
|
// SDL2 implicitly activates text input on window creation. Turn it off for now, it will be activated again e.g. when focusing a text input field.
|
||||||
|
SDL_StopTextInput();
|
||||||
|
auto CreateSurface = [](VkInstance instance, VkSurfaceKHR* out_surface) {
|
||||||
|
return (bool)SDL_Vulkan_CreateSurface(data->window, instance, out_surface);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!window)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "SDL error on create window: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(window);
|
||||||
|
data->window = window;
|
||||||
|
|
||||||
|
Rml::Vector<const char*> extensions;
|
||||||
|
{
|
||||||
|
unsigned int count;
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const char* const* extensions_list = SDL_Vulkan_GetInstanceExtensions(&count);
|
||||||
|
if (!extensions_list)
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to get required vulkan extensions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
extensions.resize(count);
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
extensions[i] = extensions_list[i];
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (!SDL_Vulkan_GetInstanceExtensions(window, &count, nullptr))
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to get required vulkan extensions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
extensions.resize(count);
|
||||||
|
if (!SDL_Vulkan_GetInstanceExtensions(window, &count, extensions.data()))
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to get required vulkan extensions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data->render_interface.Initialize(std::move(extensions), CreateSurface))
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize Vulkan render interface");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.Shutdown();
|
||||||
|
|
||||||
|
SDL_DestroyWindow(data->window);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool WaitForValidSwapchain()
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
#else
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any render
|
||||||
|
// calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead, we keep the
|
||||||
|
// application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
while (!data->render_interface.IsSwapchainValid())
|
||||||
|
{
|
||||||
|
SDL_Event ev;
|
||||||
|
while (SDL_PollEvent(&ev))
|
||||||
|
{
|
||||||
|
if (ev.type == event_quit)
|
||||||
|
{
|
||||||
|
// Restore the window so that we can recreate the swapchain, and then properly release all resource and shutdown cleanly.
|
||||||
|
SDL_RestoreWindow(data->window);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_Delay(10);
|
||||||
|
data->render_interface.RecreateSwapchain();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetDisplayScale = []() { return SDL_GetWindowDisplayScale(data->window); };
|
||||||
|
constexpr auto event_quit = SDL_EVENT_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_EVENT_TEXT_EDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
|
||||||
|
bool has_event = false;
|
||||||
|
#else
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN \
|
||||||
|
case SDL_WINDOWEVENT: \
|
||||||
|
{ \
|
||||||
|
switch (ev.window.event) \
|
||||||
|
{
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetDisplayScale = []() { return 1.f; };
|
||||||
|
constexpr auto event_quit = SDL_QUIT;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_text_editing = SDL_TEXTEDITING;
|
||||||
|
constexpr auto event_window_size_changed = SDL_WINDOWEVENT_SIZE_CHANGED;
|
||||||
|
int has_event = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
SDL_Event ev;
|
||||||
|
if (power_save)
|
||||||
|
has_event = SDL_WaitEventTimeout(&ev, static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000));
|
||||||
|
else
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
|
||||||
|
while (has_event)
|
||||||
|
{
|
||||||
|
bool propagate_event = true;
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case event_quit:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSDL::ConvertKey(GetKey(ev));
|
||||||
|
const int key_modifier = RmlSDL::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDisplayScale();
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSDL::InputEventHandler(context, data->window, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_editing:
|
||||||
|
{
|
||||||
|
propagate_event = false;
|
||||||
|
data->text_input_method_editor.HandleEdit(ev.edit);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
|
||||||
|
case event_window_size_changed:
|
||||||
|
{
|
||||||
|
Rml::Vector2i dimensions = {ev.window.data1, ev.window.data2};
|
||||||
|
data->render_interface.SetViewport(dimensions.x, dimensions.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_END
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propagate_event)
|
||||||
|
RmlSDL::InputEventHandler(context, data->window, ev);
|
||||||
|
|
||||||
|
has_event = SDL_PollEvent(&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WaitForValidSwapchain())
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
}
|
||||||
296
vendor/rmlui_backend/RmlUi_Backend_SFML_GL2.cpp
vendored
Normal file
296
vendor/rmlui_backend/RmlUi_Backend_SFML_GL2.cpp
vendored
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Platform_SFML.h"
|
||||||
|
#include "RmlUi_Renderer_GL2.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
#include <RmlUi/Debugger/Debugger.h>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/Window.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
#define SFML_COORDINATE(x, y) {x, y}
|
||||||
|
#else
|
||||||
|
#define SFML_COORDINATE(x, y) x, y
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom render interface example for the SFML/GL2 backend.
|
||||||
|
|
||||||
|
Overloads the OpenGL2 render interface to load textures through SFML's built-in texture loading functionality.
|
||||||
|
*/
|
||||||
|
class RenderInterface_GL2_SFML : public RenderInterface_GL2 {
|
||||||
|
public:
|
||||||
|
// -- Inherited from Rml::RenderInterface --
|
||||||
|
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override
|
||||||
|
{
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
sf::Texture::bind((sf::Texture*)texture);
|
||||||
|
texture = RenderInterface_GL2::TextureEnableWithoutBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInterface_GL2::RenderGeometry(handle, translation, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
sf::Image image;
|
||||||
|
if (!image.loadFromMemory(buffer.get(), buffer_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
for (unsigned int x = 0; x < image.getSize().x; x++)
|
||||||
|
{
|
||||||
|
for (unsigned int y = 0; y < image.getSize().y; y++)
|
||||||
|
{
|
||||||
|
sf::Color color = image.getPixel(SFML_COORDINATE(x, y));
|
||||||
|
color.r = static_cast<std::uint8_t>((color.r * color.a) / 255);
|
||||||
|
color.g = static_cast<std::uint8_t>((color.g * color.a) / 255);
|
||||||
|
color.b = static_cast<std::uint8_t>((color.b * color.a) / 255);
|
||||||
|
image.setPixel(SFML_COORDINATE(x, y), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sf::Texture* texture = new sf::Texture();
|
||||||
|
texture->setSmooth(true);
|
||||||
|
|
||||||
|
if (!texture->loadFromImage(image))
|
||||||
|
{
|
||||||
|
delete texture;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_dimensions = Rml::Vector2i(texture->getSize().x, texture->getSize().y);
|
||||||
|
return (Rml::TextureHandle)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions_i) override
|
||||||
|
{
|
||||||
|
const auto source_dimensions = Rml::Vector2<unsigned int>(source_dimensions_i);
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
sf::Texture* texture = new sf::Texture(sf::Vector2u{source_dimensions.x, source_dimensions.y});
|
||||||
|
#else
|
||||||
|
sf::Texture* texture = new sf::Texture();
|
||||||
|
if (!texture->create(source_dimensions.x, source_dimensions.y))
|
||||||
|
{
|
||||||
|
delete texture;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
texture->setSmooth(true);
|
||||||
|
texture->update(source.data(), SFML_COORDINATE(source_dimensions.x, source_dimensions.y), SFML_COORDINATE(0, 0));
|
||||||
|
return (Rml::TextureHandle)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override { delete (sf::Texture*)texture_handle; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Updates the viewport and context dimensions, should be called whenever the window size changes.
|
||||||
|
static void UpdateWindowDimensions(sf::RenderWindow& window, RenderInterface_GL2_SFML& render_interface, Rml::Context* context)
|
||||||
|
{
|
||||||
|
const int width = (int)window.getSize().x;
|
||||||
|
const int height = (int)window.getSize().y;
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
context->SetDimensions(Rml::Vector2i(width, height));
|
||||||
|
|
||||||
|
sf::View view(sf::FloatRect(SFML_COORDINATE(0.f, 0.f), SFML_COORDINATE((float)width, (float)height)));
|
||||||
|
window.setView(view);
|
||||||
|
|
||||||
|
render_interface.SetViewport(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
SystemInterface_SFML system_interface;
|
||||||
|
RenderInterface_GL2_SFML render_interface;
|
||||||
|
sf::RenderWindow window;
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>();
|
||||||
|
|
||||||
|
const std::uint32_t style = (allow_resize ? sf::Style::Default : (sf::Style::Titlebar | sf::Style::Close));
|
||||||
|
constexpr unsigned int anti_aliasing_level = 2;
|
||||||
|
|
||||||
|
// Create the window.
|
||||||
|
sf::RenderWindow out_window;
|
||||||
|
sf::ContextSettings context_settings;
|
||||||
|
context_settings.stencilBits = 8;
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
context_settings.antiAliasingLevel = anti_aliasing_level;
|
||||||
|
data->window.create(sf::VideoMode({(unsigned int)width, (unsigned int)height}), window_name, style, sf::State::Windowed, context_settings);
|
||||||
|
#else
|
||||||
|
context_settings.antialiasingLevel = anti_aliasing_level;
|
||||||
|
data->window.create(sf::VideoMode(width, height), window_name, style, context_settings);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
data->window.setVerticalSyncEnabled(true);
|
||||||
|
if (!data->window.isOpen())
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally apply the SFML window to the system interface so that it can change its mouse cursor.
|
||||||
|
data->system_interface.SetWindow(&data->window);
|
||||||
|
|
||||||
|
UpdateWindowDimensions(data->window, data->render_interface, nullptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
// SFML does not seem to provide a way to wait for events with a timeout.
|
||||||
|
(void)power_save;
|
||||||
|
|
||||||
|
// The contents of this function is intended to be copied directly into your main loop.
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
auto handle_key_pressed = [&](const sf::Event& ev, sf::Keyboard::Key key_pressed_code) {
|
||||||
|
const Rml::Input::KeyIdentifier key = RmlSFML::ConvertKey(key_pressed_code);
|
||||||
|
const int key_modifier = RmlSFML::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = 1.f;
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
return;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlSFML::InputHandler(context, ev))
|
||||||
|
return;
|
||||||
|
// 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, native_dp_ratio, false))
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
while (const std::optional ev = data->window.pollEvent())
|
||||||
|
{
|
||||||
|
if (ev->is<sf::Event::Resized>())
|
||||||
|
{
|
||||||
|
UpdateWindowDimensions(data->window, data->render_interface, context);
|
||||||
|
}
|
||||||
|
else if (auto key_pressed = ev->getIf<sf::Event::KeyPressed>())
|
||||||
|
{
|
||||||
|
handle_key_pressed(*ev, key_pressed->code);
|
||||||
|
}
|
||||||
|
else if (ev->is<sf::Event::Closed>())
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RmlSFML::InputHandler(context, *ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
sf::Event ev;
|
||||||
|
while (data->window.pollEvent(ev))
|
||||||
|
{
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case sf::Event::Resized: UpdateWindowDimensions(data->window, data->render_interface, context); break;
|
||||||
|
case sf::Event::KeyPressed: handle_key_pressed(ev, ev.key.code); break;
|
||||||
|
case sf::Event::Closed: result = false; break;
|
||||||
|
default: RmlSFML::InputHandler(context, ev); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
sf::RenderWindow& window = data->window;
|
||||||
|
|
||||||
|
window.resetGLStates();
|
||||||
|
window.clear();
|
||||||
|
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Draw a simple shape with SFML for demonstration purposes. Make sure to push and pop GL states as appropriate.
|
||||||
|
sf::Vector2f circle_position(100.f, 100.f);
|
||||||
|
|
||||||
|
window.pushGLStates();
|
||||||
|
|
||||||
|
sf::CircleShape circle(50.f);
|
||||||
|
circle.setPosition(circle_position);
|
||||||
|
circle.setFillColor(sf::Color::Blue);
|
||||||
|
circle.setOutlineColor(sf::Color::Red);
|
||||||
|
circle.setOutlineThickness(10.f);
|
||||||
|
window.draw(circle);
|
||||||
|
|
||||||
|
window.popGLStates();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
data->window.display();
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
393
vendor/rmlui_backend/RmlUi_Backend_Win32_DX12.cpp
vendored
Normal file
393
vendor/rmlui_backend/RmlUi_Backend_Win32_DX12.cpp
vendored
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
#include "RmlUi/Config/Config.h"
|
||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include "RmlUi_Platform_Win32.h"
|
||||||
|
#include "RmlUi_Renderer_DX12.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
High DPI support using Windows Per Monitor V2 DPI awareness.
|
||||||
|
|
||||||
|
Requires Windows 10, version 1703.
|
||||||
|
*/
|
||||||
|
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) - 4)
|
||||||
|
#endif
|
||||||
|
#ifndef WM_DPICHANGED
|
||||||
|
#define WM_DPICHANGED 0x02E0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FIX_WARNING_UNUSED(code) (void)(code);
|
||||||
|
|
||||||
|
// Declare pointers to the DPI aware Windows API functions.
|
||||||
|
using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
|
||||||
|
using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
|
||||||
|
using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
|
||||||
|
|
||||||
|
static bool has_dpi_support = false;
|
||||||
|
static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
|
||||||
|
static ProcGetDpiForWindow procGetDpiForWindow = NULL;
|
||||||
|
static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
|
||||||
|
|
||||||
|
// Make ourselves DPI aware on supported Windows versions.
|
||||||
|
static void InitializeDpiSupport()
|
||||||
|
{
|
||||||
|
// Cast function pointers to void* first for MinGW not to emit errors.
|
||||||
|
procSetProcessDpiAwarenessContext =
|
||||||
|
(ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "SetProcessDpiAwarenessContext");
|
||||||
|
procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "GetDpiForWindow");
|
||||||
|
procAdjustWindowRectExForDpi =
|
||||||
|
(ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "AdjustWindowRectExForDpi");
|
||||||
|
|
||||||
|
if (!has_dpi_support && procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL)
|
||||||
|
{
|
||||||
|
// Activate Per Monitor V2.
|
||||||
|
if (procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
|
||||||
|
has_dpi_support = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT GetWindowDpi(HWND window_handle)
|
||||||
|
{
|
||||||
|
if (has_dpi_support)
|
||||||
|
{
|
||||||
|
UINT dpi = procGetDpiForWindow(window_handle);
|
||||||
|
if (dpi != 0)
|
||||||
|
return dpi;
|
||||||
|
}
|
||||||
|
return USER_DEFAULT_SCREEN_DPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float GetDensityIndependentPixelRatio(HWND window_handle)
|
||||||
|
{
|
||||||
|
return float(GetWindowDpi(window_handle)) / float(USER_DEFAULT_SCREEN_DPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the window but don't show it yet. Returns the pixel size of the window, which may be different from the passed size due to DPI settings.
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
SystemInterface_Win32 system_interface;
|
||||||
|
Rml::UniquePtr<RenderInterface_DX12> render_interface;
|
||||||
|
TextInputMethodEditor_Win32 text_input_method_editor;
|
||||||
|
|
||||||
|
HINSTANCE instance_handle = nullptr;
|
||||||
|
std::wstring instance_name;
|
||||||
|
HWND window_handle = nullptr;
|
||||||
|
|
||||||
|
bool context_dimensions_dirty = true;
|
||||||
|
Rml::Vector2i window_dimensions;
|
||||||
|
bool running = 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* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
const std::wstring name = RmlWin32::ConvertToUTF16(Rml::String(window_name));
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>();
|
||||||
|
|
||||||
|
data->instance_handle = GetModuleHandle(nullptr);
|
||||||
|
data->instance_name = name;
|
||||||
|
|
||||||
|
InitializeDpiSupport();
|
||||||
|
|
||||||
|
// Initialize the window but don't show it yet.
|
||||||
|
HWND window_handle = InitializeWindow(data->instance_handle, name, width, height, allow_resize);
|
||||||
|
if (!window_handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data->window_handle = window_handle;
|
||||||
|
|
||||||
|
RmlRendererSettings settings = {};
|
||||||
|
settings.vsync = true;
|
||||||
|
settings.msaa_sample_count = RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT;
|
||||||
|
|
||||||
|
Rml::String initialization_message;
|
||||||
|
data->render_interface = Rml::MakeUnique<RenderInterface_DX12>(window_handle, settings);
|
||||||
|
|
||||||
|
if (!data->render_interface)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Could not initialize DirectX 12 render interface: %s", initialization_message.c_str());
|
||||||
|
::CloseWindow(window_handle);
|
||||||
|
data.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->system_interface.SetWindow(window_handle);
|
||||||
|
data->render_interface->SetViewport(width, height);
|
||||||
|
|
||||||
|
// Now we are ready to show the window.
|
||||||
|
::ShowWindow(window_handle, SW_SHOW);
|
||||||
|
::SetForegroundWindow(window_handle);
|
||||||
|
::SetFocus(window_handle);
|
||||||
|
|
||||||
|
// Provide a backend-specific text input handler to manage the IME.
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
// As we forcefully override the global text input handler, we must reset it before the data is destroyed to avoid any potential use-after-free.
|
||||||
|
if (Rml::GetTextInputHandler() == &data->text_input_method_editor)
|
||||||
|
Rml::SetTextInputHandler(nullptr);
|
||||||
|
|
||||||
|
if (data->render_interface)
|
||||||
|
{
|
||||||
|
data->render_interface.reset();
|
||||||
|
::DestroyWindow(data->window_handle);
|
||||||
|
::UnregisterClassW((LPCWSTR)data->instance_name.data(), data->instance_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return data->render_interface.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NextEvent(MSG& message, UINT timeout)
|
||||||
|
{
|
||||||
|
if (timeout != 0)
|
||||||
|
{
|
||||||
|
UINT_PTR timer_id = SetTimer(NULL, NULL, timeout, NULL);
|
||||||
|
BOOL res = GetMessage(&message, NULL, 0, 0);
|
||||||
|
KillTimer(NULL, timer_id);
|
||||||
|
if (message.message != WM_TIMER || message.hwnd != nullptr || message.wParam != timer_id)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return PeekMessage(&message, nullptr, 0, 0, PM_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
const float dp_ratio = GetDensityIndependentPixelRatio(data->window_handle);
|
||||||
|
context->SetDimensions(data->window_dimensions);
|
||||||
|
context->SetDensityIndependentPixelRatio(dp_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = context;
|
||||||
|
data->key_down_callback = key_down_callback;
|
||||||
|
|
||||||
|
MSG message;
|
||||||
|
// Process events.
|
||||||
|
bool has_message = NextEvent(message, power_save ? static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000.0) : 0);
|
||||||
|
while (has_message || !data->render_interface->IsSwapchainValid())
|
||||||
|
{
|
||||||
|
if (has_message)
|
||||||
|
{
|
||||||
|
// Dispatch the message to our local event handler below.
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any
|
||||||
|
// render calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead,
|
||||||
|
// we trap the application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
if (!data->render_interface->IsSwapchainValid())
|
||||||
|
data->render_interface->RecreateSwapchain();
|
||||||
|
|
||||||
|
has_message = NextEvent(message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = nullptr;
|
||||||
|
data->key_down_callback = nullptr;
|
||||||
|
|
||||||
|
return data->running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
RMLUI_ASSERT(data->render_interface);
|
||||||
|
|
||||||
|
if (data->render_interface)
|
||||||
|
{
|
||||||
|
data->render_interface->BeginFrame();
|
||||||
|
data->render_interface->Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
RMLUI_ASSERT(data->render_interface);
|
||||||
|
|
||||||
|
data->render_interface->EndFrame();
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local event handler for window and input events.
|
||||||
|
static LRESULT CALLBACK WindowProcedureHandler(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
{
|
||||||
|
data->running = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_SIZE:
|
||||||
|
{
|
||||||
|
const int width = LOWORD(l_param);
|
||||||
|
const int height = HIWORD(l_param);
|
||||||
|
data->window_dimensions.x = width;
|
||||||
|
data->window_dimensions.y = height;
|
||||||
|
if (data->context)
|
||||||
|
{
|
||||||
|
data->render_interface->SetViewport(width, height);
|
||||||
|
data->context->SetDimensions(data->window_dimensions);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
{
|
||||||
|
RECT* new_pos = (RECT*)l_param;
|
||||||
|
SetWindowPos(window_handle, NULL, new_pos->left, new_pos->top, new_pos->right - new_pos->left, new_pos->bottom - new_pos->top,
|
||||||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
if (data->context && has_dpi_support)
|
||||||
|
data->context->SetDensityIndependentPixelRatio(GetDensityIndependentPixelRatio(window_handle));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
const Rml::Input::KeyIdentifier rml_key = RmlWin32::ConvertKey((int)w_param);
|
||||||
|
const int rml_modifier = RmlWin32::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDensityIndependentPixelRatio(window_handle);
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, true))
|
||||||
|
return 0;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlWin32::WindowProcedure(context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, false))
|
||||||
|
return 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Submit it to the platform handler for default input handling.
|
||||||
|
if (!RmlWin32::WindowProcedure(data->context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All unhandled messages go to DefWindowProc.
|
||||||
|
return DefWindowProc(window_handle, message, w_param, l_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize)
|
||||||
|
{
|
||||||
|
WNDCLASSW window_class;
|
||||||
|
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||||
|
window_class.lpfnWndProc = &WindowProcedureHandler; // Attach our local event handler.
|
||||||
|
window_class.cbClsExtra = 0;
|
||||||
|
window_class.cbWndExtra = 0;
|
||||||
|
window_class.hInstance = instance_handle;
|
||||||
|
window_class.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
|
||||||
|
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
|
window_class.hbrBackground = nullptr;
|
||||||
|
window_class.lpszMenuName = nullptr;
|
||||||
|
window_class.lpszClassName = name.data();
|
||||||
|
|
||||||
|
if (!RegisterClassW(&window_class))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to register window class");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND window_handle = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
|
||||||
|
name.data(), // Window class name.
|
||||||
|
name.data(), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 0, 0, // Window position.
|
||||||
|
0, 0, // Window size.
|
||||||
|
nullptr, nullptr, instance_handle, nullptr);
|
||||||
|
|
||||||
|
if (!window_handle)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to create window");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT window_dpi = GetWindowDpi(window_handle);
|
||||||
|
inout_width = (inout_width * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
inout_height = (inout_height * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
|
||||||
|
DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
|
||||||
|
DWORD extended_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||||
|
|
||||||
|
// Adjust the window size to take the edges into account.
|
||||||
|
RECT window_rect;
|
||||||
|
window_rect.top = 0;
|
||||||
|
window_rect.left = 0;
|
||||||
|
window_rect.right = inout_width;
|
||||||
|
window_rect.bottom = inout_height;
|
||||||
|
if (has_dpi_support)
|
||||||
|
procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
|
||||||
|
else
|
||||||
|
AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
|
||||||
|
|
||||||
|
SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
|
||||||
|
SetWindowLong(window_handle, GWL_STYLE, style);
|
||||||
|
|
||||||
|
// Resize the window and center it on the screen.
|
||||||
|
Rml::Vector2i screen_size = {GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
|
||||||
|
Rml::Vector2i window_size = {int(window_rect.right - window_rect.left), int(window_rect.bottom - window_rect.top)};
|
||||||
|
Rml::Vector2i window_pos = Rml::Math::Max((screen_size - window_size) / 2, Rml::Vector2i(0));
|
||||||
|
|
||||||
|
SetWindowPos(window_handle, HWND_TOP, window_pos.x, window_pos.y, window_size.x, window_size.y, SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
return window_handle;
|
||||||
|
}
|
||||||
444
vendor/rmlui_backend/RmlUi_Backend_Win32_GL2.cpp
vendored
Normal file
444
vendor/rmlui_backend/RmlUi_Backend_Win32_GL2.cpp
vendored
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include "RmlUi_Platform_Win32.h"
|
||||||
|
#include "RmlUi_Renderer_GL2.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
High DPI support using Windows Per Monitor V2 DPI awareness.
|
||||||
|
|
||||||
|
Requires Windows 10, version 1703.
|
||||||
|
*/
|
||||||
|
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
|
||||||
|
#endif
|
||||||
|
#ifndef WM_DPICHANGED
|
||||||
|
#define WM_DPICHANGED 0x02E0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Declare pointers to the DPI aware Windows API functions.
|
||||||
|
using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
|
||||||
|
using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
|
||||||
|
using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
|
||||||
|
|
||||||
|
static bool has_dpi_support = false;
|
||||||
|
static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
|
||||||
|
static ProcGetDpiForWindow procGetDpiForWindow = NULL;
|
||||||
|
static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
|
||||||
|
|
||||||
|
// Make ourselves DPI aware on supported Windows versions.
|
||||||
|
static void InitializeDpiSupport()
|
||||||
|
{
|
||||||
|
// Cast function pointers to void* first for MinGW not to emit errors.
|
||||||
|
procSetProcessDpiAwarenessContext =
|
||||||
|
(ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "SetProcessDpiAwarenessContext");
|
||||||
|
procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "GetDpiForWindow");
|
||||||
|
procAdjustWindowRectExForDpi =
|
||||||
|
(ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "AdjustWindowRectExForDpi");
|
||||||
|
|
||||||
|
if (!has_dpi_support && procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL)
|
||||||
|
{
|
||||||
|
// Activate Per Monitor V2.
|
||||||
|
if (procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
|
||||||
|
has_dpi_support = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT GetWindowDpi(HWND window_handle)
|
||||||
|
{
|
||||||
|
if (has_dpi_support)
|
||||||
|
{
|
||||||
|
UINT dpi = procGetDpiForWindow(window_handle);
|
||||||
|
if (dpi != 0)
|
||||||
|
return dpi;
|
||||||
|
}
|
||||||
|
return USER_DEFAULT_SCREEN_DPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float GetDensityIndependentPixelRatio(HWND window_handle)
|
||||||
|
{
|
||||||
|
return float(GetWindowDpi(window_handle)) / float(USER_DEFAULT_SCREEN_DPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the window but don't show it yet. Returns the pixel size of the window, which may be different than the passed size due to DPI settings.
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize);
|
||||||
|
// Attach the OpenGL context.
|
||||||
|
static bool AttachToNative(HWND window_handle, HDC& out_device_context, HGLRC& out_render_context);
|
||||||
|
// Detach the OpenGL context.
|
||||||
|
static void DetachFromNative(HWND window_handle, HDC device_context, HGLRC render_context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
SystemInterface_Win32 system_interface;
|
||||||
|
RenderInterface_GL2 render_interface;
|
||||||
|
TextInputMethodEditor_Win32 text_input_method_editor;
|
||||||
|
|
||||||
|
HINSTANCE instance_handle = nullptr;
|
||||||
|
std::wstring instance_name;
|
||||||
|
HWND window_handle = nullptr;
|
||||||
|
|
||||||
|
HDC device_context = nullptr;
|
||||||
|
HGLRC render_context = nullptr;
|
||||||
|
|
||||||
|
bool context_dimensions_dirty = true;
|
||||||
|
Rml::Vector2i window_dimensions;
|
||||||
|
bool running = 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* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
const std::wstring name = RmlWin32::ConvertToUTF16(Rml::String(window_name));
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>();
|
||||||
|
|
||||||
|
data->instance_handle = GetModuleHandle(nullptr);
|
||||||
|
data->instance_name = name;
|
||||||
|
|
||||||
|
InitializeDpiSupport();
|
||||||
|
|
||||||
|
// Initialize the window but don't show it yet.
|
||||||
|
HWND window_handle = InitializeWindow(data->instance_handle, name, width, height, allow_resize);
|
||||||
|
if (!window_handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Attach the OpenGL context.
|
||||||
|
if (!AttachToNative(window_handle, data->device_context, data->render_context))
|
||||||
|
{
|
||||||
|
::CloseWindow(window_handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->window_handle = window_handle;
|
||||||
|
data->system_interface.SetWindow(window_handle);
|
||||||
|
|
||||||
|
// Now we are ready to show the window.
|
||||||
|
::ShowWindow(window_handle, SW_SHOW);
|
||||||
|
::SetForegroundWindow(window_handle);
|
||||||
|
::SetFocus(window_handle);
|
||||||
|
|
||||||
|
// Provide a backend-specific text input handler to manage the IME.
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
// As we forcefully override the global text input handler, we must reset it before the data is destroyed to avoid any potential use-after-free.
|
||||||
|
if (Rml::GetTextInputHandler() == &data->text_input_method_editor)
|
||||||
|
Rml::SetTextInputHandler(nullptr);
|
||||||
|
|
||||||
|
DetachFromNative(data->window_handle, data->device_context, data->render_context);
|
||||||
|
|
||||||
|
::DestroyWindow(data->window_handle);
|
||||||
|
::UnregisterClassW((LPCWSTR)data->instance_name.data(), data->instance_handle);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NextEvent(MSG& message, UINT timeout)
|
||||||
|
{
|
||||||
|
if (timeout != 0)
|
||||||
|
{
|
||||||
|
UINT_PTR timer_id = SetTimer(NULL, 0, timeout, NULL);
|
||||||
|
BOOL res = GetMessage(&message, NULL, 0, 0);
|
||||||
|
KillTimer(NULL, timer_id);
|
||||||
|
if (message.message != WM_TIMER || message.hwnd != nullptr || message.wParam != timer_id)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return PeekMessage(&message, nullptr, 0, 0, PM_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
const float dp_ratio = GetDensityIndependentPixelRatio(data->window_handle);
|
||||||
|
context->SetDimensions(data->window_dimensions);
|
||||||
|
context->SetDensityIndependentPixelRatio(dp_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = context;
|
||||||
|
data->key_down_callback = key_down_callback;
|
||||||
|
|
||||||
|
MSG message;
|
||||||
|
bool has_message = NextEvent(message, power_save ? static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000.0) : 0);
|
||||||
|
while (has_message)
|
||||||
|
{
|
||||||
|
// Dispatch the message to our local event handler below.
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessage(&message);
|
||||||
|
|
||||||
|
has_message = NextEvent(message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = nullptr;
|
||||||
|
data->key_down_callback = nullptr;
|
||||||
|
|
||||||
|
const bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
data->render_interface.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
|
||||||
|
// Flips the OpenGL buffers.
|
||||||
|
SwapBuffers(data->device_context);
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local event handler for window and input events.
|
||||||
|
static LRESULT CALLBACK WindowProcedureHandler(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
{
|
||||||
|
data->running = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_SIZE:
|
||||||
|
{
|
||||||
|
const int width = LOWORD(l_param);
|
||||||
|
const int height = HIWORD(l_param);
|
||||||
|
data->window_dimensions.x = width;
|
||||||
|
data->window_dimensions.y = height;
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
if (data->context)
|
||||||
|
data->context->SetDimensions(data->window_dimensions);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
{
|
||||||
|
RECT* new_pos = (RECT*)l_param;
|
||||||
|
SetWindowPos(window_handle, NULL, new_pos->left, new_pos->top, new_pos->right - new_pos->left, new_pos->bottom - new_pos->top,
|
||||||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
if (data->context && has_dpi_support)
|
||||||
|
data->context->SetDensityIndependentPixelRatio(GetDensityIndependentPixelRatio(window_handle));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
const Rml::Input::KeyIdentifier rml_key = RmlWin32::ConvertKey((int)w_param);
|
||||||
|
const int rml_modifier = RmlWin32::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDensityIndependentPixelRatio(window_handle);
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, true))
|
||||||
|
return 0;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlWin32::WindowProcedure(context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, false))
|
||||||
|
return 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Submit it to the platform handler for default input handling.
|
||||||
|
if (!RmlWin32::WindowProcedure(data->context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All unhandled messages go to DefWindowProc.
|
||||||
|
return DefWindowProc(window_handle, message, w_param, l_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize)
|
||||||
|
{
|
||||||
|
// Fill out the window class struct.
|
||||||
|
WNDCLASSW window_class;
|
||||||
|
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||||
|
window_class.lpfnWndProc = &WindowProcedureHandler; // Attach our local event handler.
|
||||||
|
window_class.cbClsExtra = 0;
|
||||||
|
window_class.cbWndExtra = 0;
|
||||||
|
window_class.hInstance = instance_handle;
|
||||||
|
window_class.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
|
||||||
|
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
|
window_class.hbrBackground = nullptr;
|
||||||
|
window_class.lpszMenuName = nullptr;
|
||||||
|
window_class.lpszClassName = name.data();
|
||||||
|
|
||||||
|
if (!RegisterClassW(&window_class))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to register window class");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND window_handle = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
|
||||||
|
name.data(), // Window class name.
|
||||||
|
name.data(), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 0, 0, // Window position.
|
||||||
|
0, 0, // Window size.
|
||||||
|
nullptr, nullptr, instance_handle, nullptr);
|
||||||
|
|
||||||
|
if (!window_handle)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to create window");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT window_dpi = GetWindowDpi(window_handle);
|
||||||
|
inout_width = (inout_width * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
inout_height = (inout_height * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
|
||||||
|
DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
|
||||||
|
DWORD extended_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||||
|
|
||||||
|
// Adjust the window size to take the edges into account.
|
||||||
|
RECT window_rect;
|
||||||
|
window_rect.top = 0;
|
||||||
|
window_rect.left = 0;
|
||||||
|
window_rect.right = inout_width;
|
||||||
|
window_rect.bottom = inout_height;
|
||||||
|
if (has_dpi_support)
|
||||||
|
procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
|
||||||
|
else
|
||||||
|
AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
|
||||||
|
|
||||||
|
SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
|
||||||
|
SetWindowLong(window_handle, GWL_STYLE, style);
|
||||||
|
|
||||||
|
// Resize the window and center it on the screen.
|
||||||
|
Rml::Vector2i screen_size = {GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
|
||||||
|
Rml::Vector2i window_size = {int(window_rect.right - window_rect.left), int(window_rect.bottom - window_rect.top)};
|
||||||
|
Rml::Vector2i window_pos = Rml::Math::Max((screen_size - window_size) / 2, Rml::Vector2i(0));
|
||||||
|
|
||||||
|
SetWindowPos(window_handle, HWND_TOP, window_pos.x, window_pos.y, window_size.x, window_size.y, SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
return window_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AttachToNative(HWND window_handle, HDC& out_device_context, HGLRC& out_render_context)
|
||||||
|
{
|
||||||
|
HDC device_context = GetDC(window_handle);
|
||||||
|
|
||||||
|
if (!device_context)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to get device context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR pixel_format_descriptor = {};
|
||||||
|
pixel_format_descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||||
|
pixel_format_descriptor.nVersion = 1;
|
||||||
|
pixel_format_descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||||
|
pixel_format_descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pixel_format_descriptor.cColorBits = 32;
|
||||||
|
pixel_format_descriptor.cRedBits = 8;
|
||||||
|
pixel_format_descriptor.cGreenBits = 8;
|
||||||
|
pixel_format_descriptor.cBlueBits = 8;
|
||||||
|
pixel_format_descriptor.cAlphaBits = 8;
|
||||||
|
pixel_format_descriptor.cDepthBits = 24;
|
||||||
|
pixel_format_descriptor.cStencilBits = 8;
|
||||||
|
|
||||||
|
int pixel_format = ChoosePixelFormat(device_context, &pixel_format_descriptor);
|
||||||
|
if (!pixel_format)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to choose 32-bit pixel format");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetPixelFormat(device_context, pixel_format, &pixel_format_descriptor))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to set pixel format");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC render_context = wglCreateContext(device_context);
|
||||||
|
if (!render_context)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to create OpenGL rendering context");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate the rendering context.
|
||||||
|
if (!wglMakeCurrent(device_context, render_context))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to make rendering context current");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_device_context = device_context;
|
||||||
|
out_render_context = render_context;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DetachFromNative(HWND window_handle, HDC device_context, HGLRC render_context)
|
||||||
|
{
|
||||||
|
// Shutdown OpenGL
|
||||||
|
if (render_context)
|
||||||
|
{
|
||||||
|
wglMakeCurrent(nullptr, nullptr);
|
||||||
|
wglDeleteContext(render_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_context)
|
||||||
|
{
|
||||||
|
ReleaseDC(window_handle, device_context);
|
||||||
|
}
|
||||||
|
}
|
||||||
395
vendor/rmlui_backend/RmlUi_Backend_Win32_VK.cpp
vendored
Normal file
395
vendor/rmlui_backend/RmlUi_Backend_Win32_VK.cpp
vendored
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include "RmlUi_Platform_Win32.h"
|
||||||
|
#include "RmlUi_Renderer_VK.h"
|
||||||
|
#include <RmlUi/Config/Config.h>
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Profiling.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
High DPI support using Windows Per Monitor V2 DPI awareness.
|
||||||
|
|
||||||
|
Requires Windows 10, version 1703.
|
||||||
|
*/
|
||||||
|
#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
|
||||||
|
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
|
||||||
|
#endif
|
||||||
|
#ifndef WM_DPICHANGED
|
||||||
|
#define WM_DPICHANGED 0x02E0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Declare pointers to the DPI aware Windows API functions.
|
||||||
|
using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
|
||||||
|
using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
|
||||||
|
using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
|
||||||
|
|
||||||
|
static bool has_dpi_support = false;
|
||||||
|
static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
|
||||||
|
static ProcGetDpiForWindow procGetDpiForWindow = NULL;
|
||||||
|
static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
|
||||||
|
|
||||||
|
// Make ourselves DPI aware on supported Windows versions.
|
||||||
|
static void InitializeDpiSupport()
|
||||||
|
{
|
||||||
|
// Cast function pointers to void* first for MinGW not to emit errors.
|
||||||
|
procSetProcessDpiAwarenessContext =
|
||||||
|
(ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "SetProcessDpiAwarenessContext");
|
||||||
|
procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "GetDpiForWindow");
|
||||||
|
procAdjustWindowRectExForDpi =
|
||||||
|
(ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(GetModuleHandle(TEXT("User32.dll")), "AdjustWindowRectExForDpi");
|
||||||
|
|
||||||
|
if (!has_dpi_support && procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL)
|
||||||
|
{
|
||||||
|
// Activate Per Monitor V2.
|
||||||
|
if (procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
|
||||||
|
has_dpi_support = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT GetWindowDpi(HWND window_handle)
|
||||||
|
{
|
||||||
|
if (has_dpi_support)
|
||||||
|
{
|
||||||
|
UINT dpi = procGetDpiForWindow(window_handle);
|
||||||
|
if (dpi != 0)
|
||||||
|
return dpi;
|
||||||
|
}
|
||||||
|
return USER_DEFAULT_SCREEN_DPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float GetDensityIndependentPixelRatio(HWND window_handle)
|
||||||
|
{
|
||||||
|
return float(GetWindowDpi(window_handle)) / float(USER_DEFAULT_SCREEN_DPI);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the window but don't show it yet. Returns the pixel size of the window, which may be different than the passed size due to DPI settings.
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize);
|
||||||
|
// Create the Win32 Vulkan surface.
|
||||||
|
static bool CreateVulkanSurface(VkInstance instance, VkSurfaceKHR* out_surface);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
SystemInterface_Win32 system_interface;
|
||||||
|
RenderInterface_VK render_interface;
|
||||||
|
TextInputMethodEditor_Win32 text_input_method_editor;
|
||||||
|
|
||||||
|
HINSTANCE instance_handle = nullptr;
|
||||||
|
std::wstring instance_name;
|
||||||
|
HWND window_handle = nullptr;
|
||||||
|
|
||||||
|
bool context_dimensions_dirty = true;
|
||||||
|
Rml::Vector2i window_dimensions;
|
||||||
|
bool running = 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* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
const std::wstring name = RmlWin32::ConvertToUTF16(Rml::String(window_name));
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>();
|
||||||
|
|
||||||
|
data->instance_handle = GetModuleHandle(nullptr);
|
||||||
|
data->instance_name = name;
|
||||||
|
|
||||||
|
InitializeDpiSupport();
|
||||||
|
|
||||||
|
// Initialize the window but don't show it yet.
|
||||||
|
HWND window_handle = InitializeWindow(data->instance_handle, name, width, height, allow_resize);
|
||||||
|
if (!window_handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data->window_handle = window_handle;
|
||||||
|
|
||||||
|
Rml::Vector<const char*> extensions;
|
||||||
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
if (!data->render_interface.Initialize(std::move(extensions), CreateVulkanSurface))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to initialize Vulkan render interface");
|
||||||
|
::CloseWindow(window_handle);
|
||||||
|
data.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->system_interface.SetWindow(window_handle);
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
|
||||||
|
// Now we are ready to show the window.
|
||||||
|
::ShowWindow(window_handle, SW_SHOW);
|
||||||
|
::SetForegroundWindow(window_handle);
|
||||||
|
::SetFocus(window_handle);
|
||||||
|
|
||||||
|
// Provide a backend-specific text input handler to manage the IME.
|
||||||
|
Rml::SetTextInputHandler(&data->text_input_method_editor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
// As we forcefully override the global text input handler, we must reset it before the data is destroyed to avoid any potential use-after-free.
|
||||||
|
if (Rml::GetTextInputHandler() == &data->text_input_method_editor)
|
||||||
|
Rml::SetTextInputHandler(nullptr);
|
||||||
|
|
||||||
|
data->render_interface.Shutdown();
|
||||||
|
|
||||||
|
::DestroyWindow(data->window_handle);
|
||||||
|
::UnregisterClassW((LPCWSTR)data->instance_name.data(), data->instance_handle);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool NextEvent(MSG& message, UINT timeout)
|
||||||
|
{
|
||||||
|
if (timeout != 0)
|
||||||
|
{
|
||||||
|
UINT_PTR timer_id = SetTimer(NULL, 0, timeout, NULL);
|
||||||
|
BOOL res = GetMessage(&message, NULL, 0, 0);
|
||||||
|
KillTimer(NULL, timer_id);
|
||||||
|
if (message.message != WM_TIMER || message.hwnd != nullptr || message.wParam != timer_id)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return PeekMessage(&message, nullptr, 0, 0, PM_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
const float dp_ratio = GetDensityIndependentPixelRatio(data->window_handle);
|
||||||
|
context->SetDimensions(data->window_dimensions);
|
||||||
|
context->SetDensityIndependentPixelRatio(dp_ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = context;
|
||||||
|
data->key_down_callback = key_down_callback;
|
||||||
|
|
||||||
|
MSG message;
|
||||||
|
// Process events.
|
||||||
|
bool has_message = NextEvent(message, power_save ? static_cast<int>(Rml::Math::Min(context->GetNextUpdateDelay(), 10.0) * 1000.0) : 0);
|
||||||
|
while (has_message || !data->render_interface.IsSwapchainValid())
|
||||||
|
{
|
||||||
|
if (has_message)
|
||||||
|
{
|
||||||
|
// Dispatch the message to our local event handler below.
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In some situations the swapchain may become invalid, such as when the window is minimized. In this state the renderer cannot accept any
|
||||||
|
// render calls. Since we don't have full control over the main loop here we may risk calls to Context::Render if we were to return. Instead,
|
||||||
|
// we trap the application inside this loop until we are able to recreate the swapchain and render again.
|
||||||
|
if (!data->render_interface.IsSwapchainValid())
|
||||||
|
data->render_interface.RecreateSwapchain();
|
||||||
|
|
||||||
|
has_message = NextEvent(message, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->context = nullptr;
|
||||||
|
data->key_down_callback = nullptr;
|
||||||
|
|
||||||
|
return data->running;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
|
||||||
|
// Optional, used to mark frames during performance profiling.
|
||||||
|
RMLUI_FrameMark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local event handler for window and input events.
|
||||||
|
static LRESULT CALLBACK WindowProcedureHandler(HWND window_handle, UINT message, WPARAM w_param, LPARAM l_param)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
{
|
||||||
|
data->running = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_SIZE:
|
||||||
|
{
|
||||||
|
const int width = LOWORD(l_param);
|
||||||
|
const int height = HIWORD(l_param);
|
||||||
|
data->window_dimensions.x = width;
|
||||||
|
data->window_dimensions.y = height;
|
||||||
|
if (data->context)
|
||||||
|
{
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
data->context->SetDimensions(data->window_dimensions);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
{
|
||||||
|
RECT* new_pos = (RECT*)l_param;
|
||||||
|
SetWindowPos(window_handle, NULL, new_pos->left, new_pos->top, new_pos->right - new_pos->left, new_pos->bottom - new_pos->top,
|
||||||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
if (data->context && has_dpi_support)
|
||||||
|
data->context->SetDensityIndependentPixelRatio(GetDensityIndependentPixelRatio(window_handle));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
const Rml::Input::KeyIdentifier rml_key = RmlWin32::ConvertKey((int)w_param);
|
||||||
|
const int rml_modifier = RmlWin32::GetKeyModifierState();
|
||||||
|
const float native_dp_ratio = GetDensityIndependentPixelRatio(window_handle);
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, true))
|
||||||
|
return 0;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlWin32::WindowProcedure(context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
// The key was not consumed by the context either, try keyboard shortcuts of lower priority.
|
||||||
|
if (key_down_callback && !key_down_callback(context, rml_key, rml_modifier, native_dp_ratio, false))
|
||||||
|
return 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Submit it to the platform handler for default input handling.
|
||||||
|
if (!RmlWin32::WindowProcedure(data->context, data->text_input_method_editor, window_handle, message, w_param, l_param))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All unhandled messages go to DefWindowProc.
|
||||||
|
return DefWindowProc(window_handle, message, w_param, l_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HWND InitializeWindow(HINSTANCE instance_handle, const std::wstring& name, int& inout_width, int& inout_height, bool allow_resize)
|
||||||
|
{
|
||||||
|
// Fill out the window class struct.
|
||||||
|
WNDCLASSW window_class;
|
||||||
|
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||||
|
window_class.lpfnWndProc = &WindowProcedureHandler; // Attach our local event handler.
|
||||||
|
window_class.cbClsExtra = 0;
|
||||||
|
window_class.cbWndExtra = 0;
|
||||||
|
window_class.hInstance = instance_handle;
|
||||||
|
window_class.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
|
||||||
|
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
|
window_class.hbrBackground = nullptr;
|
||||||
|
window_class.lpszMenuName = nullptr;
|
||||||
|
window_class.lpszClassName = name.data();
|
||||||
|
|
||||||
|
if (!RegisterClassW(&window_class))
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to register window class");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND window_handle = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
|
||||||
|
name.data(), // Window class name.
|
||||||
|
name.data(), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 0, 0, // Window position.
|
||||||
|
0, 0, // Window size.
|
||||||
|
nullptr, nullptr, instance_handle, nullptr);
|
||||||
|
|
||||||
|
if (!window_handle)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to create window");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT window_dpi = GetWindowDpi(window_handle);
|
||||||
|
inout_width = (inout_width * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
inout_height = (inout_height * (int)window_dpi) / USER_DEFAULT_SCREEN_DPI;
|
||||||
|
|
||||||
|
DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
|
||||||
|
DWORD extended_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
|
||||||
|
|
||||||
|
// Adjust the window size to take the edges into account.
|
||||||
|
RECT window_rect;
|
||||||
|
window_rect.top = 0;
|
||||||
|
window_rect.left = 0;
|
||||||
|
window_rect.right = inout_width;
|
||||||
|
window_rect.bottom = inout_height;
|
||||||
|
if (has_dpi_support)
|
||||||
|
procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
|
||||||
|
else
|
||||||
|
AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
|
||||||
|
|
||||||
|
SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
|
||||||
|
SetWindowLong(window_handle, GWL_STYLE, style);
|
||||||
|
|
||||||
|
// Resize the window and center it on the screen.
|
||||||
|
Rml::Vector2i screen_size = {GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
|
||||||
|
Rml::Vector2i window_size = {int(window_rect.right - window_rect.left), int(window_rect.bottom - window_rect.top)};
|
||||||
|
Rml::Vector2i window_pos = Rml::Math::Max((screen_size - window_size) / 2, Rml::Vector2i(0));
|
||||||
|
|
||||||
|
SetWindowPos(window_handle, HWND_TOP, window_pos.x, window_pos.y, window_size.x, window_size.y, SWP_NOACTIVATE);
|
||||||
|
|
||||||
|
return window_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateVulkanSurface(VkInstance instance, VkSurfaceKHR* out_surface)
|
||||||
|
{
|
||||||
|
VkWin32SurfaceCreateInfoKHR info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||||
|
info.hinstance = GetModuleHandle(NULL);
|
||||||
|
info.hwnd = data->window_handle;
|
||||||
|
|
||||||
|
VkResult status = vkCreateWin32SurfaceKHR(instance, &info, nullptr, out_surface);
|
||||||
|
|
||||||
|
bool result = (status == VK_SUCCESS);
|
||||||
|
RMLUI_VK_ASSERTMSG(result, "Failed to create Win32 Vulkan surface");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
292
vendor/rmlui_backend/RmlUi_Backend_X11_GL2.cpp
vendored
Normal file
292
vendor/rmlui_backend/RmlUi_Backend_X11_GL2.cpp
vendored
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
#include "RmlUi_Backend.h"
|
||||||
|
#include "RmlUi_Include_Xlib.h"
|
||||||
|
#include "RmlUi_Platform_X11.h"
|
||||||
|
#include "RmlUi_Renderer_GL2.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Debug.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/cursorfont.h>
|
||||||
|
#include <X11/extensions/xf86vmode.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Attach the OpenGL context to the window.
|
||||||
|
static bool AttachToNative(GLXContext& out_gl_context, Display* display, Window window, XVisualInfo* visual_info)
|
||||||
|
{
|
||||||
|
GLXContext gl_context = glXCreateContext(display, visual_info, nullptr, GL_TRUE);
|
||||||
|
if (!gl_context)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!glXMakeCurrent(display, window, gl_context))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!glXIsDirect(display, gl_context))
|
||||||
|
Rml::Log::Message(Rml::Log::LT_INFO, "OpenGL context does not support direct rendering; performance is likely to be poor.");
|
||||||
|
|
||||||
|
out_gl_context = gl_context;
|
||||||
|
|
||||||
|
Window root_window;
|
||||||
|
int x, y;
|
||||||
|
unsigned int width, height;
|
||||||
|
unsigned int border_width, depth;
|
||||||
|
XGetGeometry(display, window, &root_window, &x, &y, &width, &height, &border_width, &depth);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown the OpenGL context.
|
||||||
|
static void DetachFromNative(GLXContext gl_context, Display* display)
|
||||||
|
{
|
||||||
|
glXMakeCurrent(display, 0L, nullptr);
|
||||||
|
glXDestroyContext(display, gl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Global data used by this backend.
|
||||||
|
|
||||||
|
Lifetime governed by the calls to Backend::Initialize() and Backend::Shutdown().
|
||||||
|
*/
|
||||||
|
struct BackendData {
|
||||||
|
BackendData(Display* display) : system_interface(display) {}
|
||||||
|
|
||||||
|
SystemInterface_X11 system_interface;
|
||||||
|
RenderInterface_GL2 render_interface;
|
||||||
|
|
||||||
|
Display* display = nullptr;
|
||||||
|
Window window = 0;
|
||||||
|
GLXContext gl_context = nullptr;
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
|
static Rml::UniquePtr<BackendData> data;
|
||||||
|
|
||||||
|
bool Backend::Initialize(const char* window_name, int width, int height, bool allow_resize)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!data);
|
||||||
|
|
||||||
|
Display* display = XOpenDisplay(0);
|
||||||
|
if (!display)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int screen = XDefaultScreen(display);
|
||||||
|
|
||||||
|
// Fetch an appropriate 32-bit visual interface.
|
||||||
|
int attribute_list[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8,
|
||||||
|
0L};
|
||||||
|
|
||||||
|
XVisualInfo* visual_info = glXChooseVisual(display, screen, attribute_list);
|
||||||
|
if (!visual_info)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Build up our window attributes.
|
||||||
|
XSetWindowAttributes window_attributes;
|
||||||
|
window_attributes.colormap = XCreateColormap(display, RootWindow(display, visual_info->screen), visual_info->visual, AllocNone);
|
||||||
|
window_attributes.border_pixel = 0;
|
||||||
|
window_attributes.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask;
|
||||||
|
|
||||||
|
// Create the window.
|
||||||
|
Window window = XCreateWindow(display, RootWindow(display, visual_info->screen), 0, 0, width, height, 0, visual_info->depth, InputOutput,
|
||||||
|
visual_info->visual, CWBorderPixel | CWColormap | CWEventMask, &window_attributes);
|
||||||
|
|
||||||
|
// Handle delete events in windowed mode.
|
||||||
|
Atom delete_atom = XInternAtom(display, "WM_DELETE_WINDOW", True);
|
||||||
|
XSetWMProtocols(display, window, &delete_atom, 1);
|
||||||
|
|
||||||
|
// Capture the events we're interested in.
|
||||||
|
XSelectInput(display, window,
|
||||||
|
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | LeaveWindowMask | PointerMotionMask | StructureNotifyMask);
|
||||||
|
|
||||||
|
if (!allow_resize)
|
||||||
|
{
|
||||||
|
// Force the window to remain at the fixed size by asking the window manager nicely, it may choose to ignore us
|
||||||
|
XSizeHints* win_size_hints = XAllocSizeHints(); // Allocate a size hint structure
|
||||||
|
if (!win_size_hints)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "XAllocSizeHints - out of memory");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Initialize the structure and specify which hints will be providing
|
||||||
|
win_size_hints->flags = PSize | PMinSize | PMaxSize;
|
||||||
|
|
||||||
|
// Set the sizes we want the window manager to use
|
||||||
|
win_size_hints->base_width = width;
|
||||||
|
win_size_hints->base_height = height;
|
||||||
|
win_size_hints->min_width = width;
|
||||||
|
win_size_hints->min_height = height;
|
||||||
|
win_size_hints->max_width = width;
|
||||||
|
win_size_hints->max_height = height;
|
||||||
|
|
||||||
|
// Pass the size hints to the window manager.
|
||||||
|
XSetWMNormalHints(display, window, win_size_hints);
|
||||||
|
|
||||||
|
// Free the size buffer
|
||||||
|
XFree(win_size_hints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the window title and show the window.
|
||||||
|
XSetStandardProperties(display, window, window_name, "", 0L, nullptr, 0, nullptr);
|
||||||
|
XMapRaised(display, window);
|
||||||
|
|
||||||
|
GLXContext gl_context = {};
|
||||||
|
if (!AttachToNative(gl_context, display, window, visual_info))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data = Rml::MakeUnique<BackendData>(display);
|
||||||
|
|
||||||
|
data->display = display;
|
||||||
|
data->window = window;
|
||||||
|
data->gl_context = gl_context;
|
||||||
|
|
||||||
|
data->system_interface.SetWindow(window);
|
||||||
|
data->render_interface.SetViewport(width, height);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::Shutdown()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
|
||||||
|
DetachFromNative(data->gl_context, data->display);
|
||||||
|
XCloseDisplay(data->display);
|
||||||
|
|
||||||
|
data.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::SystemInterface* Backend::GetSystemInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->system_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::RenderInterface* Backend::GetRenderInterface()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
return &data->render_interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEvents(Rml::Context* context, KeyDownCallback key_down_callback, bool power_save)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data && context);
|
||||||
|
|
||||||
|
Display* display = data->display;
|
||||||
|
bool result = data->running;
|
||||||
|
data->running = true;
|
||||||
|
|
||||||
|
if (power_save && XPending(display) == 0)
|
||||||
|
{
|
||||||
|
int display_fd = ConnectionNumber(display);
|
||||||
|
fd_set fds{};
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(display_fd, &fds);
|
||||||
|
|
||||||
|
double timeout = Rml::Math::Min(context->GetNextUpdateDelay(), 10.0);
|
||||||
|
struct timeval tv {};
|
||||||
|
double seconds;
|
||||||
|
tv.tv_usec = std::modf(timeout, &seconds) * 1000000.0;
|
||||||
|
tv.tv_sec = seconds;
|
||||||
|
|
||||||
|
int ready_fd_count;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ready_fd_count = select(display_fd + 1, &fds, NULL, NULL, &tv);
|
||||||
|
// We don't care about the return value as long as select didn't error out
|
||||||
|
RMLUI_ASSERT(ready_fd_count >= 0);
|
||||||
|
} while (XPending(display) == 0 && ready_fd_count != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (XPending(display) > 0)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
XNextEvent(display, &ev);
|
||||||
|
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case ClientMessage:
|
||||||
|
{
|
||||||
|
// The only message we register for is WM_DELETE_WINDOW, so if we receive a client message then the window has been closed.
|
||||||
|
char* event_type = XGetAtomName(display, ev.xclient.message_type);
|
||||||
|
if (strcmp(event_type, "WM_PROTOCOLS") == 0)
|
||||||
|
data->running = false;
|
||||||
|
XFree(event_type);
|
||||||
|
event_type = nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ConfigureNotify:
|
||||||
|
{
|
||||||
|
int x = ev.xconfigure.width;
|
||||||
|
int y = ev.xconfigure.height;
|
||||||
|
|
||||||
|
context->SetDimensions({x, y});
|
||||||
|
data->render_interface.SetViewport(x, y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
{
|
||||||
|
Rml::Input::KeyIdentifier key = RmlX11::ConvertKey(display, ev.xkey.keycode);
|
||||||
|
const int key_modifier = RmlX11::GetKeyModifierState(ev.xkey.state);
|
||||||
|
const float native_dp_ratio = 1.f;
|
||||||
|
|
||||||
|
// See if we have any global shortcuts that take priority over the context.
|
||||||
|
if (key_down_callback && !key_down_callback(context, key, key_modifier, native_dp_ratio, true))
|
||||||
|
break;
|
||||||
|
// Otherwise, hand the event over to the context by calling the input handler as normal.
|
||||||
|
if (!RmlX11::HandleInputEvent(context, display, ev))
|
||||||
|
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, native_dp_ratio, false))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SelectionRequest:
|
||||||
|
{
|
||||||
|
data->system_interface.HandleSelectionRequest(ev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// Pass unhandled events to the platform layer's input handler.
|
||||||
|
RmlX11::HandleInputEvent(context, display, ev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::RequestExit()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::BeginFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.BeginFrame();
|
||||||
|
data->render_interface.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Backend::PresentFrame()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(data);
|
||||||
|
data->render_interface.EndFrame();
|
||||||
|
|
||||||
|
// Flips the OpenGL buffers.
|
||||||
|
glXSwapBuffers(data->display, data->window);
|
||||||
|
}
|
||||||
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
|
||||||
2
vendor/rmlui_backend/RmlUi_DirectX/.clang-format
vendored
Normal file
2
vendor/rmlui_backend/RmlUi_DirectX/.clang-format
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
10247
vendor/rmlui_backend/RmlUi_DirectX/D3D12MemAlloc.cpp
vendored
Normal file
10247
vendor/rmlui_backend/RmlUi_DirectX/D3D12MemAlloc.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2533
vendor/rmlui_backend/RmlUi_DirectX/D3D12MemAlloc.h
vendored
Normal file
2533
vendor/rmlui_backend/RmlUi_DirectX/D3D12MemAlloc.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
74
vendor/rmlui_backend/RmlUi_DirectX/LICENSE.txt
vendored
Normal file
74
vendor/rmlui_backend/RmlUi_DirectX/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
The RmlUi DirectX 12 renderer includes thirdparty code with the following licenses.
|
||||||
|
|
||||||
|
|
||||||
|
----- D3D12MemAlloc.cpp/.h -----
|
||||||
|
|
||||||
|
Copyright (c) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
----- offsetAllocator.cpp/.hpp -----
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Sebastian Aaltonen
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
----- Snippets from d3dx12.h header (included directly in RmlUi_Renderer_DX12.cpp) -----
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft
|
||||||
|
|
||||||
|
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.
|
||||||
513
vendor/rmlui_backend/RmlUi_DirectX/offsetAllocator.cpp
vendored
Normal file
513
vendor/rmlui_backend/RmlUi_DirectX/offsetAllocator.cpp
vendored
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
// (C) Sebastian Aaltonen 2023
|
||||||
|
// MIT License (see file: LICENSE)
|
||||||
|
|
||||||
|
#include "offsetAllocator.hpp"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define ASSERT(x) assert(x)
|
||||||
|
//#define DEBUG_VERBOSE
|
||||||
|
#else
|
||||||
|
#define ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace OffsetAllocator
|
||||||
|
{
|
||||||
|
inline uint32 lzcnt_nonzero(uint32 v)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
unsigned long retVal;
|
||||||
|
_BitScanReverse(&retVal, v);
|
||||||
|
return 31 - retVal;
|
||||||
|
#else
|
||||||
|
return __builtin_clz(v);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 tzcnt_nonzero(uint32 v)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
unsigned long retVal;
|
||||||
|
_BitScanForward(&retVal, v);
|
||||||
|
return retVal;
|
||||||
|
#else
|
||||||
|
return __builtin_ctz(v);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace SmallFloat
|
||||||
|
{
|
||||||
|
static constexpr uint32 MANTISSA_BITS = 3;
|
||||||
|
static constexpr uint32 MANTISSA_VALUE = 1 << MANTISSA_BITS;
|
||||||
|
static constexpr uint32 MANTISSA_MASK = MANTISSA_VALUE - 1;
|
||||||
|
|
||||||
|
// Bin sizes follow floating point (exponent + mantissa) distribution (piecewise linear log approx)
|
||||||
|
// This ensures that for each size class, the average overhead percentage stays the same
|
||||||
|
uint32 uintToFloatRoundUp(uint32 size)
|
||||||
|
{
|
||||||
|
uint32 exp = 0;
|
||||||
|
uint32 mantissa = 0;
|
||||||
|
|
||||||
|
if (size < MANTISSA_VALUE)
|
||||||
|
{
|
||||||
|
// Denorm: 0..(MANTISSA_VALUE-1)
|
||||||
|
mantissa = size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normalized: Hidden high bit always 1. Not stored. Just like float.
|
||||||
|
uint32 leadingZeros = lzcnt_nonzero(size);
|
||||||
|
uint32 highestSetBit = 31 - leadingZeros;
|
||||||
|
|
||||||
|
uint32 mantissaStartBit = highestSetBit - MANTISSA_BITS;
|
||||||
|
exp = mantissaStartBit + 1;
|
||||||
|
mantissa = (size >> mantissaStartBit) & MANTISSA_MASK;
|
||||||
|
|
||||||
|
uint32 lowBitsMask = (1 << mantissaStartBit) - 1;
|
||||||
|
|
||||||
|
// Round up!
|
||||||
|
if ((size & lowBitsMask) != 0)
|
||||||
|
mantissa++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (exp << MANTISSA_BITS) + mantissa; // + allows mantissa->exp overflow for round up
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 uintToFloatRoundDown(uint32 size)
|
||||||
|
{
|
||||||
|
uint32 exp = 0;
|
||||||
|
uint32 mantissa = 0;
|
||||||
|
|
||||||
|
if (size < MANTISSA_VALUE)
|
||||||
|
{
|
||||||
|
// Denorm: 0..(MANTISSA_VALUE-1)
|
||||||
|
mantissa = size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normalized: Hidden high bit always 1. Not stored. Just like float.
|
||||||
|
uint32 leadingZeros = lzcnt_nonzero(size);
|
||||||
|
uint32 highestSetBit = 31 - leadingZeros;
|
||||||
|
|
||||||
|
uint32 mantissaStartBit = highestSetBit - MANTISSA_BITS;
|
||||||
|
exp = mantissaStartBit + 1;
|
||||||
|
mantissa = (size >> mantissaStartBit) & MANTISSA_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (exp << MANTISSA_BITS) | mantissa;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 floatToUint(uint32 floatValue)
|
||||||
|
{
|
||||||
|
uint32 exponent = floatValue >> MANTISSA_BITS;
|
||||||
|
uint32 mantissa = floatValue & MANTISSA_MASK;
|
||||||
|
if (exponent == 0)
|
||||||
|
{
|
||||||
|
// Denorms
|
||||||
|
return mantissa;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (mantissa | MANTISSA_VALUE) << (exponent - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
uint32 findLowestSetBitAfter(uint32 bitMask, uint32 startBitIndex)
|
||||||
|
{
|
||||||
|
uint32 maskBeforeStartIndex = (1 << startBitIndex) - 1;
|
||||||
|
uint32 maskAfterStartIndex = ~maskBeforeStartIndex;
|
||||||
|
uint32 bitsAfter = bitMask & maskAfterStartIndex;
|
||||||
|
if (bitsAfter == 0) return Allocation::NO_SPACE;
|
||||||
|
return tzcnt_nonzero(bitsAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocator...
|
||||||
|
Allocator::Allocator(uint32 size, uint32 maxAllocs) :
|
||||||
|
m_size(size),
|
||||||
|
m_maxAllocs(maxAllocs),
|
||||||
|
m_nodes(nullptr),
|
||||||
|
m_freeNodes(nullptr)
|
||||||
|
{
|
||||||
|
if (sizeof(NodeIndex) == 2)
|
||||||
|
{
|
||||||
|
ASSERT(maxAllocs <= 65536);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator::Allocator(Allocator &&other) :
|
||||||
|
m_size(other.m_size),
|
||||||
|
m_maxAllocs(other.m_maxAllocs),
|
||||||
|
m_freeStorage(other.m_freeStorage),
|
||||||
|
m_usedBinsTop(other.m_usedBinsTop),
|
||||||
|
m_nodes(other.m_nodes),
|
||||||
|
m_freeNodes(other.m_freeNodes),
|
||||||
|
m_freeOffset(other.m_freeOffset)
|
||||||
|
{
|
||||||
|
memcpy(m_usedBins, other.m_usedBins, sizeof(uint8) * NUM_TOP_BINS);
|
||||||
|
memcpy(m_binIndices, other.m_binIndices, sizeof(NodeIndex) * NUM_LEAF_BINS);
|
||||||
|
|
||||||
|
other.m_nodes = nullptr;
|
||||||
|
other.m_freeNodes = nullptr;
|
||||||
|
other.m_freeOffset = 0;
|
||||||
|
other.m_maxAllocs = 0;
|
||||||
|
other.m_usedBinsTop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Allocator::reset()
|
||||||
|
{
|
||||||
|
m_freeStorage = 0;
|
||||||
|
m_usedBinsTop = 0;
|
||||||
|
m_freeOffset = m_maxAllocs - 1;
|
||||||
|
|
||||||
|
for (uint32 i = 0 ; i < NUM_TOP_BINS; i++)
|
||||||
|
m_usedBins[i] = 0;
|
||||||
|
|
||||||
|
for (uint32 i = 0 ; i < NUM_LEAF_BINS; i++)
|
||||||
|
m_binIndices[i] = Node::unused;
|
||||||
|
|
||||||
|
if (m_nodes) delete[] m_nodes;
|
||||||
|
if (m_freeNodes) delete[] m_freeNodes;
|
||||||
|
|
||||||
|
m_nodes = new Node[m_maxAllocs];
|
||||||
|
m_freeNodes = new NodeIndex[m_maxAllocs];
|
||||||
|
|
||||||
|
// Freelist is a stack. Nodes in inverse order so that [0] pops first.
|
||||||
|
for (uint32 i = 0; i < m_maxAllocs; i++)
|
||||||
|
{
|
||||||
|
m_freeNodes[i] = m_maxAllocs - i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start state: Whole storage as one big node
|
||||||
|
// Algorithm will split remainders and push them back as smaller nodes
|
||||||
|
insertNodeIntoBin(m_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator::~Allocator()
|
||||||
|
{
|
||||||
|
delete[] m_nodes;
|
||||||
|
delete[] m_freeNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocation Allocator::allocate(uint32 size)
|
||||||
|
{
|
||||||
|
// Out of allocations?
|
||||||
|
if (m_freeOffset == 0)
|
||||||
|
{
|
||||||
|
Allocation result;
|
||||||
|
result.offset = Allocation::NO_SPACE;
|
||||||
|
result.metadata = Allocation::NO_SPACE;
|
||||||
|
//return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round up to bin index to ensure that alloc >= bin
|
||||||
|
// Gives us min bin index that fits the size
|
||||||
|
uint32 minBinIndex = SmallFloat::uintToFloatRoundUp(size);
|
||||||
|
|
||||||
|
uint32 minTopBinIndex = minBinIndex >> TOP_BINS_INDEX_SHIFT;
|
||||||
|
uint32 minLeafBinIndex = minBinIndex & LEAF_BINS_INDEX_MASK;
|
||||||
|
|
||||||
|
uint32 topBinIndex = minTopBinIndex;
|
||||||
|
uint32 leafBinIndex = Allocation::NO_SPACE;
|
||||||
|
|
||||||
|
// If top bin exists, scan its leaf bin. This can fail (NO_SPACE).
|
||||||
|
if (m_usedBinsTop & (1 << topBinIndex))
|
||||||
|
{
|
||||||
|
leafBinIndex = findLowestSetBitAfter(m_usedBins[topBinIndex], minLeafBinIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find space in top bin, we search top bin from +1
|
||||||
|
if (leafBinIndex == Allocation::NO_SPACE)
|
||||||
|
{
|
||||||
|
topBinIndex = findLowestSetBitAfter(m_usedBinsTop, minTopBinIndex + 1);
|
||||||
|
|
||||||
|
// Out of space?
|
||||||
|
if (topBinIndex == Allocation::NO_SPACE)
|
||||||
|
{
|
||||||
|
Allocation result;
|
||||||
|
result.offset = Allocation::NO_SPACE;
|
||||||
|
result.metadata = Allocation::NO_SPACE;
|
||||||
|
//return {.offset = Allocation::NO_SPACE, .metadata = Allocation::NO_SPACE};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All leaf bins here fit the alloc, since the top bin was rounded up. Start leaf search from bit 0.
|
||||||
|
// NOTE: This search can't fail since at least one leaf bit was set because the top bit was set.
|
||||||
|
leafBinIndex = tzcnt_nonzero(m_usedBins[topBinIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 binIndex = (topBinIndex << TOP_BINS_INDEX_SHIFT) | leafBinIndex;
|
||||||
|
|
||||||
|
// Pop the top node of the bin. Bin top = node.next.
|
||||||
|
uint32 nodeIndex = m_binIndices[binIndex];
|
||||||
|
Node& node = m_nodes[nodeIndex];
|
||||||
|
uint32 nodeTotalSize = node.dataSize;
|
||||||
|
node.dataSize = size;
|
||||||
|
node.used = true;
|
||||||
|
m_binIndices[binIndex] = node.binListNext;
|
||||||
|
if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = Node::unused;
|
||||||
|
m_freeStorage -= nodeTotalSize;
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Free storage: %u (-%u) (allocate)\n", m_freeStorage, nodeTotalSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Bin empty?
|
||||||
|
if (m_binIndices[binIndex] == Node::unused)
|
||||||
|
{
|
||||||
|
// Remove a leaf bin mask bit
|
||||||
|
m_usedBins[topBinIndex] &= ~(1 << leafBinIndex);
|
||||||
|
|
||||||
|
// All leaf bins empty?
|
||||||
|
if (m_usedBins[topBinIndex] == 0)
|
||||||
|
{
|
||||||
|
// Remove a top bin mask bit
|
||||||
|
m_usedBinsTop &= ~(1 << topBinIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push back reminder N elements to a lower bin
|
||||||
|
uint32 reminderSize = nodeTotalSize - size;
|
||||||
|
if (reminderSize > 0)
|
||||||
|
{
|
||||||
|
uint32 newNodeIndex = insertNodeIntoBin(reminderSize, node.dataOffset + size);
|
||||||
|
|
||||||
|
// Link nodes next to each other so that we can merge them later if both are free
|
||||||
|
// And update the old next neighbor to point to the new node (in middle)
|
||||||
|
if (node.neighborNext != Node::unused) m_nodes[node.neighborNext].neighborPrev = newNodeIndex;
|
||||||
|
m_nodes[newNodeIndex].neighborPrev = nodeIndex;
|
||||||
|
m_nodes[newNodeIndex].neighborNext = node.neighborNext;
|
||||||
|
node.neighborNext = newNodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return {.offset = node.dataOffset, .metadata = nodeIndex};
|
||||||
|
Allocation result;
|
||||||
|
result.offset = node.dataOffset;
|
||||||
|
result.metadata = nodeIndex;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Allocator::free(Allocation allocation)
|
||||||
|
{
|
||||||
|
ASSERT(allocation.metadata != Allocation::NO_SPACE);
|
||||||
|
if (!m_nodes) return;
|
||||||
|
|
||||||
|
uint32 nodeIndex = allocation.metadata;
|
||||||
|
Node& node = m_nodes[nodeIndex];
|
||||||
|
|
||||||
|
// Double delete check
|
||||||
|
ASSERT(node.used == true);
|
||||||
|
|
||||||
|
// Merge with neighbors...
|
||||||
|
uint32 offset = node.dataOffset;
|
||||||
|
uint32 size = node.dataSize;
|
||||||
|
|
||||||
|
if ((node.neighborPrev != Node::unused) && (m_nodes[node.neighborPrev].used == false))
|
||||||
|
{
|
||||||
|
// Previous (contiguous) free node: Change offset to previous node offset. Sum sizes
|
||||||
|
Node& prevNode = m_nodes[node.neighborPrev];
|
||||||
|
offset = prevNode.dataOffset;
|
||||||
|
size += prevNode.dataSize;
|
||||||
|
|
||||||
|
// Remove node from the bin linked list and put it in the freelist
|
||||||
|
removeNodeFromBin(node.neighborPrev);
|
||||||
|
|
||||||
|
ASSERT(prevNode.neighborNext == nodeIndex);
|
||||||
|
node.neighborPrev = prevNode.neighborPrev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((node.neighborNext != Node::unused) && (m_nodes[node.neighborNext].used == false))
|
||||||
|
{
|
||||||
|
// Next (contiguous) free node: Offset remains the same. Sum sizes.
|
||||||
|
Node& nextNode = m_nodes[node.neighborNext];
|
||||||
|
size += nextNode.dataSize;
|
||||||
|
|
||||||
|
// Remove node from the bin linked list and put it in the freelist
|
||||||
|
removeNodeFromBin(node.neighborNext);
|
||||||
|
|
||||||
|
ASSERT(nextNode.neighborPrev == nodeIndex);
|
||||||
|
node.neighborNext = nextNode.neighborNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 neighborNext = node.neighborNext;
|
||||||
|
uint32 neighborPrev = node.neighborPrev;
|
||||||
|
|
||||||
|
// Insert the removed node to freelist
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Putting node %u into freelist[%u] (free)\n", nodeIndex, m_freeOffset + 1);
|
||||||
|
#endif
|
||||||
|
m_freeNodes[++m_freeOffset] = nodeIndex;
|
||||||
|
|
||||||
|
// Insert the (combined) free node to bin
|
||||||
|
uint32 combinedNodeIndex = insertNodeIntoBin(size, offset);
|
||||||
|
|
||||||
|
// Connect neighbors with the new combined node
|
||||||
|
if (neighborNext != Node::unused)
|
||||||
|
{
|
||||||
|
m_nodes[combinedNodeIndex].neighborNext = neighborNext;
|
||||||
|
m_nodes[neighborNext].neighborPrev = combinedNodeIndex;
|
||||||
|
}
|
||||||
|
if (neighborPrev != Node::unused)
|
||||||
|
{
|
||||||
|
m_nodes[combinedNodeIndex].neighborPrev = neighborPrev;
|
||||||
|
m_nodes[neighborPrev].neighborNext = combinedNodeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Allocator::insertNodeIntoBin(uint32 size, uint32 dataOffset)
|
||||||
|
{
|
||||||
|
// Round down to bin index to ensure that bin >= alloc
|
||||||
|
uint32 binIndex = SmallFloat::uintToFloatRoundDown(size);
|
||||||
|
|
||||||
|
uint32 topBinIndex = binIndex >> TOP_BINS_INDEX_SHIFT;
|
||||||
|
uint32 leafBinIndex = binIndex & LEAF_BINS_INDEX_MASK;
|
||||||
|
|
||||||
|
// Bin was empty before?
|
||||||
|
if (m_binIndices[binIndex] == Node::unused)
|
||||||
|
{
|
||||||
|
// Set bin mask bits
|
||||||
|
m_usedBins[topBinIndex] |= 1 << leafBinIndex;
|
||||||
|
m_usedBinsTop |= 1 << topBinIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a freelist node and insert on top of the bin linked list (next = old top)
|
||||||
|
uint32 topNodeIndex = m_binIndices[binIndex];
|
||||||
|
uint32 nodeIndex = m_freeNodes[m_freeOffset--];
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Getting node %u from freelist[%u]\n", nodeIndex, m_freeOffset + 1);
|
||||||
|
#endif
|
||||||
|
// m_nodes[nodeIndex] = {.dataOffset = dataOffset, .dataSize = size, .binListNext = topNodeIndex};
|
||||||
|
Node node_instance;
|
||||||
|
node_instance.dataOffset = dataOffset;
|
||||||
|
node_instance.dataSize = size;
|
||||||
|
node_instance.binListNext = topNodeIndex;
|
||||||
|
m_nodes[nodeIndex] = node_instance;
|
||||||
|
|
||||||
|
if (topNodeIndex != Node::unused) m_nodes[topNodeIndex].binListPrev = nodeIndex;
|
||||||
|
m_binIndices[binIndex] = nodeIndex;
|
||||||
|
|
||||||
|
m_freeStorage += size;
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Free storage: %u (+%u) (insertNodeIntoBin)\n", m_freeStorage, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return nodeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Allocator::removeNodeFromBin(uint32 nodeIndex)
|
||||||
|
{
|
||||||
|
Node &node = m_nodes[nodeIndex];
|
||||||
|
|
||||||
|
if (node.binListPrev != Node::unused)
|
||||||
|
{
|
||||||
|
// Easy case: We have previous node. Just remove this node from the middle of the list.
|
||||||
|
m_nodes[node.binListPrev].binListNext = node.binListNext;
|
||||||
|
if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = node.binListPrev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Hard case: We are the first node in a bin. Find the bin.
|
||||||
|
|
||||||
|
// Round down to bin index to ensure that bin >= alloc
|
||||||
|
uint32 binIndex = SmallFloat::uintToFloatRoundDown(node.dataSize);
|
||||||
|
|
||||||
|
uint32 topBinIndex = binIndex >> TOP_BINS_INDEX_SHIFT;
|
||||||
|
uint32 leafBinIndex = binIndex & LEAF_BINS_INDEX_MASK;
|
||||||
|
|
||||||
|
m_binIndices[binIndex] = node.binListNext;
|
||||||
|
if (node.binListNext != Node::unused) m_nodes[node.binListNext].binListPrev = Node::unused;
|
||||||
|
|
||||||
|
// Bin empty?
|
||||||
|
if (m_binIndices[binIndex] == Node::unused)
|
||||||
|
{
|
||||||
|
// Remove a leaf bin mask bit
|
||||||
|
m_usedBins[topBinIndex] &= ~(1 << leafBinIndex);
|
||||||
|
|
||||||
|
// All leaf bins empty?
|
||||||
|
if (m_usedBins[topBinIndex] == 0)
|
||||||
|
{
|
||||||
|
// Remove a top bin mask bit
|
||||||
|
m_usedBinsTop &= ~(1 << topBinIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the node to freelist
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Putting node %u into freelist[%u] (removeNodeFromBin)\n", nodeIndex, m_freeOffset + 1);
|
||||||
|
#endif
|
||||||
|
m_freeNodes[++m_freeOffset] = nodeIndex;
|
||||||
|
|
||||||
|
m_freeStorage -= node.dataSize;
|
||||||
|
#ifdef DEBUG_VERBOSE
|
||||||
|
printf("Free storage: %u (-%u) (removeNodeFromBin)\n", m_freeStorage, node.dataSize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Allocator::allocationSize(Allocation allocation) const
|
||||||
|
{
|
||||||
|
if (allocation.metadata == Allocation::NO_SPACE) return 0;
|
||||||
|
if (!m_nodes) return 0;
|
||||||
|
|
||||||
|
return m_nodes[allocation.metadata].dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageReport Allocator::storageReport() const
|
||||||
|
{
|
||||||
|
uint32 largestFreeRegion = 0;
|
||||||
|
uint32 freeStorage = 0;
|
||||||
|
|
||||||
|
// Out of allocations? -> Zero free space
|
||||||
|
if (m_freeOffset > 0)
|
||||||
|
{
|
||||||
|
freeStorage = m_freeStorage;
|
||||||
|
if (m_usedBinsTop)
|
||||||
|
{
|
||||||
|
uint32 topBinIndex = 31 - lzcnt_nonzero(m_usedBinsTop);
|
||||||
|
uint32 leafBinIndex = 31 - lzcnt_nonzero(m_usedBins[topBinIndex]);
|
||||||
|
largestFreeRegion = SmallFloat::floatToUint((topBinIndex << TOP_BINS_INDEX_SHIFT) | leafBinIndex);
|
||||||
|
ASSERT(freeStorage >= largestFreeRegion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return {.totalFreeSpace = freeStorage, .largestFreeRegion = largestFreeRegion};
|
||||||
|
StorageReport result;
|
||||||
|
result.totalFreeSpace = freeStorage;
|
||||||
|
result.largestFreeRegion = largestFreeRegion;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageReportFull Allocator::storageReportFull() const
|
||||||
|
{
|
||||||
|
StorageReportFull report;
|
||||||
|
StorageReportFull::Region region;
|
||||||
|
for (uint32 i = 0; i < NUM_LEAF_BINS; i++)
|
||||||
|
{
|
||||||
|
uint32 count = 0;
|
||||||
|
uint32 nodeIndex = m_binIndices[i];
|
||||||
|
while (nodeIndex != Node::unused)
|
||||||
|
{
|
||||||
|
nodeIndex = m_nodes[nodeIndex].binListNext;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
region.size = SmallFloat::floatToUint(i);
|
||||||
|
region.count = count;
|
||||||
|
// report.freeRegions[i] = { .size = SmallFloat::floatToUint(i), .count = count };
|
||||||
|
report.freeRegions[i] = region;
|
||||||
|
}
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
}
|
||||||
97
vendor/rmlui_backend/RmlUi_DirectX/offsetAllocator.hpp
vendored
Normal file
97
vendor/rmlui_backend/RmlUi_DirectX/offsetAllocator.hpp
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// (C) Sebastian Aaltonen 2023
|
||||||
|
// MIT License (see file: LICENSE)
|
||||||
|
|
||||||
|
//#define USE_16_BIT_OFFSETS
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace OffsetAllocator
|
||||||
|
{
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
|
||||||
|
// 16 bit offsets mode will halve the metadata storage cost
|
||||||
|
// But it only supports up to 65536 maximum allocation count
|
||||||
|
#ifdef USE_16_BIT_NODE_INDICES
|
||||||
|
typedef uint16 NodeIndex;
|
||||||
|
#else
|
||||||
|
typedef uint32 NodeIndex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr uint32 NUM_TOP_BINS = 32;
|
||||||
|
static constexpr uint32 BINS_PER_LEAF = 8;
|
||||||
|
static constexpr uint32 TOP_BINS_INDEX_SHIFT = 3;
|
||||||
|
static constexpr uint32 LEAF_BINS_INDEX_MASK = 0x7;
|
||||||
|
static constexpr uint32 NUM_LEAF_BINS = NUM_TOP_BINS * BINS_PER_LEAF;
|
||||||
|
|
||||||
|
struct Allocation
|
||||||
|
{
|
||||||
|
static constexpr uint32 NO_SPACE = 0xffffffff;
|
||||||
|
|
||||||
|
uint32 offset = NO_SPACE;
|
||||||
|
NodeIndex metadata = NO_SPACE; // internal: node index
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageReport
|
||||||
|
{
|
||||||
|
uint32 totalFreeSpace;
|
||||||
|
uint32 largestFreeRegion;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageReportFull
|
||||||
|
{
|
||||||
|
struct Region
|
||||||
|
{
|
||||||
|
uint32 size;
|
||||||
|
uint32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
Region freeRegions[NUM_LEAF_BINS];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Allocator(uint32 size, uint32 maxAllocs = 128 * 1024);
|
||||||
|
Allocator(Allocator &&other);
|
||||||
|
~Allocator();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Allocation allocate(uint32 size);
|
||||||
|
void free(Allocation allocation);
|
||||||
|
|
||||||
|
uint32 allocationSize(Allocation allocation) const;
|
||||||
|
StorageReport storageReport() const;
|
||||||
|
StorageReportFull storageReportFull() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 insertNodeIntoBin(uint32 size, uint32 dataOffset);
|
||||||
|
void removeNodeFromBin(uint32 nodeIndex);
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
static constexpr NodeIndex unused = 0xffffffff;
|
||||||
|
|
||||||
|
uint32 dataOffset = 0;
|
||||||
|
uint32 dataSize = 0;
|
||||||
|
NodeIndex binListPrev = unused;
|
||||||
|
NodeIndex binListNext = unused;
|
||||||
|
NodeIndex neighborPrev = unused;
|
||||||
|
NodeIndex neighborNext = unused;
|
||||||
|
bool used = false; // TODO: Merge as bit flag
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32 m_size;
|
||||||
|
uint32 m_maxAllocs;
|
||||||
|
uint32 m_freeStorage;
|
||||||
|
|
||||||
|
uint32 m_usedBinsTop;
|
||||||
|
uint8 m_usedBins[NUM_TOP_BINS];
|
||||||
|
NodeIndex m_binIndices[NUM_LEAF_BINS];
|
||||||
|
|
||||||
|
Node* m_nodes;
|
||||||
|
NodeIndex* m_freeNodes;
|
||||||
|
uint32 m_freeOffset;
|
||||||
|
};
|
||||||
|
}
|
||||||
284
vendor/rmlui_backend/RmlUi_Include_DirectX_12.h
vendored
Normal file
284
vendor/rmlui_backend/RmlUi_Include_DirectX_12.h
vendored
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined _MSC_VER
|
||||||
|
#pragma warning(push, 0)
|
||||||
|
#elif defined __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wall"
|
||||||
|
#pragma clang diagnostic ignored "-Wextra"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability-extension"
|
||||||
|
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability-completeness"
|
||||||
|
#elif defined __GNUC__
|
||||||
|
#pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "RmlUi_DirectX/D3D12MemAlloc.h"
|
||||||
|
#include "RmlUi_DirectX/offsetAllocator.hpp"
|
||||||
|
#include <bitset>
|
||||||
|
#include <chrono>
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <d3dcompiler.h>
|
||||||
|
#include <dxgi1_6.h>
|
||||||
|
|
||||||
|
namespace Rml {
|
||||||
|
inline constexpr const char* DXGIFormatToString(DXGI_FORMAT format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_UNKNOWN: return "DXGI_FORMAT_UNKNOWN";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_TYPELESS: return "DXGI_FORMAT_R32G32B32A32_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_FLOAT: return "DXGI_FORMAT_R32G32B32A32_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_UINT: return "DXGI_FORMAT_R32G32B32A32_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_SINT: return "DXGI_FORMAT_R32G32B32A32_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32_TYPELESS: return "DXGI_FORMAT_R32G32B32_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32_FLOAT: return "DXGI_FORMAT_R32G32B32_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32_UINT: return "DXGI_FORMAT_R32G32B32_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32B32_SINT: return "DXGI_FORMAT_R32G32B32_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_TYPELESS: return "DXGI_FORMAT_R16G16B16A16_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_FLOAT: return "DXGI_FORMAT_R16G16B16A16_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_UNORM: return "DXGI_FORMAT_R16G16B16A16_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_UINT: return "DXGI_FORMAT_R16G16B16A16_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_SNORM: return "DXGI_FORMAT_R16G16B16A16_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_SINT: return "DXGI_FORMAT_R16G16B16A16_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32_TYPELESS: return "DXGI_FORMAT_R32G32_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32_FLOAT: return "DXGI_FORMAT_R32G32_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32_UINT: return "DXGI_FORMAT_R32G32_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G32_SINT: return "DXGI_FORMAT_R32G32_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32G8X24_TYPELESS: return "DXGI_FORMAT_R32G8X24_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return "DXGI_FORMAT_D32_FLOAT_S8X24_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: return "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: return "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R10G10B10A2_TYPELESS: return "DXGI_FORMAT_R10G10B10A2_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R10G10B10A2_UNORM: return "DXGI_FORMAT_R10G10B10A2_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R10G10B10A2_UINT: return "DXGI_FORMAT_R10G10B10A2_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R11G11B10_FLOAT: return "DXGI_FORMAT_R11G11B10_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_TYPELESS: return "DXGI_FORMAT_R8G8B8A8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM: return "DXGI_FORMAT_R8G8B8A8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UINT: return "DXGI_FORMAT_R8G8B8A8_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_SNORM: return "DXGI_FORMAT_R8G8B8A8_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_SINT: return "DXGI_FORMAT_R8G8B8A8_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_TYPELESS: return "DXGI_FORMAT_R16G16_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_FLOAT: return "DXGI_FORMAT_R16G16_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_UNORM: return "DXGI_FORMAT_R16G16_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_UINT: return "DXGI_FORMAT_R16G16_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_SNORM: return "DXGI_FORMAT_R16G16_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16G16_SINT: return "DXGI_FORMAT_R16G16_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32_TYPELESS: return "DXGI_FORMAT_R32_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_D32_FLOAT: return "DXGI_FORMAT_D32_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32_FLOAT: return "DXGI_FORMAT_R32_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32_UINT: return "DXGI_FORMAT_R32_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R32_SINT: return "DXGI_FORMAT_R32_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R24G8_TYPELESS: return "DXGI_FORMAT_R24G8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_D24_UNORM_S8_UINT: return "DXGI_FORMAT_D24_UNORM_S8_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return "DXGI_FORMAT_R24_UNORM_X8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_X24_TYPELESS_G8_UINT: return "DXGI_FORMAT_X24_TYPELESS_G8_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_TYPELESS: return "DXGI_FORMAT_R8G8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_UNORM: return "DXGI_FORMAT_R8G8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_UINT: return "DXGI_FORMAT_R8G8_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_SNORM: return "DXGI_FORMAT_R8G8_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_SINT: return "DXGI_FORMAT_R8G8_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_TYPELESS: return "DXGI_FORMAT_R16_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_FLOAT: return "DXGI_FORMAT_R16_FLOAT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_D16_UNORM: return "DXGI_FORMAT_D16_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_UNORM: return "DXGI_FORMAT_R16_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_UINT: return "DXGI_FORMAT_R16_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_SNORM: return "DXGI_FORMAT_R16_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R16_SINT: return "DXGI_FORMAT_R16_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8_TYPELESS: return "DXGI_FORMAT_R8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8_UNORM: return "DXGI_FORMAT_R8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8_UINT: return "DXGI_FORMAT_R8_UINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8_SNORM: return "DXGI_FORMAT_R8_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8_SINT: return "DXGI_FORMAT_R8_SINT";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_A8_UNORM: return "DXGI_FORMAT_A8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R1_UNORM: return "DXGI_FORMAT_R1_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R9G9B9E5_SHAREDEXP: return "DXGI_FORMAT_R9G9B9E5_SHAREDEXP";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R8G8_B8G8_UNORM: return "DXGI_FORMAT_R8G8_B8G8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_G8R8_G8B8_UNORM: return "DXGI_FORMAT_G8R8_G8B8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC1_TYPELESS: return "DXGI_FORMAT_BC1_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC1_UNORM: return "DXGI_FORMAT_BC1_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC1_UNORM_SRGB: return "DXGI_FORMAT_BC1_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC2_TYPELESS: return "DXGI_FORMAT_BC2_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC2_UNORM: return "DXGI_FORMAT_BC2_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC2_UNORM_SRGB: return "DXGI_FORMAT_BC2_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC3_TYPELESS: return "DXGI_FORMAT_BC3_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC3_UNORM: return "DXGI_FORMAT_BC3_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC3_UNORM_SRGB: return "DXGI_FORMAT_BC3_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC4_TYPELESS: return "DXGI_FORMAT_BC4_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC4_UNORM: return "DXGI_FORMAT_BC4_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC4_SNORM: return "DXGI_FORMAT_BC4_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC5_TYPELESS: return "DXGI_FORMAT_BC5_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC5_UNORM: return "DXGI_FORMAT_BC5_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC5_SNORM: return "DXGI_FORMAT_BC5_SNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B5G6R5_UNORM: return "DXGI_FORMAT_B5G6R5_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B5G5R5A1_UNORM: return "DXGI_FORMAT_B5G5R5A1_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM: return "DXGI_FORMAT_B8G8R8A8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8X8_UNORM: return "DXGI_FORMAT_B8G8R8X8_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: return "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_TYPELESS: return "DXGI_FORMAT_B8G8R8A8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: return "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8X8_TYPELESS: return "DXGI_FORMAT_B8G8R8X8_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: return "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC6H_TYPELESS: return "DXGI_FORMAT_BC6H_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC6H_UF16: return "DXGI_FORMAT_BC6H_UF16";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC6H_SF16: return "DXGI_FORMAT_BC6H_SF16";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC7_TYPELESS: return "DXGI_FORMAT_BC7_TYPELESS";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM: return "DXGI_FORMAT_BC7_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM_SRGB: return "DXGI_FORMAT_BC7_UNORM_SRGB";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_AYUV: return "DXGI_FORMAT_AYUV";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_Y410: return "DXGI_FORMAT_Y410";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_Y416: return "DXGI_FORMAT_Y416";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_NV12: return "DXGI_FORMAT_NV12";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_P010: return "DXGI_FORMAT_P010";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_P016: return "DXGI_FORMAT_P016";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_420_OPAQUE: return "DXGI_FORMAT_420_OPAQUE";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_YUY2: return "DXGI_FORMAT_YUY2";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_Y210: return "DXGI_FORMAT_Y210";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_Y216: return "DXGI_FORMAT_Y216";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_NV11: return "DXGI_FORMAT_NV11";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_AI44: return "DXGI_FORMAT_AI44";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_IA44: return "DXGI_FORMAT_IA44";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_P8: return "DXGI_FORMAT_P8";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_A8P8: return "DXGI_FORMAT_A8P8";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_B4G4R4A4_UNORM: return "DXGI_FORMAT_B4G4R4A4_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_P208: return "DXGI_FORMAT_P208";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_V208: return "DXGI_FORMAT_V208";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_V408: return "DXGI_FORMAT_V408";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE: return "DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE: return "DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_A4B4G4R4_UNORM: return "DXGI_FORMAT_A4B4G4R4_UNORM";
|
||||||
|
case DXGI_FORMAT::DXGI_FORMAT_FORCE_UINT: return "DXGI_FORMAT_FORCE_UINT";
|
||||||
|
default: return "UNKNOWN_DXGI_FORMAT";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Rml
|
||||||
|
|
||||||
|
#ifdef RMLUI_DEBUG
|
||||||
|
#define RMLUI_DX_VERIFY_MSG(statement, msg) RMLUI_ASSERTMSG(SUCCEEDED(statement), msg)
|
||||||
|
|
||||||
|
// Uncomment the following line to enable additional DirectX debugging.
|
||||||
|
// #define RMLUI_DX_DEBUG
|
||||||
|
#else
|
||||||
|
#define RMLUI_DX_VERIFY_MSG(statement, msg) static_cast<void>(statement)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#elif defined __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// user's preprocessor overrides
|
||||||
|
|
||||||
|
// system field (it is not supposed to specify by initialization structure)
|
||||||
|
// on some render backend implementations (Vulkan/DirectX-12) we have to check memory leaks but
|
||||||
|
// if we don't reserve memory for a field that contains layers (it is vector)
|
||||||
|
// at runtime we will get a called dtor of move-to-copy object (because of reallocation)
|
||||||
|
// and for that matter we will get a false-positive trigger of assert and it is not right generally
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_RESERVECOUNT_OF_RENDERSTACK_LAYERS
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_RESERVECOUNT_OF_RENDERSTACK_LAYERS 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// this field specifies the default amount of swapchain buffer that will be created
|
||||||
|
// but it is used only when user provided invalid input in initialization structure of backend
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT 3
|
||||||
|
#endif
|
||||||
|
static_assert(RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT > 0);
|
||||||
|
|
||||||
|
// this field specifies the default amount of videomemory that will be used on creation
|
||||||
|
// this field is used when user provided invalid input in initialization structure of backend
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_BUFFER_ALLOCATION
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_BUFFER_ALLOCATION (1024 * 1024 * 2)
|
||||||
|
#endif
|
||||||
|
static_assert(RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_BUFFER_ALLOCATION > 0);
|
||||||
|
|
||||||
|
// this field specifies the default amount of videomemory that will be used for texture creation
|
||||||
|
// on some backends it determines the size of a temp buffer that might be used not trivial (just for uploading texture by copying data in it)
|
||||||
|
// like on DirectX-12 it has a placement resources feature and making this value lower (4 Mb) the placement resource feature becomes pointless
|
||||||
|
// and doesn't gain any performance related boosting
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_TEXTURE_ALLOCATION
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_TEXTURE_ALLOCATION (4 * 1024 * 1024)
|
||||||
|
#endif
|
||||||
|
static_assert(RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_TEXTURE_ALLOCATION > 0);
|
||||||
|
|
||||||
|
// system field that is not supposed to be in initialization structure and used as default (input user doesn't affect it at all like we always
|
||||||
|
// use it, not just because we handling invalid input from user)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_ALIGNMENT_FOR_BUFFER
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_ALIGNMENT_FOR_BUFFER D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// system field that is not supposed to be in initialization structure and used as default (input user doesn't affect it at all like we always
|
||||||
|
// use it, not just because we handling invalid input from user)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_COLOR_TEXTURE_FORMAT DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// system field that is not supposed to be in initialization structure and used as default (input user doesn't affect it at all like we always
|
||||||
|
// use it, not just because we handling invalid input from user)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_DEPTHSTENCIL_TEXTURE_FORMAT DXGI_FORMAT::DXGI_FORMAT_D32_FLOAT_S8X24_UINT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// system field that is not supposed to be in initialization structure and used as default (input user doesn't affect it at all like we always
|
||||||
|
// use it, not just because we handling invalid input from user)
|
||||||
|
// notice: this field is shared for all srv and cbv and uav it doesn't mean that it specifically allocates for srv 128, cbv 128 and uav 128,
|
||||||
|
// no! it allocates only on descriptor for all of such types and total amount is 128 not 3 * 128 = 384 !!!
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_DESCRIPTORAMOUNT_FOR_SRV_CBV_UAV
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_DESCRIPTORAMOUNT_FOR_SRV_CBV_UAV 128
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_MAXNUMPROGRAMS
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_MAXNUMPROGRAMS 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// for getting total size of constant buffers you should multiply kPreAllocatedConstantBuffers * kSwapchainBackBufferCount e.g. 512 *
|
||||||
|
// RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT = 1536 (if RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT=3) but keep in mind that
|
||||||
|
// allocation per constant buffer is 512 bytes (due to fact of the max presented CB in shaders) so 1536 * 512 will be 786'432 bytes and knowing
|
||||||
|
// that default buffer budget is just 2Mb (2'097'152) you will have 1'310'720 bytes (~37% of budget took by CBs) but some information will go to
|
||||||
|
// vertices and some information will go to indices and then you will have some free space (maybe small depends on your input) for handling other
|
||||||
|
// constant buffers that weren't sufficient for your current frame aka reallocation happens at some point it is fine just because the memory
|
||||||
|
// management of this backend handles a reallocation situations and you will just get a new allocated buffer and all stuff goes to that buffer but
|
||||||
|
// I give you this reasoning for being a developer that cares about optimizations and cares about pipeline development for end user and for that
|
||||||
|
// reason I gave you understanding that generally constant buffers even 512 bytes but uses so much in frame will take a big chunk from your VB/IB
|
||||||
|
// budget just because GAPI needs to handle many frames from swapchain, just because we expect indeed hard scene for rendering, but for average
|
||||||
|
// mid or low pages that's enough for sure (in terms of preallocated memory for VB,IB,CB)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_PREALLOCATED_CONSTANTBUFFERS 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_MSAA_SAMPLE_COUNT 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_RTV 12
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_DSV
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_DESCRIPTOR_HEAP_DSV 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// specifies general (for all depth stencil textures that might be allocated by backend) depth value on clear operation (::ClearDepthStencilView)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_DEPTH_VALUE
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_DEPTH_VALUE 1.0f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// specifies general (for all depth stencil textures that might be allocated by backend) stencil value on clear operation
|
||||||
|
// (::ClearDepthStencilView)
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_STENCIL_VALUE
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_DEPTHSTENCIL_STENCIL_VALUE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_RENDERTARGET_COLOR_VAlUE
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_CLEAR_VALUE_RENDERTARGET_COLOR_VAlUE 0.0f, 0.0f, 0.0f, 1.0f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_SIZE
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_SIZE 1024 * 1024 * 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED
|
||||||
|
#define RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED 1
|
||||||
|
#endif
|
||||||
3582
vendor/rmlui_backend/RmlUi_Include_GL3.h
vendored
Normal file
3582
vendor/rmlui_backend/RmlUi_Include_GL3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
32
vendor/rmlui_backend/RmlUi_Include_Vulkan.h
vendored
Normal file
32
vendor/rmlui_backend/RmlUi_Include_Vulkan.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef RMLUI_BACKENDS_INCLUDE_VULKAN_H
|
||||||
|
#define RMLUI_BACKENDS_INCLUDE_VULKAN_H
|
||||||
|
|
||||||
|
#if defined RMLUI_PLATFORM_UNIX
|
||||||
|
#define VK_USE_PLATFORM_XCB_KHR 1
|
||||||
|
#endif
|
||||||
|
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||||
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined _MSC_VER
|
||||||
|
#pragma warning(push, 0)
|
||||||
|
#elif defined __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wall"
|
||||||
|
#pragma clang diagnostic ignored "-Wextra"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability-extension"
|
||||||
|
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability-completeness"
|
||||||
|
#elif defined __GNUC__
|
||||||
|
#pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "RmlUi_Vulkan/vulkan.h"
|
||||||
|
// Always include "vulkan.h" first, this comment prevents clang-format from reordering the includes.
|
||||||
|
#include "RmlUi_Vulkan/vk_mem_alloc.h"
|
||||||
|
|
||||||
|
#if defined _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#elif defined __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
20
vendor/rmlui_backend/RmlUi_Include_Windows.h
vendored
Normal file
20
vendor/rmlui_backend/RmlUi_Include_Windows.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef RMLUI_DISABLE_INCLUDE_WINDOWS
|
||||||
|
|
||||||
|
#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0601
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
// Target Windows 7
|
||||||
|
#define _WIN32_WINNT 0x0601
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UNICODE
|
||||||
|
#define _UNICODE
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
#define NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
18
vendor/rmlui_backend/RmlUi_Include_Xlib.h
vendored
Normal file
18
vendor/rmlui_backend/RmlUi_Include_Xlib.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef RMLUI_DISABLE_INCLUDE_XLIB
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
// The None and Always defines from X.h conflicts with RmlUi code base,
|
||||||
|
// use their underlying constants where necessary.
|
||||||
|
#ifdef None
|
||||||
|
// Value 0L
|
||||||
|
#undef None
|
||||||
|
#endif
|
||||||
|
#ifdef Always
|
||||||
|
// Value 2
|
||||||
|
#undef Always
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
330
vendor/rmlui_backend/RmlUi_Platform_GLFW.cpp
vendored
Normal file
330
vendor/rmlui_backend/RmlUi_Platform_GLFW.cpp
vendored
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
#include "RmlUi_Platform_GLFW.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/Math.h>
|
||||||
|
#include <RmlUi/Core/StringUtilities.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#define GLFW_HAS_EXTRA_CURSORS (GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 4)
|
||||||
|
|
||||||
|
SystemInterface_GLFW::SystemInterface_GLFW(GLFWwindow* window) : window(window)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERTMSG(window, "Please provide a valid SDL window to the SDL system interface");
|
||||||
|
|
||||||
|
cursor_pointer = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
|
||||||
|
cursor_cross = glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR);
|
||||||
|
cursor_text = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||||
|
#if GLFW_HAS_EXTRA_CURSORS
|
||||||
|
cursor_move = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
|
||||||
|
cursor_resize = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
|
||||||
|
cursor_unavailable = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
|
||||||
|
#else
|
||||||
|
cursor_move = cursor_pointer;
|
||||||
|
cursor_resize = cursor_pointer;
|
||||||
|
cursor_unavailable = nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInterface_GLFW::~SystemInterface_GLFW()
|
||||||
|
{
|
||||||
|
glfwDestroyCursor(cursor_pointer);
|
||||||
|
glfwDestroyCursor(cursor_cross);
|
||||||
|
glfwDestroyCursor(cursor_text);
|
||||||
|
#if GLFW_HAS_EXTRA_CURSORS
|
||||||
|
glfwDestroyCursor(cursor_move);
|
||||||
|
glfwDestroyCursor(cursor_resize);
|
||||||
|
glfwDestroyCursor(cursor_unavailable);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
double SystemInterface_GLFW::GetElapsedTime()
|
||||||
|
{
|
||||||
|
return glfwGetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_GLFW::SetMouseCursor(const Rml::String& cursor_name)
|
||||||
|
{
|
||||||
|
GLFWcursor* cursor = nullptr;
|
||||||
|
|
||||||
|
if (cursor_name.empty() || cursor_name == "arrow")
|
||||||
|
cursor = nullptr;
|
||||||
|
else if (cursor_name == "move")
|
||||||
|
cursor = cursor_move;
|
||||||
|
else if (cursor_name == "pointer")
|
||||||
|
cursor = cursor_pointer;
|
||||||
|
else if (cursor_name == "resize")
|
||||||
|
cursor = cursor_resize;
|
||||||
|
else if (cursor_name == "cross")
|
||||||
|
cursor = cursor_cross;
|
||||||
|
else if (cursor_name == "text")
|
||||||
|
cursor = cursor_text;
|
||||||
|
else if (cursor_name == "unavailable")
|
||||||
|
cursor = cursor_unavailable;
|
||||||
|
else if (Rml::StringUtilities::StartsWith(cursor_name, "rmlui-scroll"))
|
||||||
|
cursor = cursor_move;
|
||||||
|
|
||||||
|
glfwSetCursor(window, cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_GLFW::SetClipboardText(const Rml::String& text_utf8)
|
||||||
|
{
|
||||||
|
glfwSetClipboardString(window, text_utf8.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_GLFW::GetClipboardText(Rml::String& text)
|
||||||
|
{
|
||||||
|
if (const char* clipboard = glfwGetClipboardString(window))
|
||||||
|
{
|
||||||
|
text = Rml::String(clipboard);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlGLFW::ProcessKeyCallback(Rml::Context* context, int key, int action, int mods)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GLFW_PRESS:
|
||||||
|
case GLFW_REPEAT:
|
||||||
|
result = context->ProcessKeyDown(RmlGLFW::ConvertKey(key), RmlGLFW::ConvertKeyModifiers(mods));
|
||||||
|
if (key == GLFW_KEY_ENTER || key == GLFW_KEY_KP_ENTER)
|
||||||
|
result &= context->ProcessTextInput('\n');
|
||||||
|
break;
|
||||||
|
case GLFW_RELEASE: result = context->ProcessKeyUp(RmlGLFW::ConvertKey(key), RmlGLFW::ConvertKeyModifiers(mods)); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
bool RmlGLFW::ProcessCharCallback(Rml::Context* context, unsigned int codepoint)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = context->ProcessTextInput((Rml::Character)codepoint);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlGLFW::ProcessCursorEnterCallback(Rml::Context* context, int entered)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
if (!entered)
|
||||||
|
result = context->ProcessMouseLeave();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlGLFW::ProcessCursorPosCallback(Rml::Context* context, GLFWwindow* window, double xpos, double ypos, int mods)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
using Rml::Vector2i;
|
||||||
|
using Vector2d = Rml::Vector2<double>;
|
||||||
|
|
||||||
|
Vector2i window_size, framebuffer_size;
|
||||||
|
glfwGetWindowSize(window, &window_size.x, &window_size.y);
|
||||||
|
glfwGetFramebufferSize(window, &framebuffer_size.x, &framebuffer_size.y);
|
||||||
|
|
||||||
|
// Convert from mouse position in GLFW screen coordinates to framebuffer coordinates (pixels) used by RmlUi.
|
||||||
|
const Vector2d mouse_pos = Vector2d(xpos, ypos) * (Vector2d(framebuffer_size) / Vector2d(window_size));
|
||||||
|
const Vector2i mouse_pos_round = {int(Rml::Math::Round(mouse_pos.x)), int(Rml::Math::Round(mouse_pos.y))};
|
||||||
|
|
||||||
|
bool result = context->ProcessMouseMove(mouse_pos_round.x, mouse_pos_round.y, RmlGLFW::ConvertKeyModifiers(mods));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlGLFW::ProcessMouseButtonCallback(Rml::Context* context, int button, int action, int mods)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GLFW_PRESS: result = context->ProcessMouseButtonDown(button, RmlGLFW::ConvertKeyModifiers(mods)); break;
|
||||||
|
case GLFW_RELEASE: result = context->ProcessMouseButtonUp(button, RmlGLFW::ConvertKeyModifiers(mods)); break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlGLFW::ProcessScrollCallback(Rml::Context* context, double yoffset, int mods)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = context->ProcessMouseWheel(-float(yoffset), RmlGLFW::ConvertKeyModifiers(mods));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RmlGLFW::ProcessFramebufferSizeCallback(Rml::Context* context, int width, int height)
|
||||||
|
{
|
||||||
|
if (context)
|
||||||
|
context->SetDimensions(Rml::Vector2i(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RmlGLFW::ProcessContentScaleCallback(Rml::Context* context, float xscale)
|
||||||
|
{
|
||||||
|
if (context)
|
||||||
|
context->SetDensityIndependentPixelRatio(xscale);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlGLFW::ConvertKeyModifiers(int glfw_mods)
|
||||||
|
{
|
||||||
|
int key_modifier_state = 0;
|
||||||
|
|
||||||
|
if (GLFW_MOD_SHIFT & glfw_mods)
|
||||||
|
key_modifier_state |= Rml::Input::KM_SHIFT;
|
||||||
|
|
||||||
|
if (GLFW_MOD_CONTROL & glfw_mods)
|
||||||
|
key_modifier_state |= Rml::Input::KM_CTRL;
|
||||||
|
|
||||||
|
if (GLFW_MOD_ALT & glfw_mods)
|
||||||
|
key_modifier_state |= Rml::Input::KM_ALT;
|
||||||
|
|
||||||
|
if (GLFW_MOD_CAPS_LOCK & glfw_mods)
|
||||||
|
key_modifier_state |= Rml::Input::KM_SCROLLLOCK;
|
||||||
|
|
||||||
|
if (GLFW_MOD_NUM_LOCK & glfw_mods)
|
||||||
|
key_modifier_state |= Rml::Input::KM_NUMLOCK;
|
||||||
|
|
||||||
|
return key_modifier_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Input::KeyIdentifier RmlGLFW::ConvertKey(int glfw_key)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
switch (glfw_key)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_A: return Rml::Input::KI_A;
|
||||||
|
case GLFW_KEY_B: return Rml::Input::KI_B;
|
||||||
|
case GLFW_KEY_C: return Rml::Input::KI_C;
|
||||||
|
case GLFW_KEY_D: return Rml::Input::KI_D;
|
||||||
|
case GLFW_KEY_E: return Rml::Input::KI_E;
|
||||||
|
case GLFW_KEY_F: return Rml::Input::KI_F;
|
||||||
|
case GLFW_KEY_G: return Rml::Input::KI_G;
|
||||||
|
case GLFW_KEY_H: return Rml::Input::KI_H;
|
||||||
|
case GLFW_KEY_I: return Rml::Input::KI_I;
|
||||||
|
case GLFW_KEY_J: return Rml::Input::KI_J;
|
||||||
|
case GLFW_KEY_K: return Rml::Input::KI_K;
|
||||||
|
case GLFW_KEY_L: return Rml::Input::KI_L;
|
||||||
|
case GLFW_KEY_M: return Rml::Input::KI_M;
|
||||||
|
case GLFW_KEY_N: return Rml::Input::KI_N;
|
||||||
|
case GLFW_KEY_O: return Rml::Input::KI_O;
|
||||||
|
case GLFW_KEY_P: return Rml::Input::KI_P;
|
||||||
|
case GLFW_KEY_Q: return Rml::Input::KI_Q;
|
||||||
|
case GLFW_KEY_R: return Rml::Input::KI_R;
|
||||||
|
case GLFW_KEY_S: return Rml::Input::KI_S;
|
||||||
|
case GLFW_KEY_T: return Rml::Input::KI_T;
|
||||||
|
case GLFW_KEY_U: return Rml::Input::KI_U;
|
||||||
|
case GLFW_KEY_V: return Rml::Input::KI_V;
|
||||||
|
case GLFW_KEY_W: return Rml::Input::KI_W;
|
||||||
|
case GLFW_KEY_X: return Rml::Input::KI_X;
|
||||||
|
case GLFW_KEY_Y: return Rml::Input::KI_Y;
|
||||||
|
case GLFW_KEY_Z: return Rml::Input::KI_Z;
|
||||||
|
|
||||||
|
case GLFW_KEY_0: return Rml::Input::KI_0;
|
||||||
|
case GLFW_KEY_1: return Rml::Input::KI_1;
|
||||||
|
case GLFW_KEY_2: return Rml::Input::KI_2;
|
||||||
|
case GLFW_KEY_3: return Rml::Input::KI_3;
|
||||||
|
case GLFW_KEY_4: return Rml::Input::KI_4;
|
||||||
|
case GLFW_KEY_5: return Rml::Input::KI_5;
|
||||||
|
case GLFW_KEY_6: return Rml::Input::KI_6;
|
||||||
|
case GLFW_KEY_7: return Rml::Input::KI_7;
|
||||||
|
case GLFW_KEY_8: return Rml::Input::KI_8;
|
||||||
|
case GLFW_KEY_9: return Rml::Input::KI_9;
|
||||||
|
|
||||||
|
case GLFW_KEY_BACKSPACE: return Rml::Input::KI_BACK;
|
||||||
|
case GLFW_KEY_TAB: return Rml::Input::KI_TAB;
|
||||||
|
|
||||||
|
case GLFW_KEY_ENTER: return Rml::Input::KI_RETURN;
|
||||||
|
|
||||||
|
case GLFW_KEY_PAUSE: return Rml::Input::KI_PAUSE;
|
||||||
|
case GLFW_KEY_CAPS_LOCK: return Rml::Input::KI_CAPITAL;
|
||||||
|
|
||||||
|
case GLFW_KEY_ESCAPE: return Rml::Input::KI_ESCAPE;
|
||||||
|
|
||||||
|
case GLFW_KEY_SPACE: return Rml::Input::KI_SPACE;
|
||||||
|
case GLFW_KEY_PAGE_UP: return Rml::Input::KI_PRIOR;
|
||||||
|
case GLFW_KEY_PAGE_DOWN: return Rml::Input::KI_NEXT;
|
||||||
|
case GLFW_KEY_END: return Rml::Input::KI_END;
|
||||||
|
case GLFW_KEY_HOME: return Rml::Input::KI_HOME;
|
||||||
|
case GLFW_KEY_LEFT: return Rml::Input::KI_LEFT;
|
||||||
|
case GLFW_KEY_UP: return Rml::Input::KI_UP;
|
||||||
|
case GLFW_KEY_RIGHT: return Rml::Input::KI_RIGHT;
|
||||||
|
case GLFW_KEY_DOWN: return Rml::Input::KI_DOWN;
|
||||||
|
case GLFW_KEY_PRINT_SCREEN: return Rml::Input::KI_SNAPSHOT;
|
||||||
|
case GLFW_KEY_INSERT: return Rml::Input::KI_INSERT;
|
||||||
|
case GLFW_KEY_DELETE: return Rml::Input::KI_DELETE;
|
||||||
|
|
||||||
|
case GLFW_KEY_LEFT_SUPER: return Rml::Input::KI_LWIN;
|
||||||
|
case GLFW_KEY_RIGHT_SUPER: return Rml::Input::KI_RWIN;
|
||||||
|
|
||||||
|
case GLFW_KEY_KP_0: return Rml::Input::KI_NUMPAD0;
|
||||||
|
case GLFW_KEY_KP_1: return Rml::Input::KI_NUMPAD1;
|
||||||
|
case GLFW_KEY_KP_2: return Rml::Input::KI_NUMPAD2;
|
||||||
|
case GLFW_KEY_KP_3: return Rml::Input::KI_NUMPAD3;
|
||||||
|
case GLFW_KEY_KP_4: return Rml::Input::KI_NUMPAD4;
|
||||||
|
case GLFW_KEY_KP_5: return Rml::Input::KI_NUMPAD5;
|
||||||
|
case GLFW_KEY_KP_6: return Rml::Input::KI_NUMPAD6;
|
||||||
|
case GLFW_KEY_KP_7: return Rml::Input::KI_NUMPAD7;
|
||||||
|
case GLFW_KEY_KP_8: return Rml::Input::KI_NUMPAD8;
|
||||||
|
case GLFW_KEY_KP_9: return Rml::Input::KI_NUMPAD9;
|
||||||
|
case GLFW_KEY_KP_ENTER: return Rml::Input::KI_NUMPADENTER;
|
||||||
|
case GLFW_KEY_KP_MULTIPLY: return Rml::Input::KI_MULTIPLY;
|
||||||
|
case GLFW_KEY_KP_ADD: return Rml::Input::KI_ADD;
|
||||||
|
case GLFW_KEY_KP_SUBTRACT: return Rml::Input::KI_SUBTRACT;
|
||||||
|
case GLFW_KEY_KP_DECIMAL: return Rml::Input::KI_DECIMAL;
|
||||||
|
case GLFW_KEY_KP_DIVIDE: return Rml::Input::KI_DIVIDE;
|
||||||
|
|
||||||
|
case GLFW_KEY_F1: return Rml::Input::KI_F1;
|
||||||
|
case GLFW_KEY_F2: return Rml::Input::KI_F2;
|
||||||
|
case GLFW_KEY_F3: return Rml::Input::KI_F3;
|
||||||
|
case GLFW_KEY_F4: return Rml::Input::KI_F4;
|
||||||
|
case GLFW_KEY_F5: return Rml::Input::KI_F5;
|
||||||
|
case GLFW_KEY_F6: return Rml::Input::KI_F6;
|
||||||
|
case GLFW_KEY_F7: return Rml::Input::KI_F7;
|
||||||
|
case GLFW_KEY_F8: return Rml::Input::KI_F8;
|
||||||
|
case GLFW_KEY_F9: return Rml::Input::KI_F9;
|
||||||
|
case GLFW_KEY_F10: return Rml::Input::KI_F10;
|
||||||
|
case GLFW_KEY_F11: return Rml::Input::KI_F11;
|
||||||
|
case GLFW_KEY_F12: return Rml::Input::KI_F12;
|
||||||
|
case GLFW_KEY_F13: return Rml::Input::KI_F13;
|
||||||
|
case GLFW_KEY_F14: return Rml::Input::KI_F14;
|
||||||
|
case GLFW_KEY_F15: return Rml::Input::KI_F15;
|
||||||
|
case GLFW_KEY_F16: return Rml::Input::KI_F16;
|
||||||
|
case GLFW_KEY_F17: return Rml::Input::KI_F17;
|
||||||
|
case GLFW_KEY_F18: return Rml::Input::KI_F18;
|
||||||
|
case GLFW_KEY_F19: return Rml::Input::KI_F19;
|
||||||
|
case GLFW_KEY_F20: return Rml::Input::KI_F20;
|
||||||
|
case GLFW_KEY_F21: return Rml::Input::KI_F21;
|
||||||
|
case GLFW_KEY_F22: return Rml::Input::KI_F22;
|
||||||
|
case GLFW_KEY_F23: return Rml::Input::KI_F23;
|
||||||
|
case GLFW_KEY_F24: return Rml::Input::KI_F24;
|
||||||
|
|
||||||
|
case GLFW_KEY_NUM_LOCK: return Rml::Input::KI_NUMLOCK;
|
||||||
|
case GLFW_KEY_SCROLL_LOCK: return Rml::Input::KI_SCROLL;
|
||||||
|
|
||||||
|
case GLFW_KEY_LEFT_SHIFT: return Rml::Input::KI_LSHIFT;
|
||||||
|
case GLFW_KEY_LEFT_CONTROL: return Rml::Input::KI_LCONTROL;
|
||||||
|
case GLFW_KEY_RIGHT_SHIFT: return Rml::Input::KI_RSHIFT;
|
||||||
|
case GLFW_KEY_RIGHT_CONTROL: return Rml::Input::KI_RCONTROL;
|
||||||
|
case GLFW_KEY_MENU: return Rml::Input::KI_LMENU;
|
||||||
|
|
||||||
|
case GLFW_KEY_KP_EQUAL: return Rml::Input::KI_OEM_NEC_EQUAL;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return Rml::Input::KI_UNKNOWN;
|
||||||
|
}
|
||||||
56
vendor/rmlui_backend/RmlUi_Platform_GLFW.h
vendored
Normal file
56
vendor/rmlui_backend/RmlUi_Platform_GLFW.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
class SystemInterface_GLFW : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
SystemInterface_GLFW(GLFWwindow* window);
|
||||||
|
~SystemInterface_GLFW();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::SystemInterface --
|
||||||
|
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
|
||||||
|
void SetMouseCursor(const Rml::String& cursor_name) override;
|
||||||
|
|
||||||
|
void SetClipboardText(const Rml::String& text) override;
|
||||||
|
void GetClipboardText(Rml::String& text) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLFWwindow* window = nullptr;
|
||||||
|
|
||||||
|
GLFWcursor* cursor_pointer = nullptr;
|
||||||
|
GLFWcursor* cursor_cross = nullptr;
|
||||||
|
GLFWcursor* cursor_text = nullptr;
|
||||||
|
GLFWcursor* cursor_move = nullptr;
|
||||||
|
GLFWcursor* cursor_resize = nullptr;
|
||||||
|
GLFWcursor* cursor_unavailable = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Optional helper functions for the GLFW plaform.
|
||||||
|
*/
|
||||||
|
namespace RmlGLFW {
|
||||||
|
|
||||||
|
// The following optional functions are intended to be called from their respective GLFW callback functions. The functions expect arguments passed
|
||||||
|
// directly from GLFW, in addition to the RmlUi context to apply the input or sizing event on. The input callbacks return true if the event is
|
||||||
|
// propagating, i.e. was not handled by the context.
|
||||||
|
bool ProcessKeyCallback(Rml::Context* context, int key, int action, int mods);
|
||||||
|
bool ProcessCharCallback(Rml::Context* context, unsigned int codepoint);
|
||||||
|
bool ProcessCursorEnterCallback(Rml::Context* context, int entered);
|
||||||
|
bool ProcessCursorPosCallback(Rml::Context* context, GLFWwindow* window, double xpos, double ypos, int mods);
|
||||||
|
bool ProcessMouseButtonCallback(Rml::Context* context, int button, int action, int mods);
|
||||||
|
bool ProcessScrollCallback(Rml::Context* context, double yoffset, int mods);
|
||||||
|
void ProcessFramebufferSizeCallback(Rml::Context* context, int width, int height);
|
||||||
|
void ProcessContentScaleCallback(Rml::Context* context, float xscale);
|
||||||
|
|
||||||
|
// Converts the GLFW key to RmlUi key.
|
||||||
|
Rml::Input::KeyIdentifier ConvertKey(int glfw_key);
|
||||||
|
|
||||||
|
// Converts the GLFW key modifiers to RmlUi key modifiers.
|
||||||
|
int ConvertKeyModifiers(int glfw_mods);
|
||||||
|
|
||||||
|
} // namespace RmlGLFW
|
||||||
569
vendor/rmlui_backend/RmlUi_Platform_SDL.cpp
vendored
Normal file
569
vendor/rmlui_backend/RmlUi_Platform_SDL.cpp
vendored
Normal file
@@ -0,0 +1,569 @@
|
|||||||
|
#include "RmlUi_Platform_SDL.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/StringUtilities.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/TextInputContext.h>
|
||||||
|
|
||||||
|
static Rml::TouchList TouchEventToTouchList(SDL_Event& ev, Rml::Context* context, SDL_FingerID finger_id)
|
||||||
|
{
|
||||||
|
const Rml::Vector2f position = Rml::Vector2f{ev.tfinger.x, ev.tfinger.y} * Rml::Vector2f{context->GetDimensions()};
|
||||||
|
return {Rml::Touch{static_cast<Rml::TouchId>(finger_id), position}};
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInterface_SDL::SystemInterface_SDL(SDL_Window* in_window) : window(in_window)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERTMSG(window, "Please provide a valid SDL window to the SDL system interface");
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
cursor_default = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
||||||
|
cursor_move = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE);
|
||||||
|
cursor_pointer = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER);
|
||||||
|
cursor_resize = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE);
|
||||||
|
cursor_cross = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
|
||||||
|
cursor_text = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT);
|
||||||
|
cursor_unavailable = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED);
|
||||||
|
#else
|
||||||
|
cursor_default = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
|
||||||
|
cursor_move = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
|
||||||
|
cursor_pointer = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
|
||||||
|
cursor_resize = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
|
||||||
|
cursor_cross = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
|
||||||
|
cursor_text = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
|
||||||
|
cursor_unavailable = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
|
||||||
|
(void)window; // Window is unused on SDL 2.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInterface_SDL::~SystemInterface_SDL()
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto DestroyCursor = [](SDL_Cursor* cursor) { SDL_DestroyCursor(cursor); };
|
||||||
|
#else
|
||||||
|
auto DestroyCursor = [](SDL_Cursor* cursor) { SDL_FreeCursor(cursor); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DestroyCursor(cursor_default);
|
||||||
|
DestroyCursor(cursor_move);
|
||||||
|
DestroyCursor(cursor_pointer);
|
||||||
|
DestroyCursor(cursor_resize);
|
||||||
|
DestroyCursor(cursor_cross);
|
||||||
|
DestroyCursor(cursor_text);
|
||||||
|
DestroyCursor(cursor_unavailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
double SystemInterface_SDL::GetElapsedTime()
|
||||||
|
{
|
||||||
|
static const Uint64 start = SDL_GetPerformanceCounter();
|
||||||
|
static const double frequency = double(SDL_GetPerformanceFrequency());
|
||||||
|
return double(SDL_GetPerformanceCounter() - start) / frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SDL::SetMouseCursor(const Rml::String& cursor_name)
|
||||||
|
{
|
||||||
|
SDL_Cursor* cursor = nullptr;
|
||||||
|
|
||||||
|
if (cursor_name.empty() || cursor_name == "arrow")
|
||||||
|
cursor = cursor_default;
|
||||||
|
else if (cursor_name == "move")
|
||||||
|
cursor = cursor_move;
|
||||||
|
else if (cursor_name == "pointer")
|
||||||
|
cursor = cursor_pointer;
|
||||||
|
else if (cursor_name == "resize")
|
||||||
|
cursor = cursor_resize;
|
||||||
|
else if (cursor_name == "cross")
|
||||||
|
cursor = cursor_cross;
|
||||||
|
else if (cursor_name == "text")
|
||||||
|
cursor = cursor_text;
|
||||||
|
else if (cursor_name == "unavailable")
|
||||||
|
cursor = cursor_unavailable;
|
||||||
|
else if (Rml::StringUtilities::StartsWith(cursor_name, "rmlui-scroll"))
|
||||||
|
cursor = cursor_move;
|
||||||
|
|
||||||
|
if (cursor)
|
||||||
|
SDL_SetCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SDL::SetClipboardText(const Rml::String& text)
|
||||||
|
{
|
||||||
|
SDL_SetClipboardText(text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SDL::GetClipboardText(Rml::String& text)
|
||||||
|
{
|
||||||
|
char* raw_text = SDL_GetClipboardText();
|
||||||
|
text = Rml::String(raw_text);
|
||||||
|
SDL_free(raw_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SDL::ActivateKeyboard(Rml::Vector2f caret_position, float line_height)
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
const SDL_Rect rect = {int(caret_position.x), int(caret_position.y), 1, int(line_height)};
|
||||||
|
SDL_SetTextInputArea(window, &rect, 0);
|
||||||
|
SDL_StartTextInput(window);
|
||||||
|
#else
|
||||||
|
(void)caret_position;
|
||||||
|
(void)line_height;
|
||||||
|
SDL_StartTextInput();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SDL::DeactivateKeyboard()
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_StopTextInput(window);
|
||||||
|
#else
|
||||||
|
SDL_StopTextInput();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlSDL::InputEventHandler(Rml::Context* context, SDL_Window* window, SDL_Event& ev)
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.key; };
|
||||||
|
auto GetPixelDensity = [](SDL_Window* target_window) { return SDL_GetWindowPixelDensity(target_window); };
|
||||||
|
auto GetFingerId = [](const SDL_Event& event) { return event.tfinger.fingerID; };
|
||||||
|
constexpr auto event_mouse_motion = SDL_EVENT_MOUSE_MOTION;
|
||||||
|
constexpr auto event_mouse_down = SDL_EVENT_MOUSE_BUTTON_DOWN;
|
||||||
|
constexpr auto event_mouse_up = SDL_EVENT_MOUSE_BUTTON_UP;
|
||||||
|
constexpr auto event_mouse_wheel = SDL_EVENT_MOUSE_WHEEL;
|
||||||
|
constexpr auto event_key_down = SDL_EVENT_KEY_DOWN;
|
||||||
|
constexpr auto event_key_up = SDL_EVENT_KEY_UP;
|
||||||
|
constexpr auto event_text_input = SDL_EVENT_TEXT_INPUT;
|
||||||
|
constexpr auto event_window_size_changed = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
|
||||||
|
constexpr auto event_window_leave = SDL_EVENT_WINDOW_MOUSE_LEAVE;
|
||||||
|
constexpr auto event_finger_down = SDL_EVENT_FINGER_DOWN;
|
||||||
|
constexpr auto event_finger_up = SDL_EVENT_FINGER_UP;
|
||||||
|
constexpr auto event_finger_motion = SDL_EVENT_FINGER_MOTION;
|
||||||
|
|
||||||
|
constexpr auto rmlsdl_true = true;
|
||||||
|
constexpr auto rmlsdl_false = false;
|
||||||
|
#else
|
||||||
|
(void)window;
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_BEGIN \
|
||||||
|
case SDL_WINDOWEVENT: \
|
||||||
|
{ \
|
||||||
|
switch (ev.window.event) \
|
||||||
|
{
|
||||||
|
#define RMLSDL_WINDOW_EVENTS_END \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
break;
|
||||||
|
auto GetKey = [](const SDL_Event& event) { return event.key.keysym.sym; };
|
||||||
|
auto GetPixelDensity = [](SDL_Window* /*target_window*/) { return 1.f; };
|
||||||
|
auto GetFingerId = [](const SDL_Event& event) { return event.tfinger.fingerId; };
|
||||||
|
constexpr auto event_mouse_motion = SDL_MOUSEMOTION;
|
||||||
|
constexpr auto event_mouse_down = SDL_MOUSEBUTTONDOWN;
|
||||||
|
constexpr auto event_mouse_up = SDL_MOUSEBUTTONUP;
|
||||||
|
constexpr auto event_mouse_wheel = SDL_MOUSEWHEEL;
|
||||||
|
constexpr auto event_key_down = SDL_KEYDOWN;
|
||||||
|
constexpr auto event_key_up = SDL_KEYUP;
|
||||||
|
constexpr auto event_text_input = SDL_TEXTINPUT;
|
||||||
|
constexpr auto event_window_size_changed = SDL_WINDOWEVENT_SIZE_CHANGED;
|
||||||
|
constexpr auto event_window_leave = SDL_WINDOWEVENT_LEAVE;
|
||||||
|
constexpr auto event_finger_down = SDL_FINGERDOWN;
|
||||||
|
constexpr auto event_finger_up = SDL_FINGERUP;
|
||||||
|
constexpr auto event_finger_motion = SDL_FINGERMOTION;
|
||||||
|
|
||||||
|
constexpr auto rmlsdl_true = SDL_TRUE;
|
||||||
|
constexpr auto rmlsdl_false = SDL_FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
#ifndef RMLUI_BACKEND_SIMULATE_TOUCH
|
||||||
|
case event_mouse_motion:
|
||||||
|
{
|
||||||
|
const float pixel_density = GetPixelDensity(window);
|
||||||
|
result = context->ProcessMouseMove(int(ev.motion.x * pixel_density), int(ev.motion.y * pixel_density), GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_mouse_down:
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseButtonDown(ConvertMouseButton(ev.button.button), GetKeyModifierState());
|
||||||
|
SDL_CaptureMouse(rmlsdl_true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_mouse_up:
|
||||||
|
{
|
||||||
|
SDL_CaptureMouse(rmlsdl_false);
|
||||||
|
result = context->ProcessMouseButtonUp(ConvertMouseButton(ev.button.button), GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case event_mouse_wheel:
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseWheel(float(-ev.wheel.y), GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_down:
|
||||||
|
{
|
||||||
|
result = context->ProcessKeyDown(ConvertKey(GetKey(ev)), GetKeyModifierState());
|
||||||
|
if (GetKey(ev) == SDLK_RETURN || GetKey(ev) == SDLK_KP_ENTER)
|
||||||
|
result &= context->ProcessTextInput('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_key_up:
|
||||||
|
{
|
||||||
|
result = context->ProcessKeyUp(ConvertKey(GetKey(ev)), GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_text_input:
|
||||||
|
{
|
||||||
|
result = context->ProcessTextInput(Rml::String(&ev.text.text[0]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_finger_down:
|
||||||
|
{
|
||||||
|
const Rml::TouchList touches = TouchEventToTouchList(ev, context, GetFingerId(ev));
|
||||||
|
result = context->ProcessTouchStart(touches, GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_finger_motion:
|
||||||
|
{
|
||||||
|
const Rml::TouchList touches = TouchEventToTouchList(ev, context, GetFingerId(ev));
|
||||||
|
result = context->ProcessTouchMove(touches, GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_finger_up:
|
||||||
|
{
|
||||||
|
const Rml::TouchList touches = TouchEventToTouchList(ev, context, GetFingerId(ev));
|
||||||
|
result = context->ProcessTouchEnd(touches, GetKeyModifierState());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_BEGIN
|
||||||
|
|
||||||
|
case event_window_size_changed:
|
||||||
|
{
|
||||||
|
Rml::Vector2i dimensions(ev.window.data1, ev.window.data2);
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
// SDL_Renderer backend (SDL3): if SDL_SetRenderLogicalPresentation() is enabled, the renderer uses a fixed logical
|
||||||
|
// output size (render coordinates) and scales it to the window; use that logical size for the RmlUi context.
|
||||||
|
// Input events should be converted to render coordinates first (e.g. SDL_ConvertEventToRenderCoordinates()).
|
||||||
|
SDL_Renderer* renderer = SDL_GetRenderer(window);
|
||||||
|
if (renderer)
|
||||||
|
{
|
||||||
|
int logical_w = 0;
|
||||||
|
int logical_h = 0;
|
||||||
|
SDL_RendererLogicalPresentation mode{};
|
||||||
|
if (SDL_GetRenderLogicalPresentation(renderer, &logical_w, &logical_h, &mode)
|
||||||
|
&& mode != SDL_LOGICAL_PRESENTATION_DISABLED
|
||||||
|
&& logical_w > 0 && logical_h > 0)
|
||||||
|
dimensions = Rml::Vector2i(logical_w, logical_h);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
context->SetDimensions(dimensions);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case event_window_leave:
|
||||||
|
{
|
||||||
|
context->ProcessMouseLeave();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
|
||||||
|
{
|
||||||
|
const float display_scale = SDL_GetWindowDisplayScale(window);
|
||||||
|
context->SetDensityIndependentPixelRatio(display_scale);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RMLSDL_WINDOW_EVENTS_END
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Input::KeyIdentifier RmlSDL::ConvertKey(int sdlkey)
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
constexpr auto key_a = SDLK_A;
|
||||||
|
constexpr auto key_b = SDLK_B;
|
||||||
|
constexpr auto key_c = SDLK_C;
|
||||||
|
constexpr auto key_d = SDLK_D;
|
||||||
|
constexpr auto key_e = SDLK_E;
|
||||||
|
constexpr auto key_f = SDLK_F;
|
||||||
|
constexpr auto key_g = SDLK_G;
|
||||||
|
constexpr auto key_h = SDLK_H;
|
||||||
|
constexpr auto key_i = SDLK_I;
|
||||||
|
constexpr auto key_j = SDLK_J;
|
||||||
|
constexpr auto key_k = SDLK_K;
|
||||||
|
constexpr auto key_l = SDLK_L;
|
||||||
|
constexpr auto key_m = SDLK_M;
|
||||||
|
constexpr auto key_n = SDLK_N;
|
||||||
|
constexpr auto key_o = SDLK_O;
|
||||||
|
constexpr auto key_p = SDLK_P;
|
||||||
|
constexpr auto key_q = SDLK_Q;
|
||||||
|
constexpr auto key_r = SDLK_R;
|
||||||
|
constexpr auto key_s = SDLK_S;
|
||||||
|
constexpr auto key_t = SDLK_T;
|
||||||
|
constexpr auto key_u = SDLK_U;
|
||||||
|
constexpr auto key_v = SDLK_V;
|
||||||
|
constexpr auto key_w = SDLK_W;
|
||||||
|
constexpr auto key_x = SDLK_X;
|
||||||
|
constexpr auto key_y = SDLK_Y;
|
||||||
|
constexpr auto key_z = SDLK_Z;
|
||||||
|
constexpr auto key_grave = SDLK_GRAVE;
|
||||||
|
constexpr auto key_dblapostrophe = SDLK_DBLAPOSTROPHE;
|
||||||
|
#else
|
||||||
|
constexpr auto key_a = SDLK_a;
|
||||||
|
constexpr auto key_b = SDLK_b;
|
||||||
|
constexpr auto key_c = SDLK_c;
|
||||||
|
constexpr auto key_d = SDLK_d;
|
||||||
|
constexpr auto key_e = SDLK_e;
|
||||||
|
constexpr auto key_f = SDLK_f;
|
||||||
|
constexpr auto key_g = SDLK_g;
|
||||||
|
constexpr auto key_h = SDLK_h;
|
||||||
|
constexpr auto key_i = SDLK_i;
|
||||||
|
constexpr auto key_j = SDLK_j;
|
||||||
|
constexpr auto key_k = SDLK_k;
|
||||||
|
constexpr auto key_l = SDLK_l;
|
||||||
|
constexpr auto key_m = SDLK_m;
|
||||||
|
constexpr auto key_n = SDLK_n;
|
||||||
|
constexpr auto key_o = SDLK_o;
|
||||||
|
constexpr auto key_p = SDLK_p;
|
||||||
|
constexpr auto key_q = SDLK_q;
|
||||||
|
constexpr auto key_r = SDLK_r;
|
||||||
|
constexpr auto key_s = SDLK_s;
|
||||||
|
constexpr auto key_t = SDLK_t;
|
||||||
|
constexpr auto key_u = SDLK_u;
|
||||||
|
constexpr auto key_v = SDLK_v;
|
||||||
|
constexpr auto key_w = SDLK_w;
|
||||||
|
constexpr auto key_x = SDLK_x;
|
||||||
|
constexpr auto key_y = SDLK_y;
|
||||||
|
constexpr auto key_z = SDLK_z;
|
||||||
|
constexpr auto key_grave = SDLK_BACKQUOTE;
|
||||||
|
constexpr auto key_dblapostrophe = SDLK_QUOTEDBL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
switch (sdlkey)
|
||||||
|
{
|
||||||
|
case SDLK_UNKNOWN: return Rml::Input::KI_UNKNOWN;
|
||||||
|
case SDLK_ESCAPE: return Rml::Input::KI_ESCAPE;
|
||||||
|
case SDLK_SPACE: return Rml::Input::KI_SPACE;
|
||||||
|
case SDLK_0: return Rml::Input::KI_0;
|
||||||
|
case SDLK_1: return Rml::Input::KI_1;
|
||||||
|
case SDLK_2: return Rml::Input::KI_2;
|
||||||
|
case SDLK_3: return Rml::Input::KI_3;
|
||||||
|
case SDLK_4: return Rml::Input::KI_4;
|
||||||
|
case SDLK_5: return Rml::Input::KI_5;
|
||||||
|
case SDLK_6: return Rml::Input::KI_6;
|
||||||
|
case SDLK_7: return Rml::Input::KI_7;
|
||||||
|
case SDLK_8: return Rml::Input::KI_8;
|
||||||
|
case SDLK_9: return Rml::Input::KI_9;
|
||||||
|
case key_a: return Rml::Input::KI_A;
|
||||||
|
case key_b: return Rml::Input::KI_B;
|
||||||
|
case key_c: return Rml::Input::KI_C;
|
||||||
|
case key_d: return Rml::Input::KI_D;
|
||||||
|
case key_e: return Rml::Input::KI_E;
|
||||||
|
case key_f: return Rml::Input::KI_F;
|
||||||
|
case key_g: return Rml::Input::KI_G;
|
||||||
|
case key_h: return Rml::Input::KI_H;
|
||||||
|
case key_i: return Rml::Input::KI_I;
|
||||||
|
case key_j: return Rml::Input::KI_J;
|
||||||
|
case key_k: return Rml::Input::KI_K;
|
||||||
|
case key_l: return Rml::Input::KI_L;
|
||||||
|
case key_m: return Rml::Input::KI_M;
|
||||||
|
case key_n: return Rml::Input::KI_N;
|
||||||
|
case key_o: return Rml::Input::KI_O;
|
||||||
|
case key_p: return Rml::Input::KI_P;
|
||||||
|
case key_q: return Rml::Input::KI_Q;
|
||||||
|
case key_r: return Rml::Input::KI_R;
|
||||||
|
case key_s: return Rml::Input::KI_S;
|
||||||
|
case key_t: return Rml::Input::KI_T;
|
||||||
|
case key_u: return Rml::Input::KI_U;
|
||||||
|
case key_v: return Rml::Input::KI_V;
|
||||||
|
case key_w: return Rml::Input::KI_W;
|
||||||
|
case key_x: return Rml::Input::KI_X;
|
||||||
|
case key_y: return Rml::Input::KI_Y;
|
||||||
|
case key_z: return Rml::Input::KI_Z;
|
||||||
|
case SDLK_SEMICOLON: return Rml::Input::KI_OEM_1;
|
||||||
|
case SDLK_PLUS: return Rml::Input::KI_OEM_PLUS;
|
||||||
|
case SDLK_COMMA: return Rml::Input::KI_OEM_COMMA;
|
||||||
|
case SDLK_MINUS: return Rml::Input::KI_OEM_MINUS;
|
||||||
|
case SDLK_PERIOD: return Rml::Input::KI_OEM_PERIOD;
|
||||||
|
case SDLK_SLASH: return Rml::Input::KI_OEM_2;
|
||||||
|
case key_grave: return Rml::Input::KI_OEM_3;
|
||||||
|
case SDLK_LEFTBRACKET: return Rml::Input::KI_OEM_4;
|
||||||
|
case SDLK_BACKSLASH: return Rml::Input::KI_OEM_5;
|
||||||
|
case SDLK_RIGHTBRACKET: return Rml::Input::KI_OEM_6;
|
||||||
|
case key_dblapostrophe: return Rml::Input::KI_OEM_7;
|
||||||
|
case SDLK_KP_0: return Rml::Input::KI_NUMPAD0;
|
||||||
|
case SDLK_KP_1: return Rml::Input::KI_NUMPAD1;
|
||||||
|
case SDLK_KP_2: return Rml::Input::KI_NUMPAD2;
|
||||||
|
case SDLK_KP_3: return Rml::Input::KI_NUMPAD3;
|
||||||
|
case SDLK_KP_4: return Rml::Input::KI_NUMPAD4;
|
||||||
|
case SDLK_KP_5: return Rml::Input::KI_NUMPAD5;
|
||||||
|
case SDLK_KP_6: return Rml::Input::KI_NUMPAD6;
|
||||||
|
case SDLK_KP_7: return Rml::Input::KI_NUMPAD7;
|
||||||
|
case SDLK_KP_8: return Rml::Input::KI_NUMPAD8;
|
||||||
|
case SDLK_KP_9: return Rml::Input::KI_NUMPAD9;
|
||||||
|
case SDLK_KP_ENTER: return Rml::Input::KI_NUMPADENTER;
|
||||||
|
case SDLK_KP_MULTIPLY: return Rml::Input::KI_MULTIPLY;
|
||||||
|
case SDLK_KP_PLUS: return Rml::Input::KI_ADD;
|
||||||
|
case SDLK_KP_MINUS: return Rml::Input::KI_SUBTRACT;
|
||||||
|
case SDLK_KP_PERIOD: return Rml::Input::KI_DECIMAL;
|
||||||
|
case SDLK_KP_DIVIDE: return Rml::Input::KI_DIVIDE;
|
||||||
|
case SDLK_KP_EQUALS: return Rml::Input::KI_OEM_NEC_EQUAL;
|
||||||
|
case SDLK_BACKSPACE: return Rml::Input::KI_BACK;
|
||||||
|
case SDLK_TAB: return Rml::Input::KI_TAB;
|
||||||
|
case SDLK_CLEAR: return Rml::Input::KI_CLEAR;
|
||||||
|
case SDLK_RETURN: return Rml::Input::KI_RETURN;
|
||||||
|
case SDLK_PAUSE: return Rml::Input::KI_PAUSE;
|
||||||
|
case SDLK_CAPSLOCK: return Rml::Input::KI_CAPITAL;
|
||||||
|
case SDLK_PAGEUP: return Rml::Input::KI_PRIOR;
|
||||||
|
case SDLK_PAGEDOWN: return Rml::Input::KI_NEXT;
|
||||||
|
case SDLK_END: return Rml::Input::KI_END;
|
||||||
|
case SDLK_HOME: return Rml::Input::KI_HOME;
|
||||||
|
case SDLK_LEFT: return Rml::Input::KI_LEFT;
|
||||||
|
case SDLK_UP: return Rml::Input::KI_UP;
|
||||||
|
case SDLK_RIGHT: return Rml::Input::KI_RIGHT;
|
||||||
|
case SDLK_DOWN: return Rml::Input::KI_DOWN;
|
||||||
|
case SDLK_INSERT: return Rml::Input::KI_INSERT;
|
||||||
|
case SDLK_DELETE: return Rml::Input::KI_DELETE;
|
||||||
|
case SDLK_HELP: return Rml::Input::KI_HELP;
|
||||||
|
case SDLK_F1: return Rml::Input::KI_F1;
|
||||||
|
case SDLK_F2: return Rml::Input::KI_F2;
|
||||||
|
case SDLK_F3: return Rml::Input::KI_F3;
|
||||||
|
case SDLK_F4: return Rml::Input::KI_F4;
|
||||||
|
case SDLK_F5: return Rml::Input::KI_F5;
|
||||||
|
case SDLK_F6: return Rml::Input::KI_F6;
|
||||||
|
case SDLK_F7: return Rml::Input::KI_F7;
|
||||||
|
case SDLK_F8: return Rml::Input::KI_F8;
|
||||||
|
case SDLK_F9: return Rml::Input::KI_F9;
|
||||||
|
case SDLK_F10: return Rml::Input::KI_F10;
|
||||||
|
case SDLK_F11: return Rml::Input::KI_F11;
|
||||||
|
case SDLK_F12: return Rml::Input::KI_F12;
|
||||||
|
case SDLK_F13: return Rml::Input::KI_F13;
|
||||||
|
case SDLK_F14: return Rml::Input::KI_F14;
|
||||||
|
case SDLK_F15: return Rml::Input::KI_F15;
|
||||||
|
case SDLK_NUMLOCKCLEAR: return Rml::Input::KI_NUMLOCK;
|
||||||
|
case SDLK_SCROLLLOCK: return Rml::Input::KI_SCROLL;
|
||||||
|
case SDLK_LSHIFT: return Rml::Input::KI_LSHIFT;
|
||||||
|
case SDLK_RSHIFT: return Rml::Input::KI_RSHIFT;
|
||||||
|
case SDLK_LCTRL: return Rml::Input::KI_LCONTROL;
|
||||||
|
case SDLK_RCTRL: return Rml::Input::KI_RCONTROL;
|
||||||
|
case SDLK_LALT: return Rml::Input::KI_LMENU;
|
||||||
|
case SDLK_RALT: return Rml::Input::KI_RMENU;
|
||||||
|
case SDLK_LGUI: return Rml::Input::KI_LMETA;
|
||||||
|
case SDLK_RGUI: return Rml::Input::KI_RMETA;
|
||||||
|
/*
|
||||||
|
case SDLK_LSUPER: return Rml::Input::KI_LWIN;
|
||||||
|
case SDLK_RSUPER: return Rml::Input::KI_RWIN;
|
||||||
|
*/
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return Rml::Input::KI_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlSDL::ConvertMouseButton(int button)
|
||||||
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
|
case SDL_BUTTON_LEFT: return 0;
|
||||||
|
case SDL_BUTTON_RIGHT: return 1;
|
||||||
|
case SDL_BUTTON_MIDDLE: return 2;
|
||||||
|
default: return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlSDL::GetKeyModifierState()
|
||||||
|
{
|
||||||
|
SDL_Keymod sdl_mods = SDL_GetModState();
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
constexpr auto mod_ctrl = SDL_KMOD_CTRL;
|
||||||
|
constexpr auto mod_shift = SDL_KMOD_SHIFT;
|
||||||
|
constexpr auto mod_alt = SDL_KMOD_ALT;
|
||||||
|
constexpr auto mod_num = SDL_KMOD_NUM;
|
||||||
|
constexpr auto mod_caps = SDL_KMOD_CAPS;
|
||||||
|
#else
|
||||||
|
constexpr auto mod_ctrl = KMOD_CTRL;
|
||||||
|
constexpr auto mod_shift = KMOD_SHIFT;
|
||||||
|
constexpr auto mod_alt = KMOD_ALT;
|
||||||
|
constexpr auto mod_num = KMOD_NUM;
|
||||||
|
constexpr auto mod_caps = KMOD_CAPS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
if (sdl_mods & mod_ctrl)
|
||||||
|
retval |= Rml::Input::KM_CTRL;
|
||||||
|
|
||||||
|
if (sdl_mods & mod_shift)
|
||||||
|
retval |= Rml::Input::KM_SHIFT;
|
||||||
|
|
||||||
|
if (sdl_mods & mod_alt)
|
||||||
|
retval |= Rml::Input::KM_ALT;
|
||||||
|
|
||||||
|
if (sdl_mods & mod_num)
|
||||||
|
retval |= Rml::Input::KM_NUMLOCK;
|
||||||
|
|
||||||
|
if (sdl_mods & mod_caps)
|
||||||
|
retval |= Rml::Input::KM_CAPSLOCK;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_SDL::OnActivate(Rml::TextInputContext* input_context)
|
||||||
|
{
|
||||||
|
context = input_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_SDL::OnDeactivate(Rml::TextInputContext* input_context)
|
||||||
|
{
|
||||||
|
if (context == input_context)
|
||||||
|
context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_SDL::OnDestroy(Rml::TextInputContext* input_context)
|
||||||
|
{
|
||||||
|
if (context == input_context)
|
||||||
|
context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_SDL::HandleEdit(const SDL_TextEditingEvent& ev)
|
||||||
|
{
|
||||||
|
if (context == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto string = Rml::String(ev.text);
|
||||||
|
auto length = static_cast<int>(Rml::StringUtilities::LengthUTF8(string));
|
||||||
|
|
||||||
|
auto composing = start != end;
|
||||||
|
|
||||||
|
if (!composing)
|
||||||
|
context->GetSelectionRange(start, end);
|
||||||
|
|
||||||
|
if (composing || length > 0)
|
||||||
|
context->SetText(string, start, end);
|
||||||
|
|
||||||
|
end = start + length;
|
||||||
|
context->SetCompositionRange(start, end);
|
||||||
|
|
||||||
|
if (length > 0 && ev.start >= 0 && ev.length >= 0)
|
||||||
|
context->SetSelectionRange(start + ev.start, start + ev.start + ev.length);
|
||||||
|
else if (composing)
|
||||||
|
context->SetCursorPosition(end);
|
||||||
|
|
||||||
|
// When committing, SDL sends a text editing event with an empty string and a
|
||||||
|
// separate text input event with the committed text.
|
||||||
|
if (composing && length == 0)
|
||||||
|
context->CommitComposition(Rml::StringView());
|
||||||
|
}
|
||||||
78
vendor/rmlui_backend/RmlUi_Platform_SDL.h
vendored
Normal file
78
vendor/rmlui_backend/RmlUi_Platform_SDL.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/TextInputHandler.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
|
||||||
|
#if RMLUI_SDL_VERSION_MAJOR == 3
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#elif RMLUI_SDL_VERSION_MAJOR == 2
|
||||||
|
#include <SDL.h>
|
||||||
|
#else
|
||||||
|
#error "Unspecified RMLUI_SDL_VERSION_MAJOR. Please set this definition to the major version of the SDL library being linked to."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SystemInterface_SDL : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
SystemInterface_SDL(SDL_Window* window);
|
||||||
|
~SystemInterface_SDL();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::SystemInterface --
|
||||||
|
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
|
||||||
|
void SetMouseCursor(const Rml::String& cursor_name) override;
|
||||||
|
|
||||||
|
void SetClipboardText(const Rml::String& text) override;
|
||||||
|
void GetClipboardText(Rml::String& text) override;
|
||||||
|
|
||||||
|
void ActivateKeyboard(Rml::Vector2f caret_position, float line_height) override;
|
||||||
|
void DeactivateKeyboard() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Window* window = nullptr;
|
||||||
|
|
||||||
|
SDL_Cursor* cursor_default = nullptr;
|
||||||
|
SDL_Cursor* cursor_move = nullptr;
|
||||||
|
SDL_Cursor* cursor_pointer = nullptr;
|
||||||
|
SDL_Cursor* cursor_resize = nullptr;
|
||||||
|
SDL_Cursor* cursor_cross = nullptr;
|
||||||
|
SDL_Cursor* cursor_text = nullptr;
|
||||||
|
SDL_Cursor* cursor_unavailable = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace RmlSDL {
|
||||||
|
|
||||||
|
// Applies input on the context based on the given SDL event.
|
||||||
|
//
|
||||||
|
// Note (SDL3 + SDL_Renderer): When using SDL_SetRenderLogicalPresentation(), SDL_Renderer operates in render
|
||||||
|
// coordinates (logical coordinates). Therefore, before passing an SDL_Event to InputEventHandler, input event
|
||||||
|
// coordinates (mouse/touch/etc.) should be converted to render coordinates, e.g.
|
||||||
|
// SDL_ConvertEventToRenderCoordinates(renderer, &ev).
|
||||||
|
// @return True if the event is still propagating, false if it was handled by the context.
|
||||||
|
bool InputEventHandler(Rml::Context* context, SDL_Window* window, SDL_Event& ev);
|
||||||
|
|
||||||
|
// Converts the SDL key to RmlUi key.
|
||||||
|
Rml::Input::KeyIdentifier ConvertKey(int sdl_key);
|
||||||
|
|
||||||
|
// Converts the SDL mouse button to RmlUi mouse button.
|
||||||
|
int ConvertMouseButton(int sdl_mouse_button);
|
||||||
|
|
||||||
|
// Returns the active RmlUi key modifier state.
|
||||||
|
int GetKeyModifierState();
|
||||||
|
|
||||||
|
} // namespace RmlSDL
|
||||||
|
|
||||||
|
class TextInputMethodEditor_SDL final : public Rml::TextInputHandler {
|
||||||
|
public:
|
||||||
|
void OnActivate(Rml::TextInputContext* input_context) override;
|
||||||
|
void OnDeactivate(Rml::TextInputContext* input_context) override;
|
||||||
|
void OnDestroy(Rml::TextInputContext* input_context) override;
|
||||||
|
|
||||||
|
void HandleEdit(const SDL_TextEditingEvent& ev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Rml::TextInputContext* context = nullptr;
|
||||||
|
int start = 0, end = 0;
|
||||||
|
};
|
||||||
287
vendor/rmlui_backend/RmlUi_Platform_SFML.cpp
vendored
Normal file
287
vendor/rmlui_backend/RmlUi_Platform_SFML.cpp
vendored
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
#include "RmlUi_Platform_SFML.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/StringUtilities.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
SystemInterface_SFML::Cursors::Cursors() :
|
||||||
|
cursor_default(sf::Cursor::Type::Arrow), cursor_move(sf::Cursor::Type::SizeAll), cursor_pointer(sf::Cursor::Type::Hand),
|
||||||
|
cursor_resize(sf::Cursor::createFromSystem(sf::Cursor::Type::SizeTopLeftBottomRight).value_or(sf::Cursor(sf::Cursor::Type::SizeAll))),
|
||||||
|
cursor_cross(sf::Cursor::Type::Cross), cursor_text(sf::Cursor::Type::Text), cursor_unavailable(sf::Cursor::Type::NotAllowed)
|
||||||
|
{}
|
||||||
|
SystemInterface_SFML::SystemInterface_SFML()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cursors = std::make_unique<Cursors>();
|
||||||
|
} catch (const sf::Exception& /*exception*/)
|
||||||
|
{
|
||||||
|
cursors.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
SystemInterface_SFML::Cursors::Cursors() {}
|
||||||
|
SystemInterface_SFML::SystemInterface_SFML()
|
||||||
|
{
|
||||||
|
cursors = std::make_unique<Cursors>();
|
||||||
|
bool cursors_valid = true;
|
||||||
|
cursors_valid &= cursors->cursor_default.loadFromSystem(sf::Cursor::Arrow);
|
||||||
|
cursors_valid &= cursors->cursor_move.loadFromSystem(sf::Cursor::SizeAll);
|
||||||
|
cursors_valid &= cursors->cursor_pointer.loadFromSystem(sf::Cursor::Hand);
|
||||||
|
cursors_valid &=
|
||||||
|
cursors->cursor_resize.loadFromSystem(sf::Cursor::SizeTopLeftBottomRight) || cursors->cursor_resize.loadFromSystem(sf::Cursor::SizeAll);
|
||||||
|
cursors_valid &= cursors->cursor_cross.loadFromSystem(sf::Cursor::Cross);
|
||||||
|
cursors_valid &= cursors->cursor_text.loadFromSystem(sf::Cursor::Text);
|
||||||
|
cursors_valid &= cursors->cursor_unavailable.loadFromSystem(sf::Cursor::NotAllowed);
|
||||||
|
if (!cursors_valid)
|
||||||
|
cursors.reset();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SystemInterface_SFML::SetWindow(sf::RenderWindow* in_window)
|
||||||
|
{
|
||||||
|
window = in_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
double SystemInterface_SFML::GetElapsedTime()
|
||||||
|
{
|
||||||
|
return static_cast<double>(timer.getElapsedTime().asMicroseconds()) / 1'000'000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SFML::SetMouseCursor(const Rml::String& cursor_name)
|
||||||
|
{
|
||||||
|
if (cursors && window)
|
||||||
|
{
|
||||||
|
sf::Cursor* cursor = nullptr;
|
||||||
|
if (cursor_name.empty() || cursor_name == "arrow")
|
||||||
|
cursor = &cursors->cursor_default;
|
||||||
|
else if (cursor_name == "move")
|
||||||
|
cursor = &cursors->cursor_move;
|
||||||
|
else if (cursor_name == "pointer")
|
||||||
|
cursor = &cursors->cursor_pointer;
|
||||||
|
else if (cursor_name == "resize")
|
||||||
|
cursor = &cursors->cursor_resize;
|
||||||
|
else if (cursor_name == "cross")
|
||||||
|
cursor = &cursors->cursor_cross;
|
||||||
|
else if (cursor_name == "text")
|
||||||
|
cursor = &cursors->cursor_text;
|
||||||
|
else if (cursor_name == "unavailable")
|
||||||
|
cursor = &cursors->cursor_unavailable;
|
||||||
|
else if (Rml::StringUtilities::StartsWith(cursor_name, "rmlui-scroll"))
|
||||||
|
cursor = &cursors->cursor_move;
|
||||||
|
|
||||||
|
if (cursor)
|
||||||
|
window->setMouseCursor(*cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SFML::SetClipboardText(const Rml::String& text_utf8)
|
||||||
|
{
|
||||||
|
sf::Clipboard::setString(text_utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_SFML::GetClipboardText(Rml::String& text)
|
||||||
|
{
|
||||||
|
text = sf::Clipboard::getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlSFML::InputHandler(Rml::Context* context, const sf::Event& ev)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
|
||||||
|
if (auto mouse_moved = ev.getIf<sf::Event::MouseMoved>())
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseMove(mouse_moved->position.x, mouse_moved->position.y, RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
else if (auto mouse_pressed = ev.getIf<sf::Event::MouseButtonPressed>())
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseButtonDown(int(mouse_pressed->button), RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
else if (auto mouse_released = ev.getIf<sf::Event::MouseButtonReleased>())
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseButtonUp(int(mouse_released->button), RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
else if (auto wheel_scrolled = ev.getIf<sf::Event::MouseWheelScrolled>())
|
||||||
|
{
|
||||||
|
const Rml::Vector2f delta = {
|
||||||
|
wheel_scrolled->wheel == sf::Mouse::Wheel::Horizontal ? -wheel_scrolled->delta : 0.f,
|
||||||
|
wheel_scrolled->wheel == sf::Mouse::Wheel::Vertical ? -wheel_scrolled->delta : 0.f,
|
||||||
|
};
|
||||||
|
result = context->ProcessMouseWheel(delta, RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
else if (ev.is<sf::Event::MouseLeft>())
|
||||||
|
{
|
||||||
|
result = context->ProcessMouseLeave();
|
||||||
|
}
|
||||||
|
else if (auto text_entered = ev.getIf<sf::Event::TextEntered>())
|
||||||
|
{
|
||||||
|
Rml::Character character = Rml::Character(text_entered->unicode);
|
||||||
|
if (character == Rml::Character('\r'))
|
||||||
|
character = Rml::Character('\n');
|
||||||
|
|
||||||
|
if (text_entered->unicode >= 32 || character == Rml::Character('\n'))
|
||||||
|
result = context->ProcessTextInput(character);
|
||||||
|
}
|
||||||
|
else if (auto key_pressed = ev.getIf<sf::Event::KeyPressed>())
|
||||||
|
{
|
||||||
|
result = context->ProcessKeyDown(RmlSFML::ConvertKey(key_pressed->code), RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
else if (auto key_released = ev.getIf<sf::Event::KeyReleased>())
|
||||||
|
{
|
||||||
|
result = context->ProcessKeyUp(RmlSFML::ConvertKey(key_released->code), RmlSFML::GetKeyModifierState());
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case sf::Event::MouseMoved: result = context->ProcessMouseMove(ev.mouseMove.x, ev.mouseMove.y, RmlSFML::GetKeyModifierState()); break;
|
||||||
|
case sf::Event::MouseButtonPressed: result = context->ProcessMouseButtonDown(ev.mouseButton.button, RmlSFML::GetKeyModifierState()); break;
|
||||||
|
case sf::Event::MouseButtonReleased: result = context->ProcessMouseButtonUp(ev.mouseButton.button, RmlSFML::GetKeyModifierState()); break;
|
||||||
|
case sf::Event::MouseWheelMoved: result = context->ProcessMouseWheel(float(-ev.mouseWheel.delta), RmlSFML::GetKeyModifierState()); break;
|
||||||
|
case sf::Event::MouseLeft: result = context->ProcessMouseLeave(); break;
|
||||||
|
case sf::Event::TextEntered:
|
||||||
|
{
|
||||||
|
Rml::Character character = Rml::Character(ev.text.unicode);
|
||||||
|
if (character == Rml::Character('\r'))
|
||||||
|
character = Rml::Character('\n');
|
||||||
|
|
||||||
|
if (ev.text.unicode >= 32 || character == Rml::Character('\n'))
|
||||||
|
result = context->ProcessTextInput(character);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case sf::Event::KeyPressed: result = context->ProcessKeyDown(RmlSFML::ConvertKey(ev.key.code), RmlSFML::GetKeyModifierState()); break;
|
||||||
|
case sf::Event::KeyReleased: result = context->ProcessKeyUp(RmlSFML::ConvertKey(ev.key.code), RmlSFML::GetKeyModifierState()); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Input::KeyIdentifier RmlSFML::ConvertKey(sf::Keyboard::Key sfml_key)
|
||||||
|
{
|
||||||
|
#if SFML_VERSION_MAJOR >= 3
|
||||||
|
constexpr auto sfBackspace = sf::Keyboard::Key::Backspace;
|
||||||
|
constexpr auto sfEnter = sf::Keyboard::Key::Enter;
|
||||||
|
#else
|
||||||
|
constexpr auto sfBackspace = sf::Keyboard::Key::BackSpace;
|
||||||
|
constexpr auto sfEnter = sf::Keyboard::Key::Return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
switch (sfml_key)
|
||||||
|
{
|
||||||
|
case sf::Keyboard::Key::A: return Rml::Input::KI_A;
|
||||||
|
case sf::Keyboard::Key::B: return Rml::Input::KI_B;
|
||||||
|
case sf::Keyboard::Key::C: return Rml::Input::KI_C;
|
||||||
|
case sf::Keyboard::Key::D: return Rml::Input::KI_D;
|
||||||
|
case sf::Keyboard::Key::E: return Rml::Input::KI_E;
|
||||||
|
case sf::Keyboard::Key::F: return Rml::Input::KI_F;
|
||||||
|
case sf::Keyboard::Key::G: return Rml::Input::KI_G;
|
||||||
|
case sf::Keyboard::Key::H: return Rml::Input::KI_H;
|
||||||
|
case sf::Keyboard::Key::I: return Rml::Input::KI_I;
|
||||||
|
case sf::Keyboard::Key::J: return Rml::Input::KI_J;
|
||||||
|
case sf::Keyboard::Key::K: return Rml::Input::KI_K;
|
||||||
|
case sf::Keyboard::Key::L: return Rml::Input::KI_L;
|
||||||
|
case sf::Keyboard::Key::M: return Rml::Input::KI_M;
|
||||||
|
case sf::Keyboard::Key::N: return Rml::Input::KI_N;
|
||||||
|
case sf::Keyboard::Key::O: return Rml::Input::KI_O;
|
||||||
|
case sf::Keyboard::Key::P: return Rml::Input::KI_P;
|
||||||
|
case sf::Keyboard::Key::Q: return Rml::Input::KI_Q;
|
||||||
|
case sf::Keyboard::Key::R: return Rml::Input::KI_R;
|
||||||
|
case sf::Keyboard::Key::S: return Rml::Input::KI_S;
|
||||||
|
case sf::Keyboard::Key::T: return Rml::Input::KI_T;
|
||||||
|
case sf::Keyboard::Key::U: return Rml::Input::KI_U;
|
||||||
|
case sf::Keyboard::Key::V: return Rml::Input::KI_V;
|
||||||
|
case sf::Keyboard::Key::W: return Rml::Input::KI_W;
|
||||||
|
case sf::Keyboard::Key::X: return Rml::Input::KI_X;
|
||||||
|
case sf::Keyboard::Key::Y: return Rml::Input::KI_Y;
|
||||||
|
case sf::Keyboard::Key::Z: return Rml::Input::KI_Z;
|
||||||
|
case sf::Keyboard::Key::Num0: return Rml::Input::KI_0;
|
||||||
|
case sf::Keyboard::Key::Num1: return Rml::Input::KI_1;
|
||||||
|
case sf::Keyboard::Key::Num2: return Rml::Input::KI_2;
|
||||||
|
case sf::Keyboard::Key::Num3: return Rml::Input::KI_3;
|
||||||
|
case sf::Keyboard::Key::Num4: return Rml::Input::KI_4;
|
||||||
|
case sf::Keyboard::Key::Num5: return Rml::Input::KI_5;
|
||||||
|
case sf::Keyboard::Key::Num6: return Rml::Input::KI_6;
|
||||||
|
case sf::Keyboard::Key::Num7: return Rml::Input::KI_7;
|
||||||
|
case sf::Keyboard::Key::Num8: return Rml::Input::KI_8;
|
||||||
|
case sf::Keyboard::Key::Num9: return Rml::Input::KI_9;
|
||||||
|
case sf::Keyboard::Key::Numpad0: return Rml::Input::KI_NUMPAD0;
|
||||||
|
case sf::Keyboard::Key::Numpad1: return Rml::Input::KI_NUMPAD1;
|
||||||
|
case sf::Keyboard::Key::Numpad2: return Rml::Input::KI_NUMPAD2;
|
||||||
|
case sf::Keyboard::Key::Numpad3: return Rml::Input::KI_NUMPAD3;
|
||||||
|
case sf::Keyboard::Key::Numpad4: return Rml::Input::KI_NUMPAD4;
|
||||||
|
case sf::Keyboard::Key::Numpad5: return Rml::Input::KI_NUMPAD5;
|
||||||
|
case sf::Keyboard::Key::Numpad6: return Rml::Input::KI_NUMPAD6;
|
||||||
|
case sf::Keyboard::Key::Numpad7: return Rml::Input::KI_NUMPAD7;
|
||||||
|
case sf::Keyboard::Key::Numpad8: return Rml::Input::KI_NUMPAD8;
|
||||||
|
case sf::Keyboard::Key::Numpad9: return Rml::Input::KI_NUMPAD9;
|
||||||
|
case sf::Keyboard::Key::Left: return Rml::Input::KI_LEFT;
|
||||||
|
case sf::Keyboard::Key::Right: return Rml::Input::KI_RIGHT;
|
||||||
|
case sf::Keyboard::Key::Up: return Rml::Input::KI_UP;
|
||||||
|
case sf::Keyboard::Key::Down: return Rml::Input::KI_DOWN;
|
||||||
|
case sf::Keyboard::Key::Add: return Rml::Input::KI_ADD;
|
||||||
|
case sfBackspace: return Rml::Input::KI_BACK;
|
||||||
|
case sf::Keyboard::Key::Delete: return Rml::Input::KI_DELETE;
|
||||||
|
case sf::Keyboard::Key::Divide: return Rml::Input::KI_DIVIDE;
|
||||||
|
case sf::Keyboard::Key::End: return Rml::Input::KI_END;
|
||||||
|
case sf::Keyboard::Key::Escape: return Rml::Input::KI_ESCAPE;
|
||||||
|
case sf::Keyboard::Key::F1: return Rml::Input::KI_F1;
|
||||||
|
case sf::Keyboard::Key::F2: return Rml::Input::KI_F2;
|
||||||
|
case sf::Keyboard::Key::F3: return Rml::Input::KI_F3;
|
||||||
|
case sf::Keyboard::Key::F4: return Rml::Input::KI_F4;
|
||||||
|
case sf::Keyboard::Key::F5: return Rml::Input::KI_F5;
|
||||||
|
case sf::Keyboard::Key::F6: return Rml::Input::KI_F6;
|
||||||
|
case sf::Keyboard::Key::F7: return Rml::Input::KI_F7;
|
||||||
|
case sf::Keyboard::Key::F8: return Rml::Input::KI_F8;
|
||||||
|
case sf::Keyboard::Key::F9: return Rml::Input::KI_F9;
|
||||||
|
case sf::Keyboard::Key::F10: return Rml::Input::KI_F10;
|
||||||
|
case sf::Keyboard::Key::F11: return Rml::Input::KI_F11;
|
||||||
|
case sf::Keyboard::Key::F12: return Rml::Input::KI_F12;
|
||||||
|
case sf::Keyboard::Key::F13: return Rml::Input::KI_F13;
|
||||||
|
case sf::Keyboard::Key::F14: return Rml::Input::KI_F14;
|
||||||
|
case sf::Keyboard::Key::F15: return Rml::Input::KI_F15;
|
||||||
|
case sf::Keyboard::Key::Home: return Rml::Input::KI_HOME;
|
||||||
|
case sf::Keyboard::Key::Insert: return Rml::Input::KI_INSERT;
|
||||||
|
case sf::Keyboard::Key::LControl: return Rml::Input::KI_LCONTROL;
|
||||||
|
case sf::Keyboard::Key::LShift: return Rml::Input::KI_LSHIFT;
|
||||||
|
case sf::Keyboard::Key::Multiply: return Rml::Input::KI_MULTIPLY;
|
||||||
|
case sf::Keyboard::Key::Pause: return Rml::Input::KI_PAUSE;
|
||||||
|
case sf::Keyboard::Key::RControl: return Rml::Input::KI_RCONTROL;
|
||||||
|
case sfEnter: return Rml::Input::KI_RETURN;
|
||||||
|
case sf::Keyboard::Key::RShift: return Rml::Input::KI_RSHIFT;
|
||||||
|
case sf::Keyboard::Key::Space: return Rml::Input::KI_SPACE;
|
||||||
|
case sf::Keyboard::Key::Subtract: return Rml::Input::KI_SUBTRACT;
|
||||||
|
case sf::Keyboard::Key::Tab: return Rml::Input::KI_TAB;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return Rml::Input::KI_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlSFML::GetKeyModifierState()
|
||||||
|
{
|
||||||
|
int modifiers = 0;
|
||||||
|
|
||||||
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift) || sf::Keyboard::isKeyPressed(sf::Keyboard::Key::RShift))
|
||||||
|
modifiers |= Rml::Input::KM_SHIFT;
|
||||||
|
|
||||||
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LControl) || sf::Keyboard::isKeyPressed(sf::Keyboard::Key::RControl))
|
||||||
|
modifiers |= Rml::Input::KM_CTRL;
|
||||||
|
|
||||||
|
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LAlt) || sf::Keyboard::isKeyPressed(sf::Keyboard::Key::RAlt))
|
||||||
|
modifiers |= Rml::Input::KM_ALT;
|
||||||
|
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
60
vendor/rmlui_backend/RmlUi_Platform_SFML.h
vendored
Normal file
60
vendor/rmlui_backend/RmlUi_Platform_SFML.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <SFML/Graphics.hpp>
|
||||||
|
#include <SFML/System.hpp>
|
||||||
|
#include <SFML/Window.hpp>
|
||||||
|
|
||||||
|
class SystemInterface_SFML : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
SystemInterface_SFML();
|
||||||
|
|
||||||
|
// Optionally, provide or change the window to be used for setting the mouse cursors.
|
||||||
|
// @lifetime Any window provided here must be destroyed before the system interface.
|
||||||
|
// @lifetime The currently active window must stay alive until after the call to Rml::Shutdown.
|
||||||
|
void SetWindow(sf::RenderWindow* window);
|
||||||
|
|
||||||
|
// -- Inherited from Rml::SystemInterface --
|
||||||
|
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
|
||||||
|
void SetMouseCursor(const Rml::String& cursor_name) override;
|
||||||
|
|
||||||
|
void SetClipboardText(const Rml::String& text) override;
|
||||||
|
void GetClipboardText(Rml::String& text) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sf::Clock timer;
|
||||||
|
sf::RenderWindow* window = nullptr;
|
||||||
|
|
||||||
|
struct Cursors {
|
||||||
|
Cursors();
|
||||||
|
sf::Cursor cursor_default;
|
||||||
|
sf::Cursor cursor_move;
|
||||||
|
sf::Cursor cursor_pointer;
|
||||||
|
sf::Cursor cursor_resize;
|
||||||
|
sf::Cursor cursor_cross;
|
||||||
|
sf::Cursor cursor_text;
|
||||||
|
sf::Cursor cursor_unavailable;
|
||||||
|
};
|
||||||
|
Rml::UniquePtr<Cursors> cursors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Optional helper functions for the SFML platform.
|
||||||
|
*/
|
||||||
|
namespace RmlSFML {
|
||||||
|
|
||||||
|
// Applies input on the context based on the given SFML event.
|
||||||
|
// @return True if the event is still propagating, false if it was handled by the context.
|
||||||
|
bool InputHandler(Rml::Context* context, const sf::Event& ev);
|
||||||
|
|
||||||
|
// Converts the SFML key to RmlUi key.
|
||||||
|
Rml::Input::KeyIdentifier ConvertKey(sf::Keyboard::Key sfml_key);
|
||||||
|
|
||||||
|
// Returns the active RmlUi key modifier state.
|
||||||
|
int GetKeyModifierState();
|
||||||
|
|
||||||
|
} // namespace RmlSFML
|
||||||
730
vendor/rmlui_backend/RmlUi_Platform_Win32.cpp
vendored
Normal file
730
vendor/rmlui_backend/RmlUi_Platform_Win32.cpp
vendored
Normal file
@@ -0,0 +1,730 @@
|
|||||||
|
#include "RmlUi_Platform_Win32.h"
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/StringUtilities.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/TextInputContext.h>
|
||||||
|
#include <RmlUi/Core/TextInputHandler.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Used to interact with the input method editor (IME). Users of MinGW should manually link to this.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "imm32")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SystemInterface_Win32::SystemInterface_Win32()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER time_ticks_per_second;
|
||||||
|
QueryPerformanceFrequency(&time_ticks_per_second);
|
||||||
|
QueryPerformanceCounter(&time_startup);
|
||||||
|
|
||||||
|
time_frequency = 1.0 / (double)time_ticks_per_second.QuadPart;
|
||||||
|
|
||||||
|
// Load cursors
|
||||||
|
cursor_default = LoadCursor(nullptr, IDC_ARROW);
|
||||||
|
cursor_move = LoadCursor(nullptr, IDC_SIZEALL);
|
||||||
|
cursor_pointer = LoadCursor(nullptr, IDC_HAND);
|
||||||
|
cursor_resize = LoadCursor(nullptr, IDC_SIZENWSE);
|
||||||
|
cursor_cross = LoadCursor(nullptr, IDC_CROSS);
|
||||||
|
cursor_text = LoadCursor(nullptr, IDC_IBEAM);
|
||||||
|
cursor_unavailable = LoadCursor(nullptr, IDC_NO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemInterface_Win32::~SystemInterface_Win32() = default;
|
||||||
|
|
||||||
|
void SystemInterface_Win32::SetWindow(HWND in_window_handle)
|
||||||
|
{
|
||||||
|
window_handle = in_window_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
double SystemInterface_Win32::GetElapsedTime()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER counter;
|
||||||
|
QueryPerformanceCounter(&counter);
|
||||||
|
|
||||||
|
return double(counter.QuadPart - time_startup.QuadPart) * time_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_Win32::SetMouseCursor(const Rml::String& cursor_name)
|
||||||
|
{
|
||||||
|
if (window_handle)
|
||||||
|
{
|
||||||
|
HCURSOR cursor_handle = nullptr;
|
||||||
|
if (cursor_name.empty() || cursor_name == "arrow")
|
||||||
|
cursor_handle = cursor_default;
|
||||||
|
else if (cursor_name == "move")
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
else if (cursor_name == "pointer")
|
||||||
|
cursor_handle = cursor_pointer;
|
||||||
|
else if (cursor_name == "resize")
|
||||||
|
cursor_handle = cursor_resize;
|
||||||
|
else if (cursor_name == "cross")
|
||||||
|
cursor_handle = cursor_cross;
|
||||||
|
else if (cursor_name == "text")
|
||||||
|
cursor_handle = cursor_text;
|
||||||
|
else if (cursor_name == "unavailable")
|
||||||
|
cursor_handle = cursor_unavailable;
|
||||||
|
else if (Rml::StringUtilities::StartsWith(cursor_name, "rmlui-scroll"))
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
|
||||||
|
if (cursor_handle)
|
||||||
|
{
|
||||||
|
SetCursor(cursor_handle);
|
||||||
|
SetClassLongPtrA(window_handle, GCLP_HCURSOR, (LONG_PTR)cursor_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_Win32::SetClipboardText(const Rml::String& text_utf8)
|
||||||
|
{
|
||||||
|
if (window_handle)
|
||||||
|
{
|
||||||
|
if (!OpenClipboard(window_handle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
EmptyClipboard();
|
||||||
|
|
||||||
|
const std::wstring text = RmlWin32::ConvertToUTF16(text_utf8);
|
||||||
|
const size_t size = sizeof(wchar_t) * (text.size() + 1);
|
||||||
|
|
||||||
|
HGLOBAL clipboard_data = GlobalAlloc(GMEM_FIXED, size);
|
||||||
|
memcpy(clipboard_data, text.data(), size);
|
||||||
|
|
||||||
|
if (SetClipboardData(CF_UNICODETEXT, clipboard_data) == nullptr)
|
||||||
|
{
|
||||||
|
CloseClipboard();
|
||||||
|
GlobalFree(clipboard_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_Win32::GetClipboardText(Rml::String& text)
|
||||||
|
{
|
||||||
|
if (window_handle)
|
||||||
|
{
|
||||||
|
if (!OpenClipboard(window_handle))
|
||||||
|
return;
|
||||||
|
|
||||||
|
HANDLE clipboard_data = GetClipboardData(CF_UNICODETEXT);
|
||||||
|
if (clipboard_data == nullptr)
|
||||||
|
{
|
||||||
|
CloseClipboard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* clipboard_text = (const wchar_t*)GlobalLock(clipboard_data);
|
||||||
|
if (clipboard_text)
|
||||||
|
text = RmlWin32::ConvertToUTF8(clipboard_text);
|
||||||
|
GlobalUnlock(clipboard_data);
|
||||||
|
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_Win32::ActivateKeyboard(Rml::Vector2f caret_position, float line_height)
|
||||||
|
{
|
||||||
|
HIMC himc = ImmGetContext(window_handle);
|
||||||
|
if (himc == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
constexpr LONG BottomMargin = 2;
|
||||||
|
|
||||||
|
// Adjust the position of the input method editor (IME) to the caret.
|
||||||
|
const LONG x = static_cast<LONG>(caret_position.x);
|
||||||
|
const LONG y = static_cast<LONG>(caret_position.y);
|
||||||
|
const LONG w = 1;
|
||||||
|
const LONG h = static_cast<LONG>(line_height) + BottomMargin;
|
||||||
|
|
||||||
|
COMPOSITIONFORM comp = {};
|
||||||
|
comp.dwStyle = CFS_FORCE_POSITION;
|
||||||
|
comp.ptCurrentPos = {x, y};
|
||||||
|
ImmSetCompositionWindow(himc, &comp);
|
||||||
|
|
||||||
|
CANDIDATEFORM cand = {};
|
||||||
|
cand.dwStyle = CFS_EXCLUDE;
|
||||||
|
cand.ptCurrentPos = {x, y};
|
||||||
|
cand.rcArea = {x, y, x + w, y + h};
|
||||||
|
ImmSetCandidateWindow(himc, &cand);
|
||||||
|
|
||||||
|
ImmReleaseContext(window_handle, himc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::String RmlWin32::ConvertToUTF8(const std::wstring& wstr)
|
||||||
|
{
|
||||||
|
const int count = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
|
||||||
|
Rml::String str(count, 0);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring RmlWin32::ConvertToUTF16(const Rml::String& str)
|
||||||
|
{
|
||||||
|
const int count = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), NULL, 0);
|
||||||
|
std::wstring wstr(count, 0);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &wstr[0], count);
|
||||||
|
return wstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int IMEGetCursorPosition(HIMC context)
|
||||||
|
{
|
||||||
|
return ImmGetCompositionString(context, GCS_CURSORPOS, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::wstring IMEGetCompositionString(HIMC context, bool finalize)
|
||||||
|
{
|
||||||
|
DWORD type = finalize ? GCS_RESULTSTR : GCS_COMPSTR;
|
||||||
|
int len_bytes = ImmGetCompositionString(context, type, nullptr, 0);
|
||||||
|
|
||||||
|
if (len_bytes <= 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
int len_chars = len_bytes / sizeof(TCHAR);
|
||||||
|
Rml::UniquePtr<TCHAR[]> buffer(new TCHAR[len_chars + 1]);
|
||||||
|
ImmGetCompositionString(context, type, buffer.get(), len_bytes);
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
return std::wstring(buffer.get(), len_chars);
|
||||||
|
#else
|
||||||
|
return RmlWin32::ConvertToUTF16(Rml::String(buffer.get(), len_chars));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IMECompleteComposition(HWND window_handle)
|
||||||
|
{
|
||||||
|
if (HIMC context = ImmGetContext(window_handle))
|
||||||
|
{
|
||||||
|
ImmNotifyIME(context, NI_COMPOSITIONSTR, CPS_COMPLETE, NULL);
|
||||||
|
ImmReleaseContext(window_handle, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlWin32::WindowProcedure(Rml::Context* context, TextInputMethodEditor_Win32& text_input_method_editor, HWND window_handle, UINT message,
|
||||||
|
WPARAM w_param, LPARAM l_param)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
static bool tracking_mouse_leave = false;
|
||||||
|
|
||||||
|
// If the user tries to interact with the window by using the mouse in any way, end the
|
||||||
|
// composition by committing the current string. This behavior is identical to other
|
||||||
|
// browsers and is expected, yet, Windows does not send any IME messages in such a case.
|
||||||
|
if (text_input_method_editor.IsComposing() && message >= WM_LBUTTONDOWN && message <= WM_MBUTTONDBLCLK)
|
||||||
|
IMECompleteComposition(window_handle);
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
result = context->ProcessMouseButtonDown(0, RmlWin32::GetKeyModifierState());
|
||||||
|
SetCapture(window_handle);
|
||||||
|
break;
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
ReleaseCapture();
|
||||||
|
result = context->ProcessMouseButtonUp(0, RmlWin32::GetKeyModifierState());
|
||||||
|
break;
|
||||||
|
case WM_RBUTTONDOWN: result = context->ProcessMouseButtonDown(1, RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_RBUTTONUP: result = context->ProcessMouseButtonUp(1, RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_MBUTTONDOWN: result = context->ProcessMouseButtonDown(2, RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_MBUTTONUP: result = context->ProcessMouseButtonUp(2, RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
result = context->ProcessMouseMove(static_cast<int>((short)LOWORD(l_param)), static_cast<int>((short)HIWORD(l_param)),
|
||||||
|
RmlWin32::GetKeyModifierState());
|
||||||
|
|
||||||
|
if (!tracking_mouse_leave)
|
||||||
|
{
|
||||||
|
TRACKMOUSEEVENT tme = {};
|
||||||
|
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||||
|
tme.dwFlags = TME_LEAVE;
|
||||||
|
tme.hwndTrack = window_handle;
|
||||||
|
tracking_mouse_leave = TrackMouseEvent(&tme);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_MOUSEWHEEL:
|
||||||
|
result = context->ProcessMouseWheel(static_cast<float>((short)HIWORD(w_param)) / static_cast<float>(-WHEEL_DELTA),
|
||||||
|
RmlWin32::GetKeyModifierState());
|
||||||
|
break;
|
||||||
|
case WM_MOUSELEAVE:
|
||||||
|
result = context->ProcessMouseLeave();
|
||||||
|
tracking_mouse_leave = false;
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN: result = context->ProcessKeyDown(RmlWin32::ConvertKey((int)w_param), RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_KEYUP: result = context->ProcessKeyUp(RmlWin32::ConvertKey((int)w_param), RmlWin32::GetKeyModifierState()); break;
|
||||||
|
case WM_CHAR:
|
||||||
|
{
|
||||||
|
static wchar_t first_u16_code_unit = 0;
|
||||||
|
|
||||||
|
const wchar_t c = (wchar_t)w_param;
|
||||||
|
Rml::Character character = (Rml::Character)c;
|
||||||
|
|
||||||
|
// Windows sends two-wide characters as two messages.
|
||||||
|
if (c >= 0xD800 && c < 0xDC00)
|
||||||
|
{
|
||||||
|
// First 16-bit code unit of a two-wide character.
|
||||||
|
first_u16_code_unit = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (c >= 0xDC00 && c < 0xE000 && first_u16_code_unit != 0)
|
||||||
|
{
|
||||||
|
// Second 16-bit code unit of a two-wide character.
|
||||||
|
Rml::String utf8 = ConvertToUTF8(std::wstring{first_u16_code_unit, c});
|
||||||
|
character = Rml::StringUtilities::ToCharacter(utf8.data(), utf8.data() + utf8.size());
|
||||||
|
}
|
||||||
|
else if (c == '\r')
|
||||||
|
{
|
||||||
|
// Windows sends new-lines as carriage returns, convert to endlines.
|
||||||
|
character = (Rml::Character)'\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
first_u16_code_unit = 0;
|
||||||
|
|
||||||
|
// Only send through printable characters.
|
||||||
|
if (((char32_t)character >= 32 || character == (Rml::Character)'\n') && character != (Rml::Character)127)
|
||||||
|
result = context->ProcessTextInput(character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_IME_STARTCOMPOSITION:
|
||||||
|
text_input_method_editor.StartComposition();
|
||||||
|
// Prevent the native composition window from appearing by capturing the message.
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
case WM_IME_ENDCOMPOSITION:
|
||||||
|
if (text_input_method_editor.IsComposing())
|
||||||
|
text_input_method_editor.ConfirmComposition(Rml::StringView());
|
||||||
|
break;
|
||||||
|
case WM_IME_COMPOSITION:
|
||||||
|
{
|
||||||
|
HIMC imm_context = ImmGetContext(window_handle);
|
||||||
|
|
||||||
|
// Not every IME starts a composition.
|
||||||
|
if (!text_input_method_editor.IsComposing())
|
||||||
|
text_input_method_editor.StartComposition();
|
||||||
|
|
||||||
|
if (!!(l_param & GCS_CURSORPOS))
|
||||||
|
{
|
||||||
|
// The cursor position is the wchar_t offset in the composition string. Because we
|
||||||
|
// work with UTF-8 and not UTF-16, we will have to convert the character offset.
|
||||||
|
int cursor_pos = IMEGetCursorPosition(imm_context);
|
||||||
|
|
||||||
|
std::wstring composition = IMEGetCompositionString(imm_context, false);
|
||||||
|
Rml::String converted = RmlWin32::ConvertToUTF8(composition.substr(0, cursor_pos));
|
||||||
|
cursor_pos = (int)Rml::StringUtilities::LengthUTF8(converted);
|
||||||
|
|
||||||
|
text_input_method_editor.SetCursorPosition(cursor_pos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!(l_param & CS_NOMOVECARET))
|
||||||
|
{
|
||||||
|
// Suppress the cursor position update. CS_NOMOVECARET is always a part of a more
|
||||||
|
// complex message which means that the cursor is updated from a different event.
|
||||||
|
text_input_method_editor.SetCursorPosition(-1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!(l_param & GCS_RESULTSTR))
|
||||||
|
{
|
||||||
|
std::wstring composition = IMEGetCompositionString(imm_context, true);
|
||||||
|
text_input_method_editor.ConfirmComposition(RmlWin32::ConvertToUTF8(composition));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!(l_param & GCS_COMPSTR))
|
||||||
|
{
|
||||||
|
std::wstring composition = IMEGetCompositionString(imm_context, false);
|
||||||
|
text_input_method_editor.SetComposition(RmlWin32::ConvertToUTF8(composition));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The composition has been canceled.
|
||||||
|
if (!l_param)
|
||||||
|
text_input_method_editor.CancelComposition();
|
||||||
|
|
||||||
|
ImmReleaseContext(window_handle, imm_context);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_IME_CHAR:
|
||||||
|
case WM_IME_REQUEST:
|
||||||
|
// Ignore WM_IME_CHAR and WM_IME_REQUEST to block the system from appending the composition string.
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlWin32::GetKeyModifierState()
|
||||||
|
{
|
||||||
|
int key_modifier_state = 0;
|
||||||
|
|
||||||
|
if (GetKeyState(VK_CAPITAL) & 1)
|
||||||
|
key_modifier_state |= Rml::Input::KM_CAPSLOCK;
|
||||||
|
|
||||||
|
if (GetKeyState(VK_NUMLOCK) & 1)
|
||||||
|
key_modifier_state |= Rml::Input::KM_NUMLOCK;
|
||||||
|
|
||||||
|
if (HIWORD(GetKeyState(VK_SHIFT)) & 1)
|
||||||
|
key_modifier_state |= Rml::Input::KM_SHIFT;
|
||||||
|
|
||||||
|
if (HIWORD(GetKeyState(VK_CONTROL)) & 1)
|
||||||
|
key_modifier_state |= Rml::Input::KM_CTRL;
|
||||||
|
|
||||||
|
if (HIWORD(GetKeyState(VK_MENU)) & 1)
|
||||||
|
key_modifier_state |= Rml::Input::KM_ALT;
|
||||||
|
|
||||||
|
return key_modifier_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are defined in winuser.h of MinGW 64 but are missing from MinGW 32
|
||||||
|
// Visual Studio has them by default
|
||||||
|
#if defined(__MINGW32__) && !defined(__MINGW64__)
|
||||||
|
#define VK_OEM_NEC_EQUAL 0x92
|
||||||
|
#define VK_OEM_FJ_JISHO 0x92
|
||||||
|
#define VK_OEM_FJ_MASSHOU 0x93
|
||||||
|
#define VK_OEM_FJ_TOUROKU 0x94
|
||||||
|
#define VK_OEM_FJ_LOYA 0x95
|
||||||
|
#define VK_OEM_FJ_ROYA 0x96
|
||||||
|
#define VK_OEM_AX 0xE1
|
||||||
|
#define VK_ICO_HELP 0xE3
|
||||||
|
#define VK_ICO_00 0xE4
|
||||||
|
#define VK_ICO_CLEAR 0xE6
|
||||||
|
#endif // !defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
|
||||||
|
Rml::Input::KeyIdentifier RmlWin32::ConvertKey(int win32_key_code)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
switch (win32_key_code)
|
||||||
|
{
|
||||||
|
case 'A': return Rml::Input::KI_A;
|
||||||
|
case 'B': return Rml::Input::KI_B;
|
||||||
|
case 'C': return Rml::Input::KI_C;
|
||||||
|
case 'D': return Rml::Input::KI_D;
|
||||||
|
case 'E': return Rml::Input::KI_E;
|
||||||
|
case 'F': return Rml::Input::KI_F;
|
||||||
|
case 'G': return Rml::Input::KI_G;
|
||||||
|
case 'H': return Rml::Input::KI_H;
|
||||||
|
case 'I': return Rml::Input::KI_I;
|
||||||
|
case 'J': return Rml::Input::KI_J;
|
||||||
|
case 'K': return Rml::Input::KI_K;
|
||||||
|
case 'L': return Rml::Input::KI_L;
|
||||||
|
case 'M': return Rml::Input::KI_M;
|
||||||
|
case 'N': return Rml::Input::KI_N;
|
||||||
|
case 'O': return Rml::Input::KI_O;
|
||||||
|
case 'P': return Rml::Input::KI_P;
|
||||||
|
case 'Q': return Rml::Input::KI_Q;
|
||||||
|
case 'R': return Rml::Input::KI_R;
|
||||||
|
case 'S': return Rml::Input::KI_S;
|
||||||
|
case 'T': return Rml::Input::KI_T;
|
||||||
|
case 'U': return Rml::Input::KI_U;
|
||||||
|
case 'V': return Rml::Input::KI_V;
|
||||||
|
case 'W': return Rml::Input::KI_W;
|
||||||
|
case 'X': return Rml::Input::KI_X;
|
||||||
|
case 'Y': return Rml::Input::KI_Y;
|
||||||
|
case 'Z': return Rml::Input::KI_Z;
|
||||||
|
|
||||||
|
case '0': return Rml::Input::KI_0;
|
||||||
|
case '1': return Rml::Input::KI_1;
|
||||||
|
case '2': return Rml::Input::KI_2;
|
||||||
|
case '3': return Rml::Input::KI_3;
|
||||||
|
case '4': return Rml::Input::KI_4;
|
||||||
|
case '5': return Rml::Input::KI_5;
|
||||||
|
case '6': return Rml::Input::KI_6;
|
||||||
|
case '7': return Rml::Input::KI_7;
|
||||||
|
case '8': return Rml::Input::KI_8;
|
||||||
|
case '9': return Rml::Input::KI_9;
|
||||||
|
|
||||||
|
case VK_BACK: return Rml::Input::KI_BACK;
|
||||||
|
case VK_TAB: return Rml::Input::KI_TAB;
|
||||||
|
|
||||||
|
case VK_CLEAR: return Rml::Input::KI_CLEAR;
|
||||||
|
case VK_RETURN: return Rml::Input::KI_RETURN;
|
||||||
|
|
||||||
|
case VK_PAUSE: return Rml::Input::KI_PAUSE;
|
||||||
|
case VK_CAPITAL: return Rml::Input::KI_CAPITAL;
|
||||||
|
|
||||||
|
case VK_KANA: return Rml::Input::KI_KANA;
|
||||||
|
//case VK_HANGUL: return Rml::Input::KI_HANGUL; /* overlaps with VK_KANA */
|
||||||
|
case VK_JUNJA: return Rml::Input::KI_JUNJA;
|
||||||
|
case VK_FINAL: return Rml::Input::KI_FINAL;
|
||||||
|
case VK_HANJA: return Rml::Input::KI_HANJA;
|
||||||
|
//case VK_KANJI: return Rml::Input::KI_KANJI; /* overlaps with VK_HANJA */
|
||||||
|
|
||||||
|
case VK_ESCAPE: return Rml::Input::KI_ESCAPE;
|
||||||
|
|
||||||
|
case VK_CONVERT: return Rml::Input::KI_CONVERT;
|
||||||
|
case VK_NONCONVERT: return Rml::Input::KI_NONCONVERT;
|
||||||
|
case VK_ACCEPT: return Rml::Input::KI_ACCEPT;
|
||||||
|
case VK_MODECHANGE: return Rml::Input::KI_MODECHANGE;
|
||||||
|
|
||||||
|
case VK_SPACE: return Rml::Input::KI_SPACE;
|
||||||
|
case VK_PRIOR: return Rml::Input::KI_PRIOR;
|
||||||
|
case VK_NEXT: return Rml::Input::KI_NEXT;
|
||||||
|
case VK_END: return Rml::Input::KI_END;
|
||||||
|
case VK_HOME: return Rml::Input::KI_HOME;
|
||||||
|
case VK_LEFT: return Rml::Input::KI_LEFT;
|
||||||
|
case VK_UP: return Rml::Input::KI_UP;
|
||||||
|
case VK_RIGHT: return Rml::Input::KI_RIGHT;
|
||||||
|
case VK_DOWN: return Rml::Input::KI_DOWN;
|
||||||
|
case VK_SELECT: return Rml::Input::KI_SELECT;
|
||||||
|
case VK_PRINT: return Rml::Input::KI_PRINT;
|
||||||
|
case VK_EXECUTE: return Rml::Input::KI_EXECUTE;
|
||||||
|
case VK_SNAPSHOT: return Rml::Input::KI_SNAPSHOT;
|
||||||
|
case VK_INSERT: return Rml::Input::KI_INSERT;
|
||||||
|
case VK_DELETE: return Rml::Input::KI_DELETE;
|
||||||
|
case VK_HELP: return Rml::Input::KI_HELP;
|
||||||
|
|
||||||
|
case VK_LWIN: return Rml::Input::KI_LWIN;
|
||||||
|
case VK_RWIN: return Rml::Input::KI_RWIN;
|
||||||
|
case VK_APPS: return Rml::Input::KI_APPS;
|
||||||
|
|
||||||
|
case VK_SLEEP: return Rml::Input::KI_SLEEP;
|
||||||
|
|
||||||
|
case VK_NUMPAD0: return Rml::Input::KI_NUMPAD0;
|
||||||
|
case VK_NUMPAD1: return Rml::Input::KI_NUMPAD1;
|
||||||
|
case VK_NUMPAD2: return Rml::Input::KI_NUMPAD2;
|
||||||
|
case VK_NUMPAD3: return Rml::Input::KI_NUMPAD3;
|
||||||
|
case VK_NUMPAD4: return Rml::Input::KI_NUMPAD4;
|
||||||
|
case VK_NUMPAD5: return Rml::Input::KI_NUMPAD5;
|
||||||
|
case VK_NUMPAD6: return Rml::Input::KI_NUMPAD6;
|
||||||
|
case VK_NUMPAD7: return Rml::Input::KI_NUMPAD7;
|
||||||
|
case VK_NUMPAD8: return Rml::Input::KI_NUMPAD8;
|
||||||
|
case VK_NUMPAD9: return Rml::Input::KI_NUMPAD9;
|
||||||
|
case VK_MULTIPLY: return Rml::Input::KI_MULTIPLY;
|
||||||
|
case VK_ADD: return Rml::Input::KI_ADD;
|
||||||
|
case VK_SEPARATOR: return Rml::Input::KI_SEPARATOR;
|
||||||
|
case VK_SUBTRACT: return Rml::Input::KI_SUBTRACT;
|
||||||
|
case VK_DECIMAL: return Rml::Input::KI_DECIMAL;
|
||||||
|
case VK_DIVIDE: return Rml::Input::KI_DIVIDE;
|
||||||
|
case VK_F1: return Rml::Input::KI_F1;
|
||||||
|
case VK_F2: return Rml::Input::KI_F2;
|
||||||
|
case VK_F3: return Rml::Input::KI_F3;
|
||||||
|
case VK_F4: return Rml::Input::KI_F4;
|
||||||
|
case VK_F5: return Rml::Input::KI_F5;
|
||||||
|
case VK_F6: return Rml::Input::KI_F6;
|
||||||
|
case VK_F7: return Rml::Input::KI_F7;
|
||||||
|
case VK_F8: return Rml::Input::KI_F8;
|
||||||
|
case VK_F9: return Rml::Input::KI_F9;
|
||||||
|
case VK_F10: return Rml::Input::KI_F10;
|
||||||
|
case VK_F11: return Rml::Input::KI_F11;
|
||||||
|
case VK_F12: return Rml::Input::KI_F12;
|
||||||
|
case VK_F13: return Rml::Input::KI_F13;
|
||||||
|
case VK_F14: return Rml::Input::KI_F14;
|
||||||
|
case VK_F15: return Rml::Input::KI_F15;
|
||||||
|
case VK_F16: return Rml::Input::KI_F16;
|
||||||
|
case VK_F17: return Rml::Input::KI_F17;
|
||||||
|
case VK_F18: return Rml::Input::KI_F18;
|
||||||
|
case VK_F19: return Rml::Input::KI_F19;
|
||||||
|
case VK_F20: return Rml::Input::KI_F20;
|
||||||
|
case VK_F21: return Rml::Input::KI_F21;
|
||||||
|
case VK_F22: return Rml::Input::KI_F22;
|
||||||
|
case VK_F23: return Rml::Input::KI_F23;
|
||||||
|
case VK_F24: return Rml::Input::KI_F24;
|
||||||
|
|
||||||
|
case VK_NUMLOCK: return Rml::Input::KI_NUMLOCK;
|
||||||
|
case VK_SCROLL: return Rml::Input::KI_SCROLL;
|
||||||
|
|
||||||
|
case VK_OEM_NEC_EQUAL: return Rml::Input::KI_OEM_NEC_EQUAL;
|
||||||
|
|
||||||
|
//case VK_OEM_FJ_JISHO: return Rml::Input::KI_OEM_FJ_JISHO; /* overlaps with VK_OEM_NEC_EQUAL */
|
||||||
|
case VK_OEM_FJ_MASSHOU: return Rml::Input::KI_OEM_FJ_MASSHOU;
|
||||||
|
case VK_OEM_FJ_TOUROKU: return Rml::Input::KI_OEM_FJ_TOUROKU;
|
||||||
|
case VK_OEM_FJ_LOYA: return Rml::Input::KI_OEM_FJ_LOYA;
|
||||||
|
case VK_OEM_FJ_ROYA: return Rml::Input::KI_OEM_FJ_ROYA;
|
||||||
|
|
||||||
|
case VK_SHIFT: return Rml::Input::KI_LSHIFT;
|
||||||
|
case VK_CONTROL: return Rml::Input::KI_LCONTROL;
|
||||||
|
case VK_MENU: return Rml::Input::KI_LMENU;
|
||||||
|
|
||||||
|
case VK_BROWSER_BACK: return Rml::Input::KI_BROWSER_BACK;
|
||||||
|
case VK_BROWSER_FORWARD: return Rml::Input::KI_BROWSER_FORWARD;
|
||||||
|
case VK_BROWSER_REFRESH: return Rml::Input::KI_BROWSER_REFRESH;
|
||||||
|
case VK_BROWSER_STOP: return Rml::Input::KI_BROWSER_STOP;
|
||||||
|
case VK_BROWSER_SEARCH: return Rml::Input::KI_BROWSER_SEARCH;
|
||||||
|
case VK_BROWSER_FAVORITES: return Rml::Input::KI_BROWSER_FAVORITES;
|
||||||
|
case VK_BROWSER_HOME: return Rml::Input::KI_BROWSER_HOME;
|
||||||
|
|
||||||
|
case VK_VOLUME_MUTE: return Rml::Input::KI_VOLUME_MUTE;
|
||||||
|
case VK_VOLUME_DOWN: return Rml::Input::KI_VOLUME_DOWN;
|
||||||
|
case VK_VOLUME_UP: return Rml::Input::KI_VOLUME_UP;
|
||||||
|
case VK_MEDIA_NEXT_TRACK: return Rml::Input::KI_MEDIA_NEXT_TRACK;
|
||||||
|
case VK_MEDIA_PREV_TRACK: return Rml::Input::KI_MEDIA_PREV_TRACK;
|
||||||
|
case VK_MEDIA_STOP: return Rml::Input::KI_MEDIA_STOP;
|
||||||
|
case VK_MEDIA_PLAY_PAUSE: return Rml::Input::KI_MEDIA_PLAY_PAUSE;
|
||||||
|
case VK_LAUNCH_MAIL: return Rml::Input::KI_LAUNCH_MAIL;
|
||||||
|
case VK_LAUNCH_MEDIA_SELECT: return Rml::Input::KI_LAUNCH_MEDIA_SELECT;
|
||||||
|
case VK_LAUNCH_APP1: return Rml::Input::KI_LAUNCH_APP1;
|
||||||
|
case VK_LAUNCH_APP2: return Rml::Input::KI_LAUNCH_APP2;
|
||||||
|
|
||||||
|
case VK_OEM_1: return Rml::Input::KI_OEM_1;
|
||||||
|
case VK_OEM_PLUS: return Rml::Input::KI_OEM_PLUS;
|
||||||
|
case VK_OEM_COMMA: return Rml::Input::KI_OEM_COMMA;
|
||||||
|
case VK_OEM_MINUS: return Rml::Input::KI_OEM_MINUS;
|
||||||
|
case VK_OEM_PERIOD: return Rml::Input::KI_OEM_PERIOD;
|
||||||
|
case VK_OEM_2: return Rml::Input::KI_OEM_2;
|
||||||
|
case VK_OEM_3: return Rml::Input::KI_OEM_3;
|
||||||
|
|
||||||
|
case VK_OEM_4: return Rml::Input::KI_OEM_4;
|
||||||
|
case VK_OEM_5: return Rml::Input::KI_OEM_5;
|
||||||
|
case VK_OEM_6: return Rml::Input::KI_OEM_6;
|
||||||
|
case VK_OEM_7: return Rml::Input::KI_OEM_7;
|
||||||
|
case VK_OEM_8: return Rml::Input::KI_OEM_8;
|
||||||
|
|
||||||
|
case VK_OEM_AX: return Rml::Input::KI_OEM_AX;
|
||||||
|
case VK_OEM_102: return Rml::Input::KI_OEM_102;
|
||||||
|
case VK_ICO_HELP: return Rml::Input::KI_ICO_HELP;
|
||||||
|
case VK_ICO_00: return Rml::Input::KI_ICO_00;
|
||||||
|
|
||||||
|
case VK_PROCESSKEY: return Rml::Input::KI_PROCESSKEY;
|
||||||
|
|
||||||
|
case VK_ICO_CLEAR: return Rml::Input::KI_ICO_CLEAR;
|
||||||
|
|
||||||
|
case VK_ATTN: return Rml::Input::KI_ATTN;
|
||||||
|
case VK_CRSEL: return Rml::Input::KI_CRSEL;
|
||||||
|
case VK_EXSEL: return Rml::Input::KI_EXSEL;
|
||||||
|
case VK_EREOF: return Rml::Input::KI_EREOF;
|
||||||
|
case VK_PLAY: return Rml::Input::KI_PLAY;
|
||||||
|
case VK_ZOOM: return Rml::Input::KI_ZOOM;
|
||||||
|
case VK_PA1: return Rml::Input::KI_PA1;
|
||||||
|
case VK_OEM_CLEAR: return Rml::Input::KI_OEM_CLEAR;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return Rml::Input::KI_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInputMethodEditor_Win32::TextInputMethodEditor_Win32() :
|
||||||
|
input_context(nullptr), composing(false), cursor_pos(-1), composition_range_start(0), composition_range_end(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::OnActivate(Rml::TextInputContext* _input_context)
|
||||||
|
{
|
||||||
|
input_context = _input_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::OnDeactivate(Rml::TextInputContext* _input_context)
|
||||||
|
{
|
||||||
|
if (input_context == _input_context)
|
||||||
|
input_context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::OnDestroy(Rml::TextInputContext* _input_context)
|
||||||
|
{
|
||||||
|
if (input_context == _input_context)
|
||||||
|
input_context = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextInputMethodEditor_Win32::IsComposing() const
|
||||||
|
{
|
||||||
|
return composing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::StartComposition()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(!composing);
|
||||||
|
composing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::EndComposition()
|
||||||
|
{
|
||||||
|
if (input_context != nullptr)
|
||||||
|
input_context->SetCompositionRange(0, 0);
|
||||||
|
|
||||||
|
RMLUI_ASSERT(composing);
|
||||||
|
composing = false;
|
||||||
|
|
||||||
|
composition_range_start = 0;
|
||||||
|
composition_range_end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::CancelComposition()
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(IsComposing());
|
||||||
|
|
||||||
|
if (input_context != nullptr)
|
||||||
|
{
|
||||||
|
// Purge the current composition string.
|
||||||
|
input_context->SetText(Rml::StringView(), composition_range_start, composition_range_end);
|
||||||
|
// Move the cursor back to where the composition began.
|
||||||
|
input_context->SetCursorPosition(composition_range_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
EndComposition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::SetComposition(Rml::StringView composition)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(IsComposing());
|
||||||
|
|
||||||
|
SetCompositionString(composition);
|
||||||
|
UpdateCursorPosition();
|
||||||
|
|
||||||
|
// Update the composition range only if the cursor can be moved around. Editors working with a single
|
||||||
|
// character (e.g., Hangul IME) should have no visual feedback; they use a selection range instead.
|
||||||
|
if (cursor_pos != -1 && input_context != nullptr)
|
||||||
|
input_context->SetCompositionRange(composition_range_start, composition_range_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::ConfirmComposition(Rml::StringView composition)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(IsComposing());
|
||||||
|
|
||||||
|
SetCompositionString(composition);
|
||||||
|
|
||||||
|
if (input_context != nullptr)
|
||||||
|
{
|
||||||
|
input_context->SetCompositionRange(composition_range_start, composition_range_end);
|
||||||
|
input_context->CommitComposition(composition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the cursor to the end of the string.
|
||||||
|
SetCursorPosition(composition_range_end - composition_range_start, true);
|
||||||
|
|
||||||
|
EndComposition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::SetCursorPosition(int _cursor_pos, bool update)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(IsComposing());
|
||||||
|
|
||||||
|
cursor_pos = _cursor_pos;
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
UpdateCursorPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::SetCompositionString(Rml::StringView composition)
|
||||||
|
{
|
||||||
|
if (input_context == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Retrieve the composition range if it is missing.
|
||||||
|
if (composition_range_start == 0 && composition_range_end == 0)
|
||||||
|
input_context->GetSelectionRange(composition_range_start, composition_range_end);
|
||||||
|
|
||||||
|
input_context->SetText(composition, composition_range_start, composition_range_end);
|
||||||
|
|
||||||
|
size_t length = Rml::StringUtilities::LengthUTF8(composition);
|
||||||
|
composition_range_end = composition_range_start + (int)length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextInputMethodEditor_Win32::UpdateCursorPosition()
|
||||||
|
{
|
||||||
|
// Cursor position update happens before a composition is set; ignore this event.
|
||||||
|
if (input_context == nullptr || (composition_range_start == 0 && composition_range_end == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cursor_pos != -1)
|
||||||
|
{
|
||||||
|
int position = composition_range_start + cursor_pos;
|
||||||
|
input_context->SetCursorPosition(position);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the API reports no cursor position, select the entire composition string for a better UX.
|
||||||
|
input_context->SetSelectionRange(composition_range_start, composition_range_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
119
vendor/rmlui_backend/RmlUi_Platform_Win32.h
vendored
Normal file
119
vendor/rmlui_backend/RmlUi_Platform_Win32.h
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/StringUtilities.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/TextInputHandler.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class SystemInterface_Win32 : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
SystemInterface_Win32();
|
||||||
|
~SystemInterface_Win32();
|
||||||
|
|
||||||
|
// Optionally, provide or change the window to be used for setting the mouse cursor, clipboard text and IME position.
|
||||||
|
void SetWindow(HWND window_handle);
|
||||||
|
|
||||||
|
// -- Inherited from Rml::SystemInterface --
|
||||||
|
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
|
||||||
|
void SetMouseCursor(const Rml::String& cursor_name) override;
|
||||||
|
|
||||||
|
void SetClipboardText(const Rml::String& text) override;
|
||||||
|
void GetClipboardText(Rml::String& text) override;
|
||||||
|
|
||||||
|
void ActivateKeyboard(Rml::Vector2f caret_position, float line_height) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HWND window_handle = nullptr;
|
||||||
|
|
||||||
|
double time_frequency = {};
|
||||||
|
LARGE_INTEGER time_startup = {};
|
||||||
|
|
||||||
|
HCURSOR cursor_default = nullptr;
|
||||||
|
HCURSOR cursor_move = nullptr;
|
||||||
|
HCURSOR cursor_pointer = nullptr;
|
||||||
|
HCURSOR cursor_resize = nullptr;
|
||||||
|
HCURSOR cursor_cross = nullptr;
|
||||||
|
HCURSOR cursor_text = nullptr;
|
||||||
|
HCURSOR cursor_unavailable = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextInputMethodEditor_Win32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Optional helper functions for the Win32 platform.
|
||||||
|
*/
|
||||||
|
namespace RmlWin32 {
|
||||||
|
|
||||||
|
// Convenience helpers for converting between RmlUi strings (UTF-8) and Windows strings (UTF-16).
|
||||||
|
Rml::String ConvertToUTF8(const std::wstring& wstr);
|
||||||
|
std::wstring ConvertToUTF16(const Rml::String& str);
|
||||||
|
|
||||||
|
// Window event handler to submit default input behavior to the context.
|
||||||
|
// @return True if the event is still propagating, false if it was handled by the context.
|
||||||
|
bool WindowProcedure(Rml::Context* context, TextInputMethodEditor_Win32& text_input_method_editor, HWND window_handle, UINT message, WPARAM w_param,
|
||||||
|
LPARAM l_param);
|
||||||
|
|
||||||
|
// Converts the key from Win32 key code to RmlUi key.
|
||||||
|
Rml::Input::KeyIdentifier ConvertKey(int win32_key_code);
|
||||||
|
|
||||||
|
// Returns the active RmlUi key modifier state.
|
||||||
|
int GetKeyModifierState();
|
||||||
|
|
||||||
|
} // namespace RmlWin32
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom backend implementation of TextInputHandler to handle the system's Input Method Editor (IME).
|
||||||
|
This version supports only one active text input context.
|
||||||
|
*/
|
||||||
|
class TextInputMethodEditor_Win32 final : public Rml::TextInputHandler {
|
||||||
|
public:
|
||||||
|
TextInputMethodEditor_Win32();
|
||||||
|
|
||||||
|
void OnActivate(Rml::TextInputContext* input_context) override;
|
||||||
|
void OnDeactivate(Rml::TextInputContext* input_context) override;
|
||||||
|
void OnDestroy(Rml::TextInputContext* input_context) override;
|
||||||
|
|
||||||
|
/// Check that a composition is currently active.
|
||||||
|
/// @return True if we are composing, false otherwise.
|
||||||
|
bool IsComposing() const;
|
||||||
|
|
||||||
|
void StartComposition();
|
||||||
|
void CancelComposition();
|
||||||
|
|
||||||
|
/// Set the composition string.
|
||||||
|
/// @param[in] composition A string to be set.
|
||||||
|
void SetComposition(Rml::StringView composition);
|
||||||
|
|
||||||
|
/// End the current composition by confirming the composition string.
|
||||||
|
/// @param[in] composition A string to confirm.
|
||||||
|
void ConfirmComposition(Rml::StringView composition);
|
||||||
|
|
||||||
|
/// Set the cursor position within the composition.
|
||||||
|
/// @param[in] cursor_pos A character position of the cursor within the composition string.
|
||||||
|
/// @param[in] update Update the cursor position within active input contexts.
|
||||||
|
void SetCursorPosition(int cursor_pos, bool update);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EndComposition();
|
||||||
|
void SetCompositionString(Rml::StringView composition);
|
||||||
|
|
||||||
|
void UpdateCursorPosition();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// An actively used text input method context.
|
||||||
|
Rml::TextInputContext* input_context;
|
||||||
|
|
||||||
|
// A flag to mark a composition is currently active.
|
||||||
|
bool composing;
|
||||||
|
// Character position of the cursor in the composition string.
|
||||||
|
int cursor_pos;
|
||||||
|
|
||||||
|
// Composition range (character position) relative to the text input value.
|
||||||
|
int composition_range_start;
|
||||||
|
int composition_range_end;
|
||||||
|
};
|
||||||
610
vendor/rmlui_backend/RmlUi_Platform_X11.cpp
vendored
Normal file
610
vendor/rmlui_backend/RmlUi_Platform_X11.cpp
vendored
Normal file
@@ -0,0 +1,610 @@
|
|||||||
|
#include "RmlUi_Platform_X11.h"
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <X11/cursorfont.h>
|
||||||
|
#include <X11/extensions/xf86vmode.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef HAS_X11XKBLIB
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
#endif // HAS_X11XKBLIB
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
|
||||||
|
static Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state);
|
||||||
|
|
||||||
|
SystemInterface_X11::SystemInterface_X11(Display* display) : display(display)
|
||||||
|
{
|
||||||
|
// Create cursors
|
||||||
|
cursor_default = XCreateFontCursor(display, XC_left_ptr);
|
||||||
|
cursor_move = XCreateFontCursor(display, XC_fleur);
|
||||||
|
cursor_pointer = XCreateFontCursor(display, XC_hand1);
|
||||||
|
cursor_resize = XCreateFontCursor(display, XC_sizing);
|
||||||
|
cursor_cross = XCreateFontCursor(display, XC_crosshair);
|
||||||
|
cursor_text = XCreateFontCursor(display, XC_xterm);
|
||||||
|
cursor_unavailable = XCreateFontCursor(display, XC_X_cursor);
|
||||||
|
|
||||||
|
// For copy & paste functions
|
||||||
|
UTF8_atom = XInternAtom(display, "UTF8_STRING", 1);
|
||||||
|
XSEL_DATA_atom = XInternAtom(display, "XSEL_DATA", 0);
|
||||||
|
CLIPBOARD_atom = XInternAtom(display, "CLIPBOARD", 0);
|
||||||
|
TARGETS_atom = XInternAtom(display, "TARGETS", 0);
|
||||||
|
TEXT_atom = XInternAtom(display, "TEXT", 0);
|
||||||
|
|
||||||
|
gettimeofday(&start_time, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_X11::SetWindow(Window in_window)
|
||||||
|
{
|
||||||
|
window = in_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemInterface_X11::HandleSelectionRequest(const XEvent& ev)
|
||||||
|
{
|
||||||
|
if (ev.type == SelectionRequest && XGetSelectionOwner(display, CLIPBOARD_atom) == window && ev.xselectionrequest.selection == CLIPBOARD_atom)
|
||||||
|
{
|
||||||
|
XCopy(clipboard_text, ev);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double SystemInterface_X11::GetElapsedTime()
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
gettimeofday(&now, nullptr);
|
||||||
|
|
||||||
|
double sec = now.tv_sec - start_time.tv_sec;
|
||||||
|
double usec = now.tv_usec - start_time.tv_usec;
|
||||||
|
double result = sec + (usec / 1000000.0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_X11::SetMouseCursor(const Rml::String& cursor_name)
|
||||||
|
{
|
||||||
|
if (display && window)
|
||||||
|
{
|
||||||
|
Cursor cursor_handle = 0;
|
||||||
|
if (cursor_name.empty() || cursor_name == "arrow")
|
||||||
|
cursor_handle = cursor_default;
|
||||||
|
else if (cursor_name == "move")
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
else if (cursor_name == "pointer")
|
||||||
|
cursor_handle = cursor_pointer;
|
||||||
|
else if (cursor_name == "resize")
|
||||||
|
cursor_handle = cursor_resize;
|
||||||
|
else if (cursor_name == "cross")
|
||||||
|
cursor_handle = cursor_cross;
|
||||||
|
else if (cursor_name == "text")
|
||||||
|
cursor_handle = cursor_text;
|
||||||
|
else if (cursor_name == "rmlui-scroll-idle")
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
else if (cursor_name == "rmlui-scroll-up")
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
else if (cursor_name == "rmlui-scroll-down")
|
||||||
|
cursor_handle = cursor_move;
|
||||||
|
else if (cursor_name == "unavailable")
|
||||||
|
cursor_handle = cursor_unavailable;
|
||||||
|
|
||||||
|
if (cursor_handle)
|
||||||
|
{
|
||||||
|
XDefineCursor(display, window, cursor_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_X11::SetClipboardText(const Rml::String& text)
|
||||||
|
{
|
||||||
|
clipboard_text = text;
|
||||||
|
XSetSelectionOwner(display, CLIPBOARD_atom, window, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_X11::GetClipboardText(Rml::String& text)
|
||||||
|
{
|
||||||
|
if (XGetSelectionOwner(display, CLIPBOARD_atom) != window)
|
||||||
|
{
|
||||||
|
if (!UTF8_atom || !XPaste(UTF8_atom, text))
|
||||||
|
{
|
||||||
|
// fallback
|
||||||
|
XPaste(XA_STRING_atom, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = clipboard_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemInterface_X11::XCopy(const Rml::String& clipboard_data, const XEvent& event)
|
||||||
|
{
|
||||||
|
Atom format = (UTF8_atom ? UTF8_atom : XA_STRING_atom);
|
||||||
|
|
||||||
|
XSelectionEvent ev = {
|
||||||
|
SelectionNotify, // the event type that will be sent to the requestor
|
||||||
|
0, // serial
|
||||||
|
0, // send_event
|
||||||
|
event.xselectionrequest.display, event.xselectionrequest.requestor, event.xselectionrequest.selection, event.xselectionrequest.target,
|
||||||
|
event.xselectionrequest.property,
|
||||||
|
0 // time
|
||||||
|
};
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
if (ev.target == TARGETS_atom)
|
||||||
|
{
|
||||||
|
retval = XChangeProperty(ev.display, ev.requestor, ev.property, XA_atom, 32, PropModeReplace, (unsigned char*)&format, 1);
|
||||||
|
}
|
||||||
|
else if (ev.target == XA_STRING_atom || ev.target == TEXT_atom)
|
||||||
|
{
|
||||||
|
retval = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING_atom, 8, PropModeReplace, (unsigned char*)clipboard_data.c_str(),
|
||||||
|
clipboard_data.size());
|
||||||
|
}
|
||||||
|
else if (ev.target == UTF8_atom)
|
||||||
|
{
|
||||||
|
retval = XChangeProperty(ev.display, ev.requestor, ev.property, UTF8_atom, 8, PropModeReplace, (unsigned char*)clipboard_data.c_str(),
|
||||||
|
clipboard_data.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ev.property = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((retval & 2) == 0)
|
||||||
|
{
|
||||||
|
// Notify the requestor that clipboard data is available
|
||||||
|
XSendEvent(display, ev.requestor, 0, 0, (XEvent*)&ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemInterface_X11::XPaste(Atom target_atom, Rml::String& clipboard_data)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
|
||||||
|
// A SelectionRequest event will be sent to the clipboard owner, which should respond with SelectionNotify
|
||||||
|
XConvertSelection(display, CLIPBOARD_atom, target_atom, XSEL_DATA_atom, window, CurrentTime);
|
||||||
|
XSync(display, 0);
|
||||||
|
XNextEvent(display, &ev);
|
||||||
|
|
||||||
|
if (ev.type == SelectionNotify)
|
||||||
|
{
|
||||||
|
if (ev.xselection.property == 0)
|
||||||
|
{
|
||||||
|
// If no owner for the specified selection exists, the X server generates
|
||||||
|
// a SelectionNotify event with property None (0).
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ev.xselection.selection == CLIPBOARD_atom)
|
||||||
|
{
|
||||||
|
int actual_format;
|
||||||
|
unsigned long bytes_after, nitems;
|
||||||
|
char* prop = nullptr;
|
||||||
|
Atom actual_type;
|
||||||
|
XGetWindowProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property,
|
||||||
|
0L, // offset
|
||||||
|
(~0L), // length
|
||||||
|
0, // delete?
|
||||||
|
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, (unsigned char**)&prop);
|
||||||
|
|
||||||
|
if (actual_type == UTF8_atom || actual_type == XA_STRING_atom)
|
||||||
|
{
|
||||||
|
clipboard_data = Rml::String(prop, prop + nitems);
|
||||||
|
XFree(prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
XDeleteProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RmlX11::HandleInputEvent(Rml::Context* context, Display* display, const XEvent& ev)
|
||||||
|
{
|
||||||
|
switch (ev.type)
|
||||||
|
{
|
||||||
|
case ButtonPress:
|
||||||
|
{
|
||||||
|
switch (ev.xbutton.button)
|
||||||
|
{
|
||||||
|
case Button1:
|
||||||
|
case Button2:
|
||||||
|
case Button3: return context->ProcessMouseButtonDown(ConvertMouseButton(ev.xbutton.button), RmlX11::GetKeyModifierState(ev.xbutton.state));
|
||||||
|
case Button4: return context->ProcessMouseWheel(-1, RmlX11::GetKeyModifierState(ev.xbutton.state));
|
||||||
|
case Button5: return context->ProcessMouseWheel(1, RmlX11::GetKeyModifierState(ev.xbutton.state));
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ButtonRelease:
|
||||||
|
{
|
||||||
|
switch (ev.xbutton.button)
|
||||||
|
{
|
||||||
|
case Button1:
|
||||||
|
case Button2:
|
||||||
|
case Button3: return context->ProcessMouseButtonUp(ConvertMouseButton(ev.xbutton.button), RmlX11::GetKeyModifierState(ev.xbutton.state));
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MotionNotify:
|
||||||
|
{
|
||||||
|
return context->ProcessMouseMove(ev.xmotion.x, ev.xmotion.y, RmlX11::GetKeyModifierState(ev.xmotion.state));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LeaveNotify:
|
||||||
|
{
|
||||||
|
return context->ProcessMouseLeave();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
{
|
||||||
|
Rml::Input::KeyIdentifier key_identifier = RmlX11::ConvertKey(display, ev.xkey.keycode);
|
||||||
|
const int key_modifier_state = RmlX11::GetKeyModifierState(ev.xkey.state);
|
||||||
|
|
||||||
|
bool propagates = true;
|
||||||
|
|
||||||
|
if (key_identifier != Rml::Input::KI_UNKNOWN)
|
||||||
|
propagates = context->ProcessKeyDown(key_identifier, key_modifier_state);
|
||||||
|
|
||||||
|
Rml::Character character = GetCharacterCode(key_identifier, key_modifier_state);
|
||||||
|
if (character != Rml::Character::Null && !(key_modifier_state & Rml::Input::KM_CTRL))
|
||||||
|
propagates &= context->ProcessTextInput(character);
|
||||||
|
|
||||||
|
return propagates;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyRelease:
|
||||||
|
{
|
||||||
|
Rml::Input::KeyIdentifier key_identifier = RmlX11::ConvertKey(display, ev.xkey.keycode);
|
||||||
|
const int key_modifier_state = RmlX11::GetKeyModifierState(ev.xkey.state);
|
||||||
|
|
||||||
|
bool propagates = true;
|
||||||
|
|
||||||
|
if (key_identifier != Rml::Input::KI_UNKNOWN)
|
||||||
|
propagates = context->ProcessKeyUp(key_identifier, key_modifier_state);
|
||||||
|
|
||||||
|
return propagates;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlX11::GetKeyModifierState(int x11_state)
|
||||||
|
{
|
||||||
|
int key_modifier_state = 0;
|
||||||
|
|
||||||
|
if (x11_state & ShiftMask)
|
||||||
|
key_modifier_state |= Rml::Input::KM_SHIFT;
|
||||||
|
|
||||||
|
if (x11_state & LockMask)
|
||||||
|
key_modifier_state |= Rml::Input::KM_CAPSLOCK;
|
||||||
|
|
||||||
|
if (x11_state & ControlMask)
|
||||||
|
key_modifier_state |= Rml::Input::KM_CTRL;
|
||||||
|
|
||||||
|
if (x11_state & Mod5Mask)
|
||||||
|
key_modifier_state |= Rml::Input::KM_ALT;
|
||||||
|
|
||||||
|
if (x11_state & Mod2Mask)
|
||||||
|
key_modifier_state |= Rml::Input::KM_NUMLOCK;
|
||||||
|
|
||||||
|
return key_modifier_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
X11 Key data used for key code conversion.
|
||||||
|
*/
|
||||||
|
struct XKeyData {
|
||||||
|
#ifdef HAS_X11XKBLIB
|
||||||
|
bool has_xkblib = false;
|
||||||
|
#endif // HAS_X11XKBLIB
|
||||||
|
|
||||||
|
bool initialized = false;
|
||||||
|
int min_keycode = 0, max_keycode = 0, keysyms_per_keycode = 0;
|
||||||
|
KeySym* x11_key_mapping = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the key data, which is initialized and filled on the first fetch.
|
||||||
|
static const XKeyData& GetXKeyData(Display* display)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(display);
|
||||||
|
static XKeyData data;
|
||||||
|
|
||||||
|
if (!data.initialized)
|
||||||
|
{
|
||||||
|
data.initialized = true;
|
||||||
|
|
||||||
|
#ifdef HAS_X11XKBLIB
|
||||||
|
int opcode_rtrn = -1;
|
||||||
|
int event_rtrn = -1;
|
||||||
|
int error_rtrn = -1;
|
||||||
|
int major_in_out = -1;
|
||||||
|
int minor_in_out = -1;
|
||||||
|
|
||||||
|
// Xkb extension may not exist in the server. This checks for its existence and initializes the extension if available.
|
||||||
|
data.has_xkblib = XkbQueryExtension(display, &opcode_rtrn, &event_rtrn, &error_rtrn, &major_in_out, &minor_in_out);
|
||||||
|
|
||||||
|
// if Xkb isn't available, fall back to using XGetKeyboardMapping, which may occur if RmlUi is compiled with Xkb support but the server
|
||||||
|
// doesn't support it. This occurs with older X11 servers or virtual framebuffers such as x11vnc server.
|
||||||
|
if (!data.has_xkblib)
|
||||||
|
#endif // HAS_X11XKBLIB
|
||||||
|
{
|
||||||
|
XDisplayKeycodes(display, &data.min_keycode, &data.max_keycode);
|
||||||
|
|
||||||
|
data.x11_key_mapping = XGetKeyboardMapping(display, data.min_keycode, data.max_keycode + 1 - data.min_keycode, &data.keysyms_per_keycode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::Input::KeyIdentifier RmlX11::ConvertKey(Display* display, unsigned int x11_key_code)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(display);
|
||||||
|
const XKeyData& key_data = GetXKeyData(display);
|
||||||
|
|
||||||
|
const int group_index = 0; // this is always 0 for our limited example
|
||||||
|
KeySym sym = {};
|
||||||
|
|
||||||
|
#ifdef HAS_X11XKBLIB
|
||||||
|
if (key_data.has_xkblib)
|
||||||
|
{
|
||||||
|
sym = XkbKeycodeToKeysym(display, x11_key_code, 0, group_index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // HAS_X11XKBLIB
|
||||||
|
{
|
||||||
|
KeySym sym_full = key_data.x11_key_mapping[(x11_key_code - key_data.min_keycode) * key_data.keysyms_per_keycode + group_index];
|
||||||
|
|
||||||
|
KeySym lower_sym, upper_sym;
|
||||||
|
XConvertCase(sym_full, &lower_sym, &upper_sym);
|
||||||
|
sym = lower_sym;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
switch (sym & 0xFF)
|
||||||
|
{
|
||||||
|
case XK_BackSpace & 0xFF: return Rml::Input::KI_BACK;
|
||||||
|
case XK_Tab & 0xFF: return Rml::Input::KI_TAB;
|
||||||
|
case XK_Clear & 0xFF: return Rml::Input::KI_CLEAR;
|
||||||
|
case XK_Return & 0xFF: return Rml::Input::KI_RETURN;
|
||||||
|
case XK_Pause & 0xFF: return Rml::Input::KI_PAUSE;
|
||||||
|
case XK_Scroll_Lock & 0xFF: return Rml::Input::KI_SCROLL;
|
||||||
|
case XK_Escape & 0xFF: return Rml::Input::KI_ESCAPE;
|
||||||
|
case XK_Delete & 0xFF: return Rml::Input::KI_DELETE;
|
||||||
|
|
||||||
|
case XK_Kanji & 0xFF: return Rml::Input::KI_KANJI;
|
||||||
|
// case XK_Muhenkan & 0xFF: return Rml::Input::; /* Cancel Conversion */
|
||||||
|
// case XK_Henkan_Mode & 0xFF: return Rml::Input::; /* Start/Stop Conversion */
|
||||||
|
// case XK_Henkan & 0xFF: return Rml::Input::; /* Alias for Henkan_Mode */
|
||||||
|
// case XK_Romaji & 0xFF: return Rml::Input::; /* to Romaji */
|
||||||
|
// case XK_Hiragana & 0xFF: return Rml::Input::; /* to Hiragana */
|
||||||
|
// case XK_Katakana & 0xFF: return Rml::Input::; /* to Katakana */
|
||||||
|
// case XK_Hiragana_Katakana & 0xFF: return Rml::Input::; /* Hiragana/Katakana toggle */
|
||||||
|
// case XK_Zenkaku & 0xFF: return Rml::Input::; /* to Zenkaku */
|
||||||
|
// case XK_Hankaku & 0xFF: return Rml::Input::; /* to Hankaku */
|
||||||
|
// case XK_Zenkaku_Hankaku & 0xFF: return Rml::Input::; /* Zenkaku/Hankaku toggle */
|
||||||
|
case XK_Touroku & 0xFF: return Rml::Input::KI_OEM_FJ_TOUROKU;
|
||||||
|
// case XK_Massyo & 0xFF: return Rml::Input::KI_OEM_FJ_MASSHOU;
|
||||||
|
// case XK_Kana_Lock & 0xFF: return Rml::Input::; /* Kana Lock */
|
||||||
|
// case XK_Kana_Shift & 0xFF: return Rml::Input::; /* Kana Shift */
|
||||||
|
// case XK_Eisu_Shift & 0xFF: return Rml::Input::; /* Alphanumeric Shift */
|
||||||
|
// case XK_Eisu_toggle & 0xFF: return Rml::Input::; /* Alphanumeric toggle */
|
||||||
|
|
||||||
|
case XK_Home & 0xFF: return Rml::Input::KI_HOME;
|
||||||
|
case XK_Left & 0xFF: return Rml::Input::KI_LEFT;
|
||||||
|
case XK_Up & 0xFF: return Rml::Input::KI_UP;
|
||||||
|
case XK_Right & 0xFF: return Rml::Input::KI_RIGHT;
|
||||||
|
case XK_Down & 0xFF: return Rml::Input::KI_DOWN;
|
||||||
|
case XK_Prior & 0xFF: return Rml::Input::KI_PRIOR;
|
||||||
|
case XK_Next & 0xFF: return Rml::Input::KI_NEXT;
|
||||||
|
case XK_End & 0xFF: return Rml::Input::KI_END;
|
||||||
|
case XK_Begin & 0xFF: return Rml::Input::KI_HOME;
|
||||||
|
|
||||||
|
// case XK_Print & 0xFF: return Rml::Input::KI_SNAPSHOT;
|
||||||
|
// case XK_Insert & 0xFF: return Rml::Input::KI_INSERT;
|
||||||
|
case XK_Num_Lock & 0xFF: return Rml::Input::KI_NUMLOCK;
|
||||||
|
|
||||||
|
case XK_KP_Space & 0xFF: return Rml::Input::KI_SPACE;
|
||||||
|
case XK_KP_Tab & 0xFF: return Rml::Input::KI_TAB;
|
||||||
|
case XK_KP_Enter & 0xFF: return Rml::Input::KI_NUMPADENTER;
|
||||||
|
case XK_KP_F1 & 0xFF: return Rml::Input::KI_F1;
|
||||||
|
case XK_KP_F2 & 0xFF: return Rml::Input::KI_F2;
|
||||||
|
case XK_KP_F3 & 0xFF: return Rml::Input::KI_F3;
|
||||||
|
case XK_KP_F4 & 0xFF: return Rml::Input::KI_F4;
|
||||||
|
case XK_KP_Home & 0xFF: return Rml::Input::KI_NUMPAD7;
|
||||||
|
case XK_KP_Left & 0xFF: return Rml::Input::KI_NUMPAD4;
|
||||||
|
case XK_KP_Up & 0xFF: return Rml::Input::KI_NUMPAD8;
|
||||||
|
case XK_KP_Right & 0xFF: return Rml::Input::KI_NUMPAD6;
|
||||||
|
case XK_KP_Down & 0xFF: return Rml::Input::KI_NUMPAD2;
|
||||||
|
case XK_KP_Prior & 0xFF: return Rml::Input::KI_NUMPAD9;
|
||||||
|
case XK_KP_Next & 0xFF: return Rml::Input::KI_NUMPAD3;
|
||||||
|
case XK_KP_End & 0xFF: return Rml::Input::KI_NUMPAD1;
|
||||||
|
case XK_KP_Begin & 0xFF: return Rml::Input::KI_NUMPAD5;
|
||||||
|
case XK_KP_Insert & 0xFF: return Rml::Input::KI_NUMPAD0;
|
||||||
|
case XK_KP_Delete & 0xFF: return Rml::Input::KI_DECIMAL;
|
||||||
|
case XK_KP_Equal & 0xFF: return Rml::Input::KI_OEM_NEC_EQUAL;
|
||||||
|
case XK_KP_Multiply & 0xFF: return Rml::Input::KI_MULTIPLY;
|
||||||
|
case XK_KP_Add & 0xFF: return Rml::Input::KI_ADD;
|
||||||
|
case XK_KP_Separator & 0xFF: return Rml::Input::KI_SEPARATOR;
|
||||||
|
case XK_KP_Subtract & 0xFF: return Rml::Input::KI_SUBTRACT;
|
||||||
|
case XK_KP_Decimal & 0xFF: return Rml::Input::KI_DECIMAL;
|
||||||
|
case XK_KP_Divide & 0xFF: return Rml::Input::KI_DIVIDE;
|
||||||
|
|
||||||
|
case XK_F1 & 0xFF: return Rml::Input::KI_F1;
|
||||||
|
case XK_F2 & 0xFF: return Rml::Input::KI_F2;
|
||||||
|
case XK_F3 & 0xFF: return Rml::Input::KI_F3;
|
||||||
|
case XK_F4 & 0xFF: return Rml::Input::KI_F4;
|
||||||
|
case XK_F5 & 0xFF: return Rml::Input::KI_F5;
|
||||||
|
case XK_F6 & 0xFF: return Rml::Input::KI_F6;
|
||||||
|
case XK_F7 & 0xFF: return Rml::Input::KI_F7;
|
||||||
|
case XK_F8 & 0xFF: return Rml::Input::KI_F8;
|
||||||
|
case XK_F9 & 0xFF: return Rml::Input::KI_F9;
|
||||||
|
case XK_F10 & 0xFF: return Rml::Input::KI_F10;
|
||||||
|
case XK_F11 & 0xFF: return Rml::Input::KI_F11;
|
||||||
|
case XK_F12 & 0xFF: return Rml::Input::KI_F12;
|
||||||
|
case XK_F13 & 0xFF: return Rml::Input::KI_F13;
|
||||||
|
case XK_F14 & 0xFF: return Rml::Input::KI_F14;
|
||||||
|
case XK_F15 & 0xFF: return Rml::Input::KI_F15;
|
||||||
|
case XK_F16 & 0xFF: return Rml::Input::KI_F16;
|
||||||
|
case XK_F17 & 0xFF: return Rml::Input::KI_F17;
|
||||||
|
case XK_F18 & 0xFF: return Rml::Input::KI_F18;
|
||||||
|
case XK_F19 & 0xFF: return Rml::Input::KI_F19;
|
||||||
|
case XK_F20 & 0xFF: return Rml::Input::KI_F20;
|
||||||
|
case XK_F21 & 0xFF: return Rml::Input::KI_F21;
|
||||||
|
case XK_F22 & 0xFF: return Rml::Input::KI_F22;
|
||||||
|
case XK_F23 & 0xFF: return Rml::Input::KI_F23;
|
||||||
|
case XK_F24 & 0xFF: return Rml::Input::KI_F24;
|
||||||
|
|
||||||
|
case XK_Shift_L & 0xFF: return Rml::Input::KI_LSHIFT;
|
||||||
|
case XK_Shift_R & 0xFF: return Rml::Input::KI_RSHIFT;
|
||||||
|
case XK_Control_L & 0xFF: return Rml::Input::KI_LCONTROL;
|
||||||
|
case XK_Control_R & 0xFF: return Rml::Input::KI_RCONTROL;
|
||||||
|
case XK_Caps_Lock & 0xFF: return Rml::Input::KI_CAPITAL;
|
||||||
|
|
||||||
|
case XK_Alt_L & 0xFF: return Rml::Input::KI_LMENU;
|
||||||
|
case XK_Alt_R & 0xFF: return Rml::Input::KI_RMENU;
|
||||||
|
|
||||||
|
case XK_space & 0xFF: return Rml::Input::KI_SPACE;
|
||||||
|
case XK_apostrophe & 0xFF: return Rml::Input::KI_OEM_7;
|
||||||
|
case XK_comma & 0xFF: return Rml::Input::KI_OEM_COMMA;
|
||||||
|
case XK_minus & 0xFF: return Rml::Input::KI_OEM_MINUS;
|
||||||
|
case XK_period & 0xFF: return Rml::Input::KI_OEM_PERIOD;
|
||||||
|
case XK_slash & 0xFF: return Rml::Input::KI_OEM_2;
|
||||||
|
case XK_0 & 0xFF: return Rml::Input::KI_0;
|
||||||
|
case XK_1 & 0xFF: return Rml::Input::KI_1;
|
||||||
|
case XK_2 & 0xFF: return Rml::Input::KI_2;
|
||||||
|
case XK_3 & 0xFF: return Rml::Input::KI_3;
|
||||||
|
case XK_4 & 0xFF: return Rml::Input::KI_4;
|
||||||
|
case XK_5 & 0xFF: return Rml::Input::KI_5;
|
||||||
|
case XK_6 & 0xFF: return Rml::Input::KI_6;
|
||||||
|
case XK_7 & 0xFF: return Rml::Input::KI_7;
|
||||||
|
case XK_8 & 0xFF: return Rml::Input::KI_8;
|
||||||
|
case XK_9 & 0xFF: return Rml::Input::KI_9;
|
||||||
|
case XK_semicolon & 0xFF: return Rml::Input::KI_OEM_1;
|
||||||
|
case XK_equal & 0xFF: return Rml::Input::KI_OEM_PLUS;
|
||||||
|
case XK_bracketleft & 0xFF: return Rml::Input::KI_OEM_4;
|
||||||
|
case XK_backslash & 0xFF: return Rml::Input::KI_OEM_5;
|
||||||
|
case XK_bracketright & 0xFF: return Rml::Input::KI_OEM_6;
|
||||||
|
case XK_grave & 0xFF: return Rml::Input::KI_OEM_3;
|
||||||
|
case XK_a & 0xFF: return Rml::Input::KI_A;
|
||||||
|
case XK_b & 0xFF: return Rml::Input::KI_B;
|
||||||
|
case XK_c & 0xFF: return Rml::Input::KI_C;
|
||||||
|
case XK_d & 0xFF: return Rml::Input::KI_D;
|
||||||
|
case XK_e & 0xFF: return Rml::Input::KI_E;
|
||||||
|
case XK_f & 0xFF: return Rml::Input::KI_F;
|
||||||
|
case XK_g & 0xFF: return Rml::Input::KI_G;
|
||||||
|
case XK_h & 0xFF: return Rml::Input::KI_H;
|
||||||
|
case XK_i & 0xFF: return Rml::Input::KI_I;
|
||||||
|
case XK_j & 0xFF: return Rml::Input::KI_J;
|
||||||
|
case XK_k & 0xFF: return Rml::Input::KI_K;
|
||||||
|
case XK_l & 0xFF: return Rml::Input::KI_L;
|
||||||
|
case XK_m & 0xFF: return Rml::Input::KI_M;
|
||||||
|
case XK_n & 0xFF: return Rml::Input::KI_N;
|
||||||
|
case XK_o & 0xFF: return Rml::Input::KI_O;
|
||||||
|
case XK_p & 0xFF: return Rml::Input::KI_P;
|
||||||
|
case XK_q & 0xFF: return Rml::Input::KI_Q;
|
||||||
|
case XK_r & 0xFF: return Rml::Input::KI_R;
|
||||||
|
case XK_s & 0xFF: return Rml::Input::KI_S;
|
||||||
|
case XK_t & 0xFF: return Rml::Input::KI_T;
|
||||||
|
case XK_u & 0xFF: return Rml::Input::KI_U;
|
||||||
|
case XK_v & 0xFF: return Rml::Input::KI_V;
|
||||||
|
case XK_w & 0xFF: return Rml::Input::KI_W;
|
||||||
|
case XK_x & 0xFF: return Rml::Input::KI_X;
|
||||||
|
case XK_y & 0xFF: return Rml::Input::KI_Y;
|
||||||
|
case XK_z & 0xFF: return Rml::Input::KI_Z;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return Rml::Input::KI_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RmlX11::ConvertMouseButton(unsigned int x11_mouse_button)
|
||||||
|
{
|
||||||
|
switch (x11_mouse_button)
|
||||||
|
{
|
||||||
|
case Button1: return 0;
|
||||||
|
case Button2: return 2;
|
||||||
|
case Button3: return 1;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
This map contains 4 different mappings from key identifiers to character codes. Each entry represents a different
|
||||||
|
combination of shift and capslock state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char ascii_map[4][51] = {
|
||||||
|
// shift off and capslock off
|
||||||
|
{0, ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
|
||||||
|
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ';', '=', ',', '-', '.', '/', '`', '[', '\\', ']', '\'', 0, 0},
|
||||||
|
// shift on and capslock off
|
||||||
|
{0, ' ', ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
|
||||||
|
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ':', '+', '<', '_', '>', '?', '~', '{', '|', '}', '"', 0, 0},
|
||||||
|
// shift on and capslock on
|
||||||
|
{0, ' ', ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
|
||||||
|
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ':', '+', '<', '_', '>', '?', '~', '{', '|', '}', '"', 0, 0},
|
||||||
|
// shift off and capslock on
|
||||||
|
{0, ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
|
||||||
|
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ';', '=', ',', '-', '.', '/', '`', '[', '\\', ']', '\'', 0, 0}};
|
||||||
|
|
||||||
|
static char keypad_map[2][18] = {{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\n', '*', '+', 0, '-', '.', '/', '='},
|
||||||
|
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', '*', '+', 0, '-', 0, '/', '='}};
|
||||||
|
|
||||||
|
// Returns the character code for a key identifer / key modifier combination.
|
||||||
|
static Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state)
|
||||||
|
{
|
||||||
|
using Rml::Character;
|
||||||
|
|
||||||
|
// Check if we have a keycode capable of generating characters on the main keyboard (ie, not on the numeric
|
||||||
|
// keypad; that is dealt with below).
|
||||||
|
if (key_identifier <= Rml::Input::KI_OEM_102)
|
||||||
|
{
|
||||||
|
// Get modifier states
|
||||||
|
bool shift = (key_modifier_state & Rml::Input::KM_SHIFT) > 0;
|
||||||
|
bool capslock = (key_modifier_state & Rml::Input::KM_CAPSLOCK) > 0;
|
||||||
|
|
||||||
|
// Return character code based on identifier and modifiers
|
||||||
|
if (shift && !capslock)
|
||||||
|
return (Character)ascii_map[1][key_identifier];
|
||||||
|
|
||||||
|
if (shift && capslock)
|
||||||
|
return (Character)ascii_map[2][key_identifier];
|
||||||
|
|
||||||
|
if (!shift && capslock)
|
||||||
|
return (Character)ascii_map[3][key_identifier];
|
||||||
|
|
||||||
|
return (Character)ascii_map[0][key_identifier];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have a keycode from the numeric keypad.
|
||||||
|
else if (key_identifier <= Rml::Input::KI_OEM_NEC_EQUAL)
|
||||||
|
{
|
||||||
|
if (key_modifier_state & Rml::Input::KM_NUMLOCK)
|
||||||
|
return (Character)keypad_map[0][key_identifier - Rml::Input::KI_NUMPAD0];
|
||||||
|
else
|
||||||
|
return (Character)keypad_map[1][key_identifier - Rml::Input::KI_NUMPAD0];
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (key_identifier == Rml::Input::KI_RETURN)
|
||||||
|
return (Character)'\n';
|
||||||
|
|
||||||
|
return Character::Null;
|
||||||
|
}
|
||||||
75
vendor/rmlui_backend/RmlUi_Platform_X11.h
vendored
Normal file
75
vendor/rmlui_backend/RmlUi_Platform_X11.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RmlUi_Include_Xlib.h"
|
||||||
|
#include <RmlUi/Core/Input.h>
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
class SystemInterface_X11 : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
SystemInterface_X11(Display* display);
|
||||||
|
|
||||||
|
// Optionally, provide or change the window to be used for setting the mouse cursors and clipboard text.
|
||||||
|
void SetWindow(Window window);
|
||||||
|
|
||||||
|
// Handle selection request events.
|
||||||
|
// @return True if the event is still propagating, false if it was handled here.
|
||||||
|
bool HandleSelectionRequest(const XEvent& ev);
|
||||||
|
|
||||||
|
// -- Inherited from Rml::SystemInterface --
|
||||||
|
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
|
||||||
|
void SetMouseCursor(const Rml::String& cursor_name) override;
|
||||||
|
|
||||||
|
void SetClipboardText(const Rml::String& text) override;
|
||||||
|
void GetClipboardText(Rml::String& text) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void XCopy(const Rml::String& clipboard_data, const XEvent& event);
|
||||||
|
bool XPaste(Atom target_atom, Rml::String& clipboard_data);
|
||||||
|
|
||||||
|
Display* display = nullptr;
|
||||||
|
Window window = 0;
|
||||||
|
timeval start_time;
|
||||||
|
|
||||||
|
Cursor cursor_default = 0;
|
||||||
|
Cursor cursor_move = 0;
|
||||||
|
Cursor cursor_pointer = 0;
|
||||||
|
Cursor cursor_resize = 0;
|
||||||
|
Cursor cursor_cross = 0;
|
||||||
|
Cursor cursor_text = 0;
|
||||||
|
Cursor cursor_unavailable = 0;
|
||||||
|
|
||||||
|
// -- Clipboard
|
||||||
|
Rml::String clipboard_text;
|
||||||
|
Atom XA_atom = 4;
|
||||||
|
Atom XA_STRING_atom = 31;
|
||||||
|
Atom UTF8_atom;
|
||||||
|
Atom CLIPBOARD_atom;
|
||||||
|
Atom XSEL_DATA_atom;
|
||||||
|
Atom TARGETS_atom;
|
||||||
|
Atom TEXT_atom;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Optional helper functions for the X11 plaform.
|
||||||
|
*/
|
||||||
|
namespace RmlX11 {
|
||||||
|
|
||||||
|
// Applies input on the context based on the given SFML event.
|
||||||
|
// @return True if the event is still propagating, false if it was handled by the context.
|
||||||
|
bool HandleInputEvent(Rml::Context* context, Display* display, const XEvent& ev);
|
||||||
|
|
||||||
|
// Converts the X11 key code to RmlUi key.
|
||||||
|
// @note The display must be passed here as it needs to query the connected X server display for information about its install keymap abilities.
|
||||||
|
Rml::Input::KeyIdentifier ConvertKey(Display* display, unsigned int x11_key_code);
|
||||||
|
|
||||||
|
// Converts the X11 mouse button to RmlUi mouse button.
|
||||||
|
int ConvertMouseButton(unsigned int x11_mouse_button);
|
||||||
|
|
||||||
|
// Converts the X11 key modifier to RmlUi key modifier.
|
||||||
|
int GetKeyModifierState(int x11_state);
|
||||||
|
|
||||||
|
} // namespace RmlX11
|
||||||
9995
vendor/rmlui_backend/RmlUi_Renderer_DX12.cpp
vendored
Normal file
9995
vendor/rmlui_backend/RmlUi_Renderer_DX12.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
696
vendor/rmlui_backend/RmlUi_Renderer_DX12.h
vendored
Normal file
696
vendor/rmlui_backend/RmlUi_Renderer_DX12.h
vendored
Normal file
@@ -0,0 +1,696 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
|
||||||
|
#ifndef RMLUI_PLATFORM_WIN32
|
||||||
|
#error "DirectX 12 renderer only supported on Windows"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#include "RmlUi_Include_DirectX_12.h"
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
enum class ProgramId;
|
||||||
|
|
||||||
|
class RenderLayerStack;
|
||||||
|
namespace Gfx {
|
||||||
|
struct ProgramData;
|
||||||
|
struct FramebufferData;
|
||||||
|
} // namespace Gfx
|
||||||
|
|
||||||
|
namespace Backend {
|
||||||
|
struct RmlRenderInitInfo;
|
||||||
|
struct RmlRendererSettings;
|
||||||
|
} // namespace Backend
|
||||||
|
|
||||||
|
class RenderInterface_DX12 : public Rml::RenderInterface {
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t InvalidConstantBuffer_RootParameterIndex = std::numeric_limits<uint32_t>::max();
|
||||||
|
static constexpr uint8_t MaxConstantBuffersPerShader = 3;
|
||||||
|
static constexpr size_t NumPrograms = 23;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct GraphicsAllocationInfo {
|
||||||
|
int buffer_index = -1;
|
||||||
|
size_t offset = {};
|
||||||
|
size_t size = {};
|
||||||
|
D3D12MA::VirtualAllocation alloc_info = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureHandleType : Rml::NonCopyMoveable {
|
||||||
|
public:
|
||||||
|
TextureHandleType() = default;
|
||||||
|
~TextureHandleType()
|
||||||
|
{
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
RMLUI_ASSERTMSG(m_is_destroyed, "The texture was not destroyed");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphicsAllocationInfo& Get_Info() const noexcept { return m_info; }
|
||||||
|
void Set_Info(const GraphicsAllocationInfo& info) { m_info = info; }
|
||||||
|
void Set_Resource(void* p_resource) { m_p_resource = p_resource; }
|
||||||
|
void* Get_Resource() const noexcept { return m_p_resource; }
|
||||||
|
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
/// @brief returns debug resource name. Implementation of this method exists only when DEBUG is enabled for this project
|
||||||
|
/// @return debug resource name when the source string is passed in LoadTexture method
|
||||||
|
const Rml::String& Get_ResourceName() const { return m_debug_resource_name; }
|
||||||
|
|
||||||
|
/// @brief sets m_debug_resource_name field with specified argument as resource_name
|
||||||
|
/// @param resource_name this string is getting from LoadTexture method from source argument
|
||||||
|
void Set_ResourceName(const Rml::String& resource_name) { m_debug_resource_name = resource_name; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// this method calls texture manager! don't call it manually because you must ensure that you freed virtual block if it had
|
||||||
|
void Destroy()
|
||||||
|
{
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
RMLUI_ASSERTMSG(!m_is_destroyed, "The texture has already been destroyed");
|
||||||
|
m_is_destroyed = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_p_resource)
|
||||||
|
{
|
||||||
|
if (m_info.buffer_index != -1)
|
||||||
|
{
|
||||||
|
static_cast<ID3D12Resource*>(m_p_resource)->Release();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D3D12MA::Allocation* p_committed_resource = static_cast<D3D12MA::Allocation*>(m_p_resource);
|
||||||
|
if (auto* underlying_resource = p_committed_resource->GetResource())
|
||||||
|
underlying_resource->Release();
|
||||||
|
|
||||||
|
p_committed_resource->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_info = GraphicsAllocationInfo();
|
||||||
|
m_p_resource = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const OffsetAllocator::Allocation& Get_Allocation_DescriptorHeap() const noexcept { return m_allocation_descriptor_heap; }
|
||||||
|
void Set_Allocation_DescriptorHeap(const OffsetAllocator::Allocation& allocation) noexcept { m_allocation_descriptor_heap = allocation; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GraphicsAllocationInfo m_info;
|
||||||
|
OffsetAllocator::Allocation m_allocation_descriptor_heap;
|
||||||
|
void* m_p_resource = nullptr; // placed or committed (CreateResource from D3D12MA)
|
||||||
|
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
Rml::String m_debug_resource_name;
|
||||||
|
bool m_is_destroyed = false;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstantBufferType {
|
||||||
|
GraphicsAllocationInfo m_alloc_info;
|
||||||
|
void* m_p_gpu_start_memory_for_binding_data = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GeometryHandleType : Rml::NonCopyMoveable {
|
||||||
|
public:
|
||||||
|
GeometryHandleType() = default;
|
||||||
|
|
||||||
|
void Set_InfoVertex(const GraphicsAllocationInfo& info) { m_info_vertex = info; }
|
||||||
|
const GraphicsAllocationInfo& Get_InfoVertex() const noexcept { return m_info_vertex; }
|
||||||
|
|
||||||
|
void Set_InfoIndex(const GraphicsAllocationInfo& info) { m_info_index = info; }
|
||||||
|
const GraphicsAllocationInfo& Get_InfoIndex() const noexcept { return m_info_index; }
|
||||||
|
|
||||||
|
void Set_NumVertices(int num) { m_num_vertices = num; }
|
||||||
|
int Get_NumVertices() const { return m_num_vertices; }
|
||||||
|
|
||||||
|
void Set_NumIndices(int num) { m_num_indices = num; }
|
||||||
|
int Get_NumIndices() const { return m_num_indices; }
|
||||||
|
|
||||||
|
void Set_SizeOfOneVertex(size_t size) { m_one_element_vertex_size = size; }
|
||||||
|
size_t Get_SizeOfOneVertex() const { return m_one_element_vertex_size; }
|
||||||
|
|
||||||
|
void Set_SizeOfOneIndex(size_t size) { m_one_element_index_size = size; }
|
||||||
|
size_t Get_SizeOfOneIndex() const { return m_one_element_index_size; }
|
||||||
|
|
||||||
|
const OffsetAllocator::Allocation& Get_Allocation_DescriptorHeap() const noexcept { return m_allocation_descriptor_heap; }
|
||||||
|
void Set_Allocation_DescriptorHeap(const OffsetAllocator::Allocation& allocation) noexcept { m_allocation_descriptor_heap = allocation; }
|
||||||
|
|
||||||
|
int Get_HistoryBackBufferFrameIndex(void) const { return m_history_backbuffer_frame_index; }
|
||||||
|
void Set_HistoryBackBufferFrameIndex(int frame_index) { m_history_backbuffer_frame_index = frame_index; }
|
||||||
|
|
||||||
|
void Set_ConstantBuffer(ConstantBufferType* p_constant_buffer)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERTMSG(p_constant_buffer, "must be valid constant buffer!");
|
||||||
|
m_p_constant_buffer_override = p_constant_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset_ConstantBuffer()
|
||||||
|
{
|
||||||
|
m_p_constant_buffer_override = nullptr;
|
||||||
|
for (uint8_t i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||||
|
{
|
||||||
|
m_constant_buffer_root_parameter_indices[i] = InvalidConstantBuffer_RootParameterIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstantBufferType* Get_ConstantBuffer() const { return m_p_constant_buffer_override; }
|
||||||
|
|
||||||
|
// use this only for shared CBV that will be used among all shaders otherwise we need to provide a new array that will hold a GPU addresses to
|
||||||
|
// different cbv and their indices but for now it is only for ONE CBV that can be used among vertex and pixel shaders
|
||||||
|
void Add_ConstantBufferRootParameterIndices(uint32_t index)
|
||||||
|
{
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
bool found_empty_slot = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (unsigned char i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||||
|
{
|
||||||
|
if (m_constant_buffer_root_parameter_indices[i] == InvalidConstantBuffer_RootParameterIndex)
|
||||||
|
{
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
found_empty_slot = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_constant_buffer_root_parameter_indices[i] = index;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
RMLUI_ASSERTMSG(found_empty_slot,
|
||||||
|
"failed to obtain empty slot in such case you have to set another limits for engine using "
|
||||||
|
"MaxConstantBuffersPerShader field");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t* Get_ConstantBufferRootParameterIndices(uint8_t& amount_of_indices) const
|
||||||
|
{
|
||||||
|
amount_of_indices = 0;
|
||||||
|
|
||||||
|
// might be slow for big arrays otherwise provide a cache field for this class just like field that will show current size of
|
||||||
|
// m_constant_buffer_root_parameter_indices member in terms of current entries that are filled the array for now just to reduce the
|
||||||
|
// memory footprint for this class and I don't use this cache field as size so we determine in runtime
|
||||||
|
for (uint8_t i = 0; i < MaxConstantBuffersPerShader; ++i)
|
||||||
|
{
|
||||||
|
if (m_constant_buffer_root_parameter_indices[i] != InvalidConstantBuffer_RootParameterIndex)
|
||||||
|
{
|
||||||
|
amount_of_indices = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_constant_buffer_root_parameter_indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_num_vertices = {};
|
||||||
|
int m_num_indices = {};
|
||||||
|
int m_history_backbuffer_frame_index = -1;
|
||||||
|
ConstantBufferType* m_p_constant_buffer_override = {};
|
||||||
|
size_t m_one_element_vertex_size = {};
|
||||||
|
size_t m_one_element_index_size = {};
|
||||||
|
uint32_t m_constant_buffer_root_parameter_indices[MaxConstantBuffersPerShader] = {
|
||||||
|
InvalidConstantBuffer_RootParameterIndex,
|
||||||
|
InvalidConstantBuffer_RootParameterIndex,
|
||||||
|
InvalidConstantBuffer_RootParameterIndex,
|
||||||
|
};
|
||||||
|
GraphicsAllocationInfo m_info_vertex;
|
||||||
|
GraphicsAllocationInfo m_info_index;
|
||||||
|
OffsetAllocator::Allocation m_allocation_descriptor_heap;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferMemoryManager : Rml::NonCopyMoveable {
|
||||||
|
public:
|
||||||
|
BufferMemoryManager();
|
||||||
|
~BufferMemoryManager();
|
||||||
|
|
||||||
|
void Initialize(ID3D12Device* m_p_device, D3D12MA::Allocator* p_allocator,
|
||||||
|
OffsetAllocator::Allocator* p_offset_allocator_for_descriptor_heap_srv_cbv_uav, D3D12_CPU_DESCRIPTOR_HANDLE* p_handle,
|
||||||
|
uint32_t size_descriptor_element, size_t size_for_allocation = RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_BUFFER_ALLOCATION,
|
||||||
|
size_t size_alignment = RMLUI_RENDER_BACKEND_FIELD_ALIGNMENT_FOR_BUFFER);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void Alloc_Vertex(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data, GeometryHandleType* p_handle);
|
||||||
|
void Alloc_Index(const void* p_data, int num_vertices, size_t size_of_one_element_in_p_data, GeometryHandleType* p_handle);
|
||||||
|
|
||||||
|
GraphicsAllocationInfo Alloc_ConstantBuffer(ConstantBufferType* p_resource, size_t size);
|
||||||
|
|
||||||
|
void Free_ConstantBuffer(ConstantBufferType* p_constantbuffer);
|
||||||
|
void Free_Geometry(GeometryHandleType* p_geometryhandle);
|
||||||
|
|
||||||
|
void* Get_WritableMemoryFromBufferByOffset(const GraphicsAllocationInfo& info);
|
||||||
|
|
||||||
|
D3D12MA::Allocation* Get_BufferByIndex(int buffer_index);
|
||||||
|
|
||||||
|
bool Is_Initialized() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Alloc_Buffer(size_t size
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
,
|
||||||
|
const std::wstring& debug_name
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
// Searches for block that has enough memory for requested allocation size, otherwise returns nullptr that means no block!
|
||||||
|
D3D12MA::VirtualBlock* Get_AvailableBlock(size_t size_for_allocation, int* p_result_buffer_index);
|
||||||
|
|
||||||
|
D3D12MA::VirtualBlock* Get_NotOutOfMemoryAndAvailableBlock(size_t size_for_allocation, int* p_result_buffer_index);
|
||||||
|
|
||||||
|
int Alloc(GraphicsAllocationInfo& info, size_t size, size_t alignment = 0);
|
||||||
|
|
||||||
|
void TryToFreeAvailableBlock();
|
||||||
|
|
||||||
|
uint32_t m_descriptor_increment_size_srv_cbv_uav;
|
||||||
|
size_t m_size_for_allocation_in_bytes;
|
||||||
|
size_t m_size_alignment_in_bytes;
|
||||||
|
ID3D12Device* m_p_device;
|
||||||
|
D3D12MA::Allocator* m_p_allocator;
|
||||||
|
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_start_pointer_of_descriptor_heap_srv_cbv_uav;
|
||||||
|
/// @brief this is for sub allocating purposes using 'Virtual Allocation' from D3D12MA
|
||||||
|
Rml::Vector<D3D12MA::VirtualBlock*> m_virtual_buffers;
|
||||||
|
/// @brief this is physical representation of VRAM and uses from CPU side for binding data
|
||||||
|
Rml::Vector<Rml::Pair<D3D12MA::Allocation*, void*>> m_buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key feature of this manager is texture management and if texture size is less or equal to 1.0 MB it will
|
||||||
|
* allocate heap for placing resources and if resource is less (or equal) to 1 MB then it will be written to that
|
||||||
|
* heap Otherwise will be used heap per texture (committed resource)
|
||||||
|
*/
|
||||||
|
class TextureMemoryManager : Rml::NonCopyMoveable {
|
||||||
|
public:
|
||||||
|
TextureMemoryManager();
|
||||||
|
~TextureMemoryManager();
|
||||||
|
|
||||||
|
void Initialize(D3D12MA::Allocator* p_allocator, OffsetAllocator::Allocator* p_offset_allocator_for_descriptor_heap_srv_cbv_uav,
|
||||||
|
ID3D12Device* p_device, ID3D12GraphicsCommandList* p_copy_command_list, ID3D12GraphicsCommandList* p_backend_command_list,
|
||||||
|
ID3D12CommandAllocator* p_copy_allocator_command, ID3D12DescriptorHeap* p_descriptor_heap_srv,
|
||||||
|
ID3D12DescriptorHeap* p_descriptor_heap_rtv, ID3D12DescriptorHeap* p_descriptor_heap_dsv, ID3D12CommandQueue* p_copy_queue,
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* p_handle, RenderInterface_DX12* p_renderer,
|
||||||
|
size_t size_for_placed_heap = RMLUI_RENDER_BACKEND_FIELD_VIDEOMEMORY_FOR_TEXTURE_ALLOCATION);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
ID3D12Resource* Alloc_Texture(D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
,
|
||||||
|
const Rml::String& debug_name
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
// if you want to create texture for rendering to it aka render target texture
|
||||||
|
ID3D12Resource* Alloc_Texture(D3D12_RESOURCE_DESC& desc, Gfx::FramebufferData* p_impl, D3D12_RESOURCE_FLAGS flags,
|
||||||
|
D3D12_RESOURCE_STATES initial_state
|
||||||
|
#ifdef RMLUI_DX_DEBUG
|
||||||
|
,
|
||||||
|
const Rml::String& debug_name
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
void Free_Texture(TextureHandleType* type);
|
||||||
|
void Free_Texture(Gfx::FramebufferData* p_texture);
|
||||||
|
void Free_Texture(TextureHandleType* p_allocated_texture_with_class, bool is_rt, D3D12MA::VirtualAllocation& allocation);
|
||||||
|
|
||||||
|
bool Is_Initialized() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool CanAllocate(size_t total_memory_for_allocation, D3D12MA::VirtualBlock* p_block);
|
||||||
|
bool CanBePlacedResource(size_t total_memory_for_allocation);
|
||||||
|
// don't use it for MSAA texture because we don't implement a such feature!
|
||||||
|
bool CanBeSmallResource(size_t base_memory);
|
||||||
|
|
||||||
|
// use index for obtaining heap from m_heaps_placed
|
||||||
|
D3D12MA::VirtualBlock* Get_AvailableBlock(size_t total_memory_for_allocation, int* result_index);
|
||||||
|
|
||||||
|
void Alloc_As_Committed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl,
|
||||||
|
const Rml::byte* p_data);
|
||||||
|
// we don't upload to GPU because it is render target and needed to be written
|
||||||
|
void Alloc_As_Committed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initial_state,
|
||||||
|
TextureHandleType* p_texture, Gfx::FramebufferData* p_impl);
|
||||||
|
void Alloc_As_Placed(size_t base_memory, size_t total_memory, D3D12_RESOURCE_DESC& desc, TextureHandleType* p_impl, const Rml::byte* p_data);
|
||||||
|
|
||||||
|
void Upload(bool is_committed, TextureHandleType* p_texture_handle, const D3D12_RESOURCE_DESC& desc, const Rml::byte* p_data,
|
||||||
|
ID3D12Resource* p_impl);
|
||||||
|
|
||||||
|
size_t BytesPerPixel(DXGI_FORMAT format);
|
||||||
|
size_t BitsPerPixel(DXGI_FORMAT format);
|
||||||
|
|
||||||
|
Rml::Pair<ID3D12Heap*, D3D12MA::VirtualBlock*> Create_HeapPlaced(size_t size_for_creation);
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE Alloc_RenderTargetResourceView(ID3D12Resource* p_resource, D3D12MA::VirtualAllocation* p_allocation);
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE Alloc_DepthStencilResourceView(ID3D12Resource* p_resource, D3D12MA::VirtualAllocation* p_allocation);
|
||||||
|
|
||||||
|
size_t m_size_for_placed_heap;
|
||||||
|
/// @brief limit size that we define as acceptable. On 4 Mb it is enough for placing 1 Mb but higher it is bad. 1 Mb occupies 25% from 4 Mb
|
||||||
|
/// and that means that m_size_limit_for_being_placed will be determined as 25% * m_size_for_placed_heap;
|
||||||
|
size_t m_size_limit_for_being_placed;
|
||||||
|
size_t m_size_srv_cbv_uav_descriptor;
|
||||||
|
size_t m_size_rtv_descriptor;
|
||||||
|
size_t m_size_dsv_descriptor;
|
||||||
|
size_t m_fence_value;
|
||||||
|
D3D12MA::Allocator* m_p_allocator;
|
||||||
|
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_srv_cbv_uav;
|
||||||
|
ID3D12Device* m_p_device;
|
||||||
|
ID3D12GraphicsCommandList* m_p_copy_command_list;
|
||||||
|
/// @brief command list from drawing
|
||||||
|
ID3D12GraphicsCommandList* m_p_backend_command_list;
|
||||||
|
ID3D12CommandAllocator* m_p_command_allocator;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_srv;
|
||||||
|
ID3D12CommandQueue* m_p_copy_queue;
|
||||||
|
ID3D12Fence* m_p_fence;
|
||||||
|
HANDLE m_p_fence_event;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_handle;
|
||||||
|
RenderInterface_DX12* m_p_renderer;
|
||||||
|
D3D12MA::VirtualBlock* m_p_virtual_block_for_render_target_heap_allocations;
|
||||||
|
D3D12MA::VirtualBlock* m_p_virtual_block_for_depth_stencil_heap_allocations;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_rtv;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_dsv;
|
||||||
|
#if RMLUI_RENDER_BACKEND_FIELD_STAGING_BUFFER_CACHE_ENABLED == 1
|
||||||
|
D3D12MA::Allocation* m_p_upload_buffer;
|
||||||
|
#endif
|
||||||
|
Rml::Vector<D3D12MA::VirtualBlock*> m_blocks;
|
||||||
|
Rml::Vector<ID3D12Heap*> m_heaps_placed;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Manages render targets, including the layer stack and postprocessing framebuffers.
|
||||||
|
|
||||||
|
Layers can be pushed and popped, creating new framebuffers as needed. Typically, geometry is rendered to the top
|
||||||
|
layer. The layer framebuffers may have MSAA enabled.
|
||||||
|
|
||||||
|
Postprocessing framebuffers are separate from the layers, and are commonly used to apply texture-wide effects
|
||||||
|
such as filters. They are used both as input and output during rendering, and do not use MSAA.
|
||||||
|
*/
|
||||||
|
class RenderLayerStack : Rml::NonCopyMoveable {
|
||||||
|
public:
|
||||||
|
RenderLayerStack();
|
||||||
|
~RenderLayerStack();
|
||||||
|
|
||||||
|
void Initialize(RenderInterface_DX12* p_owner);
|
||||||
|
void Shutdown();
|
||||||
|
// Push a new layer. All references to previously retrieved layers are invalidated.
|
||||||
|
Rml::LayerHandle PushLayer();
|
||||||
|
|
||||||
|
// Pop the top layer. All references to previously retrieved layers are invalidated.
|
||||||
|
void PopLayer();
|
||||||
|
|
||||||
|
const Gfx::FramebufferData& GetLayer(Rml::LayerHandle layer) const;
|
||||||
|
const Gfx::FramebufferData& GetTopLayer() const;
|
||||||
|
const Gfx::FramebufferData& Get_SharedDepthStencil_Layers();
|
||||||
|
// const Gfx::FramebufferData& Get_SharedDepthStencil_Postprocess();
|
||||||
|
Rml::LayerHandle GetTopLayerHandle() const;
|
||||||
|
|
||||||
|
const Gfx::FramebufferData& GetPostprocessPrimary() { return EnsureFramebufferPostprocess(0); }
|
||||||
|
const Gfx::FramebufferData& GetPostprocessSecondary() { return EnsureFramebufferPostprocess(1); }
|
||||||
|
const Gfx::FramebufferData& GetPostprocessTertiary() { return EnsureFramebufferPostprocess(2); }
|
||||||
|
const Gfx::FramebufferData& GetBlendMask() { return EnsureFramebufferPostprocess(3); }
|
||||||
|
|
||||||
|
void SwapPostprocessPrimarySecondary();
|
||||||
|
|
||||||
|
void BeginFrame(int new_width, int new_height);
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DestroyFramebuffers();
|
||||||
|
const Gfx::FramebufferData& EnsureFramebufferPostprocess(int index);
|
||||||
|
|
||||||
|
void CreateFramebuffer(Gfx::FramebufferData* p_result, int width, int height, int sample_count, bool is_depth_stencil);
|
||||||
|
void DestroyFramebuffer(Gfx::FramebufferData* p_data);
|
||||||
|
|
||||||
|
unsigned char m_msaa_sample_count;
|
||||||
|
int m_width, m_height;
|
||||||
|
// The number of active layers is manually tracked since we re-use the framebuffers stored in the fb_layers stack.
|
||||||
|
int m_layers_size;
|
||||||
|
TextureMemoryManager* m_p_manager_texture;
|
||||||
|
BufferMemoryManager* m_p_manager_buffer;
|
||||||
|
ID3D12Device* m_p_device;
|
||||||
|
Rml::UniquePtr<Gfx::FramebufferData> m_p_depth_stencil_for_layers;
|
||||||
|
Rml::Vector<Gfx::FramebufferData> m_fb_layers;
|
||||||
|
Rml::Vector<Gfx::FramebufferData> m_fb_postprocess;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderInterface_DX12(void* p_window_handle, const Backend::RmlRendererSettings& settings);
|
||||||
|
~RenderInterface_DX12();
|
||||||
|
|
||||||
|
// Returns true if the renderer was successfully constructed.
|
||||||
|
explicit operator bool() const;
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
// Draws the result to the backbuffer and restores OpenGL state.
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
// Optional, can be used to clear the active framebuffer.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::RenderInterface --
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||||
|
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
void EnableClipMask(bool enable) override;
|
||||||
|
void RenderToClipMask(Rml::ClipMaskOperation mask_operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions) override;
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
|
||||||
|
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||||
|
|
||||||
|
Rml::LayerHandle PushLayer() override;
|
||||||
|
void CompositeLayers(Rml::LayerHandle source, Rml::LayerHandle destination, Rml::BlendMode blend_mode,
|
||||||
|
Rml::Span<const Rml::CompiledFilterHandle> filters) override;
|
||||||
|
void PopLayer() override;
|
||||||
|
|
||||||
|
Rml::TextureHandle SaveLayerAsTexture() override;
|
||||||
|
|
||||||
|
Rml::CompiledFilterHandle SaveLayerAsMaskImage() override;
|
||||||
|
|
||||||
|
Rml::CompiledFilterHandle CompileFilter(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||||
|
void ReleaseFilter(Rml::CompiledFilterHandle filter) override;
|
||||||
|
|
||||||
|
Rml::CompiledShaderHandle CompileShader(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||||
|
void RenderShader(Rml::CompiledShaderHandle shader_handle, Rml::CompiledGeometryHandle geometry_handle, Rml::Vector2f translation,
|
||||||
|
Rml::TextureHandle texture) override;
|
||||||
|
void ReleaseShader(Rml::CompiledShaderHandle effect_handle) override;
|
||||||
|
|
||||||
|
// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
|
||||||
|
static constexpr Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
|
||||||
|
// Can be passed to RenderGeometry() to leave the bound texture and used program unchanged.
|
||||||
|
static constexpr Rml::TextureHandle TexturePostprocess = Rml::TextureHandle(-2);
|
||||||
|
|
||||||
|
bool IsSwapchainValid() noexcept;
|
||||||
|
void RecreateSwapchain() noexcept;
|
||||||
|
|
||||||
|
ID3D12Fence* Get_Fence();
|
||||||
|
HANDLE Get_FenceEvent();
|
||||||
|
Rml::Array<uint64_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT>& Get_FenceValues();
|
||||||
|
uint32_t Get_CurrentFrameIndex();
|
||||||
|
|
||||||
|
ID3D12Device* Get_Device() const;
|
||||||
|
TextureMemoryManager& Get_TextureManager();
|
||||||
|
BufferMemoryManager& Get_BufferManager();
|
||||||
|
|
||||||
|
unsigned char Get_MSAASampleCount() const;
|
||||||
|
|
||||||
|
void Set_UserFramebufferIndex(unsigned char framebuffer_index);
|
||||||
|
void Set_UserRenderTarget(void* rtv_where_we_render_to);
|
||||||
|
void Set_UserDepthStencil(void* dsv_where_we_render_to);
|
||||||
|
|
||||||
|
bool CaptureScreen(int& width, int& height, int& num_components, Rml::UniquePtr<Rml::byte[]>& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Initialize_Device() noexcept;
|
||||||
|
void Initialize_Adapter() noexcept;
|
||||||
|
void Initialize_DebugLayer() noexcept;
|
||||||
|
|
||||||
|
void Initialize_Swapchain(int width, int height) noexcept;
|
||||||
|
void Initialize_SyncPrimitives() noexcept;
|
||||||
|
void Initialize_SyncPrimitives_Screenshot() noexcept;
|
||||||
|
void Initialize_CommandAllocators();
|
||||||
|
|
||||||
|
void Initialize_Allocator() noexcept;
|
||||||
|
|
||||||
|
void Destroy_Swapchain() noexcept;
|
||||||
|
void Destroy_SyncPrimitives() noexcept;
|
||||||
|
void Destroy_CommandAllocators() noexcept;
|
||||||
|
void Destroy_CommandList() noexcept;
|
||||||
|
void Destroy_Allocator() noexcept;
|
||||||
|
void Destroy_SyncPrimitives_Screenshot() noexcept;
|
||||||
|
|
||||||
|
void Flush() noexcept;
|
||||||
|
uint64_t Signal(uint32_t frame_index) noexcept;
|
||||||
|
void WaitForFenceValue(uint32_t frame_index);
|
||||||
|
|
||||||
|
void Create_Resources_DependentOnSize() noexcept;
|
||||||
|
void Destroy_Resources_DependentOnSize() noexcept;
|
||||||
|
|
||||||
|
ID3D12DescriptorHeap* Create_Resource_DescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
|
||||||
|
uint32_t descriptor_count) noexcept;
|
||||||
|
|
||||||
|
ID3D12CommandAllocator* Create_CommandAllocator(D3D12_COMMAND_LIST_TYPE type);
|
||||||
|
ID3D12GraphicsCommandList* Create_CommandList(ID3D12CommandAllocator* p_allocator, D3D12_COMMAND_LIST_TYPE type) noexcept;
|
||||||
|
|
||||||
|
ID3D12CommandQueue* Create_CommandQueue(D3D12_COMMAND_LIST_TYPE type) noexcept;
|
||||||
|
|
||||||
|
void Create_Resource_RenderTargetViews();
|
||||||
|
void Destroy_Resource_RenderTagetViews();
|
||||||
|
|
||||||
|
void Destroy_Resource_For_Shaders();
|
||||||
|
|
||||||
|
void Create_Resource_Pipelines();
|
||||||
|
void Create_Resource_Pipeline_Color();
|
||||||
|
void Create_Resource_Pipeline_Texture();
|
||||||
|
void Create_Resource_Pipeline_Gradient();
|
||||||
|
void Create_Resource_Pipeline_Creation();
|
||||||
|
void Create_Resource_Pipeline_Passthrough();
|
||||||
|
void Create_Resource_Pipeline_Passthrough_NoBlend();
|
||||||
|
void Create_Resource_Pipeline_ColorMatrix();
|
||||||
|
void Create_Resource_Pipeline_BlendMask();
|
||||||
|
void Create_Resource_Pipeline_Blur();
|
||||||
|
void Create_Resource_Pipeline_DropShadow();
|
||||||
|
|
||||||
|
void Create_Resource_DepthStencil();
|
||||||
|
void Destroy_Resource_DepthStencil();
|
||||||
|
|
||||||
|
void Destroy_Resource_Pipelines();
|
||||||
|
|
||||||
|
bool CheckTearingSupport() noexcept;
|
||||||
|
|
||||||
|
IDXGIAdapter* Get_Adapter(bool is_use_warp) noexcept;
|
||||||
|
void PrintAdapterDesc(IDXGIAdapter* p_adapter);
|
||||||
|
|
||||||
|
void SetScissor(Rml::Rectanglei region, bool vertically_flip = false);
|
||||||
|
|
||||||
|
void SubmitTransformUniform(ConstantBufferType& constant_buffer, const Rml::Vector2f& translation);
|
||||||
|
|
||||||
|
void UseProgram(ProgramId pipeline_id);
|
||||||
|
|
||||||
|
ConstantBufferType* Get_ConstantBuffer(uint32_t current_back_buffer_index);
|
||||||
|
|
||||||
|
void Free_Geometry(GeometryHandleType* p_handle);
|
||||||
|
void Free_Texture(TextureHandleType* p_handle);
|
||||||
|
|
||||||
|
void Update_PendingForDeletion_Geometry();
|
||||||
|
|
||||||
|
void BlitLayerToPostprocessPrimary(Rml::LayerHandle layer_id);
|
||||||
|
|
||||||
|
void RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles);
|
||||||
|
void RenderBlur(float sigma, const Gfx::FramebufferData& source_destination, const Gfx::FramebufferData& temp,
|
||||||
|
const Rml::Rectanglei window_flipped);
|
||||||
|
|
||||||
|
void DrawFullscreenQuad(ConstantBufferType* p_override_constant_buffer = nullptr);
|
||||||
|
void DrawFullscreenQuad(Rml::Vector2f uv_offset, Rml::Vector2f uv_scaling = Rml::Vector2f(1.f),
|
||||||
|
ConstantBufferType* p_override_constant_buffer = nullptr);
|
||||||
|
|
||||||
|
void BindTexture(TextureHandleType* p_texture, UINT root_parameter_index = 0);
|
||||||
|
void BindRenderTarget(const Gfx::FramebufferData& framebuffer, bool depth_included = true);
|
||||||
|
|
||||||
|
void OverrideConstantBufferOfGeometry(Rml::CompiledGeometryHandle geometry, ConstantBufferType* p_override_constant_buffer);
|
||||||
|
|
||||||
|
// 1 means not supported
|
||||||
|
// otherwise return max value of supported multisample count
|
||||||
|
unsigned char GetMSAASupportedSampleCount(unsigned char max_samples);
|
||||||
|
|
||||||
|
void BlitFramebuffer(const Gfx::FramebufferData& source, const Gfx::FramebufferData& dest, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0,
|
||||||
|
int dstY0, int dstX1, int dstY1);
|
||||||
|
|
||||||
|
// debug only
|
||||||
|
void ValidateTextureAllocationNotAsPlaced(const Gfx::FramebufferData& data);
|
||||||
|
|
||||||
|
ID3D12Resource* GetResourceFromFramebufferData(const Gfx::FramebufferData& data);
|
||||||
|
|
||||||
|
bool m_is_use_vsync;
|
||||||
|
bool m_is_use_tearing;
|
||||||
|
bool m_is_scissor_was_set;
|
||||||
|
bool m_is_stencil_enabled;
|
||||||
|
bool m_is_stencil_equal;
|
||||||
|
bool m_is_use_msaa;
|
||||||
|
bool m_is_execute_when_end_frame_issued;
|
||||||
|
bool m_is_command_list_user;
|
||||||
|
unsigned char m_msaa_sample_count;
|
||||||
|
unsigned char m_user_framebuffer_index;
|
||||||
|
// Current viewport's width
|
||||||
|
int m_width;
|
||||||
|
// Current viewport's height
|
||||||
|
int m_height;
|
||||||
|
int m_current_clip_operation;
|
||||||
|
ProgramId m_active_program_id;
|
||||||
|
Rml::Rectanglei m_scissor;
|
||||||
|
uint32_t m_size_descriptor_heap_render_target_view;
|
||||||
|
uint32_t m_size_descriptor_heap_shaders;
|
||||||
|
UINT m_current_back_buffer_index;
|
||||||
|
UINT m_stencil_ref_value;
|
||||||
|
// For debug builds: D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, otherwise 0.
|
||||||
|
UINT m_default_shader_flags;
|
||||||
|
ID3D12Device* m_p_device;
|
||||||
|
ID3D12CommandQueue* m_p_command_queue;
|
||||||
|
ID3D12CommandQueue* m_p_copy_queue;
|
||||||
|
IDXGISwapChain4* m_p_swapchain;
|
||||||
|
ID3D12GraphicsCommandList* m_p_command_graphics_list;
|
||||||
|
ID3D12GraphicsCommandList* m_p_command_graphics_list_screenshot;
|
||||||
|
ID3D12CommandAllocator* m_p_command_allocator_screenshot;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_render_target_view;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_render_target_view_for_texture_manager;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_depth_stencil_view_for_texture_manager;
|
||||||
|
// cbv; srv; uav; all in one
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_shaders;
|
||||||
|
ID3D12DescriptorHeap* m_p_descriptor_heap_depthstencil;
|
||||||
|
D3D12MA::Allocation* m_p_depthstencil_resource;
|
||||||
|
ID3D12Fence* m_p_backbuffer_fence;
|
||||||
|
ID3D12Fence* m_p_fence_screenshot;
|
||||||
|
IDXGIAdapter* m_p_adapter;
|
||||||
|
|
||||||
|
ID3D12PipelineState* m_pipelines[NumPrograms];
|
||||||
|
ID3D12RootSignature* m_root_signatures[NumPrograms];
|
||||||
|
|
||||||
|
ID3D12CommandAllocator* m_p_copy_allocator;
|
||||||
|
ID3D12GraphicsCommandList* m_p_copy_command_list;
|
||||||
|
|
||||||
|
D3D12MA::Allocator* m_p_allocator;
|
||||||
|
OffsetAllocator::Allocator* m_p_offset_allocator_for_descriptor_heap_shaders;
|
||||||
|
// where user wants to render rmlui final image
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_user_rtv_present;
|
||||||
|
// as well as rtv just dsv
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE* m_p_user_dsv_present;
|
||||||
|
HWND m_p_window_handle;
|
||||||
|
HANDLE m_p_fence_event;
|
||||||
|
HANDLE m_p_fence_event_screenshot;
|
||||||
|
uint64_t m_fence_value;
|
||||||
|
uint64_t m_fence_screenshot_value;
|
||||||
|
Rml::CompiledGeometryHandle m_precompiled_fullscreen_quad_geometry;
|
||||||
|
|
||||||
|
Rml::Array<ID3D12Resource*, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_resources;
|
||||||
|
Rml::Array<ID3D12CommandAllocator*, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_allocators;
|
||||||
|
Rml::Array<uint64_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_backbuffers_fence_values;
|
||||||
|
Rml::Array<size_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_constant_buffer_count_per_frame;
|
||||||
|
Rml::Array<size_t, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_vertex_and_index_buffer_count_per_frame;
|
||||||
|
// per object (per draw)
|
||||||
|
Rml::Array<Rml::Vector<ConstantBufferType>, RMLUI_RENDER_BACKEND_FIELD_SWAPCHAIN_BACKBUFFER_COUNT> m_constantbuffers;
|
||||||
|
Rml::Vector<GeometryHandleType*> m_pending_for_deletion_geometry;
|
||||||
|
|
||||||
|
DXGI_SAMPLE_DESC m_desc_sample;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE m_handle_shaders;
|
||||||
|
BufferMemoryManager m_manager_buffer;
|
||||||
|
TextureMemoryManager m_manager_texture;
|
||||||
|
Rml::Matrix4f m_constant_buffer_data_transform;
|
||||||
|
Rml::Matrix4f m_constant_buffer_data_projection;
|
||||||
|
Rml::Matrix4f m_projection;
|
||||||
|
RenderLayerStack m_manager_render_layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Backend {
|
||||||
|
struct RmlRendererSettings {
|
||||||
|
bool vsync;
|
||||||
|
unsigned char msaa_sample_count;
|
||||||
|
};
|
||||||
|
} // namespace Backend
|
||||||
325
vendor/rmlui_backend/RmlUi_Renderer_GL2.cpp
vendored
Normal file
325
vendor/rmlui_backend/RmlUi_Renderer_GL2.cpp
vendored
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
#include "RmlUi_Renderer_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>
|
||||||
|
#elif defined RMLUI_PLATFORM_MACOSX
|
||||||
|
#include <AGL/agl.h>
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
#include <OpenGL/glext.h>
|
||||||
|
#elif defined RMLUI_PLATFORM_UNIX
|
||||||
|
#include "RmlUi_Include_Xlib.h"
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define GL_CLAMP_TO_EDGE 0x812F
|
||||||
|
|
||||||
|
RenderInterface_GL2::RenderInterface_GL2() {}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::SetViewport(int in_viewport_width, int in_viewport_height)
|
||||||
|
{
|
||||||
|
viewport_width = in_viewport_width;
|
||||||
|
viewport_height = in_viewport_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_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_ONE, 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);
|
||||||
|
|
||||||
|
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_GL2::EndFrame() {}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::Clear()
|
||||||
|
{
|
||||||
|
glClearStencil(0);
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle RenderInterface_GL2::CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices)
|
||||||
|
{
|
||||||
|
GeometryView* data = new GeometryView{vertices, indices};
|
||||||
|
return reinterpret_cast<Rml::CompiledGeometryHandle>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
|
||||||
|
{
|
||||||
|
delete reinterpret_cast<GeometryView*>(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture)
|
||||||
|
{
|
||||||
|
const GeometryView* geometry = reinterpret_cast<GeometryView*>(handle);
|
||||||
|
const Rml::Vertex* vertices = geometry->vertices.data();
|
||||||
|
const int* indices = geometry->indices.data();
|
||||||
|
const int num_indices = (int)geometry->indices.size();
|
||||||
|
|
||||||
|
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_GL2::EnableScissorRegion(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
glEnable(GL_SCISSOR_TEST);
|
||||||
|
else
|
||||||
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::SetScissorRegion(Rml::Rectanglei region)
|
||||||
|
{
|
||||||
|
glScissor(region.Left(), viewport_height - region.Bottom(), region.Width(), region.Height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::EnableClipMask(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
else
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::RenderToClipMask(Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(glIsEnabled(GL_STENCIL_TEST));
|
||||||
|
using Rml::ClipMaskOperation;
|
||||||
|
|
||||||
|
const bool clear_stencil = (operation == ClipMaskOperation::Set || operation == ClipMaskOperation::SetInverse);
|
||||||
|
if (clear_stencil)
|
||||||
|
{
|
||||||
|
// @performance Increment the reference value instead of clearing each time.
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint stencil_test_value = 0;
|
||||||
|
glGetIntegerv(GL_STENCIL_REF, &stencil_test_value);
|
||||||
|
|
||||||
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
|
glStencilFunc(GL_ALWAYS, GLint(1), GLuint(-1));
|
||||||
|
|
||||||
|
switch (operation)
|
||||||
|
{
|
||||||
|
case ClipMaskOperation::Set:
|
||||||
|
{
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
stencil_test_value = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ClipMaskOperation::SetInverse:
|
||||||
|
{
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
stencil_test_value = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ClipMaskOperation::Intersect:
|
||||||
|
{
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
|
stencil_test_value += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderGeometry(geometry, translation, {});
|
||||||
|
|
||||||
|
// Restore state
|
||||||
|
// @performance Cache state so we don't toggle it unnecessarily.
|
||||||
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||||
|
glStencilFunc(GL_EQUAL, stencil_test_value, 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()
|
||||||
|
|
||||||
|
Rml::TextureHandle RenderInterface_GL2::LoadTexture(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;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
TGAHeader header;
|
||||||
|
memcpy(&header, buffer.get(), sizeof(TGAHeader));
|
||||||
|
|
||||||
|
int color_mode = header.bitsPerPixel / 8;
|
||||||
|
const size_t 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.");
|
||||||
|
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.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte* image_src = buffer.get() + sizeof(TGAHeader);
|
||||||
|
Rml::UniquePtr<byte[]> image_dest_buffer(new byte[image_size]);
|
||||||
|
byte* image_dest = image_dest_buffer.get();
|
||||||
|
const bool top_to_bottom_order = ((header.imageDescriptor & 32) != 0);
|
||||||
|
|
||||||
|
// Targa is BGR, swap to RGB, flip Y axis as necessary, and convert to premultiplied alpha.
|
||||||
|
for (long y = 0; y < header.height; y++)
|
||||||
|
{
|
||||||
|
long read_index = y * header.width * color_mode;
|
||||||
|
long write_index = top_to_bottom_order ? (y * header.width * 4) : (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 byte alpha = image_src[read_index + 3];
|
||||||
|
for (size_t j = 0; j < 3; j++)
|
||||||
|
image_dest[write_index + j] = byte((image_dest[write_index + j] * alpha) / 255);
|
||||||
|
image_dest[write_index + 3] = 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;
|
||||||
|
|
||||||
|
return GenerateTexture({image_dest, image_size}, texture_dimensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle RenderInterface_GL2::GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(source.data() && source.size() == size_t(source_dimensions.x * source_dimensions.y * 4));
|
||||||
|
|
||||||
|
GLuint texture_id = 0;
|
||||||
|
glGenTextures(1, &texture_id);
|
||||||
|
if (texture_id == 0)
|
||||||
|
{
|
||||||
|
Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
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.data());
|
||||||
|
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);
|
||||||
|
|
||||||
|
return (Rml::TextureHandle)texture_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::ReleaseTexture(Rml::TextureHandle texture_handle)
|
||||||
|
{
|
||||||
|
glDeleteTextures(1, (GLuint*)&texture_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_GL2::SetTransform(const Rml::Matrix4f* transform)
|
||||||
|
{
|
||||||
|
transform_enabled = (transform != nullptr);
|
||||||
|
|
||||||
|
if (transform)
|
||||||
|
{
|
||||||
|
if (std::is_same_v<Rml::Matrix4f, Rml::ColumnMajorMatrix4f>)
|
||||||
|
glLoadMatrixf(transform->data());
|
||||||
|
else if (std::is_same_v<Rml::Matrix4f, Rml::RowMajorMatrix4f>)
|
||||||
|
glLoadMatrixf(transform->Transpose().data());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glLoadIdentity();
|
||||||
|
}
|
||||||
49
vendor/rmlui_backend/RmlUi_Renderer_GL2.h
vendored
Normal file
49
vendor/rmlui_backend/RmlUi_Renderer_GL2.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
|
||||||
|
class RenderInterface_GL2 : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
RenderInterface_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 --
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions) override;
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
void EnableClipMask(bool enable) override;
|
||||||
|
void RenderToClipMask(Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation) 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:
|
||||||
|
struct GeometryView {
|
||||||
|
Rml::Span<const Rml::Vertex> vertices;
|
||||||
|
Rml::Span<const int> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
int viewport_width = 0;
|
||||||
|
int viewport_height = 0;
|
||||||
|
bool transform_enabled = false;
|
||||||
|
};
|
||||||
2171
vendor/rmlui_backend/RmlUi_Renderer_GL3.cpp
vendored
Normal file
2171
vendor/rmlui_backend/RmlUi_Renderer_GL3.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
210
vendor/rmlui_backend/RmlUi_Renderer_GL3.h
vendored
Normal file
210
vendor/rmlui_backend/RmlUi_Renderer_GL3.h
vendored
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
enum class ProgramId;
|
||||||
|
enum class UniformId;
|
||||||
|
class RenderLayerStack;
|
||||||
|
namespace Gfx {
|
||||||
|
struct ProgramData;
|
||||||
|
struct FramebufferData;
|
||||||
|
} // namespace Gfx
|
||||||
|
|
||||||
|
class RenderInterface_GL3 : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
RenderInterface_GL3();
|
||||||
|
~RenderInterface_GL3();
|
||||||
|
|
||||||
|
// Returns true if the renderer was successfully constructed.
|
||||||
|
explicit operator bool() const { return static_cast<bool>(program_data); }
|
||||||
|
|
||||||
|
// The viewport should be updated whenever the window size changes.
|
||||||
|
void SetViewport(int viewport_width, int viewport_height, int viewport_offset_x = 0, int viewport_offset_y = 0);
|
||||||
|
|
||||||
|
// Sets up OpenGL states for taking rendering commands from RmlUi.
|
||||||
|
void BeginFrame();
|
||||||
|
// Draws the result to the backbuffer and restores OpenGL state.
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
// Optional, can be used to clear the active framebuffer.
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::RenderInterface --
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle handle) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions) override;
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
void EnableClipMask(bool enable) override;
|
||||||
|
void RenderToClipMask(Rml::ClipMaskOperation mask_operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation) override;
|
||||||
|
|
||||||
|
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||||
|
|
||||||
|
Rml::LayerHandle PushLayer() override;
|
||||||
|
void CompositeLayers(Rml::LayerHandle source, Rml::LayerHandle destination, Rml::BlendMode blend_mode,
|
||||||
|
Rml::Span<const Rml::CompiledFilterHandle> filters) override;
|
||||||
|
void PopLayer() override;
|
||||||
|
|
||||||
|
Rml::TextureHandle SaveLayerAsTexture() override;
|
||||||
|
|
||||||
|
Rml::CompiledFilterHandle SaveLayerAsMaskImage() override;
|
||||||
|
|
||||||
|
Rml::CompiledFilterHandle CompileFilter(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||||
|
void ReleaseFilter(Rml::CompiledFilterHandle filter) override;
|
||||||
|
|
||||||
|
Rml::CompiledShaderHandle CompileShader(const Rml::String& name, const Rml::Dictionary& parameters) override;
|
||||||
|
void RenderShader(Rml::CompiledShaderHandle shader_handle, Rml::CompiledGeometryHandle geometry_handle, Rml::Vector2f translation,
|
||||||
|
Rml::TextureHandle texture) override;
|
||||||
|
void ReleaseShader(Rml::CompiledShaderHandle effect_handle) override;
|
||||||
|
|
||||||
|
// Can be passed to RenderGeometry() to enable texture rendering without changing the bound texture.
|
||||||
|
static constexpr Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);
|
||||||
|
// Can be passed to RenderGeometry() to leave the bound texture and used program unchanged.
|
||||||
|
static constexpr Rml::TextureHandle TexturePostprocess = Rml::TextureHandle(-2);
|
||||||
|
|
||||||
|
// -- Utility functions for clients --
|
||||||
|
|
||||||
|
const Rml::Matrix4f& GetTransform() const;
|
||||||
|
void ResetProgram();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UseProgram(ProgramId program_id);
|
||||||
|
int GetUniformLocation(UniformId uniform_id) const;
|
||||||
|
void SubmitTransformUniform(Rml::Vector2f translation);
|
||||||
|
|
||||||
|
void BlitLayerToPostprocessPrimary(Rml::LayerHandle layer_handle);
|
||||||
|
void RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles);
|
||||||
|
|
||||||
|
void SetScissor(Rml::Rectanglei region, bool vertically_flip = false);
|
||||||
|
|
||||||
|
void DrawFullscreenQuad();
|
||||||
|
void DrawFullscreenQuad(Rml::Vector2f uv_offset, Rml::Vector2f uv_scaling = Rml::Vector2f(1.f));
|
||||||
|
|
||||||
|
void RenderBlur(float sigma, const Gfx::FramebufferData& source_destination, const Gfx::FramebufferData& temp, Rml::Rectanglei window_flipped);
|
||||||
|
|
||||||
|
static constexpr size_t MaxNumPrograms = 32;
|
||||||
|
std::bitset<MaxNumPrograms> program_transform_dirty;
|
||||||
|
|
||||||
|
Rml::Matrix4f transform;
|
||||||
|
Rml::Matrix4f projection;
|
||||||
|
|
||||||
|
ProgramId active_program = {};
|
||||||
|
Rml::Rectanglei scissor_state;
|
||||||
|
|
||||||
|
int viewport_width = 0;
|
||||||
|
int viewport_height = 0;
|
||||||
|
int viewport_offset_x = 0;
|
||||||
|
int viewport_offset_y = 0;
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle fullscreen_quad_geometry = {};
|
||||||
|
|
||||||
|
Rml::UniquePtr<const Gfx::ProgramData> program_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Manages render targets, including the layer stack and postprocessing framebuffers.
|
||||||
|
|
||||||
|
Layers can be pushed and popped, creating new framebuffers as needed. Typically, geometry is rendered to the top
|
||||||
|
layer. The layer framebuffers may have MSAA enabled.
|
||||||
|
|
||||||
|
Postprocessing framebuffers are separate from the layers, and are commonly used to apply texture-wide effects
|
||||||
|
such as filters. They are used both as input and output during rendering, and do not use MSAA.
|
||||||
|
*/
|
||||||
|
class RenderLayerStack {
|
||||||
|
public:
|
||||||
|
RenderLayerStack();
|
||||||
|
~RenderLayerStack();
|
||||||
|
|
||||||
|
// Push a new layer. All references to previously retrieved layers are invalidated.
|
||||||
|
Rml::LayerHandle PushLayer();
|
||||||
|
|
||||||
|
// Pop the top layer. All references to previously retrieved layers are invalidated.
|
||||||
|
void PopLayer();
|
||||||
|
|
||||||
|
const Gfx::FramebufferData& GetLayer(Rml::LayerHandle layer) const;
|
||||||
|
const Gfx::FramebufferData& GetTopLayer() const;
|
||||||
|
Rml::LayerHandle GetTopLayerHandle() const;
|
||||||
|
|
||||||
|
const Gfx::FramebufferData& GetPostprocessPrimary() { return EnsureFramebufferPostprocess(0); }
|
||||||
|
const Gfx::FramebufferData& GetPostprocessSecondary() { return EnsureFramebufferPostprocess(1); }
|
||||||
|
const Gfx::FramebufferData& GetPostprocessTertiary() { return EnsureFramebufferPostprocess(2); }
|
||||||
|
const Gfx::FramebufferData& GetBlendMask() { return EnsureFramebufferPostprocess(3); }
|
||||||
|
|
||||||
|
void SwapPostprocessPrimarySecondary();
|
||||||
|
|
||||||
|
void BeginFrame(int new_width, int new_height);
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DestroyFramebuffers();
|
||||||
|
const Gfx::FramebufferData& EnsureFramebufferPostprocess(int index);
|
||||||
|
|
||||||
|
int width = 0, height = 0;
|
||||||
|
|
||||||
|
// The number of active layers is manually tracked since we re-use the framebuffers stored in the fb_layers stack.
|
||||||
|
int layers_size = 0;
|
||||||
|
|
||||||
|
Rml::Vector<Gfx::FramebufferData> fb_layers;
|
||||||
|
Rml::Vector<Gfx::FramebufferData> fb_postprocess;
|
||||||
|
};
|
||||||
|
|
||||||
|
RenderLayerStack render_layers;
|
||||||
|
|
||||||
|
struct GLStateBackup {
|
||||||
|
bool enable_cull_face;
|
||||||
|
bool enable_blend;
|
||||||
|
bool enable_stencil_test;
|
||||||
|
bool enable_scissor_test;
|
||||||
|
bool enable_depth_test;
|
||||||
|
|
||||||
|
int viewport[4];
|
||||||
|
int scissor[4];
|
||||||
|
|
||||||
|
int active_texture;
|
||||||
|
|
||||||
|
int stencil_clear_value;
|
||||||
|
float color_clear_value[4];
|
||||||
|
unsigned char color_writemask[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
|
||||||
212
vendor/rmlui_backend/RmlUi_Renderer_SDL.cpp
vendored
Normal file
212
vendor/rmlui_backend/RmlUi_Renderer_SDL.cpp
vendored
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#include "RmlUi_Renderer_SDL.h"
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
#else
|
||||||
|
#include <SDL_image.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION == 2 && !(SDL_VIDEO_RENDER_OGL)
|
||||||
|
#error "Only the OpenGL SDL backend is supported."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void SetRenderClipRect(SDL_Renderer* renderer, const SDL_Rect* rect)
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetRenderClipRect(renderer, rect);
|
||||||
|
#else
|
||||||
|
SDL_RenderSetClipRect(renderer, rect);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void SetRenderViewport(SDL_Renderer* renderer, const SDL_Rect* rect)
|
||||||
|
{
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
SDL_SetRenderViewport(renderer, rect);
|
||||||
|
#else
|
||||||
|
SDL_RenderSetViewport(renderer, rect);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInterface_SDL::RenderInterface_SDL(SDL_Renderer* renderer) : renderer(renderer)
|
||||||
|
{
|
||||||
|
// RmlUi serves vertex colors and textures with premultiplied alpha, set the blend mode accordingly.
|
||||||
|
// Equivalent to glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA).
|
||||||
|
blend_mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ONE,
|
||||||
|
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::BeginFrame()
|
||||||
|
{
|
||||||
|
SetRenderViewport(renderer, nullptr);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer, blend_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::EndFrame() {}
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle RenderInterface_SDL::CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices)
|
||||||
|
{
|
||||||
|
GeometryView* data = new GeometryView{vertices, indices};
|
||||||
|
return reinterpret_cast<Rml::CompiledGeometryHandle>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::ReleaseGeometry(Rml::CompiledGeometryHandle geometry)
|
||||||
|
{
|
||||||
|
delete reinterpret_cast<GeometryView*>(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture)
|
||||||
|
{
|
||||||
|
const GeometryView* geometry = reinterpret_cast<GeometryView*>(handle);
|
||||||
|
const Rml::Vertex* vertices = geometry->vertices.data();
|
||||||
|
const size_t num_vertices = geometry->vertices.size();
|
||||||
|
const int* indices = geometry->indices.data();
|
||||||
|
const size_t num_indices = geometry->indices.size();
|
||||||
|
|
||||||
|
if (sdl_vertices_size < num_vertices)
|
||||||
|
{
|
||||||
|
sdl_vertices_size = num_vertices * 1.5;
|
||||||
|
sdl_vertices.reset(new SDL_Vertex[sdl_vertices_size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_vertices; i++)
|
||||||
|
{
|
||||||
|
SDL_Vertex& sdl_vertex = sdl_vertices[i];
|
||||||
|
sdl_vertex.position = {vertices[i].position.x + translation.x, vertices[i].position.y + translation.y};
|
||||||
|
sdl_vertex.tex_coord = {vertices[i].tex_coord.x, vertices[i].tex_coord.y};
|
||||||
|
|
||||||
|
const auto& color = vertices[i].colour;
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
sdl_vertex.color = {color.red / 255.f, color.green / 255.f, color.blue / 255.f, color.alpha / 255.f};
|
||||||
|
#else
|
||||||
|
sdl_vertex.color = {color.red, color.green, color.blue, color.alpha};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture* sdl_texture = (SDL_Texture*)texture;
|
||||||
|
|
||||||
|
SDL_RenderGeometry(renderer, sdl_texture, sdl_vertices.get(), (int)num_vertices, indices, (int)num_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::EnableScissorRegion(bool enable)
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
SetRenderClipRect(renderer, &rect_scissor);
|
||||||
|
else
|
||||||
|
SetRenderClipRect(renderer, nullptr);
|
||||||
|
|
||||||
|
scissor_region_enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::SetScissorRegion(Rml::Rectanglei region)
|
||||||
|
{
|
||||||
|
rect_scissor.x = region.Left();
|
||||||
|
rect_scissor.y = region.Top();
|
||||||
|
rect_scissor.w = region.Width();
|
||||||
|
rect_scissor.h = region.Height();
|
||||||
|
|
||||||
|
if (scissor_region_enabled)
|
||||||
|
SetRenderClipRect(renderer, &rect_scissor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle RenderInterface_SDL::LoadTexture(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 {};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
const size_t i_ext = source.rfind('.');
|
||||||
|
Rml::String extension = (i_ext == Rml::String::npos ? Rml::String() : source.substr(i_ext + 1));
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_IO(SDL_IOFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, SDL_PixelFormat format) { return SDL_ConvertSurface(surface, format); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_DestroySurface(surface); };
|
||||||
|
#else
|
||||||
|
auto CreateSurface = [&]() { return IMG_LoadTyped_RW(SDL_RWFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str()); };
|
||||||
|
auto GetSurfaceFormat = [](SDL_Surface* surface) { return surface->format->format; };
|
||||||
|
auto ConvertSurface = [](SDL_Surface* surface, Uint32 format) { return SDL_ConvertSurfaceFormat(surface, format, 0); };
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_FreeSurface(surface); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* surface = CreateSurface();
|
||||||
|
if (!surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
if (GetSurfaceFormat(surface) != SDL_PIXELFORMAT_RGBA32 && GetSurfaceFormat(surface) != SDL_PIXELFORMAT_BGRA32)
|
||||||
|
{
|
||||||
|
SDL_Surface* converted_surface = ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
DestroySurface(surface);
|
||||||
|
if (!converted_surface)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
surface = converted_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
const size_t pixels_byte_size = surface->w * surface->h * 4;
|
||||||
|
byte* pixels = static_cast<byte*>(surface->pixels);
|
||||||
|
for (size_t i = 0; i < pixels_byte_size; i += 4)
|
||||||
|
{
|
||||||
|
const byte alpha = pixels[i + 3];
|
||||||
|
for (size_t j = 0; j < 3; ++j)
|
||||||
|
pixels[i + j] = byte(int(pixels[i + j]) * int(alpha) / 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
texture_dimensions = Rml::Vector2i(surface->w, surface->h);
|
||||||
|
DestroySurface(surface);
|
||||||
|
|
||||||
|
if (texture)
|
||||||
|
SDL_SetTextureBlendMode(texture, blend_mode);
|
||||||
|
|
||||||
|
return (Rml::TextureHandle)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle RenderInterface_SDL::GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions)
|
||||||
|
{
|
||||||
|
RMLUI_ASSERT(source.data() && source.size() == size_t(source_dimensions.x * source_dimensions.y * 4));
|
||||||
|
|
||||||
|
#if SDL_MAJOR_VERSION >= 3
|
||||||
|
auto CreateSurface = [&]() {
|
||||||
|
return SDL_CreateSurfaceFrom(source_dimensions.x, source_dimensions.y, SDL_PIXELFORMAT_RGBA32, (void*)source.data(), source_dimensions.x * 4);
|
||||||
|
};
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_DestroySurface(surface); };
|
||||||
|
#else
|
||||||
|
auto CreateSurface = [&]() {
|
||||||
|
return SDL_CreateRGBSurfaceWithFormatFrom((void*)source.data(), source_dimensions.x, source_dimensions.y, 32, source_dimensions.x * 4,
|
||||||
|
SDL_PIXELFORMAT_RGBA32);
|
||||||
|
};
|
||||||
|
auto DestroySurface = [](SDL_Surface* surface) { SDL_FreeSurface(surface); };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* surface = CreateSurface();
|
||||||
|
|
||||||
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
SDL_SetTextureBlendMode(texture, blend_mode);
|
||||||
|
|
||||||
|
DestroySurface(surface);
|
||||||
|
return (Rml::TextureHandle)texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL::ReleaseTexture(Rml::TextureHandle texture_handle)
|
||||||
|
{
|
||||||
|
SDL_DestroyTexture((SDL_Texture*)texture_handle);
|
||||||
|
}
|
||||||
46
vendor/rmlui_backend/RmlUi_Renderer_SDL.h
vendored
Normal file
46
vendor/rmlui_backend/RmlUi_Renderer_SDL.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
|
||||||
|
#if RMLUI_SDL_VERSION_MAJOR == 3
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#elif RMLUI_SDL_VERSION_MAJOR == 2
|
||||||
|
#include <SDL.h>
|
||||||
|
#else
|
||||||
|
#error "Unspecified RMLUI_SDL_VERSION_MAJOR. Please set this definition to the major version of the SDL library being linked to."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class RenderInterface_SDL : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
RenderInterface_SDL(SDL_Renderer* renderer);
|
||||||
|
|
||||||
|
// Sets up OpenGL states for taking rendering commands from RmlUi.
|
||||||
|
void BeginFrame();
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::RenderInterface --
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions) override;
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct GeometryView {
|
||||||
|
Rml::Span<const Rml::Vertex> vertices;
|
||||||
|
Rml::Span<const int> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
SDL_BlendMode blend_mode = {};
|
||||||
|
SDL_Rect rect_scissor = {};
|
||||||
|
bool scissor_region_enabled = false;
|
||||||
|
Rml::UniquePtr<SDL_Vertex[]> sdl_vertices;
|
||||||
|
size_t sdl_vertices_size = 0;
|
||||||
|
};
|
||||||
630
vendor/rmlui_backend/RmlUi_Renderer_SDL_GPU.cpp
vendored
Normal file
630
vendor/rmlui_backend/RmlUi_Renderer_SDL_GPU.cpp
vendored
Normal file
@@ -0,0 +1,630 @@
|
|||||||
|
#include "RmlUi_Renderer_SDL_GPU.h"
|
||||||
|
#include "RmlUi_SDL_GPU/ShadersCompiledSPV.h"
|
||||||
|
#include <RmlUi/Core/Core.h>
|
||||||
|
#include <RmlUi/Core/FileInterface.h>
|
||||||
|
#include <RmlUi/Core/Log.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
|
||||||
|
using namespace Rml;
|
||||||
|
|
||||||
|
enum ShaderType {
|
||||||
|
ShaderTypeColor,
|
||||||
|
ShaderTypeTexture,
|
||||||
|
ShaderTypeVert,
|
||||||
|
ShaderTypeCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShaderFormat {
|
||||||
|
ShaderFormatSPIRV,
|
||||||
|
ShaderFormatMSL,
|
||||||
|
ShaderFormatDXIL,
|
||||||
|
ShaderFormatCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Shader {
|
||||||
|
Span<const byte> data[ShaderFormatCount];
|
||||||
|
int uniforms;
|
||||||
|
int samplers;
|
||||||
|
SDL_GPUShaderStage stage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
#define X(name) \
|
||||||
|
Span<const byte> \
|
||||||
|
{ \
|
||||||
|
name, sizeof(name) \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Shader shaders[ShaderTypeCount] = {
|
||||||
|
{{X(shader_frag_color_spirv), X(shader_frag_color_msl), X(shader_frag_color_dxil)}, 0, 0, SDL_GPU_SHADERSTAGE_FRAGMENT},
|
||||||
|
{{X(shader_frag_texture_spirv), X(shader_frag_texture_msl), X(shader_frag_texture_dxil)}, 0, 1, SDL_GPU_SHADERSTAGE_FRAGMENT},
|
||||||
|
{{X(shader_vert_spirv), X(shader_vert_msl), X(shader_vert_dxil)}, 2, 0, SDL_GPU_SHADERSTAGE_VERTEX}};
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
static SDL_GPUShader* CreateShaderFromMemory(SDL_GPUDevice* device, ShaderType type)
|
||||||
|
{
|
||||||
|
SDL_GPUShaderFormat sdl_shader_format = SDL_GetGPUShaderFormats(device);
|
||||||
|
ShaderFormat format = ShaderFormatCount;
|
||||||
|
const char* entrypoint = nullptr;
|
||||||
|
if (sdl_shader_format & SDL_GPU_SHADERFORMAT_SPIRV)
|
||||||
|
{
|
||||||
|
sdl_shader_format = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||||
|
format = ShaderFormatSPIRV;
|
||||||
|
entrypoint = "main";
|
||||||
|
}
|
||||||
|
else if (sdl_shader_format & SDL_GPU_SHADERFORMAT_DXIL)
|
||||||
|
{
|
||||||
|
sdl_shader_format = SDL_GPU_SHADERFORMAT_DXIL;
|
||||||
|
format = ShaderFormatDXIL;
|
||||||
|
entrypoint = "main";
|
||||||
|
}
|
||||||
|
else if (sdl_shader_format & SDL_GPU_SHADERFORMAT_MSL)
|
||||||
|
{
|
||||||
|
sdl_shader_format = SDL_GPU_SHADERFORMAT_MSL;
|
||||||
|
format = ShaderFormatMSL;
|
||||||
|
entrypoint = "main0";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RMLUI_ERRORMSG("Invalid shader format");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const Shader& shader = shaders[type];
|
||||||
|
SDL_GPUShaderCreateInfo info{};
|
||||||
|
info.code = static_cast<const Uint8*>(shader.data[format].data());
|
||||||
|
info.code_size = shader.data[format].size();
|
||||||
|
info.entrypoint = entrypoint;
|
||||||
|
info.format = sdl_shader_format;
|
||||||
|
info.stage = shader.stage;
|
||||||
|
info.num_samplers = shader.samplers;
|
||||||
|
info.num_uniform_buffers = shader.uniforms;
|
||||||
|
SDL_GPUShader* sdl_shader = SDL_CreateGPUShader(device, &info);
|
||||||
|
if (!sdl_shader)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create shader: %s", SDL_GetError());
|
||||||
|
RMLUI_ERROR;
|
||||||
|
}
|
||||||
|
return sdl_shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::CreatePipelines()
|
||||||
|
{
|
||||||
|
SDL_GPUShader* color_shader = CreateShaderFromMemory(device, ShaderTypeColor);
|
||||||
|
SDL_GPUShader* texture_shader = CreateShaderFromMemory(device, ShaderTypeTexture);
|
||||||
|
SDL_GPUShader* vert_shader = CreateShaderFromMemory(device, ShaderTypeVert);
|
||||||
|
|
||||||
|
SDL_GPUColorTargetDescription target{};
|
||||||
|
target.format = SDL_GetGPUSwapchainTextureFormat(device, window);
|
||||||
|
target.blend_state.enable_blend = true;
|
||||||
|
target.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
|
||||||
|
target.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
|
||||||
|
target.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||||
|
target.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||||
|
target.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
target.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
|
||||||
|
SDL_GPUVertexAttribute attrib[3]{};
|
||||||
|
attrib[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
||||||
|
attrib[0].location = 0;
|
||||||
|
attrib[0].offset = offsetof(Vertex, position);
|
||||||
|
attrib[1].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM;
|
||||||
|
attrib[1].location = 1;
|
||||||
|
attrib[1].offset = offsetof(Vertex, colour);
|
||||||
|
attrib[2].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
||||||
|
attrib[2].location = 2;
|
||||||
|
attrib[2].offset = offsetof(Vertex, tex_coord);
|
||||||
|
|
||||||
|
SDL_GPUVertexBufferDescription buffer{};
|
||||||
|
buffer.pitch = sizeof(Vertex);
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipelineCreateInfo info{};
|
||||||
|
info.vertex_shader = vert_shader;
|
||||||
|
|
||||||
|
info.target_info.num_color_targets = 1;
|
||||||
|
info.target_info.color_target_descriptions = ⌖
|
||||||
|
|
||||||
|
info.vertex_input_state.num_vertex_attributes = 3;
|
||||||
|
info.vertex_input_state.num_vertex_buffers = 1;
|
||||||
|
info.vertex_input_state.vertex_attributes = attrib;
|
||||||
|
info.vertex_input_state.vertex_buffer_descriptions = &buffer;
|
||||||
|
|
||||||
|
info.fragment_shader = color_shader;
|
||||||
|
color_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info);
|
||||||
|
if (!color_pipeline)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create color pipeline: %s", SDL_GetError());
|
||||||
|
RMLUI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.fragment_shader = texture_shader;
|
||||||
|
texture_pipeline = SDL_CreateGPUGraphicsPipeline(device, &info);
|
||||||
|
if (!texture_pipeline)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create texture pipeline: %s", SDL_GetError());
|
||||||
|
RMLUI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_ReleaseGPUShader(device, color_shader);
|
||||||
|
SDL_ReleaseGPUShader(device, texture_shader);
|
||||||
|
SDL_ReleaseGPUShader(device, vert_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInterface_SDL_GPU::RenderInterface_SDL_GPU(SDL_GPUDevice* device, SDL_Window* window) :
|
||||||
|
device(device), window(window), render_pass(nullptr), copy_pass(nullptr)
|
||||||
|
{
|
||||||
|
CreatePipelines();
|
||||||
|
|
||||||
|
SDL_GPUSamplerCreateInfo info{};
|
||||||
|
info.min_filter = SDL_GPU_FILTER_LINEAR;
|
||||||
|
info.mag_filter = SDL_GPU_FILTER_LINEAR;
|
||||||
|
info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
|
||||||
|
info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
|
||||||
|
info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
|
||||||
|
info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
|
||||||
|
linear_sampler = SDL_CreateGPUSampler(device, &info);
|
||||||
|
if (!linear_sampler)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to acquire command buffer: %s", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::Shutdown()
|
||||||
|
{
|
||||||
|
for (Rml::UniquePtr<Command>& command : commands)
|
||||||
|
{
|
||||||
|
command->Update(*this);
|
||||||
|
}
|
||||||
|
for (Rml::UniquePtr<Buffer>& buffer : buffers)
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device, buffer->transfer_buffer);
|
||||||
|
SDL_ReleaseGPUBuffer(device, buffer->buffer);
|
||||||
|
}
|
||||||
|
SDL_ReleaseGPUSampler(device, linear_sampler);
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(device, color_pipeline);
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(device, texture_pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::BeginFrame(SDL_GPUCommandBuffer* command_buffer, SDL_GPUTexture* swapchain_texture, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
this->command_buffer = command_buffer;
|
||||||
|
this->swapchain_texture = swapchain_texture;
|
||||||
|
swapchain_width = width;
|
||||||
|
swapchain_height = height;
|
||||||
|
proj = Matrix4f::ProjectOrtho(0.0f, static_cast<float>(width), static_cast<float>(height), 0.0f, -10'000.f, 10'000.f);
|
||||||
|
SetTransform(nullptr);
|
||||||
|
EnableScissorRegion(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::EndFrame()
|
||||||
|
{
|
||||||
|
for (Rml::UniquePtr<Command>& command : commands)
|
||||||
|
{
|
||||||
|
command->Update(*this);
|
||||||
|
}
|
||||||
|
commands.clear();
|
||||||
|
|
||||||
|
if (copy_pass)
|
||||||
|
{
|
||||||
|
SDL_EndGPUCopyPass(copy_pass);
|
||||||
|
copy_pass = nullptr;
|
||||||
|
}
|
||||||
|
if (render_pass)
|
||||||
|
{
|
||||||
|
SDL_EndGPURenderPass(render_pass);
|
||||||
|
render_pass = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderInterface_SDL_GPU::BeginCopyPass()
|
||||||
|
{
|
||||||
|
if (copy_pass)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (render_pass)
|
||||||
|
{
|
||||||
|
SDL_EndGPURenderPass(render_pass);
|
||||||
|
render_pass = nullptr;
|
||||||
|
}
|
||||||
|
copy_pass = SDL_BeginGPUCopyPass(command_buffer);
|
||||||
|
if (!copy_pass)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to begin copy pass: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderInterface_SDL_GPU::BeginRenderPass()
|
||||||
|
{
|
||||||
|
if (render_pass)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (copy_pass)
|
||||||
|
{
|
||||||
|
SDL_EndGPUCopyPass(copy_pass);
|
||||||
|
copy_pass = nullptr;
|
||||||
|
}
|
||||||
|
SDL_GPUColorTargetInfo color_info{};
|
||||||
|
color_info.texture = swapchain_texture;
|
||||||
|
color_info.load_op = SDL_GPU_LOADOP_LOAD;
|
||||||
|
color_info.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
render_pass = SDL_BeginGPURenderPass(command_buffer, &color_info, 1, nullptr);
|
||||||
|
if (!render_pass)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to begin render pass: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompiledGeometryHandle RenderInterface_SDL_GPU::CompileGeometry(Span<const Vertex> vertices, Span<const int> indices)
|
||||||
|
{
|
||||||
|
if (!BeginCopyPass())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vertex_size = static_cast<int>(vertices.size() * sizeof(Vertex));
|
||||||
|
uint32_t index_size = static_cast<int>(indices.size() * sizeof(int));
|
||||||
|
|
||||||
|
GeometryView* geometry = new GeometryView();
|
||||||
|
geometry->vertex_buffer = RequestBuffer(vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX);
|
||||||
|
geometry->index_buffer = RequestBuffer(index_size, SDL_GPU_BUFFERUSAGE_INDEX);
|
||||||
|
if (!geometry->vertex_buffer || !geometry->index_buffer)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to request buffer(s)");
|
||||||
|
delete geometry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* vertex_data = SDL_MapGPUTransferBuffer(device, geometry->vertex_buffer->transfer_buffer, true);
|
||||||
|
void* index_data = SDL_MapGPUTransferBuffer(device, geometry->index_buffer->transfer_buffer, true);
|
||||||
|
if (!vertex_data || !index_data)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to map transfer buffer(s): %s", SDL_GetError());
|
||||||
|
delete geometry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(vertex_data, vertices.data(), vertex_size);
|
||||||
|
std::memcpy(index_data, indices.data(), index_size);
|
||||||
|
SDL_UnmapGPUTransferBuffer(device, geometry->vertex_buffer->transfer_buffer);
|
||||||
|
SDL_UnmapGPUTransferBuffer(device, geometry->index_buffer->transfer_buffer);
|
||||||
|
|
||||||
|
SDL_GPUTransferBufferLocation location{};
|
||||||
|
SDL_GPUBufferRegion region{};
|
||||||
|
|
||||||
|
location.transfer_buffer = geometry->vertex_buffer->transfer_buffer;
|
||||||
|
region.buffer = geometry->vertex_buffer->buffer;
|
||||||
|
region.size = vertex_size;
|
||||||
|
SDL_UploadToGPUBuffer(copy_pass, &location, ®ion, false);
|
||||||
|
|
||||||
|
location.transfer_buffer = geometry->index_buffer->transfer_buffer;
|
||||||
|
region.buffer = geometry->index_buffer->buffer;
|
||||||
|
region.size = index_size;
|
||||||
|
SDL_UploadToGPUBuffer(copy_pass, &location, ®ion, false);
|
||||||
|
|
||||||
|
geometry->num_indices = static_cast<int>(indices.size());
|
||||||
|
geometry->vertex_buffer->in_use = true;
|
||||||
|
geometry->index_buffer->in_use = true;
|
||||||
|
|
||||||
|
return reinterpret_cast<Rml::CompiledGeometryHandle>(geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::ReleaseGeometryCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
(void)interface;
|
||||||
|
GeometryView* geometry = reinterpret_cast<GeometryView*>(handle);
|
||||||
|
geometry->vertex_buffer->in_use = false;
|
||||||
|
geometry->index_buffer->in_use = false;
|
||||||
|
delete geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::ReleaseGeometry(CompiledGeometryHandle handle)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<ReleaseGeometryCommand>(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::RenderGeometryCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
if (!interface.BeginRenderPass())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeometryView* geometry = reinterpret_cast<GeometryView*>(handle);
|
||||||
|
|
||||||
|
if (texture != 0)
|
||||||
|
{
|
||||||
|
SDL_BindGPUGraphicsPipeline(interface.render_pass, interface.texture_pipeline);
|
||||||
|
|
||||||
|
SDL_GPUTextureSamplerBinding texture_binding{};
|
||||||
|
texture_binding.texture = reinterpret_cast<SDL_GPUTexture*>(texture);
|
||||||
|
texture_binding.sampler = interface.linear_sampler;
|
||||||
|
SDL_BindGPUFragmentSamplers(interface.render_pass, 0, &texture_binding, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SDL_BindGPUGraphicsPipeline(interface.render_pass, interface.color_pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUBufferBinding vertex_buffer_binding{};
|
||||||
|
SDL_GPUBufferBinding index_buffer_binding{};
|
||||||
|
vertex_buffer_binding.buffer = geometry->vertex_buffer->buffer;
|
||||||
|
index_buffer_binding.buffer = geometry->index_buffer->buffer;
|
||||||
|
|
||||||
|
SDL_BindGPUVertexBuffers(interface.render_pass, 0, &vertex_buffer_binding, 1);
|
||||||
|
SDL_BindGPUIndexBuffer(interface.render_pass, &index_buffer_binding, SDL_GPU_INDEXELEMENTSIZE_32BIT);
|
||||||
|
|
||||||
|
SDL_SetGPUScissor(interface.render_pass, &interface.scissor);
|
||||||
|
|
||||||
|
SDL_PushGPUVertexUniformData(interface.command_buffer, 0, &interface.transform, sizeof(interface.transform));
|
||||||
|
SDL_PushGPUVertexUniformData(interface.command_buffer, 1, &translation, sizeof(translation));
|
||||||
|
|
||||||
|
SDL_DrawGPUIndexedPrimitives(interface.render_pass, geometry->num_indices, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::RenderGeometry(CompiledGeometryHandle handle, Vector2f translation, TextureHandle texture)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<RenderGeometryCommand>(handle, translation, texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::EnableScissorRegionCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
interface.scissor.x = 0;
|
||||||
|
interface.scissor.y = 0;
|
||||||
|
interface.scissor.w = interface.swapchain_width;
|
||||||
|
interface.scissor.h = interface.swapchain_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::EnableScissorRegion(bool enable)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<EnableScissorRegionCommand>(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::SetScissorRegionCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
interface.scissor.x = region.Left();
|
||||||
|
interface.scissor.w = region.Width();
|
||||||
|
interface.scissor.y = region.Top();
|
||||||
|
interface.scissor.h = region.Height();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::SetScissorRegion(Rectanglei region)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<SetScissorRegionCommand>(region));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureHandle RenderInterface_SDL_GPU::LoadTexture(Vector2i& texture_dimensions, const String& source)
|
||||||
|
{
|
||||||
|
Rml::FileInterface* file_interface = Rml::GetFileInterface();
|
||||||
|
Rml::FileHandle file_handle = file_interface->Open(source);
|
||||||
|
if (!file_handle)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
using Rml::byte;
|
||||||
|
Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
|
||||||
|
file_interface->Read(buffer.get(), buffer_size, file_handle);
|
||||||
|
file_interface->Close(file_handle);
|
||||||
|
|
||||||
|
const size_t i_ext = source.rfind('.');
|
||||||
|
Rml::String extension = (i_ext == Rml::String::npos ? Rml::String() : source.substr(i_ext + 1));
|
||||||
|
|
||||||
|
SDL_Surface* surface = IMG_LoadTyped_IO(SDL_IOFromMem(buffer.get(), int(buffer_size)), 1, extension.c_str());
|
||||||
|
if (!surface)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
if (surface->format != SDL_PIXELFORMAT_RGBA32)
|
||||||
|
{
|
||||||
|
SDL_Surface* converted_surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
if (!converted_surface)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
surface = converted_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert colors to premultiplied alpha, which is necessary for correct alpha compositing.
|
||||||
|
const size_t pixels_byte_size = surface->w * surface->h * 4;
|
||||||
|
byte* pixels = static_cast<byte*>(surface->pixels);
|
||||||
|
for (size_t i = 0; i < pixels_byte_size; i += 4)
|
||||||
|
{
|
||||||
|
const byte alpha = pixels[i + 3];
|
||||||
|
for (size_t j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
pixels[i + j] = byte(int(pixels[i + j]) * int(alpha) / 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<const byte> data{static_cast<const byte*>(surface->pixels), static_cast<size_t>(surface->pitch * surface->h)};
|
||||||
|
texture_dimensions = {surface->w, surface->h};
|
||||||
|
|
||||||
|
TextureHandle handle = GenerateTexture(data, texture_dimensions);
|
||||||
|
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureHandle RenderInterface_SDL_GPU::GenerateTexture(Span<const byte> source, Vector2i source_dimensions)
|
||||||
|
{
|
||||||
|
SDL_GPUTransferBuffer* transfer_buffer;
|
||||||
|
{
|
||||||
|
SDL_GPUTransferBufferCreateInfo info{};
|
||||||
|
info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
||||||
|
info.size = source_dimensions.x * source_dimensions.y * 4;
|
||||||
|
transfer_buffer = SDL_CreateGPUTransferBuffer(device, &info);
|
||||||
|
if (!transfer_buffer)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create transfer buffer: %s", SDL_GetError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* dst = SDL_MapGPUTransferBuffer(device, transfer_buffer, false);
|
||||||
|
if (!dst)
|
||||||
|
{
|
||||||
|
SDL_Log("Failed to map transfer buffer: %s", SDL_GetError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(dst, source.data(), source_dimensions.x * source_dimensions.y * 4);
|
||||||
|
SDL_UnmapGPUTransferBuffer(device, transfer_buffer);
|
||||||
|
|
||||||
|
SDL_GPUTexture* texture;
|
||||||
|
{
|
||||||
|
SDL_GPUTextureCreateInfo info{};
|
||||||
|
info.type = SDL_GPU_TEXTURETYPE_2D;
|
||||||
|
info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
||||||
|
info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
||||||
|
info.width = source_dimensions.x;
|
||||||
|
info.height = source_dimensions.y;
|
||||||
|
info.layer_count_or_depth = 1;
|
||||||
|
info.num_levels = 1;
|
||||||
|
texture = SDL_CreateGPUTexture(device, &info);
|
||||||
|
if (!texture)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create texture: %s", SDL_GetError());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUTextureTransferInfo transfer_info{};
|
||||||
|
SDL_GPUTextureRegion region{};
|
||||||
|
transfer_info.transfer_buffer = transfer_buffer;
|
||||||
|
region.texture = texture;
|
||||||
|
region.w = source_dimensions.x;
|
||||||
|
region.h = source_dimensions.y;
|
||||||
|
region.d = 1;
|
||||||
|
|
||||||
|
// We can get calls out outside of Begin/End Frame so always acquire a command buffer here
|
||||||
|
SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(device);
|
||||||
|
if (!command_buffer)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to acquire command buffer: %s", SDL_GetError());
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||||
|
SDL_ReleaseGPUTexture(device, texture);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(command_buffer);
|
||||||
|
if (!copy_pass)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to begin copy pass: %s", SDL_GetError());
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||||
|
SDL_ReleaseGPUTexture(device, texture);
|
||||||
|
SDL_CancelGPUCommandBuffer(command_buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_UploadToGPUTexture(copy_pass, &transfer_info, ®ion, false);
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device, transfer_buffer);
|
||||||
|
SDL_EndGPUCopyPass(copy_pass);
|
||||||
|
SDL_SubmitGPUCommandBuffer(command_buffer);
|
||||||
|
|
||||||
|
return reinterpret_cast<TextureHandle>(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::ReleaseTextureCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
SDL_GPUTexture* texture = reinterpret_cast<SDL_GPUTexture*>(handle);
|
||||||
|
SDL_ReleaseGPUTexture(interface.device, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::ReleaseTexture(TextureHandle texture_handle)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<ReleaseTextureCommand>(texture_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInterface_SDL_GPU::SetTransformCommand::SetTransformCommand(const Rml::Matrix4f* new_transform)
|
||||||
|
{
|
||||||
|
if (new_transform)
|
||||||
|
{
|
||||||
|
has_transform = true;
|
||||||
|
transform = *new_transform;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
has_transform = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::SetTransformCommand::Update(RenderInterface_SDL_GPU& interface)
|
||||||
|
{
|
||||||
|
if (has_transform)
|
||||||
|
{
|
||||||
|
interface.transform = interface.proj * transform;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
interface.transform = interface.proj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderInterface_SDL_GPU::SetTransform(const Rml::Matrix4f* new_transform)
|
||||||
|
{
|
||||||
|
commands.push_back(Rml::MakeUnique<SetTransformCommand>(new_transform));
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderInterface_SDL_GPU::Buffer* RenderInterface_SDL_GPU::RequestBuffer(int capacity, SDL_GPUBufferUsageFlags usage)
|
||||||
|
{
|
||||||
|
auto it = std::lower_bound(buffers.begin(), buffers.end(), capacity,
|
||||||
|
[](const Rml::UniquePtr<Buffer>& lhs, int capacity) { return lhs->capacity < capacity; });
|
||||||
|
|
||||||
|
for (auto tmp_it = it; tmp_it != buffers.end(); ++tmp_it)
|
||||||
|
{
|
||||||
|
const auto& buffer = *tmp_it;
|
||||||
|
if (!buffer->in_use && buffer->usage == usage)
|
||||||
|
{
|
||||||
|
// set in_use as false and expect the caller to set it to true themselves
|
||||||
|
buffer->in_use = false;
|
||||||
|
return buffer.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::UniquePtr<Buffer> buffer = Rml::MakeUnique<Buffer>();
|
||||||
|
{
|
||||||
|
SDL_GPUTransferBufferCreateInfo info{};
|
||||||
|
info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
||||||
|
info.size = capacity;
|
||||||
|
buffer->transfer_buffer = SDL_CreateGPUTransferBuffer(device, &info);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
SDL_GPUBufferCreateInfo info{};
|
||||||
|
info.usage = usage;
|
||||||
|
info.size = capacity;
|
||||||
|
buffer->buffer = SDL_CreateGPUBuffer(device, &info);
|
||||||
|
}
|
||||||
|
if (!buffer->transfer_buffer || !buffer->buffer)
|
||||||
|
{
|
||||||
|
Log::Message(Log::LT_ERROR, "Failed to create buffer(s): %s", SDL_GetError());
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device, buffer->transfer_buffer);
|
||||||
|
SDL_ReleaseGPUBuffer(device, buffer->buffer);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
buffer->usage = usage;
|
||||||
|
buffer->in_use = false;
|
||||||
|
buffer->capacity = capacity;
|
||||||
|
auto inserted_it = buffers.insert(it, std::move(buffer));
|
||||||
|
return inserted_it->get();
|
||||||
|
}
|
||||||
122
vendor/rmlui_backend/RmlUi_Renderer_SDL_GPU.h
vendored
Normal file
122
vendor/rmlui_backend/RmlUi_Renderer_SDL_GPU.h
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
#include <RmlUi/Core/Types.h>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
class RenderInterface_SDL_GPU : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
RenderInterface_SDL_GPU(SDL_GPUDevice* device, SDL_Window* window);
|
||||||
|
void Shutdown();
|
||||||
|
void BeginFrame(SDL_GPUCommandBuffer* command_buffer, SDL_GPUTexture* swapchain_texture, uint32_t width, uint32_t height);
|
||||||
|
void EndFrame();
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i source_dimensions) override;
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
void SetTransform(const Rml::Matrix4f* new_transform) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_GPUDevice* device;
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_GPUGraphicsPipeline* texture_pipeline;
|
||||||
|
SDL_GPUGraphicsPipeline* color_pipeline;
|
||||||
|
SDL_GPUSampler* linear_sampler;
|
||||||
|
SDL_GPUCommandBuffer* command_buffer;
|
||||||
|
SDL_GPUTexture* swapchain_texture;
|
||||||
|
uint32_t swapchain_width;
|
||||||
|
uint32_t swapchain_height;
|
||||||
|
SDL_GPURenderPass* render_pass;
|
||||||
|
SDL_GPUCopyPass* copy_pass;
|
||||||
|
SDL_Rect scissor;
|
||||||
|
Rml::Matrix4f transform;
|
||||||
|
Rml::Matrix4f proj;
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
virtual ~Command() = default;
|
||||||
|
virtual void Update(RenderInterface_SDL_GPU& interface) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EnableScissorRegionCommand : Command {
|
||||||
|
EnableScissorRegionCommand(bool enable) : enable(enable) {}
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
bool enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SetScissorRegionCommand : Command {
|
||||||
|
SetScissorRegionCommand(Rml::Rectanglei region) : region(region) {}
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
Rml::Rectanglei region;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderGeometryCommand : Command {
|
||||||
|
RenderGeometryCommand(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) :
|
||||||
|
handle(handle), translation(translation), texture(texture)
|
||||||
|
{}
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle handle;
|
||||||
|
Rml::Vector2f translation;
|
||||||
|
Rml::TextureHandle texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReleaseGeometryCommand : Command {
|
||||||
|
ReleaseGeometryCommand(Rml::CompiledGeometryHandle handle) : handle(handle) {}
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReleaseTextureCommand : Command {
|
||||||
|
ReleaseTextureCommand(Rml::TextureHandle handle) : handle(handle) {}
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SetTransformCommand : Command {
|
||||||
|
SetTransformCommand(const Rml::Matrix4f* new_transform);
|
||||||
|
void Update(RenderInterface_SDL_GPU& interface) override;
|
||||||
|
|
||||||
|
Rml::Matrix4f transform;
|
||||||
|
bool has_transform;
|
||||||
|
};
|
||||||
|
|
||||||
|
friend struct EnableScissorRegionCommand;
|
||||||
|
friend struct SetScissorRegionCommand;
|
||||||
|
friend struct RenderGeometryCommand;
|
||||||
|
friend struct ReleaseGeometryCommand;
|
||||||
|
friend struct ReleaseTextureCommand;
|
||||||
|
friend struct SetTransformCommand;
|
||||||
|
|
||||||
|
struct Buffer {
|
||||||
|
SDL_GPUTransferBuffer* transfer_buffer;
|
||||||
|
SDL_GPUBuffer* buffer;
|
||||||
|
SDL_GPUBufferUsageFlags usage;
|
||||||
|
int capacity;
|
||||||
|
bool in_use;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GeometryView {
|
||||||
|
Buffer* vertex_buffer;
|
||||||
|
Buffer* index_buffer;
|
||||||
|
int num_indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
// List of ordered render commands
|
||||||
|
Rml::Vector<Rml::UniquePtr<Command>> commands;
|
||||||
|
|
||||||
|
// Sorted vertex/index buffers by capacities
|
||||||
|
Rml::Vector<Rml::UniquePtr<Buffer>> buffers;
|
||||||
|
|
||||||
|
void CreatePipelines();
|
||||||
|
bool BeginCopyPass();
|
||||||
|
bool BeginRenderPass();
|
||||||
|
Buffer* RequestBuffer(int capacity, SDL_GPUBufferUsageFlags usage);
|
||||||
|
};
|
||||||
3017
vendor/rmlui_backend/RmlUi_Renderer_VK.cpp
vendored
Normal file
3017
vendor/rmlui_backend/RmlUi_Renderer_VK.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
563
vendor/rmlui_backend/RmlUi_Renderer_VK.h
vendored
Normal file
563
vendor/rmlui_backend/RmlUi_Renderer_VK.h
vendored
Normal file
@@ -0,0 +1,563 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
|
||||||
|
#ifdef RMLUI_PLATFORM_WIN32
|
||||||
|
#include "RmlUi_Include_Windows.h"
|
||||||
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "RmlUi_Include_Vulkan.h"
|
||||||
|
|
||||||
|
#ifdef RMLUI_DEBUG
|
||||||
|
#define RMLUI_VK_ASSERTMSG(statement, msg) RMLUI_ASSERTMSG(statement, msg)
|
||||||
|
|
||||||
|
// Uncomment the following line to enable additional Vulkan debugging.
|
||||||
|
// #define RMLUI_VK_DEBUG
|
||||||
|
#else
|
||||||
|
#define RMLUI_VK_ASSERTMSG(statement, msg) static_cast<void>(statement)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Your specified API version. Ideally, this will be dynamic in the future.
|
||||||
|
#define RMLUI_VK_API_VERSION VK_API_VERSION_1_0
|
||||||
|
|
||||||
|
class RenderInterface_VK : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t kSwapchainBackBufferCount = 3;
|
||||||
|
static constexpr VkDeviceSize kVideoMemoryForAllocation = 4 * 1024 * 1024; // [bytes]
|
||||||
|
|
||||||
|
RenderInterface_VK();
|
||||||
|
~RenderInterface_VK();
|
||||||
|
|
||||||
|
using CreateSurfaceCallback = bool (*)(VkInstance instance, VkSurfaceKHR* out_surface);
|
||||||
|
|
||||||
|
bool Initialize(Rml::Vector<const char*> required_extensions, CreateSurfaceCallback create_surface_callback);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void BeginFrame();
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
void SetViewport(int width, int height);
|
||||||
|
bool IsSwapchainValid();
|
||||||
|
void RecreateSwapchain();
|
||||||
|
|
||||||
|
// -- Inherited from Rml::RenderInterface --
|
||||||
|
|
||||||
|
/// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future.
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) override;
|
||||||
|
/// Called by RmlUi when it wants to render application-compiled geometry.
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture) override;
|
||||||
|
/// Called by RmlUi when it wants to release application-compiled geometry.
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
|
||||||
|
|
||||||
|
/// Called by RmlUi when a texture is required by the library.
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
|
||||||
|
/// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels.
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions) override;
|
||||||
|
/// Called by RmlUi when a loaded texture is no longer required.
|
||||||
|
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
|
||||||
|
|
||||||
|
/// Called by RmlUi when it wants to enable or disable scissoring to clip content.
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
/// Called by RmlUi when it wants to change the scissor region.
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
/// Called by RmlUi when it wants to set the current transform matrix to a new matrix.
|
||||||
|
void SetTransform(const Rml::Matrix4f* transform) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class shader_type_t : int { Vertex, Fragment, Unknown = -1 };
|
||||||
|
enum class shader_id_t : int { Vertex, Fragment_WithoutTextures, Fragment_WithTextures };
|
||||||
|
|
||||||
|
struct shader_vertex_user_data_t {
|
||||||
|
// Member objects are order-sensitive to match shader.
|
||||||
|
Rml::Matrix4f m_transform;
|
||||||
|
Rml::Vector2f m_translate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct texture_data_t {
|
||||||
|
VkImage m_p_vk_image;
|
||||||
|
VkImageView m_p_vk_image_view;
|
||||||
|
VkSampler m_p_vk_sampler;
|
||||||
|
VkDescriptorSet m_p_vk_descriptor_set;
|
||||||
|
VmaAllocation m_p_vma_allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct geometry_handle_t {
|
||||||
|
int m_num_indices;
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo m_p_vertex;
|
||||||
|
VkDescriptorBufferInfo m_p_index;
|
||||||
|
VkDescriptorBufferInfo m_p_shader;
|
||||||
|
|
||||||
|
// @ this is for freeing our logical blocks for VMA
|
||||||
|
// see https://gpuopen-librariesandsdks.github.io/VulkanMemoryAllocator/html/virtual_allocator.html
|
||||||
|
VmaVirtualAllocation m_p_vertex_allocation;
|
||||||
|
VmaVirtualAllocation m_p_index_allocation;
|
||||||
|
VmaVirtualAllocation m_p_shader_allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buffer_data_t {
|
||||||
|
VkBuffer m_p_vk_buffer;
|
||||||
|
VmaAllocation m_p_vma_allocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UploadResourceManager {
|
||||||
|
public:
|
||||||
|
UploadResourceManager() : m_p_device{}, m_p_fence{}, m_p_command_buffer{}, m_p_command_pool{}, m_p_graphics_queue{} {}
|
||||||
|
~UploadResourceManager() {}
|
||||||
|
|
||||||
|
void Initialize(VkDevice p_device, VkQueue p_queue, uint32_t queue_family_index)
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(p_queue, "you have to pass a valid VkQueue");
|
||||||
|
RMLUI_VK_ASSERTMSG(p_device, "you have to pass a valid VkDevice for creation resources");
|
||||||
|
|
||||||
|
m_p_device = p_device;
|
||||||
|
m_p_graphics_queue = p_queue;
|
||||||
|
|
||||||
|
Create_All(queue_family_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown()
|
||||||
|
{
|
||||||
|
vkDestroyFence(m_p_device, m_p_fence, nullptr);
|
||||||
|
vkDestroyCommandPool(m_p_device, m_p_command_pool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Func>
|
||||||
|
void UploadToGPU(Func&& p_user_commands) noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(m_p_command_buffer, "you didn't initialize VkCommandBuffer");
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo info_command = {};
|
||||||
|
|
||||||
|
info_command.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
info_command.pNext = nullptr;
|
||||||
|
info_command.pInheritanceInfo = nullptr;
|
||||||
|
info_command.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
|
||||||
|
VkResult status = vkBeginCommandBuffer(m_p_command_buffer, &info_command);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkBeginCommandBuffer");
|
||||||
|
|
||||||
|
p_user_commands(m_p_command_buffer);
|
||||||
|
|
||||||
|
status = vkEndCommandBuffer(m_p_command_buffer);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "faield to vkEndCommandBuffer");
|
||||||
|
|
||||||
|
Submit();
|
||||||
|
Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Create_Fence() noexcept
|
||||||
|
{
|
||||||
|
VkFenceCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
|
||||||
|
VkResult status = vkCreateFence(m_p_device, &info, nullptr, &m_p_fence);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkCreateFence");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Create_CommandBuffer() noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(m_p_command_pool, "you have to initialize VkCommandPool before calling this method!");
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.commandPool = m_p_command_pool;
|
||||||
|
info.commandBufferCount = 1;
|
||||||
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
|
||||||
|
VkResult status = vkAllocateCommandBuffers(m_p_device, &info, &m_p_command_buffer);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkAllocateCommandBuffers");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Create_CommandPool(uint32_t queue_family_index) noexcept
|
||||||
|
{
|
||||||
|
VkCommandPoolCreateInfo info = {};
|
||||||
|
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.queueFamilyIndex = queue_family_index;
|
||||||
|
info.flags = 0;
|
||||||
|
|
||||||
|
VkResult status = vkCreateCommandPool(m_p_device, &info, nullptr, &m_p_command_pool);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkCreateCommandPool");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Create_All(uint32_t queue_family_index) noexcept
|
||||||
|
{
|
||||||
|
Create_Fence();
|
||||||
|
Create_CommandPool(queue_family_index);
|
||||||
|
Create_CommandBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wait() noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(m_p_fence, "you must initialize your VkFence");
|
||||||
|
|
||||||
|
vkWaitForFences(m_p_device, 1, &m_p_fence, VK_TRUE, UINT64_MAX);
|
||||||
|
vkResetFences(m_p_device, 1, &m_p_fence);
|
||||||
|
vkResetCommandPool(m_p_device, m_p_command_pool, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Submit() noexcept
|
||||||
|
{
|
||||||
|
VkSubmitInfo info = {};
|
||||||
|
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.waitSemaphoreCount = 0;
|
||||||
|
info.signalSemaphoreCount = 0;
|
||||||
|
info.pSignalSemaphores = nullptr;
|
||||||
|
info.pWaitSemaphores = nullptr;
|
||||||
|
info.pWaitDstStageMask = nullptr;
|
||||||
|
info.pCommandBuffers = &m_p_command_buffer;
|
||||||
|
info.commandBufferCount = 1;
|
||||||
|
|
||||||
|
auto status = vkQueueSubmit(m_p_graphics_queue, 1, &info, m_p_fence);
|
||||||
|
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkQueueSubmit");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDevice m_p_device;
|
||||||
|
VkFence m_p_fence;
|
||||||
|
VkCommandBuffer m_p_command_buffer;
|
||||||
|
VkCommandPool m_p_command_pool;
|
||||||
|
VkQueue m_p_graphics_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ main manager for "allocating" vertex, index, uniform stuff
|
||||||
|
class MemoryPool {
|
||||||
|
public:
|
||||||
|
MemoryPool();
|
||||||
|
~MemoryPool();
|
||||||
|
|
||||||
|
void Initialize(VkDeviceSize byte_size, VkDeviceSize device_min_uniform_alignment, VmaAllocator p_allocator, VkDevice p_device) noexcept;
|
||||||
|
void Shutdown() noexcept;
|
||||||
|
|
||||||
|
bool Alloc_GeneralBuffer(VkDeviceSize size, void** p_data, VkDescriptorBufferInfo* p_out, VmaVirtualAllocation* p_alloc) noexcept;
|
||||||
|
bool Alloc_VertexBuffer(uint32_t number_of_elements, uint32_t stride_in_bytes, void** p_data, VkDescriptorBufferInfo* p_out,
|
||||||
|
VmaVirtualAllocation* p_alloc) noexcept;
|
||||||
|
bool Alloc_IndexBuffer(uint32_t number_of_elements, uint32_t stride_in_bytes, void** p_data, VkDescriptorBufferInfo* p_out,
|
||||||
|
VmaVirtualAllocation* p_alloc) noexcept;
|
||||||
|
|
||||||
|
void SetDescriptorSet(uint32_t binding_index, uint32_t size, VkDescriptorType descriptor_type, VkDescriptorSet p_set) noexcept;
|
||||||
|
void SetDescriptorSet(uint32_t binding_index, VkDescriptorBufferInfo* p_info, VkDescriptorType descriptor_type,
|
||||||
|
VkDescriptorSet p_set) noexcept;
|
||||||
|
void SetDescriptorSet(uint32_t binding_index, VkSampler p_sampler, VkImageLayout layout, VkImageView p_view, VkDescriptorType descriptor_type,
|
||||||
|
VkDescriptorSet p_set) noexcept;
|
||||||
|
|
||||||
|
void Free_GeometryHandle(geometry_handle_t* p_valid_geometry_handle) noexcept;
|
||||||
|
void Free_GeometryHandle_ShaderDataOnly(geometry_handle_t* p_valid_geometry_handle) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkDeviceSize m_memory_total_size;
|
||||||
|
VkDeviceSize m_device_min_uniform_alignment;
|
||||||
|
char* m_p_data;
|
||||||
|
VkBuffer m_p_buffer;
|
||||||
|
VmaAllocation m_p_buffer_alloc;
|
||||||
|
VkDevice m_p_device;
|
||||||
|
VmaAllocator m_p_vk_allocator;
|
||||||
|
VmaVirtualBlock m_p_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we need additional command buffers, we can add them to this list and retrieve them from the ring.
|
||||||
|
enum class CommandBufferName { Primary, Count };
|
||||||
|
|
||||||
|
// The command buffer ring stores a unique set of named command buffers for each bufferd frame.
|
||||||
|
// Explanation of how to use Vulkan efficiently: https://vkguide.dev/docs/chapter-4/double_buffering/
|
||||||
|
class CommandBufferRing {
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t kNumFramesToBuffer = kSwapchainBackBufferCount;
|
||||||
|
static constexpr uint32_t kNumCommandBuffersPerFrame = static_cast<uint32_t>(CommandBufferName::Count);
|
||||||
|
|
||||||
|
CommandBufferRing();
|
||||||
|
|
||||||
|
void Initialize(VkDevice p_device, uint32_t queue_index_graphics) noexcept;
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void OnBeginFrame();
|
||||||
|
VkCommandBuffer GetCommandBufferForActiveFrame(CommandBufferName named_command_buffer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CommandBuffersPerFrame {
|
||||||
|
Rml::Array<VkCommandPool, kNumCommandBuffersPerFrame> m_command_pools;
|
||||||
|
Rml::Array<VkCommandBuffer, kNumCommandBuffersPerFrame> m_command_buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDevice m_p_device;
|
||||||
|
uint32_t m_frame_index;
|
||||||
|
CommandBuffersPerFrame* m_p_current_frame;
|
||||||
|
Rml::Array<CommandBuffersPerFrame, kNumFramesToBuffer> m_frames;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DescriptorPoolManager {
|
||||||
|
public:
|
||||||
|
DescriptorPoolManager() : m_allocated_descriptor_count{}, m_p_descriptor_pool{} {}
|
||||||
|
~DescriptorPoolManager()
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(m_allocated_descriptor_count <= 0, "something is wrong. You didn't free some VkDescriptorSet");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(VkDevice p_device, uint32_t count_uniform_buffer, uint32_t count_image_sampler, uint32_t count_sampler,
|
||||||
|
uint32_t count_storage_buffer) noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(p_device, "you can't pass an invalid VkDevice here");
|
||||||
|
|
||||||
|
Rml::Array<VkDescriptorPoolSize, 5> sizes;
|
||||||
|
sizes[0] = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, count_uniform_buffer};
|
||||||
|
sizes[1] = {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, count_uniform_buffer};
|
||||||
|
sizes[2] = {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, count_image_sampler};
|
||||||
|
sizes[3] = {VK_DESCRIPTOR_TYPE_SAMPLER, count_sampler};
|
||||||
|
sizes[4] = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, count_storage_buffer};
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||||
|
info.maxSets = 1000;
|
||||||
|
info.poolSizeCount = static_cast<uint32_t>(sizes.size());
|
||||||
|
info.pPoolSizes = sizes.data();
|
||||||
|
|
||||||
|
auto status = vkCreateDescriptorPool(p_device, &info, nullptr, &m_p_descriptor_pool);
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkCreateDescriptorPool");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown(VkDevice p_device)
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(p_device, "you can't pass an invalid VkDevice here");
|
||||||
|
|
||||||
|
vkDestroyDescriptorPool(p_device, m_p_descriptor_pool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Get_AllocatedDescriptorCount() const noexcept { return m_allocated_descriptor_count; }
|
||||||
|
|
||||||
|
bool Alloc_Descriptor(VkDevice p_device, VkDescriptorSetLayout* p_layouts, VkDescriptorSet* p_sets,
|
||||||
|
uint32_t descriptor_count_for_creation = 1) noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(p_layouts, "you have to pass a valid and initialized VkDescriptorSetLayout (probably you must create it)");
|
||||||
|
RMLUI_VK_ASSERTMSG(p_device, "you must pass a valid VkDevice here");
|
||||||
|
|
||||||
|
VkDescriptorSetAllocateInfo info = {};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.descriptorPool = m_p_descriptor_pool;
|
||||||
|
info.descriptorSetCount = descriptor_count_for_creation;
|
||||||
|
info.pSetLayouts = p_layouts;
|
||||||
|
|
||||||
|
auto status = vkAllocateDescriptorSets(p_device, &info, p_sets);
|
||||||
|
RMLUI_VK_ASSERTMSG(status == VkResult::VK_SUCCESS, "failed to vkAllocateDescriptorSets");
|
||||||
|
|
||||||
|
m_allocated_descriptor_count += descriptor_count_for_creation;
|
||||||
|
|
||||||
|
return status == VkResult::VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Free_Descriptors(VkDevice p_device, VkDescriptorSet* p_sets, uint32_t descriptor_count = 1) noexcept
|
||||||
|
{
|
||||||
|
RMLUI_VK_ASSERTMSG(p_device, "you must pass a valid VkDevice here");
|
||||||
|
|
||||||
|
if (p_sets)
|
||||||
|
{
|
||||||
|
m_allocated_descriptor_count -= descriptor_count;
|
||||||
|
vkFreeDescriptorSets(p_device, m_p_descriptor_pool, descriptor_count, p_sets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_allocated_descriptor_count;
|
||||||
|
VkDescriptorPool m_p_descriptor_pool;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicalDeviceWrapper {
|
||||||
|
VkPhysicalDevice m_p_physical_device;
|
||||||
|
VkPhysicalDeviceProperties m_physical_device_properties;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PhysicalDeviceWrapperList = Rml::Vector<PhysicalDeviceWrapper>;
|
||||||
|
using LayerPropertiesList = Rml::Vector<VkLayerProperties>;
|
||||||
|
using ExtensionPropertiesList = Rml::Vector<VkExtensionProperties>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Rml::TextureHandle CreateTexture(Rml::Span<const Rml::byte> source, Rml::Vector2i dimensions, const Rml::String& name);
|
||||||
|
|
||||||
|
void Initialize_Instance(Rml::Vector<const char*> required_extensions) noexcept;
|
||||||
|
void Initialize_Device() noexcept;
|
||||||
|
void Initialize_PhysicalDevice(VkPhysicalDeviceProperties& out_physical_device_properties) noexcept;
|
||||||
|
void Initialize_Swapchain(VkExtent2D window_extent) noexcept;
|
||||||
|
void Initialize_Surface(CreateSurfaceCallback create_surface_callback) noexcept;
|
||||||
|
void Initialize_QueueIndecies() noexcept;
|
||||||
|
void Initialize_Queues() noexcept;
|
||||||
|
void Initialize_SyncPrimitives() noexcept;
|
||||||
|
void Initialize_Resources(const VkPhysicalDeviceProperties& physical_device_properties) noexcept;
|
||||||
|
void Initialize_Allocator() noexcept;
|
||||||
|
|
||||||
|
void Destroy_Instance() noexcept;
|
||||||
|
void Destroy_Device() noexcept;
|
||||||
|
void Destroy_Swapchain() noexcept;
|
||||||
|
void Destroy_Surface() noexcept;
|
||||||
|
void Destroy_SyncPrimitives() noexcept;
|
||||||
|
void Destroy_Resources() noexcept;
|
||||||
|
void Destroy_Allocator() noexcept;
|
||||||
|
|
||||||
|
void QueryInstanceLayers(LayerPropertiesList& result) noexcept;
|
||||||
|
void QueryInstanceExtensions(ExtensionPropertiesList& result, const LayerPropertiesList& instance_layer_properties) noexcept;
|
||||||
|
bool AddLayerToInstance(Rml::Vector<const char*>& result, const LayerPropertiesList& instance_layer_properties,
|
||||||
|
const char* p_instance_layer_name) noexcept;
|
||||||
|
bool AddExtensionToInstance(Rml::Vector<const char*>& result, const ExtensionPropertiesList& instance_extension_properties,
|
||||||
|
const char* p_instance_extension_name) noexcept;
|
||||||
|
void CreatePropertiesFor_Instance(Rml::Vector<const char*>& instance_layer_names, Rml::Vector<const char*>& instance_extension_names) noexcept;
|
||||||
|
|
||||||
|
bool IsLayerPresent(const LayerPropertiesList& properties, const char* p_layer_name) noexcept;
|
||||||
|
bool IsExtensionPresent(const ExtensionPropertiesList& properties, const char* p_extension_name) noexcept;
|
||||||
|
|
||||||
|
bool AddExtensionToDevice(Rml::Vector<const char*>& result, const ExtensionPropertiesList& device_extension_properties,
|
||||||
|
const char* p_device_extension_name) noexcept;
|
||||||
|
void CreatePropertiesFor_Device(ExtensionPropertiesList& result) noexcept;
|
||||||
|
|
||||||
|
void CreateReportDebugCallback() noexcept;
|
||||||
|
void Destroy_ReportDebugCallback() noexcept;
|
||||||
|
|
||||||
|
uint32_t GetUserAPIVersion() const noexcept;
|
||||||
|
uint32_t GetRequiredVersionAndValidateMachine() noexcept;
|
||||||
|
|
||||||
|
void CollectPhysicalDevices(PhysicalDeviceWrapperList& out_physical_devices) noexcept;
|
||||||
|
const PhysicalDeviceWrapper* ChoosePhysicalDevice(const PhysicalDeviceWrapperList& physical_devices, VkPhysicalDeviceType device_type) noexcept;
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR ChooseSwapchainFormat() noexcept;
|
||||||
|
VkSurfaceTransformFlagBitsKHR CreatePretransformSwapchain() noexcept;
|
||||||
|
VkCompositeAlphaFlagBitsKHR ChooseSwapchainCompositeAlpha() noexcept;
|
||||||
|
int Choose_SwapchainImageCount(uint32_t user_swapchain_count_for_creation = kSwapchainBackBufferCount, bool if_failed_choose_min = true) noexcept;
|
||||||
|
VkPresentModeKHR GetPresentMode(VkPresentModeKHR type = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR) noexcept;
|
||||||
|
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities() noexcept;
|
||||||
|
|
||||||
|
VkExtent2D GetValidSurfaceExtent() noexcept;
|
||||||
|
|
||||||
|
void CreateShaders() noexcept;
|
||||||
|
void CreateDescriptorSetLayout() noexcept;
|
||||||
|
void CreatePipelineLayout() noexcept;
|
||||||
|
void CreateDescriptorSets() noexcept;
|
||||||
|
void CreateSamplers() noexcept;
|
||||||
|
void Create_Pipelines() noexcept;
|
||||||
|
void CreateRenderPass() noexcept;
|
||||||
|
|
||||||
|
void CreateSwapchainFrameBuffers(const VkExtent2D& real_render_image_size) noexcept;
|
||||||
|
|
||||||
|
// This method is called in Views, so don't call it manually
|
||||||
|
void CreateSwapchainImages() noexcept;
|
||||||
|
void CreateSwapchainImageViews() noexcept;
|
||||||
|
|
||||||
|
void Create_DepthStencilImage() noexcept;
|
||||||
|
void Create_DepthStencilImageViews() noexcept;
|
||||||
|
|
||||||
|
void CreateResourcesDependentOnSize(const VkExtent2D& real_render_image_size) noexcept;
|
||||||
|
|
||||||
|
buffer_data_t CreateResource_StagingBuffer(VkDeviceSize size, VkBufferUsageFlags flags) noexcept;
|
||||||
|
void DestroyResource_StagingBuffer(const buffer_data_t& data) noexcept;
|
||||||
|
|
||||||
|
void Destroy_Textures() noexcept;
|
||||||
|
void Destroy_Geometries() noexcept;
|
||||||
|
|
||||||
|
void Destroy_Texture(const texture_data_t& p_texture) noexcept;
|
||||||
|
|
||||||
|
void DestroyResourcesDependentOnSize() noexcept;
|
||||||
|
void DestroySwapchainImageViews() noexcept;
|
||||||
|
void DestroySwapchainFrameBuffers() noexcept;
|
||||||
|
void DestroyRenderPass() noexcept;
|
||||||
|
void Destroy_Pipelines() noexcept;
|
||||||
|
void DestroyDescriptorSets() noexcept;
|
||||||
|
void DestroyPipelineLayout() noexcept;
|
||||||
|
void DestroySamplers() noexcept;
|
||||||
|
|
||||||
|
void Wait() noexcept;
|
||||||
|
|
||||||
|
void Update_PendingForDeletion_Textures_By_Frames() noexcept;
|
||||||
|
void Update_PendingForDeletion_Geometries() noexcept;
|
||||||
|
|
||||||
|
void Submit() noexcept;
|
||||||
|
void Present() noexcept;
|
||||||
|
|
||||||
|
VkFormat Get_SupportedDepthFormat();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_is_transform_enabled;
|
||||||
|
bool m_is_apply_to_regular_geometry_stencil;
|
||||||
|
bool m_is_use_scissor_specified;
|
||||||
|
bool m_is_use_stencil_pipeline;
|
||||||
|
|
||||||
|
int m_width;
|
||||||
|
int m_height;
|
||||||
|
|
||||||
|
uint32_t m_queue_index_present;
|
||||||
|
uint32_t m_queue_index_graphics;
|
||||||
|
uint32_t m_queue_index_compute;
|
||||||
|
uint32_t m_semaphore_index;
|
||||||
|
uint32_t m_semaphore_index_previous;
|
||||||
|
uint32_t m_image_index;
|
||||||
|
|
||||||
|
VkInstance m_p_instance;
|
||||||
|
VkDevice m_p_device;
|
||||||
|
VkPhysicalDevice m_p_physical_device;
|
||||||
|
VkSurfaceKHR m_p_surface;
|
||||||
|
VkSwapchainKHR m_p_swapchain;
|
||||||
|
VmaAllocator m_p_allocator;
|
||||||
|
// @ obtained from command list see PrepareRenderBuffer method
|
||||||
|
VkCommandBuffer m_p_current_command_buffer;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout m_p_descriptor_set_layout_vertex_transform;
|
||||||
|
VkDescriptorSetLayout m_p_descriptor_set_layout_texture;
|
||||||
|
VkPipelineLayout m_p_pipeline_layout;
|
||||||
|
VkPipeline m_p_pipeline_with_textures;
|
||||||
|
VkPipeline m_p_pipeline_without_textures;
|
||||||
|
VkPipeline m_p_pipeline_stencil_for_region_where_geometry_will_be_drawn;
|
||||||
|
VkPipeline m_p_pipeline_stencil_for_regular_geometry_that_applied_to_region_with_textures;
|
||||||
|
VkPipeline m_p_pipeline_stencil_for_regular_geometry_that_applied_to_region_without_textures;
|
||||||
|
VkDescriptorSet m_p_descriptor_set;
|
||||||
|
VkRenderPass m_p_render_pass;
|
||||||
|
VkSampler m_p_sampler_linear;
|
||||||
|
VkRect2D m_scissor;
|
||||||
|
|
||||||
|
// @ means it captures the window size full width and full height, offset equals both x and y to 0
|
||||||
|
VkRect2D m_scissor_original;
|
||||||
|
VkViewport m_viewport;
|
||||||
|
|
||||||
|
VkQueue m_p_queue_present;
|
||||||
|
VkQueue m_p_queue_graphics;
|
||||||
|
VkQueue m_p_queue_compute;
|
||||||
|
|
||||||
|
#ifdef RMLUI_VK_DEBUG
|
||||||
|
VkDebugUtilsMessengerEXT m_debug_messenger;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VkSurfaceFormatKHR m_swapchain_format;
|
||||||
|
shader_vertex_user_data_t m_user_data_for_vertex_shader;
|
||||||
|
texture_data_t m_texture_depthstencil;
|
||||||
|
|
||||||
|
Rml::Matrix4f m_projection;
|
||||||
|
Rml::Vector<VkFence> m_executed_fences;
|
||||||
|
Rml::Vector<VkSemaphore> m_semaphores_image_available;
|
||||||
|
Rml::Vector<VkSemaphore> m_semaphores_finished_render;
|
||||||
|
Rml::Vector<VkFramebuffer> m_swapchain_frame_buffers;
|
||||||
|
Rml::Vector<VkImage> m_swapchain_images;
|
||||||
|
Rml::Vector<VkImageView> m_swapchain_image_views;
|
||||||
|
Rml::Vector<VkShaderModule> m_shaders;
|
||||||
|
Rml::Array<Rml::Vector<texture_data_t*>, kSwapchainBackBufferCount> m_pending_for_deletion_textures_by_frames;
|
||||||
|
|
||||||
|
// vma handles that thing, so there's no need for frame splitting
|
||||||
|
Rml::Vector<geometry_handle_t*> m_pending_for_deletion_geometries;
|
||||||
|
|
||||||
|
CommandBufferRing m_command_buffer_ring;
|
||||||
|
MemoryPool m_memory_pool;
|
||||||
|
UploadResourceManager m_upload_manager;
|
||||||
|
DescriptorPoolManager m_manager_descriptors;
|
||||||
|
};
|
||||||
28
vendor/rmlui_backend/RmlUi_SDL_GPU/SDL_shadercross/LICENSE.txt
vendored
Normal file
28
vendor/rmlui_backend/RmlUi_SDL_GPU/SDL_shadercross/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
The SDL GPU backend for RmlUi uses the following third-party tool to generate
|
||||||
|
the included shader binaries:
|
||||||
|
|
||||||
|
SDL_shadercross
|
||||||
|
https://github.com/libsdl-org/SDL_shadercross
|
||||||
|
|
||||||
|
This tool is licensed separately from Rmlui. The license of this dependency
|
||||||
|
is recited below.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Copyright (C) 2024 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
817
vendor/rmlui_backend/RmlUi_SDL_GPU/ShadersCompiledSPV.h
vendored
Normal file
817
vendor/rmlui_backend/RmlUi_SDL_GPU/ShadersCompiledSPV.h
vendored
Normal file
@@ -0,0 +1,817 @@
|
|||||||
|
// RmlUi SDL GPU shaders compiled using command: 'python compile_shaders.py'. Do not edit manually.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_color_spirv[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x0F,0x00,0x07,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x03,0x00,0x05,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x05,0x00,0x07,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x69,0x6E,0x2E,0x76,0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x07,0x00,0x03,0x00,0x00,0x00,0x6F,0x75,0x74,0x2E,0x76,0x61,0x72,0x2E,0x53,0x56,0x5F,0x54,
|
||||||
|
0x61,0x72,0x67,0x65,0x74,0x30,0x00,0x00,0x05,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x02,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x03,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x03,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x05,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x13,0x00,0x02,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0xF8,0x00,0x02,0x00,0x0A,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x0B,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_color_msl[] = {
|
||||||
|
0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x6D,0x65,0x74,0x61,0x6C,0x5F,0x73,0x74,0x64,0x6C,
|
||||||
|
0x69,0x62,0x3E,0x0A,0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x73,0x69,0x6D,0x64,0x2F,0x73,
|
||||||
|
0x69,0x6D,0x64,0x2E,0x68,0x3E,0x0A,0x0A,0x75,0x73,0x69,0x6E,0x67,0x20,0x6E,0x61,0x6D,0x65,0x73,0x70,
|
||||||
|
0x61,0x63,0x65,0x20,0x6D,0x65,0x74,0x61,0x6C,0x3B,0x0A,0x0A,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6D,
|
||||||
|
0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,
|
||||||
|
0x34,0x20,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x53,0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x30,
|
||||||
|
0x20,0x5B,0x5B,0x63,0x6F,0x6C,0x6F,0x72,0x28,0x30,0x29,0x5D,0x5D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x73,
|
||||||
|
0x74,0x72,0x75,0x63,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x69,0x6E,0x0A,0x7B,0x0A,0x20,0x20,0x20,
|
||||||
|
0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x20,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,
|
||||||
|
0x4F,0x52,0x44,0x30,0x20,0x5B,0x5B,0x75,0x73,0x65,0x72,0x28,0x6C,0x6F,0x63,0x6E,0x30,0x29,0x5D,0x5D,
|
||||||
|
0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x66,0x72,0x61,0x67,0x6D,0x65,0x6E,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,
|
||||||
|
0x5F,0x6F,0x75,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x28,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x69,0x6E,0x20,
|
||||||
|
0x69,0x6E,0x20,0x5B,0x5B,0x73,0x74,0x61,0x67,0x65,0x5F,0x69,0x6E,0x5D,0x5D,0x29,0x0A,0x7B,0x0A,0x20,
|
||||||
|
0x20,0x20,0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x20,0x6F,0x75,0x74,0x20,0x3D,0x20,0x7B,
|
||||||
|
0x7D,0x3B,0x0A,0x20,0x20,0x20,0x20,0x6F,0x75,0x74,0x2E,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x53,
|
||||||
|
0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x30,0x20,0x3D,0x20,0x69,0x6E,0x2E,0x69,0x6E,0x5F,0x76,0x61,
|
||||||
|
0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x3B,0x0A,0x20,0x20,0x20,0x20,0x72,0x65,0x74,
|
||||||
|
0x75,0x72,0x6E,0x20,0x6F,0x75,0x74,0x3B,0x0A,0x7D,0x0A,0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_color_dxil[] = {
|
||||||
|
0x44,0x58,0x42,0x43,0x2E,0x2E,0xA9,0x96,0x45,0xE1,0xC0,0xAA,0xE2,0x19,0x19,0xF0,0x13,0x89,0x7B,0xCC,
|
||||||
|
0x01,0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,
|
||||||
|
0x88,0x00,0x00,0x00,0xC4,0x00,0x00,0x00,0x58,0x01,0x00,0x00,0x08,0x06,0x00,0x00,0x24,0x06,0x00,0x00,
|
||||||
|
0x53,0x46,0x49,0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x53,0x47,0x31,
|
||||||
|
0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x00,0x00,0x00,0x4F,0x53,0x47,0x31,
|
||||||
|
0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x53,0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x00,0x00,0x00,0x50,0x53,0x56,0x30,
|
||||||
|
0x8C,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x01,
|
||||||
|
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x6D,0x61,
|
||||||
|
0x69,0x6E,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x01,0x00,0x44,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x44,0x10,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x53,0x54,0x41,0x54,0xA8,0x04,0x00,0x00,0x60,0x00,0x00,0x00,0x2A,0x01,0x00,0x00,
|
||||||
|
0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x90,0x04,0x00,0x00,0x42,0x43,0xC0,0xDE,
|
||||||
|
0x21,0x0C,0x00,0x00,0x21,0x01,0x00,0x00,0x0B,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,
|
||||||
|
0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,
|
||||||
|
0x1E,0x04,0x8B,0x62,0x80,0x10,0x45,0x02,0x42,0x92,0x0B,0x42,0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,
|
||||||
|
0x0A,0x32,0x42,0x88,0x48,0x90,0x14,0x20,0x43,0x46,0x88,0xA5,0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,
|
||||||
|
0x11,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,0xE1,0x83,0xE5,0x8A,0x04,0x21,0x46,0x06,0x51,0x18,0x00,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,0xFF,0xFF,0xFF,0x07,0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,
|
||||||
|
0xFF,0xFF,0x03,0x20,0x01,0x00,0x00,0x00,0x49,0x18,0x00,0x00,0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,
|
||||||
|
0x20,0x00,0x00,0x00,0x89,0x20,0x00,0x00,0x0F,0x00,0x00,0x00,0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,
|
||||||
|
0x13,0x22,0xA4,0x84,0x04,0x13,0x22,0xE3,0x84,0xA1,0x90,0x14,0x12,0x4C,0x88,0x8C,0x0B,0x84,0x84,0x4C,
|
||||||
|
0x10,0x30,0x23,0x00,0x25,0x00,0x8A,0x19,0x80,0x39,0x02,0x30,0x98,0x23,0x40,0x8A,0x31,0x44,0x54,0x44,
|
||||||
|
0x56,0x0C,0x20,0xA2,0x1A,0xC2,0x81,0x80,0x34,0x20,0x00,0x00,0x13,0x14,0x72,0xC0,0x87,0x74,0x60,0x87,
|
||||||
|
0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,0x0E,0x6D,0xD0,0x0E,0x7A,0x50,0x0E,0x6D,
|
||||||
|
0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0xA0,0x07,0x73,0x20,0x07,
|
||||||
|
0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xD0,
|
||||||
|
0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x76,0x40,0x07,0x7A,0x60,0x07,0x74,
|
||||||
|
0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,0x60,0x0E,0x73,0x20,0x07,0x7A,0x30,0x07,
|
||||||
|
0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,0x6D,0xE0,0x0E,0x78,0xA0,0x07,0x71,0x60,
|
||||||
|
0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x79,0x10,0x20,
|
||||||
|
0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x02,0x01,0x0B,0x00,0x00,0x00,0x32,0x1E,0x98,0x14,
|
||||||
|
0x19,0x11,0x4C,0x90,0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0xA2,0x12,0x18,0x01,0x28,0x86,0x32,0x28,0x8F,
|
||||||
|
0x92,0x28,0x04,0xAA,0x92,0x18,0x01,0x28,0x82,0x42,0x28,0x10,0xDA,0xB1,0x0C,0x82,0x08,0x04,0x02,0x01,
|
||||||
|
0x79,0x18,0x00,0x00,0x57,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,0x46,0x02,0x13,0xC4,0x8E,0x0C,0x6F,0xEC,
|
||||||
|
0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,0x05,0x07,0x04,0x45,0x8C,0xE6,0x26,0x26,
|
||||||
|
0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x88,0x61,0x82,0x40,0x10,0x1B,0x84,0x81,0xD8,0x20,
|
||||||
|
0x10,0x04,0x05,0xB8,0xB9,0x09,0x02,0x51,0x6C,0x18,0x0E,0x84,0x98,0x20,0x08,0xC0,0x06,0x60,0xC3,0x40,
|
||||||
|
0x2C,0xCB,0x86,0x80,0xD9,0x30,0x0C,0x4A,0x33,0x41,0x58,0x9E,0x0D,0xC1,0x43,0xA2,0x2D,0x2C,0xCD,0x8D,
|
||||||
|
0x08,0x55,0x11,0xD6,0xD0,0xD3,0x93,0x14,0xD1,0x04,0xA1,0x50,0x26,0x08,0xC5,0xB2,0x21,0x20,0x26,0x08,
|
||||||
|
0x05,0x33,0x41,0x28,0x9A,0x09,0x02,0x61,0x4C,0x10,0x88,0x63,0x83,0x80,0x65,0x1B,0x16,0x42,0x9A,0xA8,
|
||||||
|
0xCA,0x1A,0x2E,0x82,0xD2,0x36,0x04,0x1B,0x93,0x29,0xAB,0x2F,0xAA,0x30,0xB9,0xB3,0x32,0xBA,0x09,0x42,
|
||||||
|
0xE1,0x6C,0x58,0x88,0x6E,0xF2,0x2A,0x6A,0xB8,0x08,0x4A,0xDB,0x10,0x7C,0x1B,0x06,0x0E,0x0C,0x80,0x0D,
|
||||||
|
0x85,0x12,0x85,0x01,0x00,0xB0,0x48,0x73,0x9B,0xA3,0x9B,0x9B,0x20,0x10,0x08,0x8D,0xB9,0xB4,0xB3,0x2F,
|
||||||
|
0x36,0xB2,0x09,0x02,0x91,0xD0,0x98,0x4B,0x3B,0xFB,0x9A,0xA3,0xDB,0x60,0x8C,0x01,0x19,0x94,0x81,0x19,
|
||||||
|
0x9C,0x81,0x19,0x54,0x61,0x63,0xB3,0x6B,0x73,0x49,0x23,0x2B,0x73,0xA3,0x9B,0x12,0x04,0x55,0xC8,0xF0,
|
||||||
|
0x5C,0xEC,0xCA,0xE4,0xE6,0xD2,0xDE,0xDC,0xA6,0x04,0x44,0x13,0x32,0x3C,0x17,0xBB,0x30,0x36,0xBB,0x32,
|
||||||
|
0xB9,0x29,0x41,0x51,0x87,0x0C,0xCF,0x65,0x0E,0x2D,0x8C,0xAC,0x4C,0xAE,0xE9,0x8D,0xAC,0x8C,0x6D,0x4A,
|
||||||
|
0x80,0x54,0x22,0xC3,0x73,0xA1,0xCB,0x83,0x2B,0x0B,0x72,0x73,0x7B,0xA3,0x0B,0xA3,0x4B,0x7B,0x73,0x9B,
|
||||||
|
0x9B,0x12,0x34,0x75,0xC8,0xF0,0x5C,0xEC,0xD2,0xCA,0xEE,0x92,0xC8,0xA6,0xE8,0xC2,0xE8,0xCA,0xA6,0x04,
|
||||||
|
0x4F,0x1D,0x32,0x3C,0x97,0x32,0x37,0x3A,0xB9,0x3C,0xA8,0xB7,0x34,0x37,0xBA,0xB9,0x29,0x41,0x18,0x74,
|
||||||
|
0x21,0xC3,0x73,0x19,0x7B,0xAB,0x73,0xA3,0x2B,0x93,0x9B,0x9B,0x12,0x9C,0x01,0x00,0x79,0x18,0x00,0x00,
|
||||||
|
0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,0x14,0x01,0x3D,0x88,0x43,0x38,0x84,0xC3,
|
||||||
|
0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,0x00,0x0F,0xED,0x10,0x0E,0xF4,0x80,0x0E,
|
||||||
|
0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,0x05,0x3D,0x88,0x43,0x38,0x84,0x83,0x1B,
|
||||||
|
0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,0x74,0x70,0x07,0x7B,0x08,0x07,0x79,0x48,
|
||||||
|
0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xCC,0x11,0x0E,0xEC,0x90,0x0E,
|
||||||
|
0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,0x33,0x10,0xC4,0x1D,0xDE,0x21,0x1C,0xD8,
|
||||||
|
0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,0xD0,0x43,0x39,0xB4,0x03,0x3C,0xBC,0x83,
|
||||||
|
0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,
|
||||||
|
0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xF8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,
|
||||||
|
0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2C,0xEE,0xF0,0x0E,0xEE,0xE0,0x0E,0xF5,
|
||||||
|
0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,0xCC,0xA1,0x1C,0xE4,0xA1,0x1C,0xDC,0x61,
|
||||||
|
0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,0x43,0x39,0xC8,0x43,0x39,0x98,0x43,0x39,
|
||||||
|
0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,0x94,0xC3,0x2F,0xBC,0x83,0x3C,0xFC,0x82,
|
||||||
|
0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,0x03,0x72,0x10,0x87,0x73,0x70,0x03,0x7B,
|
||||||
|
0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,0x98,0x81,0x3C,0xE4,0x80,0x0F,0x6E,0x40,
|
||||||
|
0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x0B,0x00,0x00,0x00,0x16,0x30,0x0D,0x97,
|
||||||
|
0xEF,0x3C,0xFE,0xE2,0x00,0x83,0xD8,0x3C,0xD4,0xE4,0x17,0xB7,0x6D,0x02,0xD5,0x70,0xF9,0xCE,0xE3,0x4B,
|
||||||
|
0x93,0x13,0x11,0x28,0x35,0x3D,0xD4,0xE4,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x48,0x41,0x53,0x48,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65,0xE3,0x7F,0x22,
|
||||||
|
0xB6,0x5B,0x10,0xF4,0xA4,0x0F,0xBE,0x64,0x48,0x54,0x5A,0xC1,0x44,0x58,0x49,0x4C,0xD4,0x04,0x00,0x00,
|
||||||
|
0x60,0x00,0x00,0x00,0x35,0x01,0x00,0x00,0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0xBC,0x04,0x00,0x00,0x42,0x43,0xC0,0xDE,0x21,0x0C,0x00,0x00,0x2C,0x01,0x00,0x00,0x0B,0x82,0x20,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,0x06,0x10,0x32,0x39,
|
||||||
|
0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,0x1E,0x04,0x8B,0x62,0x80,0x10,0x45,0x02,0x42,0x92,0x0B,0x42,
|
||||||
|
0x84,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,0x0A,0x32,0x42,0x88,0x48,0x90,0x14,0x20,0x43,0x46,0x88,0xA5,
|
||||||
|
0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,0x11,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,0xE1,0x83,0xE5,0x8A,
|
||||||
|
0x04,0x21,0x46,0x06,0x51,0x18,0x00,0x00,0x06,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,0xFF,0xFF,0xFF,0x07,
|
||||||
|
0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,0xFF,0xFF,0x03,0x20,0x01,0x00,0x00,0x00,0x49,0x18,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x00,0x00,0x00,0x89,0x20,0x00,0x00,0x0F,0x00,0x00,0x00,
|
||||||
|
0x32,0x22,0x08,0x09,0x20,0x64,0x85,0x04,0x13,0x22,0xA4,0x84,0x04,0x13,0x22,0xE3,0x84,0xA1,0x90,0x14,
|
||||||
|
0x12,0x4C,0x88,0x8C,0x0B,0x84,0x84,0x4C,0x10,0x30,0x23,0x00,0x25,0x00,0x8A,0x19,0x80,0x39,0x02,0x30,
|
||||||
|
0x98,0x23,0x40,0x8A,0x31,0x44,0x54,0x44,0x56,0x0C,0x20,0xA2,0x1A,0xC2,0x81,0x80,0x34,0x20,0x00,0x00,
|
||||||
|
0x13,0x14,0x72,0xC0,0x87,0x74,0x60,0x87,0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,
|
||||||
|
0x0E,0x6D,0xD0,0x0E,0x7A,0x50,0x0E,0x6D,0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x90,0x0E,0x71,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,
|
||||||
|
0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,
|
||||||
|
0x0E,0x76,0x40,0x07,0x7A,0x60,0x07,0x74,0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x60,0x0E,0x73,0x20,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,
|
||||||
|
0x6D,0xE0,0x0E,0x78,0xA0,0x07,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x0C,0x79,0x10,0x20,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC8,0x02,0x01,
|
||||||
|
0x0B,0x00,0x00,0x00,0x32,0x1E,0x98,0x10,0x19,0x11,0x4C,0x90,0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0xA2,
|
||||||
|
0x12,0x18,0x01,0x28,0x88,0x62,0x28,0x83,0xF2,0xA0,0x2A,0x89,0x11,0x80,0x22,0x28,0x84,0x02,0xA1,0x1D,
|
||||||
|
0xCB,0x20,0x88,0x40,0x20,0x10,0x00,0x00,0x79,0x18,0x00,0x00,0x42,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,
|
||||||
|
0x46,0x02,0x13,0xC4,0x8E,0x0C,0x6F,0xEC,0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,
|
||||||
|
0x05,0x07,0x04,0x45,0x8C,0xE6,0x26,0x26,0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x88,0x61,
|
||||||
|
0x82,0x40,0x10,0x1B,0x84,0x81,0x98,0x20,0x10,0xC5,0x06,0x61,0x30,0x28,0xC0,0xCD,0x4D,0x10,0x08,0x63,
|
||||||
|
0xC3,0x80,0x24,0xC4,0x04,0x61,0x71,0x36,0x04,0xCB,0x04,0x41,0x00,0x48,0xB4,0x85,0xA5,0xB9,0x11,0xA1,
|
||||||
|
0x2A,0xC2,0x1A,0x7A,0x7A,0x92,0x22,0x9A,0x20,0x14,0xC9,0x04,0xA1,0x50,0x36,0x04,0xC4,0x04,0xA1,0x58,
|
||||||
|
0x26,0x08,0x05,0x33,0x41,0x20,0x8E,0x09,0x02,0x81,0x6C,0x10,0x2A,0x6B,0xC3,0x42,0x3C,0x50,0x24,0x4D,
|
||||||
|
0x03,0x45,0x44,0xD7,0x86,0x00,0x63,0x32,0x65,0xF5,0x45,0x15,0x26,0x77,0x56,0x46,0x37,0x41,0x28,0x9A,
|
||||||
|
0x0D,0x0B,0xA1,0x41,0x9B,0x14,0x0D,0x14,0x11,0x5D,0x1B,0x02,0x6E,0xC3,0x90,0x75,0xC0,0x86,0xA2,0x71,
|
||||||
|
0x3C,0x00,0xA8,0xC2,0xC6,0x66,0xD7,0xE6,0x92,0x46,0x56,0xE6,0x46,0x37,0x25,0x08,0xAA,0x90,0xE1,0xB9,
|
||||||
|
0xD8,0x95,0xC9,0xCD,0xA5,0xBD,0xB9,0x4D,0x09,0x88,0x26,0x64,0x78,0x2E,0x76,0x61,0x6C,0x76,0x65,0x72,
|
||||||
|
0x53,0x02,0xA3,0x0E,0x19,0x9E,0xCB,0x1C,0x5A,0x18,0x59,0x99,0x5C,0xD3,0x1B,0x59,0x19,0xDB,0x94,0x20,
|
||||||
|
0xA9,0x43,0x86,0xE7,0x62,0x97,0x56,0x76,0x97,0x44,0x36,0x45,0x17,0x46,0x57,0x36,0x25,0x58,0xEA,0x90,
|
||||||
|
0xE1,0xB9,0x94,0xB9,0xD1,0xC9,0xE5,0x41,0xBD,0xA5,0xB9,0xD1,0xCD,0x4D,0x09,0x3C,0x00,0x00,0x00,0x00,
|
||||||
|
0x79,0x18,0x00,0x00,0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,0x14,0x01,0x3D,0x88,
|
||||||
|
0x43,0x38,0x84,0xC3,0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,0x00,0x0F,0xED,0x10,
|
||||||
|
0x0E,0xF4,0x80,0x0E,0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,0x05,0x3D,0x88,0x43,
|
||||||
|
0x38,0x84,0x83,0x1B,0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,0x74,0x70,0x07,0x7B,
|
||||||
|
0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xCC,0x11,
|
||||||
|
0x0E,0xEC,0x90,0x0E,0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,0x33,0x10,0xC4,0x1D,
|
||||||
|
0xDE,0x21,0x1C,0xD8,0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,0xD0,0x43,0x39,0xB4,
|
||||||
|
0x03,0x3C,0xBC,0x83,0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,0x07,0x37,0x68,0x87,
|
||||||
|
0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xF8,0x05,0x76,0x78,
|
||||||
|
0x87,0x77,0x80,0x87,0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2C,0xEE,0xF0,0x0E,
|
||||||
|
0xEE,0xE0,0x0E,0xF5,0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,0xCC,0xA1,0x1C,0xE4,
|
||||||
|
0xA1,0x1C,0xDC,0x61,0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,0x43,0x39,0xC8,0x43,
|
||||||
|
0x39,0x98,0x43,0x39,0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,0x94,0xC3,0x2F,0xBC,
|
||||||
|
0x83,0x3C,0xFC,0x82,0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,0x03,0x72,0x10,0x87,
|
||||||
|
0x73,0x70,0x03,0x7B,0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,0x98,0x81,0x3C,0xE4,
|
||||||
|
0x80,0x0F,0x6E,0x40,0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x0B,0x00,0x00,0x00,
|
||||||
|
0x16,0x30,0x0D,0x97,0xEF,0x3C,0xFE,0xE2,0x00,0x83,0xD8,0x3C,0xD4,0xE4,0x17,0xB7,0x6D,0x02,0xD5,0x70,
|
||||||
|
0xF9,0xCE,0xE3,0x4B,0x93,0x13,0x11,0x28,0x35,0x3D,0xD4,0xE4,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,
|
||||||
|
0x00,0x00,0x00,0x00,0x61,0x20,0x00,0x00,0x1E,0x00,0x00,0x00,0x13,0x04,0x41,0x2C,0x10,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x44,0x85,0x30,0x03,0x50,0x0A,0x54,0x25,0x50,0x06,0x00,0x00,0x23,0x06,0x09,0x00,
|
||||||
|
0x82,0x60,0x60,0x4C,0x05,0x04,0x29,0xC4,0x88,0x41,0x02,0x80,0x20,0x18,0x18,0x94,0x11,0x45,0x43,0x31,
|
||||||
|
0x62,0x90,0x00,0x20,0x08,0x06,0x46,0x75,0x48,0xD2,0x62,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x61,0x21,
|
||||||
|
0xD3,0x44,0x1C,0x23,0x06,0x09,0x00,0x82,0x60,0x80,0x58,0x07,0x45,0x39,0xC4,0x88,0x41,0x02,0x80,0x20,
|
||||||
|
0x18,0x20,0xD6,0x41,0x51,0xC6,0x30,0x62,0x90,0x00,0x20,0x08,0x06,0x88,0x75,0x50,0x54,0x23,0x8C,0x18,
|
||||||
|
0x24,0x00,0x08,0x82,0x01,0x62,0x1D,0x14,0x55,0x04,0x08,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_texture_spirv[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x0F,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x05,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x05,0x00,0x06,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x74,0x79,0x70,0x65,0x2E,0x32,0x64,0x2E,0x69,0x6D,0x61,0x67,0x65,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x54,0x65,0x78,0x74,0x75,0x72,0x65,0x00,0x05,0x00,0x06,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x74,0x79,0x70,0x65,0x2E,0x73,0x61,0x6D,0x70,0x6C,0x65,0x72,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x53,0x61,0x6D,0x70,0x6C,0x65,0x72,0x00,0x05,0x00,0x07,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x69,0x6E,0x2E,0x76,0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,
|
||||||
|
0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,0x03,0x00,0x00,0x00,0x69,0x6E,0x2E,0x76,0x61,0x72,0x2E,0x54,
|
||||||
|
0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x6F,0x75,0x74,0x2E,0x76,0x61,0x72,0x2E,0x53,0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x30,0x00,0x00,
|
||||||
|
0x05,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,
|
||||||
|
0x09,0x00,0x00,0x00,0x74,0x79,0x70,0x65,0x2E,0x73,0x61,0x6D,0x70,0x6C,0x65,0x64,0x2E,0x69,0x6D,0x61,
|
||||||
|
0x67,0x65,0x00,0x00,0x47,0x00,0x04,0x00,0x02,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x03,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x21,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x03,0x00,
|
||||||
|
0x0A,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
|
||||||
|
0x1A,0x00,0x02,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x17,0x00,0x04,0x00,
|
||||||
|
0x0F,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x0D,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x12,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x13,0x00,0x00,0x00,
|
||||||
|
0x12,0x00,0x00,0x00,0x1B,0x00,0x03,0x00,0x09,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x0B,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0C,0x00,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x3B,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x36,0x00,0x05,0x00,
|
||||||
|
0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0xF8,0x00,0x02,0x00,
|
||||||
|
0x14,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x0F,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x56,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x19,0x00,0x00,0x00,
|
||||||
|
0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x57,0x00,0x06,0x00,0x0D,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,
|
||||||
|
0x19,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0x00,0x05,0x00,0x0D,0x00,0x00,0x00,
|
||||||
|
0x1B,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x1B,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_texture_msl[] = {
|
||||||
|
0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x6D,0x65,0x74,0x61,0x6C,0x5F,0x73,0x74,0x64,0x6C,
|
||||||
|
0x69,0x62,0x3E,0x0A,0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x73,0x69,0x6D,0x64,0x2F,0x73,
|
||||||
|
0x69,0x6D,0x64,0x2E,0x68,0x3E,0x0A,0x0A,0x75,0x73,0x69,0x6E,0x67,0x20,0x6E,0x61,0x6D,0x65,0x73,0x70,
|
||||||
|
0x61,0x63,0x65,0x20,0x6D,0x65,0x74,0x61,0x6C,0x3B,0x0A,0x0A,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6D,
|
||||||
|
0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,
|
||||||
|
0x34,0x20,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x53,0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x30,
|
||||||
|
0x20,0x5B,0x5B,0x63,0x6F,0x6C,0x6F,0x72,0x28,0x30,0x29,0x5D,0x5D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x73,
|
||||||
|
0x74,0x72,0x75,0x63,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x69,0x6E,0x0A,0x7B,0x0A,0x20,0x20,0x20,
|
||||||
|
0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x20,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,
|
||||||
|
0x4F,0x52,0x44,0x30,0x20,0x5B,0x5B,0x75,0x73,0x65,0x72,0x28,0x6C,0x6F,0x63,0x6E,0x30,0x29,0x5D,0x5D,
|
||||||
|
0x3B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x32,0x20,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,
|
||||||
|
0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x20,0x5B,0x5B,0x75,0x73,0x65,0x72,0x28,0x6C,0x6F,0x63,
|
||||||
|
0x6E,0x31,0x29,0x5D,0x5D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x66,0x72,0x61,0x67,0x6D,0x65,0x6E,0x74,0x20,
|
||||||
|
0x6D,0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x28,0x6D,0x61,0x69,0x6E,
|
||||||
|
0x30,0x5F,0x69,0x6E,0x20,0x69,0x6E,0x20,0x5B,0x5B,0x73,0x74,0x61,0x67,0x65,0x5F,0x69,0x6E,0x5D,0x5D,
|
||||||
|
0x2C,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3C,0x66,0x6C,0x6F,0x61,0x74,0x3E,0x20,0x54,
|
||||||
|
0x65,0x78,0x74,0x75,0x72,0x65,0x20,0x5B,0x5B,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5D,
|
||||||
|
0x5D,0x2C,0x20,0x73,0x61,0x6D,0x70,0x6C,0x65,0x72,0x20,0x53,0x61,0x6D,0x70,0x6C,0x65,0x72,0x20,0x5B,
|
||||||
|
0x5B,0x73,0x61,0x6D,0x70,0x6C,0x65,0x72,0x28,0x30,0x29,0x5D,0x5D,0x29,0x0A,0x7B,0x0A,0x20,0x20,0x20,
|
||||||
|
0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x20,0x6F,0x75,0x74,0x20,0x3D,0x20,0x7B,0x7D,0x3B,
|
||||||
|
0x0A,0x20,0x20,0x20,0x20,0x6F,0x75,0x74,0x2E,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x53,0x56,0x5F,
|
||||||
|
0x54,0x61,0x72,0x67,0x65,0x74,0x30,0x20,0x3D,0x20,0x69,0x6E,0x2E,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,
|
||||||
|
0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x20,0x2A,0x20,0x54,0x65,0x78,0x74,0x75,0x72,0x65,0x2E,
|
||||||
|
0x73,0x61,0x6D,0x70,0x6C,0x65,0x28,0x53,0x61,0x6D,0x70,0x6C,0x65,0x72,0x2C,0x20,0x69,0x6E,0x2E,0x69,
|
||||||
|
0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x29,0x3B,0x0A,0x20,0x20,
|
||||||
|
0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6E,0x20,0x6F,0x75,0x74,0x3B,0x0A,0x7D,0x0A,0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_texture_dxil[] = {
|
||||||
|
0x44,0x58,0x42,0x43,0xD6,0xEC,0x87,0x84,0xAB,0xDB,0x76,0x44,0x3D,0x9B,0x09,0x21,0x5C,0x7F,0x90,0x2E,
|
||||||
|
0x01,0x00,0x00,0x00,0x14,0x0F,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,
|
||||||
|
0xA8,0x00,0x00,0x00,0xE4,0x00,0x00,0x00,0xD8,0x01,0x00,0x00,0x30,0x08,0x00,0x00,0x4C,0x08,0x00,0x00,
|
||||||
|
0x53,0x46,0x49,0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x53,0x47,0x31,
|
||||||
|
0x54,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,
|
||||||
|
0x4F,0x4F,0x52,0x44,0x00,0x00,0x00,0x00,0x4F,0x53,0x47,0x31,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x56,0x5F,0x54,
|
||||||
|
0x61,0x72,0x67,0x65,0x74,0x00,0x00,0x00,0x50,0x53,0x56,0x30,0xEC,0x00,0x00,0x00,0x34,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x18,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,
|
||||||
|
0x44,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x6D,0x61,0x69,0x6E,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x44,0x00,0x03,0x02,0x00,0x00,0x0A,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x42,0x00,
|
||||||
|
0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x44,0x10,0x03,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,
|
||||||
|
0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x54,0x41,0x54,0x50,0x06,0x00,0x00,
|
||||||
|
0x60,0x00,0x00,0x00,0x94,0x01,0x00,0x00,0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0x38,0x06,0x00,0x00,0x42,0x43,0xC0,0xDE,0x21,0x0C,0x00,0x00,0x8B,0x01,0x00,0x00,0x0B,0x82,0x20,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,0x06,0x10,0x32,0x39,
|
||||||
|
0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,0x1E,0x04,0x8B,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0B,0x42,
|
||||||
|
0xA4,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,0x0A,0x32,0x52,0x88,0x48,0x90,0x14,0x20,0x43,0x46,0x88,0xA5,
|
||||||
|
0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,0x91,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,0xE1,0x83,0xE5,0x8A,
|
||||||
|
0x04,0x29,0x46,0x06,0x51,0x18,0x00,0x00,0x08,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,0xFF,0xFF,0xFF,0x07,
|
||||||
|
0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,0xFF,0xFF,0x03,0x20,0x6D,0x30,0x86,0xFF,0xFF,0xFF,0xFF,0x1F,
|
||||||
|
0x00,0x09,0xA8,0x00,0x49,0x18,0x00,0x00,0x03,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x4C,0x08,0x06,
|
||||||
|
0x00,0x00,0x00,0x00,0x89,0x20,0x00,0x00,0x43,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,
|
||||||
|
0x93,0x22,0xA4,0x84,0x04,0x93,0x22,0xE3,0x84,0xA1,0x90,0x14,0x12,0x4C,0x8A,0x8C,0x0B,0x84,0xA4,0x4C,
|
||||||
|
0x10,0x68,0x23,0x00,0x25,0x00,0x14,0x66,0x00,0xE6,0x08,0xC0,0x60,0x8E,0x00,0x29,0xC6,0x20,0x84,0x14,
|
||||||
|
0x42,0xA6,0x18,0x80,0x10,0x52,0x06,0xA1,0x9B,0x86,0xCB,0x9F,0xB0,0x87,0x90,0xFC,0x95,0x90,0x56,0x62,
|
||||||
|
0xF2,0x8B,0xDB,0x46,0xC5,0x18,0x63,0x10,0x2A,0xF7,0x0C,0x97,0x3F,0x61,0x0F,0x21,0xF9,0x21,0xD0,0x0C,
|
||||||
|
0x0B,0x81,0x82,0x55,0x18,0x45,0x18,0x1B,0x63,0x0C,0x42,0xC8,0xA0,0x36,0x47,0x10,0x14,0x83,0x91,0x42,
|
||||||
|
0xC8,0x23,0x38,0x10,0x30,0x8C,0x40,0x0C,0x33,0xB5,0xC1,0x38,0xB0,0x43,0x38,0xCC,0xC3,0x3C,0xB8,0x01,
|
||||||
|
0x2D,0x94,0x03,0x3E,0xD0,0x43,0x3D,0xC8,0x43,0x39,0xC8,0x01,0x29,0xF0,0x81,0x3D,0x94,0xC3,0x38,0xD0,
|
||||||
|
0xC3,0x3B,0xC8,0x03,0x1F,0x98,0x03,0x3B,0xBC,0x43,0x38,0xD0,0x03,0x1B,0x80,0x01,0x1D,0xF8,0x01,0x18,
|
||||||
|
0xF8,0x81,0x1E,0xE8,0x41,0x3B,0xA4,0x03,0x3C,0xCC,0xC3,0x2F,0xD0,0x43,0x3E,0xC0,0x43,0x39,0xA0,0x80,
|
||||||
|
0xCC,0x24,0x06,0xE3,0xC0,0x0E,0xE1,0x30,0x0F,0xF3,0xE0,0x06,0xB4,0x50,0x0E,0xF8,0x40,0x0F,0xF5,0x20,
|
||||||
|
0x0F,0xE5,0x20,0x07,0xA4,0xC0,0x07,0xF6,0x50,0x0E,0xE3,0x40,0x0F,0xEF,0x20,0x0F,0x7C,0x60,0x0E,0xEC,
|
||||||
|
0xF0,0x0E,0xE1,0x40,0x0F,0x6C,0x00,0x06,0x74,0xE0,0x07,0x60,0xE0,0x07,0x48,0x98,0x94,0xEA,0x4D,0xD2,
|
||||||
|
0x14,0x51,0xC2,0xE4,0xB3,0x00,0xF3,0x2C,0x44,0xC4,0x4E,0xC0,0x44,0xA0,0x80,0xD0,0x4D,0x04,0x02,0x00,
|
||||||
|
0x13,0x14,0x72,0xC0,0x87,0x74,0x60,0x87,0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,
|
||||||
|
0x0E,0x6D,0xD0,0x0E,0x7A,0x50,0x0E,0x6D,0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x90,0x0E,0x71,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,
|
||||||
|
0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,
|
||||||
|
0x0E,0x76,0x40,0x07,0x7A,0x60,0x07,0x74,0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x60,0x0E,0x73,0x20,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,
|
||||||
|
0x6D,0xE0,0x0E,0x78,0xA0,0x07,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,
|
||||||
|
0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x0C,0x79,0x10,0x20,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xF2,0x34,
|
||||||
|
0x40,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xE4,0x81,0x80,0x00,0x18,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x20,0x0B,0x04,0x00,0x00,0x0E,0x00,0x00,0x00,0x32,0x1E,0x98,0x14,0x19,0x11,0x4C,0x90,
|
||||||
|
0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0x22,0x25,0x30,0x02,0x50,0x0C,0x45,0x50,0x12,0x65,0x50,0x1E,0x85,
|
||||||
|
0x50,0x2C,0x54,0x4A,0x62,0x04,0xA0,0x08,0x0A,0xA1,0x40,0xC8,0xCE,0x00,0x10,0x9E,0x01,0xA0,0x3C,0x16,
|
||||||
|
0x62,0x10,0x81,0x40,0x20,0xCF,0x03,0x00,0x79,0x18,0x00,0x00,0x79,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,
|
||||||
|
0x46,0x02,0x13,0xC4,0x8E,0x0C,0x6F,0xEC,0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,
|
||||||
|
0x05,0x07,0x04,0x45,0x8C,0xE6,0x26,0x26,0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x88,0x62,
|
||||||
|
0x82,0x40,0x18,0x1B,0x84,0x81,0xD8,0x20,0x10,0x04,0x05,0xB8,0xB9,0x09,0x02,0x71,0x6C,0x18,0x0E,0x84,
|
||||||
|
0x98,0x20,0x58,0x13,0x0F,0xAA,0x32,0x3C,0xBA,0x3A,0xB9,0xB2,0x09,0x02,0x81,0x4C,0x10,0x88,0x64,0x83,
|
||||||
|
0x40,0x34,0x1B,0x12,0x42,0x59,0x18,0x62,0x60,0x08,0x67,0x43,0xF0,0x4C,0x10,0x30,0x8A,0xC7,0x54,0x58,
|
||||||
|
0x1B,0x1C,0x5B,0x99,0xDC,0x06,0x84,0x88,0x24,0x86,0x18,0x08,0x60,0x43,0x30,0x6D,0x20,0x20,0x00,0xA0,
|
||||||
|
0x26,0x08,0x02,0xB0,0x01,0xD8,0x30,0x10,0xD7,0xB5,0x21,0xC0,0x36,0x0C,0x83,0x95,0x4D,0x10,0xB2,0x6A,
|
||||||
|
0x43,0xB0,0x91,0x68,0x0B,0x4B,0x73,0x23,0x42,0x55,0x84,0x35,0xF4,0xF4,0x24,0x45,0x34,0x41,0x28,0x9C,
|
||||||
|
0x09,0x42,0xF1,0x6C,0x08,0x88,0x09,0x42,0x01,0x4D,0x10,0x8A,0x68,0x82,0x40,0x28,0x13,0x04,0x62,0xD9,
|
||||||
|
0x20,0x90,0x41,0x19,0x6C,0x58,0x08,0xEF,0x03,0x83,0x30,0x10,0x83,0x61,0x0C,0x08,0x30,0x30,0x83,0x0D,
|
||||||
|
0xC1,0xB0,0x41,0x20,0x03,0x32,0xD8,0xB0,0x0C,0xDE,0x07,0x06,0x68,0x20,0x06,0x83,0x18,0x0C,0x60,0x90,
|
||||||
|
0x06,0x1B,0x84,0x33,0x50,0x03,0x26,0x53,0x56,0x5F,0x54,0x61,0x72,0x67,0x65,0x74,0x13,0x84,0x42,0xDA,
|
||||||
|
0xB0,0x10,0x6C,0xF0,0xB5,0x41,0x18,0x80,0xC1,0x30,0x06,0x04,0x18,0x98,0xC1,0x86,0xC0,0x0D,0x36,0x0C,
|
||||||
|
0x6B,0xF0,0x06,0xC0,0x86,0xC2,0xEA,0xE0,0xA0,0x02,0x68,0x98,0xB1,0xBD,0x85,0xD1,0xCD,0x4D,0x10,0x08,
|
||||||
|
0x86,0x45,0x9A,0xDB,0x1C,0xDD,0xDC,0x04,0x81,0x68,0x68,0xCC,0xA5,0x9D,0x7D,0xB1,0x91,0xD1,0x98,0x4B,
|
||||||
|
0x3B,0xFB,0x9A,0xA3,0x23,0x42,0x57,0x86,0xF7,0xE5,0xF6,0x26,0xD7,0xB6,0x41,0x91,0x83,0x39,0xA0,0x83,
|
||||||
|
0x3A,0xB0,0x03,0xE4,0x0E,0xE6,0x00,0x0F,0x86,0x2A,0x6C,0x6C,0x76,0x6D,0x2E,0x69,0x64,0x65,0x6E,0x74,
|
||||||
|
0x53,0x82,0xA0,0x0A,0x19,0x9E,0x8B,0x5D,0x99,0xDC,0x5C,0xDA,0x9B,0xDB,0x94,0x80,0x68,0x42,0x86,0xE7,
|
||||||
|
0x62,0x17,0xC6,0x66,0x57,0x26,0x37,0x25,0x28,0xEA,0x90,0xE1,0xB9,0xCC,0xA1,0x85,0x91,0x95,0xC9,0x35,
|
||||||
|
0xBD,0x91,0x95,0xB1,0x4D,0x09,0x90,0x32,0x64,0x78,0x2E,0x72,0x65,0x73,0x6F,0x75,0x72,0x63,0x65,0x73,
|
||||||
|
0x53,0x02,0xAA,0x12,0x19,0x9E,0x0B,0x5D,0x1E,0x5C,0x59,0x90,0x9B,0xDB,0x1B,0x5D,0x18,0x5D,0xDA,0x9B,
|
||||||
|
0xDB,0xDC,0x94,0x20,0xAB,0x43,0x86,0xE7,0x62,0x97,0x56,0x76,0x97,0x44,0x36,0x45,0x17,0x46,0x57,0x36,
|
||||||
|
0x25,0xD8,0xEA,0x90,0xE1,0xB9,0x94,0xB9,0xD1,0xC9,0xE5,0x41,0xBD,0xA5,0xB9,0xD1,0xCD,0x4D,0x09,0xE0,
|
||||||
|
0xA0,0x0B,0x19,0x9E,0xCB,0xD8,0x5B,0x9D,0x1B,0x5D,0x99,0xDC,0xDC,0x94,0x00,0x0F,0x00,0x00,0x00,0x00,
|
||||||
|
0x79,0x18,0x00,0x00,0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,0x14,0x01,0x3D,0x88,
|
||||||
|
0x43,0x38,0x84,0xC3,0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,0x00,0x0F,0xED,0x10,
|
||||||
|
0x0E,0xF4,0x80,0x0E,0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,0x05,0x3D,0x88,0x43,
|
||||||
|
0x38,0x84,0x83,0x1B,0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,0x74,0x70,0x07,0x7B,
|
||||||
|
0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xCC,0x11,
|
||||||
|
0x0E,0xEC,0x90,0x0E,0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,0x33,0x10,0xC4,0x1D,
|
||||||
|
0xDE,0x21,0x1C,0xD8,0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,0xD0,0x43,0x39,0xB4,
|
||||||
|
0x03,0x3C,0xBC,0x83,0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,0x07,0x37,0x68,0x87,
|
||||||
|
0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xF8,0x05,0x76,0x78,
|
||||||
|
0x87,0x77,0x80,0x87,0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2C,0xEE,0xF0,0x0E,
|
||||||
|
0xEE,0xE0,0x0E,0xF5,0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,0xCC,0xA1,0x1C,0xE4,
|
||||||
|
0xA1,0x1C,0xDC,0x61,0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,0x43,0x39,0xC8,0x43,
|
||||||
|
0x39,0x98,0x43,0x39,0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,0x94,0xC3,0x2F,0xBC,
|
||||||
|
0x83,0x3C,0xFC,0x82,0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,0x03,0x72,0x10,0x87,
|
||||||
|
0x73,0x70,0x03,0x7B,0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,0x98,0x81,0x3C,0xE4,
|
||||||
|
0x80,0x0F,0x6E,0x40,0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x12,0x00,0x00,0x00,
|
||||||
|
0x46,0x20,0x0D,0x97,0xEF,0x3C,0xBE,0x10,0x11,0xC0,0x44,0x84,0x40,0x33,0x2C,0x84,0x05,0x4C,0xC3,0xE5,
|
||||||
|
0x3B,0x8F,0xBF,0x38,0xC0,0x20,0x36,0x0F,0x35,0xF9,0xC5,0x6D,0xDB,0x00,0x34,0x5C,0xBE,0xF3,0xF8,0x12,
|
||||||
|
0xC0,0x3C,0x0B,0xE1,0x17,0xB7,0x6D,0x02,0xD5,0x70,0xF9,0xCE,0xE3,0x4B,0x93,0x13,0x11,0x28,0x35,0x3D,
|
||||||
|
0xD4,0xE4,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x41,0x53,0x48,
|
||||||
|
0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x40,0x62,0x49,0x8C,0x9B,0x86,0xEE,0x5C,0xCE,0x55,0xED,
|
||||||
|
0xA7,0x1A,0xB9,0x7D,0x44,0x58,0x49,0x4C,0xC0,0x06,0x00,0x00,0x60,0x00,0x00,0x00,0xB0,0x01,0x00,0x00,
|
||||||
|
0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0xA8,0x06,0x00,0x00,0x42,0x43,0xC0,0xDE,
|
||||||
|
0x21,0x0C,0x00,0x00,0xA7,0x01,0x00,0x00,0x0B,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,
|
||||||
|
0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,
|
||||||
|
0x1E,0x04,0x8B,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0B,0x42,0xA4,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,
|
||||||
|
0x0A,0x32,0x52,0x88,0x48,0x90,0x14,0x20,0x43,0x46,0x88,0xA5,0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,
|
||||||
|
0x91,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,0xE1,0x83,0xE5,0x8A,0x04,0x29,0x46,0x06,0x51,0x18,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,0xFF,0xFF,0xFF,0x07,0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,
|
||||||
|
0xFF,0xFF,0x03,0x20,0x6D,0x30,0x86,0xFF,0xFF,0xFF,0xFF,0x1F,0x00,0x09,0xA8,0x00,0x49,0x18,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x4C,0x08,0x06,0x00,0x00,0x00,0x00,0x89,0x20,0x00,0x00,
|
||||||
|
0x43,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,0x93,0x22,0xA4,0x84,0x04,0x93,0x22,0xE3,
|
||||||
|
0x84,0xA1,0x90,0x14,0x12,0x4C,0x8A,0x8C,0x0B,0x84,0xA4,0x4C,0x10,0x68,0x23,0x00,0x25,0x00,0x14,0x66,
|
||||||
|
0x00,0xE6,0x08,0xC0,0x60,0x8E,0x00,0x29,0xC6,0x20,0x84,0x14,0x42,0xA6,0x18,0x80,0x10,0x52,0x06,0xA1,
|
||||||
|
0x9B,0x86,0xCB,0x9F,0xB0,0x87,0x90,0xFC,0x95,0x90,0x56,0x62,0xF2,0x8B,0xDB,0x46,0xC5,0x18,0x63,0x10,
|
||||||
|
0x2A,0xF7,0x0C,0x97,0x3F,0x61,0x0F,0x21,0xF9,0x21,0xD0,0x0C,0x0B,0x81,0x82,0x55,0x18,0x45,0x18,0x1B,
|
||||||
|
0x63,0x0C,0x42,0xC8,0xA0,0x36,0x47,0x10,0x14,0x83,0x91,0x42,0xC8,0x23,0x38,0x10,0x30,0x8C,0x40,0x0C,
|
||||||
|
0x33,0xB5,0xC1,0x38,0xB0,0x43,0x38,0xCC,0xC3,0x3C,0xB8,0x01,0x2D,0x94,0x03,0x3E,0xD0,0x43,0x3D,0xC8,
|
||||||
|
0x43,0x39,0xC8,0x01,0x29,0xF0,0x81,0x3D,0x94,0xC3,0x38,0xD0,0xC3,0x3B,0xC8,0x03,0x1F,0x98,0x03,0x3B,
|
||||||
|
0xBC,0x43,0x38,0xD0,0x03,0x1B,0x80,0x01,0x1D,0xF8,0x01,0x18,0xF8,0x81,0x1E,0xE8,0x41,0x3B,0xA4,0x03,
|
||||||
|
0x3C,0xCC,0xC3,0x2F,0xD0,0x43,0x3E,0xC0,0x43,0x39,0xA0,0x80,0xCC,0x24,0x06,0xE3,0xC0,0x0E,0xE1,0x30,
|
||||||
|
0x0F,0xF3,0xE0,0x06,0xB4,0x50,0x0E,0xF8,0x40,0x0F,0xF5,0x20,0x0F,0xE5,0x20,0x07,0xA4,0xC0,0x07,0xF6,
|
||||||
|
0x50,0x0E,0xE3,0x40,0x0F,0xEF,0x20,0x0F,0x7C,0x60,0x0E,0xEC,0xF0,0x0E,0xE1,0x40,0x0F,0x6C,0x00,0x06,
|
||||||
|
0x74,0xE0,0x07,0x60,0xE0,0x07,0x48,0x98,0x94,0xEA,0x4D,0xD2,0x14,0x51,0xC2,0xE4,0xB3,0x00,0xF3,0x2C,
|
||||||
|
0x44,0xC4,0x4E,0xC0,0x44,0xA0,0x80,0xD0,0x4D,0x04,0x02,0x00,0x13,0x14,0x72,0xC0,0x87,0x74,0x60,0x87,
|
||||||
|
0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,0x0E,0x6D,0xD0,0x0E,0x7A,0x50,0x0E,0x6D,
|
||||||
|
0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0xA0,0x07,0x73,0x20,0x07,
|
||||||
|
0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xD0,
|
||||||
|
0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x76,0x40,0x07,0x7A,0x60,0x07,0x74,
|
||||||
|
0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,0x60,0x0E,0x73,0x20,0x07,0x7A,0x30,0x07,
|
||||||
|
0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,0x6D,0xE0,0x0E,0x78,0xA0,0x07,0x71,0x60,
|
||||||
|
0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x79,0x10,0x20,
|
||||||
|
0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xF2,0x34,0x40,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x30,0xE4,0x81,0x80,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x0B,0x04,0x00,0x00,
|
||||||
|
0x0E,0x00,0x00,0x00,0x32,0x1E,0x98,0x14,0x19,0x11,0x4C,0x90,0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0x22,
|
||||||
|
0x25,0x30,0x02,0x50,0x10,0xC5,0x50,0x04,0x25,0x51,0x06,0xE5,0x41,0xA5,0x24,0x46,0x00,0x8A,0xA0,0x10,
|
||||||
|
0x0A,0x84,0xEC,0x0C,0x00,0xE1,0x19,0x00,0xCA,0x63,0x21,0x06,0x11,0x08,0x04,0xF2,0x3C,0x00,0x00,0x00,
|
||||||
|
0x79,0x18,0x00,0x00,0x58,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,0x46,0x02,0x13,0xC4,0x8E,0x0C,0x6F,0xEC,
|
||||||
|
0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,0x05,0x07,0x04,0x45,0x8C,0xE6,0x26,0x26,
|
||||||
|
0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x88,0x62,0x82,0x40,0x18,0x1B,0x84,0x81,0x98,0x20,
|
||||||
|
0x10,0xC7,0x06,0x61,0x30,0x28,0xC0,0xCD,0x4D,0x10,0x08,0x64,0xC3,0x80,0x24,0xC4,0x04,0xC1,0x92,0x08,
|
||||||
|
0x4C,0x10,0x88,0x64,0x82,0x40,0x28,0x1B,0x04,0xC2,0xD9,0x90,0x10,0x0B,0xD3,0x10,0x43,0x43,0x3C,0x1B,
|
||||||
|
0x02,0x68,0x82,0x80,0x4D,0x1B,0x10,0x42,0x62,0x1A,0x62,0x20,0x80,0x0D,0xC1,0xB4,0x81,0x88,0x00,0x80,
|
||||||
|
0x9A,0x20,0x64,0xD4,0x86,0xC0,0x9A,0x20,0x08,0x00,0x89,0xB6,0xB0,0x34,0x37,0x22,0x54,0x45,0x58,0x43,
|
||||||
|
0x4F,0x4F,0x52,0x44,0x13,0x84,0xA2,0x99,0x20,0x14,0xCE,0x86,0x80,0x98,0x20,0x14,0xCF,0x04,0xA1,0x80,
|
||||||
|
0x26,0x08,0xC4,0x32,0x41,0x20,0x98,0x0D,0x02,0x18,0x84,0xC1,0x86,0x85,0xD0,0x36,0xAE,0xF3,0x86,0x8F,
|
||||||
|
0xE0,0xC4,0x60,0x43,0x30,0x6C,0x10,0xC0,0x00,0x0C,0x36,0x2C,0x83,0xB6,0x71,0x64,0xE0,0x0D,0xDE,0xC0,
|
||||||
|
0x95,0xC1,0x06,0x61,0x0C,0xCC,0x80,0xC9,0x94,0xD5,0x17,0x55,0x98,0xDC,0x59,0x19,0xDD,0x04,0xA1,0x88,
|
||||||
|
0x36,0x2C,0x04,0x1A,0x6C,0x69,0xD0,0x71,0xC3,0x47,0x70,0x62,0xB0,0x21,0x50,0x83,0x0D,0xC3,0x19,0xAC,
|
||||||
|
0x01,0xB0,0xA1,0xC0,0x32,0x36,0xA8,0x80,0x2A,0x6C,0x6C,0x76,0x6D,0x2E,0x69,0x64,0x65,0x6E,0x74,0x53,
|
||||||
|
0x82,0xA0,0x0A,0x19,0x9E,0x8B,0x5D,0x99,0xDC,0x5C,0xDA,0x9B,0xDB,0x94,0x80,0x68,0x42,0x86,0xE7,0x62,
|
||||||
|
0x17,0xC6,0x66,0x57,0x26,0x37,0x25,0x30,0xEA,0x90,0xE1,0xB9,0xCC,0xA1,0x85,0x91,0x95,0xC9,0x35,0xBD,
|
||||||
|
0x91,0x95,0xB1,0x4D,0x09,0x92,0x32,0x64,0x78,0x2E,0x72,0x65,0x73,0x6F,0x75,0x72,0x63,0x65,0x73,0x53,
|
||||||
|
0x02,0xAA,0x0E,0x19,0x9E,0x8B,0x5D,0x5A,0xD9,0x5D,0x12,0xD9,0x14,0x5D,0x18,0x5D,0xD9,0x94,0xC0,0xAA,
|
||||||
|
0x43,0x86,0xE7,0x52,0xE6,0x46,0x27,0x97,0x07,0xF5,0x96,0xE6,0x46,0x37,0x37,0x25,0x60,0x03,0x00,0x00,
|
||||||
|
0x79,0x18,0x00,0x00,0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,0x14,0x01,0x3D,0x88,
|
||||||
|
0x43,0x38,0x84,0xC3,0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,0x00,0x0F,0xED,0x10,
|
||||||
|
0x0E,0xF4,0x80,0x0E,0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,0x05,0x3D,0x88,0x43,
|
||||||
|
0x38,0x84,0x83,0x1B,0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,0x74,0x70,0x07,0x7B,
|
||||||
|
0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xCC,0x11,
|
||||||
|
0x0E,0xEC,0x90,0x0E,0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,0x33,0x10,0xC4,0x1D,
|
||||||
|
0xDE,0x21,0x1C,0xD8,0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,0xD0,0x43,0x39,0xB4,
|
||||||
|
0x03,0x3C,0xBC,0x83,0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,0x07,0x37,0x68,0x87,
|
||||||
|
0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xF8,0x05,0x76,0x78,
|
||||||
|
0x87,0x77,0x80,0x87,0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2C,0xEE,0xF0,0x0E,
|
||||||
|
0xEE,0xE0,0x0E,0xF5,0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,0xCC,0xA1,0x1C,0xE4,
|
||||||
|
0xA1,0x1C,0xDC,0x61,0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,0x43,0x39,0xC8,0x43,
|
||||||
|
0x39,0x98,0x43,0x39,0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,0x94,0xC3,0x2F,0xBC,
|
||||||
|
0x83,0x3C,0xFC,0x82,0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,0x03,0x72,0x10,0x87,
|
||||||
|
0x73,0x70,0x03,0x7B,0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,0x98,0x81,0x3C,0xE4,
|
||||||
|
0x80,0x0F,0x6E,0x40,0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x12,0x00,0x00,0x00,
|
||||||
|
0x46,0x20,0x0D,0x97,0xEF,0x3C,0xBE,0x10,0x11,0xC0,0x44,0x84,0x40,0x33,0x2C,0x84,0x05,0x4C,0xC3,0xE5,
|
||||||
|
0x3B,0x8F,0xBF,0x38,0xC0,0x20,0x36,0x0F,0x35,0xF9,0xC5,0x6D,0xDB,0x00,0x34,0x5C,0xBE,0xF3,0xF8,0x12,
|
||||||
|
0xC0,0x3C,0x0B,0xE1,0x17,0xB7,0x6D,0x02,0xD5,0x70,0xF9,0xCE,0xE3,0x4B,0x93,0x13,0x11,0x28,0x35,0x3D,
|
||||||
|
0xD4,0xE4,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,0x00,0x00,0x61,0x20,0x00,0x00,0x3B,0x00,0x00,0x00,
|
||||||
|
0x13,0x04,0x41,0x2C,0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0xF4,0x46,0x00,0x88,0xCC,0x00,0x14,0x42,
|
||||||
|
0x29,0x94,0x5C,0xE1,0x51,0x29,0x83,0x12,0xA0,0x31,0x03,0x00,0x23,0x06,0x09,0x00,0x82,0x60,0x00,0x69,
|
||||||
|
0x05,0x84,0x61,0xC9,0x88,0x41,0x02,0x80,0x20,0x18,0x40,0x9B,0x41,0x64,0x99,0x32,0x62,0x90,0x00,0x20,
|
||||||
|
0x08,0x06,0xC6,0x97,0x6C,0x9A,0xA4,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x01,0x06,0x0A,0xB7,0x15,0xCB,
|
||||||
|
0x88,0x41,0x02,0x80,0x20,0x18,0x18,0x61,0xB0,0x70,0x1C,0xC5,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x21,
|
||||||
|
0x06,0x4C,0xD7,0x1D,0xCD,0x88,0x41,0x02,0x80,0x20,0x18,0x18,0x63,0xD0,0x78,0x5E,0xE5,0x8C,0x18,0x24,
|
||||||
|
0x00,0x08,0x82,0x81,0x41,0x06,0xCE,0xF7,0x29,0xCF,0x88,0xC1,0x03,0x80,0x20,0x18,0x34,0x63,0xC0,0x20,
|
||||||
|
0x87,0x51,0x24,0x09,0x18,0x80,0x01,0x94,0x8C,0x26,0x04,0xC0,0x68,0x82,0x10,0x8C,0x26,0x0C,0xC2,0x68,
|
||||||
|
0x02,0x31,0x18,0x91,0xC8,0xC7,0x88,0x44,0x3E,0x46,0x24,0xF2,0x31,0x22,0x91,0xCF,0x88,0x41,0x02,0x80,
|
||||||
|
0x20,0x18,0x20,0x6D,0x70,0xA5,0x41,0x1A,0x84,0x01,0x31,0x62,0x90,0x00,0x20,0x08,0x06,0x48,0x1B,0x5C,
|
||||||
|
0x69,0x90,0x06,0xD3,0x30,0x62,0x90,0x00,0x20,0x08,0x06,0x48,0x1B,0x5C,0x69,0x90,0x06,0x60,0x20,0x8C,
|
||||||
|
0x18,0x24,0x00,0x08,0x82,0x01,0xD2,0x06,0x57,0x1A,0xA4,0x01,0x15,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_vert_spirv[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x2B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x0F,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x05,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x05,0x00,0x09,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x74,0x79,0x70,0x65,0x2E,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,
|
||||||
|
0x6B,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x00,0x00,0x06,0x00,0x06,0x00,0x08,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x00,0x00,0x00,0x05,0x00,0x08,0x00,
|
||||||
|
0x09,0x00,0x00,0x00,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,
|
||||||
|
0x73,0x66,0x6F,0x72,0x6D,0x00,0x00,0x00,0x05,0x00,0x09,0x00,0x0A,0x00,0x00,0x00,0x74,0x79,0x70,0x65,
|
||||||
|
0x2E,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,
|
||||||
|
0x74,0x65,0x00,0x00,0x06,0x00,0x06,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x72,0x61,0x6E,
|
||||||
|
0x73,0x6C,0x61,0x74,0x65,0x00,0x00,0x00,0x05,0x00,0x08,0x00,0x0B,0x00,0x00,0x00,0x55,0x6E,0x69,0x66,
|
||||||
|
0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x07,0x00,0x02,0x00,0x00,0x00,0x69,0x6E,0x2E,0x76,0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,
|
||||||
|
0x4F,0x52,0x44,0x30,0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,0x03,0x00,0x00,0x00,0x69,0x6E,0x2E,0x76,
|
||||||
|
0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x69,0x6E,0x2E,0x76,0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x32,
|
||||||
|
0x00,0x00,0x00,0x00,0x05,0x00,0x07,0x00,0x05,0x00,0x00,0x00,0x6F,0x75,0x74,0x2E,0x76,0x61,0x72,0x2E,
|
||||||
|
0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x00,0x00,0x00,0x05,0x00,0x07,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x6F,0x75,0x74,0x2E,0x76,0x61,0x72,0x2E,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x03,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x05,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00,
|
||||||
|
0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x21,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x48,0x00,0x04,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x08,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x0A,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x04,0x00,
|
||||||
|
0x0C,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,0x0C,0x00,0x00,0x00,
|
||||||
|
0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x0E,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
|
||||||
|
0x2B,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,
|
||||||
|
0x0E,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x80,0x3F,0x17,0x00,0x04,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x0E,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x18,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x1E,0x00,0x03,0x00,0x08,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
|
||||||
|
0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x0E,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1E,0x00,0x03,0x00,0x0A,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
|
||||||
|
0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x13,0x00,0x02,0x00,0x1A,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x1B,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x1C,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
|
||||||
|
0x1D,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x13,0x00,0x00,0x00,
|
||||||
|
0x09,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x3B,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x16,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x18,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x19,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x36,0x00,0x05,0x00,0x1A,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0x00,0x00,0x00,
|
||||||
|
0xF8,0x00,0x02,0x00,0x1E,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x41,0x00,0x05,0x00,
|
||||||
|
0x1C,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x14,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x81,0x00,0x05,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x24,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x0E,0x00,0x00,0x00,
|
||||||
|
0x25,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x0E,0x00,0x00,0x00,
|
||||||
|
0x26,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x27,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0x41,0x00,0x05,0x00,0x1D,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x12,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x90,0x00,0x05,0x00,
|
||||||
|
0x11,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x21,0x00,0x00,0x00,
|
||||||
|
0x3E,0x00,0x03,0x00,0x07,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_vert_msl[] = {
|
||||||
|
0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x6D,0x65,0x74,0x61,0x6C,0x5F,0x73,0x74,0x64,0x6C,
|
||||||
|
0x69,0x62,0x3E,0x0A,0x23,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x20,0x3C,0x73,0x69,0x6D,0x64,0x2F,0x73,
|
||||||
|
0x69,0x6D,0x64,0x2E,0x68,0x3E,0x0A,0x0A,0x75,0x73,0x69,0x6E,0x67,0x20,0x6E,0x61,0x6D,0x65,0x73,0x70,
|
||||||
|
0x61,0x63,0x65,0x20,0x6D,0x65,0x74,0x61,0x6C,0x3B,0x0A,0x0A,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x74,
|
||||||
|
0x79,0x70,0x65,0x5F,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,
|
||||||
|
0x73,0x66,0x6F,0x72,0x6D,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x78,0x34,
|
||||||
|
0x20,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x73,0x74,0x72,0x75,
|
||||||
|
0x63,0x74,0x20,0x74,0x79,0x70,0x65,0x5F,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,
|
||||||
|
0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,
|
||||||
|
0x74,0x32,0x20,0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x73,0x74,
|
||||||
|
0x72,0x75,0x63,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x6F,0x75,0x74,0x0A,0x7B,0x0A,0x20,0x20,0x20,
|
||||||
|
0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x20,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,
|
||||||
|
0x4F,0x4F,0x52,0x44,0x30,0x20,0x5B,0x5B,0x75,0x73,0x65,0x72,0x28,0x6C,0x6F,0x63,0x6E,0x30,0x29,0x5D,
|
||||||
|
0x5D,0x3B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x32,0x20,0x6F,0x75,0x74,0x5F,0x76,0x61,
|
||||||
|
0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x20,0x5B,0x5B,0x75,0x73,0x65,0x72,0x28,0x6C,
|
||||||
|
0x6F,0x63,0x6E,0x31,0x29,0x5D,0x5D,0x3B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x20,
|
||||||
|
0x67,0x6C,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x20,0x5B,0x5B,0x70,0x6F,0x73,0x69,0x74,0x69,
|
||||||
|
0x6F,0x6E,0x5D,0x5D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6D,0x61,0x69,
|
||||||
|
0x6E,0x30,0x5F,0x69,0x6E,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x32,0x20,0x69,
|
||||||
|
0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x20,0x5B,0x5B,0x61,0x74,
|
||||||
|
0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30,0x29,0x5D,0x5D,0x3B,0x0A,0x20,0x20,0x20,0x20,0x66,0x6C,
|
||||||
|
0x6F,0x61,0x74,0x34,0x20,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,
|
||||||
|
0x31,0x20,0x5B,0x5B,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x31,0x29,0x5D,0x5D,0x3B,0x0A,
|
||||||
|
0x20,0x20,0x20,0x20,0x66,0x6C,0x6F,0x61,0x74,0x32,0x20,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,
|
||||||
|
0x58,0x43,0x4F,0x4F,0x52,0x44,0x32,0x20,0x5B,0x5B,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,
|
||||||
|
0x32,0x29,0x5D,0x5D,0x3B,0x0A,0x7D,0x3B,0x0A,0x0A,0x76,0x65,0x72,0x74,0x65,0x78,0x20,0x6D,0x61,0x69,
|
||||||
|
0x6E,0x30,0x5F,0x6F,0x75,0x74,0x20,0x6D,0x61,0x69,0x6E,0x30,0x28,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x69,
|
||||||
|
0x6E,0x20,0x69,0x6E,0x20,0x5B,0x5B,0x73,0x74,0x61,0x67,0x65,0x5F,0x69,0x6E,0x5D,0x5D,0x2C,0x20,0x63,
|
||||||
|
0x6F,0x6E,0x73,0x74,0x61,0x6E,0x74,0x20,0x74,0x79,0x70,0x65,0x5F,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,
|
||||||
|
0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x26,0x20,0x55,0x6E,0x69,0x66,
|
||||||
|
0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x20,0x5B,0x5B,
|
||||||
|
0x62,0x75,0x66,0x66,0x65,0x72,0x28,0x30,0x29,0x5D,0x5D,0x2C,0x20,0x63,0x6F,0x6E,0x73,0x74,0x61,0x6E,
|
||||||
|
0x74,0x20,0x74,0x79,0x70,0x65,0x5F,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,
|
||||||
|
0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x26,0x20,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,0x42,0x6C,0x6F,
|
||||||
|
0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x20,0x5B,0x5B,0x62,0x75,0x66,0x66,0x65,0x72,
|
||||||
|
0x28,0x31,0x29,0x5D,0x5D,0x29,0x0A,0x7B,0x0A,0x20,0x20,0x20,0x20,0x6D,0x61,0x69,0x6E,0x30,0x5F,0x6F,
|
||||||
|
0x75,0x74,0x20,0x6F,0x75,0x74,0x20,0x3D,0x20,0x7B,0x7D,0x3B,0x0A,0x20,0x20,0x20,0x20,0x6F,0x75,0x74,
|
||||||
|
0x2E,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x20,0x3D,
|
||||||
|
0x20,0x69,0x6E,0x2E,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,
|
||||||
|
0x3B,0x0A,0x20,0x20,0x20,0x20,0x6F,0x75,0x74,0x2E,0x6F,0x75,0x74,0x5F,0x76,0x61,0x72,0x5F,0x54,0x45,
|
||||||
|
0x58,0x43,0x4F,0x4F,0x52,0x44,0x31,0x20,0x3D,0x20,0x69,0x6E,0x2E,0x69,0x6E,0x5F,0x76,0x61,0x72,0x5F,
|
||||||
|
0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x32,0x3B,0x0A,0x20,0x20,0x20,0x20,0x6F,0x75,0x74,0x2E,0x67,
|
||||||
|
0x6C,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x20,0x3D,0x20,0x55,0x6E,0x69,0x66,0x6F,0x72,0x6D,
|
||||||
|
0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x2E,0x54,0x72,0x61,0x6E,0x73,
|
||||||
|
0x66,0x6F,0x72,0x6D,0x20,0x2A,0x20,0x66,0x6C,0x6F,0x61,0x74,0x34,0x28,0x69,0x6E,0x2E,0x69,0x6E,0x5F,
|
||||||
|
0x76,0x61,0x72,0x5F,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x30,0x20,0x2B,0x20,0x55,0x6E,0x69,0x66,
|
||||||
|
0x6F,0x72,0x6D,0x42,0x6C,0x6F,0x63,0x6B,0x54,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x2E,0x54,0x72,
|
||||||
|
0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x2C,0x20,0x30,0x2E,0x30,0x2C,0x20,0x31,0x2E,0x30,0x29,0x3B,0x0A,
|
||||||
|
0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6E,0x20,0x6F,0x75,0x74,0x3B,0x0A,0x7D,0x0A,0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_vert_dxil[] = {
|
||||||
|
0x44,0x58,0x42,0x43,0x41,0x89,0x95,0x46,0xEE,0xBB,0xC2,0x51,0x0B,0xA5,0x2F,0x16,0x3D,0x58,0x9E,0xDD,
|
||||||
|
0x01,0x00,0x00,0x00,0x9C,0x11,0x00,0x00,0x07,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x4C,0x00,0x00,0x00,
|
||||||
|
0xC8,0x00,0x00,0x00,0x50,0x01,0x00,0x00,0xA4,0x02,0x00,0x00,0xB4,0x09,0x00,0x00,0xD0,0x09,0x00,0x00,
|
||||||
|
0x53,0x46,0x49,0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x53,0x47,0x31,
|
||||||
|
0x74,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x68,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x00,0x00,0x00,
|
||||||
|
0x4F,0x53,0x47,0x31,0x80,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,
|
||||||
|
0x00,0x53,0x56,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,0x00,0x00,0x00,0x50,0x53,0x56,0x30,
|
||||||
|
0x4C,0x01,0x00,0x00,0x34,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x00,0x00,0x03,0x03,0x00,0x03,
|
||||||
|
0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0x00,0x00,0x00,
|
||||||
|
0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x54,
|
||||||
|
0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x54,0x45,0x58,0x43,0x4F,0x4F,0x52,0x44,0x00,0x54,0x45,0x58,
|
||||||
|
0x43,0x4F,0x4F,0x52,0x44,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x42,0x00,0x03,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x01,0x44,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x02,0x42,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x44,0x00,0x03,0x02,0x00,0x00,0x25,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x01,0x01,0x42,0x00,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x02,0x44,0x03,0x03,0x04,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
|
||||||
|
0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x54,0x41,0x54,
|
||||||
|
0x08,0x07,0x00,0x00,0x60,0x00,0x01,0x00,0xC2,0x01,0x00,0x00,0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,
|
||||||
|
0x10,0x00,0x00,0x00,0xF0,0x06,0x00,0x00,0x42,0x43,0xC0,0xDE,0x21,0x0C,0x00,0x00,0xB9,0x01,0x00,0x00,
|
||||||
|
0x0B,0x82,0x20,0x00,0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,
|
||||||
|
0x06,0x10,0x32,0x39,0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,0x1E,0x04,0x8B,0x62,0x80,0x14,0x45,0x02,
|
||||||
|
0x42,0x92,0x0B,0x42,0xA4,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,0x0A,0x32,0x52,0x88,0x48,0x90,0x14,0x20,
|
||||||
|
0x43,0x46,0x88,0xA5,0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,0x91,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,
|
||||||
|
0xE1,0x83,0xE5,0x8A,0x04,0x29,0x46,0x06,0x51,0x18,0x00,0x00,0x08,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,
|
||||||
|
0xFF,0xFF,0xFF,0x07,0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,0xFF,0xFF,0x03,0x20,0x6D,0x30,0x86,0xFF,
|
||||||
|
0xFF,0xFF,0xFF,0x1F,0x00,0x09,0xA8,0x00,0x49,0x18,0x00,0x00,0x03,0x00,0x00,0x00,0x13,0x82,0x60,0x42,
|
||||||
|
0x20,0x4C,0x08,0x06,0x00,0x00,0x00,0x00,0x89,0x20,0x00,0x00,0x2E,0x00,0x00,0x00,0x32,0x22,0x48,0x09,
|
||||||
|
0x20,0x64,0x85,0x04,0x93,0x22,0xA4,0x84,0x04,0x93,0x22,0xE3,0x84,0xA1,0x90,0x14,0x12,0x4C,0x8A,0x8C,
|
||||||
|
0x0B,0x84,0xA4,0x4C,0x10,0x74,0x23,0x00,0x25,0x00,0x14,0x66,0x00,0xE6,0x08,0xC0,0x60,0x8E,0x00,0x29,
|
||||||
|
0xC6,0x20,0x84,0x14,0x42,0xA6,0x18,0x80,0x10,0x52,0x06,0xA1,0xA3,0x86,0xCB,0x9F,0xB0,0x87,0x90,0x7C,
|
||||||
|
0x6E,0xA3,0x8A,0x95,0x98,0xFC,0xE2,0xB6,0x11,0x31,0xC6,0x18,0x54,0xEE,0x19,0x2E,0x7F,0xC2,0x1E,0x42,
|
||||||
|
0xF2,0x43,0xA0,0x19,0x16,0x02,0x05,0xAB,0x10,0x8A,0x30,0x42,0xAD,0x14,0x83,0x8C,0x31,0xE8,0xCD,0x11,
|
||||||
|
0x04,0xC5,0x60,0xA4,0x10,0x12,0x49,0x0E,0x04,0x0C,0x23,0x10,0x43,0x12,0xD4,0x2B,0x83,0xC3,0x91,0xA6,
|
||||||
|
0x05,0xC0,0x1C,0x6A,0xF2,0x27,0xEC,0x21,0x7E,0xB7,0x41,0x0A,0x27,0x62,0xB6,0xC5,0x11,0x94,0x36,0x02,
|
||||||
|
0x1A,0xA9,0x70,0x22,0x06,0x05,0x96,0xEE,0x30,0x82,0x30,0x9C,0x36,0x61,0x0F,0xF1,0xBB,0x0D,0x52,0x38,
|
||||||
|
0x11,0xB3,0x2D,0x8E,0xA0,0xB4,0x11,0xD0,0x48,0x0B,0x30,0x11,0x28,0xC8,0xA4,0x93,0x81,0x00,0x00,0x00,
|
||||||
|
0x13,0x14,0x72,0xC0,0x87,0x74,0x60,0x87,0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,
|
||||||
|
0x0E,0x6D,0xD0,0x0E,0x7A,0x50,0x0E,0x6D,0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x90,0x0E,0x71,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,
|
||||||
|
0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,
|
||||||
|
0x0E,0x76,0x40,0x07,0x7A,0x60,0x07,0x74,0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,
|
||||||
|
0x60,0x0E,0x73,0x20,0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,
|
||||||
|
0x6D,0xE0,0x0E,0x78,0xA0,0x07,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,
|
||||||
|
0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x0C,0x79,0x10,0x20,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xF2,0x34,
|
||||||
|
0x40,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xE4,0x79,0x80,0x00,0x08,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x60,0xC8,0x23,0x01,0x01,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,
|
||||||
|
0x14,0x00,0x00,0x00,0x32,0x1E,0x98,0x14,0x19,0x11,0x4C,0x90,0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0x22,
|
||||||
|
0x25,0x30,0x02,0x50,0x0C,0x05,0x18,0x50,0x10,0x65,0x50,0x0E,0x25,0x51,0x1A,0x45,0x50,0x08,0xE5,0x51,
|
||||||
|
0x14,0xA5,0x46,0xA5,0x24,0x46,0x00,0x8A,0xA0,0x10,0xCA,0x80,0xEE,0x0C,0x00,0xE1,0x19,0x00,0xD2,0x33,
|
||||||
|
0x00,0xB4,0x67,0x00,0x88,0x8F,0xC5,0x28,0x0C,0x88,0x0F,0x20,0x3E,0x00,0x40,0x20,0x10,0x08,0x04,0x06,
|
||||||
|
0x00,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0xAD,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,0x46,0x02,0x13,0xC4,
|
||||||
|
0x8E,0x0C,0x6F,0xEC,0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,0x05,0x07,0x04,0x45,
|
||||||
|
0x8C,0xE6,0x26,0x26,0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x08,0x63,0x82,0x40,0x1C,0x1B,
|
||||||
|
0x84,0x81,0xD8,0x20,0x10,0x04,0x05,0xBB,0xB9,0x09,0x02,0x81,0x6C,0x18,0x0E,0x84,0x98,0x20,0x60,0x1A,
|
||||||
|
0x35,0xBA,0x3C,0xB8,0xB2,0xAF,0x2A,0xB7,0x34,0xB3,0x37,0xB9,0x36,0x21,0xB6,0xB7,0xB1,0x35,0x2A,0xB9,
|
||||||
|
0x30,0xB7,0x39,0xB3,0x37,0xB9,0xB6,0x09,0x02,0x91,0x6C,0x40,0x08,0x65,0x19,0x88,0x81,0x01,0x26,0x08,
|
||||||
|
0x1B,0x47,0x8D,0x2E,0x0F,0xAE,0xEC,0xAB,0xCA,0x2D,0xCD,0xEC,0x4D,0xAE,0x4D,0x88,0xED,0x6D,0x6C,0x8D,
|
||||||
|
0x4A,0x2E,0xCC,0x6D,0x8E,0x2D,0x8C,0xAE,0x6C,0x82,0x40,0x28,0x1B,0x90,0xC1,0x79,0x86,0x61,0x80,0x80,
|
||||||
|
0x0D,0x42,0x13,0x6D,0x20,0x00,0x40,0x02,0x26,0x08,0xDA,0xC6,0xAF,0xCA,0x2D,0xCD,0xEC,0x4D,0xAE,0x4D,
|
||||||
|
0x88,0xED,0x6D,0x6C,0x8D,0x4A,0x2E,0xCC,0x6D,0x8E,0x2D,0x8C,0xAE,0xEC,0x8B,0x4A,0x2E,0xCC,0x6D,0x8E,
|
||||||
|
0x2D,0x8C,0xAE,0x6C,0x82,0x40,0x2C,0x13,0x04,0x82,0x99,0x20,0x10,0xCD,0x04,0x81,0x70,0x26,0x08,0xC4,
|
||||||
|
0xB3,0x01,0x41,0x2A,0x8B,0xB8,0xB0,0x4C,0xDB,0x20,0x40,0xDB,0x04,0xE1,0xCA,0xF8,0x55,0xB9,0xA5,0x99,
|
||||||
|
0xBD,0xC9,0xB5,0x09,0xB1,0xBD,0x8D,0xAD,0x51,0xC9,0x85,0xB9,0xCD,0x99,0xBD,0xC9,0xB5,0x7D,0x51,0xC9,
|
||||||
|
0x85,0xB9,0xCD,0x99,0xBD,0xC9,0xB5,0x4D,0x10,0x08,0x68,0xC3,0xF0,0x7D,0xDA,0x06,0x04,0xF1,0x34,0x30,
|
||||||
|
0xB0,0x88,0x0B,0xDB,0x20,0x30,0x61,0xB0,0xA1,0x20,0x28,0xAE,0x13,0x83,0x09,0x82,0x00,0x6C,0x00,0x36,
|
||||||
|
0x0C,0x44,0x19,0x94,0xC1,0x86,0xC0,0x0C,0x36,0x0C,0x03,0x19,0x9C,0xC1,0x04,0x81,0xEB,0x36,0x04,0x69,
|
||||||
|
0x40,0xA2,0x2D,0x2C,0xCD,0x8D,0x08,0x55,0x11,0xD6,0xD0,0xD3,0x93,0x14,0xD1,0x04,0xA1,0xA0,0x26,0x08,
|
||||||
|
0x45,0xB5,0x21,0x20,0x26,0x08,0x85,0xB5,0x41,0xB0,0xAC,0x0D,0x0B,0xC1,0x06,0x6D,0xE0,0x06,0x6F,0xE0,
|
||||||
|
0x06,0x03,0x1C,0x10,0x6E,0x10,0x07,0x1B,0x82,0x61,0x82,0x50,0x5C,0x13,0x04,0x22,0xDA,0x20,0x58,0x75,
|
||||||
|
0xB0,0x61,0x19,0xD8,0xA0,0x0D,0xDC,0x60,0x0E,0xDC,0x60,0xA0,0x83,0xC1,0x0D,0xEC,0x60,0x43,0xA0,0x6D,
|
||||||
|
0x58,0x34,0x36,0x68,0x03,0x37,0xC0,0x03,0x37,0x18,0xE0,0x40,0x73,0x83,0x38,0xD8,0x30,0xC8,0xC1,0x1D,
|
||||||
|
0xE4,0xC1,0x86,0x85,0x60,0x83,0x36,0x70,0x83,0x37,0x80,0x83,0x81,0x0E,0x08,0x37,0xB0,0x83,0x0D,0xCB,
|
||||||
|
0xC0,0x06,0x6D,0xE0,0x06,0x73,0x00,0x07,0x03,0x1C,0x0C,0x6E,0x10,0x07,0x5C,0xA6,0xAC,0xBE,0xA0,0xDE,
|
||||||
|
0xE6,0xD2,0xE8,0xD2,0xDE,0xDC,0x26,0x08,0x05,0xB6,0x61,0xD1,0xFA,0xA0,0x0D,0xFC,0xE0,0x0D,0xE8,0x60,
|
||||||
|
0xA0,0x03,0xCD,0x0D,0xEC,0x60,0xC3,0xB0,0x07,0x7C,0xF0,0x07,0x1B,0x06,0x3D,0x00,0x05,0x60,0x43,0x41,
|
||||||
|
0x06,0x6B,0x10,0x0A,0x13,0x40,0xC3,0x8C,0xED,0x2D,0x8C,0x6E,0x6E,0x82,0x40,0x48,0x2C,0xD2,0xDC,0xE6,
|
||||||
|
0xE8,0xE6,0x26,0x08,0xC4,0x44,0x63,0x2E,0xED,0xEC,0x8B,0x8D,0x8C,0xC6,0x5C,0xDA,0xD9,0xD7,0x1C,0xDD,
|
||||||
|
0x06,0x64,0x14,0x48,0xA1,0x14,0x4C,0xE1,0x14,0x20,0x54,0x20,0x85,0x2A,0x6C,0x6C,0x76,0x6D,0x2E,0x69,
|
||||||
|
0x64,0x65,0x6E,0x74,0x53,0x82,0xA0,0x0A,0x19,0x9E,0x8B,0x5D,0x99,0xDC,0x5C,0xDA,0x9B,0xDB,0x94,0x80,
|
||||||
|
0x68,0x42,0x86,0xE7,0x62,0x17,0xC6,0x66,0x57,0x26,0x37,0x25,0x28,0xEA,0x90,0xE1,0xB9,0xCC,0xA1,0x85,
|
||||||
|
0x91,0x95,0xC9,0x35,0xBD,0x91,0x95,0xB1,0x4D,0x09,0x90,0x32,0x64,0x78,0x2E,0x72,0x65,0x73,0x6F,0x75,
|
||||||
|
0x72,0x63,0x65,0x73,0x53,0x02,0xA9,0x12,0x19,0x9E,0x0B,0x5D,0x1E,0x5C,0x59,0x90,0x9B,0xDB,0x1B,0x5D,
|
||||||
|
0x18,0x5D,0xDA,0x9B,0xDB,0xDC,0x14,0x41,0x0C,0xCE,0xA0,0x0E,0x19,0x9E,0x8B,0x5D,0x5A,0xD9,0x5D,0x12,
|
||||||
|
0xD9,0x14,0x5D,0x18,0x5D,0xD9,0x94,0x20,0x0D,0xEA,0x90,0xE1,0xB9,0x94,0xB9,0xD1,0xC9,0xE5,0x41,0xBD,
|
||||||
|
0xA5,0xB9,0xD1,0xCD,0x4D,0x09,0x42,0xA1,0x0B,0x19,0x9E,0xCB,0xD8,0x5B,0x9D,0x1B,0x5D,0x99,0xDC,0xDC,
|
||||||
|
0x94,0x00,0x15,0x00,0x79,0x18,0x00,0x00,0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,
|
||||||
|
0x14,0x01,0x3D,0x88,0x43,0x38,0x84,0xC3,0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,
|
||||||
|
0x00,0x0F,0xED,0x10,0x0E,0xF4,0x80,0x0E,0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,
|
||||||
|
0x05,0x3D,0x88,0x43,0x38,0x84,0x83,0x1B,0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,
|
||||||
|
0x74,0x70,0x07,0x7B,0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,
|
||||||
|
0x87,0x19,0xCC,0x11,0x0E,0xEC,0x90,0x0E,0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,
|
||||||
|
0x33,0x10,0xC4,0x1D,0xDE,0x21,0x1C,0xD8,0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,
|
||||||
|
0xD0,0x43,0x39,0xB4,0x03,0x3C,0xBC,0x83,0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,
|
||||||
|
0x07,0x37,0x68,0x87,0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,
|
||||||
|
0xF8,0x05,0x76,0x78,0x87,0x77,0x80,0x87,0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,
|
||||||
|
0x2C,0xEE,0xF0,0x0E,0xEE,0xE0,0x0E,0xF5,0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,
|
||||||
|
0xCC,0xA1,0x1C,0xE4,0xA1,0x1C,0xDC,0x61,0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,
|
||||||
|
0x43,0x39,0xC8,0x43,0x39,0x98,0x43,0x39,0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,
|
||||||
|
0x94,0xC3,0x2F,0xBC,0x83,0x3C,0xFC,0x82,0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,
|
||||||
|
0x03,0x72,0x10,0x87,0x73,0x70,0x03,0x7B,0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,
|
||||||
|
0x98,0x81,0x3C,0xE4,0x80,0x0F,0x6E,0x40,0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,
|
||||||
|
0x18,0x00,0x00,0x00,0x36,0xB0,0x0D,0x97,0xEF,0x3C,0xBE,0x10,0x50,0x45,0x41,0x44,0xA5,0x03,0x0C,0x25,
|
||||||
|
0x61,0x00,0x02,0xE6,0x17,0xB7,0x6D,0x05,0xD2,0x70,0xF9,0xCE,0xE3,0x0B,0x11,0x01,0x4C,0x44,0x08,0x34,
|
||||||
|
0xC3,0x42,0x58,0xC0,0x34,0x5C,0xBE,0xF3,0xF8,0x8B,0x03,0x0C,0x62,0xF3,0x50,0x93,0x5F,0xDC,0xB6,0x09,
|
||||||
|
0x54,0xC3,0xE5,0x3B,0x8F,0x2F,0x4D,0x4E,0x44,0xA0,0xD4,0xF4,0x50,0x93,0x5F,0xDC,0xB6,0x11,0x48,0xC3,
|
||||||
|
0xE5,0x3B,0x8F,0x3F,0x11,0xD1,0x84,0x00,0x11,0xE6,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x48,0x41,0x53,0x48,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xC5,0xB4,0xCB,
|
||||||
|
0x0D,0xAD,0xA7,0x7C,0x41,0x76,0x11,0xF5,0xDD,0x93,0xF6,0x75,0x44,0x58,0x49,0x4C,0xC4,0x07,0x00,0x00,
|
||||||
|
0x60,0x00,0x01,0x00,0xF1,0x01,0x00,0x00,0x44,0x58,0x49,0x4C,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0xAC,0x07,0x00,0x00,0x42,0x43,0xC0,0xDE,0x21,0x0C,0x00,0x00,0xE8,0x01,0x00,0x00,0x0B,0x82,0x20,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x07,0x81,0x23,0x91,0x41,0xC8,0x04,0x49,0x06,0x10,0x32,0x39,
|
||||||
|
0x92,0x01,0x84,0x0C,0x25,0x05,0x08,0x19,0x1E,0x04,0x8B,0x62,0x80,0x14,0x45,0x02,0x42,0x92,0x0B,0x42,
|
||||||
|
0xA4,0x10,0x32,0x14,0x38,0x08,0x18,0x4B,0x0A,0x32,0x52,0x88,0x48,0x90,0x14,0x20,0x43,0x46,0x88,0xA5,
|
||||||
|
0x00,0x19,0x32,0x42,0xE4,0x48,0x0E,0x90,0x91,0x22,0xC4,0x50,0x41,0x51,0x81,0x8C,0xE1,0x83,0xE5,0x8A,
|
||||||
|
0x04,0x29,0x46,0x06,0x51,0x18,0x00,0x00,0x08,0x00,0x00,0x00,0x1B,0x8C,0xE0,0xFF,0xFF,0xFF,0xFF,0x07,
|
||||||
|
0x40,0x02,0xA8,0x0D,0x84,0xF0,0xFF,0xFF,0xFF,0xFF,0x03,0x20,0x6D,0x30,0x86,0xFF,0xFF,0xFF,0xFF,0x1F,
|
||||||
|
0x00,0x09,0xA8,0x00,0x49,0x18,0x00,0x00,0x03,0x00,0x00,0x00,0x13,0x82,0x60,0x42,0x20,0x4C,0x08,0x06,
|
||||||
|
0x00,0x00,0x00,0x00,0x89,0x20,0x00,0x00,0x2E,0x00,0x00,0x00,0x32,0x22,0x48,0x09,0x20,0x64,0x85,0x04,
|
||||||
|
0x93,0x22,0xA4,0x84,0x04,0x93,0x22,0xE3,0x84,0xA1,0x90,0x14,0x12,0x4C,0x8A,0x8C,0x0B,0x84,0xA4,0x4C,
|
||||||
|
0x10,0x74,0x23,0x00,0x25,0x00,0x14,0x66,0x00,0xE6,0x08,0xC0,0x60,0x8E,0x00,0x29,0xC6,0x20,0x84,0x14,
|
||||||
|
0x42,0xA6,0x18,0x80,0x10,0x52,0x06,0xA1,0xA3,0x86,0xCB,0x9F,0xB0,0x87,0x90,0x7C,0x6E,0xA3,0x8A,0x95,
|
||||||
|
0x98,0xFC,0xE2,0xB6,0x11,0x31,0xC6,0x18,0x54,0xEE,0x19,0x2E,0x7F,0xC2,0x1E,0x42,0xF2,0x43,0xA0,0x19,
|
||||||
|
0x16,0x02,0x05,0xAB,0x10,0x8A,0x30,0x42,0xAD,0x14,0x83,0x8C,0x31,0xE8,0xCD,0x11,0x04,0xC5,0x60,0xA4,
|
||||||
|
0x10,0x12,0x49,0x0E,0x04,0x0C,0x23,0x10,0x43,0x12,0xD4,0x2B,0x83,0xC3,0x91,0xA6,0x05,0xC0,0x1C,0x6A,
|
||||||
|
0xF2,0x27,0xEC,0x21,0x7E,0xB7,0x41,0x0A,0x27,0x62,0xB6,0xC5,0x11,0x94,0x36,0x02,0x1A,0xA9,0x70,0x22,
|
||||||
|
0x06,0x05,0x96,0xEE,0x30,0x82,0x30,0x9C,0x36,0x61,0x0F,0xF1,0xBB,0x0D,0x52,0x38,0x11,0xB3,0x2D,0x8E,
|
||||||
|
0xA0,0xB4,0x11,0xD0,0x48,0x0B,0x30,0x11,0x28,0xC8,0xA4,0x93,0x81,0x00,0x00,0x00,0x13,0x14,0x72,0xC0,
|
||||||
|
0x87,0x74,0x60,0x87,0x36,0x68,0x87,0x79,0x68,0x03,0x72,0xC0,0x87,0x0D,0xAF,0x50,0x0E,0x6D,0xD0,0x0E,
|
||||||
|
0x7A,0x50,0x0E,0x6D,0x00,0x0F,0x7A,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0xA0,
|
||||||
|
0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x78,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x71,0x60,0x07,0x7A,
|
||||||
|
0x30,0x07,0x72,0xD0,0x06,0xE9,0x30,0x07,0x72,0xA0,0x07,0x73,0x20,0x07,0x6D,0x90,0x0E,0x76,0x40,0x07,
|
||||||
|
0x7A,0x60,0x07,0x74,0xD0,0x06,0xE6,0x10,0x07,0x76,0xA0,0x07,0x73,0x20,0x07,0x6D,0x60,0x0E,0x73,0x20,
|
||||||
|
0x07,0x7A,0x30,0x07,0x72,0xD0,0x06,0xE6,0x60,0x07,0x74,0xA0,0x07,0x76,0x40,0x07,0x6D,0xE0,0x0E,0x78,
|
||||||
|
0xA0,0x07,0x71,0x60,0x07,0x7A,0x30,0x07,0x72,0xA0,0x07,0x76,0x40,0x07,0x43,0x9E,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x3C,0x06,0x10,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x0C,0x79,0x10,0x20,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xF2,0x34,0x40,0x00,0x0C,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xE4,0x79,0x80,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,
|
||||||
|
0xC8,0x23,0x01,0x01,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x16,0x08,0x00,0x10,0x00,0x00,0x00,
|
||||||
|
0x32,0x1E,0x98,0x14,0x19,0x11,0x4C,0x90,0x8C,0x09,0x26,0x47,0xC6,0x04,0x43,0x22,0x25,0x30,0x02,0x50,
|
||||||
|
0x10,0xC5,0x50,0x80,0x01,0x65,0x50,0x1E,0x45,0x40,0xA5,0x24,0x46,0x00,0x8A,0xA0,0x10,0xCA,0x80,0xF0,
|
||||||
|
0x0C,0x00,0xED,0x19,0x00,0xE2,0x63,0x31,0x0A,0x03,0xE2,0x03,0x88,0x0F,0x00,0x10,0x08,0x04,0x02,0x81,
|
||||||
|
0x01,0x00,0x00,0x00,0x79,0x18,0x00,0x00,0x61,0x00,0x00,0x00,0x1A,0x03,0x4C,0x90,0x46,0x02,0x13,0xC4,
|
||||||
|
0x8E,0x0C,0x6F,0xEC,0xED,0x4D,0x0C,0x24,0xC6,0x05,0xC7,0x45,0xA6,0x06,0x46,0xC6,0x05,0x07,0x04,0x45,
|
||||||
|
0x8C,0xE6,0x26,0x26,0x06,0x67,0x26,0xA7,0x2C,0x65,0x43,0x10,0x4C,0x10,0x08,0x63,0x82,0x40,0x1C,0x1B,
|
||||||
|
0x84,0x81,0x98,0x20,0x10,0xC8,0x06,0x61,0x30,0x28,0xD8,0xCD,0x4D,0x10,0x88,0x64,0xC3,0x80,0x24,0xC4,
|
||||||
|
0x04,0x01,0x9B,0x08,0x4C,0x10,0x08,0x65,0x03,0x42,0x2C,0xCC,0x40,0x0C,0x0D,0x30,0x41,0xD8,0xA8,0x0D,
|
||||||
|
0xC8,0xF0,0x30,0xC3,0x30,0x18,0xC0,0x06,0xC1,0x81,0x36,0x10,0x00,0x10,0x01,0x13,0x04,0xAE,0xDA,0x10,
|
||||||
|
0x4C,0x13,0x04,0x01,0x20,0xD1,0x16,0x96,0xE6,0x46,0x84,0xAA,0x08,0x6B,0xE8,0xE9,0x49,0x8A,0x68,0x82,
|
||||||
|
0x50,0x38,0x13,0x84,0xE2,0xD9,0x10,0x10,0x13,0x84,0x02,0x9A,0x20,0x10,0xCB,0x06,0x81,0xE3,0x36,0x2C,
|
||||||
|
0xC4,0x85,0x65,0x5A,0x36,0x6C,0x44,0xD6,0x6D,0x08,0x86,0x09,0x42,0x11,0x4D,0x10,0x08,0x66,0x83,0xC0,
|
||||||
|
0x85,0xC1,0x86,0x65,0xB8,0xB0,0xEC,0xCB,0x06,0x30,0x18,0x32,0x31,0x98,0x20,0x10,0xCD,0x86,0x80,0x0C,
|
||||||
|
0x36,0x2C,0x64,0x70,0x61,0x59,0x19,0x64,0xC3,0x46,0x06,0x59,0xB7,0x61,0xF0,0xC6,0xC0,0x0C,0x36,0x2C,
|
||||||
|
0xC4,0x85,0x65,0xDA,0x36,0x80,0x01,0x91,0x89,0xC1,0x86,0x65,0xB8,0xB0,0xEC,0xDB,0x86,0x6D,0xC8,0x3A,
|
||||||
|
0x2E,0x53,0x56,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x13,0x84,0x42,0xDA,0xB0,0x90,0x81,0x1A,
|
||||||
|
0x60,0x6B,0xA0,0x81,0xC1,0x00,0x06,0x64,0x90,0x89,0xC1,0x86,0x01,0x0D,0xD2,0x80,0x0D,0x36,0x0C,0x67,
|
||||||
|
0xD0,0x06,0xC0,0x86,0xA2,0xB2,0xDC,0x40,0x02,0xAA,0xB0,0xB1,0xD9,0xB5,0xB9,0xA4,0x91,0x95,0xB9,0xD1,
|
||||||
|
0x4D,0x09,0x82,0x2A,0x64,0x78,0x2E,0x76,0x65,0x72,0x73,0x69,0x6F,0x6E,0x53,0x02,0xA2,0x09,0x19,0x9E,
|
||||||
|
0x8B,0x5D,0x18,0x9B,0x5D,0x99,0xDC,0x94,0xC0,0xA8,0x43,0x86,0xE7,0x32,0x87,0x16,0x46,0x56,0x26,0xD7,
|
||||||
|
0xF4,0x46,0x56,0xC6,0x36,0x25,0x48,0xCA,0x90,0xE1,0xB9,0xC8,0x95,0xCD,0xBD,0xD5,0xC9,0x8D,0x95,0xCD,
|
||||||
|
0x4D,0x09,0xA2,0x3A,0x64,0x78,0x2E,0x76,0x69,0x65,0x77,0x49,0x64,0x53,0x74,0x61,0x74,0x65,0x53,0x82,
|
||||||
|
0xA9,0x0E,0x19,0x9E,0x4B,0x99,0x1B,0x9D,0x5C,0x1E,0xD4,0x5B,0x9A,0x1B,0xDD,0xDC,0x94,0xC0,0x0D,0x00,
|
||||||
|
0x79,0x18,0x00,0x00,0x4C,0x00,0x00,0x00,0x33,0x08,0x80,0x1C,0xC4,0xE1,0x1C,0x66,0x14,0x01,0x3D,0x88,
|
||||||
|
0x43,0x38,0x84,0xC3,0x8C,0x42,0x80,0x07,0x79,0x78,0x07,0x73,0x98,0x71,0x0C,0xE6,0x00,0x0F,0xED,0x10,
|
||||||
|
0x0E,0xF4,0x80,0x0E,0x33,0x0C,0x42,0x1E,0xC2,0xC1,0x1D,0xCE,0xA1,0x1C,0x66,0x30,0x05,0x3D,0x88,0x43,
|
||||||
|
0x38,0x84,0x83,0x1B,0xCC,0x03,0x3D,0xC8,0x43,0x3D,0x8C,0x03,0x3D,0xCC,0x78,0x8C,0x74,0x70,0x07,0x7B,
|
||||||
|
0x08,0x07,0x79,0x48,0x87,0x70,0x70,0x07,0x7A,0x70,0x03,0x76,0x78,0x87,0x70,0x20,0x87,0x19,0xCC,0x11,
|
||||||
|
0x0E,0xEC,0x90,0x0E,0xE1,0x30,0x0F,0x6E,0x30,0x0F,0xE3,0xF0,0x0E,0xF0,0x50,0x0E,0x33,0x10,0xC4,0x1D,
|
||||||
|
0xDE,0x21,0x1C,0xD8,0x21,0x1D,0xC2,0x61,0x1E,0x66,0x30,0x89,0x3B,0xBC,0x83,0x3B,0xD0,0x43,0x39,0xB4,
|
||||||
|
0x03,0x3C,0xBC,0x83,0x3C,0x84,0x03,0x3B,0xCC,0xF0,0x14,0x76,0x60,0x07,0x7B,0x68,0x07,0x37,0x68,0x87,
|
||||||
|
0x72,0x68,0x07,0x37,0x80,0x87,0x70,0x90,0x87,0x70,0x60,0x07,0x76,0x28,0x07,0x76,0xF8,0x05,0x76,0x78,
|
||||||
|
0x87,0x77,0x80,0x87,0x5F,0x08,0x87,0x71,0x18,0x87,0x72,0x98,0x87,0x79,0x98,0x81,0x2C,0xEE,0xF0,0x0E,
|
||||||
|
0xEE,0xE0,0x0E,0xF5,0xC0,0x0E,0xEC,0x30,0x03,0x62,0xC8,0xA1,0x1C,0xE4,0xA1,0x1C,0xCC,0xA1,0x1C,0xE4,
|
||||||
|
0xA1,0x1C,0xDC,0x61,0x1C,0xCA,0x21,0x1C,0xC4,0x81,0x1D,0xCA,0x61,0x06,0xD6,0x90,0x43,0x39,0xC8,0x43,
|
||||||
|
0x39,0x98,0x43,0x39,0xC8,0x43,0x39,0xB8,0xC3,0x38,0x94,0x43,0x38,0x88,0x03,0x3B,0x94,0xC3,0x2F,0xBC,
|
||||||
|
0x83,0x3C,0xFC,0x82,0x3B,0xD4,0x03,0x3B,0xB0,0xC3,0x8C,0xC8,0x21,0x07,0x7C,0x70,0x03,0x72,0x10,0x87,
|
||||||
|
0x73,0x70,0x03,0x7B,0x08,0x07,0x79,0x60,0x87,0x70,0xC8,0x87,0x77,0xA8,0x07,0x7A,0x98,0x81,0x3C,0xE4,
|
||||||
|
0x80,0x0F,0x6E,0x40,0x0F,0xE5,0xD0,0x0E,0xF0,0x00,0x00,0x00,0x71,0x20,0x00,0x00,0x18,0x00,0x00,0x00,
|
||||||
|
0x36,0xB0,0x0D,0x97,0xEF,0x3C,0xBE,0x10,0x50,0x45,0x41,0x44,0xA5,0x03,0x0C,0x25,0x61,0x00,0x02,0xE6,
|
||||||
|
0x17,0xB7,0x6D,0x05,0xD2,0x70,0xF9,0xCE,0xE3,0x0B,0x11,0x01,0x4C,0x44,0x08,0x34,0xC3,0x42,0x58,0xC0,
|
||||||
|
0x34,0x5C,0xBE,0xF3,0xF8,0x8B,0x03,0x0C,0x62,0xF3,0x50,0x93,0x5F,0xDC,0xB6,0x09,0x54,0xC3,0xE5,0x3B,
|
||||||
|
0x8F,0x2F,0x4D,0x4E,0x44,0xA0,0xD4,0xF4,0x50,0x93,0x5F,0xDC,0xB6,0x11,0x48,0xC3,0xE5,0x3B,0x8F,0x3F,
|
||||||
|
0x11,0xD1,0x84,0x00,0x11,0xE6,0x17,0xB7,0x6D,0x00,0x04,0x03,0x20,0x0D,0x00,0x00,0x61,0x20,0x00,0x00,
|
||||||
|
0x7D,0x00,0x00,0x00,0x13,0x04,0x41,0x2C,0x10,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x44,0x4A,0xA1,0x10,
|
||||||
|
0x66,0x00,0xCA,0xAE,0xB8,0x4A,0x8E,0x4A,0x09,0x50,0x1C,0x01,0x00,0x00,0x00,0x00,0x23,0x06,0x09,0x00,
|
||||||
|
0x82,0x60,0x20,0x65,0x83,0x83,0x61,0xC1,0x88,0x41,0x02,0x80,0x20,0x18,0x48,0x1A,0xF1,0x60,0x98,0x30,
|
||||||
|
0x62,0x90,0x00,0x20,0x08,0x06,0xC6,0x97,0x4C,0x59,0x84,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x01,0x06,
|
||||||
|
0x0A,0xA5,0x15,0xC9,0x88,0x41,0x02,0x80,0x20,0x18,0x18,0x61,0xB0,0x70,0xDB,0xA4,0x8C,0x18,0x24,0x00,
|
||||||
|
0x08,0x82,0x81,0x21,0x06,0x4C,0xC7,0x1D,0xCB,0x88,0x41,0x02,0x80,0x20,0x18,0x18,0x63,0xD0,0x78,0x1D,
|
||||||
|
0xC5,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x41,0x06,0xCE,0xE7,0x4D,0xCD,0x88,0x41,0x02,0x80,0x20,0x18,
|
||||||
|
0x18,0x65,0xF0,0x7C,0xDF,0xE5,0x8C,0x18,0x24,0x00,0x08,0x82,0x81,0x61,0x06,0x10,0x18,0x80,0xC1,0xF2,
|
||||||
|
0x8C,0x18,0x1C,0x00,0x08,0x82,0x41,0x53,0x06,0x8F,0x12,0x06,0xA3,0x09,0x01,0x30,0x9A,0x20,0x04,0x26,
|
||||||
|
0x14,0xF0,0x31,0xA1,0x80,0xCF,0x88,0xC1,0x01,0x80,0x20,0x18,0x34,0x6A,0x40,0x39,0x66,0x30,0x9A,0x10,
|
||||||
|
0x00,0xA3,0x09,0x42,0x30,0x9A,0x30,0x08,0xA3,0x09,0xC4,0x30,0x62,0x70,0x00,0x20,0x08,0x06,0xCD,0x1B,
|
||||||
|
0x64,0x13,0x1B,0x8C,0x26,0x04,0xC0,0x68,0x82,0x10,0x8C,0x26,0x0C,0xC2,0x68,0x02,0x31,0x8C,0x18,0x1C,
|
||||||
|
0x00,0x08,0x82,0x41,0x43,0x07,0x1E,0xC6,0x06,0xA3,0x09,0x01,0x30,0x9A,0x20,0x04,0xA3,0x09,0x83,0x30,
|
||||||
|
0x9A,0x40,0x0C,0xE6,0x44,0xF2,0x19,0x31,0x40,0x00,0x10,0x04,0x83,0x27,0x0F,0xC6,0x40,0x89,0x02,0x33,
|
||||||
|
0x02,0xE8,0x18,0x44,0xC9,0x67,0xC4,0x00,0x01,0x40,0x10,0x0C,0x1E,0x3E,0x30,0x03,0x86,0x0A,0x2C,0x40,
|
||||||
|
0xA0,0x63,0xD2,0x25,0x9F,0x11,0x03,0x04,0x00,0x41,0x30,0x78,0xFE,0x20,0x0D,0x9C,0x2B,0xB0,0x40,0x81,
|
||||||
|
0x8E,0x51,0x9A,0x7C,0x46,0x0C,0x10,0x00,0x04,0xC1,0xE0,0x11,0x05,0x36,0x80,0xB4,0xC0,0x02,0x06,0x3A,
|
||||||
|
0x23,0x06,0x09,0x00,0x82,0x60,0x80,0x98,0x82,0x1C,0x84,0x42,0x28,0xE4,0x81,0x19,0x8C,0x18,0x24,0x00,
|
||||||
|
0x08,0x82,0x01,0x62,0x0A,0x72,0x10,0x0A,0xA1,0xC0,0x06,0x65,0x30,0x62,0x90,0x00,0x20,0x08,0x06,0x88,
|
||||||
|
0x29,0xC8,0x41,0x28,0x84,0x02,0x1E,0x90,0xC1,0x88,0x41,0x02,0x80,0x20,0x18,0x20,0xA6,0x20,0x07,0xA1,
|
||||||
|
0x10,0x0A,0x76,0x30,0x06,0x23,0x06,0x09,0x00,0x82,0x60,0x80,0x98,0x82,0x1C,0x88,0x42,0x28,0xE4,0x01,
|
||||||
|
0x1A,0x8C,0x18,0x24,0x00,0x08,0x82,0x01,0x62,0x0A,0x72,0x20,0x0A,0xA1,0xC0,0x06,0x67,0x30,0x62,0x90,
|
||||||
|
0x00,0x20,0x08,0x06,0x88,0x29,0xC8,0xC1,0x1E,0x84,0x42,0x1E,0x28,0x23,0x06,0x09,0x00,0x82,0x60,0x80,
|
||||||
|
0x98,0x82,0x1C,0xEC,0x41,0x28,0xB0,0xC1,0x31,0x62,0x90,0x00,0x20,0x08,0x06,0x88,0x29,0xC8,0xC1,0x1E,
|
||||||
|
0x84,0x02,0x1E,0x10,0x23,0x06,0x09,0x00,0x82,0x60,0x80,0x98,0x82,0x1C,0xEC,0x41,0x28,0xD8,0x41,0x80,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
};
|
||||||
58
vendor/rmlui_backend/RmlUi_SDL_GPU/compile_shaders.py
vendored
Normal file
58
vendor/rmlui_backend/RmlUi_SDL_GPU/compile_shaders.py
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# Compiles all .frag and .vert files in this directory to SPIR-V, MSL, and DXIL binary C character arrays.
|
||||||
|
#
|
||||||
|
# Requires the SDL_shadercross tool. Binaries can be found here: https://github.com/libsdl-org/SDL_shadercross/actions
|
||||||
|
# Click on the latest workflow and download them for the platform of your choice.
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python compile_shaders.py <shadercross_path>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
out_file = "ShadersCompiledSPV.h"
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(os.path.realpath(__file__));
|
||||||
|
shadercross_path = os.path.realpath(sys.argv[1])
|
||||||
|
|
||||||
|
if not os.path.isfile(shadercross_path):
|
||||||
|
print(f"Error: The specified shadercross path '{shadercross_path}' does not exist.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
out_path = os.path.join(current_dir, out_file)
|
||||||
|
|
||||||
|
with open(out_path,'w') as result_file:
|
||||||
|
result_file.write('// RmlUi SDL GPU shaders compiled using command: \'python compile_shaders.py\'. Do not edit manually.\n\n#include <stdint.h>\n')
|
||||||
|
|
||||||
|
for file in os.listdir(current_dir):
|
||||||
|
if file.endswith(".vert") or file.endswith(".frag"):
|
||||||
|
shader_path = os.path.join(current_dir, file)
|
||||||
|
|
||||||
|
def compile(target):
|
||||||
|
print("Compiling '{}' to '{}' using SDL_shadercross.".format(file, target))
|
||||||
|
|
||||||
|
variable_name = "{}_{}".format(os.path.splitext(file)[0], target)
|
||||||
|
temp_path = os.path.join(current_dir, ".temp.{}".format(target))
|
||||||
|
|
||||||
|
print(temp_path)
|
||||||
|
|
||||||
|
subprocess.run([shadercross_path, "-s", "hlsl", shader_path, "-o", temp_path, "-d", target], check = True)
|
||||||
|
|
||||||
|
print("Success, writing output to variable '{}' in {}".format(variable_name, out_file))
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
result_file.write('\nalignas(uint32_t) static const unsigned char {}[] = {{'.format(variable_name))
|
||||||
|
for b in open(temp_path, 'rb').read():
|
||||||
|
if i % 20 == 0:
|
||||||
|
result_file.write('\n\t')
|
||||||
|
result_file.write('0x%02X,' % b)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
result_file.write('\n};\n')
|
||||||
|
|
||||||
|
os.remove(temp_path)
|
||||||
|
|
||||||
|
compile("spirv")
|
||||||
|
compile("msl")
|
||||||
|
compile("dxil")
|
||||||
3
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_frag_color.frag
vendored
Normal file
3
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_frag_color.frag
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
float4 main(float4 Color : TEXCOORD0) : SV_Target0 {
|
||||||
|
return Color;
|
||||||
|
}
|
||||||
8
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_frag_texture.frag
vendored
Normal file
8
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_frag_texture.frag
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Texture2D<float4> Texture : register(t0, space2);
|
||||||
|
SamplerState Sampler : register(s0, space2);
|
||||||
|
|
||||||
|
// NOTE: Seems like TEXCOORD0 is getting optimized out and TEXCOORD1 is taking its spot
|
||||||
|
// Might need to fix when later versions of SDL_shadercross preserve unused bindings
|
||||||
|
float4 main(float4 Color : TEXCOORD0, float2 TexCoord : TEXCOORD1) : SV_Target0 {
|
||||||
|
return Color * Texture.Sample(Sampler, TexCoord);
|
||||||
|
}
|
||||||
28
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_vert.vert
vendored
Normal file
28
vendor/rmlui_backend/RmlUi_SDL_GPU/shader_vert.vert
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
cbuffer UniformBlockTransform : register(b0, space1) {
|
||||||
|
float4x4 Transform : packoffset(c0);
|
||||||
|
};
|
||||||
|
|
||||||
|
cbuffer UniformBlockTranslate : register(b1, space1) {
|
||||||
|
float2 Translate : packoffset(c0);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
float2 Position : TEXCOORD0;
|
||||||
|
float4 InColor : TEXCOORD1;
|
||||||
|
float2 TexCoord : TEXCOORD2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Output {
|
||||||
|
float4 Color : TEXCOORD0;
|
||||||
|
float2 TexCoord : TEXCOORD1;
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
Output main(Input input) {
|
||||||
|
Output output;
|
||||||
|
output.TexCoord = input.TexCoord;
|
||||||
|
output.Color = input.InColor;
|
||||||
|
float4 position = float4(input.Position + Translate, 0, 1);
|
||||||
|
output.Position = mul(Transform, position);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
2
vendor/rmlui_backend/RmlUi_Vulkan/.clang-format
vendored
Normal file
2
vendor/rmlui_backend/RmlUi_Vulkan/.clang-format
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DisableFormat: true
|
||||||
|
SortIncludes: Never
|
||||||
29
vendor/rmlui_backend/RmlUi_Vulkan/LICENSE.txt
vendored
Normal file
29
vendor/rmlui_backend/RmlUi_Vulkan/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
The Vulkan backend for RmlUi includes the third-party dependency:
|
||||||
|
|
||||||
|
Vulkan Memory Allocator
|
||||||
|
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
|
||||||
|
|
||||||
|
This dependency is located in the file 'vk_mem_alloc.h' and is licensed
|
||||||
|
separately from Rmlui. The license of this dependency is recited below.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Copyright (c) 2017-2022 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
180
vendor/rmlui_backend/RmlUi_Vulkan/ShadersCompiledSPV.h
vendored
Normal file
180
vendor/rmlui_backend/RmlUi_Vulkan/ShadersCompiledSPV.h
vendored
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
// RmlUi SPIR-V Vulkan shaders compiled using command: 'python compile_shaders.py'. Do not edit manually.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_color[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x0A,0x00,0x0D,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0B,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x47,0x4C,0x53,0x4C,
|
||||||
|
0x2E,0x73,0x74,0x64,0x2E,0x34,0x35,0x30,0x00,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x0F,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,
|
||||||
|
0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x10,0x00,0x03,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x4A,0x01,0x00,0x00,
|
||||||
|
0x04,0x00,0x09,0x00,0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x65,0x5F,
|
||||||
|
0x73,0x68,0x61,0x64,0x65,0x72,0x5F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x73,0x00,0x00,0x04,0x00,0x09,0x00,
|
||||||
|
0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x68,0x61,0x64,0x69,0x6E,0x67,0x5F,0x6C,0x61,0x6E,0x67,0x75,
|
||||||
|
0x61,0x67,0x65,0x5F,0x34,0x32,0x30,0x70,0x61,0x63,0x6B,0x00,0x04,0x00,0x0A,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x63,0x70,0x70,0x5F,0x73,0x74,0x79,0x6C,0x65,0x5F,0x6C,0x69,0x6E,0x65,
|
||||||
|
0x5F,0x64,0x69,0x72,0x65,0x63,0x74,0x69,0x76,0x65,0x00,0x00,0x04,0x00,0x08,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x5F,0x64,0x69,0x72,0x65,0x63,0x74,
|
||||||
|
0x69,0x76,0x65,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x66,0x69,0x6E,0x61,0x6C,0x43,0x6F,0x6C,0x6F,0x72,0x00,0x00,
|
||||||
|
0x05,0x00,0x05,0x00,0x0B,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x43,0x6F,0x6C,0x6F,0x72,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x06,0x00,0x0F,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x54,0x65,0x78,0x43,0x6F,0x6F,0x72,0x64,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x0F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0A,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0A,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x0E,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xF8,0x00,0x02,0x00,0x05,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,
|
||||||
|
0x09,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_frag_texture[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x0A,0x00,0x0D,0x00,0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0B,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x47,0x4C,0x53,0x4C,
|
||||||
|
0x2E,0x73,0x74,0x64,0x2E,0x34,0x35,0x30,0x00,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x0F,0x00,0x08,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,
|
||||||
|
0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x10,0x00,0x03,0x00,
|
||||||
|
0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x4A,0x01,0x00,0x00,
|
||||||
|
0x04,0x00,0x09,0x00,0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x65,0x5F,
|
||||||
|
0x73,0x68,0x61,0x64,0x65,0x72,0x5F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x73,0x00,0x00,0x04,0x00,0x09,0x00,
|
||||||
|
0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x68,0x61,0x64,0x69,0x6E,0x67,0x5F,0x6C,0x61,0x6E,0x67,0x75,
|
||||||
|
0x61,0x67,0x65,0x5F,0x34,0x32,0x30,0x70,0x61,0x63,0x6B,0x00,0x04,0x00,0x0A,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x63,0x70,0x70,0x5F,0x73,0x74,0x79,0x6C,0x65,0x5F,0x6C,0x69,0x6E,0x65,
|
||||||
|
0x5F,0x64,0x69,0x72,0x65,0x63,0x74,0x69,0x76,0x65,0x00,0x00,0x04,0x00,0x08,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x5F,0x64,0x69,0x72,0x65,0x63,0x74,
|
||||||
|
0x69,0x76,0x65,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x74,0x65,0x78,0x43,0x6F,0x6C,0x6F,0x72,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x5F,0x74,0x65,0x78,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,
|
||||||
|
0x11,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x54,0x65,0x78,0x43,0x6F,0x6F,0x72,0x64,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x66,0x69,0x6E,0x61,0x6C,0x43,0x6F,0x6C,0x6F,0x72,0x00,0x00,
|
||||||
|
0x05,0x00,0x05,0x00,0x17,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x43,0x6F,0x6C,0x6F,0x72,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x0D,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x15,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x19,0x00,0x09,0x00,0x0A,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x1B,0x00,0x03,0x00,0x0B,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0C,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0C,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x0F,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x14,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x14,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
|
||||||
|
0x03,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x3B,0x00,0x04,0x00,0x16,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x36,0x00,0x05,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xF8,0x00,0x02,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x0F,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x57,0x00,0x05,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x13,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x09,0x00,0x00,0x00,
|
||||||
|
0x13,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
|
||||||
|
0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x85,0x00,0x05,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,
|
||||||
|
0x15,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
alignas(uint32_t) static const unsigned char shader_vert[] = {
|
||||||
|
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x0A,0x00,0x0D,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0B,0x00,0x06,0x00,0x01,0x00,0x00,0x00,0x47,0x4C,0x53,0x4C,
|
||||||
|
0x2E,0x73,0x74,0x64,0x2E,0x34,0x35,0x30,0x00,0x00,0x00,0x00,0x0E,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x0F,0x00,0x0B,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,
|
||||||
|
0x00,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x15,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x4A,0x01,0x00,0x00,
|
||||||
|
0x04,0x00,0x09,0x00,0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x65,0x5F,
|
||||||
|
0x73,0x68,0x61,0x64,0x65,0x72,0x5F,0x6F,0x62,0x6A,0x65,0x63,0x74,0x73,0x00,0x00,0x04,0x00,0x09,0x00,
|
||||||
|
0x47,0x4C,0x5F,0x41,0x52,0x42,0x5F,0x73,0x68,0x61,0x64,0x69,0x6E,0x67,0x5F,0x6C,0x61,0x6E,0x67,0x75,
|
||||||
|
0x61,0x67,0x65,0x5F,0x34,0x32,0x30,0x70,0x61,0x63,0x6B,0x00,0x04,0x00,0x0A,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x63,0x70,0x70,0x5F,0x73,0x74,0x79,0x6C,0x65,0x5F,0x6C,0x69,0x6E,0x65,
|
||||||
|
0x5F,0x64,0x69,0x72,0x65,0x63,0x74,0x69,0x76,0x65,0x00,0x00,0x04,0x00,0x08,0x00,0x47,0x4C,0x5F,0x47,
|
||||||
|
0x4F,0x4F,0x47,0x4C,0x45,0x5F,0x69,0x6E,0x63,0x6C,0x75,0x64,0x65,0x5F,0x64,0x69,0x72,0x65,0x63,0x74,
|
||||||
|
0x69,0x76,0x65,0x00,0x05,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x6D,0x61,0x69,0x6E,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x06,0x00,0x09,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x54,0x65,0x78,0x43,0x6F,0x6F,0x72,0x64,
|
||||||
|
0x00,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x0B,0x00,0x00,0x00,0x69,0x6E,0x54,0x65,0x78,0x43,0x6F,0x6F,
|
||||||
|
0x72,0x64,0x30,0x00,0x05,0x00,0x05,0x00,0x0F,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x43,0x6F,0x6C,0x6F,
|
||||||
|
0x72,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x11,0x00,0x00,0x00,0x69,0x6E,0x43,0x6F,0x6C,0x6F,0x72,0x30,
|
||||||
|
0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x14,0x00,0x00,0x00,0x74,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,
|
||||||
|
0x65,0x64,0x50,0x6F,0x73,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x15,0x00,0x00,0x00,0x69,0x6E,0x50,0x6F,
|
||||||
|
0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,0x00,0x05,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x55,0x73,0x65,0x72,
|
||||||
|
0x44,0x61,0x74,0x61,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x6D,0x5F,0x74,0x72,0x61,0x6E,0x73,0x66,0x6F,0x72,0x6D,0x00,0x06,0x00,0x06,0x00,0x18,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x6D,0x5F,0x74,0x72,0x61,0x6E,0x73,0x6C,0x61,0x74,0x65,0x00,0x05,0x00,0x05,0x00,
|
||||||
|
0x1A,0x00,0x00,0x00,0x75,0x73,0x65,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00,0x05,0x00,0x04,0x00,
|
||||||
|
0x22,0x00,0x00,0x00,0x6F,0x75,0x74,0x50,0x6F,0x73,0x00,0x00,0x05,0x00,0x06,0x00,0x31,0x00,0x00,0x00,
|
||||||
|
0x67,0x6C,0x5F,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,
|
||||||
|
0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x6C,0x5F,0x50,0x6F,0x73,0x69,0x74,0x69,0x6F,0x6E,0x00,
|
||||||
|
0x06,0x00,0x07,0x00,0x31,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x67,0x6C,0x5F,0x50,0x6F,0x69,0x6E,0x74,
|
||||||
|
0x53,0x69,0x7A,0x65,0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x67,0x6C,0x5F,0x43,0x6C,0x69,0x70,0x44,0x69,0x73,0x74,0x61,0x6E,0x63,0x65,0x00,0x05,0x00,0x03,0x00,
|
||||||
|
0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x0B,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x47,0x00,0x04,0x00,0x0F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x11,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x15,0x00,0x00,0x00,
|
||||||
|
0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x10,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x18,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x23,0x00,0x00,0x00,
|
||||||
|
0x40,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
|
||||||
|
0x1A,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1A,0x00,0x00,0x00,
|
||||||
|
0x21,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x31,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x0B,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x0B,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x31,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x13,0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x16,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x0A,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x0A,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,
|
||||||
|
0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x0D,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0E,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,
|
||||||
|
0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x13,0x00,0x00,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x0A,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x18,0x00,0x04,0x00,0x17,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
|
||||||
|
0x1E,0x00,0x04,0x00,0x18,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
|
||||||
|
0x19,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x19,0x00,0x00,0x00,
|
||||||
|
0x1A,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x1B,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,0x1B,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
|
||||||
|
0x20,0x00,0x04,0x00,0x1D,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
|
||||||
|
0x21,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,0x1B,0x00,0x00,0x00,
|
||||||
|
0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x24,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
|
||||||
|
0x17,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x2B,0x00,0x04,0x00,0x06,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x00,0x00,0x80,0x3F,0x15,0x00,0x04,0x00,
|
||||||
|
0x2E,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2B,0x00,0x04,0x00,0x2E,0x00,0x00,0x00,
|
||||||
|
0x2F,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1C,0x00,0x04,0x00,0x30,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x2F,0x00,0x00,0x00,0x1E,0x00,0x05,0x00,0x31,0x00,0x00,0x00,0x0D,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
|
||||||
|
0x30,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x31,0x00,0x00,0x00,
|
||||||
|
0x3B,0x00,0x04,0x00,0x32,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x36,0x00,0x05,0x00,
|
||||||
|
0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xF8,0x00,0x02,0x00,
|
||||||
|
0x05,0x00,0x00,0x00,0x3B,0x00,0x04,0x00,0x13,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x3B,0x00,0x04,0x00,0x21,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x07,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x0B,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x09,0x00,0x00,0x00,
|
||||||
|
0x0C,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
|
||||||
|
0x3E,0x00,0x03,0x00,0x0F,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x16,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x1D,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,
|
||||||
|
0x1A,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,
|
||||||
|
0x1E,0x00,0x00,0x00,0x81,0x00,0x05,0x00,0x07,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x16,0x00,0x00,0x00,
|
||||||
|
0x1F,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x14,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x41,0x00,0x05,0x00,
|
||||||
|
0x24,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x1A,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,
|
||||||
|
0x17,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
|
||||||
|
0x27,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2A,0x00,0x00,0x00,
|
||||||
|
0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x06,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,
|
||||||
|
0x27,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x50,0x00,0x07,0x00,0x0D,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,
|
||||||
|
0x2A,0x00,0x00,0x00,0x2B,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x91,0x00,0x05,0x00,
|
||||||
|
0x0D,0x00,0x00,0x00,0x2D,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x2C,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,
|
||||||
|
0x22,0x00,0x00,0x00,0x2D,0x00,0x00,0x00,0x3D,0x00,0x04,0x00,0x0D,0x00,0x00,0x00,0x34,0x00,0x00,0x00,
|
||||||
|
0x22,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x0E,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x33,0x00,0x00,0x00,
|
||||||
|
0x23,0x00,0x00,0x00,0x3E,0x00,0x03,0x00,0x35,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0xFD,0x00,0x01,0x00,
|
||||||
|
0x38,0x00,0x01,0x00,
|
||||||
|
};
|
||||||
38
vendor/rmlui_backend/RmlUi_Vulkan/compile_shaders.py
vendored
Normal file
38
vendor/rmlui_backend/RmlUi_Vulkan/compile_shaders.py
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# Compiles all .frag and .vert files in this directory to SPIR-V binary C character arrays. Requires 'glslc' installed and available system-wide.
|
||||||
|
|
||||||
|
out_file = "ShadersCompiledSPV.h"
|
||||||
|
|
||||||
|
current_dir = os.path.dirname(os.path.realpath(__file__));
|
||||||
|
|
||||||
|
temp_spirv_path = os.path.join(current_dir, ".temp.spv")
|
||||||
|
out_path = os.path.join(current_dir, out_file)
|
||||||
|
|
||||||
|
with open(out_path,'w') as result_file:
|
||||||
|
result_file.write('// RmlUi SPIR-V Vulkan shaders compiled using command: \'python compile_shaders.py\'. Do not edit manually.\n\n#include <stdint.h>\n')
|
||||||
|
|
||||||
|
for file in os.listdir(current_dir):
|
||||||
|
if file.endswith(".vert") or file.endswith(".frag"):
|
||||||
|
shader_path = os.path.join(current_dir, file)
|
||||||
|
variable_name = os.path.splitext(file)[0]
|
||||||
|
|
||||||
|
print("Compiling '{}' to SPIR-V using glslc.".format(file))
|
||||||
|
|
||||||
|
subprocess.run(["glslc", shader_path, "-o", temp_spirv_path], check = True)
|
||||||
|
|
||||||
|
print("Success, writing output to variable '{}' in {}".format(variable_name, out_file))
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
result_file.write('\nalignas(uint32_t) static const unsigned char {}[] = {{'.format(variable_name))
|
||||||
|
for b in open(temp_spirv_path, 'rb').read():
|
||||||
|
if i % 20 == 0:
|
||||||
|
result_file.write('\n\t')
|
||||||
|
result_file.write('0x%02X,' % b)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
result_file.write('\n};\n')
|
||||||
|
|
||||||
|
os.remove(temp_spirv_path)
|
||||||
12
vendor/rmlui_backend/RmlUi_Vulkan/shader_frag_color.frag
vendored
Normal file
12
vendor/rmlui_backend/RmlUi_Vulkan/shader_frag_color.frag
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
#extension GL_ARB_shading_language_420pack : enable
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 fragTexCoord;
|
||||||
|
layout (location = 1) in vec4 fragColor;
|
||||||
|
layout (location = 0) out vec4 finalColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
finalColor = fragColor;
|
||||||
|
}
|
||||||
15
vendor/rmlui_backend/RmlUi_Vulkan/shader_frag_texture.frag
vendored
Normal file
15
vendor/rmlui_backend/RmlUi_Vulkan/shader_frag_texture.frag
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
#extension GL_ARB_shading_language_420pack : enable
|
||||||
|
|
||||||
|
layout(set=1, binding=2) uniform sampler2D _tex;
|
||||||
|
layout (location = 0) in vec2 fragTexCoord;
|
||||||
|
layout (location = 1) in vec4 fragColor;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 finalColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 texColor = texture(_tex, fragTexCoord);
|
||||||
|
finalColor = fragColor * texColor;
|
||||||
|
}
|
||||||
25
vendor/rmlui_backend/RmlUi_Vulkan/shader_vert.vert
vendored
Normal file
25
vendor/rmlui_backend/RmlUi_Vulkan/shader_vert.vert
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
#extension GL_ARB_shading_language_420pack : enable
|
||||||
|
|
||||||
|
layout(set=0, binding=1) uniform UserData
|
||||||
|
{
|
||||||
|
mat4 m_transform;
|
||||||
|
vec2 m_translate;
|
||||||
|
} userdata;
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 inPosition;
|
||||||
|
layout (location = 1) in vec4 inColor0;
|
||||||
|
layout (location = 2) in vec2 inTexCoord0;
|
||||||
|
|
||||||
|
layout (location = 0) out vec2 fragTexCoord;
|
||||||
|
layout (location = 1) out vec4 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
fragTexCoord = inTexCoord0;
|
||||||
|
fragColor = inColor0;
|
||||||
|
vec2 translatedPos = inPosition + userdata.m_translate.xy;
|
||||||
|
vec4 outPos = userdata.m_transform * vec4(translatedPos, 0, 1);
|
||||||
|
gl_Position = outPos;
|
||||||
|
}
|
||||||
19558
vendor/rmlui_backend/RmlUi_Vulkan/vk_mem_alloc.h
vendored
Normal file
19558
vendor/rmlui_backend/RmlUi_Vulkan/vk_mem_alloc.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4486
vendor/rmlui_backend/RmlUi_Vulkan/vulkan.h
vendored
Normal file
4486
vendor/rmlui_backend/RmlUi_Vulkan/vulkan.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user