RmlUi_Renderer_GL3.cpp 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149
  1. /*
  2. * This source file is part of RmlUi, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://github.com/mikke89/RmlUi
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. * Copyright (c) 2019-2023 The RmlUi Team, and contributors
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. *
  27. */
  28. #include "RmlUi_Renderer_GL3.h"
  29. #include <RmlUi/Core/Core.h>
  30. #include <RmlUi/Core/DecorationTypes.h>
  31. #include <RmlUi/Core/FileInterface.h>
  32. #include <RmlUi/Core/Geometry.h>
  33. #include <RmlUi/Core/Log.h>
  34. #include <RmlUi/Core/MeshUtilities.h>
  35. #include <RmlUi/Core/Platform.h>
  36. #include <RmlUi/Core/SystemInterface.h>
  37. #include <string.h>
  38. #if defined(RMLUI_PLATFORM_WIN32) && !defined(__MINGW32__)
  39. // function call missing argument list
  40. #pragma warning(disable : 4551)
  41. // unreferenced local function has been removed
  42. #pragma warning(disable : 4505)
  43. #endif
  44. #if defined RMLUI_PLATFORM_EMSCRIPTEN
  45. #define RMLUI_SHADER_HEADER_VERSION "#version 300 es\nprecision highp float;\n"
  46. #include <GLES3/gl3.h>
  47. #elif defined RMLUI_GL3_CUSTOM_LOADER
  48. #define RMLUI_SHADER_HEADER_VERSION "#version 330\n"
  49. #include RMLUI_GL3_CUSTOM_LOADER
  50. #else
  51. #define RMLUI_SHADER_HEADER_VERSION "#version 330\n"
  52. #define GLAD_GL_IMPLEMENTATION
  53. #include "RmlUi_Include_GL3.h"
  54. #endif
  55. // Determines the anti-aliasing quality when creating layers. Enables better-looking visuals, especially when transforms are applied.
  56. static constexpr int NUM_MSAA_SAMPLES = 2;
  57. #define MAX_NUM_STOPS 16
  58. #define BLUR_SIZE 7
  59. #define BLUR_NUM_WEIGHTS ((BLUR_SIZE + 1) / 2)
  60. #define RMLUI_STRINGIFY_IMPL(x) #x
  61. #define RMLUI_STRINGIFY(x) RMLUI_STRINGIFY_IMPL(x)
  62. #define RMLUI_SHADER_HEADER RMLUI_SHADER_HEADER_VERSION "#define MAX_NUM_STOPS " RMLUI_STRINGIFY(MAX_NUM_STOPS) "\n"
  63. static const char* shader_vert_main = RMLUI_SHADER_HEADER R"(
  64. uniform vec2 _translate;
  65. uniform mat4 _transform;
  66. in vec2 inPosition;
  67. in vec4 inColor0;
  68. in vec2 inTexCoord0;
  69. out vec2 fragTexCoord;
  70. out vec4 fragColor;
  71. void main() {
  72. fragTexCoord = inTexCoord0;
  73. fragColor = inColor0;
  74. vec2 translatedPos = inPosition + _translate;
  75. vec4 outPos = _transform * vec4(translatedPos, 0.0, 1.0);
  76. gl_Position = outPos;
  77. }
  78. )";
  79. static const char* shader_frag_texture = RMLUI_SHADER_HEADER R"(
  80. uniform sampler2D _tex;
  81. in vec2 fragTexCoord;
  82. in vec4 fragColor;
  83. out vec4 finalColor;
  84. void main() {
  85. vec4 texColor = texture(_tex, fragTexCoord);
  86. finalColor = fragColor * texColor;
  87. }
  88. )";
  89. static const char* shader_frag_color = RMLUI_SHADER_HEADER R"(
  90. in vec2 fragTexCoord;
  91. in vec4 fragColor;
  92. out vec4 finalColor;
  93. void main() {
  94. finalColor = fragColor;
  95. }
  96. )";
  97. enum class ShaderGradientFunction { Linear, Radial, Conic, RepeatingLinear, RepeatingRadial, RepeatingConic }; // Must match shader definitions below.
  98. static const char* shader_frag_gradient = RMLUI_SHADER_HEADER R"(
  99. #define LINEAR 0
  100. #define RADIAL 1
  101. #define CONIC 2
  102. #define REPEATING_LINEAR 3
  103. #define REPEATING_RADIAL 4
  104. #define REPEATING_CONIC 5
  105. #define PI 3.14159265
  106. uniform int _func; // one of the above definitions
  107. uniform vec2 _p; // linear: starting point, radial: center, conic: center
  108. uniform vec2 _v; // linear: vector to ending point, radial: 2d curvature (inverse radius), conic: angled unit vector
  109. uniform vec4 _stop_colors[MAX_NUM_STOPS];
  110. uniform float _stop_positions[MAX_NUM_STOPS]; // normalized, 0 -> starting point, 1 -> ending point
  111. uniform int _num_stops;
  112. in vec2 fragTexCoord;
  113. in vec4 fragColor;
  114. out vec4 finalColor;
  115. vec4 mix_stop_colors(float t) {
  116. vec4 color = _stop_colors[0];
  117. for (int i = 1; i < _num_stops; i++)
  118. color = mix(color, _stop_colors[i], smoothstep(_stop_positions[i-1], _stop_positions[i], t));
  119. return color;
  120. }
  121. void main() {
  122. float t = 0;
  123. if (_func == LINEAR || _func == REPEATING_LINEAR)
  124. {
  125. float dist_square = dot(_v, _v);
  126. vec2 V = fragTexCoord - _p;
  127. t = dot(_v, V) / dist_square;
  128. }
  129. else if (_func == RADIAL || _func == REPEATING_RADIAL)
  130. {
  131. vec2 V = fragTexCoord - _p;
  132. t = length(_v * V);
  133. }
  134. else if (_func == CONIC || _func == REPEATING_CONIC)
  135. {
  136. mat2 R = mat2(_v.x, -_v.y, _v.y, _v.x);
  137. vec2 V = R * (fragTexCoord - _p);
  138. t = 0.5 + atan(-V.x, V.y) / (2.0 * PI);
  139. }
  140. if (_func == REPEATING_LINEAR || _func == REPEATING_RADIAL || _func == REPEATING_CONIC)
  141. {
  142. float t0 = _stop_positions[0];
  143. float t1 = _stop_positions[_num_stops - 1];
  144. t = t0 + mod(t - t0, t1 - t0);
  145. }
  146. finalColor = fragColor * mix_stop_colors(t);
  147. }
  148. )";
  149. // "Creation" by Danilo Guanabara, based on: https://www.shadertoy.com/view/XsXXDn
  150. static const char* shader_frag_creation = RMLUI_SHADER_HEADER R"(
  151. uniform float _value;
  152. uniform vec2 _dimensions;
  153. in vec2 fragTexCoord;
  154. in vec4 fragColor;
  155. out vec4 finalColor;
  156. void main() {
  157. float t = _value;
  158. vec3 c;
  159. float l;
  160. for (int i = 0; i < 3; i++) {
  161. vec2 p = fragTexCoord;
  162. vec2 uv = p;
  163. p -= .5;
  164. p.x *= _dimensions.x / _dimensions.y;
  165. float z = t + float(i) * .07;
  166. l = length(p);
  167. uv += p / l * (sin(z) + 1.) * abs(sin(l * 9. - z - z));
  168. c[i] = .01 / length(mod(uv, 1.) - .5);
  169. }
  170. finalColor = vec4(c / l, fragColor.a);
  171. }
  172. )";
  173. static const char* shader_vert_passthrough = RMLUI_SHADER_HEADER R"(
  174. in vec2 inPosition;
  175. in vec2 inTexCoord0;
  176. out vec2 fragTexCoord;
  177. void main() {
  178. fragTexCoord = inTexCoord0;
  179. gl_Position = vec4(inPosition, 0.0, 1.0);
  180. }
  181. )";
  182. static const char* shader_frag_passthrough = RMLUI_SHADER_HEADER R"(
  183. uniform sampler2D _tex;
  184. in vec2 fragTexCoord;
  185. out vec4 finalColor;
  186. void main() {
  187. finalColor = texture(_tex, fragTexCoord);
  188. }
  189. )";
  190. static const char* shader_frag_color_matrix = RMLUI_SHADER_HEADER R"(
  191. uniform sampler2D _tex;
  192. uniform mat4 _color_matrix;
  193. in vec2 fragTexCoord;
  194. out vec4 finalColor;
  195. void main() {
  196. // The general case uses a 4x5 color matrix for full rgba transformation, plus a constant term with the last column.
  197. // However, we only consider the case of rgb transformations. Thus, we could in principle use a 3x4 matrix, but we
  198. // keep the alpha row for simplicity.
  199. // In the general case we should do the matrix transformation in non-premultiplied space. However, without alpha
  200. // transformations, we can do it directly in premultiplied space to avoid the extra division and multiplication
  201. // steps. In this space, the constant term needs to be multiplied by the alpha value, instead of unity.
  202. vec4 texColor = texture(_tex, fragTexCoord);
  203. vec3 transformedColor = vec3(_color_matrix * texColor);
  204. finalColor = vec4(transformedColor, texColor.a);
  205. }
  206. )";
  207. static const char* shader_frag_blend_mask = RMLUI_SHADER_HEADER R"(
  208. uniform sampler2D _tex;
  209. uniform sampler2D _texMask;
  210. in vec2 fragTexCoord;
  211. out vec4 finalColor;
  212. void main() {
  213. vec4 texColor = texture(_tex, fragTexCoord);
  214. float maskAlpha = texture(_texMask, fragTexCoord).a;
  215. finalColor = texColor * maskAlpha;
  216. }
  217. )";
  218. #define RMLUI_SHADER_BLUR_HEADER \
  219. RMLUI_SHADER_HEADER "\n#define BLUR_SIZE " RMLUI_STRINGIFY(BLUR_SIZE) "\n#define BLUR_NUM_WEIGHTS " RMLUI_STRINGIFY(BLUR_NUM_WEIGHTS)
  220. static const char* shader_vert_blur = RMLUI_SHADER_BLUR_HEADER R"(
  221. uniform vec2 _texelOffset;
  222. in vec3 inPosition;
  223. in vec2 inTexCoord0;
  224. out vec2 fragTexCoord[BLUR_SIZE];
  225. void main() {
  226. for(int i = 0; i < BLUR_SIZE; i++)
  227. fragTexCoord[i] = inTexCoord0 - float(i - BLUR_NUM_WEIGHTS + 1) * _texelOffset;
  228. gl_Position = vec4(inPosition, 1.0);
  229. }
  230. )";
  231. static const char* shader_frag_blur = RMLUI_SHADER_BLUR_HEADER R"(
  232. uniform sampler2D _tex;
  233. uniform float _weights[BLUR_NUM_WEIGHTS];
  234. uniform vec2 _texCoordMin;
  235. uniform vec2 _texCoordMax;
  236. in vec2 fragTexCoord[BLUR_SIZE];
  237. out vec4 finalColor;
  238. void main() {
  239. vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
  240. for(int i = 0; i < BLUR_SIZE; i++)
  241. {
  242. vec2 in_region = step(_texCoordMin, fragTexCoord[i]) * step(fragTexCoord[i], _texCoordMax);
  243. color += texture(_tex, fragTexCoord[i]) * in_region.x * in_region.y * _weights[abs(i - BLUR_NUM_WEIGHTS + 1)];
  244. }
  245. finalColor = color;
  246. }
  247. )";
  248. static const char* shader_frag_drop_shadow = RMLUI_SHADER_HEADER R"(
  249. uniform sampler2D _tex;
  250. uniform vec2 _texCoordMin;
  251. uniform vec2 _texCoordMax;
  252. uniform vec4 _color;
  253. in vec2 fragTexCoord;
  254. out vec4 finalColor;
  255. void main() {
  256. vec2 in_region = step(_texCoordMin, fragTexCoord) * step(fragTexCoord, _texCoordMax);
  257. finalColor = texture(_tex, fragTexCoord).a * in_region.x * in_region.y * _color;
  258. }
  259. )";
  260. enum class ProgramId {
  261. None,
  262. Color,
  263. Texture,
  264. Gradient,
  265. Creation,
  266. Passthrough,
  267. ColorMatrix,
  268. BlendMask,
  269. Blur,
  270. DropShadow,
  271. Count,
  272. };
  273. enum class VertShaderId {
  274. Main,
  275. Passthrough,
  276. Blur,
  277. Count,
  278. };
  279. enum class FragShaderId {
  280. Color,
  281. Texture,
  282. Gradient,
  283. Creation,
  284. Passthrough,
  285. ColorMatrix,
  286. BlendMask,
  287. Blur,
  288. DropShadow,
  289. Count,
  290. };
  291. enum class UniformId {
  292. Translate,
  293. Transform,
  294. Tex,
  295. Color,
  296. ColorMatrix,
  297. TexelOffset,
  298. TexCoordMin,
  299. TexCoordMax,
  300. TexMask,
  301. Weights,
  302. Func,
  303. P,
  304. V,
  305. StopColors,
  306. StopPositions,
  307. NumStops,
  308. Value,
  309. Dimensions,
  310. Count,
  311. };
  312. namespace Gfx {
  313. static const char* const program_uniform_names[(size_t)UniformId::Count] = {"_translate", "_transform", "_tex", "_color", "_color_matrix",
  314. "_texelOffset", "_texCoordMin", "_texCoordMax", "_texMask", "_weights[0]", "_func", "_p", "_v", "_stop_colors[0]", "_stop_positions[0]",
  315. "_num_stops", "_value", "_dimensions"};
  316. enum class VertexAttribute { Position, Color0, TexCoord0, Count };
  317. static const char* const vertex_attribute_names[(size_t)VertexAttribute::Count] = {"inPosition", "inColor0", "inTexCoord0"};
  318. struct VertShaderDefinition {
  319. VertShaderId id;
  320. const char* name_str;
  321. const char* code_str;
  322. };
  323. struct FragShaderDefinition {
  324. FragShaderId id;
  325. const char* name_str;
  326. const char* code_str;
  327. };
  328. struct ProgramDefinition {
  329. ProgramId id;
  330. const char* name_str;
  331. VertShaderId vert_shader;
  332. FragShaderId frag_shader;
  333. };
  334. // clang-format off
  335. static const VertShaderDefinition vert_shader_definitions[] = {
  336. {VertShaderId::Main, "main", shader_vert_main},
  337. {VertShaderId::Passthrough, "passthrough", shader_vert_passthrough},
  338. {VertShaderId::Blur, "blur", shader_vert_blur},
  339. };
  340. static const FragShaderDefinition frag_shader_definitions[] = {
  341. {FragShaderId::Color, "color", shader_frag_color},
  342. {FragShaderId::Texture, "texture", shader_frag_texture},
  343. {FragShaderId::Gradient, "gradient", shader_frag_gradient},
  344. {FragShaderId::Creation, "creation", shader_frag_creation},
  345. {FragShaderId::Passthrough, "passthrough", shader_frag_passthrough},
  346. {FragShaderId::ColorMatrix, "color_matrix", shader_frag_color_matrix},
  347. {FragShaderId::BlendMask, "blend_mask", shader_frag_blend_mask},
  348. {FragShaderId::Blur, "blur", shader_frag_blur},
  349. {FragShaderId::DropShadow, "drop_shadow", shader_frag_drop_shadow},
  350. };
  351. static const ProgramDefinition program_definitions[] = {
  352. {ProgramId::Color, "color", VertShaderId::Main, FragShaderId::Color},
  353. {ProgramId::Texture, "texture", VertShaderId::Main, FragShaderId::Texture},
  354. {ProgramId::Gradient, "gradient", VertShaderId::Main, FragShaderId::Gradient},
  355. {ProgramId::Creation, "creation", VertShaderId::Main, FragShaderId::Creation},
  356. {ProgramId::Passthrough, "passthrough", VertShaderId::Passthrough, FragShaderId::Passthrough},
  357. {ProgramId::ColorMatrix, "color_matrix", VertShaderId::Passthrough, FragShaderId::ColorMatrix},
  358. {ProgramId::BlendMask, "blend_mask", VertShaderId::Passthrough, FragShaderId::BlendMask},
  359. {ProgramId::Blur, "blur", VertShaderId::Blur, FragShaderId::Blur},
  360. {ProgramId::DropShadow, "drop_shadow", VertShaderId::Passthrough, FragShaderId::DropShadow},
  361. };
  362. // clang-format on
  363. template <typename T, typename Enum>
  364. class EnumArray {
  365. public:
  366. const T& operator[](Enum id) const
  367. {
  368. RMLUI_ASSERT((size_t)id < (size_t)Enum::Count);
  369. return ids[size_t(id)];
  370. }
  371. T& operator[](Enum id)
  372. {
  373. RMLUI_ASSERT((size_t)id < (size_t)Enum::Count);
  374. return ids[size_t(id)];
  375. }
  376. auto begin() const { return ids.begin(); }
  377. auto end() const { return ids.end(); }
  378. private:
  379. Rml::Array<T, (size_t)Enum::Count> ids = {};
  380. };
  381. using Programs = EnumArray<GLuint, ProgramId>;
  382. using VertShaders = EnumArray<GLuint, VertShaderId>;
  383. using FragShaders = EnumArray<GLuint, FragShaderId>;
  384. class Uniforms {
  385. public:
  386. GLint Get(ProgramId id, UniformId uniform) const
  387. {
  388. auto it = map.find(ToKey(id, uniform));
  389. if (it != map.end())
  390. return it->second;
  391. return -1;
  392. }
  393. void Insert(ProgramId id, UniformId uniform, GLint location) { map[ToKey(id, uniform)] = location; }
  394. private:
  395. using Key = std::uint64_t;
  396. Key ToKey(ProgramId id, UniformId uniform) const { return (static_cast<Key>(id) << 32) | static_cast<Key>(uniform); }
  397. Rml::UnorderedMap<Key, GLint> map;
  398. };
  399. struct ProgramData {
  400. Programs programs;
  401. VertShaders vert_shaders;
  402. FragShaders frag_shaders;
  403. Uniforms uniforms;
  404. };
  405. struct CompiledGeometryData {
  406. GLuint vao;
  407. GLuint vbo;
  408. GLuint ibo;
  409. GLsizei draw_count;
  410. };
  411. struct FramebufferData {
  412. int width, height;
  413. GLuint framebuffer;
  414. GLuint color_tex_buffer;
  415. GLuint color_render_buffer;
  416. GLuint depth_stencil_buffer;
  417. bool owns_depth_stencil_buffer;
  418. };
  419. enum class FramebufferAttachment { None, Depth, DepthStencil };
  420. static void CheckGLError(const char* operation_name)
  421. {
  422. #ifdef RMLUI_DEBUG
  423. GLenum error_code = glGetError();
  424. if (error_code != GL_NO_ERROR)
  425. {
  426. static const Rml::Pair<GLenum, const char*> error_names[] = {{GL_INVALID_ENUM, "GL_INVALID_ENUM"}, {GL_INVALID_VALUE, "GL_INVALID_VALUE"},
  427. {GL_INVALID_OPERATION, "GL_INVALID_OPERATION"}, {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY"}};
  428. const char* error_str = "''";
  429. for (auto& err : error_names)
  430. {
  431. if (err.first == error_code)
  432. {
  433. error_str = err.second;
  434. break;
  435. }
  436. }
  437. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL error during %s. Error code 0x%x (%s).", operation_name, error_code, error_str);
  438. }
  439. #endif
  440. (void)operation_name;
  441. }
  442. // Create the shader, 'shader_type' is either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
  443. static bool CreateShader(GLuint& out_shader_id, GLenum shader_type, const char* code_string)
  444. {
  445. RMLUI_ASSERT(shader_type == GL_VERTEX_SHADER || shader_type == GL_FRAGMENT_SHADER);
  446. GLuint id = glCreateShader(shader_type);
  447. glShaderSource(id, 1, (const GLchar**)&code_string, NULL);
  448. glCompileShader(id);
  449. GLint status = 0;
  450. glGetShaderiv(id, GL_COMPILE_STATUS, &status);
  451. if (status == GL_FALSE)
  452. {
  453. GLint info_log_length = 0;
  454. glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
  455. char* info_log_string = new char[info_log_length + 1];
  456. glGetShaderInfoLog(id, info_log_length, NULL, info_log_string);
  457. Rml::Log::Message(Rml::Log::LT_ERROR, "Compile failure in OpenGL shader: %s", info_log_string);
  458. delete[] info_log_string;
  459. glDeleteShader(id);
  460. return false;
  461. }
  462. CheckGLError("CreateShader");
  463. out_shader_id = id;
  464. return true;
  465. }
  466. static bool CreateProgram(GLuint& out_program, Uniforms& inout_uniform_map, ProgramId program_id, GLuint vertex_shader, GLuint fragment_shader)
  467. {
  468. GLuint id = glCreateProgram();
  469. RMLUI_ASSERT(id);
  470. for (GLuint i = 0; i < (GLuint)VertexAttribute::Count; i++)
  471. glBindAttribLocation(id, i, vertex_attribute_names[i]);
  472. CheckGLError("BindAttribLocations");
  473. glAttachShader(id, vertex_shader);
  474. glAttachShader(id, fragment_shader);
  475. glLinkProgram(id);
  476. glDetachShader(id, vertex_shader);
  477. glDetachShader(id, fragment_shader);
  478. GLint status = 0;
  479. glGetProgramiv(id, GL_LINK_STATUS, &status);
  480. if (status == GL_FALSE)
  481. {
  482. GLint info_log_length = 0;
  483. glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
  484. char* info_log_string = new char[info_log_length + 1];
  485. glGetProgramInfoLog(id, info_log_length, NULL, info_log_string);
  486. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program linking failure: %s", info_log_string);
  487. delete[] info_log_string;
  488. glDeleteProgram(id);
  489. return false;
  490. }
  491. out_program = id;
  492. // Make a lookup table for the uniform locations.
  493. GLint num_active_uniforms = 0;
  494. glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
  495. constexpr size_t name_size = 64;
  496. GLchar name_buf[name_size] = "";
  497. for (int unif = 0; unif < num_active_uniforms; ++unif)
  498. {
  499. GLint array_size = 0;
  500. GLenum type = 0;
  501. GLsizei actual_length = 0;
  502. glGetActiveUniform(id, unif, name_size, &actual_length, &array_size, &type, name_buf);
  503. GLint location = glGetUniformLocation(id, name_buf);
  504. // See if we have the name in our pre-defined name list.
  505. UniformId program_uniform = UniformId::Count;
  506. for (int i = 0; i < (int)UniformId::Count; i++)
  507. {
  508. const char* uniform_name = program_uniform_names[i];
  509. if (strcmp(name_buf, uniform_name) == 0)
  510. {
  511. program_uniform = (UniformId)i;
  512. break;
  513. }
  514. }
  515. if ((size_t)program_uniform < (size_t)UniformId::Count)
  516. {
  517. inout_uniform_map.Insert(program_id, program_uniform, location);
  518. }
  519. else
  520. {
  521. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program uses unknown uniform '%s'.", name_buf);
  522. return false;
  523. }
  524. }
  525. CheckGLError("CreateProgram");
  526. return true;
  527. }
  528. static bool CreateFramebuffer(FramebufferData& out_fb, int width, int height, int samples, FramebufferAttachment attachment,
  529. GLuint shared_depth_stencil_buffer)
  530. {
  531. #ifdef RMLUI_PLATFORM_EMSCRIPTEN
  532. constexpr GLint wrap_mode = GL_CLAMP_TO_EDGE;
  533. #else
  534. constexpr GLint wrap_mode = GL_CLAMP_TO_BORDER; // GL_REPEAT GL_MIRRORED_REPEAT GL_CLAMP_TO_EDGE
  535. #endif
  536. constexpr GLenum color_format = GL_RGBA8; // GL_RGBA8 GL_SRGB8_ALPHA8 GL_RGBA16F
  537. constexpr GLint min_mag_filter = GL_LINEAR; // GL_NEAREST
  538. const Rml::Colourf border_color(0.f, 0.f);
  539. GLuint framebuffer = 0;
  540. glGenFramebuffers(1, &framebuffer);
  541. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  542. GLuint color_tex_buffer = 0;
  543. GLuint color_render_buffer = 0;
  544. if (samples > 0)
  545. {
  546. glGenRenderbuffers(1, &color_render_buffer);
  547. glBindRenderbuffer(GL_RENDERBUFFER, color_render_buffer);
  548. glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, color_format, width, height);
  549. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_render_buffer);
  550. }
  551. else
  552. {
  553. glGenTextures(1, &color_tex_buffer);
  554. glBindTexture(GL_TEXTURE_2D, color_tex_buffer);
  555. glTexImage2D(GL_TEXTURE_2D, 0, color_format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  556. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_mag_filter);
  557. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, min_mag_filter);
  558. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode);
  559. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode);
  560. #ifndef RMLUI_PLATFORM_EMSCRIPTEN
  561. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, &border_color[0]);
  562. #endif
  563. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex_buffer, 0);
  564. }
  565. // Create depth/stencil buffer storage attachment.
  566. GLuint depth_stencil_buffer = 0;
  567. if (attachment != FramebufferAttachment::None)
  568. {
  569. if (shared_depth_stencil_buffer)
  570. {
  571. // Share depth/stencil buffer
  572. depth_stencil_buffer = shared_depth_stencil_buffer;
  573. }
  574. else
  575. {
  576. // Create new depth/stencil buffer
  577. glGenRenderbuffers(1, &depth_stencil_buffer);
  578. glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_buffer);
  579. const GLenum internal_format = (attachment == FramebufferAttachment::DepthStencil ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT24);
  580. glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internal_format, width, height);
  581. }
  582. const GLenum attachment_type = (attachment == FramebufferAttachment::DepthStencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
  583. glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_type, GL_RENDERBUFFER, depth_stencil_buffer);
  584. }
  585. const GLuint framebuffer_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  586. if (framebuffer_status != GL_FRAMEBUFFER_COMPLETE)
  587. {
  588. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL framebuffer could not be generated. Error code %x.", framebuffer_status);
  589. return false;
  590. }
  591. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  592. glBindTexture(GL_TEXTURE_2D, 0);
  593. glBindRenderbuffer(GL_RENDERBUFFER, 0);
  594. CheckGLError("CreateFramebuffer");
  595. out_fb = {};
  596. out_fb.width = width;
  597. out_fb.height = height;
  598. out_fb.framebuffer = framebuffer;
  599. out_fb.color_tex_buffer = color_tex_buffer;
  600. out_fb.color_render_buffer = color_render_buffer;
  601. out_fb.depth_stencil_buffer = depth_stencil_buffer;
  602. out_fb.owns_depth_stencil_buffer = !shared_depth_stencil_buffer;
  603. return true;
  604. }
  605. static void DestroyFramebuffer(FramebufferData& fb)
  606. {
  607. if (fb.framebuffer)
  608. glDeleteFramebuffers(1, &fb.framebuffer);
  609. if (fb.color_tex_buffer)
  610. glDeleteTextures(1, &fb.color_tex_buffer);
  611. if (fb.color_render_buffer)
  612. glDeleteRenderbuffers(1, &fb.color_render_buffer);
  613. if (fb.owns_depth_stencil_buffer && fb.depth_stencil_buffer)
  614. glDeleteRenderbuffers(1, &fb.depth_stencil_buffer);
  615. fb = {};
  616. }
  617. static void BindTexture(const FramebufferData& fb)
  618. {
  619. if (!fb.color_tex_buffer)
  620. {
  621. RMLUI_ERRORMSG("Only framebuffers with color textures can be bound as textures. This framebuffer probably uses multisampling which needs a "
  622. "blit step first.");
  623. }
  624. glBindTexture(GL_TEXTURE_2D, fb.color_tex_buffer);
  625. }
  626. static bool CreateShaders(ProgramData& data)
  627. {
  628. RMLUI_ASSERT(std::all_of(data.vert_shaders.begin(), data.vert_shaders.end(), [](auto&& value) { return value == 0; }));
  629. RMLUI_ASSERT(std::all_of(data.frag_shaders.begin(), data.frag_shaders.end(), [](auto&& value) { return value == 0; }));
  630. RMLUI_ASSERT(std::all_of(data.programs.begin(), data.programs.end(), [](auto&& value) { return value == 0; }));
  631. auto ReportError = [](const char* type, const char* name) {
  632. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL %s: '%s'.", type, name);
  633. return false;
  634. };
  635. for (const VertShaderDefinition& def : vert_shader_definitions)
  636. {
  637. if (!CreateShader(data.vert_shaders[def.id], GL_VERTEX_SHADER, def.code_str))
  638. return ReportError("vertex shader", def.name_str);
  639. }
  640. for (const FragShaderDefinition& def : frag_shader_definitions)
  641. {
  642. if (!CreateShader(data.frag_shaders[def.id], GL_FRAGMENT_SHADER, def.code_str))
  643. return ReportError("fragment shader", def.name_str);
  644. }
  645. for (const ProgramDefinition& def : program_definitions)
  646. {
  647. if (!CreateProgram(data.programs[def.id], data.uniforms, def.id, data.vert_shaders[def.vert_shader], data.frag_shaders[def.frag_shader]))
  648. return ReportError("program", def.name_str);
  649. }
  650. glUseProgram(data.programs[ProgramId::BlendMask]);
  651. glUniform1i(data.uniforms.Get(ProgramId::BlendMask, UniformId::TexMask), 1);
  652. glUseProgram(0);
  653. return true;
  654. }
  655. static void DestroyShaders(const ProgramData& data)
  656. {
  657. for (GLuint id : data.programs)
  658. glDeleteProgram(id);
  659. for (GLuint id : data.vert_shaders)
  660. glDeleteShader(id);
  661. for (GLuint id : data.frag_shaders)
  662. glDeleteShader(id);
  663. }
  664. } // namespace Gfx
  665. RenderInterface_GL3::RenderInterface_GL3()
  666. {
  667. auto mut_program_data = Rml::MakeUnique<Gfx::ProgramData>();
  668. if (Gfx::CreateShaders(*mut_program_data))
  669. {
  670. program_data = std::move(mut_program_data);
  671. Rml::Mesh mesh;
  672. Rml::MeshUtilities::GenerateQuad(mesh, Rml::Vector2f(-1), Rml::Vector2f(2), {});
  673. fullscreen_quad_geometry = RenderInterface_GL3::CompileGeometry(mesh.vertices, mesh.indices);
  674. }
  675. }
  676. RenderInterface_GL3::~RenderInterface_GL3()
  677. {
  678. if (fullscreen_quad_geometry)
  679. {
  680. RenderInterface_GL3::ReleaseGeometry(fullscreen_quad_geometry);
  681. fullscreen_quad_geometry = {};
  682. }
  683. if (program_data)
  684. {
  685. Gfx::DestroyShaders(*program_data);
  686. program_data.reset();
  687. }
  688. }
  689. void RenderInterface_GL3::SetViewport(int width, int height)
  690. {
  691. viewport_width = Rml::Math::Max(width, 1);
  692. viewport_height = Rml::Math::Max(height, 1);
  693. projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
  694. }
  695. void RenderInterface_GL3::BeginFrame()
  696. {
  697. RMLUI_ASSERT(viewport_width >= 1 && viewport_height >= 1);
  698. // Backup GL state.
  699. glstate_backup.enable_cull_face = glIsEnabled(GL_CULL_FACE);
  700. glstate_backup.enable_blend = glIsEnabled(GL_BLEND);
  701. glstate_backup.enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
  702. glstate_backup.enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
  703. glGetIntegerv(GL_VIEWPORT, glstate_backup.viewport);
  704. glGetIntegerv(GL_SCISSOR_BOX, glstate_backup.scissor);
  705. glGetIntegerv(GL_ACTIVE_TEXTURE, &glstate_backup.active_texture);
  706. glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &glstate_backup.stencil_clear_value);
  707. glGetFloatv(GL_COLOR_CLEAR_VALUE, glstate_backup.color_clear_value);
  708. glGetIntegerv(GL_BLEND_EQUATION_RGB, &glstate_backup.blend_equation_rgb);
  709. glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &glstate_backup.blend_equation_alpha);
  710. glGetIntegerv(GL_BLEND_SRC_RGB, &glstate_backup.blend_src_rgb);
  711. glGetIntegerv(GL_BLEND_DST_RGB, &glstate_backup.blend_dst_rgb);
  712. glGetIntegerv(GL_BLEND_SRC_ALPHA, &glstate_backup.blend_src_alpha);
  713. glGetIntegerv(GL_BLEND_DST_ALPHA, &glstate_backup.blend_dst_alpha);
  714. glGetIntegerv(GL_STENCIL_FUNC, &glstate_backup.stencil_front.func);
  715. glGetIntegerv(GL_STENCIL_REF, &glstate_backup.stencil_front.ref);
  716. glGetIntegerv(GL_STENCIL_VALUE_MASK, &glstate_backup.stencil_front.value_mask);
  717. glGetIntegerv(GL_STENCIL_WRITEMASK, &glstate_backup.stencil_front.writemask);
  718. glGetIntegerv(GL_STENCIL_FAIL, &glstate_backup.stencil_front.fail);
  719. glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &glstate_backup.stencil_front.pass_depth_fail);
  720. glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &glstate_backup.stencil_front.pass_depth_pass);
  721. glGetIntegerv(GL_STENCIL_BACK_FUNC, &glstate_backup.stencil_back.func);
  722. glGetIntegerv(GL_STENCIL_BACK_REF, &glstate_backup.stencil_back.ref);
  723. glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &glstate_backup.stencil_back.value_mask);
  724. glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &glstate_backup.stencil_back.writemask);
  725. glGetIntegerv(GL_STENCIL_BACK_FAIL, &glstate_backup.stencil_back.fail);
  726. glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &glstate_backup.stencil_back.pass_depth_fail);
  727. glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &glstate_backup.stencil_back.pass_depth_pass);
  728. // Setup expected GL state.
  729. glViewport(0, 0, viewport_width, viewport_height);
  730. glClearStencil(0);
  731. glClearColor(0, 0, 0, 0);
  732. glActiveTexture(GL_TEXTURE0);
  733. glDisable(GL_SCISSOR_TEST);
  734. glDisable(GL_CULL_FACE);
  735. // Set blending function for premultiplied alpha.
  736. glEnable(GL_BLEND);
  737. glBlendEquation(GL_FUNC_ADD);
  738. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  739. #ifndef RMLUI_PLATFORM_EMSCRIPTEN
  740. // We do blending in nonlinear sRGB space because that is the common practice and gives results that we are used to.
  741. glDisable(GL_FRAMEBUFFER_SRGB);
  742. #endif
  743. glEnable(GL_STENCIL_TEST);
  744. glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
  745. glStencilMask(GLuint(-1));
  746. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  747. SetTransform(nullptr);
  748. render_layers.BeginFrame(viewport_width, viewport_height);
  749. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  750. glClear(GL_COLOR_BUFFER_BIT);
  751. UseProgram(ProgramId::None);
  752. program_transform_dirty.set();
  753. scissor_state = Rml::Rectanglei::MakeInvalid();
  754. Gfx::CheckGLError("BeginFrame");
  755. }
  756. void RenderInterface_GL3::EndFrame()
  757. {
  758. const Gfx::FramebufferData& fb_active = render_layers.GetTopLayer();
  759. const Gfx::FramebufferData& fb_postprocess = render_layers.GetPostprocessPrimary();
  760. // Resolve MSAA to postprocess framebuffer.
  761. glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_active.framebuffer);
  762. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_postprocess.framebuffer);
  763. glBlitFramebuffer(0, 0, fb_active.width, fb_active.height, 0, 0, fb_postprocess.width, fb_postprocess.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  764. // Draw to backbuffer
  765. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  766. // Assuming we have an opaque background, we can just write to it with the premultiplied alpha blend mode and we'll get the correct result.
  767. // Instead, if we had a transparent destination that didn't use premultiplied alpha, we would need to perform a manual un-premultiplication step.
  768. glActiveTexture(GL_TEXTURE0);
  769. Gfx::BindTexture(fb_postprocess);
  770. UseProgram(ProgramId::Passthrough);
  771. DrawFullscreenQuad();
  772. render_layers.EndFrame();
  773. // Restore GL state.
  774. if (glstate_backup.enable_cull_face)
  775. glEnable(GL_CULL_FACE);
  776. else
  777. glDisable(GL_CULL_FACE);
  778. if (glstate_backup.enable_blend)
  779. glEnable(GL_BLEND);
  780. else
  781. glDisable(GL_BLEND);
  782. if (glstate_backup.enable_stencil_test)
  783. glEnable(GL_STENCIL_TEST);
  784. else
  785. glDisable(GL_STENCIL_TEST);
  786. if (glstate_backup.enable_scissor_test)
  787. glEnable(GL_SCISSOR_TEST);
  788. else
  789. glDisable(GL_SCISSOR_TEST);
  790. glViewport(glstate_backup.viewport[0], glstate_backup.viewport[1], glstate_backup.viewport[2], glstate_backup.viewport[3]);
  791. glScissor(glstate_backup.scissor[0], glstate_backup.scissor[1], glstate_backup.scissor[2], glstate_backup.scissor[3]);
  792. glActiveTexture(glstate_backup.active_texture);
  793. glClearStencil(glstate_backup.stencil_clear_value);
  794. glClearColor(glstate_backup.color_clear_value[0], glstate_backup.color_clear_value[1], glstate_backup.color_clear_value[2],
  795. glstate_backup.color_clear_value[3]);
  796. glBlendEquationSeparate(glstate_backup.blend_equation_rgb, glstate_backup.blend_equation_alpha);
  797. glBlendFuncSeparate(glstate_backup.blend_src_rgb, glstate_backup.blend_dst_rgb, glstate_backup.blend_src_alpha, glstate_backup.blend_dst_alpha);
  798. glStencilFuncSeparate(GL_FRONT, glstate_backup.stencil_front.func, glstate_backup.stencil_front.ref, glstate_backup.stencil_front.value_mask);
  799. glStencilMaskSeparate(GL_FRONT, glstate_backup.stencil_front.writemask);
  800. glStencilOpSeparate(GL_FRONT, glstate_backup.stencil_front.fail, glstate_backup.stencil_front.pass_depth_fail,
  801. glstate_backup.stencil_front.pass_depth_pass);
  802. glStencilFuncSeparate(GL_BACK, glstate_backup.stencil_back.func, glstate_backup.stencil_back.ref, glstate_backup.stencil_back.value_mask);
  803. glStencilMaskSeparate(GL_BACK, glstate_backup.stencil_back.writemask);
  804. glStencilOpSeparate(GL_BACK, glstate_backup.stencil_back.fail, glstate_backup.stencil_back.pass_depth_fail,
  805. glstate_backup.stencil_back.pass_depth_pass);
  806. Gfx::CheckGLError("EndFrame");
  807. }
  808. void RenderInterface_GL3::Clear()
  809. {
  810. glClearColor(0, 0, 0, 1);
  811. glClear(GL_COLOR_BUFFER_BIT);
  812. }
  813. Rml::CompiledGeometryHandle RenderInterface_GL3::CompileGeometry(Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices)
  814. {
  815. constexpr GLenum draw_usage = GL_STATIC_DRAW;
  816. GLuint vao = 0;
  817. GLuint vbo = 0;
  818. GLuint ibo = 0;
  819. glGenVertexArrays(1, &vao);
  820. glGenBuffers(1, &vbo);
  821. glGenBuffers(1, &ibo);
  822. glBindVertexArray(vao);
  823. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  824. glBufferData(GL_ARRAY_BUFFER, sizeof(Rml::Vertex) * vertices.size(), (const void*)vertices.data(), draw_usage);
  825. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Position);
  826. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
  827. (const GLvoid*)(offsetof(Rml::Vertex, position)));
  828. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Color0);
  829. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Rml::Vertex),
  830. (const GLvoid*)(offsetof(Rml::Vertex, colour)));
  831. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::TexCoord0);
  832. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
  833. (const GLvoid*)(offsetof(Rml::Vertex, tex_coord)));
  834. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  835. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices.size(), (const void*)indices.data(), draw_usage);
  836. glBindVertexArray(0);
  837. glBindBuffer(GL_ARRAY_BUFFER, 0);
  838. Gfx::CheckGLError("CompileGeometry");
  839. Gfx::CompiledGeometryData* geometry = new Gfx::CompiledGeometryData;
  840. geometry->vao = vao;
  841. geometry->vbo = vbo;
  842. geometry->ibo = ibo;
  843. geometry->draw_count = (GLsizei)indices.size();
  844. return (Rml::CompiledGeometryHandle)geometry;
  845. }
  846. void RenderInterface_GL3::RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation, Rml::TextureHandle texture)
  847. {
  848. Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
  849. if (texture == TexturePostprocess)
  850. {
  851. // Do nothing.
  852. }
  853. else if (texture)
  854. {
  855. UseProgram(ProgramId::Texture);
  856. SubmitTransformUniform(translation);
  857. if (texture != TextureEnableWithoutBinding)
  858. glBindTexture(GL_TEXTURE_2D, (GLuint)texture);
  859. }
  860. else
  861. {
  862. UseProgram(ProgramId::Color);
  863. glBindTexture(GL_TEXTURE_2D, 0);
  864. SubmitTransformUniform(translation);
  865. }
  866. glBindVertexArray(geometry->vao);
  867. glDrawElements(GL_TRIANGLES, geometry->draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
  868. glBindVertexArray(0);
  869. glBindTexture(GL_TEXTURE_2D, 0);
  870. Gfx::CheckGLError("RenderCompiledGeometry");
  871. }
  872. void RenderInterface_GL3::ReleaseGeometry(Rml::CompiledGeometryHandle handle)
  873. {
  874. Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
  875. glDeleteVertexArrays(1, &geometry->vao);
  876. glDeleteBuffers(1, &geometry->vbo);
  877. glDeleteBuffers(1, &geometry->ibo);
  878. delete geometry;
  879. }
  880. /// Flip vertical axis of the rectangle, and move its origin to the vertically opposite side of the viewport.
  881. /// @note Changes coordinate system from RmlUi to OpenGL, or equivalently in reverse.
  882. /// @note The Rectangle::Top and Rectangle::Bottom members will have reverse meaning in the returned rectangle.
  883. static Rml::Rectanglei VerticallyFlipped(Rml::Rectanglei rect, int viewport_height)
  884. {
  885. RMLUI_ASSERT(rect.Valid());
  886. Rml::Rectanglei flipped_rect = rect;
  887. flipped_rect.p0.y = viewport_height - rect.p1.y;
  888. flipped_rect.p1.y = viewport_height - rect.p0.y;
  889. return flipped_rect;
  890. }
  891. void RenderInterface_GL3::SetScissor(Rml::Rectanglei region, bool vertically_flip)
  892. {
  893. if (region.Valid() != scissor_state.Valid())
  894. {
  895. if (region.Valid())
  896. glEnable(GL_SCISSOR_TEST);
  897. else
  898. glDisable(GL_SCISSOR_TEST);
  899. }
  900. if (region.Valid() && vertically_flip)
  901. region = VerticallyFlipped(region, viewport_height);
  902. if (region.Valid() && region != scissor_state)
  903. glScissor(region.Left(), viewport_height - region.Bottom(), region.Width(), region.Height());
  904. Gfx::CheckGLError("SetScissorRegion");
  905. scissor_state = region;
  906. }
  907. void RenderInterface_GL3::EnableScissorRegion(bool enable)
  908. {
  909. // Assume enable is immediately followed by a SetScissorRegion() call, and ignore it here.
  910. if (!enable)
  911. SetScissor(Rml::Rectanglei::MakeInvalid(), false);
  912. }
  913. void RenderInterface_GL3::SetScissorRegion(Rml::Rectanglei region)
  914. {
  915. SetScissor(region);
  916. }
  917. void RenderInterface_GL3::EnableClipMask(bool enable)
  918. {
  919. if (enable)
  920. glEnable(GL_STENCIL_TEST);
  921. else
  922. glDisable(GL_STENCIL_TEST);
  923. }
  924. void RenderInterface_GL3::RenderToClipMask(Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation)
  925. {
  926. RMLUI_ASSERT(glIsEnabled(GL_STENCIL_TEST));
  927. using Rml::ClipMaskOperation;
  928. const bool clear_stencil = (operation == ClipMaskOperation::Set || operation == ClipMaskOperation::SetInverse);
  929. if (clear_stencil)
  930. {
  931. // @performance Increment the reference value instead of clearing each time.
  932. glClear(GL_STENCIL_BUFFER_BIT);
  933. }
  934. GLint stencil_test_value = 0;
  935. glGetIntegerv(GL_STENCIL_REF, &stencil_test_value);
  936. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  937. glStencilFunc(GL_ALWAYS, GLint(1), GLuint(-1));
  938. switch (operation)
  939. {
  940. case ClipMaskOperation::Set:
  941. {
  942. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  943. stencil_test_value = 1;
  944. }
  945. break;
  946. case ClipMaskOperation::SetInverse:
  947. {
  948. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  949. stencil_test_value = 0;
  950. }
  951. break;
  952. case ClipMaskOperation::Intersect:
  953. {
  954. glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
  955. stencil_test_value += 1;
  956. }
  957. break;
  958. }
  959. RenderGeometry(geometry, translation, {});
  960. // Restore state
  961. // @performance Cache state so we don't toggle it unnecessarily.
  962. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  963. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  964. glStencilFunc(GL_EQUAL, stencil_test_value, GLuint(-1));
  965. }
  966. // Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
  967. #pragma pack(1)
  968. struct TGAHeader {
  969. char idLength;
  970. char colourMapType;
  971. char dataType;
  972. short int colourMapOrigin;
  973. short int colourMapLength;
  974. char colourMapDepth;
  975. short int xOrigin;
  976. short int yOrigin;
  977. short int width;
  978. short int height;
  979. char bitsPerPixel;
  980. char imageDescriptor;
  981. };
  982. // Restore packing
  983. #pragma pack()
  984. Rml::TextureHandle RenderInterface_GL3::LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source)
  985. {
  986. Rml::FileInterface* file_interface = Rml::GetFileInterface();
  987. Rml::FileHandle file_handle = file_interface->Open(source);
  988. if (!file_handle)
  989. {
  990. return false;
  991. }
  992. file_interface->Seek(file_handle, 0, SEEK_END);
  993. size_t buffer_size = file_interface->Tell(file_handle);
  994. file_interface->Seek(file_handle, 0, SEEK_SET);
  995. if (buffer_size <= sizeof(TGAHeader))
  996. {
  997. Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
  998. file_interface->Close(file_handle);
  999. return false;
  1000. }
  1001. using Rml::byte;
  1002. Rml::UniquePtr<byte[]> buffer(new byte[buffer_size]);
  1003. file_interface->Read(buffer.get(), buffer_size, file_handle);
  1004. file_interface->Close(file_handle);
  1005. TGAHeader header;
  1006. memcpy(&header, buffer.get(), sizeof(TGAHeader));
  1007. int color_mode = header.bitsPerPixel / 8;
  1008. const size_t image_size = header.width * header.height * 4; // We always make 32bit textures
  1009. if (header.dataType != 2)
  1010. {
  1011. Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
  1012. return false;
  1013. }
  1014. // Ensure we have at least 3 colors
  1015. if (color_mode < 3)
  1016. {
  1017. Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
  1018. return false;
  1019. }
  1020. const byte* image_src = buffer.get() + sizeof(TGAHeader);
  1021. Rml::UniquePtr<byte[]> image_dest_buffer(new byte[image_size]);
  1022. byte* image_dest = image_dest_buffer.get();
  1023. // Targa is BGR, swap to RGB, flip Y axis, and convert to premultiplied alpha.
  1024. for (long y = 0; y < header.height; y++)
  1025. {
  1026. long read_index = y * header.width * color_mode;
  1027. long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * 4;
  1028. for (long x = 0; x < header.width; x++)
  1029. {
  1030. image_dest[write_index] = image_src[read_index + 2];
  1031. image_dest[write_index + 1] = image_src[read_index + 1];
  1032. image_dest[write_index + 2] = image_src[read_index];
  1033. if (color_mode == 4)
  1034. {
  1035. const byte alpha = image_src[read_index + 3];
  1036. for (size_t j = 0; j < 3; j++)
  1037. image_dest[write_index + j] = byte((image_dest[write_index + j] * alpha) / 255);
  1038. image_dest[write_index + 3] = alpha;
  1039. }
  1040. else
  1041. image_dest[write_index + 3] = 255;
  1042. write_index += 4;
  1043. read_index += color_mode;
  1044. }
  1045. }
  1046. texture_dimensions.x = header.width;
  1047. texture_dimensions.y = header.height;
  1048. return GenerateTexture({image_dest, image_size}, texture_dimensions);
  1049. }
  1050. Rml::TextureHandle RenderInterface_GL3::GenerateTexture(Rml::Span<const Rml::byte> source_data, Rml::Vector2i source_dimensions)
  1051. {
  1052. GLuint texture_id = 0;
  1053. glGenTextures(1, &texture_id);
  1054. if (texture_id == 0)
  1055. {
  1056. Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
  1057. return false;
  1058. }
  1059. glBindTexture(GL_TEXTURE_2D, texture_id);
  1060. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source_data.data());
  1061. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1062. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1063. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  1064. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  1065. glBindTexture(GL_TEXTURE_2D, 0);
  1066. return (Rml::TextureHandle)texture_id;
  1067. }
  1068. void RenderInterface_GL3::DrawFullscreenQuad()
  1069. {
  1070. RenderGeometry(fullscreen_quad_geometry, {}, RenderInterface_GL3::TexturePostprocess);
  1071. }
  1072. void RenderInterface_GL3::DrawFullscreenQuad(Rml::Vector2f uv_offset, Rml::Vector2f uv_scaling)
  1073. {
  1074. Rml::Mesh mesh;
  1075. Rml::MeshUtilities::GenerateQuad(mesh, Rml::Vector2f(-1), Rml::Vector2f(2), {});
  1076. if (uv_offset != Rml::Vector2f() || uv_scaling != Rml::Vector2f(1.f))
  1077. {
  1078. for (Rml::Vertex& vertex : mesh.vertices)
  1079. vertex.tex_coord = (vertex.tex_coord * uv_scaling) + uv_offset;
  1080. }
  1081. const Rml::CompiledGeometryHandle geometry = CompileGeometry(mesh.vertices, mesh.indices);
  1082. RenderGeometry(geometry, {}, RenderInterface_GL3::TexturePostprocess);
  1083. ReleaseGeometry(geometry);
  1084. }
  1085. static Rml::Colourf ConvertToColorf(Rml::ColourbPremultiplied c0)
  1086. {
  1087. Rml::Colourf result;
  1088. for (int i = 0; i < 4; i++)
  1089. result[i] = (1.f / 255.f) * float(c0[i]);
  1090. return result;
  1091. }
  1092. static void SigmaToParameters(const float desired_sigma, int& out_pass_level, float& out_sigma)
  1093. {
  1094. constexpr int max_num_passes = 10;
  1095. static_assert(max_num_passes < 31, "");
  1096. constexpr float max_single_pass_sigma = 3.0f;
  1097. out_pass_level = Rml::Math::Clamp(Rml::Math::Log2(int(desired_sigma * (2.f / max_single_pass_sigma))), 0, max_num_passes);
  1098. out_sigma = Rml::Math::Clamp(desired_sigma / float(1 << out_pass_level), 0.0f, max_single_pass_sigma);
  1099. }
  1100. static void SetTexCoordLimits(GLint tex_coord_min_location, GLint tex_coord_max_location, Rml::Rectanglei rectangle_flipped,
  1101. Rml::Vector2i framebuffer_size)
  1102. {
  1103. // Offset by half-texel values so that texture lookups are clamped to fragment centers, thereby avoiding color
  1104. // bleeding from neighboring texels due to bilinear interpolation.
  1105. const Rml::Vector2f min = (Rml::Vector2f(rectangle_flipped.p0) + Rml::Vector2f(0.5f)) / Rml::Vector2f(framebuffer_size);
  1106. const Rml::Vector2f max = (Rml::Vector2f(rectangle_flipped.p1) - Rml::Vector2f(0.5f)) / Rml::Vector2f(framebuffer_size);
  1107. glUniform2f(tex_coord_min_location, min.x, min.y);
  1108. glUniform2f(tex_coord_max_location, max.x, max.y);
  1109. }
  1110. static void SetBlurWeights(GLint weights_location, float sigma)
  1111. {
  1112. constexpr int num_weights = BLUR_NUM_WEIGHTS;
  1113. float weights[num_weights];
  1114. float normalization = 0.0f;
  1115. for (int i = 0; i < num_weights; i++)
  1116. {
  1117. if (Rml::Math::Absolute(sigma) < 0.1f)
  1118. weights[i] = float(i == 0);
  1119. else
  1120. weights[i] = Rml::Math::Exp(-float(i * i) / (2.0f * sigma * sigma)) / (Rml::Math::SquareRoot(2.f * Rml::Math::RMLUI_PI) * sigma);
  1121. normalization += (i == 0 ? 1.f : 2.0f) * weights[i];
  1122. }
  1123. for (int i = 0; i < num_weights; i++)
  1124. weights[i] /= normalization;
  1125. glUniform1fv(weights_location, (GLsizei)num_weights, &weights[0]);
  1126. }
  1127. void RenderInterface_GL3::RenderBlur(float sigma, const Gfx::FramebufferData& source_destination, const Gfx::FramebufferData& temp,
  1128. const Rml::Rectanglei window_flipped)
  1129. {
  1130. RMLUI_ASSERT(&source_destination != &temp && source_destination.width == temp.width && source_destination.height == temp.height);
  1131. RMLUI_ASSERT(window_flipped.Valid());
  1132. int pass_level = 0;
  1133. SigmaToParameters(sigma, pass_level, sigma);
  1134. const Rml::Rectanglei original_scissor = scissor_state;
  1135. // Begin by downscaling so that the blur pass can be done at a reduced resolution for large sigma.
  1136. Rml::Rectanglei scissor = window_flipped;
  1137. UseProgram(ProgramId::Passthrough);
  1138. SetScissor(scissor, true);
  1139. // Downscale by iterative half-scaling with bilinear filtering, to reduce aliasing.
  1140. glViewport(0, 0, source_destination.width / 2, source_destination.height / 2);
  1141. // Scale UVs if we have even dimensions, such that texture fetches align perfectly between texels, thereby producing a 50% blend of
  1142. // neighboring texels.
  1143. const Rml::Vector2f uv_scaling = {(source_destination.width % 2 == 1) ? (1.f - 1.f / float(source_destination.width)) : 1.f,
  1144. (source_destination.height % 2 == 1) ? (1.f - 1.f / float(source_destination.height)) : 1.f};
  1145. for (int i = 0; i < pass_level; i++)
  1146. {
  1147. scissor.p0 = (scissor.p0 + Rml::Vector2i(1)) / 2;
  1148. scissor.p1 = Rml::Math::Max(scissor.p1 / 2, scissor.p0);
  1149. const bool from_source = (i % 2 == 0);
  1150. Gfx::BindTexture(from_source ? source_destination : temp);
  1151. glBindFramebuffer(GL_FRAMEBUFFER, (from_source ? temp : source_destination).framebuffer);
  1152. SetScissor(scissor, true);
  1153. DrawFullscreenQuad({}, uv_scaling);
  1154. }
  1155. glViewport(0, 0, source_destination.width, source_destination.height);
  1156. // Ensure texture data end up in the temp buffer. Depending on the last downscaling, we might need to move it from the source_destination buffer.
  1157. const bool transfer_to_temp_buffer = (pass_level % 2 == 0);
  1158. if (transfer_to_temp_buffer)
  1159. {
  1160. Gfx::BindTexture(source_destination);
  1161. glBindFramebuffer(GL_FRAMEBUFFER, temp.framebuffer);
  1162. DrawFullscreenQuad();
  1163. }
  1164. // Set up uniforms.
  1165. UseProgram(ProgramId::Blur);
  1166. SetBlurWeights(GetUniformLocation(UniformId::Weights), sigma);
  1167. SetTexCoordLimits(GetUniformLocation(UniformId::TexCoordMin), GetUniformLocation(UniformId::TexCoordMax), scissor,
  1168. {source_destination.width, source_destination.height});
  1169. const GLint texel_offset_location = GetUniformLocation(UniformId::TexelOffset);
  1170. auto SetTexelOffset = [texel_offset_location](Rml::Vector2f blur_direction, int texture_dimension) {
  1171. const Rml::Vector2f texel_offset = blur_direction * (1.0f / float(texture_dimension));
  1172. glUniform2f(texel_offset_location, texel_offset.x, texel_offset.y);
  1173. };
  1174. // Blur render pass - vertical.
  1175. Gfx::BindTexture(temp);
  1176. glBindFramebuffer(GL_FRAMEBUFFER, source_destination.framebuffer);
  1177. SetTexelOffset({0.f, 1.f}, temp.height);
  1178. DrawFullscreenQuad();
  1179. // Blur render pass - horizontal.
  1180. Gfx::BindTexture(source_destination);
  1181. glBindFramebuffer(GL_FRAMEBUFFER, temp.framebuffer);
  1182. SetTexelOffset({1.f, 0.f}, source_destination.width);
  1183. DrawFullscreenQuad();
  1184. // Blit the blurred image to the scissor region with upscaling.
  1185. SetScissor(window_flipped, true);
  1186. glBindFramebuffer(GL_READ_FRAMEBUFFER, temp.framebuffer);
  1187. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, source_destination.framebuffer);
  1188. const Rml::Vector2i src_min = scissor.p0;
  1189. const Rml::Vector2i src_max = scissor.p1;
  1190. const Rml::Vector2i dst_min = window_flipped.p0;
  1191. const Rml::Vector2i dst_max = window_flipped.p1;
  1192. glBlitFramebuffer(src_min.x, src_min.y, src_max.x, src_max.y, dst_min.x, dst_min.y, dst_max.x, dst_max.y, GL_COLOR_BUFFER_BIT, GL_LINEAR);
  1193. // The above upscale blit might be jittery at low resolutions (large pass levels). This is especially noticable when moving an element with
  1194. // backdrop blur around or when trying to click/hover an element within a blurred region since it may be rendered at an offset. For more stable
  1195. // and accurate rendering we next upscale the blur image by an exact power-of-two. However, this may not fill the edges completely so we need to
  1196. // do the above first. Note that this strategy may sometimes result in visible seams. Alternatively, we could try to enlargen the window to the
  1197. // next power-of-two size and then downsample and blur that.
  1198. const Rml::Vector2i target_min = src_min * (1 << pass_level);
  1199. const Rml::Vector2i target_max = src_max * (1 << pass_level);
  1200. if (target_min != dst_min || target_max != dst_max)
  1201. {
  1202. glBlitFramebuffer(src_min.x, src_min.y, src_max.x, src_max.y, target_min.x, target_min.y, target_max.x, target_max.y, GL_COLOR_BUFFER_BIT,
  1203. GL_LINEAR);
  1204. }
  1205. // Restore render state.
  1206. SetScissor(original_scissor);
  1207. Gfx::CheckGLError("Blur");
  1208. }
  1209. void RenderInterface_GL3::ReleaseTexture(Rml::TextureHandle texture_handle)
  1210. {
  1211. glDeleteTextures(1, (GLuint*)&texture_handle);
  1212. }
  1213. void RenderInterface_GL3::SetTransform(const Rml::Matrix4f* new_transform)
  1214. {
  1215. transform = (new_transform ? (projection * (*new_transform)) : projection);
  1216. program_transform_dirty.set();
  1217. }
  1218. enum class FilterType { Invalid = 0, Passthrough, Blur, DropShadow, ColorMatrix, MaskImage };
  1219. struct CompiledFilter {
  1220. FilterType type;
  1221. // Passthrough
  1222. float blend_factor;
  1223. // Blur
  1224. float sigma;
  1225. // Drop shadow
  1226. Rml::Vector2f offset;
  1227. Rml::ColourbPremultiplied color;
  1228. // ColorMatrix
  1229. Rml::Matrix4f color_matrix;
  1230. };
  1231. Rml::CompiledFilterHandle RenderInterface_GL3::CompileFilter(const Rml::String& name, const Rml::Dictionary& parameters)
  1232. {
  1233. CompiledFilter filter = {};
  1234. if (name == "opacity")
  1235. {
  1236. filter.type = FilterType::Passthrough;
  1237. filter.blend_factor = Rml::Get(parameters, "value", 1.0f);
  1238. }
  1239. else if (name == "blur")
  1240. {
  1241. filter.type = FilterType::Blur;
  1242. filter.sigma = 0.5f * Rml::Get(parameters, "radius", 1.0f);
  1243. }
  1244. else if (name == "drop-shadow")
  1245. {
  1246. filter.type = FilterType::DropShadow;
  1247. filter.sigma = Rml::Get(parameters, "sigma", 0.f);
  1248. filter.color = Rml::Get(parameters, "color", Rml::Colourb()).ToPremultiplied();
  1249. filter.offset = Rml::Get(parameters, "offset", Rml::Vector2f(0.f));
  1250. }
  1251. else if (name == "brightness")
  1252. {
  1253. filter.type = FilterType::ColorMatrix;
  1254. const float value = Rml::Get(parameters, "value", 1.0f);
  1255. filter.color_matrix = Rml::Matrix4f::Diag(value, value, value, 1.f);
  1256. }
  1257. else if (name == "contrast")
  1258. {
  1259. filter.type = FilterType::ColorMatrix;
  1260. const float value = Rml::Get(parameters, "value", 1.0f);
  1261. const float grayness = 0.5f - 0.5f * value;
  1262. filter.color_matrix = Rml::Matrix4f::Diag(value, value, value, 1.f);
  1263. filter.color_matrix.SetColumn(3, Rml::Vector4f(grayness, grayness, grayness, 1.f));
  1264. }
  1265. else if (name == "invert")
  1266. {
  1267. filter.type = FilterType::ColorMatrix;
  1268. const float value = Rml::Math::Clamp(Rml::Get(parameters, "value", 1.0f), 0.f, 1.f);
  1269. const float inverted = 1.f - 2.f * value;
  1270. filter.color_matrix = Rml::Matrix4f::Diag(inverted, inverted, inverted, 1.f);
  1271. filter.color_matrix.SetColumn(3, Rml::Vector4f(value, value, value, 1.f));
  1272. }
  1273. else if (name == "grayscale")
  1274. {
  1275. filter.type = FilterType::ColorMatrix;
  1276. const float value = Rml::Get(parameters, "value", 1.0f);
  1277. const float rev_value = 1.f - value;
  1278. const Rml::Vector3f gray = value * Rml::Vector3f(0.2126f, 0.7152f, 0.0722f);
  1279. // clang-format off
  1280. filter.color_matrix = Rml::Matrix4f::FromRows(
  1281. {gray.x + rev_value, gray.y, gray.z, 0.f},
  1282. {gray.x, gray.y + rev_value, gray.z, 0.f},
  1283. {gray.x, gray.y, gray.z + rev_value, 0.f},
  1284. {0.f, 0.f, 0.f, 1.f}
  1285. );
  1286. // clang-format on
  1287. }
  1288. else if (name == "sepia")
  1289. {
  1290. filter.type = FilterType::ColorMatrix;
  1291. const float value = Rml::Get(parameters, "value", 1.0f);
  1292. const float rev_value = 1.f - value;
  1293. const Rml::Vector3f r_mix = value * Rml::Vector3f(0.393f, 0.769f, 0.189f);
  1294. const Rml::Vector3f g_mix = value * Rml::Vector3f(0.349f, 0.686f, 0.168f);
  1295. const Rml::Vector3f b_mix = value * Rml::Vector3f(0.272f, 0.534f, 0.131f);
  1296. // clang-format off
  1297. filter.color_matrix = Rml::Matrix4f::FromRows(
  1298. {r_mix.x + rev_value, r_mix.y, r_mix.z, 0.f},
  1299. {g_mix.x, g_mix.y + rev_value, g_mix.z, 0.f},
  1300. {b_mix.x, b_mix.y, b_mix.z + rev_value, 0.f},
  1301. {0.f, 0.f, 0.f, 1.f}
  1302. );
  1303. // clang-format on
  1304. }
  1305. else if (name == "hue-rotate")
  1306. {
  1307. // Hue-rotation and saturation values based on: https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-huerotate
  1308. filter.type = FilterType::ColorMatrix;
  1309. const float value = Rml::Get(parameters, "value", 1.0f);
  1310. const float s = Rml::Math::Sin(value);
  1311. const float c = Rml::Math::Cos(value);
  1312. // clang-format off
  1313. filter.color_matrix = Rml::Matrix4f::FromRows(
  1314. {0.213f + 0.787f * c - 0.213f * s, 0.715f - 0.715f * c - 0.715f * s, 0.072f - 0.072f * c + 0.928f * s, 0.f},
  1315. {0.213f - 0.213f * c + 0.143f * s, 0.715f + 0.285f * c + 0.140f * s, 0.072f - 0.072f * c - 0.283f * s, 0.f},
  1316. {0.213f - 0.213f * c - 0.787f * s, 0.715f - 0.715f * c + 0.715f * s, 0.072f + 0.928f * c + 0.072f * s, 0.f},
  1317. {0.f, 0.f, 0.f, 1.f}
  1318. );
  1319. // clang-format on
  1320. }
  1321. else if (name == "saturate")
  1322. {
  1323. filter.type = FilterType::ColorMatrix;
  1324. const float value = Rml::Get(parameters, "value", 1.0f);
  1325. // clang-format off
  1326. filter.color_matrix = Rml::Matrix4f::FromRows(
  1327. {0.213f + 0.787f * value, 0.715f - 0.715f * value, 0.072f - 0.072f * value, 0.f},
  1328. {0.213f - 0.213f * value, 0.715f + 0.285f * value, 0.072f - 0.072f * value, 0.f},
  1329. {0.213f - 0.213f * value, 0.715f - 0.715f * value, 0.072f + 0.928f * value, 0.f},
  1330. {0.f, 0.f, 0.f, 1.f}
  1331. );
  1332. // clang-format on
  1333. }
  1334. if (filter.type != FilterType::Invalid)
  1335. return reinterpret_cast<Rml::CompiledFilterHandle>(new CompiledFilter(std::move(filter)));
  1336. Rml::Log::Message(Rml::Log::LT_WARNING, "Unsupported filter type '%s'.", name.c_str());
  1337. return {};
  1338. }
  1339. void RenderInterface_GL3::ReleaseCompiledFilter(Rml::CompiledFilterHandle filter)
  1340. {
  1341. delete reinterpret_cast<CompiledFilter*>(filter);
  1342. }
  1343. enum class CompiledShaderType { Invalid = 0, Gradient, Creation };
  1344. struct CompiledShader {
  1345. CompiledShaderType type;
  1346. // Gradient
  1347. ShaderGradientFunction gradient_function;
  1348. Rml::Vector2f p;
  1349. Rml::Vector2f v;
  1350. Rml::Vector<float> stop_positions;
  1351. Rml::Vector<Rml::Colourf> stop_colors;
  1352. // Shader
  1353. Rml::Vector2f dimensions;
  1354. };
  1355. Rml::CompiledShaderHandle RenderInterface_GL3::CompileShader(const Rml::String& name, const Rml::Dictionary& parameters)
  1356. {
  1357. auto ApplyColorStopList = [](CompiledShader& shader, const Rml::Dictionary& shader_parameters) {
  1358. auto it = shader_parameters.find("color_stop_list");
  1359. RMLUI_ASSERT(it != shader_parameters.end() && it->second.GetType() == Rml::Variant::COLORSTOPLIST);
  1360. const Rml::ColorStopList& color_stop_list = it->second.GetReference<Rml::ColorStopList>();
  1361. const int num_stops = Rml::Math::Min((int)color_stop_list.size(), MAX_NUM_STOPS);
  1362. shader.stop_positions.resize(num_stops);
  1363. shader.stop_colors.resize(num_stops);
  1364. for (int i = 0; i < num_stops; i++)
  1365. {
  1366. const Rml::ColorStop& stop = color_stop_list[i];
  1367. RMLUI_ASSERT(stop.position.unit == Rml::Unit::NUMBER);
  1368. shader.stop_positions[i] = stop.position.number;
  1369. shader.stop_colors[i] = ConvertToColorf(stop.color);
  1370. }
  1371. };
  1372. CompiledShader shader = {};
  1373. if (name == "linear-gradient")
  1374. {
  1375. shader.type = CompiledShaderType::Gradient;
  1376. const bool repeating = Rml::Get(parameters, "repeating", false);
  1377. shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingLinear : ShaderGradientFunction::Linear);
  1378. shader.p = Rml::Get(parameters, "p0", Rml::Vector2f(0.f));
  1379. shader.v = Rml::Get(parameters, "p1", Rml::Vector2f(0.f)) - shader.p;
  1380. ApplyColorStopList(shader, parameters);
  1381. }
  1382. else if (name == "radial-gradient")
  1383. {
  1384. shader.type = CompiledShaderType::Gradient;
  1385. const bool repeating = Rml::Get(parameters, "repeating", false);
  1386. shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingRadial : ShaderGradientFunction::Radial);
  1387. shader.p = Rml::Get(parameters, "center", Rml::Vector2f(0.f));
  1388. shader.v = Rml::Vector2f(1.f) / Rml::Get(parameters, "radius", Rml::Vector2f(1.f));
  1389. ApplyColorStopList(shader, parameters);
  1390. }
  1391. else if (name == "conic-gradient")
  1392. {
  1393. shader.type = CompiledShaderType::Gradient;
  1394. const bool repeating = Rml::Get(parameters, "repeating", false);
  1395. shader.gradient_function = (repeating ? ShaderGradientFunction::RepeatingConic : ShaderGradientFunction::Conic);
  1396. shader.p = Rml::Get(parameters, "center", Rml::Vector2f(0.f));
  1397. const float angle = Rml::Get(parameters, "angle", 0.f);
  1398. shader.v = {Rml::Math::Cos(angle), Rml::Math::Sin(angle)};
  1399. ApplyColorStopList(shader, parameters);
  1400. }
  1401. else if (name == "shader")
  1402. {
  1403. const Rml::String value = Rml::Get(parameters, "value", Rml::String());
  1404. if (value == "creation")
  1405. {
  1406. shader.type = CompiledShaderType::Creation;
  1407. shader.dimensions = Rml::Get(parameters, "dimensions", Rml::Vector2f(0.f));
  1408. }
  1409. }
  1410. if (shader.type != CompiledShaderType::Invalid)
  1411. return reinterpret_cast<Rml::CompiledShaderHandle>(new CompiledShader(std::move(shader)));
  1412. Rml::Log::Message(Rml::Log::LT_WARNING, "Unsupported shader type '%s'.", name.c_str());
  1413. return {};
  1414. }
  1415. void RenderInterface_GL3::RenderShader(Rml::CompiledShaderHandle shader_handle, Rml::CompiledGeometryHandle geometry_handle,
  1416. Rml::Vector2f translation, Rml::TextureHandle /*texture*/)
  1417. {
  1418. RMLUI_ASSERT(shader_handle && geometry_handle);
  1419. const CompiledShader& shader = *reinterpret_cast<CompiledShader*>(shader_handle);
  1420. const CompiledShaderType type = shader.type;
  1421. const Gfx::CompiledGeometryData& geometry = *reinterpret_cast<Gfx::CompiledGeometryData*>(geometry_handle);
  1422. switch (type)
  1423. {
  1424. case CompiledShaderType::Gradient:
  1425. {
  1426. RMLUI_ASSERT(shader.stop_positions.size() == shader.stop_colors.size());
  1427. const int num_stops = (int)shader.stop_positions.size();
  1428. UseProgram(ProgramId::Gradient);
  1429. glUniform1i(GetUniformLocation(UniformId::Func), static_cast<int>(shader.gradient_function));
  1430. glUniform2f(GetUniformLocation(UniformId::P), shader.p.x, shader.p.y);
  1431. glUniform2f(GetUniformLocation(UniformId::V), shader.v.x, shader.v.y);
  1432. glUniform1i(GetUniformLocation(UniformId::NumStops), num_stops);
  1433. glUniform1fv(GetUniformLocation(UniformId::StopPositions), num_stops, shader.stop_positions.data());
  1434. glUniform4fv(GetUniformLocation(UniformId::StopColors), num_stops, shader.stop_colors[0]);
  1435. SubmitTransformUniform(translation);
  1436. glBindVertexArray(geometry.vao);
  1437. glDrawElements(GL_TRIANGLES, geometry.draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
  1438. glBindVertexArray(0);
  1439. }
  1440. break;
  1441. case CompiledShaderType::Creation:
  1442. {
  1443. const double time = Rml::GetSystemInterface()->GetElapsedTime();
  1444. UseProgram(ProgramId::Creation);
  1445. glUniform1f(GetUniformLocation(UniformId::Value), (float)time);
  1446. glUniform2f(GetUniformLocation(UniformId::Dimensions), shader.dimensions.x, shader.dimensions.y);
  1447. SubmitTransformUniform(translation);
  1448. glBindVertexArray(geometry.vao);
  1449. glDrawElements(GL_TRIANGLES, geometry.draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
  1450. glBindVertexArray(0);
  1451. }
  1452. break;
  1453. case CompiledShaderType::Invalid:
  1454. {
  1455. Rml::Log::Message(Rml::Log::LT_WARNING, "Unhandled render shader %d.", (int)type);
  1456. }
  1457. break;
  1458. }
  1459. Gfx::CheckGLError("RenderShader");
  1460. }
  1461. void RenderInterface_GL3::ReleaseCompiledShader(Rml::CompiledShaderHandle shader_handle)
  1462. {
  1463. delete reinterpret_cast<CompiledShader*>(shader_handle);
  1464. }
  1465. void RenderInterface_GL3::BlitTopLayerToPostprocessPrimary()
  1466. {
  1467. const Gfx::FramebufferData& source = render_layers.GetTopLayer();
  1468. const Gfx::FramebufferData& destination = render_layers.GetPostprocessPrimary();
  1469. glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer);
  1470. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination.framebuffer);
  1471. // Blit and resolve MSAA. Any active scissor state will restrict the size of the blit region.
  1472. glBlitFramebuffer(0, 0, source.width, source.height, 0, 0, destination.width, destination.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  1473. }
  1474. void RenderInterface_GL3::RenderFilters(Rml::Span<const Rml::CompiledFilterHandle> filter_handles)
  1475. {
  1476. for (const Rml::CompiledFilterHandle filter_handle : filter_handles)
  1477. {
  1478. const CompiledFilter& filter = *reinterpret_cast<const CompiledFilter*>(filter_handle);
  1479. const FilterType type = filter.type;
  1480. switch (type)
  1481. {
  1482. case FilterType::Passthrough:
  1483. {
  1484. UseProgram(ProgramId::Passthrough);
  1485. glBlendFunc(GL_CONSTANT_ALPHA, GL_ZERO);
  1486. glBlendColor(0.0f, 0.0f, 0.0f, filter.blend_factor);
  1487. const Gfx::FramebufferData& source = render_layers.GetPostprocessPrimary();
  1488. const Gfx::FramebufferData& destination = render_layers.GetPostprocessSecondary();
  1489. Gfx::BindTexture(source);
  1490. glBindFramebuffer(GL_FRAMEBUFFER, destination.framebuffer);
  1491. DrawFullscreenQuad();
  1492. render_layers.SwapPostprocessPrimarySecondary();
  1493. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  1494. }
  1495. break;
  1496. case FilterType::Blur:
  1497. {
  1498. glDisable(GL_BLEND);
  1499. const Gfx::FramebufferData& source_destination = render_layers.GetPostprocessPrimary();
  1500. const Gfx::FramebufferData& temp = render_layers.GetPostprocessSecondary();
  1501. const Rml::Rectanglei window_flipped = VerticallyFlipped(scissor_state, viewport_height);
  1502. RenderBlur(filter.sigma, source_destination, temp, window_flipped);
  1503. glEnable(GL_BLEND);
  1504. }
  1505. break;
  1506. case FilterType::DropShadow:
  1507. {
  1508. UseProgram(ProgramId::DropShadow);
  1509. glDisable(GL_BLEND);
  1510. Rml::Colourf color = ConvertToColorf(filter.color);
  1511. glUniform4fv(GetUniformLocation(UniformId::Color), 1, &color[0]);
  1512. const Gfx::FramebufferData& primary = render_layers.GetPostprocessPrimary();
  1513. const Gfx::FramebufferData& secondary = render_layers.GetPostprocessSecondary();
  1514. Gfx::BindTexture(primary);
  1515. glBindFramebuffer(GL_FRAMEBUFFER, secondary.framebuffer);
  1516. const Rml::Rectanglei window_flipped = VerticallyFlipped(scissor_state, viewport_height);
  1517. SetTexCoordLimits(GetUniformLocation(UniformId::TexCoordMin), GetUniformLocation(UniformId::TexCoordMax), window_flipped,
  1518. {primary.width, primary.height});
  1519. const Rml::Vector2f uv_offset = filter.offset / Rml::Vector2f(-(float)viewport_width, (float)viewport_height);
  1520. DrawFullscreenQuad(uv_offset);
  1521. if (filter.sigma >= 0.5f)
  1522. {
  1523. const Gfx::FramebufferData& tertiary = render_layers.GetPostprocessTertiary();
  1524. RenderBlur(filter.sigma, secondary, tertiary, window_flipped);
  1525. }
  1526. UseProgram(ProgramId::Passthrough);
  1527. BindTexture(primary);
  1528. glEnable(GL_BLEND);
  1529. DrawFullscreenQuad();
  1530. render_layers.SwapPostprocessPrimarySecondary();
  1531. }
  1532. break;
  1533. case FilterType::ColorMatrix:
  1534. {
  1535. UseProgram(ProgramId::ColorMatrix);
  1536. glDisable(GL_BLEND);
  1537. const GLint uniform_location = program_data->uniforms.Get(ProgramId::ColorMatrix, UniformId::ColorMatrix);
  1538. constexpr bool transpose = std::is_same<decltype(filter.color_matrix), Rml::RowMajorMatrix4f>::value;
  1539. glUniformMatrix4fv(uniform_location, 1, transpose, filter.color_matrix.data());
  1540. const Gfx::FramebufferData& source = render_layers.GetPostprocessPrimary();
  1541. const Gfx::FramebufferData& destination = render_layers.GetPostprocessSecondary();
  1542. Gfx::BindTexture(source);
  1543. glBindFramebuffer(GL_FRAMEBUFFER, destination.framebuffer);
  1544. DrawFullscreenQuad();
  1545. render_layers.SwapPostprocessPrimarySecondary();
  1546. glEnable(GL_BLEND);
  1547. }
  1548. break;
  1549. case FilterType::MaskImage:
  1550. {
  1551. UseProgram(ProgramId::BlendMask);
  1552. glDisable(GL_BLEND);
  1553. const Gfx::FramebufferData& source = render_layers.GetPostprocessPrimary();
  1554. const Gfx::FramebufferData& blend_mask = render_layers.GetBlendMask();
  1555. const Gfx::FramebufferData& destination = render_layers.GetPostprocessSecondary();
  1556. Gfx::BindTexture(source);
  1557. glActiveTexture(GL_TEXTURE1);
  1558. Gfx::BindTexture(blend_mask);
  1559. glActiveTexture(GL_TEXTURE0);
  1560. glBindFramebuffer(GL_FRAMEBUFFER, destination.framebuffer);
  1561. DrawFullscreenQuad();
  1562. render_layers.SwapPostprocessPrimarySecondary();
  1563. glEnable(GL_BLEND);
  1564. }
  1565. break;
  1566. case FilterType::Invalid:
  1567. {
  1568. Rml::Log::Message(Rml::Log::LT_WARNING, "Unhandled render filter %d.", (int)type);
  1569. }
  1570. break;
  1571. }
  1572. }
  1573. Gfx::CheckGLError("RenderFilter");
  1574. }
  1575. void RenderInterface_GL3::PushLayer(Rml::LayerFill layer_fill)
  1576. {
  1577. if (layer_fill == Rml::LayerFill::Clone)
  1578. render_layers.PushLayerClone();
  1579. else
  1580. render_layers.PushLayer();
  1581. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  1582. if (layer_fill == Rml::LayerFill::Clear)
  1583. glClear(GL_COLOR_BUFFER_BIT);
  1584. }
  1585. void RenderInterface_GL3::PopLayer(Rml::BlendMode blend_mode, Rml::Span<const Rml::CompiledFilterHandle> filters)
  1586. {
  1587. using Rml::BlendMode;
  1588. if (blend_mode == BlendMode::Discard)
  1589. {
  1590. RMLUI_ASSERT(filters.empty());
  1591. render_layers.PopLayer();
  1592. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  1593. return;
  1594. }
  1595. // Blit stack to filter rendering buffer. Do this regardless of whether we actually have any filters to be applied,
  1596. // because we need to resolve the multi-sampled framebuffer in any case.
  1597. // @performance If we have BlendMode::Replace and no filters or mask then we can just blit directly to the destination.
  1598. BlitTopLayerToPostprocessPrimary();
  1599. // Render the filters, the PostprocessPrimary framebuffer is used for both input and output.
  1600. RenderFilters(filters);
  1601. // Pop the active layer, thereby activating the beneath layer.
  1602. render_layers.PopLayer();
  1603. // Render to the activated layer. Apply any mask if active.
  1604. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  1605. Gfx::BindTexture(render_layers.GetPostprocessPrimary());
  1606. UseProgram(ProgramId::Passthrough);
  1607. if (blend_mode == BlendMode::Replace)
  1608. glDisable(GL_BLEND);
  1609. DrawFullscreenQuad();
  1610. if (blend_mode == BlendMode::Replace)
  1611. glEnable(GL_BLEND);
  1612. Gfx::CheckGLError("PopLayer");
  1613. }
  1614. Rml::TextureHandle RenderInterface_GL3::SaveLayerAsTexture(Rml::Vector2i dimensions)
  1615. {
  1616. Rml::TextureHandle render_texture = GenerateTexture({}, dimensions);
  1617. if (!render_texture)
  1618. return {};
  1619. BlitTopLayerToPostprocessPrimary();
  1620. RMLUI_ASSERT(scissor_state.Valid() && render_texture);
  1621. const Rml::Rectanglei initial_scissor_state = scissor_state;
  1622. EnableScissorRegion(false);
  1623. const Gfx::FramebufferData& source = render_layers.GetPostprocessPrimary();
  1624. const Gfx::FramebufferData& destination = render_layers.GetPostprocessSecondary();
  1625. glBindFramebuffer(GL_READ_FRAMEBUFFER, source.framebuffer);
  1626. glBindFramebuffer(GL_DRAW_FRAMEBUFFER, destination.framebuffer);
  1627. Rml::Rectanglei bounds = initial_scissor_state;
  1628. // Flip the image vertically, as that convention is used for textures, and move to origin.
  1629. glBlitFramebuffer( //
  1630. bounds.Left(), source.height - bounds.Bottom(), // src0
  1631. bounds.Right(), source.height - bounds.Top(), // src1
  1632. 0, bounds.Height(), // dst0
  1633. bounds.Width(), 0, // dst1
  1634. GL_COLOR_BUFFER_BIT, GL_NEAREST //
  1635. );
  1636. glBindTexture(GL_TEXTURE_2D, (GLuint)render_texture);
  1637. const Gfx::FramebufferData& texture_source = destination;
  1638. glBindFramebuffer(GL_READ_FRAMEBUFFER, texture_source.framebuffer);
  1639. glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, bounds.Width(), bounds.Height());
  1640. SetScissor(initial_scissor_state);
  1641. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  1642. Gfx::CheckGLError("SaveLayerAsTexture");
  1643. return render_texture;
  1644. }
  1645. Rml::CompiledFilterHandle RenderInterface_GL3::SaveLayerAsMaskImage()
  1646. {
  1647. BlitTopLayerToPostprocessPrimary();
  1648. const Gfx::FramebufferData& source = render_layers.GetPostprocessPrimary();
  1649. const Gfx::FramebufferData& destination = render_layers.GetBlendMask();
  1650. glBindFramebuffer(GL_FRAMEBUFFER, destination.framebuffer);
  1651. BindTexture(source);
  1652. UseProgram(ProgramId::Passthrough);
  1653. glDisable(GL_BLEND);
  1654. DrawFullscreenQuad();
  1655. glEnable(GL_BLEND);
  1656. glBindFramebuffer(GL_FRAMEBUFFER, render_layers.GetTopLayer().framebuffer);
  1657. Gfx::CheckGLError("SaveLayerAsMaskImage");
  1658. CompiledFilter filter = {};
  1659. filter.type = FilterType::MaskImage;
  1660. return reinterpret_cast<Rml::CompiledFilterHandle>(new CompiledFilter(std::move(filter)));
  1661. }
  1662. void RenderInterface_GL3::UseProgram(ProgramId program_id)
  1663. {
  1664. RMLUI_ASSERT(program_data);
  1665. if (active_program != program_id)
  1666. {
  1667. if (program_id != ProgramId::None)
  1668. glUseProgram(program_data->programs[program_id]);
  1669. active_program = program_id;
  1670. }
  1671. }
  1672. int RenderInterface_GL3::GetUniformLocation(UniformId uniform_id) const
  1673. {
  1674. return program_data->uniforms.Get(active_program, uniform_id);
  1675. }
  1676. void RenderInterface_GL3::SubmitTransformUniform(Rml::Vector2f translation)
  1677. {
  1678. static_assert((size_t)ProgramId::Count < MaxNumPrograms, "Maximum number of programs exceeded.");
  1679. const size_t program_index = (size_t)active_program;
  1680. if (program_transform_dirty.test(program_index))
  1681. {
  1682. glUniformMatrix4fv(GetUniformLocation(UniformId::Transform), 1, false, transform.data());
  1683. program_transform_dirty.set(program_index, false);
  1684. }
  1685. glUniform2fv(GetUniformLocation(UniformId::Translate), 1, &translation.x);
  1686. Gfx::CheckGLError("SubmitTransformUniform");
  1687. }
  1688. RenderInterface_GL3::RenderLayerStack::RenderLayerStack()
  1689. {
  1690. fb_postprocess.resize(4);
  1691. }
  1692. RenderInterface_GL3::RenderLayerStack::~RenderLayerStack()
  1693. {
  1694. DestroyFramebuffers();
  1695. }
  1696. void RenderInterface_GL3::RenderLayerStack::PushLayer()
  1697. {
  1698. RMLUI_ASSERT(layers_size <= (int)fb_layers.size());
  1699. if (layers_size == (int)fb_layers.size())
  1700. {
  1701. // All framebuffers should share a single stencil buffer.
  1702. GLuint shared_depth_stencil = (fb_layers.empty() ? 0 : fb_layers.front().depth_stencil_buffer);
  1703. fb_layers.push_back(Gfx::FramebufferData{});
  1704. Gfx::CreateFramebuffer(fb_layers.back(), width, height, NUM_MSAA_SAMPLES, Gfx::FramebufferAttachment::DepthStencil, shared_depth_stencil);
  1705. }
  1706. layers_size += 1;
  1707. }
  1708. void RenderInterface_GL3::RenderLayerStack::PushLayerClone()
  1709. {
  1710. RMLUI_ASSERT(layers_size > 0);
  1711. fb_layers.insert(fb_layers.begin() + layers_size, Gfx::FramebufferData{fb_layers[layers_size - 1]});
  1712. layers_size += 1;
  1713. }
  1714. void RenderInterface_GL3::RenderLayerStack::PopLayer()
  1715. {
  1716. RMLUI_ASSERT(layers_size > 0);
  1717. layers_size -= 1;
  1718. // Only cloned framebuffers are removed. Other framebuffers remain for later re-use.
  1719. if (IsCloneOfBelow(layers_size))
  1720. fb_layers.erase(fb_layers.begin() + layers_size);
  1721. }
  1722. const Gfx::FramebufferData& RenderInterface_GL3::RenderLayerStack::GetTopLayer() const
  1723. {
  1724. RMLUI_ASSERT(layers_size > 0);
  1725. return fb_layers[layers_size - 1];
  1726. }
  1727. void RenderInterface_GL3::RenderLayerStack::SwapPostprocessPrimarySecondary()
  1728. {
  1729. std::swap(fb_postprocess[0], fb_postprocess[1]);
  1730. }
  1731. void RenderInterface_GL3::RenderLayerStack::BeginFrame(int new_width, int new_height)
  1732. {
  1733. RMLUI_ASSERT(layers_size == 0);
  1734. if (new_width != width || new_height != height)
  1735. {
  1736. width = new_width;
  1737. height = new_height;
  1738. DestroyFramebuffers();
  1739. }
  1740. PushLayer();
  1741. }
  1742. void RenderInterface_GL3::RenderLayerStack::EndFrame()
  1743. {
  1744. RMLUI_ASSERT(layers_size == 1);
  1745. PopLayer();
  1746. }
  1747. void RenderInterface_GL3::RenderLayerStack::DestroyFramebuffers()
  1748. {
  1749. RMLUI_ASSERTMSG(layers_size == 0, "Do not call this during frame rendering, that is, between BeginFrame() and EndFrame().");
  1750. for (Gfx::FramebufferData& fb : fb_layers)
  1751. Gfx::DestroyFramebuffer(fb);
  1752. fb_layers.clear();
  1753. for (Gfx::FramebufferData& fb : fb_postprocess)
  1754. Gfx::DestroyFramebuffer(fb);
  1755. }
  1756. bool RenderInterface_GL3::RenderLayerStack::IsCloneOfBelow(int layer_index) const
  1757. {
  1758. const bool result =
  1759. (layer_index >= 1 && layer_index < (int)fb_layers.size() && fb_layers[layer_index].framebuffer == fb_layers[layer_index - 1].framebuffer);
  1760. return result;
  1761. }
  1762. const Gfx::FramebufferData& RenderInterface_GL3::RenderLayerStack::EnsureFramebufferPostprocess(int index)
  1763. {
  1764. RMLUI_ASSERT(index < (int)fb_postprocess.size())
  1765. Gfx::FramebufferData& fb = fb_postprocess[index];
  1766. if (!fb.framebuffer)
  1767. Gfx::CreateFramebuffer(fb, width, height, 0, Gfx::FramebufferAttachment::None, 0);
  1768. return fb;
  1769. }
  1770. bool RmlGL3::Initialize(Rml::String* out_message)
  1771. {
  1772. #if defined RMLUI_PLATFORM_EMSCRIPTEN
  1773. if (out_message)
  1774. *out_message = "Started Emscripten WebGL renderer.";
  1775. #elif !defined RMLUI_GL3_CUSTOM_LOADER
  1776. const int gl_version = gladLoaderLoadGL();
  1777. if (gl_version == 0)
  1778. {
  1779. if (out_message)
  1780. *out_message = "Failed to initialize OpenGL context.";
  1781. return false;
  1782. }
  1783. if (out_message)
  1784. *out_message = Rml::CreateString(128, "Loaded OpenGL %d.%d.", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
  1785. #endif
  1786. return true;
  1787. }
  1788. void RmlGL3::Shutdown()
  1789. {
  1790. #if !defined RMLUI_PLATFORM_EMSCRIPTEN && !defined RMLUI_GL3_CUSTOM_LOADER
  1791. gladLoaderUnloadGL();
  1792. #endif
  1793. }