Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jit-test / tests / v8-v5 / check-raytrace.js
1 // The ray tracer code in this file is written by Adam Burmister. It
2 // is available in its original form from:
3 //
4 //   http://labs.flog.nz.co/raytracer/
5 //
6 // It has been modified slightly by Google to work as a standalone
7 // benchmark, but the all the computational code remains
8 // untouched. This file also contains a copy of parts of the Prototype
9 // JavaScript framework which is used by the ray tracer.
10
11 //var RayTrace = new BenchmarkSuite('RayTrace', 932666, [
12 //  new Benchmark('RayTrace', renderScene)
13 //]);
14
15
16 // Variable used to hold a number that can be used to verify that
17 // the scene was ray traced correctly.
18 var checkNumber;
19
20
21 // ------------------------------------------------------------------------
22 // ------------------------------------------------------------------------
23
24 // The following is a copy of parts of the Prototype JavaScript library:
25
26 // Prototype JavaScript framework, version 1.5.0
27 // (c) 2005-2007 Sam Stephenson
28 //
29 // Prototype is freely distributable under the terms of an MIT-style license.
30 // For details, see the Prototype web site: http://prototype.conio.net/
31
32
33 var Class = {
34   create: function() {
35     return function() {
36       this.initialize.apply(this, arguments);
37     }
38   }
39 };
40
41
42 Object.extend = function(destination, source) {
43   for (var property in source) {
44     destination[property] = source[property];
45   }
46   return destination;
47 };
48
49
50 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
52
53 // The rest of this file is the actual ray tracer written by Adam
54 // Burmister. It's a concatenation of the following files:
55 //
56 //   flog/color.js
57 //   flog/light.js
58 //   flog/vector.js
59 //   flog/ray.js
60 //   flog/scene.js
61 //   flog/material/basematerial.js
62 //   flog/material/solid.js
63 //   flog/material/chessboard.js
64 //   flog/shape/baseshape.js
65 //   flog/shape/sphere.js
66 //   flog/shape/plane.js
67 //   flog/intersectioninfo.js
68 //   flog/camera.js
69 //   flog/background.js
70 //   flog/engine.js
71
72
73 /* Fake a Flog.* namespace */
74 if(typeof(Flog) == 'undefined') var Flog = {};
75 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
76
77 Flog.RayTracer.Color = Class.create();
78
79 Flog.RayTracer.Color.prototype = {
80     red : 0.0,
81     green : 0.0,
82     blue : 0.0,
83
84     initialize : function(r, g, b) {
85         if(!r) r = 0.0;
86         if(!g) g = 0.0;
87         if(!b) b = 0.0;
88
89         this.red = r;
90         this.green = g;
91         this.blue = b;
92     },
93
94     add : function(c1, c2){
95         var result = new Flog.RayTracer.Color(0,0,0);
96
97         result.red = c1.red + c2.red;
98         result.green = c1.green + c2.green;
99         result.blue = c1.blue + c2.blue;
100
101         return result;
102     },
103
104     addScalar: function(c1, s){
105         var result = new Flog.RayTracer.Color(0,0,0);
106
107         result.red = c1.red + s;
108         result.green = c1.green + s;
109         result.blue = c1.blue + s;
110
111         result.limit();
112
113         return result;
114     },
115
116     subtract: function(c1, c2){
117         var result = new Flog.RayTracer.Color(0,0,0);
118
119         result.red = c1.red - c2.red;
120         result.green = c1.green - c2.green;
121         result.blue = c1.blue - c2.blue;
122
123         return result;
124     },
125
126     multiply : function(c1, c2) {
127         var result = new Flog.RayTracer.Color(0,0,0);
128
129         result.red = c1.red * c2.red;
130         result.green = c1.green * c2.green;
131         result.blue = c1.blue * c2.blue;
132
133         return result;
134     },
135
136     multiplyScalar : function(c1, f) {
137         var result = new Flog.RayTracer.Color(0,0,0);
138
139         result.red = c1.red * f;
140         result.green = c1.green * f;
141         result.blue = c1.blue * f;
142
143         return result;
144     },
145
146     divideFactor : function(c1, f) {
147         var result = new Flog.RayTracer.Color(0,0,0);
148
149         result.red = c1.red / f;
150         result.green = c1.green / f;
151         result.blue = c1.blue / f;
152
153         return result;
154     },
155
156     limit: function(){
157         this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0;
158         this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0;
159         this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0;
160     },
161
162     distance : function(color) {
163         var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
164         return d;
165     },
166
167     blend: function(c1, c2, w){
168         var result = new Flog.RayTracer.Color(0,0,0);
169         result = Flog.RayTracer.Color.prototype.add(
170                     Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),
171                     Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)
172                   );
173         return result;
174     },
175
176     brightness : function() {
177         var r = Math.floor(this.red*255);
178         var g = Math.floor(this.green*255);
179         var b = Math.floor(this.blue*255);
180         return (r * 77 + g * 150 + b * 29) >> 8;
181     },
182
183     toString : function () {
184         var r = Math.floor(this.red*255);
185         var g = Math.floor(this.green*255);
186         var b = Math.floor(this.blue*255);
187
188         return "rgb("+ r +","+ g +","+ b +")";
189     }
190 }
191 /* Fake a Flog.* namespace */
192 if(typeof(Flog) == 'undefined') var Flog = {};
193 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
194
195 Flog.RayTracer.Light = Class.create();
196
197 Flog.RayTracer.Light.prototype = {
198     position: null,
199     color: null,
200     intensity: 10.0,
201
202     initialize : function(pos, color, intensity) {
203         this.position = pos;
204         this.color = color;
205         this.intensity = (intensity ? intensity : 10.0);
206     },
207
208     getIntensity: function(distance){
209         if(distance >= intensity) return 0;
210
211         return Math.pow((intensity - distance) / strength, 0.2);
212     },
213
214     toString : function () {
215         return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
216     }
217 }
218 /* Fake a Flog.* namespace */
219 if(typeof(Flog) == 'undefined') var Flog = {};
220 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
221
222 Flog.RayTracer.Vector = Class.create();
223
224 Flog.RayTracer.Vector.prototype = {
225     x : 0.0,
226     y : 0.0,
227     z : 0.0,
228
229     initialize : function(x, y, z) {
230         this.x = (x ? x : 0);
231         this.y = (y ? y : 0);
232         this.z = (z ? z : 0);
233     },
234
235     copy: function(vector){
236         this.x = vector.x;
237         this.y = vector.y;
238         this.z = vector.z;
239     },
240
241     normalize : function() {
242         var m = this.magnitude();
243         return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
244     },
245
246     magnitude : function() {
247         return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
248     },
249
250     cross : function(w) {
251         return new Flog.RayTracer.Vector(
252                                             -this.z * w.y + this.y * w.z,
253                                            this.z * w.x - this.x * w.z,
254                                           -this.y * w.x + this.x * w.y);
255     },
256
257     dot : function(w) {
258         return this.x * w.x + this.y * w.y + this.z * w.z;
259     },
260
261     add : function(v, w) {
262         return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
263     },
264
265     subtract : function(v, w) {
266         if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
267         return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
268     },
269
270     multiplyVector : function(v, w) {
271         return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
272     },
273
274     multiplyScalar : function(v, w) {
275         return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
276     },
277
278     toString : function () {
279         return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
280     }
281 }
282 /* Fake a Flog.* namespace */
283 if(typeof(Flog) == 'undefined') var Flog = {};
284 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
285
286 Flog.RayTracer.Ray = Class.create();
287
288 Flog.RayTracer.Ray.prototype = {
289     position : null,
290     direction : null,
291     initialize : function(pos, dir) {
292         this.position = pos;
293         this.direction = dir;
294     },
295
296     toString : function () {
297         return 'Ray [' + this.position + ',' + this.direction + ']';
298     }
299 }
300 /* Fake a Flog.* namespace */
301 if(typeof(Flog) == 'undefined') var Flog = {};
302 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
303
304 Flog.RayTracer.Scene = Class.create();
305
306 Flog.RayTracer.Scene.prototype = {
307     camera : null,
308     shapes : [],
309     lights : [],
310     background : null,
311
312     initialize : function() {
313         this.camera = new Flog.RayTracer.Camera(
314             new Flog.RayTracer.Vector(0,0,-5),
315             new Flog.RayTracer.Vector(0,0,1),
316             new Flog.RayTracer.Vector(0,1,0)
317         );
318         this.shapes = new Array();
319         this.lights = new Array();
320         this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
321     }
322 }
323 /* Fake a Flog.* namespace */
324 if(typeof(Flog) == 'undefined') var Flog = {};
325 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
326 if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
327
328 Flog.RayTracer.Material.BaseMaterial = Class.create();
329
330 Flog.RayTracer.Material.BaseMaterial.prototype = {
331
332     gloss: 2.0,             // [0...infinity] 0 = matt
333     transparency: 0.0,      // 0=opaque
334     reflection: 0.0,        // [0...infinity] 0 = no reflection
335     refraction: 0.50,
336     hasTexture: false,
337
338     initialize : function() {
339
340     },
341
342     getColor: function(u, v){
343
344     },
345
346     wrapUp: function(t){
347         t = t % 2.0;
348         if(t < -1) t += 2.0;
349         if(t >= 1) t -= 2.0;
350         return t;
351     },
352
353     toString : function () {
354         return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
355     }
356 }
357 /* Fake a Flog.* namespace */
358 if(typeof(Flog) == 'undefined') var Flog = {};
359 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
360
361 Flog.RayTracer.Material.Solid = Class.create();
362
363 Flog.RayTracer.Material.Solid.prototype = Object.extend(
364     new Flog.RayTracer.Material.BaseMaterial(), {
365         initialize : function(color, reflection, refraction, transparency, gloss) {
366             this.color = color;
367             this.reflection = reflection;
368             this.transparency = transparency;
369             this.gloss = gloss;
370             this.hasTexture = false;
371         },
372
373         getColor: function(u, v){
374             return this.color;
375         },
376
377         toString : function () {
378             return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
379         }
380     }
381 );
382 /* Fake a Flog.* namespace */
383 if(typeof(Flog) == 'undefined') var Flog = {};
384 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
385
386 Flog.RayTracer.Material.Chessboard = Class.create();
387
388 Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
389     new Flog.RayTracer.Material.BaseMaterial(), {
390         colorEven: null,
391         colorOdd: null,
392         density: 0.5,
393
394         initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
395             this.colorEven = colorEven;
396             this.colorOdd = colorOdd;
397             this.reflection = reflection;
398             this.transparency = transparency;
399             this.gloss = gloss;
400             this.density = density;
401             this.hasTexture = true;
402         },
403
404         getColor: function(u, v){
405             var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
406
407             if(t < 0.0)
408                 return this.colorEven;
409             else
410                 return this.colorOdd;
411         },
412
413         toString : function () {
414             return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
415         }
416     }
417 );
418 /* Fake a Flog.* namespace */
419 if(typeof(Flog) == 'undefined') var Flog = {};
420 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
421 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
422
423 Flog.RayTracer.Shape.BaseShape = Class.create();
424
425 Flog.RayTracer.Shape.BaseShape.prototype = {
426     position: null,
427     material: null,
428
429     initialize : function() {
430         this.position = new Vector(0,0,0);
431         this.material = new Flog.RayTracer.Material.SolidMaterial(
432             new Flog.RayTracer.Color(1,0,1),
433             0,
434             0,
435             0
436         );
437     },
438
439     toString : function () {
440         return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
441     }
442 }
443 /* Fake a Flog.* namespace */
444 if(typeof(Flog) == 'undefined') var Flog = {};
445 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
446 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
447
448 Flog.RayTracer.Shape.Sphere = Class.create();
449
450 Flog.RayTracer.Shape.Sphere.prototype = {
451     initialize : function(pos, radius, material) {
452         this.radius = radius;
453         this.position = pos;
454         this.material = material;
455     },
456
457     intersect: function(ray){
458         var info = new Flog.RayTracer.IntersectionInfo();
459         info.shape = this;
460
461         var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
462
463         var B = dst.dot(ray.direction);
464         var C = dst.dot(dst) - (this.radius * this.radius);
465         var D = (B * B) - C;
466
467         if(D > 0){ // intersection!
468             info.isHit = true;
469             info.distance = (-B) - Math.sqrt(D);
470             info.position = Flog.RayTracer.Vector.prototype.add(
471                                                 ray.position,
472                                                 Flog.RayTracer.Vector.prototype.multiplyScalar(
473                                                     ray.direction,
474                                                     info.distance
475                                                 )
476                                             );
477             info.normal = Flog.RayTracer.Vector.prototype.subtract(
478                                             info.position,
479                                             this.position
480                                         ).normalize();
481
482             info.color = this.material.getColor(0,0);
483         } else {
484             info.isHit = false;
485         }
486         return info;
487     },
488
489     toString : function () {
490         return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
491     }
492 }
493 /* Fake a Flog.* namespace */
494 if(typeof(Flog) == 'undefined') var Flog = {};
495 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
496 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
497
498 Flog.RayTracer.Shape.Plane = Class.create();
499
500 Flog.RayTracer.Shape.Plane.prototype = {
501     d: 0.0,
502
503     initialize : function(pos, d, material) {
504         this.position = pos;
505         this.d = d;
506         this.material = material;
507     },
508
509     intersect: function(ray){
510         var info = new Flog.RayTracer.IntersectionInfo();
511
512         var Vd = this.position.dot(ray.direction);
513         if(Vd == 0) return info; // no intersection
514
515         var t = -(this.position.dot(ray.position) + this.d) / Vd;
516         if(t <= 0) return info;
517
518         info.shape = this;
519         info.isHit = true;
520         info.position = Flog.RayTracer.Vector.prototype.add(
521                                             ray.position,
522                                             Flog.RayTracer.Vector.prototype.multiplyScalar(
523                                                 ray.direction,
524                                                 t
525                                             )
526                                         );
527         info.normal = this.position;
528         info.distance = t;
529
530         if(this.material.hasTexture){
531             var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
532             var vV = vU.cross(this.position);
533             var u = info.position.dot(vU);
534             var v = info.position.dot(vV);
535             info.color = this.material.getColor(u,v);
536         } else {
537             info.color = this.material.getColor(0,0);
538         }
539
540         return info;
541     },
542
543     toString : function () {
544         return 'Plane [' + this.position + ', d=' + this.d + ']';
545     }
546 }
547 /* Fake a Flog.* namespace */
548 if(typeof(Flog) == 'undefined') var Flog = {};
549 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
550
551 Flog.RayTracer.IntersectionInfo = Class.create();
552
553 Flog.RayTracer.IntersectionInfo.prototype = {
554     isHit: false,
555     hitCount: 0,
556     shape: null,
557     position: null,
558     normal: null,
559     color: null,
560     distance: null,
561
562     initialize : function() {
563         this.color = new Flog.RayTracer.Color(0,0,0);
564     },
565
566     toString : function () {
567         return 'Intersection [' + this.position + ']';
568     }
569 }
570 /* Fake a Flog.* namespace */
571 if(typeof(Flog) == 'undefined') var Flog = {};
572 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
573
574 Flog.RayTracer.Camera = Class.create();
575
576 Flog.RayTracer.Camera.prototype = {
577     position: null,
578     lookAt: null,
579     equator: null,
580     up: null,
581     screen: null,
582
583     initialize : function(pos, lookAt, up) {
584         this.position = pos;
585         this.lookAt = lookAt;
586         this.up = up;
587         this.equator = lookAt.normalize().cross(this.up);
588         this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
589     },
590
591     getRay: function(vx, vy){
592         var pos = Flog.RayTracer.Vector.prototype.subtract(
593             this.screen,
594             Flog.RayTracer.Vector.prototype.subtract(
595                 Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
596                 Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
597             )
598         );
599         pos.y = pos.y * -1;
600         var dir = Flog.RayTracer.Vector.prototype.subtract(
601             pos,
602             this.position
603         );
604
605         var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
606
607         return ray;
608     },
609
610     toString : function () {
611         return 'Ray []';
612     }
613 }
614 /* Fake a Flog.* namespace */
615 if(typeof(Flog) == 'undefined') var Flog = {};
616 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
617
618 Flog.RayTracer.Background = Class.create();
619
620 Flog.RayTracer.Background.prototype = {
621     color : null,
622     ambience : 0.0,
623
624     initialize : function(color, ambience) {
625         this.color = color;
626         this.ambience = ambience;
627     }
628 }
629 /* Fake a Flog.* namespace */
630 if(typeof(Flog) == 'undefined') var Flog = {};
631 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
632
633 Flog.RayTracer.Engine = Class.create();
634
635 Flog.RayTracer.Engine.prototype = {
636     canvas: null, /* 2d context we can render to */
637
638     initialize: function(options){
639         this.options = Object.extend({
640                 canvasHeight: 100,
641                 canvasWidth: 100,
642                 pixelWidth: 2,
643                 pixelHeight: 2,
644                 renderDiffuse: false,
645                 renderShadows: false,
646                 renderHighlights: false,
647                 renderReflections: false,
648                 rayDepth: 2
649             }, options || {});
650
651         this.options.canvasHeight /= this.options.pixelHeight;
652         this.options.canvasWidth /= this.options.pixelWidth;
653
654         /* TODO: dynamically include other scripts */
655     },
656
657     setPixel: function(x, y, color){
658         var pxW, pxH;
659         pxW = this.options.pixelWidth;
660         pxH = this.options.pixelHeight;
661
662         if (this.canvas) {
663           this.canvas.fillStyle = color.toString();
664           this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
665         } else {
666           if (x ===  y) {
667             checkNumber += color.brightness();
668           }
669           // print(x * pxW, y * pxH, pxW, pxH);
670         }
671     },
672
673     renderScene: function(scene, canvas){
674         checkNumber = 0;
675         /* Get canvas */
676         if (canvas) {
677           this.canvas = canvas.getContext("2d");
678         } else {
679           this.canvas = null;
680         }
681
682         var canvasHeight = this.options.canvasHeight;
683         var canvasWidth = this.options.canvasWidth;
684
685         for(var y=0; y < canvasHeight; y++){
686             for(var x=0; x < canvasWidth; x++){
687                 var yp = y * 1.0 / canvasHeight * 2 - 1;
688                         var xp = x * 1.0 / canvasWidth * 2 - 1;
689
690                         var ray = scene.camera.getRay(xp, yp);
691
692                         var color = this.getPixelColor(ray, scene);
693
694                 this.setPixel(x, y, color);
695             }
696         }
697         assertEq(checkNumber, 2321);
698     },
699
700     getPixelColor: function(ray, scene){
701         var info = this.testIntersection(ray, scene, null);
702         if(info.isHit){
703             var color = this.rayTrace(info, ray, scene, 0);
704             return color;
705         }
706         return scene.background.color;
707     },
708
709     testIntersection: function(ray, scene, exclude){
710         var hits = 0;
711         var best = new Flog.RayTracer.IntersectionInfo();
712         best.distance = 2000;
713
714         for(var i=0; i<scene.shapes.length; i++){
715             var shape = scene.shapes[i];
716
717             if(shape != exclude){
718                 var info = shape.intersect(ray);
719                 if(info.isHit && info.distance >= 0 && info.distance < best.distance){
720                     best = info;
721                     hits++;
722                 }
723             }
724         }
725         best.hitCount = hits;
726         return best;
727     },
728
729     getReflectionRay: function(P,N,V){
730         var c1 = -N.dot(V);
731         var R1 = Flog.RayTracer.Vector.prototype.add(
732             Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
733             V
734         );
735         return new Flog.RayTracer.Ray(P, R1);
736     },
737
738     rayTrace: function(info, ray, scene, depth){
739         // Calc ambient
740         var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
741         var oldColor = color;
742         var shininess = Math.pow(10, info.shape.material.gloss + 1);
743
744         for(var i=0; i<scene.lights.length; i++){
745             var light = scene.lights[i];
746
747             // Calc diffuse lighting
748             var v = Flog.RayTracer.Vector.prototype.subtract(
749                                 light.position,
750                                 info.position
751                             ).normalize();
752
753             if(this.options.renderDiffuse){
754                 var L = v.dot(info.normal);
755                 if(L > 0.0){
756                     color = Flog.RayTracer.Color.prototype.add(
757                                         color,
758                                         Flog.RayTracer.Color.prototype.multiply(
759                                             info.color,
760                                             Flog.RayTracer.Color.prototype.multiplyScalar(
761                                                 light.color,
762                                                 L
763                                             )
764                                         )
765                                     );
766                 }
767             }
768
769             // The greater the depth the more accurate the colours, but
770             // this is exponentially (!) expensive
771             if(depth <= this.options.rayDepth){
772           // calculate reflection ray
773           if(this.options.renderReflections && info.shape.material.reflection > 0)
774           {
775               var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
776               var refl = this.testIntersection(reflectionRay, scene, info.shape);
777
778               if (refl.isHit && refl.distance > 0){
779                   refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
780               } else {
781                   refl.color = scene.background.color;
782                         }
783
784                   color = Flog.RayTracer.Color.prototype.blend(
785                     color,
786                     refl.color,
787                     info.shape.material.reflection
788                   );
789           }
790
791                 // Refraction
792                 /* TODO */
793             }
794
795             /* Render shadows and highlights */
796
797             var shadowInfo = new Flog.RayTracer.IntersectionInfo();
798
799             if(this.options.renderShadows){
800                 var shadowRay = new Flog.RayTracer.Ray(info.position, v);
801
802                 shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
803                 if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
804                     var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
805                     var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
806                     color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
807                 }
808             }
809
810       // Phong specular highlights
811       if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
812         var Lv = Flog.RayTracer.Vector.prototype.subtract(
813                             info.shape.position,
814                             light.position
815                         ).normalize();
816
817         var E = Flog.RayTracer.Vector.prototype.subtract(
818                             scene.camera.position,
819                             info.shape.position
820                         ).normalize();
821
822         var H = Flog.RayTracer.Vector.prototype.subtract(
823                             E,
824                             Lv
825                         ).normalize();
826
827         var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
828         color = Flog.RayTracer.Color.prototype.add(
829                             Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
830                             color
831                         );
832       }
833         }
834         color.limit();
835         return color;
836     }
837 };
838
839
840 function renderScene(){
841     var scene = new Flog.RayTracer.Scene();
842
843     scene.camera = new Flog.RayTracer.Camera(
844                         new Flog.RayTracer.Vector(0, 0, -15),
845                         new Flog.RayTracer.Vector(-0.2, 0, 5),
846                         new Flog.RayTracer.Vector(0, 1, 0)
847                     );
848
849     scene.background = new Flog.RayTracer.Background(
850                                 new Flog.RayTracer.Color(0.5, 0.5, 0.5),
851                                 0.4
852                             );
853
854     var sphere = new Flog.RayTracer.Shape.Sphere(
855         new Flog.RayTracer.Vector(-1.5, 1.5, 2),
856         1.5,
857         new Flog.RayTracer.Material.Solid(
858             new Flog.RayTracer.Color(0,0.5,0.5),
859             0.3,
860             0.0,
861             0.0,
862             2.0
863         )
864     );
865
866     var sphere1 = new Flog.RayTracer.Shape.Sphere(
867         new Flog.RayTracer.Vector(1, 0.25, 1),
868         0.5,
869         new Flog.RayTracer.Material.Solid(
870             new Flog.RayTracer.Color(0.9,0.9,0.9),
871             0.1,
872             0.0,
873             0.0,
874             1.5
875         )
876     );
877
878     var plane = new Flog.RayTracer.Shape.Plane(
879                                 new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
880                                 1.2,
881                                 new Flog.RayTracer.Material.Chessboard(
882                                     new Flog.RayTracer.Color(1,1,1),
883                                     new Flog.RayTracer.Color(0,0,0),
884                                     0.2,
885                                     0.0,
886                                     1.0,
887                                     0.7
888                                 )
889                             );
890
891     scene.shapes.push(plane);
892     scene.shapes.push(sphere);
893     scene.shapes.push(sphere1);
894
895     var light = new Flog.RayTracer.Light(
896         new Flog.RayTracer.Vector(5, 10, -1),
897         new Flog.RayTracer.Color(0.8, 0.8, 0.8)
898     );
899
900     var light1 = new Flog.RayTracer.Light(
901         new Flog.RayTracer.Vector(-3, 5, -15),
902         new Flog.RayTracer.Color(0.8, 0.8, 0.8),
903         100
904     );
905
906     scene.lights.push(light);
907     scene.lights.push(light1);
908
909     var imageWidth = 100; // $F('imageWidth');
910     var imageHeight = 100; // $F('imageHeight');
911     var pixelSize = "5,5".split(','); //  $F('pixelSize').split(',');
912     var renderDiffuse = true; // $F('renderDiffuse');
913     var renderShadows = true; // $F('renderShadows');
914     var renderHighlights = true; // $F('renderHighlights');
915     var renderReflections = true; // $F('renderReflections');
916     var rayDepth = 2;//$F('rayDepth');
917
918     var raytracer = new Flog.RayTracer.Engine(
919         {
920             canvasWidth: imageWidth,
921             canvasHeight: imageHeight,
922             pixelWidth: pixelSize[0],
923             pixelHeight: pixelSize[1],
924             "renderDiffuse": renderDiffuse,
925             "renderHighlights": renderHighlights,
926             "renderShadows": renderShadows,
927             "renderReflections": renderReflections,
928             "rayDepth": rayDepth
929         }
930     );
931
932     raytracer.renderScene(scene, null, 0);
933 }
934
935 renderScene();