From 4bf61f911194bb0b40d302df8d7dfff2fda19892 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Wed, 30 Mar 2016 08:25:04 +0200 Subject: Initial commit. --- src/ui.c | 461 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 src/ui.c (limited to 'src/ui.c') 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++; + } +} -- cgit