diff options
author | Marvin Borner | 2021-07-01 14:43:53 +0200 |
---|---|---|
committer | Marvin Borner | 2021-07-01 14:43:53 +0200 |
commit | 340e841772eb13d9087235b8707c1cfeff8710cb (patch) | |
tree | 5f4c3328105a3ab194deef9f05fd05ff3c26b7dc | |
parent | 73a7db5b48eab615a0f6258e0196a1260a88cbbb (diff) |
Math improvements and basic plotting
-rw-r--r-- | apps/test/main.c | 26 | ||||
-rw-r--r-- | libs/libc/inc/math.h | 36 | ||||
-rw-r--r-- | libs/libc/inc/vec.h | 38 | ||||
-rw-r--r-- | libs/libc/math.c | 154 | ||||
-rw-r--r-- | libs/libc/print.c | 19 | ||||
-rw-r--r-- | libs/libgui/gfx.c | 6 | ||||
-rw-r--r-- | libs/libgui/gui.c | 18 | ||||
-rw-r--r-- | libs/libgui/gui.h | 2 | ||||
-rw-r--r-- | libs/libgui/widgets.c | 86 | ||||
-rw-r--r-- | libs/libgui/widgets.h | 22 |
10 files changed, 318 insertions, 89 deletions
diff --git a/apps/test/main.c b/apps/test/main.c index 5407ee6..b0806cf 100644 --- a/apps/test/main.c +++ b/apps/test/main.c @@ -176,19 +176,19 @@ TEST(list) TEST(math) { - EQUALS(pow(2, 3), 8.0); - - EQUALS_APPROX(sqrt(2), 1.4142135); - EQUALS(sqrt(-2), 0.0); // Well... - - EQUALS_APPROX(sin(M_PI), 0.0); - EQUALS_APPROX(sin(1234), 0.601928); - EQUALS_APPROX(cos(1234), -0.798551); - EQUALS_APPROX(tan(1234), -0.753775); - EQUALS_APPROX(sqrt(1234), 35.128336); - EQUALS_APPROX(sin(-1), -0.8414709848078965); - EQUALS_APPROX(cos(-1), 0.5403023058681398); - EQUALS_APPROX(tan(-1), -1.5574077246549023); + EQUALS(mpow(2, 3), 8.0); + + EQUALS_APPROX(msqrt(2), 1.4142135); + EQUALS(msqrt(-2), 0.0); // Well... + + EQUALS_APPROX(msin(M_PI), 0.0); + EQUALS_APPROX(msin(1234), 0.601928); + EQUALS_APPROX(mcos(1234), -0.798551); + EQUALS_APPROX(mtan(1234), -0.753775); + EQUALS_APPROX(msqrt(1234), 35.128336); + EQUALS_APPROX(msin(-1), -0.8414709848078965); + EQUALS_APPROX(mcos(-1), 0.5403023058681398); + EQUALS_APPROX(mtan(-1), -1.5574077246549023); } TEST(mem) diff --git a/libs/libc/inc/math.h b/libs/libc/inc/math.h index 813ebf1..4d21e88 100644 --- a/libs/libc/inc/math.h +++ b/libs/libc/inc/math.h @@ -17,21 +17,25 @@ #define M_PI_2 1.57079632679489661923 #define M_PI_4 0.78539816339744830962 -f32 powf(f32 base, f32 exp); -f64 pow(f64 base, f64 exp); -f32 sqrtf(f32 num); -f64 sqrt(f64 num); - -f32 lerpf(f32 from, f32 to, f32 trans); -f64 lerp(f64 from, f64 to, f64 trans); -f32 blerpf(f32 a, f32 b, f32 c, f32 d, f32 transx, f32 transy); -f64 blerp(f64 a, f64 b, f64 c, f64 d, f64 transx, f64 transy); - -f32 sinf(f32 angle); -f64 sin(f64 angle); -f32 cosf(f32 angle); -f64 cos(f64 angle); -f32 tanf(f32 angle); -f64 tan(f64 angle); +f64 mceil(f64 x); +f64 mfloor(f64 x); + +f64 mexp(f64 exp); +f64 mexp2(f64 exp); + +f64 mlog(f64 x); +f64 mlog2(f64 x); + +f64 mpow(f64 base, f64 exp); +f64 msqrt(f64 num); + +f64 mcubic(f64 x, f64 a, f64 b, f64 c, f64 d); + +f64 mlerp(f64 from, f64 to, f64 trans); +f64 mblerp(f64 a, f64 b, f64 c, f64 d, f64 transx, f64 transy); + +f64 msin(f64 angle); +f64 mcos(f64 angle); +f64 mtan(f64 angle); #endif diff --git a/libs/libc/inc/vec.h b/libs/libc/inc/vec.h index bcd4cca..b2755ae 100644 --- a/libs/libc/inc/vec.h +++ b/libs/libc/inc/vec.h @@ -5,6 +5,10 @@ #include <def.h> +/** + * Unsigned 32 + */ + typedef struct vec2 { u32 x, y; } vec2; @@ -35,4 +39,38 @@ typedef struct vec3 { ((vec3){ a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }) #define vec3_sum(a) ((u32)(a.x + a.y + a.z)) +/** + * Floating 32 + */ + +typedef struct vec2f { + f64 x, y; +} vec2f; + +typedef struct vec3f { + f64 x, y, z; +} vec3f; + +#define vec2f(x, y) ((vec2f){ (x), (y) }) +#define vec2fto3f(a, z) ((vec3f){ a.x, a.y, (z) }) +#define vec2f_add(a, b) ((vec2f){ a.x + b.x, a.y + b.y }) +#define vec2f_sub(a, b) ((vec2f){ a.x - b.x, a.y - b.y }) +#define vec2f_mul(a, b) ((vec2f){ a.x * (b), a.y * (b) }) +#define vec2f_div(a, b) ((vec2f){ a.x / (b), a.y / (b) }) +#define vec2f_dot(a, b) ((f64)(a.x * b.x + a.y * b.y)) +#define vec2f_eq(a, b) (a.x == b.x && a.y == b.y) +#define vec2f_sum(a) ((f64)(a.x + a.y)) + +#define vec3f(x, y, z) ((vec3f){ (x), (y), (z) }) +#define vec3fto2f(a) ((vec2f){ a.x, a.y }) +#define vec3f_add(a, b) ((vec3f){ a.x + b.x, a.y + b.y, a.z + b.z }) +#define vec3f_sub(a, b) ((vec3f){ a.x - b.x, a.y - b.y, a.z - b.z }) +#define vec3f_mul(a, b) ((vec3f){ a.x * (b), a.y * (b), a.z * (b) }) +#define vec3f_div(a, b) ((vec3f){ a.x / (b), a.y / (b), a.z / (b) }) +#define vec3f_dot(a, b) ((f64f)(a.x * b.x + a.y * b.y + a.z * b.z)) +#define vec3f_eq(a, b) (a.x == b.x && a.y == b.y && a.z == c.z) +#define vec3f_cross(a, b) \ + ((vec3f){ a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }) +#define vec3f_sum(a) ((f64)(a.x + a.y + a.z)) + #endif diff --git a/libs/libc/math.c b/libs/libc/math.c index 606281c..4d31e04 100644 --- a/libs/libc/math.c +++ b/libs/libc/math.c @@ -2,104 +2,148 @@ #include <math.h> -f32 powf(f32 base, f32 exp) +f64 mceil(f64 x) { - return (f32)pow(base, exp); + if (x == 0.0) + return x; + + f64 out; + __asm__ volatile("frndint\n" : "=t"(out) : "0"(x)); + if (out < x) + return out + 1.0; + return out; } -f64 pow(f64 base, f64 exp) +f64 mfloor(f64 x) { + if (x == 0.0) + return x; + f64 out; - __asm__ volatile("fyl2x;" - "fld %%st;" - "frndint;" - "fsub %%st,%%st(1);" - "fxch;" - "fchs;" - "f2xm1;" - "fld1;" - "faddp;" - "fxch;" - "fld1;" - "fscale;" - "fstp %%st(1);" - "fmulp;" - : "=t"(out) - : "0"(base), "u"(exp) - : "st(1)"); + __asm__ volatile("frndint\n" : "=t"(out) : "0"(x)); + if (out > x) + return out - 1.0; return out; } -// TODO: More efficient sqrt? - -f32 sqrtf(f32 num) +f64 mexp(f64 exp) { - return powf(num, .5); + f64 out; + __asm__ volatile("fldl2e\n" + "fmulp\n" + "fld1\n" + "fld %%st(1)\n" + "fprem\n" + "f2xm1\n" + "faddp\n" + "fscale\n" + "fstp %%st(1)" + : "=t"(out) + : "0"(exp)); + return out; } -f64 sqrt(f64 num) +f64 mexp2(f64 exp) { - return pow(num, .5); + f64 out; + __asm__ volatile("fld1\n" + "fld %%st(1)\n" + "fprem\n" + "f2xm1\n" + "faddp\n" + "fscale\n" + "fstp %%st(1)" + : "=t"(out) + : "0"(exp)); + return out; } -/** - * Interpolations - */ +f64 mlog(f64 x) +{ + f64 out; + __asm__ volatile("fldln2\n" + "fld %%st(1)\n" + "fyl2x\n" + "fstp %%st(1)" + : "=t"(out) + : "0"(x)); + return out; +} -f32 lerpf(f32 from, f32 to, f32 trans) +f64 mlog2(f64 x) { - return from + (to - from) * trans; + f64 out; + __asm__ volatile("fld1\n" + "fld %%st(1)\n" + "fyl2x\n" + "fstp %%st(1)" + : "=t"(out) + : "0"(x)); + return out; } -f64 lerp(f64 from, f64 to, f64 trans) +f64 mpow(f64 base, f64 exp) { - return from + (to - from) * trans; + if (exp == 0) + return 1; + if (exp == 1) + return base; + if (base == 0) + return 0; + if (exp == (f64)((s32)exp)) { + f64 out = base; + for (u32 i = 0; i < FABS(exp) - 1; i++) + out *= base; + if (exp < 0) + out = 1.0 / out; + return out; + } + return mexp2(exp * mlog2(base)); } -f32 blerpf(f32 a, f32 b, f32 c, f32 d, f32 transx, f32 transy) +// TODO: More efficient sqrt? + +f64 msqrt(f64 num) { - return lerpf(lerpf(a, b, transx), lerpf(c, d, transx), transy); + return mpow(num, .5); } -f64 blerp(f64 a, f64 b, f64 c, f64 d, f64 transx, f64 transy) +f64 mcubic(f64 x, f64 a, f64 b, f64 c, f64 d) { - return lerp(lerp(a, b, transx), lerp(c, d, transx), transy); + return a * mpow(x, 3) + b * mpow(x, 2) + c * x + d; } /** - * Trigonometric functions + * Interpolations */ -f32 sinf(f32 angle) +f64 mlerp(f64 from, f64 to, f64 trans) { - f32 ret = 0.0; - __asm__ volatile("fsin" : "=t"(ret) : "0"(angle)); - return ret; + return from + (to - from) * trans; } -f64 sin(f64 angle) +f64 mblerp(f64 a, f64 b, f64 c, f64 d, f64 transx, f64 transy) { - f64 ret = 0.0; - __asm__ volatile("fsin" : "=t"(ret) : "0"(angle)); - return ret; + return mlerp(mlerp(a, b, transx), mlerp(c, d, transx), transy); } -f32 cosf(f32 angle) -{ - return sinf(angle + (f32)M_PI_2); -} +/** + * Trigonometric functions + */ -f64 cos(f64 angle) +f64 msin(f64 angle) { - return sin(angle + (f64)M_PI_2); + f64 ret = 0.0; + __asm__ volatile("fsin" : "=t"(ret) : "0"(angle)); + return ret; } -f32 tanf(f32 angle) +f64 mcos(f64 angle) { - return (f32)tan(angle); + return msin(angle + (f64)M_PI_2); } -f64 tan(f64 angle) +f64 mtan(f64 angle) { f64 ret = 0.0, one; __asm__ volatile("fptan" : "=t"(one), "=u"(ret) : "0"(angle)); diff --git a/libs/libc/print.c b/libs/libc/print.c index 00b47c3..4ad1021 100644 --- a/libs/libc/print.c +++ b/libs/libc/print.c @@ -23,10 +23,12 @@ int vsnprintf(char *str, u32 size, const char *format, va_list ap) int temp_int; char temp_ch; char *temp_str; - f64 temp_double; + double temp_double; + vec2 temp_vec2; char buffer[64] = { 0 }; + // TODO: Fix potential memory overflows because of str[length++]=xxx char ch; while ((ch = *format++)) { if (ch == '%') { @@ -42,11 +44,26 @@ int vsnprintf(char *str, u32 size, const char *format, va_list ap) temp_str = va_arg(ap, char *); length += strlcpy(&str[length], temp_str, size - length); break; + case 'b': + temp_int = va_arg(ap, int); + itoa(temp_int, buffer, 2); + length += strlcpy(&str[length], buffer, size - length); + break; case 'd': temp_int = va_arg(ap, int); itoa(temp_int, buffer, 10); length += strlcpy(&str[length], buffer, size - length); break; + case 'v': + str[length++] = '('; + temp_vec2 = va_arg(ap, vec2); + itoa(temp_vec2.x, buffer, 10); + length += strlcpy(&str[length], buffer, size - length); + str[length++] = '/'; + itoa(temp_vec2.y, buffer, 10); + length += strlcpy(&str[length], buffer, size - length); + str[length++] = ')'; + break; case 'x': temp_int = va_arg(ap, int); itoa(temp_int, buffer, 16); diff --git a/libs/libgui/gfx.c b/libs/libgui/gfx.c index 913fe59..8f6f163 100644 --- a/libs/libgui/gfx.c +++ b/libs/libgui/gfx.c @@ -305,8 +305,8 @@ struct gfx_context *gfx_scale(struct gfx_context *ctx, vec2 size) y++; } - f32 gx = x / (f32)size.x * (ctx->size.x - 1); - f32 gy = y / (f32)size.y * (ctx->size.y - 1); + f64 gx = x / (f64)size.x * (ctx->size.x - 1); + f64 gy = y / (f64)size.y * (ctx->size.y - 1); u32 gxi = (u32)gx; u32 gyi = (u32)gy; @@ -317,7 +317,7 @@ struct gfx_context *gfx_scale(struct gfx_context *ctx, vec2 size) u32 color = 0; for (u8 i = 0; i < bypp; i++) { - color |= ((u32)blerpf(GET_COLOR(a, i), GET_COLOR(b, i), GET_COLOR(c, i), + color |= ((u32)mblerp(GET_COLOR(a, i), GET_COLOR(b, i), GET_COLOR(c, i), GET_COLOR(d, i), gx - gxi, gy - gyi)) << (i << 3); } diff --git a/libs/libgui/gui.c b/libs/libgui/gui.c index 56457e8..2dae302 100644 --- a/libs/libgui/gui.c +++ b/libs/libgui/gui.c @@ -486,9 +486,25 @@ vec2 gui_window_size(u32 win_id) } /** - * Window data setters + * Widget data getters/setters */ +vec2 gui_widget_size(u32 win_id, u32 widget_id) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); + return widget->bg.size; +} + +struct gfx_context *gui_widget_context(u32 win_id, u32 widget_id, enum gui_layer layer) +{ + struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); + if (!widget) + gui_error(ENOENT); + return layer == GUI_LAYER_BG ? &widget->bg : &widget->fg; +} + void gui_widget_margin(u32 win_id, u32 widget_id, vec2 margin) { struct gui_widget *widget = gui_widget_by_id(win_id, widget_id); diff --git a/libs/libgui/gui.h b/libs/libgui/gui.h index 00f49b8..0a4427b 100644 --- a/libs/libgui/gui.h +++ b/libs/libgui/gui.h @@ -81,6 +81,8 @@ void gui_popup(const char *text); */ vec2 gui_window_size(u32 win_id); +vec2 gui_widget_size(u32 win_id, u32 widget_id); +struct gfx_context *gui_widget_context(u32 win_id, u32 widget_id, enum gui_layer layer); void gui_widget_margin(u32 win_id, u32 widget_id, vec2 margin); void gui_widget_layout(u32 win_id, u32 widget_id, enum gui_layout layout); diff --git a/libs/libgui/widgets.c b/libs/libgui/widgets.c index 1881655..b04f937 100644 --- a/libs/libgui/widgets.c +++ b/libs/libgui/widgets.c @@ -1,8 +1,10 @@ // MIT License, Copyright (c) 2021 Marvin Borner +#include <assert.h> #include <def.h> #include <libgui/gui.h> #include <libgui/widgets.h> +#include <math.h> #define TEXT_PAD 2 @@ -26,3 +28,87 @@ void gui_button(u32 window, u32 widget, void (*click)(struct gui_event_mouse *ev { gui_button_custom(window, widget, FONT_16, COLOR_WHITE, COLOR_BLACK, click, text); } + +/** + * Plot + */ + +static void gui_plot_redraw(struct gui_plot *plot) +{ + if (plot->current <= 1) + return; + + assert(plot->current <= plot->count); + + gfx_fill(plot->ctx, COLOR_BG); + + f64 min = 0.0, max = 0.0; + for (u32 i = 0; i < plot->current; i++) { + f64 current = plot->data[i]; + if (current < min) + min = current; + if (current > max) + max = current; + } + + vec2 size = vec2_sub(plot->ctx->size, vec2(2, 2)); // Margin + u32 diff = ABS(max - min); + u32 step = size.x / (plot->current - 1); + f64 scale = (f64)size.y / (diff + 1); + + for (u32 i = 1; i < plot->current; i++) { + vec2 prev = vec2((i - 1) * step + 2, (max - plot->data[i - 1]) * scale); + vec2 current = vec2(i * step + 2, (max - plot->data[i]) * scale); + gfx_draw_line(plot->ctx, prev, current, 1, COLOR_RED); + } +} + +void gui_plot_iterate(struct gui_plot *plot) +{ + plot->current++; + assert(plot->current <= plot->count); + gui_plot_redraw(plot); +} + +void gui_plot_destroy(struct gui_plot *plot) +{ + free(plot->data); + free(plot); +} + +void gui_plot_draw(struct gui_plot *plot) +{ + plot->current = plot->count; + gui_plot_redraw(plot); +} + +struct gui_plot *gui_plot_data(u32 window, u32 widget, const f64 *data, u32 count) +{ + f64 *buffer = malloc(count * sizeof(*data)); + memcpy(buffer, data, count * sizeof(*data)); + + struct gui_plot *plot = malloc(sizeof(*plot)); + plot->data = buffer; + plot->current = 0; + plot->count = count; + plot->ctx = gui_widget_context(window, widget, GUI_LAYER_FG); + gui_fill(window, widget, GUI_LAYER_BG, COLOR_BG); + return plot; +} + +struct gui_plot *gui_plot_cubic(u32 window, u32 widget, f64 delta, s32 x_min, s32 x_max, f64 a, + f64 b, f64 c, f64 d) +{ + assert(x_min < x_max); + u32 diff = FABS(x_max - x_min); + u32 count = mceil(diff * (1 / delta)) + 1; + f64 *data = zalloc(count * sizeof(*data)); + + for (u32 i = 0; i < count; i++) + data[i] = mcubic(x_min + i * delta, a, b, c, d); + + struct gui_plot *plot = gui_plot_data(window, widget, data, count); + + free(data); + return plot; +} diff --git a/libs/libgui/widgets.h b/libs/libgui/widgets.h index 4028af6..64bf6a8 100644 --- a/libs/libgui/widgets.h +++ b/libs/libgui/widgets.h @@ -6,9 +6,31 @@ #include <libgui/gfx.h> #include <libgui/gui.h> +/** + * Button + */ + void gui_button_custom(u32 window, u32 widget, enum font_type font_type, u32 bg, u32 fg, void (*click)(struct gui_event_mouse *event), const char *text); void gui_button(u32 window, u32 widget, void (*click)(struct gui_event_mouse *event), const char *text); +/** + * Plot + */ + +struct gui_plot { + f64 *data; + u32 current; + u32 count; + struct gfx_context *ctx; +}; + +void gui_plot_iterate(struct gui_plot *plot); +void gui_plot_destroy(struct gui_plot *plot); +void gui_plot_draw(struct gui_plot *plot); +struct gui_plot *gui_plot_data(u32 window, u32 widget, const f64 *data, u32 count); +struct gui_plot *gui_plot_cubic(u32 window, u32 widget, f64 delta, s32 x_min, s32 x_max, f64 a, + f64 b, f64 c, f64 d); + #endif |