| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323 |
- // Copyright 2013 the V8 project authors. All rights reserved.
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following
- // disclaimer in the documentation and/or other materials provided
- // with the distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived
- // from this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // Performance.now is used in latency benchmarks, the fallback is Date.now.
- var performance = performance || {};
- performance.now = (function() {
- return performance.now ||
- performance.mozNow ||
- performance.msNow ||
- performance.oNow ||
- performance.webkitNow ||
- Date.now;
- })();
- // Simple framework for running the benchmark suites and
- // computing a score based on the timing measurements.
- // A benchmark has a name (string) and a function that will be run to
- // do the performance measurement. The optional setup and tearDown
- // arguments are functions that will be invoked before and after
- // running the benchmark, but the running time of these functions will
- // not be accounted for in the benchmark score.
- function Benchmark(name, doWarmup, doDeterministic, deterministicIterations,
- run, setup, tearDown, rmsResult, minIterations) {
- this.name = name;
- this.doWarmup = doWarmup;
- this.doDeterministic = doDeterministic;
- this.deterministicIterations = deterministicIterations;
- this.run = run;
- this.Setup = setup ? setup : function() { };
- this.TearDown = tearDown ? tearDown : function() { };
- this.rmsResult = rmsResult ? rmsResult : null;
- this.minIterations = minIterations ? minIterations : 32;
- }
- // Benchmark results hold the benchmark and the measured time used to
- // run the benchmark. The benchmark score is computed later once a
- // full benchmark suite has run to completion. If latency is set to 0
- // then there is no latency score for this benchmark.
- function BenchmarkResult(benchmark, time, latency) {
- this.benchmark = benchmark;
- this.time = time;
- this.latency = latency;
- }
- // Automatically convert results to numbers. Used by the geometric
- // mean computation.
- BenchmarkResult.prototype.valueOf = function() {
- return this.time;
- }
- // Suites of benchmarks consist of a name and the set of benchmarks in
- // addition to the reference timing that the final score will be based
- // on. This way, all scores are relative to a reference run and higher
- // scores implies better performance.
- function BenchmarkSuite(name, reference, benchmarks) {
- this.name = name;
- this.reference = reference;
- this.benchmarks = benchmarks;
- BenchmarkSuite.suites.push(this);
- }
- // Keep track of all declared benchmark suites.
- BenchmarkSuite.suites = [];
- // Scores are not comparable across versions. Bump the version if
- // you're making changes that will affect that scores, e.g. if you add
- // a new benchmark or change an existing one.
- BenchmarkSuite.version = '9';
- // Defines global benchsuite running mode that overrides benchmark suite
- // behavior. Intended to be set by the benchmark driver. Undefined
- // values here allow a benchmark to define behaviour itself.
- BenchmarkSuite.config = {
- doWarmup: undefined,
- doDeterministic: undefined
- };
- // Override the alert function to throw an exception instead.
- alert = function(s) {
- throw "Alert called with argument: " + s;
- };
- // To make the benchmark results predictable, we replace Math.random
- // with a 100% deterministic alternative.
- BenchmarkSuite.ResetRNG = function() {
- Math.random = (function() {
- var seed = 49734321;
- return function() {
- // Robert Jenkins' 32 bit integer hash function.
- seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
- seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
- seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
- seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
- seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
- seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
- return (seed & 0xfffffff) / 0x10000000;
- };
- })();
- }
- // Runs all registered benchmark suites and optionally yields between
- // each individual benchmark to avoid running for too long in the
- // context of browsers. Once done, the final score is reported to the
- // runner.
- BenchmarkSuite.RunSuites = function(runner, skipBenchmarks) {
- skipBenchmarks = typeof skipBenchmarks === 'undefined' ? [] : skipBenchmarks;
- var continuation = null;
- var suites = BenchmarkSuite.suites;
- var length = suites.length;
- BenchmarkSuite.scores = [];
- var index = 0;
- function RunStep() {
- while (continuation || index < length) {
- if (continuation) {
- continuation = continuation();
- } else {
- var suite = suites[index++];
- if (runner.NotifyStart) runner.NotifyStart(suite.name);
- if (skipBenchmarks.indexOf(suite.name) > -1) {
- suite.NotifySkipped(runner);
- } else {
- continuation = suite.RunStep(runner);
- }
- }
- if (continuation && typeof window != 'undefined' && window.setTimeout) {
- window.setTimeout(RunStep, 25);
- return;
- }
- }
- // show final result
- if (runner.NotifyScore) {
- var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
- var formatted = BenchmarkSuite.FormatScore(100 * score);
- runner.NotifyScore(formatted);
- }
- }
- RunStep();
- }
- // Counts the total number of registered benchmarks. Useful for
- // showing progress as a percentage.
- BenchmarkSuite.CountBenchmarks = function() {
- var result = 0;
- var suites = BenchmarkSuite.suites;
- for (var i = 0; i < suites.length; i++) {
- result += suites[i].benchmarks.length;
- }
- return result;
- }
- // Computes the geometric mean of a set of numbers.
- BenchmarkSuite.GeometricMean = function(numbers) {
- var log = 0;
- for (var i = 0; i < numbers.length; i++) {
- log += Math.log(numbers[i]);
- }
- return Math.pow(Math.E, log / numbers.length);
- }
- // Computes the geometric mean of a set of throughput time measurements.
- BenchmarkSuite.GeometricMeanTime = function(measurements) {
- var log = 0;
- for (var i = 0; i < measurements.length; i++) {
- log += Math.log(measurements[i].time);
- }
- return Math.pow(Math.E, log / measurements.length);
- }
- // Computes the geometric mean of a set of rms measurements.
- BenchmarkSuite.GeometricMeanLatency = function(measurements) {
- var log = 0;
- var hasLatencyResult = false;
- for (var i = 0; i < measurements.length; i++) {
- if (measurements[i].latency != 0) {
- log += Math.log(measurements[i].latency);
- hasLatencyResult = true;
- }
- }
- if (hasLatencyResult) {
- return Math.pow(Math.E, log / measurements.length);
- } else {
- return 0;
- }
- }
- // Converts a score value to a string with at least three significant
- // digits.
- BenchmarkSuite.FormatScore = function(value) {
- if (value > 100) {
- return value.toFixed(0);
- } else {
- return value.toPrecision(3);
- }
- }
- // Notifies the runner that we're done running a single benchmark in
- // the benchmark suite. This can be useful to report progress.
- BenchmarkSuite.prototype.NotifyStep = function(result) {
- this.results.push(result);
- if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
- }
- // Notifies the runner that we're done with running a suite and that
- // we have a result which can be reported to the user if needed.
- BenchmarkSuite.prototype.NotifyResult = function() {
- var mean = BenchmarkSuite.GeometricMeanTime(this.results);
- var score = this.reference[0] / mean;
- BenchmarkSuite.scores.push(score);
- if (this.runner.NotifyResult) {
- var formatted = BenchmarkSuite.FormatScore(100 * score);
- this.runner.NotifyResult(this.name, formatted);
- }
- if (this.reference.length == 2) {
- var meanLatency = BenchmarkSuite.GeometricMeanLatency(this.results);
- if (meanLatency != 0) {
- var scoreLatency = this.reference[1] / meanLatency;
- BenchmarkSuite.scores.push(scoreLatency);
- if (this.runner.NotifyResult) {
- var formattedLatency = BenchmarkSuite.FormatScore(100 * scoreLatency)
- this.runner.NotifyResult(this.name + "Latency", formattedLatency);
- }
- }
- }
- }
- BenchmarkSuite.prototype.NotifySkipped = function(runner) {
- BenchmarkSuite.scores.push(1); // push default reference score.
- if (runner.NotifyResult) {
- runner.NotifyResult(this.name, "Skipped");
- }
- }
- // Notifies the runner that running a benchmark resulted in an error.
- BenchmarkSuite.prototype.NotifyError = function(error) {
- if (this.runner.NotifyError) {
- this.runner.NotifyError(this.name, error);
- }
- if (this.runner.NotifyStep) {
- this.runner.NotifyStep(this.name);
- }
- }
- // Runs a single benchmark for at least a second and computes the
- // average time it takes to run a single iteration.
- BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) {
- var config = BenchmarkSuite.config;
- var doWarmup = config.doWarmup !== undefined
- ? config.doWarmup
- : benchmark.doWarmup;
- var doDeterministic = config.doDeterministic !== undefined
- ? config.doDeterministic
- : benchmark.doDeterministic;
- function Measure(data) {
- var elapsed = 0;
- var start = new Date();
-
- // Run either for 1 second or for the number of iterations specified
- // by minIterations, depending on the config flag doDeterministic.
- for (var i = 0; (doDeterministic ?
- i<benchmark.deterministicIterations : elapsed < 1000); i++) {
- benchmark.run();
- elapsed = new Date() - start;
- }
- if (data != null) {
- data.runs += i;
- data.elapsed += elapsed;
- }
- }
- // Sets up data in order to skip or not the warmup phase.
- if (!doWarmup && data == null) {
- data = { runs: 0, elapsed: 0 };
- }
- if (data == null) {
- Measure(null);
- return { runs: 0, elapsed: 0 };
- } else {
- Measure(data);
- // If we've run too few iterations, we continue for another second.
- if (data.runs < benchmark.minIterations) return data;
- var usec = (data.elapsed * 1000) / data.runs;
- var rms = (benchmark.rmsResult != null) ? benchmark.rmsResult() : 0;
- this.NotifyStep(new BenchmarkResult(benchmark, usec, rms));
- return null;
- }
- }
- // This function starts running a suite, but stops between each
- // individual benchmark in the suite and returns a continuation
- // function which can be invoked to run the next benchmark. Once the
- // last benchmark has been executed, null is returned.
- BenchmarkSuite.prototype.RunStep = function(runner) {
- BenchmarkSuite.ResetRNG();
- this.results = [];
- this.runner = runner;
- var length = this.benchmarks.length;
- var index = 0;
- var suite = this;
- var data;
- // Run the setup, the actual benchmark, and the tear down in three
- // separate steps to allow the framework to yield between any of the
- // steps.
- function RunNextSetup() {
- if (index < length) {
- try {
- suite.benchmarks[index].Setup();
- } catch (e) {
- suite.NotifyError(e);
- return null;
- }
- return RunNextBenchmark;
- }
- suite.NotifyResult();
- return null;
- }
- function RunNextBenchmark() {
- try {
- data = suite.RunSingleBenchmark(suite.benchmarks[index], data);
- } catch (e) {
- suite.NotifyError(e);
- return null;
- }
- // If data is null, we're done with this benchmark.
- return (data == null) ? RunNextTearDown : RunNextBenchmark();
- }
- function RunNextTearDown() {
- try {
- suite.benchmarks[index++].TearDown();
- } catch (e) {
- suite.NotifyError(e);
- return null;
- }
- return RunNextSetup;
- }
- // Start out running the setup.
- return RunNextSetup();
- }
- // The ray tracer code in this file is written by Adam Burmister. It
- // is available in its original form from:
- //
- // http://labs.flog.nz.co/raytracer/
- //
- // It has been modified slightly by Google to work as a standalone
- // benchmark, but the all the computational code remains
- // untouched. This file also contains a copy of parts of the Prototype
- // JavaScript framework which is used by the ray tracer.
- var RayTrace = new BenchmarkSuite('RayTrace', [739989], [
- new Benchmark('RayTrace', true, false, 600, renderScene)
- ]);
- // Variable used to hold a number that can be used to verify that
- // the scene was ray traced correctly.
- var checkNumber;
- // ------------------------------------------------------------------------
- // ------------------------------------------------------------------------
- // The following is a copy of parts of the Prototype JavaScript library:
- // Prototype JavaScript framework, version 1.5.0
- // (c) 2005-2007 Sam Stephenson
- //
- // Prototype is freely distributable under the terms of an MIT-style license.
- // For details, see the Prototype web site: http://prototype.conio.net/
- var Class = {
- create: function() {
- return function() {
- this.initialize.apply(this, arguments);
- }
- }
- };
- Object.extend = function(destination, source) {
- for (var property in source) {
- destination[property] = source[property];
- }
- return destination;
- };
- // ------------------------------------------------------------------------
- // ------------------------------------------------------------------------
- // The rest of this file is the actual ray tracer written by Adam
- // Burmister. It's a concatenation of the following files:
- //
- // flog/color.js
- // flog/light.js
- // flog/vector.js
- // flog/ray.js
- // flog/scene.js
- // flog/material/basematerial.js
- // flog/material/solid.js
- // flog/material/chessboard.js
- // flog/shape/baseshape.js
- // flog/shape/sphere.js
- // flog/shape/plane.js
- // flog/intersectioninfo.js
- // flog/camera.js
- // flog/background.js
- // flog/engine.js
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Color = Class.create();
- Flog.RayTracer.Color.prototype = {
- red : 0.0,
- green : 0.0,
- blue : 0.0,
- initialize : function(r, g, b) {
- if(!r) r = 0.0;
- if(!g) g = 0.0;
- if(!b) b = 0.0;
- this.red = r;
- this.green = g;
- this.blue = b;
- },
- add : function(c1, c2){
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red + c2.red;
- result.green = c1.green + c2.green;
- result.blue = c1.blue + c2.blue;
- return result;
- },
- addScalar: function(c1, s){
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red + s;
- result.green = c1.green + s;
- result.blue = c1.blue + s;
- result.limit();
- return result;
- },
- subtract: function(c1, c2){
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red - c2.red;
- result.green = c1.green - c2.green;
- result.blue = c1.blue - c2.blue;
- return result;
- },
- multiply : function(c1, c2) {
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red * c2.red;
- result.green = c1.green * c2.green;
- result.blue = c1.blue * c2.blue;
- return result;
- },
- multiplyScalar : function(c1, f) {
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red * f;
- result.green = c1.green * f;
- result.blue = c1.blue * f;
- return result;
- },
- divideFactor : function(c1, f) {
- var result = new Flog.RayTracer.Color(0,0,0);
- result.red = c1.red / f;
- result.green = c1.green / f;
- result.blue = c1.blue / f;
- return result;
- },
- limit: function(){
- this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0;
- this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0;
- this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0;
- },
- distance : function(color) {
- var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
- return d;
- },
- blend: function(c1, c2, w){
- var result = new Flog.RayTracer.Color(0,0,0);
- result = Flog.RayTracer.Color.prototype.add(
- Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),
- Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)
- );
- return result;
- },
- brightness : function() {
- var r = Math.floor(this.red*255);
- var g = Math.floor(this.green*255);
- var b = Math.floor(this.blue*255);
- return (r * 77 + g * 150 + b * 29) >> 8;
- },
- toString : function () {
- var r = Math.floor(this.red*255);
- var g = Math.floor(this.green*255);
- var b = Math.floor(this.blue*255);
- return "rgb("+ r +","+ g +","+ b +")";
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Light = Class.create();
- Flog.RayTracer.Light.prototype = {
- position: null,
- color: null,
- intensity: 10.0,
- initialize : function(pos, color, intensity) {
- this.position = pos;
- this.color = color;
- this.intensity = (intensity ? intensity : 10.0);
- },
- toString : function () {
- return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Vector = Class.create();
- Flog.RayTracer.Vector.prototype = {
- x : 0.0,
- y : 0.0,
- z : 0.0,
- initialize : function(x, y, z) {
- this.x = (x ? x : 0);
- this.y = (y ? y : 0);
- this.z = (z ? z : 0);
- },
- copy: function(vector){
- this.x = vector.x;
- this.y = vector.y;
- this.z = vector.z;
- },
- normalize : function() {
- var m = this.magnitude();
- return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
- },
- magnitude : function() {
- return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
- },
- cross : function(w) {
- return new Flog.RayTracer.Vector(
- -this.z * w.y + this.y * w.z,
- this.z * w.x - this.x * w.z,
- -this.y * w.x + this.x * w.y);
- },
- dot : function(w) {
- return this.x * w.x + this.y * w.y + this.z * w.z;
- },
- add : function(v, w) {
- return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
- },
- subtract : function(v, w) {
- if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
- return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
- },
- multiplyVector : function(v, w) {
- return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
- },
- multiplyScalar : function(v, w) {
- return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
- },
- toString : function () {
- return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Ray = Class.create();
- Flog.RayTracer.Ray.prototype = {
- position : null,
- direction : null,
- initialize : function(pos, dir) {
- this.position = pos;
- this.direction = dir;
- },
- toString : function () {
- return 'Ray [' + this.position + ',' + this.direction + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Scene = Class.create();
- Flog.RayTracer.Scene.prototype = {
- camera : null,
- shapes : [],
- lights : [],
- background : null,
- initialize : function() {
- this.camera = new Flog.RayTracer.Camera(
- new Flog.RayTracer.Vector(0,0,-5),
- new Flog.RayTracer.Vector(0,0,1),
- new Flog.RayTracer.Vector(0,1,0)
- );
- this.shapes = new Array();
- this.lights = new Array();
- this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
- Flog.RayTracer.Material.BaseMaterial = Class.create();
- Flog.RayTracer.Material.BaseMaterial.prototype = {
- gloss: 2.0, // [0...infinity] 0 = matt
- transparency: 0.0, // 0=opaque
- reflection: 0.0, // [0...infinity] 0 = no reflection
- refraction: 0.50,
- hasTexture: false,
- initialize : function() {
- },
- getColor: function(u, v){
- },
- wrapUp: function(t){
- t = t % 2.0;
- if(t < -1) t += 2.0;
- if(t >= 1) t -= 2.0;
- return t;
- },
- toString : function () {
- return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Material.Solid = Class.create();
- Flog.RayTracer.Material.Solid.prototype = Object.extend(
- new Flog.RayTracer.Material.BaseMaterial(), {
- initialize : function(color, reflection, refraction, transparency, gloss) {
- this.color = color;
- this.reflection = reflection;
- this.transparency = transparency;
- this.gloss = gloss;
- this.hasTexture = false;
- },
- getColor: function(u, v){
- return this.color;
- },
- toString : function () {
- return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
- }
- }
- );
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Material.Chessboard = Class.create();
- Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
- new Flog.RayTracer.Material.BaseMaterial(), {
- colorEven: null,
- colorOdd: null,
- density: 0.5,
- initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
- this.colorEven = colorEven;
- this.colorOdd = colorOdd;
- this.reflection = reflection;
- this.transparency = transparency;
- this.gloss = gloss;
- this.density = density;
- this.hasTexture = true;
- },
- getColor: function(u, v){
- var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
- if(t < 0.0)
- return this.colorEven;
- else
- return this.colorOdd;
- },
- toString : function () {
- return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
- }
- }
- );
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
- Flog.RayTracer.Shape.Sphere = Class.create();
- Flog.RayTracer.Shape.Sphere.prototype = {
- initialize : function(pos, radius, material) {
- this.radius = radius;
- this.position = pos;
- this.material = material;
- },
- intersect: function(ray){
- var info = new Flog.RayTracer.IntersectionInfo();
- info.shape = this;
- var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
- var B = dst.dot(ray.direction);
- var C = dst.dot(dst) - (this.radius * this.radius);
- var D = (B * B) - C;
- if(D > 0){ // intersection!
- info.isHit = true;
- info.distance = (-B) - Math.sqrt(D);
- info.position = Flog.RayTracer.Vector.prototype.add(
- ray.position,
- Flog.RayTracer.Vector.prototype.multiplyScalar(
- ray.direction,
- info.distance
- )
- );
- info.normal = Flog.RayTracer.Vector.prototype.subtract(
- info.position,
- this.position
- ).normalize();
- info.color = this.material.getColor(0,0);
- } else {
- info.isHit = false;
- }
- return info;
- },
- toString : function () {
- return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
- Flog.RayTracer.Shape.Plane = Class.create();
- Flog.RayTracer.Shape.Plane.prototype = {
- d: 0.0,
- initialize : function(pos, d, material) {
- this.position = pos;
- this.d = d;
- this.material = material;
- },
- intersect: function(ray){
- var info = new Flog.RayTracer.IntersectionInfo();
- var Vd = this.position.dot(ray.direction);
- if(Vd == 0) return info; // no intersection
- var t = -(this.position.dot(ray.position) + this.d) / Vd;
- if(t <= 0) return info;
- info.shape = this;
- info.isHit = true;
- info.position = Flog.RayTracer.Vector.prototype.add(
- ray.position,
- Flog.RayTracer.Vector.prototype.multiplyScalar(
- ray.direction,
- t
- )
- );
- info.normal = this.position;
- info.distance = t;
- if(this.material.hasTexture){
- var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
- var vV = vU.cross(this.position);
- var u = info.position.dot(vU);
- var v = info.position.dot(vV);
- info.color = this.material.getColor(u,v);
- } else {
- info.color = this.material.getColor(0,0);
- }
- return info;
- },
- toString : function () {
- return 'Plane [' + this.position + ', d=' + this.d + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.IntersectionInfo = Class.create();
- Flog.RayTracer.IntersectionInfo.prototype = {
- isHit: false,
- hitCount: 0,
- shape: null,
- position: null,
- normal: null,
- color: null,
- distance: null,
- initialize : function() {
- this.color = new Flog.RayTracer.Color(0,0,0);
- },
- toString : function () {
- return 'Intersection [' + this.position + ']';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Camera = Class.create();
- Flog.RayTracer.Camera.prototype = {
- position: null,
- lookAt: null,
- equator: null,
- up: null,
- screen: null,
- initialize : function(pos, lookAt, up) {
- this.position = pos;
- this.lookAt = lookAt;
- this.up = up;
- this.equator = lookAt.normalize().cross(this.up);
- this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
- },
- getRay: function(vx, vy){
- var pos = Flog.RayTracer.Vector.prototype.subtract(
- this.screen,
- Flog.RayTracer.Vector.prototype.subtract(
- Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
- Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
- )
- );
- pos.y = pos.y * -1;
- var dir = Flog.RayTracer.Vector.prototype.subtract(
- pos,
- this.position
- );
- var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
- return ray;
- },
- toString : function () {
- return 'Ray []';
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Background = Class.create();
- Flog.RayTracer.Background.prototype = {
- color : null,
- ambience : 0.0,
- initialize : function(color, ambience) {
- this.color = color;
- this.ambience = ambience;
- }
- }
- /* Fake a Flog.* namespace */
- if(typeof(Flog) == 'undefined') var Flog = {};
- if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
- Flog.RayTracer.Engine = Class.create();
- Flog.RayTracer.Engine.prototype = {
- canvas: null, /* 2d context we can render to */
- initialize: function(options){
- this.options = Object.extend({
- canvasHeight: 100,
- canvasWidth: 100,
- pixelWidth: 2,
- pixelHeight: 2,
- renderDiffuse: false,
- renderShadows: false,
- renderHighlights: false,
- renderReflections: false,
- rayDepth: 2
- }, options || {});
- this.options.canvasHeight /= this.options.pixelHeight;
- this.options.canvasWidth /= this.options.pixelWidth;
- /* TODO: dynamically include other scripts */
- },
- setPixel: function(x, y, color){
- var pxW, pxH;
- pxW = this.options.pixelWidth;
- pxH = this.options.pixelHeight;
- if (this.canvas) {
- this.canvas.fillStyle = color.toString();
- this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
- } else {
- if (x === y) {
- checkNumber += color.brightness();
- }
- // print(x * pxW, y * pxH, pxW, pxH);
- }
- },
- renderScene: function(scene, canvas){
- checkNumber = 0;
- /* Get canvas */
- if (canvas) {
- this.canvas = canvas.getContext("2d");
- } else {
- this.canvas = null;
- }
- var canvasHeight = this.options.canvasHeight;
- var canvasWidth = this.options.canvasWidth;
- for(var y=0; y < canvasHeight; y++){
- for(var x=0; x < canvasWidth; x++){
- var yp = y * 1.0 / canvasHeight * 2 - 1;
- var xp = x * 1.0 / canvasWidth * 2 - 1;
- var ray = scene.camera.getRay(xp, yp);
- var color = this.getPixelColor(ray, scene);
- this.setPixel(x, y, color);
- }
- }
- if (checkNumber !== 2321) {
- throw new Error("Scene rendered incorrectly");
- }
- },
- getPixelColor: function(ray, scene){
- var info = this.testIntersection(ray, scene, null);
- if(info.isHit){
- var color = this.rayTrace(info, ray, scene, 0);
- return color;
- }
- return scene.background.color;
- },
- testIntersection: function(ray, scene, exclude){
- var hits = 0;
- var best = new Flog.RayTracer.IntersectionInfo();
- best.distance = 2000;
- for(var i=0; i<scene.shapes.length; i++){
- var shape = scene.shapes[i];
- if(shape != exclude){
- var info = shape.intersect(ray);
- if(info.isHit && info.distance >= 0 && info.distance < best.distance){
- best = info;
- hits++;
- }
- }
- }
- best.hitCount = hits;
- return best;
- },
- getReflectionRay: function(P,N,V){
- var c1 = -N.dot(V);
- var R1 = Flog.RayTracer.Vector.prototype.add(
- Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
- V
- );
- return new Flog.RayTracer.Ray(P, R1);
- },
- rayTrace: function(info, ray, scene, depth){
- // Calc ambient
- var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
- var oldColor = color;
- var shininess = Math.pow(10, info.shape.material.gloss + 1);
- for(var i=0; i<scene.lights.length; i++){
- var light = scene.lights[i];
- // Calc diffuse lighting
- var v = Flog.RayTracer.Vector.prototype.subtract(
- light.position,
- info.position
- ).normalize();
- if(this.options.renderDiffuse){
- var L = v.dot(info.normal);
- if(L > 0.0){
- color = Flog.RayTracer.Color.prototype.add(
- color,
- Flog.RayTracer.Color.prototype.multiply(
- info.color,
- Flog.RayTracer.Color.prototype.multiplyScalar(
- light.color,
- L
- )
- )
- );
- }
- }
- // The greater the depth the more accurate the colours, but
- // this is exponentially (!) expensive
- if(depth <= this.options.rayDepth){
- // calculate reflection ray
- if(this.options.renderReflections && info.shape.material.reflection > 0)
- {
- var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
- var refl = this.testIntersection(reflectionRay, scene, info.shape);
- if (refl.isHit && refl.distance > 0){
- refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
- } else {
- refl.color = scene.background.color;
- }
- color = Flog.RayTracer.Color.prototype.blend(
- color,
- refl.color,
- info.shape.material.reflection
- );
- }
- // Refraction
- /* TODO */
- }
- /* Render shadows and highlights */
- var shadowInfo = new Flog.RayTracer.IntersectionInfo();
- if(this.options.renderShadows){
- var shadowRay = new Flog.RayTracer.Ray(info.position, v);
- shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
- if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
- var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
- var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
- color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
- }
- }
- // Phong specular highlights
- if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
- var Lv = Flog.RayTracer.Vector.prototype.subtract(
- info.shape.position,
- light.position
- ).normalize();
- var E = Flog.RayTracer.Vector.prototype.subtract(
- scene.camera.position,
- info.shape.position
- ).normalize();
- var H = Flog.RayTracer.Vector.prototype.subtract(
- E,
- Lv
- ).normalize();
- var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
- color = Flog.RayTracer.Color.prototype.add(
- Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
- color
- );
- }
- }
- color.limit();
- return color;
- }
- };
- function renderScene(){
- var scene = new Flog.RayTracer.Scene();
- scene.camera = new Flog.RayTracer.Camera(
- new Flog.RayTracer.Vector(0, 0, -15),
- new Flog.RayTracer.Vector(-0.2, 0, 5),
- new Flog.RayTracer.Vector(0, 1, 0)
- );
- scene.background = new Flog.RayTracer.Background(
- new Flog.RayTracer.Color(0.5, 0.5, 0.5),
- 0.4
- );
- var sphere = new Flog.RayTracer.Shape.Sphere(
- new Flog.RayTracer.Vector(-1.5, 1.5, 2),
- 1.5,
- new Flog.RayTracer.Material.Solid(
- new Flog.RayTracer.Color(0,0.5,0.5),
- 0.3,
- 0.0,
- 0.0,
- 2.0
- )
- );
- var sphere1 = new Flog.RayTracer.Shape.Sphere(
- new Flog.RayTracer.Vector(1, 0.25, 1),
- 0.5,
- new Flog.RayTracer.Material.Solid(
- new Flog.RayTracer.Color(0.9,0.9,0.9),
- 0.1,
- 0.0,
- 0.0,
- 1.5
- )
- );
- var plane = new Flog.RayTracer.Shape.Plane(
- new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
- 1.2,
- new Flog.RayTracer.Material.Chessboard(
- new Flog.RayTracer.Color(1,1,1),
- new Flog.RayTracer.Color(0,0,0),
- 0.2,
- 0.0,
- 1.0,
- 0.7
- )
- );
- scene.shapes.push(plane);
- scene.shapes.push(sphere);
- scene.shapes.push(sphere1);
- var light = new Flog.RayTracer.Light(
- new Flog.RayTracer.Vector(5, 10, -1),
- new Flog.RayTracer.Color(0.8, 0.8, 0.8)
- );
- var light1 = new Flog.RayTracer.Light(
- new Flog.RayTracer.Vector(-3, 5, -15),
- new Flog.RayTracer.Color(0.8, 0.8, 0.8),
- 100
- );
- scene.lights.push(light);
- scene.lights.push(light1);
- var imageWidth = 100; // $F('imageWidth');
- var imageHeight = 100; // $F('imageHeight');
- var pixelSize = "5,5".split(','); // $F('pixelSize').split(',');
- var renderDiffuse = true; // $F('renderDiffuse');
- var renderShadows = true; // $F('renderShadows');
- var renderHighlights = true; // $F('renderHighlights');
- var renderReflections = true; // $F('renderReflections');
- var rayDepth = 2;//$F('rayDepth');
- var raytracer = new Flog.RayTracer.Engine(
- {
- canvasWidth: imageWidth,
- canvasHeight: imageHeight,
- pixelWidth: pixelSize[0],
- pixelHeight: pixelSize[1],
- "renderDiffuse": renderDiffuse,
- "renderHighlights": renderHighlights,
- "renderShadows": renderShadows,
- "renderReflections": renderReflections,
- "rayDepth": rayDepth
- }
- );
- raytracer.renderScene(scene, null, 0);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Runner
- ////////////////////////////////////////////////////////////////////////////////
- var success = true;
- function NotifyStart(name) {
- }
- function NotifyError(name, error) {
- WScript.Echo(name + " : ERROR : " + error.stack);
- success = false;
- }
- function NotifyResult(name, score) {
- if (success) {
- WScript.Echo("### SCORE:", score);
- }
- }
- function NotifyScore(score) {
- }
- BenchmarkSuite.RunSuites({
- NotifyStart: NotifyStart,
- NotifyError: NotifyError,
- NotifyResult: NotifyResult,
- NotifyScore: NotifyScore
- });
|