From: John Tsiombikas Date: Fri, 19 Jan 2018 10:27:45 +0000 (+0200) Subject: some code in the exhibit ui, and first stab at laying out the X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=commitdiff_plain;h=7ffa5c50d9254af9bd746fc5e6bc8e5db8eda675;ds=sidebyside some code in the exhibit ui, and first stab at laying out the description text. --- diff --git a/src/exman.cc b/src/exman.cc index 31ee1ae..e5cdd9f 100644 --- a/src/exman.cc +++ b/src/exman.cc @@ -8,6 +8,7 @@ #include "geomdraw.h" static Exhibit *create_exhibit(const char *type); +static void clean_desc_text(char *dest, const char *src); ExhibitSlot::ExhibitSlot(Exhibit *ex) @@ -244,7 +245,10 @@ bool ExhibitManager::load(MetaScene *mscn, const char *fname) ExData exd; if(desc) { - exd.text = std::string(desc); + char *fixed_desc = new char[strlen(desc) + 1]; + clean_desc_text(fixed_desc, desc); + exd.text = std::string(fixed_desc); + delete [] fixed_desc; } if(voice) { exd.voice = new OggVorbisStream; @@ -368,3 +372,27 @@ static Exhibit *create_exhibit(const char *type) error_log("unknown exhibit type: %s\n", type); return 0; } + +/* clean up description text to be more easily layed out later. + * more specifically: + * - remove redundant spaces + * - remove all newlines except as paragraph separators + * - remove all other whitespace chars + * destination buffer must be as large as the source buffer + */ +static void clean_desc_text(char *dest, const char *src) +{ + while(*src) { + if(isspace(*src)) { + if(*src == '\n' && *(src + 1) == '\n') { + *dest++ = '\n'; + } else { + *dest++ = ' '; + } + while(*src && isspace(*src)) ++src; + } else { + *dest++ = *src++; + } + } + *dest = 0; +} diff --git a/src/ui.cc b/src/ui.cc index a0babe4..78c7ece 100644 --- a/src/ui.cc +++ b/src/ui.cc @@ -29,7 +29,8 @@ static Text *txlist; static long timeout = 2000; static long trans_time = 250; -static dtx_font *font; +dtx_font *ui_font; +int ui_font_size = FONTSZ; void set_message_timeout(long tm) { @@ -108,7 +109,7 @@ void print_textv(const Vec2 &pos, const Vec3 &color, const char *fmt, va_list ap void draw_ui() { - if(!font) return; + if(!ui_font) return; while(msglist && msglist->show_until <= time_msec) { Message *msg = msglist; @@ -117,7 +118,7 @@ void draw_ui() delete msg; } - dtx_use_font(font, FONTSZ); + dtx_use_font(ui_font, ui_font_size); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -176,10 +177,10 @@ static bool init() done_init = true; - if(!(font = dtx_open_font("data/ui.font", 0))) { + if(!(ui_font = dtx_open_font("data/ui.font", 0))) { fprintf(stderr, "failed to open font: data/ui.font\n"); return false; } - dtx_prepare_range(font, FONTSZ, 32, 127); + dtx_prepare_range(ui_font, ui_font_size, 32, 127); return true; } diff --git a/src/ui.h b/src/ui.h index 088fb82..ed229cb 100644 --- a/src/ui.h +++ b/src/ui.h @@ -4,6 +4,10 @@ #include #include +struct dtx_font; +extern dtx_font *ui_font; +extern int ui_font_size; + void set_message_timeout(long timeout); void show_message(const char *fmt, ...); void show_message(long timeout, const Vec3 &color, const char *fmt, ...); diff --git a/src/ui_exhibit.cc b/src/ui_exhibit.cc index 409bd94..355d078 100644 --- a/src/ui_exhibit.cc +++ b/src/ui_exhibit.cc @@ -1,8 +1,28 @@ #include "ui_exhibit.h" +#include "ui.h" #include "app.h" +#include + +static void draw_titlebar(); +static void draw_tabs(); +static void layout_text(const char *text); + +static Vec3 pos; +static Vec2 size; +static float text_padding; +static Exhibit *ex; +static int vis_tab; +static float scroll; +static std::vector text_lines; +static AudioStream *voice; + bool exui_init() { + size.x = 150; + size.y = 180; + text_padding = size.x * 0.01; + return true; } @@ -10,12 +30,103 @@ void exui_shutdown() { } +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; + } + } } void exui_draw() { if(!exsel_active) return; + draw_titlebar(); + draw_tabs(); +} + +static void draw_titlebar() +{ +} + +static void draw_tabs() +{ +} + +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); + + if(pos >= size.x - 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 (%g)\n", code, size.x - 2.0 * 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; + } } diff --git a/src/ui_exhibit.h b/src/ui_exhibit.h index 6fdb6ca..bf0d222 100644 --- a/src/ui_exhibit.h +++ b/src/ui_exhibit.h @@ -1,9 +1,16 @@ #ifndef UI_EXHIBIT_H_ #define UI_EXHIBIT_H_ +#include + bool exui_init(); void exui_shutdown(); +void exui_change_tab(int dir); +void exui_scroll(float delta); + +bool exui_raytest(const Ray &ray); + void exui_update(float dt); void exui_draw();