2 #if defined(WIN32) || defined(__WIN32__)
8 #include "ui_exhibit.h"
19 static void draw_frame(const Rect &rect);
20 static void draw_titlebar(const Rect &rect);
21 static void draw_tabs(const Rect &rect);
22 static void draw_text(const Rect &rect);
23 static void layout_text(const char *text);
25 static struct dtx_font *font;
27 static unsigned int fontsdr;
30 static int ui_width, ui_height;
32 static Mat4 tilt_matrix;
34 static RenderTarget *rtarg;
35 static const SceneNode *parent;
38 static int text_padding;
39 static float text_scale = 0.65f;
40 static float scale = 1.0f;
42 static int vis_tab, num_tabs;
43 static std::vector<std::string> tab_names;
45 static std::vector<const char*> text_lines;
46 static int max_line_size;
47 static AudioStream *voice;
49 enum {COL_BG, COL_FG, COL_FRM};
50 static float color[][3] = {
51 {0.014, 0.016, 0.04}, // COL_BG
52 {0.31, 0.58, 0.9}, // COL_FG
53 {0.19, 0.23, 0.46} // COL_FRM
59 if(!(font = dtx_open_font_glyphmap("data/ui_en.glyphmap"))) {
60 error_log("failed to open exhibit ui font\n");
63 font_size = dtx_get_glyphmap_ptsize(dtx_get_glyphmap(font, 0));
65 if(!(fontsdr = create_program_load("sdr/dfont.v.glsl", "sdr/dfont.p.glsl"))) {
66 error_log("failed to load font shader\n");
70 tilt_matrix = Mat4::identity;
78 aspect = size.x / size.y;
80 ui_width = ui_height * aspect;
82 rtarg = new RenderTarget;
83 if(!rtarg->create(ui_width, ui_height, GL_RGBA)) {
84 error_log("failed to create exui render target\n");
97 void exui_setnode(const SceneNode *node)
102 void exui_rotation(const Vec3 &euler)
104 tilt_matrix.rotation(euler);
107 void exui_scale(float s)
112 void exui_change_tab(int dir)
114 vis_tab = (vis_tab + dir) % num_tabs;
117 void exui_scroll(float delta)
121 bool exui_raycast(const Ray &ray)
126 void exui_update(float dt)
128 if(exsel_active.ex != ex) {
129 ex = exsel_active.ex;
135 if(voice) voice->stop();
138 int num_data = ex->data.size();
139 for(int i=0; i<num_data; i++) {
140 if(ex->data[i].type == EXDATA_INFO) {
141 layout_text(ex->data[i].text.c_str());
142 voice = ex->data[i].voice;
144 tab_names.push_back("info");
149 voice->play(AUDIO_PLAYMODE_ONCE);
157 static void draw_2d_ui()
159 dtx_use_font(font, font_size);
160 float rowspc = dtx_line_height() * text_scale;
162 glMatrixMode(GL_PROJECTION);
165 glTranslatef(-1, 1, 0);
166 glScalef(2.0 / ui_width, -2.0 / ui_height, 1);
168 glMatrixMode(GL_MODELVIEW);
174 glPushAttrib(GL_ENABLE_BIT);
175 glDisable(GL_TEXTURE_2D);
176 glDisable(GL_LIGHTING);
177 glDisable(GL_DEPTH_TEST);
178 glEnable(GL_SCISSOR_TEST);
180 Rect rect = {0, 0, (float)ui_width, (float)ui_height};
182 Rect tbar_rect = {rect.x, rect.y, rect.w, rowspc + text_padding}; // half the padding
183 draw_titlebar(tbar_rect);
184 Rect tabs_rect = {tbar_rect.x, tbar_rect.y + tbar_rect.h, tbar_rect.w, tbar_rect.h};
185 draw_tabs(tabs_rect);
188 switch(ex->data[vis_tab].type) {
191 Rect text_rect = {rect.x, tabs_rect.y + tabs_rect.h, rect.w, rect.h - tabs_rect.y - tabs_rect.h};
192 draw_text(text_rect);
203 glMatrixMode(GL_PROJECTION);
205 glMatrixMode(GL_MODELVIEW);
211 if(!exsel_active) return;
214 // render the 2D UI in a texture
215 push_render_target(rtarg);
216 glClear(GL_COLOR_BUFFER_BIT);
220 // place UI image into the scene
221 glMatrixMode(GL_MODELVIEW);
226 glGetFloatv(GL_MODELVIEW_MATRIX, mvmat[0]);
228 mvmat = parent->get_matrix() * mvmat;
230 mvmat.translate(pos.x, pos.y, pos.z);
232 mvmat[0][0] = mvmat[1][1] = mvmat[2][2] = 1.0f;
233 mvmat[0][1] = mvmat[0][2] = mvmat[1][0] = mvmat[2][0] = mvmat[1][2] = mvmat[2][1] = 0.0f;
234 glLoadMatrixf(mvmat[0]);
238 xform = parent->get_matrix();
240 xform = tilt_matrix * xform;
241 xform.pre_scale(scale, scale, scale);
242 glMultMatrixf(xform[0]);
244 glPushAttrib(GL_ENABLE_BIT);
246 glBlendColor(0, 0, 0, 0.35);
247 glBlendFunc(GL_SRC_ALPHA, GL_CONSTANT_ALPHA);
248 glEnable(GL_TEXTURE_2D);
249 glDisable(GL_CULL_FACE);
253 bind_texture(rtarg->texture());
255 glMatrixMode(GL_TEXTURE);
256 glLoadMatrixf(rtarg->texture_matrix()[0]);
260 glTexCoord2f(0, 0); glVertex2f(-size.x / 2, -size.y / 2);
261 glTexCoord2f(1, 0); glVertex2f(size.x / 2, -size.y / 2);
262 glTexCoord2f(1, 1); glVertex2f(size.x / 2, size.y / 2);
263 glTexCoord2f(0, 1); glVertex2f(-size.x / 2, size.y / 2);
271 glMatrixMode(GL_MODELVIEW);
275 static inline float *vrect(const Rect &rect, int i)
278 v[0] = ((i + 1) & 2) ? rect.x + rect.w : rect.x;
279 v[1] = (i & 2) ? rect.y : rect.y + rect.h;
283 static inline void draw_rect(const Rect &rect, int col)
286 glColor3fv(color[col]);
287 for(int i=0; i<4; i++)
288 glVertex2fv(vrect(rect, i));
292 static void clip_rect(const Rect &rect)
294 glScissor(rect.x, ui_height - rect.y - rect.h, rect.w, rect.h);
297 static void draw_frame(const Rect &rect)
301 draw_rect(rect, COL_BG);
303 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
304 draw_rect(rect, COL_FRM);
305 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
308 static void draw_titlebar(const Rect &rect)
312 draw_rect(rect, COL_FRM);
314 const char *title = ex->get_name();
316 glUseProgram(fontsdr);
319 glTranslatef(rect.x + text_padding, rect.y + rect.h - text_padding, 0);
320 glScalef(text_scale, -text_scale, text_scale);
322 glColor3fv(color[COL_BG]);
323 dtx_string(ex->get_name());
330 static void draw_tabs(const Rect &rect)
332 if(!num_tabs) return;
338 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
339 draw_rect(rect, COL_FRM);
340 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
343 int max_tab_size = ui_width / 2;
344 int tab_size = std::min(max_tab_size, ui_width / num_tabs);
346 for(int i=0; i<num_tabs; i++) {
347 Rect tr = {rect.x + i * tab_size, rect.y, (float)tab_size, rect.h};
352 draw_rect(tr, COL_FRM);
354 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
355 draw_rect(tr, COL_FRM);
356 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
360 glTranslatef(tr.x + text_padding, tr.y + tr.h - text_padding, 0);
361 glScalef(text_scale, -text_scale, text_scale);
363 glUseProgram(fontsdr);
364 glColor3fv(color[vis_tab == i ? COL_BG : COL_FRM]);
365 dtx_string(tab_names[i].c_str());
372 static void draw_text(const Rect &rect)
376 char *buf = (char*)alloca(max_line_size + 1);
378 float dy = dtx_line_height();
380 glUseProgram(fontsdr);
382 glMatrixMode(GL_MODELVIEW);
384 glTranslatef(rect.x + text_padding, rect.y + dy + text_padding, 0);
385 glScalef(text_scale, -text_scale, text_scale);
387 glColor3fv(color[COL_FG]);
389 int nlines = text_lines.size() - 1;
390 for(int i=0; i<nlines; i++) {
392 int sz = text_lines[i + 1] - text_lines[i];
393 assert(sz <= max_line_size);
394 memcpy(buf, text_lines[i], sz);
397 buf = (char*)text_lines[i];
400 dtx_position(0, -dy * i);
409 static void layout_text(const char *text)
415 dtx_use_font(font, font_size);
417 int left_margin = text_padding;
418 int right_margin = ui_width - text_padding;
420 text_lines.push_back(text);
421 const char *last_break = 0;
425 if(*text == '\n') { // paragraph break
426 text_lines.push_back(text);
427 text_lines.push_back(++text);
432 int code = dtx_utf8_char_code(text);
433 const char *next = dtx_utf8_next_char((char*)text);
436 dtx_substring_box(text_lines.back(), 0, text - text_lines.back(), &box);
437 float pos = left_margin + (box.width + box.x) * text_scale;
439 if(code < 256 && isspace(code)) {
443 if(pos > right_margin) {
444 if(text == text_lines.back()) {
445 // not even a single character fits on a line... abort
446 warning_log("text layout failed. glyph %d doesn't fit in line (%d)\n", code, right_margin - left_margin);
451 text_lines.push_back(last_break + 1);
454 // no good point to break, just break here
455 text_lines.push_back(text);
458 int d = text_lines.back() - (text_lines[text_lines.size() - 2]);
459 if(d > max_line_size) max_line_size = d;
463 text_lines.push_back(0);
466 debug_log("text layout:\n");
467 for(size_t i=0; i<text_lines.size() - 1; i++) {
468 const char *p = text_lines[i];
469 while(*p && p != text_lines[i + 1]) {