erebus

changeset 41:2e817711d0f6

console: proper input line windowing and clipping
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 10 Jun 2014 12:28:56 +0300
parents 9d6368850fe1
children b9294cd6b9dc
files liberebus/src/geomobj.cc liberebus/src/geomobj.h liberebus/src/scene.h src/console.cc src/console.h src/main.cc
diffstat 6 files changed, 170 insertions(+), 53 deletions(-) [+]
line diff
     1.1 --- a/liberebus/src/geomobj.cc	Tue Jun 10 10:53:19 2014 +0300
     1.2 +++ b/liberebus/src/geomobj.cc	Tue Jun 10 12:28:56 2014 +0300
     1.3 @@ -1,6 +1,8 @@
     1.4  #include <math.h>
     1.5  #include <float.h>
     1.6 +#include <vmath/vmath.h>
     1.7  #include "geomobj.h"
     1.8 +#include "erebus_impl.h"
     1.9  
    1.10  static LambertRefl lambert;
    1.11  
    1.12 @@ -19,6 +21,11 @@
    1.13  	return false;
    1.14  }
    1.15  
    1.16 +Vector3 GeomObject::gen_surface_point() const
    1.17 +{
    1.18 +	return Vector3(0, 0, 0);
    1.19 +}
    1.20 +
    1.21  Vector3 GeomObject::calc_normal(const RayHit &hit) const
    1.22  {
    1.23  	// when you look at singularities, the singularities always look back at you :)
    1.24 @@ -64,6 +71,11 @@
    1.25  	return true;
    1.26  }
    1.27  
    1.28 +Vector3 Sphere::gen_surface_point() const
    1.29 +{
    1.30 +	return sphrand(1.0);
    1.31 +}
    1.32 +
    1.33  Vector3 Sphere::calc_normal(const RayHit &hit) const
    1.34  {
    1.35  	Vector3 pt = hit.local_ray.origin + hit.local_ray.dir * hit.dist;
    1.36 @@ -143,7 +155,27 @@
    1.37  		return true;
    1.38  	}
    1.39  	return false;
    1.40 +}
    1.41  
    1.42 +#define SIGN(x)	(x >= 0.0 ? 1.0 : -1.0)
    1.43 +
    1.44 +Vector3 Box::gen_surface_point() const
    1.45 +{
    1.46 +	Vector3 rnd{randf(-1, 1), randf(-1, 1), randf(-1, 1)};
    1.47 +	float absrnd[3];
    1.48 +
    1.49 +	absrnd[0] = fabs(rnd.x);
    1.50 +	absrnd[1] = fabs(rnd.y);
    1.51 +	absrnd[2] = fabs(rnd.z);
    1.52 +
    1.53 +	int major = 0;
    1.54 +	for(int i=1; i<3; i++) {
    1.55 +		if(absrnd[i] > absrnd[major]) {
    1.56 +			major = i;
    1.57 +		}
    1.58 +	}
    1.59 +	rnd[major] = SIGN(rnd[major]);
    1.60 +	return rnd;
    1.61  }
    1.62  
    1.63  #define BOX_EXT		0.499999
    1.64 @@ -176,6 +208,15 @@
    1.65  	return false;
    1.66  }
    1.67  
    1.68 +Vector3 Triangle::gen_surface_point() const
    1.69 +{
    1.70 +	float bu = randf();
    1.71 +	float bv = randf();
    1.72 +	float bw = 1.0 - (bu + bv);
    1.73 +
    1.74 +	return v[0] * bu + v[1] * bv + v[2] * bw;
    1.75 +}
    1.76 +
    1.77  // --- class Mesh ---
    1.78  
    1.79  bool Mesh::intersect(const Ray &ray, RayHit *hit) const
    1.80 @@ -200,3 +241,9 @@
    1.81  	}
    1.82  	return false;
    1.83  }
    1.84 +
    1.85 +Vector3 Mesh::gen_surface_point() const
    1.86 +{
    1.87 +	// this needs some precalculation...
    1.88 +	return Vector3(0, 0, 0);	// TODO
    1.89 +}
     2.1 --- a/liberebus/src/geomobj.h	Tue Jun 10 10:53:19 2014 +0300
     2.2 +++ b/liberebus/src/geomobj.h	Tue Jun 10 12:28:56 2014 +0300
     2.3 @@ -17,6 +17,8 @@
     2.4  
     2.5  	bool intersect(const Ray &ray, RayHit *hit = 0) const override;
     2.6  
     2.7 +	virtual Vector3 gen_surface_point() const;
     2.8 +
     2.9  	virtual Vector3 calc_normal(const RayHit &hit) const;
    2.10  	virtual Vector3 calc_tangent(const RayHit &hit) const;
    2.11  	virtual Vector2 calc_texcoords(const RayHit &hit) const;
    2.12 @@ -26,6 +28,8 @@
    2.13  public:
    2.14  	bool intersect(const Ray &ray, RayHit *hit = 0) const override;
    2.15  
    2.16 +	Vector3 gen_surface_point() const override;
    2.17 +
    2.18  	Vector3 calc_normal(const RayHit &hit) const override;
    2.19  	Vector3 calc_tangent(const RayHit &hit) const override;
    2.20  	Vector2 calc_texcoords(const RayHit &hit) const override;
    2.21 @@ -35,6 +39,8 @@
    2.22  public:
    2.23  	bool intersect(const Ray &ray, RayHit *hit = 0) const override;
    2.24  
    2.25 +	Vector3 gen_surface_point() const override;
    2.26 +
    2.27  	Vector3 calc_normal(const RayHit &hit) const override;
    2.28  	Vector3 calc_tangent(const RayHit &hit) const override;
    2.29  	Vector2 calc_texcoords(const RayHit &hit) const override;
    2.30 @@ -48,6 +54,8 @@
    2.31  	Vector2 vtex[3];
    2.32  
    2.33  	bool intersect(const Ray &ray, RayHit *hit = 0) const override;
    2.34 +
    2.35 +	Vector3 gen_surface_point() const override;
    2.36  };
    2.37  
    2.38  class Mesh : public GeomObject {
    2.39 @@ -62,6 +70,8 @@
    2.40  	void end();
    2.41  
    2.42  	bool intersect(const Ray &ray, RayHit *hit = 0) const override;
    2.43 +
    2.44 +	Vector3 gen_surface_point() const override;
    2.45  };
    2.46  
    2.47  #endif	// GEOMOBJ_H_
     3.1 --- a/liberebus/src/scene.h	Tue Jun 10 10:53:19 2014 +0300
     3.2 +++ b/liberebus/src/scene.h	Tue Jun 10 12:28:56 2014 +0300
     3.3 @@ -3,6 +3,7 @@
     3.4  
     3.5  #include <stdio.h>
     3.6  #include <vector>
     3.7 +#include <list>
     3.8  #include "snode.h"
     3.9  #include "camera.h"
    3.10  #include "color.h"
    3.11 @@ -15,6 +16,11 @@
    3.12  	Environment();
    3.13  };
    3.14  
    3.15 +struct ObjectInstance {
    3.16 +	Object *obj;
    3.17 +	SceneNode *node;
    3.18 +};
    3.19 +
    3.20  class Scene {
    3.21  private:
    3.22  	Environment env;
     4.1 --- a/src/console.cc	Tue Jun 10 10:53:19 2014 +0300
     4.2 +++ b/src/console.cc	Tue Jun 10 12:28:56 2014 +0300
     4.3 @@ -8,6 +8,7 @@
     4.4  #include "console.h"
     4.5  
     4.6  Console::Console()
     4.7 +	: prompt("> ")
     4.8  {
     4.9  	visible = false;
    4.10  	nlines = 16;
    4.11 @@ -23,6 +24,28 @@
    4.12  	font_size = 0;
    4.13  
    4.14  	cursor = 0;
    4.15 +	input_win = 0;
    4.16 +}
    4.17 +
    4.18 +void Console::set_cursor(int x)
    4.19 +{
    4.20 +	if(x < 0 || x > (int)input.size()) {
    4.21 +		return;
    4.22 +	}
    4.23 +	cursor = x;
    4.24 +
    4.25 +	int max_chars = ncolumns - (int)prompt.size() - 1;
    4.26 +
    4.27 +	if(cursor < input_win) {
    4.28 +		input_win = cursor;
    4.29 +	} else if(cursor > input_win + max_chars) {
    4.30 +		input_win = std::max(cursor - max_chars, 0);
    4.31 +	}
    4.32 +}
    4.33 +
    4.34 +int Console::get_cursor() const
    4.35 +{
    4.36 +	return cursor;
    4.37  }
    4.38  
    4.39  void Console::set_font(dtx_font *font, int sz)
    4.40 @@ -107,20 +130,19 @@
    4.41  		switch(c) {
    4.42  		case '\n':
    4.43  		case '\r':
    4.44 -			if(!input.empty() && cmd_handler) {
    4.45 -				cmd_handler(input.c_str());
    4.46 -			}
    4.47 -
    4.48  			if(echo) {
    4.49  				puts(input.c_str());
    4.50  				putchar('\n');
    4.51  			}
    4.52 +			if(!input.empty() && cmd_handler) {
    4.53 +				cmd_handler(input.c_str());
    4.54 +			}
    4.55  
    4.56  			hist.push_back(std::move(input));	// move the input string into the history buffer
    4.57  			if((int)hist.size() > max_hist_lines) {
    4.58  				hist.pop_front();
    4.59  			}
    4.60 -			cursor = 0;
    4.61 +			set_cursor(0);
    4.62  			must_redraw = true;
    4.63  			break;
    4.64  
    4.65 @@ -132,11 +154,11 @@
    4.66  			if(!input.empty()) {
    4.67  				if(cursor == (int)input.size()) {
    4.68  					input.pop_back();
    4.69 -					--cursor;
    4.70 +					set_cursor(get_cursor() - 1);
    4.71  					must_redraw = true;
    4.72  				} else if(cursor > 0) {
    4.73  					input.erase(cursor - 1, 1);
    4.74 -					--cursor;
    4.75 +					set_cursor(get_cursor() - 1);
    4.76  					must_redraw = true;
    4.77  				}
    4.78  			}
    4.79 @@ -144,25 +166,25 @@
    4.80  
    4.81  		case KEY_LEFT:
    4.82  			if(cursor > 0) {
    4.83 -				--cursor;
    4.84 +				set_cursor(get_cursor() - 1);
    4.85  				must_redraw = true;
    4.86  			}
    4.87  			break;
    4.88  
    4.89  		case KEY_RIGHT:
    4.90  			if(cursor < (int)input.size()) {
    4.91 -				++cursor;
    4.92 +				set_cursor(get_cursor() + 1);
    4.93  				must_redraw = true;
    4.94  			}
    4.95  			break;
    4.96  
    4.97  		case KEY_HOME:
    4.98 -			cursor = 0;
    4.99 +			set_cursor(0);
   4.100  			must_redraw = true;
   4.101  			break;
   4.102  
   4.103  		case KEY_END:
   4.104 -			cursor = input.size();
   4.105 +			set_cursor(input.size());
   4.106  			must_redraw = true;
   4.107  			break;
   4.108  
   4.109 @@ -178,7 +200,7 @@
   4.110  				} else {
   4.111  					input.insert(cursor, 1, c);
   4.112  				}
   4.113 -				++cursor;
   4.114 +				set_cursor(get_cursor() + 1);
   4.115  				must_redraw = true;
   4.116  			}
   4.117  		}
   4.118 @@ -202,7 +224,7 @@
   4.119  	glMatrixMode(GL_MODELVIEW);
   4.120  	glPushMatrix();
   4.121  	glLoadIdentity();
   4.122 -	glTranslatef(0, vp[3] - vp[1], 0);
   4.123 +	glTranslatef(0, vp[3], 0);
   4.124  
   4.125  	std::string buflines;
   4.126  
   4.127 @@ -215,18 +237,22 @@
   4.128  		const std::string &line = *it++;
   4.129  		buflines += line + std::string("\n");
   4.130  
   4.131 -		max_width = std::max(max_width, dtx_string_width(line.c_str()));
   4.132 +		//max_width = std::max(max_width, dtx_string_width(line.c_str()));
   4.133  	}
   4.134  
   4.135  	// draw the output box
   4.136  	float line_height = dtx_line_height();
   4.137  	float outbox_height = nlines * line_height;
   4.138 +	float console_height = outbox_height + line_height * 1.5;
   4.139  
   4.140  	glPushAttrib(GL_ENABLE_BIT);
   4.141  	glEnable(GL_BLEND);
   4.142  	glDisable(GL_TEXTURE_2D);
   4.143  	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   4.144  
   4.145 +	glEnable(GL_SCISSOR_TEST);
   4.146 +	glScissor(0, vp[3] - console_height, max_width, console_height);
   4.147 +
   4.148  	glBegin(GL_QUADS);
   4.149  	glColor4f(0.1, 0.2, 0.5, 0.7);
   4.150  	glVertex2f(0, -outbox_height);
   4.151 @@ -235,8 +261,8 @@
   4.152  	glVertex2f(0, 0);
   4.153  
   4.154  	glColor4f(0.5, 0.2, 0.1, 0.7);
   4.155 -	glVertex2f(0, -(outbox_height + line_height * 1.5));
   4.156 -	glVertex2f(max_width, -(outbox_height + line_height * 1.5));
   4.157 +	glVertex2f(0, -console_height);
   4.158 +	glVertex2f(max_width, -console_height);
   4.159  	glVertex2f(max_width, -outbox_height);
   4.160  	glVertex2f(0, -outbox_height);
   4.161  	glEnd();
   4.162 @@ -251,11 +277,11 @@
   4.163  	// draw the input line
   4.164  	glTranslatef(0, -outbox_height - line_height, 0);
   4.165  
   4.166 -	std::string inpline = std::string("> ") + input;
   4.167 +	std::string inpline = prompt + input.substr(input_win);
   4.168  	dtx_string(inpline.c_str());
   4.169  	glDisable(GL_TEXTURE_2D);
   4.170  
   4.171 -	float cursor_x = dtx_char_pos(inpline.c_str(), cursor + 2);
   4.172 +	float cursor_x = dtx_char_pos(inpline.c_str(), cursor - input_win + prompt.size());
   4.173  	glBegin(GL_QUADS);
   4.174  	glColor4f(1, 1, 1, 0.7);
   4.175  	glVertex2f(cursor_x, 0);
     5.1 --- a/src/console.h	Tue Jun 10 10:53:19 2014 +0300
     5.2 +++ b/src/console.h	Tue Jun 10 12:28:56 2014 +0300
     5.3 @@ -17,8 +17,10 @@
     5.4  	int inpq_front, inpq_back;
     5.5  	int keybuf[INPUTQ_SIZE];
     5.6  
     5.7 +	std::string prompt;
     5.8  	std::string input;	// current input line
     5.9  	int cursor;
    5.10 +	int input_win;		// first character to show in the input "window"
    5.11  
    5.12  	// input history
    5.13  	int max_hist_lines;
    5.14 @@ -34,6 +36,9 @@
    5.15  	int font_size;
    5.16  	dtx_font *font;
    5.17  
    5.18 +	void set_cursor(int x);
    5.19 +	int get_cursor() const;
    5.20 +
    5.21  public:
    5.22  	enum {
    5.23  		KEY_LEFT = 256,
     6.1 --- a/src/main.cc	Tue Jun 10 10:53:19 2014 +0300
     6.2 +++ b/src/main.cc	Tue Jun 10 12:28:56 2014 +0300
     6.3 @@ -148,8 +148,7 @@
     6.4  
     6.5  static void begin_frame(long tm)
     6.6  {
     6.7 -	printf("rendering frame (t=%ld) ... ", tm);
     6.8 -	fflush(stdout);
     6.9 +	printf("rendering frame (t=%ld) ...\n", tm);
    6.10  
    6.11  	render_pending = true;
    6.12  	glutIdleFunc(idle);
    6.13 @@ -167,7 +166,7 @@
    6.14  	long msec, sec, min, hr, days;
    6.15  
    6.16  	msec = full_msec;
    6.17 -	printf("done in ");
    6.18 +	con.printf("done in ");
    6.19  	if((sec = msec / 1000) > 0) {
    6.20  		msec %= 1000;
    6.21  		if((min = sec / 60) > 0) {
    6.22 @@ -176,15 +175,15 @@
    6.23  				min %= 60;
    6.24  				if((days = hr / 24) > 0) {
    6.25  					hr %= 24;
    6.26 -					printf("%ld days ", days);
    6.27 +					con.printf("%ld days ", days);
    6.28  				}
    6.29 -				printf("%ld hours ", hr);
    6.30 +				con.printf("%ld hours ", hr);
    6.31  			}
    6.32 -			printf("%ld min ", min);
    6.33 +			con.printf("%ld min ", min);
    6.34  		}
    6.35 -		printf("%ld sec ", sec);
    6.36 +		con.printf("%ld sec ", sec);
    6.37  	}
    6.38 -	printf("%ld ms (%ld total msec)\n", msec, full_msec);
    6.39 +	con.printf("%ld ms (%ld total msec)\n", msec, full_msec);
    6.40  
    6.41  	render_pending = false;
    6.42  	glutIdleFunc(0);
    6.43 @@ -194,44 +193,51 @@
    6.44  {
    6.45  	static unsigned char *defpix;
    6.46  
    6.47 +	if(render_pending) {
    6.48 +		erb_end_frame(erb);
    6.49 +	}
    6.50 +
    6.51  	win_width = xsz;
    6.52  	win_height = ysz;
    6.53  
    6.54  	width = xsz / opt_imgscale;
    6.55  	height = ysz / opt_imgscale;
    6.56  
    6.57 -	if(width <= rtex_width && height <= rtex_height) {
    6.58 -		return;
    6.59 -	}
    6.60 -	rtex_width = next_pow2(width);
    6.61 -	rtex_height = next_pow2(height);
    6.62 +	if(width > rtex_width || height > rtex_height) {
    6.63 +		rtex_width = next_pow2(width);
    6.64 +		rtex_height = next_pow2(height);
    6.65  
    6.66 -	printf("resizing framebuffer texture: %dx%d\n", rtex_width, rtex_height);
    6.67 +		printf("resizing framebuffer texture: %dx%d\n", rtex_width, rtex_height);
    6.68  
    6.69 -	if(!rtex) {
    6.70 -		glGenTextures(1, &rtex);
    6.71 +		if(!rtex) {
    6.72 +			glGenTextures(1, &rtex);
    6.73 +		}
    6.74 +
    6.75 +		delete [] defpix;
    6.76 +		defpix = new unsigned char[rtex_width * rtex_height * 4];
    6.77 +		unsigned char *ptr = defpix;
    6.78 +		for(int i=0; i<rtex_height; i++) {
    6.79 +			for(int j=0; j<rtex_width; j++) {
    6.80 +				bool chess = ((i >> 4) & 1) == ((j >> 4) & 1);
    6.81 +
    6.82 +				int val = chess ? 64 : 48;
    6.83 +
    6.84 +				*ptr++ = val;
    6.85 +				*ptr++ = val;
    6.86 +				*ptr++ = val;
    6.87 +				*ptr++ = 255;
    6.88 +			}
    6.89 +		}
    6.90 +
    6.91 +		glBindTexture(GL_TEXTURE_2D, rtex);
    6.92 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    6.93 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    6.94 +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, rtex_width, rtex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, defpix);
    6.95  	}
    6.96  
    6.97 -	delete [] defpix;
    6.98 -	defpix = new unsigned char[rtex_width * rtex_height * 4];
    6.99 -	unsigned char *ptr = defpix;
   6.100 -	for(int i=0; i<rtex_height; i++) {
   6.101 -		for(int j=0; j<rtex_width; j++) {
   6.102 -			bool chess = ((i >> 4) & 1) == ((j >> 4) & 1);
   6.103 -
   6.104 -			int val = chess ? 64 : 48;
   6.105 -
   6.106 -			*ptr++ = val;
   6.107 -			*ptr++ = val;
   6.108 -			*ptr++ = val;
   6.109 -			*ptr++ = 255;
   6.110 -		}
   6.111 +	if(render_pending) {
   6.112 +		begin_frame(0);
   6.113  	}
   6.114 -
   6.115 -	glBindTexture(GL_TEXTURE_2D, rtex);
   6.116 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   6.117 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   6.118 -	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, rtex_width, rtex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, defpix);
   6.119  }
   6.120  
   6.121  static void update_rect(int x, int y, int xsz, int ysz, float *pixels)
   6.122 @@ -613,6 +619,14 @@
   6.123  		}
   6.124  		begin_frame(tm);
   6.125  
   6.126 +	} else if(strcmp(args[0], "samples") == 0) {
   6.127 +		if(args[1] && (opt_samples = atoi(args[1]))) {
   6.128 +			erb_setopti(erb, ERB_OPT_MAX_SAMPLES, opt_samples);
   6.129 +			con.printf("max samples is now %d\n", opt_samples);
   6.130 +		} else {
   6.131 +			con.printf("invalid samples command: %s\n", line);
   6.132 +		}
   6.133 +
   6.134  	} else if(strcmp(args[0], "load") == 0) {
   6.135  		for(int i=1; i<argc; i++) {
   6.136  			if(erb_load_scene(erb, args[i]) == -1) {
   6.137 @@ -629,6 +643,15 @@
   6.138  			begin_frame(0);
   6.139  		}
   6.140  
   6.141 +	} else if(strcmp(args[0], "help") == 0) {
   6.142 +		con.printf("Available commands:\n");
   6.143 +		con.printf("render [anim time]    begins rendering a frame with the given time (default: 0)\n");
   6.144 +		con.printf("stop                  stops rendering\n");
   6.145 +		con.printf("samples <count>       sets the maximum number of samples per pixel\n");
   6.146 +		con.printf("iter <count>          sets the maximum number of ray bounces\n");
   6.147 +		con.printf("load <filename>       loads a scene file\n");
   6.148 +		con.printf("add <object command>  adds another object to the scene. For valid object commands see test/scene\n");
   6.149 +
   6.150  	} else {
   6.151  		con.printf("unrecognized command: %s\n", args[0]);
   6.152  	}