X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fui_exhibit.cc;h=438a52e0dacc6d2bf8f113a1cf143432ca7f9be9;hp=355d0783acabf28ed45061782fd0024154a9d7be;hb=2fd19c29d765f973a757807d4e051e09495b47b4;hpb=7ffa5c50d9254af9bd746fc5e6bc8e5db8eda675 diff --git a/src/ui_exhibit.cc b/src/ui_exhibit.cc index 355d078..438a52e 100644 --- a/src/ui_exhibit.cc +++ b/src/ui_exhibit.cc @@ -1,37 +1,117 @@ +#include +#if defined(WIN32) || defined(__WIN32__) +#include +#else +#include +#endif +#include #include "ui_exhibit.h" #include "ui.h" #include "app.h" -#include +#include "snode.h" +#include "sdr.h" +#include "rtarg.h" -static void draw_titlebar(); -static void draw_tabs(); +struct Rect { + float x, y, w, h; +}; + +static void draw_frame(const Rect &rect); +static void draw_titlebar(const Rect &rect); +static void draw_tabs(const Rect &rect); +static void draw_text(const Rect &rect); static void layout_text(const char *text); +static struct dtx_font *font; +static int font_size; +static unsigned int fontsdr; + +static float aspect; +static int ui_width, ui_height; + +static Mat4 tilt_matrix; + +static RenderTarget *rtarg; +static const SceneNode *parent; static Vec3 pos; static Vec2 size; -static float text_padding; +static int text_padding; +static float text_scale = 0.65f; +static float scale = 1.0f; static Exhibit *ex; -static int vis_tab; +static int vis_tab, num_tabs; +static std::vector tab_names; static float scroll; static std::vector text_lines; +static int max_line_size; static AudioStream *voice; +enum {COL_BG, COL_FG, COL_FRM}; +static float color[][3] = { + {0.014, 0.016, 0.04}, // COL_BG + {0.31, 0.58, 0.9}, // COL_FG + {0.19, 0.23, 0.46} // COL_FRM +}; + bool exui_init() { - size.x = 150; - size.y = 180; - text_padding = size.x * 0.01; + if(!(font = dtx_open_font_glyphmap("data/ui_en.glyphmap"))) { + error_log("failed to open exhibit ui font\n"); + return false; + } + font_size = dtx_get_glyphmap_ptsize(dtx_get_glyphmap(font, 0)); + + if(!(fontsdr = create_program_load("sdr/dfont.v.glsl", "sdr/dfont.p.glsl"))) { + error_log("failed to load font shader\n"); + return false; + } + + tilt_matrix = Mat4::identity; + + size.x = 15; + size.y = 18; + text_padding = 6; + + scale = 1.0f; + + aspect = size.x / size.y; + ui_height = 512; + ui_width = ui_height * aspect; + + rtarg = new RenderTarget; + if(!rtarg->create(ui_width, ui_height, GL_RGBA)) { + error_log("failed to create exui render target\n"); + return false; + } return true; } void exui_shutdown() { + dtx_close_font(font); + delete rtarg; +} + +void exui_setnode(const SceneNode *node) +{ + parent = node; +} + +void exui_rotation(const Vec3 &euler) +{ + tilt_matrix.rotation(euler); +} + +void exui_scale(float s) +{ + scale = s; } void exui_change_tab(int dir) { + vis_tab = (vis_tab + dir) % num_tabs; } void exui_scroll(float delta) @@ -49,6 +129,8 @@ void exui_update(float dt) ex = exsel_active.ex; scroll = 0.0f; vis_tab = 0; + num_tabs = 0; + tab_names.clear(); text_lines.clear(); if(voice) voice->stop(); @@ -58,6 +140,8 @@ void exui_update(float dt) if(ex->data[i].type == EXDATA_INFO) { layout_text(ex->data[i].text.c_str()); voice = ex->data[i].voice; + ++num_tabs; + tab_names.push_back("info"); } } @@ -70,51 +154,296 @@ void exui_update(float dt) } } +static void draw_2d_ui() +{ + dtx_use_font(font, font_size); + float rowspc = dtx_line_height() * text_scale; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(-1, 1, 0); + glScalef(2.0 / ui_width, -2.0 / ui_height, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glUseProgram(0); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glEnable(GL_SCISSOR_TEST); + + Rect rect = {0, 0, (float)ui_width, (float)ui_height}; + draw_frame(rect); + Rect tbar_rect = {rect.x, rect.y, rect.w, rowspc + text_padding}; // half the padding + draw_titlebar(tbar_rect); + Rect tabs_rect = {tbar_rect.x, tbar_rect.y + tbar_rect.h, tbar_rect.w, tbar_rect.h}; + draw_tabs(tabs_rect); + + if(num_tabs) { + switch(ex->data[vis_tab].type) { + case EXDATA_INFO: + { + Rect text_rect = {rect.x, tabs_rect.y + tabs_rect.h, rect.w, rect.h - tabs_rect.y - tabs_rect.h}; + draw_text(text_rect); + } + break; + + default: + break; + } + } + + glPopAttrib(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + void exui_draw() { if(!exsel_active) return; + if(!font) return; + + // render the 2D UI in a texture + push_render_target(rtarg); + glClearColor(0, 1, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + draw_2d_ui(); + pop_render_target(); + + // place UI image into the scene + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + /* + Mat4 mvmat; + glGetFloatv(GL_MODELVIEW_MATRIX, mvmat[0]); + if(parent) { + mvmat = parent->get_matrix() * mvmat; + } + mvmat.translate(pos.x, pos.y, pos.z); + + mvmat[0][0] = mvmat[1][1] = mvmat[2][2] = 1.0f; + mvmat[0][1] = mvmat[0][2] = mvmat[1][0] = mvmat[2][0] = mvmat[1][2] = mvmat[2][1] = 0.0f; + glLoadMatrixf(mvmat[0]); + */ + Mat4 xform; + if(parent) { + xform = parent->get_matrix(); + } + xform = tilt_matrix * xform; + xform.pre_scale(scale, scale, scale); + glMultMatrixf(xform[0]); + + glPushAttrib(GL_ENABLE_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glEnable(GL_TEXTURE_2D); + glDisable(GL_CULL_FACE); + glDepthMask(0); + + glUseProgram(0); + bind_texture(rtarg->texture()); + + glMatrixMode(GL_TEXTURE); + glLoadMatrixf(rtarg->texture_matrix()[0]); + + glBegin(GL_QUADS); + glColor3f(1, 1, 1); + glTexCoord2f(0, 0); glVertex2f(-size.x / 2, -size.y / 2); + glTexCoord2f(1, 0); glVertex2f(size.x / 2, -size.y / 2); + glTexCoord2f(1, 1); glVertex2f(size.x / 2, size.y / 2); + glTexCoord2f(0, 1); glVertex2f(-size.x / 2, size.y / 2); + glEnd(); + + glLoadIdentity(); + + glDepthMask(1); + glPopAttrib(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} - draw_titlebar(); - draw_tabs(); +static inline float *vrect(const Rect &rect, int i) +{ + static float v[2]; + v[0] = ((i + 1) & 2) ? rect.x + rect.w : rect.x; + v[1] = (i & 2) ? rect.y : rect.y + rect.h; + return v; } -static void draw_titlebar() +static inline void draw_rect(const Rect &rect, int col) { + glBegin(GL_QUADS); + glColor3fv(color[col]); + for(int i=0; i<4; i++) + glVertex2fv(vrect(rect, i)); + glEnd(); } -static void draw_tabs() +static void clip_rect(const Rect &rect) { + glScissor(rect.x, ui_height - rect.y - rect.h, rect.w, rect.h); +} + +static void draw_frame(const Rect &rect) +{ + clip_rect(rect); + + draw_rect(rect, COL_BG); + glLineWidth(3.0); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + draw_rect(rect, COL_FRM); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +} + +static void draw_titlebar(const Rect &rect) +{ + clip_rect(rect); + + draw_rect(rect, COL_FRM); + + const char *title = ex->get_name(); + if(title) { + glUseProgram(fontsdr); + + glPushMatrix(); + glTranslatef(rect.x + text_padding, rect.y + rect.h - text_padding, 0); + glScalef(text_scale, -text_scale, text_scale); + + glColor3fv(color[COL_BG]); + dtx_string(ex->get_name()); + glPopMatrix(); + + glUseProgram(0); + } +} + +static void draw_tabs(const Rect &rect) +{ + if(!num_tabs) return; + + clip_rect(rect); + + glLineWidth(1); + if(num_tabs == 1) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + draw_rect(rect, COL_FRM); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + int max_tab_size = ui_width / 2; + int tab_size = std::min(max_tab_size, ui_width / num_tabs); + + for(int i=0; i= size.x - text_padding) { + struct dtx_box box; + dtx_substring_box(text_lines.back(), 0, text - text_lines.back(), &box); + float pos = left_margin + (box.width + box.x) * text_scale; + + if(code < 256 && isspace(code)) { + last_break = text; + } + + if(pos > right_margin) { if(text == text_lines.back()) { // not even a single character fits on a line... abort - warning_log("text layout failed. glyph %d doesn't fit in line (%g)\n", code, size.x - 2.0 * text_padding); + warning_log("text layout failed. glyph %d doesn't fit in line (%d)\n", code, right_margin - left_margin); text_lines.clear(); return; } @@ -125,8 +454,24 @@ static void layout_text(const char *text) // no good point to break, just break here text_lines.push_back(text); } - pos = text_padding; + + int d = text_lines.back() - (text_lines[text_lines.size() - 2]); + if(d > max_line_size) max_line_size = d; } text = next; } + text_lines.push_back(0); + + /* + debug_log("text layout:\n"); + for(size_t i=0; i