# HG changeset patch # User John Tsiombikas # Date 1411746015 -10800 # Node ID 053a52f0cb646557bbe3c880254d2ea2617f6dcb # Parent 690ef7fa791fe6d65a5c963bdf78770ce5e04729 console diff -r 690ef7fa791f -r 053a52f0cb64 src/console.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/console.cc Fri Sep 26 18:40:15 2014 +0300 @@ -0,0 +1,434 @@ +#include +#include +#include +#include +#include +#include +#include "opengl.h" +#include "console.h" + +Console::Console() + : prompt("> ") +{ + visible = false; + nlines = 16; + ncolumns = 80; + pos_x = pos_y = 0; + anchor = TOP_LEFT; + + inpq_front = inpq_back = 0; + + max_hist_lines = 64; + max_output_lines = 128; + + hist_iter_valid = false; + + echo = true; + font = 0; + font_size = 0; + + cursor = 0; + input_win = 0; +} + +void Console::set_cursor(int x) +{ + if(x < 0 || x > (int)input.size()) { + return; + } + cursor = x; + + int max_chars = ncolumns - (int)prompt.size() - 1; + + if(cursor < input_win) { + input_win = cursor; + } else if(cursor > input_win + max_chars) { + input_win = std::max(cursor - max_chars, 0); + } +} + +int Console::get_cursor() const +{ + return cursor; +} + +void Console::set_font(dtx_font *font, int sz) +{ + this->font = font; + font_size = sz; +} + +void Console::set_history_size(int hsz) +{ + max_hist_lines = hsz; + + int drop = hist.size() - hsz; + if(drop > 0) { + auto it = hist.begin(); + for(int i=0; i 0) { + output.erase(output.begin(), output.begin() + drop); + } +} + +void Console::set_command_func(std::function func) +{ + cmd_handler = func; +} + +void Console::set_echo(bool echo) +{ + this->echo = echo; +} + +bool Console::get_echo() const +{ + return echo; +} + +void Console::set_visible(bool v) +{ + visible = v; +} + +bool Console::is_visible() const +{ + return visible; +} + +void Console::set_size(int lines, int columns) +{ + nlines = lines; + ncolumns = columns; +} + +int Console::get_size_lines() const +{ + return nlines; +} + +int Console::get_size_columns() const +{ + return ncolumns; +} + +void Console::set_position(int x, int y, Anchor anchor) +{ + pos_x = x; + pos_y = y; + this->anchor = anchor; +} + +bool Console::update() +{ + bool must_redraw = false; + + while(inpq_front != inpq_back) { + int c = keybuf[inpq_front]; + inpq_front = (inpq_front + 1) % INPUTQ_SIZE; + + switch(c) { + case '\n': + case '\r': + if(echo) { + puts(input.c_str()); + putchar('\n'); + } + if(!input.empty() && cmd_handler) { + cmd_handler(input.c_str()); + } + + hist.push_back(std::move(input)); // move the input string into the history buffer + if((int)hist.size() > max_hist_lines) { + hist.pop_front(); + } + hist_iter_valid = false; + + set_cursor(0); + must_redraw = true; + break; + + case '\t': + // TODO: completion + break; + + case '\b': + if(!input.empty()) { + if(cursor == (int)input.size()) { + input.pop_back(); + set_cursor(get_cursor() - 1); + must_redraw = true; + } else if(cursor > 0) { + input.erase(cursor - 1, 1); + set_cursor(get_cursor() - 1); + must_redraw = true; + } + } + break; + + case KEY_UP: + if(!hist.empty()) { + if(!hist_iter_valid) { + hist_iter = hist.rbegin(); + hist_iter_valid = true; + input = *hist_iter; + } else { + if(++hist_iter == hist.rend()) { + --hist_iter; + break; + } + input = *hist_iter; + } + set_cursor(input.size()); + } + break; + + case KEY_DOWN: + if(!hist.empty()) { + if(!hist_iter_valid) { + hist_iter = hist.rbegin(); + hist_iter_valid = true; + } + if(hist_iter != hist.rbegin()) { + input = *--hist_iter; + set_cursor(input.size()); + } + } + break; + + case KEY_LEFT: + if(cursor > 0) { + set_cursor(get_cursor() - 1); + must_redraw = true; + } + break; + + case KEY_RIGHT: + if(cursor < (int)input.size()) { + set_cursor(get_cursor() + 1); + must_redraw = true; + } + break; + + case KEY_HOME: + set_cursor(0); + must_redraw = true; + break; + + case KEY_END: + set_cursor(input.size()); + must_redraw = true; + break; + + case KEY_PGUP: + case KEY_PGDOWN: + // TODO scroll output buffer + break; + + default: + if(c < 256 && isprint(c)) { + if(cursor == (int)input.size()) { + input.push_back(c); + } else { + input.insert(cursor, 1, c); + } + set_cursor(get_cursor() + 1); + must_redraw = true; + } + } + } + return must_redraw; +} + +void Console::draw() const +{ + if(!font || !visible) return; + dtx_use_font(font, font_size); + + std::string buflines; + + int num_lines = std::min(nlines, (int)output.size()); + auto it = output.cbegin() + (output.size() - num_lines); + + float max_width = dtx_glyph_width('Q') * ncolumns; + + while(it != output.cend()) { + const std::string &line = *it++; + buflines += line + std::string("\n"); + + //max_width = std::max(max_width, dtx_string_width(line.c_str())); + } + + // draw the output box + float line_height = dtx_line_height(); + float outbox_height = nlines * line_height; + float console_height = outbox_height + line_height * 1.5; + + + int vp[4]; + glGetIntegerv(GL_VIEWPORT, vp); + + int px, py; + switch(anchor) { + case TOP_LEFT: + px = pos_x; + py = pos_y; + break; + + case BOTTOM_LEFT: + px = pos_x; + py = vp[3] - console_height - pos_y; + break; + + case CENTER: + px = (vp[2] - max_width) / 2 + pos_x; + py = (vp[3] - console_height) / 2 + pos_y; + break; + } + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, vp[2], 0, vp[3], -1, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(px, vp[3] - py, 0); + + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glDisable(GL_STENCIL_TEST); + glEnable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable(GL_SCISSOR_TEST); + glScissor(vp[0] + px, vp[1] + (vp[3] - py) - console_height, max_width, console_height); + + glBegin(GL_QUADS); + glColor4f(0.1, 0.2, 0.5, 0.7); + glVertex2f(0, -outbox_height); + glVertex2f(max_width, -outbox_height); + glVertex2f(max_width, 0); + glVertex2f(0, 0); + + glColor4f(0.5, 0.2, 0.1, 0.7); + glVertex2f(0, -console_height); + glVertex2f(max_width, -console_height); + glVertex2f(max_width, -outbox_height); + glVertex2f(0, -outbox_height); + glEnd(); + + // draw the output text + glPushMatrix(); + glTranslatef(0, -line_height, 0); + glColor4f(1, 1, 1, 0.7); + dtx_string(buflines.c_str()); + glPopMatrix(); + + // draw the input line + glTranslatef(0, -outbox_height - line_height, 0); + + std::string inpline = prompt + input.substr(input_win); + dtx_string(inpline.c_str()); + glDisable(GL_TEXTURE_2D); + + float cursor_x = dtx_char_pos(inpline.c_str(), cursor - input_win + prompt.size()); + glBegin(GL_QUADS); + glColor4f(1, 1, 1, 0.7); + glVertex2f(cursor_x, -2); + glVertex2f(cursor_x + 2, -2); + glVertex2f(cursor_x + 2, line_height - 2); + glVertex2f(cursor_x, line_height - 2); + glEnd(); + + glPopAttrib(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +void Console::input_key(int key) +{ + keybuf[inpq_back] = key; + inpq_back = (inpq_back + 1) % INPUTQ_SIZE; +} + +void Console::putchar(char c) +{ + if(output.empty()) { + output.push_back(std::string("")); + } + + if(c == '\n' || c == '\r') { + output.push_back(std::string("")); + if((int)output.size() > max_output_lines) { + output.erase(output.begin()); + } + } else { + output.back().push_back(c); + } +} + +void Console::puts(const char *str) +{ + while(*str) { + putchar(*str++); + } +} + +void Console::printf(const char *fmt, ...) +{ + static char buf[1024]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); + + puts(buf); +} + +void Console::debug() +{ + fprintf(stderr, "visible: %s\n", visible ? "true" : "false"); + fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns); + fprintf(stderr, "cursor: %d\n", cursor); + + int qsize = 0; + int qidx = inpq_front; + while(qidx != inpq_back) { + qsize++; + qidx = (qidx + 1) % INPUTQ_SIZE; + } + + fprintf(stderr, "input queue size: %d\n", qsize); + fprintf(stderr, "current input line: \"%s\"\n", input.c_str()); + fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines); + auto it = hist.begin(); + int idx = 0; + while(it != hist.end()) { + fprintf(stderr, " h(%d): \"%s\"\n", idx++, it++->c_str()); + } + + fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines); + for(size_t i=0; i +#include +#include +#include +#include + +#define INPUTQ_SIZE 64 + +class Console { +public: + enum Anchor {TOP_LEFT, BOTTOM_LEFT, CENTER}; + +private: + bool visible; + int nlines, ncolumns; + int pos_x, pos_y; + Anchor anchor; + + int inpq_front, inpq_back; + int keybuf[INPUTQ_SIZE]; + + std::string prompt; + std::string input; // current input line + int cursor; + int input_win; // first character to show in the input "window" + + // input history + int max_hist_lines; + std::list hist; + bool hist_iter_valid; + std::list::const_reverse_iterator hist_iter; + + // console output + int max_output_lines; + std::vector output; + bool echo; + + std::function cmd_handler; + + int font_size; + dtx_font *font; + + void set_cursor(int x); + int get_cursor() const; + +public: + enum { + KEY_LEFT = 256, + KEY_RIGHT, + KEY_UP, KEY_DOWN, + KEY_INS, + KEY_DEL, + KEY_HOME, + KEY_END, + KEY_PGUP, + KEY_PGDOWN + }; + + Console(); + + void set_font(dtx_font *font, int sz); + void set_history_size(int hsz); + void set_output_buffer_size(int sz); + void set_command_func(std::function func); + + void set_echo(bool echo); + bool get_echo() const; + + void show() { set_visible(true); } + void hide() { set_visible(false); } + void set_visible(bool v); + bool is_visible() const; + + void set_size(int lines, int columns = 80); + int get_size_lines() const; + int get_size_columns() const; + + void set_position(int x, int y, Anchor anchor = TOP_LEFT); + + // update returns true if what it did makes a redraw necessary + bool update(); + void draw() const; + + void input_key(int key); // send a keystroke to the console + + void putchar(char c); + void puts(const char *str); + void printf(const char *fmt, ...); + + void debug(); +}; + +#endif // CONSOLE_H_ diff -r 690ef7fa791f -r 053a52f0cb64 src/game.cc --- a/src/game.cc Fri Sep 26 13:19:22 2014 +0300 +++ b/src/game.cc Fri Sep 26 18:40:15 2014 +0300 @@ -6,6 +6,8 @@ #include "game.h" #include "goatvr.h" #include "teapot.h" +#include "console.h" +#include "drawtext.h" static void draw_scene(); static void material(float r, float g, float b, float roughness); @@ -13,16 +15,23 @@ static void create_rtarg(int x, int y); static int next_pow2(int x); +bool opt_separate_walk_look; + static int win_width, win_height; static unsigned int fb_tex; static unsigned int fbo, fb_depth; static int fb_xsz, fb_ysz; static int fb_tex_xsz, fb_tex_ysz; +static unsigned int chess_tex; + static float cam_theta, cam_phi; static Vector3 cam_pos; static bool keystate[256]; +static Console con; +static dtx_font *con_font; + bool game_init() { init_opengl(); @@ -35,6 +44,24 @@ glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); + unsigned char chess_pixels[] = { + 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, + 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff + }; + glGenTextures(1, &chess_tex); + glBindTexture(GL_TEXTURE_2D, chess_tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, chess_pixels); + + if(!(con_font = dtx_open_font_glyphmap("data/mono14.glyphmap"))) { + fprintf(stderr, "failed to open console font\n"); + return false; + } + con.set_size(6, 40); + con.set_font(con_font, 14); + con.set_position(0, 0, Console::CENTER); + return true; } @@ -49,7 +76,12 @@ float dt = (tm - prev_upd) / 1000.0; prev_upd = tm; - float offs = dt * 1.0; + if(con.is_visible()) { + con.update(); + return; + } + + float offs = dt * 5.0; Vector3 dir; if(keystate['d'] || keystate['D']) { @@ -65,8 +97,13 @@ dir += Vector3(0, 0, offs); } - cam_pos.x += dir.x * cos(cam_theta) - dir.y * sin(cam_theta); - cam_pos.z += dir.x * sin(cam_theta) + dir.y * cos(cam_theta); + float cos_theta = cos(DEG_TO_RAD(cam_theta)); + float sin_theta = sin(DEG_TO_RAD(cam_theta)); + cam_pos.x += dir.x * cos_theta - dir.z * sin_theta; + cam_pos.z += dir.x * sin_theta + dir.z * cos_theta; + + if(!opt_separate_walk_look) { + } } void game_display() @@ -96,6 +133,7 @@ glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z); draw_scene(); + con.draw(); vr_end(); } @@ -112,7 +150,7 @@ win_width = x; win_height = y; - create_rtarg(vr_geti_def(VR_RENDER_XRES, x), vr_geti_def(VR_RENDER_YRES, y)); + create_rtarg(vr_geti_def(VR_RENDER_XRES, x * 2), vr_geti_def(VR_RENDER_YRES, y)); vr_output_texture(fb_tex, 0, 0, (float)fb_xsz / (float)fb_tex_xsz, (float)fb_ysz / (float)fb_tex_ysz); /* these might be overriden in VR mode (see game_display) */ @@ -125,21 +163,33 @@ void game_keyboard(int key, bool pressed) { if(pressed) { - switch(key) { - case 27: - exit_game(); - break; + if(con.is_visible()) { + if(key == 27 || key == '`') { + con.hide(); + } else { + con.input_key(key); + } + } else { + switch(key) { + case 27: + exit_game(); + break; - case 'f': - toggle_hmd_fullscr(); - break; + case 'f': + toggle_hmd_fullscr(); + break; - case 'r': - vr_recenter(); - break; + case 'r': + vr_recenter(); + break; - default: - break; + case '`': + con.show(); + break; + + default: + break; + } } } @@ -197,14 +247,17 @@ glMatrixMode(GL_MODELVIEW); + glBindTexture(GL_TEXTURE_2D, chess_tex); + glEnable(GL_TEXTURE_2D); material(1, 1, 1, 1); glBegin(GL_QUADS); glNormal3f(0, 1, 0); - glVertex3f(-10, 0, 10); - glVertex3f(10, 0, 10); - glVertex3f(10, 0, -10); - glVertex3f(-10, 0, -10); + glTexCoord2f(0, 0); glVertex3f(-10, 0, 10); + glTexCoord2f(1, 0); glVertex3f(10, 0, 10); + glTexCoord2f(1, 1); glVertex3f(10, 0, -10); + glTexCoord2f(0, 1); glVertex3f(-10, 0, -10); glEnd(); + glDisable(GL_TEXTURE_2D); material(1, 1, 1, 0.4); glPushMatrix(); @@ -272,6 +325,8 @@ fb_tex_xsz = next_pow2(fb_xsz); fb_tex_ysz = next_pow2(fb_ysz); + printf("creating %dx%d render target (tex size: %dx%d)\n", fb_xsz, fb_ysz, fb_tex_xsz, fb_tex_ysz); + if(!fbo) { glGenFramebuffers(1, &fbo); diff -r 690ef7fa791f -r 053a52f0cb64 src/game.h --- a/src/game.h Fri Sep 26 13:19:22 2014 +0300 +++ b/src/game.h Fri Sep 26 18:40:15 2014 +0300 @@ -1,6 +1,8 @@ #ifndef GAME_H_ #define GAME_H_ +extern bool opt_separate_walk_look; + bool game_init(); void game_cleanup(); diff -r 690ef7fa791f -r 053a52f0cb64 src/main.cc --- a/src/main.cc Fri Sep 26 13:19:22 2014 +0300 +++ b/src/main.cc Fri Sep 26 18:40:15 2014 +0300 @@ -124,6 +124,10 @@ game_mouse_motion(ev->motion.x, ev->motion.y); break; + case SDL_QUIT: + exit_game(); + break; + default: break; } diff -r 690ef7fa791f -r 053a52f0cb64 src/opengl.h --- a/src/opengl.h Fri Sep 26 13:19:22 2014 +0300 +++ b/src/opengl.h Fri Sep 26 18:40:15 2014 +0300 @@ -3,6 +3,8 @@ #include +#ifdef __cplusplus bool init_opengl(); +#endif #endif /* OPENGL_H_ */ diff -r 690ef7fa791f -r 053a52f0cb64 src/teapot.c --- a/src/teapot.c Fri Sep 26 13:19:22 2014 +0300 +++ b/src/teapot.c Fri Sep 26 18:40:15 2014 +0300 @@ -1,9 +1,4 @@ -#ifndef __APPLE__ -#include -#else -#include -#endif - +#include "opengl.h" #include "teapot.h" #include "teapot_data.h" @@ -11,27 +6,41 @@ int patch_subdivision = 6; +static int dlist_sub[32]; + void bezier_teapot(float scale) { int i; + glMatrixMode(GL_MODELVIEW); + + if(!dlist_sub[patch_subdivision]) { + dlist_sub[patch_subdivision] = glGenLists(1); + glNewList(dlist_sub[patch_subdivision], GL_COMPILE); + + for(i=0; iLevel3 Disabled WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + 4244;4305;4996 - Windows + Console true - SDL2.lib;SDL2main.lib;opengl32.lib;glew32.lib;libgoatvr.lib;goat3d.lib;%(AdditionalDependencies) + SDL2.lib;SDL2main.lib;opengl32.lib;glu32.lib;glew32.lib;libgoatvr.lib;libvmath.lib;libdrawtext.lib;%(AdditionalDependencies) @@ -68,23 +69,31 @@ true true WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + 4244;4305;4996 Windows true true true - SDL2.lib;SDL2main.lib;opengl32.lib;glew32.lib;libgoatvr.lib;goat3d.lib;%(AdditionalDependencies) + SDL2.lib;SDL2main.lib;opengl32.lib;glu32.lib;glew32.lib;libgoatvr.lib;libvmath.lib;libdrawtext.lib;%(AdditionalDependencies) + + + + + + + diff -r 690ef7fa791f -r 053a52f0cb64 vrheights.vcxproj.filters --- a/vrheights.vcxproj.filters Fri Sep 26 13:19:22 2014 +0300 +++ b/vrheights.vcxproj.filters Fri Sep 26 18:40:15 2014 +0300 @@ -16,6 +16,15 @@ src + + src + + + src + + + src + @@ -24,5 +33,17 @@ src + + src + + + src + + + src + + + src + \ No newline at end of file