erebus

changeset 37:db8a90307386

implemented console and rudimentary commandline parser
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 09 Jun 2014 16:01:00 +0300
parents 6eab83024d28
children 5e27c85e79ca
files .clang_complete data/mono.glyphmap liberebus/src/erebus.cc liberebus/src/erebus.h src/console.cc src/console.h src/main.cc
diffstat 7 files changed, 547 insertions(+), 11 deletions(-) [+]
line diff
     1.1 --- a/.clang_complete	Mon Jun 09 07:28:03 2014 +0300
     1.2 +++ b/.clang_complete	Mon Jun 09 16:01:00 2014 +0300
     1.3 @@ -1,2 +1,3 @@
     1.4  -std=c++11
     1.5  -Iliberebus/src
     1.6 +-I/usr/local/include
     2.1 Binary file data/mono.glyphmap has changed
     3.1 --- a/liberebus/src/erebus.cc	Mon Jun 09 07:28:03 2014 +0300
     3.2 +++ b/liberebus/src/erebus.cc	Mon Jun 09 16:01:00 2014 +0300
     3.3 @@ -3,6 +3,11 @@
     3.4  #include <algorithm>
     3.5  #include <chrono>
     3.6  #include <random>
     3.7 +#ifndef _MSC_VER
     3.8 +#include <alloca.h>
     3.9 +#else
    3.10 +#include <malloc.h>
    3.11 +#endif
    3.12  #include "erebus.h"
    3.13  #include "erebus_impl.h"
    3.14  #include "scene.h"
    3.15 @@ -248,8 +253,9 @@
    3.16  
    3.17  int erb_load_scene(struct erebus *ctx, const char *fname)
    3.18  {
    3.19 -	delete ctx->scn;
    3.20 -	ctx->scn = new Scene;
    3.21 +	if(!ctx->scn) {
    3.22 +		ctx->scn = new Scene;
    3.23 +	}
    3.24  
    3.25  	if(!ctx->scn->load(fname)) {
    3.26  		return -1;
    3.27 @@ -257,6 +263,29 @@
    3.28  	return 0;
    3.29  }
    3.30  
    3.31 +int erb_proc_cmd(struct erebus *ctx, const char *cmd)
    3.32 +{
    3.33 +	if(!ctx->scn) {
    3.34 +		ctx->scn = new Scene;
    3.35 +	}
    3.36 +
    3.37 +	char *buf = (char*)alloca(strlen(cmd) + 1);
    3.38 +	strcpy(buf, cmd);
    3.39 +
    3.40 +	std::vector<char*> args;
    3.41 +	char *tok;
    3.42 +	while((tok = strtok(buf, " \t\v\n\r"))) {
    3.43 +		buf = 0;
    3.44 +		args.push_back(tok);
    3.45 +	}
    3.46 +	args.push_back(0);
    3.47 +
    3.48 +	if(!ctx->scn->proc_cmd(args.size() - 1, &args[0])) {
    3.49 +		return -1;
    3.50 +	}
    3.51 +	return 0;
    3.52 +}
    3.53 +
    3.54  bool erb_input_keyboard(struct erebus *ctx, int key, bool pressed)
    3.55  {
    3.56  	if(!ctx) return false;
     4.1 --- a/liberebus/src/erebus.h	Mon Jun 09 07:28:03 2014 +0300
     4.2 +++ b/liberebus/src/erebus.h	Mon Jun 09 16:01:00 2014 +0300
     4.3 @@ -46,6 +46,7 @@
     4.4  int erb_get_status(struct erebus *ctx, struct erb_render_status *stat);
     4.5  
     4.6  int erb_load_scene(struct erebus *ctx, const char *fname);
     4.7 +int erb_proc_cmd(struct erebus *ctx, const char *cmd);
     4.8  
     4.9  bool erb_input_keyboard(struct erebus *ctx, int key, bool pressed);
    4.10  bool erb_input_mouse_button(struct erebus *ctx, int bn, bool pressed, int x, int y);
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/console.cc	Mon Jun 09 16:01:00 2014 +0300
     5.3 @@ -0,0 +1,324 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <string.h>
     5.7 +#include <stdarg.h>
     5.8 +#include <assert.h>
     5.9 +#include <algorithm>
    5.10 +#include "opengl.h"
    5.11 +#include "console.h"
    5.12 +
    5.13 +Console::Console()
    5.14 +{
    5.15 +	visible = false;
    5.16 +	nlines = 16;
    5.17 +	ncolumns = 80;
    5.18 +
    5.19 +	inpq_front = inpq_back = 0;
    5.20 +
    5.21 +	max_hist_lines = 64;
    5.22 +	max_output_lines = 128;
    5.23 +
    5.24 +	echo = true;
    5.25 +	font = 0;
    5.26 +	font_size = 0;
    5.27 +
    5.28 +	cursor = 0;
    5.29 +}
    5.30 +
    5.31 +void Console::set_font(dtx_font *font, int sz)
    5.32 +{
    5.33 +	this->font = font;
    5.34 +	font_size = sz;
    5.35 +}
    5.36 +
    5.37 +void Console::set_history_size(int hsz)
    5.38 +{
    5.39 +	max_hist_lines = hsz;
    5.40 +
    5.41 +	int drop = hist.size() - hsz;
    5.42 +	if(drop > 0) {
    5.43 +		auto it = hist.begin();
    5.44 +		for(int i=0; i<drop; i++) {
    5.45 +			++it;
    5.46 +		}
    5.47 +		hist.erase(hist.begin(), it);
    5.48 +	}
    5.49 +}
    5.50 +
    5.51 +void Console::set_output_buffer_size(int sz)
    5.52 +{
    5.53 +	max_output_lines = sz;
    5.54 +
    5.55 +	int drop = output.size() - sz;
    5.56 +	if(drop > 0) {
    5.57 +		output.erase(output.begin(), output.begin() + drop);
    5.58 +	}
    5.59 +}
    5.60 +
    5.61 +void Console::set_command_func(std::function<void (const char*)> func)
    5.62 +{
    5.63 +	cmd_handler = func;
    5.64 +}
    5.65 +
    5.66 +void Console::set_echo(bool echo)
    5.67 +{
    5.68 +	this->echo = echo;
    5.69 +}
    5.70 +
    5.71 +bool Console::get_echo() const
    5.72 +{
    5.73 +	return echo;
    5.74 +}
    5.75 +
    5.76 +void Console::set_visible(bool v)
    5.77 +{
    5.78 +	visible = v;
    5.79 +}
    5.80 +
    5.81 +bool Console::is_visible() const
    5.82 +{
    5.83 +	return visible;
    5.84 +}
    5.85 +
    5.86 +void Console::set_size(int lines, int columns)
    5.87 +{
    5.88 +	nlines = lines;
    5.89 +	ncolumns = columns;
    5.90 +}
    5.91 +
    5.92 +int Console::get_size_lines() const
    5.93 +{
    5.94 +	return nlines;
    5.95 +}
    5.96 +
    5.97 +int Console::get_size_columns() const
    5.98 +{
    5.99 +	return ncolumns;
   5.100 +}
   5.101 +
   5.102 +bool Console::update()
   5.103 +{
   5.104 +	bool must_redraw = false;
   5.105 +
   5.106 +	while(inpq_front != inpq_back) {
   5.107 +		int c = keybuf[inpq_front];
   5.108 +		inpq_front = (inpq_front + 1) % INPUTQ_SIZE;
   5.109 +
   5.110 +		switch(c) {
   5.111 +		case '\n':
   5.112 +		case '\r':
   5.113 +			if(cmd_handler) {
   5.114 +				cmd_handler(input.c_str());
   5.115 +			}
   5.116 +
   5.117 +			if(echo) {
   5.118 +				puts(input.c_str());
   5.119 +				putchar('\n');
   5.120 +			}
   5.121 +
   5.122 +			hist.push_back(std::move(input));	// move the input string into the history buffer
   5.123 +			if((int)hist.size() > max_hist_lines) {
   5.124 +				hist.pop_front();
   5.125 +			}
   5.126 +			cursor = 0;
   5.127 +			must_redraw = true;
   5.128 +			break;
   5.129 +
   5.130 +		case '\t':
   5.131 +			// TODO: completion
   5.132 +			break;
   5.133 +
   5.134 +		case '\b':
   5.135 +			if(!input.empty()) {
   5.136 +				if(cursor == (int)input.size()) {
   5.137 +					input.pop_back();
   5.138 +					--cursor;
   5.139 +					must_redraw = true;
   5.140 +				} else if(cursor > 0) {
   5.141 +					input.erase(cursor - 1);
   5.142 +					--cursor;
   5.143 +					must_redraw = true;
   5.144 +				}
   5.145 +			}
   5.146 +			break;
   5.147 +
   5.148 +		case KEY_LEFT:
   5.149 +			if(cursor > 0) {
   5.150 +				--cursor;
   5.151 +				must_redraw = true;
   5.152 +			}
   5.153 +			break;
   5.154 +
   5.155 +		case KEY_RIGHT:
   5.156 +			if(cursor < (int)input.size()) {
   5.157 +				++cursor;
   5.158 +				must_redraw = true;
   5.159 +			}
   5.160 +			break;
   5.161 +
   5.162 +		case KEY_HOME:
   5.163 +			cursor = 0;
   5.164 +			must_redraw = true;
   5.165 +			break;
   5.166 +
   5.167 +		case KEY_END:
   5.168 +			cursor = input.size();
   5.169 +			must_redraw = true;
   5.170 +			break;
   5.171 +
   5.172 +		case KEY_PGUP:
   5.173 +		case KEY_PGDOWN:
   5.174 +			// TODO history
   5.175 +			break;
   5.176 +
   5.177 +		default:
   5.178 +			if(c < 256 && isprint(c)) {
   5.179 +				input.push_back(c);
   5.180 +				++cursor;
   5.181 +				must_redraw = true;
   5.182 +			}
   5.183 +		}
   5.184 +	}
   5.185 +	return must_redraw;
   5.186 +}
   5.187 +
   5.188 +void Console::draw() const
   5.189 +{
   5.190 +	if(!font || !visible) return;
   5.191 +	dtx_use_font(font, font_size);
   5.192 +
   5.193 +	int vp[4];
   5.194 +	glGetIntegerv(GL_VIEWPORT, vp);
   5.195 +
   5.196 +	glMatrixMode(GL_PROJECTION);
   5.197 +	glPushMatrix();
   5.198 +	glLoadIdentity();
   5.199 +	glOrtho(vp[0], vp[0] + vp[2], vp[1], vp[1] + vp[3], -1, 1);
   5.200 +
   5.201 +	glMatrixMode(GL_MODELVIEW);
   5.202 +	glPushMatrix();
   5.203 +	glLoadIdentity();
   5.204 +	glTranslatef(0, vp[3] - vp[1], 0);
   5.205 +
   5.206 +	std::string buflines;
   5.207 +
   5.208 +	int num_lines = std::min(nlines, (int)output.size());
   5.209 +	auto it = output.cbegin() + (output.size() - num_lines);
   5.210 +
   5.211 +	float max_width = dtx_glyph_width('Q') * ncolumns;
   5.212 +
   5.213 +	while(it != output.cend()) {
   5.214 +		const std::string &line = *it++;
   5.215 +		buflines += line + std::string("\n");
   5.216 +
   5.217 +		max_width = std::max(max_width, dtx_string_width(line.c_str()));
   5.218 +	}
   5.219 +
   5.220 +	// draw the output box
   5.221 +	float outbox_height = nlines * dtx_line_height();
   5.222 +
   5.223 +	glPushAttrib(GL_ENABLE_BIT);
   5.224 +	glEnable(GL_BLEND);
   5.225 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   5.226 +
   5.227 +	glBegin(GL_QUADS);
   5.228 +	glColor4f(0.1, 0.2, 0.5, 0.7);
   5.229 +	glVertex2f(0, -outbox_height);
   5.230 +	glVertex2f(max_width, -outbox_height);
   5.231 +	glVertex2f(max_width, 0);
   5.232 +	glVertex2f(0, 0);
   5.233 +
   5.234 +	glColor4f(0.5, 0.2, 0.1, 0.7);
   5.235 +	glVertex2f(0, -(outbox_height + dtx_line_height()));
   5.236 +	glVertex2f(max_width, -(outbox_height + dtx_line_height()));
   5.237 +	glVertex2f(max_width, -outbox_height);
   5.238 +	glVertex2f(0, -outbox_height);
   5.239 +	glEnd();
   5.240 +
   5.241 +	// draw the output text
   5.242 +	glPushMatrix();
   5.243 +	glTranslatef(0, -dtx_line_height(), 0);
   5.244 +	glColor4f(1, 1, 1, 0.7);
   5.245 +	dtx_string(buflines.c_str());
   5.246 +	glPopMatrix();
   5.247 +
   5.248 +	// draw the input line
   5.249 +	glTranslatef(0, -outbox_height - dtx_line_height(), 0);
   5.250 +	dtx_string((std::string("> ") + input).c_str());
   5.251 +
   5.252 +	glPopAttrib();
   5.253 +
   5.254 +	glMatrixMode(GL_PROJECTION);
   5.255 +	glPopMatrix();
   5.256 +	glMatrixMode(GL_MODELVIEW);
   5.257 +	glPopMatrix();
   5.258 +}
   5.259 +
   5.260 +void Console::input_key(int key)
   5.261 +{
   5.262 +	keybuf[inpq_back] = key;
   5.263 +	inpq_back = (inpq_back + 1) % INPUTQ_SIZE;
   5.264 +}
   5.265 +
   5.266 +void Console::putchar(char c)
   5.267 +{
   5.268 +	if(output.empty()) {
   5.269 +		output.push_back(std::string(""));
   5.270 +	}
   5.271 +
   5.272 +	if(c == '\n' || c == '\r') {
   5.273 +		output.push_back(std::string(""));
   5.274 +		if((int)output.size() > max_output_lines) {
   5.275 +			output.erase(output.begin());
   5.276 +		}
   5.277 +	} else {
   5.278 +		output.back().push_back(c);
   5.279 +	}
   5.280 +}
   5.281 +
   5.282 +void Console::puts(const char *str)
   5.283 +{
   5.284 +	while(*str) {
   5.285 +		putchar(*str++);
   5.286 +	}
   5.287 +}
   5.288 +
   5.289 +void Console::printf(const char *fmt, ...)
   5.290 +{
   5.291 +	static char buf[1024];
   5.292 +	va_list ap;
   5.293 +
   5.294 +	va_start(ap, fmt);
   5.295 +	vsnprintf(buf, sizeof buf, fmt, ap);
   5.296 +	va_end(ap);
   5.297 +
   5.298 +	puts(buf);
   5.299 +}
   5.300 +
   5.301 +void Console::debug()
   5.302 +{
   5.303 +	fprintf(stderr, "visible: %s\n", visible ? "true" : "false");
   5.304 +	fprintf(stderr, "size: %d lines x %d columns\n", nlines, ncolumns);
   5.305 +	fprintf(stderr, "cursor: %d\n", cursor);
   5.306 +
   5.307 +	int qsize = 0;
   5.308 +	int qidx = inpq_front;
   5.309 +	while(qidx != inpq_back) {
   5.310 +		qsize++;
   5.311 +		qidx = (qidx + 1) % INPUTQ_SIZE;
   5.312 +	}
   5.313 +
   5.314 +	fprintf(stderr, "input queue size: %d\n", qsize);
   5.315 +	fprintf(stderr, "current input line: \"%s\"\n", input.c_str());
   5.316 +	fprintf(stderr, "%d saved inputs in the history (max %d)\n", (int)hist.size(), max_hist_lines);
   5.317 +	auto it = hist.begin();
   5.318 +	int idx = 0;
   5.319 +	while(it != hist.end()) {
   5.320 +		fprintf(stderr, "  h(%d): \"%s\"\n", idx++, it++->c_str());
   5.321 +	}
   5.322 +
   5.323 +	fprintf(stderr, "output buffer (lines: %d/%d):\n", (int)output.size(), max_output_lines);
   5.324 +	for(size_t i=0; i<output.size(); i++) {
   5.325 +		fprintf(stderr, "o(%d): \"%s\"\n", (int)i, output[i].c_str());
   5.326 +	}
   5.327 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/console.h	Mon Jun 09 16:01:00 2014 +0300
     6.3 @@ -0,0 +1,82 @@
     6.4 +#ifndef CONSOLE_H_
     6.5 +#define CONSOLE_H_
     6.6 +
     6.7 +#include <vector>
     6.8 +#include <list>
     6.9 +#include <string>
    6.10 +#include <functional>
    6.11 +#include <drawtext.h>
    6.12 +
    6.13 +#define INPUTQ_SIZE		64
    6.14 +
    6.15 +class Console {
    6.16 +private:
    6.17 +	bool visible;
    6.18 +	int nlines, ncolumns;
    6.19 +
    6.20 +	int inpq_front, inpq_back;
    6.21 +	int keybuf[INPUTQ_SIZE];
    6.22 +
    6.23 +	std::string input;	// current input line
    6.24 +	int cursor;
    6.25 +
    6.26 +	// input history
    6.27 +	int max_hist_lines;
    6.28 +	std::list<std::string> hist;
    6.29 +
    6.30 +	// console output
    6.31 +	int max_output_lines;
    6.32 +	std::vector<std::string> output;
    6.33 +	bool echo;
    6.34 +
    6.35 +	std::function<void (const char*)> cmd_handler;
    6.36 +
    6.37 +	int font_size;
    6.38 +	dtx_font *font;
    6.39 +
    6.40 +public:
    6.41 +	enum {
    6.42 +		KEY_LEFT = 256,
    6.43 +		KEY_RIGHT,
    6.44 +		KEY_UP, KEY_DOWN,
    6.45 +		KEY_INS,
    6.46 +		KEY_DEL,
    6.47 +		KEY_HOME,
    6.48 +		KEY_END,
    6.49 +		KEY_PGUP,
    6.50 +		KEY_PGDOWN
    6.51 +	};
    6.52 +
    6.53 +	Console();
    6.54 +
    6.55 +	void set_font(dtx_font *font, int sz);
    6.56 +	void set_history_size(int hsz);
    6.57 +	void set_output_buffer_size(int sz);
    6.58 +	void set_command_func(std::function<void (const char*)> func);
    6.59 +
    6.60 +	void set_echo(bool echo);
    6.61 +	bool get_echo() const;
    6.62 +
    6.63 +	void show() { set_visible(true); }
    6.64 +	void hide() { set_visible(false); }
    6.65 +	void set_visible(bool v);
    6.66 +	bool is_visible() const;
    6.67 +
    6.68 +	void set_size(int lines, int columns = 80);
    6.69 +	int get_size_lines() const;
    6.70 +	int get_size_columns() const;
    6.71 +
    6.72 +	// update returns true if what it did makes a redraw necessary
    6.73 +	bool update();
    6.74 +	void draw() const;
    6.75 +
    6.76 +	void input_key(int key);	// send a keystroke to the console
    6.77 +
    6.78 +	void putchar(char c);
    6.79 +	void puts(const char *str);
    6.80 +	void printf(const char *fmt, ...);
    6.81 +
    6.82 +	void debug();
    6.83 +};
    6.84 +
    6.85 +#endif	// CONSOLE_H_
     7.1 --- a/src/main.cc	Mon Jun 09 07:28:03 2014 +0300
     7.2 +++ b/src/main.cc	Mon Jun 09 16:01:00 2014 +0300
     7.3 @@ -9,6 +9,7 @@
     7.4  #include <drawtext.h>
     7.5  #include "opengl.h"
     7.6  #include "erebus.h"
     7.7 +#include "console.h"
     7.8  
     7.9  using namespace std::chrono;
    7.10  
    7.11 @@ -25,6 +26,7 @@
    7.12  static void reshape(int x, int y);
    7.13  static void keyb(unsigned char key, int x, int y);
    7.14  static void keyb_up(unsigned char key, int x, int y);
    7.15 +static void skeyb(int key, int x, int y);
    7.16  static void mouse(int bn, int st, int x, int y);
    7.17  static void motion(int x, int y);
    7.18  static void sball_button(int bn, int st);
    7.19 @@ -32,6 +34,7 @@
    7.20  static int next_pow2(int x);
    7.21  static void sighandler(int s);
    7.22  static bool parse_args(int argc, char **argv);
    7.23 +static void con_parse(const char *line);
    7.24  
    7.25  static int win_width, win_height, width, height, rtex_width, rtex_height;
    7.26  static unsigned int rtex;
    7.27 @@ -48,7 +51,9 @@
    7.28  
    7.29  static std::vector<char*> sfiles;
    7.30  
    7.31 +#define FONTSZ	22
    7.32  static dtx_font *font;
    7.33 +static Console con;
    7.34  
    7.35  int main(int argc, char **argv)
    7.36  {
    7.37 @@ -66,6 +71,7 @@
    7.38  	glutReshapeFunc(reshape);
    7.39  	glutKeyboardFunc(keyb);
    7.40  	glutKeyboardUpFunc(keyb_up);
    7.41 +	glutSpecialFunc(skeyb);
    7.42  	glutMouseFunc(mouse);
    7.43  	glutMotionFunc(motion);
    7.44  	glutSpaceballButtonFunc(sball_button);
    7.45 @@ -89,11 +95,20 @@
    7.46  	width = glutGet(GLUT_WINDOW_WIDTH) / opt_imgscale;
    7.47  	height = glutGet(GLUT_WINDOW_HEIGHT) / opt_imgscale;
    7.48  
    7.49 -	//if(!(font = dtx_open_font("/usr/share/fonts/opentype/linux-libertine/LinLibertine_R.otf", 22))) {
    7.50 +	//if(!(font = dtx_open_font("/usr/share/fonts/opentype/linux-libertine/LinLibertine_R.otf", FONTSZ))) {
    7.51  	if(!(font = dtx_open_font_glyphmap("data/serif.glyphmap"))) {
    7.52  		fprintf(stderr, "warning: failed to load font!\n");
    7.53  	}
    7.54  
    7.55 +	//dtx_font *confont = dtx_open_font("/usr/share/fonts/truetype/droid/DroidSansMono.ttf", 14);
    7.56 +	dtx_font *confont = dtx_open_font_glyphmap("data/mono.glyphmap");
    7.57 +	if(confont) {
    7.58 +		con.set_font(confont, 14);
    7.59 +	} else {
    7.60 +		con.set_font(font, FONTSZ);
    7.61 +	}
    7.62 +	con.set_command_func(con_parse);
    7.63 +
    7.64  	if(!(erb = erb_init())) {
    7.65  		return false;
    7.66  	}
    7.67 @@ -256,6 +271,10 @@
    7.68  	glTexCoord2f(0, 0); glVertex2f(-1, 1);
    7.69  	glEnd();
    7.70  
    7.71 +	// draw the console
    7.72 +	con.update();
    7.73 +	con.draw();
    7.74 +
    7.75  	// draw progress information etc...
    7.76  	if(show_status) {
    7.77  		display_statusbar(status);
    7.78 @@ -268,6 +287,7 @@
    7.79  static void display_statusbar(const erb_render_status &status)
    7.80  {
    7.81  	if(!font) return;
    7.82 +	dtx_use_font(font, FONTSZ);
    7.83  
    7.84  	bool show_progress = opt_samples > 0;
    7.85  
    7.86 @@ -368,22 +388,41 @@
    7.87  {
    7.88  	switch(key) {
    7.89  	case 27:
    7.90 -		end_frame();
    7.91 -		exit(0);
    7.92 +		if(con.is_visible()) {
    7.93 +			con.hide();
    7.94 +			glutPostRedisplay();
    7.95 +		} else {
    7.96 +			end_frame();
    7.97 +			exit(0);
    7.98 +		}
    7.99 +		break;
   7.100  
   7.101  	case ' ':
   7.102 -		begin_frame(0);
   7.103 -		break;
   7.104 -
   7.105 -	case '\b':
   7.106 -		printf("saving image.\n");
   7.107 -		save_image();
   7.108 +		if(!con.is_visible()) {
   7.109 +			begin_frame(0);
   7.110 +		} else {
   7.111 +			con.input_key(' ');
   7.112 +			glutPostRedisplay();
   7.113 +		}
   7.114  		break;
   7.115  
   7.116  	case '`':
   7.117 +		con.set_visible(!con.is_visible());
   7.118 +		glutPostRedisplay();
   7.119 +		break;
   7.120 +
   7.121 +	case '~':
   7.122  		show_status = !show_status;
   7.123  		glutPostRedisplay();
   7.124  		break;
   7.125 +
   7.126 +	default:
   7.127 +		// otherwise if the console is visible, let them through
   7.128 +		if(con.is_visible()) {
   7.129 +			con.input_key(key);
   7.130 +			glutPostRedisplay();
   7.131 +			return;	// don't pass anything to the erb input handler
   7.132 +		}
   7.133  	}
   7.134  
   7.135  	if(erb_input_keyboard(erb, key, true)) {
   7.136 @@ -398,6 +437,55 @@
   7.137  	}
   7.138  }
   7.139  
   7.140 +static void skeyb(int key, int x, int y)
   7.141 +{
   7.142 +	if(key == GLUT_KEY_F12) {
   7.143 +		printf("saving image...\n");
   7.144 +		save_image();
   7.145 +		return;
   7.146 +	}
   7.147 +
   7.148 +	if(con.is_visible()) {
   7.149 +		switch(key) {
   7.150 +		case GLUT_KEY_F8:
   7.151 +			con.debug();
   7.152 +			return;
   7.153 +
   7.154 +		case GLUT_KEY_LEFT:
   7.155 +			con.input_key(Console::KEY_LEFT);
   7.156 +			break;
   7.157 +		case GLUT_KEY_RIGHT:
   7.158 +			con.input_key(Console::KEY_RIGHT);
   7.159 +			break;
   7.160 +		case GLUT_KEY_UP:
   7.161 +			con.input_key(Console::KEY_UP);
   7.162 +			break;
   7.163 +		case GLUT_KEY_DOWN:
   7.164 +			con.input_key(Console::KEY_DOWN);
   7.165 +			break;
   7.166 +		case GLUT_KEY_HOME:
   7.167 +			con.input_key(Console::KEY_HOME);
   7.168 +			break;
   7.169 +		case GLUT_KEY_END:
   7.170 +			con.input_key(Console::KEY_END);
   7.171 +			break;
   7.172 +		case GLUT_KEY_INSERT:
   7.173 +			con.input_key(Console::KEY_INS);
   7.174 +			break;
   7.175 +		case GLUT_KEY_PAGE_UP:
   7.176 +			con.input_key(Console::KEY_PGUP);
   7.177 +			break;
   7.178 +		case GLUT_KEY_PAGE_DOWN:
   7.179 +			con.input_key(Console::KEY_PGDOWN);
   7.180 +			break;
   7.181 +
   7.182 +		default:
   7.183 +			return;
   7.184 +		}
   7.185 +		glutPostRedisplay();
   7.186 +	}
   7.187 +}
   7.188 +
   7.189  static void mouse(int bn, int st, int x, int y)
   7.190  {
   7.191  	if(erb_input_mouse_button(erb, bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y)) {
   7.192 @@ -483,3 +571,14 @@
   7.193  
   7.194  	return true;
   7.195  }
   7.196 +
   7.197 +static void con_parse(const char *line)
   7.198 +{
   7.199 +	printf("got line: %s\n", line);
   7.200 +
   7.201 +	if(erb_proc_cmd(erb, line) == -1) {
   7.202 +		con.puts("invalid command\n");
   7.203 +	} else {
   7.204 +		begin_frame(0);
   7.205 +	}
   7.206 +}