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;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
div, section, article, header, footer, main, nav, aside {
|
div,
|
||||||
|
section,
|
||||||
|
article,
|
||||||
|
header,
|
||||||
|
footer,
|
||||||
|
main,
|
||||||
|
nav,
|
||||||
|
aside {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
span, em, strong, a {
|
span,
|
||||||
|
em,
|
||||||
|
strong,
|
||||||
|
a {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,18 +44,40 @@ p {
|
|||||||
margin: 1em 0px;
|
margin: 1em 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
display: block;
|
display: block;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 0.83em 0px;
|
margin: 0.83em 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 { font-size: 2em; }
|
h1 {
|
||||||
h2 { font-size: 1.5em; }
|
font-size: 2em;
|
||||||
h3 { font-size: 1.17em; }
|
}
|
||||||
h4 { font-size: 1em; }
|
|
||||||
h5 { font-size: 0.83em; }
|
h2 {
|
||||||
h6 { font-size: 0.67em; }
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.17em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 0.83em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 0.67em;
|
||||||
|
}
|
||||||
|
|
||||||
em {
|
em {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@@ -72,7 +104,8 @@ blockquote {
|
|||||||
color: #555555;
|
color: #555555;
|
||||||
}
|
}
|
||||||
|
|
||||||
code, pre {
|
code,
|
||||||
|
pre {
|
||||||
font-family: "rmlui-debugger-font";
|
font-family: "rmlui-debugger-font";
|
||||||
background-color: #606060;
|
background-color: #606060;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
@@ -88,7 +121,8 @@ pre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
ul, ol {
|
ul,
|
||||||
|
ol {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 1em 0px;
|
margin: 1em 0px;
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
@@ -109,7 +143,8 @@ tr {
|
|||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
|
|
||||||
td, th {
|
td,
|
||||||
|
th {
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -128,14 +163,19 @@ colgroup {
|
|||||||
display: table-column-group;
|
display: table-column-group;
|
||||||
}
|
}
|
||||||
|
|
||||||
thead, tbody, tfoot {
|
thead,
|
||||||
|
tbody,
|
||||||
|
tfoot {
|
||||||
display: table-row-group;
|
display: table-row-group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
Form Inputs & Interactive UI Components
|
Form Inputs & Interactive UI Components
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
button, input, select, textarea {
|
button,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: "rmlui-debugger-font";
|
font-family: "rmlui-debugger-font";
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -144,7 +184,9 @@ button, input, select, textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Traditional gray bevel button style */
|
/* Traditional gray bevel button style */
|
||||||
button, input[type="submit"], input[type="button"] {
|
button,
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="button"] {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
min-width: 40px;
|
min-width: 40px;
|
||||||
background-color: #e1e1e1;
|
background-color: #e1e1e1;
|
||||||
@@ -153,25 +195,33 @@ button, input[type="submit"], input[type="button"] {
|
|||||||
text-align: center;
|
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;
|
background-color: #d0d0d0;
|
||||||
border: 1px #4f4f4f;
|
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;
|
background-color: #b5b5b5;
|
||||||
border: 1px #000000;
|
border: 1px #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Standard text field styling */
|
/* Standard text field styling */
|
||||||
input[type="text"], input[type="password"], textarea {
|
input[type="text"],
|
||||||
|
input[type="password"],
|
||||||
|
textarea {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
border: 1px #767676;
|
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;
|
border: 1px #005aff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +264,8 @@ tab {
|
|||||||
|
|
||||||
tab:selected {
|
tab:selected {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-bottom: 1px #ffffff; /* Overlap the bottom border line */
|
border-bottom: 1px #ffffff;
|
||||||
|
/* Overlap the bottom border line */
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +287,8 @@ progress {
|
|||||||
progress-value {
|
progress-value {
|
||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #0078d7; /* Classic Windows Blue fill */
|
background-color: #0078d7;
|
||||||
|
/* Classic Windows Blue fill */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
@@ -265,3 +317,9 @@ progress-value {
|
|||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
div.gradient-test {
|
||||||
|
decorator: linear-gradient(to right, #000000, #ffffff);
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
<rml>
|
<rml>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>RmlUi Raylib</title>
|
<title>RmlUi Raylib</title>
|
||||||
<link type="text/rcss" href="main.rcss" />
|
<link type="text/rcss" href="main.rcss" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>Hello from RmlUi</h1>
|
<h1>Hello from RmlUi</h1>
|
||||||
<div style="position: relative; width: 300px; height: 200px; overflow: hidden; border-radius: 40px; background-color: #0000ff">
|
<div style="position: relative; width: 300px; height: 200px; overflow: hidden; border-radius: 40px;"
|
||||||
<div style="position: absolute; top: -20px; left: -20px; width: 150px; height: 150px; background-color: #ff0000; transform: rotate(15deg);"></div>
|
class="gradient-test">
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: -20px; left: -20px; width: 150px; height: 150px; background-color: #ff0000; transform: rotate(15deg);">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</rml>
|
</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):*
|
*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] Basic rendering
|
||||||
- [x] Clip Mask
|
- [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
|
- [ ] Layers
|
||||||
- [ ] Render textures
|
- [ ] Render textures
|
||||||
- [ ] Mask images
|
- [ ] Mask images
|
||||||
- [ ] Filters
|
- [ ] Filters
|
||||||
- [ ] Shaders
|
- [ ] Shaders
|
||||||
|
- [ ] Generic
|
||||||
|
- [x] Gradients
|
||||||
|
- [x] Linear
|
||||||
|
- [x] Radial
|
||||||
|
- [x] Conic
|
||||||
|
|
||||||
*Backend features:*
|
*Backend features:*
|
||||||
- [x] Input handling
|
- [x] Input handling
|
||||||
|
|
||||||
|
|
||||||
|
*Issue tracker:*
|
||||||
|
|
||||||
@@ -3,20 +3,125 @@
|
|||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <rlgl.h>
|
#include <rlgl.h>
|
||||||
|
|
||||||
|
#include <RmlUi/Core.h>
|
||||||
|
#include <RmlUi/Core/Dictionary.h>
|
||||||
|
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// ---- Basic rendering: geometry ----
|
||||||
|
|
||||||
struct GeometryData {
|
struct GeometryData {
|
||||||
std::vector<Rml::Vertex> vertices;
|
std::vector<Rml::Vertex> vertices;
|
||||||
std::vector<int> indices;
|
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
|
} // namespace
|
||||||
|
|
||||||
|
// ---- Basic rendering: geometry ----
|
||||||
|
|
||||||
Rml::CompiledGeometryHandle
|
Rml::CompiledGeometryHandle
|
||||||
RaylibRenderInterface::CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
RaylibRenderInterface::CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||||
Rml::Span<const int> indices) {
|
Rml::Span<const int> indices) {
|
||||||
@@ -65,6 +170,8 @@ void RaylibRenderInterface::ReleaseGeometry(
|
|||||||
delete reinterpret_cast<GeometryData *>(handle);
|
delete reinterpret_cast<GeometryData *>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Basic rendering: textures ----
|
||||||
|
|
||||||
Rml::TextureHandle
|
Rml::TextureHandle
|
||||||
RaylibRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions,
|
RaylibRenderInterface::LoadTexture(Rml::Vector2i &texture_dimensions,
|
||||||
const Rml::String &source) {
|
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);
|
std::memcpy(img.data, source_data.data(), byte_count);
|
||||||
|
|
||||||
Texture2D tex = LoadTextureFromImage(img);
|
Texture2D tex = LoadTextureFromImage(img);
|
||||||
UnloadImage(img); // frees img.data
|
UnloadImage(img);
|
||||||
|
|
||||||
return reinterpret_cast<Rml::TextureHandle>(new Texture2D(tex));
|
return reinterpret_cast<Rml::TextureHandle>(new Texture2D(tex));
|
||||||
}
|
}
|
||||||
@@ -102,6 +209,8 @@ void RaylibRenderInterface::ReleaseTexture(Rml::TextureHandle handle) {
|
|||||||
delete tex;
|
delete tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Basic rendering: scissor region ----
|
||||||
|
|
||||||
void RaylibRenderInterface::EnableScissorRegion(bool enable) {
|
void RaylibRenderInterface::EnableScissorRegion(bool enable) {
|
||||||
scissor_enabled = enable;
|
scissor_enabled = enable;
|
||||||
if (enable)
|
if (enable)
|
||||||
@@ -121,6 +230,8 @@ void RaylibRenderInterface::ApplyScissor() {
|
|||||||
scissor_region.Width(), scissor_region.Height());
|
scissor_region.Width(), scissor_region.Height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Transforms ----
|
||||||
|
|
||||||
void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
|
void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
|
||||||
if (transform) {
|
if (transform) {
|
||||||
has_transform = true;
|
has_transform = true;
|
||||||
@@ -130,8 +241,10 @@ void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaylibRenderInterface::DrawGeometryTriangles(Rml::CompiledGeometryHandle handle,
|
// ---- Clip mask ----
|
||||||
Rml::Vector2f translation) {
|
|
||||||
|
void RaylibRenderInterface::DrawGeometryTriangles(
|
||||||
|
Rml::CompiledGeometryHandle handle, Rml::Vector2f translation) {
|
||||||
auto *geo = reinterpret_cast<GeometryData *>(handle);
|
auto *geo = reinterpret_cast<GeometryData *>(handle);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
@@ -165,34 +278,34 @@ void RaylibRenderInterface::EnableClipMask(bool enable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RaylibRenderInterface::RenderToClipMask(Rml::ClipMaskOperation operation,
|
void RaylibRenderInterface::RenderToClipMask(
|
||||||
Rml::CompiledGeometryHandle geometry,
|
Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry,
|
||||||
Rml::Vector2f translation) {
|
Rml::Vector2f translation) {
|
||||||
rlDrawRenderBatchActive();
|
rlDrawRenderBatchActive();
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case Rml::ClipMaskOperation::Set:
|
case Rml::ClipMaskOperation::Set:
|
||||||
glClearStencil(0);
|
glClearStencil(0);
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
clip_mask_level = 1;
|
clip_mask_level = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Rml::ClipMaskOperation::SetInverse:
|
case Rml::ClipMaskOperation::SetInverse:
|
||||||
glClearStencil(1);
|
glClearStencil(1);
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
clip_mask_level = 1;
|
clip_mask_level = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Rml::ClipMaskOperation::Intersect:
|
case Rml::ClipMaskOperation::Intersect:
|
||||||
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
||||||
clip_mask_level += 1;
|
clip_mask_level += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawGeometryTriangles(geometry, translation);
|
DrawGeometryTriangles(geometry, translation);
|
||||||
@@ -203,3 +316,254 @@ void RaylibRenderInterface::RenderToClipMask(Rml::ClipMaskOperation operation,
|
|||||||
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
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
|
#pragma once
|
||||||
#include <RmlUi/Core/RenderInterface.h>
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
#include <raylib.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.
|
|
||||||
|
|
||||||
class RaylibRenderInterface : public Rml::RenderInterface {
|
class RaylibRenderInterface : public Rml::RenderInterface {
|
||||||
public:
|
public:
|
||||||
|
// ---- Basic rendering: geometry ----
|
||||||
Rml::CompiledGeometryHandle
|
Rml::CompiledGeometryHandle
|
||||||
CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||||
Rml::Span<const int> indices) override;
|
Rml::Span<const int> indices) override;
|
||||||
|
|
||||||
void RenderGeometry(Rml::CompiledGeometryHandle handle,
|
void RenderGeometry(Rml::CompiledGeometryHandle handle,
|
||||||
Rml::Vector2f translation,
|
Rml::Vector2f translation,
|
||||||
Rml::TextureHandle texture) override;
|
Rml::TextureHandle texture) override;
|
||||||
|
|
||||||
void ReleaseGeometry(Rml::CompiledGeometryHandle handle) override;
|
void ReleaseGeometry(Rml::CompiledGeometryHandle handle) override;
|
||||||
|
|
||||||
|
// ---- Basic rendering: textures ----
|
||||||
Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions,
|
Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions,
|
||||||
const Rml::String &source) override;
|
const Rml::String &source) override;
|
||||||
|
|
||||||
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data,
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data,
|
||||||
Rml::Vector2i source_dimensions) override;
|
Rml::Vector2i source_dimensions) override;
|
||||||
|
|
||||||
void ReleaseTexture(Rml::TextureHandle handle) override;
|
void ReleaseTexture(Rml::TextureHandle handle) override;
|
||||||
|
|
||||||
|
// ---- Basic rendering: scissor region ----
|
||||||
void EnableScissorRegion(bool enable) override;
|
void EnableScissorRegion(bool enable) override;
|
||||||
void SetScissorRegion(Rml::Rectanglei region) override;
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
// ---- Transforms ----
|
||||||
void SetTransform(const Rml::Matrix4f *transform) override;
|
void SetTransform(const Rml::Matrix4f *transform) override;
|
||||||
|
|
||||||
|
// ---- Clip mask ----
|
||||||
void EnableClipMask(bool enable) override;
|
void EnableClipMask(bool enable) override;
|
||||||
void RenderToClipMask(Rml::ClipMaskOperation operation,
|
void RenderToClipMask(Rml::ClipMaskOperation operation,
|
||||||
Rml::CompiledGeometryHandle geometry,
|
Rml::CompiledGeometryHandle geometry,
|
||||||
Rml::Vector2f translation) override;
|
Rml::Vector2f translation) override;
|
||||||
|
|
||||||
private:
|
// ---- Shaders ----
|
||||||
void ApplyScissor();
|
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;
|
bool scissor_enabled = false;
|
||||||
Rml::Rectanglei scissor_region;
|
Rml::Rectanglei scissor_region;
|
||||||
|
|
||||||
|
// ---- Transforms ----
|
||||||
bool has_transform = false;
|
bool has_transform = false;
|
||||||
Rml::Matrix4f current_transform;
|
Rml::Matrix4f current_transform;
|
||||||
|
|
||||||
|
// ---- Clip mask ----
|
||||||
|
void DrawGeometryTriangles(Rml::CompiledGeometryHandle geometry,
|
||||||
|
Rml::Vector2f translation);
|
||||||
bool clip_mask_enabled = false;
|
bool clip_mask_enabled = false;
|
||||||
unsigned int clip_mask_level = 0;
|
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;
|
||||||
|
};
|
||||||
41
src/main.cpp
41
src/main.cpp
@@ -1,14 +1,14 @@
|
|||||||
|
#include <RmlUi/Core.h>
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
#include <RmlUi/Core/Core.h>
|
#include <RmlUi/Core/Core.h>
|
||||||
#include <RmlUi/Core/Math.h>
|
#include <RmlUi/Core/Math.h>
|
||||||
|
#include <RmlUi/Debugger.h>
|
||||||
#include <RmlUi/Debugger/Debugger.h>
|
#include <RmlUi/Debugger/Debugger.h>
|
||||||
#include <raylib.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/RaylibRenderInterface.h"
|
||||||
#include "backend/RaylibSystemInterface.h"
|
#include "backend/RaylibSystemInterface.h"
|
||||||
#include "backend/RaylibInput.h"
|
|
||||||
|
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
|
||||||
@@ -16,7 +16,6 @@ static RaylibSystemInterface system_interface;
|
|||||||
static RaylibRenderInterface render_interface;
|
static RaylibRenderInterface render_interface;
|
||||||
static Rml::Context *ctx;
|
static Rml::Context *ctx;
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
|
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE);
|
||||||
@@ -31,20 +30,20 @@ int main() {
|
|||||||
ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800));
|
ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800));
|
||||||
Rml::Debugger::Initialise(ctx);
|
Rml::Debugger::Initialise(ctx);
|
||||||
|
|
||||||
auto doc = ctx->LoadDocument("assets/main.rml");
|
auto doc = ctx->LoadDocument("assets/tests.rml");
|
||||||
doc->Show();
|
doc->Show();
|
||||||
|
|
||||||
Camera3D cam3;
|
Camera3D cam3;
|
||||||
cam3.position = Vector3 {0.0f, 10.0f, 10.0f};
|
cam3.position = Vector3{0.0f, 10.0f, 10.0f};
|
||||||
cam3.target = Vector3 {0.0f, 0.0f, 0.0f};
|
cam3.target = Vector3{0.0f, 0.0f, 0.0f};
|
||||||
cam3.up = Vector3 {0, 1.0f, 0.0f};
|
cam3.up = Vector3{0, 1.0f, 0.0f};
|
||||||
cam3.fovy = 45.0f;
|
cam3.fovy = 45.0f;
|
||||||
cam3.projection = CAMERA_PERSPECTIVE;
|
cam3.projection = CAMERA_PERSPECTIVE;
|
||||||
|
|
||||||
Vector3 cubePos = Vector3 {0.0f, 0.0f, 0.0f};
|
Vector3 cubePos = Vector3{0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
// DisableCursor();
|
// DisableCursor();
|
||||||
|
|
||||||
while (!WindowShouldClose()) {
|
while (!WindowShouldClose()) {
|
||||||
|
|
||||||
if (IsWindowResized()) {
|
if (IsWindowResized()) {
|
||||||
@@ -55,20 +54,22 @@ int main() {
|
|||||||
|
|
||||||
ForwardInputToRml(ctx);
|
ForwardInputToRml(ctx);
|
||||||
ctx->Update();
|
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();
|
BeginDrawing();
|
||||||
ClearBackground(BLACK);
|
ClearBackground(BLACK);
|
||||||
DrawFPS(10, 10);
|
DrawFPS(10, 10);
|
||||||
// DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10, RAYWHITE);
|
// DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10,
|
||||||
|
// RAYWHITE);
|
||||||
|
|
||||||
BeginMode3D(cam3);
|
BeginMode3D(cam3);
|
||||||
DrawCube(cubePos, 2.0f, 2.0f, 2.0f, RED);
|
DrawCube(cubePos, 2.0f, 2.0f, 2.0f, RED);
|
||||||
DrawCubeWires(cubePos, 2.0f, 2.0f, 2.0f, BLUE);
|
DrawCubeWires(cubePos, 2.0f, 2.0f, 2.0f, BLUE);
|
||||||
DrawGrid(10, 1.0f);
|
DrawGrid(10, 1.0f);
|
||||||
EndMode3D();
|
EndMode3D();
|
||||||
|
|
||||||
ctx->Render();
|
ctx->Render();
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user