~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/raytrace.cpp

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// sphere flake bvh raytracer (c) 2005, thierry berger-perrin <tbptbp@gmail.com>
 
2
// this code is released under the GNU Public License.
 
3
// Emscripten changes: stdlib.h, some printf stuff, SIZE
 
4
 
 
5
#include <cmath>       // see http://ompf.org/ray/sphereflake/
 
6
#include <iostream>    // compile with ie g++ -O2 -ffast-math sphereflake.cc
 
7
#include <stdio.h>
 
8
#include <stdlib.h>
 
9
 
 
10
//#include "emscripten.h"
 
11
 
 
12
#define GIMME_SHADOWS  // usage: ./sphereflake [lvl=6] >pix.ppm
 
13
 
 
14
enum { childs = 9, ss= 2, ss_sqr = ss*ss }; /* not really tweakable anymore */
 
15
static const double infinity = 1./0, epsilon = 1e-12;
 
16
 
 
17
struct v_t{ double x,y,z;v_t(){}
 
18
        v_t(const double a,const double b,const double c):x(a),y(b),z(c){}
 
19
        v_t operator+(const v_t&v)const{return v_t(x+v.x,y+v.y,z+v.z);}
 
20
        v_t operator-(const v_t&v)const{return v_t(x-v.x,y-v.y,z-v.z);}
 
21
        v_t operator-()const{return v_t(-x,-y,-z);}
 
22
        v_t operator*(const double d)const{return v_t(x*d,y*d,z*d);}
 
23
        v_t cross(const v_t&v)const{return v_t(y*v.z-z*v.y,z*v.x-x*v.z,x*v.y-y*v.x);}
 
24
        v_t norm()const{return*this*(1./sqrt(magsqr()));}
 
25
        double dot(const v_t&v)const{return x*v.x+y*v.y+z*v.z;}
 
26
        double magsqr()const{return dot(*this);}
 
27
};
 
28
 
 
29
//static const v_t light(v_t(0.5,-.95,1.775).norm()); /*pick one*/
 
30
static const v_t light(v_t(-0.5,-.65,.9).norm()); /*fiat lux*/
 
31
 
 
32
struct ray_t{
 
33
        v_t o,d;
 
34
        ray_t(const v_t&v):o(v){}
 
35
         ray_t(const v_t&v,const v_t&w):o(v),d(w){}
 
36
};
 
37
struct hit_t {
 
38
        v_t n;
 
39
        double t;
 
40
        hit_t():n(v_t(0,0,0)),t(infinity){}
 
41
};
 
42
 
 
43
struct sphere_t{ 
 
44
        v_t o;
 
45
        double r;
 
46
        sphere_t(){}
 
47
        sphere_t(const v_t&v,double d):o(v),r(d){}
 
48
        v_t get_normal(const v_t&v)const{return(v-o)*(1./r);}
 
49
        double intersect(const ray_t&ray)const{
 
50
                const v_t v(o-ray.o); const double b=ray.d.dot(v),disc=b*b-v.magsqr()+r*r;
 
51
                if(disc < 0.)
 
52
                        return infinity; /*branch away from the square root*/
 
53
                const double d=sqrt(disc), t2=b+d, t1=b-d; /*cond. move*/
 
54
                if(t2 < 0.)
 
55
                        return infinity;
 
56
                else
 
57
                        return(t1 > 0.? t1 : t2);
 
58
        }
 
59
};
 
60
 
 
61
struct node_t; 
 
62
static node_t *pool=0, *end=0;
 
63
 
 
64
struct node_t { /*a bvh in array form+skip for navigation.*/
 
65
        sphere_t bound,leaf;
 
66
        long diff;/*far from optimal*/
 
67
        node_t(){} node_t(const sphere_t&b,const sphere_t&l,const long jump) :bound(b),leaf(l),diff(jump){}
 
68
        template<bool shadow> static void intersect(const ray_t &ray,hit_t &hit){
 
69
                const node_t*p=pool;
 
70
                while(p < end) {
 
71
                        if(p->bound.intersect(ray)>=hit.t) /*missed bound*/
 
72
                                p+=p->diff; /*skip subtree*/
 
73
                        else{
 
74
                                const double t=p->leaf.intersect(ray);
 
75
                                if(t < hit.t) { /*if hit, update, then break for shadows*/
 
76
                                         hit.t=t;
 
77
                                        if(shadow) break;
 
78
                                        hit.n=p->leaf.get_normal(ray.o+ray.d*t);
 
79
                                }
 
80
                                ++p; /*next!*/
 
81
                        }
 
82
                }
 
83
        }
 
84
};
 
85
 
 
86
static double ray_trace(const node_t*const scene,const ray_t&ray) {
 
87
        hit_t hit;
 
88
        scene->intersect<false>(ray,hit);// trace primary
 
89
        const double diffuse = hit.t==infinity ? 0. : -hit.n.dot(light);
 
90
        #ifdef GIMME_SHADOWS
 
91
                if (diffuse <= 0.)
 
92
                        return 0.;
 
93
                const ray_t sray(ray.o+(ray.d*hit.t)+(hit.n*epsilon),-light);
 
94
                hit_t shit;
 
95
                scene->intersect<true>(sray,shit);// trace shadow
 
96
                return shit.t==infinity ? diffuse : 0.;
 
97
        #else
 
98
                return diffuse > 0. ? diffuse : 0.;
 
99
        #endif
 
100
}
 
101
 
 
102
static const double grid[ss_sqr][2]={ /*our rotated grid*/
 
103
        {-3/3.,-1/3.},{+1/3.,-3/3.},
 
104
        {-1/3.,+3/3.},{+3/3.,+1/3.}
 
105
};
 
106
static void trace_rgss(const int width,const int height) {
 
107
        const double w=width,h=height,rcp=1/double(ss),scale=256./double(ss_sqr);
 
108
        ray_t ray(v_t(0,0,-4.5)); /* eye, looking into Z */
 
109
        v_t rgss[ss_sqr];
 
110
        for(int i=0;i<ss_sqr;++i) /*precomp.*/ {
 
111
                rgss[i]=v_t(grid[i][0]*rcp-w/2.,grid[i][1]*rcp-h/2.,0);
 
112
        }
 
113
        v_t scan(0,w-1,std::max(w,h)); /*scan line*/
 
114
        for(int i=height;i;--i) {
 
115
    int lineMean = 0;
 
116
                for(int j=width;j;--j) {
 
117
                        double g=0;
 
118
                        for(int idx=0;idx < ss_sqr;++idx){ /*AA*/
 
119
                                ray.d=(scan+rgss[idx]).norm();
 
120
                                g+=ray_trace(pool,ray); /*trace*/
 
121
                        }
 
122
                lineMean += int(scale*g);
 
123
                        scan.x+=1; /*next pixel*/
 
124
                }
 
125
    printf("%d : %d\n", i, lineMean/width);
 
126
                scan.x=0;scan.y-=1; /*next line*/
 
127
        }
 
128
}
 
129
        
 
130
struct basis_t{ /* bogus and compact, exactly what we need */
 
131
        v_t up,b1,b2;
 
132
        basis_t(const v_t&v){ const v_t n(v.norm());
 
133
                if ((n.x*n.x !=1.)&(n.y*n.y !=1.)&(n.z*n.z !=1.)) {/*cough*/
 
134
                        b1=n;
 
135
                        if(n.y*n.y>n.x*n.x) {
 
136
                                if(n.y*n.y>n.z*n.z)
 
137
                                        b1.y=-b1.y;
 
138
                                else b1.z=-b1.z;
 
139
                        }
 
140
                        else if(n.z*n.z > n.x*n.x)
 
141
                                b1.z=-b1.z;
 
142
                        else b1.x=-b1.x;
 
143
                }
 
144
                else
 
145
                        b1=v_t(n.z,n.x,n.y);/*leaves some cases out,dodge them*/
 
146
                
 
147
                up=n;
 
148
                b2=up.cross(b1);
 
149
                b1=up.cross(b2);
 
150
        }
 
151
};
 
152
 
 
153
static node_t *create(node_t*n,const int lvl,int dist,v_t c,v_t d,double r) {
 
154
        n = 1 + new (n) node_t(sphere_t(c,2.*r),sphere_t(c,r), lvl > 1 ? dist : 1);
 
155
        if (lvl <= 1)
 
156
                return n; /*if not at the bottom, recurse a bit more*/
 
157
        dist=std::max((dist-childs)/childs,1); const basis_t b(d); 
 
158
        const double nr=r*1/3.,daL=2.*M_PI/6.,daU=2.*M_PI/3.; double a=0;
 
159
        for(int i=0;i<6;++i){ /*lower ring*/
 
160
                const v_t ndir((d*-.2+b.b1*sin(a)+b.b2*cos(a)).norm()); /*transcendentals?!*/
 
161
                n=create(n,lvl-1,dist,c+ndir*(r+nr),ndir,nr);
 
162
                a+=daL;
 
163
        }
 
164
        a-=daL/3.;/*tweak*/
 
165
        for(int i=0;i<3;++i){ /*upper ring*/
 
166
                const v_t ndir((d*+.6+b.b1*sin(a)+b.b2*cos(a)).norm());
 
167
                n=create(n,lvl-1,dist,c+ndir*(r+nr),ndir,nr); a+=daU;
 
168
        }
 
169
        return n;
 
170
}
 
171
 
 
172
int main(int argc,char*argv[]){
 
173
        const int lvl=atoi(argv[1]);
 
174
        const int size=atoi(argv[2]);
 
175
        int count=childs, dec=lvl;
 
176
        while(--dec > 1) count=(count*childs)+childs;
 
177
        ++count;
 
178
        pool=new node_t[count];  /* raw */
 
179
        end=pool+count;
 
180
        create(pool,lvl,count,v_t(0,0,0),v_t(+.25,+1,-.5).norm(),1.); /* cooked */
 
181
        printf("P2\n%d %d\n%d\n", size, size, size); // std::cout << "P2\n" << size << " " << size << "\n" << size << "\n";
 
182
        trace_rgss(size, size); /* served */
 
183
        return 0;
 
184
}