rayzor

changeset 17:79609d482762

the renderer renders, also fixed an unnoticed matrix conversion problem between scenegraph and min3d
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 14 Apr 2014 07:34:45 +0300
parents 4d87b0aafbb0
children 859ccadca671
files Makefile src/camera.cc src/camera.h src/light.cc src/light.h src/main.cc src/material.h src/min3d.c src/min3d.h src/modeller.cc src/object.cc src/object.h src/raytrace.cc src/raytrace.h src/renderer.cc src/renderer.h src/scancode.h src/scene.cc src/scene.h src/screen.cc src/screen.h src/snode.cc src/snode.h src/vmath.cc src/vmath.h src/vmathmat.h
diffstat 26 files changed, 477 insertions(+), 56 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Sun Apr 13 09:54:51 2014 +0300
     1.2 +++ b/Makefile	Mon Apr 14 07:34:45 2014 +0300
     1.3 @@ -1,6 +1,6 @@
     1.4  baseobj = main.obj logger.obj screen.obj scrman.obj swapbuf.obj rbtree.obj
     1.5  modelobj = modeller.obj min3d.obj m3drast.obj lines.obj
     1.6 -rendobj = renderer.obj vmath.obj
     1.7 +rendobj = renderer.obj vmath.obj raytrace.obj
     1.8  scnobj = scene.obj object.obj light.obj camera.obj snode.obj
     1.9  sysobj = gfx.obj vbe.obj dpmi.obj timer.obj mouse.obj keyb.obj
    1.10  obj = $(baseobj) $(modelobj) $(rendobj) $(scnobj) $(sysobj)
     2.1 --- a/src/camera.cc	Sun Apr 13 09:54:51 2014 +0300
     2.2 +++ b/src/camera.cc	Mon Apr 14 07:34:45 2014 +0300
     2.3 @@ -41,7 +41,7 @@
     2.4  {
     2.5  }
     2.6  
     2.7 -bool Camera::intersect(const Ray &ray, float *dist) const
     2.8 +bool Camera::intersect(const Ray &ray, RayHit *hit) const
     2.9  {
    2.10  	return false;
    2.11  }
     3.1 --- a/src/camera.h	Sun Apr 13 09:54:51 2014 +0300
     3.2 +++ b/src/camera.h	Mon Apr 14 07:34:45 2014 +0300
     3.3 @@ -22,7 +22,7 @@
     3.4  
     3.5  	void draw() const;
     3.6  
     3.7 -	bool intersect(const Ray &ray, float *dist = 0) const;
     3.8 +	bool intersect(const Ray &ray, RayHit *hit = 0) const;
     3.9  
    3.10  	Ray get_primary_ray(int x, int y) const;
    3.11  };
     4.1 --- a/src/light.cc	Sun Apr 13 09:54:51 2014 +0300
     4.2 +++ b/src/light.cc	Mon Apr 14 07:34:45 2014 +0300
     4.3 @@ -3,12 +3,23 @@
     4.4  Light::Light()
     4.5  {
     4.6  	type = NODE_LIGHT;
     4.7 +	intens = 1.0;
     4.8  	color.x = color.y = color.z = 1.0;
     4.9  	atten.x = 1.0;
    4.10  	atten.y = 0.0;
    4.11  	atten.z = 0.0;
    4.12  }
    4.13  
    4.14 +void Light::set_intensity(float val)
    4.15 +{
    4.16 +	intens = val;
    4.17 +}
    4.18 +
    4.19 +float Light::get_intensity() const
    4.20 +{
    4.21 +	return intens;
    4.22 +}
    4.23 +
    4.24  void Light::set_color(const Vector3 &color)
    4.25  {
    4.26  	this->color = color;
    4.27 @@ -19,6 +30,11 @@
    4.28  	return color;
    4.29  }
    4.30  
    4.31 +Vector3 Light::get_color(const Vector3 &pt) const
    4.32 +{
    4.33 +	float d = (get_position() - pt).length();
    4.34 +	return color * calc_attenuation(d) * intens;
    4.35 +}
    4.36  
    4.37  void Light::set_attenuation(const Vector3 &atten)
    4.38  {
    4.39 @@ -30,11 +46,18 @@
    4.40  	return atten;
    4.41  }
    4.42  
    4.43 +float Light::calc_attenuation(float d) const
    4.44 +{
    4.45 +	float denom = atten.x + atten.y * d + atten.z * d * d;
    4.46 +	float at = denom == 0.0 ? 1.0 : 1.0 / denom;
    4.47 +	return at > 1.0 ? 1.0 : at;
    4.48 +}
    4.49 +
    4.50  void Light::draw() const
    4.51  {
    4.52  }
    4.53  
    4.54 -bool Light::intersect(const Ray &ray, float *dist)
    4.55 +bool Light::intersect(const Ray &ray, RayHit *hit) const
    4.56  {
    4.57 -	return false;
    4.58 +	return false;	// TODO
    4.59  }
     5.1 --- a/src/light.h	Sun Apr 13 09:54:51 2014 +0300
     5.2 +++ b/src/light.h	Mon Apr 14 07:34:45 2014 +0300
     5.3 @@ -6,21 +6,30 @@
     5.4  
     5.5  class Light : public SceneNode {
     5.6  private:
     5.7 +	float intens;
     5.8  	Vector3 color;
     5.9  	Vector3 atten;
    5.10  
    5.11  public:
    5.12  	Light();
    5.13  
    5.14 +	void set_intensity(float val);
    5.15 +	float get_intensity() const;
    5.16 +
    5.17  	void set_color(const Vector3 &color);
    5.18  	const Vector3 &get_color() const;
    5.19  
    5.20 +	// includes attenuation and intensity
    5.21 +	Vector3 get_color(const Vector3 &pt) const;
    5.22 +
    5.23  	void set_attenuation(const Vector3 &atten);
    5.24  	const Vector3 &get_attenuation() const;
    5.25  
    5.26 +	float calc_attenuation(float d) const;
    5.27 +
    5.28  	void draw() const;
    5.29  
    5.30 -	bool intersect(const Ray &ray, float *dist);
    5.31 +	bool intersect(const Ray &ray, RayHit *hit = 0) const;
    5.32  };
    5.33  
    5.34  #endif	// LIGHT_H_
     6.1 --- a/src/main.cc	Sun Apr 13 09:54:51 2014 +0300
     6.2 +++ b/src/main.cc	Mon Apr 14 07:34:45 2014 +0300
     6.3 @@ -3,6 +3,7 @@
     6.4  #include <string.h>
     6.5  #include <signal.h>
     6.6  #include <errno.h>
     6.7 +#include <float.h>
     6.8  #include <direct.h>
     6.9  #include "inttypes.h"
    6.10  #include "gfx.h"
    6.11 @@ -102,6 +103,9 @@
    6.12  	signal(SIGILL, sig);
    6.13  	signal(SIGFPE, sig);
    6.14  
    6.15 +	// mask all fpe except invalid op
    6.16 +	_control87(~_EM_INVALID, _MCW_EM);
    6.17 +
    6.18  	init_timer(128);
    6.19  
    6.20  	if(!novideo) {
    6.21 @@ -144,11 +148,21 @@
    6.22  	scene = new Scene;
    6.23  
    6.24  	Sphere *sph = new Sphere;
    6.25 +	sph->mtl.diffuse = Vector3(1.0, 0.3, 0.1);
    6.26 +	sph->mtl.roughness = 0.4;
    6.27  	scene->add(sph);
    6.28  
    6.29  	Box *box = new Box;
    6.30 +	box->mtl.diffuse = Vector3(0.1, 0.4, 1.0);
    6.31 +	box->mtl.roughness = 0.9;
    6.32 +	box->set_position(Vector3(0, -1.1, 0));
    6.33 +	box->set_scaling(Vector3(4, 0.1, 4));
    6.34  	scene->add(box);
    6.35 -	box->set_scaling(Vector3(2, 0.25, 2));
    6.36 +
    6.37 +	Light *lt = new Light;
    6.38 +	lt->set_intensity(0.8);
    6.39 +	lt->set_position(Vector3(-10, 10, 10));
    6.40 +	scene->add(lt);
    6.41  
    6.42  	Modeller *modeller = new Modeller;
    6.43  	if(!modeller->init()) {
    6.44 @@ -322,7 +336,7 @@
    6.45  		return;
    6.46  	}
    6.47  
    6.48 -	fprintf(fp, "P6\n" PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height);
    6.49 +	fprintf(fp, "P6\n# " PPM_COMMENT "\n%d %d\n255\n", fb_width, fb_height);
    6.50  	for(int i=0; i<fb_width * fb_height; i++) {
    6.51  		uint32_t c = fb_pixels[i];
    6.52  		fputc(UNPACK_RED(c), fp);
    6.53 @@ -353,7 +367,6 @@
    6.54  			}
    6.55  			break;
    6.56  
    6.57 -		case KB_SYSRQ:
    6.58  		case KB_F12:
    6.59  			cap_shot = true;
    6.60  			break;
    6.61 @@ -467,5 +480,11 @@
    6.62  {
    6.63  	cleanup();
    6.64  	fprintf(stderr, "signal caught: %d\n", s);
    6.65 +
    6.66 +	if(s == SIGFPE) {
    6.67 +		unsigned int st = _status87();
    6.68 +		fprintf(stderr, "fpu status: %x\n", st);
    6.69 +	}
    6.70 +
    6.71  	exit(1);
    6.72  }
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/material.h	Mon Apr 14 07:34:45 2014 +0300
     7.3 @@ -0,0 +1,22 @@
     7.4 +#ifndef MATERIAL_H_
     7.5 +#define MATERIAL_H_
     7.6 +
     7.7 +#include "vmath.h"
     7.8 +
     7.9 +class Material {
    7.10 +public:
    7.11 +	Vector3 diffuse, specular;
    7.12 +	float roughness;
    7.13 +	float reflect, refract;
    7.14 +	float ior;
    7.15 +
    7.16 +	Material()
    7.17 +		: diffuse(0.75, 0.75, 0.75), specular(1, 1, 1)
    7.18 +	{
    7.19 +		roughness = 1.0;
    7.20 +		reflect = refract = 0.0;
    7.21 +		ior = 1.0;
    7.22 +	}
    7.23 +};
    7.24 +
    7.25 +#endif	// MATERIAL_H_
     8.1 --- a/src/min3d.c	Sun Apr 13 09:54:51 2014 +0300
     8.2 +++ b/src/min3d.c	Mon Apr 14 07:34:45 2014 +0300
     8.3 @@ -126,6 +126,19 @@
     8.4  	memcpy(m3dctx->mstack[m3dctx->mmode].m[top], m, 16 * sizeof *m);
     8.5  }
     8.6  
     8.7 +void m3d_load_transpose_matrix(const float *m)
     8.8 +{
     8.9 +	int i, j, lin = 0;
    8.10 +	int top = m3dctx->mstack[m3dctx->mmode].top;
    8.11 +	float *dest = m3dctx->mstack[m3dctx->mmode].m[top];
    8.12 +
    8.13 +	for(i=0; i<4; i++) {
    8.14 +		for(j=0; j<4; j++) {
    8.15 +			*dest++ = m[j * 4 + i];
    8.16 +		}
    8.17 +	}
    8.18 +}
    8.19 +
    8.20  #define M(i,j)	(((i) << 2) + (j))
    8.21  void m3d_mult_matrix(const float *m2)
    8.22  {
    8.23 @@ -137,7 +150,7 @@
    8.24  
    8.25  	for(i=0; i<4; i++) {
    8.26  		for(j=0; j<4; j++) {
    8.27 -			dest[M(i,j)] = m1[M(0,j)] * m2[M(i,0)] +
    8.28 +			*dest++ = m1[M(0,j)] * m2[M(i,0)] +
    8.29  				m1[M(1,j)] * m2[M(i,1)] +
    8.30  				m1[M(2,j)] * m2[M(i,2)] +
    8.31  				m1[M(3,j)] * m2[M(i,3)];
    8.32 @@ -145,6 +158,24 @@
    8.33  	}
    8.34  }
    8.35  
    8.36 +void m3d_mult_transpose_matrix(const float *m2)
    8.37 +{
    8.38 +	int i, j, top = m3dctx->mstack[m3dctx->mmode].top;
    8.39 +	float m1[16];
    8.40 +	float *dest = m3dctx->mstack[m3dctx->mmode].m[top];
    8.41 +
    8.42 +	memcpy(m1, dest, sizeof m1);
    8.43 +
    8.44 +	for(i=0; i<4; i++) {
    8.45 +		for(j=0; j<4; j++) {
    8.46 +			*dest++ = m1[M(0,j)] * m2[M(0,i)] +
    8.47 +				m1[M(1,j)] * m2[M(1,i)] +
    8.48 +				m1[M(2,j)] * m2[M(2,i)] +
    8.49 +				m1[M(3,j)] * m2[M(3,i)];
    8.50 +		}
    8.51 +	}
    8.52 +}
    8.53 +
    8.54  void m3d_translate(float x, float y, float z)
    8.55  {
    8.56  	float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
     9.1 --- a/src/min3d.h	Sun Apr 13 09:54:51 2014 +0300
     9.2 +++ b/src/min3d.h	Mon Apr 14 07:34:45 2014 +0300
     9.3 @@ -61,7 +61,9 @@
     9.4  void m3d_pop_matrix(void);
     9.5  void m3d_load_identity(void);
     9.6  void m3d_load_matrix(const float *m);
     9.7 +void m3d_load_transpose_matrix(const float *m);
     9.8  void m3d_mult_matrix(const float *m);
     9.9 +void m3d_mult_transpose_matrix(const float *m);
    9.10  void m3d_translate(float x, float y, float z);
    9.11  void m3d_rotate(float angle, float x, float y, float z);
    9.12  void m3d_scale(float x, float y, float z);
    10.1 --- a/src/modeller.cc	Sun Apr 13 09:54:51 2014 +0300
    10.2 +++ b/src/modeller.cc	Mon Apr 14 07:34:45 2014 +0300
    10.3 @@ -11,7 +11,7 @@
    10.4  
    10.5  struct ModellerImpl {
    10.6  	int mx, my;
    10.7 -	float cam_theta, cam_phi, cam_dist;
    10.8 +	float cam_theta, cam_phi, cam_dist, cam_fov;
    10.9  	Camera *viewport_cam;
   10.10  
   10.11  	struct m3d_image rbuf;
   10.12 @@ -41,6 +41,7 @@
   10.13  
   10.14  	mod->cam_phi = 25;
   10.15  	mod->cam_dist = 5;
   10.16 +	mod->cam_fov = 50.0;
   10.17  
   10.18  	m3d_init();
   10.19  	mod->rbuf.pixels = fb_pixels;
   10.20 @@ -50,7 +51,7 @@
   10.21  
   10.22  	m3d_matrix_mode(M3D_PROJECTION);
   10.23  	m3d_load_identity();
   10.24 -	m3d_perspective(50.0, (float)fb_width / (float)fb_height, 0.5, 500.0);
   10.25 +	m3d_perspective(mod->cam_fov, (float)fb_width / (float)fb_height, 0.5, 500.0);
   10.26  
   10.27  	m3d_enable(M3D_CULL_FACE);
   10.28  	return true;
   10.29 @@ -155,11 +156,14 @@
   10.30  							scene->set_active_camera(mod->viewport_cam);
   10.31  						}
   10.32  						Vector3 dir;
   10.33 -						dir.x = sin(DEG2RAD(mod->cam_theta)) * cos(DEG2RAD(mod->cam_phi)) * mod->cam_dist;
   10.34 -						dir.y = sin(DEG2RAD(mod->cam_phi));
   10.35 -						dir.z = cos(DEG2RAD(mod->cam_theta)) * cos(DEG2RAD(mod->cam_phi)) * mod->cam_dist;
   10.36 +						float theta = -DEG2RAD(mod->cam_theta);
   10.37 +						float phi = DEG2RAD(mod->cam_phi);
   10.38 +						dir.x = sin(theta) * cos(phi) * mod->cam_dist;
   10.39 +						dir.y = sin(phi) * mod->cam_dist;
   10.40 +						dir.z = cos(theta) * cos(phi) * mod->cam_dist;
   10.41  						mod->viewport_cam->set_position(dir);
   10.42  						mod->viewport_cam->set_target(Vector3(0, 0, 0));
   10.43 +						mod->viewport_cam->set_fov(DEG2RAD(mod->cam_fov));
   10.44  
   10.45  						rs->message(message_atom("start"));
   10.46  					}
    11.1 --- a/src/object.cc	Sun Apr 13 09:54:51 2014 +0300
    11.2 +++ b/src/object.cc	Mon Apr 14 07:34:45 2014 +0300
    11.3 @@ -13,6 +13,11 @@
    11.4  {
    11.5  }
    11.6  
    11.7 +Vector3 Object::hit_normal(const RayHit &hit) const
    11.8 +{
    11.9 +	return Vector3(0, 0, 0);
   11.10 +}
   11.11 +
   11.12  // ---- sphere ----
   11.13  Sphere::Sphere()
   11.14  {
   11.15 @@ -83,7 +88,7 @@
   11.16  	post_draw();
   11.17  }
   11.18  
   11.19 -bool Sphere::intersect(const Ray &wray, float *dist) const
   11.20 +bool Sphere::intersect(const Ray &wray, RayHit *hit) const
   11.21  {
   11.22  	Ray ray = transform(get_inv_matrix(), wray);
   11.23  
   11.24 @@ -111,10 +116,21 @@
   11.25  	if(t < 1e-4)
   11.26  		return false;
   11.27  
   11.28 -	if(dist) *dist = t;
   11.29 +	if(hit) {
   11.30 +		hit->ray = wray;
   11.31 +		hit->lray = ray;
   11.32 +		hit->dist = t;
   11.33 +		hit->obj = this;
   11.34 +		hit->subobj = 0;
   11.35 +	}
   11.36  	return true;
   11.37  }
   11.38  
   11.39 +Vector3 Sphere::hit_normal(const RayHit &hit) const
   11.40 +{
   11.41 +	return hit.lray.origin + hit.lray.dir * hit.dist;
   11.42 +}
   11.43 +
   11.44  // ---- box ----
   11.45  
   11.46  Box::Box()
   11.47 @@ -165,7 +181,57 @@
   11.48  	post_draw();
   11.49  }
   11.50  
   11.51 -bool Box::intersect(const Ray &ray, float *dist) const
   11.52 +bool Box::intersect(const Ray &wray, RayHit *hit) const
   11.53  {
   11.54 -	return false;	// TODO
   11.55 +	Ray ray = transform(get_inv_matrix(), wray);
   11.56 +
   11.57 +	Vector3 param[2] = { Vector3(-1, -1, -1), Vector3(1, 1, 1) };
   11.58 +	Vector3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
   11.59 +	int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
   11.60 +
   11.61 +	float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
   11.62 +	float tmax = (param[1 - sign[0]].x - ray.origin.x) * inv_dir.x;
   11.63 +	float tymin = (param[sign[1]].y - ray.origin.y) * inv_dir.y;
   11.64 +	float tymax = (param[1 - sign[1]].y - ray.origin.y) * inv_dir.y;
   11.65 +
   11.66 +	if(tmin > tymax || tymin > tmax) {
   11.67 +		return false;
   11.68 +	}
   11.69 +	if(tymin > tmin) tmin = tymin;
   11.70 +	if(tymax < tmax) tmax = tymax;
   11.71 +
   11.72 +	float tzmin = (param[sign[2]].z - ray.origin.z) * inv_dir.z;
   11.73 +	float tzmax = (param[1 - sign[2]].z - ray.origin.z) * inv_dir.z;
   11.74 +
   11.75 +	if(tmin > tzmax || tzmin > tmax) {
   11.76 +		return false;
   11.77 +	}
   11.78 +	if(tzmin > tmin) tmin = tzmin;
   11.79 +	if(tzmax < tmax) tmax = tzmax;
   11.80 +
   11.81 +	float t = tmin < 1e-4 ? tmax : tmin;
   11.82 +	if(t >= 1e-4) {
   11.83 +		if(hit) {
   11.84 +			hit->dist = t;
   11.85 +			hit->ray = wray;
   11.86 +			hit->lray = ray;
   11.87 +			hit->obj = this;
   11.88 +			hit->subobj = 0;
   11.89 +		}
   11.90 +		return true;
   11.91 +	}
   11.92 +	return false;
   11.93  }
   11.94 +
   11.95 +Vector3 Box::hit_normal(const RayHit &hit) const
   11.96 +{
   11.97 +	Vector3 lpt = hit.lray.origin + hit.lray.dir * hit.dist;
   11.98 +
   11.99 +	if(fabs(lpt.x) > fabs(lpt.y) && fabs(lpt.x) > fabs(lpt.z)) {
  11.100 +		return Vector3(lpt.x, 0, 0);
  11.101 +	}
  11.102 +	if(fabs(lpt.y) > fabs(lpt.z)) {
  11.103 +		return Vector3(0, lpt.y, 0);
  11.104 +	}
  11.105 +	return Vector3(0, 0, lpt.z);
  11.106 +}
    12.1 --- a/src/object.h	Sun Apr 13 09:54:51 2014 +0300
    12.2 +++ b/src/object.h	Mon Apr 14 07:34:45 2014 +0300
    12.3 @@ -3,11 +3,16 @@
    12.4  
    12.5  #include "vmath.h"
    12.6  #include "snode.h"
    12.7 +#include "material.h"
    12.8  
    12.9  class Object : public SceneNode {
   12.10  public:
   12.11 +	Material mtl;
   12.12 +
   12.13  	Object();
   12.14  	virtual ~Object();
   12.15 +
   12.16 +	virtual Vector3 hit_normal(const RayHit &hit) const;
   12.17  };
   12.18  
   12.19  class Sphere : public Object {
   12.20 @@ -17,7 +22,8 @@
   12.21  
   12.22  	void draw(bool emph = false) const;
   12.23  
   12.24 -	bool intersect(const Ray &ray, float *dist = 0) const;
   12.25 +	bool intersect(const Ray &ray, RayHit *hit = 0) const;
   12.26 +	Vector3 hit_normal(const RayHit &hit) const;
   12.27  };
   12.28  
   12.29  class Box : public Object {
   12.30 @@ -27,7 +33,8 @@
   12.31  
   12.32  	void draw(bool emph = false) const;
   12.33  
   12.34 -	bool intersect(const Ray &ray, float *dist = 0) const;
   12.35 +	bool intersect(const Ray &ray, RayHit *hit = 0) const;
   12.36 +	Vector3 hit_normal(const RayHit &hit) const;
   12.37  };
   12.38  
   12.39  #endif	// OBJECT_H_
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/raytrace.cc	Mon Apr 14 07:34:45 2014 +0300
    13.3 @@ -0,0 +1,58 @@
    13.4 +#include <assert.h>
    13.5 +#include <float.h>
    13.6 +#include "raytrace.h"
    13.7 +#include "rayzor.h"
    13.8 +#include "scene.h"
    13.9 +#include "logger.h"
   13.10 +
   13.11 +Vector3 ray_trace(const Ray &ray, int iter)
   13.12 +{
   13.13 +	RayHit hit;
   13.14 +	if(!scene->intersect(ray, &hit)) {
   13.15 +		return scene->get_background(ray);
   13.16 +	}
   13.17 +
   13.18 +	return shade(hit, iter);
   13.19 +}
   13.20 +
   13.21 +static inline float positive(float x)
   13.22 +{
   13.23 +	return x < 0.0f ? 0.0f : x;
   13.24 +}
   13.25 +
   13.26 +Vector3 shade(const RayHit &hit, int iter)
   13.27 +{
   13.28 +	Vector3 pos = hit.ray.origin + hit.ray.dir * hit.dist;
   13.29 +	Vector3 norm = hit.obj->hit_normal(hit);
   13.30 +	norm = normalize(transform(normal_matrix(hit.obj->get_matrix()), norm));
   13.31 +	Vector3 vdir = -normalize(hit.ray.dir);
   13.32 +
   13.33 +	Vector3 color = scene->get_ambient();
   13.34 +
   13.35 +	const Vector3 &kd = hit.obj->mtl.diffuse;
   13.36 +	const Vector3 &ks = hit.obj->mtl.specular;
   13.37 +	float roughness = hit.obj->mtl.roughness;
   13.38 +
   13.39 +	int num_lights = scene->get_light_count();
   13.40 +	for(int i=0; i<num_lights; i++) {
   13.41 +		const Light *lt = scene->get_light(i);
   13.42 +		Vector3 ldir = lt->get_position() - pos;
   13.43 +		Vector3 lcol = lt->get_color(pos);
   13.44 +
   13.45 +		RayHit hit;
   13.46 +		if(!scene->intersect(Ray(pos, ldir), &hit) || hit.dist > 1.0) {
   13.47 +			// if we can see the light, calculate and add its contribution
   13.48 +			ldir.normalize();
   13.49 +			float ndotl = positive(dot(norm, ldir));
   13.50 +			Vector3 diffuse = kd * lcol * ndotl;
   13.51 +
   13.52 +			Vector3 hdir = normalize(ldir + vdir);
   13.53 +			float ndoth = positive(dot(norm, hdir));
   13.54 +			Vector3 specular = ks * lcol * pow(ndoth, roughness * 128.0);
   13.55 +
   13.56 +			color = color + lerp(specular, diffuse, roughness);
   13.57 +		}
   13.58 +	}
   13.59 +
   13.60 +	return color;
   13.61 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/raytrace.h	Mon Apr 14 07:34:45 2014 +0300
    14.3 @@ -0,0 +1,20 @@
    14.4 +#ifndef RAYTRACE_H_
    14.5 +#define RAYTRACE_H_
    14.6 +
    14.7 +#include "vmath.h"
    14.8 +#include "vmathray.h"
    14.9 +
   14.10 +class Object;
   14.11 +
   14.12 +struct RayHit {
   14.13 +	Ray ray;			// the ray in world coordinates
   14.14 +	Ray lray;			// the local coordinate system ray
   14.15 +	float dist;			// parametric distance along the ray
   14.16 +	const Object *obj;	// pointer to the object that has been hit
   14.17 +	const void *subobj;	// object-specific subobject pointer (can be null).
   14.18 +};
   14.19 +
   14.20 +Vector3 ray_trace(const Ray &ray, int iter = 0);
   14.21 +Vector3 shade(const RayHit &hit, int iter);
   14.22 +
   14.23 +#endif	// RAYTRACE_H_
    15.1 --- a/src/renderer.cc	Sun Apr 13 09:54:51 2014 +0300
    15.2 +++ b/src/renderer.cc	Mon Apr 14 07:34:45 2014 +0300
    15.3 @@ -1,4 +1,5 @@
    15.4  #include <string.h>
    15.5 +#include <stdarg.h>
    15.6  #include "renderer.h"
    15.7  #include "rayzor.h"
    15.8  #include "scene.h"
    15.9 @@ -6,6 +7,15 @@
   15.10  #include "scrman.h"
   15.11  #include "timer.h"
   15.12  #include "logger.h"
   15.13 +#include "raytrace.h"
   15.14 +
   15.15 +enum {
   15.16 +	MSG_START,
   15.17 +	MSG_GAMMA,
   15.18 +	MSG_USE_GAMMA,
   15.19 +
   15.20 +	NUM_MESSAGES
   15.21 +};
   15.22  
   15.23  struct RendererImpl {
   15.24  	bool in_progress;
   15.25 @@ -13,14 +23,13 @@
   15.26  
   15.27  	uint32_t *pixels;
   15.28  
   15.29 -	MsgAtom msg_start;
   15.30 +	float gamma, inv_gamma;
   15.31 +	bool use_gamma;
   15.32 +
   15.33 +	MsgAtom msg[NUM_MESSAGES];
   15.34  };
   15.35  
   15.36  
   15.37 -static Vector3 ray_trace(const Ray &ray, int iter = 0);
   15.38 -static Vector3 shade(const Ray &ray, float t, int iter);
   15.39 -
   15.40 -
   15.41  Renderer::Renderer()
   15.42  {
   15.43  	set_name("renderer");
   15.44 @@ -37,7 +46,13 @@
   15.45  	}
   15.46  	memset(rend->pixels, 0, fb_width * fb_height * 4);
   15.47  
   15.48 -	rend->msg_start = message_atom("start");
   15.49 +	rend->gamma = 1.8;
   15.50 +	rend->inv_gamma = 1.0 / rend->gamma;
   15.51 +	rend->use_gamma = true;
   15.52 +
   15.53 +	rend->msg[MSG_START] = message_atom("start");
   15.54 +	rend->msg[MSG_GAMMA] = message_atom("gamma");
   15.55 +	rend->msg[MSG_USE_GAMMA] = message_atom("use-gamma");
   15.56  
   15.57  	return true;
   15.58  }
   15.59 @@ -69,6 +84,13 @@
   15.60  		Ray ray = cam->get_primary_ray(rend->cur_x, rend->cur_y);
   15.61  		Vector3 color = ray_trace(ray);
   15.62  
   15.63 +		// gamma-correct before storing the pixel
   15.64 +		if(rend->use_gamma) {
   15.65 +			color.x = pow(color.x, rend->inv_gamma);
   15.66 +			color.y = pow(color.y, rend->inv_gamma);
   15.67 +			color.z = pow(color.z, rend->inv_gamma);
   15.68 +		}
   15.69 +
   15.70  		int r = color.x > 1.0 ? 255 : (int)(color.x * 255.0);
   15.71  		int g = color.y > 1.0 ? 255 : (int)(color.y * 255.0);
   15.72  		int b = color.z > 1.0 ? 255 : (int)(color.z * 255.0);
   15.73 @@ -104,24 +126,33 @@
   15.74  	}
   15.75  }
   15.76  
   15.77 -void Renderer::message(MsgAtom msg)
   15.78 +void Renderer::message(MsgAtom msg, ...)
   15.79  {
   15.80 -	if(msg == rend->msg_start) {
   15.81 -		rend->cur_x = rend->cur_y = 0;
   15.82 -		rend->in_progress = true;
   15.83 -		memset(rend->pixels, 0, fb_width * fb_height * 4);
   15.84 +	va_list ap;
   15.85 +	va_start(ap, msg);
   15.86  
   15.87 -		printlog("starting a new rendering!\n");
   15.88 +	for(int i=0; i<NUM_MESSAGES; i++) {
   15.89 +		if(msg == rend->msg[i]) {
   15.90 +			switch(i) {
   15.91 +			case MSG_START:
   15.92 +				rend->cur_x = rend->cur_y = 0;
   15.93 +				rend->in_progress = true;
   15.94 +				memset(rend->pixels, 0, fb_width * fb_height * 4);
   15.95 +
   15.96 +				printlog("starting a new rendering!\n");
   15.97 +				break;
   15.98 +
   15.99 +			case MSG_GAMMA:
  15.100 +				rend->gamma = va_arg(ap, float);
  15.101 +				rend->inv_gamma = 1.0 / rend->gamma;
  15.102 +				break;
  15.103 +
  15.104 +			case MSG_USE_GAMMA:
  15.105 +				rend->use_gamma = va_arg(ap, bool);
  15.106 +				break;
  15.107 +			}
  15.108 +		}
  15.109  	}
  15.110 +
  15.111 +	va_end(ap);
  15.112  }
  15.113 -
  15.114 -
  15.115 -static Vector3 ray_trace(const Ray &ray, int iter)
  15.116 -{
  15.117 -	return shade(ray, 0, iter);
  15.118 -}
  15.119 -
  15.120 -static Vector3 shade(const Ray &ray, float t, int iter)
  15.121 -{
  15.122 -	return Vector3(1.0, 0.0, 0.0);
  15.123 -}
    16.1 --- a/src/renderer.h	Sun Apr 13 09:54:51 2014 +0300
    16.2 +++ b/src/renderer.h	Mon Apr 14 07:34:45 2014 +0300
    16.3 @@ -19,7 +19,7 @@
    16.4  
    16.5  	void handle_keyboard(int key, bool press);
    16.6  
    16.7 -	void message(MsgAtom msg);
    16.8 +	void message(MsgAtom msg, ...);
    16.9  };
   16.10  
   16.11  #endif	// RENDERER_H_
    17.1 --- a/src/scancode.h	Sun Apr 13 09:54:51 2014 +0300
    17.2 +++ b/src/scancode.h	Mon Apr 14 07:34:45 2014 +0300
    17.3 @@ -8,9 +8,9 @@
    17.4  	'\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',			/* f - 1c */
    17.5  	KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',				/* 1d - 29 */
    17.6  	KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,			/* 2a - 36 */
    17.7 -	KB_NUM_KB_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,			/* 37 - 44 */
    17.8 -	KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_KB_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_KB_PLUS,	/* 45 - 4e */
    17.9 -	KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_KB_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,						/* 4d - 58 */
   17.10 +	KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,			/* 37 - 44 */
   17.11 +	KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,	/* 45 - 4e */
   17.12 +	KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,						/* 4d - 58 */
   17.13  	0, 0, 0, 0, 0, 0, 0,															/* 59 - 5f */
   17.14  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,									/* 60 - 6f */
   17.15  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0									/* 70 - 7f */
    18.1 --- a/src/scene.cc	Sun Apr 13 09:54:51 2014 +0300
    18.2 +++ b/src/scene.cc	Mon Apr 14 07:34:45 2014 +0300
    18.3 @@ -1,4 +1,5 @@
    18.4  #include <string.h>
    18.5 +#include <float.h>
    18.6  #include "scene.h"
    18.7  #include "min3d.h"
    18.8  
    18.9 @@ -6,6 +7,14 @@
   18.10  {
   18.11  	name = 0;
   18.12  	active_cam = 0;
   18.13 +
   18.14 +	fog_exp = 1.0;
   18.15 +
   18.16 +	set_ambient(Vector3(0.05, 0.05, 0.05));
   18.17 +
   18.18 +	set_background(Vector3(0.4, 0.3, 0.05), SCN_BG_LOW);
   18.19 +	set_background(Vector3(0.6, 0.6, 0.6), SCN_BG_MID);
   18.20 +	set_background(Vector3(0.1, 0.5, 1.0), SCN_BG_HIGH);
   18.21  }
   18.22  
   18.23  Scene::~Scene()
   18.24 @@ -41,6 +50,51 @@
   18.25  	return name ? name : "<unknown>";
   18.26  }
   18.27  
   18.28 +void Scene::set_background(const Vector3 &col, int idx)
   18.29 +{
   18.30 +	if(idx == -1) {
   18.31 +		bg[0] = bg[1] = bg[2] = col;
   18.32 +	} else {
   18.33 +		bg[idx] = col;
   18.34 +	}
   18.35 +}
   18.36 +
   18.37 +const Vector3 &Scene::get_background(int idx) const
   18.38 +{
   18.39 +	return bg[idx == -1 ? 0 : idx];
   18.40 +}
   18.41 +
   18.42 +#define LERP(a, b, t)	((a) + ((b) - (a)) * t)
   18.43 +
   18.44 +Vector3 Scene::get_background(const Ray &ray) const
   18.45 +{
   18.46 +	Vector3 dir = normalize(ray.dir);
   18.47 +
   18.48 +	float v;
   18.49 +	if(dir.z == 0.0) {
   18.50 +		v = dir.y > 0.0 ? 1.0 : -1.0;
   18.51 +	} else {
   18.52 +		float angle = atan2(dir.z, dir.y);
   18.53 +		v = angle / M_PI;
   18.54 +	}
   18.55 +
   18.56 +	float r = v >= 0.0 ? LERP(bg[1].x, bg[2].x, v) : LERP(bg[1].x, bg[0].x, -v);
   18.57 +	float g = v >= 0.0 ? LERP(bg[1].y, bg[2].y, v) : LERP(bg[1].y, bg[0].y, -v);
   18.58 +	float b = v >= 0.0 ? LERP(bg[1].z, bg[2].z, v) : LERP(bg[1].z, bg[0].z, -v);
   18.59 +	return Vector3(r, g, b);
   18.60 +}
   18.61 +
   18.62 +void Scene::set_ambient(const Vector3 &col)
   18.63 +{
   18.64 +	ambient = col;
   18.65 +}
   18.66 +
   18.67 +const Vector3 &Scene::get_ambient() const
   18.68 +{
   18.69 +	return ambient;
   18.70 +}
   18.71 +
   18.72 +
   18.73  void Scene::add(SceneNode *node)
   18.74  {
   18.75  	nodes.push_back(node);
   18.76 @@ -180,3 +234,23 @@
   18.77  {
   18.78  	return idx >= 0 && idx < (int)sel.size() ? sel[idx] : -1;
   18.79  }
   18.80 +
   18.81 +bool Scene::intersect(const Ray &ray, RayHit *hit) const
   18.82 +{
   18.83 +	if(hit) {
   18.84 +		hit->dist = FLT_MAX;
   18.85 +		hit->obj = 0;
   18.86 +	}
   18.87 +
   18.88 +	int num_obj = (int)objects.size();
   18.89 +	for(int i=0; i<num_obj; i++) {
   18.90 +		RayHit tmphit;
   18.91 +		if(objects[i]->intersect(ray, hit ? &tmphit : 0)) {
   18.92 +			if(!hit) return true;
   18.93 +			if(tmphit.dist < hit->dist) {
   18.94 +				*hit = tmphit;
   18.95 +			}
   18.96 +		}
   18.97 +	}
   18.98 +	return hit && hit->obj;
   18.99 +}
    19.1 --- a/src/scene.h	Sun Apr 13 09:54:51 2014 +0300
    19.2 +++ b/src/scene.h	Mon Apr 14 07:34:45 2014 +0300
    19.3 @@ -7,6 +7,9 @@
    19.4  #include "object.h"
    19.5  #include "light.h"
    19.6  #include "camera.h"
    19.7 +#include "raytrace.h"
    19.8 +
    19.9 +enum { SCN_BG_LOW, SCN_BG_MID, SCN_BG_HIGH };
   19.10  
   19.11  class Scene {
   19.12  private:
   19.13 @@ -18,6 +21,10 @@
   19.14  	vector<Camera*> cameras;
   19.15  	Camera *active_cam;
   19.16  
   19.17 +	Vector3 bg[3];
   19.18 +	Vector3 ambient;
   19.19 +	float fog_exp;
   19.20 +
   19.21  	vector<int> sel;
   19.22  
   19.23  public:
   19.24 @@ -29,6 +36,13 @@
   19.25  	void set_name(const char *name);
   19.26  	const char *get_name() const;
   19.27  
   19.28 +	void set_background(const Vector3 &col, int idx = -1);
   19.29 +	const Vector3 &get_background(int idx = -1) const;
   19.30 +	Vector3 get_background(const Ray &ray) const;
   19.31 +
   19.32 +	void set_ambient(const Vector3 &col);
   19.33 +	const Vector3 &get_ambient() const;
   19.34 +
   19.35  	void add(SceneNode *node);
   19.36  
   19.37  	int get_node_count() const;
   19.38 @@ -54,6 +68,8 @@
   19.39  	void clear_selection();
   19.40  	int get_selection_count() const;
   19.41  	int get_selection(int idx = 0) const;
   19.42 +
   19.43 +	bool intersect(const Ray &ray, RayHit *hit = 0) const;
   19.44  };
   19.45  
   19.46  #endif	// SCENE_H_
    20.1 --- a/src/screen.cc	Sun Apr 13 09:54:51 2014 +0300
    20.2 +++ b/src/screen.cc	Mon Apr 14 07:34:45 2014 +0300
    20.3 @@ -78,6 +78,6 @@
    20.4  {
    20.5  }
    20.6  
    20.7 -void Screen::message(MsgAtom ma)
    20.8 +void Screen::message(MsgAtom msg, ...)
    20.9  {
   20.10  }
    21.1 --- a/src/screen.h	Sun Apr 13 09:54:51 2014 +0300
    21.2 +++ b/src/screen.h	Mon Apr 14 07:34:45 2014 +0300
    21.3 @@ -26,7 +26,7 @@
    21.4  	virtual void handle_mbutton(int bn, bool press, int x, int y);
    21.5  	virtual void handle_mmotion(int x, int y);
    21.6  
    21.7 -	virtual void message(MsgAtom ma);
    21.8 +	virtual void message(MsgAtom msg, ...);
    21.9  };
   21.10  
   21.11  #endif	// SCREEN_H_
    22.1 --- a/src/snode.cc	Sun Apr 13 09:54:51 2014 +0300
    22.2 +++ b/src/snode.cc	Mon Apr 14 07:34:45 2014 +0300
    22.3 @@ -192,7 +192,7 @@
    22.4  {
    22.5  	m3d_matrix_mode(M3D_MODELVIEW);
    22.6  	m3d_push_matrix();
    22.7 -	m3d_mult_matrix(get_matrix()[0]);
    22.8 +	m3d_mult_transpose_matrix(get_matrix()[0]);
    22.9  }
   22.10  
   22.11  void SceneNode::post_draw() const
   22.12 @@ -228,7 +228,7 @@
   22.13  	}
   22.14  }
   22.15  
   22.16 -bool SceneNode::intersect(const Ray &ray, float *dist) const
   22.17 +bool SceneNode::intersect(const Ray &ray, RayHit *hit) const
   22.18  {
   22.19  	return false;
   22.20  }
    23.1 --- a/src/snode.h	Sun Apr 13 09:54:51 2014 +0300
    23.2 +++ b/src/snode.h	Mon Apr 14 07:34:45 2014 +0300
    23.3 @@ -6,6 +6,7 @@
    23.4  #include "quat.h"
    23.5  #include "vmathmat.h"
    23.6  #include "vmathray.h"
    23.7 +#include "raytrace.h"
    23.8  
    23.9  enum NodeType {
   23.10  	NODE_NULL,
   23.11 @@ -82,7 +83,7 @@
   23.12  
   23.13  	virtual void draw(bool emph = false) const;
   23.14  
   23.15 -	virtual bool intersect(const Ray &ray, float *dist = 0) const;
   23.16 +	virtual bool intersect(const Ray &ray, RayHit *hit = 0) const;
   23.17  };
   23.18  
   23.19  #endif	/* SCENE_NODE_H_ */
    24.1 --- a/src/vmath.cc	Sun Apr 13 09:54:51 2014 +0300
    24.2 +++ b/src/vmath.cc	Mon Apr 14 07:34:45 2014 +0300
    24.3 @@ -8,13 +8,17 @@
    24.4  	Vector3 vi = normalize(cross(vk, vj));
    24.5  	vj = cross(vi, vk);
    24.6  
    24.7 -	Matrix4x4 m(
    24.8 +	Matrix4x4 rm(
    24.9  			vi.x, vi.y, vi.z, 0,
   24.10  			vj.x, vj.y, vj.z, 0,
   24.11  			-vk.x, -vk.y, -vk.z, 0,
   24.12  			0, 0, 0, 1);
   24.13 -	translate(-pos.x, -pos.y, -pos.z);
   24.14 -	*this = *this * m;
   24.15 +	Matrix4x4 tm(
   24.16 +			1, 0, 0, -pos.x,
   24.17 +			0, 1, 0, -pos.y,
   24.18 +			0, 0, 1, -pos.z,
   24.19 +			0, 0, 0, 1);
   24.20 +	*this = *this * (rm * tm);
   24.21  }
   24.22  
   24.23  void Matrix4x4::transpose()
    25.1 --- a/src/vmath.h	Sun Apr 13 09:54:51 2014 +0300
    25.2 +++ b/src/vmath.h	Mon Apr 14 07:34:45 2014 +0300
    25.3 @@ -50,6 +50,11 @@
    25.4  	return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
    25.5  }
    25.6  
    25.7 +inline Vector3 operator -(const Vector3 &v)
    25.8 +{
    25.9 +	return Vector3(-v.x, -v.y, -v.z);
   25.10 +}
   25.11 +
   25.12  inline Vector3 operator *(const Vector3 &a, const Vector3 &b)
   25.13  {
   25.14  	return Vector3(a.x * b.x, a.y * b.y, a.z * b.z);
   25.15 @@ -85,6 +90,13 @@
   25.16  	return Vector3(x, y, z);
   25.17  }
   25.18  
   25.19 +inline Vector3 lerp(const Vector3 &a, const Vector3 &b, float t)
   25.20 +{
   25.21 +	return Vector3(a.x + (b.x - a.x) * t,
   25.22 +			a.y + (b.y - a.y) * t,
   25.23 +			a.z + (b.z - a.z) * t);
   25.24 +}
   25.25 +
   25.26  // ---- Vector4 ----
   25.27  
   25.28  class Vector4 {
   25.29 @@ -129,6 +141,11 @@
   25.30  	return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
   25.31  }
   25.32  
   25.33 +inline Vector4 operator -(const Vector4 &v)
   25.34 +{
   25.35 +	return Vector4(-v.x, -v.y, -v.z, -v.w);
   25.36 +}
   25.37 +
   25.38  inline Vector4 operator *(const Vector4 &v, float s)
   25.39  {
   25.40  	return Vector4(v.x * s, v.y * s, v.z * s, v.w * s);
   25.41 @@ -153,4 +170,13 @@
   25.42  	return Vector4(x, y, z, w);
   25.43  }
   25.44  
   25.45 +inline Vector4 lerp(const Vector4 &a, const Vector4 &b, float t)
   25.46 +{
   25.47 +	return Vector4(a.x + (b.x - a.x) * t,
   25.48 +			a.y + (b.y - a.y) * t,
   25.49 +			a.z + (b.z - a.z) * t,
   25.50 +			a.w + (b.w - a.w) * t);
   25.51 +}
   25.52 +
   25.53 +
   25.54  #endif	// VMATH_H_
    26.1 --- a/src/vmathmat.h	Sun Apr 13 09:54:51 2014 +0300
    26.2 +++ b/src/vmathmat.h	Mon Apr 14 07:34:45 2014 +0300
    26.3 @@ -130,4 +130,12 @@
    26.4  	*this = *this * m;
    26.5  }
    26.6  
    26.7 +inline Matrix4x4 normal_matrix(const Matrix4x4 &m)
    26.8 +{
    26.9 +	return Matrix4x4(m[0][0], m[0][1], m[0][2], 0,
   26.10 +					m[1][0], m[1][1], m[1][2], 0,
   26.11 +					m[2][0], m[2][1], m[2][2], 0,
   26.12 +					m[3][0], m[3][1], m[3][2], 1);
   26.13 +}
   26.14 +
   26.15  #endif	// VMATH_MATRIX_H_