| /* |
| * Copyright 2026 Behdad Esfahbod. All Rights Reserved. |
| */ |
| |
| #include "demo-renderer.h" |
| #include "demo-atlas.h" |
| #include "demo-glstate.h" |
| |
| |
| struct demo_renderer_gl_t : demo_renderer_t |
| { |
| GLFWwindow *window; |
| demo_glstate_t *st; |
| GLuint vao_name; |
| GLuint buf_name; |
| bool vao_ready; |
| unsigned int uploaded_count; |
| glyph_vertex_t *uploaded_ptr; |
| |
| demo_renderer_gl_t (GLFWwindow *window_) |
| : window (window_), vao_ready (false), |
| uploaded_count (0), uploaded_ptr (nullptr) |
| { |
| st = demo_glstate_create (); |
| glGenVertexArrays (1, &vao_name); |
| glGenBuffers (1, &buf_name); |
| } |
| |
| ~demo_renderer_gl_t () override |
| { |
| glDeleteVertexArrays (1, &vao_name); |
| glDeleteBuffers (1, &buf_name); |
| demo_glstate_destroy (st); |
| } |
| |
| void setup_vao () |
| { |
| if (vao_ready) |
| return; |
| vao_ready = true; |
| |
| GLint program; |
| glGetIntegerv (GL_CURRENT_PROGRAM, &program); |
| |
| glBindVertexArray (vao_name); |
| glBindBuffer (GL_ARRAY_BUFFER, buf_name); |
| |
| GLsizei stride = sizeof (glyph_vertex_t); |
| |
| GLint loc; |
| loc = glGetAttribLocation (program, "a_position"); |
| glEnableVertexAttribArray (loc); |
| glVertexAttribPointer (loc, 2, GL_FLOAT, GL_FALSE, stride, |
| (const void *) offsetof (glyph_vertex_t, x)); |
| |
| loc = glGetAttribLocation (program, "a_texcoord"); |
| glEnableVertexAttribArray (loc); |
| glVertexAttribPointer (loc, 2, GL_FLOAT, GL_FALSE, stride, |
| (const void *) offsetof (glyph_vertex_t, tx)); |
| |
| loc = glGetAttribLocation (program, "a_normal"); |
| glEnableVertexAttribArray (loc); |
| glVertexAttribPointer (loc, 2, GL_FLOAT, GL_FALSE, stride, |
| (const void *) offsetof (glyph_vertex_t, nx)); |
| |
| loc = glGetAttribLocation (program, "a_emPerPos"); |
| glEnableVertexAttribArray (loc); |
| glVertexAttribPointer (loc, 1, GL_FLOAT, GL_FALSE, stride, |
| (const void *) offsetof (glyph_vertex_t, emPerPos)); |
| |
| loc = glGetAttribLocation (program, "a_glyphLoc"); |
| glEnableVertexAttribArray (loc); |
| glVertexAttribIPointer (loc, 1, GL_UNSIGNED_INT, stride, |
| (const void *) offsetof (glyph_vertex_t, atlas_offset)); |
| |
| glBindVertexArray (0); |
| } |
| |
| demo_atlas_t *get_atlas () override |
| { |
| return demo_glstate_get_atlas (st); |
| } |
| |
| void setup () override |
| { |
| demo_glstate_setup (st); |
| } |
| |
| void set_gamma (float gamma) override |
| { |
| demo_glstate_set_gamma (st, gamma); |
| } |
| |
| void set_foreground (float r, float g, float b, float a) override |
| { |
| demo_glstate_set_foreground (st, r, g, b, a); |
| } |
| |
| void set_background (float r, float g, float b, float a) override |
| { |
| glClearColor (r, g, b, a); |
| } |
| |
| void set_debug (bool enabled) override |
| { |
| demo_glstate_set_debug (st, enabled); |
| } |
| |
| void set_stem_darkening (bool enabled) override |
| { |
| demo_glstate_set_stem_darkening (st, enabled); |
| } |
| |
| bool set_srgb (bool enabled) override |
| { |
| #if defined(GL_FRAMEBUFFER_SRGB) |
| while (glGetError () != GL_NO_ERROR) |
| ; |
| if (enabled) |
| { |
| glEnable (GL_FRAMEBUFFER_SRGB); |
| if (glGetError () != GL_NO_ERROR) |
| return false; |
| } |
| else |
| glDisable (GL_FRAMEBUFFER_SRGB); |
| return true; |
| #else |
| return false; |
| #endif |
| } |
| |
| void toggle_vsync (bool &vsync) override |
| { |
| vsync = !vsync; |
| glfwSwapInterval (vsync ? 1 : 0); |
| } |
| |
| void display (glyph_vertex_t *vertices, unsigned int count, |
| int width, int height, float mat[16]) override |
| { |
| glViewport (0, 0, width, height); |
| demo_glstate_set_matrix (st, mat); |
| |
| glClear (GL_COLOR_BUFFER_BIT); |
| |
| if (count > 0) |
| { |
| setup_vao (); |
| |
| glBindVertexArray (vao_name); |
| |
| if (vertices != uploaded_ptr || count != uploaded_count) |
| { |
| glBindBuffer (GL_ARRAY_BUFFER, buf_name); |
| glBufferData (GL_ARRAY_BUFFER, |
| sizeof (glyph_vertex_t) * count, |
| (const char *) vertices, GL_STATIC_DRAW); |
| uploaded_ptr = vertices; |
| uploaded_count = count; |
| } |
| |
| glDrawArrays (GL_TRIANGLES, 0, count); |
| |
| glBindVertexArray (0); |
| } |
| |
| glfwSwapBuffers (window); |
| } |
| }; |
| |
| |
| demo_renderer_t * |
| demo_renderer_create_gl (GLFWwindow *window) |
| { |
| return new demo_renderer_gl_t (window); |
| } |