Add very simple loading test for non-SFI NaCl.
[chromium-blink-merge.git] / chrome / test / data / v8_benchmark_v6 / raytrace.js
blob971ef7218ee6a4060e11b8def5bbc00f4dc1a087
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.
11 var RayTrace = new BenchmarkSuite('RayTrace', 739989, [
12   new Benchmark('RayTrace', renderScene)
13 ]);
16 // Variable used to hold a number that can be used to verify that
17 // the scene was ray traced correctly.
18 var checkNumber;
21 // ------------------------------------------------------------------------
22 // ------------------------------------------------------------------------
24 // The following is a copy of parts of the Prototype JavaScript library:
26 // Prototype JavaScript framework, version 1.5.0
27 // (c) 2005-2007 Sam Stephenson
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/
33 var Class = {
34   create: function() {
35     return function() {
36       this.initialize.apply(this, arguments);
37     }
38   }
42 Object.extend = function(destination, source) {
43   for (var property in source) {
44     destination[property] = source[property];
45   }
46   return destination;
50 // ------------------------------------------------------------------------
51 // ------------------------------------------------------------------------
53 // The rest of this file is the actual ray tracer written by Adam
54 // Burmister. It's a concatenation of the following files:
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
73 /* Fake a Flog.* namespace */
74 if(typeof(Flog) == 'undefined') var Flog = {};
75 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
77 Flog.RayTracer.Color = Class.create();
79 Flog.RayTracer.Color.prototype = {
80     red : 0.0,
81     green : 0.0,
82     blue : 0.0,
84     initialize : function(r, g, b) {
85         if(!r) r = 0.0;
86         if(!g) g = 0.0;
87         if(!b) b = 0.0;
89         this.red = r;
90         this.green = g;
91         this.blue = b;
92     },
94     add : function(c1, c2){
95         var result = new Flog.RayTracer.Color(0,0,0);
97         result.red = c1.red + c2.red;
98         result.green = c1.green + c2.green;
99         result.blue = c1.blue + c2.blue;
101         return result;
102     },
104     addScalar: function(c1, s){
105         var result = new Flog.RayTracer.Color(0,0,0);
107         result.red = c1.red + s;
108         result.green = c1.green + s;
109         result.blue = c1.blue + s;
111         result.limit();
113         return result;
114     },
116     subtract: function(c1, c2){
117         var result = new Flog.RayTracer.Color(0,0,0);
119         result.red = c1.red - c2.red;
120         result.green = c1.green - c2.green;
121         result.blue = c1.blue - c2.blue;
123         return result;
124     },
126     multiply : function(c1, c2) {
127         var result = new Flog.RayTracer.Color(0,0,0);
129         result.red = c1.red * c2.red;
130         result.green = c1.green * c2.green;
131         result.blue = c1.blue * c2.blue;
133         return result;
134     },
136     multiplyScalar : function(c1, f) {
137         var result = new Flog.RayTracer.Color(0,0,0);
139         result.red = c1.red * f;
140         result.green = c1.green * f;
141         result.blue = c1.blue * f;
143         return result;
144     },
146     divideFactor : function(c1, f) {
147         var result = new Flog.RayTracer.Color(0,0,0);
149         result.red = c1.red / f;
150         result.green = c1.green / f;
151         result.blue = c1.blue / f;
153         return result;
154     },
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     },
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     },
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     },
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     },
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);
188         return "rgb("+ r +","+ g +","+ b +")";
189     }
191 /* Fake a Flog.* namespace */
192 if(typeof(Flog) == 'undefined') var Flog = {};
193 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
195 Flog.RayTracer.Light = Class.create();
197 Flog.RayTracer.Light.prototype = {
198     position: null,
199     color: null,
200     intensity: 10.0,
202     initialize : function(pos, color, intensity) {
203         this.position = pos;
204         this.color = color;
205         this.intensity = (intensity ? intensity : 10.0);
206     },
208     toString : function () {
209         return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
210     }
212 /* Fake a Flog.* namespace */
213 if(typeof(Flog) == 'undefined') var Flog = {};
214 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
216 Flog.RayTracer.Vector = Class.create();
218 Flog.RayTracer.Vector.prototype = {
219     x : 0.0,
220     y : 0.0,
221     z : 0.0,
223     initialize : function(x, y, z) {
224         this.x = (x ? x : 0);
225         this.y = (y ? y : 0);
226         this.z = (z ? z : 0);
227     },
229     copy: function(vector){
230         this.x = vector.x;
231         this.y = vector.y;
232         this.z = vector.z;
233     },
235     normalize : function() {
236         var m = this.magnitude();
237         return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
238     },
240     magnitude : function() {
241         return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
242     },
244     cross : function(w) {
245         return new Flog.RayTracer.Vector(
246                                             -this.z * w.y + this.y * w.z,
247                                            this.z * w.x - this.x * w.z,
248                                           -this.y * w.x + this.x * w.y);
249     },
251     dot : function(w) {
252         return this.x * w.x + this.y * w.y + this.z * w.z;
253     },
255     add : function(v, w) {
256         return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
257     },
259     subtract : function(v, w) {
260         if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
261         return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
262     },
264     multiplyVector : function(v, w) {
265         return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
266     },
268     multiplyScalar : function(v, w) {
269         return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
270     },
272     toString : function () {
273         return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
274     }
276 /* Fake a Flog.* namespace */
277 if(typeof(Flog) == 'undefined') var Flog = {};
278 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
280 Flog.RayTracer.Ray = Class.create();
282 Flog.RayTracer.Ray.prototype = {
283     position : null,
284     direction : null,
285     initialize : function(pos, dir) {
286         this.position = pos;
287         this.direction = dir;
288     },
290     toString : function () {
291         return 'Ray [' + this.position + ',' + this.direction + ']';
292     }
294 /* Fake a Flog.* namespace */
295 if(typeof(Flog) == 'undefined') var Flog = {};
296 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
298 Flog.RayTracer.Scene = Class.create();
300 Flog.RayTracer.Scene.prototype = {
301     camera : null,
302     shapes : [],
303     lights : [],
304     background : null,
306     initialize : function() {
307         this.camera = new Flog.RayTracer.Camera(
308             new Flog.RayTracer.Vector(0,0,-5),
309             new Flog.RayTracer.Vector(0,0,1),
310             new Flog.RayTracer.Vector(0,1,0)
311         );
312         this.shapes = new Array();
313         this.lights = new Array();
314         this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
315     }
317 /* Fake a Flog.* namespace */
318 if(typeof(Flog) == 'undefined') var Flog = {};
319 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
320 if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
322 Flog.RayTracer.Material.BaseMaterial = Class.create();
324 Flog.RayTracer.Material.BaseMaterial.prototype = {
326     gloss: 2.0,             // [0...infinity] 0 = matt
327     transparency: 0.0,      // 0=opaque
328     reflection: 0.0,        // [0...infinity] 0 = no reflection
329     refraction: 0.50,
330     hasTexture: false,
332     initialize : function() {
334     },
336     getColor: function(u, v){
338     },
340     wrapUp: function(t){
341         t = t % 2.0;
342         if(t < -1) t += 2.0;
343         if(t >= 1) t -= 2.0;
344         return t;
345     },
347     toString : function () {
348         return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
349     }
351 /* Fake a Flog.* namespace */
352 if(typeof(Flog) == 'undefined') var Flog = {};
353 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
355 Flog.RayTracer.Material.Solid = Class.create();
357 Flog.RayTracer.Material.Solid.prototype = Object.extend(
358     new Flog.RayTracer.Material.BaseMaterial(), {
359         initialize : function(color, reflection, refraction, transparency, gloss) {
360             this.color = color;
361             this.reflection = reflection;
362             this.transparency = transparency;
363             this.gloss = gloss;
364             this.hasTexture = false;
365         },
367         getColor: function(u, v){
368             return this.color;
369         },
371         toString : function () {
372             return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
373         }
374     }
376 /* Fake a Flog.* namespace */
377 if(typeof(Flog) == 'undefined') var Flog = {};
378 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
380 Flog.RayTracer.Material.Chessboard = Class.create();
382 Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
383     new Flog.RayTracer.Material.BaseMaterial(), {
384         colorEven: null,
385         colorOdd: null,
386         density: 0.5,
388         initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
389             this.colorEven = colorEven;
390             this.colorOdd = colorOdd;
391             this.reflection = reflection;
392             this.transparency = transparency;
393             this.gloss = gloss;
394             this.density = density;
395             this.hasTexture = true;
396         },
398         getColor: function(u, v){
399             var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
401             if(t < 0.0)
402                 return this.colorEven;
403             else
404                 return this.colorOdd;
405         },
407         toString : function () {
408             return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
409         }
410     }
412 /* Fake a Flog.* namespace */
413 if(typeof(Flog) == 'undefined') var Flog = {};
414 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
415 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
417 Flog.RayTracer.Shape.Sphere = Class.create();
419 Flog.RayTracer.Shape.Sphere.prototype = {
420     initialize : function(pos, radius, material) {
421         this.radius = radius;
422         this.position = pos;
423         this.material = material;
424     },
426     intersect: function(ray){
427         var info = new Flog.RayTracer.IntersectionInfo();
428         info.shape = this;
430         var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
432         var B = dst.dot(ray.direction);
433         var C = dst.dot(dst) - (this.radius * this.radius);
434         var D = (B * B) - C;
436         if(D > 0){ // intersection!
437             info.isHit = true;
438             info.distance = (-B) - Math.sqrt(D);
439             info.position = Flog.RayTracer.Vector.prototype.add(
440                                                 ray.position,
441                                                 Flog.RayTracer.Vector.prototype.multiplyScalar(
442                                                     ray.direction,
443                                                     info.distance
444                                                 )
445                                             );
446             info.normal = Flog.RayTracer.Vector.prototype.subtract(
447                                             info.position,
448                                             this.position
449                                         ).normalize();
451             info.color = this.material.getColor(0,0);
452         } else {
453             info.isHit = false;
454         }
455         return info;
456     },
458     toString : function () {
459         return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
460     }
462 /* Fake a Flog.* namespace */
463 if(typeof(Flog) == 'undefined') var Flog = {};
464 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
465 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
467 Flog.RayTracer.Shape.Plane = Class.create();
469 Flog.RayTracer.Shape.Plane.prototype = {
470     d: 0.0,
472     initialize : function(pos, d, material) {
473         this.position = pos;
474         this.d = d;
475         this.material = material;
476     },
478     intersect: function(ray){
479         var info = new Flog.RayTracer.IntersectionInfo();
481         var Vd = this.position.dot(ray.direction);
482         if(Vd == 0) return info; // no intersection
484         var t = -(this.position.dot(ray.position) + this.d) / Vd;
485         if(t <= 0) return info;
487         info.shape = this;
488         info.isHit = true;
489         info.position = Flog.RayTracer.Vector.prototype.add(
490                                             ray.position,
491                                             Flog.RayTracer.Vector.prototype.multiplyScalar(
492                                                 ray.direction,
493                                                 t
494                                             )
495                                         );
496         info.normal = this.position;
497         info.distance = t;
499         if(this.material.hasTexture){
500             var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
501             var vV = vU.cross(this.position);
502             var u = info.position.dot(vU);
503             var v = info.position.dot(vV);
504             info.color = this.material.getColor(u,v);
505         } else {
506             info.color = this.material.getColor(0,0);
507         }
509         return info;
510     },
512     toString : function () {
513         return 'Plane [' + this.position + ', d=' + this.d + ']';
514     }
516 /* Fake a Flog.* namespace */
517 if(typeof(Flog) == 'undefined') var Flog = {};
518 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
520 Flog.RayTracer.IntersectionInfo = Class.create();
522 Flog.RayTracer.IntersectionInfo.prototype = {
523     isHit: false,
524     hitCount: 0,
525     shape: null,
526     position: null,
527     normal: null,
528     color: null,
529     distance: null,
531     initialize : function() {
532         this.color = new Flog.RayTracer.Color(0,0,0);
533     },
535     toString : function () {
536         return 'Intersection [' + this.position + ']';
537     }
539 /* Fake a Flog.* namespace */
540 if(typeof(Flog) == 'undefined') var Flog = {};
541 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
543 Flog.RayTracer.Camera = Class.create();
545 Flog.RayTracer.Camera.prototype = {
546     position: null,
547     lookAt: null,
548     equator: null,
549     up: null,
550     screen: null,
552     initialize : function(pos, lookAt, up) {
553         this.position = pos;
554         this.lookAt = lookAt;
555         this.up = up;
556         this.equator = lookAt.normalize().cross(this.up);
557         this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
558     },
560     getRay: function(vx, vy){
561         var pos = Flog.RayTracer.Vector.prototype.subtract(
562             this.screen,
563             Flog.RayTracer.Vector.prototype.subtract(
564                 Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
565                 Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
566             )
567         );
568         pos.y = pos.y * -1;
569         var dir = Flog.RayTracer.Vector.prototype.subtract(
570             pos,
571             this.position
572         );
574         var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
576         return ray;
577     },
579     toString : function () {
580         return 'Ray []';
581     }
583 /* Fake a Flog.* namespace */
584 if(typeof(Flog) == 'undefined') var Flog = {};
585 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
587 Flog.RayTracer.Background = Class.create();
589 Flog.RayTracer.Background.prototype = {
590     color : null,
591     ambience : 0.0,
593     initialize : function(color, ambience) {
594         this.color = color;
595         this.ambience = ambience;
596     }
598 /* Fake a Flog.* namespace */
599 if(typeof(Flog) == 'undefined') var Flog = {};
600 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
602 Flog.RayTracer.Engine = Class.create();
604 Flog.RayTracer.Engine.prototype = {
605     canvas: null, /* 2d context we can render to */
607     initialize: function(options){
608         this.options = Object.extend({
609                 canvasHeight: 100,
610                 canvasWidth: 100,
611                 pixelWidth: 2,
612                 pixelHeight: 2,
613                 renderDiffuse: false,
614                 renderShadows: false,
615                 renderHighlights: false,
616                 renderReflections: false,
617                 rayDepth: 2
618             }, options || {});
620         this.options.canvasHeight /= this.options.pixelHeight;
621         this.options.canvasWidth /= this.options.pixelWidth;
623         /* TODO: dynamically include other scripts */
624     },
626     setPixel: function(x, y, color){
627         var pxW, pxH;
628         pxW = this.options.pixelWidth;
629         pxH = this.options.pixelHeight;
631         if (this.canvas) {
632           this.canvas.fillStyle = color.toString();
633           this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
634         } else {
635           if (x ===  y) {
636             checkNumber += color.brightness();
637           }
638           // print(x * pxW, y * pxH, pxW, pxH);
639         }
640     },
642     renderScene: function(scene, canvas){
643         checkNumber = 0;
644         /* Get canvas */
645         if (canvas) {
646           this.canvas = canvas.getContext("2d");
647         } else {
648           this.canvas = null;
649         }
651         var canvasHeight = this.options.canvasHeight;
652         var canvasWidth = this.options.canvasWidth;
654         for(var y=0; y < canvasHeight; y++){
655             for(var x=0; x < canvasWidth; x++){
656                 var yp = y * 1.0 / canvasHeight * 2 - 1;
657                         var xp = x * 1.0 / canvasWidth * 2 - 1;
659                         var ray = scene.camera.getRay(xp, yp);
661                         var color = this.getPixelColor(ray, scene);
663                 this.setPixel(x, y, color);
664             }
665         }
666         if (checkNumber !== 2321) {
667           throw new Error("Scene rendered incorrectly");
668         }
669     },
671     getPixelColor: function(ray, scene){
672         var info = this.testIntersection(ray, scene, null);
673         if(info.isHit){
674             var color = this.rayTrace(info, ray, scene, 0);
675             return color;
676         }
677         return scene.background.color;
678     },
680     testIntersection: function(ray, scene, exclude){
681         var hits = 0;
682         var best = new Flog.RayTracer.IntersectionInfo();
683         best.distance = 2000;
685         for(var i=0; i<scene.shapes.length; i++){
686             var shape = scene.shapes[i];
688             if(shape != exclude){
689                 var info = shape.intersect(ray);
690                 if(info.isHit && info.distance >= 0 && info.distance < best.distance){
691                     best = info;
692                     hits++;
693                 }
694             }
695         }
696         best.hitCount = hits;
697         return best;
698     },
700     getReflectionRay: function(P,N,V){
701         var c1 = -N.dot(V);
702         var R1 = Flog.RayTracer.Vector.prototype.add(
703             Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
704             V
705         );
706         return new Flog.RayTracer.Ray(P, R1);
707     },
709     rayTrace: function(info, ray, scene, depth){
710         // Calc ambient
711         var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
712         var oldColor = color;
713         var shininess = Math.pow(10, info.shape.material.gloss + 1);
715         for(var i=0; i<scene.lights.length; i++){
716             var light = scene.lights[i];
718             // Calc diffuse lighting
719             var v = Flog.RayTracer.Vector.prototype.subtract(
720                                 light.position,
721                                 info.position
722                             ).normalize();
724             if(this.options.renderDiffuse){
725                 var L = v.dot(info.normal);
726                 if(L > 0.0){
727                     color = Flog.RayTracer.Color.prototype.add(
728                                         color,
729                                         Flog.RayTracer.Color.prototype.multiply(
730                                             info.color,
731                                             Flog.RayTracer.Color.prototype.multiplyScalar(
732                                                 light.color,
733                                                 L
734                                             )
735                                         )
736                                     );
737                 }
738             }
740             // The greater the depth the more accurate the colours, but
741             // this is exponentially (!) expensive
742             if(depth <= this.options.rayDepth){
743           // calculate reflection ray
744           if(this.options.renderReflections && info.shape.material.reflection > 0)
745           {
746               var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
747               var refl = this.testIntersection(reflectionRay, scene, info.shape);
749               if (refl.isHit && refl.distance > 0){
750                   refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
751               } else {
752                   refl.color = scene.background.color;
753                         }
755                   color = Flog.RayTracer.Color.prototype.blend(
756                     color,
757                     refl.color,
758                     info.shape.material.reflection
759                   );
760           }
762                 // Refraction
763                 /* TODO */
764             }
766             /* Render shadows and highlights */
768             var shadowInfo = new Flog.RayTracer.IntersectionInfo();
770             if(this.options.renderShadows){
771                 var shadowRay = new Flog.RayTracer.Ray(info.position, v);
773                 shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
774                 if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
775                     var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
776                     var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
777                     color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
778                 }
779             }
781       // Phong specular highlights
782       if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
783         var Lv = Flog.RayTracer.Vector.prototype.subtract(
784                             info.shape.position,
785                             light.position
786                         ).normalize();
788         var E = Flog.RayTracer.Vector.prototype.subtract(
789                             scene.camera.position,
790                             info.shape.position
791                         ).normalize();
793         var H = Flog.RayTracer.Vector.prototype.subtract(
794                             E,
795                             Lv
796                         ).normalize();
798         var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
799         color = Flog.RayTracer.Color.prototype.add(
800                             Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
801                             color
802                         );
803       }
804         }
805         color.limit();
806         return color;
807     }
811 function renderScene(){
812     var scene = new Flog.RayTracer.Scene();
814     scene.camera = new Flog.RayTracer.Camera(
815                         new Flog.RayTracer.Vector(0, 0, -15),
816                         new Flog.RayTracer.Vector(-0.2, 0, 5),
817                         new Flog.RayTracer.Vector(0, 1, 0)
818                     );
820     scene.background = new Flog.RayTracer.Background(
821                                 new Flog.RayTracer.Color(0.5, 0.5, 0.5),
822                                 0.4
823                             );
825     var sphere = new Flog.RayTracer.Shape.Sphere(
826         new Flog.RayTracer.Vector(-1.5, 1.5, 2),
827         1.5,
828         new Flog.RayTracer.Material.Solid(
829             new Flog.RayTracer.Color(0,0.5,0.5),
830             0.3,
831             0.0,
832             0.0,
833             2.0
834         )
835     );
837     var sphere1 = new Flog.RayTracer.Shape.Sphere(
838         new Flog.RayTracer.Vector(1, 0.25, 1),
839         0.5,
840         new Flog.RayTracer.Material.Solid(
841             new Flog.RayTracer.Color(0.9,0.9,0.9),
842             0.1,
843             0.0,
844             0.0,
845             1.5
846         )
847     );
849     var plane = new Flog.RayTracer.Shape.Plane(
850                                 new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
851                                 1.2,
852                                 new Flog.RayTracer.Material.Chessboard(
853                                     new Flog.RayTracer.Color(1,1,1),
854                                     new Flog.RayTracer.Color(0,0,0),
855                                     0.2,
856                                     0.0,
857                                     1.0,
858                                     0.7
859                                 )
860                             );
862     scene.shapes.push(plane);
863     scene.shapes.push(sphere);
864     scene.shapes.push(sphere1);
866     var light = new Flog.RayTracer.Light(
867         new Flog.RayTracer.Vector(5, 10, -1),
868         new Flog.RayTracer.Color(0.8, 0.8, 0.8)
869     );
871     var light1 = new Flog.RayTracer.Light(
872         new Flog.RayTracer.Vector(-3, 5, -15),
873         new Flog.RayTracer.Color(0.8, 0.8, 0.8),
874         100
875     );
877     scene.lights.push(light);
878     scene.lights.push(light1);
880     var imageWidth = 100; // $F('imageWidth');
881     var imageHeight = 100; // $F('imageHeight');
882     var pixelSize = "5,5".split(','); //  $F('pixelSize').split(',');
883     var renderDiffuse = true; // $F('renderDiffuse');
884     var renderShadows = true; // $F('renderShadows');
885     var renderHighlights = true; // $F('renderHighlights');
886     var renderReflections = true; // $F('renderReflections');
887     var rayDepth = 2;//$F('rayDepth');
889     var raytracer = new Flog.RayTracer.Engine(
890         {
891             canvasWidth: imageWidth,
892             canvasHeight: imageHeight,
893             pixelWidth: pixelSize[0],
894             pixelHeight: pixelSize[1],
895             "renderDiffuse": renderDiffuse,
896             "renderHighlights": renderHighlights,
897             "renderShadows": renderShadows,
898             "renderReflections": renderReflections,
899             "rayDepth": rayDepth
900         }
901     );
903     raytracer.renderScene(scene, null, 0);