exhibit description text rendering
[laserbrain_demo] / src / ui_exhibit.cc
index 9b42c45..e583e5d 100644 (file)
@@ -1,3 +1,9 @@
+#include <assert.h>
+#if defined(WIN32) || defined(__WIN32__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
 #include <drawtext.h>
 #include "ui_exhibit.h"
 #include "ui.h"
@@ -29,11 +35,12 @@ static Exhibit *ex;
 static int vis_tab;
 static float scroll;
 static std::vector<const char*> text_lines;
+static int max_line_size;
 static AudioStream *voice;
 
 enum {COL_BG, COL_FG, COL_FRM};
 static float color[][3] = {
-       {0.09, 0.14, 0.2},      // COL_BG
+       {0.014, 0.016, 0.04},   // COL_BG
        {0.31, 0.58, 0.9},      // COL_FG
        {0.19, 0.23, 0.46}      // COL_FRM
 };
@@ -43,14 +50,14 @@ bool exui_init()
 {
        size.x = 15;
        size.y = 18;
-       text_padding = ui_width / 100;
+       text_padding = 6;
 
        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)) {
+       if(!rtarg->create(ui_width, ui_height, GL_SRGB_ALPHA)) {
                error_log("failed to create exui render target\n");
                return false;
        }
@@ -132,11 +139,11 @@ static void draw_2d_ui()
 
        Rect rect = {0, 0, (float)ui_width, (float)ui_height};
        draw_frame(rect);
-       Rect tbar_rect = {rect.x, rect.y, rect.w, rowspc};
+       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 + rowspc, tbar_rect.w, tbar_rect.h};
+       Rect tabs_rect = {tbar_rect.x, tbar_rect.y + tbar_rect.h, 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};
+       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);
 
        glPopAttrib();
@@ -231,7 +238,7 @@ static inline void draw_rect(const Rect &rect, int col)
 static void draw_frame(const Rect &rect)
 {
        draw_rect(rect, COL_BG);
-       glLineWidth(2.0);
+       glLineWidth(3.0);
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        draw_rect(rect, COL_FRM);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@@ -259,6 +266,33 @@ static void draw_tabs(const Rect &rect)
 
 static void draw_text(const Rect &rect)
 {
+       char *buf = (char*)alloca(max_line_size + 1);
+
+       float dy = dtx_line_height() * text_scale;
+
+       glMatrixMode(GL_MODELVIEW);
+       glPushMatrix();
+       glTranslatef(rect.x + text_padding, rect.y + dy + text_padding, 0);
+       glScalef(text_scale, -text_scale, text_scale);
+
+       glColor3fv(color[COL_FG]);
+
+       int nlines = text_lines.size() - 1;
+       for(int i=0; i<nlines; i++) {
+               if(i < nlines - 1) {
+                       int sz = text_lines[i + 1] - text_lines[i];
+                       assert(sz <= max_line_size);
+                       memcpy(buf, text_lines[i], sz);
+                       buf[sz] = 0;
+               } else {
+                       buf = (char*)text_lines[i];
+               }
+
+               dtx_string(buf);
+               glTranslatef(0, -dy, 0);
+       }
+
+       glPopMatrix();
 }
 
 static void layout_text(const char *text)
@@ -269,31 +303,36 @@ static void layout_text(const char *text)
 
        dtx_use_font(ui_font, ui_font_size);
 
-       float pos = text_padding;
+       int left_margin = text_padding;
+       int right_margin = ui_width - text_padding;
+
        text_lines.push_back(text);
        const char *last_break = 0;
+       max_line_size = 1;
 
        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;
+
+               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 >= ui_width - text_padding) {
+               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 (%d)\n", code, ui_width - 2 * 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;
                        }
@@ -304,7 +343,9 @@ 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;
        }