RmlUi_Renderer_GL3.cpp 72 KB

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