RmlUi_Renderer_BackwardCompatible_GL3.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  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_BackwardCompatible_GL3.h"
  29. #include <RmlUi/Core/Core.h>
  30. #include <RmlUi/Core/FileInterface.h>
  31. #include <RmlUi/Core/Log.h>
  32. #include <RmlUi/Core/Platform.h>
  33. #include <string.h>
  34. #if defined RMLUI_PLATFORM_WIN32_NATIVE
  35. // function call missing argument list
  36. #pragma warning(disable : 4551)
  37. // unreferenced local function has been removed
  38. #pragma warning(disable : 4505)
  39. #endif
  40. #if defined RMLUI_PLATFORM_EMSCRIPTEN
  41. #define RMLUI_SHADER_HEADER "#version 300 es\nprecision highp float;\n"
  42. #include <GLES3/gl3.h>
  43. #elif defined RMLUI_GL3_CUSTOM_LOADER
  44. #define RMLUI_SHADER_HEADER "#version 330\n"
  45. #include RMLUI_GL3_CUSTOM_LOADER
  46. #else
  47. #define RMLUI_SHADER_HEADER "#version 330\n"
  48. #define GLAD_GL_IMPLEMENTATION
  49. #include "../RmlUi_Include_GL3.h"
  50. #endif
  51. static const char* shader_main_vertex = RMLUI_SHADER_HEADER R"(
  52. uniform vec2 _translate;
  53. uniform mat4 _transform;
  54. in vec2 inPosition;
  55. in vec4 inColor0;
  56. in vec2 inTexCoord0;
  57. out vec2 fragTexCoord;
  58. out vec4 fragColor;
  59. void main() {
  60. fragTexCoord = inTexCoord0;
  61. fragColor = inColor0;
  62. vec2 translatedPos = inPosition + _translate.xy;
  63. vec4 outPos = _transform * vec4(translatedPos, 0, 1);
  64. gl_Position = outPos;
  65. }
  66. )";
  67. static const char* shader_main_fragment_texture = RMLUI_SHADER_HEADER R"(
  68. uniform sampler2D _tex;
  69. in vec2 fragTexCoord;
  70. in vec4 fragColor;
  71. out vec4 finalColor;
  72. void main() {
  73. vec4 texColor = texture(_tex, fragTexCoord);
  74. finalColor = fragColor * texColor;
  75. }
  76. )";
  77. static const char* shader_main_fragment_color = RMLUI_SHADER_HEADER R"(
  78. in vec2 fragTexCoord;
  79. in vec4 fragColor;
  80. out vec4 finalColor;
  81. void main() {
  82. finalColor = fragColor;
  83. }
  84. )";
  85. namespace Gfx {
  86. enum class ProgramUniform { Translate, Transform, Tex, Count };
  87. static const char* const program_uniform_names[(size_t)ProgramUniform::Count] = {"_translate", "_transform", "_tex"};
  88. enum class VertexAttribute { Position, Color0, TexCoord0, Count };
  89. static const char* const vertex_attribute_names[(size_t)VertexAttribute::Count] = {"inPosition", "inColor0", "inTexCoord0"};
  90. struct CompiledGeometryData {
  91. Rml::TextureHandle texture;
  92. GLuint vao;
  93. GLuint vbo;
  94. GLuint ibo;
  95. GLsizei draw_count;
  96. };
  97. struct ProgramData {
  98. GLuint id;
  99. GLint uniform_locations[(size_t)ProgramUniform::Count];
  100. };
  101. struct ShadersData {
  102. ProgramData program_color;
  103. ProgramData program_texture;
  104. GLuint shader_main_vertex;
  105. GLuint shader_main_fragment_color;
  106. GLuint shader_main_fragment_texture;
  107. };
  108. static void CheckGLError(const char* operation_name)
  109. {
  110. #ifdef RMLUI_DEBUG
  111. GLenum error_code = glGetError();
  112. if (error_code != GL_NO_ERROR)
  113. {
  114. static const Rml::Pair<GLenum, const char*> error_names[] = {{GL_INVALID_ENUM, "GL_INVALID_ENUM"}, {GL_INVALID_VALUE, "GL_INVALID_VALUE"},
  115. {GL_INVALID_OPERATION, "GL_INVALID_OPERATION"}, {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY"}};
  116. const char* error_str = "''";
  117. for (auto& err : error_names)
  118. {
  119. if (err.first == error_code)
  120. {
  121. error_str = err.second;
  122. break;
  123. }
  124. }
  125. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL error during %s. Error code 0x%x (%s).", operation_name, error_code, error_str);
  126. }
  127. #endif
  128. (void)operation_name;
  129. }
  130. // Create the shader, 'shader_type' is either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
  131. static GLuint CreateShader(GLenum shader_type, const char* code_string)
  132. {
  133. GLuint id = glCreateShader(shader_type);
  134. glShaderSource(id, 1, (const GLchar**)&code_string, NULL);
  135. glCompileShader(id);
  136. GLint status = 0;
  137. glGetShaderiv(id, GL_COMPILE_STATUS, &status);
  138. if (status == GL_FALSE)
  139. {
  140. GLint info_log_length = 0;
  141. glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
  142. char* info_log_string = new char[info_log_length + 1];
  143. glGetShaderInfoLog(id, info_log_length, NULL, info_log_string);
  144. Rml::Log::Message(Rml::Log::LT_ERROR, "Compile failure in OpenGL shader: %s", info_log_string);
  145. delete[] info_log_string;
  146. glDeleteShader(id);
  147. return 0;
  148. }
  149. CheckGLError("CreateShader");
  150. return id;
  151. }
  152. static void BindAttribLocations(GLuint program)
  153. {
  154. for (GLuint i = 0; i < (GLuint)VertexAttribute::Count; i++)
  155. {
  156. glBindAttribLocation(program, i, vertex_attribute_names[i]);
  157. }
  158. CheckGLError("BindAttribLocations");
  159. }
  160. static bool CreateProgram(GLuint vertex_shader, GLuint fragment_shader, ProgramData& out_program)
  161. {
  162. GLuint id = glCreateProgram();
  163. RMLUI_ASSERT(id);
  164. BindAttribLocations(id);
  165. glAttachShader(id, vertex_shader);
  166. glAttachShader(id, fragment_shader);
  167. glLinkProgram(id);
  168. glDetachShader(id, vertex_shader);
  169. glDetachShader(id, fragment_shader);
  170. GLint status = 0;
  171. glGetProgramiv(id, GL_LINK_STATUS, &status);
  172. if (status == GL_FALSE)
  173. {
  174. GLint info_log_length = 0;
  175. glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
  176. char* info_log_string = new char[info_log_length + 1];
  177. glGetProgramInfoLog(id, info_log_length, NULL, info_log_string);
  178. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program linking failure: %s", info_log_string);
  179. delete[] info_log_string;
  180. glDeleteProgram(id);
  181. return false;
  182. }
  183. out_program = {};
  184. out_program.id = id;
  185. // Make a lookup table for the uniform locations.
  186. GLint num_active_uniforms = 0;
  187. glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_active_uniforms);
  188. constexpr size_t name_size = 64;
  189. GLchar name_buf[name_size] = "";
  190. for (int unif = 0; unif < num_active_uniforms; ++unif)
  191. {
  192. GLint array_size = 0;
  193. GLenum type = 0;
  194. GLsizei actual_length = 0;
  195. glGetActiveUniform(id, unif, name_size, &actual_length, &array_size, &type, name_buf);
  196. GLint location = glGetUniformLocation(id, name_buf);
  197. // See if we have the name in our pre-defined name list.
  198. ProgramUniform program_uniform = ProgramUniform::Count;
  199. for (int i = 0; i < (int)ProgramUniform::Count; i++)
  200. {
  201. const char* uniform_name = program_uniform_names[i];
  202. if (strcmp(name_buf, uniform_name) == 0)
  203. {
  204. program_uniform = (ProgramUniform)i;
  205. break;
  206. }
  207. }
  208. if ((size_t)program_uniform < (size_t)ProgramUniform::Count)
  209. {
  210. out_program.uniform_locations[(size_t)program_uniform] = location;
  211. }
  212. else
  213. {
  214. Rml::Log::Message(Rml::Log::LT_ERROR, "OpenGL program uses unknown uniform '%s'.", name_buf);
  215. return false;
  216. }
  217. }
  218. CheckGLError("CreateProgram");
  219. return true;
  220. }
  221. static bool CreateShaders(ShadersData& out_shaders)
  222. {
  223. out_shaders = {};
  224. GLuint& main_vertex = out_shaders.shader_main_vertex;
  225. GLuint& main_fragment_color = out_shaders.shader_main_fragment_color;
  226. GLuint& main_fragment_texture = out_shaders.shader_main_fragment_texture;
  227. main_vertex = CreateShader(GL_VERTEX_SHADER, shader_main_vertex);
  228. if (!main_vertex)
  229. {
  230. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_vertex'.");
  231. return false;
  232. }
  233. main_fragment_color = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_color);
  234. if (!main_fragment_color)
  235. {
  236. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_color'.");
  237. return false;
  238. }
  239. main_fragment_texture = CreateShader(GL_FRAGMENT_SHADER, shader_main_fragment_texture);
  240. if (!main_fragment_texture)
  241. {
  242. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL shader: 'shader_main_fragment_texture'.");
  243. return false;
  244. }
  245. if (!CreateProgram(main_vertex, main_fragment_color, out_shaders.program_color))
  246. {
  247. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_color'.");
  248. return false;
  249. }
  250. if (!CreateProgram(main_vertex, main_fragment_texture, out_shaders.program_texture))
  251. {
  252. Rml::Log::Message(Rml::Log::LT_ERROR, "Could not create OpenGL program: 'program_texture'.");
  253. return false;
  254. }
  255. return true;
  256. }
  257. static void DestroyShaders(ShadersData& shaders)
  258. {
  259. glDeleteProgram(shaders.program_color.id);
  260. glDeleteProgram(shaders.program_texture.id);
  261. glDeleteShader(shaders.shader_main_vertex);
  262. glDeleteShader(shaders.shader_main_fragment_color);
  263. glDeleteShader(shaders.shader_main_fragment_texture);
  264. shaders = {};
  265. }
  266. } // namespace Gfx
  267. RenderInterface_BackwardCompatible_GL3::RenderInterface_BackwardCompatible_GL3()
  268. {
  269. shaders = Rml::MakeUnique<Gfx::ShadersData>();
  270. if (!Gfx::CreateShaders(*shaders))
  271. shaders.reset();
  272. }
  273. RenderInterface_BackwardCompatible_GL3::~RenderInterface_BackwardCompatible_GL3()
  274. {
  275. if (shaders)
  276. Gfx::DestroyShaders(*shaders);
  277. }
  278. void RenderInterface_BackwardCompatible_GL3::SetViewport(int width, int height)
  279. {
  280. viewport_width = width;
  281. viewport_height = height;
  282. }
  283. void RenderInterface_BackwardCompatible_GL3::BeginFrame()
  284. {
  285. RMLUI_ASSERT(viewport_width >= 0 && viewport_height >= 0);
  286. // Backup GL state.
  287. glstate_backup.enable_cull_face = glIsEnabled(GL_CULL_FACE);
  288. glstate_backup.enable_blend = glIsEnabled(GL_BLEND);
  289. glstate_backup.enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
  290. glstate_backup.enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
  291. glGetIntegerv(GL_VIEWPORT, glstate_backup.viewport);
  292. glGetIntegerv(GL_SCISSOR_BOX, glstate_backup.scissor);
  293. glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &glstate_backup.stencil_clear_value);
  294. glGetFloatv(GL_COLOR_CLEAR_VALUE, glstate_backup.color_clear_value);
  295. glGetIntegerv(GL_BLEND_EQUATION_RGB, &glstate_backup.blend_equation_rgb);
  296. glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &glstate_backup.blend_equation_alpha);
  297. glGetIntegerv(GL_BLEND_SRC_RGB, &glstate_backup.blend_src_rgb);
  298. glGetIntegerv(GL_BLEND_DST_RGB, &glstate_backup.blend_dst_rgb);
  299. glGetIntegerv(GL_BLEND_SRC_ALPHA, &glstate_backup.blend_src_alpha);
  300. glGetIntegerv(GL_BLEND_DST_ALPHA, &glstate_backup.blend_dst_alpha);
  301. glGetIntegerv(GL_STENCIL_FUNC, &glstate_backup.stencil_front.func);
  302. glGetIntegerv(GL_STENCIL_REF, &glstate_backup.stencil_front.ref);
  303. glGetIntegerv(GL_STENCIL_VALUE_MASK, &glstate_backup.stencil_front.value_mask);
  304. glGetIntegerv(GL_STENCIL_WRITEMASK, &glstate_backup.stencil_front.writemask);
  305. glGetIntegerv(GL_STENCIL_FAIL, &glstate_backup.stencil_front.fail);
  306. glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &glstate_backup.stencil_front.pass_depth_fail);
  307. glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &glstate_backup.stencil_front.pass_depth_pass);
  308. glGetIntegerv(GL_STENCIL_BACK_FUNC, &glstate_backup.stencil_back.func);
  309. glGetIntegerv(GL_STENCIL_BACK_REF, &glstate_backup.stencil_back.ref);
  310. glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &glstate_backup.stencil_back.value_mask);
  311. glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &glstate_backup.stencil_back.writemask);
  312. glGetIntegerv(GL_STENCIL_BACK_FAIL, &glstate_backup.stencil_back.fail);
  313. glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &glstate_backup.stencil_back.pass_depth_fail);
  314. glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &glstate_backup.stencil_back.pass_depth_pass);
  315. // Setup expected GL state.
  316. glViewport(0, 0, viewport_width, viewport_height);
  317. glClearStencil(0);
  318. glClearColor(0, 0, 0, 1);
  319. glDisable(GL_CULL_FACE);
  320. glEnable(GL_BLEND);
  321. glBlendEquation(GL_FUNC_ADD);
  322. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  323. glEnable(GL_STENCIL_TEST);
  324. glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
  325. glStencilMask(GLuint(-1));
  326. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  327. projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
  328. SetTransform(nullptr);
  329. }
  330. void RenderInterface_BackwardCompatible_GL3::EndFrame()
  331. {
  332. // Restore GL state.
  333. if (glstate_backup.enable_cull_face)
  334. glEnable(GL_CULL_FACE);
  335. else
  336. glDisable(GL_CULL_FACE);
  337. if (glstate_backup.enable_blend)
  338. glEnable(GL_BLEND);
  339. else
  340. glDisable(GL_BLEND);
  341. if (glstate_backup.enable_stencil_test)
  342. glEnable(GL_STENCIL_TEST);
  343. else
  344. glDisable(GL_STENCIL_TEST);
  345. if (glstate_backup.enable_scissor_test)
  346. glEnable(GL_SCISSOR_TEST);
  347. else
  348. glDisable(GL_SCISSOR_TEST);
  349. glViewport(glstate_backup.viewport[0], glstate_backup.viewport[1], glstate_backup.viewport[2], glstate_backup.viewport[3]);
  350. glScissor(glstate_backup.scissor[0], glstate_backup.scissor[1], glstate_backup.scissor[2], glstate_backup.scissor[3]);
  351. glClearStencil(glstate_backup.stencil_clear_value);
  352. glClearColor(glstate_backup.color_clear_value[0], glstate_backup.color_clear_value[1], glstate_backup.color_clear_value[2],
  353. glstate_backup.color_clear_value[3]);
  354. glBlendEquationSeparate(glstate_backup.blend_equation_rgb, glstate_backup.blend_equation_alpha);
  355. glBlendFuncSeparate(glstate_backup.blend_src_rgb, glstate_backup.blend_dst_rgb, glstate_backup.blend_src_alpha, glstate_backup.blend_dst_alpha);
  356. glStencilFuncSeparate(GL_FRONT, glstate_backup.stencil_front.func, glstate_backup.stencil_front.ref, glstate_backup.stencil_front.value_mask);
  357. glStencilMaskSeparate(GL_FRONT, glstate_backup.stencil_front.writemask);
  358. glStencilOpSeparate(GL_FRONT, glstate_backup.stencil_front.fail, glstate_backup.stencil_front.pass_depth_fail,
  359. glstate_backup.stencil_front.pass_depth_pass);
  360. glStencilFuncSeparate(GL_BACK, glstate_backup.stencil_back.func, glstate_backup.stencil_back.ref, glstate_backup.stencil_back.value_mask);
  361. glStencilMaskSeparate(GL_BACK, glstate_backup.stencil_back.writemask);
  362. glStencilOpSeparate(GL_BACK, glstate_backup.stencil_back.fail, glstate_backup.stencil_back.pass_depth_fail,
  363. glstate_backup.stencil_back.pass_depth_pass);
  364. }
  365. void RenderInterface_BackwardCompatible_GL3::Clear()
  366. {
  367. glClearStencil(0);
  368. glClearColor(0, 0, 0, 1);
  369. glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  370. }
  371. void RenderInterface_BackwardCompatible_GL3::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices,
  372. const Rml::TextureHandle texture, const Rml::Vector2f& translation)
  373. {
  374. Rml::CompiledGeometryHandle geometry = CompileGeometry(vertices, num_vertices, indices, num_indices, texture);
  375. if (geometry)
  376. {
  377. RenderCompiledGeometry(geometry, translation);
  378. ReleaseCompiledGeometry(geometry);
  379. }
  380. }
  381. Rml::CompiledGeometryHandle RenderInterface_BackwardCompatible_GL3::CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices,
  382. int num_indices, Rml::TextureHandle texture)
  383. {
  384. constexpr GLenum draw_usage = GL_STATIC_DRAW;
  385. GLuint vao = 0;
  386. GLuint vbo = 0;
  387. GLuint ibo = 0;
  388. glGenVertexArrays(1, &vao);
  389. glGenBuffers(1, &vbo);
  390. glGenBuffers(1, &ibo);
  391. glBindVertexArray(vao);
  392. glBindBuffer(GL_ARRAY_BUFFER, vbo);
  393. glBufferData(GL_ARRAY_BUFFER, sizeof(Rml::Vertex) * num_vertices, (const void*)vertices, draw_usage);
  394. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Position);
  395. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
  396. (const GLvoid*)(offsetof(Rml::Vertex, position)));
  397. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::Color0);
  398. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::Color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Rml::Vertex),
  399. (const GLvoid*)(offsetof(Rml::Vertex, colour)));
  400. glEnableVertexAttribArray((GLuint)Gfx::VertexAttribute::TexCoord0);
  401. glVertexAttribPointer((GLuint)Gfx::VertexAttribute::TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Rml::Vertex),
  402. (const GLvoid*)(offsetof(Rml::Vertex, tex_coord)));
  403. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
  404. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * num_indices, (const void*)indices, draw_usage);
  405. glBindVertexArray(0);
  406. glBindBuffer(GL_ARRAY_BUFFER, 0);
  407. Gfx::CheckGLError("CompileGeometry");
  408. Gfx::CompiledGeometryData* geometry = new Gfx::CompiledGeometryData;
  409. geometry->texture = texture;
  410. geometry->vao = vao;
  411. geometry->vbo = vbo;
  412. geometry->ibo = ibo;
  413. geometry->draw_count = num_indices;
  414. return (Rml::CompiledGeometryHandle)geometry;
  415. }
  416. void RenderInterface_BackwardCompatible_GL3::RenderCompiledGeometry(Rml::CompiledGeometryHandle handle, const Rml::Vector2f& translation)
  417. {
  418. Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
  419. if (geometry->texture)
  420. {
  421. glUseProgram(shaders->program_texture.id);
  422. if (geometry->texture != TextureEnableWithoutBinding)
  423. glBindTexture(GL_TEXTURE_2D, (GLuint)geometry->texture);
  424. SubmitTransformUniform(ProgramId::Texture, shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
  425. glUniform2fv(shaders->program_texture.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
  426. }
  427. else
  428. {
  429. glUseProgram(shaders->program_color.id);
  430. glBindTexture(GL_TEXTURE_2D, 0);
  431. SubmitTransformUniform(ProgramId::Color, shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Transform]);
  432. glUniform2fv(shaders->program_color.uniform_locations[(size_t)Gfx::ProgramUniform::Translate], 1, &translation.x);
  433. }
  434. glBindVertexArray(geometry->vao);
  435. glDrawElements(GL_TRIANGLES, geometry->draw_count, GL_UNSIGNED_INT, (const GLvoid*)0);
  436. glBindVertexArray(0);
  437. glUseProgram(0);
  438. glBindTexture(GL_TEXTURE_2D, 0);
  439. Gfx::CheckGLError("RenderCompiledGeometry");
  440. }
  441. void RenderInterface_BackwardCompatible_GL3::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle handle)
  442. {
  443. Gfx::CompiledGeometryData* geometry = (Gfx::CompiledGeometryData*)handle;
  444. glDeleteVertexArrays(1, &geometry->vao);
  445. glDeleteBuffers(1, &geometry->vbo);
  446. glDeleteBuffers(1, &geometry->ibo);
  447. delete geometry;
  448. }
  449. void RenderInterface_BackwardCompatible_GL3::EnableScissorRegion(bool enable)
  450. {
  451. ScissoringState new_state = ScissoringState::Disable;
  452. if (enable)
  453. new_state = (transform_active ? ScissoringState::Stencil : ScissoringState::Scissor);
  454. if (new_state != scissoring_state)
  455. {
  456. // Disable old
  457. if (scissoring_state == ScissoringState::Scissor)
  458. glDisable(GL_SCISSOR_TEST);
  459. else if (scissoring_state == ScissoringState::Stencil)
  460. glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
  461. // Enable new
  462. if (new_state == ScissoringState::Scissor)
  463. glEnable(GL_SCISSOR_TEST);
  464. else if (new_state == ScissoringState::Stencil)
  465. glStencilFunc(GL_EQUAL, 1, GLuint(-1));
  466. scissoring_state = new_state;
  467. }
  468. }
  469. void RenderInterface_BackwardCompatible_GL3::SetScissorRegion(int x, int y, int width, int height)
  470. {
  471. if (transform_active)
  472. {
  473. const float left = float(x);
  474. const float right = float(x + width);
  475. const float top = float(y);
  476. const float bottom = float(y + height);
  477. Rml::Vertex vertices[4];
  478. vertices[0].position = {left, top};
  479. vertices[1].position = {right, top};
  480. vertices[2].position = {right, bottom};
  481. vertices[3].position = {left, bottom};
  482. int indices[6] = {0, 2, 1, 0, 3, 2};
  483. glClear(GL_STENCIL_BUFFER_BIT);
  484. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  485. glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
  486. glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  487. RenderGeometry(vertices, 4, indices, 6, 0, Rml::Vector2f(0, 0));
  488. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  489. glStencilFunc(GL_EQUAL, 1, GLuint(-1));
  490. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  491. }
  492. else
  493. {
  494. glScissor(x, viewport_height - (y + height), width, height);
  495. }
  496. }
  497. // Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
  498. #pragma pack(1)
  499. struct TGAHeader {
  500. char idLength;
  501. char colourMapType;
  502. char dataType;
  503. short int colourMapOrigin;
  504. short int colourMapLength;
  505. char colourMapDepth;
  506. short int xOrigin;
  507. short int yOrigin;
  508. short int width;
  509. short int height;
  510. char bitsPerPixel;
  511. char imageDescriptor;
  512. };
  513. // Restore packing
  514. #pragma pack()
  515. bool RenderInterface_BackwardCompatible_GL3::LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions,
  516. const Rml::String& source)
  517. {
  518. Rml::FileInterface* file_interface = Rml::GetFileInterface();
  519. Rml::FileHandle file_handle = file_interface->Open(source);
  520. if (!file_handle)
  521. {
  522. return false;
  523. }
  524. file_interface->Seek(file_handle, 0, SEEK_END);
  525. size_t buffer_size = file_interface->Tell(file_handle);
  526. file_interface->Seek(file_handle, 0, SEEK_SET);
  527. if (buffer_size <= sizeof(TGAHeader))
  528. {
  529. Rml::Log::Message(Rml::Log::LT_ERROR, "Texture file size is smaller than TGAHeader, file is not a valid TGA image.");
  530. file_interface->Close(file_handle);
  531. return false;
  532. }
  533. using Rml::byte;
  534. byte* buffer = new byte[buffer_size];
  535. file_interface->Read(buffer, buffer_size, file_handle);
  536. file_interface->Close(file_handle);
  537. TGAHeader header;
  538. memcpy(&header, buffer, sizeof(TGAHeader));
  539. int color_mode = header.bitsPerPixel / 8;
  540. int image_size = header.width * header.height * 4; // We always make 32bit textures
  541. if (header.dataType != 2)
  542. {
  543. Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported.");
  544. delete[] buffer;
  545. return false;
  546. }
  547. // Ensure we have at least 3 colors
  548. if (color_mode < 3)
  549. {
  550. Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported.");
  551. delete[] buffer;
  552. return false;
  553. }
  554. const byte* image_src = buffer + sizeof(TGAHeader);
  555. byte* image_dest = new byte[image_size];
  556. // Targa is BGR, swap to RGB and flip Y axis
  557. for (long y = 0; y < header.height; y++)
  558. {
  559. long read_index = y * header.width * color_mode;
  560. long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * 4;
  561. for (long x = 0; x < header.width; x++)
  562. {
  563. image_dest[write_index] = image_src[read_index + 2];
  564. image_dest[write_index + 1] = image_src[read_index + 1];
  565. image_dest[write_index + 2] = image_src[read_index];
  566. if (color_mode == 4)
  567. {
  568. const int alpha = image_src[read_index + 3];
  569. #ifdef RMLUI_SRGB_PREMULTIPLIED_ALPHA
  570. image_dest[write_index + 0] = (image_dest[write_index + 0] * alpha) / 255;
  571. image_dest[write_index + 1] = (image_dest[write_index + 1] * alpha) / 255;
  572. image_dest[write_index + 2] = (image_dest[write_index + 2] * alpha) / 255;
  573. #endif
  574. image_dest[write_index + 3] = (byte)alpha;
  575. }
  576. else
  577. {
  578. image_dest[write_index + 3] = 255;
  579. }
  580. write_index += 4;
  581. read_index += color_mode;
  582. }
  583. }
  584. texture_dimensions.x = header.width;
  585. texture_dimensions.y = header.height;
  586. bool success = GenerateTexture(texture_handle, image_dest, texture_dimensions);
  587. delete[] image_dest;
  588. delete[] buffer;
  589. return success;
  590. }
  591. bool RenderInterface_BackwardCompatible_GL3::GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source,
  592. const Rml::Vector2i& source_dimensions)
  593. {
  594. GLuint texture_id = 0;
  595. glGenTextures(1, &texture_id);
  596. if (texture_id == 0)
  597. {
  598. Rml::Log::Message(Rml::Log::LT_ERROR, "Failed to generate texture.");
  599. return false;
  600. }
  601. glBindTexture(GL_TEXTURE_2D, texture_id);
  602. GLint internal_format = GL_RGBA8;
  603. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source);
  604. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  605. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  606. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  607. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  608. texture_handle = (Rml::TextureHandle)texture_id;
  609. glBindTexture(GL_TEXTURE_2D, 0);
  610. return true;
  611. }
  612. void RenderInterface_BackwardCompatible_GL3::ReleaseTexture(Rml::TextureHandle texture_handle)
  613. {
  614. glDeleteTextures(1, (GLuint*)&texture_handle);
  615. }
  616. void RenderInterface_BackwardCompatible_GL3::SetTransform(const Rml::Matrix4f* new_transform)
  617. {
  618. transform_active = (new_transform != nullptr);
  619. transform = projection * (new_transform ? *new_transform : Rml::Matrix4f::Identity());
  620. transform_dirty_state = ProgramId::All;
  621. }
  622. void RenderInterface_BackwardCompatible_GL3::SubmitTransformUniform(ProgramId program_id, int uniform_location)
  623. {
  624. if ((int)program_id & (int)transform_dirty_state)
  625. {
  626. glUniformMatrix4fv(uniform_location, 1, false, transform.data());
  627. transform_dirty_state = ProgramId((int)transform_dirty_state & ~(int)program_id);
  628. }
  629. }
  630. bool RmlGL3::Initialize(Rml::String* out_message)
  631. {
  632. #if defined RMLUI_PLATFORM_EMSCRIPTEN
  633. if (out_message)
  634. *out_message = "Started Emscripten WebGL renderer.";
  635. #elif !defined RMLUI_GL3_CUSTOM_LOADER
  636. const int gl_version = gladLoaderLoadGL();
  637. if (gl_version == 0)
  638. {
  639. if (out_message)
  640. *out_message = "Failed to initialize OpenGL context.";
  641. return false;
  642. }
  643. if (out_message)
  644. *out_message = Rml::CreateString("Loaded OpenGL %d.%d.", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
  645. #endif
  646. return true;
  647. }
  648. void RmlGL3::Shutdown()
  649. {
  650. #if !defined RMLUI_PLATFORM_EMSCRIPTEN && !defined RMLUI_GL3_CUSTOM_LOADER
  651. gladLoaderUnloadGL();
  652. #endif
  653. }