gradients done, found some transform issues, added a testing rml file
This commit is contained in:
100
assets/main.rcss
100
assets/main.rcss
@@ -20,11 +20,21 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div, section, article, header, footer, main, nav, aside {
|
||||
div,
|
||||
section,
|
||||
article,
|
||||
header,
|
||||
footer,
|
||||
main,
|
||||
nav,
|
||||
aside {
|
||||
display: block;
|
||||
}
|
||||
|
||||
span, em, strong, a {
|
||||
span,
|
||||
em,
|
||||
strong,
|
||||
a {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@@ -34,18 +44,40 @@ p {
|
||||
margin: 1em 0px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
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; }
|
||||
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;
|
||||
@@ -72,7 +104,8 @@ blockquote {
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
code,
|
||||
pre {
|
||||
font-family: "rmlui-debugger-font";
|
||||
background-color: #606060;
|
||||
color: #000000;
|
||||
@@ -88,7 +121,8 @@ pre {
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
ul, ol {
|
||||
ul,
|
||||
ol {
|
||||
display: block;
|
||||
margin: 1em 0px;
|
||||
padding-left: 40px;
|
||||
@@ -109,7 +143,8 @@ tr {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
td, th {
|
||||
td,
|
||||
th {
|
||||
display: table-cell;
|
||||
padding: 4px 8px;
|
||||
text-align: left;
|
||||
@@ -128,14 +163,19 @@ colgroup {
|
||||
display: table-column-group;
|
||||
}
|
||||
|
||||
thead, tbody, tfoot {
|
||||
thead,
|
||||
tbody,
|
||||
tfoot {
|
||||
display: table-row-group;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Form Inputs & Interactive UI Components
|
||||
========================================================================== */
|
||||
button, input, select, textarea {
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
display: inline-block;
|
||||
font-family: "rmlui-debugger-font";
|
||||
font-size: 14px;
|
||||
@@ -144,7 +184,9 @@ button, input, select, textarea {
|
||||
}
|
||||
|
||||
/* Traditional gray bevel button style */
|
||||
button, input[type="submit"], input[type="button"] {
|
||||
button,
|
||||
input[type="submit"],
|
||||
input[type="button"] {
|
||||
padding: 4px 12px;
|
||||
min-width: 40px;
|
||||
background-color: #e1e1e1;
|
||||
@@ -153,25 +195,33 @@ button, input[type="submit"], input[type="button"] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button:hover, input[type="submit"]:hover, input[type="button"]:hover {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus {
|
||||
border: 1px #005aff;
|
||||
}
|
||||
|
||||
@@ -214,7 +264,8 @@ tab {
|
||||
|
||||
tab:selected {
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px #ffffff; /* Overlap the bottom border line */
|
||||
border-bottom: 1px #ffffff;
|
||||
/* Overlap the bottom border line */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -236,7 +287,8 @@ progress {
|
||||
progress-value {
|
||||
display: block;
|
||||
height: 100%;
|
||||
background-color: #0078d7; /* Classic Windows Blue fill */
|
||||
background-color: #0078d7;
|
||||
/* Classic Windows Blue fill */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@@ -265,3 +317,9 @@ progress-value {
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.gradient-test {
|
||||
decorator: linear-gradient(to right, #000000, #ffffff);
|
||||
}
|
||||
@@ -1,12 +1,17 @@
|
||||
<rml>
|
||||
|
||||
<head>
|
||||
<title>RmlUi Raylib</title>
|
||||
<link type="text/rcss" href="main.rcss" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hello from RmlUi</h1>
|
||||
<div style="position: relative; width: 300px; height: 200px; overflow: hidden; border-radius: 40px; background-color: #0000ff">
|
||||
<div style="position: absolute; top: -20px; left: -20px; width: 150px; height: 150px; background-color: #ff0000; transform: rotate(15deg);"></div>
|
||||
<div style="position: relative; width: 300px; height: 200px; overflow: hidden; border-radius: 40px;"
|
||||
class="gradient-test">
|
||||
<div
|
||||
style="position: absolute; top: -20px; left: -20px; width: 150px; height: 150px; background-color: #ff0000; transform: rotate(15deg);">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</rml>
|
||||
262
assets/tests.rml
Normal file
262
assets/tests.rml
Normal file
@@ -0,0 +1,262 @@
|
||||
<rml>
|
||||
|
||||
<head>
|
||||
<title>RmlUi Raylib Render Interface — Feature Tests</title>
|
||||
<style>
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
background-color: #101010aa;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-family: "rmlui-debugger-font";
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
width: 140px;
|
||||
height: 100px;
|
||||
margin-right: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* Basic rendering */
|
||||
.basic-solid {
|
||||
background-color: #3060ff;
|
||||
}
|
||||
|
||||
.basic-border {
|
||||
background-color: #202020;
|
||||
border: 4px #ffcc00;
|
||||
}
|
||||
|
||||
/* Transforms (2D and 3D) */
|
||||
.transform-rotate {
|
||||
background-color: #ff5050;
|
||||
transform: rotate(20deg);
|
||||
}
|
||||
|
||||
.transform-scale {
|
||||
background-color: #50ff90;
|
||||
transform: scale(1.3, 0.7);
|
||||
}
|
||||
|
||||
.transform-skew {
|
||||
background-color: #ffaa00;
|
||||
transform: skew(15deg, 0deg);
|
||||
}
|
||||
|
||||
.transform-3d {
|
||||
background-color: #a060ff;
|
||||
transform: perspective(400px) rotateY(45deg);
|
||||
}
|
||||
|
||||
/* Clip mask */
|
||||
.clip-parent {
|
||||
position: relative;
|
||||
background-color: #2050a0;
|
||||
border-radius: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.clip-parent-forced {
|
||||
position: relative;
|
||||
background-color: #2050a0;
|
||||
border-radius: 30px;
|
||||
overflow: hidden;
|
||||
clip: always;
|
||||
}
|
||||
|
||||
.clip-child-overflowing {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: -15px;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
background-color: #ff4040;
|
||||
}
|
||||
|
||||
.clip-child-transform-only {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: #ff4040;
|
||||
transform: rotate(30deg) scale(1.6);
|
||||
}
|
||||
|
||||
/* Shaders: linear-gradient */
|
||||
.gradient-linear {
|
||||
decorator: linear-gradient(to right, #000000, #ffffff);
|
||||
}
|
||||
|
||||
.gradient-linear-angled {
|
||||
decorator: linear-gradient(45deg, red 20%, white, blue 80%);
|
||||
}
|
||||
|
||||
.gradient-linear-repeating {
|
||||
decorator: repeating-linear-gradient(to right, red, yellow 20px, red 40px);
|
||||
}
|
||||
|
||||
/* Shaders: radial-gradient */
|
||||
.gradient-radial {
|
||||
decorator: radial-gradient(circle farthest-side at center, #ff6b6b, #fec84d, #4ecdc4);
|
||||
}
|
||||
|
||||
.gradient-radial-ellipse {
|
||||
decorator: radial-gradient(60px 30px at center, red, yellow, green);
|
||||
}
|
||||
|
||||
/* Shaders: conic-gradient */
|
||||
.gradient-conic {
|
||||
decorator: conic-gradient(from 0deg at center, red, yellow, lime, aqua, blue, red);
|
||||
}
|
||||
|
||||
.gradient-conic-pie {
|
||||
decorator: conic-gradient(#9acd32 40%, #ffd700 0 75%, #f06 0);
|
||||
}
|
||||
|
||||
/* Filters — not yet implemented */
|
||||
.filter-blur {
|
||||
background-color: #3060ff;
|
||||
filter: blur(4px);
|
||||
}
|
||||
|
||||
.filter-brightness {
|
||||
background-color: #3060ff;
|
||||
filter: brightness(1.8);
|
||||
}
|
||||
|
||||
.filter-dropshadow {
|
||||
background-color: #3060ff;
|
||||
filter: drop-shadow(#000 6px 6px 2px);
|
||||
}
|
||||
|
||||
.filter-grayscale {
|
||||
decorator: linear-gradient(to right, red, blue);
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
/* Backdrop-filter — not yet implemented */
|
||||
.backdrop-behind {
|
||||
position: relative;
|
||||
background-color: #ff8800;
|
||||
}
|
||||
|
||||
.backdrop-blur {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
width: 80px;
|
||||
height: 60px;
|
||||
backdrop-filter: blur(6px);
|
||||
background-color: #ffffff40;
|
||||
}
|
||||
|
||||
/* Box shadow — not yet implemented */
|
||||
.box-shadow-basic {
|
||||
background-color: #303030;
|
||||
box-shadow: #000a 0 4px 12px;
|
||||
}
|
||||
|
||||
.box-shadow-inset {
|
||||
background-color: #303030;
|
||||
box-shadow: #000a 0 0 10px inset;
|
||||
}
|
||||
|
||||
/* Mask image — not yet implemented */
|
||||
.mask-basic {
|
||||
background-color: #40c0ff;
|
||||
mask-image: radial-gradient(circle at center, white, transparent);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Basic rendering</div>
|
||||
<div class="box basic-solid"></div>
|
||||
<div class="box basic-border"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Transforms</div>
|
||||
<div class="box transform-rotate"></div>
|
||||
<div class="box transform-scale"></div>
|
||||
<div class="box transform-skew"></div>
|
||||
<div class="box transform-3d"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Clip mask</div>
|
||||
<div class="box clip-parent">
|
||||
<div class="clip-child-overflowing"></div>
|
||||
</div>
|
||||
<div class="box clip-parent">
|
||||
<div class="clip-child-transform-only"></div>
|
||||
</div>
|
||||
<div class="box clip-parent-forced">
|
||||
<div class="clip-child-transform-only"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Shaders: linear-gradient</div>
|
||||
<div class="box gradient-linear"></div>
|
||||
<div class="box gradient-linear-angled"></div>
|
||||
<div class="box gradient-linear-repeating"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Shaders: radial-gradient</div>
|
||||
<div class="box gradient-radial"></div>
|
||||
<div class="box gradient-radial-ellipse"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Shaders: conic-gradient</div>
|
||||
<div class="box gradient-conic"></div>
|
||||
<div class="box gradient-conic-pie"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Filters (not yet implemented, expect no effect)</div>
|
||||
<div class="box filter-blur"></div>
|
||||
<div class="box filter-brightness"></div>
|
||||
<div class="box filter-dropshadow"></div>
|
||||
<div class="box filter-grayscale"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Backdrop-filter (not yet implemented, expect no effect)</div>
|
||||
<div class="box backdrop-behind">
|
||||
<div class="backdrop-blur"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Box shadow (not yet implemented, expect no effect)</div>
|
||||
<div class="box box-shadow-basic"></div>
|
||||
<div class="box box-shadow-inset"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">Mask image (not yet implemented, expect no effect)</div>
|
||||
<div class="box mask-basic"></div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</rml>
|
||||
13
readme.md
13
readme.md
@@ -8,12 +8,23 @@ I originally began creating this for a Game Jam project where I got the basic re
|
||||
*Rendering features (from the RmlUi render interfface documentation https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/interfaces/render.html#feature-table):*
|
||||
- [x] Basic rendering
|
||||
- [x] Clip Mask
|
||||
- [x] Transforms
|
||||
- [-] Transforms
|
||||
- transform-only overflow (no explicit `clip: always`) may not be clipping correctly
|
||||
- 3D transforms (e.g. `perspective()` + `rotateY()`) do not render
|
||||
- [ ] Layers
|
||||
- [ ] Render textures
|
||||
- [ ] Mask images
|
||||
- [ ] Filters
|
||||
- [ ] Shaders
|
||||
- [ ] Generic
|
||||
- [x] Gradients
|
||||
- [x] Linear
|
||||
- [x] Radial
|
||||
- [x] Conic
|
||||
|
||||
*Backend features:*
|
||||
- [x] Input handling
|
||||
|
||||
|
||||
*Issue tracker:*
|
||||
|
||||
@@ -3,20 +3,125 @@
|
||||
#include <raylib.h>
|
||||
#include <rlgl.h>
|
||||
|
||||
#include <RmlUi/Core.h>
|
||||
#include <RmlUi/Core/Dictionary.h>
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
// ---- Basic rendering: geometry ----
|
||||
|
||||
struct GeometryData {
|
||||
std::vector<Rml::Vertex> vertices;
|
||||
std::vector<int> indices;
|
||||
};
|
||||
|
||||
// ---- Shaders: gradient data ----
|
||||
|
||||
enum class GradientType { Linear, Radial, Conic };
|
||||
|
||||
struct GradientStopData {
|
||||
static constexpr int MAX_STOPS = 16;
|
||||
GradientType type;
|
||||
int stop_count = 0;
|
||||
Rml::ColourbPremultiplied colors[MAX_STOPS];
|
||||
float positions[MAX_STOPS];
|
||||
};
|
||||
|
||||
struct LinearGradientData : GradientStopData {
|
||||
LinearGradientData() { type = GradientType::Linear; }
|
||||
Rml::Vector2f p0;
|
||||
Rml::Vector2f p1;
|
||||
float length = 1.0f;
|
||||
bool repeating = false;
|
||||
};
|
||||
|
||||
struct RadialGradientData : GradientStopData {
|
||||
RadialGradientData() { type = GradientType::Radial; }
|
||||
Rml::Vector2f center;
|
||||
Rml::Vector2f radius;
|
||||
bool repeating = false;
|
||||
};
|
||||
|
||||
struct ConicGradientData : GradientStopData {
|
||||
ConicGradientData() { type = GradientType::Conic; }
|
||||
Rml::Vector2f center;
|
||||
float angle = 0.0f;
|
||||
bool repeating = false;
|
||||
};
|
||||
|
||||
void FillGradientStops(GradientStopData &out, const Rml::ColorStopList &stops) {
|
||||
out.stop_count = std::min((int)stops.size(), GradientStopData::MAX_STOPS);
|
||||
for (int i = 0; i < out.stop_count; ++i) {
|
||||
out.colors[i] = stops[i].color;
|
||||
out.positions[i] = stops[i].position.number;
|
||||
}
|
||||
}
|
||||
|
||||
void UploadGradientStops(Shader &shader, int locStopCount, int locStopColors,
|
||||
int locStopPositions, const GradientStopData &data) {
|
||||
float colorsF[GradientStopData::MAX_STOPS * 4];
|
||||
float positionsF[GradientStopData::MAX_STOPS];
|
||||
for (int i = 0; i < data.stop_count; ++i) {
|
||||
colorsF[i * 4 + 0] = data.colors[i].red / 255.0f;
|
||||
colorsF[i * 4 + 1] = data.colors[i].green / 255.0f;
|
||||
colorsF[i * 4 + 2] = data.colors[i].blue / 255.0f;
|
||||
colorsF[i * 4 + 3] = data.colors[i].alpha / 255.0f;
|
||||
positionsF[i] = data.positions[i];
|
||||
}
|
||||
SetShaderValue(shader, locStopCount, &data.stop_count, SHADER_UNIFORM_INT);
|
||||
SetShaderValueV(shader, locStopColors, colorsF, SHADER_UNIFORM_VEC4,
|
||||
data.stop_count);
|
||||
SetShaderValueV(shader, locStopPositions, positionsF, SHADER_UNIFORM_FLOAT,
|
||||
data.stop_count);
|
||||
}
|
||||
|
||||
const char *kGradientVertexShader =
|
||||
"#version 330\n"
|
||||
"in vec3 vertexPosition;\n"
|
||||
"in vec2 vertexTexCoord;\n"
|
||||
"in vec4 vertexColor;\n"
|
||||
"out vec2 fragTexCoord;\n"
|
||||
"uniform mat4 mvp;\n"
|
||||
"void main() {\n"
|
||||
" fragTexCoord = vertexTexCoord;\n"
|
||||
" gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
const char *kGradientSampling =
|
||||
"uniform int u_stopCount;\n"
|
||||
"uniform vec4 u_stopColors[16];\n"
|
||||
"uniform float u_stopPositions[16];\n"
|
||||
"uniform int u_repeating;\n"
|
||||
"vec4 SampleGradient(float t) {\n"
|
||||
" if (u_repeating != 0) {\n"
|
||||
" t = fract(t);\n"
|
||||
" if (t < 0.0) t += 1.0;\n"
|
||||
" } else {\n"
|
||||
" t = clamp(t, 0.0, 1.0);\n"
|
||||
" }\n"
|
||||
" vec4 color = u_stopColors[0];\n"
|
||||
" for (int i = 0; i < u_stopCount - 1; ++i) {\n"
|
||||
" if (t >= u_stopPositions[i] && t <= u_stopPositions[i + 1]) {\n"
|
||||
" float span = max(u_stopPositions[i + 1] - u_stopPositions[i], "
|
||||
"0.0001);\n"
|
||||
" float localT = (t - u_stopPositions[i]) / span;\n"
|
||||
" color = mix(u_stopColors[i], u_stopColors[i + 1], localT);\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return color;\n"
|
||||
"}\n";
|
||||
|
||||
} // namespace
|
||||
|
||||
// ---- Basic rendering: geometry ----
|
||||
|
||||
Rml::CompiledGeometryHandle
|
||||
RaylibRenderInterface::CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||
Rml::Span<const int> indices) {
|
||||
@@ -65,6 +170,8 @@ void RaylibRenderInterface::ReleaseGeometry(
|
||||
delete reinterpret_cast<GeometryData *>(handle);
|
||||
}
|
||||
|
||||
// ---- Basic rendering: textures ----
|
||||
|
||||
Rml::TextureHandle
|
||||
RaylibRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions,
|
||||
const Rml::String &source) {
|
||||
@@ -91,7 +198,7 @@ RaylibRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source_data,
|
||||
std::memcpy(img.data, source_data.data(), byte_count);
|
||||
|
||||
Texture2D tex = LoadTextureFromImage(img);
|
||||
UnloadImage(img); // frees img.data
|
||||
UnloadImage(img);
|
||||
|
||||
return reinterpret_cast<Rml::TextureHandle>(new Texture2D(tex));
|
||||
}
|
||||
@@ -102,6 +209,8 @@ void RaylibRenderInterface::ReleaseTexture(Rml::TextureHandle handle) {
|
||||
delete tex;
|
||||
}
|
||||
|
||||
// ---- Basic rendering: scissor region ----
|
||||
|
||||
void RaylibRenderInterface::EnableScissorRegion(bool enable) {
|
||||
scissor_enabled = enable;
|
||||
if (enable)
|
||||
@@ -121,6 +230,8 @@ void RaylibRenderInterface::ApplyScissor() {
|
||||
scissor_region.Width(), scissor_region.Height());
|
||||
}
|
||||
|
||||
// ---- Transforms ----
|
||||
|
||||
void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
|
||||
if (transform) {
|
||||
has_transform = true;
|
||||
@@ -130,8 +241,10 @@ void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
|
||||
}
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::DrawGeometryTriangles(Rml::CompiledGeometryHandle handle,
|
||||
Rml::Vector2f translation) {
|
||||
// ---- Clip mask ----
|
||||
|
||||
void RaylibRenderInterface::DrawGeometryTriangles(
|
||||
Rml::CompiledGeometryHandle handle, Rml::Vector2f translation) {
|
||||
auto *geo = reinterpret_cast<GeometryData *>(handle);
|
||||
|
||||
rlPushMatrix();
|
||||
@@ -165,34 +278,34 @@ void RaylibRenderInterface::EnableClipMask(bool enable) {
|
||||
}
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::RenderToClipMask(Rml::ClipMaskOperation operation,
|
||||
Rml::CompiledGeometryHandle geometry,
|
||||
Rml::Vector2f translation) {
|
||||
void RaylibRenderInterface::RenderToClipMask(
|
||||
Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry,
|
||||
Rml::Vector2f translation) {
|
||||
rlDrawRenderBatchActive();
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
|
||||
switch (operation) {
|
||||
case Rml::ClipMaskOperation::Set:
|
||||
glClearStencil(0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
clip_mask_level = 1;
|
||||
break;
|
||||
case Rml::ClipMaskOperation::Set:
|
||||
glClearStencil(0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
clip_mask_level = 1;
|
||||
break;
|
||||
|
||||
case Rml::ClipMaskOperation::SetInverse:
|
||||
glClearStencil(1);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
clip_mask_level = 1;
|
||||
break;
|
||||
case Rml::ClipMaskOperation::SetInverse:
|
||||
glClearStencil(1);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
clip_mask_level = 1;
|
||||
break;
|
||||
|
||||
case Rml::ClipMaskOperation::Intersect:
|
||||
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||
clip_mask_level += 1;
|
||||
break;
|
||||
case Rml::ClipMaskOperation::Intersect:
|
||||
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||
clip_mask_level += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
DrawGeometryTriangles(geometry, translation);
|
||||
@@ -203,3 +316,254 @@ void RaylibRenderInterface::RenderToClipMask(Rml::ClipMaskOperation operation,
|
||||
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
}
|
||||
|
||||
// ---- Shaders ----
|
||||
|
||||
void RaylibRenderInterface::EnsureLinearGradientShaderLoaded() {
|
||||
if (linear_program.loaded)
|
||||
return;
|
||||
|
||||
std::string fs =
|
||||
std::string("#version 330\n"
|
||||
"in vec2 fragTexCoord;\n"
|
||||
"out vec4 finalColor;\n"
|
||||
"uniform vec2 u_p0;\n"
|
||||
"uniform vec2 u_p1;\n"
|
||||
"uniform float u_length;\n") +
|
||||
kGradientSampling +
|
||||
"void main() {\n"
|
||||
" vec2 dir = u_p1 - u_p0;\n"
|
||||
" float len = max(u_length, 0.0001);\n"
|
||||
" float t = dot(fragTexCoord - u_p0, normalize(dir)) / len;\n"
|
||||
" finalColor = SampleGradient(t);\n"
|
||||
"}\n";
|
||||
|
||||
linear_program.shader =
|
||||
LoadShaderFromMemory(kGradientVertexShader, fs.c_str());
|
||||
linear_program.loc_p0 = GetShaderLocation(linear_program.shader, "u_p0");
|
||||
linear_program.loc_p1 = GetShaderLocation(linear_program.shader, "u_p1");
|
||||
linear_program.loc_length =
|
||||
GetShaderLocation(linear_program.shader, "u_length");
|
||||
linear_program.loc_repeating =
|
||||
GetShaderLocation(linear_program.shader, "u_repeating");
|
||||
linear_program.loc_stopCount =
|
||||
GetShaderLocation(linear_program.shader, "u_stopCount");
|
||||
linear_program.loc_stopColors =
|
||||
GetShaderLocation(linear_program.shader, "u_stopColors");
|
||||
linear_program.loc_stopPositions =
|
||||
GetShaderLocation(linear_program.shader, "u_stopPositions");
|
||||
linear_program.loaded = true;
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::EnsureRadialGradientShaderLoaded() {
|
||||
if (radial_program.loaded)
|
||||
return;
|
||||
|
||||
std::string fs = std::string("#version 330\n"
|
||||
"in vec2 fragTexCoord;\n"
|
||||
"out vec4 finalColor;\n"
|
||||
"uniform vec2 u_center;\n"
|
||||
"uniform vec2 u_radius;\n") +
|
||||
kGradientSampling +
|
||||
"void main() {\n"
|
||||
" vec2 offset = (fragTexCoord - u_center) / "
|
||||
"max(u_radius, vec2(0.0001));\n"
|
||||
" float t = length(offset);\n"
|
||||
" finalColor = SampleGradient(t);\n"
|
||||
"}\n";
|
||||
|
||||
radial_program.shader =
|
||||
LoadShaderFromMemory(kGradientVertexShader, fs.c_str());
|
||||
radial_program.loc_center =
|
||||
GetShaderLocation(radial_program.shader, "u_center");
|
||||
radial_program.loc_radius =
|
||||
GetShaderLocation(radial_program.shader, "u_radius");
|
||||
radial_program.loc_repeating =
|
||||
GetShaderLocation(radial_program.shader, "u_repeating");
|
||||
radial_program.loc_stopCount =
|
||||
GetShaderLocation(radial_program.shader, "u_stopCount");
|
||||
radial_program.loc_stopColors =
|
||||
GetShaderLocation(radial_program.shader, "u_stopColors");
|
||||
radial_program.loc_stopPositions =
|
||||
GetShaderLocation(radial_program.shader, "u_stopPositions");
|
||||
radial_program.loaded = true;
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::EnsureConicGradientShaderLoaded() {
|
||||
if (conic_program.loaded)
|
||||
return;
|
||||
|
||||
std::string fs = std::string("#version 330\n"
|
||||
"in vec2 fragTexCoord;\n"
|
||||
"out vec4 finalColor;\n"
|
||||
"uniform vec2 u_center;\n"
|
||||
"uniform float u_angle;\n") +
|
||||
kGradientSampling +
|
||||
"void main() {\n"
|
||||
" vec2 offset = fragTexCoord - u_center;\n"
|
||||
" float theta = atan(offset.y, offset.x) - u_angle + "
|
||||
"1.5707963267948966;\n"
|
||||
" float t = theta / 6.283185307179586;\n"
|
||||
" t = t - floor(t);\n"
|
||||
" finalColor = SampleGradient(t);\n"
|
||||
"}\n";
|
||||
|
||||
conic_program.shader =
|
||||
LoadShaderFromMemory(kGradientVertexShader, fs.c_str());
|
||||
conic_program.loc_center =
|
||||
GetShaderLocation(conic_program.shader, "u_center");
|
||||
conic_program.loc_angle = GetShaderLocation(conic_program.shader, "u_angle");
|
||||
conic_program.loc_repeating =
|
||||
GetShaderLocation(conic_program.shader, "u_repeating");
|
||||
conic_program.loc_stopCount =
|
||||
GetShaderLocation(conic_program.shader, "u_stopCount");
|
||||
conic_program.loc_stopColors =
|
||||
GetShaderLocation(conic_program.shader, "u_stopColors");
|
||||
conic_program.loc_stopPositions =
|
||||
GetShaderLocation(conic_program.shader, "u_stopPositions");
|
||||
conic_program.loaded = true;
|
||||
}
|
||||
|
||||
Rml::CompiledShaderHandle
|
||||
RaylibRenderInterface::CompileShader(const Rml::String &name,
|
||||
const Rml::Dictionary ¶meters) {
|
||||
if (name == "linear-gradient") {
|
||||
EnsureLinearGradientShaderLoaded();
|
||||
auto *data = new LinearGradientData();
|
||||
data->p0 = Rml::Get(parameters, "p0", Rml::Vector2f(0, 0));
|
||||
data->p1 = Rml::Get(parameters, "p1", Rml::Vector2f(0, 0));
|
||||
data->length = Rml::Get(parameters, "length", 1.0f);
|
||||
data->repeating = Rml::Get(parameters, "repeating", false);
|
||||
FillGradientStops(
|
||||
*data, Rml::Get(parameters, "color_stop_list", Rml::ColorStopList()));
|
||||
return reinterpret_cast<Rml::CompiledShaderHandle>(data);
|
||||
}
|
||||
|
||||
if (name == "radial-gradient") {
|
||||
EnsureRadialGradientShaderLoaded();
|
||||
auto *data = new RadialGradientData();
|
||||
data->center = Rml::Get(parameters, "center", Rml::Vector2f(0, 0));
|
||||
data->radius = Rml::Get(parameters, "radius", Rml::Vector2f(1, 1));
|
||||
data->repeating = Rml::Get(parameters, "repeating", false);
|
||||
FillGradientStops(
|
||||
*data, Rml::Get(parameters, "color_stop_list", Rml::ColorStopList()));
|
||||
return reinterpret_cast<Rml::CompiledShaderHandle>(data);
|
||||
}
|
||||
|
||||
if (name == "conic-gradient") {
|
||||
EnsureConicGradientShaderLoaded();
|
||||
auto *data = new ConicGradientData();
|
||||
data->center = Rml::Get(parameters, "center", Rml::Vector2f(0, 0));
|
||||
data->angle = Rml::Get(parameters, "angle", 0.0f);
|
||||
data->repeating = Rml::Get(parameters, "repeating", false);
|
||||
FillGradientStops(
|
||||
*data, Rml::Get(parameters, "color_stop_list", Rml::ColorStopList()));
|
||||
return reinterpret_cast<Rml::CompiledShaderHandle>(data);
|
||||
}
|
||||
|
||||
TraceLog(LOG_WARNING, "[RmlUi] shader type '%s' not implemented",
|
||||
name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::RenderShader(Rml::CompiledShaderHandle shader,
|
||||
Rml::CompiledGeometryHandle handle,
|
||||
Rml::Vector2f translation,
|
||||
Rml::TextureHandle texture) {
|
||||
auto *base = reinterpret_cast<GradientStopData *>(shader);
|
||||
auto *geo = reinterpret_cast<GeometryData *>(handle);
|
||||
|
||||
rlDrawRenderBatchActive();
|
||||
|
||||
switch (base->type) {
|
||||
case GradientType::Linear: {
|
||||
auto *data = static_cast<LinearGradientData *>(base);
|
||||
BeginShaderMode(linear_program.shader);
|
||||
float p0[2] = {data->p0.x, data->p0.y};
|
||||
float p1[2] = {data->p1.x, data->p1.y};
|
||||
int repeatingInt = data->repeating ? 1 : 0;
|
||||
SetShaderValue(linear_program.shader, linear_program.loc_p0, p0,
|
||||
SHADER_UNIFORM_VEC2);
|
||||
SetShaderValue(linear_program.shader, linear_program.loc_p1, p1,
|
||||
SHADER_UNIFORM_VEC2);
|
||||
SetShaderValue(linear_program.shader, linear_program.loc_length,
|
||||
&data->length, SHADER_UNIFORM_FLOAT);
|
||||
SetShaderValue(linear_program.shader, linear_program.loc_repeating,
|
||||
&repeatingInt, SHADER_UNIFORM_INT);
|
||||
UploadGradientStops(linear_program.shader, linear_program.loc_stopCount,
|
||||
linear_program.loc_stopColors,
|
||||
linear_program.loc_stopPositions, *data);
|
||||
break;
|
||||
}
|
||||
case GradientType::Radial: {
|
||||
auto *data = static_cast<RadialGradientData *>(base);
|
||||
BeginShaderMode(radial_program.shader);
|
||||
float center[2] = {data->center.x, data->center.y};
|
||||
float radius[2] = {data->radius.x, data->radius.y};
|
||||
int repeatingInt = data->repeating ? 1 : 0;
|
||||
SetShaderValue(radial_program.shader, radial_program.loc_center, center,
|
||||
SHADER_UNIFORM_VEC2);
|
||||
SetShaderValue(radial_program.shader, radial_program.loc_radius, radius,
|
||||
SHADER_UNIFORM_VEC2);
|
||||
SetShaderValue(radial_program.shader, radial_program.loc_repeating,
|
||||
&repeatingInt, SHADER_UNIFORM_INT);
|
||||
UploadGradientStops(radial_program.shader, radial_program.loc_stopCount,
|
||||
radial_program.loc_stopColors,
|
||||
radial_program.loc_stopPositions, *data);
|
||||
break;
|
||||
}
|
||||
case GradientType::Conic: {
|
||||
auto *data = static_cast<ConicGradientData *>(base);
|
||||
BeginShaderMode(conic_program.shader);
|
||||
float center[2] = {data->center.x, data->center.y};
|
||||
int repeatingInt = data->repeating ? 1 : 0;
|
||||
SetShaderValue(conic_program.shader, conic_program.loc_center, center,
|
||||
SHADER_UNIFORM_VEC2);
|
||||
SetShaderValue(conic_program.shader, conic_program.loc_angle, &data->angle,
|
||||
SHADER_UNIFORM_FLOAT);
|
||||
SetShaderValue(conic_program.shader, conic_program.loc_repeating,
|
||||
&repeatingInt, SHADER_UNIFORM_INT);
|
||||
UploadGradientStops(conic_program.shader, conic_program.loc_stopCount,
|
||||
conic_program.loc_stopColors,
|
||||
conic_program.loc_stopPositions, *data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef(translation.x, translation.y, 0.0f);
|
||||
if (has_transform) {
|
||||
rlMultMatrixf(current_transform.data());
|
||||
}
|
||||
|
||||
rlSetTexture(rlGetTextureIdDefault());
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (size_t i = 0; i + 2 < geo->indices.size(); i += 3) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
const Rml::Vertex &v = geo->vertices[geo->indices[i + j]];
|
||||
rlTexCoord2f(v.tex_coord.x, v.tex_coord.y);
|
||||
rlVertex2f(v.position.x, v.position.y);
|
||||
}
|
||||
}
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
rlSetTexture(0);
|
||||
|
||||
rlDrawRenderBatchActive();
|
||||
EndShaderMode();
|
||||
}
|
||||
|
||||
void RaylibRenderInterface::ReleaseShader(Rml::CompiledShaderHandle shader) {
|
||||
auto *base = reinterpret_cast<GradientStopData *>(shader);
|
||||
switch (base->type) {
|
||||
case GradientType::Linear:
|
||||
delete static_cast<LinearGradientData *>(base);
|
||||
break;
|
||||
case GradientType::Radial:
|
||||
delete static_cast<RadialGradientData *>(base);
|
||||
break;
|
||||
case GradientType::Conic:
|
||||
delete static_cast<ConicGradientData *>(base);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,86 @@
|
||||
#pragma once
|
||||
#include <RmlUi/Core/RenderInterface.h>
|
||||
|
||||
// NOTE: RmlUi's RenderInterface signature has shifted across versions
|
||||
// (raw pointer+count vs. Rml::Span<>). If this fails to compile against
|
||||
// a different RmlUi commit, check RmlUi/Core/RenderInterface.h and adjust
|
||||
// CompileGeometry/GenerateTexture's parameter types, internal logic
|
||||
// stays the same.
|
||||
#include <raylib.h>
|
||||
|
||||
class RaylibRenderInterface : public Rml::RenderInterface {
|
||||
public:
|
||||
// ---- Basic rendering: geometry ----
|
||||
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;
|
||||
|
||||
// ---- Basic rendering: textures ----
|
||||
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 handle) override;
|
||||
|
||||
// ---- Basic rendering: scissor region ----
|
||||
void EnableScissorRegion(bool enable) override;
|
||||
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||
|
||||
// ---- Transforms ----
|
||||
void SetTransform(const Rml::Matrix4f *transform) override;
|
||||
|
||||
// ---- Clip mask ----
|
||||
void EnableClipMask(bool enable) override;
|
||||
void RenderToClipMask(Rml::ClipMaskOperation operation,
|
||||
Rml::CompiledGeometryHandle geometry,
|
||||
Rml::Vector2f translation) override;
|
||||
|
||||
private:
|
||||
void ApplyScissor();
|
||||
// ---- Shaders ----
|
||||
Rml::CompiledShaderHandle
|
||||
CompileShader(const Rml::String &name,
|
||||
const Rml::Dictionary ¶meters) override;
|
||||
void RenderShader(Rml::CompiledShaderHandle shader,
|
||||
Rml::CompiledGeometryHandle geometry,
|
||||
Rml::Vector2f translation,
|
||||
Rml::TextureHandle texture) override;
|
||||
void ReleaseShader(Rml::CompiledShaderHandle shader) override;
|
||||
|
||||
private:
|
||||
// ---- Basic rendering: scissor region ----
|
||||
void ApplyScissor();
|
||||
bool scissor_enabled = false;
|
||||
Rml::Rectanglei scissor_region;
|
||||
|
||||
// ---- Transforms ----
|
||||
bool has_transform = false;
|
||||
Rml::Matrix4f current_transform;
|
||||
|
||||
// ---- Clip mask ----
|
||||
void DrawGeometryTriangles(Rml::CompiledGeometryHandle geometry,
|
||||
Rml::Vector2f translation);
|
||||
bool clip_mask_enabled = false;
|
||||
unsigned int clip_mask_level = 0;
|
||||
void DrawGeometryTriangles(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation);
|
||||
|
||||
// ---- Shaders: gradient shader programs ----
|
||||
struct GradientShaderProgram {
|
||||
Shader shader{};
|
||||
bool loaded = false;
|
||||
int loc_stopCount = -1, loc_stopColors = -1, loc_stopPositions = -1,
|
||||
loc_repeating = -1;
|
||||
};
|
||||
struct LinearShaderProgram : GradientShaderProgram {
|
||||
int loc_p0 = -1, loc_p1 = -1, loc_length = -1;
|
||||
};
|
||||
struct RadialShaderProgram : GradientShaderProgram {
|
||||
int loc_center = -1, loc_radius = -1;
|
||||
};
|
||||
struct ConicShaderProgram : GradientShaderProgram {
|
||||
int loc_center = -1, loc_angle = -1;
|
||||
};
|
||||
|
||||
void EnsureLinearGradientShaderLoaded();
|
||||
void EnsureRadialGradientShaderLoaded();
|
||||
void EnsureConicGradientShaderLoaded();
|
||||
|
||||
LinearShaderProgram linear_program;
|
||||
RadialShaderProgram radial_program;
|
||||
ConicShaderProgram conic_program;
|
||||
};
|
||||
31
src/main.cpp
31
src/main.cpp
@@ -1,14 +1,14 @@
|
||||
#include <RmlUi/Core.h>
|
||||
#include <RmlUi/Core/Context.h>
|
||||
#include <RmlUi/Core/Core.h>
|
||||
#include <RmlUi/Core/Math.h>
|
||||
#include <RmlUi/Debugger.h>
|
||||
#include <RmlUi/Debugger/Debugger.h>
|
||||
#include <raylib.h>
|
||||
#include <RmlUi/Core.h>
|
||||
#include <RmlUi/Debugger.h>
|
||||
#include <RmlUi/Core/Context.h>
|
||||
|
||||
#include "backend/RaylibInput.h"
|
||||
#include "backend/RaylibRenderInterface.h"
|
||||
#include "backend/RaylibSystemInterface.h"
|
||||
#include "backend/RaylibInput.h"
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
@@ -16,7 +16,6 @@ static RaylibSystemInterface system_interface;
|
||||
static RaylibRenderInterface render_interface;
|
||||
static Rml::Context *ctx;
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
|
||||
@@ -31,17 +30,17 @@ int main() {
|
||||
ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800));
|
||||
Rml::Debugger::Initialise(ctx);
|
||||
|
||||
auto doc = ctx->LoadDocument("assets/main.rml");
|
||||
auto doc = ctx->LoadDocument("assets/tests.rml");
|
||||
doc->Show();
|
||||
|
||||
Camera3D cam3;
|
||||
cam3.position = Vector3 {0.0f, 10.0f, 10.0f};
|
||||
cam3.target = Vector3 {0.0f, 0.0f, 0.0f};
|
||||
cam3.up = Vector3 {0, 1.0f, 0.0f};
|
||||
cam3.position = Vector3{0.0f, 10.0f, 10.0f};
|
||||
cam3.target = Vector3{0.0f, 0.0f, 0.0f};
|
||||
cam3.up = Vector3{0, 1.0f, 0.0f};
|
||||
cam3.fovy = 45.0f;
|
||||
cam3.projection = CAMERA_PERSPECTIVE;
|
||||
|
||||
Vector3 cubePos = Vector3 {0.0f, 0.0f, 0.0f};
|
||||
Vector3 cubePos = Vector3{0.0f, 0.0f, 0.0f};
|
||||
|
||||
// DisableCursor();
|
||||
|
||||
@@ -56,17 +55,19 @@ int main() {
|
||||
ForwardInputToRml(ctx);
|
||||
ctx->Update();
|
||||
|
||||
if (IsKeyPressed(KEY_Z)) cam3.target = Vector3 {0.0f, 0.0f, 0.0f};
|
||||
if (IsKeyPressed(KEY_Z))
|
||||
cam3.target = Vector3{0.0f, 0.0f, 0.0f};
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
DrawFPS(10, 10);
|
||||
// DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10, RAYWHITE);
|
||||
// DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10,
|
||||
// RAYWHITE);
|
||||
|
||||
BeginMode3D(cam3);
|
||||
DrawCube(cubePos, 2.0f, 2.0f, 2.0f, RED);
|
||||
DrawCubeWires(cubePos, 2.0f, 2.0f, 2.0f, BLUE);
|
||||
DrawGrid(10, 1.0f);
|
||||
DrawCube(cubePos, 2.0f, 2.0f, 2.0f, RED);
|
||||
DrawCubeWires(cubePos, 2.0f, 2.0f, 2.0f, BLUE);
|
||||
DrawGrid(10, 1.0f);
|
||||
EndMode3D();
|
||||
|
||||
ctx->Render();
|
||||
|
||||
Reference in New Issue
Block a user