clray

changeset 54:6a30f27fa1e6

separated the OpenGL visualization and added a CPU raytracing mode
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 10 Sep 2010 16:47:00 +0100
parents 54a96b738afe
children df239a52a091
files rt.cl src/clray.cc src/common.h src/dbggl.cc src/dbgray.cc src/rt.cc src/rt.cl src/rt.h src/scene.cc src/scene.h src/vector.cc src/vector.h src/vector.inl
diffstat 13 files changed, 977 insertions(+), 498 deletions(-) [+]
line diff
     1.1 --- a/rt.cl	Sun Sep 05 16:43:55 2010 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,395 +0,0 @@
     1.4 -/* vim: set ft=opencl:ts=4:sw=4 */
     1.5 -#include "common.h"
     1.6 -
     1.7 -struct RendInfo {
     1.8 -	float4 ambient;
     1.9 -	int xsz, ysz;
    1.10 -	int num_faces, num_lights;
    1.11 -	int max_iter;
    1.12 -	int cast_shadows;
    1.13 -};
    1.14 -
    1.15 -struct Vertex {
    1.16 -	float4 pos;
    1.17 -	float4 normal;
    1.18 -	float4 tex;
    1.19 -	float4 padding;
    1.20 -};
    1.21 -
    1.22 -struct Face {
    1.23 -	struct Vertex v[3];
    1.24 -	float4 normal;
    1.25 -	int matid;
    1.26 -	int padding[3];
    1.27 -};
    1.28 -
    1.29 -struct Material {
    1.30 -	float4 kd, ks;
    1.31 -	float kr, kt;
    1.32 -	float spow;
    1.33 -	float padding;
    1.34 -};
    1.35 -
    1.36 -struct Light {
    1.37 -	float4 pos, color;
    1.38 -};
    1.39 -
    1.40 -struct Ray {
    1.41 -	float4 origin, dir;
    1.42 -};
    1.43 -
    1.44 -struct SurfPoint {
    1.45 -	float t;
    1.46 -	float4 pos, norm, dbg;
    1.47 -	global const struct Face *obj;
    1.48 -	struct Material mat;
    1.49 -};
    1.50 -
    1.51 -struct Scene {
    1.52 -	float4 ambient;
    1.53 -	global const struct Face *faces;
    1.54 -	int num_faces;
    1.55 -	global const struct Light *lights;
    1.56 -	int num_lights;
    1.57 -	global const struct Material *matlib;
    1.58 -	//global const struct KDNode *kdtree;
    1.59 -	bool cast_shadows;
    1.60 -};
    1.61 -
    1.62 -struct AABBox {
    1.63 -	float4 min, max;
    1.64 -};
    1.65 -
    1.66 -struct KDNode {
    1.67 -	struct AABBox aabb;
    1.68 -	int face_idx[MAX_NODE_FACES];
    1.69 -	int num_faces;
    1.70 -	int left, right;
    1.71 -	int padding;
    1.72 -};
    1.73 -
    1.74 -#define MIN_ENERGY	0.001
    1.75 -#define EPSILON		1e-5
    1.76 -
    1.77 -float4 shade(struct Ray ray, struct Scene *scn, const struct SurfPoint *sp, read_only image2d_t kdimg);
    1.78 -bool find_intersection(struct Ray ray, const struct Scene *scn, struct SurfPoint *sp, read_only image2d_t kdimg);
    1.79 -bool intersect(struct Ray ray, global const struct Face *face, struct SurfPoint *sp);
    1.80 -bool intersect_aabb(struct Ray ray, struct AABBox aabb);
    1.81 -
    1.82 -float4 reflect(float4 v, float4 n);
    1.83 -float4 transform(float4 v, global const float *xform);
    1.84 -void transform_ray(struct Ray *ray, global const float *xform, global const float *invtrans);
    1.85 -float4 calc_bary(float4 pt, global const struct Face *face, float4 norm);
    1.86 -float mean(float4 v);
    1.87 -
    1.88 -void read_kdnode(int idx, struct KDNode *node, read_only image2d_t kdimg);
    1.89 -
    1.90 -
    1.91 -kernel void render(write_only image2d_t fb,
    1.92 -		global const struct RendInfo *rinf,
    1.93 -		global const struct Face *faces,
    1.94 -		global const struct Material *matlib,
    1.95 -		global const struct Light *lights,
    1.96 -		global const struct Ray *primrays,
    1.97 -		global const float *xform,
    1.98 -		global const float *invtrans,
    1.99 -		//global const struct KDNode *kdtree
   1.100 -		read_only image2d_t kdtree_img)
   1.101 -{
   1.102 -	int idx = get_global_id(0);
   1.103 -
   1.104 -	struct Scene scn;
   1.105 -	scn.ambient = rinf->ambient;
   1.106 -	scn.faces = faces;
   1.107 -	scn.num_faces = rinf->num_faces;
   1.108 -	scn.lights = lights;
   1.109 -	scn.num_lights = rinf->num_lights;
   1.110 -	scn.matlib = matlib;
   1.111 -	scn.cast_shadows = rinf->cast_shadows;
   1.112 -
   1.113 -	struct Ray ray = primrays[idx];
   1.114 -	transform_ray(&ray, xform, invtrans);
   1.115 -
   1.116 -	float4 pixel = (float4)(0, 0, 0, 0);
   1.117 -	float4 energy = (float4)(1.0, 1.0, 1.0, 0.0);
   1.118 -	int iter = 0;
   1.119 -
   1.120 -	while(iter++ <= rinf->max_iter && mean(energy) > MIN_ENERGY) {
   1.121 -		struct SurfPoint sp;
   1.122 -		if(find_intersection(ray, &scn, &sp, kdtree_img)) {
   1.123 -			pixel += shade(ray, &scn, &sp, kdtree_img) * energy;
   1.124 -
   1.125 -			float4 refl_col = sp.mat.ks * sp.mat.kr;
   1.126 -
   1.127 -			ray.origin = sp.pos;
   1.128 -			ray.dir = reflect(-ray.dir, sp.norm);
   1.129 -
   1.130 -			energy *= refl_col;
   1.131 -		} else {
   1.132 -			energy = (float4)(0.0, 0.0, 0.0, 0.0);
   1.133 -		}
   1.134 -	}
   1.135 -
   1.136 -	int2 coord;
   1.137 -	coord.x = idx % rinf->xsz;
   1.138 -	coord.y = idx / rinf->xsz;
   1.139 -
   1.140 -	write_imagef(fb, coord, pixel);
   1.141 -}
   1.142 -
   1.143 -float4 shade(struct Ray ray, struct Scene *scn, const struct SurfPoint *sp, read_only image2d_t kdimg)
   1.144 -{
   1.145 -	float4 norm = sp->norm;
   1.146 -	//bool entering = true;
   1.147 -
   1.148 -	if(dot(ray.dir, norm) >= 0.0) {
   1.149 -		norm = -norm;
   1.150 -		//entering = false;
   1.151 -	}
   1.152 -
   1.153 -	float4 dcol = scn->ambient * sp->mat.kd;
   1.154 -	float4 scol = (float4)(0, 0, 0, 0);
   1.155 -
   1.156 -	for(int i=0; i<scn->num_lights; i++) {
   1.157 -		float4 ldir = scn->lights[i].pos - sp->pos;
   1.158 -
   1.159 -		struct Ray shadowray;
   1.160 -		shadowray.origin = sp->pos;
   1.161 -		shadowray.dir = ldir;
   1.162 -
   1.163 -		if(!scn->cast_shadows || !find_intersection(shadowray, scn, 0, kdimg)) {
   1.164 -			ldir = normalize(ldir);
   1.165 -			float4 vdir = -ray.dir;
   1.166 -			vdir.x = native_divide(vdir.x, RAY_MAG);
   1.167 -			vdir.y = native_divide(vdir.y, RAY_MAG);
   1.168 -			vdir.z = native_divide(vdir.z, RAY_MAG);
   1.169 -			float4 vref = reflect(vdir, norm);
   1.170 -
   1.171 -			float diff = fmax(dot(ldir, norm), 0.0f);
   1.172 -			dcol += sp->mat.kd /* scn->lights[i].color*/ * diff;
   1.173 -
   1.174 -			float spec = native_powr(fmax(dot(ldir, vref), 0.0f), sp->mat.spow);
   1.175 -			scol += sp->mat.ks /* scn->lights[i].color*/ * spec;
   1.176 -		}
   1.177 -	}
   1.178 -
   1.179 -	return dcol + scol;
   1.180 -}
   1.181 -
   1.182 -#define STACK_SIZE	MAX_TREE_DEPTH
   1.183 -bool find_intersection(struct Ray ray, const struct Scene *scn, struct SurfPoint *spres, read_only image2d_t kdimg)
   1.184 -{
   1.185 -	struct SurfPoint sp0;
   1.186 -	sp0.t = 1.0;
   1.187 -	sp0.obj = 0;
   1.188 -
   1.189 -	int idxstack[STACK_SIZE];
   1.190 -	int top = 0;			// points after the topmost element of the stack
   1.191 -	idxstack[top++] = 0;	// root at tree[0]
   1.192 -
   1.193 -	while(top > 0) {
   1.194 -		int idx = idxstack[--top];	// remove this index from the stack and process it
   1.195 -
   1.196 -		struct KDNode node;
   1.197 -		read_kdnode(idx, &node, kdimg);
   1.198 -
   1.199 -		if(intersect_aabb(ray, node.aabb)) {
   1.200 -			if(node.left == -1) {
   1.201 -				// leaf node... check each face in turn and update the nearest intersection as needed
   1.202 -				for(int i=0; i<node.num_faces; i++) {
   1.203 -					struct SurfPoint spt;
   1.204 -					int fidx = node.face_idx[i];
   1.205 -
   1.206 -					if(intersect(ray, scn->faces + fidx, &spt) && spt.t < sp0.t) {
   1.207 -						sp0 = spt;
   1.208 -					}
   1.209 -				}
   1.210 -			} else {
   1.211 -				// internal node... recurse to the children
   1.212 -				idxstack[top++] = node.left;
   1.213 -				idxstack[top++] = node.right;
   1.214 -			}
   1.215 -		}
   1.216 -	}
   1.217 -
   1.218 -	if(!sp0.obj) {
   1.219 -		return false;
   1.220 -	}
   1.221 -
   1.222 -	if(spres) {
   1.223 -		*spres = sp0;
   1.224 -		spres->mat = scn->matlib[sp0.obj->matid];
   1.225 -	}
   1.226 -	return true;
   1.227 -}
   1.228 -
   1.229 -bool intersect(struct Ray ray, global const struct Face *face, struct SurfPoint *sp)
   1.230 -{
   1.231 -	float4 origin = ray.origin;
   1.232 -	float4 dir = ray.dir;
   1.233 -	float4 norm = face->normal;
   1.234 -
   1.235 -	float ndotdir = dot(dir, norm);
   1.236 -
   1.237 -	if(fabs(ndotdir) <= EPSILON) {
   1.238 -		return false;
   1.239 -	}
   1.240 -
   1.241 -	float4 pt = face->v[0].pos;
   1.242 -	float4 vec = pt - origin;
   1.243 -
   1.244 -	float ndotvec = dot(norm, vec);
   1.245 -	float t = native_divide(ndotvec, ndotdir);
   1.246 -
   1.247 -	if(t < EPSILON || t > 1.0) {
   1.248 -		return false;
   1.249 -	}
   1.250 -	pt = origin + dir * t;
   1.251 -
   1.252 -
   1.253 -	float4 bc = calc_bary(pt, face, norm);
   1.254 -	float bc_sum = bc.x + bc.y + bc.z;
   1.255 -
   1.256 -	if(bc_sum < 1.0 - EPSILON || bc_sum > 1.0 + EPSILON) {
   1.257 -		return false;
   1.258 -		bc *= 1.2;
   1.259 -	}
   1.260 -
   1.261 -	sp->t = t;
   1.262 -	sp->pos = pt;
   1.263 -	sp->norm = normalize(face->v[0].normal * bc.x + face->v[1].normal * bc.y + face->v[2].normal * bc.z);
   1.264 -	sp->obj = face;
   1.265 -	sp->dbg = bc;
   1.266 -	return true;
   1.267 -}
   1.268 -
   1.269 -bool intersect_aabb(struct Ray ray, struct AABBox aabb)
   1.270 -{
   1.271 -	if(ray.origin.x >= aabb.min.x && ray.origin.y >= aabb.min.y && ray.origin.z >= aabb.min.z &&
   1.272 -			ray.origin.x < aabb.max.x && ray.origin.y < aabb.max.y && ray.origin.z < aabb.max.z) {
   1.273 -		return true;
   1.274 -	}
   1.275 -
   1.276 -	float4 bbox[2] = {
   1.277 -		aabb.min.x, aabb.min.y, aabb.min.z, 0,
   1.278 -		aabb.max.x, aabb.max.y, aabb.max.z, 0
   1.279 -	};
   1.280 -
   1.281 -	int xsign = (int)(ray.dir.x < 0.0);
   1.282 -	float invdirx = native_recip(ray.dir.x);
   1.283 -	float tmin = (bbox[xsign].x - ray.origin.x) * invdirx;
   1.284 -	float tmax = (bbox[1 - xsign].x - ray.origin.x) * invdirx;
   1.285 -
   1.286 -	int ysign = (int)(ray.dir.y < 0.0);
   1.287 -	float invdiry = native_recip(ray.dir.y);
   1.288 -	float tymin = (bbox[ysign].y - ray.origin.y) * invdiry;
   1.289 -	float tymax = (bbox[1 - ysign].y - ray.origin.y) * invdiry;
   1.290 -
   1.291 -	if(tmin > tymax || tymin > tmax) {
   1.292 -		return false;
   1.293 -	}
   1.294 -
   1.295 -	if(tymin > tmin) tmin = tymin;
   1.296 -	if(tymax < tmax) tmax = tymax;
   1.297 -
   1.298 -	int zsign = (int)(ray.dir.z < 0.0);
   1.299 -	float invdirz = native_recip(ray.dir.z);
   1.300 -	float tzmin = (bbox[zsign].z - ray.origin.z) * invdirz;
   1.301 -	float tzmax = (bbox[1 - zsign].z - ray.origin.z) * invdirz;
   1.302 -
   1.303 -	if(tmin > tzmax || tzmin > tmax) {
   1.304 -		return false;
   1.305 -	}
   1.306 -
   1.307 -	return tmin < 1.0 && tmax > 0.0;
   1.308 -}
   1.309 -
   1.310 -float4 reflect(float4 v, float4 n)
   1.311 -{
   1.312 -	return 2.0f * dot(v, n) * n - v;
   1.313 -}
   1.314 -
   1.315 -float4 transform(float4 v, global const float *xform)
   1.316 -{
   1.317 -	float4 res;
   1.318 -	res.x = v.x * xform[0] + v.y * xform[4] + v.z * xform[8] + xform[12];
   1.319 -	res.y = v.x * xform[1] + v.y * xform[5] + v.z * xform[9] + xform[13];
   1.320 -	res.z = v.x * xform[2] + v.y * xform[6] + v.z * xform[10] + xform[14];
   1.321 -	res.w = 0.0;
   1.322 -	return res;
   1.323 -}
   1.324 -
   1.325 -void transform_ray(struct Ray *ray, global const float *xform, global const float *invtrans)
   1.326 -{
   1.327 -	ray->origin = transform(ray->origin, xform);
   1.328 -	ray->dir = transform(ray->dir, invtrans);
   1.329 -}
   1.330 -
   1.331 -float4 calc_bary(float4 pt, global const struct Face *face, float4 norm)
   1.332 -{
   1.333 -	float4 bc = (float4)(0, 0, 0, 0);
   1.334 -
   1.335 -	// calculate area of the whole triangle
   1.336 -	float4 v1 = face->v[1].pos - face->v[0].pos;
   1.337 -	float4 v2 = face->v[2].pos - face->v[0].pos;
   1.338 -	float4 xv1v2 = cross(v1, v2);
   1.339 -
   1.340 -	float area = fabs(dot(xv1v2, norm)) * 0.5;
   1.341 -	if(area < EPSILON) {
   1.342 -		return bc;
   1.343 -	}
   1.344 -
   1.345 -	float4 pv0 = face->v[0].pos - pt;
   1.346 -	float4 pv1 = face->v[1].pos - pt;
   1.347 -	float4 pv2 = face->v[2].pos - pt;
   1.348 -
   1.349 -	// calculate the area of each sub-triangle
   1.350 -	float4 x12 = cross(pv1, pv2);
   1.351 -	float4 x20 = cross(pv2, pv0);
   1.352 -	float4 x01 = cross(pv0, pv1);
   1.353 -
   1.354 -	float a0 = fabs(dot(x12, norm)) * 0.5;
   1.355 -	float a1 = fabs(dot(x20, norm)) * 0.5;
   1.356 -	float a2 = fabs(dot(x01, norm)) * 0.5;
   1.357 -
   1.358 -	bc.x = native_divide(a0, area);
   1.359 -	bc.y = native_divide(a1, area);
   1.360 -	bc.z = native_divide(a2, area);
   1.361 -	return bc;
   1.362 -}
   1.363 -
   1.364 -float mean(float4 v)
   1.365 -{
   1.366 -	return native_divide(v.x + v.y + v.z, 3.0);
   1.367 -}
   1.368 -
   1.369 -
   1.370 -const sampler_t kdsampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST;
   1.371 -
   1.372 -// read a KD-tree node from a texture scanline
   1.373 -void read_kdnode(int idx, struct KDNode *node, read_only image2d_t kdimg)
   1.374 -{
   1.375 -	int startx = KDIMG_NODE_WIDTH * (idx / KDIMG_MAX_HEIGHT);
   1.376 -
   1.377 -	int2 tc;
   1.378 -	tc.x = startx;
   1.379 -	tc.y = idx % KDIMG_MAX_HEIGHT;
   1.380 -
   1.381 -	node->aabb.min = read_imagef(kdimg, kdsampler, tc); tc.x++;
   1.382 -	node->aabb.max = read_imagef(kdimg, kdsampler, tc);
   1.383 -
   1.384 -	tc.x = startx + 2 + MAX_NODE_FACES / 4;
   1.385 -	float4 pix = read_imagef(kdimg, kdsampler, tc);
   1.386 -	node->num_faces = (int)pix.x;
   1.387 -	node->left = (int)pix.y;
   1.388 -	node->right = (int)pix.z;
   1.389 -
   1.390 -	tc.x = startx + 2;
   1.391 -	for(int i=0; i<node->num_faces; i+=4) {
   1.392 -		float4 pix = read_imagef(kdimg, kdsampler, tc); tc.x++;
   1.393 -		node->face_idx[i] = (int)pix.x;
   1.394 -		node->face_idx[i + 1] = (int)pix.y;
   1.395 -		node->face_idx[i + 2] = (int)pix.z;
   1.396 -		node->face_idx[i + 3] = (int)pix.w;
   1.397 -	}
   1.398 -}
     2.1 --- a/src/clray.cc	Sun Sep 05 16:43:55 2010 +0100
     2.2 +++ b/src/clray.cc	Fri Sep 10 16:47:00 2010 +0100
     2.3 @@ -33,14 +33,21 @@
     2.4  static float cam_theta, cam_phi = 25.0;
     2.5  static float cam_dist = 10.0;
     2.6  
     2.7 -static bool dbg_glrender = false;
     2.8 -static bool dbg_show_kdtree = false;
     2.9 +static bool dbg_glrender;
    2.10 +static bool dbg_nocl;
    2.11 +static bool dbg_show_kdtree;
    2.12  static bool dbg_show_obj = true;
    2.13  bool dbg_frame_time = true;
    2.14  
    2.15  static Scene scn;
    2.16  static unsigned int tex;
    2.17  
    2.18 +static Light lightlist[] = {
    2.19 +	{{-8, 15, 18, 0}, {1, 1, 1, 1}}
    2.20 +};
    2.21 +
    2.22 +
    2.23 +
    2.24  int main(int argc, char **argv)
    2.25  {
    2.26  	glutInitWindowSize(800, 600);
    2.27 @@ -81,6 +88,10 @@
    2.28  				dbg_glrender = true;
    2.29  				break;
    2.30  
    2.31 +			case 'n':
    2.32 +				dbg_nocl = true;
    2.33 +				break;
    2.34 +
    2.35  			default:
    2.36  				fprintf(stderr, "unrecognized option: %s\n", argv[i]);
    2.37  				return 1;
    2.38 @@ -103,6 +114,11 @@
    2.39  		return false;
    2.40  	}
    2.41  
    2.42 +	int num_lights = sizeof lightlist / sizeof *lightlist;
    2.43 +	for(int i=0; i<num_lights; i++) {
    2.44 +		scn.add_light(lightlist[i]);
    2.45 +	}
    2.46 +
    2.47  	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    2.48  	glutCreateWindow("OpenCL Raytracer");
    2.49  
    2.50 @@ -171,11 +187,6 @@
    2.51  
    2.52  		glGetFloatv(GL_MODELVIEW_MATRIX, mat.m);
    2.53  
    2.54 -		inv_mat = mat;
    2.55 -		inv_mat.invert();
    2.56 -
    2.57 -		/*inv_trans = inv_mat;
    2.58 -		inv_trans.transpose();*/
    2.59  		inv_trans = mat;
    2.60  		inv_trans.m[3] = inv_trans.m[7] = inv_trans.m[11] = 0.0;
    2.61  		inv_trans.m[12] = inv_trans.m[13] = inv_trans.m[14] = 0.0;
    2.62 @@ -185,14 +196,21 @@
    2.63  		glPopMatrix();
    2.64  
    2.65  		if(!dbg_glrender) {
    2.66 -			if(!render()) {
    2.67 -				exit(1);
    2.68 +			if(dbg_nocl) {
    2.69 +				dbg_render(mat.m, inv_trans.m);
    2.70 +			} else {
    2.71 +				if(!render()) {
    2.72 +					exit(1);
    2.73 +				}
    2.74  			}
    2.75  			need_update = false;
    2.76  		}
    2.77  	}
    2.78  
    2.79  	if(dbg_glrender) {
    2.80 +		inv_mat = mat;
    2.81 +		inv_mat.invert();
    2.82 +
    2.83  		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    2.84  		glLoadMatrixf(inv_mat.m);
    2.85  		dbg_render_gl(&scn, dbg_show_kdtree, dbg_show_obj);
    2.86 @@ -322,6 +340,13 @@
    2.87  		dbg_frame_time = !dbg_frame_time;
    2.88  		break;
    2.89  
    2.90 +	case 'n':
    2.91 +		dbg_nocl = !dbg_nocl;
    2.92 +		printf("switching to %s rendering\n", dbg_nocl ? "debug CPU" : "OpenCL");
    2.93 +		need_update = true;
    2.94 +		glutPostRedisplay();
    2.95 +		break;
    2.96 +
    2.97  	default:
    2.98  		break;
    2.99  	}
     3.1 --- a/src/common.h	Sun Sep 05 16:43:55 2010 +0100
     3.2 +++ b/src/common.h	Fri Sep 10 16:47:00 2010 +0100
     3.3 @@ -1,6 +1,12 @@
     3.4  #ifndef COMMON_H_
     3.5  #define COMMON_H_
     3.6  
     3.7 +/* error threshold */
     3.8 +#define EPSILON		1e-5
     3.9 +
    3.10 +/* minimum trace energy threshold */
    3.11 +#define MIN_ENERGY	0.001
    3.12 +
    3.13  /* primary ray magnitude */
    3.14  #define RAY_MAG		500.0
    3.15  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/dbggl.cc	Fri Sep 10 16:47:00 2010 +0100
     4.3 @@ -0,0 +1,77 @@
     4.4 +#include <string.h>
     4.5 +#include <assert.h>
     4.6 +#include "rt.h"
     4.7 +#include "ogl.h"
     4.8 +
     4.9 +#define MIN(a, b)	((a) < (b) ? (a) : (b))
    4.10 +static void dbg_set_gl_material(Material *mat)
    4.11 +{
    4.12 +	static Material def_mat = {{0.7, 0.7, 0.7, 1}, {0, 0, 0, 0}, 0, 0, 0};
    4.13 +
    4.14 +	if(!mat) mat = &def_mat;
    4.15 +
    4.16 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat->kd);
    4.17 +	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->ks);
    4.18 +	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MIN(mat->spow, 128.0f));
    4.19 +}
    4.20 +
    4.21 +void dbg_render_gl(Scene *scn, bool show_tree, bool show_obj)
    4.22 +{
    4.23 +	const RendInfo *rinf = get_render_info();
    4.24 +	const Face *faces = scn->get_face_buffer();
    4.25 +
    4.26 +	glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_BIT);
    4.27 +
    4.28 +	for(int i=0; i<scn->get_num_lights(); i++) {
    4.29 +		float lpos[4];
    4.30 +
    4.31 +		memcpy(lpos, scn->lights[i].pos, sizeof lpos);
    4.32 +		lpos[3] = 1.0;
    4.33 +
    4.34 +		glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos);
    4.35 +		glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, scn->lights[i].color);
    4.36 +		glEnable(GL_LIGHT0 + i);
    4.37 +	}
    4.38 +
    4.39 +	glDisable(GL_TEXTURE_2D);
    4.40 +	glEnable(GL_DEPTH_TEST);
    4.41 +	glEnable(GL_LIGHTING);
    4.42 +
    4.43 +	glMatrixMode(GL_PROJECTION);
    4.44 +	glPushMatrix();
    4.45 +	glLoadIdentity();
    4.46 +	gluPerspective(45.0, (float)rinf->xsz / (float)rinf->ysz, 0.5, 1000.0);
    4.47 +
    4.48 +	if(show_obj) {
    4.49 +		Material *materials = scn->get_materials();
    4.50 +
    4.51 +		int num_faces = scn->get_num_faces();
    4.52 +		int cur_mat = -1;
    4.53 +
    4.54 +		for(int i=0; i<num_faces; i++) {
    4.55 +			if(faces[i].matid != cur_mat) {
    4.56 +				if(cur_mat != -1) {
    4.57 +					glEnd();
    4.58 +				}
    4.59 +				dbg_set_gl_material(materials ? materials + faces[i].matid : 0);
    4.60 +				cur_mat = faces[i].matid;
    4.61 +				glBegin(GL_TRIANGLES);
    4.62 +			}
    4.63 +
    4.64 +			for(int j=0; j<3; j++) {
    4.65 +				glNormal3fv(faces[i].v[j].normal);
    4.66 +				glVertex3fv(faces[i].v[j].pos);
    4.67 +			}
    4.68 +		}
    4.69 +		glEnd();
    4.70 +	}
    4.71 +
    4.72 +	if(show_tree) {
    4.73 +		scn->draw_kdtree();
    4.74 +	}
    4.75 +
    4.76 +	glPopMatrix();
    4.77 +	glPopAttrib();
    4.78 +
    4.79 +	assert(glGetError() == GL_NO_ERROR);
    4.80 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/dbgray.cc	Fri Sep 10 16:47:00 2010 +0100
     5.3 @@ -0,0 +1,342 @@
     5.4 +#include <string.h>
     5.5 +#include <assert.h>
     5.6 +#include "rt.h"
     5.7 +#include "ogl.h"
     5.8 +#include "vector.h"
     5.9 +#include "timer.h"
    5.10 +
    5.11 +struct SurfPoint {
    5.12 +	float t;
    5.13 +	Vector3 pos, norm;
    5.14 +	const Face *face;
    5.15 +};
    5.16 +
    5.17 +static void trace_ray(float *pixel, const Ray &ray, int iter, float energy = 1.0f);
    5.18 +static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy = 1.0f);
    5.19 +static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret);
    5.20 +static bool ray_aabb_test(const Ray &ray, const AABBox &aabb);
    5.21 +static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp);
    5.22 +static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm);
    5.23 +static void transform(float *res, const float *v, const float *xform);
    5.24 +static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform);
    5.25 +
    5.26 +static int xsz, ysz;
    5.27 +static float *fb;
    5.28 +static unsigned int tex;
    5.29 +static Scene *scn;
    5.30 +static const Ray *prim_rays;
    5.31 +
    5.32 +
    5.33 +bool init_dbg_renderer(int width, int height, Scene *scene, unsigned int texid)
    5.34 +{
    5.35 +	try {
    5.36 +		fb = new float[3 * width * height];
    5.37 +	}
    5.38 +	catch(...) {
    5.39 +		return false;
    5.40 +	}
    5.41 +
    5.42 +	xsz = width;
    5.43 +	ysz = height;
    5.44 +	tex = texid;
    5.45 +	scn = scene;
    5.46 +	return true;
    5.47 +}
    5.48 +
    5.49 +void destroy_dbg_renderer()
    5.50 +{
    5.51 +	delete [] fb;
    5.52 +	delete [] prim_rays;
    5.53 +}
    5.54 +
    5.55 +void dbg_set_primary_rays(const Ray *rays)
    5.56 +{
    5.57 +	prim_rays = rays;
    5.58 +}
    5.59 +
    5.60 +void dbg_render(const float *xform, const float *invtrans_xform, int num_threads)
    5.61 +{
    5.62 +	unsigned long t0 = get_msec();
    5.63 +
    5.64 +	int iter = get_render_option_int(ROPT_ITER);
    5.65 +
    5.66 +	int offs = 0;
    5.67 +	for(int i=0; i<ysz; i++) {
    5.68 +		for(int j=0; j<xsz; j++) {
    5.69 +			Ray ray = prim_rays[offs];
    5.70 +			transform_ray(&ray, xform, invtrans_xform);
    5.71 +
    5.72 +			trace_ray(fb + offs * 3, ray, iter, 1.0);
    5.73 +			offs++;
    5.74 +		}
    5.75 +	}
    5.76 +
    5.77 +	glPushAttrib(GL_TEXTURE_BIT);
    5.78 +	glBindTexture(GL_TEXTURE_2D, tex);
    5.79 +	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, fb);
    5.80 +	glPopAttrib();
    5.81 +
    5.82 +	printf("rendered in %lu msec\n", get_msec() - t0);
    5.83 +}
    5.84 +
    5.85 +static void trace_ray(float *pixel, const Ray &ray, int iter, float energy)
    5.86 +{
    5.87 +	SurfPoint sp;
    5.88 +
    5.89 +	if(find_intersection(ray, scn, scn->kdtree, &sp)) {
    5.90 +		shade(pixel, ray, sp, iter, energy);
    5.91 +	} else {
    5.92 +		pixel[0] = pixel[1] = pixel[2] = 0.05f;
    5.93 +	}
    5.94 +}
    5.95 +
    5.96 +#define MAX(a, b)	((a) > (b) ? (a) : (b))
    5.97 +
    5.98 +static void shade(float *pixel, const Ray &ray, const SurfPoint &sp, int iter, float energy)
    5.99 +{
   5.100 +	const Material *mat = scn->get_materials() + sp.face->matid;
   5.101 +
   5.102 +	bool cast_shadows = get_render_option_bool(ROPT_SHAD);
   5.103 +	Vector3 raydir(ray.dir);
   5.104 +	Vector3 norm = sp.norm;
   5.105 +
   5.106 +	if(dot(raydir, norm) >= 0.0) {
   5.107 +		norm = -norm;
   5.108 +	}
   5.109 +
   5.110 +	float dcol[3] = {0, 0, 0};
   5.111 +	float scol[3] = {0, 0, 0};
   5.112 +
   5.113 +	for(int i=0; i<scn->get_num_lights(); i++) {
   5.114 +		Vector3 lpos(scn->lights[i].pos);
   5.115 +		Vector3 ldir = lpos - sp.pos;
   5.116 +
   5.117 +		Ray shadowray;
   5.118 +		shadowray.origin[0] = sp.pos.x;
   5.119 +		shadowray.origin[1] = sp.pos.y;
   5.120 +		shadowray.origin[2] = sp.pos.z;
   5.121 +		shadowray.dir[0] = ldir.x;
   5.122 +		shadowray.dir[1] = ldir.y;
   5.123 +		shadowray.dir[2] = ldir.z;
   5.124 +
   5.125 +		if(!cast_shadows || !find_intersection(shadowray, scn, scn->kdtree, 0)) {
   5.126 +
   5.127 +			ldir.normalize();
   5.128 +
   5.129 +			Vector3 vdir = -raydir / RAY_MAG;
   5.130 +			Vector3 vref = reflect(vdir, norm);
   5.131 +
   5.132 +			float ndotl = dot(ldir, norm);
   5.133 +			float diff = MAX(ndotl, 0.0f);
   5.134 +
   5.135 +			dcol[0] += mat->kd[0] * diff;
   5.136 +			dcol[1] += mat->kd[1] * diff;
   5.137 +			dcol[2] += mat->kd[2] * diff;
   5.138 +
   5.139 +			float ldotvr = dot(ldir, vref);
   5.140 +			float spec = pow(MAX(ldotvr, 0.0f), mat->spow);
   5.141 +
   5.142 +			scol[0] += mat->ks[0] * spec;
   5.143 +			scol[1] += mat->ks[1] * spec;
   5.144 +			scol[2] += mat->ks[2] * spec;
   5.145 +		}
   5.146 +	}
   5.147 +
   5.148 +	float refl_color[3];
   5.149 +	refl_color[0] = mat->ks[0] * mat->kr;
   5.150 +	refl_color[1] = mat->ks[1] * mat->kr;
   5.151 +	refl_color[2] = mat->ks[2] * mat->kr;
   5.152 +
   5.153 +	energy *= (refl_color[0] + refl_color[1] + refl_color[2]) / 3.0;
   5.154 +	if(iter >= 0 && energy > MIN_ENERGY) {
   5.155 +		Vector3 rdir = reflect(-raydir, norm);
   5.156 +
   5.157 +		Ray refl;
   5.158 +		refl.origin[0] = sp.pos.x;
   5.159 +		refl.origin[1] = sp.pos.y;
   5.160 +		refl.origin[2] = sp.pos.z;
   5.161 +		refl.dir[0] = rdir.x;
   5.162 +		refl.dir[1] = rdir.y;
   5.163 +		refl.dir[2] = rdir.z;
   5.164 +
   5.165 +		float rcol[3];
   5.166 +		trace_ray(rcol, refl, iter - 1, energy);
   5.167 +		scol[0] += rcol[0] * mat->ks[0] * mat->kr;
   5.168 +		scol[1] += rcol[1] * mat->ks[1] * mat->kr;
   5.169 +		scol[2] += rcol[2] * mat->ks[2] * mat->kr;
   5.170 +	}
   5.171 +
   5.172 +	pixel[0] = dcol[0] + scol[0];
   5.173 +	pixel[1] = dcol[1] + scol[1];
   5.174 +	pixel[2] = dcol[2] + scol[2];
   5.175 +}
   5.176 +
   5.177 +static bool find_intersection(const Ray &ray, const Scene *scn, const KDNode *kd, SurfPoint *spret)
   5.178 +{
   5.179 +	if(!ray_aabb_test(ray, kd->aabb)) {
   5.180 +		return false;
   5.181 +	}
   5.182 +
   5.183 +	SurfPoint sp, sptmp;
   5.184 +	if(!spret) {
   5.185 +		spret = &sptmp;
   5.186 +	}
   5.187 +
   5.188 +	spret->t = RAY_MAG;
   5.189 +	spret->face = 0;
   5.190 +
   5.191 +	if(kd->left) {
   5.192 +		assert(kd->right);
   5.193 +
   5.194 +		bool found = find_intersection(ray, scn, kd->left, spret);
   5.195 +		if(find_intersection(ray, scn, kd->right, &sp)) {
   5.196 +			if(!found || sp.t < spret->t) {
   5.197 +				*spret = sp;
   5.198 +			}
   5.199 +			found = true;
   5.200 +		}
   5.201 +		return found;
   5.202 +	}
   5.203 +
   5.204 +	const Face *faces = scn->get_face_buffer();
   5.205 +
   5.206 +	for(size_t i=0; i<kd->face_idx.size(); i++) {
   5.207 +		if(ray_triangle_test(ray, faces + kd->face_idx[i], &sp) && sp.t < spret->t) {
   5.208 +			*spret = sp;
   5.209 +		}
   5.210 +	}
   5.211 +	return spret->face != 0;
   5.212 +}
   5.213 +
   5.214 +static bool ray_aabb_test(const Ray &ray, const AABBox &aabb)
   5.215 +{
   5.216 +	if(ray.origin[0] >= aabb.min[0] && ray.origin[1] >= aabb.min[1] && ray.origin[2] >= aabb.min[2] &&
   5.217 +			ray.origin[0] < aabb.max[0] && ray.origin[1] < aabb.max[1] && ray.origin[2] < aabb.max[2]) {
   5.218 +		return true;
   5.219 +	}
   5.220 +
   5.221 +	float bbox[][3] = {
   5.222 +		{aabb.min[0], aabb.min[1], aabb.min[2]},
   5.223 +		{aabb.max[0], aabb.max[1], aabb.max[2]}
   5.224 +	};
   5.225 +
   5.226 +	int xsign = (int)(ray.dir[0] < 0.0);
   5.227 +	float invdirx = 1.0 / ray.dir[0];
   5.228 +	float tmin = (bbox[xsign][0] - ray.origin[0]) * invdirx;
   5.229 +	float tmax = (bbox[1 - xsign][0] - ray.origin[0]) * invdirx;
   5.230 +
   5.231 +	int ysign = (int)(ray.dir[1] < 0.0);
   5.232 +	float invdiry = 1.0 / ray.dir[1];
   5.233 +	float tymin = (bbox[ysign][1] - ray.origin[1]) * invdiry;
   5.234 +	float tymax = (bbox[1 - ysign][1] - ray.origin[1]) * invdiry;
   5.235 +
   5.236 +	if(tmin > tymax || tymin > tmax) {
   5.237 +		return false;
   5.238 +	}
   5.239 +
   5.240 +	if(tymin > tmin) tmin = tymin;
   5.241 +	if(tymax < tmax) tmax = tymax;
   5.242 +
   5.243 +	int zsign = (int)(ray.dir[2] < 0.0);
   5.244 +	float invdirz = 1.0 / ray.dir[2];
   5.245 +	float tzmin = (bbox[zsign][2] - ray.origin[2]) * invdirz;
   5.246 +	float tzmax = (bbox[1 - zsign][2] - ray.origin[2]) * invdirz;
   5.247 +
   5.248 +	if(tmin > tzmax || tzmin > tmax) {
   5.249 +		return false;
   5.250 +	}
   5.251 +
   5.252 +	return tmin < 1.0 && tmax > 0.0;
   5.253 +
   5.254 +}
   5.255 +
   5.256 +static bool ray_triangle_test(const Ray &ray, const Face *face, SurfPoint *sp)
   5.257 +{
   5.258 +	Vector3 origin = ray.origin;
   5.259 +	Vector3 dir = ray.dir;
   5.260 +	Vector3 norm = face->normal;
   5.261 +
   5.262 +	float ndotdir = dot(dir, norm);
   5.263 +
   5.264 +	if(fabs(ndotdir) <= EPSILON) {
   5.265 +		return false;
   5.266 +	}
   5.267 +
   5.268 +	Vector3 pt = face->v[0].pos;
   5.269 +	Vector3 vec = pt - origin;
   5.270 +
   5.271 +	float ndotvec = dot(norm, vec);
   5.272 +	float t = ndotvec / ndotdir;
   5.273 +
   5.274 +	if(t < EPSILON || t > 1.0) {
   5.275 +		return false;
   5.276 +	}
   5.277 +	pt = origin + dir * t;
   5.278 +
   5.279 +
   5.280 +	Vector3 bc = calc_bary(pt, face, norm);
   5.281 +	float bc_sum = bc.x + bc.y + bc.z;
   5.282 +
   5.283 +	if(bc_sum < 1.0 - EPSILON || bc_sum > 1.0 + EPSILON) {
   5.284 +		return false;
   5.285 +	}
   5.286 +
   5.287 +	Vector3 n0(face->v[0].normal);
   5.288 +	Vector3 n1(face->v[1].normal);
   5.289 +	Vector3 n2(face->v[2].normal);
   5.290 +
   5.291 +	sp->t = t;
   5.292 +	sp->pos = pt;
   5.293 +	sp->norm = n0 * bc.x + n1 * bc.y + n2 * bc.z;
   5.294 +	sp->norm.normalize();
   5.295 +	sp->face = face;
   5.296 +	return true;
   5.297 +}
   5.298 +
   5.299 +static Vector3 calc_bary(const Vector3 &pt, const Face *face, const Vector3 &norm)
   5.300 +{
   5.301 +	Vector3 bc(0.0f, 0.0f, 0.0f);
   5.302 +
   5.303 +	Vector3 v1 = Vector3(face->v[1].pos) - Vector3(face->v[0].pos);
   5.304 +	Vector3 v2 = Vector3(face->v[2].pos) - Vector3(face->v[0].pos);
   5.305 +	Vector3 xv1v2 = cross(v1, v2);
   5.306 +
   5.307 +	float area = fabs(dot(xv1v2, norm)) * 0.5;
   5.308 +	if(area < EPSILON) {
   5.309 +		return bc;
   5.310 +	}
   5.311 +
   5.312 +	Vector3 pv0 = face->v[0].pos - pt;
   5.313 +	Vector3 pv1 = face->v[1].pos - pt;
   5.314 +	Vector3 pv2 = face->v[2].pos - pt;
   5.315 +
   5.316 +	// calculate the area of each sub-triangle
   5.317 +	Vector3 x12 = cross(pv1, pv2);
   5.318 +	Vector3 x20 = cross(pv2, pv0);
   5.319 +	Vector3 x01 = cross(pv0, pv1);
   5.320 +
   5.321 +	float a0 = fabs(dot(x12, norm)) * 0.5;
   5.322 +	float a1 = fabs(dot(x20, norm)) * 0.5;
   5.323 +	float a2 = fabs(dot(x01, norm)) * 0.5;
   5.324 +
   5.325 +	bc.x = a0 / area;
   5.326 +	bc.y = a1 / area;
   5.327 +	bc.z = a2 / area;
   5.328 +	return bc;
   5.329 +
   5.330 +}
   5.331 +
   5.332 +static void transform(float *res, const float *v, const float *xform)
   5.333 +{
   5.334 +	float tmp[3];
   5.335 +	tmp[0] = v[0] * xform[0] + v[1] * xform[4] + v[2] * xform[8] + xform[12];
   5.336 +	tmp[1] = v[0] * xform[1] + v[1] * xform[5] + v[2] * xform[9] + xform[13];
   5.337 +	tmp[2] = v[0] * xform[2] + v[1] * xform[6] + v[2] * xform[10] + xform[14];
   5.338 +	memcpy(res, tmp, sizeof tmp);
   5.339 +}
   5.340 +
   5.341 +static void transform_ray(Ray *ray, const float *xform, const float *invtrans_xform)
   5.342 +{
   5.343 +	transform(ray->origin, ray->origin, xform);
   5.344 +	transform(ray->dir, ray->dir, invtrans_xform);
   5.345 +}
     6.1 --- a/src/rt.cc	Sun Sep 05 16:43:55 2010 +0100
     6.2 +++ b/src/rt.cc	Fri Sep 10 16:47:00 2010 +0100
     6.3 @@ -24,22 +24,6 @@
     6.4  	NUM_KERNEL_ARGS
     6.5  };
     6.6  
     6.7 -struct RendInfo {
     6.8 -	float ambient[4];
     6.9 -	int xsz, ysz;
    6.10 -	int num_faces, num_lights;
    6.11 -	int max_iter;
    6.12 -	int cast_shadows;
    6.13 -};
    6.14 -
    6.15 -struct Ray {
    6.16 -	float origin[4], dir[4];
    6.17 -};
    6.18 -
    6.19 -struct Light {
    6.20 -	float pos[4], color[4];
    6.21 -};
    6.22 -
    6.23  static void update_render_info();
    6.24  static Ray get_primary_ray(int x, int y, int w, int h, float vfov_deg);
    6.25  static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret);
    6.26 @@ -49,10 +33,6 @@
    6.27  static CLProgram *prog;
    6.28  static int global_size;
    6.29  
    6.30 -static Light lightlist[] = {
    6.31 -	{{-8, 15, 18, 0}, {1, 1, 1, 1}}
    6.32 -};
    6.33 -
    6.34  
    6.35  static RendInfo rinf;
    6.36  static int saved_iter_val;
    6.37 @@ -72,7 +52,7 @@
    6.38  	rinf.xsz = xsz;
    6.39  	rinf.ysz = ysz;
    6.40  	rinf.num_faces = scn->get_num_faces();
    6.41 -	rinf.num_lights = sizeof lightlist / sizeof *lightlist;
    6.42 +	rinf.num_lights = scn->get_num_lights();
    6.43  	rinf.max_iter = saved_iter_val = 6;
    6.44  	rinf.cast_shadows = true;
    6.45  
    6.46 @@ -84,10 +64,11 @@
    6.47  			prim_rays[i * xsz + j] = get_primary_ray(j, i, xsz, ysz, 45.0);
    6.48  		}
    6.49  	}
    6.50 +	dbg_set_primary_rays(prim_rays);	// give them to the debug renderer
    6.51  
    6.52  	/* setup opencl */
    6.53  	prog = new CLProgram("render");
    6.54 -	if(!prog->load("rt.cl")) {
    6.55 +	if(!prog->load("src/rt.cl")) {
    6.56  		return false;
    6.57  	}
    6.58  
    6.59 @@ -114,7 +95,7 @@
    6.60  	prog->set_arg_buffer(KARG_RENDER_INFO, ARG_RD, sizeof rinf, &rinf);
    6.61  	prog->set_arg_buffer(KARG_FACES, ARG_RD, rinf.num_faces * sizeof(Face), faces);
    6.62  	prog->set_arg_buffer(KARG_MATLIB, ARG_RD, scn->get_num_materials() * sizeof(Material), scn->get_materials());
    6.63 -	prog->set_arg_buffer(KARG_LIGHTS, ARG_RD, sizeof lightlist, lightlist);
    6.64 +	prog->set_arg_buffer(KARG_LIGHTS, ARG_RD, scn->get_num_lights() * sizeof(Light), scn->get_lights());
    6.65  	prog->set_arg_buffer(KARG_PRIM_RAYS, ARG_RD, xsz * ysz * sizeof *prim_rays, prim_rays);
    6.66  	prog->set_arg_buffer(KARG_XFORM, ARG_RD, 16 * sizeof(float));
    6.67  	prog->set_arg_buffer(KARG_INVTRANS_XFORM, ARG_RD, 16 * sizeof(float));
    6.68 @@ -133,9 +114,12 @@
    6.69  		return false;
    6.70  	}
    6.71  
    6.72 -	delete [] prim_rays;
    6.73 +	//delete [] prim_rays; now dbg_renderer handles them
    6.74  
    6.75  	global_size = xsz * ysz;
    6.76 +
    6.77 +
    6.78 +	init_dbg_renderer(xsz, ysz, scn, tex);
    6.79  	return true;
    6.80  }
    6.81  
    6.82 @@ -143,7 +127,11 @@
    6.83  {
    6.84  	delete prog;
    6.85  
    6.86 -	printf("rendertime mean: %ld msec\n", timing_sample_sum / num_timing_samples);
    6.87 +	destroy_dbg_renderer();
    6.88 +
    6.89 +	if(num_timing_samples) {
    6.90 +		printf("rendertime mean: %ld msec\n", timing_sample_sum / num_timing_samples);
    6.91 +	}
    6.92  }
    6.93  
    6.94  bool render()
    6.95 @@ -201,75 +189,6 @@
    6.96  	return true;
    6.97  }
    6.98  
    6.99 -#define MIN(a, b)	((a) < (b) ? (a) : (b))
   6.100 -static void dbg_set_gl_material(Material *mat)
   6.101 -{
   6.102 -	static Material def_mat = {{0.7, 0.7, 0.7, 1}, {0, 0, 0, 0}, 0, 0, 0};
   6.103 -
   6.104 -	if(!mat) mat = &def_mat;
   6.105 -
   6.106 -	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat->kd);
   6.107 -	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->ks);
   6.108 -	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, MIN(mat->spow, 128.0f));
   6.109 -}
   6.110 -
   6.111 -void dbg_render_gl(Scene *scn, bool show_tree, bool show_obj)
   6.112 -{
   6.113 -	glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_LIGHTING_BIT);
   6.114 -
   6.115 -	for(int i=0; i<rinf.num_lights; i++) {
   6.116 -		float lpos[4];
   6.117 -
   6.118 -		memcpy(lpos, lightlist[i].pos, sizeof lpos);
   6.119 -		lpos[3] = 1.0;
   6.120 -
   6.121 -		glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos);
   6.122 -		glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lightlist[i].color);
   6.123 -		glEnable(GL_LIGHT0 + i);
   6.124 -	}
   6.125 -
   6.126 -	glDisable(GL_TEXTURE_2D);
   6.127 -	glEnable(GL_DEPTH_TEST);
   6.128 -	glEnable(GL_LIGHTING);
   6.129 -
   6.130 -	glMatrixMode(GL_PROJECTION);
   6.131 -	glPushMatrix();
   6.132 -	glLoadIdentity();
   6.133 -	gluPerspective(45.0, (float)rinf.xsz / (float)rinf.ysz, 0.5, 1000.0);
   6.134 -
   6.135 -	if(show_obj) {
   6.136 -		Material *materials = scn->get_materials();
   6.137 -
   6.138 -		int num_faces = scn->get_num_faces();
   6.139 -		int cur_mat = -1;
   6.140 -
   6.141 -		for(int i=0; i<num_faces; i++) {
   6.142 -			if(faces[i].matid != cur_mat) {
   6.143 -				if(cur_mat != -1) {
   6.144 -					glEnd();
   6.145 -				}
   6.146 -				dbg_set_gl_material(materials ? materials + faces[i].matid : 0);
   6.147 -				cur_mat = faces[i].matid;
   6.148 -				glBegin(GL_TRIANGLES);
   6.149 -			}
   6.150 -
   6.151 -			for(int j=0; j<3; j++) {
   6.152 -				glNormal3fv(faces[i].v[j].normal);
   6.153 -				glVertex3fv(faces[i].v[j].pos);
   6.154 -			}
   6.155 -		}
   6.156 -		glEnd();
   6.157 -	}
   6.158 -
   6.159 -	if(show_tree) {
   6.160 -		scn->draw_kdtree();
   6.161 -	}
   6.162 -
   6.163 -	glPopMatrix();
   6.164 -	glPopAttrib();
   6.165 -
   6.166 -	assert(glGetError() == GL_NO_ERROR);
   6.167 -}
   6.168  
   6.169  void set_xform(float *matrix, float *invtrans)
   6.170  {
   6.171 @@ -286,6 +205,12 @@
   6.172  	unmap_mem_buffer(mbuf_invtrans);
   6.173  }
   6.174  
   6.175 +
   6.176 +const RendInfo *get_render_info()
   6.177 +{
   6.178 +	return &rinf;
   6.179 +}
   6.180 +
   6.181  void set_render_option(int opt, bool val)
   6.182  {
   6.183  	switch(opt) {
   6.184 @@ -403,6 +328,8 @@
   6.185  	return ray;
   6.186  }
   6.187  
   6.188 +#define MIN(a, b)	((a) < (b) ? (a) : (b))
   6.189 +
   6.190  static float *create_kdimage(const KDNodeGPU *kdtree, int num_nodes, int *xsz_ret, int *ysz_ret)
   6.191  {
   6.192  	int ysz = MIN(num_nodes, KDIMG_MAX_HEIGHT);
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/rt.cl	Fri Sep 10 16:47:00 2010 +0100
     7.3 @@ -0,0 +1,393 @@
     7.4 +/* vim: set ft=opencl:ts=4:sw=4 */
     7.5 +#include "common.h"
     7.6 +
     7.7 +struct RendInfo {
     7.8 +	float4 ambient;
     7.9 +	int xsz, ysz;
    7.10 +	int num_faces, num_lights;
    7.11 +	int max_iter;
    7.12 +	int cast_shadows;
    7.13 +};
    7.14 +
    7.15 +struct Vertex {
    7.16 +	float4 pos;
    7.17 +	float4 normal;
    7.18 +	float4 tex;
    7.19 +	float4 padding;
    7.20 +};
    7.21 +
    7.22 +struct Face {
    7.23 +	struct Vertex v[3];
    7.24 +	float4 normal;
    7.25 +	int matid;
    7.26 +	int padding[3];
    7.27 +};
    7.28 +
    7.29 +struct Material {
    7.30 +	float4 kd, ks;
    7.31 +	float kr, kt;
    7.32 +	float spow;
    7.33 +	float padding;
    7.34 +};
    7.35 +
    7.36 +struct Light {
    7.37 +	float4 pos, color;
    7.38 +};
    7.39 +
    7.40 +struct Ray {
    7.41 +	float4 origin, dir;
    7.42 +};
    7.43 +
    7.44 +struct SurfPoint {
    7.45 +	float t;
    7.46 +	float4 pos, norm, dbg;
    7.47 +	global const struct Face *obj;
    7.48 +	struct Material mat;
    7.49 +};
    7.50 +
    7.51 +struct Scene {
    7.52 +	float4 ambient;
    7.53 +	global const struct Face *faces;
    7.54 +	int num_faces;
    7.55 +	global const struct Light *lights;
    7.56 +	int num_lights;
    7.57 +	global const struct Material *matlib;
    7.58 +	//global const struct KDNode *kdtree;
    7.59 +	bool cast_shadows;
    7.60 +};
    7.61 +
    7.62 +struct AABBox {
    7.63 +	float4 min, max;
    7.64 +};
    7.65 +
    7.66 +struct KDNode {
    7.67 +	struct AABBox aabb;
    7.68 +	int face_idx[MAX_NODE_FACES];
    7.69 +	int num_faces;
    7.70 +	int left, right;
    7.71 +	int padding;
    7.72 +};
    7.73 +
    7.74 +#define MIN_ENERGY	0.001
    7.75 +
    7.76 +float4 shade(struct Ray ray, struct Scene *scn, const struct SurfPoint *sp, read_only image2d_t kdimg);
    7.77 +bool find_intersection(struct Ray ray, const struct Scene *scn, struct SurfPoint *sp, read_only image2d_t kdimg);
    7.78 +bool intersect(struct Ray ray, global const struct Face *face, struct SurfPoint *sp);
    7.79 +bool intersect_aabb(struct Ray ray, struct AABBox aabb);
    7.80 +
    7.81 +float4 reflect(float4 v, float4 n);
    7.82 +float4 transform(float4 v, global const float *xform);
    7.83 +void transform_ray(struct Ray *ray, global const float *xform, global const float *invtrans);
    7.84 +float4 calc_bary(float4 pt, global const struct Face *face, float4 norm);
    7.85 +float mean(float4 v);
    7.86 +
    7.87 +void read_kdnode(int idx, struct KDNode *node, read_only image2d_t kdimg);
    7.88 +
    7.89 +
    7.90 +kernel void render(write_only image2d_t fb,
    7.91 +		global const struct RendInfo *rinf,
    7.92 +		global const struct Face *faces,
    7.93 +		global const struct Material *matlib,
    7.94 +		global const struct Light *lights,
    7.95 +		global const struct Ray *primrays,
    7.96 +		global const float *xform,
    7.97 +		global const float *invtrans,
    7.98 +		//global const struct KDNode *kdtree
    7.99 +		read_only image2d_t kdtree_img)
   7.100 +{
   7.101 +	int idx = get_global_id(0);
   7.102 +
   7.103 +	struct Scene scn;
   7.104 +	scn.ambient = rinf->ambient;
   7.105 +	scn.faces = faces;
   7.106 +	scn.num_faces = rinf->num_faces;
   7.107 +	scn.lights = lights;
   7.108 +	scn.num_lights = rinf->num_lights;
   7.109 +	scn.matlib = matlib;
   7.110 +	scn.cast_shadows = rinf->cast_shadows;
   7.111 +
   7.112 +	struct Ray ray = primrays[idx];
   7.113 +	transform_ray(&ray, xform, invtrans);
   7.114 +
   7.115 +	float4 pixel = (float4)(0, 0, 0, 0);
   7.116 +	float4 energy = (float4)(1.0, 1.0, 1.0, 0.0);
   7.117 +	int iter = 0;
   7.118 +
   7.119 +	while(iter++ <= rinf->max_iter && mean(energy) > MIN_ENERGY) {
   7.120 +		struct SurfPoint sp;
   7.121 +		if(find_intersection(ray, &scn, &sp, kdtree_img)) {
   7.122 +			pixel += shade(ray, &scn, &sp, kdtree_img) * energy;
   7.123 +
   7.124 +			float4 refl_col = sp.mat.ks * sp.mat.kr;
   7.125 +
   7.126 +			ray.origin = sp.pos;
   7.127 +			ray.dir = reflect(-ray.dir, sp.norm);
   7.128 +
   7.129 +			energy *= refl_col;
   7.130 +		} else {
   7.131 +			energy = (float4)(0.0, 0.0, 0.0, 0.0);
   7.132 +		}
   7.133 +	}
   7.134 +
   7.135 +	int2 coord;
   7.136 +	coord.x = idx % rinf->xsz;
   7.137 +	coord.y = idx / rinf->xsz;
   7.138 +
   7.139 +	write_imagef(fb, coord, pixel);
   7.140 +}
   7.141 +
   7.142 +float4 shade(struct Ray ray, struct Scene *scn, const struct SurfPoint *sp, read_only image2d_t kdimg)
   7.143 +{
   7.144 +	float4 norm = sp->norm;
   7.145 +	//bool entering = true;
   7.146 +
   7.147 +	if(dot(ray.dir, norm) >= 0.0) {
   7.148 +		norm = -norm;
   7.149 +		//entering = false;
   7.150 +	}
   7.151 +
   7.152 +	float4 dcol = scn->ambient * sp->mat.kd;
   7.153 +	float4 scol = (float4)(0, 0, 0, 0);
   7.154 +
   7.155 +	for(int i=0; i<scn->num_lights; i++) {
   7.156 +		float4 ldir = scn->lights[i].pos - sp->pos;
   7.157 +
   7.158 +		struct Ray shadowray;
   7.159 +		shadowray.origin = sp->pos;
   7.160 +		shadowray.dir = ldir;
   7.161 +
   7.162 +		if(!scn->cast_shadows || !find_intersection(shadowray, scn, 0, kdimg)) {
   7.163 +			ldir = normalize(ldir);
   7.164 +			float4 vdir = -ray.dir;
   7.165 +			vdir.x = native_divide(vdir.x, RAY_MAG);
   7.166 +			vdir.y = native_divide(vdir.y, RAY_MAG);
   7.167 +			vdir.z = native_divide(vdir.z, RAY_MAG);
   7.168 +			float4 vref = reflect(vdir, norm);
   7.169 +
   7.170 +			float diff = fmax(dot(ldir, norm), 0.0f);
   7.171 +			dcol += sp->mat.kd /* scn->lights[i].color*/ * diff;
   7.172 +
   7.173 +			float spec = native_powr(fmax(dot(ldir, vref), 0.0f), sp->mat.spow);
   7.174 +			scol += sp->mat.ks /* scn->lights[i].color*/ * spec;
   7.175 +		}
   7.176 +	}
   7.177 +
   7.178 +	return dcol + scol;
   7.179 +}
   7.180 +
   7.181 +#define STACK_SIZE	MAX_TREE_DEPTH
   7.182 +bool find_intersection(struct Ray ray, const struct Scene *scn, struct SurfPoint *spres, read_only image2d_t kdimg)
   7.183 +{
   7.184 +	struct SurfPoint sp0;
   7.185 +	sp0.t = 1.0;
   7.186 +	sp0.obj = 0;
   7.187 +
   7.188 +	int idxstack[STACK_SIZE];
   7.189 +	int top = 0;			// points after the topmost element of the stack
   7.190 +	idxstack[top++] = 0;	// root at tree[0]
   7.191 +
   7.192 +	while(top > 0) {
   7.193 +		int idx = idxstack[--top];	// remove this index from the stack and process it
   7.194 +
   7.195 +		struct KDNode node;
   7.196 +		read_kdnode(idx, &node, kdimg);
   7.197 +
   7.198 +		if(intersect_aabb(ray, node.aabb)) {
   7.199 +			if(node.left == -1) {
   7.200 +				// leaf node... check each face in turn and update the nearest intersection as needed
   7.201 +				for(int i=0; i<node.num_faces; i++) {
   7.202 +					struct SurfPoint spt;
   7.203 +					int fidx = node.face_idx[i];
   7.204 +
   7.205 +					if(intersect(ray, scn->faces + fidx, &spt) && spt.t < sp0.t) {
   7.206 +						sp0 = spt;
   7.207 +					}
   7.208 +				}
   7.209 +			} else {
   7.210 +				// internal node... recurse to the children
   7.211 +				idxstack[top++] = node.left;
   7.212 +				idxstack[top++] = node.right;
   7.213 +			}
   7.214 +		}
   7.215 +	}
   7.216 +
   7.217 +	if(!sp0.obj) {
   7.218 +		return false;
   7.219 +	}
   7.220 +
   7.221 +	if(spres) {
   7.222 +		*spres = sp0;
   7.223 +		spres->mat = scn->matlib[sp0.obj->matid];
   7.224 +	}
   7.225 +	return true;
   7.226 +}
   7.227 +
   7.228 +bool intersect(struct Ray ray, global const struct Face *face, struct SurfPoint *sp)
   7.229 +{
   7.230 +	float4 origin = ray.origin;
   7.231 +	float4 dir = ray.dir;
   7.232 +	float4 norm = face->normal;
   7.233 +
   7.234 +	float ndotdir = dot(dir, norm);
   7.235 +
   7.236 +	if(fabs(ndotdir) <= EPSILON) {
   7.237 +		return false;
   7.238 +	}
   7.239 +
   7.240 +	float4 pt = face->v[0].pos;
   7.241 +	float4 vec = pt - origin;
   7.242 +
   7.243 +	float ndotvec = dot(norm, vec);
   7.244 +	float t = native_divide(ndotvec, ndotdir);
   7.245 +
   7.246 +	if(t < EPSILON || t > 1.0) {
   7.247 +		return false;
   7.248 +	}
   7.249 +	pt = origin + dir * t;
   7.250 +
   7.251 +
   7.252 +	float4 bc = calc_bary(pt, face, norm);
   7.253 +	float bc_sum = bc.x + bc.y + bc.z;
   7.254 +
   7.255 +	if(bc_sum < 1.0 - EPSILON || bc_sum > 1.0 + EPSILON) {
   7.256 +		return false;
   7.257 +	}
   7.258 +
   7.259 +	sp->t = t;
   7.260 +	sp->pos = pt;
   7.261 +	sp->norm = normalize(face->v[0].normal * bc.x + face->v[1].normal * bc.y + face->v[2].normal * bc.z);
   7.262 +	sp->obj = face;
   7.263 +	sp->dbg = bc;
   7.264 +	return true;
   7.265 +}
   7.266 +
   7.267 +bool intersect_aabb(struct Ray ray, struct AABBox aabb)
   7.268 +{
   7.269 +	if(ray.origin.x >= aabb.min.x && ray.origin.y >= aabb.min.y && ray.origin.z >= aabb.min.z &&
   7.270 +			ray.origin.x < aabb.max.x && ray.origin.y < aabb.max.y && ray.origin.z < aabb.max.z) {
   7.271 +		return true;
   7.272 +	}
   7.273 +
   7.274 +	float4 bbox[2] = {
   7.275 +		aabb.min.x, aabb.min.y, aabb.min.z, 0,
   7.276 +		aabb.max.x, aabb.max.y, aabb.max.z, 0
   7.277 +	};
   7.278 +
   7.279 +	int xsign = (int)(ray.dir.x < 0.0);
   7.280 +	float invdirx = native_recip(ray.dir.x);
   7.281 +	float tmin = (bbox[xsign].x - ray.origin.x) * invdirx;
   7.282 +	float tmax = (bbox[1 - xsign].x - ray.origin.x) * invdirx;
   7.283 +
   7.284 +	int ysign = (int)(ray.dir.y < 0.0);
   7.285 +	float invdiry = native_recip(ray.dir.y);
   7.286 +	float tymin = (bbox[ysign].y - ray.origin.y) * invdiry;
   7.287 +	float tymax = (bbox[1 - ysign].y - ray.origin.y) * invdiry;
   7.288 +
   7.289 +	if(tmin > tymax || tymin > tmax) {
   7.290 +		return false;
   7.291 +	}
   7.292 +
   7.293 +	if(tymin > tmin) tmin = tymin;
   7.294 +	if(tymax < tmax) tmax = tymax;
   7.295 +
   7.296 +	int zsign = (int)(ray.dir.z < 0.0);
   7.297 +	float invdirz = native_recip(ray.dir.z);
   7.298 +	float tzmin = (bbox[zsign].z - ray.origin.z) * invdirz;
   7.299 +	float tzmax = (bbox[1 - zsign].z - ray.origin.z) * invdirz;
   7.300 +
   7.301 +	if(tmin > tzmax || tzmin > tmax) {
   7.302 +		return false;
   7.303 +	}
   7.304 +
   7.305 +	return tmin < 1.0 && tmax > 0.0;
   7.306 +}
   7.307 +
   7.308 +float4 reflect(float4 v, float4 n)
   7.309 +{
   7.310 +	return 2.0f * dot(v, n) * n - v;
   7.311 +}
   7.312 +
   7.313 +float4 transform(float4 v, global const float *xform)
   7.314 +{
   7.315 +	float4 res;
   7.316 +	res.x = v.x * xform[0] + v.y * xform[4] + v.z * xform[8] + xform[12];
   7.317 +	res.y = v.x * xform[1] + v.y * xform[5] + v.z * xform[9] + xform[13];
   7.318 +	res.z = v.x * xform[2] + v.y * xform[6] + v.z * xform[10] + xform[14];
   7.319 +	res.w = 0.0;
   7.320 +	return res;
   7.321 +}
   7.322 +
   7.323 +void transform_ray(struct Ray *ray, global const float *xform, global const float *invtrans)
   7.324 +{
   7.325 +	ray->origin = transform(ray->origin, xform);
   7.326 +	ray->dir = transform(ray->dir, invtrans);
   7.327 +}
   7.328 +
   7.329 +float4 calc_bary(float4 pt, global const struct Face *face, float4 norm)
   7.330 +{
   7.331 +	float4 bc = (float4)(0, 0, 0, 0);
   7.332 +
   7.333 +	// calculate area of the whole triangle
   7.334 +	float4 v1 = face->v[1].pos - face->v[0].pos;
   7.335 +	float4 v2 = face->v[2].pos - face->v[0].pos;
   7.336 +	float4 xv1v2 = cross(v1, v2);
   7.337 +
   7.338 +	float area = fabs(dot(xv1v2, norm)) * 0.5;
   7.339 +	if(area < EPSILON) {
   7.340 +		return bc;
   7.341 +	}
   7.342 +
   7.343 +	float4 pv0 = face->v[0].pos - pt;
   7.344 +	float4 pv1 = face->v[1].pos - pt;
   7.345 +	float4 pv2 = face->v[2].pos - pt;
   7.346 +
   7.347 +	// calculate the area of each sub-triangle
   7.348 +	float4 x12 = cross(pv1, pv2);
   7.349 +	float4 x20 = cross(pv2, pv0);
   7.350 +	float4 x01 = cross(pv0, pv1);
   7.351 +
   7.352 +	float a0 = fabs(dot(x12, norm)) * 0.5;
   7.353 +	float a1 = fabs(dot(x20, norm)) * 0.5;
   7.354 +	float a2 = fabs(dot(x01, norm)) * 0.5;
   7.355 +
   7.356 +	bc.x = native_divide(a0, area);
   7.357 +	bc.y = native_divide(a1, area);
   7.358 +	bc.z = native_divide(a2, area);
   7.359 +	return bc;
   7.360 +}
   7.361 +
   7.362 +float mean(float4 v)
   7.363 +{
   7.364 +	return native_divide(v.x + v.y + v.z, 3.0);
   7.365 +}
   7.366 +
   7.367 +
   7.368 +const sampler_t kdsampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_NONE | CLK_FILTER_NEAREST;
   7.369 +
   7.370 +// read a KD-tree node from a texture scanline
   7.371 +void read_kdnode(int idx, struct KDNode *node, read_only image2d_t kdimg)
   7.372 +{
   7.373 +	int startx = KDIMG_NODE_WIDTH * (idx / KDIMG_MAX_HEIGHT);
   7.374 +
   7.375 +	int2 tc;
   7.376 +	tc.x = startx;
   7.377 +	tc.y = idx % KDIMG_MAX_HEIGHT;
   7.378 +
   7.379 +	node->aabb.min = read_imagef(kdimg, kdsampler, tc); tc.x++;
   7.380 +	node->aabb.max = read_imagef(kdimg, kdsampler, tc);
   7.381 +
   7.382 +	tc.x = startx + 2 + MAX_NODE_FACES / 4;
   7.383 +	float4 pix = read_imagef(kdimg, kdsampler, tc);
   7.384 +	node->num_faces = (int)pix.x;
   7.385 +	node->left = (int)pix.y;
   7.386 +	node->right = (int)pix.z;
   7.387 +
   7.388 +	tc.x = startx + 2;
   7.389 +	for(int i=0; i<node->num_faces; i+=4) {
   7.390 +		float4 pix = read_imagef(kdimg, kdsampler, tc); tc.x++;
   7.391 +		node->face_idx[i] = (int)pix.x;
   7.392 +		node->face_idx[i + 1] = (int)pix.y;
   7.393 +		node->face_idx[i + 2] = (int)pix.z;
   7.394 +		node->face_idx[i + 3] = (int)pix.w;
   7.395 +	}
   7.396 +}
     8.1 --- a/src/rt.h	Sun Sep 05 16:43:55 2010 +0100
     8.2 +++ b/src/rt.h	Fri Sep 10 16:47:00 2010 +0100
     8.3 @@ -11,11 +11,26 @@
     8.4  	NUM_RENDER_OPTIONS
     8.5  };
     8.6  
     8.7 +struct RendInfo {
     8.8 +	float ambient[4];
     8.9 +	int xsz, ysz;
    8.10 +	int num_faces, num_lights;
    8.11 +	int max_iter;
    8.12 +	int cast_shadows;
    8.13 +};
    8.14 +
    8.15 +struct Ray {
    8.16 +	float origin[4], dir[4];
    8.17 +};
    8.18 +
    8.19 +
    8.20  bool init_renderer(int xsz, int ysz, Scene *scn, unsigned int tex);
    8.21  void destroy_renderer();
    8.22  bool render();
    8.23  void set_xform(float *matrix, float *invtrans);
    8.24  
    8.25 +const RendInfo *get_render_info();
    8.26 +
    8.27  void set_render_option(int opt, bool val);
    8.28  void set_render_option(int opt, int val);
    8.29  void set_render_option(int opt, float val);
    8.30 @@ -24,6 +39,13 @@
    8.31  int get_render_option_int(int opt);
    8.32  float get_render_option_float(int opt);
    8.33  
    8.34 +// raytrace in the CPU
    8.35 +bool init_dbg_renderer(int xsz, int ysz, Scene *scn, unsigned int texid);
    8.36 +void destroy_dbg_renderer();
    8.37 +void dbg_set_primary_rays(const Ray *rays);
    8.38 +void dbg_render(const float *xform, const float *invtrans_xform, int num_threads = -1);
    8.39 +
    8.40 +// visualize the scene using OpenGL
    8.41  void dbg_render_gl(Scene *scn, bool show_tree = false, bool show_obj = true);
    8.42  
    8.43  #endif	/* RT_H_ */
     9.1 --- a/src/scene.cc	Sun Sep 05 16:43:55 2010 +0100
     9.2 +++ b/src/scene.cc	Fri Sep 10 16:47:00 2010 +0100
     9.3 @@ -109,11 +109,27 @@
     9.4  	return true;
     9.5  }
     9.6  
     9.7 +bool Scene::add_light(const Light &lt)
     9.8 +{
     9.9 +	try {
    9.10 +		lights.push_back(lt);
    9.11 +	}
    9.12 +	catch(...) {
    9.13 +		return false;
    9.14 +	}
    9.15 +	return true;
    9.16 +}
    9.17 +
    9.18  int Scene::get_num_meshes() const
    9.19  {
    9.20  	return (int)meshes.size();
    9.21  }
    9.22  
    9.23 +int Scene::get_num_lights() const
    9.24 +{
    9.25 +	return (int)lights.size();
    9.26 +}
    9.27 +
    9.28  int Scene::get_num_faces() const
    9.29  {
    9.30  	if(num_faces >= 0) {
    9.31 @@ -137,6 +153,38 @@
    9.32  	return kdtree_nodes(kdtree);
    9.33  }
    9.34  
    9.35 +Mesh **Scene::get_meshes()
    9.36 +{
    9.37 +	if(meshes.empty()) {
    9.38 +		return 0;
    9.39 +	}
    9.40 +	return &meshes[0];
    9.41 +}
    9.42 +
    9.43 +const Mesh * const *Scene::get_meshes() const
    9.44 +{
    9.45 +	if(meshes.empty()) {
    9.46 +		return 0;
    9.47 +	}
    9.48 +	return &meshes[0];
    9.49 +}
    9.50 +
    9.51 +Light *Scene::get_lights()
    9.52 +{
    9.53 +	if(lights.empty()) {
    9.54 +		return 0;
    9.55 +	}
    9.56 +	return &lights[0];
    9.57 +}
    9.58 +
    9.59 +const Light *Scene::get_lights() const
    9.60 +{
    9.61 +	if(lights.empty()) {
    9.62 +		return 0;
    9.63 +	}
    9.64 +	return &lights[0];
    9.65 +}
    9.66 +
    9.67  Material *Scene::get_materials()
    9.68  {
    9.69  	if(matlib.empty()) {
    10.1 --- a/src/scene.h	Sun Sep 05 16:43:55 2010 +0100
    10.2 +++ b/src/scene.h	Fri Sep 10 16:47:00 2010 +0100
    10.3 @@ -34,6 +34,10 @@
    10.4  	int matid;
    10.5  };
    10.6  
    10.7 +struct Light {
    10.8 +	float pos[4], color[4];
    10.9 +};
   10.10 +
   10.11  class AABBox {
   10.12  public:
   10.13  	float min[4], max[4];
   10.14 @@ -70,6 +74,7 @@
   10.15  
   10.16  public:
   10.17  	std::vector<Mesh*> meshes;
   10.18 +	std::vector<Light> lights;
   10.19  	std::vector<Material> matlib;
   10.20  	KDNode *kdtree;
   10.21  
   10.22 @@ -77,11 +82,20 @@
   10.23  	~Scene();
   10.24  
   10.25  	bool add_mesh(Mesh *m);
   10.26 +	bool add_light(const Light &lt);
   10.27 +
   10.28  	int get_num_meshes() const;
   10.29 +	int get_num_lights() const;
   10.30  	int get_num_faces() const;
   10.31  	int get_num_materials() const;
   10.32  	int get_num_kdnodes() const;
   10.33  
   10.34 +	Mesh **get_meshes();
   10.35 +	const Mesh * const *get_meshes() const;
   10.36 +
   10.37 +	Light *get_lights();
   10.38 +	const Light *get_lights() const;
   10.39 +
   10.40  	Material *get_materials();
   10.41  	const Material *get_materials() const;
   10.42  
    11.1 --- a/src/vector.cc	Sun Sep 05 16:43:55 2010 +0100
    11.2 +++ b/src/vector.cc	Fri Sep 10 16:47:00 2010 +0100
    11.3 @@ -18,6 +18,13 @@
    11.4  	this->z = z;
    11.5  }
    11.6  
    11.7 +Vector3::Vector3(const float *arr)
    11.8 +{
    11.9 +	x = arr[0];
   11.10 +	y = arr[1];
   11.11 +	z = arr[2];
   11.12 +}
   11.13 +
   11.14  void Vector3::normalize()
   11.15  {
   11.16  	float len = sqrt(x * x + y * y + z * z);
    12.1 --- a/src/vector.h	Sun Sep 05 16:43:55 2010 +0100
    12.2 +++ b/src/vector.h	Fri Sep 10 16:47:00 2010 +0100
    12.3 @@ -15,6 +15,7 @@
    12.4  
    12.5  	Vector3();
    12.6  	Vector3(float x, float y, float z);
    12.7 +	Vector3(const float *arr);
    12.8  
    12.9  	void normalize();
   12.10  	inline float length();
   12.11 @@ -28,10 +29,13 @@
   12.12  
   12.13  inline Vector3 operator -(const Vector3 &vec);
   12.14  inline Vector3 operator *(const Vector3 &vec, float s);
   12.15 +inline Vector3 operator /(const Vector3 &vec, float s);
   12.16  
   12.17  inline float dot(const Vector3 &a, const Vector3 &b);
   12.18  inline Vector3 cross(const Vector3 &a, const Vector3 &b);
   12.19  
   12.20 +inline Vector3 reflect(const Vector3 &v, const Vector3 &n);
   12.21 +
   12.22  #include "vector.inl"
   12.23  
   12.24  #endif	/* VECTOR_H_ */
    13.1 --- a/src/vector.inl	Sun Sep 05 16:43:55 2010 +0100
    13.2 +++ b/src/vector.inl	Fri Sep 10 16:47:00 2010 +0100
    13.3 @@ -41,6 +41,10 @@
    13.4  	return Vector3(vec.x * s, vec.y * s, vec.z * s);
    13.5  }
    13.6  
    13.7 +inline Vector3 operator /(const Vector3 &vec, float s)
    13.8 +{
    13.9 +	return Vector3(vec.x / s, vec.y / s, vec.z / s);
   13.10 +}
   13.11  
   13.12  inline float dot(const Vector3 &a, const Vector3 &b)
   13.13  {
   13.14 @@ -51,3 +55,8 @@
   13.15  {
   13.16  	return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
   13.17  }
   13.18 +
   13.19 +inline Vector3 reflect(const Vector3 &v, const Vector3 &n)
   13.20 +{
   13.21 +	return n * (2.0 * dot(v, n)) - v;
   13.22 +}