X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fui_exhibit.cc;h=dd09678f64c5c8a8fd85347f25e05e43bc471dcd;hp=409bd94946e4ea5d53a7407ac5662f159508d315;hb=0d4fe99398b649a5471417f8497a828b5f128da1;hpb=91c5d07b779f24afec373047afe401b8811811c7 diff --git a/src/ui_exhibit.cc b/src/ui_exhibit.cc index 409bd94..dd09678 100644 --- a/src/ui_exhibit.cc +++ b/src/ui_exhibit.cc @@ -1,21 +1,309 @@ +#include #include "ui_exhibit.h" +#include "ui.h" #include "app.h" +#include "snode.h" +#include "shader.h" +#include "rtarg.h" + +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 float aspect; +static int ui_width, ui_height; + +static RenderTarget *rtarg; +static const SceneNode *parent; +static Vec3 pos; +static Vec2 size; +static int text_padding; +static float text_scale = 1.0f;//0.05f; +static Exhibit *ex; +static int vis_tab; +static float scroll; +static std::vector text_lines; +static AudioStream *voice; + +enum {COL_BG, COL_FG, COL_FRM}; +static float color[][3] = { + {0.09, 0.14, 0.2}, // COL_BG + {0.31, 0.58, 0.9}, // COL_FG + {0.19, 0.23, 0.46} // COL_FRM +}; + bool exui_init() { + size.x = 15; + size.y = 18; + text_padding = ui_width / 100; + + aspect = size.x / size.y; + ui_height = 512; + ui_width = ui_height * aspect; + + rtarg = new RenderTarget; + if(!rtarg->create(ui_width, ui_height, GL_RGB)) { + error_log("failed to create exui render target\n"); + return false; + } + return true; } void exui_shutdown() { + delete rtarg; +} + +void exui_setnode(const SceneNode *node) +{ + parent = node; +} + +void exui_change_tab(int dir) +{ +} + +void exui_scroll(float delta) +{ +} + +bool exui_raycast(const Ray &ray) +{ + return false; } void exui_update(float dt) { + if(exsel_active.ex != ex) { + ex = exsel_active.ex; + scroll = 0.0f; + vis_tab = 0; + text_lines.clear(); + if(voice) voice->stop(); + + if(ex) { + int num_data = ex->data.size(); + for(int i=0; idata[i].type == EXDATA_INFO) { + layout_text(ex->data[i].text.c_str()); + voice = ex->data[i].voice; + } + } + + if(voice) { + voice->play(AUDIO_PLAYMODE_ONCE); + } + } else { + voice = 0; + } + } +} + +static void draw_2d_ui() +{ + dtx_use_font(ui_font, ui_font_size); + float rowspc = dtx_line_height() * text_scale; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, ui_width, 0, ui_height, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + bind_shader(0); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + Rect rect = {0, 0, (float)ui_width, (float)ui_height}; + draw_frame(rect); + Rect tbar_rect = {rect.x, rect.y, rect.w, rowspc}; + draw_titlebar(tbar_rect); + Rect tabs_rect = {tbar_rect.x, tbar_rect.y + rowspc, tbar_rect.w, tbar_rect.h}; + draw_tabs(tabs_rect); + Rect text_rect = {rect.x, tabs_rect.y + rowspc, rect.w, rect.h - tabs_rect.y - rowspc}; + draw_text(text_rect); + + glPopAttrib(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); } void exui_draw() { if(!exsel_active) return; + if(!ui_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(); + if(parent) { + glMultMatrixf(parent->get_matrix()[0]); + } + glTranslatef(pos.x, pos.y, pos.z); + + glPushAttrib(GL_ENABLE_BIT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glEnable(GL_TEXTURE_2D); + glDepthMask(0); + + bind_shader(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(); +} + +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 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_frame(const Rect &rect) +{ + draw_rect(rect, COL_BG); + glLineWidth(2.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) +{ + draw_rect(rect, COL_FRM); + + const char *title = ex->get_name(); + if(title) { + 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(); + } +} + +static void draw_tabs(const Rect &rect) +{ +} + +static void draw_text(const Rect &rect) +{ +} + +static void layout_text(const char *text) +{ + text_lines.clear(); + if(!text) return; + if(!ui_font) return; + + dtx_use_font(ui_font, ui_font_size); + + float pos = text_padding; + text_lines.push_back(text); + const char *last_break = 0; + + while(*text) { + if(*text == '\n') { // paragraph break + text_lines.push_back(text); + text_lines.push_back(++text); + pos = text_padding; + last_break = 0; + continue; + } + + int code = dtx_utf8_char_code(text); + const char *next = dtx_utf8_next_char((char*)text); + pos += dtx_glyph_width(code) * text_scale; + + if(code < 256 && isspace(code)) { + last_break = text; + } + + if(pos >= ui_width - text_padding) { + 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 (%d)\n", code, ui_width - 2 * text_padding); + text_lines.clear(); + return; + } + if(last_break) { + text_lines.push_back(last_break + 1); + last_break = 0; + } else { + // no good point to break, just break here + text_lines.push_back(text); + } + pos = text_padding; + } + text = next; + } + text_lines.push_back(0); + /* + debug_log("text layout:\n"); + for(size_t i=0; i