/* SRAY 0.0.12 - A simple raytracer Copyright (C) 2007 Martin 'nooga' Gasperowicz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #define PI 13.141592653f #define SIGMA 0.000001f #define EPSILON 999999999.0f #define MAXTD 5 #define N 10 #define AA 1 #define W (120*N) #define H (90*N) #define PW 12.0f #define PH 9.0f #define Eye v(0,0,-12.0f) #define BKG v(0,0,0); typedef struct _Vec { double x,y,z; } Vec; Vec v(double x, double y, double z) { Vec r; r.x = x; r.y = y; r.z = z; return r; } Vec add(Vec a, Vec b) { return v(a.x+b.x, a.y+b.y, a.z+b.z); } Vec sub(Vec a, Vec b) { return v(a.x-b.x, a.y-b.y, a.z-b.z); } Vec mul(Vec a, Vec b) { return v(a.x*b.x, a.y*b.y, a.z*b.z); } Vec muls(Vec a, double b) { return v(a.x*b, a.y*b, a.z*b); } Vec divv(Vec a, double b) { return v(a.x/b, a.y/b, a.z/b); } double dot(Vec a, Vec b) { return a.x*b.x+a.y*b.y+a.z*b.z; } Vec cross(Vec a, Vec b) { return v(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.z ); } double len(Vec v) { return sqrtf(dot(v,v)); } Vec norm(Vec ve) { double m = len(ve); return v(ve.x/m,ve.y/m,ve.z/m); } void printv(Vec v) { printf("(%f, %f, %f)", v.x, v.y, v.z); } Vec mirror(Vec q, Vec n) { Vec r = sub(q, muls(n,2.0f*dot(q, n))); return r; } Vec* scr; typedef struct { Vec o,d; } Ray; Ray r(Vec o, Vec d) { Ray re; re.o = o; re.d = norm(d); return re; } typedef struct { Vec color; double diffuse; double reflect; } Mat; Mat material(Vec c, double dif) { Mat m; m.color = c; m.diffuse = dif; m.reflect = 0.0f; return m; } typedef enum _ObjType {OT_LIGHT, OT_BALL} ObjType; typedef struct { ObjType typ; Vec center; double radius; Mat* mat; } Obj; int obc; Obj scene[360]; void addObj(ObjType t, Vec c, double r, Mat* m) { Obj obj; obj.typ = t; obj.center = c; obj.radius = r; obj.mat = m; scene[obc] = obj; obc+=1; } Vec proj(int x, int y) { double xx = ((double)x/W)*PW-PW/2; double yy = ((double)y/H)*PH-PH/2; Vec q = v(xx, -yy, 0); return q; } Vec subproj(Vec v, int x, int y) { Vec ret; ret.x = v.x+x*(PW/(float)(4*W)); ret.y = v.y+y*(PH/(float)(4*H)); return ret; } double collide(Ray ray, Obj ob) { if(ob.typ == OT_BALL) { Vec o = sub(ray.o, ob.center); double a = 2*dot(ray.d, ray.d); double b = 2*dot(ray.d, o); double c = dot(o,o)-ob.radius*ob.radius; double d = b*b-2*a*c; if(d<0) return -1; d = sqrt(d); double t = (-b-d)/a; if(t>=0) return t; t = (-b+d)/a; if(t>=0) return t; } else return -1; } Vec shade(Vec pt, Obj ob) { Vec a = ob.mat->color; Vec normal = sub(pt, ob.center); int i; for(i = 0; iSIGMA) break; } } if(ob.mat->diffuse > 0 && t<=SIGMA) { double d = dot(fo, n); if(d>0) { double diff = d * ob.mat->diffuse; a = add(a, mul(ob.mat->color, muls(c.mat->color, diff))); } } } } return a; } Vec trace(Ray ray, int td) { if(td>MAXTD) return BKG; double last = EPSILON; int i; Vec re; for(i = 0; i=0 && t < last) { last = t; Vec point = add(ray.o, muls(ray.d, t)); re = shade(point, scene[i]); if(scene[i].mat->reflect > 0) { Vec n = norm(sub(point, scene[i].center)); Vec m = mirror(ray.d, n); re = add(re, muls(trace(r(add(point, muls(m, SIGMA)), m), td+1), scene[i].mat->reflect)); } } } } if(last == EPSILON) return BKG; return re; } void raytrace() { scr = (Vec*)malloc(sizeof(Vec)*W*H); int x,y; Vec pp; for(y = 0; y1.0f)?1:scr[y].x)*255); int g = round(((scr[y].y>1.0f)?1:scr[y].y)*255); int b = round(((scr[y].z>1.0f)?1:scr[y].z)*255); r = (r>255)?255:r; g = (g>255)?255:g; b = (r>255)?255:b; printf("%c%c%c", r, g, b); } } double frac(double a) { return a - floor(a); } Vec hsb2rgb(double h, double s, double b) { double tH = frac(h)*6; double tF = frac(tH); double tP = b*(1.0f-s); double tQ = b*(1.0f-s*tF); double tT = b*(1.0-(s*(1.0-tF))); Vec ret; switch ((int)round(tH)) { case 0: ret = v(b,tT,tP); break; case 1: ret = v(tQ,b,tP); break; case 2: ret = v(tP,b,tT); break; case 3: ret = v(tP,tQ,b); break; case 4: ret = v(tT,tP,b); break; default: ret = v(b,tP,tQ); break; } return ret; } Mat red, light; void populate(int n) { int i; double a,x,y,z; Vec c; Mat* m = (Mat*)malloc(n*sizeof(Mat)); for(i = 0; i