diff options
Diffstat (limited to 'project-base/src/renderers/render_gl.c')
| -rw-r--r-- | project-base/src/renderers/render_gl.c | 959 |
1 files changed, 959 insertions, 0 deletions
diff --git a/project-base/src/renderers/render_gl.c b/project-base/src/renderers/render_gl.c new file mode 100644 index 0000000..dad32a5 --- /dev/null +++ b/project-base/src/renderers/render_gl.c @@ -0,0 +1,959 @@ +/* +* BSD 2-Clause “Simplified” License +* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com +* All rights reserved. +*/ + +static u8 gl_render_depth = 1; +static vec4 current_scissor; +static float global_rotation = 0.0f; + +static void gl_render_clear(platform_window *window, color tint) +{ + IMP_glClearColor(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + IMP_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +static void gl_render_set_rotation(float32 rotation) +{ + global_rotation = rotation; +} + +static void gl_render_reset_rotation(float32 rotation, float32 x, float32 y) +{ + IMP_glPopMatrix(); +} + +static void gl_set_gl_render_depth(s32 depth) +{ + gl_render_depth = depth; +} + +static vec2f gl_rotateUV(vec2f uv, float rotation) +{ + uv = (vec2f){uv.x - 0.5f, uv.y - 0.5f}; + float m2x2[4] = { cos(rotation), sin(rotation), -sin(rotation), cos(rotation) }; + + vec2f result = {0,0}; +#if 0 + result.x = m2x2[0] * uv.x + m2x2[1] * uv.y; + result.y = m2x2[2] * uv.x + m2x2[3] * uv.y; +#else + result.x = m2x2[0] * uv.x + m2x2[2] * uv.y; + result.y = m2x2[1] * uv.x + m2x2[3] * uv.y; +#endif + + result = (vec2f){result.x + 0.5f, result.y + 0.5f}; + return result; +} + +static void gl_render_rectangle(s32 x, s32 y, s32 width, s32 height, color tint) +{ + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glBegin(GL_QUADS); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + IMP_glVertex3i(x, y, gl_render_depth); + IMP_glVertex3i(x, y + height, gl_render_depth); + IMP_glVertex3i(x + width, y + height, gl_render_depth); + IMP_glVertex3i(x + width, y, gl_render_depth); + IMP_glEnd(); +} + +static void gl_render_image(image *image, s32 x, s32 y, s32 width, s32 height) +{ + log_assert(image, "Image cannot be null"); + + if (image->loaded) + { + IMP_glBindTexture(GL_TEXTURE_2D, image->textureID); + IMP_glEnable(GL_TEXTURE_2D); + IMP_glBegin(GL_QUADS); + IMP_glColor4f(1., 1., 1., 1.); + + vec2f topleft = gl_rotateUV((vec2f){0, 0}, global_rotation); + vec2f bottomleft = gl_rotateUV((vec2f){0, 1}, global_rotation); + vec2f bottomright = gl_rotateUV((vec2f){1, 1}, global_rotation); + vec2f topright = gl_rotateUV((vec2f){1, 0}, global_rotation); + + IMP_glPushMatrix(); + IMP_glTranslatef(x + (width / 2), y + (height / 2), 0); + + IMP_glTexCoord2f(topleft.x, topleft.y); + IMP_glVertex3i(x, y, gl_render_depth); + IMP_glTexCoord2f(bottomleft.x, bottomleft.y); + IMP_glVertex3i(x, y + height, gl_render_depth); + IMP_glTexCoord2f(bottomright.x, bottomright.y); + IMP_glVertex3i(x + width, y + height, gl_render_depth); + IMP_glTexCoord2f(topright.x, topright.y); + IMP_glVertex3i(x + width, y, gl_render_depth); + + IMP_glPopMatrix(); + + IMP_glEnd(); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glDisable(GL_TEXTURE_2D); + } +} + +static void gl_render_image_tint(image *image, s32 x, s32 y, s32 width, s32 height, color tint) +{ + log_assert(image, "Image cannot be null"); + + if (image->loaded) + { + IMP_glBindTexture(GL_TEXTURE_2D, image->textureID); + IMP_glEnable(GL_TEXTURE_2D); + IMP_glBegin(GL_QUADS); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + vec2f topleft = gl_rotateUV((vec2f){0, 0}, global_rotation); + vec2f bottomleft = gl_rotateUV((vec2f){0, 1}, global_rotation); + vec2f bottomright = gl_rotateUV((vec2f){1, 1}, global_rotation); + vec2f topright = gl_rotateUV((vec2f){1, 0}, global_rotation); + + IMP_glPushMatrix(); + IMP_glTranslatef(x + (width / 2), y + (height / 2), 0); + + IMP_glTexCoord2f(topleft.x, topleft.y); + IMP_glVertex3i(x, y, gl_render_depth); + IMP_glTexCoord2f(bottomleft.x, bottomleft.y); + IMP_glVertex3i(x, y + height, gl_render_depth); + IMP_glTexCoord2f(bottomright.x, bottomright.y); + IMP_glVertex3i(x + width, y + height, gl_render_depth); + IMP_glTexCoord2f(topright.x, topright.y); + IMP_glVertex3i(x + width, y, gl_render_depth); + + IMP_glPopMatrix(); + + IMP_glEnd(); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glDisable(GL_TEXTURE_2D); + } +} + +static s32 gl_render_text_ellipsed(font *font, s32 x, s32 y, s32 maxw, char *text, color tint) +{ + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + char *ellipse = "..."; + bool in_ellipse = false; + + s32 len = utf8len(text); + + s32 x_ = x; + utf8_int32_t ch; + s32 count = 0; + while ((text = utf8codepoint(text, &ch)) && ch) + { + count++; + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + s32 y_ = y + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y_, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width, y_, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + + if (!in_ellipse && (x_ - x) > maxw - (font->glyphs['.'].width * 3) && count < len - 3) + { + in_ellipse = true; + text = ellipse; + } + } + + IMP_glDisable(GL_TEXTURE_2D); + + return maxw; +} + +static s32 gl_render_text_with_selection(font *font, s32 x, s32 y, char *text, color tint, s32 selection_start, s32 selection_length) +{ + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + s32 x_ = x; + utf8_int32_t ch; + s32 index = 0; + s32 selection_start_x = x_; + s32 selection_end_x = x_; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + s32 y_ = y + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y_, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width, y_, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + + index++; + if (index == selection_start) + { + selection_start_x = x_; + } + if (index == selection_start + selection_length) + { + selection_end_x = x_; + } + } + + IMP_glDisable(GL_TEXTURE_2D); + + gl_render_rectangle(selection_start_x, y - 3, selection_end_x - selection_start_x, TEXTBOX_HEIGHT - 10, rgba(66, 134, 244, 120)); + + return x_ - x; +} + +static s32 gl_render_text_with_cursor(font *font, s32 x, s32 y, char *text, color tint, s32 cursor_pos) +{ + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + float x_ = x; + utf8_int32_t ch; + s32 index = 0; + s32 cursor_x = x_; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + s32 y_ = y + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y_, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width, y_, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + index++; + + if (index == cursor_pos) + { + cursor_x = x_; + } + } + + IMP_glDisable(GL_TEXTURE_2D); + + gl_render_rectangle(cursor_x, y - 3, 2, TEXTBOX_HEIGHT - 10, global_ui_context.style.textbox_foreground); + + return x_ - x; +} + +static s32 gl_render_text_rd(font *font, s32 x, s32 y, char *text, color tint, u16 target_h) +{ + float size_multiplier = target_h/(float)font->size; + + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + s32 x_ = x; + utf8_int32_t ch; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) ch = 32; // Turn tab into space. + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) ch = 0x3f; // Default character for out of range glyphs. + if (ch == 10) ch = 0xB6; // What the hell is this? + if (ch == 13) continue; // Don't draw newlines. + + glyph g = font->glyphs[ch]; + + s32 y_ = y + (font->px_h + g.yoff)*size_multiplier; + s32 x_to_render = x_ + (g.lsb*size_multiplier); + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y_, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y_ + g.height*size_multiplier, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width*size_multiplier, y_ + g.height*size_multiplier, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width*size_multiplier, y_, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + x_ += (g.advance*size_multiplier); + } + + IMP_glDisable(GL_TEXTURE_2D); + + return x_ - x; +} + +static s32 gl_render_text(font *font, s32 x, s32 y, char *text, color tint) +{ + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + s32 x_ = x; + utf8_int32_t ch; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) ch = 32; // Turn tab into space. + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) ch = 0x3f; // Default character for out of range glyphs. + if (ch == 10) ch = 0xB6; // What the hell is this? + if (ch == 13) continue; // Don't draw newlines. + + glyph g = font->glyphs[ch]; + + s32 y_ = y + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y_, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width, y_ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width, y_, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + /* add kerning */ + //utf8_int32_t ch_next; + //utf8codepoint(text, &ch_next); + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + } + + IMP_glDisable(GL_TEXTURE_2D); + + return x_ - x; +} + +static s32 gl_render_text_cutoff(font *font, s32 x, s32 y, char *text, color tint, u16 cutoff_width) +{ + if (!font->loaded) + return 0; + + IMP_glEnable(GL_TEXTURE_2D); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + s32 x_ = x; + s32 y_ = y; + bool is_new_line = false; + utf8_int32_t ch; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + + if (ch == '\n') + { + x_ = x; + y_ += font->size; + is_new_line = true; + continue; + } + + if (is_new_line && ch == ' ') + { + is_new_line = false; + continue; + } + else if (is_new_line && ch != ' ') + { + is_new_line = false; + } + + glyph g = font->glyphs[ch]; + + s32 y__ = y_ + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + if (x_to_render+g.advance > x + cutoff_width) + { + x_ = x; + y_ += font->size; + y__ = y_ + font->px_h + g.yoff; + x_to_render = x_; + } + + IMP_glBindTexture(GL_TEXTURE_2D, g.textureID); + IMP_glBegin(GL_QUADS); + + IMP_glTexCoord2i(0, 0); + IMP_glVertex3i(x_to_render, y__, gl_render_depth); + IMP_glTexCoord2i(0, 1); + IMP_glVertex3i(x_to_render, y__ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 1); + IMP_glVertex3i(x_to_render + g.width, y__ + g.height, gl_render_depth); + IMP_glTexCoord2i(1, 0); + IMP_glVertex3i(x_to_render + g.width, y__, gl_render_depth); + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glEnd(); + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + + if (x_ > x + cutoff_width) + { + x_ = x; + y_ += font->size; + is_new_line = true; + } + } + + IMP_glDisable(GL_TEXTURE_2D); + + return (y_ - y) + font->size; +} + +static s32 gl_calculate_cursor_position(font *font, char *text, s32 click_x) +{ + if (!font->loaded) + return 0; + + s32 x = 0; + s32 index = 0; + utf8_int32_t ch; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + s32 width_next = font->glyphs[ch_next].width; + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x += (g.advance); + if (x - (width_next / 5) > click_x) + { + return index; + } + + ++index; + } + + return index; +} + +static s32 gl_calculate_text_width_from_upto(font *font, char *text, s32 from, s32 index) +{ + if (!font->loaded) + return 0; + + s32 x = 0; + utf8_int32_t ch; + s32 i = 0; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (index == i) + return x; + + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + if (i >= from) + { + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x += (g.advance); + } + + i++; + } + + return x; +} + +static s32 gl_calculate_text_width_upto(font *font, char *text, s32 index) +{ + if (!font->loaded) + return 0; + + s32 x = 0; + utf8_int32_t ch; + s32 i = 0; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (index == i) + return x; + + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x += (g.advance); + + i++; + } + + return x; +} + +static s32 gl_calculate_text_width(font *font, char *text) +{ + if (!font->loaded) + return 0; + + float x = 0; + utf8_int32_t ch; + while ((text = utf8codepoint(text, &ch)) && ch) + { + if (ch == 9) + ch = 32; + utf8_int32_t ch_next; + utf8codepoint(text, &ch_next); + if (ch < TEXT_CHARSET_START || ch > TEXT_CHARSET_END) + { + ch = 0x3f; + } + if (ch == '\n') + ch = 0xB6; + + glyph g = font->glyphs[ch]; + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x += (g.advance); + } + + return x; +} + +static void gl_render_triangle(s32 x, s32 y, s32 w, s32 h, color tint, triangle_direction dir) +{ + IMP_glBegin(GL_TRIANGLES); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + + if (dir == TRIANGLE_DOWN) + { + IMP_glVertex3i(x + (w / 2), y + h, gl_render_depth); + IMP_glVertex3i(x, y, gl_render_depth); + IMP_glVertex3i(x + w, y, gl_render_depth); + } + else if (dir == TRIANGLE_UP) + { + IMP_glVertex3i(x + (w / 2), y, gl_render_depth); + IMP_glVertex3i(x + w, y + h, gl_render_depth); + IMP_glVertex3i(x, y + h, gl_render_depth); + } + else if (dir == TRIANGLE_LEFT) + { + IMP_glVertex3i(x, y + (w / 2), gl_render_depth); + IMP_glVertex3i(x + h, y, gl_render_depth); + IMP_glVertex3i(x + h, y + w, gl_render_depth); + } + else if (dir == TRIANGLE_RIGHT) + { + IMP_glVertex3i(x + h, y + (w / 2), gl_render_depth); + IMP_glVertex3i(x, y, gl_render_depth); + IMP_glVertex3i(x, y + w, gl_render_depth); + } + + IMP_glEnd(); +} + +static void gl_render_line(s32 x1, s32 y1, s32 x2, s32 y2, float thickness, color tint) +{ + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glLineWidth(thickness); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + IMP_glBegin(GL_LINES); + IMP_glVertex3i(x1, y1, gl_render_depth); + IMP_glVertex3i(x2, y2, gl_render_depth); + IMP_glEnd(); +} + +static void gl_render_rectangle_outline(s32 x, s32 y, s32 width, s32 height, u16 outline_w, color tint) +{ + // left + gl_render_rectangle(x, y, outline_w, height, tint); + // right + gl_render_rectangle(x + width - outline_w, y, outline_w, height, tint); + // top + gl_render_rectangle(x + outline_w, y, width - (outline_w * 2), outline_w, tint); + // bottom + gl_render_rectangle(x + outline_w, y + height - outline_w, width - (outline_w * 2), outline_w, tint); +} + +static void gl_render_set_scissor(platform_window *window, s32 x, s32 y, s32 w, s32 h) +{ + IMP_glEnable(GL_SCISSOR_TEST); + if (window) IMP_glScissor(x - 1, window->height - h - y - 1, w + 1, h + 1); + else IMP_glScissor(x - 1, y - 1 + h, w + 1, h + 1); +} + +static vec4 gl_render_get_scissor() +{ + GLboolean enabled = false; + IMP_glGetBooleanv(GL_SCISSOR_TEST,&enabled); + vec4 vec; + + if (enabled) { + IMP_glGetIntegerv(GL_SCISSOR_BOX, (GLint *)(&vec)); + vec.x += 1; + vec.w -= 1; + vec.h -= 1; + vec.y += 1; + } else { + vec = (vec4){0,0,99999,99999}; + } + return vec; +} + +static void gl_render_reset_scissor() +{ + IMP_glDisable(GL_SCISSOR_TEST); +} + +// +// Arc drawing +// +static float gl_normalizeAngleToSmallestPositive(float angle) +{ + while (angle < 0.0) + { + angle += M_PI * 2; + } + while (angle >= M_PI * 2) + { + angle -= M_PI * 2; + } + return angle; +} + +const int ARC_VERTEX_COUNT = 100; +static void gl__render_arc(float angle1, float angle2, float radius, float x, float y, float useBiggerArc, color tint, float thickness) +{ + // Prepare angles + angle1 = gl_normalizeAngleToSmallestPositive(angle1); + angle2 = gl_normalizeAngleToSmallestPositive(angle2); + if (angle1 > angle2) + { + float buffer = angle1; + angle1 = angle2; + angle2 = buffer; + } + if (useBiggerArc != (angle2 - angle1 > M_PI)) + { + angle1 += M_PI * 2; + } + + s32 buffer_size = ARC_VERTEX_COUNT * 2; + + // Create opengl geometry + GLfloat pos[200]; + for (int i = 0; i < ARC_VERTEX_COUNT; i++) + { + pos[i * 2] = sin((float)i / (ARC_VERTEX_COUNT - 1) * (angle2 - angle1) + angle1) * radius + x; + pos[i * 2 + 1] = cos((float)i / (ARC_VERTEX_COUNT - 1) * (angle2 - angle1) + angle1) * radius + y; + } + + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glBegin(GL_LINE_STRIP); + IMP_glLineWidth(thickness); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + for (int i = 0; i < buffer_size; i += 2) + { + //printf("pos: %f %f, --- x: %f y: %f\n", x, y, pos[i], pos[i+1]); + IMP_glVertex3i(pos[i], pos[i + 1], gl_render_depth); + } + IMP_glEnd(); +} + +static void gl_render_arc(float x1, float y1, float x2, float y2, float radius, bool arcDirection, bool useBiggerArc, color tint, float thickness) +{ + // distance between points + float distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + // halfway point + float xAverage = (x1 + x2) / 2.0; + float yAverage = (y1 + y2) / 2.0; + // circle center + float xCenter = sqrt(radius * radius - distance * distance / 4.0) * (y1 - y2) / distance; + float yCenter = sqrt(radius * radius - distance * distance / 4.0) * (x2 - x1) / distance; + xCenter = xAverage + (arcDirection ? xCenter : -xCenter); + yCenter = yAverage + (arcDirection ? yCenter : -yCenter); + // angles + float angle1 = atan2(x1 - xCenter, y1 - yCenter); + float angle2 = atan2(x2 - xCenter, y2 - yCenter); + // create the arc + + //printf("%f %f %f, %f\n", distance, xCenter, yCenter, (radius*radius - distance*distance/4.0)); + gl__render_arc(angle1, angle2, radius, xCenter, yCenter, useBiggerArc, tint, thickness); +} + +#define ROUNDING_POINT_COUNT 16 // Larger values makes circle smoother. +void gl_render_rounded_rect(float x, float y, float width, float height, color tint, float radius, int innerPad) +{ + y += height; + vec2f top_left[ROUNDING_POINT_COUNT]; + vec2f bottom_left[ROUNDING_POINT_COUNT]; + vec2f top_right[ROUNDING_POINT_COUNT]; + vec2f bottom_right[ROUNDING_POINT_COUNT]; + + if( radius == 0.0 ) + { + radius = min(width, height); + radius *= 0.10; // 10% + } + + int i = 0; + float x_offset, y_offset; + float step = ( 2.0f * M_PI ) / (ROUNDING_POINT_COUNT * 4), + angle = 0.0f; + + unsigned int index = 0, segment_count = ROUNDING_POINT_COUNT; + vec2f bottom_left_corner = { x + radius, y - height + radius }; + + + while( i != segment_count ) + { + x_offset = cosf( angle ); + y_offset = sinf( angle ); + + + top_left[ index ].x = bottom_left_corner.x - + ( x_offset * radius ); + top_left[ index ].y = ( height - ( radius * 2.0f ) ) + + bottom_left_corner.y - + ( y_offset * radius ); + + + top_right[ index ].x = ( width - ( radius * 2.0f ) ) + + bottom_left_corner.x + + ( x_offset * radius ) + (i == 0 ? -1 : 0); + top_right[ index ].y = ( height - ( radius * 2.0f ) ) + + bottom_left_corner.y - + ( y_offset * radius ); + + + bottom_right[ index ].x = ( width - ( radius * 2.0f ) ) + + bottom_left_corner.x + + ( x_offset * radius ) + (i == 0 ? -1 : 0); + bottom_right[ index ].y = bottom_left_corner.y + + ( y_offset * radius ); + + + bottom_left[ index ].x = bottom_left_corner.x - + ( x_offset * radius ); + bottom_left[ index ].y = bottom_left_corner.y + + ( y_offset * radius ); + +#if 1 + top_left[ index ].x = (top_left[ index ].x)+innerPad; + top_left[ index ].y = (top_left[ index ].y)-innerPad; + + + top_right[ index ].x = (top_right[ index ].x)-innerPad; + top_right[ index ].y = (top_right[ index ].y)-innerPad; + + + bottom_right[ index ].x = (bottom_right[ index ].x)-innerPad; + bottom_right[ index ].y = (bottom_right[ index ].y)+innerPad; + + + bottom_left[ index ].x = (bottom_left[ index ].x)+innerPad; + bottom_left[ index ].y = (bottom_left[ index ].y)+innerPad; +#endif + + angle -= step; + + ++index; + + ++i; + } + + IMP_glBindTexture(GL_TEXTURE_2D, 0); + IMP_glColor4f(tint.r / 255.0f, tint.g / 255.0f, tint.b / 255.0f, tint.a / 255.0f); + IMP_glBegin( GL_TRIANGLE_STRIP ); + { + // Top + for( i = segment_count - 1 ; i >= 0 ; i--) + { + IMP_glVertex3i( top_left[ i ].x, top_left[ i ].y, gl_render_depth); + IMP_glVertex3i( top_right[ i ].x, top_right[ i ].y, gl_render_depth ); + } + + // In order to stop and restart the strip. + IMP_glVertex3i( top_right[ 0 ].x, top_right[ 0 ].y, gl_render_depth ); + IMP_glVertex3i( top_right[ 0 ].x, top_right[ 0 ].y, gl_render_depth ); + + // Center + IMP_glVertex3i( top_right[ 0 ].x, top_right[ 0 ].y, gl_render_depth ); + IMP_glVertex3i( top_left[ 0 ].x, top_left[ 0 ].y, gl_render_depth ); + IMP_glVertex3i( bottom_right[ 0 ].x, bottom_right[ 0 ].y, gl_render_depth ); + IMP_glVertex3i( bottom_left[ 0 ].x, bottom_left[ 0 ].y, gl_render_depth ); + + // Bottom + for( i = 0; i != segment_count ; i++ ) + { + IMP_glVertex3i( bottom_right[ i ].x, bottom_right[ i ].y, gl_render_depth ); + IMP_glVertex3i( bottom_left[ i ].x, bottom_left[ i ].y, gl_render_depth ); + } + } + IMP_glEnd(); +} + +render_driver render_gl_driver = +{ + "GL", + gl_set_gl_render_depth, + gl_render_clear, + + gl_render_image, + gl_render_image_tint, + + gl_render_text, + gl_render_text_ellipsed, + gl_render_text_cutoff, + gl_render_text_with_cursor, + gl_render_text_with_selection, + + gl_calculate_cursor_position, + gl_calculate_text_width, + gl_calculate_text_width_upto, + gl_calculate_text_width_from_upto, + + gl_render_rectangle, + gl_render_line, + gl_render_rectangle_outline, + gl_render_triangle, + + gl_render_set_scissor, + gl_render_get_scissor, + gl_render_reset_scissor, + + gl_render_set_rotation, + gl_render_reset_rotation, + gl_render_arc, + + gl_render_text_rd, + gl_render_rounded_rect, +};
\ No newline at end of file |
