aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-07-01 14:43:53 +0200
committerMarvin Borner2021-07-01 14:43:53 +0200
commit340e841772eb13d9087235b8707c1cfeff8710cb (patch)
tree5f4c3328105a3ab194deef9f05fd05ff3c26b7dc
parent73a7db5b48eab615a0f6258e0196a1260a88cbbb (diff)
Math improvements and basic plotting
-rw-r--r--apps/test/main.c26
-rw-r--r--libs/libc/inc/math.h36
-rw-r--r--libs/libc/inc/vec.h38
-rw-r--r--libs/libc/math.c154
-rw-r--r--libs/libc/print.c19
-rw-r--r--libs/libgui/gfx.c6
-rw-r--r--libs/libgui/gui.c18
-rw-r--r--libs/libgui/gui.h2
-rw-r--r--libs/libgui/widgets.c86
-rw-r--r--libs/libgui/widgets.h22
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