aboutsummaryrefslogtreecommitdiff
path: root/graytrace.cpp
blob: c09a2022dd16ea8d1c92761e5cf2898e34412466 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <cmath>
#include <cassert>
#include "lodepng.h"

#define SCREEN_WIDTH (960)
#define SCREEN_HEIGHT (640)

#define FLOAT_SMALL_NUM (1e-8)

using namespace std;

/*
Scene description file (.rtsc, Ray Trace SCene)
===============================================

Z           The positive Y-axis points away from you in this picture.
^  _Y
|  /'
| /
|/
#------> X

A "number" is a floating-point number, unless stated otherwise.
A "coordinate" is three numbers, separated by a space.
Between numbers, any amount of whitespace is tolerated.

First line: coordinate of camera, the coordinate of point the camera looks at
  directly and a number in [0,2π) indicating the amount the camera is rotated
  clockwise around the axis between the camera position and the point the camera
  looks at. Z normally faces up in this right-handed coordinate system.
Second line: coordinate of the point light source, followed by the intensity in
  [0,1].
Further lines: a string in {triangle,sphere} giving the object shape, a
  coordinate giving the centre of the object and further parameters for the
  object. For a sphere, give the size (radius); for a triangle give the
  coordinates of the two other vertices; for a plane, give the normal the
  position is any point on the plane.

Example file:
1 -15 2  0 0 0  0
-2 -2 6  1
sphere 0 0 0  1
sphere 1 10 -3  1.5
*/

bool samesign(const double a,const double b){
	return (a>0&&b>0)||(a<0&&b<0);
}

class Vec3{
public:
	double x,y,z;
	Vec3(void){x=y=z=0;}
	Vec3(double _x,double _y,double _z){x=_x;y=_y;z=_z;}
	Vec3& operator=(const Vec3 &other){
		x=other.x;
		y=other.y;
		z=other.z;
		return *this;
	}
	Vec3 operator+(const Vec3 other) const{return Vec3(x+other.x,y+other.y,z+other.z);}
	Vec3 operator-(const Vec3 other) const{return Vec3(x-other.x,y-other.y,z-other.z);}
	Vec3 operator*(const double other) const{return Vec3(x*other,y*other,z*other);}
	double norm(void) const{return sqrt(x*x+y*y+z*z);}
	double dot(const Vec3 &other) const{
		return x*other.x+y*other.y+z*other.z;
	}
	Vec3 cross(const Vec3 &other) const{
		return Vec3(y*other.z-z*other.y,z*other.x-x*other.z,x*other.y-y*other.x);
	}
	bool hasnan(void) const{return isnan(x)||isnan(y)||isnan(z);}
	Vec3 normalised(void) const{return *this*(1/norm());}
	void normalise(void){
		double n=norm();
		x/=n; y/=n; z/=n;
	}
	/*The Vec3::rotated[XYZ] functions rotate around that axis, anti-clockwise
	  if looking at the rotation when said axis is pointer towards the observer.
	  Matrices from en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions */
	Vec3 rotatedX(double theta) const{
		return Vec3(x,y*cos(theta)-z*sin(theta),y*sin(theta)+z*cos(theta));
	}
	Vec3 rotatedY(double theta) const{
		return Vec3(x*cos(theta)+z*sin(theta),y,-x*sin(theta)+z*cos(theta));
	}
	Vec3 rotatedZ(double theta) const{
		return Vec3(x*cos(theta)-y*sin(theta),x*sin(theta)+y*cos(theta),z);
	}
	string str(void) const{
		stringstream ss;
		ss<<'['<<x<<' '<<y<<' '<<z<<']';
		return ss.str();
	}
};

double angleBetween(const Vec3 &a,const Vec3 &b){
	//          /  u . v  \
	//theta=acos|---------|
	//          \|u| * |v|/
	double angle=acos(a.dot(b)/(a.norm()*b.norm()));
	//if(angle<0)cerr<<"angleBetween(Vec3("<<a.x<<','<<a.y<<','<<a.z<<"),Vec3("<<b.x<<','<<b.y<<','<<b.z<<"))="<<angle<<endl;
	return angle;
}

class Camera{
public:
	Vec3 pos,lookat;
	double rot;
	Camera(void){pos=Vec3(0,0,0);lookat=Vec3(1,0,0);rot=0;}
	Camera(Vec3 p,Vec3 l,double r){pos=p;lookat=l;rot=r;}
	Camera(double px,double py,double pz,double lx,double ly,double lz,double r){
		pos=Vec3(px,py,pz);
		lookat=Vec3(lx,ly,lz);
		rot=r;
	}
};

class Primitive{
public:
	bool isLight;
	Primitive(void):isLight(false){}
	virtual ~Primitive(void){}
	/* A line is represented by the formula:
	    X = P + D * t
	   for any t in R, where P is a point on the line, D is the direction vector
	   of the line and X is any point on the line determined by t.
	   This method finds the intersection of the line with this object which is
	   closest to P. It returns Vec3(nan,nan,nan) if no intersections.*/
	virtual Vec3 lineIntersect(const Vec3 &P,const Vec3 &D)=0;
	virtual Vec3 normalat(const Vec3 &P)=0;
};

class Light:public Primitive{
public:
	Vec3 pos;
	double intensity;
	Light(void){isLight=true;}
	Vec3 lineIntersect(const Vec3 &P,const Vec3 &D){
		return Vec3(NAN,NAN,NAN);
	}
	Vec3 normalat(const Vec3 &P){
		return Vec3(NAN,NAN,NAN);
	}
};

class Sphere:public Primitive{
public:
	double size;
	Vec3 pos;
	/* A sphere is represented by the formula:
	    r^2 = abs(X - C)^2
	   where the radius is r, C is the centre of the sphere and X is any
	   resulting point on the sphere's surface.
	   The t of the intersection is given by: (en.wikipedia.org/wiki/Line–sphere_intersection)
	   t=-(D * (P-C)) plusminus sqrt((D * (P-C))^2 - (P-C)^2 + r^2),
	   iff |D|=1, and thus the point X of the intersection by:
	   X = P + D * t.*/
	Vec3 lineIntersect(const Vec3 &P,const Vec3 &D){
		double discr,DPminC;
		Vec3 unitD,PminC;
		unitD=D.normalised(); //to make sure |D|=1
		PminC=P-pos;
		DPminC=unitD.dot(PminC);
		discr=DPminC*DPminC-PminC.dot(PminC)+size*size;
		if(discr<0)return Vec3(NAN,NAN,NAN); //no intersection
		else if(discr<FLOAT_SMALL_NUM)return P+unitD*-DPminC; //one intersection
		else { //two intersections, choose that for which abs(t) is smallest
			if(abs(-DPminC-sqrt(discr))<abs(-DPminC+discr))return P+unitD*(-DPminC-sqrt(discr));
			else return P+unitD*(-DPminC+sqrt(discr));
		}
	}
	//returns unit vector *from origin*, only indicating direction.
	Vec3 normalat(const Vec3 &P){
		return (P-pos).normalised();
	}
};

class Triangle:public Primitive{
private:
	Vec3 normal;
public:
	Vec3 pos0,pos1,pos2;
	Triangle(void):normal(NAN,NAN,NAN){}
	/*Follows the algorithm at http://geomalgorithms.com/a06-_intersect-2.html ;
	  anything that's unclear should be found there!*/
	Vec3 lineIntersect(const Vec3 &P,const Vec3 &D){
		Vec3 P1(P+D); //P0==P
		double ri,si,ti,udotv,udotu,vdotv,wdotu,wdotv;
		Vec3 normal=normalat(pos0);
		ri=normal.dot(P1-P); //denominator actually
		//cerr<<ri<<' ';
		if(abs(ri)<FLOAT_SMALL_NUM)return Vec3(NAN,NAN,NAN); //parallel to plane
		ri=normal.dot(pos0-P)/ri;
		if(ri<0)return Vec3(NAN,NAN,NAN);
		Vec3 intersection=P+D*ri; //intersection with plane, maybe with triangle
		Vec3 u=pos1-pos0,v=pos2-pos0,w=intersection-pos0;
		udotv=u.dot(v); udotu=u.dot(u); vdotv=v.dot(v); wdotu=w.dot(u); wdotv=w.dot(v);
		ti=udotv*udotv-udotu*vdotv; //actually denominator for si and ti
		si=(udotv*wdotv-vdotv*wdotu)/ti;
		if(si<0||si>1)return Vec3(NAN,NAN,NAN); //if si>1, si+ti>1 as well. Saves calculating ti for real
		ti=(udotv*wdotu-udotu*wdotv)/ti;
		if(ti<0||si+ti>1)return Vec3(NAN,NAN,NAN);
		return intersection; //apparently, the ray intersects the triangle as well. Yay!
	}
	Vec3 normalat(const Vec3 &P){
		if(!normal.hasnan())return normal;
		return normal=(pos1-pos0).cross(pos2-pos0).normalised();
	}
};

class Plane:public Primitive{
public:
	Vec3 pos,normal;
	//Also follows the algorithm from http://geomalgorithms.com/a06-_intersect-2.html
	Vec3 lineIntersect(const Vec3 &P,const Vec3 &D){
		Vec3 P1(P+D); //P0==P
		double ri;
		ri=normal.dot(P1-P); //denominator actually
		//cerr<<ri<<' ';
		if(abs(ri)<FLOAT_SMALL_NUM)return Vec3(NAN,NAN,NAN); //if parallel to plane
		ri=normal.dot(pos-P)/ri;
		if(ri<0)return Vec3(NAN,NAN,NAN);
		return P+D*ri;
	}
	Vec3 normalat(const Vec3 &P){
		return normal;
	}
};

/*x,y are screen coordinates in [0,1], FOV is the horizontal field of view in
  radians, N is the number of objects.*/
double calcColour(double x,double y,double FOV,int N,Camera &camera,vector<Primitive*> objs){
	int i,minatidx=0; //=0 for compiler soothing
	double mindist,dist,angle;
	Vec3 intersection,midD,midDrot,minatinter;
	midD=(camera.lookat-camera.pos).normalised();
	mindist=HUGE_VALF;
	//first we rotate midD around Z such that it lies on the XZ plane
	angle=atan2(midD.y,midD.x); //get angle relative to XZ plane, around Z axis (thus, horizontal)
	midDrot=midD.rotatedZ(-angle);
	//then we rotate it around the Y axis (thus, vertically) by the needed amount
	midDrot=midDrot.rotatedY(-FOV*((double)1-2*y*SCREEN_HEIGHT/SCREEN_WIDTH)); //negative in front because it rotates the wrong way round. See axes at top of source and description of Vec3::rotated[XYZ] functions.
	//then we rotate it back around Z to its previous angle
	midDrot=midDrot.rotatedZ(angle);
	//then we apply the necessary horizontal rotation (around Z)
	midDrot=midDrot.rotatedZ(FOV*((double)1-2*x));
	for(i=0;i<N;i++){
		intersection=objs[i]->lineIntersect(camera.pos,midDrot);
		if(!intersection.hasnan()){ //if intersection was found
			//now go test whether it's BEHIND the camera...
			if((intersection.x-camera.pos.x)*midDrot.x<0||(intersection.y-camera.pos.y)*midDrot.y<0||(intersection.z-camera.pos.z)*midDrot.z<0)continue;
			dist=(intersection-camera.pos).norm();
			if(dist<mindist){
				mindist=dist;
				minatidx=i;
				minatinter=intersection;
			}
		}
	}
	if(mindist==HUGE_VALF){
		//cout<<". ";
		return 0;
	}

	if(objs[minatidx]->isLight){ //if intersection was found
		double cross=(camera.pos-intersection).normalised().cross(objs[minatidx]->normalat(intersection)).norm(); //cross==sin(angle between those vectors)
		return 1-cross/6; //this looks reasonable
	}
	//cout<<minatidx<<' ';
	Light *light=NULL;
	for(i=0;i<N;i++)if(objs[i]->isLight){light=(Light*)objs[i];break;}
	if(light==NULL)return 0.1;
	Vec3 DlightToInter=minatinter-light->pos;
	double distLightToInter=DlightToInter.norm();
	for(i=0;i<N;i++){
		if(objs[i]->isLight)continue;
		intersection=objs[i]->lineIntersect(light->pos,DlightToInter);
		dist=abs((intersection-light->pos).norm());
		if(!intersection.hasnan()&&abs((intersection-minatinter).norm())>FLOAT_SMALL_NUM&&dist<distLightToInter){
			//cout<<abs((intersection-minatinter).norm())<<' ';
			break;
		}
	}
	if(i==N){
		//cout<<"N ";
		//return 1;
		//return 1-abs((light->pos-minatinter).normalised().cross((camera.pos-minatinter).normalised()).norm());
		Vec3 cam=(camera.pos-minatinter).normalised(),nor=objs[minatidx]->normalat(minatinter),lig=(light->pos-minatinter).normalised();
		/*double diff=asin(cam.cross(nor).norm())-asin(nor.cross(lig).norm()); //ANCIENT
		if(diff<0)return 0.1;
		else return 0.1+diff*0.9;*/
		//if(abs(factor)>M_PI/2||!samesign(angleBetween(cam,lig)-angleBetween(cam,nor),angleBetween(nor,lig)))return 0.1;
		//else return 0.1+(1-abs(factor))*0.9;
		/*double ligCamAngle=angleBetween(cam,lig);
		double ligNorAngle=angleBetween(nor,lig);
		double camNorAngle=angleBetween(cam,nor);
		angle=abs(ligCamAngle-2*camNorAngle); //how far, in radians, from the perfect reflection angle
		if(angle>M_PI/2)return 0.1;
		else return 0.1+(1-angle/M_PI)*0.9;*/

		/*double factor=angleBetween(cam,nor)-angleBetween(nor,lig); //for spheres
		if(factor>M_PI/2)return 0.5+(double)rand()/RAND_MAX*0.5;
		if(factor<0)return 0.1;
		return 0.1+factor/(M_PI/2)*0.9;*/
		/*double factor=angleBetween(cam,lig)-2*angleBetween(cam,nor); //for cubes
		if(abs(factor)>M_PI)return 0.1;
		return 0.1+(1-abs(factor)/M_PI)*0.9;*/
		Vec3 reflected=nor*cam.dot(nor)*2-cam; // paulbourke.net/geometry/reflected/
		double diff=angleBetween(lig,reflected); //always >=0
		if(diff>M_PI)return 0.1;
		//else return 0.1+0.9*(pow(M_E,-diff)-diff*0.01375541740409698); //y=e^(-x)-x*e^(-pi)/pi gives an exponential thing through (0,1) and (pi,0)
		//else return 0.1+0.9*cos(diff/2);
		//else return 0.1+0.9*sin(0.5*M_PI*nor.dot(lig))*(1-diff/M_PI);
		else return 0.1+0.9*0.5*(sin(M_PI*(nor.dot(lig)-0.5))+1)*(1-diff/M_PI);
	} else {
		//cout<<abs((intersection-minatinter).norm())<<' ';
		return 0.1;
	}
	//return 1/(mindist+1);
	//return (minatinter.z+1)/2;
}

void makeimage(vector<uint8_t> &image,Camera &camera,vector<Primitive*> objs,int N){
	double x,y;
	//double minclr=10000,maxclr=-10000;
	//cerr<<"camera.pos="<<camera.pos.str()<<endl;
	for(y=0;y<SCREEN_HEIGHT;y++){
		for(x=0;x<SCREEN_WIDTH;x++){
			//cout<<".abcdefghijklmnopqrstuvwxyz"[lround(calcColour((double)x/SCREEN_WIDTH,(double)y/SCREEN_HEIGHT,M_PI/4,N,camera,objs)*26)]<<flush;
			//cout<<calcColour((double)x/SCREEN_WIDTH,(double)y/SCREEN_HEIGHT,M_PI/2,N,camera,objs)<<" "<<flush;
			image[4*(SCREEN_WIDTH*y+x)+0]=
			image[4*(SCREEN_WIDTH*y+x)+1]=
			image[4*(SCREEN_WIDTH*y+x)+2]=calcColour((double)x/SCREEN_WIDTH,(double)y/SCREEN_HEIGHT,M_PI/4,N,camera,objs)*255;
			image[4*(SCREEN_WIDTH*y+x)+3]=255;
			//if(image[4*(SCREEN_WIDTH*y+x)+0]/255.0<minclr)minclr=image[4*(SCREEN_WIDTH*y+x)+0]/255.0;
			//if(image[4*(SCREEN_WIDTH*y+x)+0]/255.0>maxclr)maxclr=image[4*(SCREEN_WIDTH*y+x)+0]/255.0;
			//cout<<hex<<setw(2)<<(int)image[4*(SCREEN_WIDTH*y+x)+0]<<' ';
		}
		//cout<<endl;
	}
	//cout<<"colour: ["<<minclr<<','<<maxclr<<']'<<endl;
}

int main(int argc,char **argv){
	if(argc!=2){
		cout<<"Please give the scene description file as a command-line parameter."<<endl;
		return 1;
	}
	ifstream in(argv[1]);
	if(!in.good()){
		cout<<"Could not open file '"<<argv[1]<<"'."<<endl;
		return 1;
	}
	int N,i;
	string type;
	Camera camera;
	vector<Primitive*> objs;
	in>>camera.pos.x>>camera.pos.y>>camera.pos.z>>camera.lookat.x>>camera.lookat.y>>camera.lookat.z>>camera.rot;
	if(camera.rot!=0){
		cout<<"No camera rotation is currently supported; the given value of "<<camera.rot<<" should be 0."<<endl;
		return 1;
	}
	objs.push_back(new Light);
	in>>((Light*)objs[0])->pos.x>>((Light*)objs[0])->pos.y>>((Light*)objs[0])->pos.z>>((Light*)objs[0])->intensity;
	objs[0]->isLight=true;
	N=1;
	for(i=1;;i++){
		in>>type;
		if(!in.good())break;
		if(type=="sphere"){
			objs.push_back(new Sphere);
			in>>((Sphere*)objs[i])->pos.x>>((Sphere*)objs[i])->pos.y>>((Sphere*)objs[i])->pos.z>>((Sphere*)objs[i])->size;
			//((Sphere*)objs[i])->printName();
			N++;
		} else if(type=="triangle"){
			objs.push_back(new Triangle);
			in>>((Triangle*)objs[i])->pos0.x>>((Triangle*)objs[i])->pos0.y>>((Triangle*)objs[i])->pos0.z
			  >>((Triangle*)objs[i])->pos1.x>>((Triangle*)objs[i])->pos1.y>>((Triangle*)objs[i])->pos1.z
			  >>((Triangle*)objs[i])->pos2.x>>((Triangle*)objs[i])->pos2.y>>((Triangle*)objs[i])->pos2.z;
			//((Triangle*)objs[i])->printName();
			N++;
		} else if(type=="cuboid"){
			Vec3 p1,p2;
			in>>p1.x>>p1.y>>p1.z>>p2.x>>p2.y>>p2.z;
			objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z;

			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p2.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p2.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;

			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p2.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p2.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z;

			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p2.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p2.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;

			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p1.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p2.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p1.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p2.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p1.z;

			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p1.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p1.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p2.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			i++; N++; objs.push_back(new Triangle);
			((Triangle*)objs[i])->pos0.x=p1.x; ((Triangle*)objs[i])->pos0.y=p1.y; ((Triangle*)objs[i])->pos0.z=p1.z;
			((Triangle*)objs[i])->pos1.x=p1.x; ((Triangle*)objs[i])->pos1.y=p2.y; ((Triangle*)objs[i])->pos1.z=p2.z;
			((Triangle*)objs[i])->pos2.x=p1.x; ((Triangle*)objs[i])->pos2.y=p1.y; ((Triangle*)objs[i])->pos2.z=p2.z;
			//((Triangle*)objs[i])->printName();
			N++;
		} else if(type=="plane"){
			objs.push_back(new Plane);
			in>>((Plane*)objs[i])->pos.x>>((Plane*)objs[i])->pos.y>>((Plane*)objs[i])->pos.z
			  >>((Plane*)objs[i])->normal.x>>((Plane*)objs[i])->normal.y>>((Plane*)objs[i])->normal.z;
			((Plane*)objs[i])->normal.normalise();
			N++;
		} else {
			cout<<"Unknown object type '"<<type<<"'!"<<endl;
			return 1;
		}
	}
	cout<<"Read objects: "<<N<<" objects"<<endl;

	string fnamebase;
	if(strrchr(argv[1],'/')==NULL)fnamebase=argv[1];
	else fnamebase=strrchr(argv[1],'/');
	vector<uint8_t> image;
	image.resize(4*SCREEN_WIDTH*SCREEN_HEIGHT);
	int error;
#if 0
	char fname[fnamebase.length()+8];
	cout<<"Rendered frames: "<<endl;
	for(i=0;i<36;i++){
		makeimage(image,camera,objs,N);
		cout<<i<<' '<<flush;
		snprintf(fname,sizeof(fname),"%s%02d.png",fnamebase.c_str(),i);
		error=lodepng::encode(fname,image,SCREEN_WIDTH,SCREEN_HEIGHT);
		if(error){
			cout<<"Lodepng encoder error "<<error<<": "<<lodepng_error_text(error)<<endl;
			return 1;
		}
		//camera.lookat=(camera.lookat-camera.pos).rotated(M_PI/9,0)+camera.pos;
		camera.pos=camera.pos.rotatedZ(M_PI/18);
	}
	cout<<endl<<"Written images"<<endl;
#else
	fnamebase+=".png";
	//camera.pos=camera.pos.rotatedZ(M_PI/2);
	makeimage(image,camera,objs,N);
	cout<<"Rendered objects"<<endl;
	error=lodepng::encode(fnamebase.c_str(),image,SCREEN_WIDTH,SCREEN_HEIGHT);
	if(error){
		cout<<"Lodepng encoder error "<<error<<": "<<lodepng_error_text(error)<<endl;
		return 1;
	}
	cout<<"Written image"<<endl;
#endif
	return 0;
}