diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2024-11-23 22:33:43 +0100 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2024-11-23 22:33:43 +0100 |
| commit | b1e857cf1471d1871a9396696b22fa531da98249 (patch) | |
| tree | 3923008a8653057698cb339faf6dcfa92e18364b /project-base/src/renderers | |
| parent | 106bb7fcadf637cec883648916cc8d19529d6199 (diff) | |
add projbase to repo
Diffstat (limited to 'project-base/src/renderers')
| -rw-r--r-- | project-base/src/renderers/render_cpu.c | 760 | ||||
| -rw-r--r-- | project-base/src/renderers/render_gl.c | 959 |
2 files changed, 1719 insertions, 0 deletions
diff --git a/project-base/src/renderers/render_cpu.c b/project-base/src/renderers/render_cpu.c new file mode 100644 index 0000000..750de97 --- /dev/null +++ b/project-base/src/renderers/render_cpu.c @@ -0,0 +1,760 @@ +/* +* BSD 2-Clause “Simplified” License +* Copyright (c) 2019, Aldrik Ramaekers, aldrik.ramaekers@protonmail.com +* All rights reserved. +*/ + +static u8 cpu_render_depth = 1; +static vec4 current_scissor; + +static platform_window *drawing_window = 0; + +static void _copy_image_pixel(s32 x, s32 y, image *image, render_target rec) +{ + s32 offset = (y * (drawing_window->backbuffer.width) * 5) + x * 5; + u8 *buffer_entry = drawing_window->backbuffer.buffer + offset; + + if (buffer_entry[4] > cpu_render_depth) + return; + buffer_entry[4] = cpu_render_depth; + + s32 _x = x - rec.x + rec.offset_x; + s32 _y = y - rec.y + rec.offset_y; + s32 image_offset = (_y * (image->width) * 4) + _x * 4; + u8 *color = image->data + image_offset; + + float32 alpha = color[3] / 255.0f; + float32 oneminusalpha = 1 - alpha; + + u8 b = ((color[0] * alpha) + (oneminusalpha * buffer_entry[0])); + u8 g = ((color[1] * alpha) + (oneminusalpha * buffer_entry[1])); + u8 r = ((color[2] * alpha) + (oneminusalpha * buffer_entry[2])); + u8 a = color[3]; + + s32 c = (a << 24) | (r << 16) | (g << 8) | (b << 0); + + memcpy(buffer_entry, &c, 4); +} + +static void _copy_glyph_pixel(s32 x, s32 y, glyph *gl, render_target rec, color tint) +{ + s32 offset = (y * (drawing_window->backbuffer.width) * 5) + x * 5; + u8 *buffer_entry = drawing_window->backbuffer.buffer + offset; + + if (buffer_entry[4] > cpu_render_depth) + return; + buffer_entry[4] = cpu_render_depth; + + s32 _x = x - rec.x + rec.offset_x; + s32 _y = y - rec.y + rec.offset_y; + s32 image_offset = (_y * gl->width) + _x; + u8 *color = gl->bitmap + image_offset; + + float32 alpha = color[0] / 255.0f; + float32 oneminusalpha = 1 - alpha; + + u8 r = ((tint.r * alpha) + (oneminusalpha * buffer_entry[2])); + u8 g = ((tint.g * alpha) + (oneminusalpha * buffer_entry[1])); + u8 b = ((tint.b * alpha) + (oneminusalpha * buffer_entry[0])); + u8 a = color[0]; + + s32 c = (a << 24) | (r << 16) | (g << 8) | (b << 0); + + memcpy(buffer_entry, &c, 4); +} + +static void _set_pixel(s32 x, s32 y, color tint) +{ + s32 offset = (y * (drawing_window->backbuffer.width) * 5) + x * 5; + u8 *buffer_entry = drawing_window->backbuffer.buffer + offset; + + if (buffer_entry[4] > cpu_render_depth) + return; + buffer_entry[4] = cpu_render_depth; + + float32 alpha = tint.a / 255.0f; + float32 oneminusalpha = 1 - alpha; + + u8 r = ((tint.r * alpha) + (oneminusalpha * buffer_entry[2])); + u8 g = ((tint.g * alpha) + (oneminusalpha * buffer_entry[1])); + u8 b = ((tint.b * alpha) + (oneminusalpha * buffer_entry[0])); + u8 a = tint.a; + + s32 c = (a << 24) | (r << 16) | (g << 8) | (b << 0); + + memcpy(buffer_entry, &c, 4); +} + +// returns topleft and bottomright corners. not width + height +static render_target _get_actual_rect(s32 x, s32 y, s32 width, s32 height) +{ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + s32 start_x = x; + s32 start_y = y; + s32 end_x = start_x + width; + s32 end_y = start_y + height; + s32 offset_x = 0; + s32 offset_y = 0; + + if (start_x < current_scissor.x) + { + offset_x = current_scissor.x - start_x; + start_x = current_scissor.x; + } + if (start_y < current_scissor.y) + { + offset_y = current_scissor.y - start_y; + start_y = current_scissor.y; + } + + if (end_x > current_scissor.x + current_scissor.w) + end_x = current_scissor.x + current_scissor.w; + if (end_y > current_scissor.y + current_scissor.h) + end_y = current_scissor.y + current_scissor.h; + + if (end_x > drawing_window->backbuffer.width) + end_x = drawing_window->backbuffer.width; + if (end_y > drawing_window->backbuffer.height) + end_y = drawing_window->backbuffer.height; + + return (render_target){start_x, start_y, end_x, end_y, offset_x, offset_y}; +} + +static void cpu_render_reset_scissor() +{ + current_scissor = (vec4){0, 0, drawing_window->width + 1, drawing_window->height + 1}; +} + +static void cpu_render_rectangle(s32 x, s32 y, s32 width, s32 height, color tint) +{ + render_target rec = _get_actual_rect(x, y, width, height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _set_pixel(x, y, tint); + } + } +} + +static void cpu_render_clear(platform_window *window, color tint) +{ + drawing_window = window; + cpu_render_reset_scissor(); + + cpu_render_depth = 1; + + u8 pixel[5] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00}; + s32 pixel_count = window->backbuffer.width * window->backbuffer.height; + for (s32 i = 0; i < pixel_count; i++) + memcpy(window->backbuffer.buffer + (i * 5), pixel, 5); +} + +static void cpu_render_set_rotation(float32 rotation) +{ + log_assert(0, "render_set_rotation not implemented on cpu"); +} + +static void cpu_render_reset_rotation(float32 rotation, float32 x, float32 y) +{ + log_assert(0, "render_reset_rotation not implemented on cpu"); +} + +static void cpu_set_cpu_render_depth(s32 depth) +{ + cpu_render_depth = depth; +} + +static void cpu_render_image(image *image, s32 x, s32 y, s32 width, s32 height) +{ + log_assert(image, "Image cannot be null"); + + if (image->loaded) + { + render_target rec = _get_actual_rect(x, y, image->width, image->height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_image_pixel(x, y, image, rec); + } + } + } +} + +static void cpu_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) + { + log_assert(0, "render_image_tint not implemented for on cpu"); + } +} + +static s32 cpu_render_text_ellipsed(font *font, s32 x, s32 y, s32 maxw, char *text, color tint) +{ + if (!font->loaded) + return 0; + + 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); + + render_target rec = _get_actual_rect(x_to_render, y_, g.width, g.height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_glyph_pixel(x, y, &g, rec, tint); + } + } + + /* 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; + } + } + + return maxw; +} + +static s32 cpu_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; + + 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); + + render_target rec = _get_actual_rect(x_to_render, y_, g.width, g.height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_glyph_pixel(x, y, &g, rec, tint); + } + } + + /* 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_; + } + } + + cpu_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 cpu_render_text_with_cursor(font *font, s32 x, s32 y, char *text, color tint, s32 cursor_pos) +{ + if (!font->loaded) + return 0; + + 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); + + render_target rec = _get_actual_rect(x_to_render, y_, g.width, g.height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_glyph_pixel(x, y, &g, rec, tint); + } + } + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + index++; + + if (index == cursor_pos) + { + cursor_x = x_; + } + } + + cpu_render_rectangle(cursor_x, y - 3, 2, TEXTBOX_HEIGHT - 10, global_ui_context.style.textbox_foreground); + + return x_ - x; +} + +static s32 cpu_render_text(font *font, s32 x, s32 y, char *text, color tint) +{ + if (!font->loaded) + return 0; + + s32 x_ = x; + 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 == 10) + ch = 0xB6; + if (ch == 13) + continue; + + glyph g = font->glyphs[ch]; + + s32 y_ = y + font->px_h + g.yoff; + s32 x_to_render = x_ + (g.lsb); + + render_target rec = _get_actual_rect(x_to_render, y_, g.width, g.height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_glyph_pixel(x, y, &g, rec, tint); + } + } + + /* add kerning */ + //kern = stbtt_GetCodepointKernAdvance(&font->info, ch, ch_next); + x_ += (g.advance); + } + + return x_ - x; +} + +static s32 cpu_render_text_cutoff(font *font, s32 x, s32 y, char *text, color tint, u16 cutoff_width) +{ + if (!font->loaded) + return 0; + + 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); + + render_target rec = _get_actual_rect(x_to_render, y__, g.width, g.height); + + for (s32 y = rec.y; y < rec.h; y++) + { + for (s32 x = rec.x; x < rec.w; x++) + { + _copy_glyph_pixel(x, y, &g, rec, tint); + } + } + + /* 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; + } + } + + return (y_ - y) + font->size; +} + +static s32 cpu_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 cpu_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 cpu_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 cpu_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 cpu_render_triangle(s32 x, s32 y, s32 w, s32 h, color tint, triangle_direction dir) +{ + render_target rec = _get_actual_rect(x, y, w, h); + + s32 ac_w = rec.w - rec.x; + + if (dir == TRIANGLE_DOWN) + { + for (s32 y = rec.y; y < rec.h; y++) + { + s32 _y = y - rec.y; + + for (s32 x = rec.x; x < rec.w; x++) + { + s32 _x = x - rec.x; + if (_x < _y / 2 || _x >= ac_w - (_y / 2) - 1) + continue; + + _set_pixel(x, y, tint); + } + } + } + else if (dir == TRIANGLE_UP) + { + s32 ac_h = rec.h - rec.y; + + for (s32 y = rec.y; y < rec.h; y++) + { + s32 _y = (y - rec.y); + _y = ac_h - _y; + + for (s32 x = rec.x; x < rec.w; x++) + { + s32 _x = x - rec.x; + if (_x < _y / 2 || _x >= ac_w - (_y / 2)) + continue; + + _set_pixel(x, y, tint); + } + } + } + else if (dir == TRIANGLE_LEFT) + { + s32 ac_h = rec.h - rec.y; + + for (s32 y = rec.y; y < rec.h; y++) + { + s32 _y = (y - rec.y); + _y = ac_h - _y; + + for (s32 x = rec.x; x < rec.w; x++) + { + s32 _x = x - rec.x; + _x = ac_w - _x; + if (_x / 2 > _y - 1 || _x / 2 >= ac_w - (_y)) + continue; + + _set_pixel(x, y, tint); + } + } + } + else if (dir == TRIANGLE_RIGHT) + { + log_assert(0, "TRIANGLE_RIGHT not implemented"); + } +} + +static void cpu_render_line(s32 x1, s32 y1, s32 x2, s32 y2, float thickness, color tint) +{ + log_assert(0, "render_line not implemented on cpu"); +} + +static void cpu_render_rectangle_outline(s32 x, s32 y, s32 width, s32 height, u16 outline_w, color tint) +{ + // left + cpu_render_rectangle(x, y, outline_w, height, tint); + // right + cpu_render_rectangle(x + width - outline_w, y, outline_w, height, tint); + // top + cpu_render_rectangle(x + outline_w, y, width - (outline_w * 2), outline_w, tint); + // bottom + cpu_render_rectangle(x + outline_w, y + height - outline_w, width - (outline_w * 2), outline_w, tint); +} + +static void cpu_render_set_scissor(platform_window *window, s32 x, s32 y, s32 w, s32 h) +{ + current_scissor = (vec4){x, y, w + 1, h + 1}; +} + +static vec4 cpu_render_get_scissor(platform_window *window) +{ + return current_scissor; +} + +// +// Arc drawing +// +static void cpu_render_arc(float x1, float y1, float x2, float y2, float radius, bool arcDirection, bool useBiggerArc, color tint, float thickness) +{ + log_assert(0, "render_arc not implemented on cpu"); +} + +render_driver render_cpu_driver = +{ + "CPU", + cpu_set_cpu_render_depth, + cpu_render_clear, + + cpu_render_image, + cpu_render_image_tint, + + cpu_render_text, + cpu_render_text_ellipsed, + cpu_render_text_cutoff, + cpu_render_text_with_cursor, + cpu_render_text_with_selection, + + cpu_calculate_cursor_position, + cpu_calculate_text_width, + cpu_calculate_text_width_upto, + cpu_calculate_text_width_from_upto, + + cpu_render_rectangle, + cpu_render_line, + cpu_render_rectangle_outline, + cpu_render_triangle, + + cpu_render_set_scissor, + cpu_render_get_scissor, + cpu_render_reset_scissor, + + cpu_render_set_rotation, + cpu_render_reset_rotation, + cpu_render_arc, + + 0, + 0, +};
\ No newline at end of file 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 |
