RmlUi_Renderer_GL3.cpp 60 KB

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