summaryrefslogtreecommitdiff
path: root/src/ui.c
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2016-03-30 08:25:04 +0200
committerPaweł Redman <pawel.redman@gmail.com>2016-03-30 08:25:04 +0200
commit4bf61f911194bb0b40d302df8d7dfff2fda19892 (patch)
tree1d8619d4cff047bf2a72aa6a1bcfe4e683f43226 /src/ui.c
Initial commit.
Diffstat (limited to 'src/ui.c')
-rw-r--r--src/ui.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..0f4477b
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,461 @@
+#include "common.h"
+
+struct {
+ float font_size;
+ float color_text[4];
+ float color_text_light[4];
+ float color_background[4];
+ float color_main[4];
+ float color_info[4];
+ float color_selection[4];
+} theme =
+{
+ .font_size = 20,
+ .color_text = {0, 0, 0, 1},
+ .color_text_light = {0.5, 0.5, 0.5, 1},
+ .color_background = {0.1, 0.1, 0.1, 1},
+ .color_main = {0.75, 0.75, 0.75, 1},
+ .color_info = {1, 1, 1, 1},
+ .color_selection = {1, 0, 0, 1}
+};
+
+#define MAX_INFO 1024
+
+typedef struct {
+ bool dragging;
+ r_xsection_type xsection_type;
+ float xsection_frac;
+ bool selected;
+ vec3_t selection;
+
+ bool info_valid;
+ int64_t info_time;
+ char info[MAX_INFO];
+
+ float margin_bottom, margin_top;
+
+ mst2_t origin, scale; // in virtual space
+ mst2_t tf_v2s, tf_x2s;
+ r_xsection xsection;
+} ui_simview;
+
+typedef enum {
+ UI_WINDOW_SIMVIEW
+} ui_window_type;
+
+typedef struct ui_window_s ui_window;
+struct ui_window_s {
+ int w, h;
+ r_window *rw;
+ ui_window *prev, *next;
+
+ bool initialized;
+ int64_t last_frame;
+ size_t frame_count;
+ vec2_t mouse;
+
+ ui_window_type type;
+ ui_simview simview;
+};
+
+static struct {
+ ui_window *windows;
+
+ bool use_window_open_timer;
+ int64_t window_open_timer;
+} uis;
+
+
+int ui_init(void)
+{
+ return 0;
+}
+
+static void ui_window_destroy(ui_window *uiw)
+{
+ con_printf("ui_window_destroy: destroying uiw=%p\n", uiw);
+
+ if (uiw->prev)
+ uiw->prev->next = uiw->next;
+ if (uiw->next)
+ uiw->next->prev = uiw->prev;
+
+ if (uis.windows == uiw)
+ uis.windows = uiw->next;
+
+ r_xsection_destroy(&uiw->simview.xsection);
+
+ free(uiw);
+}
+
+void ui_quit(void)
+{
+ while (uis.windows)
+ ui_window_destroy(uis.windows);
+}
+
+void ui_renderer_window_register(r_window *rw)
+{
+ ui_window *uiw;
+
+ uiw = calloc(1, sizeof(ui_window));
+ if (!uiw)
+ abort();
+
+ uiw->prev = NULL;
+ if (uis.windows)
+ uis.windows->prev = uiw;
+ uiw->next = uis.windows;
+ uis.windows = uiw;
+
+ uiw->rw = rw;
+
+ con_printf("ui_renderer_window_register: registered window #%i"
+ ", uiw = %p\n", SDL_GetWindowID(rw->window), uiw);
+
+ r_xsection_create(&uiw->simview.xsection);
+}
+
+static ui_window *ui_find_window(int id)
+{
+ ui_window *uiw;
+
+ for (uiw = uis.windows; uiw; uiw = uiw->next)
+ if (SDL_GetWindowID(uiw->rw->window) == id)
+ return uiw;
+
+ return NULL;
+}
+
+void ui_infof(ui_window *uiw, const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ vsnprintf(uiw->simview.info, MAX_INFO, fmt, vl);
+ va_end(vl);
+
+ uiw->simview.info_valid = true;
+ uiw->simview.info_time = get_time();
+}
+
+static void ui_simview_set_selection(ui_simview *sv, vec2_t sel_2d)
+{
+ if (sel_2d[0] < 0.0f || sel_2d[0] > 1.0f ||
+ sel_2d[1] < 0.0f || sel_2d[1] > 1.0f) {
+ sv->selected = false;
+ return;
+ }
+
+ switch (sv->xsection_type) {
+ case XSECTION_XY:
+ v3_set(sv->selection, sel_2d[0], sel_2d[1], sv->xsection_frac);
+ break;
+
+ case XSECTION_XZ:
+ v3_set(sv->selection, sel_2d[0], sv->xsection_frac, sel_2d[1]);
+ break;
+
+ case XSECTION_YZ:
+ v3_set(sv->selection, sv->xsection_frac, sel_2d[0], sel_2d[1]);
+ break;
+ }
+
+ sv->selected = true;
+}
+
+void ui_event_window(SDL_Event *event, ui_window *uiw)
+{
+ ui_simview *sv = &uiw->simview;
+
+ if (!uiw->initialized)
+ return;
+
+ switch (event->type) {
+ case SDL_MOUSEWHEEL:
+ {
+ vec2_t mouse_v;
+ float delta;
+
+ v2_div_mst2(mouse_v, uiw->mouse, sv->tf_v2s);
+
+ delta = pow(1.1, event->wheel.y);
+
+ v2_mul(sv->scale, sv->scale, delta);
+
+ v2_sub(sv->origin, sv->origin, mouse_v);
+ v2_mul(sv->origin, sv->origin, delta);
+ v2_add(sv->origin, sv->origin, mouse_v);
+ }
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ if (event->button.button == SDL_BUTTON_LEFT &&
+ event->button.y > sv->margin_top &&
+ event->button.y < uiw->h - sv->margin_bottom)
+ sv->dragging = true;
+
+ if (event->button.button == SDL_BUTTON_RIGHT) {
+ vec2_t sel_2d;
+
+ v2_div_mst2(sel_2d, uiw->mouse, sv->tf_x2s);
+ ui_simview_set_selection(sv, sel_2d);
+ }
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ if (event->button.button == SDL_BUTTON_LEFT)
+ sv->dragging = false;
+ break;
+
+ case SDL_MOUSEMOTION:
+ uiw->mouse[0] = event->motion.x;
+ uiw->mouse[1] = event->motion.y;
+
+ if (sv->dragging) {
+ vec2_t delta_v;
+
+ v2_set(delta_v, event->motion.xrel, event->motion.yrel);
+ v2_div_mst2_nt(delta_v, delta_v, sv->tf_v2s);
+ v2_add(sv->origin, sv->origin, delta_v);
+ }
+ break;
+
+ case SDL_KEYDOWN:
+ switch (event->key.keysym.sym) {
+ case SDLK_1:
+ sv->xsection_type = XSECTION_XY;
+ break;
+
+ case SDLK_2:
+ sv->xsection_type = XSECTION_XZ;
+ break;
+
+ case SDLK_3:
+ sv->xsection_type = XSECTION_YZ;
+ break;
+
+ case SDLK_w:
+ sv->xsection_frac += 0.1f;
+ if (sv->xsection_frac > 1.0f)
+ sv->xsection_frac = 1.0f;
+ break;
+
+ case SDLK_s:
+ sv->xsection_frac -= 0.1f;
+ if (sv->xsection_frac < 0.0f)
+ sv->xsection_frac = 0.0f;
+ break;
+ }
+ }
+}
+
+void ui_event(SDL_Event *event)
+{
+ if (event->type == SDL_KEYDOWN &&
+ event->key.keysym.sym == SDLK_RETURN) {
+
+ if (!uis.use_window_open_timer ||
+ uis.window_open_timer + 500000000 <= get_time()) {
+ r_window *rw;
+
+ uis.use_window_open_timer = true;
+ uis.window_open_timer = get_time();
+
+ rw = r_window_create();
+ if (rw)
+ ui_renderer_window_register(rw);
+ }
+ } else if (event->type == SDL_WINDOWEVENT &&
+ event->window.event == SDL_WINDOWEVENT_CLOSE) {
+ ui_window *uiw;
+
+ uiw = ui_find_window(event->window.windowID);
+ if (!uiw)
+ con_printf("WARNING: ui_event: SDL_WINDOWEVENT_"
+ "CLOSE for a window not registered"
+ " by ui\n");
+ else {
+ r_window_destroy(uiw->rw);
+ ui_window_destroy(uiw);
+ }
+ } else {
+ ui_window *uiw;
+
+ // SDL sends some SDL_WINDOWEVENTs after a window's been closed
+
+ uiw = ui_find_window(event->window.windowID);
+ if (uiw)
+ ui_event_window(event, uiw);
+ }
+}
+
+void ui_animate_exp(float *val, float targ, float lambda, float dt)
+{
+ *val = targ + (*val - targ) * exp(-lambda * dt);
+}
+
+void ui_draw_window_simview(ui_window *uiw, phy_sim *sim, int64_t time,
+ float dt)
+{
+ ui_simview *sv = &uiw->simview;
+ float aspect_ratio;
+ vec2_t origin_s, scale_s;
+ phy_field_em *field_em = sim->fields + 2;
+
+ const char *xsection_type_strings[] = {
+ "Przekrój XY przez Z",
+ "Przekrój XZ przez Y",
+ "Przekrój YZ przez X"
+ };
+
+ // xsection
+
+ SDL_mutexP(sim->rotate_lock);
+ r_xsection_update(uiw->rw, &sv->xsection, &sim->field_info,
+ field_em->E, sv->xsection_type, sv->xsection_frac);
+ SDL_mutexV(sim->rotate_lock);
+
+ aspect_ratio = sv->xsection.aspect_ratio;
+
+ if (uiw->w > uiw->h * aspect_ratio)
+ mst2_set(sv->tf_v2s, (uiw->w - uiw->h * aspect_ratio) / 2.0f, 0,
+ uiw->h * aspect_ratio, uiw->h);
+ else
+ mst2_set(sv->tf_v2s, 0, (uiw->h - uiw->w / aspect_ratio) / 2.0f,
+ uiw->w, uiw->w / aspect_ratio);
+
+ v2_mul_mst2(origin_s, sv->origin, sv->tf_v2s);
+ v2_mul_mst2_nt(scale_s, sv->scale, sv->tf_v2s);
+
+ mst2_set(sv->tf_x2s, origin_s[0], origin_s[1],
+ scale_s[0], scale_s[1]);
+
+ r_xsection_draw(uiw->rw, &sv->xsection, origin_s[0], origin_s[1],
+ scale_s[0], scale_s[1]);
+
+ // xsection - selection
+
+ if (sv->selected)
+ {
+ vec2_t selection_s;
+
+ switch (sv->xsection_type) {
+ case XSECTION_XY:
+ v2_set(selection_s, sv->selection[0], sv->selection[1]);
+ break;
+
+ case XSECTION_XZ:
+ v2_set(selection_s, sv->selection[0], sv->selection[2]);
+ break;
+
+ case XSECTION_YZ:
+ v2_set(selection_s, sv->selection[1], sv->selection[2]);
+ break;
+ }
+
+ v2_mul_mst2(selection_s, selection_s, sv->tf_x2s);
+
+ r_draw_line(uiw->rw, selection_s[0], 0, selection_s[0], uiw->h,
+ theme.color_selection);
+ r_draw_line(uiw->rw, 0, selection_s[1], uiw->w, selection_s[1],
+ theme.color_selection);
+
+
+ r_draw_rect(uiw->rw, 0, uiw->h - theme.font_size,
+ uiw->w, theme.font_size, theme.color_main);
+
+ r_draw_text(uiw->rw, 0, uiw->h - theme.font_size,
+ theme.font_size,
+ va("x = [%f %f %f]", sv->selection[0],
+ sv->selection[1], sv->selection[2]),
+ theme.color_text, 0);
+
+ sv->margin_bottom = 1 * theme.font_size;
+ }
+ else
+ sv->margin_bottom = 0;
+
+ // status
+
+ r_draw_rect(uiw->rw, 0, 0, uiw->w, theme.font_size, theme.color_main);
+
+ r_draw_text(uiw->rw, uiw->w, 0, theme.font_size,
+ va("%.0fkl./s %04zu", 1.0f / dt, uiw->frame_count % 10000),
+ theme.color_text_light, TEXT_RIGHTX);
+
+ r_draw_text(uiw->rw, 0, 0, theme.font_size,
+ va("%s = %f", xsection_type_strings[sv->xsection_type],
+ sv->xsection_frac),
+ theme.color_text, 0);
+
+ // info text
+
+ if (sv->info_valid && sv->info_time + 2000000000ll > time)
+ {
+ vec4_t color;
+
+ if (sv->info_time + 1000000000ll >= time)
+ color[3] = 1.0f;
+ else
+ color[3] = 1.0f - (time - sv->info_time - 1000000000ll)
+ / 1.0e9f;
+
+ v3_copy(color, theme.color_info);
+
+ r_draw_rect(uiw->rw, 0, theme.font_size, uiw->w,
+ theme.font_size, color);
+
+ v3_copy(color, theme.color_text);
+
+ r_draw_text(uiw->rw, uiw->w / 2.0f, theme.font_size,
+ theme.font_size, sv->info, color, TEXT_CENTERX);
+ }
+}
+
+void ui_draw_window(ui_window *uiw, phy_sim *sim)
+{
+ ui_simview *sv = &uiw->simview;
+ int64_t time;
+ float dt;
+
+ time = get_time();
+
+ if (!uiw->initialized) {
+ uiw->initialized = true;
+ uiw->last_frame = time;
+
+ v2_set(sv->origin, 0, 0);
+ v2_set(sv->scale, 1, 1);
+ sv->xsection_type = XSECTION_XY;
+ sv->xsection_frac = 0.5f;
+
+ sv->selected = false;
+ sv->margin_top = theme.font_size;
+ sv->margin_bottom = 0;
+
+ sv->info_valid = false;
+
+ r_clear(uiw->rw, r_color_black);
+ return;
+ }
+
+ dt = (get_time() - uiw->last_frame) * 1.0e-9;
+
+ r_clear(uiw->rw, r_color_black);
+ ui_draw_window_simview(uiw, sim, time, dt);
+ r_flip(uiw->rw);
+
+ uiw->last_frame = time;
+}
+
+void ui_draw(phy_sim *sim)
+{
+ ui_window *uiw;
+
+ for (uiw = uis.windows; uiw; uiw = uiw->next) {
+ SDL_GetWindowSize(uiw->rw->window, &uiw->w, &uiw->h);
+ ui_draw_window(uiw, sim);
+ uiw->frame_count++;
+ }
+}