diff --git a/Q/Q-tests.ts b/Q/Q-tests.ts new file mode 100644 index 000000000..8724ed5a6 --- /dev/null +++ b/Q/Q-tests.ts @@ -0,0 +1,49 @@ +/// + +var delay = function (delay) { + var d = Q.defer(); + setTimeout(d.resolve, delay); + return d.promise; +}; + +Q.when(delay(1000), function () { + console.log('Hello, World!'); +}); + +var eventually = function (eventually) { + return Q.delay(eventually, 1000); +}; + +var x = Q.all([1, 2, 3].map(eventually)); +Q.when(x, function (x) { + console.log(x); +}); + +Q.all([ + eventually(10), + eventually(20) +]) +.spread(function (x, y) { + console.log(x, y); +}); + +Q.fcall(function () { }) +.then(function () { }) +.then(function () { }) +.then(function () { }) +.then(function (value4) { + // Do something with value4 +}, function (error) { + // Handle any error from step1 through step4 +}).done(); + +Q.allResolved([]) +.then(function (promises: Qpromise[]) { + promises.forEach(function (promise) { + if (promise.isFulfilled()) { + var value = promise.valueOf(); + } else { + var exception = promise.valueOf().exception; + } + }) +}); diff --git a/Q/Q.d.ts b/Q/Q.d.ts index f7a871ea4..029550162 100644 --- a/Q/Q.d.ts +++ b/Q/Q.d.ts @@ -8,16 +8,17 @@ interface Qdeferred { resolve(value: any): any; reject(reason: any); notify(value: any); - makeNodeResolver(); + makeNodeResolver(): Function; } interface Qpromise { fail(errorCallback: Function): Qpromise; fin(finallyCallback: Function): Qpromise; then(onFulfilled: Function, onRejected?: Function, onProgress?: Function): Qpromise; + spread(onFulfilled: Function, onRejected?: Function): Qpromise; catch(onRejected: Function): Qpromise; progress(onProgress: Function): Qpromise; - done(onFulfilled: Function, onRejected?: Function, onProgress?: Function): Qpromise; + done(onFulfilled?: Function, onRejected?: Function, onProgress?: Function): Qpromise; get (propertyName: String): Qpromise; set (propertyName: String, value: any): Qpromise; delete (propertyName: String): Qpromise; @@ -35,6 +36,7 @@ interface Qpromise { } interface QStatic { + when(value: any, onFulfilled: Function, onRejected?: Function): Qpromise; try(method: Function, ...args: any[]): Qpromise; fbind(method: Function, ...args: any[]): Qpromise; fcall(method: Function, ...args: any[]): Qpromise; diff --git a/Q/q.module-tests.ts b/Q/q.module-tests.ts new file mode 100644 index 000000000..02116c2e8 --- /dev/null +++ b/Q/q.module-tests.ts @@ -0,0 +1,75 @@ +/// +/// + +import Q = module("q"); + +describe("q", function () { + it("should return", function (done) { + Q({ myValue: true }).then(function (obj) { + + if (obj.myValue) done(); + else done("didn't work =("); + }, + (err) => done(err)); + }); + + it("should process all", function (done: (err?) => void ) { + Q.all([Q(1), Q(2), Q(3)]).then(function (arr: number[]) { + var sum = arr.reduce(function (memo, cur) { + return memo + cur; + }, 0); + + if (sum === 6) done(); + else done({ actual: sum }); + }, + (err) => done(err)); + }); +}); + +var delay = function (delay) { + var d = Q.defer(); + setTimeout(d.resolve, delay); + return d.promise; +}; + +Q.when(delay(1000), function () { + console.log('Hello, World!'); +}); + +var eventually = function (eventually) { + return Q.delay(eventually, 1000); +}; + +var x = Q.all([1, 2, 3].map(eventually)); +Q.when(x, function (x) { + console.log(x); +}); + +Q.all([ + eventually(10), + eventually(20) +]) +.spread(function (x, y) { + console.log(x, y); +}); + +Q.fcall(function () { }) +.then(function () { }) +.then(function () { }) +.then(function () { }) +.then(function (value4) { + // Do something with value4 +}, function (error) { + // Handle any error from step1 through step4 +}).done(); + +Q.allResolved([]) +.then(function (promises: Qpromise[]) { + promises.forEach(function (promise) { + if (promise.isFulfilled()) { + var value = promise.valueOf(); + } else { + var exception = promise.valueOf().exception; + } + }) +}); \ No newline at end of file diff --git a/Q/q.module.d.ts b/Q/q.module.d.ts new file mode 100644 index 000000000..9850e7276 --- /dev/null +++ b/Q/q.module.d.ts @@ -0,0 +1,27 @@ +/// + +module "q" { + export function when(value: any, onFulfilled: Function, onRejected?: Function): Qpromise; + export function try(method: Function, ...args: any[]): Qpromise; + export function fbind(method: Function, ...args: any[]): Qpromise; + export function fcall(method: Function, ...args: any[]): Qpromise; + export function all(promises: Qpromise[]): Qpromise; + export function allResolved(promises: Qpromise[]): Qpromise; + export function spread(onFulfilled: Function, onRejected: Function): Qpromise; + export function timeout(ms: number): Qpromise; + export function delay(ms: number): Qpromise; + export function delay(value: any, ms: number): Qpromise; + export function isFulfilled(): bool; + export function isRejected(): bool; + export function isPending(): bool; + export function valueOf(): any; + export function defer(): Qdeferred; + export function (value: any): Qpromise; + export function reject(): Qpromise; + export function promise(factory: { resolve: Function; reject: Function; notify: Function; }): Qpromise; + export function isPromise(value: any): bool; + export function async(generatorFunction: any): Qdeferred; + export function nextTick(callback: Function); + export var oneerror: any; + export var longStackJumpLimit: number; +} \ No newline at end of file diff --git a/README.md b/README.md index beedf1ea6..843ef6448 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,10 @@ List of Definitions * [Chosen](http://harvesthq.github.com/chosen/) (by [Boris Yankov](https://github.com/borisyankov)) * [Chrome](http://developer.chrome.com/extensions/) (by [Matthew Kimber](https://github.com/matthewkimber)) * [CodeMirror](http://codemirror.net) (by [Fran�ois de Campredon](https://github.com/fdecampredon)) +* [Commander](http://github.com/visionmedia/commander.js) (by [Marcelo Dezem](https://github.com/mdezem)) * [d3.js](http://d3js.org/) (from TypeScript samples) * [domo](http://domo-js.com/) (by [Steve Fenton](https://github.com/Steve-Fenton)) -* [dust](http://linkedin.github.com/dustjs) (by [Marcelo Dezem](https://github.com/mdezem) +* [dust](http://linkedin.github.com/dustjs) (by [Marcelo Dezem](https://github.com/mdezem)) * [EaselJS](http://www.createjs.com/#!/EaselJS) (by [Pedro Ferreira](https://bitbucket.org/drk4)) * [ember.js](http://emberjs.com/) (by [Boris Yankov](https://github.com/borisyankov)) * [EpicEditor](http://epiceditor.com/) (by [Boris Yankov](https://github.com/borisyankov)) @@ -55,9 +56,11 @@ List of Definitions * [Finite State Machine](https://github.com/jakesgordon/javascript-state-machine) (by [Boris Yankov](https://github.com/borisyankov)) * [FlexSlider](http://www.woothemes.com/flexslider/) (by [Diullei Gomes](https://github.com/Diullei)) * [Foundation](http://foundation.zurb.com/) (by [Boris Yankov](https://github.com/borisyankov)) +* [Gamepad](http://www.w3.org/TR/gamepad/) (by [Kon](http://phyzkit.net/)) * [glDatePicker](http://glad.github.com/glDatePicker/) (by [D�niel Tar](https://github.com/qcz)) * [GreenSock Animation Platform (GSAP)](http://www.greensock.com/get-started-js/) (by [Robert S.](https://github.com/codeBelt)) * [GoogleMaps](https://developers.google.com/maps/) (by [Esben Nepper](https://github.com/eNepper)) +* [Google Geolocation](https://code.google.com/p/geo-location-javascript/) (by [Vincent Bortone](https://github.com/vbortone)) * [Hammer.js](http://eightmedia.github.com/hammer.js/) (by [Boris Yankov](https://github.com/borisyankov)) * [Handlebars](http://handlebarsjs.com/) (by [Boris Yankov](https://github.com/borisyankov)) * [Highcharts](http://www.highcharts.com/) (by [damianog](https://github.com/damianog)) @@ -89,6 +92,7 @@ List of Definitions * [jQuery.Transit](http://ricostacruz.com/jquery.transit/) (by [MrBigDog2U](https://github.com/MrBigDog2U)) * [jQuery.Validation](http://bassistance.de/jquery-plugins/jquery-plugin-validation/) (by [Boris Yankov](https://github.com/borisyankov)) * [jQuery.Watermark](http://jquery-watermark.googlecode.com) (by [Anwar Javed](https://github.com/anwarjaved)) +* [JSDeferred](http://cho45.stfuawsc.com/jsdeferred/) (by [Daisuke Mino](https://github.com/minodisk)) * [JSONEditorOnline](https://github.com/josdejong/jsoneditoronline) (by [Vincent Bortone](https://github.com/vbortone/)) * [KeyboardJS](https://github.com/RobertWHurst/KeyboardJS) (by [Vincent Bortone](https://github.com/vbortone/)) * [Knockback](http://kmalakoff.github.com/knockback/) (by [Marcel Binot](https://github.com/docgit)) @@ -102,6 +106,7 @@ List of Definitions * [Leaflet](https://github.com/Leaflet/Leaflet) (by [Vladimir](https://github.com/rgripper)) * [Libxmljs](https://github.com/polotek/libxmljs) (by [François de Campredon](https://github.com/fdecampredon)) * [linq.js](http://linqjs.codeplex.com/) (by [Marcin Najder](https://github.com/marcinnajder)) +* [Livestamp.js](https://github.com/mattbradley/livestampjs) (by [Vincent Bortone] (https://github.com/vbortone)) * [Marked](https://github.com/chjj/marked) (by [William Orr](https://github.com/worr)) * [Modernizr](http://modernizr.com/) (by [Boris Yankov](https://github.com/borisyankov)) * [Moment.js](https://github.com/timrwood/moment) (by [Michael Lakerveld](https://github.com/Lakerfield)) @@ -129,18 +134,21 @@ List of Definitions * [SockJS](https://github.com/sockjs/sockjs-client) (by [Emil Ivanov](https://github.com/vladev)) * [SoundJS](http://www.createjs.com/#!/SoundJS) (by [Pedro Ferreira](https://bitbucket.org/drk4)) * [Spin](http://fgnass.github.com/spin.js/) (by [Boris Yankov](https://github.com/borisyankov)) -* [Store.js](https://github.com/marcuswestin/store.js/) (by [Vincent Bortone](https://github.com/vbortone/)) +* [Store.js](https://github.com/marcuswestin/store.js/) (by [Vincent Bortone](https://github.com/vbortone)) * [Sugar](http://sugarjs.com/) (by [Josh Baldwin](https://github.com/jbaldwin/)) * [SwipeView](http://cubiq.org/swipeview) (by [Boris Yankov](https://github.com/borisyankov)) +* [Tags Manager](http://welldonethings.com/tags/manager) (by [Vincent Bortone](https://github.com/vbortone)) * [Teechart](http://www.steema.com) (by [Steema](http://www.steema.com)) * [three.js](http://mrdoob.github.com/three.js/) (by [Kon](http://phyzkit.net/)) * [Toastr](https://github.com/CodeSeven/toastr) (by [Boris Yankov](https://github.com/borisyankov)) +* [trunk8](https://github.com/rviscomi/trunk8) (by [Blake Niemyjski](https://github.com/niemyjski)) * [TweenJS](http://www.createjs.com/#!/TweenJS) (by [Pedro Ferreira](https://bitbucket.org/drk4)) * [tween.js](https://github.com/sole/tween.js/) (by [Adam R. Smith](https://github.com/sunetos)) * [twitter-bootstrap-wizard](https://github.com/VinceG/twitter-bootstrap-wizard) (by [Blake Niemyjski](https://github.com/niemyjski)) * [Ubuntu Unity Web API](https://launchpad.net/libunity-webapps) (by [John Vrbanac](https://github.com/jmvrbanac)) * [Underscore.js](http://underscorejs.org/) (by [Boris Yankov](https://github.com/borisyankov)) * [Underscore.js (Typed)](http://underscorejs.org/) (by [Josh Baldwin](https://github.com/jbaldwin/)) +* [Underscore-ko.js](https://github.com/kamranayub/UnderscoreKO) (by [Maurits Elbers](https://github.com/MagicMau)) * [Viewporter](https://github.com/zynga/viewporter) (by [Boris Yankov](https://github.com/borisyankov)) * [Vimeo](http://developer.vimeo.com/player/js-api) (by [Daz Wilkin](https://github.com/DazWilkin/)) * [WebRTC](http://dev.w3.org/2011/webrtc/editor/webrtc.html) (by [Ken Smith](https://github.com/smithkl42)) @@ -151,13 +159,11 @@ List of Definitions Requested Definitions --------------------- * [Rickshaw](https://github.com/shutterstock/rickshaw) -* [Livestamp.js](https://github.com/mattbradley/livestampjs) * [jQuery ScrollTo](https://github.com/balupton/jquery-scrollto) * [Crossfilter](https://github.com/square/crossfilter) * [dc.js](https://github.com/NickQiZhu/dc.js) * [google.visualizations](https://developers.google.com/chart/) -* [Tags Manager](http://welldonethings.com/tags/manager) * [Prelude.ls](http://gkz.github.com/prelude-ls/) * [MooTools](http://mootools.net/) * [Lo-Dash](http://lodash.com/) -* [Google geolocation](https://code.google.com/p/geo-location-javascript/) +* [java](https://github.com/nearinfinity/node-java) diff --git a/angularjs/angular-mocks.d.ts b/angularjs/angular-mocks.d.ts index 33dfaa303..72f6454f0 100644 --- a/angularjs/angular-mocks.d.ts +++ b/angularjs/angular-mocks.d.ts @@ -24,7 +24,7 @@ module ng { debug(obj: any): string; // see http://docs.angularjs.org/api/angular.mock.inject - inject(...fns: Function[]): void; + inject(...fns: Function[]): any; // see http://docs.angularjs.org/api/angular.mock.module module(...modules: any[]): any; @@ -71,7 +71,7 @@ module ng { // see http://docs.angularjs.org/api/ngMock.$httpBackend /////////////////////////////////////////////////////////////////////////// interface IHttpBackendService { - flush(count: number): void; + flush(count?: number): void; resetExpectations(): void; verifyNoOutstandingExpectation(): void; verifyNoOutstandingRequest(): void; diff --git a/angularjs/angular-tests.ts b/angularjs/angular-tests.ts new file mode 100644 index 000000000..d5414dc62 --- /dev/null +++ b/angularjs/angular-tests.ts @@ -0,0 +1,140 @@ +/// + +// issue: https://github.com/borisyankov/DefinitelyTyped/issues/369 +https://github.com/witoldsz/angular-http-auth/blob/master/src/angular-http-auth.js +/** + * @license HTTP Auth Interceptor Module for AngularJS + * (c) 2012 Witold Szczerba + * License: MIT + */ +angular.module('http-auth-interceptor', []) + + .provider('authService', function () { + /** + * Holds all the requests which failed due to 401 response, + * so they can be re-requested in future, once login is completed. + */ + var buffer = []; + + /** + * Required by HTTP interceptor. + * Function is attached to provider to be invisible for regular users of this service. + */ + this.pushToBuffer = function (config: ng.IRequestConfig, deferred: ng.IDeferred) { + buffer.push({ + config: config, + deferred: deferred + }); + } + + this.$get = ['$rootScope', '$injector', function ($rootScope: ng.IScope, $injector: ng.auto.IInjectorService) { + var $http: ng.IHttpService; //initialized later because of circular dependency problem + function retry(config: ng.IRequestConfig, deferred: ng.IDeferred) { + $http = $http || $injector.get('$http'); + $http(config).then(function (response) { + deferred.resolve(response); + }); + } + function retryAll() { + for (var i = 0; i < buffer.length; ++i) { + retry(buffer[i].config, buffer[i].deferred); + } + buffer = []; + } + + return { + loginConfirmed: function () { + $rootScope.$broadcast('event:auth-loginConfirmed'); + retryAll(); + } + } + }] + }) + + /** + * $http interceptor. + * On 401 response - it stores the request and broadcasts 'event:angular-auth-loginRequired'. + */ + .config(['$httpProvider', 'authServiceProvider', function ($httpProvider: ng.IHttpProvider, authServiceProvider) { + + var interceptor = ['$rootScope', '$q', function ($rootScope: ng.IScope, $q: ng.IQService) { + function success(response: ng.IHttpPromiseCallbackArg) { + return response; + } + + function error(response: ng.IHttpPromiseCallbackArg) { + if (response.status === 401) { + var deferred = $q.defer(); + authServiceProvider.pushToBuffer(response.config, deferred); + $rootScope.$broadcast('event:auth-loginRequired'); + return deferred.promise; + } + // otherwise + return $q.reject(response); + } + + return function (promise: ng.IHttpPromise) { + return promise.then(success, error); + } + + }]; + $httpProvider.responseInterceptors.push(interceptor); + }]); + + +module HttpAndRegularPromiseTests { + interface Person { + firstName: string; + lastName: string; + } + + interface ExpectedResponse extends Person {} + + interface SomeControllerScope extends ng.IScope { + person: Person; + theAnswer: number; + letters: string[]; + } + + interface OurApiPromiseCallbackArg extends ng.IHttpPromiseCallbackArg { + data?: ExpectedResponse; + } + + var someController: Function = ($scope: SomeControllerScope, $http: ng.IHttpService, $q: ng.IQService) => { + $http.get("http://somewhere/some/resource") + .success((data: ExpectedResponse) => { + $scope.person = data; + }); + + $http.get("http://somewhere/some/resource") + .then((response: ng.IHttpPromiseCallbackArg) => { + // typing lost, so something like + // var i: number = response.data + // would type check + $scope.person = response.data; + }); + + $http.get("http://somewhere/some/resource") + .then((response: OurApiPromiseCallbackArg) => { + // typing lost, so something like + // var i: number = response.data + // would NOT type check + $scope.person = response.data; + }); + + var aPromise: ng.IPromise = $q.when({firstName: "Jack", lastName: "Sparrow"}); + aPromise.then((person: Person) => { + $scope.person = person; + }); + + var bPromise: ng.IPromise = $q.when(42); + bPromise.then((answer: number) => { + $scope.theAnswer = answer; + }); + + var cPromise: ng.IPromise = $q.when(["a", "b", "c"]); + cPromise.then((letters: string[]) => { + $scope.letters = letters; + }); + } +} diff --git a/angularjs/angular.d.ts b/angularjs/angular.d.ts index 7fa05364d..b8d683c5c 100644 --- a/angularjs/angular.d.ts +++ b/angularjs/angular.d.ts @@ -45,16 +45,16 @@ module ng { isString(value: any): bool; isUndefined(value: any): bool; lowercase(str: string): string; - /** construct your angular application + /** construct your angular application official docs: Interface for configuring angular modules. see: http://docs.angularjs.org/api/angular.Module */ module( - /** name of your module you want to create */ - name: string, - /** name of modules yours depends on */ - requires?: string[], - configFunction?: Function): IModule; + /** name of your module you want to create */ + name: string, + /** name of modules yours depends on */ + requires?: string[], + configFunction?: Function): IModule; noop(...args: any[]): void; toJson(obj: any, pretty?: bool): string; uppercase(str: string): string; @@ -72,11 +72,11 @@ module ng { // see http://docs.angularjs.org/api/angular.Module /////////////////////////////////////////////////////////////////////////// interface IModule { - /** configure existing services. + /** configure existing services. Use this method to register work which needs to be performed on module loading */ - config(configFn: Function): IModule; - /** configure existing services. + config(configFn: Function): IModule; + /** configure existing services. Use this method to register work which needs to be performed on module loading */ config(inlineAnnotadedFunction: any[]): IModule; @@ -84,17 +84,17 @@ module ng { controller(name: string, controllerConstructor: Function): IModule; controller(name: string, inlineAnnotadedConstructor: any[]): IModule; directive(name: string, directiveFactory: Function): IModule; - directive(name: string, inlineAnnotadedFunction: any[]): IModule; + directive(name: string, inlineAnnotadedFunction: any[]): IModule; factory(name: string, serviceFactoryFunction: Function): IModule; - factory(name: string, inlineAnnotadedFunction: any[]): IModule; + factory(name: string, inlineAnnotadedFunction: any[]): IModule; filter(name: string, filterFactoryFunction: Function): IModule; - filter(name: string, inlineAnnotadedFunction: any[]): IModule; + filter(name: string, inlineAnnotadedFunction: any[]): IModule; provider(name: string, serviceProviderConstructor: Function): IModule; provider(name: string, inlineAnnotadedConstructor: any[]): IModule; run(initializationFunction: Function): IModule; - run(inlineAnnotadedFunction: any[]): IModule; + run(inlineAnnotadedFunction: any[]): IModule; service(name: string, serviceConstructor: Function): IModule; - service(name: string, inlineAnnotadedConstructor: any[]): IModule; + service(name: string, inlineAnnotadedConstructor: any[]): IModule; value(name: string, value: any): IModule; // Properties @@ -139,14 +139,14 @@ module ng { // XXX Same as avove $modelValue: any; - + $parsers: IModelParser[]; $formatters: IModelFormatter[]; $error: any; $pristine: bool; $dirty: bool; $valid: bool; - $invalid: bool; + $invalid: bool; } interface IModelParser { @@ -165,12 +165,12 @@ module ng { // Documentation says exp is optional, but actual implementaton counts on it $apply(exp: string): any; $apply(exp: (scope: IScope) => any): any; - + $broadcast(name: string, ...args: any[]): IAngularEvent; $destroy(): void; $digest(): void; $emit(name: string, ...args: any[]): IAngularEvent; - + // Documentation says exp is optional, but actual implementaton counts on it $eval(expression: string): any; $eval(expression: (scope: IScope) => any): any; @@ -183,25 +183,25 @@ module ng { $new(isolate?: bool): IScope; $on(name: string, listener: (event: IAngularEvent, ...args: any[]) => any): Function; - + $watch(watchExpression: string, listener?: string, objectEquality?: bool): Function; $watch(watchExpression: string, listener?: (newValue: any, oldValue: any, scope: IScope) => any, objectEquality?: bool): Function; $watch(watchExpression: (scope: IScope) => any, listener?: string, objectEquality?: bool): Function; $watch(watchExpression: (scope: IScope) => any, listener?: (newValue: any, oldValue: any, scope: IScope) => any, objectEquality?: bool): Function; - + $id: number; } interface IAngularEvent { targetScope: IScope; currentScope: IScope; - name: string; + name: string; preventDefault: Function; defaultPrevented: bool; // Available only events that were $emit-ted stopPropagation?: Function; - } + } /////////////////////////////////////////////////////////////////////////// // WindowService @@ -386,12 +386,12 @@ module ng { } interface IPromise { - then(successCallback: Function, errorCallback?: Function): IPromise; + then(successCallback: (promiseValue: any) => any, errorCallback?: (reason: any) => any): IPromise; } interface IDeferred { resolve(value?: any): void; - reject(reason?: string): void; + reject(reason?: any): void; promise: IPromise; } @@ -420,7 +420,7 @@ module ng { // Methods bellow are not documented info(): any; - get(cacheId: string): ICacheObject; + get (cacheId: string): ICacheObject; } interface ICacheObject { @@ -432,7 +432,7 @@ module ng { //capacity: number; }; put(key: string, value?: any): void; - get(key: string): any; + get (key: string): any; remove(key: string): void; removeAll(): void; destroy(): void; @@ -484,8 +484,8 @@ module ng { interface IHttpService { // At least moethod and url must be provided... (config: IRequestConfig): IHttpPromise; - get(url: string, RequestConfig?: any): IHttpPromise; - delete(url: string, RequestConfig?: any): IHttpPromise; + get (url: string, RequestConfig?: any): IHttpPromise; + delete (url: string, RequestConfig?: any): IHttpPromise; head(url: string, RequestConfig?: any): IHttpPromise; jsonp(url: string, RequestConfig?: any): IHttpPromise; post(url: string, data: any, RequestConfig?: any): IHttpPromise; @@ -503,10 +503,10 @@ module ng { method: string; url: string; params?: any; - + // XXX it has it's own structure... perhaps we should define it in the future headers?: any; - + cache?: any; timeout?: number; withCredentials?: bool; @@ -517,12 +517,20 @@ module ng { transformResponse?: any; } + interface IHttpPromiseCallbackArg { + data?: any; + status?: number; + headers?: (headerName: string) => string; + config?: IRequestConfig; + } + interface IHttpPromise extends IPromise { success(callback: (data: any, status: number, headers: (headerName: string) => string, config: IRequestConfig) => any): IHttpPromise; error(callback: (data: any, status: number, headers: (headerName: string) => string, config: IRequestConfig) => any): IHttpPromise; + then(successCallback: (response: IHttpPromiseCallbackArg) => any, errorCallback?: (response: IHttpPromiseCallbackArg) => any): IPromise; } - interface IHttpProvider extends IServiceProvider { + interface IHttpProvider extends IServiceProvider { defaults: IRequestConfig; responseInterceptors: any[]; } @@ -589,7 +597,7 @@ module ng { // May not always be available. For instance, current will not be available // to a controller that was not initialized as a result of a route maching. current?: ICurrentRoute; - } + } // see http://docs.angularjs.org/api/ng.$routeProvider#when for options explanations interface IRoute { @@ -609,9 +617,9 @@ module ng { }; } - interface IRouteProviderProvider extends IServiceProvider { - otherwise(params: any): IRouteProviderProvider; - when(path: string, route: IRoute): IRouteProviderProvider; + interface IRouteProvider extends IServiceProvider { + otherwise(params: any): IRouteProvider; + when(path: string, route: IRoute): IRouteProvider; } /////////////////////////////////////////////////////////////////////////// @@ -626,7 +634,7 @@ module ng { interface IInjectorService { annotate(fn: Function): string[]; annotate(inlineAnnotadedFunction: any[]): string[]; - get(name: string): any; + get (name: string): any; instantiate(typeConstructor: Function, locals?: any): any; invoke(func: Function, context?: any, locals?: any): any; } diff --git a/bgiframe/typescript.bgiframe.d.ts b/bgiframe/typescript.bgiframe.d.ts new file mode 100644 index 000000000..b0b77cf07 --- /dev/null +++ b/bgiframe/typescript.bgiframe.d.ts @@ -0,0 +1,33 @@ +// Type definitions for typescript.bgiframe 1.0 +// Project: https://github.com/sumegizoltan/BgiFrame +// Definitions by: Zoltan Sumegi +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/*! The plugin based on: + * + * bgiframe for IE6 + * https://github.com/brandonaaron/bgiframe + * + * Copyrights for the jQuery plugin: + * Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net) + */ + +module BgiFrame { + interface ISettings { + top: string; + left: string; + width: string; + height: string; + opacity: bool; + src: string; + conditional: bool; + } + + interface IBgiframe { + s: ISettings; + createIframe(): HTMLElement; + fire(element: HTMLElement): void; + getIframe(element: HTMLElement): HTMLElement; + prop(n: any): string; + } +} \ No newline at end of file diff --git a/breeze/breeze-tests.ts b/breeze/breeze-tests.ts index 06a50b3fc..09dd6a4a3 100644 --- a/breeze/breeze-tests.ts +++ b/breeze/breeze-tests.ts @@ -279,10 +279,10 @@ function test_entityManager() { var entity = changeArgs.entity; }); var em = new breeze.EntityManager({ serviceName: "api/NorthwindIBModel" }); - //em.hasChanges.subscribe(function (args) { - // var hasChanges = args.hasChanges; - // var entityManager = args.entityManager; - //}); + em.hasChangesChanged.subscribe(function (args) { + var hasChangesChanged = args.hasChanges; + var entityManager = args.entityManager; + }); } function test_entityQuery() { @@ -784,4 +784,4 @@ function test_demo() { .from("Employees"); manager.executeQuery(query).then(function (data) { }); -} \ No newline at end of file +} diff --git a/breeze/breeze.d.ts b/breeze/breeze.d.ts index da8f04377..8a6458498 100644 --- a/breeze/breeze.d.ts +++ b/breeze/breeze.d.ts @@ -280,7 +280,7 @@ declare module Breeze { validationOptions: ValidationOptions; entityChanged: EntityChangedEvent; - // hasChanges: BreezeCore.Event; + hasChangesChanged: BreezeCore.Event; constructor (config?: EntityManagerOptions); constructor (config?: string); @@ -290,6 +290,7 @@ declare module Breeze { clear(): void; createEmptyCopy(): EntityManager; detachEntity(entity: Entity): bool; + createEntity(entityTypeName: string, propertyInitializer: {}): Entity; executeQuery(query: string, callback?: ExecuteQuerySuccessCallback, errorCallback?: ExecuteQueryErrorCallback): Promise; executeQuery(query: EntityQuery, callback?: ExecuteQuerySuccessCallback, errorCallback?: ExecuteQueryErrorCallback): Promise; @@ -727,4 +728,4 @@ declare module Breeze { messageTemplate: string; message?: string; } -} \ No newline at end of file +} diff --git a/commander/commander-tests.ts b/commander/commander-tests.ts new file mode 100644 index 000000000..e9e99b988 --- /dev/null +++ b/commander/commander-tests.ts @@ -0,0 +1,50 @@ +/// + +// +// TODO: improve tests +// [the code below was extracted from the documentation and examples, but does not seem to cover all cases] +// + +import program = module("commander"); + +program + .version('0.0.1') + .option('-C, --chdir ', 'change the working directory') + .option('-c, --config ', 'set config path [./deploy.conf]') + .option('-T, --no-tests', 'ignore test hook') + +// $ deploy setup stage +// $ deploy setup +program + .command('setup [env]') + .description('run setup commands for all envs') + .action(function (env) { + env = env || 'all'; + console.log('setup for %s env(s)', env); + }); + +// $ deploy stage +// $ deploy production +program + .command('*') + .action(function (env) { + console.log('deploying "%s"', env); + }); + +program.option('-p, --pepper', 'add pepper'); + +program.option('-C, --chdir ', 'change the working directory'); + +program.prompt('Username: ', function (name) { + console.log('hi %s', name); +}); + +program.prompt('Description:', function (desc) { + console.log('description was "%s"', desc.trim()); +}); + +program.promptForNumber("Enter a number:", (n) => { }); + +program.confirm("Confirm? ", (f) => { }); + +program.choose(["a", "b", "c"], (i) => { }); \ No newline at end of file diff --git a/commander/commander.d.ts b/commander/commander.d.ts new file mode 100644 index 000000000..341395026 --- /dev/null +++ b/commander/commander.d.ts @@ -0,0 +1,228 @@ +// Type definitions for commanderjs 1.1.1 +// Project: https://github.com/visionmedia/commander.js +// Definitions by: Marcelo Dezem +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +declare module "commander" { + export interface Command { + /** + * The command name. + */ + name: string; + + // + // + // NOTE: the methods below are COPIED to the module + // as functions exports. If changes need to be made here, + // remember to re-paste the definitions in the module. + // Read below to know why such ugly thing is required. + // + // + + /** + * Register callback fn for the command. + */ + action(fn: (...args: any[]) => any): Command; + + /** + * Define option with flags, description and optional coercion function and default value. + * The flags string should contain both the short and long flags + * separated by comma, a pipe or space. The following are all valid + * all will output this way when --help is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * @param flags the option flags. + * @param description the option description. The description is printed when "--help" is used. + * @param coerceFn (optional) specifies a callback function to coerce the option arg. + * @param defaultValue (optional) specifies a default value. + */ + option(flags: string, description: string, coerceFn?: (value: string) => any, defaultValue?: any): Command; + + + /** + * Sets the command version + */ + version(version: string): Command; + + /** + * Parse the arguments array and invokes the commands passing the parsed options. + * @param argv the arguments array. + */ + parse(argv: string[]): Command; + + /** + * Gets or sets the command description. + * @param description the new description for the command. When ommited this returns the current description, otherwise returns the current Command. + */ + description(description: string): Command; + description(): string; + + /** + * Gets or sets the usage help string. + */ + usage(usage: string): Command; + usage(): string; + + /* + * Prompt the user for a value, calling the callback function. + * + * Supports single-line and multi-line prompts. + * To issue a single-line prompt simply add a whitespace + * to the end of label, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * @param label the label string to be printed in console. + * @param callback a callback function to handle the inputed string. + */ + prompt(label: string, callback: (value: string) => any): void; + + promptForNumber(label: string, callback: (value: number) => any): void; + promptForDate(label: string, callback: (value: Date) => any): void; + promptSingleLine(label: string, callback: (value: string) => any): void; + promptMultiLine(label: string, callback: (value: string) => any): void; + + /** + * Prompt for password with a label, a optional mask char and callback function. + * The mask string defaults to '', aka no output is written while typing, you may want to use "*" etc. + */ + password(label: string, mask: string, callback: (value: string) => any): void; + password(label: string, callback: (value: string) => any): void; + + /** + * Prompts the user for a confirmation. + */ + confirm(label: string, callback: (flag: bool) => any): void; + + /** + * Prompt for password with str, mask char and callback fn(val). + * The mask string defaults to '', aka no output is written while typing, you may want to use "*" etc. + */ + choose(options: string[], callback: (idx: number) => any): void; + choose(options: any[], callback: (idx: number) => any): void; + + /** + * Add command with the specified name. Returns a new instance of Command. + * + * The .action() callback is invoked when the + * command name is specified via ARGV, + * and the remaining arguments are applied to the + * function for access. + + * When the name is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of ARGV remaining. + * + * @param name the name of the command. Pass "*" to trap un-matched commands. + */ + command(name: string): Command; + } + + // + // + // since TypeScript (and ECMA6) does not supports module.exports, + // there is no way to set the default Command instance as the module itself. + // It's ugly but the only way is to copy all the methods from Command + // and paste it in the module as functions exports. + // + // + + /** + * Register callback fn for the command. + */ + export function action(fn: (...args: any[]) => any): Command; + + /** + * Define option with flags, description and optional coercion function and default value. + * The flags string should contain both the short and long flags + * separated by comma, a pipe or space. The following are all valid + * all will output this way when --help is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * @param flags the option flags. + * @param description the option description. The description is printed when "--help" is used. + * @param coerceFn (optional) specifies a callback function to coerce the option arg. + * @param defaultValue (optional) specifies a default value. + */ + export function option(flags: string, description: string, coerceFn?: (value: string) => any, defaultValue?: any): Command; + + + /** + * Sets the command version + */ + export function version(version: string): Command; + + /** + * Parse the arguments array and invokes the commands passing the parsed options. + * @param argv the arguments array. + */ + export function parse(argv: string[]): Command; + + /** + * Gets or sets the command description. + * @param description the new description for the command. When ommited this returns the current description, otherwise returns the current Command. + */ + export function description(description: string): Command; + export function description(): string; + + /** + * Gets or sets the usage help string. + */ + export function usage(usage: string): Command; + export function usage(): string; + + /* + * Prompt the user for a value, calling the callback function. + * + * Supports single-line and multi-line prompts. + * To issue a single-line prompt simply add a whitespace + * to the end of label, something like "name: ", whereas + * for a multi-line prompt omit this "description:". + * @param label the label string to be printed in console. + * @param callback a callback function to handle the inputed string. + */ + export function prompt(label: string, callback: (value: string) => any): void; + + export function promptForNumber(label: string, callback: (value: number) => any): void; + export function promptForDate(label: string, callback: (value: Date) => any): void; + export function promptSingleLine(label: string, callback: (value: string) => any): void; + export function promptMultiLine(label: string, callback: (value: string) => any): void; + /** + * Prompt for password with a label, a optional mask char and callback function. + * The mask string defaults to '', aka no output is written while typing, you may want to use "*" etc. + */ + export function password(label: string, mask: string, callback: (value: string) => any): void; + export function password(label: string, callback: (value: string) => any): void; + + /** + * Prompts the user for a confirmation. + */ + export function confirm(label: string, callback: (flag: bool) => any): void; + + /** + * Prompt for password with str, mask char and callback fn(val). + * The mask string defaults to '', aka no output is written while typing, you may want to use "*" etc. + */ + export function choose(options: string[], callback: (idx: number) => any): void; + export function choose(options: any[], callback: (idx: number) => any): void; + + /** + * Add command with the specified name. Returns a new instance of Command. + * + * The .action() callback is invoked when the + * command name is specified via ARGV, + * and the remaining arguments are applied to the + * function for access. + + * When the name is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of ARGV remaining. + * + * @param name the name of the command. Pass "*" to trap un-matched commands. + */ + export function command(name: string): Command; +} \ No newline at end of file diff --git a/durandal/durandal.d.ts b/durandal/durandal.d.ts index 5e85b3f67..c5c5de3b1 100644 --- a/durandal/durandal.d.ts +++ b/durandal/durandal.d.ts @@ -64,7 +64,7 @@ declare module "durandal/app" { * @param transition If you have a splash screen, you may want to specify an optional transition to animate from the splash to your main shell. * @param applicationHost parameter is optional. If provided it should be an element id for the node into which the UI should be composed. If it is not provided the default is to look for an element with an id of "applicationHost". */ - export var setRoot: (root: any, transition: string, applicationHost: string) => void; + export var setRoot: (root: any, transition: string, applicationHost?: string) => void; /** * If you intend to run on mobile, you should also call app.adaptToDevice() before setting the root. */ @@ -368,6 +368,10 @@ declare module "durandal/plugins/router" { * An observable whose value is the currently active item/module/page. */ export var activeItem: IDurandalViewModelActiveItem; + /** + * An observable whose value is the currently active route. + */ + export var activeRoute: KnockoutObservableAny; /** * called after an a new module is composed */ @@ -376,6 +380,10 @@ declare module "durandal/plugins/router" { * Causes the router to move backwards in page history. */ export var navigateBack: () => void; + /** + * Use router default convention. + */ + export var useConvention: () => void; /** * Causes the router to navigate to a specific url. */ @@ -400,6 +408,10 @@ declare module "durandal/plugins/router" { * This should not normally be overwritten. But advanced users can override this to completely transform the developer's routeInfo input into the final version used to configure the router. */ export var prepareRouteInfo: (info: routeInfo) => void; + /** + * This should not normally be overwritten. But advanced users can override this to completely transform the developer's routeInfo input into the final version used to configure the router. + */ + export var handleInvalidRoute: (route: routeInfo, parameters: any) => void; /** * Once the router is required, you can call router.mapAuto(). This is the most basic configuration option. When you call this function (with no parameters) it tells the router to directly correlate route parameters to module names in the viewmodels folder. */ @@ -411,7 +423,7 @@ declare module "durandal/plugins/router" { /** * You can pass a single routeInfo to this function, or you can pass the basic configuration parameters. url is your url pattern, moduleId is the module path this pattern will map to, name is used as the document title and visible determines whether or not to include it in the router's visibleRoutes array for easy navigation UI binding. */ - export var mapRoute: (url: string, moduleId: string, name: string, visible: bool) => routeInfo; + export var mapRoute: (urlOrRouteInfo: any, moduleId?: string, name?: string, visible?: bool) => routeInfo; /** * This function takes an array of routeInfo objects or a single routeInfo object and uses it to configure the router. The finalized routeInfo (or array of infos) is returned. */ @@ -423,4 +435,4 @@ declare module "durandal/plugins/router" { * After you've configured the router, you need to activate it. This is usually done in your shell. The activate function of the router returns a promise that resolves when the router is ready to start. To use the router, you should add an activate function to your shell and return the result from that. The application startup infrastructure of Durandal will detect your shell's activate function and call it at the appropriate time, waiting for it's promise to resolve. This allows Durandal to properly orchestrate the timing of composition and databinding along with animations and splash screen display. */ export var activate: (defaultRoute: string) => JQueryPromise; -} \ No newline at end of file +} diff --git a/easeljs/easeljs.d.ts b/easeljs/easeljs.d.ts index 979745753..0e6dde9b6 100644 --- a/easeljs/easeljs.d.ts +++ b/easeljs/easeljs.d.ts @@ -78,15 +78,19 @@ module createjs { mousedown: (event: MouseEvent) => any; tick: () => any; - // EventDispatcher mixins - addEventListener(type: string, listener: (eventObj: Object) => bool): Function; - addEventListener(type: string, listener: (eventObj: Object) => bool): Object; - removeEventListener(type: string, listener: (eventObj: Function) => bool): void; - removeEventListener(type: string, listener: (eventObj: Object) => bool): void; - removeAllEventListeners(type: string): void; - dispatchEvent(eventObj: string, target: Object): bool; - dispatchEvent(eventObj: Object, target: Object): bool; - hasEventListener(type: string): bool; + // EventDispatcher mixins + addEventListener(type: string, listener: (eventObj: Object) => bool): Function; + addEventListener(type: string, listener: (eventObj: Object) => void): Function; + addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): Object; + addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): Object; + removeEventListener(type: string, listener: (eventObj: Object) => bool): void; + removeEventListener(type: string, listener: (eventObj: Object) => void): void; + removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): void; + removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): void; + removeAllEventListeners(type: string): void; + dispatchEvent(eventObj: string, target: Object): bool; + dispatchEvent(eventObj: Object, target: Object): bool; + hasEventListener(type: string): bool; } @@ -166,20 +170,20 @@ module createjs { onAnimationEnd: (event: Object) => any; } - export class ButtonHelper { - // properties - target: Object; - overLabel: string; - outLabel: string; - downLabel: string; - play: bool; + export class ButtonHelper { + // properties + target: Object; + overLabel: string; + outLabel: string; + downLabel: string; + play: bool; - // methods - constructor(target: MovieClip, outLabel: string, overLabel: string, downLabel: string, play: bool, hitArea: DisplayObject, hitLabel: string); - constructor(target: BitmapAnimation, outLabel: string, overLabel: string, downLabel: string, play: bool, hitArea: DisplayObject, hitLabel: string); - setEnabled(value: bool); - toString(): string; - } + // methods + constructor(target: MovieClip, outLabel: string, overLabel: string, downLabel: string, play: bool, hitArea: DisplayObject, hitLabel: string); + constructor(target: BitmapAnimation, outLabel: string, overLabel: string, downLabel: string, play: bool, hitArea: DisplayObject, hitLabel: string); + setEnabled(value: bool); + toString(): string; + } export class BoxBlurFilter extends Filter { // properties @@ -280,27 +284,31 @@ module createjs { export class EaselJS { - // properties - version: string; - buildDate: string; + // properties + version: string; + buildDate: string; } export class EventDispatcher { - // properties + // properties - // methods - static initialize(target: Object): void; + // methods + static initialize(target: Object): void; - addEventListener(type: string, listener: (eventObj: Object) => bool): Function; - addEventListener(type: string, listener: (eventObj: Object) => bool): Object; - removeEventListener(type: string, listener: (eventObj: Function) => bool): void; - removeEventListener(type: string, listener: (eventObj: Object) => bool): void; - removeAllEventListeners(type: string): void; - dispatchEvent(eventObj: string, target: Object): bool; - dispatchEvent(eventObj: Object, target: Object): bool; - hasEventListener(type: string): bool; - toString(): string; + addEventListener(type: string, listener: (eventObj: Object) => bool): Function; + addEventListener(type: string, listener: (eventObj: Object) => void): Function; + addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): Object; + addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): Object; + removeEventListener(type: string, listener: (eventObj: Object) => bool): void; + removeEventListener(type: string, listener: (eventObj: Object) => void): void; + removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): void; + removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): void; + removeAllEventListeners(type: string): void; + dispatchEvent(eventObj: string, target: Object): bool; + dispatchEvent(eventObj: Object, target: Object): bool; + hasEventListener(type: string): bool; + toString(): string; } @@ -352,20 +360,20 @@ module createjs { } - export class Log { - // properties - static NONE: number; - static ERROR: number; - static WARNING: number; - static TRACE: number; - static ALL: number; - static level: number; + export class Log { + // properties + static NONE: number; + static ERROR: number; + static WARNING: number; + static TRACE: number; + static ALL: number; + static level: number; - // methods - static out(message: string, details: string, level: number); - static addKeys(keys: Object); - static log(message: string, details: string, level: number); - } + // methods + static out(message: string, details: string, level: number); + static addKeys(keys: Object); + static log(message: string, details: string, level: number); + } export class Matrix2D { // properties @@ -552,14 +560,15 @@ module createjs { toString(): string; // events - complete: (event: Object) => any; - onProgress: (event: Object) => any; + complete: (event: Object) => any; + onProgress: (event: Object) => any; } export class SpriteSheetUtils { static addFlippedFrames(spriteSheet: SpriteSheet, horizontal?: bool, vertical?: bool, both?: bool): void; - static extractFrame(spriteSheet: HTMLImageElement, frame: number): HTMLImageElement; + static extractFrame(spriteSheet: SpriteSheet, frame: number): HTMLImageElement; + static extractFrame(spriteSheet: SpriteSheet, animationName: string): HTMLImageElement; static flip(spriteSheet: HTMLImageElement, flipData: Object): void; static mergeAlpha(rgbImage: HTMLImageElement, alphaImage: HTMLImageElement, canvas?: HTMLCanvasElement): HTMLCanvasElement; } @@ -582,11 +591,11 @@ module createjs { constructor (canvas: HTMLCanvasElement); clone(): Stage; enableMouseOver(frequency: number): void; - enableDOMEvents(enable: bool): void; + enableDOMEvents(enable: bool): void; toDataURL(backgroundColor: string, mimeType: string): string; update(): void; clear(): void; - handleEvent(evt: Object): void; + handleEvent(evt: Object): void; // events stagemousemove: (event: MouseEvent) => any; @@ -634,6 +643,16 @@ module createjs { static setInterval(interval: number): void; static setPaused(value: bool): void; + // EventDispatcher mixins + static addEventListener(type: string, listener: (eventObj: Object) => bool): Function; + static addEventListener(type: string, listener: (eventObj: Object) => void): Function; + static addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): Object; + static addEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): Object; + static removeEventListener(type: string, listener: (eventObj: Object) => bool): void; + static removeEventListener(type: string, listener: (eventObj: Object) => void): void; + static removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => bool; }): void; + static removeEventListener(type: string, listener: { handleEvent: (eventObj: Object) => void; }): void; + // events tick: (timeElapsed: number) => any; } diff --git a/fabricjs/fabricjs.d.ts b/fabricjs/fabricjs.d.ts index ec4559e94..256e4cb41 100644 --- a/fabricjs/fabricjs.d.ts +++ b/fabricjs/fabricjs.d.ts @@ -758,6 +758,7 @@ declare module fabric { fromURL(url: string): IImage; fromURL(url: string, callback: (image: IImage) => any): IImage; fromURL(url: string, callback: (image: IImage) => any, objObjects: IObjectOptions): IImage; + new (element: HTMLImageElement, objObjects: IObjectOptions): IImage; prototype: any; filters: diff --git a/gamepad/gamepad-tests.ts b/gamepad/gamepad-tests.ts new file mode 100644 index 000000000..7491d7970 --- /dev/null +++ b/gamepad/gamepad-tests.ts @@ -0,0 +1,72 @@ +/// + + +()=>{ + function runAnimation() + { + window.requestAnimationFrame(runAnimation); + + var gamepads = navigator.getGamepads(); + + for (var i = 0; i < gamepads.length; ++i) + { + var pad = gamepads[i]; + // todo; simple demo of displaying pad.axes and pad.buttons + } + } + + window.requestAnimationFrame(runAnimation); +}; + +()=>{ + window.addEventListener('GamepadConnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' connected!'); + }, false); + window.addEventListener('GamepadDisconnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' disconnected!'); + }, false); + window.addEventListener('webkitGamepadConnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' connected!'); + }, false); + window.addEventListener('webkitGamepadDisconnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' disconnected!'); + }, false); + window.addEventListener('mozGamepadConnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' connected!'); + }, false); + window.addEventListener('mozGamepadDisconnected', (e: GamepadEvent)=>{ + console.log('Gamepad ' + e.gamepad.index + ' disconnected!'); + }, false); + + var requestAnimationFrame = window.requestAnimationFrame || window["mozRequestAnimationFrame"]; + var getGamepads = navigator.getGamepads || navigator.webkitGetGamepads; + if(getGamepads){ + function runAnimation() + { + requestAnimationFrame.call(window, runAnimation); + + var gamepads: GamepadList = getGamepads.call(navigator); + for(var i = 0; i < gamepads.length; i++){ + var pad: Gamepad = gamepads[i]; + if(pad){ + for (var k = 0; k < pad.buttons.length; k++) + { + var button = pad.buttons[k]; + if(button !== 0){ + console.log('pad[' + pad.index + ']: ' + 'time=' + pad.timestamp + ' id="' + pad.id + '" button[' + k + '] = ' + button); + } + } + for (var k = 0; k < pad.axes.length; k++) + { + var axis = pad.axes[k]; + if(Math.abs(axis) > 0.1){ + console.log('pad[' + pad.index + ']: ' + 'time=' + pad.timestamp + ' id="' + pad.id + '" axis[' + k + '] = ' + axis); + } + } + } + } + } + + runAnimation(); + } +}(); \ No newline at end of file diff --git a/gamepad/gamepad.d.ts b/gamepad/gamepad.d.ts new file mode 100644 index 000000000..833b71434 --- /dev/null +++ b/gamepad/gamepad.d.ts @@ -0,0 +1,78 @@ +// Type definitions for Gamepad API +// Project: http://www.w3.org/TR/gamepad/ +// Definitions by: Kon +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/** + * This interface defines an individual gamepad device. + */ +interface Gamepad{ + /** + * An identification string for the gamepad. This string identifies the brand or style of connected gamepad device. Typically, this will include the USB vendor and a product ID. + * @readonly + */ + id:string; + + /** + * The index of the gamepad in the Navigator. When multiple gamepads are connected to a user agent, indices must be assigned on a first-come, first-serve basis, starting at zero. If a gamepad is disconnected, previously assigned indices must not be reassigned to gamepads that continue to be connected. However, if a gamepad is disconnected, and subsequently the same or a different gamepad is then connected, index entries must be reused. + * @readonly + */ + index:number; + + /** + * Last time the data for this gamepad was updated. Timestamp is a monotonically increasing value that allows the author to determine if the axes and button data have been updated from the hardware, relative to a previously saved timestamp. + * @readonly + */ + timestamp:number; + + /** + * Array of values for all axes of the gamepad. All axis values must be linearly normalized to the range [-1.0 .. 1.0]. As appropriate, -1.0 should correspond to "up" or "left", and 1.0 should correspond to "down" or "right". Axes that are drawn from a 2D input device should appear next to each other in the axes array, X then Y. It is recommended that axes appear in decreasing order of importance, such that element 0 and 1 typically represent the X and Y axis of a directional stick. + * @readonly + */ + axes:number[]; + + /** + * Array of values for all buttons of the gamepad. All button values must be linearly normalized to the range [0.0 .. 1.0]. 0.0 must mean fully unpressed, and 1.0 must mean fully pressed. It is recommended that buttons appear in decreasing importance such that the primary button, secondary button, tertiary button, and so on appear as elements 0, 1, 2, ... in the buttons array. + * @readonly + */ + buttons:number[]; +} + +/** + * + */ +interface GamepadEvent extends Event{ + /** + * The single gamepad attribute provides access to the associated gamepad data for this event. + * @readonly + */ + gamepad:Gamepad; +} + +interface GamepadList{ + [index: number]: Gamepad; + length: number; +} + +interface Navigator{ + /** + * The currently connected and interacted-with gamepads. Gamepads must only appear in the list if they are currently connected to the user agent, and have been interacted with by the user. Otherwise, they must not appear in the list to avoid a malicious page from fingerprinting the user based on connected devices. + * @readonly + */ + getGamepads(): Gamepad[]; + + webkitGetGamepads(): GamepadList; + + // Not supported yet :( + // mozGetGamepads(): Gamepad[]; +} + +/* + * @event gamepadconnected + * A user agent must dispatch this event type to indicate the user has connected a gamepad. If a gamepad was already connected when the page was loaded, the gamepadconnected event will be dispatched when the user presses a button or moves an axis. + */ + +/* + * @event gamepaddisconnected + * When a gamepad is disconnected from the user agent, if the user agent has previously dispatched a gamepadconnected event, a gamepaddisconnected event must be dispatched. + */ \ No newline at end of file diff --git a/google.geolocation/google.geolocation-tests.ts b/google.geolocation/google.geolocation-tests.ts new file mode 100644 index 000000000..f6574cfea --- /dev/null +++ b/google.geolocation/google.geolocation-tests.ts @@ -0,0 +1,18 @@ +// Test files for Geolocation Definition file +/// + +//determine if the handset has client side geo location capabilities +var isInit: bool = geo_position_js.init(); +if(isInit){ + geo_position_js.getCurrentPosition(success_callback, error_callback); +} else { + alert("Functionality not available"); +} + +function success_callback(position: Position): void { + geo_position_js.showMap(position.coords.latitude, position.coords.longitude); +} + +function error_callback(positionError: PositionError): void { + console.log(positionError.code); +} \ No newline at end of file diff --git a/google.geolocation/google.geolocation.d.ts b/google.geolocation/google.geolocation.d.ts new file mode 100644 index 000000000..5260ba01e --- /dev/null +++ b/google.geolocation/google.geolocation.d.ts @@ -0,0 +1,12 @@ +// Type definitions for Google Geolocation 0.4.8 +// Project: https://code.google.com/p/geo-location-javascript/ +// Definitions by: Vincent Bortone +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +interface GeolocationStatic { + init(): bool; + getCurrentPosition(success: (position: Position) => void, error?: (positionError: PositionError) => void, opts?: PositionOptions): void; + showMap(latitude: number, longitude: number): void; +} + +declare var geo_position_js: GeolocationStatic; \ No newline at end of file diff --git a/googlemaps/google.maps.d.ts b/googlemaps/google.maps.d.ts index 340387c44..3596da3d4 100644 --- a/googlemaps/google.maps.d.ts +++ b/googlemaps/google.maps.d.ts @@ -1123,7 +1123,7 @@ declare module google.maps { worldSize?: Size; } - export interface StreetViewService { + export class StreetViewService { getPanoramaById(pano: string, callback: (streetViewPanoramaData: StreetViewPanoramaData, streetViewStatus: StreetViewStatus) => void ); getPanoramaByLocation(latlng: LatLng, radius: number, callback: (streetViewPanoramaData: StreetViewPanoramaData, streetViewStatus: StreetViewStatus) => void ); } diff --git a/jasmine/jasmine.d.ts b/jasmine/jasmine.d.ts index 56f41b48f..05e437004 100644 --- a/jasmine/jasmine.d.ts +++ b/jasmine/jasmine.d.ts @@ -7,7 +7,8 @@ declare function describe(description: string, specDefinitions: Function): void; declare function xdescribe(description: string, specDefinitions: Function): void; -declare function it(expectation: string, assertion: Function): void; +declare function it(expectation: string, assertion: () => void ): void; +declare function it(expectation: string, assertion: (done: (err?) => void) => void ): void; declare function xit(expectation: string, assertion: Function): void; declare function beforeEach(action: Function): void; diff --git a/jquery.elang/jquery.elang.d.ts b/jquery.elang/jquery.elang.d.ts new file mode 100644 index 000000000..f01a466cd --- /dev/null +++ b/jquery.elang/jquery.elang.d.ts @@ -0,0 +1,314 @@ +// Type definitions for eLang 0.5.1 +// Project: https://github.com/sumegizoltan/ELang/ +// Definitions by: Zoltan Sumegi +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +interface IPageResource { + lang?: IPageLangItems; + selectedLang?: string; +} + +interface IPageLangItems { + en?: IPageLabels; + hu?: IPageLabels; +} + +interface IPageLabels { + lblTitle?: string; + lblPageHeader?: string; + lblSearchField?: string; + lblEditKeyField?: string; + lblEditValueField?: string; + lblFindedExpressionsHead?: string; + lblEditedExpressionsHead?: string; + lblFindHead?: string; + lblEditHead?: string; + lblFind?: string; + lblAdd?: string; + lblModify?: string; + lblRemove?: string; + lblSearchInExpressions?: string; + lblSearchInMeanings?: string; + lblSearchInExpressionsHlp?: string; + lblSearchInMeaningsHlp?: string; + lblTestHead?: string; + lblOrderedTest?: string; + lblRandomlyTest?: string; + lblTypedTest?: string; + lblSelectedTest?: string; + lblWrittedTest?: string; + lblVoicedTest?: string; + lblStartTest?: string; + lblStopTest?: string; + lblTypedTestHlp?: string; + lblSelectedTestHlp?: string; + lblOrderedTestHlp?: string; + lblRandomlyTestHlp?: string; + lblWrittedTestHlp?: string; + lblVoicedTestHlp?: string; +} + +interface ELangCommonStatic { + resource: IPageResource; + getLabel(labelid: string, langid?: string): string; + setLang(langid: string, node?: JQuery): void; +} + +// ELang database (LocalStorage) functionality with Singleton instance + +interface IELangDBOptions { + autocompleteRows: number; +} + +interface IELangDBDelegates { + selectHandler: Function; + insertHandler: Function; + modifyHandler: Function; + removeHandler: Function; +} + +interface IELangDBEvents { + select: JQueryDeferred; + insert: JQueryDeferred; + modify: JQueryDeferred; + remove: JQueryDeferred; +} + +interface IELangDB { + cache?: any; + delegates?: IELangDBDelegates; + events?: IELangDBEvents; + isInitialized?: bool; + options?: IELangDBOptions; + + name?: string; + description?: string; + + initialize(options?: IELangDBOptions): void; + + _onSelect(id: string, callback?: Function): void; + _onInsert(id: string, value: string, callback?: Function): void; + _onModify(id: string, value: string, callback?: Function): void; + _onRemove(id: string, callback?: Function): void; + + select(id: string, callback?: Function): void; + insert(id: string, value: string, callback?: Function): void; + modify(id: string, value: string, callback?: Function): void; + remove(id: string, callback?: Function): void; + + sort(): void; + setOptions(options: IELangDBOptions): void; + getIndexHash(id: string): string; + getOptions(): IELangDBOptions; +} + +interface ELangStatic { + getInstance(options?: IELangDBOptions): IELangDB; +} + +// ELangBase + +interface IELangBaseDefaults { + contentCSS: string; + contentInnerCSS: string; + resultCSS: string; + resultHeadCSS: string; + contentInnerHtml: string; + fluidRowHtml: string; + radioGroupHtml: string; + radioButtonHtml: string; + submitButtonHtml: string; + headLabelHtml: string; + resultHeadLabelHtml: string; + resultHtml: string; + headLabel: string; + resultHeadLabel: string; +} + +interface IELangBase { + name: string; + description: string; + delegates: any; + element: JQuery; + events: any; + options: any; + defaults: IELangBaseDefaults; + + initialize(target: HTMLElement, options: any): void; + + createContent(): void; + + createRadioGroup(node: JQuery, + isMethodAppend: bool, + buttonNumber: number, + defaultButton: number, + btnLabels: string[], + clickHandler: Function, + btnTooltips?: string[]): void; + appendAsLastChild(node: JQuery, element: JQuery): JQuery; + getLastChild(node: JQuery): JQuery; + isRdoChecked(eSrc: HTMLElement, rdoId: string): bool; + processCommand(command: string): JQuery; + setOptions(options: any): void; +} + +// ELangSearch + +interface IELangSearchDefaults extends IELangBaseDefaults { + expressionsLabel: string; + expressionsTooltip: string; + meaningsLabel: string; + meaningsTooltip: string; + searchFormHtml: string; + searchFieldHtml: string; + searchButtonLabel: string; +} + +interface IELangSearchDelegates { + selectHandler: Function; + selectCallback: Function; + langDirectionHandler: Function; + langDirectionClickHandler: Function; + searchHandler: Function; + searchClickHandler: Function; +} + +interface IELangSearchEvents { + select: JQueryDeferred; +} + +interface IELangSearch extends IELangBase { + defaults: IELangSearchDefaults; + delegates: IELangSearchDelegates; + events: IELangSearchEvents; + isSearchInExp: bool; + + initialize(target: HTMLElement, options: any): void; + createContent(): void; + + _onDirectionClick(eSrc: HTMLElement): void; + _onSelect(eSrc: HTMLInputElement): void; + _onSelectCallback(): void; + + _select(eSrc: HTMLInputElement): void; +} + +// ELangEdit + +interface IELangEditDelegates { + insertHandler: Function; + modifyHandler: Function; + removeHandler: Function; + selectHandler: Function; + btnAddHandler: Function; + btnAddClickHandler: Function; + + insertCallback: Function; + modifyCallback: Function; + removeCallback: Function; + selectCallback: Function; +} + +interface IELangEditEvents { + insert: JQueryDeferred; + modify: JQueryDeferred; + remove: JQueryDeferred; + select: JQueryDeferred; +} + +interface IELangEditDefaults extends IELangBaseDefaults { + editFormHtml: string; + editFieldHtml: string; + addButtonHtml: string; + addButtonLabel: string; + editKeyLabel: string; + editValueLabel: string; +} + +interface IELangEdit extends IELangBase { + defaults: IELangEditDefaults; + delegates: IELangEditDelegates; + events: IELangEditEvents; + + initialize(target: HTMLElement, options: any): void; + createContent(): void; + + _onAddClick(key: HTMLInputElement, value: HTMLInputElement): void; + _onInsert(): void; + _onInsertCallback(): void; + _onModify(): void; + _onModifyCallback(): void; + _onRemove(): void; + _onRemoveCallback(): void; + _onSelect(): void; + _onSelectCallback(): void; + + + _insert(): void; + _modify(): void; + _remove(): void; + _select(): void; +} + +// ELangTest + +interface IELangTestDefaults extends IELangBaseDefaults { + formHtml: string; + startButtonLabel: string; + stopButtonLabel: string; + rdoTypedLabel: string; + rdoSelectedLabel: string; + rdoOrderedLabel: string; + rdoRandomlyLabel: string; + rdoWrittedLabel: string; + rdoVoicedLabel: string; + rdoTypedTooltip: string; + rdoSelectedTooltip: string; + rdoOrderedTooltip: string; + rdoRandomlyTooltip: string; + rdoWrittedTooltip: string; + rdoVoicedTooltip: string; +} + +interface IELangTestDelegates { + startStopHandler: Function; + + rdoVariantHandler: Function; + rdoModeHandler: Function; + rdoQuestionHandler: Function; + + rdoVariantClickHandler: Function; + rdoModeClickHandler: Function; + rdoQuestionClickHandler: Function; +} + +interface IELangTest extends IELangBase { + defaults: IELangTestDefaults; + delegates: IELangTestDelegates; + + initialize(target: HTMLElement, options: any): void; + createContent(): void; + + _onRdoVariantClick(eSrc: HTMLElement): void; + _onRdoModeClick(eSrc: HTMLElement): void; + _onRdoQuestionClick(eSrc: HTMLElement): void; + _onStartStopClick(): void; +} + +// interfaces for jQuery.fn.__plugin + +interface IFnNewInstance { + createInstance(el: HTMLElement, + options: any, + pluginName: string): JQuery; +} + +interface IFnJQuery { + fnPlugin(context: JQuery, + options: any, + command: string, + pluginName: string, + pluginDataAttribute: string): JQuery; +} \ No newline at end of file diff --git a/jquery.livestampjs/jquery.livestampjs-tests.ts b/jquery.livestampjs/jquery.livestampjs-tests.ts new file mode 100644 index 000000000..72dc968cb --- /dev/null +++ b/jquery.livestampjs/jquery.livestampjs-tests.ts @@ -0,0 +1,15 @@ +// Tests for Livestamp.js type definitions +/// +/// +/// + +$('#test1').livestamp(new Date('June 18, 1987')); +$('#test2').livestamp(1362282933); +$('#test3').livestamp('destroy'); +$('#test4').livestamp(moment(new Date('June 18, 1987'))); + +$.livestamp.update(); +$.livestamp.pause(); +$.livestamp.resume(); +$.livestamp.interval(340); +var result:number = $.livestamp.interval(); \ No newline at end of file diff --git a/jquery.livestampjs/jquery.livestampjs.d.ts b/jquery.livestampjs/jquery.livestampjs.d.ts new file mode 100644 index 000000000..d460b888d --- /dev/null +++ b/jquery.livestampjs/jquery.livestampjs.d.ts @@ -0,0 +1,27 @@ +// Type definitions for Livestamp.js +// A simple, unobtrusive jQuery plugin that provides auto-updating timeago text to your timestamped HTML elements using Moment.js. +// Project: http://http://mattbradley.github.com/livestampjs/ +// Definitions by: Vincent Bortone +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// +/// + +interface LivestampGlobal { + update(): void; + pause(): void; + resume(): void; + interval(): number; + interval(interval: number): void; +} + +interface JQueryStatic { + livestamp: LivestampGlobal; +} + +interface JQuery { + livestamp(date: Date): JQuery; + livestamp(moment: Moment): JQuery; + livestamp(timestamp: number): JQuery; + livestamp(timestamp: string): JQuery; +} \ No newline at end of file diff --git a/jquery/jquery.d.ts b/jquery/jquery.d.ts index af17e8d6b..41d7d5e61 100644 --- a/jquery/jquery.d.ts +++ b/jquery/jquery.d.ts @@ -714,7 +714,7 @@ interface JQuery { ***********/ length: number; selector: string; - [x: string]: HTMLElement; + [x: string]: any; [x: number]: HTMLElement; /********** diff --git a/jsdeferred/jsdeferred-tests.ts b/jsdeferred/jsdeferred-tests.ts new file mode 100644 index 000000000..a42119bce --- /dev/null +++ b/jsdeferred/jsdeferred-tests.ts @@ -0,0 +1,858 @@ +/// +/// + +declare function alert(a:any):void; +declare function log(a:any):void; + +interface DeferredizedJQueryStatic extends JQueryStatic { + get(url:string, data?:any, success?:any, dataType?:any): Deferred; +} +declare var $: DeferredizedJQueryStatic; + +declare interface http { + get(url:string):Deferred; +} + + +/***** jsDoc case *****/ + + // constructor +(()=> { + var d = new Deferred(); + var d = Deferred(); +})(); + +// define +(()=> { + Deferred.define(); + $.get("/hoge").next(function (data) { + alert(data); + }). + parallel([$.get("foo.html"), $.get("bar.html")]).next(function (values) { + log($.map(values, function (v) { return v.length })); + if (values[1].match(/nextUrl:\s*(\S+)/)) { + return $.get(RegExp.$1).next(function (d) { + return d; + }); + } + }). + next(function (d) { + log(d.length); + }); +})(); + +// next +(()=> { + var d = new Deferred(); + d. + next(function () { + alert(1); + }). + next(function () { + alert(2); + }); + d.call(); +})(); + +// error +(()=> { + var d = new Deferred(); + d. + next(function () { + alert(1); + throw "foo"; + }). + next(function () { + alert('not shown'); + }). + error(function (e) { + alert(e); //=> "foo" + }); + d.call(); +})(); + +// call +(()=> { + var d = new Deferred(); + setTimeout(function () { + d.call('value'); + }, 100); + return d; +})(); + +// fail +(()=> { + var d = new Deferred(); + var x = new XMLHttpRequest(); + x.onreadystatechange = function () { + if (x.readyState == 4) { + if (x.status == 200) d.call(x); else d.fail(x); + } + }; + return d; +})(); + +// chain +(()=> { + chain( + function () { + return wait(0.5); + }, + function (w) { + throw "foo"; + }, + function error(e) { + alert(e); + }, + [ + function () { + return wait(1); + }, + function () { + return wait(2); + } + ], + function (result) { + alert([ result[0], result[1] ]); + }, + { + foo: wait(1), + bar: wait(1) + }, + function (result) { + alert([ result.foo, result.bar ]); + }, + function error(e) { + alert(e); + } + ); +})(); + +// wait +(()=> { + wait(1).next(function (elapsed) { + log(elapsed); //=> may be 990-1100 + }); +})(); + +// call +(()=> { + next(function () { + function pow(x, n) { + function _pow(n, r) { + print([n, r]); + if (n == 0) return r; + return call(_pow, n - 1, x * r); + } + + return call(_pow, n, 1); + } + + return call(pow, 2, 10); + }). + next(function (r) { + print([r, "end"]); + }); +})(); + +// parallel +(()=> { + parallel([ + $.get("foo.html"), + $.get("bar.html") + ]).next(function (values) { + values[0] //=> foo.html data + values[1] //=> bar.html data + }); + + parallel({ + foo: $.get("foo.html"), + bar: $.get("bar.html") + }).next(function (values) { + values.foo //=> foo.html data + values.bar //=> bar.html data + }); +})(); + +// loop +(()=> { + //=> loop 1 to 100 + loop({begin: 1, end: 100, step: 10}, function (n, o) { + for (var i = 0; i < o.step; i++) { + log(n + i); + } + }); + + //=> loop 10 times with sleeping 1 sec in each loop. + loop(10, function (n) { + log(n); + return wait(1); + }); +})(); + +// repeat +(()=> { + repeat(10, function (i) { + i //=> 0,1,2,3,4,5,6,7,8,9 + }); +})(); + +// register +(()=> { + // Deferred.register("loop", loop); + + // Global Deferred function + loop(10,function (n) { + print(n); + }). + // Registered Deferred.prototype.loop + loop(10, function (n) { + print(n); + }); +})(); + +// connect +(()=> { + var timeout = Deferred.connect(setTimeout, { target: window, ok: 0 }); + timeout(1).next(function () { + alert('after 1 sec'); + }); + + var timeout = Deferred.connect(window, "setTimeout"); + timeout(1).next(function () { + alert('after 1 sec'); + }); +})(); + +// retry +(()=> { + Deferred.retry(3,function () { + return http.get('foo.html'); + }). + next(function (res) { + res //=> response if succeeded + }). + error(function (e) { + e //=> error if all try failed + }); +})(); + + +/***** Tutorial case *****/ + +(()=> { + Deferred.define(); + + next(function () { + alert("Hello!"); + return wait(5); + }). + next(function () { + alert("World!"); + }); + + Deferred.next(function () { + alert("Hello!"); + return Deferred.wait(5); + }). + next(function () { + alert("World!"); + }); + + // http.get is assumed to be a function that takes a URI as an argument and returns a Deferred instance + var results = []; + next(function () { + return http.get("/foo.json").next(function (data) { + results.push(data); + }); + }). + next(function () { + return http.get("/baz.json").next(function (data) { + results.push(data); + }); + }). + next(function () { + return http.get("/baz.json").next(function (data) { + results.push(data); + }); + }). + next(function () { + alert(results); + }); + + var wants = ["/foo.json", "/bar.json", "/baz.json"]; + var results = []; + loop(wants.length,function (i) { + return http.get(wants[i]).next(function (data) { + results.push(data); + }); + }). + next(function () { + alert(results); + }); + + parallel([ + http.get("/foo.json"), + http.get("/bar.json"), + http.get("/baz.json") + ]). + next(function (results) { + alert(results); + }); + + next(function () { + // something 1 + }). + next(function () { + // asynchronous process + throw "error!"; + }). + next(function () { + // something 2 (not executed as an error occurs in the previous process) + }); + + next(function () { + // something 1 + }). + next(function () { + // asynchronous process + throw "error!"; + }). + next(function () { + // something 2 (not executed as an error occurs in the previous process) + }). + error(function (e) { + alert(e); + }); + + next(function () { + // something 1 + }). + next(function () { + // asynchronous process + throw "error!"; + }). + error(function (e) { + alert(e); + }). + next(function () { + // something 2 (executed since the exception would already be handled) + }). + error(function (e) { + alert(e); + }); + + next(function () { + alert("Hello!"); + return wait(5); + }). + next(function () { + alert("World!"); + }); + + next(function () { + alert(1); + return next(function () { + alert(2); + }). + next(function () { + alert(3); + }); + }). + next(function () { + alert(4); + }); + + var http = {} + http.get = function (uri) { + var deferred = new Deferred(); + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + deferred.call(xhr); + } else { + deferred.fail(xhr); + } + } + }; + deferred.canceller = function () { xhr.abort() }; + return deferred; + } + + loop(1000, function (n) { + // heavy process + }); + + function repeat(n, f) { + var i = 0, end = {}, ret = null; + return Deferred.next(function () { + var t = (new Date()).getTime(); + divide: { + do { + if (i >= n) break divide; + ret = f(i++); + } while ((new Date()).getTime() - t < 20); + return Deferred.call(arguments.callee); + } + }); + } + + next(function () { + console.log("start"); + }). + next(function () { + function pow(x, n) { + function _pow(n, r) { + console.log([n, r]); + if (n == 0) return r; + return call(_pow, n - 1, x * r); + } + + return call(_pow, n, 1); + } + + return call(pow, 2, 10); + }). + next(function (r) { + console.log([r, "end"]); + }). + error(function (e) { + alert(e); + }) + + loop(10, function (i) { + console.log(i) + }); + + $.get("README.markdown").next(function (data) { + console.log(data); + }); + +})(); + +(()=> { + console.log("start. gathering data."); + + parallel([$.get("README.markdown"), $.get("ChangeLog")]). + next(function (values) { + var lengths = $.map(values, function (i) { return i.length }); + console.log(lengths.join(", ")); + }); +})(); + +(()=> { + console.log("start. gathering data."); + + parallel({html: $.get("README.markdown"), js: $.get("ChangeLog")}). + next(function (values) { + console.log(["html=", values.html.length, " js=", values.js.length].join("")); + }); +})(); + +(()=> { + console.log("start. wait 3 sec."); + + var list = []; + var printAndReturn = function (i) { + console.log(i + "msec elapsed"); + return i; + }; + list.push(wait(0).next(printAndReturn)); + list.push(wait(1).next(printAndReturn)); + list.push(wait(2).next(printAndReturn)); + list.push(wait(3).next(printAndReturn)); + + parallel(list).next(function (values) { + console.log("Completed. values: " + values.join(", ")); + }); +})(); + +(()=> { + var queue = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + var workers = new Array(2); + var work = function (job) { + console.log('working... ' + job); + return wait(Math.random() * 4); + }; + + for (var i = 0, len = workers.length; i < len; i++) { + workers[i] = next(function me() { + var job = queue.shift(); + if (!job) return; + + console.log("start worker: " + job); + return next(function () { return job }). + next(work). + next(me); + }). + error(function (e) { + alert(e); + }); + } + + parallel(workers).next(function () { + console.log('all done!'); + }); +})(); + +(()=> { + next(function () { + var sum = 0; + return loop({end: 100000, step: 1000}, function (n, o) { + console.log(["Processing divided loop:n=", n, ", sum=", sum, " last?=", o.last].join("")); + for (var i = 0; i < o.step; i++) { + // console.log(i + n); + sum += i + n; + } + console.log(["sum=", sum].join("")); + return sum; + }); + }). + next(function (e) { + console.log("Result:" + e); + console.log("end"); + }). + error(function (e) { + console.log(e); + }); +})(); + +(()=> { + loop({begin: 1, end: 100, step: 10}, function (n, o) { + console.log(["Processing divided loop:n=", n, " last?=", o.last].join("")); + for (var i = 0; i < o.step; i++) { + var j = n + i; + console.log(j); + } + }); +})(); + +(()=> { + Deferred.repeat(100, function (n, o) { + console.log(n); + for (var i = 0; i < Math.pow(n, 2); i++) { + for (var j = n; j; j--); + } + }); +})(); + +(()=> { + loop(10, function (n) { + console.log(n); + return wait(0.1); + }); + + loop(10, function (n) { + console.log(String.fromCharCode(97 + n)); + return wait(0.2); + }); +})(); + +(()=> { + console.log(0); + loop(10,function (n) { + console.log(n); + return n; + }). + wait(1). + loop(10,function (n) { + var c = String.fromCharCode(97 + n); + console.log(c); + return c; + }). + next(function (i) { + console.log("end"); + }). + error(function (e) { + alert(e); + }); +})(); + +(()=> { + loop(5,function (i, o) { + console.log(i); + return o.last ? i : wait(1); + }). + next(function (e) { + console.log("end [" + e + "]"); + }). + error(function (e) { + console.log(e); + }); +})(); + +(()=> { + next(function (i) { + function delayloop(i) { + console.log(i++); + if (i < 5) { + return wait(1).next(function () { + return call(delayloop, i); + }); + } + } + + return call(delayloop, 0); + }). + next(function (e) { + console.log("end"); + }). + error(function (e) { + console.log(e); + }); +})(); + +(()=> { + function callcc(fun) { + var error = new Deferred(); + return call(function () { + // JSDeferred passes current Deferred Object to this. + var ccdeferred = this; + // Call with current continuation (calling Deferred.next) + return fun(function (a) { + ccdeferred._next.call(a); + throw error + }); + }). + error(function (e) { + // Current Deferred chain must be stopped + if (e === error) { + return e; + } else { + throw e; + } + }); + } + + callcc(function (cont) { + return 10 * 10 * cont(20); + }). + next(function (val) { + console.log("callcc1 returns:" + val); + }); + // should show "callcc1 returns:20" + + var cont; + var i = 0; + callcc(function (c) { + cont = c; + return 10; + }). + next(function (val) { + console.log("callcc2 returns:" + val); + if (!i++) cont(20); + }); + // should show "callcc2 returns:10", "callcc returns:20" +})(); + +(()=> { + function callcc(fun) { + var error = new Deferred(); + return call(function () { + // JSDeferred passes current Deferred Object to this. + var ccdeferred = this; + // Call with current continuation (calling Deferred.next) + return fun(function (a) { + ccdeferred._next.call(a); + throw error + }); + }). + error(function (e) { + // Current Deferred chain must be stopped + if (e === error) { + return e; + } else { + throw e; + } + }); + } + + // http://www.sampou.org/scheme/t-y-scheme/t-y-scheme-Z-H-16.html#node_chap_14 + // Just port above. + function amb() { + var alts = arguments; + var prevAmbFail = amb.ambFail; + + return callcc(function (sk) { + return loop(alts.length,function (i) { + var alt = alts[i]; + return callcc(function (fk) { + amb.ambFail = function () { + amb.ambFail = prevAmbFail; + return fk("fail"); + }; + return sk(alt); + }); + }). + next(prevAmbFail); + }); + } + + amb.ambFail = function () { throw "amb tree exhausted" }; + + // Utility function + function amb1(ambvars) { + var f = wait(0); + var vars = {}; + for (var k in ambvars) if (ambvars.hasOwnProperty(k)) (function (name, val) { + console.log(name); + f = f.next(function () { + return amb.apply(this, val).next(function (i) { + vars[name] = i; + return vars; + }); + }); + })(k, ambvars[k]); + + return f; + } + + function assert(cond) { + if (!cond) throw amb(); + } + + // http://mayokara.info/note/view/251 + Array.prototype.uniq = function () { + for (var i = 0, l = this.length; i < l; i++) { + if (this.indexOf(this[i]) < i) { + this.splice(i--, l-- && 1); + } + } + return this; + }; + + amb1({ + baker : [1, 2, 3, 4, 5], + cooper : [1, 2, 3, 4, 5], + fletcher: [1, 2, 3, 4, 5], + miller : [1, 2, 3, 4, 5], + smith : [1, 2, 3, 4, 5] + }). + next(function (vars) { + with (vars) { + console.log(vars); + // 簡易 distinct + assert([baker, cooper, fletcher, miller, smith].uniq().length == 5); + console.log("distinct passed"); + assert(baker != 5); + assert(cooper != 1); + assert(fletcher != 1 && fletcher != 5); + assert(miller > cooper); + assert(Math.abs(smith - fletcher) != 1); + assert(Math.abs(fletcher - cooper) != 1); + + return vars; + } + }). + next(function (vars) { + with (vars) { + console.log("solved"); + console.log(vars); + alert(uneval(vars)); + } + }). + error(function (e) { + alert(e) + }); +})(); + +(()=> { + var d1 = new Deferred(); + d1.callback.ok = function () { + alert("1"); + }; + + var d2 = new Deferred(); + d2.callback.ok = function () { + alert("2"); + }; + + // Set d2 as continuation of d1. + d1._next = d2; + + // Invoke the chain. + d1.call(); +})(); + +(()=> { + next(function () { // this `next` is global function + alert("1"); + }). + next(function () { // this `next` is Deferred#next + alert("2"); + }). + next(function () { + alert("3"); + }); +})(); + +(()=> { + next(function () { + alert("1"); + }). + next(function () { + alert("2"); + // child Deferred + return next(function () { + alert("3"); + }); + }). + next(function () { + alert("4"); + }); +})(); + +(()=> { + next(function () { + alert("1"); + }). + next(function () { + alert("2"); + var d = next(function () { + alert("3"); + }); + d._next = this._next; + this.cancel(); + }). + next(function () { + alert("4"); + }); +})(); + +(()=> { + next(function () { + alert("1"); + }). + next(function () { + alert("2"); + next(function () { + alert("3"); + }). + next(function () { + alert("4"); + }); + }); +})(); + +(()=> { + next(function () { + throw "Error"; + }). + error(function (e) { + expect("Errorback called", "Error", e); + return e; // recovering error + }). + next(function (e) { + expect("Callback called", "Error", e); + throw "Error2"; + }). + next(function (e) { + // This process is not called because + // the error is not recovered. + ng("Must not be called!!"); + }). + error(function (e) { + expect("Errorback called", "Error2", e); + }); +})(); diff --git a/jsdeferred/jsdeferred.d.ts b/jsdeferred/jsdeferred.d.ts new file mode 100644 index 000000000..1e354e7ee --- /dev/null +++ b/jsdeferred/jsdeferred.d.ts @@ -0,0 +1,98 @@ +// Type definitions for JSDeferred +// Project: https://github.com/cho45/jsdeferred +// Definitions by: Daisuke Mino +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +interface Loop { + begin:number; + end:number; + step:number; +} + +interface ConnectOption { + target:any; + args?:any[]; + ok?:number; + ng?:number; +} + +interface RetryOption { + wait:number; +} + +interface DeferredizedFunction { (...arg:any[]):Deferred; } +interface DeferredizedFunctionWithNumber { (n:number):Deferred; } +interface FunctionWithNumber { (i:number); } +interface ErrorCallback { (d:Deferred, ...args:any[]); } + +declare class Deferred { + + static methods:string[]; + + static isDeferred(obj:any):bool; + + static next(fun:Function):Deferred; + + static chain(...args:any[]):Deferred; + + static wait(n:number):Deferred; + + static call(fun?:Function, ...args:any[]):Deferred; + + static parallel(dl:any):Deferred; + + static earlier(dl:any):Deferred; + + static loop(n:number, fun:FunctionWithNumber):Deferred; + + static loop(n:Loop, fun:FunctionWithNumber):Deferred; + + static repeat(n:number, fun:FunctionWithNumber):Deferred; + + static register(name:string, fun:DeferredizedFunction):void; + + static connect(funo:any, options:string):DeferredizedFunction; + + static connect(funo:Function, options?:ConnectOption):DeferredizedFunction; + + static retry(retryCount:number, funcDeferred:DeferredizedFunctionWithNumber, options?:RetryOption):Deferred; + + static define(obj?:any, list?:string[]):any; + + constructor(); + + next(fun:Function):Deferred; + + wait(n:number):Deferred; + + error(fun:ErrorCallback):Deferred; + + call(val?:any):Deferred; + + fail(err:any):Deferred; + + cancel():Deferred; + + parallel(dl:any):Deferred; + + loop(n:number, fun:FunctionWithNumber):Deferred; + + loop(n:Loop, fun:FunctionWithNumber):Deferred; + +} + + +declare function chain(...args:any[]):Deferred; + +declare function wait(n:number):Deferred; + +declare function call(fun?:Function, ...args:any[]):Deferred; + +declare function parallel(dl:any):Deferred; + +declare function earlier(dl:any):Deferred; + +declare function loop(n:number, fun:FunctionWithNumber):Deferred; +declare function loop(n:Loop, fun:FunctionWithNumber):Deferred; + +declare function repeat(n:number, fun:FunctionWithNumber):Deferred; \ No newline at end of file diff --git a/knockout/knockout.d.ts b/knockout/knockout.d.ts index c13856198..19cf7ba33 100644 --- a/knockout/knockout.d.ts +++ b/knockout/knockout.d.ts @@ -1,526 +1,533 @@ -// Type definitions for Knockout 2.2 -// Project: http://knockoutjs.com -// Definitions by: Boris Yankov -// Definitions: https://github.com/borisyankov/DefinitelyTyped - - -interface KnockoutSubscribableFunctions { - extend(source); - dispose(): void; - peek(): any; - valueHasMutated(): void; - - valueWillMutate(): void; -} - -interface KnockoutComputedFunctions extends KnockoutSubscribableFunctions { - getDependenciesCount(): number; - hasWriteFunction(): bool; -} - -interface KnockoutObservableFunctions extends KnockoutSubscribableFunctions { -} - -interface KnockoutObservableArrayFunctions extends KnockoutObservableFunctions { - // General Array functions - indexOf(searchElement, fromIndex?: number): number; - slice(start: number, end?: number): any[]; - splice(start: number): any[]; - splice(start: number, deleteCount: number, ...items: any[]): any[]; - pop(); - push(...items: any[]): void; - shift(); - unshift(...items: any[]): number; - reverse(): any[]; - sort(): void; - sort(compareFunction): void; - - // Ko specific - replace(oldItem: any, newItem: any): void; - - remove(item): any[]; - removeAll(items: any[]): any[]; - removeAll(): any[]; - - destroy(item): void; - destroyAll(items: any[]): void; - destroyAll(): void; -} - -interface KnockoutSubscribableStatic { - fn: KnockoutSubscribableFunctions; - - new (): KnockoutSubscription; -} - -interface KnockoutSubscription extends KnockoutSubscribableFunctions { - subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite, topic?: string); -} - -interface KnockoutComputedStatic { - fn: KnockoutComputedFunctions; - - (): KnockoutComputed; - (func: Function, context?: any, options?: any): KnockoutComputed; - (def: KnockoutComputedDefine): KnockoutComputed; - (options?: any): KnockoutComputed; -} - -interface KnockoutComputed extends KnockoutComputedFunctions { - (): any; - (value: any): void; - - subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite, topic?: string); -} - -interface KnockoutObservableArrayStatic { - - fn: KnockoutObservableArrayFunctions; - - (): KnockoutObservableArray; - (value: any[]): KnockoutObservableArray; - - new(): KnockoutObservableArray; - new(value: any[]): KnockoutObservableArray; -} - -interface KnockoutObservableArray extends KnockoutObservableArrayFunctions { - (): any[]; - (value: any[]): void; - - subscribe(callback: (newValue: any[]) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite: any[], topic?: string); -} - -interface KnockoutObservableStatic { - fn: KnockoutObservableFunctions; - - (value: string): KnockoutObservableString; - (value: Date): KnockoutObservableDate; - (value: number): KnockoutObservableNumber; - (value: bool): KnockoutObservableBool; - (value?: any): KnockoutObservableAny; - - new(value: string): KnockoutObservableString; - new(value: Date): KnockoutObservableDate; - new(value: number): KnockoutObservableNumber; - new(value: bool): KnockoutObservableBool; - new(value?: any): KnockoutObservableAny; -} - -/** use as method to get/set the value */ -interface KnockoutObservableBase extends KnockoutObservableFunctions { - getSubscriptionsCount(): number; -} - -/** use as method to get/set the value -can cast to a more appropriate (typed) interface such as KnockoutObservableString or KnockoutObservableNumber -*/ -interface KnockoutObservableAny extends KnockoutObservableBase { - - (): any; - (value): void; - - subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite, topic?: string); -} - -interface KnockoutObservableString extends KnockoutObservableBase { - (): string; - (value: string): void; - - subscribe(callback: (newValue: string) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite: string, topic?: string); -} - - -interface KnockoutObservableNumber extends KnockoutObservableBase { - (): number; - (value: number): void; - - subscribe(callback: (newValue: number) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite: number, topic?: string); -} - -interface KnockoutObservableBool extends KnockoutObservableBase { - (): bool; - (value: bool): void; - - subscribe(callback: (newValue: bool) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite: bool, topic?: string); -} - -interface KnockoutObservableDate extends KnockoutObservableBase { - (): Date; - (value: Date): void; - - subscribe(callback: (newValue: Date) => void, target?:any, topic?: string): KnockoutSubscription; - notifySubscribers(valueToWrite: Date, topic?: string); -} - -interface KnockoutComputedDefine { - read(): any; - write(any); -} - -interface KnockoutBindingContext { - $parent: any; - $parents: any[]; - $root: any; - $data: any; - $index?: number; - $parentContext?: KnockoutBindingContext; - - extend(any): any; - createChildContext(any): any; -} - -interface KnockoutBindingHandler { - init?(element: any, valueAccessor: () => any, allBindingsAccessor: () => any, viewModel: any, bindingContext: KnockoutBindingContext): void; - update?(element: any, valueAccessor: () => any, allBindingsAccessor: () => any, viewModel: any, bindingContext: KnockoutBindingContext): void; - options?: any; -} - -interface KnockoutBindingHandlers { - // Controlling text and appearance - visible: KnockoutBindingHandler; - text: KnockoutBindingHandler; - html: KnockoutBindingHandler; - css: KnockoutBindingHandler; - style: KnockoutBindingHandler; - attr: KnockoutBindingHandler; - - // Control Flow - foreach: KnockoutBindingHandler; - if: KnockoutBindingHandler; - ifnot: KnockoutBindingHandler; - with: KnockoutBindingHandler; - - // Working with form fields - click: KnockoutBindingHandler; - event: KnockoutBindingHandler; - submit: KnockoutBindingHandler; - enable: KnockoutBindingHandler; - disable: KnockoutBindingHandler; - value: KnockoutBindingHandler; - hasfocus: KnockoutBindingHandler; - checked: KnockoutBindingHandler; - options: KnockoutBindingHandler; - selectedOptions: KnockoutBindingHandler; - uniqueName: KnockoutBindingHandler; - - // Rendering templates - template: KnockoutBindingHandler; -} - -interface KnockoutMemoization { - memoize(callback); - unmemoize(memoId, callbackParams); - unmemoizeDomNodeAndDescendants(domNode, extraCallbackParamsArray); - parseMemoText(memoText); -} - -interface KnockoutVirtualElements { - allowedBindings; - emptyNode; - firstChild; - insertAfter; - nextSibling; - prepend; - setDomNodeChildren; -} - -interface KnockoutExtenders { - throttle(target: any, timeout: number): KnockoutComputed; - notify(target: any, notifyWhen: string): any; -} - -interface KnockoutUtils { - - ////////////////////////////////// - // utils.domManipulation.js - ////////////////////////////////// - - simpleHtmlParse(html: string); - - jQueryHtmlParse(html: string); - - parseHtmlFragment(html: string); - - setHtml(node: Element, html: string): void; - - setHtml(node: Element, html: () => string): void; - - ////////////////////////////////// - // utils.domData.js - ////////////////////////////////// - - domData: { - get (node: Element, key: string); - - set (node: Element, key: string, value: any); - - getAll(node: Element, createIfNotFound: bool); - - clear(node: Element); - }; - - ////////////////////////////////// - // utils.domNodeDisposal.js - ////////////////////////////////// - - domNodeDisposal: { - addDisposeCallback(node: Element, callback: Function); - - removeDisposeCallback(node: Element, callback: Function); - - cleanNode(node: Element); - - removeNode(node: Element); - }; - - ////////////////////////////////// - // utils.js - ////////////////////////////////// - - fieldsIncludedWithJsonPost: any[]; - - arrayForEach(array: any[], action: (any) => void ): void; - - arrayIndexOf(array: any[], item: any): number; - - arrayFirst(array: any[], predicate: (item) => bool, predicateOwner?: any): any; - - arrayRemoveItem(array: any[], itemToRemove: any): void; - - arrayGetDistinctValues(array: any[]): any[]; - - arrayMap(array: any[], mapping: (item) => any): any[]; - - arrayFilter(array: any[], predicate: (item) => bool): any[]; - - arrayPushAll(array: any[], valuesToPush: any[]): any[]; - - extend(target, source); - - emptyDomNode(domNode): void; - - moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement; - - cloneNodes(nodesArray: any[], shouldCleanNodes: bool): any[]; - - setDomNodeChildren(domNode: any, childNodes: any[]): void; - - replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void; - - setOptionNodeSelectionState(optionNode: any, isSelected: bool): void; - - stringTrim(str: string): string; - - stringTokenize(str: string, delimiter: string): string; - - stringStartsWith(str: string, startsWith: string): string; - - domNodeIsContainedBy(node: any, containedByNode: any): bool; - - domNodeIsAttachedToDocument(node: any): bool; - - tagNameLower(element: any): string; - - registerEventHandler(element: any, eventType: any, handler: Function): void; - - triggerEvent(element: any, eventType: any): void; - - unwrapObservable(value: any): any; - - toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: bool): void; - - //setTextContent(element: any, textContent: string): void; // NOT PART OF THE MINIFIED API SURFACE (ONLY IN knockout-{version}.debug.js) https://github.com/SteveSanderson/knockout/issues/670 - - setElementName(element: any, name: string): void; - - ensureSelectElementIsRenderedCorrectly(selectElement); - - forceRefresh(node: any): void; - - ensureSelectElementIsRenderedCorrectly(selectElement: any): void; - - range(min: any, max: any): any; - - makeArray(arrayLikeObject: any): any[]; - - getFormFields(form: any, fieldName: string): any[]; - - parseJson(jsonString: string): any; - - stringifyJson(data: any, replacer: Function, space: string): string; - - postJson(urlOrForm: any, data: any, options: any): void; - - ieVersion: number; - - isIe6: bool; - - isIe7: bool; -} - -////////////////////////////////// -// templateSources.js -////////////////////////////////// - -interface KnockoutTemplateSourcesDomElement { - - text(valueToWrite?); - - data(key, valueToWrite?); -} - - -interface KnockoutTemplateSources { - - domElement: KnockoutTemplateSourcesDomElement; - - anonymousTemplate: { - - prototype: KnockoutTemplateSourcesDomElement; - - new (element: Element): KnockoutTemplateSourcesDomElement; - }; -}; - -////////////////////////////////// -// nativeTemplateEngine.js -////////////////////////////////// - -interface KnockoutNativeTemplateEngine { - - renderTemplateSource(templateSource, bindingContext, options?); -} - -////////////////////////////////// -// templateEngine.js -////////////////////////////////// - -interface KnockoutTemplateEngine extends KnockoutNativeTemplateEngine { - - createJavaScriptEvaluatorBlock(script: string); - - makeTemplateSource(template, templateDocument); - - renderTemplate(template, bindingContext, options, templateDocument); - - isTemplateRewritten(template, templateDocument): bool; - - rewriteTemplate(template, rewriterCallback, templateDocument); -} - -///////////////////////////////// - -interface KnockoutStatic { - utils: KnockoutUtils; - memoization: KnockoutMemoization; - bindingHandlers: KnockoutBindingHandlers; - virtualElements: KnockoutVirtualElements; - extenders: KnockoutExtenders; - - applyBindings(viewModel: any, rootNode?: any): void; - applyBindingsToDescendants(viewModel: any, rootNode: any): void; - applyBindingsToNode(node: Element, options: any, viewModel: any): void; - - subscribable: KnockoutSubscribableStatic; - observable: KnockoutObservableStatic; - computed: KnockoutComputedStatic; - observableArray: KnockoutObservableArrayStatic; - - contextFor(node: any): any; - isSubscribable(instance: any): bool; - toJSON(viewModel: any, replacer?: Function, space?: any): string; - toJS(viewModel: any): any; - isObservable(instance: any): bool; - isComputed(instance: any): bool; - dataFor(node: any): any; - removeNode(node: Element); - cleanNode(node: Element); - renderTemplate(template: Function, viewModel: any, options?: any, target?: any, renderMode?: any); - renderTemplate(template: string, viewModel: any, options?: any, target?: any, renderMode?: any); - - ////////////////////////////////// - // templateSources.js - ////////////////////////////////// - - templateSources: KnockoutTemplateSources; - - ////////////////////////////////// - // templateEngine.js - ////////////////////////////////// - - templateEngine: { - - prototype: KnockoutTemplateEngine; - - new (): KnockoutTemplateEngine; - }; - - ////////////////////////////////// - // templateRewriting.js - ////////////////////////////////// - - templateRewriting: { - - ensureTemplateIsRewritten(template, templateEngine, templateDocument); - - memoizeBindingAttributeSyntax(htmlString: string, templateEngine: KnockoutTemplateEngine); - - applyMemoizedBindingsToNextSibling(bindings); - }; - - ////////////////////////////////// - // nativeTemplateEngine.js - ////////////////////////////////// - - nativeTemplateEngine: { - - prototype: KnockoutNativeTemplateEngine; - - new (): KnockoutNativeTemplateEngine; - - instance: KnockoutNativeTemplateEngine; - }; - - ////////////////////////////////// - // jqueryTmplTemplateEngine.js - ////////////////////////////////// - - jqueryTmplTemplateEngine: { - - prototype: KnockoutTemplateEngine; - - renderTemplateSource(templateSource, bindingContext, options); - - createJavaScriptEvaluatorBlock(script: string): string; - - addTemplate(templateName, templateMarkup); - }; - - ////////////////////////////////// - // templating.js - ////////////////////////////////// - - setTemplateEngine(templateEngine: KnockoutNativeTemplateEngine); - - renderTemplate(template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode); - - renderTemplateForEach(template, arrayOrObservableArray, options, targetNode, parentBindingContext); - - expressionRewriting: { - bindingRewriteValidators: any; - }; - - ///////////////////////////////// - - bindingProvider: any; -} - -declare var ko: KnockoutStatic; \ No newline at end of file +// Type definitions for Knockout 2.2 +// Project: http://knockoutjs.com +// Definitions by: Boris Yankov +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +interface KnockoutSubscribableFunctions { + extend(source); + dispose(): void; + peek(): any; + valueHasMutated(): void; + + valueWillMutate(): void; +} + +interface KnockoutComputedFunctions extends KnockoutSubscribableFunctions { + getDependenciesCount(): number; + hasWriteFunction(): bool; +} + +interface KnockoutObservableFunctions extends KnockoutSubscribableFunctions { +} + +interface KnockoutObservableArrayFunctions extends KnockoutObservableFunctions { + // General Array functions + indexOf(searchElement, fromIndex?: number): number; + slice(start: number, end?: number): any[]; + splice(start: number): any[]; + splice(start: number, deleteCount: number, ...items: any[]): any[]; + pop(); + push(...items: any[]): void; + shift(); + unshift(...items: any[]): number; + reverse(): any[]; + sort(): void; + sort(compareFunction): void; + + // Ko specific + replace(oldItem: any, newItem: any): void; + + remove(item): any[]; + removeAll(items: any[]): any[]; + removeAll(): any[]; + + destroy(item): void; + destroyAll(items: any[]): void; + destroyAll(): void; +} + +interface KnockoutSubscribableStatic { + fn: KnockoutSubscribableFunctions; + + new (): KnockoutSubscription; +} + +interface KnockoutSubscription extends KnockoutSubscribableFunctions { + subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite, topic?: string); +} + +interface KnockoutComputedStatic { + fn: KnockoutComputedFunctions; + + (): KnockoutComputed; + (func: Function, context?: any, options?: any): KnockoutComputed; + (def: KnockoutComputedDefine): KnockoutComputed; + (options?: any): KnockoutComputed; +} + +interface KnockoutComputed extends KnockoutComputedFunctions { + (): any; + (value: any): void; + + subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite, topic?: string); +} + +interface KnockoutObservableArrayStatic { + + fn: KnockoutObservableArrayFunctions; + + (): KnockoutObservableArray; + (value: any[]): KnockoutObservableArray; + + new(): KnockoutObservableArray; + new(value: any[]): KnockoutObservableArray; +} + +interface KnockoutObservableArray extends KnockoutObservableArrayFunctions { + (): any[]; + (value: any[]): void; + + subscribe(callback: (newValue: any[]) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: any[], topic?: string); +} + +interface KnockoutObservableStatic { + fn: KnockoutObservableFunctions; + + (value: string): KnockoutObservableString; + (value: Date): KnockoutObservableDate; + (value: number): KnockoutObservableNumber; + (value: bool): KnockoutObservableBool; + (value?: any): KnockoutObservableAny; + + new(value: string): KnockoutObservableString; + new(value: Date): KnockoutObservableDate; + new(value: number): KnockoutObservableNumber; + new(value: bool): KnockoutObservableBool; + new(value?: any): KnockoutObservableAny; +} + +/** use as method to get/set the value */ +interface KnockoutObservableBase extends KnockoutObservableFunctions { + getSubscriptionsCount(): number; +} + +/** use as method to get/set the value +can cast to a more appropriate (typed) interface such as KnockoutObservableString or KnockoutObservableNumber +*/ +interface KnockoutObservableAny extends KnockoutObservableBase { + + (): any; + (value): void; + + subscribe(callback: (newValue: any) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite, topic?: string); +} + +interface KnockoutObservableString extends KnockoutObservableBase { + (): string; + (value: string): void; + + subscribe(callback: (newValue: string) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: string, topic?: string); +} + +interface KnockoutObservableObject extends KnockoutObservableBase { + (): {}; + (value: {}): void; + + subscribe(callback: (newValue: {}) => void , target?: any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: {}, topic?: string); +} + +interface KnockoutObservableNumber extends KnockoutObservableBase { + (): number; + (value: number): void; + + subscribe(callback: (newValue: number) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: number, topic?: string); +} + +interface KnockoutObservableBool extends KnockoutObservableBase { + (): bool; + (value: bool): void; + + subscribe(callback: (newValue: bool) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: bool, topic?: string); +} + +interface KnockoutObservableDate extends KnockoutObservableBase { + (): Date; + (value: Date): void; + + subscribe(callback: (newValue: Date) => void, target?:any, topic?: string): KnockoutSubscription; + notifySubscribers(valueToWrite: Date, topic?: string); +} + +interface KnockoutComputedDefine { + read(): any; + write(any); +} + +interface KnockoutBindingContext { + $parent: any; + $parents: any[]; + $root: any; + $data: any; + $index?: number; + $parentContext?: KnockoutBindingContext; + + extend(any): any; + createChildContext(any): any; +} + +interface KnockoutBindingHandler { + init?(element: any, valueAccessor: () => any, allBindingsAccessor: () => any, viewModel: any, bindingContext: KnockoutBindingContext): void; + update?(element: any, valueAccessor: () => any, allBindingsAccessor: () => any, viewModel: any, bindingContext: KnockoutBindingContext): void; + options?: any; +} + +interface KnockoutBindingHandlers { + // Controlling text and appearance + visible: KnockoutBindingHandler; + text: KnockoutBindingHandler; + html: KnockoutBindingHandler; + css: KnockoutBindingHandler; + style: KnockoutBindingHandler; + attr: KnockoutBindingHandler; + + // Control Flow + foreach: KnockoutBindingHandler; + if: KnockoutBindingHandler; + ifnot: KnockoutBindingHandler; + with: KnockoutBindingHandler; + + // Working with form fields + click: KnockoutBindingHandler; + event: KnockoutBindingHandler; + submit: KnockoutBindingHandler; + enable: KnockoutBindingHandler; + disable: KnockoutBindingHandler; + value: KnockoutBindingHandler; + hasfocus: KnockoutBindingHandler; + checked: KnockoutBindingHandler; + options: KnockoutBindingHandler; + selectedOptions: KnockoutBindingHandler; + uniqueName: KnockoutBindingHandler; + + // Rendering templates + template: KnockoutBindingHandler; +} + +interface KnockoutMemoization { + memoize(callback); + unmemoize(memoId, callbackParams); + unmemoizeDomNodeAndDescendants(domNode, extraCallbackParamsArray); + parseMemoText(memoText); +} + +interface KnockoutVirtualElements { + allowedBindings; + emptyNode; + firstChild; + insertAfter; + nextSibling; + prepend; + setDomNodeChildren; +} + +interface KnockoutExtenders { + throttle(target: any, timeout: number): KnockoutComputed; + notify(target: any, notifyWhen: string): any; +} + +interface KnockoutUtils { + + ////////////////////////////////// + // utils.domManipulation.js + ////////////////////////////////// + + simpleHtmlParse(html: string); + + jQueryHtmlParse(html: string); + + parseHtmlFragment(html: string); + + setHtml(node: Element, html: string): void; + + setHtml(node: Element, html: () => string): void; + + ////////////////////////////////// + // utils.domData.js + ////////////////////////////////// + + domData: { + get (node: Element, key: string); + + set (node: Element, key: string, value: any); + + getAll(node: Element, createIfNotFound: bool); + + clear(node: Element); + }; + + ////////////////////////////////// + // utils.domNodeDisposal.js + ////////////////////////////////// + + domNodeDisposal: { + addDisposeCallback(node: Element, callback: Function); + + removeDisposeCallback(node: Element, callback: Function); + + cleanNode(node: Element); + + removeNode(node: Element); + }; + + ////////////////////////////////// + // utils.js + ////////////////////////////////// + + fieldsIncludedWithJsonPost: any[]; + + arrayForEach(array: any[], action: (any) => void ): void; + + arrayIndexOf(array: any[], item: any): number; + + arrayFirst(array: any[], predicate: (item) => bool, predicateOwner?: any): any; + + arrayRemoveItem(array: any[], itemToRemove: any): void; + + arrayGetDistinctValues(array: any[]): any[]; + + arrayMap(array: any[], mapping: (item) => any): any[]; + + arrayFilter(array: any[], predicate: (item) => bool): any[]; + + arrayPushAll(array: any[], valuesToPush: any[]): any[]; + + extend(target, source); + + emptyDomNode(domNode): void; + + moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement; + + cloneNodes(nodesArray: any[], shouldCleanNodes: bool): any[]; + + setDomNodeChildren(domNode: any, childNodes: any[]): void; + + replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void; + + setOptionNodeSelectionState(optionNode: any, isSelected: bool): void; + + stringTrim(str: string): string; + + stringTokenize(str: string, delimiter: string): string; + + stringStartsWith(str: string, startsWith: string): string; + + domNodeIsContainedBy(node: any, containedByNode: any): bool; + + domNodeIsAttachedToDocument(node: any): bool; + + tagNameLower(element: any): string; + + registerEventHandler(element: any, eventType: any, handler: Function): void; + + triggerEvent(element: any, eventType: any): void; + + unwrapObservable(value: any): any; + + toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: bool): void; + + //setTextContent(element: any, textContent: string): void; // NOT PART OF THE MINIFIED API SURFACE (ONLY IN knockout-{version}.debug.js) https://github.com/SteveSanderson/knockout/issues/670 + + setElementName(element: any, name: string): void; + + ensureSelectElementIsRenderedCorrectly(selectElement); + + forceRefresh(node: any): void; + + ensureSelectElementIsRenderedCorrectly(selectElement: any): void; + + range(min: any, max: any): any; + + makeArray(arrayLikeObject: any): any[]; + + getFormFields(form: any, fieldName: string): any[]; + + parseJson(jsonString: string): any; + + stringifyJson(data: any, replacer: Function, space: string): string; + + postJson(urlOrForm: any, data: any, options: any): void; + + ieVersion: number; + + isIe6: bool; + + isIe7: bool; +} + +////////////////////////////////// +// templateSources.js +////////////////////////////////// + +interface KnockoutTemplateSourcesDomElement { + + text(valueToWrite?); + + data(key, valueToWrite?); +} + + +interface KnockoutTemplateSources { + + domElement: KnockoutTemplateSourcesDomElement; + + anonymousTemplate: { + + prototype: KnockoutTemplateSourcesDomElement; + + new (element: Element): KnockoutTemplateSourcesDomElement; + }; +}; + +////////////////////////////////// +// nativeTemplateEngine.js +////////////////////////////////// + +interface KnockoutNativeTemplateEngine { + + renderTemplateSource(templateSource, bindingContext, options?); +} + +////////////////////////////////// +// templateEngine.js +////////////////////////////////// + +interface KnockoutTemplateEngine extends KnockoutNativeTemplateEngine { + + createJavaScriptEvaluatorBlock(script: string); + + makeTemplateSource(template, templateDocument); + + renderTemplate(template, bindingContext, options, templateDocument); + + isTemplateRewritten(template, templateDocument): bool; + + rewriteTemplate(template, rewriterCallback, templateDocument); +} + +///////////////////////////////// + +interface KnockoutStatic { + utils: KnockoutUtils; + memoization: KnockoutMemoization; + bindingHandlers: KnockoutBindingHandlers; + virtualElements: KnockoutVirtualElements; + extenders: KnockoutExtenders; + + applyBindings(viewModel: any, rootNode?: any): void; + applyBindingsToDescendants(viewModel: any, rootNode: any): void; + applyBindingsToNode(node: Element, options: any, viewModel: any): void; + + subscribable: KnockoutSubscribableStatic; + observable: KnockoutObservableStatic; + computed: KnockoutComputedStatic; + observableArray: KnockoutObservableArrayStatic; + + contextFor(node: any): any; + isSubscribable(instance: any): bool; + toJSON(viewModel: any, replacer?: Function, space?: any): string; + toJS(viewModel: any): any; + isObservable(instance: any): bool; + isComputed(instance: any): bool; + dataFor(node: any): any; + removeNode(node: Element); + cleanNode(node: Element); + renderTemplate(template: Function, viewModel: any, options?: any, target?: any, renderMode?: any); + renderTemplate(template: string, viewModel: any, options?: any, target?: any, renderMode?: any); + + ////////////////////////////////// + // templateSources.js + ////////////////////////////////// + + templateSources: KnockoutTemplateSources; + + ////////////////////////////////// + // templateEngine.js + ////////////////////////////////// + + templateEngine: { + + prototype: KnockoutTemplateEngine; + + new (): KnockoutTemplateEngine; + }; + + ////////////////////////////////// + // templateRewriting.js + ////////////////////////////////// + + templateRewriting: { + + ensureTemplateIsRewritten(template, templateEngine, templateDocument); + + memoizeBindingAttributeSyntax(htmlString: string, templateEngine: KnockoutTemplateEngine); + + applyMemoizedBindingsToNextSibling(bindings); + }; + + ////////////////////////////////// + // nativeTemplateEngine.js + ////////////////////////////////// + + nativeTemplateEngine: { + + prototype: KnockoutNativeTemplateEngine; + + new (): KnockoutNativeTemplateEngine; + + instance: KnockoutNativeTemplateEngine; + }; + + ////////////////////////////////// + // jqueryTmplTemplateEngine.js + ////////////////////////////////// + + jqueryTmplTemplateEngine: { + + prototype: KnockoutTemplateEngine; + + renderTemplateSource(templateSource, bindingContext, options); + + createJavaScriptEvaluatorBlock(script: string): string; + + addTemplate(templateName, templateMarkup); + }; + + ////////////////////////////////// + // templating.js + ////////////////////////////////// + + setTemplateEngine(templateEngine: KnockoutNativeTemplateEngine); + + renderTemplate(template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode); + + renderTemplateForEach(template, arrayOrObservableArray, options, targetNode, parentBindingContext); + + expressionRewriting: { + bindingRewriteValidators: any; + }; + + ///////////////////////////////// + + bindingProvider: any; +} + +declare var ko: KnockoutStatic; diff --git a/preloadjs/preloadjs.d.ts b/preloadjs/preloadjs.d.ts index 4edbe81ae..51c9cee1f 100644 --- a/preloadjs/preloadjs.d.ts +++ b/preloadjs/preloadjs.d.ts @@ -21,42 +21,42 @@ module createjs { close(): void; getItem(value: string): Object; load(): void; - toString(): string; + toString(): string; // events - complete: (event: Object) => any; - error: (event: Object) => any; - fileload: (event: Object) => any; - fileprogress: (event: Object) => any; - loadStart: (event: Object) => any; + complete: (event: Object) => any; + error: (event: Object) => any; + fileload: (event: Object) => any; + fileprogress: (event: Object) => any; + loadStart: (event: Object) => any; - // EventDispatcher mixins - addEventListener(type: string, listener: (eventObj: Object) => bool): Function; - addEventListener(type: string, listener: (eventObj: Object) => bool): Object; - removeEventListener(type: string, listener: (eventObj: Function) => bool): void; - removeEventListener(type: string, listener: (eventObj: Object) => bool): void; - removeAllEventListeners(type: string): void; - dispatchEvent(eventObj: string, target: Object): bool; - dispatchEvent(eventObj: Object, target: Object): bool; - hasEventListener(type: string): bool; + // EventDispatcher mixins + addEventListener(type: string, listener: (eventObj: Object) => bool): Function; + addEventListener(type: string, listener: (eventObj: Object) => bool): Object; + removeEventListener(type: string, listener: (eventObj: Function) => bool): void; + removeEventListener(type: string, listener: (eventObj: Object) => bool): void; + removeAllEventListeners(type: string): void; + dispatchEvent(eventObj: string, target: Object): bool; + dispatchEvent(eventObj: Object, target: Object): bool; + hasEventListener(type: string): bool; } - export class PreloadJS { - version: string; - buildDate: string; - } + export class PreloadJS { + version: string; + buildDate: string; + } export class LoadQueue extends AbstractLoader { constructor (useXHR?: bool); // properties - static BINARY: string; + static BINARY: string; static CSS: string; static IMAGE: string; static JAVASCRIPT: string; static JSON: string; static SOUND: string; - static SVG: string; + static SVG: string; static TEXT: string; static LOAD_TIMEOUT: number; static XML: string; @@ -68,24 +68,23 @@ module createjs { // methods BrowserDetect(): Object; - init(useXHR?: bool): void; + init(useXHR?: bool): void; close(): void; - getResult(value: string): Object; initialize(useXHR: bool): void; installPlugin(plugin: () => any): void; load(): void; - loadFile(file: Object, loadNow: bool): void; - loadFile(file: string, loadNow: bool): void; - loadManifest(manifest: Object[], loadNow: bool): void; - loadManifest(manifest: string[], loadNow: bool): void; - getItem(value: string): Object; - getResult(value: string, rawResult?: bool): Object; - removeAll(): void; - remove(idsOrUrls: string): void; - remove(idsOrUrls: Array): void; - reset(): void; + loadFile(file: Object, loadNow?: bool): void; + loadFile(file: string, loadNow?: bool): void; + loadManifest(manifest: Object[], loadNow?: bool): void; + loadManifest(manifest: string[], loadNow?: bool): void; + getItem(value: string): Object; + getResult(value: string, rawResult?: bool): Object; + removeAll(): void; + remove(idsOrUrls: string): void; + remove(idsOrUrls: Array): void; + reset(): void; setMaxConnections(value: number): void; - setUseXHR(value: bool): void; + setUseXHR(value: bool): void; setPaused(value: bool): void; } @@ -93,13 +92,13 @@ module createjs { export class TagLoader extends AbstractLoader { constructor (item: Object, srcAttr: string, useXHR: bool); constructor (item: string, srcAttr: string, useXHR: bool); - getResult(): HTMLImageElement; - getResult(): HTMLAudioElement; + getResult(): HTMLImageElement; + getResult(): HTMLAudioElement; } export class XHRLoader extends AbstractLoader { constructor (file: Object); - getResult(rawResult?: bool); + getResult(rawResult?: bool); } } diff --git a/threejs/three-tests.ts b/threejs/three-tests.ts new file mode 100644 index 000000000..5b3bbb2ca --- /dev/null +++ b/threejs/three-tests.ts @@ -0,0 +1,23815 @@ +/// +/// + +/* +The MIT License + +Copyright (c) 2010-2013 three.js authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// https://github.com/mrdoob/three.js/tree/master/test/unit/math + +()=>{ + var x = 2; + var y = 3; + var z = 4; + var w = 5; + + var negInf2 = new THREE.Vector2( -Infinity, -Infinity ); + var posInf2 = new THREE.Vector2( Infinity, Infinity ); + + var zero2 = new THREE.Vector2(); + var one2 = new THREE.Vector2( 1, 1 ); + var two2 = new THREE.Vector2( 2, 2 ); + + var negInf3 = new THREE.Vector3( -Infinity, -Infinity, -Infinity ); + var posInf3 = new THREE.Vector3( Infinity, Infinity, Infinity ); + + var zero3 = new THREE.Vector3(); + var one3 = new THREE.Vector3( 1, 1, 1 ); + var two3 = new THREE.Vector3( 2, 2, 2 ); + + (QUnit.module)( "Box2" ); + + test( "constructor", function() { + var a = new THREE.Box2(); + ok( a.min.equals( posInf2 ), "Passed!" ); + ok( a.max.equals( negInf2 ), "Passed!" ); + + a = new THREE.Box2( zero2.clone(), zero2.clone() ); + ok( a.min.equals( zero2 ), "Passed!" ); + ok( a.max.equals( zero2 ), "Passed!" ); + + a = new THREE.Box2( zero2.clone(), one2.clone() ); + ok( a.min.equals( zero2 ), "Passed!" ); + ok( a.max.equals( one2 ), "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Box2( zero2.clone(), one2.clone() ); + var b = new THREE.Box2().copy( a ); + ok( b.min.equals( zero2 ), "Passed!" ); + ok( b.max.equals( one2 ), "Passed!" ); + + // ensure that it is a true copy + a.min = zero2; + a.max = one2; + ok( b.min.equals( zero2 ), "Passed!" ); + ok( b.max.equals( one2 ), "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Box2(); + + a.set( zero2, one2 ); + ok( a.min.equals( zero2 ), "Passed!" ); + ok( a.max.equals( one2 ), "Passed!" ); + }); + + test( "empty/makeEmpty", function() { + var a = new THREE.Box2(); + + ok( a.empty(), "Passed!" ); + + var a = new THREE.Box2( zero2.clone(), one2.clone() ); + ok( ! a.empty(), "Passed!" ); + + a.makeEmpty(); + ok( a.empty(), "Passed!" ); + }); + + test( "center", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + ok( a.center().equals( zero2 ), "Passed!" ); + + a = new THREE.Box2( zero2, one2 ); + var midpoint = one2.clone().multiplyScalar( 0.5 ); + ok( a.center().equals( midpoint ), "Passed!" ); + }); + + test( "size", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + ok( a.size().equals( zero2 ), "Passed!" ); + + a = new THREE.Box2( zero2.clone(), one2.clone() ); + ok( a.size().equals( one2 ), "Passed!" ); + }); + + test( "expandByPoint", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + a.expandByPoint( zero2 ); + ok( a.size().equals( zero2 ), "Passed!" ); + + a.expandByPoint( one2 ); + ok( a.size().equals( one2 ), "Passed!" ); + + a.expandByPoint( one2.clone().negate() ); + ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero2 ), "Passed!" ); + }); + + test( "expandByVector", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + a.expandByVector( zero2 ); + ok( a.size().equals( zero2 ), "Passed!" ); + + a.expandByVector( one2 ); + ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero2 ), "Passed!" ); + }); + + test( "expandByScalar", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + a.expandByScalar( 0 ); + ok( a.size().equals( zero2 ), "Passed!" ); + + a.expandByScalar( 1 ); + ok( a.size().equals( one2.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero2 ), "Passed!" ); + }); + + test( "containsPoint", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + + ok( a.containsPoint( zero2 ), "Passed!" ); + ok( ! a.containsPoint( one2 ), "Passed!" ); + + a.expandByScalar( 1 ); + ok( a.containsPoint( zero2 ), "Passed!" ); + ok( a.containsPoint( one2 ), "Passed!" ); + ok( a.containsPoint( one2.clone().negate() ), "Passed!" ); + }); + + test( "containsBox", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( zero2.clone(), one2.clone() ); + var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.containsBox( a ), "Passed!" ); + ok( ! a.containsBox( b ), "Passed!" ); + ok( ! a.containsBox( c ), "Passed!" ); + + ok( b.containsBox( a ), "Passed!" ); + ok( c.containsBox( a ), "Passed!" ); + ok( ! b.containsBox( c ), "Passed!" ); + }); + + test( "getParameter", function() { + var a = new THREE.Box2( zero2.clone(), one2.clone() ); + var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.getParameter( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + ok( a.getParameter( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); + + ok( b.getParameter( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + ok( b.getParameter( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0.5, 0.5 ) ), "Passed!" ); + ok( b.getParameter( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); + }); + + test( "clampPoint", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.clampPoint( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + ok( a.clampPoint( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + ok( a.clampPoint( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + + ok( b.clampPoint( new THREE.Vector2( 2, 2 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector2( 1, 1 ) ).equals( new THREE.Vector2( 1, 1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector2( 0, 0 ) ).equals( new THREE.Vector2( 0, 0 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector2( -1, -1 ) ).equals( new THREE.Vector2( -1, -1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector2( -2, -2 ) ).equals( new THREE.Vector2( -1, -1 ) ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == Math.sqrt( 2 ), "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == Math.sqrt( 2 ), "Passed!" ); + + ok( b.distanceToPoint( new THREE.Vector2( 2, 2 ) ) == Math.sqrt( 2 ), "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( -2, -2 ) ) == Math.sqrt( 2 ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == Math.sqrt( 2 ), "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == Math.sqrt( 2 ), "Passed!" ); + + ok( b.distanceToPoint( new THREE.Vector2( 2, 2 ) ) == Math.sqrt( 2 ), "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( 1, 1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( 0, 0 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( -1, -1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector2( -2, -2 ) ) == Math.sqrt( 2 ), "Passed!" ); + }); + + test( "isIntersectionBox", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( zero2.clone(), one2.clone() ); + var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.isIntersectionBox( a ), "Passed!" ); + ok( a.isIntersectionBox( b ), "Passed!" ); + ok( a.isIntersectionBox( c ), "Passed!" ); + + ok( b.isIntersectionBox( a ), "Passed!" ); + ok( c.isIntersectionBox( a ), "Passed!" ); + ok( b.isIntersectionBox( c ), "Passed!" ); + + b.translate( new THREE.Vector2( 2, 2 ) ); + ok( ! a.isIntersectionBox( b ), "Passed!" ); + ok( ! b.isIntersectionBox( a ), "Passed!" ); + ok( ! b.isIntersectionBox( c ), "Passed!" ); + }); + + test( "intersect", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( zero2.clone(), one2.clone() ); + var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.clone().intersect( a ).equals( a ), "Passed!" ); + ok( a.clone().intersect( b ).equals( a ), "Passed!" ); + ok( b.clone().intersect( b ).equals( b ), "Passed!" ); + ok( a.clone().intersect( c ).equals( a ), "Passed!" ); + ok( b.clone().intersect( c ).equals( b ), "Passed!" ); + ok( c.clone().intersect( c ).equals( c ), "Passed!" ); + }); + + test( "union", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( zero2.clone(), one2.clone() ); + var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); + + ok( a.clone().union( a ).equals( a ), "Passed!" ); + ok( a.clone().union( b ).equals( b ), "Passed!" ); + ok( a.clone().union( c ).equals( c ), "Passed!" ); + ok( b.clone().union( c ).equals( c ), "Passed!" ); + }); + + test( "translate", function() { + var a = new THREE.Box2( zero2.clone(), zero2.clone() ); + var b = new THREE.Box2( zero2.clone(), one2.clone() ); + var c = new THREE.Box2( one2.clone().negate(), one2.clone() ); + var d = new THREE.Box2( one2.clone().negate(), zero2.clone() ); + + ok( a.clone().translate( one2 ).equals( new THREE.Box2( one2, one2 ) ), "Passed!" ); + ok( a.clone().translate( one2 ).translate( one2.clone().negate() ).equals( a ), "Passed!" ); + ok( d.clone().translate( one2 ).equals( b ), "Passed!" ); + ok( b.clone().translate( one2.clone().negate() ).equals( d ), "Passed!" ); + }); + + test( "constructor", function() { + var a = new THREE.Box3(); + ok( a.min.equals( posInf3 ), "Passed!" ); + ok( a.max.equals( negInf3 ), "Passed!" ); + + a = new THREE.Box3( zero3.clone(), zero3.clone() ); + ok( a.min.equals( zero3 ), "Passed!" ); + ok( a.max.equals( zero3 ), "Passed!" ); + + a = new THREE.Box3( zero3.clone(), one3.clone() ); + ok( a.min.equals( zero3 ), "Passed!" ); + ok( a.max.equals( one3 ), "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Box3( zero3.clone(), one3.clone() ); + var b = new THREE.Box3().copy( a ); + ok( b.min.equals( zero3 ), "Passed!" ); + ok( b.max.equals( one3 ), "Passed!" ); + + // ensure that it is a true copy + a.min = zero3; + a.max = one3; + ok( b.min.equals( zero3 ), "Passed!" ); + ok( b.max.equals( one3 ), "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Box3(); + + a.set( zero3, one3 ); + ok( a.min.equals( zero3 ), "Passed!" ); + ok( a.max.equals( one3 ), "Passed!" ); + }); + + test( "empty/makeEmpty", function() { + var a = new THREE.Box3(); + + ok( a.empty(), "Passed!" ); + + var a = new THREE.Box3( zero3.clone(), one3.clone() ); + ok( ! a.empty(), "Passed!" ); + + a.makeEmpty(); + ok( a.empty(), "Passed!" ); + }); + + test( "center", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + ok( a.center().equals( zero3 ), "Passed!" ); + + a = new THREE.Box3( zero3.clone(), one3.clone() ); + var midpoint = one3.clone().multiplyScalar( 0.5 ); + ok( a.center().equals( midpoint ), "Passed!" ); + }); + + test( "size", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + ok( a.size().equals( zero3 ), "Passed!" ); + + a = new THREE.Box3( zero3.clone(), one3.clone() ); + ok( a.size().equals( one3 ), "Passed!" ); + }); + + test( "expandByPoint", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + a.expandByPoint( zero3 ); + ok( a.size().equals( zero3 ), "Passed!" ); + + a.expandByPoint( one3 ); + ok( a.size().equals( one3 ), "Passed!" ); + + a.expandByPoint( one3.clone().negate() ); + ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero3 ), "Passed!" ); + }); + + test( "expandByVector", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + a.expandByVector( zero3 ); + ok( a.size().equals( zero3 ), "Passed!" ); + + a.expandByVector( one3 ); + ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero3 ), "Passed!" ); + }); + + test( "expandByScalar", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + a.expandByScalar( 0 ); + ok( a.size().equals( zero3 ), "Passed!" ); + + a.expandByScalar( 1 ); + ok( a.size().equals( one3.clone().multiplyScalar( 2 ) ), "Passed!" ); + ok( a.center().equals( zero3 ), "Passed!" ); + }); + + test( "containsPoint", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + + ok( a.containsPoint( zero3 ), "Passed!" ); + ok( ! a.containsPoint( one3 ), "Passed!" ); + + a.expandByScalar( 1 ); + ok( a.containsPoint( zero3 ), "Passed!" ); + ok( a.containsPoint( one3 ), "Passed!" ); + ok( a.containsPoint( one3.clone().negate() ), "Passed!" ); + }); + + test( "containsBox", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.containsBox( a ), "Passed!" ); + ok( ! a.containsBox( b ), "Passed!" ); + ok( ! a.containsBox( c ), "Passed!" ); + + ok( b.containsBox( a ), "Passed!" ); + ok( c.containsBox( a ), "Passed!" ); + ok( ! b.containsBox( c ), "Passed!" ); + }); + + test( "getParameter", function() { + var a = new THREE.Box3( zero3.clone(), one3.clone() ); + var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.getParameter( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( a.getParameter( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); + + ok( b.getParameter( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( b.getParameter( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0.5, 0.5, 0.5 ) ), "Passed!" ); + ok( b.getParameter( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); + }); + + test( "clampPoint", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.clampPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( a.clampPoint( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( a.clampPoint( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + ok( b.clampPoint( new THREE.Vector3( 2, 2, 2 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector3( 1, 1, 1 ) ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector3( -1, -1, -1 ) ).equals( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); + ok( b.clampPoint( new THREE.Vector3( -2, -2, -2 ) ).equals( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == Math.sqrt( 3 ), "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == Math.sqrt( 3 ), "Passed!" ); + + ok( b.distanceToPoint( new THREE.Vector3( 2, 2, 2 ) ) == Math.sqrt( 3 ), "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( -2, -2, -2 ) ) == Math.sqrt( 3 ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == Math.sqrt( 3 ), "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == Math.sqrt( 3 ), "Passed!" ); + + ok( b.distanceToPoint( new THREE.Vector3( 2, 2, 2 ) ) == Math.sqrt( 3 ), "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( 1, 1, 1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( 0, 0, 0 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( -1, -1, -1 ) ) == 0, "Passed!" ); + ok( b.distanceToPoint( new THREE.Vector3( -2, -2, -2 ) ) == Math.sqrt( 3 ), "Passed!" ); + }); + + test( "isIntersectionBox", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.isIntersectionBox( a ), "Passed!" ); + ok( a.isIntersectionBox( b ), "Passed!" ); + ok( a.isIntersectionBox( c ), "Passed!" ); + + ok( b.isIntersectionBox( a ), "Passed!" ); + ok( c.isIntersectionBox( a ), "Passed!" ); + ok( b.isIntersectionBox( c ), "Passed!" ); + + b.translate( new THREE.Vector3( 2, 2, 2 ) ); + ok( ! a.isIntersectionBox( b ), "Passed!" ); + ok( ! b.isIntersectionBox( a ), "Passed!" ); + ok( ! b.isIntersectionBox( c ), "Passed!" ); + }); + + test( "getBoundingSphere", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.getBoundingSphere().equals( new THREE.Sphere( zero3, 0 ) ), "Passed!" ); + ok( b.getBoundingSphere().equals( new THREE.Sphere( one3.clone().multiplyScalar( 0.5 ), Math.sqrt( 3 ) * 0.5 ) ), "Passed!" ); + ok( c.getBoundingSphere().equals( new THREE.Sphere( zero3, Math.sqrt( 12 ) * 0.5 ) ), "Passed!" ); + }); + + test( "intersect", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.clone().intersect( a ).equals( a ), "Passed!" ); + ok( a.clone().intersect( b ).equals( a ), "Passed!" ); + ok( b.clone().intersect( b ).equals( b ), "Passed!" ); + ok( a.clone().intersect( c ).equals( a ), "Passed!" ); + ok( b.clone().intersect( c ).equals( b ), "Passed!" ); + ok( c.clone().intersect( c ).equals( c ), "Passed!" ); + }); + + test( "union", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + + ok( a.clone().union( a ).equals( a ), "Passed!" ); + ok( a.clone().union( b ).equals( b ), "Passed!" ); + ok( a.clone().union( c ).equals( c ), "Passed!" ); + ok( b.clone().union( c ).equals( c ), "Passed!" ); + }); + + var compareBox = function ( a, b, threshold? ) { + threshold = threshold || 0.0001; + return ( a.min.distanceTo( b.min ) < threshold && + a.max.distanceTo( b.max ) < threshold ); + }; + + test( "applyMatrix4", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + var d = new THREE.Box3( one3.clone().negate(), zero3.clone() ); + + var m = new THREE.Matrix4().makeTranslation( 1, -2, 1 ); + var t1 = new THREE.Vector3( 1, -2, 1 ); + + ok( compareBox( a.clone().applyMatrix4( m ), a.clone().translate( t1 ) ), "Passed!" ); + ok( compareBox( b.clone().applyMatrix4( m ), b.clone().translate( t1 ) ), "Passed!" ); + ok( compareBox( c.clone().applyMatrix4( m ), c.clone().translate( t1 ) ), "Passed!" ); + ok( compareBox( d.clone().applyMatrix4( m ), d.clone().translate( t1 ) ), "Passed!" ); + }); + + test( "translate", function() { + var a = new THREE.Box3( zero3.clone(), zero3.clone() ); + var b = new THREE.Box3( zero3.clone(), one3.clone() ); + var c = new THREE.Box3( one3.clone().negate(), one3.clone() ); + var d = new THREE.Box3( one3.clone().negate(), zero3.clone() ); + + ok( a.clone().translate( one3 ).equals( new THREE.Box3( one3, one3 ) ), "Passed!" ); + ok( a.clone().translate( one3 ).translate( one3.clone().negate() ).equals( a ), "Passed!" ); + ok( d.clone().translate( one3 ).equals( b ), "Passed!" ); + ok( b.clone().translate( one3.clone().negate() ).equals( d ), "Passed!" ); + }); + + test( "constructor", function(){ + var c = new THREE.Color(); + ok( c.r, "Red: " + c.r ); + ok( c.g, "Green: " + c.g ); + ok( c.b, "Blue: " + c.g ); + }); + + test( "copyHex", function(){ + var c = new THREE.Color(); + var c2 = new THREE.Color(0xF5FFFA); + c.copy(c2); + ok(c.getHex() == c2.getHex(), "Hex c: " + c.getHex() + " Hex c2: " + c2.getHex()); + }); + + test( "copyColorString", function(){ + var c = new THREE.Color(); + var c2 = new THREE.Color('ivory'); + c.copy(c2); + ok(c.getHex() == c2.getHex(), "Hex c: " + c.getHex() + " Hex c2: " + c2.getHex()); + }); + + test( "setRGB", function(){ + var c = new THREE.Color() + c.setRGB(255, 2, 1); + ok( c.r == 255, "Red: " + c.r ); + ok( c.g == 2, "Green: " + c.g ); + ok( c.b == 1, "Blue: " + c.b ); + }); + + test( "copyGammaToLinear", function(){ + var c = new THREE.Color(); + var c2 = new THREE.Color(); + c2.setRGB(2, 4, 8) + c.copyGammaToLinear(c2) + ok( c.r == 4, "Red c: " + c.r + " Red c2: " + c2.r); + ok( c.g == 16, "Green c: " + c.g + " Green c2: " + c2.g); + ok( c.b == 64, "Blue c: " + c.b + " Blue c2: " + c2.b); + }); + + test( "copyLinearToGamma", function(){ + var c = new THREE.Color(); + var c2 = new THREE.Color(); + c2.setRGB(4, 9, 16) + c.copyLinearToGamma(c2) + ok( c.r == 2, "Red c: " + c.r + " Red c2: " + c2.r); + ok( c.g == 3, "Green c: " + c.g + " Green c2: " + c2.g); + ok( c.b == 4, "Blue c: " + c.b + " Blue c2: " + c2.b); + }); + + + test( "convertGammaToLinear", function(){ + var c = new THREE.Color(); + c.setRGB(2, 4, 8) + c.convertGammaToLinear() + ok( c.r == 4, "Red: " + c.r ); + ok( c.g == 16, "Green: " + c.g ); + ok( c.b == 64, "Blue: " + c.b ); + }); + + + test( "convertLinearToGamma", function(){ + var c = new THREE.Color(); + c.setRGB(4, 9, 16) + c.convertLinearToGamma() + ok( c.r == 2, "Red: " + c.r ); + ok( c.g == 3, "Green: " + c.g ); + ok( c.b == 4, "Blue: " + c.b ); + }); + + test("setWithNum", function(){ + var c = new THREE.Color(); + c.set(0xFF0000); + ok( c.r == 1, "Red: " + c.r ); + ok( c.g == 0, "Green: " + c.g ); + ok( c.b == 0, "Blue: " + c.b ); + }); + + + test( "setWithString", function(){ + var c = new THREE.Color(); + c.set('silver'); + ok(c.getHex() == 0xC0C0C0, "Hex c: " + c.getHex()); + }); + + + test( "clone", function(){ + var c = new THREE.Color('teal'); + var c2 = c.clone(); + ok(c2.getHex() == 0x008080, "Hex c2: " + c2.getHex()); + }); + + test( "lerp", function(){ + var c = new THREE.Color(); + var c2 = new THREE.Color(); + c.setRGB(0, 0, 0); + c.lerp(c2, 2); + ok( c.r == 2, "Red: " + c.r ); + ok( c.g == 2, "Green: " + c.g ); + ok( c.b == 2, "Blue: " + c.b ); + + }); + + + test( "setStyleRGBRed", function(){ + var c = new THREE.Color(); + c.setStyle('rgb(255,0,0)'); + ok( c.r == 1, "Red: " + c.r ); + ok( c.g == 0, "Green: " + c.g ); + ok( c.b == 0, "Blue: " + c.b ); + }); + + test( "setStyleRGBPercent", function(){ + var c = new THREE.Color(); + c.setStyle('rgb(100%,50%,10%)'); + ok( c.r == 1, "Red: " + c.r ); + ok( c.g == 0.5, "Green: " + c.g ); + ok( c.b == 0.1, "Blue: " + c.b ); + }); + + test( "setStyleHexSkyBlue", function(){ + var c = new THREE.Color(); + c.setStyle('#87CEEB'); + ok(c.getHex() == 0x87CEEB, "Hex c: " + c.getHex()); + }); + + test( "setStyleHex2Olive", function(){ + var c = new THREE.Color(); + c.setStyle('#F00'); + ok(c.getHex() == 0xFF0000, "Hex c: " + c.getHex()); + }); + + test( "setStyleColorName", function(){ + var c = new THREE.Color(); + c.setStyle('powderblue'); + ok(c.getHex() == 0xB0E0E6, "Hex c: " + c.getHex()); + }); + + + test( "getHex", function(){ + var c = new THREE.Color('red'); + var res = c.getHex(); + ok( res == 0xFF0000, "Hex: " + res ); + }); + + test( "setHex", function(){ + var c = new THREE.Color(); + c.setHex(0xFA8072); + ok( c.getHex() == 0xFA8072, "Hex: " + c.getHex()); + }); + + test( "getHexString", function(){ + var c = new THREE.Color('tomato'); + var res = c.getHexString(); + ok( res == 'ff6347', "Hex: " + res ); + }); + + test( "getStyle", function(){ + var c = new THREE.Color('plum'); + var res = c.getStyle(); + ok( res == 'rgb(221,160,221)', "style: " + res ); + }); + + test( "getHSL", function () { + var c = new THREE.Color( 0x80ffff ); + var hsl = c.getHSL(); + + ok( hsl.h == 0.5, "hue: " + hsl.h ); + ok( hsl.s == 1.0, "saturation: " + hsl.s ); + + + //ok( (Math.round(parseFloat(hsl.l)*100)/100) == 0.75, "lightness: " + hsl.l ); + ok( (Math.round(hsl.l*100)/100) == 0.75, "lightness: " + hsl.l ); + }); + + test( "setHSL", function () { + var c = new THREE.Color(); + c.setHSL(0.75, 1.0, 0.25); + var hsl = c.getHSL(); + + ok( hsl.h == 0.75, "hue: " + hsl.h ); + ok( hsl.s == 1.00, "saturation: " + hsl.s ); + ok( hsl.l == 0.25, "lightness: " + hsl.l ); + }); + + var unit3 = new THREE.Vector3( 1, 0, 0 ); + + var planeEquals = function ( a, b, tolerance ) { + tolerance = tolerance || 0.0001; + if( a.normal.distanceTo( b.normal ) > tolerance ) { + return false; + } + if( Math.abs( a.constant - b.constant ) > tolerance ) { + return false; + } + return true; + }; + + test( "constructor", function() { + var a = new THREE.Frustum(); + + ok( a.planes !== undefined, "Passed!" ); + ok( a.planes.length === 6, "Passed!" ); + + var pDefault = new THREE.Plane(); + for( var i = 0; i < 6; i ++ ) { + ok( a.planes[i].equals( pDefault ), "Passed!" ); + } + + var p0 = new THREE.Plane( unit3, -1 ); + var p1 = new THREE.Plane( unit3, 1 ); + var p2 = new THREE.Plane( unit3, 2 ); + var p3 = new THREE.Plane( unit3, 3 ); + var p4 = new THREE.Plane( unit3, 4 ); + var p5 = new THREE.Plane( unit3, 5 ); + + a = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); + ok( a.planes[0].equals( p0 ), "Passed!" ); + ok( a.planes[1].equals( p1 ), "Passed!" ); + ok( a.planes[2].equals( p2 ), "Passed!" ); + ok( a.planes[3].equals( p3 ), "Passed!" ); + ok( a.planes[4].equals( p4 ), "Passed!" ); + ok( a.planes[5].equals( p5 ), "Passed!" ); + }); + + test( "copy", function() { + + var p0 = new THREE.Plane( unit3, -1 ); + var p1 = new THREE.Plane( unit3, 1 ); + var p2 = new THREE.Plane( unit3, 2 ); + var p3 = new THREE.Plane( unit3, 3 ); + var p4 = new THREE.Plane( unit3, 4 ); + var p5 = new THREE.Plane( unit3, 5 ); + + var b = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); + var a = new THREE.Frustum().copy( b ); + ok( a.planes[0].equals( p0 ), "Passed!" ); + ok( a.planes[1].equals( p1 ), "Passed!" ); + ok( a.planes[2].equals( p2 ), "Passed!" ); + ok( a.planes[3].equals( p3 ), "Passed!" ); + ok( a.planes[4].equals( p4 ), "Passed!" ); + ok( a.planes[5].equals( p5 ), "Passed!" ); + + // ensure it is a true copy by modifying source + b.planes[0] = p1; + ok( a.planes[0].equals( p0 ), "Passed!" ); + }); + + test( "setFromMatrix/makeOrthographic/containsPoint", function() { + var m = new THREE.Matrix4().makeOrthographic( -1, 1, -1, 1, 1, 100 ) + var a = new THREE.Frustum().setFromMatrix( m ); + + ok( ! a.containsPoint( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -50 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( -1, -1, -1.001 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 1, 1, -1.001 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -100 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( -1, -1, -100 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -100.1 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 1, 1, -100 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -100.1 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 0, 0, -101 ) ), "Passed!" ); + + }); + + test( "setFromMatrix/makeFrustum/containsPoint", function() { + var m = new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 100 ) + var a = new THREE.Frustum().setFromMatrix( m ); + + ok( ! a.containsPoint( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -50 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( -1, -1, -1.001 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -1.1, -1.1, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 1, 1, -1.001 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 1.1, 1.1, -1.001 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 0, 0, -99.999 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( -99.999, -99.999, -99.999 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -100.1, -100.1, -100.1 ) ), "Passed!" ); + ok( a.containsPoint( new THREE.Vector3( 99.999, 99.999, -99.999 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 100.1, 100.1, -100.1 ) ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( 0, 0, -101 ) ), "Passed!" ); + }); + + test( "setFromMatrix/makeFrustum/intersectsSphere", function() { + var m = new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 100 ) + var a = new THREE.Frustum().setFromMatrix( m ); + + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 0 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 0.9 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, 0 ), 1.1 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -50 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -1.001 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1, -1, -1.001 ), 0 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1.1, -1.1, -1.001 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -1.1, -1.1, -1.001 ), 0.5 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1, 1, -1.001 ), 0 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1.1, 1.1, -1.001 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 1.1, 1.1, -1.001 ), 0.5 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -99.999 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -99.999, -99.999, -99.999 ), 0 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -100.1, -100.1, -100.1 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( -100.1, -100.1, -100.1 ), 0.5 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 99.999, 99.999, -99.999 ), 0 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 100.1, 100.1, -100.1 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 100.1, 100.1, -100.1 ), 0.2 ) ), "Passed!" ); + ok( ! a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -101 ), 0 ) ), "Passed!" ); + ok( a.intersectsSphere( new THREE.Sphere( new THREE.Vector3( 0, 0, -101 ), 1.1 ) ), "Passed!" ); + }); + + test( "clone", function() { + + var p0 = new THREE.Plane( unit3, -1 ); + var p1 = new THREE.Plane( unit3, 1 ); + var p2 = new THREE.Plane( unit3, 2 ); + var p3 = new THREE.Plane( unit3, 3 ); + var p4 = new THREE.Plane( unit3, 4 ); + var p5 = new THREE.Plane( unit3, 5 ); + + var b = new THREE.Frustum( p0, p1, p2, p3, p4, p5 ); + var a = b.clone(); + ok( a.planes[0].equals( p0 ), "Passed!" ); + ok( a.planes[1].equals( p1 ), "Passed!" ); + ok( a.planes[2].equals( p2 ), "Passed!" ); + ok( a.planes[3].equals( p3 ), "Passed!" ); + ok( a.planes[4].equals( p4 ), "Passed!" ); + ok( a.planes[5].equals( p5 ), "Passed!" ); + + // ensure it is a true copy by modifying source + a.planes[0].copy( p1 ); + ok( b.planes[0].equals( p0 ), "Passed!" ); + }); + + + test( "constructor/equals", function() { + var a = new THREE.Line3(); + ok( a.start.equals( zero3 ), "Passed!" ); + ok( a.end.equals( zero3 ), "Passed!" ); + + a = new THREE.Line3( two3.clone(), one3.clone() ); + ok( a.start.equals( two3 ), "Passed!" ); + ok( a.end.equals( one3 ), "Passed!" ); + }); + + test( "copy/equals", function() { + var a = new THREE.Line3( zero3.clone(), one3.clone() ); + var b = new THREE.Line3().copy( a ); + ok( b.start.equals( zero3 ), "Passed!" ); + ok( b.end.equals( one3 ), "Passed!" ); + + // ensure that it is a true copy + a.start = zero3; + a.end = one3; + ok( b.start.equals( zero3 ), "Passed!" ); + ok( b.end.equals( one3 ), "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Line3(); + + a.set( one3, one3 ); + ok( a.start.equals( one3 ), "Passed!" ); + ok( a.end.equals( one3 ), "Passed!" ); + }); + + test( "at", function() { + var a = new THREE.Line3( one3.clone(), new THREE.Vector3( 1, 1, 2 ) ); + + ok( a.at( -1 ).distanceTo( new THREE.Vector3( 1, 1, 0 ) ) < 0.0001, "Passed!" ); + ok( a.at( 0 ).distanceTo( one3.clone() ) < 0.0001, "Passed!" ); + ok( a.at( 1 ).distanceTo( new THREE.Vector3( 1, 1, 2 ) ) < 0.0001, "Passed!" ); + ok( a.at( 2 ).distanceTo( new THREE.Vector3( 1, 1, 3 ) ) < 0.0001, "Passed!" ); + }); + + test( "closestPointToPoint/closestPointToPointParameter", function() { + var a = new THREE.Line3( one3.clone(), new THREE.Vector3( 1, 1, 2 ) ); + + // nearby the ray + ok( a.closestPointToPointParameter( zero3.clone(), true ) == 0, "Passed!" ); + var b1 = a.closestPointToPoint( zero3.clone(), true ); + ok( b1.distanceTo( new THREE.Vector3( 1, 1, 1 ) ) < 0.0001, "Passed!" ); + + // nearby the ray + ok( a.closestPointToPointParameter( zero3.clone(), false ) == -1, "Passed!" ); + var b2 = a.closestPointToPoint( zero3.clone(), false ); + console.log( b2 ); + ok( b2.distanceTo( new THREE.Vector3( 1, 1, 0 ) ) < 0.0001, "Passed!" ); + + // nearby the ray + ok( a.closestPointToPointParameter( new THREE.Vector3( 1, 1, 5 ), true ) == 1, "Passed!" ); + var b = a.closestPointToPoint( new THREE.Vector3( 1, 1, 5 ), true ); + ok( b.distanceTo( new THREE.Vector3( 1, 1, 2 ) ) < 0.0001, "Passed!" ); + + // exactly on the ray + ok( a.closestPointToPointParameter( one3.clone(), true ) == 0, "Passed!" ); + var c = a.closestPointToPoint( one3.clone(), true ); + ok( c.distanceTo( one3.clone() ) < 0.0001, "Passed!" ); + }); + + + + var matrixEquals3 = function( a, b, tolerance? ) { + tolerance = tolerance || 0.0001; + if( a.elements.length != b.elements.length ) { + return false; + } + for( var i = 0, il = a.elements.length; i < il; i ++ ) { + var delta = a.elements[i] - b.elements[i]; + if( delta > tolerance ) { + return false; + } + } + return true; + }; + + + var toMatrix4 = function( m3 ) { + var result = new THREE.Matrix4(); + var re = result.elements; + var me = m3.elements; + re[0] = me[0]; + re[1] = me[1]; + re[2] = me[2]; + re[4] = me[3]; + re[5] = me[4]; + re[6] = me[5]; + re[8] = me[6]; + re[9] = me[7]; + re[10] = me[8]; + + return result; + }; + + test( "constructor", function() { + var a = new THREE.Matrix3(); + ok( a.determinant() == 1, "Passed!" ); + + var b = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 3 ); + ok( b.elements[2] == 6 ); + ok( b.elements[3] == 1 ); + ok( b.elements[4] == 4 ); + ok( b.elements[5] == 7 ); + ok( b.elements[6] == 2 ); + ok( b.elements[7] == 5 ); + ok( b.elements[8] == 8 ); + + ok( ! matrixEquals3( a, b ), "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + var b = new THREE.Matrix3().copy( a ); + + ok( matrixEquals3( a, b ), "Passed!" ); + + // ensure that it is a true copy + a.elements[0] = 2; + ok( ! matrixEquals3( a, b ), "Passed!" ); + }); + + test( "set", function() { + var b = new THREE.Matrix3(); + ok( b.determinant() == 1, "Passed!" ); + + b.set( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 3 ); + ok( b.elements[2] == 6 ); + ok( b.elements[3] == 1 ); + ok( b.elements[4] == 4 ); + ok( b.elements[5] == 7 ); + ok( b.elements[6] == 2 ); + ok( b.elements[7] == 5 ); + ok( b.elements[8] == 8 ); + }); + + test( "identity", function() { + var b = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 3 ); + ok( b.elements[2] == 6 ); + ok( b.elements[3] == 1 ); + ok( b.elements[4] == 4 ); + ok( b.elements[5] == 7 ); + ok( b.elements[6] == 2 ); + ok( b.elements[7] == 5 ); + ok( b.elements[8] == 8 ); + + var a = new THREE.Matrix3(); + ok( ! matrixEquals3( a, b ), "Passed!" ); + + b.identity(); + ok( matrixEquals3( a, b ), "Passed!" ); + }); + + test( "multiplyScalar", function() { + var b = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 3 ); + ok( b.elements[2] == 6 ); + ok( b.elements[3] == 1 ); + ok( b.elements[4] == 4 ); + ok( b.elements[5] == 7 ); + ok( b.elements[6] == 2 ); + ok( b.elements[7] == 5 ); + ok( b.elements[8] == 8 ); + + b.multiplyScalar( 2 ); + ok( b.elements[0] == 0*2 ); + ok( b.elements[1] == 3*2 ); + ok( b.elements[2] == 6*2 ); + ok( b.elements[3] == 1*2 ); + ok( b.elements[4] == 4*2 ); + ok( b.elements[5] == 7*2 ); + ok( b.elements[6] == 2*2 ); + ok( b.elements[7] == 5*2 ); + ok( b.elements[8] == 8*2 ); + }); + + test( "determinant", function() { + var a = new THREE.Matrix3(); + ok( a.determinant() == 1, "Passed!" ); + + a.elements[0] = 2; + ok( a.determinant() == 2, "Passed!" ); + + a.elements[0] = 0; + ok( a.determinant() == 0, "Passed!" ); + + // calculated via http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/threeD/index.htm + a.set( 2, 3, 4, 5, 13, 7, 8, 9, 11 ); + ok( a.determinant() == -73, "Passed!" ); + }); + + + test( "getInverse", function() { + var identity = new THREE.Matrix4(); + var a = new THREE.Matrix4(); + var b = new THREE.Matrix3( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + //var c = new THREE.Matrix4( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + var c = new THREE.Matrix4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + ok( ! matrixEquals3( a, b ), "Passed!" ); + b.getInverse( a, false ); + ok( matrixEquals3( b, new THREE.Matrix3() ), "Passed!" ); + + try { + b.getInverse( c, true ); + ok( false, "Passed!" ); // should never get here. + } + catch( err ) { + ok( true, "Passed!" ); + } + + var testMatrices = [ + new THREE.Matrix4().makeRotationX( 0.3 ), + new THREE.Matrix4().makeRotationX( -0.3 ), + new THREE.Matrix4().makeRotationY( 0.3 ), + new THREE.Matrix4().makeRotationY( -0.3 ), + new THREE.Matrix4().makeRotationZ( 0.3 ), + new THREE.Matrix4().makeRotationZ( -0.3 ), + new THREE.Matrix4().makeScale( 1, 2, 3 ), + new THREE.Matrix4().makeScale( 1/8, 1/2, 1/3 ) + ]; + + for( var i = 0, il = testMatrices.length; i < il; i ++ ) { + var m = testMatrices[i]; + var mInverse3 = new THREE.Matrix3().getInverse( m ); + + var mInverse = toMatrix4( mInverse3 ); + + // the determinant of the inverse should be the reciprocal + ok( Math.abs( m.determinant() * mInverse3.determinant() - 1 ) < 0.0001, "Passed!" ); + ok( Math.abs( m.determinant() * mInverse.determinant() - 1 ) < 0.0001, "Passed!" ); + + var mProduct = new THREE.Matrix4().multiplyMatrices( m, mInverse ); + ok( Math.abs( mProduct.determinant() - 1 ) < 0.0001, "Passed!" ); + ok( matrixEquals3( mProduct, identity ), "Passed!" ); + } + }); + + test( "transpose", function() { + var a = new THREE.Matrix3(); + var b = a.clone().transpose(); + ok( matrixEquals3( a, b ), "Passed!" ); + + b = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + var c = b.clone().transpose(); + ok( ! matrixEquals3( b, c ), "Passed!" ); + c.transpose(); + ok( matrixEquals3( b, c ), "Passed!" ); + }); + + test( "clone", function() { + var a = new THREE.Matrix3( 0, 1, 2, 3, 4, 5, 6, 7, 8 ); + var b = a.clone(); + + ok( matrixEquals3( a, b ), "Passed!" ); + + // ensure that it is a true copy + a.elements[0] = 2; + ok( ! matrixEquals3( a, b ), "Passed!" ); + }); + + var matrixEquals4 = function( a, b, tolerance? ) { + tolerance = tolerance || 0.0001; + if( a.elements.length != b.elements.length ) { + return false; + } + for( var i = 0, il = a.elements.length; i < il; i ++ ) { + var delta = a.elements[i] - b.elements[i]; + if( delta > tolerance ) { + return false; + } + } + return true; + }; + + test( "constructor", function() { + var a = new THREE.Matrix4(); + ok( a.determinant() == 1, "Passed!" ); + + var b = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 4 ); + ok( b.elements[2] == 8 ); + ok( b.elements[3] == 12 ); + ok( b.elements[4] == 1 ); + ok( b.elements[5] == 5 ); + ok( b.elements[6] == 9 ); + ok( b.elements[7] == 13 ); + ok( b.elements[8] == 2 ); + ok( b.elements[9] == 6 ); + ok( b.elements[10] == 10 ); + ok( b.elements[11] == 14 ); + ok( b.elements[12] == 3 ); + ok( b.elements[13] == 7 ); + ok( b.elements[14] == 11 ); + ok( b.elements[15] == 15 ); + + ok( ! matrixEquals4( a, b ), "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + var b = new THREE.Matrix4().copy( a ); + + ok( matrixEquals4( a, b ), "Passed!" ); + + // ensure that it is a true copy + a.elements[0] = 2; + ok( ! matrixEquals4( a, b ), "Passed!" ); + }); + + test( "set", function() { + var b = new THREE.Matrix4(); + ok( b.determinant() == 1, "Passed!" ); + + b.set( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 4 ); + ok( b.elements[2] == 8 ); + ok( b.elements[3] == 12 ); + ok( b.elements[4] == 1 ); + ok( b.elements[5] == 5 ); + ok( b.elements[6] == 9 ); + ok( b.elements[7] == 13 ); + ok( b.elements[8] == 2 ); + ok( b.elements[9] == 6 ); + ok( b.elements[10] == 10 ); + ok( b.elements[11] == 14 ); + ok( b.elements[12] == 3 ); + ok( b.elements[13] == 7 ); + ok( b.elements[14] == 11 ); + ok( b.elements[15] == 15 ); + }); + + test( "identity", function() { + var b = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 4 ); + ok( b.elements[2] == 8 ); + ok( b.elements[3] == 12 ); + ok( b.elements[4] == 1 ); + ok( b.elements[5] == 5 ); + ok( b.elements[6] == 9 ); + ok( b.elements[7] == 13 ); + ok( b.elements[8] == 2 ); + ok( b.elements[9] == 6 ); + ok( b.elements[10] == 10 ); + ok( b.elements[11] == 14 ); + ok( b.elements[12] == 3 ); + ok( b.elements[13] == 7 ); + ok( b.elements[14] == 11 ); + ok( b.elements[15] == 15 ); + + var a = new THREE.Matrix4(); + ok( ! matrixEquals4( a, b ), "Passed!" ); + + b.identity(); + ok( matrixEquals4( a, b ), "Passed!" ); + }); + + test( "multiplyScalar", function() { + var b = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + ok( b.elements[0] == 0 ); + ok( b.elements[1] == 4 ); + ok( b.elements[2] == 8 ); + ok( b.elements[3] == 12 ); + ok( b.elements[4] == 1 ); + ok( b.elements[5] == 5 ); + ok( b.elements[6] == 9 ); + ok( b.elements[7] == 13 ); + ok( b.elements[8] == 2 ); + ok( b.elements[9] == 6 ); + ok( b.elements[10] == 10 ); + ok( b.elements[11] == 14 ); + ok( b.elements[12] == 3 ); + ok( b.elements[13] == 7 ); + ok( b.elements[14] == 11 ); + ok( b.elements[15] == 15 ); + + b.multiplyScalar( 2 ); + ok( b.elements[0] == 0*2 ); + ok( b.elements[1] == 4*2 ); + ok( b.elements[2] == 8*2 ); + ok( b.elements[3] == 12*2 ); + ok( b.elements[4] == 1*2 ); + ok( b.elements[5] == 5*2 ); + ok( b.elements[6] == 9*2 ); + ok( b.elements[7] == 13*2 ); + ok( b.elements[8] == 2*2 ); + ok( b.elements[9] == 6*2 ); + ok( b.elements[10] == 10*2 ); + ok( b.elements[11] == 14*2 ); + ok( b.elements[12] == 3*2 ); + ok( b.elements[13] == 7*2 ); + ok( b.elements[14] == 11*2 ); + ok( b.elements[15] == 15*2 ); + }); + + test( "determinant", function() { + var a = new THREE.Matrix4(); + ok( a.determinant() == 1, "Passed!" ); + + a.elements[0] = 2; + ok( a.determinant() == 2, "Passed!" ); + + a.elements[0] = 0; + ok( a.determinant() == 0, "Passed!" ); + + // calculated via http://www.euclideanspace.com/maths/algebra/matrix/functions/determinant/fourD/index.htm + a.set( 2, 3, 4, 5, -1, -21, -3, -4, 6, 7, 8, 10, -8, -9, -10, -12 ); + ok( a.determinant() == 76, "Passed!" ); + }); + + test( "getInverse", function() { + var identity = new THREE.Matrix4(); + + var a = new THREE.Matrix4(); + var b = new THREE.Matrix4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + var c = new THREE.Matrix4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + ok( ! matrixEquals4( a, b ), "Passed!" ); + b.getInverse( a, false ); + ok( matrixEquals4( b, new THREE.Matrix4() ), "Passed!" ); + + try { + b.getInverse( c, true ); + ok( false, "Passed!" ); // should never get here. + } + catch( err ) { + ok( true, "Passed!" ); + } + + var testMatrices = [ + new THREE.Matrix4().makeRotationX( 0.3 ), + new THREE.Matrix4().makeRotationX( -0.3 ), + new THREE.Matrix4().makeRotationY( 0.3 ), + new THREE.Matrix4().makeRotationY( -0.3 ), + new THREE.Matrix4().makeRotationZ( 0.3 ), + new THREE.Matrix4().makeRotationZ( -0.3 ), + new THREE.Matrix4().makeScale( 1, 2, 3 ), + new THREE.Matrix4().makeScale( 1/8, 1/2, 1/3 ), + new THREE.Matrix4().makeFrustum( -1, 1, -1, 1, 1, 1000 ), + new THREE.Matrix4().makeFrustum( -16, 16, -9, 9, 0.1, 10000 ), + new THREE.Matrix4().makeTranslation( 1, 2, 3 ) + ]; + + for( var i = 0, il = testMatrices.length; i < il; i ++ ) { + var m = testMatrices[i]; + + var mInverse = new THREE.Matrix4().getInverse( m ); + + // the determinant of the inverse should be the reciprocal + ok( Math.abs( m.determinant() * mInverse.determinant() - 1 ) < 0.0001, "Passed!" ); + + var mProduct = new THREE.Matrix4().multiplyMatrices( m, mInverse ); + + // the determinant of the identity matrix is 1 + ok( Math.abs( mProduct.determinant() - 1 ) < 0.0001, "Passed!" ); + ok( matrixEquals4( mProduct, identity ), "Passed!" ); + } + }); + + test( "transpose", function() { + var a = new THREE.Matrix4(); + var b = a.clone().transpose(); + ok( matrixEquals4( a, b ), "Passed!" ); + + b = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + var c = b.clone().transpose(); + ok( ! matrixEquals4( b, c ), "Passed!" ); + c.transpose(); + ok( matrixEquals4( b, c ), "Passed!" ); + }); + + test( "clone", function() { + var a = new THREE.Matrix4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ); + var b = a.clone(); + + ok( matrixEquals4( a, b ), "Passed!" ); + + // ensure that it is a true copy + a.elements[0] = 2; + ok( ! matrixEquals4( a, b ), "Passed!" ); + }); + + + var comparePlane = function ( a, b, threshold? ) { + threshold = threshold || 0.0001; + return ( a.normal.distanceTo( b.normal ) < threshold && + Math.abs( a.constant - b.constant ) < threshold ); + }; + + + test( "constructor", function() { + var a = new THREE.Plane(); + ok( a.normal.x == 1, "Passed!" ); + ok( a.normal.y == 0, "Passed!" ); + ok( a.normal.z == 0, "Passed!" ); + ok( a.constant == 0, "Passed!" ); + + a = new THREE.Plane( one3.clone(), 0 ); + ok( a.normal.x == 1, "Passed!" ); + ok( a.normal.y == 1, "Passed!" ); + ok( a.normal.z == 1, "Passed!" ); + ok( a.constant == 0, "Passed!" ); + + a = new THREE.Plane( one3.clone(), 1 ); + ok( a.normal.x == 1, "Passed!" ); + ok( a.normal.y == 1, "Passed!" ); + ok( a.normal.z == 1, "Passed!" ); + ok( a.constant == 1, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Plane( new THREE.Vector3( x, y, z ), w ); + var b = new THREE.Plane().copy( a ); + ok( b.normal.x == x, "Passed!" ); + ok( b.normal.y == y, "Passed!" ); + ok( b.normal.z == z, "Passed!" ); + ok( b.constant == w, "Passed!" ); + + // ensure that it is a true copy + a.normal.x = 0; + a.normal.y = -1; + a.normal.z = -2; + a.constant = -3; + ok( b.normal.x == x, "Passed!" ); + ok( b.normal.y == y, "Passed!" ); + ok( b.normal.z == z, "Passed!" ); + ok( b.constant == w, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Plane(); + ok( a.normal.x == 1, "Passed!" ); + ok( a.normal.y == 0, "Passed!" ); + ok( a.normal.z == 0, "Passed!" ); + ok( a.constant == 0, "Passed!" ); + + var b = a.clone().set( new THREE.Vector3( x, y, z ), w ); + ok( b.normal.x == x, "Passed!" ); + ok( b.normal.y == y, "Passed!" ); + ok( b.normal.z == z, "Passed!" ); + ok( b.constant == w, "Passed!" ); + }); + + test( "setComponents", function() { + var a = new THREE.Plane(); + ok( a.normal.x == 1, "Passed!" ); + ok( a.normal.y == 0, "Passed!" ); + ok( a.normal.z == 0, "Passed!" ); + ok( a.constant == 0, "Passed!" ); + + var b = a.clone().setComponents( x, y, z , w ); + ok( b.normal.x == x, "Passed!" ); + ok( b.normal.y == y, "Passed!" ); + ok( b.normal.z == z, "Passed!" ); + ok( b.constant == w, "Passed!" ); + }); + + test( "setFromNormalAndCoplanarPoint", function() { + var normal = one3.clone().normalize(); + var a = new THREE.Plane().setFromNormalAndCoplanarPoint( normal, zero3 ); + + ok( a.normal.equals( normal ), "Passed!" ); + ok( a.constant == 0, "Passed!" ); + }); + + test( "normalize", function() { + var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), 2 ); + + a.normalize(); + ok( a.normal.length() == 1, "Passed!" ); + ok( a.normal.equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); + ok( a.constant == 1, "Passed!" ); + }); + + test( "negate/distanceToPoint", function() { + var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), -2 ); + + a.normalize(); + ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === 3, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( 1, 0, 0 ) ) === 0, "Passed!" ); + + a.negate(); + ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === -3, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( 1, 0, 0 ) ) === 0, "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Plane( new THREE.Vector3( 2, 0, 0 ), -2 ); + + a.normalize(); + ok( a.distanceToPoint( a.projectPoint( zero3.clone() ) ) === 0, "Passed!" ); + ok( a.distanceToPoint( new THREE.Vector3( 4, 0, 0 ) ) === 3, "Passed!" ); + }); + + test( "distanceToSphere", function() { + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + + var b = new THREE.Sphere( new THREE.Vector3( 2, 0, 0 ), 1 ); + + ok( a.distanceToSphere( b ) === 1, "Passed!" ); + + a.set( new THREE.Vector3( 1, 0, 0 ), 2 ); + ok( a.distanceToSphere( b ) === 3, "Passed!" ); + a.set( new THREE.Vector3( 1, 0, 0 ), -2 ); + ok( a.distanceToSphere( b ) === -1, "Passed!" ); + }); + + test( "isInterestionLine/intersectLine", function() { + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + + var l1 = new THREE.Line3( new THREE.Vector3( -10, 0, 0 ), new THREE.Vector3( 10, 0, 0 ) ); + ok( a.isIntersectionLine( l1 ), "Passed!" ); + ok( a.intersectLine( l1 ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), -3 ); + + ok( a.isIntersectionLine( l1 ), "Passed!" ); + ok( a.intersectLine( l1 ).equals( new THREE.Vector3( 3, 0, 0 ) ), "Passed!" ); + + + a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), -11 ); + + ok( ! a.isIntersectionLine( l1 ), "Passed!" ); + ok( a.intersectLine( l1 ) === undefined, "Passed!" ); + + a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 11 ); + + ok( ! a.isIntersectionLine( l1 ), "Passed!" ); + ok( a.intersectLine( l1 ) === undefined, "Passed!" ); + + }); + + test( "projectPoint", function() { + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + + ok( a.projectPoint( new THREE.Vector3( 10, 0, 0 ) ).equals( zero3 ), "Passed!" ); + ok( a.projectPoint( new THREE.Vector3( -10, 0, 0 ) ).equals( zero3 ), "Passed!" ); + + a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); + ok( a.projectPoint( new THREE.Vector3( 0, 0, 0 ) ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + ok( a.projectPoint( new THREE.Vector3( 0, 1, 0 ) ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + + }); + + test( "orthoPoint", function() { + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + + ok( a.orthoPoint( new THREE.Vector3( 10, 0, 0 ) ).equals( new THREE.Vector3( 10, 0, 0 ) ), "Passed!" ); + ok( a.orthoPoint( new THREE.Vector3( -10, 0, 0 ) ).equals( new THREE.Vector3( -10, 0, 0 ) ), "Passed!" ); + }); + + test( "coplanarPoint", function() { + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + ok( a.distanceToPoint( a.coplanarPoint() ) === 0, "Passed!" ); + + a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); + ok( a.distanceToPoint( a.coplanarPoint() ) === 0, "Passed!" ); + }); + + test( "applyMatrix4/translate", function() { + + var a = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 ); + + var m = new THREE.Matrix4(); + m.makeRotationZ( Math.PI * 0.5 ); + + ok( comparePlane( a.clone().applyMatrix4( m ), new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), 0 ) ), "Passed!" ); + + a = new THREE.Plane( new THREE.Vector3( 0, 1, 0 ), -1 ); + ok( comparePlane( a.clone().applyMatrix4( m ), new THREE.Plane( new THREE.Vector3( -1, 0, 0 ), -1 ) ), "Passed!" ); + + m.makeTranslation( 1, 1, 1 ); + ok( comparePlane( a.clone().applyMatrix4( m ), a.clone().translate( new THREE.Vector3( 1, 1, 1 ) ) ), "Passed!" ); + }); + + var orders = [ 'XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY' ]; + var eulerAngles = new THREE.Vector3( 0.1, -0.3, 0.25 ); + + + + var qSub = function ( a, b ) { + var result = new THREE.Quaternion(); + result.copy( a ); + + result.x -= b.x; + result.y -= b.y; + result.z -= b.z; + result.w -= b.w; + + return result; + + }; + + test( "constructor", function() { + var a = new THREE.Quaternion(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a = new THREE.Quaternion( x, y, z, w ); + ok( a.x === x, "Passed!" ); + ok( a.y === y, "Passed!" ); + ok( a.z === z, "Passed!" ); + ok( a.w === w, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Quaternion( x, y, z, w ); + var b = new THREE.Quaternion().copy( a ); + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + ok( b.z == z, "Passed!" ); + ok( b.w == w, "Passed!" ); + + // ensure that it is a true copy + a.x = 0; + a.y = -1; + a.z = 0; + a.w = -1; + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Quaternion(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a.set( x, y, z, w ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z === z, "Passed!" ); + ok( a.w === w, "Passed!" ); + }); + + test( "setFromAxisAngle", function() { + + // TODO: find cases to validate. + ok( true, "Passed!" ); + + var zero = new THREE.Quaternion(); + + var a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), 0 ); + ok( a.equals( zero ), "Passed!" ); + a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), 0 ); + ok( a.equals( zero ), "Passed!" ); + a = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), 0 ); + ok( a.equals( zero ), "Passed!" ); + + var b1 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), Math.PI ); + ok( ! a.equals( b1 ), "Passed!" ); + var b2 = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), -Math.PI ); + ok( ! a.equals( b2 ), "Passed!" ); + + b1.multiply( b2 ); + ok( a.equals( b1 ), "Passed!" ); + }); + + + test( "setFromEuler/setEulerFromQuaternion", function() { + + var angles = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ]; + + // ensure euler conversion to/from Quaternion matches. + for( var i = 0; i < orders.length; i ++ ) { + for( var j = 0; j < angles.length; j ++ ) { + var eulers2 = new THREE.Vector3().setEulerFromQuaternion( new THREE.Quaternion().setFromEuler( angles[j], orders[i] ), orders[i] ); + + ok( eulers2.distanceTo( angles[j] ) < 0.001, "Passed!" ); + } + } + + }); + + test( "setFromEuler/setFromRotationMatrix", function() { + + // ensure euler conversion for Quaternion matches that of Matrix4 + for( var i = 0; i < orders.length; i ++ ) { + var q = new THREE.Quaternion().setFromEuler( eulerAngles, orders[i] ); + var m = new THREE.Matrix4().setRotationFromEuler( eulerAngles, orders[i] ); + var q2 = new THREE.Quaternion().setFromRotationMatrix( m ); + + ok( qSub( q, q2 ).length() < 0.001, "Passed!" ); + } + + }); + + test( "normalize/length/lengthSq", function() { + var a = new THREE.Quaternion( x, y, z, w ); + var b = new THREE.Quaternion( -x, -y, -z, -w ); + + ok( a.length() != 1, "Passed!"); + ok( a.lengthSq() != 1, "Passed!"); + a.normalize(); + ok( a.length() == 1, "Passed!"); + ok( a.lengthSq() == 1, "Passed!"); + + a.set( 0, 0, 0, 0 ); + ok( a.lengthSq() == 0, "Passed!"); + ok( a.length() == 0, "Passed!"); + a.normalize(); + ok( a.lengthSq() == 1, "Passed!"); + ok( a.length() == 1, "Passed!"); + }); + + test( "inverse/conjugate", function() { + var a = new THREE.Quaternion( x, y, z, w ); + + // TODO: add better validation here. + + var b = a.clone().conjugate(); + + ok( a.x == -b.x, "Passed!" ); + ok( a.y == -b.y, "Passed!" ); + ok( a.z == -b.z, "Passed!" ); + ok( a.w == b.w, "Passed!" ); + }); + + + test( "multiplyQuaternions/multiply", function() { + + var angles = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ]; + + var q1 = new THREE.Quaternion().setFromEuler( angles[0], "XYZ" ); + var q2 = new THREE.Quaternion().setFromEuler( angles[1], "XYZ" ); + var q3 = new THREE.Quaternion().setFromEuler( angles[2], "XYZ" ); + + var q = new THREE.Quaternion().multiplyQuaternions( q1, q2 ).multiply( q3 ); + + var m1 = new THREE.Matrix4().setRotationFromEuler( angles[0], "XYZ" ); + var m2 = new THREE.Matrix4().setRotationFromEuler( angles[1], "XYZ" ); + var m3 = new THREE.Matrix4().setRotationFromEuler( angles[2], "XYZ" ); + + var m = new THREE.Matrix4().multiplyMatrices( m1, m2 ).multiply( m3 ); + + var qFromM = new THREE.Quaternion().setFromRotationMatrix( m ); + + ok( qSub( q, qFromM ).length() < 0.001, "Passed!" ); + }); + + test( "multiplyVector3", function() { + + var angles = [ new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ]; + + // ensure euler conversion for Quaternion matches that of Matrix4 + for( var i = 0; i < orders.length; i ++ ) { + for( var j = 0; j < angles.length; j ++ ) { + var q = new THREE.Quaternion().setFromEuler( angles[j], orders[i] ); + var m = new THREE.Matrix4().setRotationFromEuler( angles[j], orders[i] ); + + var v0 = new THREE.Vector3(1, 0, 0); + var qv = v0.clone().applyQuaternion( q ); + var mv = v0.clone().applyMatrix4( m ); + + ok( qv.distanceTo( mv ) < 0.001, "Passed!" ); + } + } + + }); + + test( "equals", function() { + var a = new THREE.Quaternion( x, y, z, w ); + var b = new THREE.Quaternion( -x, -y, -z, -w ); + + ok( a.x != b.x, "Passed!" ); + ok( a.y != b.y, "Passed!" ); + + ok( ! a.equals( b ), "Passed!" ); + ok( ! b.equals( a ), "Passed!" ); + + a.copy( b ); + ok( a.x == b.x, "Passed!" ); + ok( a.y == b.y, "Passed!" ); + + ok( a.equals( b ), "Passed!" ); + ok( b.equals( a ), "Passed!" ); + }); + + + test( "constructor/equals", function() { + var a = new THREE.Ray(); + ok( a.origin.equals( zero3 ), "Passed!" ); + ok( a.direction.equals( zero3 ), "Passed!" ); + + a = new THREE.Ray( two3.clone(), one3.clone() ); + ok( a.origin.equals( two3 ), "Passed!" ); + ok( a.direction.equals( one3 ), "Passed!" ); + }); + + test( "copy/equals", function() { + var a = new THREE.Ray( zero3.clone(), one3.clone() ); + var b = new THREE.Ray().copy( a ); + ok( b.origin.equals( zero3 ), "Passed!" ); + ok( b.direction.equals( one3 ), "Passed!" ); + + // ensure that it is a true copy + a.origin = zero3; + a.direction = one3; + ok( b.origin.equals( zero3 ), "Passed!" ); + ok( b.direction.equals( one3 ), "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Ray(); + + a.set( one3, one3 ); + ok( a.origin.equals( one3 ), "Passed!" ); + ok( a.direction.equals( one3 ), "Passed!" ); + }); + + test( "at", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + ok( a.at( 0 ).equals( one3 ), "Passed!" ); + ok( a.at( -1 ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); + ok( a.at( 1 ).equals( new THREE.Vector3( 1, 1, 2 ) ), "Passed!" ); + }); + + test( "recast/clone", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + ok( a.recast( 0 ).equals( a ), "Passed!" ); + + var b = a.clone(); + ok( b.recast( -1 ).equals( new THREE.Ray( new THREE.Vector3( 1, 1, 0 ), new THREE.Vector3( 0, 0, 1 ) ) ), "Passed!" ); + + var c = a.clone(); + ok( c.recast( 1 ).equals( new THREE.Ray( new THREE.Vector3( 1, 1, 2 ), new THREE.Vector3( 0, 0, 1 ) ) ), "Passed!" ); + + var d = a.clone(); + var e = d.clone().recast( 1 ); + ok( d.equals( a ), "Passed!" ); + ok( ! e.equals( d ), "Passed!" ); + ok( e.equals( c ), "Passed!" ); + }); + + test( "closestPointToPoint", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + // nearby the ray + var b = a.closestPointToPoint( zero3 ); + ok( b.equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); + + // exactly on the ray + var c = a.closestPointToPoint( one3 ); + ok( c.equals( one3 ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + // nearby the ray + var b = a.distanceToPoint( zero3 ); + ok( b == Math.sqrt( 2 ), "Passed!" ); + + // exactly on the ray + var c = a.distanceToPoint( one3 ); + ok( c == 0, "Passed!" ); + }); + + test( "isIntersectionSphere", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + var b = new THREE.Sphere( zero3, 0.5 ); + var c = new THREE.Sphere( zero3, 1.5 ); + var d = new THREE.Sphere( one3, 0.1 ); + var e = new THREE.Sphere( two3, 0.1 ); + var f = new THREE.Sphere( two3, 1 ); + + ok( ! a.isIntersectionSphere( b ), "Passed!" ); + ok( a.isIntersectionSphere( c ), "Passed!" ); + ok( a.isIntersectionSphere( d ), "Passed!" ); + ok( ! a.isIntersectionSphere( e ), "Passed!" ); + ok( ! a.isIntersectionSphere( f ), "Passed!" ); + }); + + test( "isIntersectionPlane", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + // parallel plane behind + var b = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, -1 ) ) ); + ok( a.isIntersectionPlane( b ), "Passed!" ); + + // parallel plane coincident with origin + var c = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, 0 ) ) ); + ok( a.isIntersectionPlane( c ), "Passed!" ); + + // parallel plane infront + var d = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), one3.clone().sub( new THREE.Vector3( 0, 0, 1 ) ) ); + ok( a.isIntersectionPlane( d ), "Passed!" ); + + // perpendical ray that overlaps exactly + var e = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), one3 ); + ok( a.isIntersectionPlane( e ), "Passed!" ); + + // perpendical ray that doesn't overlap + var f = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), zero3 ); + ok( ! a.isIntersectionPlane( f ), "Passed!" ); + }); + + test( "intersectPlane", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + + // parallel plane behind + var b = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, -1 ) ); + ok( a.intersectPlane( b ).equals( new THREE.Vector3( 1, 1, -1 ) ), "Passed!" ); + + // parallel plane coincident with origin + var c = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, 0 ) ); + ok( a.intersectPlane( c ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); + + // parallel plane infront + var d = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 0, 0, 1 ), new THREE.Vector3( 1, 1, 1 ) ); + ok( a.intersectPlane( d ).equals( new THREE.Vector3( 1, 1, 1 ) ), "Passed!" ); + + // perpendical ray that overlaps exactly + var e = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), one3 ); + ok( a.intersectPlane( e ).equals( a.origin ), "Passed!" ); + + // perpendical ray that doesn't overlap + var f = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3( 1, 0, 0 ), zero3 ); + ok( a.intersectPlane( f ) === undefined, "Passed!" ); + }); + + + test( "applyMatrix4", function() { + var a = new THREE.Ray( one3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + var m = new THREE.Matrix4().identity(); + + ok( a.clone().applyMatrix4( m ).equals( a ), "Passed!" ); + + a = new THREE.Ray( zero3.clone(), new THREE.Vector3( 0, 0, 1 ) ); + m.rotateByAxis( new THREE.Vector3( 0, 0, 1 ), Math.PI ); + ok( a.clone().applyMatrix4( m ).equals( a ), "Passed!" ); + + m.identity().rotateX( Math.PI ); + var b = a.clone(); + b.direction.negate(); + var a2 = a.clone().applyMatrix4( m ); + ok( a2.origin.distanceTo( b.origin ) < 0.0001, "Passed!" ); + ok( a2.direction.distanceTo( b.direction ) < 0.0001, "Passed!" ); + + a.origin = new THREE.Vector3( 0, 0, 1 ); + b.origin = new THREE.Vector3( 0, 0, -1 ); + var a2 = a.clone().applyMatrix4( m ); + ok( a2.origin.distanceTo( b.origin ) < 0.0001, "Passed!" ); + ok( a2.direction.distanceTo( b.direction ) < 0.0001, "Passed!" ); + }); + + + test( "constructor", function() { + var a = new THREE.Sphere(); + ok( a.center.equals( zero3 ), "Passed!" ); + ok( a.radius == 0, "Passed!" ); + + a = new THREE.Sphere( one3.clone(), 1 ); + ok( a.center.equals( one3 ), "Passed!" ); + ok( a.radius == 1, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + var b = new THREE.Sphere().copy( a ); + + ok( b.center.equals( one3 ), "Passed!" ); + ok( b.radius == 1, "Passed!" ); + + // ensure that it is a true copy + a.center = zero3; + a.radius = 0; + ok( b.center.equals( one3 ), "Passed!" ); + ok( b.radius == 1, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Sphere(); + ok( a.center.equals( zero3 ), "Passed!" ); + ok( a.radius == 0, "Passed!" ); + + a.set( one3, 1 ); + ok( a.center.equals( one3 ), "Passed!" ); + ok( a.radius == 1, "Passed!" ); + }); + + test( "empty", function() { + var a = new THREE.Sphere(); + ok( a.empty(), "Passed!" ); + + a.set( one3, 1 ); + ok( ! a.empty(), "Passed!" ); + }); + + test( "containsPoint", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + ok( ! a.containsPoint( zero3 ), "Passed!" ); + ok( a.containsPoint( one3 ), "Passed!" ); + }); + + test( "distanceToPoint", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + ok( ( a.distanceToPoint( zero3 ) - 0.7320 ) < 0.001, "Passed!" ); + ok( a.distanceToPoint( one3 ) === -1, "Passed!" ); + }); + + test( "intersectsSphere", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + var b = new THREE.Sphere( zero3.clone(), 1 ); + var c = new THREE.Sphere( zero3.clone(), 0.25 ); + + ok( a.intersectsSphere( b ) , "Passed!" ); + ok( ! a.intersectsSphere( c ) , "Passed!" ); + }); + + test( "clampPoint", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + ok( a.clampPoint( new THREE.Vector3( 1, 1, 3 ) ).equals( new THREE.Vector3( 1, 1, 2 ) ), "Passed!" ); + ok( a.clampPoint( new THREE.Vector3( 1, 1, -3 ) ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); + }); + + test( "getBoundingBox", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + ok( a.getBoundingBox().equals( new THREE.Box3( zero3, two3 ) ), "Passed!" ); + + a.set( zero3, 0 ) + ok( a.getBoundingBox().equals( new THREE.Box3( zero3, zero3 ) ), "Passed!" ); + }); + + test( "applyMatrix4", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + var m = new THREE.Matrix4().makeTranslation( 1, -2, 1 ); + + ok( a.clone().applyMatrix4( m ).getBoundingBox().equals( a.getBoundingBox().applyMatrix4( m ) ), "Passed!" ); + }); + + test( "translate", function() { + var a = new THREE.Sphere( one3.clone(), 1 ); + + a.translate( one3.clone().negate() ); + ok( a.center.equals( zero3 ), "Passed!" ); + }); + + test( "constructor", function() { + var a = new THREE.Triangle(); + ok( a.a.equals( zero3 ), "Passed!" ); + ok( a.b.equals( zero3 ), "Passed!" ); + ok( a.c.equals( zero3 ), "Passed!" ); + + a = new THREE.Triangle( one3.clone().negate(), one3.clone(), two3.clone() ); + ok( a.a.equals( one3.clone().negate() ), "Passed!" ); + ok( a.b.equals( one3 ), "Passed!" ); + ok( a.c.equals( two3 ), "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Triangle( one3.clone().negate(), one3.clone(), two3.clone() ); + var b = new THREE.Triangle().copy( a ); + ok( b.a.equals( one3.clone().negate() ), "Passed!" ); + ok( b.b.equals( one3 ), "Passed!" ); + ok( b.c.equals( two3 ), "Passed!" ); + + // ensure that it is a true copy + a.a = one3; + a.b = zero3; + a.c = zero3; + ok( b.a.equals( one3.clone().negate() ), "Passed!" ); + ok( b.b.equals( one3 ), "Passed!" ); + ok( b.c.equals( two3 ), "Passed!" ); + }); + + test( "setFromPointsAndIndices", function() { + var a = new THREE.Triangle(); + + var points = [ one3, one3.clone().negate(), two3 ]; + a.setFromPointsAndIndices( points, 1, 0, 2 ); + ok( a.a.equals( one3.clone().negate() ), "Passed!" ); + ok( a.b.equals( one3 ), "Passed!" ); + ok( a.c.equals( two3 ), "Passed!" ); + + }); + + test( "set", function() { + var a = new THREE.Triangle(); + + a.set( one3.clone().negate(), one3, two3 ); + ok( a.a.equals( one3.clone().negate() ), "Passed!" ); + ok( a.b.equals( one3 ), "Passed!" ); + ok( a.c.equals( two3 ), "Passed!" ); + + }); + + test( "area", function() { + var a = new THREE.Triangle(); + + ok( a.area() == 0, "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.area() == 0.5, "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.area() == 2, "Passed!" ); + + // colinear triangle. + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 3, 0, 0 ) ); + ok( a.area() == 0, "Passed!" ); + }); + + test( "midpoint", function() { + var a = new THREE.Triangle(); + + ok( a.midpoint().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.midpoint().equals( new THREE.Vector3( 1/3, 1/3, 0 ) ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.midpoint().equals( new THREE.Vector3( 2/3, 0, 2/3 ) ), "Passed!" ); + }); + + test( "normal", function() { + var a = new THREE.Triangle(); + + ok( a.normal().equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.normal().equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.normal().equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + }); + + test( "plane", function() { + var a = new THREE.Triangle(); + + // artificial normal is created in this case. + ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); + ok( a.plane().normal.equals( a.normal() ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); + ok( a.plane().normal.equals( a.normal() ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.plane().distanceToPoint( a.a ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.b ) == 0, "Passed!" ); + ok( a.plane().distanceToPoint( a.c ) == 0, "Passed!" ); + ok( a.plane().normal.clone().normalize().equals( a.normal() ), "Passed!" ); + }); + + test( "barycoordFromPoint", function() { + var a = new THREE.Triangle(); + + var bad = new THREE.Vector3( -2, -1, -1 ); + + ok( a.barycoordFromPoint( a.a ).equals( bad ), "Passed!" ); + ok( a.barycoordFromPoint( a.b ).equals( bad ), "Passed!" ); + ok( a.barycoordFromPoint( a.c ).equals( bad ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.barycoordFromPoint( a.a ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.b ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.c ).equals( new THREE.Vector3( 0, 0, 1 ) ), "Passed!" ); + ok( a.barycoordFromPoint( a.midpoint() ).distanceTo( new THREE.Vector3( 1/3, 1/3, 1/3 ) ) < 0.0001, "Passed!" ); + }); + + test( "containsPoint", function() { + var a = new THREE.Triangle(); + + ok( ! a.containsPoint( a.a ), "Passed!" ); + ok( ! a.containsPoint( a.b ), "Passed!" ); + ok( ! a.containsPoint( a.c ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 1, 0, 0 ), new THREE.Vector3( 0, 1, 0 ) ); + ok( a.containsPoint( a.a ), "Passed!" ); + ok( a.containsPoint( a.b ), "Passed!" ); + ok( a.containsPoint( a.c ), "Passed!" ); + ok( a.containsPoint( a.midpoint() ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); + + a = new THREE.Triangle( new THREE.Vector3( 2, 0, 0 ), new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, 2 ) ); + ok( a.containsPoint( a.a ), "Passed!" ); + ok( a.containsPoint( a.b ), "Passed!" ); + ok( a.containsPoint( a.c ), "Passed!" ); + ok( a.containsPoint( a.midpoint() ), "Passed!" ); + ok( ! a.containsPoint( new THREE.Vector3( -1, -1, -1 ) ), "Passed!" ); + }); + + + test( "constructor", function() { + var a = new THREE.Vector2(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + + a = new THREE.Vector2( x, y ); + ok( a.x === x, "Passed!" ); + ok( a.y === y, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2().copy( a ); + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + + // ensure that it is a true copy + a.x = 0; + a.y = -1; + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Vector2(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + + a.set( x, y ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + }); + + test( "setX,setY", function() { + var a = new THREE.Vector2(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + + a.setX( x ); + a.setY( y ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + }); + + test( "setComponent,getComponent", function() { + var a = new THREE.Vector2(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + + a.setComponent( 0, 1 ); + a.setComponent( 1, 2 ); + ok( a.getComponent( 0 ) == 1, "Passed!" ); + ok( a.getComponent( 1 ) == 2, "Passed!" ); + }); + + test( "add", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2( -x, -y ); + + a.add( b ); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + + var c = new THREE.Vector2().addVectors( b, b ); + ok( c.x == -2*x, "Passed!" ); + ok( c.y == -2*y, "Passed!" ); + }); + + test( "sub", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2( -x, -y ); + + a.sub( b ); + ok( a.x == 2*x, "Passed!" ); + ok( a.y == 2*y, "Passed!" ); + + var c = new THREE.Vector2().subVectors( a, a ); + ok( c.x == 0, "Passed!" ); + ok( c.y == 0, "Passed!" ); + }); + + test( "multiply/divide", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2( -x, -y ); + + a.multiplyScalar( -2 ); + ok( a.x == x*-2, "Passed!" ); + ok( a.y == y*-2, "Passed!" ); + + b.multiplyScalar( -2 ); + ok( b.x == 2*x, "Passed!" ); + ok( b.y == 2*y, "Passed!" ); + + a.divideScalar( -2 ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + + b.divideScalar( -2 ); + ok( b.x == -x, "Passed!" ); + ok( b.y == -y, "Passed!" ); + }); + + + test( "min/max/clamp", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2( -x, -y ); + var c = new THREE.Vector2(); + + c.copy( a ).min( b ); + ok( c.x == -x, "Passed!" ); + ok( c.y == -y, "Passed!" ); + + c.copy( a ).max( b ); + ok( c.x == x, "Passed!" ); + ok( c.y == y, "Passed!" ); + + c.set( -2*x, 2*y ); + c.clamp( b, a ); + ok( c.x == -x, "Passed!" ); + ok( c.y == y, "Passed!" ); + }); + + test( "negate", function() { + var a = new THREE.Vector2( x, y ); + + a.negate(); + ok( a.x == -x, "Passed!" ); + ok( a.y == -y, "Passed!" ); + }); + + test( "dot", function() { + var a = new THREE.Vector2( x, y ); + var b = new THREE.Vector2( -x, -y ); + var c = new THREE.Vector2(); + + var result = a.dot( b ); + ok( result == (-x*x-y*y), "Passed!" ); + + result = a.dot( c ); + ok( result == 0, "Passed!" ); + }); + + test( "length/lengthSq", function() { + var a = new THREE.Vector2( x, 0 ); + var b = new THREE.Vector2( 0, -y ); + var c = new THREE.Vector2(); + + ok( a.length() == x, "Passed!" ); + ok( a.lengthSq() == x*x, "Passed!" ); + ok( b.length() == y, "Passed!" ); + ok( b.lengthSq() == y*y, "Passed!" ); + ok( c.length() == 0, "Passed!" ); + ok( c.lengthSq() == 0, "Passed!" ); + + a.set( x, y ); + ok( a.length() == Math.sqrt( x*x + y*y ), "Passed!" ); + ok( a.lengthSq() == ( x*x + y*y ), "Passed!" ); + }); + + test( "normalize", function() { + var a = new THREE.Vector2( x, 0 ); + var b = new THREE.Vector2( 0, -y ); + var c = new THREE.Vector2(); + + a.normalize(); + ok( a.length() == 1, "Passed!" ); + ok( a.x == 1, "Passed!" ); + + b.normalize(); + ok( b.length() == 1, "Passed!" ); + ok( b.y == -1, "Passed!" ); + }); + + test( "distanceTo/distanceToSquared", function() { + var a = new THREE.Vector2( x, 0 ); + var b = new THREE.Vector2( 0, -y ); + var c = new THREE.Vector2(); + + ok( a.distanceTo( c ) == x, "Passed!" ); + ok( a.distanceToSquared( c ) == x*x, "Passed!" ); + + ok( b.distanceTo( c ) == y, "Passed!" ); + ok( b.distanceToSquared( c ) == y*y, "Passed!" ); + }); + + test( "setLength", function() { + var a = new THREE.Vector2( x, 0 ); + + ok( a.length() == x, "Passed!" ); + a.setLength( y ); + ok( a.length() == y, "Passed!" ); + + a = new THREE.Vector2( 0, 0 ); + ok( a.length() == 0, "Passed!" ); + a.setLength( y ); + ok( a.length() == 0, "Passed!" ); + }); + + test( "lerp/clone", function() { + var a = new THREE.Vector2( x, 0 ); + var b = new THREE.Vector2( 0, -y ); + + ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); + ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); + + ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); + + ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); + + ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); + }); + + test( "equals", function() { + var a = new THREE.Vector2( x, 0 ); + var b = new THREE.Vector2( 0, -y ); + + ok( a.x != b.x, "Passed!" ); + ok( a.y != b.y, "Passed!" ); + + ok( ! a.equals( b ), "Passed!" ); + ok( ! b.equals( a ), "Passed!" ); + + a.copy( b ); + ok( a.x == b.x, "Passed!" ); + ok( a.y == b.y, "Passed!" ); + + ok( a.equals( b ), "Passed!" ); + ok( b.equals( a ), "Passed!" ); + }); + + + test( "constructor", function() { + var a = new THREE.Vector3(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + + a = new THREE.Vector3( x, y, z ); + ok( a.x === x, "Passed!" ); + ok( a.y === y, "Passed!" ); + ok( a.z === z, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3().copy( a ); + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + ok( b.z == z, "Passed!" ); + + // ensure that it is a true copy + a.x = 0; + a.y = -1; + a.z = -2; + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + ok( b.z == z, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Vector3(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + + a.set( x, y, z ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + }); + + test( "setX,setY,setZ", function() { + var a = new THREE.Vector3(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + + a.setX( x ); + a.setY( y ); + a.setZ( z ); + + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + }); + + test( "setComponent,getComponent", function() { + var a = new THREE.Vector3(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + + a.setComponent( 0, 1 ); + a.setComponent( 1, 2 ); + a.setComponent( 2, 3 ); + ok( a.getComponent( 0 ) == 1, "Passed!" ); + ok( a.getComponent( 1 ) == 2, "Passed!" ); + ok( a.getComponent( 2 ) == 3, "Passed!" ); + }); + + test( "add", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3( -x, -y, -z ); + + a.add( b ); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + + var c = new THREE.Vector3().addVectors( b, b ); + ok( c.x == -2*x, "Passed!" ); + ok( c.y == -2*y, "Passed!" ); + ok( c.z == -2*z, "Passed!" ); + }); + + test( "sub", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3( -x, -y, -z ); + + a.sub( b ); + ok( a.x == 2*x, "Passed!" ); + ok( a.y == 2*y, "Passed!" ); + ok( a.z == 2*z, "Passed!" ); + + var c = new THREE.Vector3().subVectors( a, a ); + ok( c.x == 0, "Passed!" ); + ok( c.y == 0, "Passed!" ); + ok( c.z == 0, "Passed!" ); + }); + + test( "multiply/divide", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3( -x, -y, -z ); + + a.multiplyScalar( -2 ); + ok( a.x == x*-2, "Passed!" ); + ok( a.y == y*-2, "Passed!" ); + ok( a.z == z*-2, "Passed!" ); + + b.multiplyScalar( -2 ); + ok( b.x == 2*x, "Passed!" ); + ok( b.y == 2*y, "Passed!" ); + ok( b.z == 2*z, "Passed!" ); + + a.divideScalar( -2 ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + + b.divideScalar( -2 ); + ok( b.x == -x, "Passed!" ); + ok( b.y == -y, "Passed!" ); + ok( b.z == -z, "Passed!" ); + }); + + test( "min/max/clamp", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3( -x, -y, -z ); + var c = new THREE.Vector3(); + + c.copy( a ).min( b ); + ok( c.x == -x, "Passed!" ); + ok( c.y == -y, "Passed!" ); + ok( c.z == -z, "Passed!" ); + + c.copy( a ).max( b ); + ok( c.x == x, "Passed!" ); + ok( c.y == y, "Passed!" ); + ok( c.z == z, "Passed!" ); + + c.set( -2*x, 2*y, -2*z ); + c.clamp( b, a ); + ok( c.x == -x, "Passed!" ); + ok( c.y == y, "Passed!" ); + ok( c.z == -z, "Passed!" ); + }); + + test( "negate", function() { + var a = new THREE.Vector3( x, y, z ); + + a.negate(); + ok( a.x == -x, "Passed!" ); + ok( a.y == -y, "Passed!" ); + ok( a.z == -z, "Passed!" ); + }); + + test( "dot", function() { + var a = new THREE.Vector3( x, y, z ); + var b = new THREE.Vector3( -x, -y, -z ); + var c = new THREE.Vector3(); + + var result = a.dot( b ); + ok( result == (-x*x-y*y-z*z), "Passed!" ); + + result = a.dot( c ); + ok( result == 0, "Passed!" ); + }); + + test( "length/lengthSq", function() { + var a = new THREE.Vector3( x, 0, 0 ); + var b = new THREE.Vector3( 0, -y, 0 ); + var c = new THREE.Vector3( 0, 0, z ); + var d = new THREE.Vector3(); + + ok( a.length() == x, "Passed!" ); + ok( a.lengthSq() == x*x, "Passed!" ); + ok( b.length() == y, "Passed!" ); + ok( b.lengthSq() == y*y, "Passed!" ); + ok( c.length() == z, "Passed!" ); + ok( c.lengthSq() == z*z, "Passed!" ); + ok( d.length() == 0, "Passed!" ); + ok( d.lengthSq() == 0, "Passed!" ); + + a.set( x, y, z ); + ok( a.length() == Math.sqrt( x*x + y*y + z*z ), "Passed!" ); + ok( a.lengthSq() == ( x*x + y*y + z*z ), "Passed!" ); + }); + + test( "normalize", function() { + var a = new THREE.Vector3( x, 0, 0 ); + var b = new THREE.Vector3( 0, -y, 0 ); + var c = new THREE.Vector3( 0, 0, z ); + + a.normalize(); + ok( a.length() == 1, "Passed!" ); + ok( a.x == 1, "Passed!" ); + + b.normalize(); + ok( b.length() == 1, "Passed!" ); + ok( b.y == -1, "Passed!" ); + + c.normalize(); + ok( c.length() == 1, "Passed!" ); + ok( c.z == 1, "Passed!" ); + }); + + test( "distanceTo/distanceToSquared", function() { + var a = new THREE.Vector3( x, 0, 0 ); + var b = new THREE.Vector3( 0, -y, 0 ); + var c = new THREE.Vector3( 0, 0, z ); + var d = new THREE.Vector3(); + + ok( a.distanceTo( d ) == x, "Passed!" ); + ok( a.distanceToSquared( d ) == x*x, "Passed!" ); + + ok( b.distanceTo( d ) == y, "Passed!" ); + ok( b.distanceToSquared( d ) == y*y, "Passed!" ); + + ok( c.distanceTo( d ) == z, "Passed!" ); + ok( c.distanceToSquared( d ) == z*z, "Passed!" ); + }); + + test( "setLength", function() { + var a = new THREE.Vector3( x, 0, 0 ); + + ok( a.length() == x, "Passed!" ); + a.setLength( y ); + ok( a.length() == y, "Passed!" ); + + a = new THREE.Vector3( 0, 0, 0 ); + ok( a.length() == 0, "Passed!" ); + a.setLength( y ); + ok( a.length() == 0, "Passed!" ); + + }); + + test( "projectOnVector", function() { + var a = new THREE.Vector3( 1, 0, 0 ); + var b = new THREE.Vector3(); + var normal = new THREE.Vector3( 10, 0, 0 ); + + ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); + + a.set( 0, 1, 0 ); + ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a.set( 0, 0, -1 ); + ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a.set( -1, 0, 0 ); + ok( b.copy( a ).projectOnVector( normal ).equals( new THREE.Vector3( -1, 0, 0 ) ), "Passed!" ); + + }); + + test( "projectOnPlane", function() { + var a = new THREE.Vector3( 1, 0, 0 ); + var b = new THREE.Vector3(); + var normal = new THREE.Vector3( 1, 0, 0 ); + + ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + a.set( 0, 1, 0 ); + ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 1, 0 ) ), "Passed!" ); + + a.set( 0, 0, -1 ); + ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, -1 ) ), "Passed!" ); + + a.set( -1, 0, 0 ); + ok( b.copy( a ).projectOnPlane( normal ).equals( new THREE.Vector3( 0, 0, 0 ) ), "Passed!" ); + + }); + + test( "reflect", function() { + var a = new THREE.Vector3( 1, 0, 0 ); + var normal = new THREE.Vector3( 1, 0, 0 ); + var b = new THREE.Vector3( 0, 0, 0 ); + + ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( 1, 0, 0 ) ), "Passed!" ); + + a.set( 1, -1, 0 ); + ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( 1, 1, 0 ) ), "Passed!" ); + + a.set( 1, -1, 0 ); + normal.set( 0, -1, 0 ); + ok( b.copy( a ).reflect( normal ).equals( new THREE.Vector3( -1, -1, 0 ) ), "Passed!" ); + }); + + test( "angleTo", function() { + var a = new THREE.Vector3( 0, -0.18851655680720186, 0.9820700116639124 ); + var b = new THREE.Vector3( 0, 0.18851655680720186, -0.9820700116639124 ); + + equal( a.angleTo( a ), 0 ); + equal( a.angleTo( b ), Math.PI ); + + var x = new THREE.Vector3( 1, 0, 0 ); + var y = new THREE.Vector3( 0, 1, 0 ); + var z = new THREE.Vector3( 0, 0, 1 ); + + equal( x.angleTo( y ), Math.PI / 2 ); + equal( x.angleTo( z ), Math.PI / 2 ); + equal( z.angleTo( x ), Math.PI / 2 ); + + ok( Math.abs( x.angleTo( new THREE.Vector3( 1, 1, 0 ) ) - ( Math.PI / 4 ) ) < 0.0000001 ); + }); + + test( "lerp/clone", function() { + var a = new THREE.Vector3( x, 0, z ); + var b = new THREE.Vector3( 0, -y, 0 ); + + ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); + ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); + + ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); + + ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).z == z*0.5, "Passed!" ); + + ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); + }); + + test( "equals", function() { + var a = new THREE.Vector3( x, 0, z ); + var b = new THREE.Vector3( 0, -y, 0 ); + + ok( a.x != b.x, "Passed!" ); + ok( a.y != b.y, "Passed!" ); + ok( a.z != b.z, "Passed!" ); + + ok( ! a.equals( b ), "Passed!" ); + ok( ! b.equals( a ), "Passed!" ); + + a.copy( b ); + ok( a.x == b.x, "Passed!" ); + ok( a.y == b.y, "Passed!" ); + ok( a.z == b.z, "Passed!" ); + + ok( a.equals( b ), "Passed!" ); + ok( b.equals( a ), "Passed!" ); + }); + + + test( "constructor", function() { + var a = new THREE.Vector4(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a = new THREE.Vector4( x, y, z, w ); + ok( a.x === x, "Passed!" ); + ok( a.y === y, "Passed!" ); + ok( a.z === z, "Passed!" ); + ok( a.w === w, "Passed!" ); + }); + + test( "copy", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4().copy( a ); + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + ok( b.z == z, "Passed!" ); + ok( b.w == w, "Passed!" ); + + // ensure that it is a true copy + a.x = 0; + a.y = -1; + a.z = -2; + a.w = -3; + ok( b.x == x, "Passed!" ); + ok( b.y == y, "Passed!" ); + ok( b.z == z, "Passed!" ); + ok( b.w == w, "Passed!" ); + }); + + test( "set", function() { + var a = new THREE.Vector4(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a.set( x, y, z, w ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + ok( a.w == w, "Passed!" ); + }); + + test( "setX,setY,setZ,setW", function() { + var a = new THREE.Vector4(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a.setX( x ); + a.setY( y ); + a.setZ( z ); + a.setW( w ); + + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + ok( a.w == w, "Passed!" ); + }); + + test( "setComponent,getComponent", function() { + var a = new THREE.Vector4(); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 1, "Passed!" ); + + a.setComponent( 0, 1 ); + a.setComponent( 1, 2 ); + a.setComponent( 2, 3 ); + a.setComponent( 3, 4 ); + ok( a.getComponent( 0 ) == 1, "Passed!" ); + ok( a.getComponent( 1 ) == 2, "Passed!" ); + ok( a.getComponent( 2 ) == 3, "Passed!" ); + ok( a.getComponent( 3 ) == 4, "Passed!" ); + }); + + test( "add", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4( -x, -y, -z, -w ); + + a.add( b ); + ok( a.x == 0, "Passed!" ); + ok( a.y == 0, "Passed!" ); + ok( a.z == 0, "Passed!" ); + ok( a.w == 0, "Passed!" ); + + var c = new THREE.Vector4().addVectors( b, b ); + ok( c.x == -2*x, "Passed!" ); + ok( c.y == -2*y, "Passed!" ); + ok( c.z == -2*z, "Passed!" ); + ok( c.w == -2*w, "Passed!" ); + }); + + test( "sub", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4( -x, -y, -z, -w ); + + a.sub( b ); + ok( a.x == 2*x, "Passed!" ); + ok( a.y == 2*y, "Passed!" ); + ok( a.z == 2*z, "Passed!" ); + ok( a.w == 2*w, "Passed!" ); + + var c = new THREE.Vector4().subVectors( a, a ); + ok( c.x == 0, "Passed!" ); + ok( c.y == 0, "Passed!" ); + ok( c.z == 0, "Passed!" ); + ok( c.w == 0, "Passed!" ); + }); + + test( "multiply/divide", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4( -x, -y, -z, -w ); + + a.multiplyScalar( -2 ); + ok( a.x == x*-2, "Passed!" ); + ok( a.y == y*-2, "Passed!" ); + ok( a.z == z*-2, "Passed!" ); + ok( a.w == w*-2, "Passed!" ); + + b.multiplyScalar( -2 ); + ok( b.x == 2*x, "Passed!" ); + ok( b.y == 2*y, "Passed!" ); + ok( b.z == 2*z, "Passed!" ); + ok( b.w == 2*w, "Passed!" ); + + a.divideScalar( -2 ); + ok( a.x == x, "Passed!" ); + ok( a.y == y, "Passed!" ); + ok( a.z == z, "Passed!" ); + ok( a.w == w, "Passed!" ); + + b.divideScalar( -2 ); + ok( b.x == -x, "Passed!" ); + ok( b.y == -y, "Passed!" ); + ok( b.z == -z, "Passed!" ); + ok( b.w == -w, "Passed!" ); + }); + + test( "min/max/clamp", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4( -x, -y, -z, -w ); + var c = new THREE.Vector4(); + + c.copy( a ).min( b ); + ok( c.x == -x, "Passed!" ); + ok( c.y == -y, "Passed!" ); + ok( c.z == -z, "Passed!" ); + ok( c.w == -w, "Passed!" ); + + c.copy( a ).max( b ); + ok( c.x == x, "Passed!" ); + ok( c.y == y, "Passed!" ); + ok( c.z == z, "Passed!" ); + ok( c.w == w, "Passed!" ); + + c.set( -2*x, 2*y, -2*z, 2*w ); + c.clamp( b, a ); + ok( c.x == -x, "Passed!" ); + ok( c.y == y, "Passed!" ); + ok( c.z == -z, "Passed!" ); + ok( c.w == w, "Passed!" ); + }); + + test( "negate", function() { + var a = new THREE.Vector4( x, y, z, w ); + + a.negate(); + ok( a.x == -x, "Passed!" ); + ok( a.y == -y, "Passed!" ); + ok( a.z == -z, "Passed!" ); + ok( a.w == -w, "Passed!" ); + }); + + test( "dot", function() { + var a = new THREE.Vector4( x, y, z, w ); + var b = new THREE.Vector4( -x, -y, -z, -w ); + var c = new THREE.Vector4( 0, 0, 0, 0 ); + + var result = a.dot( b ); + ok( result == (-x*x-y*y-z*z-w*w), "Passed!" ); + + result = a.dot( c ); + ok( result == 0, "Passed!" ); + }); + + test( "length/lengthSq", function() { + var a = new THREE.Vector4( x, 0, 0, 0 ); + var b = new THREE.Vector4( 0, -y, 0, 0 ); + var c = new THREE.Vector4( 0, 0, z, 0 ); + var d = new THREE.Vector4( 0, 0, 0, w ); + var e = new THREE.Vector4( 0, 0, 0, 0 ); + + ok( a.length() == x, "Passed!" ); + ok( a.lengthSq() == x*x, "Passed!" ); + ok( b.length() == y, "Passed!" ); + ok( b.lengthSq() == y*y, "Passed!" ); + ok( c.length() == z, "Passed!" ); + ok( c.lengthSq() == z*z, "Passed!" ); + ok( d.length() == w, "Passed!" ); + ok( d.lengthSq() == w*w, "Passed!" ); + ok( e.length() == 0, "Passed!" ); + ok( e.lengthSq() == 0, "Passed!" ); + + a.set( x, y, z, w ); + ok( a.length() == Math.sqrt( x*x + y*y + z*z + w*w ), "Passed!" ); + ok( a.lengthSq() == ( x*x + y*y + z*z + w*w ), "Passed!" ); + }); + + test( "normalize", function() { + var a = new THREE.Vector4( x, 0, 0, 0 ); + var b = new THREE.Vector4( 0, -y, 0, 0 ); + var c = new THREE.Vector4( 0, 0, z, 0 ); + var d = new THREE.Vector4( 0, 0, 0, -w ); + + a.normalize(); + ok( a.length() == 1, "Passed!" ); + ok( a.x == 1, "Passed!" ); + + b.normalize(); + ok( b.length() == 1, "Passed!" ); + ok( b.y == -1, "Passed!" ); + + c.normalize(); + ok( c.length() == 1, "Passed!" ); + ok( c.z == 1, "Passed!" ); + + d.normalize(); + ok( d.length() == 1, "Passed!" ); + ok( d.w == -1, "Passed!" ); + }); + + /* + test( "distanceTo/distanceToSquared", function() { + var a = new THREE.Vector4( x, 0, 0, 0 ); + var b = new THREE.Vector4( 0, -y, 0, 0 ); + var c = new THREE.Vector4( 0, 0, z, 0 ); + var d = new THREE.Vector4( 0, 0, 0, -w ); + var e = new THREE.Vector4(); + + ok( a.distanceTo( e ) == x, "Passed!" ); + ok( a.distanceToSquared( e ) == x*x, "Passed!" ); + + ok( b.distanceTo( e ) == y, "Passed!" ); + ok( b.distanceToSquared( e ) == y*y, "Passed!" ); + + ok( c.distanceTo( e ) == z, "Passed!" ); + ok( c.distanceToSquared( e ) == z*z, "Passed!" ); + + ok( d.distanceTo( e ) == w, "Passed!" ); + ok( d.distanceToSquared( e ) == w*w, "Passed!" ); + }); + */ + + + test( "setLength", function() { + var a = new THREE.Vector4( x, 0, 0, 0 ); + + ok( a.length() == x, "Passed!" ); + a.setLength( y ); + ok( a.length() == y, "Passed!" ); + + a = new THREE.Vector4( 0, 0, 0, 0 ); + ok( a.length() == 0, "Passed!" ); + a.setLength( y ); + ok( a.length() == 0, "Passed!" ); + }); + + test( "lerp/clone", function() { + var a = new THREE.Vector4( x, 0, z, 0 ); + var b = new THREE.Vector4( 0, -y, 0, -w ); + + ok( a.lerp( a, 0 ).equals( a.lerp( a, 0.5 ) ), "Passed!" ); + ok( a.lerp( a, 0 ).equals( a.lerp( a, 1 ) ), "Passed!" ); + + ok( a.clone().lerp( b, 0 ).equals( a ), "Passed!" ); + + ok( a.clone().lerp( b, 0.5 ).x == x*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).y == -y*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).z == z*0.5, "Passed!" ); + ok( a.clone().lerp( b, 0.5 ).w == -w*0.5, "Passed!" ); + + ok( a.clone().lerp( b, 1 ).equals( b ), "Passed!" ); + }); + + test( "equals", function() { + var a = new THREE.Vector4( x, 0, z, 0 ); + var b = new THREE.Vector4( 0, -y, 0, -w ); + + ok( a.x != b.x, "Passed!" ); + ok( a.y != b.y, "Passed!" ); + ok( a.z != b.z, "Passed!" ); + ok( a.w != b.w, "Passed!" ); + + ok( ! a.equals( b ), "Passed!" ); + ok( ! b.equals( a ), "Passed!" ); + + a.copy( b ); + ok( a.x == b.x, "Passed!" ); + ok( a.y == b.y, "Passed!" ); + ok( a.z == b.z, "Passed!" ); + ok( a.w == b.w, "Passed!" ); + + ok( a.equals( b ), "Passed!" ); + ok( b.equals( a ), "Passed!" ); + }); +}; + +///////////////////////////////////////////////////////////// +// https://github.com/mrdoob/three.js/tree/master/examples +////////////////////////////////////////////////////////////// + + +declare var Stats: any; +declare var TWEEN: any; +declare var Detector: any; +declare var Qrcode: any; +declare var ImprovedNoise: any; + + +declare module THREE{ + var PDBLoader: any; + var CSS3Renderer: any; + var CSS3DSprite: any; + var CSS3DRenderer: any; + var CSS3DObject: any; + var TrackballControls: any; + var FlyControls: any; + var RenderPass: any; + var FilmPass: any; + var EffectComposer: any; + var OrbitControls: any; + var PathControls: any; + var PointerLockControls: any; + var RollControls: any; + var FirstPersonControls: any; + var SVGRenderer: any; + var SoftwareRenderer: any; + var UVsDebug: any; + var UVsUtils: any; + var Curves: any; + var ParametricGeometries: any; + var BinaryLoader: any; + var OculusRiftEffect: any; + var SubdivisionModifier: any; + var TessellateModifier: any; + var ExplodeModifier: any; + var RenderPass: any; + var BloomPass:any; + var FilmPass: any; + var ShaderPass: any; + var FXAAShader: any; + var CopyShader: any; + var ColladaLoader: any; + var CTMLoader: any; + var VTKLoader: any; + var STLLoader: any; + var OBJLoader: any; + var ColladaLoader: any; + var UTF8Loader: any; + var UnpackDepthRGBAShader: any; +} + +interface CSS3Properties{ + WebkitFilter: string; +} + +interface HTMLDocument{ + pointerLockElement: any; + mozPointerLockElement: any; + webkitPointerLockElement: any; + fullscreenElement: any; + mozFullscreenElement: any; + mozFullScreenElement: any; + webkitFullscreenElement: any; +} +interface HTMLElement{ + requestPointerLock: any; + mozRequestPointerLock: any; + webkitRequestPointerLock: any; + requestFullScreen: any; + requestFullscreen: any; + mozRequestFullScreen: any; + mozRequestFullscreen: any; + webkitRequestFullscreen: any; +} + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_camera_orthographic.html + +()=>{ + var container, stats; + var camera, scene, renderer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - orthographic view'; + container.appendChild( info ); + + camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 500, 1000 ); + camera.position.x = 200; + camera.position.y = 100; + camera.position.z = 200; + + scene = new THREE.Scene(); + + // Grid + + var size = 500, step = 50; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, 0, i ) ); + geometry.vertices.push( new THREE.Vector3( size, 0, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, 0, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, 0, size ) ); + + } + + var materialLine = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ); + + var line = new THREE.Line( geometry, materialLine ); + line.type = THREE.LinePieces; + scene.add( line ); + + // Cubes + + var geometry = new THREE.CubeGeometry( 50, 50, 50 ); + var materialCube = new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ); + + for ( var i = 0; i < 100; i ++ ) { + + var cube = new THREE.Mesh( geometry, materialCube ); + + cube.scale.y = Math.floor( Math.random() * 2 + 1 ); + + cube.position.x = Math.floor( ( Math.random() * 1000 - 500 ) / 50 ) * 50 + 25; + cube.position.y = ( cube.scale.y * 50 ) / 2; + cube.position.z = Math.floor( ( Math.random() * 1000 - 500 ) / 50 ) * 50 + 25; + + scene.add( cube ); + + } + + // Lights + + var ambientLight = new THREE.AmbientLight( Math.random() * 0x10 ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.left = window.innerWidth / - 2; + camera.right = window.innerWidth / 2; + camera.top = window.innerHeight / 2; + camera.bottom = window.innerHeight / - 2; + + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0001; + + camera.position.x = Math.cos( timer ) * 200; + camera.position.z = Math.sin( timer ) * 200; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_geometry_cube.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var cube, plane; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Drag to spin the cube'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.y = 150; + camera.position.z = 500; + + scene = new THREE.Scene(); + + // Cube + + var geometryCube = new THREE.CubeGeometry( 200, 200, 200 ); + + for ( var i = 0; i < geometryCube.faces.length; i ++ ) { + + geometryCube.faces[ i ].color.setHex( Math.random() * 0xffffff ); + + } + + var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors } ); + + cube = new THREE.Mesh( geometryCube, material ); + cube.position.y = 150; + scene.add( cube ); + + // Plane + + var geometryPlane = new THREE.PlaneGeometry( 200, 200 ); + geometryPlane.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ); + + plane = new THREE.Mesh( geometryPlane, material ); + scene.add( plane ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + plane.rotation.y = cube.rotation.y += ( targetRotation - cube.rotation.y ) * 0.05; + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_geometry_hierarchy.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var geometry, group; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + var geometry = new THREE.CubeGeometry( 100, 100, 100 ); + var material = new THREE.MeshNormalMaterial(); + + group = new THREE.Object3D(); + + for ( var i = 0; i < 200; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = Math.random() * 2000 - 1000; + mesh.position.y = Math.random() * 2000 - 1000; + mesh.position.z = Math.random() * 2000 - 1000; + mesh.rotation.x = Math.random() * 2 * Math.PI; + mesh.rotation.y = Math.random() * 2 * Math.PI; + mesh.matrixAutoUpdate = false; + mesh.updateMatrix(); + group.add( mesh ); + + } + + scene.add( group ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = false; + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ) * 10; + mouseY = ( event.clientY - windowHalfY ) * 10; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + var currentSeconds = Date.now(); + group.rotation.x = Math.sin( currentSeconds * 0.0007 ) * 0.5; + group.rotation.y = Math.sin( currentSeconds * 0.0003 ) * 0.5; + group.rotation.z = Math.sin( currentSeconds * 0.0002 ) * 0.5; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_geometry_panorama.html + +()=>{ + var camera, scene, renderer; + + var texture_placeholder, + isUserInteracting = false, + onPointerDownPointerX = 0, onPointerDownPointerY = 0, + lon = 90, onPointerDownLon = 0, + lat = 0, onPointerDownLat = 0, + phi = 0, theta = 0, + target = new THREE.Vector3(); + + init(); + + function init() { + + var container, mesh; + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 ); + + scene = new THREE.Scene(); + + texture_placeholder = document.createElement( 'canvas' ); + texture_placeholder.width = 128; + texture_placeholder.height = 128; + + var context = texture_placeholder.getContext( '2d' ); + context.fillStyle = 'rgb( 200, 200, 200 )'; + context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height ); + + var materials = [ + + loadTexture( 'textures/cube/skybox/px.jpg' ), // right + loadTexture( 'textures/cube/skybox/nx.jpg' ), // left + loadTexture( 'textures/cube/skybox/py.jpg' ), // top + loadTexture( 'textures/cube/skybox/ny.jpg' ), // bottom + loadTexture( 'textures/cube/skybox/pz.jpg' ), // back + loadTexture( 'textures/cube/skybox/nz.jpg' ) // front + + ]; + + mesh = new THREE.Mesh( new THREE.CubeGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MeshFaceMaterial( materials ) ); + mesh.scale.x = - 1; + scene.add( mesh ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mousewheel', onDocumentMouseWheel, false ); + + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + render(); + + } + + function loadTexture( path ) { + + var texture = new THREE.Texture( texture_placeholder ); + var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } ); + + var image = new Image(); + image.onload = function () { + + texture.needsUpdate = true; + material.map.image = this; + + render(); + + }; + image.src = path; + + return material; + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + isUserInteracting = true; + + onPointerDownPointerX = event.clientX; + onPointerDownPointerY = event.clientY; + + onPointerDownLon = lon; + onPointerDownLat = lat; + + } + + function onDocumentMouseMove( event ) { + + if ( isUserInteracting ) { + + lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon; + lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat; + render(); + + } + + } + + function onDocumentMouseUp( event ) { + + isUserInteracting = false; + render(); + + } + + function onDocumentMouseWheel( event ) { + + camera.fov -= event.wheelDeltaY * 0.05; + camera.updateProjectionMatrix(); + + render(); + + } + + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + onPointerDownPointerX = event.touches[ 0 ].pageX; + onPointerDownPointerY = event.touches[ 0 ].pageY; + + onPointerDownLon = lon; + onPointerDownLat = lat; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + lon = ( onPointerDownPointerX - event.touches[0].pageX ) * 0.1 + onPointerDownLon; + lat = ( event.touches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat; + + render(); + + } + + } + + function render() { + + lat = Math.max( - 85, Math.min( 85, lat ) ); + phi = THREE.Math.degToRad( 90 - lat ); + theta = THREE.Math.degToRad( lon ); + + target.x = 500 * Math.sin( phi ) * Math.cos( theta ); + target.y = 500 * Math.cos( phi ); + target.z = 500 * Math.sin( phi ) * Math.sin( theta ); + + camera.lookAt( target ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_geometry_panorama_fisheye.html + +()=>{ + var camera, scene, renderer; + + var texture_placeholder, + isUserInteracting = false, + onPointerDownPointerX = 0, onPointerDownPointerY = 0, + lon = 90, onPointerDownLon = 0, + lat = 0, onPointerDownLat = 0, + phi = 0, theta = 0, + target = new THREE.Vector3(); + + init(); + + function init() { + + var container, mesh; + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 ); + + scene = new THREE.Scene(); + + texture_placeholder = document.createElement( 'canvas' ); + texture_placeholder.width = 128; + texture_placeholder.height = 128; + + var context = texture_placeholder.getContext( '2d' ); + context.fillStyle = 'rgb( 200, 200, 200 )'; + context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height ); + + var materials = [ + + loadTexture( 'textures/cube/skybox/px.jpg' ), // right + loadTexture( 'textures/cube/skybox/nx.jpg' ), // left + loadTexture( 'textures/cube/skybox/py.jpg' ), // top + loadTexture( 'textures/cube/skybox/ny.jpg' ), // bottom + loadTexture( 'textures/cube/skybox/pz.jpg' ), // back + loadTexture( 'textures/cube/skybox/nz.jpg' ) // front + + ]; + + mesh = new THREE.Mesh( new THREE.CubeGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MeshFaceMaterial( materials ) ); + mesh.scale.x = - 1; + scene.add( mesh ); + + for ( var i = 0, l = mesh.geometry.vertices.length; i < l; i ++ ) { + + var vertex = mesh.geometry.vertices[ i ]; + + vertex.normalize(); + vertex.multiplyScalar( 550 ); + + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mousewheel', onDocumentMouseWheel, false ); + document.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false); + + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + render(); + + } + + function loadTexture( path ) { + + var texture = new THREE.Texture( texture_placeholder ); + var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } ); + + var image = new Image(); + image.onload = function () { + + texture.needsUpdate = true; + material.map.image = this; + + render(); + + }; + image.src = path; + + return material; + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + isUserInteracting = true; + + onPointerDownPointerX = event.clientX; + onPointerDownPointerY = event.clientY; + + onPointerDownLon = lon; + onPointerDownLat = lat; + + } + + function onDocumentMouseMove( event ) { + + if ( isUserInteracting ) { + + lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon; + lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat; + render(); + + } + } + + function onDocumentMouseUp( event ) { + + isUserInteracting = false; + render(); + + } + + function onDocumentMouseWheel( event ) { + + // WebKit + + if ( event.wheelDeltaY ) { + + camera.fov -= event.wheelDeltaY * 0.05; + + // Opera / Explorer 9 + + } else if ( event.wheelDelta ) { + + camera.fov -= event.wheelDelta * 0.05; + + // Firefox + + } else if ( event.detail ) { + + camera.fov -= event.detail * 0.05; + + } + + camera.updateProjectionMatrix(); + + render(); + + } + + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + onPointerDownPointerX = event.touches[ 0 ].pageX; + onPointerDownPointerY = event.touches[ 0 ].pageY; + + onPointerDownLon = lon; + onPointerDownLat = lat; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + lon = ( onPointerDownPointerX - event.touches[0].pageX ) * 0.1 + onPointerDownLon; + lat = ( event.touches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat; + + render(); + + } + + } + + function render() { + + lat = Math.max( - 85, Math.min( 85, lat ) ); + phi = THREE.Math.degToRad( 90 - lat ); + theta = THREE.Math.degToRad( lon ); + + target.x = 500 * Math.sin( phi ) * Math.cos( theta ); + target.y = 500 * Math.cos( phi ); + target.z = 500 * Math.sin( phi ) * Math.sin( theta ); + + camera.position.x = - target.x; + camera.position.y = - target.y; + camera.position.z = - target.z; + camera.lookAt( target ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_geometry_shapes.html + +()=>{ +var container, stats; + + var camera, scene, renderer; + + var text, plane; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var parent; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, 150, 500 ); + + scene = new THREE.Scene(); + + parent = new THREE.Object3D(); + parent.position.y = 50; + scene.add( parent ); + + function addShape( shape, color, x, y, z, rx, ry, rz, s ) { + + // flat shape + + var geometry = new THREE.ShapeGeometry( shape ); + var materialMesh = new THREE.MeshBasicMaterial( { color: color, overdraw: true } ); + + var mesh = new THREE.Mesh( geometry, materialMesh ); + mesh.position.set( x, y, z ); + mesh.rotation.set( rx, ry, rz ); + mesh.scale.set( s, s, s ); + parent.add( mesh ); + + // line + + var geometry = shape.createPointsGeometry(); + var materialLine = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333, transparent: true } ); + + var line = new THREE.Line( geometry, materialLine ); + line.position.set( x, y, z ); + line.rotation.set( rx, ry, rz ); + line.scale.set( s, s, s ); + parent.add( line ); + + } + + + // California + + var californiaPts = []; + + californiaPts.push( new THREE.Vector2 ( 610, 320 ) ); + californiaPts.push( new THREE.Vector2 ( 450, 300 ) ); + californiaPts.push( new THREE.Vector2 ( 392, 392 ) ); + californiaPts.push( new THREE.Vector2 ( 266, 438 ) ); + californiaPts.push( new THREE.Vector2 ( 190, 570 ) ); + californiaPts.push( new THREE.Vector2 ( 190, 600 ) ); + californiaPts.push( new THREE.Vector2 ( 160, 620 ) ); + californiaPts.push( new THREE.Vector2 ( 160, 650 ) ); + californiaPts.push( new THREE.Vector2 ( 180, 640 ) ); + californiaPts.push( new THREE.Vector2 ( 165, 680 ) ); + californiaPts.push( new THREE.Vector2 ( 150, 670 ) ); + californiaPts.push( new THREE.Vector2 ( 90, 737 ) ); + californiaPts.push( new THREE.Vector2 ( 80, 795 ) ); + californiaPts.push( new THREE.Vector2 ( 50, 835 ) ); + californiaPts.push( new THREE.Vector2 ( 64, 870 ) ); + californiaPts.push( new THREE.Vector2 ( 60, 945 ) ); + californiaPts.push( new THREE.Vector2 ( 300, 945 ) ); + californiaPts.push( new THREE.Vector2 ( 300, 743 ) ); + californiaPts.push( new THREE.Vector2 ( 600, 473 ) ); + californiaPts.push( new THREE.Vector2 ( 626, 425 ) ); + californiaPts.push( new THREE.Vector2 ( 600, 370 ) ); + californiaPts.push( new THREE.Vector2 ( 610, 320 ) ); + + var californiaShape = new THREE.Shape( californiaPts ); + + + // Triangle + + var triangleShape = new THREE.Shape(); + triangleShape.moveTo( 80, 20 ); + triangleShape.lineTo( 40, 80 ); + triangleShape.lineTo( 120, 80 ); + triangleShape.lineTo( 80, 20 ); // close path + + + // Heart + + var x = 0, y = 0; + + var heartShape = new THREE.Shape(); // From http://blog.burlock.org/html5/130-paths + + heartShape.moveTo( x + 25, y + 25 ); + heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y ); + heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 ); + heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 ); + heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 ); + heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y ); + heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 ); + + + // Square + + var sqLength = 80; + + var squareShape = new THREE.Shape(); + squareShape.moveTo( 0,0 ); + squareShape.lineTo( 0, sqLength ); + squareShape.lineTo( sqLength, sqLength ); + squareShape.lineTo( sqLength, 0 ); + squareShape.lineTo( 0, 0 ); + + + // Rectangle + + var rectLength = 120, rectWidth = 40; + + var rectShape = new THREE.Shape(); + rectShape.moveTo( 0,0 ); + rectShape.lineTo( 0, rectWidth ); + rectShape.lineTo( rectLength, rectWidth ); + rectShape.lineTo( rectLength, 0 ); + rectShape.lineTo( 0, 0 ); + + + // Rounded rectangle + + var roundedRectShape = new THREE.Shape(); + + ( function roundedRect( ctx, x, y, width, height, radius ){ + + ctx.moveTo( x, y + radius ); + ctx.lineTo( x, y + height - radius ); + ctx.quadraticCurveTo( x, y + height, x + radius, y + height ); + ctx.lineTo( x + width - radius, y + height) ; + ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius ); + ctx.lineTo( x + width, y + radius ); + ctx.quadraticCurveTo( x + width, y, x + width - radius, y ); + ctx.lineTo( x + radius, y ); + ctx.quadraticCurveTo( x, y, x, y + radius ); + + } )( roundedRectShape, 0, 0, 50, 50, 20 ); + + + // Circle + + var circleRadius = 40; + var circleShape = new THREE.Shape(); + circleShape.moveTo( 0, circleRadius ); + circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 ); + circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius ); + circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 ); + circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius ); + + + // Fish + + x = y = 0; + + var fishShape = new THREE.Shape(); + + fishShape.moveTo(x,y); + fishShape.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10); + fishShape.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40); + fishShape.quadraticCurveTo(x + 115, y, x + 115, y + 40); + fishShape.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10); + fishShape.quadraticCurveTo(x + 50, y + 80, x, y); + + + // Arc circle + + var arcShape = new THREE.Shape(); + arcShape.moveTo( 50, 10 ); + arcShape.absarc( 10, 10, 40, 0, Math.PI*2, false ); + + var holePath = new THREE.Path(); + holePath.moveTo( 20, 10 ); + holePath.absarc( 10, 10, 10, 0, Math.PI*2, true ); + arcShape.holes.push( holePath ); + + + // Smiley + + var smileyShape = new THREE.Shape(); + smileyShape.moveTo( 80, 40 ); + smileyShape.absarc( 40, 40, 40, 0, Math.PI*2, false ); + + var smileyEye1Path = new THREE.Path(); + smileyEye1Path.moveTo( 35, 20 ); + // smileyEye1Path.absarc( 25, 20, 10, 0, Math.PI*2, true ); + smileyEye1Path.absellipse( 25, 20, 10, 10, 0, Math.PI*2, true ); + + smileyShape.holes.push( smileyEye1Path ); + + var smileyEye2Path = new THREE.Path(); + smileyEye2Path.moveTo( 65, 20 ); + smileyEye2Path.absarc( 55, 20, 10, 0, Math.PI*2, true ); + smileyShape.holes.push( smileyEye2Path ); + + var smileyMouthPath = new THREE.Path(); + // ugly box mouth + // smileyMouthPath.moveTo( 20, 40 ); + // smileyMouthPath.lineTo( 60, 40 ); + // smileyMouthPath.lineTo( 60, 60 ); + // smileyMouthPath.lineTo( 20, 60 ); + // smileyMouthPath.lineTo( 20, 40 ); + + smileyMouthPath.moveTo( 20, 40 ); + smileyMouthPath.quadraticCurveTo( 40, 60, 60, 40 ); + smileyMouthPath.bezierCurveTo( 70, 45, 70, 50, 60, 60 ); + smileyMouthPath.quadraticCurveTo( 40, 80, 20, 60 ); + smileyMouthPath.quadraticCurveTo( 5, 50, 20, 40 ); + + smileyShape.holes.push( smileyMouthPath ); + + + // Spline shape + path extrusion + + var splinepts = []; + splinepts.push( new THREE.Vector2 ( 350, 100 ) ); + splinepts.push( new THREE.Vector2 ( 400, 450 ) ); + splinepts.push( new THREE.Vector2 ( -140, 350 ) ); + splinepts.push( new THREE.Vector2 ( 0, 0 ) ); + + var splineShape = new THREE.Shape( ); + splineShape.moveTo( 0, 0 ); + splineShape.splineThru( splinepts ); + + + // addShape( shape, color, x, y, z, rx, ry,rz, s ); + + addShape( californiaShape, 0xffaa00, -300, -100, 0, 0, 0, 0, 0.25 ); + addShape( triangleShape, 0xffee00, -180, 0, 0, 0, 0, 0, 1 ); + addShape( roundedRectShape, 0x005500, -150, 150, 0, 0, 0, 0, 1 ); + addShape( squareShape, 0x0055ff, 150, 100, 0, 0, 0, 0, 1 ); + addShape( heartShape, 0xff1100, 60, 100, 0, 0, 0, Math.PI, 1 ); + addShape( circleShape, 0x00ff11, 120, 250, 0, 0, 0, 0, 1 ); + addShape( fishShape, 0x222222, -60, 200, 0, 0, 0, 0, 1 ); + addShape( smileyShape, 0xee00ff, -200, 250, 0, 0, 0, Math.PI, 1 ); + addShape( arcShape, 0xbb4422, 150, 0, 0, 0, 0, 0, 1 ); + addShape( splineShape, 0x888888, -50, -100, 0, 0, 0, 0, 0.2 ); + + // + + renderer = new THREE.CanvasRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = false; + renderer.sortElements = false; + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05; + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_interactive_cubes.html + +()=>{ + var container, stats; + var camera, scene, projector, renderer; + var particleMaterial; + + var objects = []; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - clickable objects'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 300, 500 ); + + scene = new THREE.Scene(); + + var geometry = new THREE.CubeGeometry( 100, 100, 100 ); + + for ( var i = 0; i < 10; i ++ ) { + + var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, opacity: 0.5 } ) ); + object.position.x = Math.random() * 800 - 400; + object.position.y = Math.random() * 800 - 400; + object.position.z = Math.random() * 800 - 400; + + object.scale.x = Math.random() * 2 + 1; + object.scale.y = Math.random() * 2 + 1; + object.scale.z = Math.random() * 2 + 1; + + object.rotation.x = Math.random() * 2 * Math.PI; + object.rotation.y = Math.random() * 2 * Math.PI; + object.rotation.z = Math.random() * 2 * Math.PI; + + scene.add( object ); + + objects.push( object ); + + } + + var PI2 = Math.PI * 2; + particleMaterial = new THREE.ParticleCanvasMaterial( { + + color: 0x000000, + program: function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + } ); + + projector = new THREE.Projector(); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); + projector.unprojectVector( vector, camera ); + + var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() ); + + var intersects = raycaster.intersectObjects( objects ); + + if ( intersects.length > 0 ) { + + var mesh = intersects[ 0 ].object; + var mat = mesh.material; + mat.color.setHex( Math.random() * 0xffffff ); + + var particle = new THREE.Particle( particleMaterial ); + particle.position = intersects[ 0 ].point; + particle.scale.x = particle.scale.y = 8; + scene.add( particle ); + + } + + /* + // Parse all the faces + for ( var i in intersects ) { + + intersects[ i ].face.material[ 0 ].color.setHex( Math.random() * 0xffffff | 0x80000000 ); + + } + */ + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + var radius = 600; + var theta = 0; + + function render() { + + theta += 0.1; + + camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) ); + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_interactive_particles.html + +()=>{ + var container, stats; + var camera, scene, projector, renderer; + + var PI2 = Math.PI * 2; + + var programFill = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + var programStroke = function ( context ) { + + context.lineWidth = 0.05; + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.stroke(); + + } + + var mouse = { x: 0, y: 0 }, INTERSECTED; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js canvas - interactive particles'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 300, 500 ); + + scene = new THREE.Scene(); + + for ( var i = 0; i < 100; i ++ ) { + + var particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808080 + 0x808080, program: programStroke } ) ); + particle.position.x = Math.random() * 800 - 400; + particle.position.y = Math.random() * 800 - 400; + particle.position.z = Math.random() * 800 - 400; + particle.scale.x = particle.scale.y = Math.random() * 10 + 10; + scene.add( particle ); + + } + + projector = new THREE.Projector(); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + event.preventDefault(); + + mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; + mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + var radius = 600; + var theta = 0; + + function render() { + + // rotate camera + + theta += 0.1; + + camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) ); + camera.lookAt( scene.position ); + + // find intersections + + camera.updateMatrixWorld(); + + var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 ); + projector.unprojectVector( vector, camera ); + + var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() ); + + var intersects = raycaster.intersectObjects( scene.children ); + + if ( intersects.length > 0 ) { + + if ( INTERSECTED != intersects[ 0 ].object ) { + + if ( INTERSECTED ) INTERSECTED.material.program = programStroke; + + INTERSECTED = intersects[ 0 ].object; + INTERSECTED.material.program = programFill; + + } + + } else { + + if ( INTERSECTED ) INTERSECTED.material.program = programStroke; + + INTERSECTED = null; + + } + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_camera_orthographic.html + +()=>{ + var container, stats; + var camera, scene, renderer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - orthographic view'; + container.appendChild( info ); + + camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 500, 1000 ); + camera.position.x = 200; + camera.position.y = 100; + camera.position.z = 200; + + scene = new THREE.Scene(); + + // Grid + + var size = 500, step = 50; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, 0, i ) ); + geometry.vertices.push( new THREE.Vector3( size, 0, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, 0, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, 0, size ) ); + + } + + var lineMaterial = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ); + + var line = new THREE.Line( geometry, lineMaterial ); + line.type = THREE.LinePieces; + scene.add( line ); + + // Cubes + + var geometry = new THREE.CubeGeometry( 50, 50, 50 ); + var cubeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ); + + for ( var i = 0; i < 100; i ++ ) { + + var cube = new THREE.Mesh( geometry, cubeMaterial ); + + cube.scale.y = Math.floor( Math.random() * 2 + 1 ); + + cube.position.x = Math.floor( ( Math.random() * 1000 - 500 ) / 50 ) * 50 + 25; + cube.position.y = ( cube.scale.y * 50 ) / 2; + cube.position.z = Math.floor( ( Math.random() * 1000 - 500 ) / 50 ) * 50 + 25; + + scene.add( cube ); + + } + + // Lights + + var ambientLight = new THREE.AmbientLight( Math.random() * 0x10 ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.left = window.innerWidth / - 2; + camera.right = window.innerWidth / 2; + camera.top = window.innerHeight / 2; + camera.bottom = window.innerHeight / - 2; + + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0001; + + camera.position.x = Math.cos( timer ) * 200; + camera.position.z = Math.sin( timer ) * 200; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_interactive_voxelpainter.html + +()=>{ + var container, stats; + var camera, scene, renderer; + var projector, plane; + var mouse2D, mouse3D, raycaster, theta = 45, + isShiftDown = false, isCtrlDown = false, + target = new THREE.Vector3( 0, 200, 0 ); + var ROLLOVERED; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - voxel painter
click: add voxel, control + click: remove voxel, shift: rotate, save .png'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.y = 800; + + scene = new THREE.Scene(); + + // Grid + + var size = 500, step = 50; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, 0, i ) ); + geometry.vertices.push( new THREE.Vector3( size, 0, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, 0, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, 0, size ) ); + + } + + var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ); + + var line = new THREE.Line( geometry, material ); + line.type = THREE.LinePieces; + scene.add( line ); + + // + + projector = new THREE.Projector(); + + plane = new THREE.Mesh( new THREE.PlaneGeometry( 1000, 1000 ), new THREE.MeshBasicMaterial() ); + plane.rotation.x = - Math.PI / 2; + plane.visible = false; + scene.add( plane ); + + mouse2D = new THREE.Vector3( 0, 10000, 0.5 ); + + // Lights + + var ambientLight = new THREE.AmbientLight( 0x606060 ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + var directionalLight = new THREE.DirectionalLight( 0x808080 ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild(renderer.domElement); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'keydown', onDocumentKeyDown, false ); + document.addEventListener( 'keyup', onDocumentKeyUp, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + event.preventDefault(); + + mouse2D.x = ( event.clientX / window.innerWidth ) * 2 - 1; + mouse2D.y = - ( event.clientY / window.innerHeight ) * 2 + 1; + + var intersects = raycaster.intersectObjects( scene.children ); + + if ( intersects.length > 0 ) { + + if ( ROLLOVERED ) ROLLOVERED.color.setHex( 0x00ff80 ); + + ROLLOVERED = intersects[ 0 ].face; + ROLLOVERED.color.setHex( 0xff8000 ) + + } + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + var intersects = raycaster.intersectObjects( scene.children ); + + if ( intersects.length > 0 ) { + + var interect = intersects[ 0 ]; + + if ( isCtrlDown ) { + + if ( interect.object != plane ) { + + scene.remove( interect.object ); + + } + + } else { + + var normal = interect.face.normal.clone(); + normal.applyMatrix4( interect.object.matrixRotationWorld ); + + var position = new THREE.Vector3().addVectors( interect.point, normal ); + + var geometry = new THREE.CubeGeometry( 50, 50, 50 ); + + for ( var i = 0; i < geometry.faces.length; i ++ ) { + + geometry.faces[ i ].color.setHex( 0x00ff80 ); + + } + + var material = new THREE.MeshLambertMaterial( { vertexColors: THREE.FaceColors } ); + + var voxel = new THREE.Mesh( geometry, material ); + voxel.position.x = Math.floor( position.x / 50 ) * 50 + 25; + voxel.position.y = Math.floor( position.y / 50 ) * 50 + 25; + voxel.position.z = Math.floor( position.z / 50 ) * 50 + 25; + voxel.matrixAutoUpdate = false; + voxel.updateMatrix(); + scene.add( voxel ); + + } + + } + } + + function onDocumentKeyDown( event ) { + + switch( event.keyCode ) { + + case 16: isShiftDown = true; break; + case 17: isCtrlDown = true; break; + + } + + } + + function onDocumentKeyUp( event ) { + + switch( event.keyCode ) { + + case 16: isShiftDown = false; break; + case 17: isCtrlDown = false; break; + + } + } + + function save() { + + window.open( renderer.domElement.toDataURL('image/png'), 'mywindow' ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + if ( isShiftDown ) { + + theta += mouse2D.x * 3; + + } + + camera.position.x = 1400 * Math.sin( theta * Math.PI / 360 ); + camera.position.z = 1400 * Math.cos( theta * Math.PI / 360 ); + camera.lookAt( target ); + + raycaster = projector.pickingRay( mouse2D.clone(), camera ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_lights_pointlights.html + +()=>{ + var camera, scene, renderer, + particle1, particle2, particle3, + light1, light2, light3, + loader, mesh; + + init(); + animate(); + + function init() { + + var container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, - 6, 100 ); + + scene = new THREE.Scene(); + + scene.add( new THREE.AmbientLight( 0x00020 ) ); + + light1 = new THREE.PointLight( 0xff0040, 1, 50 ); + scene.add( light1 ); + + light2 = new THREE.PointLight( 0x0040ff, 1, 50 ); + scene.add( light2 ); + + light3 = new THREE.PointLight( 0x80ff80, 1, 50 ); + scene.add( light3 ); + + var PI2 = Math.PI * 2; + var program = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.fill(); + + } + + particle1 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0xff0040, program: program } ) ); + particle1.scale.x = particle1.scale.y = particle1.scale.z = 0.5; + scene.add( particle1 ); + + particle2 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x0040ff, program: program } ) ); + particle2.scale.x = particle2.scale.y = particle2.scale.z = 0.5; + scene.add( particle2 ); + + particle3 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x80ff80, program: program } ) ); + particle3.scale.x = particle3.scale.y = particle3.scale.z = 0.5; + scene.add( particle3 ); + + loader = new THREE.JSONLoader(); + loader.load( 'obj/WaltHeadLo.js', function ( geometry ) { + + mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ) ); + scene.add( mesh ); + + } ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + render(); + + } + + function render() { + + var time = Date.now() * 0.0005; + + if ( mesh ) mesh.rotation.y -= 0.01; + + particle1.position.x = Math.sin( time * 0.7 ) * 30; + particle1.position.y = Math.cos( time * 0.5 ) * 40; + particle1.position.z = Math.cos( time * 0.3 ) * 30; + + light1.position.x = particle1.position.x; + light1.position.y = particle1.position.y; + light1.position.z = particle1.position.z; + + particle2.position.x = Math.cos( time * 0.3 ) * 30; + particle2.position.y = Math.sin( time * 0.5 ) * 40; + particle2.position.z = Math.sin( time * 0.7 ) * 30; + + light2.position.x = particle2.position.x; + light2.position.y = particle2.position.y; + light2.position.z = particle2.position.z; + + particle3.position.x = Math.sin( time * 0.7 ) * 30; + particle3.position.y = Math.cos( time * 0.3 ) * 40; + particle3.position.z = Math.sin( time * 0.5 ) * 30; + + light3.position.x = particle3.position.x; + light3.position.y = particle3.position.y; + light3.position.z = particle3.position.z; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_lights_pointlights_smooth.html + +()=>{ + var camera, scene, renderer, + particle1, particle2, particle3, + light1, light2, light3, + loader, mesh; + + init(); + animate(); + + function init() { + + var container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, - 6, 100 ); + + scene = new THREE.Scene(); + + scene.add( new THREE.AmbientLight( 0x00020 ) ); + + light1 = new THREE.PointLight( 0xff0040, 1, 50 ); + scene.add( light1 ); + + light2 = new THREE.PointLight( 0x0040ff, 1, 50 ); + scene.add( light2 ); + + light3 = new THREE.PointLight( 0x80ff80, 1, 50 ); + scene.add( light3 ); + + var PI2 = Math.PI * 2; + var program = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.fill(); + + } + + particle1 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0xff0040, program: program } ) ); + particle1.scale.x = particle1.scale.y = particle1.scale.z = 0.5; + scene.add( particle1 ); + + particle2 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x0040ff, program: program } ) ); + particle2.scale.x = particle2.scale.y = particle2.scale.z = 0.5; + scene.add( particle2 ); + + particle3 = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0x80ff80, program: program } ) ); + particle3.scale.x = particle3.scale.y = particle3.scale.z = 0.5; + scene.add( particle3 ); + + loader = new THREE.JSONLoader(); + loader.load( 'obj/WaltHeadLo.js', function ( geometry ) { + + geometry.computeVertexNormals(); + + mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0xffffff, overdraw: true } ) ); + scene.add( mesh ); + + } ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + var time = Date.now() * 0.0005; + + if ( mesh ) mesh.rotation.y -= 0.01; + + particle1.position.x = Math.sin( time * 0.7 ) * 30; + particle1.position.y = Math.cos( time * 0.5 ) * 40; + particle1.position.z = Math.cos( time * 0.3 ) * 30; + + light1.position.x = particle1.position.x; + light1.position.y = particle1.position.y; + light1.position.z = particle1.position.z; + + particle2.position.x = Math.cos( time * 0.3 ) * 30; + particle2.position.y = Math.sin( time * 0.5 ) * 40; + particle2.position.z = Math.sin( time * 0.7 ) * 30; + + light2.position.x = particle2.position.x; + light2.position.y = particle2.position.y; + light2.position.z = particle2.position.z; + + particle3.position.x = Math.sin( time * 0.7 ) * 30; + particle3.position.y = Math.cos( time * 0.3 ) * 40; + particle3.position.z = Math.sin( time * 0.5 ) * 30; + + light3.position.x = particle3.position.x; + light3.position.y = particle3.position.y; + light3.position.z = particle3.position.z; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_lines.html + +()=>{ + + var mouseX = 0, mouseY = 0, + + windowHalfX = window.innerWidth / 2, + windowHalfY = window.innerHeight / 2, + + SEPARATION = 200, + AMOUNTX = 10, + AMOUNTY = 10, + + camera, scene, renderer; + + init(); + animate(); + + function init() { + + var container, separation = 100, amountX = 50, amountY = 50, + particles, particle; + + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 100; + + scene = new THREE.Scene(); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + // particles + + var PI2 = Math.PI * 2; + var material = new THREE.ParticleCanvasMaterial( { + + color: 0xffffff, + program: function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + } ); + + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < 100; i ++ ) { + + particle = new THREE.Particle( material ); + particle.position.x = Math.random() * 2 - 1; + particle.position.y = Math.random() * 2 - 1; + particle.position.z = Math.random() * 2 - 1; + particle.position.normalize(); + particle.position.multiplyScalar( Math.random() * 10 + 450 ); + particle.scale.x = particle.scale.y = 5; + scene.add( particle ); + + geometry.vertices.push( particle.position ); + + } + + // lines + + var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.5 } ) ); + scene.add( line ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseMove(event) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length > 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_lines_sphere.html + +()=>{ + + var SCREEN_WIDTH = window.innerWidth, + SCREEN_HEIGHT = window.innerHeight, + + mouseX = 0, mouseY = 0, + + windowHalfX = window.innerWidth / 2, + windowHalfY = window.innerHeight / 2, + + SEPARATION = 200, + AMOUNTX = 10, + AMOUNTY = 10, + + camera, scene, renderer; + + init(); + animate(); + + function init() { + + var container, separation = 100, amountX = 50, amountY = 50, + particles, particle; + + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( renderer.domElement ); + + // particles + + var PI2 = Math.PI * 2; + var material = new THREE.ParticleCanvasMaterial( { + + color: 0xffffff, + program: function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + } ); + + for ( var i = 0; i < 1000; i ++ ) { + + particle = new THREE.Particle( material ); + particle.position.x = Math.random() * 2 - 1; + particle.position.y = Math.random() * 2 - 1; + particle.position.z = Math.random() * 2 - 1; + particle.position.normalize(); + particle.position.multiplyScalar( Math.random() * 10 + 450 ); + scene.add( particle ); + + } + + // lines + + for (var i = 0; i < 300; i++) { + + var geometry = new THREE.Geometry(); + + var vertex = new THREE.Vector3( Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1 ); + vertex.normalize(); + vertex.multiplyScalar( 450 ); + + geometry.vertices.push( vertex ); + + var vertex2 = vertex.clone(); + vertex2.multiplyScalar( Math.random() * 0.3 + 1 ); + + geometry.vertices.push( vertex2 ); + + var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xffffff, opacity: Math.random() } ) ); + scene.add( line ); + } + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseMove(event) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length > 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_materials.html + +()=>{ + + var container, stats; + + var camera, scene, renderer, objects; + var particleLight, pointLight; + + init(); + animate(); + + function init() { + + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 0, 200, 800 ); + + scene = new THREE.Scene(); + + // Grid + + var size = 500, step = 100; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, - 120, i ) ); + geometry.vertices.push( new THREE.Vector3( size, - 120, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, - 120, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, - 120, size ) ); + + } + + var material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.2 } ); + + var line = new THREE.Line( geometry, material ); + line.type = THREE.LinePieces; + scene.add( line ); + + // Spheres + + var geometry = new THREE.SphereGeometry( 100, 14, 7 ); + + var materials:THREE.Material[] = [ + + new THREE.MeshBasicMaterial( { color: 0x00ffff, wireframe: true, side: THREE.DoubleSide } ), + new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.AdditiveBlending, side: THREE.DoubleSide } ), + new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, side: THREE.DoubleSide, overdraw: true } ), + new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.SmoothShading, overdraw: true } ), + new THREE.MeshDepthMaterial( { overdraw: true } ), + new THREE.MeshNormalMaterial( { overdraw: true } ), + new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading, overdraw: true } ), + new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'textures/land_ocean_ice_cloud_2048.jpg' ) } ), + new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'textures/envmap.png', new THREE.SphericalReflectionMapping() ) } ) + + ]; + + for ( var i = 0, l = geometry.faces.length; i < l; i ++ ) { + + var face = geometry.faces[ i ]; + if ( Math.random() > 0.5 ) face.materialIndex = Math.floor( Math.random() * materials.length ); + + } + + materials.push( new THREE.MeshFaceMaterial( materials ) ); + + objects = []; + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + var sphere = new THREE.Mesh( geometry, materials[ i ] ); + + sphere.position.x = ( i % 5 ) * 200 - 400; + sphere.position.z = Math.floor( i / 5 ) * 200 - 200; + + sphere.rotation.x = Math.random() * 200 - 100; + sphere.rotation.y = Math.random() * 200 - 100; + sphere.rotation.z = Math.random() * 200 - 100; + + objects.push( sphere ); + + scene.add( sphere ); + + } + + var PI2 = Math.PI * 2; + var program = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + particleLight = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: 0xffffff, program: program } ) ); + particleLight.scale.x = particleLight.scale.y = particleLight.scale.z = 4; + scene.add( particleLight ); + + // Lights + + scene.add( new THREE.AmbientLight( Math.random() * 0x202020 ) ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffffff, 1 ); + scene.add( pointLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + var debugCanvas:HTMLCanvasElement = document.createElement( 'canvas' ); + debugCanvas.width = 512; + debugCanvas.height = 512; + debugCanvas.style.position = 'absolute'; + debugCanvas.style.top = '0px'; + debugCanvas.style.left = '0px'; + + container.appendChild( debugCanvas ); + + var debugContext = debugCanvas.getContext( '2d' ); + debugContext.setTransform( 1, 0, 0, 1, 256, 256 ); + debugContext.strokeStyle = '#000000'; + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild(stats.domElement); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function loadImage( path ) { + + var image:HTMLImageElement = document.createElement( 'img' ); + var texture = new THREE.Texture( image, new THREE.UVMapping() ) + + image.onload = function () { texture.needsUpdate = true; }; + image.src = path; + + return texture; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0001; + + camera.position.x = Math.cos( timer ) * 1000; + camera.position.z = Math.sin( timer ) * 1000; + camera.lookAt( scene.position ); + + for ( var i = 0, l = objects.length; i < l; i++ ) { + + var object = objects[ i ]; + + object.rotation.x += 0.01; + object.rotation.y += 0.005; + + } + + particleLight.position.x = Math.sin( timer * 7 ) * 300; + particleLight.position.y = Math.cos( timer * 5 ) * 400; + particleLight.position.z = Math.cos( timer * 3 ) * 300; + + pointLight.position.x = particleLight.position.x; + pointLight.position.y = particleLight.position.y; + pointLight.position.z = particleLight.position.z; + + renderer.render( scene, camera ); + + } + +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_materials_depth.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var cube, plane, objects = []; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var moveForward = false; + var moveBackwards = false; + var moveLeft = false; + var moveRight = false; + var moveUp = false; + var moveDown = false; + + var targetMoveLeft = false; + var targetMoveRight = false; + + var debugContext; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 1000, 1000, 1000 ); + camera.target = new THREE.Vector3( 0, 150, 0 ); + + scene = new THREE.Scene(); + + // Plane + + var material = new THREE.MeshDepthMaterial( { side: THREE.DoubleSide, overdraw: true } ); + + plane = new THREE.Mesh( new THREE.PlaneGeometry( 1000, 1000, 10, 10 ), material ); + plane.position.y = - 100; + plane.rotation.x = - Math.PI / 2; + scene.add( plane ); + + // Cubes + + var geometry = new THREE.CubeGeometry( 100, 100, 100 ); + material = new THREE.MeshDepthMaterial( { overdraw: true } ); + + for ( var i = 0; i < 20; i ++ ) { + + cube = new THREE.Mesh( geometry, material ); + + cube.position.x = ( i % 5 ) * 200 - 400; + cube.position.z = Math.floor( i / 5 ) * 200 - 350; + + cube.rotation.x = Math.random() * 200 - 100; + cube.rotation.y = Math.random() * 200 - 100; + cube.rotation.z = Math.random() * 200 - 100; + + scene.add( cube ); + + objects.push( cube ); + + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + var debugCanvas = document.createElement( 'canvas' ); + debugCanvas.width = 512; + debugCanvas.height = 512; + debugCanvas.style.position = 'absolute'; + debugCanvas.style.top = '0px'; + debugCanvas.style.left = '0px'; + + container.appendChild( debugCanvas ); + + debugContext = debugCanvas.getContext( '2d' ); + debugContext.setTransform( 1, 0, 0, 1, 256, 256 ); + debugContext.strokeStyle = '#808080'; + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild(stats.domElement); + + document.addEventListener( 'keydown', onDocumentKeyDown, false ); + document.addEventListener( 'keyup', onDocumentKeyUp, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentKeyDown( event ) { + + switch ( event.keyCode ) { + + case 38: moveForward = true; break; // up + case 40: moveBackwards = true; break; // down + case 37: moveLeft = true; break; // left + case 39: moveRight = true; break; // right + case 87: moveUp = true; break; // w + case 83: moveDown = true; break; // s + case 65: targetMoveLeft = true; break; // a + case 68: targetMoveRight = true; break; // d + + } + + } + + function onDocumentKeyUp( event ) { + + switch ( event.keyCode ) { + + case 38: moveForward = false; break; // up + case 40: moveBackwards = false; break; // down + case 37: moveLeft = false; break; // left + case 39: moveRight = false; break; // right + case 87: moveUp = false; break; // w + case 83: moveDown = false; break; // s + case 65: targetMoveLeft = false; break; // a + case 68: targetMoveRight = false; break; // d + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + if ( moveForward ) camera.position.z -= 10; + if ( moveBackwards ) camera.position.z += 10; + + if ( moveLeft ) camera.position.x -= 10; + if ( moveRight ) camera.position.x += 10; + + if ( moveUp ) camera.position.y += 10; + if ( moveDown ) camera.position.y -= 10; + + if ( targetMoveLeft ) camera.target.x -= 10; + if ( targetMoveRight ) camera.target.x += 10; + + camera.lookAt( camera.target ); + + debugContext.clearRect( - 256, - 256, 512, 512 ); + + debugContext.beginPath(); + + // center + debugContext.moveTo( - 10, 0 ); + debugContext.lineTo( 10, 0 ); + debugContext.moveTo( 0, - 10 ); + debugContext.lineTo( 0, 10 ); + + // camera + + debugContext.moveTo( camera.position.x * 0.1, camera.position.z * 0.1 ); + debugContext.lineTo( camera.target.x * 0.1, camera.target.z * 0.1 ); + debugContext.rect( camera.position.x * 0.1 - 5, camera.position.z * 0.1 - 5, 10, 10 ); + debugContext.rect( camera.target.x * 0.1 - 5, camera.target.z * 0.1 - 5, 10, 10 ); + debugContext.rect( - 50, - 50, 100, 100 ); + + for ( var i = 0; i < objects.length; i++ ) { + + var object = objects[ i ]; + + object.rotation.x += 0.01; + object.rotation.y += 0.005; + object.position.y = Math.sin( object.rotation.x ) * 200 + 200; + + debugContext.rect( object.position.x * 0.1 - 5, object.position.z * 0.1 - 5, 10, 10 ); + + } + + debugContext.closePath(); + debugContext.stroke(); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_materials_normal.html + +()=>{ + var camera, scene, renderer, + loader, mesh; + + init(); + animate(); + + function init() { + + var container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 0, - 6, 100 ); + + scene = new THREE.Scene(); + + loader = new THREE.JSONLoader(); + loader.load( 'obj/WaltHeadLo.js', function ( geometry ) { + + mesh = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial( { overdraw: true } ) ); + scene.add( mesh ); + + } ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + render(); + + } + + function render() { + + var time = Date.now() * 0.0005; + + if ( mesh ) { + + mesh.rotation.x -= 0.005; + mesh.rotation.y -= 0.01; + + } + + renderer.render( scene, camera ); + + } +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_materials_reflection.html + +()=>{ + + var camera, scene, renderer, + particle1, particle2, particle2, + light1, light2, light3, + loader, mesh; + + init(); + animate(); + + function init() { + + var container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, - 6, 100 ); + + scene = new THREE.Scene(); + + loader = new THREE.JSONLoader(); + loader.load( 'obj/WaltHeadLo.js', function ( geometry ) { + + geometry.computeVertexNormals(); + + mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'textures/metal.jpg', new THREE.SphericalReflectionMapping() ), overdraw: true } ) ); + scene.add( mesh ); + + } ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + var time = Date.now() * 0.0005; + + if ( mesh ) mesh.rotation.y -= 0.01; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_materials_video.html + +()=>{ + var AMOUNT = 100; + + var container, stats; + + var camera, scene, renderer; + + var video, image, imageContext, + imageReflection, imageReflectionContext, imageReflectionGradient, + texture, textureReflection; + + var mesh; + + var mouseX = 0; + var mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - video demo. playing sintel trailer'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + video = document.getElementById( 'video' ); + + // + + image = document.createElement( 'canvas' ); + image.width = 480; + image.height = 204; + + imageContext = image.getContext( '2d' ); + imageContext.fillStyle = '#000000'; + imageContext.fillRect( 0, 0, 480, 204 ); + + texture = new THREE.Texture( image ); + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.LinearFilter; + + var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } ); + + imageReflection = document.createElement( 'canvas' ); + imageReflection.width = 480; + imageReflection.height = 204; + + imageReflectionContext = imageReflection.getContext( '2d' ); + imageReflectionContext.fillStyle = '#000000'; + imageReflectionContext.fillRect( 0, 0, 480, 204 ); + + imageReflectionGradient = imageReflectionContext.createLinearGradient( 0, 0, 0, 204 ); + imageReflectionGradient.addColorStop( 0.2, 'rgba(240, 240, 240, 1)' ); + imageReflectionGradient.addColorStop( 1, 'rgba(240, 240, 240, 0.8)' ); + + textureReflection = new THREE.Texture( imageReflection ); + textureReflection.minFilter = THREE.LinearFilter; + textureReflection.magFilter = THREE.LinearFilter; + + var materialReflection = new THREE.MeshBasicMaterial( { map: textureReflection, side: THREE.BackSide, overdraw: true } ); + + // + + var plane = new THREE.PlaneGeometry( 480, 204, 4, 4 ); + + mesh = new THREE.Mesh( plane, material ); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 1.5; + scene.add(mesh); + + mesh = new THREE.Mesh( plane, materialReflection ); + mesh.position.y = -306; + mesh.rotation.x = - Math.PI; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 1.5; + scene.add( mesh ); + + // + + var separation = 150; + var amountx = 10; + var amounty = 10; + + var PI2 = Math.PI * 2; + var materialParticle = new THREE.ParticleCanvasMaterial( { + + color: 0x0808080, + program: function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + } ); + + for ( var ix = 0; ix < amountx; ix++ ) { + + for ( var iy = 0; iy < amounty; iy++ ) { + + var particle = new THREE.Particle( materialParticle ); + particle.position.x = ix * separation - ( ( amountx * separation ) / 2 ); + particle.position.y = -153 + particle.position.z = iy * separation - ( ( amounty * separation ) / 2 ); + scene.add( particle ); + + } + + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ) * 0.2; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + camera.lookAt( scene.position ); + + if ( video.readyState === video.HAVE_ENOUGH_DATA ) { + + imageContext.drawImage( video, 0, 0 ); + + if ( texture ) texture.needsUpdate = true; + if ( textureReflection ) textureReflection.needsUpdate = true; + + } + + imageReflectionContext.drawImage( image, 0, 0 ); + imageReflectionContext.fillStyle = imageReflectionGradient; + imageReflectionContext.fillRect( 0, 0, 480, 204 ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_particles_floor.html + +()=>{ + var SEPARATION = 100; + var AMOUNTX = 50; + var AMOUNTY = 50; + + var container, stats; + var camera, scene, renderer, particle; + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + var material = new THREE.ParticleBasicMaterial(); + + for ( var ix = 0; ix < AMOUNTX; ix++ ) { + + for ( var iy = 0; iy < AMOUNTY; iy++ ) { + + particle = new THREE.Particle( material ); + particle.scale.y = 4; + particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 ); + particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 ); + scene.add( particle ); + } + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length > 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + } + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_particles_random.html + +()=>{ + var container, stats; + var camera, scene, renderer, group, particle; + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 3000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + var PI2 = Math.PI * 2; + var program = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + group = new THREE.Object3D(); + scene.add( group ); + + for ( var i = 0; i < 1000; i++ ) { + + particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808008 + 0x808080, program: program } ) ); + particle.position.x = Math.random() * 2000 - 1000; + particle.position.y = Math.random() * 2000 - 1000; + particle.position.z = Math.random() * 2000 - 1000; + particle.scale.x = particle.scale.y = Math.random() * 10 + 5; + group.add( particle ); + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + camera.lookAt( scene.position ); + + group.rotation.x += 0.01; + group.rotation.y += 0.02; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_particles_sprites.html + +()=>{ + var container, stats; + var camera, scene, renderer, particle; + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + var material = new THREE.ParticleBasicMaterial( { map: new THREE.Texture( generateSprite() ), blending: THREE.AdditiveBlending } ); + + for ( var i = 0; i < 1000; i++ ) { + + particle = new THREE.Particle( material ); + + initParticle( particle, i * 10 ); + + scene.add( particle ); + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortElements = false; + renderer.setClearColorHex( 0x0000ff, 0.25 ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function generateSprite() { + + var canvas = document.createElement( 'canvas' ); + canvas.width = 16; + canvas.height = 16; + + var context = canvas.getContext( '2d' ); + var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 ); + gradient.addColorStop( 0, 'rgba(255,255,255,1)' ); + gradient.addColorStop( 0.2, 'rgba(0,255,255,1)' ); + gradient.addColorStop( 0.4, 'rgba(0,0,64,1)' ); + gradient.addColorStop( 1, 'rgba(0,0,0,1)' ); + + context.fillStyle = gradient; + context.fillRect( 0, 0, canvas.width, canvas.height ); + + return canvas; + + } + + function initParticle( particle, delay ) { + + var particle = this instanceof THREE.Particle ? this : particle; + var delay = delay !== undefined ? delay : 0; + + particle.position.x = 0; + particle.position.y = 0; + particle.position.z = 0; + particle.scale.x = particle.scale.y = Math.random() * 3 + 1; + + new TWEEN.Tween( particle ) + .delay( delay ) + .to( {}, 10000 ) + .onComplete( initParticle ) + .start(); + + new TWEEN.Tween( particle.position ) + .delay( delay ) + .to( { x: Math.random() * 4000 - 2000, y: Math.random() * 1000 - 500, z: Math.random() * 4000 - 2000 }, 10000 ) + .start(); + + new TWEEN.Tween( particle.scale ) + .delay( delay ) + .to( { x: 0, y: 0 }, 10000 ) + .start(); + + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + TWEEN.update(); + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +var container, stats; + var camera, scene, renderer, particle; + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + var material = new THREE.ParticleBasicMaterial( { map: new THREE.Texture( generateSprite() ), blending: THREE.AdditiveBlending } ); + + for ( var i = 0; i < 1000; i++ ) { + + particle = new THREE.Particle( material ); + + initParticle( particle, i * 10 ); + + scene.add( particle ); + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortElements = false; + renderer.setClearColorHex( 0x0000ff, 0.25 ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function generateSprite() { + + var canvas = document.createElement( 'canvas' ); + canvas.width = 16; + canvas.height = 16; + + var context = canvas.getContext( '2d' ); + var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 ); + gradient.addColorStop( 0, 'rgba(255,255,255,1)' ); + gradient.addColorStop( 0.2, 'rgba(0,255,255,1)' ); + gradient.addColorStop( 0.4, 'rgba(0,0,64,1)' ); + gradient.addColorStop( 1, 'rgba(0,0,0,1)' ); + + context.fillStyle = gradient; + context.fillRect( 0, 0, canvas.width, canvas.height ); + + return canvas; + + } + + function initParticle( particle, delay ) { + + var particle = this instanceof THREE.Particle ? this : particle; + var delay = delay !== undefined ? delay : 0; + + particle.position.x = 0; + particle.position.y = 0; + particle.position.z = 0; + particle.scale.x = particle.scale.y = Math.random() * 3 + 1; + + new TWEEN.Tween( particle ) + .delay( delay ) + .to( {}, 10000 ) + .onComplete( initParticle ) + .start(); + + new TWEEN.Tween( particle.position ) + .delay( delay ) + .to( { x: Math.random() * 4000 - 2000, y: Math.random() * 1000 - 500, z: Math.random() * 4000 - 2000 }, 10000 ) + .start(); + + new TWEEN.Tween( particle.scale ) + .delay( delay ) + .to( { x: 0, y: 0 }, 10000 ) + .start(); + + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + TWEEN.update(); + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_particles_waves.html + +()=>{ + var SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50; + + var container, stats; + var camera, scene, renderer; + + var particles, particle, count = 0; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + particles = new Array(); + + var PI2 = Math.PI * 2; + var material = new THREE.ParticleCanvasMaterial( { + + color: 0xffffff, + program: function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.fill(); + + } + + } ); + + var i = 0; + + for ( var ix = 0; ix < AMOUNTX; ix ++ ) { + + for ( var iy = 0; iy < AMOUNTY; iy ++ ) { + + particle = particles[ i ++ ] = new THREE.Particle( material ); + particle.position.x = ix * SEPARATION - ( ( AMOUNTX * SEPARATION ) / 2 ); + particle.position.z = iy * SEPARATION - ( ( AMOUNTY * SEPARATION ) / 2 ); + scene.add( particle ); + + } + + } + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + var i = 0; + + for ( var ix = 0; ix < AMOUNTX; ix ++ ) { + + for ( var iy = 0; iy < AMOUNTY; iy ++ ) { + + particle = particles[ i++ ]; + particle.position.y = ( Math.sin( ( ix + count ) * 0.3 ) * 50 ) + ( Math.sin( ( iy + count ) * 0.5 ) * 50 ); + particle.scale.x = particle.scale.y = ( Math.sin( ( ix + count ) * 0.3 ) + 1 ) * 2 + ( Math.sin( ( iy + count ) * 0.5 ) + 1 ) * 2; + + } + + } + + renderer.render( scene, camera ); + + count += 0.1; + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_performance.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var sphere, plane; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 1000, 1000 ); + + scene = new THREE.Scene(); + + // Grid + + var size = 500, step = 100; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, 0, i ) ); + geometry.vertices.push( new THREE.Vector3( size, 0, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, 0, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, 0, size ) ); + + } + + var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.5 } ); + + var line = new THREE.Line( geometry, material ); + line.type = THREE.LinePieces; + scene.add( line ); + + // Spheres + + geometry = new THREE.SphereGeometry( 100, 26, 18 ); + var materialLambert = new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ); + + for ( var i = 0; i < 20; i ++ ) { + + sphere = new THREE.Mesh( geometry, materialLambert ); + + sphere.position.x = ( i % 5 ) * 200 - 400; + sphere.position.z = Math.floor( i / 5 ) * 200 - 400; + + scene.add( sphere ); + + } + + // Lights + + var ambientLight = new THREE.AmbientLight( Math.random() * 0x202020 ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.set( 0, 1, 0 ); + scene.add( directionalLight ); + + var pointLight = new THREE.PointLight( 0xff0000, 1, 500 ); + scene.add( pointLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild(stats.domElement); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/canvas_sandbox.html + +()=>{ + var container, stats; + + var camera, scene, renderer, objects; + var pointLight; + + var sphere; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var moveForward = false; + var moveBackwards = false; + var moveLeft = false; + var moveRight = false; + var moveUp = false; + var moveDown = false; + + var targetMoveLeft = false; + var targetMoveRight = false; + + var debugContext; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 150, 400 ); + camera.target = new THREE.Vector3( 0, 150, 0 ); + + scene = new THREE.Scene(); + + + // Grid + + var size = 500, step = 100; + + var geometry = new THREE.Geometry(); + + for ( var i = - size; i <= size; i += step ) { + + geometry.vertices.push( new THREE.Vector3( - size, 0, i ) ); + geometry.vertices.push( new THREE.Vector3( size, 0, i ) ); + + geometry.vertices.push( new THREE.Vector3( i, 0, - size ) ); + geometry.vertices.push( new THREE.Vector3( i, 0, size ) ); + + } + + var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.5 } ); + + var line = new THREE.Line( geometry, material ); + line.type = THREE.LinePieces; + scene.add( line ); + + // Spheres + + objects = []; + + geometry = new THREE.IcosahedronGeometry( 100, 1 ); + + var materialBasic = new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'textures/metal.jpg', new THREE.SphericalReflectionMapping() ), overdraw: true } ); + + for ( var i = 0; i < 10; i ++ ) { + + sphere = new THREE.Mesh( geometry, materialBasic ); + + sphere.position.x = Math.random() * 1000 - 500; + sphere.position.y = Math.random() * 1000 - 500; + sphere.position.z = Math.random() * 1000 - 500; + + sphere.rotation.x = Math.random() * 200 - 100; + sphere.rotation.y = Math.random() * 200 - 100; + sphere.rotation.z = Math.random() * 200 - 100; + + sphere.scale.x = sphere.scale.y = sphere.scale.z = Math.random() + 0.5; + + objects.push( sphere ); + + scene.add( sphere ); + + } + + // Lights + + var ambientLight = new THREE.AmbientLight( Math.random() * 0x202020 ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( Math.random() * 0xffffff ); + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + directionalLight.position.normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xff0000, 1 ); + scene.add( pointLight ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + var debugCanvas = document.createElement( 'canvas' ); + debugCanvas.width = 512; + debugCanvas.height = 512; + debugCanvas.style.position = 'absolute'; + debugCanvas.style.top = '0px'; + debugCanvas.style.left = '0px'; + + container.appendChild( debugCanvas ); + + debugContext = debugCanvas.getContext( '2d' ); + debugContext.setTransform( 1, 0, 0, 1, 256, 256 ); + debugContext.strokeStyle = '#000000'; + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild(stats.domElement); + + document.addEventListener( 'keydown', onDocumentKeyDown, false ); + document.addEventListener( 'keyup', onDocumentKeyUp, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentKeyDown( event ) { + + switch ( event.keyCode ) { + + case 38: moveForward = true; break; // up + case 40: moveBackwards = true; break; // down + case 37: moveLeft = true; break; // left + case 39: moveRight = true; break; // right + case 87: moveUp = true; break; // w + case 83: moveDown = true; break; // s + case 65: targetMoveLeft = true; break; // a + case 68: targetMoveRight = true; break; // d + + } + + } + + function onDocumentKeyUp( event ) { + + switch ( event.keyCode ) { + + case 38: moveForward = false; break; // up + case 40: moveBackwards = false; break; // down + case 37: moveLeft = false; break; // left + case 39: moveRight = false; break; // right + case 87: moveUp = false; break; // w + case 83: moveDown = false; break; // s + case 65: targetMoveLeft = false; break; // a + case 68: targetMoveRight = false; break; // d + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + if ( moveForward ) camera.position.z -= 10; + if ( moveBackwards ) camera.position.z += 10; + + if ( moveLeft ) camera.position.x -= 10; + if ( moveRight ) camera.position.x += 10; + + if ( moveUp ) camera.position.y += 10; + if ( moveDown ) camera.position.y -= 10; + + if ( targetMoveLeft ) camera.target.x -= 10; + if ( targetMoveRight ) camera.target.x += 10; + + camera.lookAt( camera.target ); + + debugContext.clearRect( -256, -256, 512, 512 ); + + debugContext.beginPath(); + + // center + debugContext.moveTo( -10, 0 ); + debugContext.lineTo( 10, 0 ); + debugContext.moveTo( 0, -10 ); + debugContext.lineTo( 0, 10 ); + + // camera + + debugContext.moveTo( camera.position.x * 0.1, camera.position.z * 0.1 ); + debugContext.lineTo( camera.target.x * 0.1, camera.target.z * 0.1 ); + debugContext.rect( camera.position.x * 0.1 - 5, camera.position.z * 0.1 - 5, 10, 10 ); + debugContext.rect( camera.target.x * 0.1 - 5, camera.target.z * 0.1 - 5, 10, 10 ); + debugContext.rect( - 50, - 50, 100, 100 ); + + for ( var i = 0, l = objects.length; i < l; i++ ) { + + var object = objects[ i ]; + + object.rotation.x += 0.01; + object.rotation.y += 0.005; + object.position.y = Math.sin( object.rotation.x ) * 200; + + debugContext.rect( object.position.x * 0.1 - 5, object.position.z * 0.1 - 5, 10, 10 ); + + } + + + debugContext.closePath(); + debugContext.stroke(); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/css3d_molecules.html + +()=>{ + var camera, scene, renderer; + var controls; + var root; + + var objects = []; + var tmpVec1 = new THREE.Vector3(); + var tmpVec2 = new THREE.Vector3(); + var tmpVec3 = new THREE.Vector3(); + var tmpVec4 = new THREE.Vector3(); + + var visualizationType = 2; + + var MOLECULES = { + "Ethanol" :"ethanol.pdb", + "Aspirin" :"aspirin.pdb", + "Caffeine" :"caffeine.pdb", + "Nicotine" :"nicotine.pdb", + "LSD" :"lsd.pdb", + "Cocaine" :"cocaine.pdb", + "Cholesterol" :"cholesterol.pdb", + "Lycopene" :"lycopene.pdb", + "Glucose" : "glucose.pdb", + "Aluminium oxide":"Al2O3.pdb", + "Cubane" :"cubane.pdb", + "Copper" :"cu.pdb", + "Fluorite" :"caf2.pdb", + "Salt" :"nacl.pdb", + "YBCO superconductor":"ybco.pdb", + "Buckyball" : "buckyball.pdb", + //"Diamond" :"diamond.pdb", + "Graphite" :"graphite.pdb" + }; + + var loader = new THREE.PDBLoader(); + var colorSpriteMap = {}; + var baseSprite = document.createElement( 'img' ); + + var menu = document.getElementById( "menu" ); + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.z = 1500; + + scene = new THREE.Scene(); + + root = new THREE.Object3D(); + scene.add( root ); + + // + + renderer = new THREE.CSS3DRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.getElementById( 'container' ).appendChild( renderer.domElement ); + + // + + controls = new THREE.TrackballControls( camera, renderer.domElement ); + controls.rotateSpeed = 0.5; + controls.addEventListener( 'change', render ); + + // + + baseSprite.onload = function () { + + loadMolecule( "models/molecules/caffeine.pdb" ); + createMenu(); + + }; + + baseSprite.src = 'textures/sprites/ball.png'; + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + // + + function generateButtonCallback( url ) { + + return function ( event ) { + + loadMolecule( url ); + + } + + } + + function createMenu() { + + for ( var m in MOLECULES ) { + + var button = document.createElement( 'button' ); + button.innerHTML = m; + menu.appendChild( button ); + + var url = "models/molecules/" + MOLECULES[ m ]; + + button.addEventListener( 'click', generateButtonCallback( url ), false ); + + } + + var b_a = document.getElementById( "b_a" ); + var b_b = document.getElementById( "b_b" ); + var b_ab = document.getElementById( "b_ab" ); + + b_a.addEventListener( 'click', function() { visualizationType = 0; showAtoms() } ); + b_b.addEventListener( 'click', function() { visualizationType = 1; showBonds() } ); + b_ab.addEventListener( 'click', function() { visualizationType = 2; showAtomsBonds() } ); + + } + + // + + function showAtoms() { + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + + if ( object instanceof THREE.CSS3DSprite ) { + + object.element.style.display = ""; + object.visible = true; + + } else { + + object.element.style.display = "none"; + object.visible = false; + + } + + } + + } + + function showBonds() { + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + + if ( object instanceof THREE.CSS3DSprite ) { + + object.element.style.display = "none"; + object.visible = false; + + } else { + + object.element.style.display = ""; + object.element.style.height = object.properties.bondLengthFull; + object.visible = true; + + } + + } + + } + + function showAtomsBonds() { + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + + object.element.style.display = ""; + object.visible = true; + + if ( ! ( object instanceof THREE.CSS3DSprite ) ) { + + object.element.style.height = object.properties.bondLengthShort; + + } + + } + + } + + // + + function colorify( ctx, width, height, color, a ) { + + var r = color.r; + var g = color.g; + var b = color.b; + + var imageData = ctx.getImageData( 0, 0, width, height ); + var data = imageData.data; + + for ( var y = 0; y < height; y ++ ) { + + for ( var x = 0; x < width; x ++ ) { + + var index = ( y * width + x ) * 4; + + data[ index ] *= r; + data[ index + 1 ] *= g; + data[ index + 2 ] *= b; + data[ index + 3 ] *= a; + + } + + } + + ctx.putImageData( imageData, 0, 0 ); + + } + + function imageToCanvas( image ) { + + var width = image.width; + var height = image.height; + + var canvas = document.createElement( 'canvas' ); + + canvas.width = width; + canvas.height = height; + + var context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, width, height ); + + return canvas; + + } + + // + + function loadMolecule( url ) { + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + + object.parent.remove( object ); + + if ( object.element.parentNode === renderer.cameraElement ) { + + renderer.cameraElement.removeChild( object.element ); + + } + + if ( object.properties.joint ) { + + object.properties.joint.parent.remove( object.properties.joint ); + + } + + } + + objects = []; + + loader.load( url, function ( geometry, geometryBonds ) { + + var offset = THREE.GeometryUtils.center( geometry ); + geometryBonds.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); + + for ( var i = 0; i < geometry.vertices.length; i ++ ) { + + var position = geometry.vertices[ i ]; + var color = geometry.colors[ i ]; + var element = geometry.elements[ i ]; + + if ( ! colorSpriteMap[ element ] ) { + + var canvas = imageToCanvas( baseSprite ); + var context = canvas.getContext( '2d' ); + + colorify( context, canvas.width, canvas.height, color, 1 ); + + var dataUrl = canvas.toDataURL(); + + colorSpriteMap[ element ] = dataUrl; + + } + + var colorSprite = colorSpriteMap[ element ]; + + var atom = document.createElement( 'img' ); + atom.src = colorSprite; + + var object = new THREE.CSS3DSprite( atom ); + object.position.copy( position ); + object.position.multiplyScalar( 75 ); + object.billboard = true; + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + root.add( object ); + + objects.push( object ); + + } + + for ( var i = 0; i < geometryBonds.vertices.length; i += 2 ) { + + var start = geometryBonds.vertices[ i ]; + var end = geometryBonds.vertices[ i + 1 ]; + + start.multiplyScalar( 75 ); + end.multiplyScalar( 75 ); + + tmpVec1.subVectors( end, start ); + var bondLength = tmpVec1.length() - 50; + + + // + + var bond = document.createElement( 'div' ); + bond.className = "bond"; + bond.style.height = bondLength + "px"; + + var object = new THREE.CSS3DObject( bond ); + object.position.copy( start ); + object.position.lerp( end, 0.5 ); + + object.properties.bondLengthShort = bondLength + "px"; + object.properties.bondLengthFull = ( bondLength + 55 ) + "px"; + + // + + var axis = tmpVec2.set( 0, 1, 0 ).cross( tmpVec1 ); + var radians = Math.acos( tmpVec3.set( 0, 1, 0 ).dot( tmpVec4.copy( tmpVec1 ).normalize() ) ); + + var objMatrix = new THREE.Matrix4().makeRotationAxis( axis.normalize(), radians ); + object.matrix = objMatrix; + object.rotation.setEulerFromRotationMatrix( object.matrix, object.eulerOrder ); + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + root.add( object ); + + objects.push( object ); + + // + + var bond = document.createElement( 'div' ); + bond.className = "bond"; + bond.style.height = bondLength + "px"; + + + // three-tests/ts: + // var joint = new THREE.Object3D( bond ); + // It seems a parameter "bond" is not used by Object3D. + var joint = new THREE.Object3D(); + + + joint.position.copy( start ); + joint.position.lerp( end, 0.5 ); + + joint.matrix.copy( objMatrix ); + joint.rotation.setEulerFromRotationMatrix( joint.matrix, joint.eulerOrder ); + + joint.matrixAutoUpdate = false; + joint.updateMatrix(); + + var object = new THREE.CSS3DObject( bond ); + object.rotation.y = Math.PI/2; + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + object.properties.bondLengthShort = bondLength + "px"; + object.properties.bondLengthFull = ( bondLength + 55 ) + "px"; + + object.properties.joint = joint; + + joint.add( object ); + root.add( joint ); + + objects.push( object ); + + } + + //console.log( "CSS3DObjects:", objects.length ); + + switch ( visualizationType ) { + + case 0: showAtoms(); break; + case 1: showBonds(); break; + case 2: showAtomsBonds(); break; + + } + + render(); + + } ); + + + } + + // + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + render(); + + } + + function animate() { + + requestAnimationFrame( animate ); + controls.update(); + + var time = Date.now() * 0.0004; + + root.rotation.x = time; + root.rotation.y = time * 0.7; + + render(); + + } + + function render() { + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/css3d_panorama.html + +()=>{ + var camera, scene, renderer; + var geometry, material, mesh; + var target = new THREE.Vector3(); + + var lon = 90, lat = 0; + var phi = 0, theta = 0; + + var touchX, touchY; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 ); + + scene = new THREE.Scene(); + + var sides = [ + { + url: 'textures/cube/Bridge2/posx.jpg', + position: new THREE.Vector3( -512, 0, 0 ), + rotation: new THREE.Vector3( 0, Math.PI / 2, 0 ) + }, + { + url: 'textures/cube/Bridge2/negx.jpg', + position: new THREE.Vector3( 512, 0, 0 ), + rotation: new THREE.Vector3( 0, -Math.PI / 2, 0 ) + }, + { + url: 'textures/cube/Bridge2/posy.jpg', + position: new THREE.Vector3( 0, 512, 0 ), + rotation: new THREE.Vector3( Math.PI / 2, 0, Math.PI ) + }, + { + url: 'textures/cube/Bridge2/negy.jpg', + position: new THREE.Vector3( 0, -512, 0 ), + rotation: new THREE.Vector3( - Math.PI / 2, 0, Math.PI ) + }, + { + url: 'textures/cube/Bridge2/posz.jpg', + position: new THREE.Vector3( 0, 0, 512 ), + rotation: new THREE.Vector3( 0, Math.PI, 0 ) + }, + { + url: 'textures/cube/Bridge2/negz.jpg', + position: new THREE.Vector3( 0, 0, -512 ), + rotation: new THREE.Vector3( 0, 0, 0 ) + } + ]; + + for ( var i = 0; i < sides.length; i ++ ) { + + var side = sides[ i ]; + + var element = document.createElement( 'img' ); + element.width = 1026; // 2 pixels extra to close the gap. + element.src = side.url; + + var object = new THREE.CSS3DObject( element ); + object.position = side.position; + object.rotation = side.rotation; + scene.add( object ); + + } + + renderer = new THREE.CSS3DRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + // + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'mousewheel', onDocumentMouseWheel, false ); + + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + + } + + function onDocumentMouseMove( event ) { + + var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; + var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; + + lon -= movementX * 0.1; + lat += movementY * 0.1; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove ); + document.removeEventListener( 'mouseup', onDocumentMouseUp ); + + } + + function onDocumentMouseWheel( event ) { + + camera.fov -= event.wheelDeltaY * 0.05; + camera.updateProjectionMatrix(); + + } + + function onDocumentTouchStart( event ) { + + event.preventDefault(); + + var touch = event.touches[ 0 ]; + + touchX = touch.screenX; + touchY = touch.screenY; + + } + + function onDocumentTouchMove( event ) { + + event.preventDefault(); + + var touch = event.touches[ 0 ]; + + lon -= ( touch.screenX - touchX ) * 0.1; + lat += ( touch.screenY - touchY ) * 0.1; + + touchX = touch.screenX; + touchY = touch.screenY; + + } + + function animate() { + + requestAnimationFrame( animate ); + + lon += 0.1; + lat = Math.max( - 85, Math.min( 85, lat ) ); + phi = THREE.Math.degToRad( 90 - lat ); + theta = THREE.Math.degToRad( lon ); + + target.x = Math.sin( phi ) * Math.cos( theta ); + target.y = Math.cos( phi ); + target.z = Math.sin( phi ) * Math.sin( theta ); + + camera.lookAt( target ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/css3d_periodictable.html + +()=>{ + + var table: any[][] = [ + [ "H", "Hydrogen", "1.00794", 1, 1 ], + [ "He", "Helium", "4.002602", 18, 1 ], + [ "Li", "Lithium", "6.941", 1, 2 ], + [ "Be", "Beryllium", "9.012182", 2, 2 ], + [ "B", "Boron", "10.811", 13, 2 ], + [ "C", "Carbon", "12.0107", 14, 2 ], + [ "N", "Nitrogen", "14.0067", 15, 2 ], + [ "O", "Oxygen", "15.9994", 16, 2 ], + [ "F", "Fluorine", "18.9984032", 17, 2 ], + [ "Ne", "Neon", "20.1797", 18, 2 ], + [ "Na", "Sodium", "22.98976...", 1, 3 ], + [ "Mg", "Magnesium", "24.305", 2, 3 ], + [ "Al", "Aluminium", "26.9815386", 13, 3 ], + [ "Si", "Silicon", "28.0855", 14, 3 ], + [ "P", "Phosphorus", "30.973762", 15, 3 ], + [ "S", "Sulfur", "32.065", 16, 3 ], + [ "Cl", "Chlorine", "35.453", 17, 3 ], + [ "Ar", "Argon", "39.948", 18, 3 ], + [ "K", "Potassium", "39.948", 1, 4 ], + [ "Ca", "Calcium", "40.078", 2, 4 ], + [ "Sc", "Scandium", "44.955912", 3, 4 ], + [ "Ti", "Titanium", "47.867", 4, 4 ], + [ "V", "Vanadium", "50.9415", 5, 4 ], + [ "Cr", "Chromium", "51.9961", 6, 4 ], + [ "Mn", "Manganese", "54.938045", 7, 4 ], + [ "Fe", "Iron", "55.845", 8, 4 ], + [ "Co", "Cobalt", "58.933195", 9, 4 ], + [ "Ni", "Nickel", "58.6934", 10, 4 ], + [ "Cu", "Copper", "63.546", 11, 4 ], + [ "Zn", "Zinc", "65.38", 12, 4 ], + [ "Ga", "Gallium", "69.723", 13, 4 ], + [ "Ge", "Germanium", "72.63", 14, 4 ], + [ "As", "Arsenic", "74.9216", 15, 4 ], + [ "Se", "Selenium", "78.96", 16, 4 ], + [ "Br", "Bromine", "79.904", 17, 4 ], + [ "Kr", "Krypton", "83.798", 18, 4 ], + [ "Rb", "Rubidium", "85.4678", 1, 5 ], + [ "Sr", "Strontium", "87.62", 2, 5 ], + [ "Y", "Yttrium", "88.90585", 3, 5 ], + [ "Zr", "Zirconium", "91.224", 4, 5 ], + [ "Nb", "Niobium", "92.90628", 5, 5 ], + [ "Mo", "Molybdenum", "95.96", 6, 5 ], + [ "Tc", "Technetium", "(98)", 7, 5 ], + [ "Ru", "Ruthenium", "101.07", 8, 5 ], + [ "Rh", "Rhodium", "102.9055", 9, 5 ], + [ "Pd", "Palladium", "106.42", 10, 5 ], + [ "Ag", "Silver", "107.8682", 11, 5 ], + [ "Cd", "Cadmium", "112.411", 12, 5 ], + [ "In", "Indium", "114.818", 13, 5 ], + [ "Sn", "Tin", "118.71", 14, 5 ], + [ "Sb", "Antimony", "121.76", 15, 5 ], + [ "Te", "Tellurium", "127.6", 16, 5 ], + [ "I", "Iodine", "126.90447", 17, 5 ], + [ "Xe", "Xenon", "131.293", 18, 5 ], + [ "Cs", "Caesium", "132.9054", 1, 6 ], + [ "Ba", "Barium", "132.9054", 2, 6 ], + [ "La", "Lanthanum", "138.90547", 4, 9 ], + [ "Ce", "Cerium", "140.116", 5, 9 ], + [ "Pr", "Praseodymium", "140.90765", 6, 9 ], + [ "Nd", "Neodymium", "144.242", 7, 9 ], + [ "Pm", "Promethium", "(145)", 8, 9 ], + [ "Sm", "Samarium", "150.36", 9, 9 ], + [ "Eu", "Europium", "151.964", 10, 9 ], + [ "Gd", "Gadolinium", "157.25", 11, 9 ], + [ "Tb", "Terbium", "158.92535", 12, 9 ], + [ "Dy", "Dysprosium", "162.5", 13, 9 ], + [ "Ho", "Holmium", "164.93032", 14, 9 ], + [ "Er", "Erbium", "167.259", 15, 9 ], + [ "Tm", "Thulium", "168.93421", 16, 9 ], + [ "Yb", "Ytterbium", "173.054", 17, 9 ], + [ "Lu", "Lutetium", "174.9668", 18, 9 ], + [ "Hf", "Hafnium", "178.49", 4, 6 ], + [ "Ta", "Tantalum", "180.94788", 5, 6 ], + [ "W", "Tungsten", "183.84", 6, 6 ], + [ "Re", "Rhenium", "186.207", 7, 6 ], + [ "Os", "Osmium", "190.23", 8, 6 ], + [ "Ir", "Iridium", "192.217", 9, 6 ], + [ "Pt", "Platinum", "195.084", 10, 6 ], + [ "Au", "Gold", "196.966569", 11, 6 ], + [ "Hg", "Mercury", "200.59", 12, 6 ], + [ "Tl", "Thallium", "204.3833", 13, 6 ], + [ "Pb", "Lead", "207.2", 14, 6 ], + [ "Bi", "Bismuth", "208.9804", 15, 6 ], + [ "Po", "Polonium", "(209)", 16, 6 ], + [ "At", "Astatine", "(210)", 17, 6 ], + [ "Rn", "Radon", "(222)", 18, 6 ], + [ "Fr", "Francium", "(223)", 1, 7 ], + [ "Ra", "Radium", "(226)", 2, 7 ], + [ "Ac", "Actinium", "(227)", 4, 10 ], + [ "Th", "Thorium", "232.03806", 5, 10 ], + [ "Pa", "Protactinium", "231.0588", 6, 10 ], + [ "U", "Uranium", "238.02891", 7, 10 ], + [ "Np", "Neptunium", "(237)", 8, 10 ], + [ "Pu", "Plutonium", "(244)", 9, 10 ], + [ "Am", "Americium", "(243)", 10, 10 ], + [ "Cm", "Curium", "(247)", 11, 10 ], + [ "Bk", "Berkelium", "(247)", 12, 10 ], + [ "Cf", "Californium", "(251)", 13, 10 ], + [ "Es", "Einstenium", "(252)", 14, 10 ], + [ "Fm", "Fermium", "(257)", 15, 10 ], + [ "Md", "Mendelevium", "(258)", 16, 10 ], + [ "No", "Nobelium", "(259)", 17, 10 ], + [ "Lr", "Lawrencium", "(262)", 18, 10 ], + [ "Rf", "Rutherfordium", "(267)", 4, 7 ], + [ "Db", "Dubnium", "(268)", 5, 7 ], + [ "Sg", "Seaborgium", "(271)", 6, 7 ], + [ "Bh", "Bohrium", "(272)", 7, 7 ], + [ "Hs", "Hassium", "(270)", 8, 7 ], + [ "Mt", "Meitnerium", "(276)", 9, 7 ], + [ "Ds", "Darmstadium", "(281)", 10, 7 ], + [ "Rg", "Roentgenium", "(280)", 11, 7 ], + [ "Cn", "Copernicium", "(285)", 12, 7 ], + [ "Uut", "Unutrium", "(284)", 13, 7 ], + [ "Fl", "Flerovium", "(289)", 14, 7 ], + [ "Uup", "Ununpentium", "(288)", 15, 7 ], + [ "Lv", "Livermorium", "(293)", 16, 7 ], + [ "Uus", "Ununseptium", "(294)", 17, 7 ], + [ "Uuo", "Ununoctium", "(294)", 18, 7 ] + ]; + + var camera, scene, renderer; + var controls; + + var objects = []; + var targets = { table: [], sphere: [], helix: [], grid: [] }; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.z = 1800; + + scene = new THREE.Scene(); + + for ( var i = 0; i < table.length; i ++ ) { + + var item = table[ i ]; + + var element = document.createElement( 'div' ); + element.className = 'element'; + element.style.backgroundColor = 'rgba(0,127,127,' + ( Math.random() * 0.5 + 0.25 ) + ')'; + + var number = document.createElement( 'div' ); + number.className = 'number'; + number.textContent = (i + 1).toString(); + element.appendChild( number ); + + var symbol = document.createElement( 'div' ); + symbol.className = 'symbol'; + symbol.textContent = item[ 0 ]; + element.appendChild( symbol ); + + var details = document.createElement( 'div' ); + details.className = 'details'; + details.innerHTML = item[ 1 ] + '
' + item[ 2 ]; + element.appendChild( details ); + + var object = new THREE.CSS3DObject( element ); + object.position.x = Math.random() * 4000 - 2000; + object.position.y = Math.random() * 4000 - 2000; + object.position.z = Math.random() * 4000 - 2000; + scene.add( object ); + + objects.push( object ); + + } + + // table + + for ( var i = 0; i < objects.length; i ++ ) { + + var item = table[ i ]; + + var object = new THREE.Object3D(); + object.position.x = ( item[ 3 ] * 160 ) - 1540; + object.position.y = - ( item[ 4 ] * 200 ) + 1100; + + targets.table.push( object ); + + } + + // sphere + + var vector = new THREE.Vector3(); + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + var phi = Math.acos( -1 + ( 2 * i ) / l ); + var theta = Math.sqrt( l * Math.PI ) * phi; + + var object = new THREE.Object3D(); + + object.position.x = 1000 * Math.cos( theta ) * Math.sin( phi ); + object.position.y = 1000 * Math.sin( theta ) * Math.sin( phi ); + object.position.z = 1000 * Math.cos( phi ); + + vector.copy( object.position ).multiplyScalar( 2 ); + + object.lookAt( vector ); + + targets.sphere.push( object ); + + } + + // helix + + var vector = new THREE.Vector3(); + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + var phi = i * 0.175 + Math.PI; + + var object = new THREE.Object3D(); + + object.position.x = 1100 * Math.sin( phi ); + object.position.y = - ( i * 8 ) + 450; + object.position.z = 1100 * Math.cos( phi ); + + vector.copy( object.position ); + vector.x *= 2; + vector.z *= 2; + + object.lookAt( vector ); + + targets.helix.push( object ); + + } + + // grid + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = new THREE.Object3D(); + + object.position.x = ( ( i % 5 ) * 400 ) - 800; + object.position.y = ( - ( Math.floor( i / 5 ) % 5 ) * 400 ) + 800; + object.position.z = ( Math.floor( i / 25 ) ) * 1000 - 2000; + + targets.grid.push( object ); + + } + + // + + renderer = new THREE.CSS3DRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.domElement.style.position = 'absolute'; + document.getElementById( 'container' ).appendChild( renderer.domElement ); + + // + + controls = new THREE.TrackballControls( camera, renderer.domElement ); + controls.rotateSpeed = 0.5; + controls.addEventListener( 'change', render ); + + var button = document.getElementById( 'table' ); + button.addEventListener( 'click', function ( event ) { + + transform( targets.table, 2000 ); + + }, false ); + + var button = document.getElementById( 'sphere' ); + button.addEventListener( 'click', function ( event ) { + + transform( targets.sphere, 2000 ); + + }, false ); + + var button = document.getElementById( 'helix' ); + button.addEventListener( 'click', function ( event ) { + + transform( targets.helix, 2000 ); + + }, false ); + + var button = document.getElementById( 'grid' ); + button.addEventListener( 'click', function ( event ) { + + transform( targets.grid, 2000 ); + + }, false ); + + transform( targets.table, 5000 ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function transform( targets, duration ) { + + TWEEN.removeAll(); + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + var target = targets[ i ]; + + new TWEEN.Tween( object.position ) + .to( { x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration ) + .easing( TWEEN.Easing.Exponential.InOut ) + .start(); + + new TWEEN.Tween( object.rotation ) + .to( { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration ) + .easing( TWEEN.Easing.Exponential.InOut ) + .start(); + + } + + new TWEEN.Tween( this ) + .to( {}, duration * 2 ) + .onUpdate( render ) + .start(); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + TWEEN.update(); + controls.update(); + + } + + function render() { + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/css3d_sandbox.html + +()=>{ + var camera, scene, renderer; + var geometry, material, mesh; + + var scene2, renderer2; + + var controls; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 200, 200, 200 ); + + controls = new THREE.TrackballControls( camera ); + + controls.rotateSpeed = 1.0; + controls.zoomSpeed = 1.2; + controls.panSpeed = 0.8; + + controls.noZoom = false; + controls.noPan = false; + + controls.staticMoving = false; + controls.dynamicDampingFactor = 0.3; + + controls.keys = [ 65, 83, 68 ]; + + scene = new THREE.Scene(); + + geometry = new THREE.CubeGeometry( 200, 200, 200 ); + material = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 1 } ); + + mesh = new THREE.Mesh( geometry, material ); + scene.add( mesh ); + + renderer = new THREE.CanvasRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + // + + scene2 = new THREE.Scene(); + + for ( var i = 0; i < 20; i ++ ) { + + var element = document.createElement( 'div' ); + element.style.width = '100px'; + element.style.height = '100px'; + element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle(); + + var object = new THREE.CSS3DObject( element ); + object.position.x = Math.random() * 200 - 100; + object.position.y = Math.random() * 200 - 100; + object.position.z = Math.random() * 200 - 100; + object.scale.x = Math.random() + 0.5; + object.scale.y = Math.random() + 0.5; + scene2.add( object ); + + } + + // + + renderer2 = new THREE.CSS3DRenderer(); + renderer2.setSize( window.innerWidth, window.innerHeight ); + renderer2.domElement.style.position = 'absolute'; + renderer2.domElement.style.top = 0; + document.body.appendChild( renderer2.domElement ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + controls.update(); + + renderer.render( scene, camera ); + renderer2.render( scene2, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/css3d_youtube.html + +()=>{ + var camera, scene, renderer; + var objects = [], player; + + var auto = true; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.y = - 25; + + scene = new THREE.Scene(); + + renderer = new THREE.CSS3DRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.domElement.style.position = 'absolute'; + renderer.domElement.style.top = 0; + document.getElementById( 'container' ).appendChild( renderer.domElement ); + + // + + var query = document.getElementById( 'query' ); + query.addEventListener( 'keyup', function ( event:KeyboardEvent ) { + + if ( event.keyCode === 13 ) { + + search( query.value ); + + } + + }, false ); + + var button = document.getElementById( 'button' ); + button.addEventListener( 'click', function ( event ) { + + search( query.value ); + + }, false ); + + if ( window.location.hash.length > 0 ) { + + query.value = window.location.hash.substr( 1 ); + + } + + search( query.value ); + + document.body.addEventListener( 'mousewheel', onMouseWheel, false ); + + document.body.addEventListener( 'click', function ( event ) { + + auto = true; + + if ( player !== undefined ) { + + player.parentNode.removeChild( player ); + player = undefined; + + } + + new TWEEN.Tween( camera.position ) + .to( { x: 0, y: - 25 }, 1500 ) + .easing( TWEEN.Easing.Exponential.Out ) + .start(); + + }, false ); + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function search( query ) { + + window.location.hash = query; + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + var object = objects[ i ]; + var delay = Math.random() * 1000; + + new TWEEN.Tween( object.position ) + .to( { y: - 3000 }, 1000 ) + .delay( delay ) + .easing( TWEEN.Easing.Exponential.In ) + .start(); + + new TWEEN.Tween( object ) + .to( {}, 2000 ) + .delay( delay ) + .onComplete( function () { + + scene.remove( this ); + renderer.cameraElement.removeChild( this.element ); + + var index = objects.indexOf( this ); + objects.splice( index, 1 ); + + } ) + .start(); + + } + + var request = new XMLHttpRequest(); + request.addEventListener( 'load', onData, false ); + request.open( 'GET', 'https://gdata.youtube.com/feeds/api/videos?v=2&alt=json&max-results=50&q=' + query, true ); + request.send( null ); + + } + + function onData( event ) { + + var data = JSON.parse( event.target.responseText ); + var entries = data.feed.entry; + + // console.log( entries ); + + for ( var i = 0; i < entries.length; i ++ ) { + + var entry = entries[ i ]; + + var element = document.createElement( 'div' ); + element.style.width = '480px'; + element.style.height = '360px'; + + var image = document.createElement( 'img' ); + image.addEventListener( 'load', function ( event ) { + + var object = this.properties.object; + var button = this.properties.button; + + button.style.visibility = 'visible'; + + new TWEEN.Tween( object.position ) + .to( { y: Math.random() * 2000 - 1000 }, 2000 ) + .easing( TWEEN.Easing.Exponential.Out ) + .start(); + + }, false ); + image.style.position = 'absolute'; + image.style.width = '480px'; + image.style.height = '360px'; + image.src = entry.media$group.media$thumbnail[ 2 ].url; + element.appendChild( image ); + + var button = document.createElement( 'img' ); + button.style.position = 'absolute'; + button.style.left = ( ( 480 - 86 ) / 2 ) + 'px'; + button.style.top = ( ( 360 - 61 ) / 2 ) + 'px'; + button.style.visibility = 'hidden'; + button.style.WebkitFilter = 'grayscale()'; + button.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFYAAAA9CAYAAAA3ZZ5uAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wLBQ0uMbsnLZIAAAbXSURBVHja7ZxvbBvlHcc/z/maf4PGg9FtbaZeS2I1iUgP1q7QEmFpmxB7AYxXk/aCvETaC/Zy2qSpk7apL/YCTbCyoU0uUAGdRv8uVCorzsQGSRu4tFoahbYxpEkKayvHaRInvnt+e5HEzb92cez4bHRfyS/ufPbd8/H3vs/vZ99Zkac+erB5OxhhAG1oS4myZp5RYVFi5/PeSpSFwrrd84I4QDLH93RAksusjwM89PH5DgoglcvGZ+ymp8RQTytRliCWUsriyywhCTiiJKFQCaUmXtjRfXk0b7Bnv7211vUq2xSqDaVsAoGII0jMDE3F7gT5tmA/tJue0qiYgnBAczkzkzSQtoed3qMrBvt+y7ZnlTJiAb6VGFi3PXqu78D/Bft+y7ZnhQBqbhPVUrgLwP6rsXGza+IEp3/usWC62HsuXPh0bp05f4NMSGKgwhKwylXhTIgXgB8ucezp5sh2MJyAUR7O1cr67qxrs471kDZF4NW8slbpNuBXC8CKNmxRAZz8LKuiS8BqJBoYNm9FF2Rs+7b6x8CIB1wKIR39Qd/FDnOmyFU2gV0LlbQ2MAPW02Ip5UPAVlXB44/Dxk0zy8NDcOYMDA+XcScmVjZjtWD7URFU79zJzp//gtraWgBGR0cZGBhgsLMT3nyjLAGLYGfBimhbKL5jv7FnTxYqQG1tLbZtE4lE6N+1i5Hjx5n+x7vlBVjkFlitlC8t7Ncbm5ZdX1NTg23bNDc30//MM3wWj5P+66HyADzLUv1ty5bN2lAJP46h9bXXuW/XrhVt29/fT197O96Rw0iJAza0WKYnYkkZdAaRSIRIJMLlJ5+k7+23mTx+vGQBi4hlagiL+FNqrWavW7du5VvPP0//E0+QaG9n4sQJZGiotNIAwqaA7RNXRITVfKimadLU1IRlWfRGowydepfMyZPo0gFsm54mjPKLbH4vr6mpYceOHTQ0NHDu0T1cO3aMqXdOwuSkz1lA2NQitn/7L8wHWltbS2trK4OWRX80SrL9Habicf8AC7apfexkRaCQ+V5XV0ddXR399fVc2rObsTcPkTl/3pcz0dRI2D+wwlpMnA0NDWzatIlPGhsZPHWK1FuH0DduFHNoYVOD7df3L3qNwAJUV1fT0tJCfX09Zx94gKuxA0x1dhVv8tIiPkaBRkSv7fcR1VW0fv97DNTfz5lf/5Z0vKMoYzNmcs6vhxTtYVkWj+z9JcbGjUUZm6+O1SLoIs6eVckUjKYoxph9joK1y9jFutrZyennfkJmbKwo+/O53JI1z9jpVIre2Ks4v3+pqGPzNwq0Rmu9hi7tous3+7hxoa/oYzO1f4ZFa1kTsDevDOG8+AcuHj7q29jMSddzKkOGL22tlsI69ubQEM6L+30FCjDlacesMFTSrzSYiQKvAECHuXj4GD0vvVwSX21VGCo5O3mJj2BX79jp1Bi9rx2k99WDZMZuUkoytXgOGNFyAjudGuOz0+/Rte93JQcUIK11whStkn79MuNpjed5OQG9ePQEPfv/VJJA51SJSpifuy5fM82Sj4Le19+gZ/8rJQ10TtdcF/MejLhfTYKnPTzPvb1Dx8YYfO+f9Lz8Z8aHr1Iuugcjbn7iprnfqPblAEa6urnvwe1LZ/nhET4/+zHn/vgXxkfKB+icLrlpzEtpN7Glwp8D+M/BQ3yzdTdfjTRkgQ78/STnX4lRzrqUdhMK4Gd33SvrlH/XFmx4aMa1X3zUQ7krI8K+m9eVCTCudXK9EfLtJ5qr3eUPdE7jWidh7opuEUeLRAmUv0ScLNgJTydqlBFAKYAmPJ3Igp0UHB1c0F0QTQq3HDuQmXY2hkIBlQJoIDPtwLwb6H687m7ZYJgBmTx0Q3scyKTUrckLmBKJC8EElo9S4mXv7MyC/UJ7RzaoUNRUwV10q9V1rbOdjXGr/pqMXRMvoLNK/Vd7uFqOLAHbDaMj4sZcCcqDXOWKcEUysX+T/nQJWADPY29Cu8kAVW5KaDfpeeydv25BjTWIO3qvClVVoKJfCRqGFemyznAd77kPJN1xW7AAV8TtuAvDAuz1Adw7nv4JcbkmXtuHXnrJf8Is2xVcEffoelQ4KfrhdUpRHQBeAPS6aC5LJpny3B91ytRby213x9rqEaoekxB7K1DRShTzHVyBolIpalB8mUu0lGjGZi+DSolmAo0nxDI6/dNuyP1/t+ZrN1WbBSwxmN9AWCgsEbGVUuEaFKFF8AHuXrTsd7xMiTA1+3P/hGjmF5jjs8sewgQCQgJFQkQchUoqTXyatHMnoDmBXYm+w7rtIULhRfBBsbibK5nuTkQcpVQSIQEkAARJGlo5ChLzy6dc9T9S8wu+HzDbBQAAAABJRU5ErkJggg=='; + element.appendChild( button ); + + var blocker = document.createElement( 'div' ); + blocker.style.position = 'absolute'; + blocker.style.width = '480px'; + blocker.style.height = '360px'; + blocker.style.background = 'rgba(0,0,0,0.5)'; + blocker.style.cursor = 'pointer'; + element.appendChild( blocker ); + + var object = new THREE.CSS3DObject( element ); + object.position.x = Math.random() * 4000 - 2000; + // object.position.y = Math.random() * 2000 - 1000; + object.position.y = 3000; + object.position.z = Math.random() * - 5000; + scene.add( object ); + + objects.push( object ); + + // + + var properties = { data: entry, blocker: blocker, button: button, object: object } + + element["properties"] = properties; + image["properties"] = properties; + + element.addEventListener( 'mouseover', function () { + + this.properties.button.style.WebkitFilter = ''; + this.properties.blocker.style.background = 'rgba(0,0,0,0)'; + + }, false ); + + element.addEventListener( 'mouseout', function () { + + this.properties.button.style.WebkitFilter = 'grayscale()'; + this.properties.blocker.style.background = 'rgba(0,0,0,0.75)'; + + }, false ); + + element.addEventListener( 'click', function ( event ) { + + event.stopPropagation(); + + var data = this.properties.data; + var object = this.properties.object; + + auto = false; + + if ( player !== undefined ) { + + player.parentNode.removeChild( player ); + player = undefined; + + } + + player = document.createElement( 'iframe' ); + player.style.position = 'absolute'; + player.style.width = '480px'; + player.style.height = '360px'; + player.style.border = '0px'; + player.src = 'http://www.youtube.com/embed/' + data.id.$t.split( ':' ).pop() + '?rel=0&autoplay=1&controls=1&showinfo=0'; + this.appendChild( player ); + + // + + var prev = object.position.z + 400; + + new TWEEN.Tween( camera.position ) + .to( { x: object.position.x, y: object.position.y - 25 }, 1500 ) + .easing( TWEEN.Easing.Exponential.Out ) + .start(); + + new TWEEN.Tween( { value: prev } ) + .to( { value: 0 }, 2000 ) + .onUpdate( function () { + + move( this.value - prev ); + prev = this.value; + + } ) + .easing( TWEEN.Easing.Exponential.Out ) + .start(); + + }, false ); + + } + + } + + function move( delta ) { + + for ( var i = 0; i < objects.length; i ++ ) { + + var object = objects[ i ]; + + object.position.z += delta; + + if ( object.position.z > 0 ) { + + object.position.z -= 5000; + + } else if ( object.position.z < - 5000 ) { + + object.position.z += 5000; + + } + + } + + } + + function onMouseWheel( event ) { + + move( event.wheelDelta ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + TWEEN.update(); + + if ( auto === true ) { + + move( 1 ); + + } + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_fly.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var radius = 6371; + var tilt = 0.41; + var rotationSpeed = 0.02; + + var cloudsScale = 1.005; + var moonScale = 0.23; + + var MARGIN = 0; + var SCREEN_HEIGHT = window.innerHeight - MARGIN * 2; + var SCREEN_WIDTH = window.innerWidth; + + var container, stats; + var camera, controls, scene, sceneCube, renderer; + var geometry, meshPlanet, meshClouds, meshMoon; + var dirLight, pointLight, ambientLight; + + var d, dPlanet, dMoon, dMoonVec = new THREE.Vector3(); + + var clock = new THREE.Clock(); + + var composer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 25, SCREEN_WIDTH / SCREEN_HEIGHT, 50, 1e7 ); + camera.position.z = radius * 5; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0x000000, 0.00000025 ); + + controls = new THREE.FlyControls( camera ); + + controls.movementSpeed = 1000; + controls.domElement = container; + controls.rollSpeed = Math.PI / 24; + controls.autoForward = false; + controls.dragToLook = false; + + dirLight = new THREE.DirectionalLight( 0xffffff ); + dirLight.position.set( -1, 0, 1 ).normalize(); + scene.add( dirLight ); + + ambientLight = new THREE.AmbientLight( 0x000000 ); + scene.add( ambientLight ); + + var planetTexture = THREE.ImageUtils.loadTexture( "textures/planets/earth_atmos_2048.jpg" ); + var cloudsTexture = THREE.ImageUtils.loadTexture( "textures/planets/earth_clouds_1024.png" ); + var normalTexture = THREE.ImageUtils.loadTexture( "textures/planets/earth_normal_2048.jpg" ); + var specularTexture = THREE.ImageUtils.loadTexture( "textures/planets/earth_specular_2048.jpg" ); + + var moonTexture = THREE.ImageUtils.loadTexture( "textures/planets/moon_1024.jpg" ); + + var shader = THREE.ShaderLib[ "normalmap" ]; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + uniforms[ "tNormal" ].value = normalTexture; + uniforms[ "uNormalScale" ].value.set( 0.85, 0.85 ); + + uniforms[ "tDiffuse" ].value = planetTexture; + uniforms[ "tSpecular" ].value = specularTexture; + + uniforms[ "enableAO" ].value = false; + uniforms[ "enableDiffuse" ].value = true; + uniforms[ "enableSpecular" ].value = true; + + uniforms[ "uDiffuseColor" ].value.setHex( 0xffffff ); + uniforms[ "uSpecularColor" ].value.setHex( 0x333333 ); + uniforms[ "uAmbientColor" ].value.setHex( 0x000000 ); + + uniforms[ "uShininess" ].value = 15; + + var parameters = { + + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: uniforms, + lights: true, + fog: true + + }; + + var materialNormalMap = new THREE.ShaderMaterial( parameters ); + + // planet + + geometry = new THREE.SphereGeometry( radius, 100, 50 ); + geometry.computeTangents(); + + meshPlanet = new THREE.Mesh( geometry, materialNormalMap ); + meshPlanet.rotation.y = 0; + meshPlanet.rotation.z = tilt; + scene.add( meshPlanet ); + + // clouds + + var materialClouds = new THREE.MeshLambertMaterial( { color: 0xffffff, map: cloudsTexture, transparent: true } ); + + meshClouds = new THREE.Mesh( geometry, materialClouds ); + meshClouds.scale.set( cloudsScale, cloudsScale, cloudsScale ); + meshClouds.rotation.z = tilt; + scene.add( meshClouds ); + + // moon + + var materialMoon = new THREE.MeshPhongMaterial( { color: 0xffffff, map: moonTexture } ); + + meshMoon = new THREE.Mesh( geometry, materialMoon ); + meshMoon.position.set( radius * 5, 0, 0 ); + meshMoon.scale.set( moonScale, moonScale, moonScale ); + scene.add( meshMoon ); + + // stars + + var i, r = radius, starsGeometry = [ new THREE.Geometry(), new THREE.Geometry() ]; + + for ( i = 0; i < 250; i ++ ) { + + var vertex = new THREE.Vector3(); + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar( r ); + + starsGeometry[ 0 ].vertices.push( vertex ); + + } + + for ( i = 0; i < 1500; i ++ ) { + + var vertex = new THREE.Vector3(); + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar( r ); + + starsGeometry[ 1 ].vertices.push( vertex ); + + } + + var stars; + var starsMaterials = [ + new THREE.ParticleBasicMaterial( { color: 0x555555, size: 2, sizeAttenuation: false } ), + new THREE.ParticleBasicMaterial( { color: 0x555555, size: 1, sizeAttenuation: false } ), + new THREE.ParticleBasicMaterial( { color: 0x333333, size: 2, sizeAttenuation: false } ), + new THREE.ParticleBasicMaterial( { color: 0x3a3a3a, size: 1, sizeAttenuation: false } ), + new THREE.ParticleBasicMaterial( { color: 0x1a1a1a, size: 2, sizeAttenuation: false } ), + new THREE.ParticleBasicMaterial( { color: 0x1a1a1a, size: 1, sizeAttenuation: false } ) + ]; + + for ( i = 10; i < 30; i ++ ) { + + stars = new THREE.ParticleSystem( starsGeometry[ i % 2 ], starsMaterials[ i % 6 ] ); + + stars.rotation.x = Math.random() * 6; + stars.rotation.y = Math.random() * 6; + stars.rotation.z = Math.random() * 6; + + var s = i * 10; + stars.scale.set( s, s, s ); + + stars.matrixAutoUpdate = false; + stars.updateMatrix(); + + scene.add( stars ); + + } + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.sortObjects = false; + + renderer.autoClear = false; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + window.addEventListener( 'resize', onWindowResize, false ); + + // postprocessing + + var renderModel = new THREE.RenderPass( scene, camera ); + var effectFilm = new THREE.FilmPass( 0.35, 0.75, 2048, false ); + + effectFilm.renderToScreen = true; + + composer = new THREE.EffectComposer( renderer ); + + composer.addPass( renderModel ); + composer.addPass( effectFilm ); + + }; + + function onWindowResize( event ) { + + SCREEN_HEIGHT = window.innerHeight; + SCREEN_WIDTH = window.innerWidth; + + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + composer.reset(); + + }; + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + }; + + function render() { + + // rotate the planet and clouds + + var delta = clock.getDelta(); + + meshPlanet.rotation.y += rotationSpeed * delta; + meshClouds.rotation.y += 1.25 * rotationSpeed * delta; + + // slow down as we approach the surface + + dPlanet = camera.position.length(); + + dMoonVec.subVectors( camera.position, meshMoon.position ); + dMoon = dMoonVec.length(); + + if ( dMoon < dPlanet ) { + + d = ( dMoon - radius * moonScale * 1.01 ); + + } else { + + d = ( dPlanet - radius * 1.01 ); + + } + + controls.movementSpeed = 0.33 * d; + controls.update( delta ); + + renderer.clear(); + composer.render( delta ); + + }; +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_orbit.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, controls, scene, renderer; + + var cross; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 500; + + controls = new THREE.OrbitControls( camera ); + controls.addEventListener( 'change', render ); + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); + + // world + + var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 ); + var material = new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } ); + + for ( var i = 0; i < 500; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = ( Math.random() - 0.5 ) * 1000; + mesh.position.y = ( Math.random() - 0.5 ) * 1000; + mesh.position.z = ( Math.random() - 0.5 ) * 1000; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add( mesh ); + + } + + + // lights + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 1, 1, 1 ); + scene.add( light ); + + light = new THREE.DirectionalLight( 0x002288 ); + light.position.set( -1, -1, -1 ); + scene.add( light ); + + var lightAmbient = new THREE.AmbientLight( 0x222222 ); + scene.add( lightAmbient ); + + + // renderer + + renderer = new THREE.WebGLRenderer( { antialias: false } ); + renderer.setClearColor( scene.fog.color, 1 ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + render(); + + } + + function animate() { + + requestAnimationFrame( animate ); + controls.update(); + + } + + function render() { + + renderer.render( scene, camera ); + stats.update(); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_path.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, controls, scene, renderer; + + var cross; + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 ); + + controls = new THREE.PathControls( camera ); + + controls.waypoints = [ [ -500, 0, 0 ], [ 0, 200, 0 ], [ 500, 0, 0 ] ]; + controls.duration = 28 + controls.useConstantSpeed = true; + //controls.createDebugPath = true; + //controls.createDebugDummy = true; + controls.lookSpeed = 0.06; + controls.lookVertical = true; + controls.lookHorizontal = true; + controls.verticalAngleMap = { srcRange: [ 0, 2 * Math.PI ], dstRange: [ 1.1, 3.8 ] }; + controls.horizontalAngleMap = { srcRange: [ 0, 2 * Math.PI ], dstRange: [ 0.3, Math.PI - 0.3 ] }; + controls.lon = 180; + + controls.init(); + + // world + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); + + scene.add( controls.animationParent ); + + var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 ); + var material = new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } ); + + for ( var i = 0; i < 500; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = ( Math.random() - 0.5 ) * 1000; + mesh.position.y = ( Math.random() - 0.5 ) * 1000; + mesh.position.z = ( Math.random() - 0.5 ) * 1000; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add( mesh ); + + } + + // lights + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 1, 1, 1 ); + scene.add( light ); + + light = new THREE.DirectionalLight( 0x002288 ); + light.position.set( -1, -1, -1 ); + scene.add( light ); + + var lightAmbient = new THREE.AmbientLight( 0x222222 ); + scene.add( lightAmbient ); + + + // renderer + + renderer = new THREE.WebGLRenderer( { antialias: false } ); + renderer.setClearColor( scene.fog.color, 1 ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + // stats + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + // start animation + + controls.animation.play( true, 0 ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + THREE.AnimationHandler.update( delta ); + + controls.update( delta ); + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_pointerlock.html + +()=>{ + var camera, scene, renderer; + var geometry, material, mesh; + var controls,time = Date.now(); + + var objects = []; + + var ray; + + var blocker = document.getElementById( 'blocker' ); + var instructions = document.getElementById( 'instructions' ); + + // http://www.html5rocks.com/en/tutorials/pointerlock/intro/ + + var havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document; + + if ( havePointerLock ) { + + var element = document.body; + + var pointerlockchange = function ( event ) { + + if ( document.pointerLockElement === element || document.mozPointerLockElement === element || document.webkitPointerLockElement === element ) { + + controls.enabled = true; + + blocker.style.display = 'none'; + + } else { + + controls.enabled = false; + + blocker.style.display = '-webkit-box'; + blocker.style.display = '-moz-box'; + blocker.style.display = 'box'; + + instructions.style.display = ''; + + } + + } + + var pointerlockerror = function ( event ) { + + instructions.style.display = ''; + + } + + // Hook pointer lock state change events + document.addEventListener( 'pointerlockchange', pointerlockchange, false ); + document.addEventListener( 'mozpointerlockchange', pointerlockchange, false ); + document.addEventListener( 'webkitpointerlockchange', pointerlockchange, false ); + + document.addEventListener( 'pointerlockerror', pointerlockerror, false ); + document.addEventListener( 'mozpointerlockerror', pointerlockerror, false ); + document.addEventListener( 'webkitpointerlockerror', pointerlockerror, false ); + + instructions.addEventListener( 'click', function ( event ) { + + instructions.style.display = 'none'; + + // Ask the browser to lock the pointer + element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock; + + if ( /Firefox/i.test( navigator.userAgent ) ) { + + var fullscreenchange = function ( event ) { + + if ( document.fullscreenElement === element || document.mozFullscreenElement === element || document.mozFullScreenElement === element ) { + + document.removeEventListener( 'fullscreenchange', fullscreenchange ); + document.removeEventListener( 'mozfullscreenchange', fullscreenchange ); + + element.requestPointerLock(); + } + + } + + document.addEventListener( 'fullscreenchange', fullscreenchange, false ); + document.addEventListener( 'mozfullscreenchange', fullscreenchange, false ); + + element.requestFullscreen = element.requestFullscreen || element.mozRequestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen; + + element.requestFullscreen(); + + } else { + + element.requestPointerLock(); + + } + + }, false ); + + } else { + + instructions.innerHTML = 'Your browser doesn\'t seem to support Pointer Lock API'; + + } + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 ); + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0xffffff, 0, 750 ); + + var light = new THREE.DirectionalLight( 0xffffff, 1.5 ); + light.position.set( 1, 1, 1 ); + scene.add( light ); + + var light = new THREE.DirectionalLight( 0xffffff, 0.75 ); + light.position.set( -1, - 0.5, -1 ); + scene.add( light ); + + controls = new THREE.PointerLockControls( camera ); + scene.add( controls.getObject() ); + + ray = new THREE.Raycaster(); + ray.ray.direction.set( 0, -1, 0 ); + + // floor + + geometry = new THREE.PlaneGeometry( 2000, 2000, 100, 100 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) { + + var vertex = geometry.vertices[ i ]; + vertex.x += Math.random() * 20 - 10; + vertex.y += Math.random() * 2; + vertex.z += Math.random() * 20 - 10; + + } + + for ( var i = 0, l = geometry.faces.length; i < l; i ++ ) { + + var face = geometry.faces[ i ]; + face.vertexColors[ 0 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 1 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 2 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 3 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + + } + + material = new THREE.MeshBasicMaterial( { vertexColors: THREE.VertexColors } ); + + mesh = new THREE.Mesh( geometry, material ); + scene.add( mesh ); + + // objects + + geometry = new THREE.CubeGeometry( 20, 20, 20 ); + + for ( var i = 0, l = geometry.faces.length; i < l; i ++ ) { + + var face = geometry.faces[ i ]; + face.vertexColors[ 0 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 1 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 2 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + face.vertexColors[ 3 ] = new THREE.Color().setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + + } + + for ( var i = 0; i < 500; i ++ ) { + + material = new THREE.MeshPhongMaterial( { specular: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors } ); + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = Math.floor( Math.random() * 20 - 10 ) * 20; + mesh.position.y = Math.floor( Math.random() * 20 ) * 20 + 10; + mesh.position.z = Math.floor( Math.random() * 20 - 10 ) * 20; + scene.add( mesh ); + + material.color.setHSL( Math.random() * 0.2 + 0.5, 0.75, Math.random() * 0.25 + 0.75 ); + + objects.push( mesh ); + + } + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + document.body.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + // + + controls.isOnObject( false ); + + ray.ray.origin.copy( controls.getObject().position ); + ray.ray.origin.y -= 10; + + var intersections = ray.intersectObjects( objects ); + + if ( intersections.length > 0 ) { + + var distance = intersections[ 0 ].distance; + + if ( distance > 0 && distance < 10 ) { + + controls.isOnObject( true ); + + } + + } + + controls.update( Date.now() - time ); + + renderer.render( scene, camera ); + + time = Date.now(); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_roll.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, controls, scene, renderer; + + var cross; + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + + controls = new THREE.RollControls( camera ); + + controls.movementSpeed = 100; + controls.lookSpeed = 3; + controls.constrainVertical = [ -0.5, 0.5 ]; + //controls.autoForward = true; + + // world + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); + + var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 ); + var material = new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } ); + + for ( var i = 0; i < 500; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = ( Math.random() - 0.5 ) * 1000; + mesh.position.y = ( Math.random() - 0.5 ) * 1000; + mesh.position.z = ( Math.random() - 0.5 ) * 1000; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add( mesh ); + + } + + // lights + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 1, 1, 1 ); + scene.add( light ); + + light = new THREE.DirectionalLight( 0x002288 ); + light.position.set( -1, -1, -1 ); + scene.add( light ); + + var lightAmbient = new THREE.AmbientLight( 0x555555 ); + scene.add( lightAmbient ); + + + // renderer + + renderer = new THREE.WebGLRenderer( { antialias: false } ); + renderer.setClearColor( scene.fog.color, 1 ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + controls.update( clock.getDelta() ); + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_controls_trackball.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, controls, scene, renderer; + + var cross; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 500; + + controls = new THREE.TrackballControls( camera ); + + controls.rotateSpeed = 1.0; + controls.zoomSpeed = 1.2; + controls.panSpeed = 0.8; + + controls.noZoom = false; + controls.noPan = false; + + controls.staticMoving = true; + controls.dynamicDampingFactor = 0.3; + + controls.keys = [ 65, 83, 68 ]; + + controls.addEventListener( 'change', render ); + + // world + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); + + var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 ); + var material = new THREE.MeshLambertMaterial( { color:0xffffff, shading: THREE.FlatShading } ); + + for ( var i = 0; i < 500; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = ( Math.random() - 0.5 ) * 1000; + mesh.position.y = ( Math.random() - 0.5 ) * 1000; + mesh.position.z = ( Math.random() - 0.5 ) * 1000; + mesh.updateMatrix(); + mesh.matrixAutoUpdate = false; + scene.add( mesh ); + + } + + + // lights + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 1, 1, 1 ); + scene.add( light ); + + light = new THREE.DirectionalLight( 0x002288 ); + light.position.set( -1, -1, -1 ); + scene.add( light ); + + var lightAmbient = new THREE.AmbientLight( 0x222222 ); + scene.add( lightAmbient ); + + + // renderer + + renderer = new THREE.WebGLRenderer( { antialias: false } ); + renderer.setClearColor( scene.fog.color, 1 ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + render(); + + } + + function animate() { + + requestAnimationFrame( animate ); + controls.update(); + + } + + function render() { + + renderer.render( scene, camera ); + stats.update(); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_lights_test.html + +()=>{ + var SCREEN_WIDTH = window.innerWidth / 2; + var SCREEN_HEIGHT = window.innerHeight; + var FLOOR = -250; + + var container, stats; + + var camera, scene, canvasRenderer, webglRenderer; + + var mesh, zmesh, lightMesh, geometry; + var materialSpheres, materialTorus; + + var directionalLight, pointLight; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var render_canvas = true, render_gl = true; + var has_gl = 0; + + var lightAdded = false; + + var clock = new THREE.Clock(); + + var bcanvas = document.getElementById( 'rcanvas' ); + var bwebgl = document.getElementById( 'rwebgl' ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + //render_canvas = !has_gl; + bwebgl.style.display = has_gl ? 'inline' : 'none'; + bcanvas.className = render_canvas ? 'button' : 'button inactive'; + + function init() { + + container = document.createElement('div'); + document.body.appendChild(container); + + camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + // Spheres + + var geometry = new THREE.SphereGeometry( 100, 16, 8 ); + materialSpheres = new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, overdraw: true } ); + + for ( var i = 0; i < 30; i ++ ) { + + mesh = new THREE.Mesh( geometry, materialSpheres ); + mesh.position.x = 500 * ( Math.random() - 0.5 ); + mesh.position.y = 500 * ( Math.random() - 0.5 ); + mesh.position.z = 500 * ( Math.random() - 0.5 ); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 0.25 * ( Math.random() + 0.5 ); + scene.add( mesh ); + + } + + // Torus + + materialTorus = new THREE.MeshLambertMaterial( { color: 0xffffff, overdraw: true } ); + mesh = new THREE.Mesh( new THREE.TorusGeometry( 100, 25, 15, 30 ), materialTorus ); + scene.add( mesh ); + + // Lights + + var ambient = new THREE.AmbientLight( 0x101010 ); + scene.add( ambient ); + + directionalLight = new THREE.DirectionalLight( 0xffffff ); + directionalLight.position.set( 0, -70, 100 ).normalize(); + //scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffaa00 ); + scene.add( pointLight ); + + lightMesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xffaa00 } ) ); + lightMesh.scale.x = lightMesh.scale.y = lightMesh.scale.z = 0.05; + lightMesh.position = pointLight.position; + scene.add( lightMesh ); + + + if ( render_canvas ) { + + canvasRenderer = new THREE.CanvasRenderer(); + canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( canvasRenderer.domElement ); + + } + + if ( render_gl ) { + + try { + + webglRenderer = new THREE.WebGLRenderer( { alpha: true } ); + webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + webglRenderer.domElement.style.position = "relative"; + container.appendChild( webglRenderer.domElement ); + + has_gl = 1; + + } catch (e) { + + } + + } + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + bcanvas.addEventListener("click", toggleCanvas, false); + bwebgl.addEventListener("click", toggleWebGL, false); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + SCREEN_WIDTH = window.innerWidth / 2; + SCREEN_HEIGHT = window.innerHeight; + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + if ( canvasRenderer ) canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + if ( webglRenderer ) webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + var r = clock.getElapsedTime(); + + if ( ! lightAdded && r >= 3.0 ) { + + scene.add( directionalLight ); + + materialTorus.needsUpdate = true; + materialSpheres.needsUpdate = true; + + lightAdded = true; + + } + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + + camera.lookAt( scene.position ); + + for ( var i = 0, l = scene.children.length; i < l; i ++ ) { + + var object = scene.children[ i ]; + + if ( object instanceof THREE.Mesh ) { + + if ( i % 3 == 1 ) + + object.rotation.z += 1.5 * delta; + + else if ( i % 3 == 2 ) + + object.rotation.y += 1.5 * delta; + + else if ( i % 3 == 0 ) + + object.rotation.x += 1.5 * delta; + + } + + } + + + lightMesh.position.x = 200 * Math.cos( r ); + lightMesh.position.z = 200 * Math.sin( r ); + + if ( render_canvas ) canvasRenderer.render( scene, camera ); + if ( render_gl && has_gl ) webglRenderer.render( scene, camera ); + + } + + function toggleCanvas() { + + render_canvas = !render_canvas; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + render_gl = !render_canvas; + bwebgl.className = render_gl ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } + + function toggleWebGL() { + + render_gl = !render_gl; + bwebgl.className = render_gl ? "button" : "button inactive"; + + render_canvas = !render_gl; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_lookat.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var mesh, geometry, sphere; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 15000 ); + camera.position.z = 3200; + + scene = new THREE.Scene(); + + sphere = new THREE.Mesh( new THREE.SphereGeometry( 100, 20, 20 ), new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } ) ); + scene.add( sphere ); + + var geometry = new THREE.CylinderGeometry( 0, 10, 100, 3 ); + geometry.applyMatrix( new THREE.Matrix4().setRotationFromEuler( new THREE.Vector3( Math.PI / 2, Math.PI, 0 ) ) ); + + var material = new THREE.MeshNormalMaterial(); + + for ( var i = 0; i < 1000; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = Math.random() * 4000 - 2000; + mesh.position.y = Math.random() * 4000 - 2000; + mesh.position.z = Math.random() * 4000 - 2000; + mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 4 + 2; + scene.add( mesh ); + + } + + scene.matrixAutoUpdate = false; + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = false; + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ) * 10; + mouseY = ( event.clientY - windowHalfY ) * 10; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.0005; + + sphere.position.x = Math.sin( time * 0.7 ) * 2000; + sphere.position.y = Math.cos( time * 0.5 ) * 2000; + sphere.position.z = Math.cos( time * 0.3 ) * 2000; + + for ( var i = 1, l = scene.children.length; i < l; i ++ ) { + + scene.children[ i ].lookAt( sphere.position ); + + } + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_sound.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container; + var camera, controls, scene, renderer; + var light, pointLight; + + var mesh; + var material_sphere1, material_sphere2; + + var sound1, sound2; + + var clock = new THREE.Clock(); + + var Sound = function ( sources, radius, volume ) { + + var audio = document.createElement( 'audio' ); + + for ( var i = 0; i < sources.length; i ++ ) { + + var source = document.createElement( 'source' ); + source.src = sources[ i ]; + + audio.appendChild( source ); + + } + + this.position = new THREE.Vector3(); + + this.play = function () { + + audio.play(); + + } + + this.update = function ( camera ) { + + var distance = this.position.distanceTo( camera.position ); + + if ( distance <= radius ) { + + audio.volume = volume * ( 1 - distance / radius ); + + } else { + + audio.volume = 0; + + } + + } + + } + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 25, 0 ); + + controls = new THREE.FirstPersonControls( camera ); + + controls.movementSpeed = 70; + controls.lookSpeed = 0.05; + controls.noFly = true; + controls.lookVertical = false; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0x000000, 0.0035 ); + + light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0.5, 1 ).normalize(); + scene.add( light ); + + var sphere = new THREE.SphereGeometry( 20, 32, 16 ); + + material_sphere1 = new THREE.MeshLambertMaterial( { color: 0xffaa00, shading: THREE.FlatShading } ); + material_sphere2 = new THREE.MeshLambertMaterial( { color: 0xff2200, shading: THREE.FlatShading } ); + + // sound spheres + + var s = 1; + + var mesh1 = new THREE.Mesh( sphere, material_sphere1 ); + mesh1.position.set( -250, 30, 0 ); + mesh1.scale.set( s, s, s ); + scene.add( mesh1 ); + + sound1 = new Sound( [ 'sounds/358232_j_s_song.mp3', 'sounds/358232_j_s_song.ogg' ], 275, 1 ); + sound1.position.copy( mesh1.position ); + sound1.play(); + + // + + var mesh2 = new THREE.Mesh( sphere, material_sphere2 ); + mesh2.position.set( 250, 30, 0 ); + mesh2.scale.set( s, s, s ); + scene.add( mesh2 ); + + sound2 = new Sound( [ 'sounds/376737_Skullbeatz___Bad_Cat_Maste.mp3', 'sounds/376737_Skullbeatz___Bad_Cat_Maste.ogg' ], 275, 1 ); + sound2.position.copy( mesh2.position ); + sound2.play(); + + + // ground + + var material = new THREE.MeshLambertMaterial( { color: 0x7f7566, wireframe: true, wireframeLinewidth: 1 } ); + + mesh = new THREE.Mesh( new THREE.PlaneGeometry( 1000, 1000, 100, 100 ), material ); + mesh.position.y = 0.1; + mesh.rotation.x = - Math.PI / 2; + scene.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1, antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + container.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function animate() { + + requestAnimationFrame( animate ); + render(); + + } + + + function render() { + + var delta = clock.getDelta(), + time = clock.getElapsedTime() * 5; + + controls.update( delta ); + + material_sphere1.color.setHSL( 0.0, 0.3 + 0.7 * ( 1 + Math.cos( time ) ) / 2, 0.5 ); + material_sphere2.color.setHSL( 0.1, 0.3 + 0.7 * ( 1 + Math.sin( time ) ) / 2, 0.5 ); + + renderer.render( scene, camera ); + + sound1.update( camera ); + sound2.update( camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_ubiquity_test.html + +()=>{ + var SCREEN_WIDTH = window.innerWidth / 2; + var SCREEN_HEIGHT = window.innerHeight / 2; + var AMOUNT = 100; + + var container, stats; + + var camera, scene; + var canvasRenderer, svgRenderer, softwareRenderer, webglRenderer; + + var mesh, group; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + // QRCODE + + mesh = new THREE.Mesh( new Qrcode(), new THREE.MeshLambertMaterial( { /*emissive: 0xff0000,*/ vertexColors: THREE.FaceColors } ) ); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add( mesh ); + + // CUBES + + var cube = new THREE.CubeGeometry( 100, 100, 100 ); + + mesh = new THREE.Mesh( cube, new THREE.MeshBasicMaterial( { color: 0x0000ff, opacity: 0.5, transparent: true } ) ); + mesh.position.x = 500; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add( mesh ); + + mesh = new THREE.Mesh( cube, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) ); + mesh.position.x = 500; + mesh.position.y = 500; + mesh.rotation.x = Math.random(); + mesh.rotation.y = Math.random(); + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add( mesh ); + + // PLANE + + mesh = new THREE.Mesh( new THREE.PlaneGeometry( 100, 100 ), new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, side: THREE.DoubleSide } ) ); + mesh.position.y = -500; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add( mesh ); + + // CYLINDER + + mesh = new THREE.Mesh( new THREE.CylinderGeometry( 20, 100, 200, 10 ), new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) ); + mesh.position.x = -500; + mesh.rotation.x = - Math.PI / 2; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 2; + scene.add( mesh ); + + // POLYFIELD + + var geometry = new THREE.Geometry(); + var materials = []; + + for ( var i = 0; i < 100; i ++ ) { + + var v = new THREE.Vector3( Math.random() * 1000 - 500, Math.random() * 1000 - 500, Math.random() * 1000 - 500 ); + + var v0 = new THREE.Vector3( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); + var v1 = new THREE.Vector3( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); + var v2 = new THREE.Vector3( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); + + v0.add( v ); + v1.add( v ); + v2.add( v ); + + var face = new THREE.Face3( geometry.vertices.push( v0 ) - 1, geometry.vertices.push( v1 ) - 1, geometry.vertices.push( v2 ) - 1, null, null, i ); + + geometry.faces.push( face ); + + materials.push( new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, side: THREE.DoubleSide } ) ); + + } + + geometry.computeFaceNormals(); + geometry.computeCentroids(); + + group = new THREE.Object3D(); + group.scale.x = group.scale.y = group.scale.z = 2; + scene.add( group ); + + mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) ); + group.add( mesh ); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x80ffff ); + scene.add( ambient ); + + var directional = new THREE.DirectionalLight( 0xffff00 ); + directional.position.set( - 1, 0.5, 0 ); + scene.add( directional ); + + canvasRenderer = new THREE.CanvasRenderer(); + canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( canvasRenderer.domElement ); + + svgRenderer = new THREE.SVGRenderer(); + svgRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + svgRenderer.setQuality( 'low' ); + container.appendChild( svgRenderer.domElement ); + + softwareRenderer = new THREE.SoftwareRenderer(); + softwareRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( softwareRenderer.domElement ); + + webglRenderer = new THREE.WebGLRenderer( { antialias: true } ); + webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( webglRenderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + SCREEN_WIDTH = window.innerWidth / 2; + SCREEN_HEIGHT = window.innerHeight / 2; + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + svgRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + softwareRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.lookAt( scene.position ); + + group.rotation.y += 0.01; + + canvasRenderer.render( scene, camera ); + svgRenderer.render( scene, camera ); + softwareRenderer.render( scene, camera ); + webglRenderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/misc_uv_tests.html + +()=>{ + /* + * This is to help debug UVs problems in geometry, + * as well as allow a new user to visualize what UVs are about. + */ + + + function test(name, geometry) { + + var d = document.createElement('div'); + d.innerHTML = '

' + name + '
'; + d.appendChild(THREE.UVsDebug(geometry)); + document.body.appendChild(d); + + } + + + test('new THREE.PlaneGeometry( 100, 100, 4, 4 )', new THREE.PlaneGeometry( 100, 100, 4, 4 )); + test('new THREE.SphereGeometry( 75, 12, 6 )', new THREE.SphereGeometry( 75, 12, 6 )); + + test('new THREE.IcosahedronGeometry( 30, 1 )', new THREE.IcosahedronGeometry( 30, 1 )); + test('new THREE.OctahedronGeometry( 30, 2 )', new THREE.OctahedronGeometry( 30, 2 )); + + test('new THREE.CylinderGeometry( 25, 75, 100, 10, 5 )', new THREE.CylinderGeometry( 25, 75, 100, 10, 5 )); + + test('new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 )', new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 )); + + var points = []; + + for ( var i = 0; i < 10; i ++ ) { + + points.push( new THREE.Vector3( Math.sin( i * 0.2 ) * 15 + 50, 0, ( i - 5 ) * 2 ) ); + + } + + + test('new THREE.LatheGeometry( points, 8 )', new THREE.LatheGeometry( points, 8 )); + test('new THREE.TorusGeometry( 50, 20, 8, 8 )', new THREE.TorusGeometry( 50, 20, 8, 8 )); + test('new THREE.TorusKnotGeometry( 50, 10, 12, 6 )', new THREE.TorusKnotGeometry( 50, 10, 12, 6 )); + + /* + Not sure how UVs for ExtrudeGeometry are done currently... + */ + + var pts = [], starPoints = 5, l; + for (i=0; i{ + var container, stats; + + var camera, controls, scene, renderer; + + var torus, cube; + + var start = Date.now(); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js - software renderer
drag to change the point of view'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 600; + + controls = new THREE.TrackballControls( camera ); + + scene = new THREE.Scene(); + + torus = new THREE.Mesh( new THREE.TorusKnotGeometry( 150 ), new THREE.MeshBasicMaterial( { color: 0x0000ff } ) ); + scene.add( torus ); + + // Plane + + cube = new THREE.Mesh( new THREE.CubeGeometry( 200, 200, 200 ), new THREE.MeshBasicMaterial( { color: 0x00ff00 } ) ); + scene.add( cube ); + + renderer = new THREE.SoftwareRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() - start; + + torus.position.y = Math.sin( timer * 0.002 ) * 150; + torus.rotation.x = timer * 0.0003; + torus.rotation.z = timer * 0.0002; + + cube.rotation.x = timer * 0.0002; + cube.rotation.z = timer * 0.0003; + + + controls.update(); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_animation_cloth.html + + +declare var cloth: any; +declare var clothFunction: any; +declare var ballSize: number; +declare var windStrength: number; +declare var windForce: THREE.Vector3; +declare function simulate(time: number); +declare var ballPosition: THREE.Vector3; +()=>{ + /* testing cloth simulation */ + + var pinsFormation = []; + var pins = [6]; + + pinsFormation.push( pins ); + + pins = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; + pinsFormation.push( pins ); + + pins = [ 0 ]; + pinsFormation.push( pins ); + + pins = []; // cut the rope ;) + pinsFormation.push( pins ); + + pins = [ 0, cloth.w ]; // classic 2 pins + pinsFormation.push( pins ); + + pins = pinsFormation[ 1 ]; + + + function togglePins() { + + pins = pinsFormation[ ~~( Math.random() * pinsFormation.length ) ]; + + } + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + var camera, scene, renderer; + + var clothGeometry; + var sphere; + var object, arrow; + + var rotate = true; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + // scene + + scene = new THREE.Scene(); + + scene.fog = new THREE.Fog( 0xcce0ff, 500, 10000 ); + + // camera + + camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.y = 50; + camera.position.z = 1500; + scene.add( camera ); + + // lights + + var light, materials; + + scene.add( new THREE.AmbientLight( 0x666666 ) ); + + light = new THREE.DirectionalLight( 0xdfebff, 1.75 ); + light.position.set( 50, 200, 100 ); + light.position.multiplyScalar( 1.3 ); + + light.castShadow = true; + //light.shadowCameraVisible = true; + + light.shadowMapWidth = 2048; + light.shadowMapHeight = 2048; + + var d = 300; + + light.shadowCameraLeft = -d; + light.shadowCameraRight = d; + light.shadowCameraTop = d; + light.shadowCameraBottom = -d; + + light.shadowCameraFar = 1000; + light.shadowDarkness = 0.5; + + scene.add( light ); + + light = new THREE.DirectionalLight( 0x3dff0c, 0.35 ); + light.position.set( 0, -1, 0 ); + + scene.add( light ); + + // cloth material + + var clothTexture = THREE.ImageUtils.loadTexture( 'textures/patterns/circuit_pattern.png' ); + clothTexture.wrapS = clothTexture.wrapT = THREE.RepeatWrapping; + clothTexture.anisotropy = 16; + + var clothMaterial = new THREE.MeshPhongMaterial( { alphaTest: 0.5, ambient: 0xffffff, color: 0xffffff, specular: 0x030303, emissive: 0x111111, shiness: 10, map: clothTexture, side: THREE.DoubleSide } ); + + // cloth geometry + clothGeometry = new THREE.ParametricGeometry( clothFunction, cloth.w, cloth.h, true ); + clothGeometry.dynamic = true; + clothGeometry.computeFaceNormals(); + + var uniforms = { texture: { type: "t", value: clothTexture } }; + var vertexShader = document.getElementById( 'vertexShaderDepth' ).textContent; + var fragmentShader = document.getElementById( 'fragmentShaderDepth' ).textContent; + + // cloth mesh + + object = new THREE.Mesh( clothGeometry, clothMaterial ); + object.position.set( 0, 0, 0 ); + object.castShadow = true; + object.receiveShadow = true; + scene.add( object ); + + object.customDepthMaterial = new THREE.ShaderMaterial( { uniforms: uniforms, vertexShader: vertexShader, fragmentShader: fragmentShader } ); + + // sphere + + var ballGeo = new THREE.SphereGeometry( ballSize, 20, 20 ); + var ballMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } ); + + sphere = new THREE.Mesh( ballGeo, ballMaterial ); + sphere.castShadow = true; + sphere.receiveShadow = true; + scene.add( sphere ); + + // arrow + + arrow = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50, 0xff0000 ); + arrow.position.set( -200, 0, -200 ); + // scene.add( arrow ); + + // ground + + var initColor = new THREE.Color( 0x497f13 ); + var initTexture = THREE.ImageUtils.generateDataTexture( 1, 1, initColor ); + + var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: initTexture } ); + + var groundTexture = THREE.ImageUtils.loadTexture( "textures/terrain/grasslight-big.jpg", undefined, function() { groundMaterial.map = groundTexture } ); + groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping; + groundTexture.repeat.set( 25, 25 ); + groundTexture.anisotropy = 16; + + var mesh = new THREE.Mesh( new THREE.PlaneGeometry( 20000, 20000 ), groundMaterial ); + mesh.position.y = -250; + mesh.rotation.x = - Math.PI / 2; + mesh.receiveShadow = true; + scene.add( mesh ); + + // poles + + var poleGeo = new THREE.CubeGeometry( 5, 375, 5 ); + var poleMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shiness: 100 } ); + + var mesh = new THREE.Mesh( poleGeo, poleMat ); + mesh.position.x = -125; + mesh.position.y = -62; + mesh.receiveShadow = true; + mesh.castShadow = true; + scene.add( mesh ); + + var mesh = new THREE.Mesh( poleGeo, poleMat ); + mesh.position.x = 125; + mesh.position.y = -62; + mesh.receiveShadow = true; + mesh.castShadow = true; + scene.add( mesh ); + + var mesh = new THREE.Mesh( new THREE.CubeGeometry( 255, 5, 5 ), poleMat ); + mesh.position.y = -250 + 750/2; + mesh.position.x = 0; + mesh.receiveShadow = true; + mesh.castShadow = true; + scene.add( mesh ); + + var gg = new THREE.CubeGeometry( 10, 10, 10 ); + var mesh = new THREE.Mesh( gg, poleMat ); + mesh.position.y = -250; + mesh.position.x = 125; + mesh.receiveShadow = true; + mesh.castShadow = true; + scene.add( mesh ); + + var mesh = new THREE.Mesh( gg, poleMat ); + mesh.position.y = -250; + mesh.position.x = -125; + mesh.receiveShadow = true; + mesh.castShadow = true; + scene.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color ); + + container.appendChild( renderer.domElement ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + renderer.shadowMapEnabled = true; + + // + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + sphere.visible = !true + + } + + // + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + var time = Date.now(); + + windStrength = Math.cos( time / 7000 ) * 20 + 40; + windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) ).normalize().multiplyScalar( windStrength ); + arrow.setLength( windStrength ); + arrow.setDirection( windForce ); + + simulate(time); + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0002; + + var p = cloth.particles; + + for ( var i = 0, il = p.length; i < il; i ++ ) { + + clothGeometry.vertices[ i ].copy( p[ i ].position ); + + } + + clothGeometry.computeFaceNormals(); + clothGeometry.computeVertexNormals(); + + clothGeometry.normalsNeedUpdate = true; + clothGeometry.verticesNeedUpdate = true; + + sphere.position.copy( ballPosition ); + + if ( rotate ) { + + camera.position.x = Math.cos( timer ) * 1500; + camera.position.z = Math.sin( timer ) * 1500; + + } + + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_animation_skinning.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + window.onload = init; + + var container, stats; + + var camera, scene, renderer; + + var mesh, light; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var animations = []; + var buffalos = []; + var offset = []; + + var floor, dz = 0, dstep = -10, playback = false; + + var clock = new THREE.Clock(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 185, 2500 ); + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xfff4e5, 0.0003 ); + + light = new THREE.DirectionalLight( 0xffffff, 1.5 ); + light.position.set( 0, 1, 1 ).normalize(); + scene.add( light ); + + var planeSimple = new THREE.PlaneGeometry( 200, 300 ); + var planeTesselated = new THREE.PlaneGeometry( 100, 300, 25, 40 ); + var matWire = new THREE.MeshBasicMaterial( { color: 0x110000, wireframe: true, wireframeLinewidth: 2 } ); + var matSolid = new THREE.MeshBasicMaterial( { color: 0xffb23f } ); + + floor = new THREE.Mesh( planeSimple, matSolid ); + floor.position.y = -10; + floor.rotation.x = - Math.PI / 2; + floor.scale.set( 25, 25, 25 ); + scene.add( floor ); + + floor = new THREE.Mesh( planeTesselated, matWire ); + floor.rotation.x = - Math.PI / 2; + floor.scale.set( 25, 25, 25 ); + scene.add( floor ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0xffffff, clearAlpha: 1, antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color, 1 ); + renderer.sortObjects = false; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'click', startAnimation, false ); + + var loader = new THREE.JSONLoader(); + loader.load( "obj/buffalo/buffalo.js", createScene ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + // + + loop(); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function createScene( geometry, materials ) { + + buffalos = []; + animations = []; + + var x, y, + buffalo, animation, + gridx = 25, gridz = 15, + sepx = 150, sepz = 300; + + var material = new THREE.MeshFaceMaterial( materials ); + + var originalMaterial = materials[ 0 ]; + + originalMaterial.skinning = true; + originalMaterial.transparent = true; + originalMaterial.alphaTest = 0.75; + + THREE.AnimationHandler.add( geometry.animation ); + + for(var x = 0; x < gridx; x ++ ) { + + for(var z = 0; z < gridz; z ++ ) { + + buffalo = new THREE.SkinnedMesh( geometry, material, false ); + + buffalo.position.x = - ( gridx - 1 ) * sepx * 0.5 + x * sepx + Math.random() * 0.5 * sepx; + buffalo.position.z = - ( gridz - 1 ) * sepz * 0.5 + z * sepz + Math.random() * 0.5 * sepz - 500; + + buffalo.position.y = buffalo.geometry.boundingSphere.radius * 0.5; + buffalo.rotation.y = 0.2 - Math.random() * 0.4; + + scene.add( buffalo ); + + buffalos.push( buffalo ); + + animation = new THREE.Animation( buffalo, "take_001" ); + animations.push( animation ); + + offset.push( Math.random() ); + + } + + } + + } + + function startAnimation() { + + for( var i = 0; i < animations.length; i ++ ) { + + animations[ i ].offset = 0.05 * Math.random(); + animations[ i ].play(); + + } + + dz = dstep; + playback = true; + + } + + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + function loop() { + + requestAnimationFrame( loop ); + + var delta = clock.getDelta(); + + THREE.AnimationHandler.update( delta ); + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.lookAt( scene.position ); + + if ( buffalos && playback ) { + + var elapsed = clock.getElapsedTime(); + + camera.position.z += 2 * Math.sin( elapsed ); + + for(var i = 0; i < buffalos.length; i++ ) { + + buffalos[ i ].position.z += 2 * Math.sin( elapsed + offset[ i ] ); + + } + + } + + floor.position.z += dz; + if( floor.position.z < -500 ) floor.position.z = 0; + + + renderer.render( scene, camera ); + + stats.update(); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_animation_skinning_morph.html + +()=>{ + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + var FLOOR = -250; + + var container,stats; + + var camera, scene; + var renderer; + + var mesh; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var clock = new THREE.Clock(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 30, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 ); + camera.position.z = 2200; + + scene = new THREE.Scene(); + + scene.fog = new THREE.Fog( 0xffffff, 2000, 10000 ); + + scene.add( camera ); + + // GROUND + + var groundMaterial = new THREE.MeshPhongMaterial( { emissive: 0xbbbbbb } ); + var planeGeometry = new THREE.PlaneGeometry( 16000, 16000 ); + + var ground = new THREE.Mesh( planeGeometry, groundMaterial ); + ground.position.set( 0, FLOOR, 0 ); + ground.rotation.x = -Math.PI/2; + scene.add( ground ); + + ground.receiveShadow = true; + + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x222222 ); + scene.add( ambient ); + + + var light = new THREE.DirectionalLight( 0xebf3ff, 1.6 ); + light.position.set( 0, 140, 500 ).multiplyScalar( 1.1 ); + scene.add( light ); + + light.castShadow = true; + + light.shadowMapWidth = 2048; + light.shadowMapHeight = 2048; + + var d = 390; + + light.shadowCameraLeft = -d * 2; + light.shadowCameraRight = d * 2; + light.shadowCameraTop = d * 1.5; + light.shadowCameraBottom = -d; + + light.shadowCameraFar = 3500; + //light.shadowCameraVisible = true; + + // + + var light = new THREE.DirectionalLight( 0x497f13, 1 ); + light.position.set( 0, -1, 0 ); + scene.add( light ); + + // RENDERER + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + renderer.shadowMapEnabled = true; + + + // STATS + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // + + var loader = new THREE.JSONLoader(); + loader.load( "models/skinned/knight.js", function ( geometry, materials ) { createScene( geometry, materials, 0, FLOOR, -300, 60 ) } ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function ensureLoop( animation ) { + + for ( var i = 0; i < animation.hierarchy.length; i ++ ) { + + var bone = animation.hierarchy[ i ]; + + var first = bone.keys[ 0 ]; + var last = bone.keys[ bone.keys.length - 1 ]; + + last.pos = first.pos; + last.rot = first.rot; + last.scl = first.scl; + + } + + } + + function createScene( geometry, materials, x, y, z, s ) { + + ensureLoop( geometry.animation ); + + geometry.computeBoundingBox(); + var bb = geometry.boundingBox; + + THREE.AnimationHandler.add( geometry.animation ); + + var path = "textures/cube/Park2/"; + var format = '.jpg'; + var urls = [ + path + 'posx' + format, path + 'negx' + format, + path + 'posy' + format, path + 'negy' + format, + path + 'posz' + format, path + 'negz' + format + ]; + + + //var envMap = THREE.ImageUtils.loadTextureCube( urls ); + + //var map = THREE.ImageUtils.loadTexture( "textures/ash_uvgrid01.jpg" ); + + //var bumpMap = THREE.ImageUtils.generateDataTexture( 1, 1, new THREE.Color() ); + //var bumpMap = THREE.ImageUtils.loadTexture( "textures/water.jpg" ); + + for ( var i = 0; i < materials.length; i ++ ) { + + var m = materials[ i ]; + m.skinning = true; + m.morphTargets = true; + + m.specular.setHSL( 0, 0, 0.1 ); + + m.color.setHSL( 0.6, 0, 0.6 ); + m.ambient.copy( m.color ); + + //m.map = map; + //m.envMap = envMap; + //m.bumpMap = bumpMap; + //m.bumpScale = 2; + + //m.combine = THREE.MixOperation; + //m.reflectivity = 0.75; + + m.wrapAround = true; + + } + + mesh = new THREE.SkinnedMesh( geometry, new THREE.MeshFaceMaterial( materials ) ); + mesh.position.set( x, y - bb.min.y * s, z ); + mesh.scale.set( s, s, s ); + scene.add( mesh ); + + mesh.castShadow = true; + mesh.receiveShadow = true; + + var animation = new THREE.Animation( mesh, geometry.animation.name ); + animation.JITCompile = false; + animation.interpolationType = THREE.AnimationHandler.LINEAR; + + animation.play(); + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = 0.75 * clock.getDelta(); + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y = THREE.Math.clamp( camera.position.y + ( - mouseY - camera.position.y ) * .05, 0, 1000 ); + + camera.lookAt( scene.position ); + + // update skinning + + THREE.AnimationHandler.update( delta ); + + // update morphs + + if ( mesh ) { + + var time = Date.now() * 0.001; + + // mouth + + mesh.morphTargetInfluences[ 1 ] = ( 1 + Math.sin( 4 * time ) ) / 2; + + // frown ? + + mesh.morphTargetInfluences[ 2 ] = ( 1 + Math.sin( 2 * time ) ) / 2; + + // eyes + + mesh.morphTargetInfluences[ 3 ] = ( 1 + Math.cos( 4 * time ) ) / 2; + + } + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + var mesh; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + // + + camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 3500 ); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x050505, 2000, 3500 ); + + // + + scene.add( new THREE.AmbientLight( 0x444444 ) ); + + var light1 = new THREE.DirectionalLight( 0xffffff, 0.5 ); + light1.position.set( 1, 1, 1 ); + scene.add( light1 ); + + var light2 = new THREE.DirectionalLight( 0xffffff, 1.5 ); + light2.position.set( 0, -1, 0 ); + scene.add( light2 ); + + // + + var triangles = 160000; + + var geometry = new THREE.BufferGeometry(); + geometry.attributes = { + index: { + itemSize: 1, + array: new Uint16Array( triangles * 3 ), + numItems: triangles * 3 + }, + position: { + itemSize: 3, + array: new Float32Array( triangles * 3 * 3 ), + numItems: triangles * 3 * 3 + }, + normal: { + itemSize: 3, + array: new Float32Array( triangles * 3 * 3 ), + numItems: triangles * 3 * 3 + }, + color: { + itemSize: 3, + array: new Float32Array( triangles * 3 * 3 ), + numItems: triangles * 3 * 3 + } + } + + // break geometry into + // chunks of 21,845 triangles (3 unique vertices per triangle) + // for indices to fit into 16 bit integer number + // floor(2^16 / 3) = 21845 + + var chunkSize = 21845; + + var indices = geometry.attributes.index.array; + + for ( var i = 0; i < indices.length; i ++ ) { + + indices[ i ] = i % ( 3 * chunkSize ); + + } + + var positions = geometry.attributes.position.array; + var normals = geometry.attributes.normal.array; + var colors = geometry.attributes.color.array; + + var color = new THREE.Color(); + + var n = 800, n2 = n/2; // triangles spread in the cube + var d = 12, d2 = d/2; // individual triangle size + + var pA = new THREE.Vector3(); + var pB = new THREE.Vector3(); + var pC = new THREE.Vector3(); + + var cb = new THREE.Vector3(); + var ab = new THREE.Vector3(); + + for ( var i = 0; i < positions.length; i += 9 ) { + + // positions + + var x = Math.random() * n - n2; + var y = Math.random() * n - n2; + var z = Math.random() * n - n2; + + var ax = x + Math.random() * d - d2; + var ay = y + Math.random() * d - d2; + var az = z + Math.random() * d - d2; + + var bx = x + Math.random() * d - d2; + var by = y + Math.random() * d - d2; + var bz = z + Math.random() * d - d2; + + var cx = x + Math.random() * d - d2; + var cy = y + Math.random() * d - d2; + var cz = z + Math.random() * d - d2; + + positions[ i ] = ax; + positions[ i + 1 ] = ay; + positions[ i + 2 ] = az; + + positions[ i + 3 ] = bx; + positions[ i + 4 ] = by; + positions[ i + 5 ] = bz; + + positions[ i + 6 ] = cx; + positions[ i + 7 ] = cy; + positions[ i + 8 ] = cz; + + // flat face normals + + pA.set( ax, ay, az ); + pB.set( bx, by, bz ); + pC.set( cx, cy, cz ); + + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); + + cb.normalize(); + + var nx = cb.x; + var ny = cb.y; + var nz = cb.z; + + normals[ i ] = nx; + normals[ i + 1 ] = ny; + normals[ i + 2 ] = nz; + + normals[ i + 3 ] = nx; + normals[ i + 4 ] = ny; + normals[ i + 5 ] = nz; + + normals[ i + 6 ] = nx; + normals[ i + 7 ] = ny; + normals[ i + 8 ] = nz; + + // colors + + var vx = ( x / n ) + 0.5; + var vy = ( y / n ) + 0.5; + var vz = ( z / n ) + 0.5; + + //color.setHSV( 0.5 + 0.5 * vx, 0.25 + 0.75 * vy, 0.25 + 0.75 * vz ); + color.setRGB( vx, vy, vz ); + + colors[ i ] = color.r; + colors[ i + 1 ] = color.g; + colors[ i + 2 ] = color.b; + + colors[ i + 3 ] = color.r; + colors[ i + 4 ] = color.g; + colors[ i + 5 ] = color.b; + + colors[ i + 6 ] = color.r; + colors[ i + 7 ] = color.g; + colors[ i + 8 ] = color.b; + + } + + geometry.offsets = []; + + var offsets = triangles / chunkSize; + + for ( var i = 0; i < offsets; i ++ ) { + + var offset = { + start: i * chunkSize * 3, + index: i * chunkSize * 3, + count: Math.min( triangles - ( i * chunkSize ), chunkSize ) * 3 + }; + + geometry.offsets.push( offset ); + + } + + geometry.computeBoundingSphere(); + + var material = new THREE.MeshPhongMaterial( { + color: 0xaaaaaa, ambient: 0xaaaaaa, specular: 0xffffff, shininess: 250, + side: THREE.DoubleSide, vertexColors: THREE.VertexColors + } ); + + mesh = new THREE.Mesh( geometry, material ); + scene.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: false, clearColor: 0x333333, clearAlpha: 1, alpha: false } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color, 1 ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_lines.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + var mesh; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + // + + camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 4000 ); + camera.position.z = 2750; + + scene = new THREE.Scene(); + + + var segments = 10000; + + var geometry = new THREE.BufferGeometry(); + var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors }); + + geometry.attributes = { + position: { + itemSize: 3, + array: new Float32Array(segments * 3), + numItems: segments * 3 + }, + color: { + itemSize: 3, + array: new Float32Array(segments * 3), + numItems: segments * 3 + } + }; + + var positions = geometry.attributes.position.array; + var colors = geometry.attributes.color.array; + + var r = 800; + + for ( var i = 0; i < segments; i ++ ) { + + var x = Math.random() * r - r / 2; + var y = Math.random() * r - r / 2; + var z = Math.random() * r - r / 2; + + // positions + + positions[ i * 3 ] = x; + positions[ i * 3 + 1 ] = y; + positions[ i * 3 + 2 ] = z; + + // colors + + colors[ i * 3 ] = ( x / r ) + 0.5; + colors[ i * 3 + 1 ] = ( y / r ) + 0.5; + colors[ i * 3 + 2 ] = ( z / r ) + 0.5; + + } + + geometry.computeBoundingSphere(); + + mesh = new THREE.Line( geometry, material ); + scene.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: false, clearColor: 0x000000, clearAlpha: 0, alpha: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + mesh.rotation.x = time * 0.25; + mesh.rotation.y = time * 0.5; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_buffergeometry_particles.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + var mesh; + + var particleSystem; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + // + + camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 5, 3500 ); + camera.position.z = 2750; + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x050505, 2000, 3500 ); + + // + + var particles = 500000; + + var geometry = new THREE.BufferGeometry(); + geometry.attributes = { + + position: { + itemSize: 3, + array: new Float32Array( particles * 3 ), + numItems: particles * 3 + }, + color: { + itemSize: 3, + array: new Float32Array( particles * 3 ), + numItems: particles * 3 + } + + } + + + var positions = geometry.attributes.position.array; + var colors = geometry.attributes.color.array; + + var color = new THREE.Color(); + + var n = 1000, n2 = n / 2; // particles spread in the cube + + for ( var i = 0; i < positions.length; i += 3 ) { + + // positions + + var x = Math.random() * n - n2; + var y = Math.random() * n - n2; + var z = Math.random() * n - n2; + + positions[ i ] = x; + positions[ i + 1 ] = y; + positions[ i + 2 ] = z; + + // colors + + var vx = ( x / n ) + 0.5; + var vy = ( y / n ) + 0.5; + var vz = ( z / n ) + 0.5; + + color.setRGB( vx, vy, vz ); + + colors[ i ] = color.r; + colors[ i + 1 ] = color.g; + colors[ i + 2 ] = color.b; + + } + + geometry.computeBoundingSphere(); + + // + + var material = new THREE.ParticleBasicMaterial( { size: 15, vertexColors: true } ); + + particleSystem = new THREE.ParticleSystem( geometry, material ); + scene.add( particleSystem ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: false, clearColor: 0x333333, clearAlpha: 1, alpha: false } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + particleSystem.rotation.x = time * 0.25; + particleSystem.rotation.y = time * 0.5; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_camera.html + +()=>{ + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + + var container, stats; + var camera, scene, renderer, mesh; + var cameraRig, activeCamera, activeHelper; + var cameraPerspective, cameraOrtho; + var cameraPerspectiveHelper, cameraOrthoHelper; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + scene = new THREE.Scene(); + + // + + camera = new THREE.PerspectiveCamera( 50, 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 ); + camera.position.z = 2500; + + cameraPerspective = new THREE.PerspectiveCamera( 50, 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT, 150, 1000 ); + + cameraPerspectiveHelper = new THREE.CameraHelper( cameraPerspective ); + scene.add( cameraPerspectiveHelper ); + + // + + cameraOrtho = new THREE.OrthographicCamera( 0.5 * SCREEN_WIDTH / - 2, 0.5 * SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, 150, 1000 ); + + cameraOrthoHelper = new THREE.CameraHelper( cameraOrtho ); + scene.add( cameraOrthoHelper ); + + // + + activeCamera = cameraPerspective; + activeHelper = cameraPerspectiveHelper; + + + // counteract different front orientation of cameras vs rig + + cameraOrtho.rotation.y = Math.PI; + cameraPerspective.rotation.y = Math.PI; + + cameraRig = new THREE.Object3D(); + + cameraRig.add( cameraPerspective ); + cameraRig.add( cameraOrtho ); + + scene.add( cameraRig ); + + // + + mesh = new THREE.Mesh( new THREE.SphereGeometry( 100, 16, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true } ) ); + scene.add( mesh ); + + var mesh2 = new THREE.Mesh( new THREE.SphereGeometry( 50, 16, 8 ), new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe: true } ) ); + mesh2.position.y = 150; + mesh.add( mesh2 ); + + var mesh3 = new THREE.Mesh( new THREE.SphereGeometry( 5, 16, 8 ), new THREE.MeshBasicMaterial( { color: 0x0000ff, wireframe: true } ) ); + mesh3.position.z = 150; + cameraRig.add( mesh3 ); + + // + + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < 10000; i ++ ) { + + var vertex = new THREE.Vector3(); + vertex.x = THREE.Math.randFloatSpread( 2000 ); + vertex.y = THREE.Math.randFloatSpread( 2000 ); + vertex.z = THREE.Math.randFloatSpread( 2000 ); + + geometry.vertices.push( vertex ); + + } + + var particles = new THREE.ParticleSystem( geometry, new THREE.ParticleBasicMaterial( { color: 0x888888 } ) ); + scene.add( particles ); + + // + + + renderer = new THREE.WebGLRenderer( { antialias: true, clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + container.appendChild( renderer.domElement ); + + renderer.autoClear = false; + + // + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + document.addEventListener( 'keydown', onKeyDown, false ); + + } + + // + + function onKeyDown ( event ) { + + switch( event.keyCode ) { + + case 79: /*O*/ + + activeCamera = cameraOrtho; + activeHelper = cameraOrthoHelper; + + break; + + case 80: /*P*/ + + activeCamera = cameraPerspective; + activeHelper = cameraPerspectiveHelper; + + break; + + } + + }; + + // + + function onWindowResize( event ) { + + SCREEN_WIDTH = window.innerWidth; + SCREEN_HEIGHT = window.innerHeight; + + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + camera.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + cameraPerspective.aspect = 0.5 * SCREEN_WIDTH / SCREEN_HEIGHT; + cameraPerspective.updateProjectionMatrix(); + + cameraOrtho.left = - 0.5 * SCREEN_WIDTH / 2; + cameraOrtho.right = 0.5 * SCREEN_WIDTH / 2; + cameraOrtho.top = SCREEN_HEIGHT / 2; + cameraOrtho.bottom = - SCREEN_HEIGHT / 2; + cameraOrtho.updateProjectionMatrix(); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + + function render() { + + var r = Date.now() * 0.0005; + + mesh.position.x = 700 * Math.cos( r ); + mesh.position.z = 700 * Math.sin( r ); + mesh.position.y = 700 * Math.sin( r ); + + mesh.children[ 0 ].position.x = 70 * Math.cos( 2 * r ); + mesh.children[ 0 ].position.z = 70 * Math.sin( r ); + + if ( activeCamera === cameraPerspective ) { + + cameraPerspective.fov = 35 + 30 * Math.sin( 0.5 * r ); + cameraPerspective.far = mesh.position.length(); + cameraPerspective.updateProjectionMatrix(); + + cameraPerspectiveHelper.update(); + cameraPerspectiveHelper.visible = true; + + cameraOrthoHelper.visible = false; + + } else { + + cameraOrtho.far = mesh.position.length(); + cameraOrtho.updateProjectionMatrix(); + + cameraOrthoHelper.update(); + cameraOrthoHelper.visible = true; + + cameraPerspectiveHelper.visible = false; + + } + + cameraRig.lookAt( mesh.position ); + + renderer.clear(); + + activeHelper.visible = false; + + renderer.setViewport( 0, 0, SCREEN_WIDTH/2, SCREEN_HEIGHT ); + renderer.render( scene, activeCamera ); + + activeHelper.visible = true; + + renderer.setViewport( SCREEN_WIDTH/2, 0, SCREEN_WIDTH/2, SCREEN_HEIGHT ); + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var sphere, uniforms, attributes; + + var noise = []; + + var WIDTH = window.innerWidth, + HEIGHT = window.innerHeight; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 30, WIDTH / HEIGHT, 1, 10000 ); + camera.position.z = 300; + + scene = new THREE.Scene(); + + attributes = { + + displacement: { type: 'f', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 1.0 }, + color: { type: "c", value: new THREE.Color( 0xff2200 ) }, + texture: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/water.jpg" ) }, + + }; + + uniforms.texture.value.wrapS = uniforms.texture.value.wrapT = THREE.RepeatWrapping; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent + + }); + + + var radius = 50, segments = 128, rings = 64; + var geometry = new THREE.SphereGeometry( radius, segments, rings ); + geometry.dynamic = true; + + sphere = new THREE.Mesh( geometry, shaderMaterial ); + + var vertices = sphere.geometry.vertices; + var values = attributes.displacement.value; + + for ( var v = 0; v < vertices.length; v++ ) { + + values[ v ] = 0; + noise[ v ] = Math.random() * 5; + + } + + scene.add( sphere ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x050505, clearAlpha: 1 } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.01; + + sphere.rotation.y = sphere.rotation.z = 0.01 * time; + + uniforms.amplitude.value = 2.5 * Math.sin( sphere.rotation.y * 0.125 ); + uniforms.color.value.offsetHSL( 0.0005, 0, 0 ); + + for ( var i = 0; i < attributes.displacement.value.length; i ++ ) { + + attributes.displacement.value[ i ] = Math.sin( 0.1 * i + time ); + + noise[ i ] += 0.5 * ( 0.5 - Math.random() ); + noise[ i ] = THREE.Math.clamp( noise[ i ], -5, 5 ); + + attributes.displacement.value[ i ] += noise[ i ]; + + } + + attributes.displacement.needsUpdate = true; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes_lines.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var object, uniforms, attributes; + + var text = "three.js", + + height = 15, + size = 50, + + curveSegments = 10, + steps = 40, + + bevelThickness = 5, + bevelSize = 1.5, + bevelSegments = 10, + bevelEnabled = true, + + font = "helvetiker", // helvetiker, optimer, gentilis, droid sans, droid serif + weight = "bold", // normal bold + style = "normal"; // normal italic + + var WIDTH = window.innerWidth, + HEIGHT = window.innerHeight; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 30, WIDTH / HEIGHT, 1, 10000 ); + camera.position.z = 400; + + scene = new THREE.Scene(); + + attributes = { + + displacement: { type: 'v3', value: [] }, + customColor: { type: 'c', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 5.0 }, + opacity: { type: "f", value: 0.3 }, + color: { type: "c", value: new THREE.Color( 0xff0000 ) } + + }; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent, + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true + + }); + + (shaderMaterial).linewidth = 1; + + var geometry = new THREE.TextGeometry( text, { + + size: size, + height: height, + curveSegments: curveSegments, + + font: font, + weight: weight, + style: style, + + bevelThickness: bevelThickness, + bevelSize: bevelSize, + bevelEnabled: bevelEnabled, + bevelSegments: bevelSegments, + + steps: steps + + }); + + geometry.dynamic = true; + + THREE.GeometryUtils.center( geometry ); + + object = new THREE.Line( geometry, shaderMaterial, THREE.LineStrip ); + + var vertices = object.geometry.vertices; + + var displacement = attributes.displacement.value; + var color = attributes.customColor.value; + + for( var v = 0; v < vertices.length; v ++ ) { + + displacement[ v ] = new THREE.Vector3(); + + color[ v ] = new THREE.Color( 0xffffff ); + color[ v ].setHSL( v / vertices.length, 0.5, 0.5 ); + + } + + object.rotation.x = 0.2; + + scene.add( object ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x050505, clearAlpha: 1, antialias: true } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + object.rotation.y = 0.25 * time; + + uniforms.amplitude.value = 0.5 * Math.sin( 0.5 * time ); + uniforms.color.value.offsetHSL( 0.0005, 0, 0 ); + + var nx, ny, nz, value; + + for( var i = 0, il = attributes.displacement.value.length; i < il; i ++ ) { + + nx = 0.3 * ( 0.5 - Math.random() ); + ny = 0.3 * ( 0.5 - Math.random() ); + nz = 0.3 * ( 0.5 - Math.random() ); + + value = attributes.displacement.value[ i ]; + + value.x += nx; + value.y += ny; + value.z += nz; + + } + + attributes.displacement.needsUpdate = true; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes_particles.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var sphere, uniforms, attributes; + + var noise = []; + + var WIDTH = window.innerWidth; + var HEIGHT = window.innerHeight; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 ); + camera.position.z = 300; + + scene = new THREE.Scene(); + + attributes = { + + size: { type: 'f', value: [] }, + customColor: { type: 'c', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 1.0 }, + color: { type: "c", value: new THREE.Color( 0xffffff ) }, + texture: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/sprites/spark1.png" ) }, + + }; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent, + + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true + + }); + + + var radius = 200; + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < 100000; i++ ) { + + var vertex = new THREE.Vector3(); + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar( radius ); + + geometry.vertices.push( vertex ); + + } + + sphere = new THREE.ParticleSystem( geometry, shaderMaterial ); + + sphere.dynamic = true; + //sphere.sortParticles = true; + + var vertices = sphere.geometry.vertices; + var values_size = attributes.size.value; + var values_color = attributes.customColor.value; + + + for( var v = 0; v < vertices.length; v++ ) { + + values_size[ v ] = 10; + values_color[ v ] = new THREE.Color( 0xffaa00 ); + + if ( vertices[ v ].x < 0 ) + values_color[ v ].setHSL( 0.5 + 0.1 * ( v / vertices.length ), 0.7, 0.9 ); + else + values_color[ v ].setHSL( 0.0 + 0.1 * ( v / vertices.length ), 0.9, 0.9 ); + + } + + scene.add( sphere ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.005; + + sphere.rotation.z = 0.01 * time; + + for( var i = 0; i < attributes.size.value.length; i++ ) { + + attributes.size.value[ i ] = 14 + 13 * Math.sin( 0.1 * i + time ); + + + } + + attributes.size.needsUpdate = true; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes_particles2.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var sphere, uniforms, attributes; + + var vc1; + + var WIDTH = window.innerWidth; + var HEIGHT = window.innerHeight; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 45, WIDTH / HEIGHT, 1, 10000 ); + camera.position.z = 300; + + scene = new THREE.Scene(); + + attributes = { + + size: { type: 'f', value: [] }, + ca: { type: 'c', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 1.0 }, + color: { type: "c", value: new THREE.Color( 0xffffff ) }, + texture: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/sprites/disc.png" ) }, + + }; + + uniforms.texture.value.wrapS = uniforms.texture.value.wrapT = THREE.RepeatWrapping; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent, + transparent: true + + }); + + + var radius = 100, segments = 68, rings = 38; + var geometry = new THREE.SphereGeometry( radius, segments, rings ); + + vc1 = geometry.vertices.length; + + var geometry2 = new THREE.CubeGeometry( 0.8 * radius, 0.8 * radius, 0.8 * radius, 10, 10, 10 ); + + THREE.GeometryUtils.merge( geometry, geometry2 ); + + sphere = new THREE.ParticleSystem( geometry, shaderMaterial ); + + sphere.dynamic = true; + sphere.sortParticles = true; + + var vertices = sphere.geometry.vertices; + var values_size = attributes.size.value; + var values_color = attributes.ca.value; + + for( var v = 0; v < vertices.length; v++ ) { + + values_size[ v ] = 10; + values_color[ v ] = new THREE.Color( 0xffffff ); + + if ( v < vc1 ) { + + values_color[ v ].setHSL( 0.01 + 0.1 * ( v / vc1 ), 0.99, ( vertices[ v ].y + radius ) / ( 2 *radius ) ); + + } else { + + values_size[ v ] = 40; + values_color[ v ].setHSL( 0.6, 0.75, 0.5 + vertices[ v ].y / ( 0.8 * radius ) ); + + } + + } + + scene.add( sphere ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.005; + + sphere.rotation.y = 0.02 * time; + sphere.rotation.z = 0.02 * time; + + for( var i = 0; i < attributes.size.value.length; i ++ ) { + + if ( i < vc1 ) + attributes.size.value[ i ] = 16 + 12 * Math.sin( 0.1 * i + time ); + + + } + + attributes.size.needsUpdate = true; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes_particles3.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var object, uniforms, attributes; + + var vc1; + + var WIDTH = window.innerWidth; + var HEIGHT = window.innerHeight; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 1000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + attributes = { + + size: { type: 'f', value: [] }, + ca: { type: 'c', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 1.0 }, + color: { type: "c", value: new THREE.Color( 0xffffff ) }, + texture: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/sprites/ball.png" ) }, + + }; + + uniforms.texture.value.wrapS = uniforms.texture.value.wrapT = THREE.RepeatWrapping; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent + + }); + + + var radius = 100, inner = 0.6 * radius; + var geometry = new THREE.Geometry(); + + for ( var i = 0; i < 100000; i ++ ) { + + var vertex = new THREE.Vector3(); + vertex.x = Math.random() * 2 - 1; + vertex.y = Math.random() * 2 - 1; + vertex.z = Math.random() * 2 - 1; + vertex.multiplyScalar( radius ); + + if ( ( vertex.x > inner || vertex.x < -inner ) || + ( vertex.y > inner || vertex.y < -inner ) || + ( vertex.z > inner || vertex.z < -inner ) ) + + geometry.vertices.push( vertex ); + + } + + vc1 = geometry.vertices.length; + + var m, dummyMaterial = new THREE.MeshFaceMaterial(); + + radius = 200; + var geometry2 = new THREE.CubeGeometry( radius, 0.1 * radius, 0.1 * radius, 50, 5, 5 ); + + function addGeo( geo, x, y, z, ry ) { + + m = new THREE.Mesh( geo, dummyMaterial ); + m.position.set( x, y, z ); + m.rotation.y = ry; + + THREE.GeometryUtils.merge( geometry, m ); + + } + + // side 1 + + addGeo( geometry2, 0, 110, 110, 0 ); + addGeo( geometry2, 0, 110, -110, 0 ); + addGeo( geometry2, 0, -110, 110, 0 ); + addGeo( geometry2, 0, -110, -110, 0 ); + + // side 2 + + addGeo( geometry2, 110, 110, 0, Math.PI/2 ); + addGeo( geometry2, 110, -110, 0, Math.PI/2 ); + addGeo( geometry2, -110, 110, 0, Math.PI/2 ); + addGeo( geometry2, -110, -110, 0, Math.PI/2 ); + + // corner edges + + var geometry3 = new THREE.CubeGeometry( 0.1 * radius, radius * 1.2, 0.1 * radius, 5, 60, 5 ); + + addGeo( geometry3, 110, 0, 110, 0 ); + addGeo( geometry3, 110, 0, -110, 0 ); + addGeo( geometry3, -110, 0, 110, 0 ); + addGeo( geometry3, -110, 0, -110, 0 ); + + // particle system + + object = new THREE.ParticleSystem( geometry, shaderMaterial ); + object.dynamic = true; + + // custom attributes + + var vertices = object.geometry.vertices; + + var values_size = attributes.size.value; + var values_color = attributes.ca.value; + + for( var v = 0; v < vertices.length; v ++ ) { + + values_size[ v ] = 10; + values_color[ v ] = new THREE.Color( 0xffffff ); + + if ( v < vc1 ) { + + values_color[ v ].setHSL( 0.5 + 0.2 * ( v / vc1 ), 0.99, 1.0 ); + + } else { + + values_size[ v ] = 55; + values_color[ v ].setHSL( 0.1, 0.99, 1.0 ); + + } + + } + + //console.log( vertices.length ); + + scene.add( object ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.01; + + object.rotation.y = object.rotation.z = 0.02 * time; + + for( var i = 0; i < attributes.size.value.length; i ++ ) { + + if ( i < vc1 ) + attributes.size.value[ i ] = Math.max(0, 26 + 32 * Math.sin( 0.1 * i + 0.6 * time )); + + + } + + attributes.size.needsUpdate = true; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_custom_attributes_ribbons.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + var camera, scene, renderer; + + var materials = []; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 3000 ); + camera.position.z = 1200; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0x000000, 0.0016 ); + + // + + var vertexShader = document.getElementById( 'vertexShader' ).textContent; + var fragmentShader = document.getElementById( 'fragmentShader' ).textContent; + + var attributes = { customColor: { type: 'c', boundTo: 'vertices', value: [] }, + position2: { type: 'v3', boundTo: 'vertices', value: [] } + }; + + var uniforms = { ratio: { type: "f", value: 1.0 }, + color: { type: "c", value: new THREE.Color( 0xffffff ) } + }; + + var material = new THREE.ShaderMaterial( { uniforms: uniforms, attributes: attributes, vertexShader: vertexShader, fragmentShader: fragmentShader, side: THREE.DoubleSide } ); + + var position2 = attributes.position2.value; + var colors = attributes.customColor.value; + + // + + var geometry = new THREE.Geometry(); + + var i, i2; + var x1, y1, z1; + var x2, y2, z2; + var color; + + var n = 200; + + for ( i = -n; i < n; i ++ ) { + + i2 = i + n; + + x1 = 10 * i; + y1 = - 50 + ( i2 % 2 ) * 100 - Math.cos( 4 * Math.PI * i/n ) * 50; + z1 = 0; + + x2 = x1; + y2 = y1 + Math.cos( 4 * Math.PI * i/n ) * 100; + z2 = z1; + + var h = i2 % 2 ? 1 : 0.15; + if ( i2 % 4 <= 2 ) h -= 0.15; + + color = new THREE.Color( 0xffffff ); + color.setHSL( 0.1 * Math.random(), 0.15, h ); + + position2[ geometry.vertices.length ] = new THREE.Vector3( x2, y2, z2 ); + colors[ geometry.vertices.length ] = color; + + geometry.vertices.push( new THREE.Vector3( x1, y1, z1 ) ); + + } + + var ribbon = new THREE.Ribbon( geometry, material ); + scene.add( ribbon ); + + materials.push( ribbon.material ); + + var ribbon = new THREE.Ribbon( geometry, material.clone() ); + ribbon.position.y = 250; + ribbon.position.x = 250; + scene.add( ribbon ); + + var ribbonMaterial = ribbon.material; + + ribbonMaterial.uniforms.color.value.setHSL( 0, 0.75, 1 ); + materials.push( ribbon.material ); + + var ribbon = new THREE.Ribbon( geometry, material.clone() ); + ribbon.position.y = -250; + ribbon.position.x = 250; + scene.add( ribbon ); + + ribbonMaterial.uniforms.color.value.setHSL( 0.1, 0.75, 1 ); + materials.push( ribbon.material ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.0025; + + //camera.position.x += ( mouseX - camera.position.x ) * 0.036; + //camera.position.y += ( - mouseY - camera.position.y ) * 0.036; + + camera.lookAt( scene.position ); + + for ( var i = 0; i < materials.length; i ++ ) { + + var uniforms = materials[ i ].uniforms; + uniforms.ratio.value = 0.5 * ( Math.sin( time ) + 1 ); + + } + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometries.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.y = 400; + + scene = new THREE.Scene(); + + var light, object, object2, materials: THREE.Material[]; + + scene.add( new THREE.AmbientLight( 0x404040 ) ); + + light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 1, 0 ); + scene.add( light ); + + var map = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' ); + map.wrapS = map.wrapT = THREE.RepeatWrapping; + map.anisotropy = 16; + + materials = [ + new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: map, side: THREE.DoubleSide } ), + new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1, side: THREE.DoubleSide } ) + ]; + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.CubeGeometry( 100, 100, 100, 4, 4, 4 ), materials ); + object.position.set( -200, 0, 400 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.CylinderGeometry( 25, 75, 100, 40, 5 ), materials ); + object.position.set( 0, 0, 400 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.IcosahedronGeometry( 75, 1 ), materials ); + object.position.set( -200, 0, 200 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.OctahedronGeometry( 75, 2 ), materials ); + object.position.set( 0, 0, 200 ); + scene.add( object ); + + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.TetrahedronGeometry( 75, 0 ), materials ); + object.position.set( 200, 0, 200 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.PlaneGeometry( 100, 100, 4, 4 ), materials ); + object.position.set( -200, 0, 0 ); + scene.add( object ); + + object2 = THREE.SceneUtils.createMultiMaterialObject( new THREE.CircleGeometry( 50, 10, 0, Math.PI ), materials ); + object2.rotation.x = Math.PI/2; + object.add( object2 ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.SphereGeometry( 75, 20, 10 ), materials ); + object.position.set( 0, 0, 0 ); + scene.add( object ); + + var points = []; + + for ( var i = 0; i < 50; i ++ ) { + + points.push( new THREE.Vector3( Math.sin( i * 0.2 ) * 15 + 50, 0, ( i - 5 ) * 2 ) ); + + } + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.LatheGeometry( points, 20 ), materials ); + object.position.set( 200, 0, 0 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.TorusGeometry( 50, 20, 20, 20 ), materials ); + object.position.set( -200, 0, -200 ); + scene.add( object ); + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.TorusKnotGeometry( 50, 10, 50, 20 ), materials ); + object.position.set( 0, 0, -200 ); + scene.add( object ); + + object = new THREE.AxisHelper( 50 ); + object.position.set( 200, 0, -200 ); + scene.add( object ); + + object = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50 ); + object.position.set( 200, 0, 400 ); + scene.add( object ); + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0001; + + camera.position.x = Math.cos( timer ) * 800; + camera.position.z = Math.sin( timer ) * 800; + + camera.lookAt( scene.position ); + + for ( var i = 0, l = scene.children.length; i < l; i ++ ) { + + var object = scene.children[ i ]; + + object.rotation.x = timer * 5; + object.rotation.y = timer * 2.5; + + } + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometries2.html + +()=>{ + /* Testing the new Parametric Surfaces Geometries*/ + + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.y = 400; + + scene = new THREE.Scene(); + + var light, object, materials: THREE.Material[]; + + scene.add( new THREE.AmbientLight( 0x404040 ) ); + + light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0, 1 ); + scene.add( light ); + + var map = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' ); + map.wrapS = map.wrapT = THREE.RepeatWrapping; + map.anisotropy = 16; + + materials = [ + new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: map, side: THREE.DoubleSide } ), + new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1, side: THREE.DoubleSide } ) + ]; + + + var heightScale = 1; + var p = 2; + var q = 3; + var radius = 150, tube = 10, segmentsR = 50, segmentsT = 20; + + var GrannyKnot = new THREE.Curves.GrannyKnot(); + + var torus2 = new THREE.ParametricGeometries.TorusKnotGeometry( radius, tube, segmentsR, segmentsT, p , q, heightScale ); + var sphere2 = new THREE.ParametricGeometries.SphereGeometry( 75, 20, 10 ); + var tube2 = new THREE.ParametricGeometries.TubeGeometry( GrannyKnot, 150, 2, 8, true, false ); + + // var torus = new THREE.TorusKnotGeometry( radius, tube, segmentsR, segmentsT, p , q, heightScale ); + // var sphere = new THREE.SphereGeometry( 75, 20, 10 ); + // var tube = new THREE.TubeGeometry( GrannyKnot, 150, 2, 8, true, false ); + + + // var benchmarkCopies = 1000; + // var benchmarkObject = tube; + // var rand = function() { return (Math.random() - 0.5 ) * 600; }; + // for (var b=0;b{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + var mesh, mesh2, mesh3, light; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 1800; + + scene = new THREE.Scene(); + + light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0, 1 ).normalize(); + scene.add( light ); + + var loader = new THREE.JSONLoader(); + + loader.load( "obj/cubecolors/cubecolors.js", createScene1 ); + loader.load( "obj/cubecolors/cube_fvc.js", createScene2 ); + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function createScene1( geometry, materials ) { + + materials[ 0 ].shading = THREE.FlatShading; + + mesh = new THREE.Object3D(); + mesh.position.x = 400; + mesh.scale.x = mesh.scale.y = mesh.scale.z = 250; + scene.add( mesh ); + + var part1 = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) ); + mesh.add( part1 ); + + var part2 = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0xffffff, opacity: 0.9, shading: THREE.FlatShading, wireframe: true, wireframeLinewidth: 2, transparent: true } ) ); + mesh.add( part2 ); + + } + + function createScene2( geometry, materials ) { + + materials[ 0 ].shading = THREE.FlatShading; + + mesh2 = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) ); + mesh2.position.x = - 400; + mesh2.scale.x = mesh2.scale.y = mesh2.scale.z = 250; + scene.add( mesh2 ); + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * 0.05; + camera.position.y += ( - mouseY - camera.position.y ) * 0.05; + + camera.lookAt( scene.position ); + + if ( mesh ) { + + mesh.rotation.x += 0.01; + mesh.rotation.y += 0.01; + } + + if ( mesh2 ) { + + mesh2.rotation.x += 0.01; + mesh2.rotation.y += 0.01; + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_convex.html + +()=>{ + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.y = 400; + + scene = new THREE.Scene(); + + var light, object, materials: THREE.Material[]; + + scene.add( new THREE.AmbientLight( 0x404040 ) ); + + light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 1, 0 ); + scene.add( light ); + + var map = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' ); + map.wrapS = map.wrapT = THREE.RepeatWrapping; + map.anisotropy = 16; + + materials = [ + new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: map } ), + new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: true, transparent: true, opacity: 0.1 } ) + ]; + + + // tetrahedron + + var points = [ + new THREE.Vector3( 100, 0, 0 ), + new THREE.Vector3( 0, 100, 0 ), + new THREE.Vector3( 0, 0, 100 ), + new THREE.Vector3( 0, 0, 0 ) + ]; + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials ); + object.position.set( 0, 0, 0 ); + scene.add( object ); + + // cube + + var points = [ + new THREE.Vector3( 50, 50, 50 ), + new THREE.Vector3( 50, 50, -50 ), + new THREE.Vector3( -50, 50, -50 ), + new THREE.Vector3( -50, 50, 50 ), + new THREE.Vector3( 50, -50, 50 ), + new THREE.Vector3( 50, -50, -50 ), + new THREE.Vector3( -50, -50, -50 ), + new THREE.Vector3( -50, -50, 50 ), + ]; + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials ); + object.position.set( -200, 0, -200 ); + scene.add( object ); + + // random convex + + points = []; + for ( var i = 0; i < 30; i ++ ) { + + points.push( randomPointInSphere( 50 ) ); + + } + + object = THREE.SceneUtils.createMultiMaterialObject( new THREE.ConvexGeometry( points ), materials ); + object.position.set( -200, 0, 200 ); + scene.add( object ); + + + object = new THREE.AxisHelper( 50 ); + object.position.set( 200, 0, -200 ); + scene.add( object ); + + object = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50 ); + object.position.set( 200, 0, 400 ); + scene.add( object ); + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + + function randomPointInSphere( radius ) { + + return new THREE.Vector3( + ( Math.random() - 0.5 ) * 2 * radius, + ( Math.random() - 0.5 ) * 2 * radius, + ( Math.random() - 0.5 ) * 2 * radius + ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0001; + + camera.position.x = Math.cos( timer ) * 800; + camera.position.z = Math.sin( timer ) * 800; + + camera.lookAt( scene.position ); + + for ( var i = 0, l = scene.children.length; i < l; i ++ ) { + + var object = scene.children[ i ]; + + object.rotation.x = timer * 5; + object.rotation.y = timer * 2.5; + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_cube.html + +()=>{ + var camera, scene, renderer; + var mesh; + + init(); + animate(); + + function init() { + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + // + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 400; + + scene = new THREE.Scene(); + + var geometry = new THREE.CubeGeometry( 200, 200, 200 ); + + var texture = THREE.ImageUtils.loadTexture( 'textures/crate.gif' ); + texture.anisotropy = renderer.getMaxAnisotropy(); + + var material = new THREE.MeshBasicMaterial( { map: texture } ); + + mesh = new THREE.Mesh( geometry, material ); + scene.add( mesh ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + mesh.rotation.x += 0.005; + mesh.rotation.y += 0.01; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_dynamic.html + +()=>{ + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh, texture, geometry, material; + + var worldWidth = 128, worldDepth = 128, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2; + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 ); + camera.position.y = 200; + + controls = new THREE.FirstPersonControls( camera ); + + controls.movementSpeed = 500; + controls.lookSpeed = 0.1 + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xaaccff, 0.0007 ); + + geometry = new THREE.PlaneGeometry( 20000, 20000, worldWidth - 1, worldDepth - 1 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + geometry.dynamic = true; + + var i, j, il, jl; + + for ( i = 0, il = geometry.vertices.length; i < il; i ++ ) { + + geometry.vertices[ i ].y = 35 * Math.sin( i/2 ); + + } + + + //console.log( "triangles: " + geometry.faces.length * 2 + " faces: " + geometry.faces.length + " vertices: " + geometry.vertices.length ); + + geometry.computeFaceNormals(); + geometry.computeVertexNormals(); + + var texture = THREE.ImageUtils.loadTexture( "textures/water.jpg" ); + texture.wrapS = texture.wrapT = THREE.RepeatWrapping; + texture.repeat.set( 5, 5 ); + + material = new THREE.MeshBasicMaterial( { color: 0x0044ff, map: texture } ); + + mesh = new THREE.Mesh( geometry, material ); + scene.add( mesh ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0xaaccff, clearAlpha: 1 } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(), + time = clock.getElapsedTime() * 10; + + for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) { + + geometry.vertices[ i ].y = 35 * Math.sin( i / 5 + ( time + i ) / 7 ); + + } + + //geometry.computeFaceNormals(); + //geometry.computeVertexNormals(); + + mesh.geometry.verticesNeedUpdate = true; + //mesh.geometry.normalsNeedUpdate = true; + + controls.update( delta ); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_extrude_shapes.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var text, plane; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var parent; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Shapes Extrusion via Spline path
Drag to spin'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, 150, 500 ); + + scene = new THREE.Scene(); + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0, 1 ); + scene.add( light ); + + parent = new THREE.Object3D(); + parent.position.y = 50; + scene.add( parent ); + + function addGeometry( geometry, color, x, y, z, rx, ry, rz, s ) { + + // 3d shape + + var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [ new THREE.MeshLambertMaterial( { color: color, opacity: 0.2, transparent: true } ), new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, opacity: 0.3 } ) ] ); + + mesh.position.set( x, y, z - 75 ); + // mesh.rotation.set( rx, ry, rz ); + mesh.scale.set( s, s, s ); + + if ( geometry.debug ) mesh.add( geometry.debug ); + + parent.add( mesh ); + + } + + var extrudeSettings: { amount: number; bevelEnabled: bool; bevelSegments: number; steps: number; extrudePath?: THREE.SplineCurve3; }; + extrudeSettings = { amount: 200, bevelEnabled: true, bevelSegments: 2, steps: 150 }; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5, + + // var extrudePath = new THREE.Path(); + + // extrudePath.moveTo( 0, 0 ); + // extrudePath.lineTo( 10, 10 ); + // extrudePath.quadraticCurveTo( 80, 60, 160, 10 ); + // extrudePath.quadraticCurveTo( 240, -40, 320, 10 ); + + + extrudeSettings.bevelEnabled = false; + + var extrudeBend = new THREE.SplineCurve3( //Closed + [ + + new THREE.Vector3( 30, 12, 83), + new THREE.Vector3( 40, 20, 67), + new THREE.Vector3( 60, 40, 99), + new THREE.Vector3( 10, 60, 49), + new THREE.Vector3( 25, 80, 40) + + ]); + + var pipeSpline = new THREE.SplineCurve3([ + new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)] + ); + + var sampleClosedSpline = new THREE.ClosedSplineCurve3([ + new THREE.Vector3(0, -40, -40), + new THREE.Vector3(0, 40, -40), + new THREE.Vector3(0, 140, -40), + new THREE.Vector3(0, 40, 40), + new THREE.Vector3(0, -40, 40), + ]); + + var randomPoints = []; + + for ( var i = 0; i < 10; i ++ ) { + + randomPoints.push( new THREE.Vector3(Math.random() * 200,Math.random() * 200,Math.random() * 200 ) ); + + } + + var randomSpline = new THREE.SplineCurve3( randomPoints ); + + extrudeSettings.extrudePath = randomSpline; // extrudeBend sampleClosedSpline pipeSpline randomSpline + + // Circle + + var circleRadius = 4; + var circleShape = new THREE.Shape(); + circleShape.moveTo( 0, circleRadius ); + circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 ); + circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius ); + circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 ); + circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius); + + var rectLength = 12, rectWidth = 4; + + var rectShape = new THREE.Shape(); + + rectShape.moveTo( -rectLength/2, -rectWidth/2 ); + rectShape.lineTo( -rectLength/2, rectWidth/2 ); + rectShape.lineTo( rectLength/2, rectWidth/2 ); + rectShape.lineTo( rectLength/2, -rectLength/2 ); + rectShape.lineTo( -rectLength/2, -rectLength/2 ); + + + var pts = [], starPoints = 5, l; + + for ( i = 0; i < starPoints * 2; i ++ ) { + + if ( i % 2 == 1 ) { + + l = 5; + + } else { + + l = 10; + + } + + var a = i / starPoints * Math.PI; + pts.push( new THREE.Vector2 ( Math.cos( a ) * l, Math.sin( a ) * l ) ); + + } + + var starShape = new THREE.Shape( pts ); + + // Smiley + + var smileyShape = new THREE.Shape(); + smileyShape.moveTo( 80, 40 ); + smileyShape.arc( 40, 40, 40, 0, Math.PI*2, false ); + + var smileyEye1Path = new THREE.Path(); + smileyEye1Path.moveTo( 35, 20 ); + smileyEye1Path.arc( 25, 20, 10, 0, Math.PI*2, true ); + smileyShape.holes.push( smileyEye1Path ); + + var smileyEye2Path = new THREE.Path(); + smileyEye2Path.moveTo( 65, 20 ); + smileyEye2Path.arc( 55, 20, 10, 0, Math.PI*2, true ); + smileyShape.holes.push( smileyEye2Path ); + + var smileyMouthPath = new THREE.Path(); + + smileyMouthPath.moveTo( 20, 40 ); + smileyMouthPath.quadraticCurveTo( 40, 60, 60, 40 ); + smileyMouthPath.bezierCurveTo( 70, 45, 70, 50, 60, 60 ); + smileyMouthPath.quadraticCurveTo( 40, 80, 20, 60 ); + smileyMouthPath.quadraticCurveTo( 5, 50, 20, 40 ); + + smileyShape.holes.push( smileyMouthPath ); + + var circle3d = starShape.extrude( extrudeSettings ); //circleShape rectShape smileyShape starShape + // var circle3d = new THREE.ExtrudeGeometry(circleShape, extrudeBend, extrudeSettings ); + + var tube = new THREE.TubeGeometry(extrudeSettings.extrudePath, 150, 4, 5, false, true); + // new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug); + + + addGeometry( circle3d, 0xff1111, -100, 0, 0, 0, 0, 0, 1 ); + addGeometry( tube, 0x00ff11, 0, 0, 0, 0, 0, 0, 1 ); + console.log(tube); + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + +} + +function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + +} + +// + +function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + +} + +function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + +} + +function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + +} + +function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + +} + +function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + +} + +function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + +} + +// + +function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + +} + +function render() { + + parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05; + renderer.render( scene, camera ); + +} +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_extrude_splines.html + +()=>{ + var container, stats; + + var camera, scene, renderer, splineCamera, cameraHelper, cameraEye; + + var text, plane; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var binormal = new THREE.Vector3(); + var normal = new THREE.Vector3(); + + + var pipeSpline = new THREE.SplineCurve3([ + new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]); + + var sampleClosedSpline = new THREE.ClosedSplineCurve3([ + new THREE.Vector3(0, -40, -40), + new THREE.Vector3(0, 40, -40), + new THREE.Vector3(0, 140, -40), + new THREE.Vector3(0, 40, 40), + new THREE.Vector3(0, -40, 40), + ]); + + // Keep a dictionary of Curve instances + var splines = { + GrannyKnot: new THREE.Curves.GrannyKnot(), + HeartCurve: new THREE.Curves.HeartCurve(3.5), + VivianiCurve: new THREE.Curves.VivianiCurve(70), + KnotCurve: new THREE.Curves.KnotCurve(), + HelixCurve: new THREE.Curves.HelixCurve(), + TrefoilKnot: new THREE.Curves.TrefoilKnot(), + TorusKnot: new THREE.Curves.TorusKnot(20), + CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20), + TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14), + FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(), + DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(), + DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(), + DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(), + DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(), + PipeSpline: pipeSpline, + SampleClosedSpline: sampleClosedSpline + }; + + + + + var extrudePath = new THREE.Curves.TrefoilKnot(); + + var dropdown = ''; + + var closed2 = true; + var debug = true; + var parent; + var tube, tubeMesh; + var animation = false, lookAhead = false; + var scale; + var showCameraHelper = false; + + function addTube() { + + var value = (document.getElementById('dropdown')).value; + + var segments = parseInt((document.getElementById('segments')).value); + closed2 = (document.getElementById('closed')).checked; + debug = (document.getElementById('debug')).checked; + + var radiusSegments = parseInt((document.getElementById('radiusSegments')).value); + + console.log('adding tube', value, closed2, debug, radiusSegments); + if (tubeMesh) parent.remove(tubeMesh); + + extrudePath = splines[value]; + + tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug); + + addGeometry(tube, 0xff00ff); + setScale(); + + } + + function setScale() { + + scale = parseInt( (document.getElementById('scale')).value ); + tubeMesh.scale.set( scale, scale, scale ); + + } + + + function addGeometry( geometry, color ) { + + // 3d shape + + tubeMesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [ + new THREE.MeshLambertMaterial({ + color: color, + opacity: geometry.debug ? 0.2 : 0.8, + transparent: true + }), + new THREE.MeshBasicMaterial({ + color: 0x000000, + opacity: 0.5, + wireframe: true + })]); + + if ( geometry.debug ) tubeMesh.add( geometry.debug ); + + parent.add( tubeMesh ); + + } + + function animateCamera( toggle ) { + + if ( toggle ) { + + animation = animation === false; + (document.getElementById('animation')).value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF'); + + } + + lookAhead = (document.getElementById('lookAhead')).checked; + + showCameraHelper = (document.getElementById('cameraHelper')).checked; + + cameraHelper.visible = showCameraHelper; + cameraEye.visible = showCameraHelper; + } + + + init(); + animate(); + + function init() { + + container = document.createElement('div'); + document.body.appendChild(container); + + var info = document.createElement('div'); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Spline Extrusion Examples by
zz85
Select spline:'; + + info.innerHTML += dropdown; + + info.innerHTML += '
Scale: '; + info.innerHTML += '
Extrusion Segments: '; + info.innerHTML += '
Radius Segments: '; + info.innerHTML += '
Debug normals: Closed:'; + + info.innerHTML += '


Look Ahead Camera Helper '; + + container.appendChild(info); + + // + + camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000); + camera.position.set(0, 50, 500); + + scene = new THREE.Scene(); + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0, 1 ); + scene.add( light ); + + parent = new THREE.Object3D(); + parent.position.y = 100; + scene.add( parent ); + + splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 ); + parent.add( splineCamera ); + + cameraHelper = new THREE.CameraHelper( splineCamera ); + scene.add( cameraHelper ); + + addTube(); + + // Debug point + + cameraEye = new THREE.Mesh( new THREE.SphereGeometry( 5 ), new THREE.MeshBasicMaterial( { color: 0xdddddd } ) ); + parent.add( cameraEye ); + + cameraHelper.visible = showCameraHelper; + cameraEye.visible = showCameraHelper; + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false ); + renderer.domElement.addEventListener( 'touchstart', onDocumentTouchStart, false ); + renderer.domElement.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown(event) { + + event.preventDefault(); + + renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); + renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false ); + renderer.domElement.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + function onDocumentMouseMove(event) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02; + + } + + function onDocumentMouseUp(event) { + + renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentMouseOut(event) { + + renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentTouchStart(event) { + + if (event.touches.length == 1) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + } + + function onDocumentTouchMove(event) { + + if (event.touches.length == 1) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + // Try Animate Camera Along Spline + var time = Date.now(); + var looptime = 20 * 1000; + var t = ( time % looptime ) / looptime; + + var pos = tube.path.getPointAt( t ); + pos.multiplyScalar( scale ); + + // interpolation + var segments = tube.tangents.length; + var pickt = t * segments; + var pick = Math.floor( pickt ); + var pickNext = ( pick + 1 ) % segments; + + binormal.subVectors( tube.binormals[ pickNext ], tube.binormals[ pick ] ); + binormal.multiplyScalar( pickt - pick ).add( tube.binormals[ pick ] ); + + + var dir = tube.path.getTangentAt( t ); + + var offset = 15; + + normal.copy( binormal ).cross( dir ); + + // We move on a offset on its binormal + pos.add( normal.clone().multiplyScalar( offset ) ); + + splineCamera.position = pos; + cameraEye.position = pos; + + + // Camera Orientation 1 - default look at + // splineCamera.lookAt( lookAt ); + + // Using arclength for stablization in look ahead. + var lookAt = tube.path.getPointAt( ( t + 30 / tube.path.getLength() ) % 1 ).multiplyScalar( scale ); + + // Camera Orientation 2 - up orientation via normal + if (!lookAhead) + lookAt.copy( pos ).add( dir ); + splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal); + splineCamera.rotation.setEulerFromRotationMatrix( splineCamera.matrix, splineCamera.eulerOrder ); + + cameraHelper.update(); + + parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05; + + renderer.render( scene, animation === true ? splineCamera : camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_extrude_uvs2.html + +()=>{ + (function(){ + 'use strict'; + + var tex; + var testShape; + var holeShape; + var testMesh = null; + var WIDTH = 640; + var HEIGHT = 480; + var targetCanvas; + var uvGenerator; + + var scene, renderer, camera; + + var rX = 0; + var rY = 0; + + window["launch"] = function() { + + camera = new THREE.PerspectiveCamera(30, WIDTH / HEIGHT); + camera.position.z = 20; + + scene = new THREE.Scene(); + + /** Custom UV mapper **/ + uvGenerator = new THREE.UVsUtils.CylinderUVGenerator(); + testShape = setupShape(8, 3); + holeShape = setupShape(8, 2); + testShape.holes.push(holeShape); + + tex = setupTexture(TestTextureData); + renewMesh(); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize(WIDTH, HEIGHT); + + // show canvas + targetCanvas = renderer.domElement; + targetCanvas.width = WIDTH; + targetCanvas.height = HEIGHT; + document.getElementById('canvas-container').appendChild(targetCanvas); + + setupAnimation(); + render(); + }; + + function setupAnimation(n?) { + new AnimationController( + document.getElementById('html-el'), + function(x, y) { + rX = x; + rY = y; + render(); + }); + } + + function updateRotation() { + rX = (rX + 3600) % 360; + rY = (rY + 3600) % 360; + testMesh.rotation.set( THREE.Math.degToRad( rY ), 0, THREE.Math.degToRad( rX ) ); + } + + function render() { + if (testMesh) { + var rx = pickRepeatSetting(); + if (uvGenerator.uRepeat != rx) { + uvGenerator.uRepeat = rx; + renewMesh(); + } + + updateRotation(); + renderer.render( scene, camera ); + } + } + + function pickRepeatSetting() { + var radios = (document.getElementById('repeat-setting'))["repeat"]; + for (var i = 0;i < 3;i++) { + if (radios[i].checked) { return radios[i].value - 0; } + } + + return 1; + } + + function setupShape(n, r) { + // Make shape + var sh = new THREE.Shape(); + for (var i = 0; i < n;i++) { + var method = i ? 'lineTo' : 'moveTo'; + var a = (i/n) * Math.PI * 2; + var x = Math.cos(a) * r; + var y = Math.sin(a) * r; + sh[method](x, y); + } + + return sh; + } + + function setupGeometry(shape) { + // Make extruded geometory + var exoption = { + bevelEnabled: true, + bevelSize: 1, + amount: 3, + extrudeMaterial: 0, + material: 1, + uvGenerator: uvGenerator + }; + + var geom = shape.extrude(exoption); + return geom; + } + + function setupTexture(dat) { + var img = new Image(); + var t = new THREE.Texture(img); + t.wrapS = THREE.RepeatWrapping; + + img.onload = function() { + t.needsUpdate = true; + render(); + }; + img.src = dat; + return t; + } + + function setupMesh(geom, side_texture) { + var materials = [ + new THREE.MeshBasicMaterial( { map: side_texture } ), + new THREE.MeshBasicMaterial( { color: 0x447766 } ) + ]; + var mesh = new THREE.Mesh(geom, new THREE.MeshFaceMaterial(materials)); + + scene.add(mesh); + return mesh; + } + + function renewMesh() { + if (testMesh) { + scene.remove(testMesh); + } + + testMesh = setupMesh( setupGeometry(testShape) , tex); + testMesh.position.set(0, 0, -30); + } + + function AnimationController(target, callback) { + var _this = this; + this.callback = callback; + target.addEventListener('mousemove', function(e) { + _this.onMouseMove(e); + }, false); + } + + AnimationController.prototype = { + onMouseMove: function(e) { + this.callback(e.clientX, e.clientY); + } + }; + + var TestTextureData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEABAMAAACuXLVVAAAAAXNSR0IArs4c6QAAADBQTFRFB1B5B1iEA16QAGCPAGaWE2WXJHJMJntSLoJVKopbQX+fMJBgLZlnbZuyZaiGgrCY0v66KwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wEEBE0NIvLSa4AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAa7ElEQVR42u1cTWwbR5YuUuIlQAA2qb4YEMCm3JcBDEhyeBlgAdsJLwECsJus41xlEiImN0eCCeQmk2AjvlFssDDJZmcvAXS1SbAxvlHd6ELW1iQXAbzOTrDB+OZx4EC936tuyXIws4ct7M4uQEZ/MfsVu169+t73Xr1+jHNuchffnLt22TUlXl4UyEjOpSelz2sN2+U2XcXtht2UQ7wde5EcyHksA6krz0rczjsGzztV2zWNZiGaz6WI8CV8XCMPMQAv4pLSmlPLbZuV4KHsRmEvnHfkJJSDWFeemY5tuBBscLtpb3EzCvwIA0g1Siw9x2zwKjcd+so3axZmIGQsw/SKQOrKM6iuzHnTdHnN5S1egwJjucA7ePWkDBwokPO6w+0WtFjjcoIBIjnFN2bg+7ryrO6U87Q4Dq9atuHkQ188HR4FgyMx9vcjv920HbvSxDRMxzDdgisPw14UBsdyLAc0UV15LIGR54bLi5gG7IjT/QUR7o+0FAUCMtxyCzCihskd08X76WuSzlJXHksAC4WaylzpistfvHi9mQ6NSWCAZuBBMBr6shP2Ynkw15VnroO7y1VMwzEd03LWnspBqh7YcT+c9GBEJrRoWTCz4p2Cc9gLu7PT3hMxiXHFINaVZxbnVjPP+Y4Le951Csp28SOUx54fBUED1ovBoUIXmoYKSbt0hVR/SV15BgWWOCaBgRo2dCTTpUmXES+X0w5KgSSPhcTQAggyhh0DbwZSV57Z7obFC9jMHIZsWHYoBtHhOBZT+UT60wj7eIcGqNhmo2xiu8veKW1zH58TEJLpyjNOpoMb3M3gMr4yH4IJKRpQHRC2CZwhS+KkYZohrBkDTaSuPG6gvoF/51a95tg1bmfSUGE6lFN3ecE1W7SG/K7pRl4Y+EeYZufp4WjeiXXlmXW3lCsWGhsGLzVgyoWo3Q4fjuL2g6AtZscTr2FW3NyddcsxK2bFMCsTcQrVyXmQfZKuPEHx5Uspc3Eoo1R7Us4i6TUIQmmKmMmu2ufKuAjP8SViXXlWNWjx0gHqNrefSDWASJdJ9siK67jEhY2VXBsqPA0m43F7dv9YPBAHY115ZuRauUaOmxVm7hjrTmksx0960wEcdifqHE27MGBsHnu3srHNgSUlbOF4OFNmBI8vpa48U4TimhbVwij7ERHp0cEOJxRtYib2L6CWLtOVT29AbSNaQ8fOdpCcZV7DzQbgtkVo7/oAUAweYJMfjuXRXFeelXbcvJN3GDOMom0U8+N5ZxQcxQeDeBh1QJy2a0WeA4wX1w3ODF4MRAiI7UVyL8ZAB1JXXmkA27SmLKlE+xi7ZJaqCIDec+o7dOdV3DxN1FD2HQJNOsqKI115dQNw06kp1xSpjACUeDOIYEkC+MrT5bvHay2eA9ETk4UcjbsYP05JqY48s5v3gOSOZTqFOyUTWD4ajg59KcawYsBZt4EBNir1HHytW8BOkr1YpB+RvnTlWYrkXJEF+iu6slFB0+gR1SDaTQ6NmKeyMAU00Rz0U+rKwxeQI3fJn7bIisf0dqwYaywG0nOxsLR85FQwQDX2ppP+02AQe+OxP8YNaMqz0vZWubhmWTnD3rbMit2X+yOxF+0fgz12B1Fv2zTcXNE0ts0dByo0Qo+4HqaXgbmuPONKcUBKMhVoMcAigbtfEhapdrhCcks5VQnOfcnqMU5fV54BqM1sAOjIMYPYI8aK9Qtgo7HHifJyxTa4eZeXInEcDMbSB7kOaBq68sywiU06Vp18BQaII29B9tOfdSJvfLrfsPPwI2ZZbSeLIh81O8B4pKiFrjwjwyHOCFXW6AeAJFQzUIsUScW1HZpejf66JBwHMlh4I18MdOVBSkGYTacKI0WE42yIGPjVh+4yZ3KPxIt8AxN0TMzxNBj1xbHcpwhM4YCmPCKjZs3hDu0l011r5CUcNlTY34e5eqEIrHqxiAGwg5hbqzr2acYkKPYOVGSkJ69IqXPJZ8DhJe2TOCZEV/ze4beV6u4S94atUdwPK+4tuos9DzG4rjxDQLle4WyH4ocmjGj2VCzkfeKrwcgbh55BSAbjoTdL4HxhfDD3ZnIYBYuAYj9deYWEFs9h+RDnYxSfNirWx5Od8WQ8kSCbTs0gTmsSt7DDjPVmrEPqymek9JLWkRWnjO4yiM1I/9VLDTCW'+ + 'D+PJWPZjv68rz+wNp3YXN5hvYqO6OR5Q0NqJZTfynmIQAAnWDpzCIXdTctkjsTiY9ONuPPDJkua68swGQhZv5oHTds4xqnwciTDaj+fdcAgjirpuk6Je4hQGqCXFfuF1fyd15QmKyYrJoZl02VBxCZlu05BIJWKqe2/VLCn1FEsfbCNuj6O2rjyza0Qbqw7lkCiJIIgsDOMB9nAo+lIYfN25adwrFaFrG1hCQW03DD6LheJdQleemVWKbGGkjgPQdvmEcOxQDrGW00BEnpVyCV5qFYrV9UY9C/subUzqyjOyXPfKRltcKdC75PZEq2vNd3k/gL5PUX4Ud8bBRFcefKBSA5927DKvNW4a9mAq/RiEMYAxyYfwdkDR1lrD3P7AVpg3EgNiOvuhfKRIp648s0uV2g7RpuaHICxOvR/LR7Ib7g/DXoi19Ix7a266xHDpu00+IgvDHCnXitdQV56puP0amqgEGuBcJTCECr2U6po0ACYxloMYzhRXdOTkqRzoyjOedwCkZiMHzNwBlohTDypckDPFNWREnDwpb1QxwbxTCikB5tMMyOHiAzTlGd8FSpC3dNPQZv8U7oqgNAx8uR/LCs836muOvZNFH1kSShE+isF15VmK07ZzqcIgvQIoJjLCAcF1oGmduzV80TYPYMVHwaHfGY8PdOWZS2/yUsM2mohe7nLs0o58GLUnp14sJpEog2UQxADoHbPaMEfBOPb68aBPWSZsNV15ZgC9cjwHILFhqZX6w1OsUHchQNkAKZEogeryDXfDpk0OPcdyEgeTdI/TdteVZ8QWSsSsFWuscWXAKW0P6RaVZnOcb9VaLqV9Kcsu9gnOOlEXe0lXHjZg8Fw93zCLPG8Yxj1vEfixryJ4bJIw2ALLKGGAKt+hbEvpVE6iwIu8fhrcCF15ZuXp/kvg7q2yDc9GAUss/LAbgrsexLJEdDPNQbZoMmqC4HyU6hTRYKIrfz1Nx6+n2ymZp4CkZatkbwlu9TbczSkgdNAOsdAHsjd+J03335JnlbpTY4ov0KEK42IKpPBArkPMZF8OKL9bLTTsSqnkVDHRqZzHh0JeOTRdecZs8CVuVHGL8NZAsihG6BzNek/Ekzl2kkVHHtDeJeBOs6AzogMBbGpteZU9yMImohbB2xwaBRgSpNetEuXlNQdoaj+S/ZEcxw+PfTHCKnu68ozSZzCjpl0x63SZOA3mcBUzOOwnUS8UhmM2SiVrgw4byJ58yq6ouCYLvzXlmQrryUoQvFIWg/Zx1JUqjKc0V+tvGVk6zVPpTwJdeXVoBRW6tsqkVDj+WZIRXZJXJWXylsHrxfKOZYbzTtRvx96TuBvKIy/WlWc2MwDVdOrEK0VY8eFIHp52wz3xSI6EiGc5a227lrubY27OqBr3eH/qhYEEr6fpkbPRlGeEECY5bEyAMtuwTGwjxG2xxIaKhbFDh478KiWcWZhQSp7Iia48S9+6pDUuD2C7sVCptJBMRaUXCs3LJEzLJ7bvEeEbULJtqCvPLCLVDggFcLpRa/CH9LaHPXosj2HFwQ62D8WVao7A9AGpLqBTJy89MdGUZ+7l/YNZKiOKKZUrswgqBKtNVbfO1ZkT7fOQ+FYPWCcWk4muPJagRGefnKvowuDBQganFLlTggF6NCm5VnYdBOBFx3byg2C4GLbDtoiVHqWuPCsWii55s3yOks6W642ktxCDBZbx0fTh8axQMStb607VbJnKtU8UlbwMLaXUlVeREVeHeumpBu4qXSRiNuk+Thl16x1vB8jvYQbxga48bmCLl51aEf7CpHSWgBWr5MkozWgTpW8R7XLsYtls5P1wGE46YXc02w9xrdSVxy7IAUhgn0WYsrlDWO4vglnoPQWjOww9s2E27q1XKAen8jA+bWHvKvSTuvKXhKR2mei6dvI6J03CsFXQefMalkdpig0R9rSvK8927Y8osrvNyxTlVgnJgvAKRijy4VtuzeXsQ161imsuvFx45IXD4UKM5F4/1pVnRqHi5pzbzAFU5yuFxrAftQ+kfzQAZ4S7irHH8latQkUYCL24AwubZ4cOVI4ideUzQsILrZRR/KIEg86EKL9gXHpTRwiZESrayDOpK09AxNP6Bu5AU67CMVokBHcIr8ZUIXOXAo8iN8BqKmIYt5+KAVjvuJtuMz155rTW3fUdC+FLuQhYL/pU1xDiCoS5UFSfm9sEcq1qiZDcqNIeVicymRnryjMoiCC65qQqKstrZkw6VMUZ2aEc/U75zISSjZgg1lhTninVqS2kynBMVV8SUYYFHiseCleV6OQbtgPWAU1jesO+bMf9Pfkw9DtSV56BVG/Xq0auaOWLJVYunHpTuTce9o/EI39/sT8tlixuIO60CfIBdrITqvxCj4rmyBdoyjOHvBW37S0iDlZaYJC6iTFFkDJNxtdaWb7XlT06EFGHEYSkUl'+ + 'f+emjmwKXYaaFbShmoFIEyzXTmaZucSmG2ZfcUCEM5prBLyQZdeaYSiVaTwpciSMXGaTDATvL3qcbncDRpO3nDrCh31iyQW1PpF5X9SA1ZV55ZTTgxdbYNK23xWpxVFqgkkko0qveyYh2+C70GEwqq8OZTKFNXnrlNeGqjCaeNyNFQBYlyMiMY9dR9ko+nCiVcY9+pmkbYe4LYfhgGhws4vGGkK88chE5lY8egarNC0Sqcimk08GNvgYsOx2JALtYih4vxaQpZGZgyITp+0pVn6qTpbRkOfwsjqS076p8LCmzrnComSQxQ681g55NYV55R9Mq3VPhMHqMuo0MYiS+P04zzkM6DjEbBsfJ3bOaU2LR3JIaL7pPBfijHQghdeUZ1gFYe2jN2c2WEsDMYyL4fBfdlO/RGY7HDc9XiLs+wzq7J1OGHGdRKXXl2edj0yxSL'+ + 'zAIHnp77vfu+GoAOyT2pK8+4Q8kzB0NsUXRnwlFQ8Ij/PFXnsAXNNl1YUm7HLiO2mXoR2KxYyPZ45i0QHWvKM4PdZka+YuagSifn5I8HXuiDTI4ItMeyXUTcTQUgDmDEdGq1OFWhqpmkRJSuPLt26KeOVi9teBZ31dmTqoNUNqbovcJ6ygXCq6sYVFeebqDOFZ2E0+INDDAHn53KfgxF+WGvxXPNtGCyAfrHy6E3o9QCBbmBVKGZnjyzmG1U1orNnGMwnrO4PzoMZ+1ZCqSATQvjFygLs66KAPjboCqmeq25rjydG+b5ZRLNzKxUXKZxpCxBwzbVbRPe3OV2JOaUAzwMRX/WfhT4uvIshSmVaaZaMx4ovor1Cb1wcjCZFRxKqNfKQFy3VNzaONqfhd2ncSeU7ZlIYz8teWbCn7oI7Qzu5Iv8rj2Ieguf4uaFt5gM4wGnqJYqZeyrfUxkwrs6N9SUz+oJd7L0Aedp1C7TraKCSzXBumvuqlRD5sg9ORtIMY7buvIMQZvhbFi8VG0UuJtrerR7+weyfRSMo+HULzXg5SqmUSkZrm055qkQZMOIrQd08CZ05Zlpp1lGk/w2/uey7FpkBWfZmVvdrV+pME7fVnoMdOX/brr+qjrezWrVlI5dE+NO5YiOnidUnzrUlYcRshLVIJUqhumUjOL+6eQwnvRDj7CkM5vligVrhzXXKioZ7hRGAR3OXlXLSV15Zju1qiqCspyagyhOUq7XwxVPwCoRZtG5+BXc2i4CDy9OT1s8KtUa6MqzKyqTZRmUpxbKitUtAscV46ES9bLZMCOElbI97TwCv/ajyUBXntUct9Cwcm6JzjRaeRduYnxMBQ50+ipGAXAcwU8T/nSjYdec2tFVMV4KqLryjO80VSlkTcXxNr86+U9rgyWo9kdpAuZa3fBlzn0GI9OUv7YLSFM3nWHKJuMgO3dS+LLVRNRhursbFVvE4lgeRmBbh0eftQNfV56VqNYRsWU+V+RgJ8XO0aAdtu8fDw6OO4v+wM9vm2S9puHmGzU4lA6VHXTDICN1A115LMFtu2EbO7x+N4XKt08oqBkUHJ7V7HJ1+CSyCpBpyjs8XXnG7awY7W8ASTbAhzSyxW3Lrll1byGOhB8HPYnY8pEQuvKslndLKs9cxq26ue1gDMb0EHxmFPQjuR/R0zm80DB3Ff/f4r1Q0KN06txT7QJNeWiA6iFrdzhiWN5E9HqcZtBgoaoOQCXBMI3qL2cYCSpVkLryLFPgHXpWTW2jcfqISJpOwwBU+YFp5NybMOTKRzChvjyMhwOq3B3EA115littE2PcJqCCpTrykdwbi2Ho9UfdhXd8RDBCBcFm01Ql+nC3AxXgxz2FJbryTOW3XLMIVdYJrKWqyw2yMD+MeYmvKQN2a6pSQ0X2ILwy9OJxN/R15dUugJpqnLI8agD1KFz2KFZfUokMB6kzG3mLCmG6oTiIuiMxWYhTEUQTXXnWLDQMKr12mbGVr+Qqnf5M+H6bDp3apxNP7tLBMJUhudmxmwoq5FVVnq68MsL6WyNtpo5aXFpxVKcTCZNnD/NxOhmdU65TlaSB+OrKs7eOIgX0q5PdCV0jQtBdqpim0wirWd5pDo/lAT2a4IXBlFBVV54ZIJTlHW7QM2vFml2kBxEj4R+Lw7AznndDrGGJMISy0U3bdUUGpIE6HQ6lrjxrphUWW2ShZewTUo9K6WdwQSZEGE7pSDoWUo/0Dg4Ad5LOx/q68syBYEHlOGknmU3ZlkBT3GSkyKvvrLn5O2aF0uHMqua2geRDOpgEjvmEprryzOEVdeBHlae7O4BSjx4C6sTyCFqKJ8Ix3fRxRjoYwDzk27BPpEkoPXmWPSWmftWvsDq4uuz6g2yX'+ + '6fY4fWhTIBL3deWZRZXx2EZNYCaIsyWHkQc+EwWA82jela0CPR5QrdpuHdy74GJmiDvlFDAyj7HeuvKsxIsmjDNnwanmHLs687A5ov0wGC68Iy+IgOPYQdv0RCnV49GZj0dPTMtQVYbOdeVZSlTqGW0nFcaBevhBYYmUiOsBpPTcMj0qYTv+MOo9nXViSjMhupzpyqtitpTQbvFqnW9R+YEawIvVqYoagFgVPS0Fjq9Ou6R6jGEo1amZnjxb9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R9Y9R/4P99/oLj7v9J/oIpXaqZgEe/0D6jks/4BLdPaNf+L/gPVX/QfIHc/kTGIImJWGGq1hK8r+eH0nf4DLsPLVv0Djh+82z/g1lnWP8DK4Rrr7/cfyOSv+g882Q/jvdkePQmaKznqE67Jf3b4Tv8Bd4mXslX+6at3+wdsnqX9A7Yr7y2X35T+bv8BN5O/6j/w7I0fJfNkm+cbyzWnulymn5HJP3v9Tv8BdQOtrVaryR//NBdzGc/nEX7h9+aZebe5VufF9+iaFx+E84EM+rF3FByO2/3+we0STP/2huMuq1Vsw11ICeVpnr2RcRK8/Lq+8evzdc7TG7hbngEmJgfy81d+51r/AXdZgSEzVmKlT1/t3X/QfnB/7+nwgfCP9t4/W6sg8jSLJ+d3Nz5+Xnqwtzf3jvBTTj5r7w3GbI3fg263i0vGKrkiG7fl/fZ+1J48exNPktnj5+7aP31H/Qdat56bO0W25x0f7e35+Jj9a/0H3KVVteyTr6yTr5MkeZ38NvkpeTJMggcvk5OzfPFk+ZX5q2Ud9tS0HicXh/PfJsmfgxiX/fsXy3++Y723PM/dwvxuPT9ZfvpKjBPqP/DsTRgns9+d2/mTf1X9B26dtaxvlhcPj18myQAf8+Za/wF3SUb4yXc3l3V6R33PoMDPk2R5Zp1g7A9unLfcXevmDbz3aowfidemn8ny3LqB9//4G7oBfH9xEfzuIlA2gBuYf3tuV5cfqf4Dt17UcWXy+ovsI3661n/gnjKQ9eV7f7z3+FXQTy4GkbqBT18Hn7y4sfwwd/L15nc7DcbyJ3+dP774IvnzF8mPk+THb5MfP16yk/Pb753nl3Z+c/kv94aJ9/kb6j/w7M3TOJkGy93yMu0/sPm8evKd8ezi8V+HX/z58at3+g+kRlg+Ofk9f/xahonnh8l0AhuO5ftnm88Zw88z3oQRLvf29pIvL2L5+M0s8cJkaC0NUt+yurxZ3vyOc/Fy+PgH6j/w7M0xNCBPvr5xnvYfuHXWPIENQPqzfoxdcL3/gLukp/Favzq/yb9UxovvOb7wx62zTbq7s80/mg7dAKn901ehePzms6Q7SuawfmXf1SWtMoDo3354qThXugvkJy82v6ur/gObL3ZwXZJgCf40xjyv9x/AKNQ/4MaS1aGbftKDFsZYhWQyeP/F+zT+9zfO887uZnYD2MSPf54ksMOgsrTUDQAH7FtnjItnf01U/4Fnr2dhEgw2X7z/PO0/8P6LqrqB2bcvk/949tM7/QfcpYF1Mk5OvuKPsUGTXjRNHnyW+EmfbuB5qbpjfrw0dqubZ8u9yezoy9eT2eOfJrQEA7bEBqwytrUsGbfOgITfXlyo/gNfvj56lMTiV+cnX6f9B6CfpVEd9afjycs3z15NvWv9B9JdUD7/5Hnty4u9wwQ3l/zpt4CRv94/gRF+xW6cGcvzInv/xcmrB3uf/yF5sJf8gBsYJT13uXVyztg3Nq66dWZxaOVnNbVvkwefX0gJw7mX9h/YfG6dvGB7Lz9/sPfpT4QD1/oPKCM0N7/7YFn7gnDAC2fYrMmMtuGLDdqGZ8YnCgl/TUsg8eYFrTC+oLyP1R7CVUoDi+SHtP8ALvw5FMZymfUf2Hzh/pqW4Eu88R/4mJ+v9x9Qu+Dkq42T33svkx+TrpR/wC8pXl588j3/6GR5/hFvfQNfUG/9Jbn4i/zDy4sfoSTpJwFfOi3cwe9hQMvffO9yb/Hyx7T/wLfJBfUfODnPCnp/8z3HlRd/gQlAM/iY/6H+A4uXwT+2/8DRxT+4/8CXP/+D+w+8/HHVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf2DVf+D/V/+B/wT15JbOMyhx1QAAAABJRU5ErkJggg=='; + + })(); +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_hierarchy.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var geometry, group; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0xffffff, 1, 10000 ); + + var geometry = new THREE.CubeGeometry( 100, 100, 100 ); + var material = new THREE.MeshNormalMaterial(); + + group = new THREE.Object3D(); + + for ( var i = 0; i < 1000; i ++ ) { + + var mesh = new THREE.Mesh( geometry, material ); + mesh.position.x = Math.random() * 2000 - 1000; + mesh.position.y = Math.random() * 2000 - 1000; + mesh.position.z = Math.random() * 2000 - 1000; + + mesh.rotation.x = Math.random() * 2 * Math.PI; + mesh.rotation.y = Math.random() * 2 * Math.PI; + + mesh.matrixAutoUpdate = false; + mesh.updateMatrix(); + + group.add( mesh ); + + } + + scene.add( group ); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = false; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ) * 10; + mouseY = ( event.clientY - windowHalfY ) * 10; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + var rx = Math.sin( time * 0.7 ) * 0.5, + ry = Math.sin( time * 0.3 ) * 0.5, + rz = Math.sin( time * 0.2 ) * 0.5; + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + + group.rotation.x = rx; + group.rotation.y = ry; + group.rotation.z = rz; + + renderer.render( scene, camera ); + + } + +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_hierarchy2.html + +()=>{ + var container, stats; + + var camera, scene, renderer; + + var geometry, root; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 15000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + var geometry = new THREE.CubeGeometry( 100, 100, 100 ); + var material = new THREE.MeshNormalMaterial(); + + root = new THREE.Mesh( geometry, material ); + root.position.x = 1000; + scene.add( root ); + + var amount = 200, object, parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.x = 100; + + parent.add( object ); + parent = object; + + } + + parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.x = - 100; + + parent.add( object ); + parent = object; + + } + + parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.y = - 100; + + parent.add( object ); + parent = object; + + } + + parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.y = 100; + + parent.add( object ); + parent = object; + + } + + parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.z = - 100; + + parent.add( object ); + parent = object; + + } + + parent = root; + + for ( var i = 0; i < amount; i ++ ) { + + object = new THREE.Mesh( geometry, material ); + object.position.z = 100; + + parent.add( object ); + parent = object; + + } + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = false; + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ) * 10; + mouseY = ( event.clientY - windowHalfY ) * 10; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + var rx = Math.sin( time * 0.7 ) * 0.2; + var ry = Math.sin( time * 0.3 ) * 0.1; + var rz = Math.sin( time * 0.2 ) * 0.1; + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + + root.traverse( function ( object ) { + + object.rotation.x = rx; + object.rotation.y = ry; + object.rotation.z = rz; + + } ); + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_large_mesh.html + +()=>{ + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + var FLOOR = -250; + + var container, stats; + + var camera, scene, canvasRenderer, webglRenderer; + + var loader; + + var mesh, zmesh, lightMesh; + + var directionalLight, pointLight; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var render_canvas = true, render_gl = true; + var has_gl = false; + + var bcanvas = document.getElementById( "rcanvas" ); + var bwebgl = document.getElementById( "rwebgl" ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + render_canvas = !has_gl; + bwebgl.style.display = has_gl ? "inline" : "none"; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + function addMesh( geometry, scale, x, y, z, rx, ry, rz, material ) { + + mesh = new THREE.Mesh( geometry, material ); + + mesh.scale.set( scale, scale, scale ); + mesh.position.set( x, y, z ); + mesh.rotation.set( rx, ry, rz ); + + scene.add( mesh ); + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 50, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 ); + camera.position.z = 1500; + + scene = new THREE.Scene(); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x101010 ); + scene.add( ambient ); + + directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 ); + directionalLight.position.set( 1, 1, 2 ).normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffaa00 ); + pointLight.position.set( 0, 0, 0 ); + scene.add( pointLight ); + + // light representation + + var sphere = new THREE.SphereGeometry( 100, 16, 8, 1 ); + lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color: 0xffaa00 } ) ); + lightMesh.scale.set( 0.05, 0.05, 0.05 ); + lightMesh.position = pointLight.position; + scene.add( lightMesh ); + + + if ( render_gl ) { + try { + + webglRenderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } ); + webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + webglRenderer.domElement.style.position = "relative"; + container.appendChild( webglRenderer.domElement ); + has_gl = true; + + } + catch (e) { + } + } + + if( render_canvas ) { + + canvasRenderer = new THREE.CanvasRenderer(); + canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( canvasRenderer.domElement ); + + } + + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + bcanvas.addEventListener( "click", toggleCanvas, false ); + bwebgl.addEventListener( "click", toggleWebGL, false ); + + var loader = new THREE.BinaryLoader( true ); + //loader = new THREE.JSONLoader( true ); + document.body.appendChild( loader.statusDomElement ); + + var start = Date.now(); + + //loader.load( 'obj/lucy/Lucy100k_slim.js', callback ); + loader.load( 'obj/lucy/Lucy100k_bin.js', function ( geometry, materials ) { + + addMesh( geometry, 0.75, 900, 0, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0x990000, shininess: 30 } ) ); + addMesh( geometry, 0.75, 300, 0, 0, 0,0,0, new THREE.MeshFaceMaterial( materials ) ); + addMesh( geometry, 0.75, -300, 0, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x111111, specular: 0xffaa00, shininess: 10 } ) ); + addMesh( geometry, 0.75, -900, 0, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x555555, specular: 0x666666, shininess: 10 } ) ); + + loader.statusDomElement.style.display = "none"; + + _log( "geometry.vertices: " + geometry.vertices.length ); + _log( "geometry.faces: " + geometry.faces.length ); + + _log( "model loaded and created in " + ( Date.now() - start ) + " ms" ); + + } ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + if ( render_canvas ) canvasRenderer.setSize( window.innerWidth, window.innerHeight ); + if ( render_gl && has_gl ) webglRenderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + var r = 0; + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + + lightMesh.position.x = 700 * Math.cos( r ); + lightMesh.position.z = 700 * Math.sin( r ); + + r += 0.01; + + if ( render_canvas ) canvasRenderer.render( scene, camera ); + if ( render_gl && has_gl ) webglRenderer.render( scene, camera ); + + } + + function _log( text ) { + + var e = document.getElementById( "log" ); + e.innerHTML = text + "
" + e.innerHTML; + + } + + function toggleCanvas() { + + render_canvas = !render_canvas; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + render_gl = !render_canvas; + bwebgl.className = render_gl ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } + + function toggleWebGL() { + + render_gl = !render_gl; + bwebgl.className = render_gl ? "button" : "button inactive"; + + render_canvas = !render_gl; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_minecraft.html + +()=>{ + + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh; + + var worldWidth = 128, worldDepth = 128, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2, + data = generateHeight( worldWidth, worldDepth ); + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 ); + camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100; + + controls = new THREE.FirstPersonControls( camera ); + + controls.movementSpeed = 1000; + controls.lookSpeed = 0.125; + controls.lookVertical = true; + + scene = new THREE.Scene(); + + // sides + + var matrix = new THREE.Matrix4(); + + var pxGeometry = new THREE.PlaneGeometry( 100, 100 ); + pxGeometry.faces[ 0 ].materialIndex = 1; + pxGeometry.applyMatrix( matrix.makeRotationY( Math.PI / 2 ) ); + pxGeometry.applyMatrix( matrix.makeTranslation( 50, 0, 0 ) ); + + var nxGeometry = new THREE.PlaneGeometry( 100, 100 ); + nxGeometry.faces[ 0 ].materialIndex = 1; + nxGeometry.applyMatrix( matrix.makeRotationY( - Math.PI / 2 ) ); + nxGeometry.applyMatrix( matrix.makeTranslation( - 50, 0, 0 ) ); + + var pyGeometry = new THREE.PlaneGeometry( 100, 100 ); + pyGeometry.faces[ 0 ].materialIndex = 0; + pyGeometry.applyMatrix( matrix.makeRotationX( - Math.PI / 2 ) ); + pyGeometry.applyMatrix( matrix.makeTranslation( 0, 50, 0 ) ); + + var pzGeometry = new THREE.PlaneGeometry( 100, 100 ); + pzGeometry.faces[ 0 ].materialIndex = 1; + pzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, 50 ) ); + + var nzGeometry = new THREE.PlaneGeometry( 100, 100 ); + nzGeometry.faces[ 0 ].materialIndex = 1; + nzGeometry.applyMatrix( matrix.makeRotationY( Math.PI ) ); + nzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, -50 ) ); + // + + var geometry = new THREE.Geometry(); + var dummy = new THREE.Mesh(); + + for ( var z = 0; z < worldDepth; z ++ ) { + + for ( var x = 0; x < worldWidth; x ++ ) { + + var h = getY( x, z ); + + dummy.position.x = x * 100 - worldHalfWidth * 100; + dummy.position.y = h * 100; + dummy.position.z = z * 100 - worldHalfDepth * 100; + + var px = getY( x + 1, z ); + var nx = getY( x - 1, z ); + var pz = getY( x, z + 1 ); + var nz = getY( x, z - 1 ); + + dummy.geometry = pyGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + if ( ( px != h && px != h + 1 ) || x == 0 ) { + + dummy.geometry = pxGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nx != h && nx != h + 1 ) || x == worldWidth - 1 ) { + + dummy.geometry = nxGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( pz != h && pz != h + 1 ) || z == worldDepth - 1 ) { + + dummy.geometry = pzGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nz != h && nz != h + 1 ) || z == 0 ) { + + dummy.geometry = nzGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + } + + } + + var textureGrass = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass.png' ); + textureGrass.magFilter = THREE.NearestFilter; + textureGrass.minFilter = THREE.LinearMipMapLinearFilter; + + var textureGrassDirt = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass_dirt.png' ); + textureGrassDirt.magFilter = THREE.NearestFilter; + textureGrassDirt.minFilter = THREE.LinearMipMapLinearFilter; + + var material1 = new THREE.MeshLambertMaterial( { map: textureGrass, ambient: 0xbbbbbb } ); + var material2 = new THREE.MeshLambertMaterial( { map: textureGrassDirt, ambient: 0xbbbbbb } ); + + var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( [ material1, material2 ] ) ); + scene.add( mesh ); + + var ambientLight = new THREE.AmbientLight( 0xcccccc ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 ); + directionalLight.position.set( 1, 1, 0.5 ).normalize(); + scene.add( directionalLight ); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function generateHeight( width, height ) { + + var data = [], perlin = new ImprovedNoise(), + size = width * height, quality = 2, z = Math.random() * 100; + + for ( var j = 0; j < 4; j ++ ) { + + if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0; + + for ( var i = 0; i < size; i ++ ) { + + var x = i % width, y = ( i / width ) | 0; + data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality; + + + } + + quality *= 4 + + } + + return data; + + } + + function getY( x, z ) { + + return ( data[ x + z * worldWidth ] * 0.2 ) | 0; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + controls.update( clock.getDelta() ); + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_minecraft_ao.html + +()=>{ + + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var fogExp2 = true; + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh, mat; + + var worldWidth = 200, worldDepth = 200, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2, + data = generateHeight( worldWidth, worldDepth ); + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 ); + camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100; + + controls = new THREE.FirstPersonControls( camera ); + + controls.movementSpeed = 1000; + controls.lookSpeed = 0.125; + controls.lookVertical = true; + controls.constrainVertical = true; + controls.verticalMin = 1.1; + controls.verticalMax = 2.2; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xffffff, 0.00015 ); + + // sides + + var light = new THREE.Color( 0xffffff ); + var shadow = new THREE.Color( 0x505050 ); + + var matrix = new THREE.Matrix4(); + + var pxGeometry = new THREE.PlaneGeometry( 100, 100 ); + pxGeometry.faces[ 0 ].materialIndex = 1; + pxGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; + pxGeometry.applyMatrix( matrix.makeRotationY( Math.PI / 2 ) ); + pxGeometry.applyMatrix( matrix.makeTranslation( 50, 0, 0 ) ); + + var nxGeometry = new THREE.PlaneGeometry( 100, 100 ); + nxGeometry.faces[ 0 ].materialIndex = 1; + nxGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; + nxGeometry.applyMatrix( matrix.makeRotationY( - Math.PI / 2 ) ); + nxGeometry.applyMatrix( matrix.makeTranslation( - 50, 0, 0 ) ); + + var pyGeometry = new THREE.PlaneGeometry( 100, 100 ); + pyGeometry.faces[ 0 ].materialIndex = 0; + pyGeometry.faces[ 0 ].vertexColors = [ light, light, light, light ]; + pyGeometry.applyMatrix( matrix.makeRotationX( - Math.PI / 2 ) ); + pyGeometry.applyMatrix( matrix.makeTranslation( 0, 50, 0 ) ); + + var pzGeometry = new THREE.PlaneGeometry( 100, 100 ); + pzGeometry.faces[ 0 ].materialIndex = 1; + pzGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; + pzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, 50 ) ); + + var nzGeometry = new THREE.PlaneGeometry( 100, 100 ); + nzGeometry.faces[ 0 ].materialIndex = 1; + nzGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; + nzGeometry.applyMatrix( matrix.makeRotationY( Math.PI ) ); + nzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, -50 ) ); + + // + + var geometry = new THREE.Geometry(); + var dummy = new THREE.Mesh(); + + for ( var z = 0; z < worldDepth; z ++ ) { + + for ( var x = 0; x < worldWidth; x ++ ) { + + var h = getY( x, z ); + + dummy.position.x = x * 100 - worldHalfWidth * 100; + dummy.position.y = h * 100; + dummy.position.z = z * 100 - worldHalfDepth * 100; + + var px = getY( x + 1, z ); + var nx = getY( x - 1, z ); + var pz = getY( x, z + 1 ); + var nz = getY( x, z - 1 ); + + var pxpz = getY( x + 1, z + 1 ); + var nxpz = getY( x - 1, z + 1 ); + var pxnz = getY( x + 1, z - 1 ); + var nxnz = getY( x - 1, z - 1 ); + + dummy.geometry = pyGeometry; + + var colors = dummy.geometry.faces[ 0 ].vertexColors; + colors[ 0 ] = nx > h || nz > h || nxnz > h ? shadow : light; + colors[ 1 ] = nx > h || pz > h || nxpz > h ? shadow : light; + colors[ 2 ] = px > h || pz > h || pxpz > h ? shadow : light; + colors[ 3 ] = px > h || nz > h || pxnz > h ? shadow : light; + + THREE.GeometryUtils.merge( geometry, dummy ); + + if ( ( px != h && px != h + 1 ) || x == 0 ) { + + dummy.geometry = pxGeometry; + + var colors = dummy.geometry.faces[ 0 ].vertexColors; + colors[ 0 ] = pxpz > px && x > 0 ? shadow : light; + colors[ 3 ] = pxnz > px && x > 0 ? shadow : light; + + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nx != h && nx != h + 1 ) || x == worldWidth - 1 ) { + + dummy.geometry = nxGeometry; + + var colors = dummy.geometry.faces[ 0 ].vertexColors; + colors[ 0 ] = nxnz > nx && x < worldWidth - 1 ? shadow : light; + colors[ 3 ] = nxpz > nx && x < worldWidth - 1 ? shadow : light; + + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( pz != h && pz != h + 1 ) || z == worldDepth - 1 ) { + + dummy.geometry = pzGeometry; + + var colors = dummy.geometry.faces[ 0 ].vertexColors; + colors[ 0 ] = nxpz > pz && z < worldDepth - 1 ? shadow : light; + colors[ 3 ] = pxpz > pz && z < worldDepth - 1 ? shadow : light; + + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nz != h && nz != h + 1 ) || z == 0 ) { + + dummy.geometry = nzGeometry; + + var colors = dummy.geometry.faces[ 0 ].vertexColors; + colors[ 0 ] = pxnz > nz && z > 0 ? shadow : light; + colors[ 3 ] = nxnz > nz && z > 0 ? shadow : light; + + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + } + + } + + var textureGrass = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass.png' ); + textureGrass.magFilter = THREE.NearestFilter; + textureGrass.minFilter = THREE.LinearMipMapLinearFilter; + + var textureGrassDirt = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass_dirt.png' ); + textureGrassDirt.magFilter = THREE.NearestFilter; + textureGrassDirt.minFilter = THREE.LinearMipMapLinearFilter; + + var material1 = new THREE.MeshLambertMaterial( { map: textureGrass, ambient: 0xbbbbbb, vertexColors: THREE.VertexColors } ); + var material2 = new THREE.MeshLambertMaterial( { map: textureGrassDirt, ambient: 0xbbbbbb, vertexColors: THREE.VertexColors } ); + + var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( [ material1, material2 ] ) ); + scene.add( mesh ); + + var ambientLight = new THREE.AmbientLight( 0xcccccc ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 ); + directionalLight.position.set( 1, 1, 0.5 ).normalize(); + scene.add( directionalLight ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0xffffff } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function loadTexture( path, callback ) { + + var image = new Image(); + + image.onload = function () { callback(); }; + image.src = path; + + return image; + + } + + function generateHeight( width, height ) { + + var data = [], perlin = new ImprovedNoise(), + size = width * height, quality = 2, z = Math.random() * 100; + + for ( var j = 0; j < 4; j ++ ) { + + if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0; + + for ( var i = 0; i < size; i ++ ) { + + var x = i % width, y = ( i / width ) | 0; + data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality; + + } + + quality *= 4 + + } + + return data; + + } + + function getY( x, z ) { + + return ( data[ x + z * worldWidth ] * 0.2 ) | 0; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + controls.update( clock.getDelta() ); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_minecraft_oculusrift.html + +()=>{ + + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh; + + var effect; + + var worldWidth = 128, worldDepth = 128, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2, + data = generateHeight( worldWidth, worldDepth ); + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 ); + camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100; + + controls = new THREE.FirstPersonControls( camera ); + + controls.movementSpeed = 1000; + controls.lookSpeed = 0.125; + controls.lookVertical = true; + + scene = new THREE.Scene(); + + // sides + + var matrix = new THREE.Matrix4(); + + var pxGeometry = new THREE.PlaneGeometry( 100, 100 ); + pxGeometry.faces[ 0 ].materialIndex = 1; + pxGeometry.applyMatrix( matrix.makeRotationY( Math.PI / 2 ) ); + pxGeometry.applyMatrix( matrix.makeTranslation( 50, 0, 0 ) ); + + var nxGeometry = new THREE.PlaneGeometry( 100, 100 ); + nxGeometry.faces[ 0 ].materialIndex = 1; + nxGeometry.applyMatrix( matrix.makeRotationY( - Math.PI / 2 ) ); + nxGeometry.applyMatrix( matrix.makeTranslation( - 50, 0, 0 ) ); + + var pyGeometry = new THREE.PlaneGeometry( 100, 100 ); + pyGeometry.faces[ 0 ].materialIndex = 0; + pyGeometry.applyMatrix( matrix.makeRotationX( - Math.PI / 2 ) ); + pyGeometry.applyMatrix( matrix.makeTranslation( 0, 50, 0 ) ); + + var pzGeometry = new THREE.PlaneGeometry( 100, 100 ); + pzGeometry.faces[ 0 ].materialIndex = 1; + pzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, 50 ) ); + + var nzGeometry = new THREE.PlaneGeometry( 100, 100 ); + nzGeometry.faces[ 0 ].materialIndex = 1; + nzGeometry.applyMatrix( matrix.makeRotationY( Math.PI ) ); + nzGeometry.applyMatrix( matrix.makeTranslation( 0, 0, -50 ) ); + // + + var geometry = new THREE.Geometry(); + var dummy = new THREE.Mesh(); + + for ( var z = 0; z < worldDepth; z ++ ) { + + for ( var x = 0; x < worldWidth; x ++ ) { + + var h = getY( x, z ); + + dummy.position.x = x * 100 - worldHalfWidth * 100; + dummy.position.y = h * 100; + dummy.position.z = z * 100 - worldHalfDepth * 100; + + var px = getY( x + 1, z ); + var nx = getY( x - 1, z ); + var pz = getY( x, z + 1 ); + var nz = getY( x, z - 1 ); + + dummy.geometry = pyGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + if ( ( px != h && px != h + 1 ) || x == 0 ) { + + dummy.geometry = pxGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nx != h && nx != h + 1 ) || x == worldWidth - 1 ) { + + dummy.geometry = nxGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( pz != h && pz != h + 1 ) || z == worldDepth - 1 ) { + + dummy.geometry = pzGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + if ( ( nz != h && nz != h + 1 ) || z == 0 ) { + + dummy.geometry = nzGeometry; + THREE.GeometryUtils.merge( geometry, dummy ); + + } + + } + + } + + var textureGrass = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass.png' ); + textureGrass.magFilter = THREE.NearestFilter; + textureGrass.minFilter = THREE.LinearMipMapLinearFilter; + + var textureGrassDirt = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass_dirt.png' ); + textureGrassDirt.magFilter = THREE.NearestFilter; + textureGrassDirt.minFilter = THREE.LinearMipMapLinearFilter; + + var material1 = new THREE.MeshLambertMaterial( { map: textureGrass, ambient: 0xbbbbbb } ); + var material2 = new THREE.MeshLambertMaterial( { map: textureGrassDirt, ambient: 0xbbbbbb } ); + + var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( [ material1, material2 ] ) ); + scene.add( mesh ); + + var ambientLight = new THREE.AmbientLight( 0xcccccc ); + scene.add( ambientLight ); + + var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 ); + directionalLight.position.set( 1, 1, 0.5 ).normalize(); + scene.add( directionalLight ); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + effect = new THREE.OculusRiftEffect( renderer ); + effect.setSize( window.innerWidth, window.innerHeight ); + + // Right Oculus Parameters are yet to be determined + effect.separation = 20; + effect.distortion = 0.1; + effect.fov = 110; + + + document.getElementById( 'distVal' ).innerHTML = effect.distortion.toFixed(2); + document.getElementById( 'sepVal' ).innerHTML = effect.separation; + document.getElementById( 'fovVal' ).innerHTML = effect.fov; + + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // GUI + window.addEventListener( 'resize', onWindowResize, false ); + document.addEventListener( 'keydown', keyPressed, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + effect.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function keyPressed (event) { + switch ( event.keyCode ) { + case 79: /*O*/ effect.distortion -= 0.01; document.getElementById( 'distVal' ).innerHTML = effect.distortion.toFixed(2); break; + case 80: /*P*/ effect.distortion += 0.01; document.getElementById( 'distVal' ).innerHTML = effect.distortion.toFixed(2); break; + case 75: /*K*/ effect.separation -= 1; document.getElementById( 'sepVal' ).innerHTML = effect.separation; break; + case 76: /*L*/ effect.separation += 1; document.getElementById( 'sepVal' ).innerHTML = effect.separation; break; + case 78: /*N*/ effect.fov -= 1; document.getElementById( 'fovVal' ).innerHTML = effect.fov; break; + case 77: /*M*/ effect.fov += 1; document.getElementById( 'fovVal' ).innerHTML = effect.fov; break; + + } + } + + function generateHeight( width, height ) { + + var data = [], perlin = new ImprovedNoise(), + size = width * height, quality = 2, z = Math.random() * 100; + + for ( var j = 0; j < 4; j ++ ) { + + if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0; + + for ( var i = 0; i < size; i ++ ) { + + var x = i % width, y = ( i / width ) | 0; + data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality; + + + } + + quality *= 4 + + } + + return data; + + } + + function getY( x, z ) { + + return ( data[ x + z * worldWidth ] * 0.2 ) | 0; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + controls.update( clock.getDelta() ); + effect.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_normals.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var cube, plane; + + var targetYRotation = 0; + var targetXRotation = 0; + var targetYRotationOnMouseDown = 0; + var targetXRotationOnMouseDown = 0; + + var mouseX = 0, mouseY = 0; + var mouseXOnMouseDown = 0; + var mouseYOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var group; + + var targetRotationOnMouseDown; + var targetRotation; + + + // Create new object by parameters + + var createSomething = function( klass, args ) { + + var F = function( klass, args ) { + + return klass.apply( this, args ); + + } + + F.prototype = klass.prototype; + + return new F( klass, args ); + + }; + + + // Cube + + var materials = []; + + for ( var i = 0; i < 6; i ++ ) { + + materials.push( [ new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: false } ) ] ); + + } + + + + var geometriesParams: {type:string;args:any[];}[] = [ + + { type: 'CubeGeometry', args: [ 200, 200, 200, 2, 2, 2, materials ] }, + { type: 'TorusGeometry', args: [ 100, 60, 12, 12 ] }, + { type: 'TorusKnotGeometry', args: [ ] }, + { type: 'SphereGeometry', args: [ 100, 12, 12 ] }, + { type: 'SphereGeometry', args: [ 100, 5, 5 ] }, + { type: 'SphereGeometry', args: [ 100, 13, 13 ] }, + { type: 'IcosahedronGeometry', args: [ 100, 1 ] }, + { type: 'CylinderGeometry', args: [ 25, 75, 200, 8, 3 ]} , + { type: 'OctahedronGeometry', args: [200, 0] }, + { type: 'LatheGeometry', args: [ [ + new THREE.Vector3(0,0,-100), + new THREE.Vector3(0,50,-50), + new THREE.Vector3(0,10,0), + new THREE.Vector3(0,50,050), + new THREE.Vector3(0,0,100) ] ]}, + { type: 'LatheGeometry', args: [ [ + new THREE.Vector3(0,0,-100), + new THREE.Vector3(0,50,-50), + new THREE.Vector3(0,10,0), + new THREE.Vector3(0,50,050), + new THREE.Vector3(0,100,100) ], 12, 0, Math.PI ] }, + { type: 'LatheGeometry', args: [ [ + new THREE.Vector3(0,10,-100), + new THREE.Vector3(0,50,-50), + new THREE.Vector3(0,10,0), + new THREE.Vector3(0,50,050), + new THREE.Vector3(0,0,100) ], 12, Math.PI*2/3, Math.PI*3/2 ] }, + { type: 'TextGeometry', args: ['&', { + size: 200, + height: 50, + curveSegments: 1, + font: "helvetiker" + + }]}, + { type: 'PlaneGeometry', args: [ 200, 200, 4, 4 ] } + + ]; + + var info; + var geometryIndex = 0; + + // start scene + + init(); + animate(); + + function nextGeometry() { + + geometryIndex ++; + + if ( geometryIndex > geometriesParams.length - 1 ) { + + geometryIndex = 0; + + } + + addStuff(); + + } + + function switchGeometry(i) { + + geometryIndex = i; + + addStuff(); + } + + function updateInfo() { + + var params = geometriesParams[ geometryIndex ]; + + var dropdown = ''; + + var text = + 'Drag to spin THREE.' + params.type + + '
' + + '
Geometry: ' + dropdown + ' next'; + + text += + '

Blue Arrows: Face Normals' + + '
Red Arrows: Vertex Normals before Geometry.mergeVertices' + + '
Black Arrows: Vertex Normals after Geometry.mergeVertices'; + + info.innerHTML = text; + + } + + function addStuff() { + + if ( group !== undefined ) { + + scene.remove( group ); + + } + + + + var params = geometriesParams[ geometryIndex ]; + + var geometry = createSomething( THREE[ params.type ], params.args ); + + // scale geometry to a uniform size + geometry.computeBoundingSphere(); + + var scaleFactor = 160 / geometry.boundingSphere.radius; + geometry.applyMatrix( new THREE.Matrix4().makeScale( scaleFactor, scaleFactor, scaleFactor ) ); + + var originalGeometry = geometry.clone(); + originalGeometry.computeFaceNormals(); + originalGeometry.computeVertexNormals( true ); + + // in case of duplicated vertices + geometry.mergeVertices(); + geometry.computeCentroids(); + geometry.computeFaceNormals(); + geometry.computeVertexNormals( true ); + + updateInfo(); + + var faceABCD = "abcd"; + var color, f, p, n, vertexIndex; + + for ( i = 0; i < geometry.faces.length; i ++ ) { + + f = geometry.faces[ i ]; + + + n = ( f instanceof THREE.Face3 ) ? 3 : 4; + + for( var j = 0; j < n; j++ ) { + + vertexIndex = f[ faceABCD.charAt( j ) ]; + + p = geometry.vertices[ vertexIndex ]; + + color = new THREE.Color( 0xffffff ); + color.setHSL( ( p.y ) / 400 + 0.5, 1.0, 1.0 ); + + f.vertexColors[ j ] = color; + + } + + } + + + group = new THREE.Object3D(); + var mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xfefefe, wireframe: true, opacity: 0.5 } ) ); + group.add( mesh ); + scene.add( group ); + + var fvNames = [ 'a', 'b', 'c', 'd' ]; + + var normalLength = 15; + + for( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { + var face = geometry.faces[ f ]; + var arrow = new THREE.ArrowHelper( + face.normal, + face.centroid, + normalLength, + 0x3333FF ); + mesh.add( arrow ); + } + + for( var f = 0, fl = originalGeometry.faces.length; f < fl; f ++ ) { + var face = originalGeometry.faces[ f ]; + if( face.vertexNormals === undefined ) { + continue; + } + for( var v = 0, vl = face.vertexNormals.length; v < vl; v ++ ) { + var arrow = new THREE.ArrowHelper( + face.vertexNormals[ v ], + originalGeometry.vertices[ face[ fvNames[ v ] ] ], + normalLength, + 0xFF3333 ); + mesh.add( arrow ); + } + } + + for( var f = 0, fl = mesh.geometry.faces.length; f < fl; f ++ ) { + var face = mesh.geometry.faces[ f ]; + if( face.vertexNormals === undefined ) { + continue; + } + for( var v = 0, vl = face.vertexNormals.length; v < vl; v ++ ) { + var arrow = new THREE.ArrowHelper( + face.vertexNormals[ v ], + mesh.geometry.vertices[ face[ fvNames[ v ] ] ], + normalLength, + 0x000000 ); + mesh.add( arrow ); + } + } + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Drag to spin the geometry '; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + var light = new THREE.PointLight( 0xffffff, 1.5 ); + light.position.set( 1000, 1000, 2000 ); + scene.add( light ); + + addStuff(); + + renderer = new THREE.WebGLRenderer( { antialias: true } ); // WebGLRenderer CanvasRenderer + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown( event ) { + + //event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + mouseYOnMouseDown = event.clientY - windowHalfY; + targetYRotationOnMouseDown = targetYRotation; + targetXRotationOnMouseDown = targetXRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + targetYRotation = targetYRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + targetXRotation = targetXRotationOnMouseDown + ( mouseY - mouseYOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + group.rotation.x = ( targetXRotation) * 0.15; + group.rotation.y = ( targetYRotation ) * 0.15; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_shapes.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var text, plane; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var parent; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Simple procedurally generated 3D shapes example by zz85
Drag to spin'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, 150, 500 ); + + scene = new THREE.Scene(); + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( 0, 0, 1 ); + scene.add( light ); + + parent = new THREE.Object3D(); + parent.position.y = 50; + scene.add( parent ); + + function addShape( shape, extrudeSettings, color, x, y, z, rx, ry, rz, s ) { + + var points = shape.createPointsGeometry(); + var spacedPoints = shape.createSpacedPointsGeometry( 100 ); + + // flat shape + + var geometry = new THREE.ShapeGeometry( shape ); + + var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [ new THREE.MeshLambertMaterial( { color: color } ), new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, transparent: true } ) ] ); + mesh.position.set( x, y, z - 125 ); + mesh.rotation.set( rx, ry, rz ); + mesh.scale.set( s, s, s ); + parent.add( mesh ); + + // 3d shape + + var geometryExtrude = new THREE.ExtrudeGeometry( shape, extrudeSettings ); + + var mesh = THREE.SceneUtils.createMultiMaterialObject( geometryExtrude, [ new THREE.MeshLambertMaterial( { color: color } ), new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, transparent: true } ) ] ); + mesh.position.set( x, y, z - 75 ); + mesh.rotation.set( rx, ry, rz ); + mesh.scale.set( s, s, s ); + parent.add( mesh ); + + // solid line + + var line = new THREE.Line( points, new THREE.LineBasicMaterial( { color: color, linewidth: 2 } ) ); + line.position.set( x, y, z + 25 ); + line.rotation.set( rx, ry, rz ); + line.scale.set( s, s, s ); + parent.add( line ); + + // transparent line from real points + + var line = new THREE.Line( points, new THREE.LineBasicMaterial( { color: color, opacity: 0.5 } ) ); + line.position.set( x, y, z + 75 ); + line.rotation.set( rx, ry, rz ); + line.scale.set( s, s, s ); + parent.add( line ); + + // vertices from real points + + var pgeo = points.clone(); + var particles = new THREE.ParticleSystem( pgeo, new THREE.ParticleBasicMaterial( { color: color, size: 2, opacity: 0.75 } ) ); + particles.position.set( x, y, z + 75 ); + particles.rotation.set( rx, ry, rz ); + particles.scale.set( s, s, s ); + parent.add( particles ); + + // transparent line from equidistance sampled points + + var line = new THREE.Line( spacedPoints, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) ); + line.position.set( x, y, z + 125 ); + line.rotation.set( rx, ry, rz ); + line.scale.set( s, s, s ); + parent.add( line ); + + // equidistance sampled points + + var pgeo = spacedPoints.clone(); + var particles2 = new THREE.ParticleSystem( pgeo, new THREE.ParticleBasicMaterial( { color: color, size: 2, opacity: 0.5 } ) ); + particles2.position.set( x, y, z + 125 ); + particles2.rotation.set( rx, ry, rz ); + particles2.scale.set( s, s, s ); + parent.add( particles2 ); + + } + + + // California + + var californiaPts = []; + + californiaPts.push( new THREE.Vector2 ( 610, 320 ) ); + californiaPts.push( new THREE.Vector2 ( 450, 300 ) ); + californiaPts.push( new THREE.Vector2 ( 392, 392 ) ); + californiaPts.push( new THREE.Vector2 ( 266, 438 ) ); + californiaPts.push( new THREE.Vector2 ( 190, 570 ) ); + californiaPts.push( new THREE.Vector2 ( 190, 600 ) ); + californiaPts.push( new THREE.Vector2 ( 160, 620 ) ); + californiaPts.push( new THREE.Vector2 ( 160, 650 ) ); + californiaPts.push( new THREE.Vector2 ( 180, 640 ) ); + californiaPts.push( new THREE.Vector2 ( 165, 680 ) ); + californiaPts.push( new THREE.Vector2 ( 150, 670 ) ); + californiaPts.push( new THREE.Vector2 ( 90, 737 ) ); + californiaPts.push( new THREE.Vector2 ( 80, 795 ) ); + californiaPts.push( new THREE.Vector2 ( 50, 835 ) ); + californiaPts.push( new THREE.Vector2 ( 64, 870 ) ); + californiaPts.push( new THREE.Vector2 ( 60, 945 ) ); + californiaPts.push( new THREE.Vector2 ( 300, 945 ) ); + californiaPts.push( new THREE.Vector2 ( 300, 743 ) ); + californiaPts.push( new THREE.Vector2 ( 600, 473 ) ); + californiaPts.push( new THREE.Vector2 ( 626, 425 ) ); + californiaPts.push( new THREE.Vector2 ( 600, 370 ) ); + californiaPts.push( new THREE.Vector2 ( 610, 320 ) ); + + var californiaShape = new THREE.Shape( californiaPts ); + + + // Triangle + + var triangleShape = new THREE.Shape(); + triangleShape.moveTo( 80, 20 ); + triangleShape.lineTo( 40, 80 ); + triangleShape.lineTo( 120, 80 ); + triangleShape.lineTo( 80, 20 ); // close path + + + // Heart + + var x = 0, y = 0; + + var heartShape = new THREE.Shape(); // From http://blog.burlock.org/html5/130-paths + + heartShape.moveTo( x + 25, y + 25 ); + heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y ); + heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 ); + heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 ); + heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 ); + heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y ); + heartShape.bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 ); + + + // Square + + var sqLength = 80; + + var squareShape = new THREE.Shape(); + squareShape.moveTo( 0,0 ); + squareShape.lineTo( 0, sqLength ); + squareShape.lineTo( sqLength, sqLength ); + squareShape.lineTo( sqLength, 0 ); + squareShape.lineTo( 0, 0 ); + + + // Rectangle + + var rectLength = 120, rectWidth = 40; + + var rectShape = new THREE.Shape(); + rectShape.moveTo( 0,0 ); + rectShape.lineTo( 0, rectWidth ); + rectShape.lineTo( rectLength, rectWidth ); + rectShape.lineTo( rectLength, 0 ); + rectShape.lineTo( 0, 0 ); + + + // Rounded rectangle + + var roundedRectShape = new THREE.Shape(); + + ( function roundedRect( ctx, x, y, width, height, radius ){ + + ctx.moveTo( x, y + radius ); + ctx.lineTo( x, y + height - radius ); + ctx.quadraticCurveTo( x, y + height, x + radius, y + height ); + ctx.lineTo( x + width - radius, y + height) ; + ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius ); + ctx.lineTo( x + width, y + radius ); + ctx.quadraticCurveTo( x + width, y, x + width - radius, y ); + ctx.lineTo( x + radius, y ); + ctx.quadraticCurveTo( x, y, x, y + radius ); + + } )( roundedRectShape, 0, 0, 50, 50, 20 ); + + + // Circle + + var circleRadius = 40; + var circleShape = new THREE.Shape(); + circleShape.moveTo( 0, circleRadius ); + circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 ); + circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius ); + circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 ); + circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius ); + + + // Fish + + x = y = 0; + + var fishShape = new THREE.Shape(); + + fishShape.moveTo(x,y); + fishShape.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10); + fishShape.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40); + fishShape.quadraticCurveTo(x + 115, y, x + 115, y + 40); + fishShape.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10); + fishShape.quadraticCurveTo(x + 50, y + 80, x, y); + + + // Arc circle + + var arcShape = new THREE.Shape(); + arcShape.moveTo( 50, 10 ); + arcShape.absarc( 10, 10, 40, 0, Math.PI*2, false ); + + var holePath = new THREE.Path(); + holePath.moveTo( 20, 10 ); + holePath.absarc( 10, 10, 10, 0, Math.PI*2, true ); + arcShape.holes.push( holePath ); + + + // Smiley + + var smileyShape = new THREE.Shape(); + smileyShape.moveTo( 80, 40 ); + smileyShape.absarc( 40, 40, 40, 0, Math.PI*2, false ); + + var smileyEye1Path = new THREE.Path(); + smileyEye1Path.moveTo( 35, 20 ); + // smileyEye1Path.absarc( 25, 20, 10, 0, Math.PI*2, true ); + smileyEye1Path.absellipse( 25, 20, 10, 10, 0, Math.PI*2, true ); + + smileyShape.holes.push( smileyEye1Path ); + + var smileyEye2Path = new THREE.Path(); + smileyEye2Path.moveTo( 65, 20 ); + smileyEye2Path.absarc( 55, 20, 10, 0, Math.PI*2, true ); + smileyShape.holes.push( smileyEye2Path ); + + var smileyMouthPath = new THREE.Path(); + // ugly box mouth + // smileyMouthPath.moveTo( 20, 40 ); + // smileyMouthPath.lineTo( 60, 40 ); + // smileyMouthPath.lineTo( 60, 60 ); + // smileyMouthPath.lineTo( 20, 60 ); + // smileyMouthPath.lineTo( 20, 40 ); + + smileyMouthPath.moveTo( 20, 40 ); + smileyMouthPath.quadraticCurveTo( 40, 60, 60, 40 ); + smileyMouthPath.bezierCurveTo( 70, 45, 70, 50, 60, 60 ); + smileyMouthPath.quadraticCurveTo( 40, 80, 20, 60 ); + smileyMouthPath.quadraticCurveTo( 5, 50, 20, 40 ); + + smileyShape.holes.push( smileyMouthPath ); + + + // Spline shape + path extrusion + + var splinepts = []; + splinepts.push( new THREE.Vector2 ( 350, 100 ) ); + splinepts.push( new THREE.Vector2 ( 400, 450 ) ); + splinepts.push( new THREE.Vector2 ( -140, 350 ) ); + splinepts.push( new THREE.Vector2 ( 0, 0 ) ); + + var splineShape = new THREE.Shape( ); + splineShape.moveTo( 0, 0 ); + splineShape.splineThru( splinepts ); + + // splineShape.debug( document.getElementById("debug") ); + + // TODO 3d path? + + var apath = new THREE.SplineCurve3(); + apath.points.push(new THREE.Vector3(-50, 150, 10)); + apath.points.push(new THREE.Vector3(-20, 180, 20)); + apath.points.push(new THREE.Vector3(40, 220, 50)); + apath.points.push(new THREE.Vector3(200, 290, 100)); + + + var extrudeSettings:any = { amount: 20 }; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5 + + // addShape( shape, color, x, y, z, rx, ry,rz, s ); + + addShape( californiaShape, extrudeSettings, 0xffaa00, -300, -100, 0, 0, 0, 0, 0.25 ); + + extrudeSettings.bevelEnabled = true; + extrudeSettings.bevelSegments = 2; + extrudeSettings.steps = 2; + + addShape( triangleShape, extrudeSettings, 0xffee00, -180, 0, 0, 0, 0, 0, 1 ); + addShape( roundedRectShape, extrudeSettings, 0x005500, -150, 150, 0, 0, 0, 0, 1 ); + addShape( squareShape, extrudeSettings, 0x0055ff, 150, 100, 0, 0, 0, 0, 1 ); + addShape( heartShape, extrudeSettings, 0xff1100, 60, 100, 0, 0, 0, Math.PI, 1 ); + addShape( circleShape, extrudeSettings, 0x00ff11, 120, 250, 0, 0, 0, 0, 1 ); + addShape( fishShape, extrudeSettings, 0x222222, -60, 200, 0, 0, 0, 0, 1 ); + addShape( smileyShape, extrudeSettings, 0xee00ff, -200, 250, 0, 0, 0, Math.PI, 1 ); + addShape( arcShape, extrudeSettings, 0xbb4422, 150, 0, 0, 0, 0, 0, 1 ); + + extrudeSettings.extrudePath = apath; + extrudeSettings.bevelEnabled = false; + extrudeSettings.steps = 20; + + addShape( splineShape, extrudeSettings, 0x888888, -50, -100, -50, 0, 0, 0, 0.2 ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05; + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_subdivision.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var cube, plane; + + var targetYRotation = 0; + var targetXRotation = 0; + var targetYRotationOnMouseDown = 0; + var targetXRotationOnMouseDown = 0; + var targetRotationOnMouseDown = 0; + var targetRotation = 0; + + var mouseX = 0, mouseY = 0; + var mouseXOnMouseDown = 0; + var mouseYOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var scene, group, cube, geometry, smooth; + + + // Create new object by parameters + + var createSomething = function( klass, args ) { + + var F = function( klass, args ) { + + return klass.apply( this, args ); + + } + + F.prototype = klass.prototype; + + return new F( klass, args ); + + }; + + + // Cube + + var materials = []; + + for ( var i = 0; i < 6; i ++ ) { + + materials.push( [ new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, wireframe: false } ) ] ); + + } + + + + var geometriesParams:{type:string;args:any[];}[] = [ + + { type: 'CubeGeometry', args: [ 200, 200, 200, 2, 2, 2, materials ] }, + { type: 'TorusGeometry', args: [ 100, 60, 4, 8, Math.PI*2 ] }, + { type: 'TorusKnotGeometry', args: [ ], scale:0.25, meshScale:4 }, + { type: 'SphereGeometry', args: [ 100, 3, 3 ], meshScale:2 }, + { type: 'IcosahedronGeometry', args: [ 100, 1 ], meshScale:2 }, + { type: 'CylinderGeometry', args: [ 25, 75, 200, 8, 3 ]} , + { type: 'OctahedronGeometry', args: [200, 0], meshScale:2 }, + { type: 'LatheGeometry', args: [ [ + new THREE.Vector3(0,0,0), + new THREE.Vector3(0,50,50), + new THREE.Vector3(0,10,100), + new THREE.Vector3(0,50,150), + new THREE.Vector3(0,0,200) ] ]}, + { type: 'TextGeometry', args: ['&', { + size: 200, + height: 50, + curveSegments: 1, + font: "helvetiker" + + }]}, + { type: 'PlaneGeometry', args: [ 200, 200, 4, 4 ] } + + ]; + + var loader = new THREE.JSONLoader(); + loader.load( 'obj/WaltHeadLo.js', function ( geometry ) { + + geometriesParams.push({type: 'WaltHead', args: [ ], meshScale: 6 }); + + THREE["WaltHead"] = function() { + return geometry.clone(); + }; + + updateInfo() + + }); + + var loader2 = new THREE.JSONLoader(); + loader2.load( 'obj/Suzanne.js', function ( geometry ) { + + geometriesParams.push({type: 'Suzanne', args: [ ], scale: 100, meshScale:2 }); + + THREE["Suzanne"] = function() { + return geometry.clone(); + }; + + updateInfo() + + } ); + + + var info; + var subdivisions = 2; + var geometryIndex = 0; + + // start scene + + init(); + animate(); + + function nextSubdivision( x ) { + + subdivisions = Math.max( 0, subdivisions + x ); + addStuff(); + + } + + function nextGeometry() { + + geometryIndex ++; + + if ( geometryIndex > geometriesParams.length - 1 ) { + + geometryIndex = 0; + + } + + addStuff(); + + } + + function switchGeometry(i) { + + geometryIndex = i; + + addStuff(); + } + + function updateInfo() { + + var params = geometriesParams[ geometryIndex ]; + + var dropdown = ''; + + info.innerHTML = 'Drag to spin THREE.' + params.type + + + '

Subdivisions: ' + subdivisions + + ' more/less' + + '
Geometry: ' + dropdown + ' next' + + '

Vertices count: before ' + geometry.vertices.length + ' after ' + smooth.vertices.length + + '
Face count: before ' + geometry.faces.length + ' after ' + smooth.faces.length + ; //+ params.args; + } + + function addStuff() { + + if ( cube ) { + + scene.remove( group ); + scene.remove( cube ); + + } + + + var modifier = new THREE.SubdivisionModifier( subdivisions ); + + + var params:any = geometriesParams[ geometryIndex ]; + + geometry = createSomething( THREE[ params.type ], params.args ); + + // Scale Geometry + + if ( params.scale ) { + + geometry.applyMatrix( new THREE.Matrix4().makeScale( params.scale, params.scale, params.scale ) ); + + } + + // Cloning original geometry for debuging + + var smooth = geometry.clone(); + + // mergeVertices(); is run in case of duplicated vertices + smooth.mergeVertices(); + + smooth.computeCentroids(); + smooth.computeFaceNormals(); + smooth.computeVertexNormals(); + + modifier.modify( smooth ); + + updateInfo(); + + var faceABCD = "abcd"; + var color, f, p, n, vertexIndex; + + for ( i = 0; i < smooth.faces.length; i ++ ) { + + f = smooth.faces[ i ]; + + + n = ( f instanceof THREE.Face3 ) ? 3 : 4; + + for( var j = 0; j < n; j++ ) { + + vertexIndex = f[ faceABCD.charAt( j ) ]; + + p = smooth.vertices[ vertexIndex ]; + + color = new THREE.Color( 0xffffff ); + color.setHSL( ( p.y ) / 200 + 0.5, 1.0, 1.0 ); + + f.vertexColors[ j ] = color; + + } + + } + + + group = new THREE.Object3D(); + group.add( new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xfefefe, wireframe: true, opacity: 0.5 } ) ) ); + scene.add( group ); + + + var debugNewPoints = false; + var debugOldPoints = false; + + // Debug new Points + + if (debugNewPoints) { + var PI2 = Math.PI * 2; + var program = function ( context ) { + + context.beginPath(); + context.arc( 0, 0, 1, 0, PI2, true ); + context.closePath(); + context.fill(); + + } + + for ( var i = 0; i < smooth.vertices.length; i++ ) { + + var particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808008 + 0x808080, program: program } ) ); + particle.position = smooth.vertices[ i ]; + var pos = smooth.vertices.position + particle.scale.x = particle.scale.y = 5; + group.add( particle ); + } + + } + + + //Debug original points + + if (debugOldPoints) { + + var drawText = function(i) { + + return function ( context ) { + + context.beginPath(); + context.scale(0.1,-0.1); + + context.fillText(i, 0,0); + + }; + + } + + for ( var i = 0; i < geometry.vertices.length; i++ ) { + + particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808008 + 0x808080, program: drawText(i) } ) ); + particle.position = smooth.vertices[ i ]; + var pos = geometry.vertices.position + particle.scale.x = particle.scale.y = 30; + group.add( particle ); + } + } + + + var meshmaterials:THREE.Material[] = [ + new THREE.MeshLambertMaterial( { color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors } ), + new THREE.MeshBasicMaterial( { color: 0x405040, wireframe: true, opacity: 0.8, transparent: true } ) + ]; + + cube = THREE.SceneUtils.createMultiMaterialObject( smooth, meshmaterials ); + + var meshScale = params.meshScale ? params.meshScale : 1; + + cube.scale.x = meshScale; + cube.scale.y = meshScale; + cube.scale.z = meshScale; + + scene.add( cube ); + + group.scale.copy( cube.scale ); + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'Drag to spin the geometry '; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 500; + + scene = new THREE.Scene(); + + var light = new THREE.PointLight( 0xffffff, 1.5 ); + light.position.set( 1000, 1000, 2000 ); + scene.add( light ); + + addStuff(); + + renderer = new THREE.WebGLRenderer( { antialias: true } ); // WebGLRenderer CanvasRenderer + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function onDocumentMouseDown( event ) { + + //event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + mouseYOnMouseDown = event.clientY - windowHalfY; + targetYRotationOnMouseDown = targetYRotation; + targetXRotationOnMouseDown = targetXRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + targetYRotation = targetYRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + targetXRotation = targetXRotationOnMouseDown + ( mouseY - mouseYOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + group.rotation.x = cube.rotation.x += ( targetXRotation - cube.rotation.x ) * 0.05; + group.rotation.y = cube.rotation.y += ( targetYRotation - cube.rotation.y ) * 0.05; + + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_terrain.html + +()=>{ + + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh, texture; + + var worldWidth = 256, worldDepth = 256, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2; + + var clock = new THREE.Clock(); + + var data; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 ); + + scene = new THREE.Scene(); + + controls = new THREE.FirstPersonControls( camera ); + controls.movementSpeed = 1000; + controls.lookSpeed = 0.1; + + data = generateHeight( worldWidth, worldDepth ); + + camera.position.y = data[ worldHalfWidth + worldHalfDepth * worldWidth ] + 500; + + var geometry = new THREE.PlaneGeometry( 7500, 7500, worldWidth - 1, worldDepth - 1 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) { + + geometry.vertices[ i ].y = data[ i ] * 10; + + } + + texture = new THREE.Texture( generateTexture( data, worldWidth, worldDepth ), new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping ); + texture.needsUpdate = true; + + mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: texture } ) ); + scene.add( mesh ); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function generateHeight( width, height ) { + + var size = width * height, data = new Float32Array( size ), + perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 100; + + for ( var i = 0; i < size; i ++ ) { + + data[ i ] = 0 + + } + + for ( var j = 0; j < 4; j ++ ) { + + for ( var i = 0; i < size; i ++ ) { + + var x = i % width, y = ~~ ( i / width ); + data[ i ] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality * 1.75 ); + + + } + + quality *= 5; + + } + + return data; + + } + + function generateTexture( data, width, height ) { + + var canvas, canvasScaled, context, image, imageData, + level, diff, vector3, sun, shade; + + vector3 = new THREE.Vector3( 0, 0, 0 ); + + sun = new THREE.Vector3( 1, 1, 1 ); + sun.normalize(); + + canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; + + context = canvas.getContext( '2d' ); + context.fillStyle = '#000'; + context.fillRect( 0, 0, width, height ); + + image = context.getImageData( 0, 0, canvas.width, canvas.height ); + imageData = image.data; + + for ( var i = 0, j = 0, l = imageData.length; i < l; i += 4, j ++ ) { + + vector3.x = data[ j - 2 ] - data[ j + 2 ]; + vector3.y = 2; + vector3.z = data[ j - width * 2 ] - data[ j + width * 2 ]; + vector3.normalize(); + + shade = vector3.dot( sun ); + + imageData[ i ] = ( 96 + shade * 128 ) * ( 0.5 + data[ j ] * 0.007 ); + imageData[ i + 1 ] = ( 32 + shade * 96 ) * ( 0.5 + data[ j ] * 0.007 ); + imageData[ i + 2 ] = ( shade * 96 ) * ( 0.5 + data[ j ] * 0.007 ); + } + + context.putImageData( image, 0, 0 ); + + // Scaled 4x + + canvasScaled = document.createElement( 'canvas' ); + canvasScaled.width = width * 4; + canvasScaled.height = height * 4; + + context = canvasScaled.getContext( '2d' ); + context.scale( 4, 4 ); + context.drawImage( canvas, 0, 0 ); + + image = context.getImageData( 0, 0, canvasScaled.width, canvasScaled.height ); + imageData = image.data; + + for ( var i = 0, l = imageData.length; i < l; i += 4 ) { + + var v = ~~ ( Math.random() * 5 ); + + imageData[ i ] += v; + imageData[ i + 1 ] += v; + imageData[ i + 2 ] += v; + + } + + context.putImageData( image, 0, 0 ); + + return canvasScaled; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + controls.update( clock.getDelta() ); + renderer.render( scene, camera ); + + } + +}; + + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_terrain_fog.html + +()=>{ + + if ( ! Detector.webgl ) { + + Detector.addGetWebGLMessage(); + document.getElementById( 'container' ).innerHTML = ""; + + } + + var container, stats; + + var camera, controls, scene, renderer; + + var mesh, texture; + + var worldWidth = 256, worldDepth = 256, + worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2; + + var clock = new THREE.Clock(); + + var data; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 ); + + controls = new THREE.FirstPersonControls( camera ); + controls.movementSpeed = 150; + controls.lookSpeed = 0.1; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0xefd1b5, 0.0025 ); + + data = generateHeight( worldWidth, worldDepth ); + + camera.position.y = data[ worldHalfWidth + worldHalfDepth * worldWidth ] * 10 + 500; + + var geometry = new THREE.PlaneGeometry( 7500, 7500, worldWidth - 1, worldDepth - 1 ); + geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); + + for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) { + + geometry.vertices[ i ].y = data[ i ] * 10; + + } + + texture = new THREE.Texture( generateTexture( data, worldWidth, worldDepth ), new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping ); + texture.needsUpdate = true; + + mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: texture } ) ); + scene.add( mesh ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0xefd1b5, clearAlpha: 1 } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.innerHTML = ""; + + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + controls.handleResize(); + + } + + function generateHeight( width, height ) { + + var size = width * height, data = new Float32Array( size ), + perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 100; + + for ( var i = 0; i < size; i ++ ) { + + data[ i ] = 0 + + } + + for ( var j = 0; j < 4; j ++ ) { + + for ( var i = 0; i < size; i ++ ) { + + var x = i % width, y = ~~ ( i / width ); + data[ i ] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality * 1.75 ); + + + } + + quality *= 5; + + } + + return data; + + } + + function generateTexture( data, width, height ) { + + var canvas, canvasScaled, context, image, imageData, + level, diff, vector3, sun, shade; + + vector3 = new THREE.Vector3( 0, 0, 0 ); + + sun = new THREE.Vector3( 1, 1, 1 ); + sun.normalize(); + + canvas = document.createElement( 'canvas' ); + canvas.width = width; + canvas.height = height; + + context = canvas.getContext( '2d' ); + context.fillStyle = '#000'; + context.fillRect( 0, 0, width, height ); + + image = context.getImageData( 0, 0, canvas.width, canvas.height ); + imageData = image.data; + + for ( var i = 0, j = 0, l = imageData.length; i < l; i += 4, j ++ ) { + + vector3.x = data[ j - 2 ] - data[ j + 2 ]; + vector3.y = 2; + vector3.z = data[ j - width * 2 ] - data[ j + width * 2 ]; + vector3.normalize(); + + shade = vector3.dot( sun ); + + imageData[ i ] = ( 96 + shade * 128 ) * ( 0.5 + data[ j ] * 0.007 ); + imageData[ i + 1 ] = ( 32 + shade * 96 ) * ( 0.5 + data[ j ] * 0.007 ); + imageData[ i + 2 ] = ( shade * 96 ) * ( 0.5 + data[ j ] * 0.007 ); + + } + + context.putImageData( image, 0, 0 ); + + // Scaled 4x + + canvasScaled = document.createElement( 'canvas' ); + canvasScaled.width = width * 4; + canvasScaled.height = height * 4; + + context = canvasScaled.getContext( '2d' ); + context.scale( 4, 4 ); + context.drawImage( canvas, 0, 0 ); + + image = context.getImageData( 0, 0, canvasScaled.width, canvasScaled.height ); + imageData = image.data; + + for ( var i = 0, l = imageData.length; i < l; i += 4 ) { + + var v = ~~ ( Math.random() * 5 ); + + imageData[ i ] += v; + imageData[ i + 1 ] += v; + imageData[ i + 2 ] += v; + + } + + context.putImageData( image, 0, 0 ); + + return canvasScaled; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + + function render() { + + controls.update( clock.getDelta() ); + renderer.render( scene, camera ); + + } +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_tessellation.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var renderer, scene, camera, stats; + + var mesh, uniforms, attributes; + + var WIDTH = window.innerWidth, + HEIGHT = window.innerHeight; + + var controls; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 25, WIDTH / HEIGHT, 1, 10000 ); + camera.position.z = 350; + + controls = new THREE.TrackballControls( camera ); + + scene = new THREE.Scene(); + + // + + attributes = { + + displacement: { type: 'v3', value: [] }, + customColor: { type: 'c', value: [] } + + }; + + uniforms = { + + amplitude: { type: "f", value: 0.0 } + + }; + + var shaderMaterial = new THREE.ShaderMaterial( { + + uniforms: uniforms, + attributes: attributes, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent, + shading: THREE.FlatShading, + side: THREE.DoubleSide + + }); + + + var geometry = new THREE.TextGeometry( "THREE.JS", { + + size: 40, + height: 5, + curveSegments: 3, + + font: "helvetiker", + weight: "bold", + style: "normal", + + bevelThickness: 2, + bevelSize: 1, + bevelEnabled: true + + }); + + geometry.dynamic = true; + + THREE.GeometryUtils.center( geometry ); + + var tessellateModifier = new THREE.TessellateModifier( 4 ); + + for ( var i = 0; i < 6; i ++ ) { + + tessellateModifier.modify( geometry ); + + } + + var explodeModifier = new THREE.ExplodeModifier(); + explodeModifier.modify( geometry ); + + var vertices = geometry.vertices; + + var colors = attributes.customColor.value; + var displacement = attributes.displacement.value; + + var h, d, x, y, z, s; + var nv, v = 0; + + for( var f = 0; f < geometry.faces.length; f ++ ) { + + var face = geometry.faces[ f ]; + + if ( face instanceof THREE.Face3 ) { + + nv = 3; + + } else { + + nv = 4; + + } + + h = 0.15 * Math.random(); + s = 0.7 * Math.random(); + + d = 10 * ( 0.5 - Math.random() ); + + x = 2 * ( 0.5 - Math.random() ); + y = 2 * ( 0.5 - Math.random() ); + z = 2 * ( 0.5 - Math.random() ); + + for ( var i = 0; i < nv; i ++ ) { + + colors[ v ] = new THREE.Color(); + displacement[ v ] = new THREE.Vector3(); + + colors[ v ].setHSL( h, s, 1 ); + colors[ v ].convertGammaToLinear(); + + displacement[ v ].set( x, y, z ); + + v += 1; + + } + + } + + console.log( "faces", geometry.faces.length ); + + mesh = new THREE.Mesh( geometry, shaderMaterial ); + mesh.rotation.set( 0.5, 0.5, 0 ); + + scene.add( mesh ); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x050505, clearAlpha: 1, antialias: true } ); + renderer.setSize( WIDTH, HEIGHT ); + + var container = document.getElementById( 'container' ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.001; + + uniforms.amplitude.value = 0.125 * Math.sin( time * 0.5 ); + + controls.update(); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_text.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats, permalink, hex, color; + + var camera, cameraTarget, scene, renderer; + + var composer; + var effectFXAA; + + var textMesh1, textMesh2, textGeo, material, parent; + + var firstLetter = true; + + var text = "three.js", + + height = 20, + size = 70, + hover = 30, + + curveSegments = 4, + + bevelThickness = 2, + bevelSize = 1.5, + bevelSegments = 3, + bevelEnabled = true, + + font = "optimer", // helvetiker, optimer, gentilis, droid sans, droid serif + weight = "bold", // normal bold + style = "normal"; // normal italic + + var mirror = true; + + var fontMap = { + + "helvetiker": 0, + "optimer": 1, + "gentilis": 2, + "droid sans": 3, + "droid serif": 4 + + }; + + var weightMap = { + + "normal": 0, + "bold": 1 + + }; + + var reverseFontMap = {}; + var reverseWeightMap = {}; + + for ( var i in fontMap ) reverseFontMap[ fontMap[i] ] = i; + for ( var i in weightMap ) reverseWeightMap[ weightMap[i] ] = i; + + var targetRotation = 0; + var targetRotationOnMouseDown = 0; + + var mouseX = 0; + var mouseXOnMouseDown = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var postprocessing = { enabled : false }; + var glow = 0.9; + + init(); + animate(); + + function capitalize( txt ) { + + return txt.substring( 0, 1 ).toUpperCase() + txt.substring( 1 ); + + } + + function decimalToHex( d ) { + + var hex = Number( d ).toString( 16 ); + hex = "000000".substr( 0, 6 - hex.length ) + hex; + return hex.toUpperCase(); + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + permalink = document.getElementById( "permalink" ); + + // CAMERA + + camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 1500 ); + camera.position.set( 0, 400, 700 ); + + cameraTarget = new THREE.Vector3( 0, 150, 0 ); + + // SCENE + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x000000, 250, 1400 ); + + // LIGHTS + + var dirLight = new THREE.DirectionalLight( 0xffffff, 0.125 ); + dirLight.position.set( 0, 0, 1 ).normalize(); + scene.add( dirLight ); + + var pointLight = new THREE.PointLight( 0xffffff, 1.5 ); + pointLight.position.set( 0, 100, 90 ); + scene.add( pointLight ); + + //text = capitalize( font ) + " " + capitalize( weight ); + //text = "abcdefghijklmnopqrstuvwxyz0123456789"; + //text = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + // Get text from hash + + var hash = document.location.hash.substr( 1 ); + + if ( hash.length !== 0 ) { + + var colorhash = hash.substring( 0, 6 ); + var fonthash = hash.substring( 6, 7 ); + var weighthash = hash.substring( 7, 8 ); + var pphash = hash.substring( 8, 9 ); + var bevelhash = hash.substring( 9, 10 ); + var texthash = hash.substring( 10 ); + + hex = colorhash; + pointLight.color.setHex( parseInt( colorhash, 16 ) ); + + font = reverseFontMap[ parseInt( fonthash ) ]; + weight = reverseWeightMap[ parseInt( weighthash ) ]; + + postprocessing.enabled = parseInt( pphash ) ? true : false; + bevelEnabled = parseInt( bevelhash ) ? true : false; + + text = decodeURI( texthash ); + + updatePermalink(); + + } else { + + pointLight.color.setHSL( Math.random(), 0.95, 0.85 ); + hex = decimalToHex( pointLight.color.getHex() ); + + } + + material = new THREE.MeshFaceMaterial( [ + new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front + new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side + ] ); + + parent = new THREE.Object3D(); + parent.position.y = 100; + + scene.add( parent ); + + createText(); + + var plane = new THREE.Mesh( new THREE.PlaneGeometry( 10000, 10000 ), new THREE.MeshBasicMaterial( { color: 0xffffff, opacity: 0.5, transparent: true } ) ); + plane.position.y = 100; + plane.rotation.x = - Math.PI / 2; + scene.add( plane ); + + // RENDERER + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + // STATS + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + //container.appendChild( stats.domElement ); + + // EVENTS + + document.addEventListener( 'mousedown', onDocumentMouseDown, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + document.addEventListener( 'keypress', onDocumentKeyPress, false ); + document.addEventListener( 'keydown', onDocumentKeyDown, false ); + + document.getElementById( "color" ).addEventListener( 'click', function() { + + pointLight.color.setHSL( Math.random(), 0.95, 0.85 ); + hex = decimalToHex( pointLight.color.getHex() ); + + updatePermalink(); + + }, false ); + + document.getElementById( "font" ).addEventListener( 'click', function() { + + if ( font == "helvetiker" ) { + + font = "optimer"; + + } else if ( font == "optimer" ) { + + font = "gentilis"; + + } else if ( font == "gentilis" ) { + + font = "droid sans"; + + } else if ( font == "droid sans" ) { + + font = "droid serif"; + + } else { + + font = "helvetiker"; + + } + + refreshText(); + + }, false ); + + document.getElementById( "weight" ).addEventListener( 'click', function() { + + if ( weight == "bold" ) { + + weight = "normal"; + + } else { + + weight = "bold"; + + } + + refreshText(); + + }, false ); + + document.getElementById( "bevel" ).addEventListener( 'click', function() { + + bevelEnabled = !bevelEnabled; + + refreshText(); + + }, false ); + + document.getElementById( "postprocessing" ).addEventListener( 'click', function() { + + postprocessing.enabled = !postprocessing.enabled; + updatePermalink(); + + }, false ); + + + // POSTPROCESSING + + renderer.autoClear = false; + + var renderModel = new THREE.RenderPass( scene, camera ); + var effectBloom = new THREE.BloomPass( 0.25 ); + var effectFilm = new THREE.FilmPass( 0.5, 0.125, 2048, false ); + + effectFXAA = new THREE.ShaderPass( THREE.FXAAShader ); + + var width = window.innerWidth || 2; + var height = window.innerHeight || 2; + + effectFXAA.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height ); + + effectFilm.renderToScreen = true; + + composer = new THREE.EffectComposer( renderer ); + + composer.addPass( renderModel ); + composer.addPass( effectFXAA ); + composer.addPass( effectBloom ); + composer.addPass( effectFilm ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + composer.reset(); + + effectFXAA.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight ); + + } + + // + + function boolToNum( b ) { + + return b ? 1 : 0; + + } + + function updatePermalink() { + + var link = hex + fontMap[ font ] + weightMap[ weight ] + boolToNum( postprocessing.enabled ) + boolToNum( bevelEnabled ) + "#" + encodeURI( text ); + + permalink.href = "#" + link; + window.location.hash = link; + + } + + function onDocumentKeyDown( event ) { + + if ( firstLetter ) { + + firstLetter = false; + text = ""; + + } + + var keyCode = event.keyCode; + + // backspace + + if ( keyCode == 8 ) { + + event.preventDefault(); + + text = text.substring( 0, text.length - 1 ); + refreshText(); + + return false; + + } + + } + + function onDocumentKeyPress( event ) { + + var keyCode = event.which; + + // backspace + + if ( keyCode == 8 ) { + + event.preventDefault(); + + } else { + + var ch = String.fromCharCode( keyCode ); + text += ch; + + refreshText(); + + } + + } + + function createText() { + + textGeo = new THREE.TextGeometry( text, { + + size: size, + height: height, + curveSegments: curveSegments, + + font: font, + weight: weight, + style: style, + + bevelThickness: bevelThickness, + bevelSize: bevelSize, + bevelEnabled: bevelEnabled, + + material: 0, + extrudeMaterial: 1 + + }); + + textGeo.computeBoundingBox(); + textGeo.computeVertexNormals(); + + // "fix" side normals by removing z-component of normals for side faces + // (this doesn't work well for beveled geometry as then we lose nice curvature around z-axis) + + if ( ! bevelEnabled ) { + + var triangleAreaHeuristics = 0.1 * ( height * size ); + + for ( var i = 0; i < textGeo.faces.length; i ++ ) { + + var face = textGeo.faces[ i ]; + + if ( face.materialIndex == 1 ) { + + for ( var j = 0; j < face.vertexNormals.length; j ++ ) { + + face.vertexNormals[ j ].z = 0; + face.vertexNormals[ j ].normalize(); + + } + + var va = textGeo.vertices[ face.a ]; + var vb = textGeo.vertices[ face.b ]; + var vc = textGeo.vertices[ face.c ]; + + var s = THREE.GeometryUtils.triangleArea( va, vb, vc ); + + if ( s > triangleAreaHeuristics ) { + + for ( var j = 0; j < face.vertexNormals.length; j ++ ) { + + face.vertexNormals[ j ].copy( face.normal ); + + } + + } + + } + + } + + } + + var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x ); + + textMesh1 = new THREE.Mesh( textGeo, material ); + + textMesh1.position.x = centerOffset; + textMesh1.position.y = hover; + textMesh1.position.z = 0; + + textMesh1.rotation.x = 0; + textMesh1.rotation.y = Math.PI * 2; + + parent.add( textMesh1 ); + + if ( mirror ) { + + textMesh2 = new THREE.Mesh( textGeo, material ); + + textMesh2.position.x = centerOffset; + textMesh2.position.y = -hover; + textMesh2.position.z = height; + + textMesh2.rotation.x = Math.PI; + textMesh2.rotation.y = Math.PI * 2; + + parent.add( textMesh2 ); + + } + + } + + function refreshText() { + + updatePermalink(); + + parent.remove( textMesh1 ); + if ( mirror ) parent.remove( textMesh2 ); + + if ( !text ) return; + + createText(); + + } + + function onDocumentMouseDown( event ) { + + event.preventDefault(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'mouseup', onDocumentMouseUp, false ); + document.addEventListener( 'mouseout', onDocumentMouseOut, false ); + + mouseXOnMouseDown = event.clientX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02; + + } + + function onDocumentMouseUp( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentMouseOut( event ) { + + document.removeEventListener( 'mousemove', onDocumentMouseMove, false ); + document.removeEventListener( 'mouseup', onDocumentMouseUp, false ); + document.removeEventListener( 'mouseout', onDocumentMouseOut, false ); + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX; + targetRotationOnMouseDown = targetRotation; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05; + + camera.lookAt( cameraTarget ); + + renderer.clear(); + + if ( postprocessing.enabled ) { + + composer.render( 0.05 ); + + } else { + + renderer.render( scene, camera ); + + } + + } +}; + + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_hdr.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + var materialHDR, quad; + + var sign = 1, rate = 1; + + var clock = new THREE.Clock(); + + var delta; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 900; + + scene = new THREE.Scene(); + + var texture = THREE.ImageUtils.loadTexture( "textures/memorial.png" ); + texture.minFilter = THREE.LinearFilter; + texture.magFilter = THREE.NearestFilter; + + materialHDR = new THREE.ShaderMaterial( { + + uniforms: { + tDiffuse: { type: "t", value: texture }, + exposure: { type: "f", value: 0.125 }, + brightMax: { type: "f", value: 0.5 } + }, + vertexShader: getText( 'vs-hdr' ), + fragmentShader: getText( 'fs-hdr' ) + + } ); + + var plane = new THREE.PlaneGeometry( 512, 768 ); + + quad = new THREE.Mesh( plane, materialHDR ); + quad.position.z = -100; + scene.add( quad ); + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function getText( id ) { + + return document.getElementById( id ).textContent; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + delta = clock.getDelta() * 5; + + if ( materialHDR.uniforms.exposure.value > 0 || materialHDR.uniforms.exposure.value < 1 ) { + + rate = 0.25; + + } else { + + rate = 1; + + } + + if ( materialHDR.uniforms.exposure.value > 5 || materialHDR.uniforms.exposure.value <= 0 ) { + + sign *= -1; + + } + + materialHDR.uniforms.exposure.value += sign * rate * delta; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_interactive_cubes.html + +()=>{ + + var container, stats; + var camera, scene, projector, renderer; + + var mouse = { x: 0, y: 0 }, INTERSECTED; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var info = document.createElement( 'div' ); + info.style.position = 'absolute'; + info.style.top = '10px'; + info.style.width = '100%'; + info.style.textAlign = 'center'; + info.innerHTML = 'three.js webgl - interactive cubes'; + container.appendChild( info ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.set( 0, 300, 500 ); + + scene = new THREE.Scene(); + + var light = new THREE.DirectionalLight( 0xffffff, 2 ); + light.position.set( 1, 1, 1 ).normalize(); + scene.add( light ); + + var light = new THREE.DirectionalLight( 0xffffff ); + light.position.set( -1, -1, -1 ).normalize(); + scene.add( light ); + + var geometry = new THREE.CubeGeometry( 20, 20, 20 ); + + for ( var i = 0; i < 2000; i ++ ) { + + var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) ); + + object.position.x = Math.random() * 800 - 400; + object.position.y = Math.random() * 800 - 400; + object.position.z = Math.random() * 800 - 400; + + object.rotation.x = Math.random() * 2 * Math.PI; + object.rotation.y = Math.random() * 2 * Math.PI; + object.rotation.z = Math.random() * 2 * Math.PI; + + object.scale.x = Math.random() + 0.5; + object.scale.y = Math.random() + 0.5; + object.scale.z = Math.random() + 0.5; + + scene.add( object ); + + } + + projector = new THREE.Projector(); + + renderer = new THREE.WebGLRenderer(); + renderer.sortObjects = false; + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild(renderer.domElement); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onDocumentMouseMove( event ) { + + event.preventDefault(); + + mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; + mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + var radius = 100; + var theta = 0; + + function render() { + + theta += 0.1; + + camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) ); + camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) ); + + camera.lookAt( scene.position ); + + // find intersections + + var vector = new THREE.Vector3( mouse.x, mouse.y, 1 ); + projector.unprojectVector( vector, camera ); + + var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() ); + + var intersects = raycaster.intersectObjects( scene.children ); + + if ( intersects.length > 0 ) { + + if ( INTERSECTED != intersects[ 0 ].object ) { + + if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex ); + + INTERSECTED = intersects[ 0 ].object; + INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex(); + INTERSECTED.material.emissive.setHex( 0xff0000 ); + + } + + } else { + + if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex ); + + INTERSECTED = null; + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_interactive_cubes_gpu.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_interactive_draggablecubes.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_interactive_voxelpainter.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_kinect.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lensflares.html + +()=>{ + + var container, stats; + + var camera, scene, renderer; + + var clock = new THREE.Clock(); + + var composer; + + var controls; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + // camera + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 15000 ); + camera.position.z = 250; + + controls = new THREE.FlyControls( camera ); + + controls.movementSpeed = 2500; + controls.domElement = container; + controls.rollSpeed = Math.PI / 6; + controls.autoForward = false; + controls.dragToLook = false + + // scene + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x000000, 3500, 15000 ); + scene.fog.color.setHSL( 0.51, 0.6, 0.025 ); + + // world + + var s = 250; + + var cube = new THREE.CubeGeometry( s, s, s ); + var material = new THREE.MeshPhongMaterial( { ambient: 0x333333, color: 0xffffff, specular: 0xffffff, shininess: 50 } ); + + + for ( var i = 0; i < 3000; i ++ ) { + + var mesh = new THREE.Mesh( cube, material ); + + mesh.position.x = 8000 * ( 2.0 * Math.random() - 1.0 ); + mesh.position.y = 8000 * ( 2.0 * Math.random() - 1.0 ); + mesh.position.z = 8000 * ( 2.0 * Math.random() - 1.0 ); + + mesh.rotation.x = Math.random() * Math.PI; + mesh.rotation.y = Math.random() * Math.PI; + mesh.rotation.z = Math.random() * Math.PI; + + mesh.matrixAutoUpdate = false; + mesh.updateMatrix(); + + scene.add( mesh ); + + } + + + // lights + + var ambient = new THREE.AmbientLight( 0xffffff ); + ambient.color.setHSL( 0.1, 0.5, 0.3 ); + scene.add( ambient ); + + + var dirLight = new THREE.DirectionalLight( 0xffffff, 0.125 ); + dirLight.position.set( 0, -1, 0 ).normalize(); + scene.add( dirLight ); + + dirLight.color.setHSL( 0.1, 0.725, 0.9 ); + + // lens flares + + var textureFlare0 = THREE.ImageUtils.loadTexture( "textures/lensflare/lensflare0.png" ); + var textureFlare2 = THREE.ImageUtils.loadTexture( "textures/lensflare/lensflare2.png" ); + var textureFlare3 = THREE.ImageUtils.loadTexture( "textures/lensflare/lensflare3.png" ); + + addLight( 0.55, 0.825, 0.99, 5000, 0, -1000 ); + addLight( 0.08, 0.825, 0.99, 0, 0, -1000 ); + addLight( 0.995, 0.025, 0.99, 5000, 5000, -1000 ); + + function addLight( h, s, v, x, y, z ) { + + var light = new THREE.PointLight( 0xffffff, 1.5, 4500 ); + light.color.setHSL( h, s, v ); + light.position.set( x, y, z ); + scene.add( light ); + + var flareColor = new THREE.Color( 0xffffff ); + flareColor.setHSL( h, s - 0.5, v + 0.5 ); + + var lensFlare = new THREE.LensFlare( textureFlare0, 700, 0.0, THREE.AdditiveBlending, flareColor ); + + lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); + lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); + lensFlare.add( textureFlare2, 512, 0.0, THREE.AdditiveBlending ); + + lensFlare.add( textureFlare3, 60, 0.6, THREE.AdditiveBlending ); + lensFlare.add( textureFlare3, 70, 0.7, THREE.AdditiveBlending ); + lensFlare.add( textureFlare3, 120, 0.9, THREE.AdditiveBlending ); + lensFlare.add( textureFlare3, 70, 1.0, THREE.AdditiveBlending ); + + lensFlare.customUpdateCallback = lensFlareUpdateCallback; + lensFlare.position = light.position; + + scene.add( lensFlare ); + + } + + // renderer + + renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + // + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + // stats + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // events + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + // + + function lensFlareUpdateCallback( object ) { + + var f, fl = object.lensFlares.length; + var flare; + var vecX = -object.positionScreen.x * 2; + var vecY = -object.positionScreen.y * 2; + + + for( f = 0; f < fl; f++ ) { + + flare = object.lensFlares[ f ]; + + flare.x = object.positionScreen.x + vecX * flare.distance; + flare.y = object.positionScreen.y + vecY * flare.distance; + + flare.rotation = 0; + + } + + object.lensFlares[ 2 ].y += 0.025; + object.lensFlares[ 3 ].rotation = object.positionScreen.x * 0.5 + THREE.Math.degToRad( 45 ); + + } + + // + + function onWindowResize( event ) { + + renderer.setSize( window.innerWidth, window.innerHeight ); + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + controls.update( delta ); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lights_hemisphere.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var camera, scene, renderer, dirLight, hemiLight; + var morphs = []; + var stats; + + var clock = new THREE.Clock(); + + var morph: THREE.MorphAnimMesh; + + init(); + animate(); + + function init() { + + var container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.set( 0, 0, 250 ); + + scene = new THREE.Scene(); + + scene.fog = new THREE.Fog( 0xffffff, 1, 5000 ); + scene.fog.color.setHSL( 0.6, 0, 1 ); + + /* + controls = new THREE.TrackballControls( camera ); + + controls.rotateSpeed = 1.0; + controls.zoomSpeed = 1.2; + controls.panSpeed = 0.8; + + controls.noZoom = false; + controls.noPan = false; + + controls.staticMoving = true; + controls.dynamicDampingFactor = 0.15; + */ + + // LIGHTS + + hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 ); + hemiLight.color.setHSL( 0.6, 0.75, 1 ); + hemiLight.groundColor.setHSL( 0.095, 0.5, 1 ); + hemiLight.position.set( 0, 500, 0 ); + scene.add( hemiLight ); + + // + + dirLight = new THREE.DirectionalLight( 0xffffff, 1 ); + dirLight.color.setHSL( 0.1, 0.1, 1 ); + dirLight.position.set( -1, 1.75, 1 ); + dirLight.position.multiplyScalar( 50 ); + scene.add( dirLight ); + + dirLight.castShadow = true; + + dirLight.shadowMapWidth = 2048; + dirLight.shadowMapHeight = 2048; + + var d = 50; + + dirLight.shadowCameraLeft = -d; + dirLight.shadowCameraRight = d; + dirLight.shadowCameraTop = d; + dirLight.shadowCameraBottom = -d; + + dirLight.shadowCameraFar = 3500; + dirLight.shadowBias = -0.0001; + dirLight.shadowDarkness = 0.35; + //dirLight.shadowCameraVisible = true; + + // GROUND + + var groundGeo = new THREE.PlaneGeometry( 10000, 10000 ); + var groundMat = new THREE.MeshPhongMaterial( { ambient: 0xffffff, color: 0xffffff, specular: 0x050505 } ); + groundMat.color.setHSL( 0.095, 0.5, 1 ); + + var ground = new THREE.Mesh( groundGeo, groundMat ); + ground.rotation.x = -Math.PI/2; + ground.position.y = -33; + scene.add( ground ); + + ground.receiveShadow = true; + + // SKYDOME + + var vertexShader = document.getElementById( 'vertexShader' ).textContent; + var fragmentShader = document.getElementById( 'fragmentShader' ).textContent; + var uniforms = { + topColor: { type: "c", value: new THREE.Color( 0x0077ff ) }, + bottomColor: { type: "c", value: new THREE.Color( 0xffffff ) }, + offset: { type: "f", value: 33 }, + exponent: { type: "f", value: 0.6 } + } + uniforms.topColor.value.copy( hemiLight.color ); + + scene.fog.color.copy( uniforms.bottomColor.value ); + + var skyGeo = new THREE.SphereGeometry( 4000, 32, 15 ); + var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } ); + + var sky = new THREE.Mesh( skyGeo, skyMat ); + scene.add( sky ); + + // MODEL + + var loader = new THREE.JSONLoader(); + + loader.load( "models/animated/flamingo.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + geometry.computeMorphNormals(); + + var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, morphNormals: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } ); + var meshAnim = new THREE.MorphAnimMesh( geometry, material ); + + meshAnim.duration = 1000; + + var s = 0.35; + meshAnim.scale.set( s, s, s ); + meshAnim.position.y = 15; + meshAnim.rotation.y = -1; + + meshAnim.castShadow = true; + meshAnim.receiveShadow = true; + + scene.add( meshAnim ); + morphs.push( meshAnim ); + + } ); + + // RENDERER + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + container.appendChild( renderer.domElement ); + + renderer.setClearColor( scene.fog.color, 1 ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + renderer.shadowMapEnabled = true; + renderer.shadowMapCullFace = THREE.CullFaceBack; + + // STATS + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + document.addEventListener( 'keydown', onKeyDown, false ); + + } + + function morphColorsToFaceColors( geometry ) { + + if ( geometry.morphColors && geometry.morphColors.length ) { + + var colorMap = geometry.morphColors[ 0 ]; + + for ( var i = 0; i < colorMap.colors.length; i ++ ) { + + geometry.faces[ i ].color = colorMap.colors[ i ]; + + } + + } + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function onKeyDown ( event ) { + + switch ( event.keyCode ) { + + case 72: /*h*/ + + hemiLight.visible = !hemiLight.visible; + break; + + case 68: /*d*/ + + dirLight.visible = !dirLight.visible; + break; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + //controls.update(); + + for ( var i = 0; i < morphs.length; i ++ ) { + + morph = morphs[ i ]; + morph.updateAnimation( 1000 * delta ); + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lights_pointlights.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lights_pointlights2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lines_colors.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var effectFXAA; + + var mouseX = 0, mouseY = 0, + + windowHalfX = window.innerWidth / 2, + windowHalfY = window.innerHeight / 2, + + camera, scene, renderer, material, composer; + + var stats: any; + + init(); + animate(); + + function init() { + + var i, container; + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 33, window.innerWidth / window.innerHeight, 1, 10000 ); + camera.position.z = 700; + + scene = new THREE.Scene(); + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1, antialias: false } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.autoClear = false; + + container.appendChild( renderer.domElement ); + + var geometry = new THREE.Geometry(), + geometry2 = new THREE.Geometry(), + geometry3 = new THREE.Geometry(), + points = hilbert3D( new THREE.Vector3( 0,0,0 ), 200.0, 2, 0, 1, 2, 3, 4, 5, 6, 7 ), + colors = [], colors2 = [], colors3 = []; + + for ( i = 0; i < points.length; i ++ ) { + + geometry.vertices.push( points[ i ] ); + + colors[ i ] = new THREE.Color( 0xffffff ); + colors[ i ].setHSV( 0.6, ( 200 + points[ i ].x ) / 400, 1.0 ); + + colors2[ i ] = new THREE.Color( 0xffffff ); + colors2[ i ].setHSV( 0.3, 1.0, ( 200 + points[ i ].x ) / 400 ); + + colors3[ i ] = new THREE.Color( 0xffffff ); + colors3[ i ].setHSV( i / points.length, 1.0, 1.0 ); + + } + + geometry2.vertices = geometry3.vertices = geometry.vertices; + + geometry.colors = colors; + geometry2.colors = colors2; + geometry3.colors = colors3; + + // lines + + material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 1, linewidth: 3, vertexColors: THREE.VertexColors } ); + + var line, p, scale = 0.3, d = 225; + var parameters = [ + [ material, scale*1.5, [-d,0,0], geometry ], + [ material, scale*1.5, [0,0,0], geometry2 ], + [ material, scale*1.5, [d,0,0], geometry3 ] + ]; + + for ( i = 0; i < parameters.length; ++i ) { + + p = parameters[ i ]; + line = new THREE.Line( p[ 3 ], p[ 0 ] ); + line.scale.x = line.scale.y = line.scale.z = p[ 1 ]; + line.position.x = p[ 2 ][ 0 ]; + line.position.y = p[ 2 ][ 1 ]; + line.position.z = p[ 2 ][ 2 ]; + scene.add( line ); + + } + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + //container.appendChild( stats.domElement ); + + // + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + var renderModel = new THREE.RenderPass( scene, camera ); + var effectBloom = new THREE.BloomPass( 1.3 ); + var effectCopy = new THREE.ShaderPass( THREE.CopyShader ); + + effectFXAA = new THREE.ShaderPass( THREE.FXAAShader ); + + var width = window.innerWidth || 2; + var height = window.innerHeight || 2; + + effectFXAA.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height ); + + effectCopy.renderToScreen = true; + + composer = new THREE.EffectComposer( renderer ); + + composer.addPass( renderModel ); + composer.addPass( effectFXAA ); + composer.addPass( effectBloom ); + composer.addPass( effectCopy ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + effectFXAA.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight ); + + composer.reset(); + + } + + // port of Processing Java code by Thomas Diewald + // http://www.openprocessing.org/visuals/?visualID=15599 + + function hilbert3D( center, side, iterations, v0, v1, v2, v3, v4, v5, v6, v7 ) { + + var half = side / 2, + + vec_s = [ + + new THREE.Vector3( center.x - half, center.y + half, center.z - half ), + new THREE.Vector3( center.x - half, center.y + half, center.z + half ), + new THREE.Vector3( center.x - half, center.y - half, center.z + half ), + new THREE.Vector3( center.x - half, center.y - half, center.z - half ), + new THREE.Vector3( center.x + half, center.y - half, center.z - half ), + new THREE.Vector3( center.x + half, center.y - half, center.z + half ), + new THREE.Vector3( center.x + half, center.y + half, center.z + half ), + new THREE.Vector3( center.x + half, center.y + half, center.z - half ) + + ], + + vec = [ vec_s[ v0 ], vec_s[ v1 ], vec_s[ v2 ], vec_s[ v3 ], vec_s[ v4 ], vec_s[ v5 ], vec_s[ v6 ], vec_s[ v7 ] ]; + + if( --iterations >= 0 ) { + + var tmp = []; + + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 0 ], half, iterations, v0, v3, v4, v7, v6, v5, v2, v1 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 1 ], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 2 ], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 3 ], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 4 ], half, iterations, v2, v3, v0, v1, v6, v7, v4, v5 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 5 ], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 6 ], half, iterations, v4, v3, v2, v5, v6, v1, v0, v7 ) ); + Array.prototype.push.apply( tmp, hilbert3D ( vec[ 7 ], half, iterations, v6, v5, v2, v1, v0, v3, v4, v7 ) ); + + return tmp; + + } + + return vec; + } + + // + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length > 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length == 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + render(); + + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + + var time = Date.now() * 0.0005; + + for ( var i = 0; i < scene.children.length; i ++ ) { + + var object = scene.children[ i ]; + if ( object instanceof THREE.Line ) object.rotation.y = time * ( i % 2 ? 1 : -1 ); + + } + + renderer.clear(); + composer.render(); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lines_cubes.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lines_dashed.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lines_sphere.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lines_splines.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_collada.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_collada_keyframe.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_ctm.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_ctm_materials.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_json_blender.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer, objects; + var particleLight, pointLight; + var dae, skin; + + var clock = new THREE.Clock(); + var morphs = []; + var morph: THREE.MorphAnimMesh; + + // Collada model + + var loader = new THREE.ColladaLoader(); + loader.options.convertUpAxis = true; + loader.load( 'models/collada/monster/monster.dae', function ( collada ) { + + dae = collada.scene; + skin = collada.skins[ 0 ]; + + dae.scale.x = dae.scale.y = dae.scale.z = 0.002; + dae.position.x = -1; + dae.updateMatrix(); + + init(); + animate(); + + } ); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 2, 4, 5 ); + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0x000000, 0.035 ); + + // Add Blender exported Collada model + + var loader = new THREE.JSONLoader(); + loader.load( 'models/animated/monster/monster.js', function ( geometry, materials ) { + + // adjust color a bit + + var material = materials[ 0 ]; + material.morphTargets = true; + material.color.setHex( 0xffaaaa ); + material.ambient.setHex( 0x222222 ); + + var faceMaterial = new THREE.MeshFaceMaterial( materials ); + + for ( var i = 0; i < 729; i ++ ) { + + // random placement in a grid + + var x = ( ( i % 27 ) - 13.5 ) * 2 + THREE.Math.randFloatSpread( 1 ); + var z = ( Math.floor( i / 27 ) - 13.5 ) * 2 + THREE.Math.randFloatSpread( 1 ); + + // leave space for big monster + + if ( Math.abs( x ) < 2 && Math.abs( z ) < 2 ) continue; + + morph = new THREE.MorphAnimMesh( geometry, faceMaterial ); + + // one second duration + + morph.duration = 1000; + + // random animation offset + + morph.time = 1000 * Math.random(); + + var s = THREE.Math.randFloat( 0.00075, 0.001 ); + morph.scale.set( s, s, s ); + + morph.position.set( x, 0, z ); + morph.rotation.y = THREE.Math.randFloat( -0.25, 0.25 ); + + morph.matrixAutoUpdate = false; + morph.updateMatrix(); + + scene.add( morph ); + + morphs.push( morph ); + + } + + } ); + + + // Add the COLLADA + + scene.add( dae ); + + // Lights + + scene.add( new THREE.AmbientLight( 0xcccccc ) ); + + pointLight = new THREE.PointLight( 0xff4400, 5, 30 ); + pointLight.position.set( 5, 0, 0 ); + scene.add( pointLight ); + + // Renderer + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + // Stats + + stats = new Stats(); + container.appendChild( stats.domElement ); + + // Events + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + // + + function onWindowResize( event ) { + + renderer.setSize( window.innerWidth, window.innerHeight ); + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + } + + // + + var t = 0; + function animate() { + + requestAnimationFrame( animate ); + + // animate Collada model + + if ( t > 30 ) t = 0; + + if ( skin ) { + + // guess this can be done smarter... + + // (Indeed, there are way more frames than needed and interpolation is not used at all + // could be something like - one morph per each skinning pose keyframe, or even less, + // animation could be resampled, morphing interpolation handles sparse keyframes quite well. + // Simple animation cycles like this look ok with 10-15 frames instead of 100 ;) + + for ( var i = 0; i < skin.morphTargetInfluences.length; i++ ) { + + skin.morphTargetInfluences[ i ] = 0; + + } + + skin.morphTargetInfluences[ Math.floor( t ) ] = 1; + + t += 0.5; + + } + + // animate morphs + + var delta = clock.getDelta(); + + if ( morphs.length ) { + + for ( var i = 0; i < morphs.length; i ++ ) + morphs[ i ].updateAnimation( 1000 * delta ); + + + } + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.0005; + + camera.position.x = Math.cos( timer ) * 10; + camera.position.y = 4; + camera.position.z = Math.sin( timer ) * 10; + + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_json_objconverter.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_obj.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_obj_mtl.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_scene.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + + var container,stats; + + var camera, scene, loaded; + var renderer; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var rotatingObjects = []; + var morphAnimatedObjects = []; + + var clock = new THREE.Clock(); + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function $( id ) { + + return document.getElementById( id ); + + } + + function handle_update( result, pieces ) { + + refreshSceneView( result ); + //renderer.initWebGLObjects( result.scene ); + + var m, material, count = 0; + + for ( m in result.materials ) { + + material = result.materials[ m ]; + if ( ! ( material instanceof THREE.MeshFaceMaterial || material instanceof THREE.ShaderMaterial || material.morphTargets ) ) { + + if( !material.program ) { + + renderer.initMaterial( material, result.scene.__lights, result.scene.fog ); + + count += 1; + + if( count > pieces ) { + + //console.log("xxxxxxxxx"); + break; + + } + + } + + } + + } + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var loadScene = createLoadScene(); + + camera = loadScene.camera; + scene = loadScene.scene; + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + container.appendChild( renderer.domElement ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.right = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + $( "start" ).addEventListener( 'click', onStartClick, false ); + + var callbackProgress = function( progress, result ) { + + var bar = 250, + total = progress.totalModels + progress.totalTextures, + loaded = progress.loadedModels + progress.loadedTextures; + + if ( total ) + bar = Math.floor( bar * loaded / total ); + + $( "bar" ).style.width = bar + "px"; + + var count = 0; + for ( var m in result.materials ) count++; + + handle_update( result, Math.floor( count/total ) ); + + } + + var callbackSync = function( result ) { + + /* + + // uncomment to see progressive scene loading + + scene = result.scene; + camera = result.currentCamera; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + */ + + //handle_update( result, 1 ); + + } + + var callbackFinished = function ( result ) { + + loaded = result; + + $( "message" ).style.display = "none"; + $( "progressbar" ).style.display = "none"; + $( "start" ).style.display = "block"; + $( "start" ).className = "enabled"; + + handle_update( result, 1 ); + + result.scene.traverse( function ( object ) { + + if ( object.properties.rotating === true ) { + + rotatingObjects.push( object ); + + } + + if ( object instanceof THREE.MorphAnimMesh ) { + + morphAnimatedObjects.push( object ); + + } + + if ( object instanceof THREE.SkinnedMesh ) { + + if ( object.geometry.animation ) { + + THREE.AnimationHandler.add( object.geometry.animation ); + + var animation = new THREE.Animation( object, object.geometry.animation.name ); + animation.JITCompile = false; + animation.interpolationType = THREE.AnimationHandler.LINEAR; + + animation.play(); + + } + + } + + } ); + + } + + $( "progress" ).style.display = "block"; + + var loader = new THREE.SceneLoader(); + + loader.addGeometryHandler( "binary", THREE.BinaryLoader ); + loader.addGeometryHandler( "ctm", THREE.CTMLoader ); + loader.addGeometryHandler( "vtk", THREE.VTKLoader ); + loader.addGeometryHandler( "stl", THREE.STLLoader ); + + loader.addHierarchyHandler( "obj", THREE.OBJLoader ); + loader.addHierarchyHandler( "dae", THREE.ColladaLoader ); + loader.addHierarchyHandler( "utf8", THREE.UTF8Loader ); + + loader.callbackSync = callbackSync; + loader.callbackProgress = callbackProgress; + + loader.load( "scenes/test_scene.js", callbackFinished ); + + $( "plus_exp" ).addEventListener( 'click', createToggle( "exp" ), false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function setButtonActive( id ) { + + $( "start" ).style.backgroundColor = "green"; + + } + + function onStartClick() { + + $( "progress" ).style.display = "none"; + + camera = loaded.currentCamera; + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + scene = loaded.scene; + + } + + function onDocumentMouseMove( event ) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + function createLoadScene() { + + var result = { + + scene: new THREE.Scene(), + camera: new THREE.PerspectiveCamera( 65, window.innerWidth / window.innerHeight, 1, 1000 ) + + }; + + result.camera.position.z = 100; + result.scene.add( result.camera ); + + var object, geometry, material, light, count = 500, range = 200; + + material = new THREE.MeshLambertMaterial( { color:0xffffff } ); + geometry = new THREE.CubeGeometry( 5, 5, 5 ); + + for( var i = 0; i < count; i++ ) { + + object = new THREE.Mesh( geometry, material ); + + object.position.x = ( Math.random() - 0.5 ) * range; + object.position.y = ( Math.random() - 0.5 ) * range; + object.position.z = ( Math.random() - 0.5 ) * range; + + object.rotation.x = Math.random() * 6; + object.rotation.y = Math.random() * 6; + object.rotation.z = Math.random() * 6; + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + result.scene.add( object ); + + } + + result.scene.matrixAutoUpdate = false; + + light = new THREE.PointLight( 0xffffff ); + result.scene.add( light ); + + light = new THREE.DirectionalLight( 0x111111 ); + light.position.x = 1; + result.scene.add( light ); + + return result; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + camera.position.x += ( mouseX - camera.position.x ) * .001; + camera.position.y += ( - mouseY - camera.position.y ) * .001; + + camera.lookAt( scene.position ); + + // update skinning + + THREE.AnimationHandler.update( delta * 0.75 ); + + for ( var i = 0; i < rotatingObjects.length; i ++ ) { + + var object = rotatingObjects[ i ]; + + if ( object.properties.rotateX ) object.rotation.x += 1 * delta; + if ( object.properties.rotateY ) object.rotation.y += 0.5 * delta; + + } + + for ( var i = 0; i < morphAnimatedObjects.length; i ++ ) { + + var object = morphAnimatedObjects[ i ]; + + object.updateAnimation( 1000 * delta ); + + } + + renderer.render( scene, camera ); + + } + + // Scene explorer user interface + + function toggle( id ) { + + var scn = $( "section_" + id ).style, + btn = $( "plus_" + id ); + + if ( scn.display == "block" ) { + + scn.display = "none"; + btn.innerHTML = "[+]"; + + } + else { + + scn.display = "block"; + btn.innerHTML = "[-]"; + + } + + } + + function createToggle( label ) { return function() { toggle( label ) } }; + + function refreshSceneView( result ) { + + $( "section_exp" ).innerHTML = generateSceneView( result ); + + var config = [ "obj", "geo", "mat", "tex", "lit", "cam" ]; + + for ( var i = 0; i < config.length; i++ ) + $( "plus_" + config[i] ).addEventListener( 'click', createToggle( config[i] ), false ); + + } + + function generateSection( label, id, objects ) { + + var html = ""; + + html += "

[+] " + label + "

"; + html += "
"; + + for( var o in objects ) { + + html += o + "
"; + + } + html += "
"; + + return html; + + } + + function generateSceneView( result ) { + + var config = [ + [ "Objects", "obj", result.objects ], + [ "Geometries", "geo", result.geometries ], + [ "Materials", "mat", result.materials ], + [ "Textures", "tex", result.textures ], + [ "Lights", "lit", result.lights ], + [ "Cameras", "cam", result.cameras ] + ]; + + var html = ""; + + for ( var i = 0; i < config.length; i++ ) + html += generateSection( config[i][0], config[i][1], config[i][2] ); + + return html; + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_scene_blender.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + + var container,stats; + + var camera, scene: THREE.Scene, loaded; + var renderer; + + var mesh, zmesh, geometry; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + init(); + animate(); + + function $( id ) { + + return document.getElementById( id ); + + } + + function handle_update( result, pieces ) { + + refreshSceneView( result ); + //renderer.initWebGLObjects( result.scene ); + + var m, material, count = 0; + + for ( m in result.materials ) { + + material = result.materials[ m ]; + if ( ! ( material instanceof THREE.MeshFaceMaterial ) ) { + + if( !material.program ) { + + console.log(m); + renderer.initMaterial( material, result.scene.__lights, result.scene.fog ); + + count += 1; + if( count > pieces ) { + + //console.log("xxxxxxxxx"); + break; + + } + + } + + } + + } + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + var loadScene = createLoadScene(); + + camera = loadScene.camera; + scene = loadScene.scene; + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.right = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + $( "start" ).addEventListener( 'click', onStartClick, false ); + + var callbackProgress = function( progress, result ) { + + var bar = 250, + total = progress.total_models + progress.total_textures, + loaded = progress.loaded_models + progress.loaded_textures; + + if ( total ) + bar = Math.floor( bar * loaded / total ); + + $( "bar" ).style.width = bar + "px"; + + var count = 0; + for ( var m in result.materials ) count++; + + handle_update( result, Math.floor( count/total ) ); + + } + + var callbackFinished = function( result ) { + + loaded = result; + + $( "message" ).style.display = "none"; + $( "progressbar" ).style.display = "none"; + $( "start" ).style.display = "block"; + $( "start" ).className = "enabled"; + + handle_update( result, 1 ); + + } + + $( "progress" ).style.display = "block"; + + var loader = new THREE.SceneLoader(); + loader.callbackProgress = callbackProgress; + + loader.load( "obj/blenderscene/scene.js", callbackFinished ); + + $( "plus_exp" ).addEventListener( 'click', createToggle( "exp" ), false ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function setButtonActive( id ) { + + $( "start" ).style.backgroundColor = "green"; + + } + + function onStartClick() { + + $( "progress" ).style.display = "none"; + + camera = loaded.currentCamera; + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + scene = loaded.scene; + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + function createLoadScene() { + + var result = { + + scene: new THREE.Scene(), + camera: new THREE.PerspectiveCamera( 65, window.innerWidth / window.innerHeight, 1, 1000 ) + + }; + + result.camera.position.z = 100; + + var object, geometry, material, light, count = 500, range = 200; + + material = new THREE.MeshLambertMaterial( { color:0xffffff } ); + geometry = new THREE.CubeGeometry( 5, 5, 5 ); + + for( var i = 0; i < count; i++ ) { + + object = new THREE.Mesh( geometry, material ); + + object.position.x = ( Math.random() - 0.5 ) * range; + object.position.y = ( Math.random() - 0.5 ) * range; + object.position.z = ( Math.random() - 0.5 ) * range; + + object.rotation.x = Math.random() * 6; + object.rotation.y = Math.random() * 6; + object.rotation.z = Math.random() * 6; + + object.matrixAutoUpdate = false; + object.updateMatrix(); + + result.scene.add( object ); + + } + + result.scene.matrixAutoUpdate = false; + + light = new THREE.PointLight( 0xffffff ); + result.scene.add( light ); + + light = new THREE.DirectionalLight( 0x111111 ); + light.position.x = 1; + result.scene.add( light ); + + return result; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + camera.position.x += ( mouseX - camera.position.x ) * .001; + camera.position.y += ( - mouseY - camera.position.y ) * .001; + + camera.lookAt( scene.position ); + + renderer.render( scene, camera ); + + } + + // Scene explorer user interface + + function toggle( id ) { + + var scn = $( "section_" + id ).style, + btn = $( "plus_" + id ); + + if ( scn.display == "block" ) { + + scn.display = "none"; + btn.innerHTML = "[+]"; + + } + else { + + scn.display = "block"; + btn.innerHTML = "[-]"; + + } + + } + + function createToggle( label ) { return function() { toggle( label ) } }; + + function refreshSceneView( result ) { + + $( "section_exp" ).innerHTML = generateSceneView( result ); + + var config = [ "obj", "geo", "mat", "tex", "lit", "cam" ]; + + for ( var i = 0; i < config.length; i++ ) + $( "plus_" + config[i] ).addEventListener( 'click', createToggle( config[i] ), false ); + + } + + function generateSection( label, id, objects ) { + + var html = ""; + + html += "

[+] " + label + "

"; + html += "
"; + + for( var o in objects ) { + + html += o + "
"; + + } + html += "
"; + + return html; + + } + + function generateSceneView( result ) { + + var config = [ + [ "Objects", "obj", result.objects ], + [ "Geometries", "geo", result.geometries ], + [ "Materials", "mat", result.materials ], + [ "Textures", "tex", result.textures ], + [ "Lights", "lit", result.lights ], + [ "Cameras", "cam", result.cameras ] + ]; + + var html = ""; + + for ( var i = 0; i < config.length; i++ ) + html += generateSection( config[i][0], config[i][1], config[i][2] ); + + return html; + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_stl.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_utf8.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_loader_vtk.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_lod.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_marching_cubes.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer, objects; + var particleLight, pointLight; + + var materials = []; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 0, 200, 800 ); + + scene = new THREE.Scene(); + + // Grid + + var line_material = new THREE.LineBasicMaterial( { color: 0x303030 } ), + geometry = new THREE.Geometry(), + floor = -75, step = 25; + + for ( var i = 0; i <= 40; i ++ ) { + + geometry.vertices.push( new THREE.Vector3( - 500, floor, i * step - 500 ) ); + geometry.vertices.push( new THREE.Vector3( 500, floor, i * step - 500 ) ); + + geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, -500 ) ); + geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, 500 ) ); + + } + + var line = new THREE.Line( geometry, line_material, THREE.LinePieces ); + scene.add( line ); + + // Materials + + var texture = new THREE.Texture( generateTexture() ); + texture.needsUpdate = true; + + materials.push( new THREE.MeshLambertMaterial( { map: texture, transparent: true } ) ); + materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading } ) ); + materials.push( new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) ); + materials.push( new THREE.MeshNormalMaterial( ) ); + materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } ) ); + //materials.push( new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.SubtractiveBlending } ) ); + + materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.SmoothShading } ) ); + materials.push( new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading, map: texture, transparent: true } ) ); + materials.push( new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } ) ); + materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } ) ); + + materials.push( new THREE.MeshDepthMaterial() ); + + materials.push( new THREE.MeshLambertMaterial( { color: 0x666666, emissive: 0xff0000, ambient: 0x000000, shading: THREE.SmoothShading } ) ); + materials.push( new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0xff0000, ambient: 0x000000, shininess: 10, shading: THREE.SmoothShading, opacity: 0.9, transparent: true } ) ); + + materials.push( new THREE.MeshBasicMaterial( { map: texture, transparent: true } ) ); + + // Spheres geometry + + var geometry_smooth = new THREE.SphereGeometry( 70, 32, 16 ); + var geometry_flat = new THREE.SphereGeometry( 70, 32, 16 ); + var geometry_pieces = new THREE.SphereGeometry( 70, 32, 16 ); // Extra geometry to be broken down for MeshFaceMaterial + + for ( var i = 0, l = geometry_pieces.faces.length; i < l; i ++ ) { + + var face = geometry_pieces.faces[ i ]; + face.materialIndex = Math.floor( Math.random() * materials.length ); + + } + + geometry_pieces["materials"] = materials; + + materials.push( new THREE.MeshFaceMaterial( materials ) ); + + objects = []; + + var sphere, geometry, material; + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + material = materials[ i ]; + + geometry = material instanceof THREE.MeshFaceMaterial ? geometry_pieces : + ( material.shading == THREE.FlatShading ? geometry_flat : geometry_smooth ); + + sphere = new THREE.Mesh( geometry, material ); + + sphere.position.x = ( i % 4 ) * 200 - 400; + sphere.position.z = Math.floor( i / 4 ) * 200 - 200; + + sphere.rotation.x = Math.random() * 200 - 100; + sphere.rotation.y = Math.random() * 200 - 100; + sphere.rotation.z = Math.random() * 200 - 100; + + objects.push( sphere ); + + scene.add( sphere ); + + } + + particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) ); + scene.add( particleLight ); + + // Lights + + scene.add( new THREE.AmbientLight( 0x111111 ) ); + + var directionalLight = new THREE.DirectionalLight( /*Math.random() * */ 0xffffff, 0.125 ); + + directionalLight.position.x = Math.random() - 0.5; + directionalLight.position.y = Math.random() - 0.5; + directionalLight.position.z = Math.random() - 0.5; + + directionalLight.position.normalize(); + + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffffff, 1 ); + scene.add( pointLight ); + + // + + renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function generateTexture() { + + var canvas = document.createElement( 'canvas' ); + canvas.width = 256; + canvas.height = 256; + + var context = canvas.getContext( '2d' ); + var image = context.getImageData( 0, 0, 256, 256 ); + + var x = 0, y = 0; + + for ( var i = 0, j = 0, l = image.data.length; i < l; i += 4, j ++ ) { + + x = j % 256; + y = x == 0 ? y + 1 : y; + + image.data[ i ] = 255; + image.data[ i + 1 ] = 255; + image.data[ i + 2 ] = 255; + image.data[ i + 3 ] = Math.floor( x ^ y ); + + } + + context.putImageData( image, 0, 0 ); + + return canvas; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = 0.0001 * Date.now(); + + camera.position.x = Math.cos( timer ) * 1000; + camera.position.z = Math.sin( timer ) * 1000; + + camera.lookAt( scene.position ); + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + var object = objects[ i ]; + + object.rotation.x += 0.01; + object.rotation.y += 0.005; + + } + + materials[ materials.length - 3 ].emissive.setHSV( 0.54, 1, 0.7 * ( 0.5 + 0.5 * Math.sin( 35 * timer ) ) ); + materials[ materials.length - 4 ].emissive.setHSV( 0.04, 1, 0.7 * ( 0.5 + 0.5 * Math.cos( 35 * timer ) ) ); + + particleLight.position.x = Math.sin( timer * 7 ) * 300; + particleLight.position.y = Math.cos( timer * 5 ) * 400; + particleLight.position.z = Math.cos( timer * 3 ) * 300; + + pointLight.position.x = particleLight.position.x; + pointLight.position.y = particleLight.position.y; + pointLight.position.z = particleLight.position.z; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials2.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer, objects; + var particleLight, pointLight; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 ); + camera.position.set( 0, 200, 0 ); + + scene = new THREE.Scene(); + + // Materials + + var imgTexture2 = THREE.ImageUtils.loadTexture( "textures/planets/moon_1024.jpg" ); + imgTexture2.wrapS = imgTexture2.wrapT = THREE.RepeatWrapping; + imgTexture2.anisotropy = 16; + + var imgTexture = THREE.ImageUtils.loadTexture( "textures/lava/lavatile.jpg" ); + imgTexture.repeat.set( 4, 2 ); + imgTexture.wrapS = imgTexture.wrapT = THREE.RepeatWrapping; + imgTexture.anisotropy = 16; + + var shininess = 50, specular = 0x333333, bumpScale = 1, shading = THREE.SmoothShading; + + var materials = []; + + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0xffffff, ambient: 0x777777, specular: specular, shininess: shininess, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x00ff00, ambient: 0x777777, specular: specular, shininess: shininess, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x00ff00, ambient: 0x007700, specular: specular, shininess: shininess, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture, bumpMap: imgTexture, bumpScale: bumpScale, color: 0x000000, ambient: 0x00ff00, specular: specular, shininess: shininess, shading: shading } ) ); + + materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xffffff, ambient: 0x777777, shading: shading } ) ); + materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xff0000, ambient: 0x777777, shading: shading } ) ); + materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0xff0000, ambient: 0x770000, shading: shading } ) ); + materials.push( new THREE.MeshLambertMaterial( { map: imgTexture, color: 0x000000, ambient: 0xff0000, shading: shading } ) ); + + shininess = 15; + + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0xffaa00, shininess: shininess, metal: true, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0xaaff00, shininess: shininess, metal: true, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0x00ffaa, shininess: shininess, metal: true, shading: shading } ) ); + materials.push( new THREE.MeshPhongMaterial( { map: imgTexture2, bumpMap: imgTexture2, bumpScale: bumpScale, color: 0x000000, ambient: 0x000000, specular: 0x00aaff, shininess: shininess, metal: true, shading: shading } ) ); + + // Spheres geometry + + var geometry_smooth = new THREE.SphereGeometry( 70, 32, 16 ); + var geometry_flat = new THREE.SphereGeometry( 70, 32, 16 ); + + objects = []; + + var sphere, geometry, material; + + for ( var i = 0, l = materials.length; i < l; i ++ ) { + + material = materials[ i ]; + + geometry = material.shading == THREE.FlatShading ? geometry_flat : geometry_smooth; + + sphere = new THREE.Mesh( geometry, material ); + + sphere.position.x = ( i % 4 ) * 200 - 200; + sphere.position.z = Math.floor( i / 4 ) * 200 - 200; + + objects.push( sphere ); + + scene.add( sphere ); + + } + + particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) ); + scene.add( particleLight ); + + // Lights + + scene.add( new THREE.AmbientLight( 0x444444 ) ); + + var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); + directionalLight.position.set( 1, 1, 1 ).normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffffff, 2, 800 ); + scene.add( pointLight ); + + particleLight.material.color = pointLight.color; + pointLight.position = particleLight.position; + + // + + renderer = new THREE.WebGLRenderer( { clearColor: 0x0a0a0a, clearAlpha: 1, antialias: true } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.sortObjects = true; + + container.appendChild( renderer.domElement ); + + renderer.gammaInput = true; + renderer.gammaOutput = true; + renderer.physicallyBasedShading = true; + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = Date.now() * 0.00025; + + camera.position.x = Math.cos( timer ) * 800; + camera.position.z = Math.sin( timer ) * 800; + + camera.lookAt( scene.position ); + + for ( var i = 0, l = objects.length; i < l; i ++ ) { + + var object = objects[ i ]; + + object.rotation.y += 0.005; + + } + + particleLight.position.x = Math.sin( timer * 7 ) * 300; + particleLight.position.y = Math.cos( timer * 5 ) * 400; + particleLight.position.z = Math.cos( timer * 3 ) * 300; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_blending.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var camera, scene, renderer; + var mesh; + + init(); + animate(); + + function init() { + + // CAMERA + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.z = 600; + + // SCENE + + scene = new THREE.Scene(); + + // BACKGROUND + + var x = document.createElement( "canvas" ); + var xc = x.getContext( "2d" ); + x.width = x.height = 128; + xc.fillStyle = "#ddd"; + xc.fillRect( 0, 0, 128, 128 ); + xc.fillStyle = "#555"; + xc.fillRect( 0, 0, 64, 64 ); + xc.fillStyle = "#999"; + xc.fillRect( 32, 32, 32, 32 ); + xc.fillStyle = "#555"; + xc.fillRect( 64, 64, 64, 64 ); + xc.fillStyle = "#777"; + xc.fillRect( 96, 96, 32, 32 ); + + var mapBg = new THREE.Texture( x ); + mapBg.wrapS = mapBg.wrapT = THREE.RepeatWrapping; + mapBg.repeat.set( 128, 64 ); + mapBg.needsUpdate = true; + + /* + var mapBg = THREE.ImageUtils.loadTexture( "textures/disturb.jpg" ); + mapBg.wrapS = mapBg.wrapT = THREE.RepeatWrapping; + mapBg.repeat.set( 8, 4 ); + */ + + var materialBg = new THREE.MeshBasicMaterial( { map: mapBg } ); + + var meshBg = new THREE.Mesh( new THREE.PlaneGeometry( 4000, 2000 ), materialBg ); + meshBg.position.set( 0, 0, -1 ); + scene.add( meshBg ); + + // OBJECTS + + var blendings = [ "NoBlending", "NormalBlending", "AdditiveBlending", "SubtractiveBlending", "MultiplyBlending", "AdditiveAlphaBlending" ]; + + var map0 = THREE.ImageUtils.loadTexture( 'textures/ash_uvgrid01.jpg' ); + var map1 = THREE.ImageUtils.loadTexture( 'textures/sprite0.jpg' ); + var map2 = THREE.ImageUtils.loadTexture( 'textures/sprite0.png' ); + var map3 = THREE.ImageUtils.loadTexture( 'textures/lensflare/lensflare0.png' ); + var map4 = THREE.ImageUtils.loadTexture( 'textures/lensflare/lensflare0_alpha.png' ); + + var geo1 = new THREE.PlaneGeometry( 100, 100 ); + var geo2 = new THREE.PlaneGeometry( 100, 25 ); + + addImageRow( map0, 300 ); + addImageRow( map1, 150 ); + addImageRow( map2, 0 ); + addImageRow( map3, -150 ); + addImageRow( map4, -300 ); + + function addImageRow( map, y ) { + + for ( var i = 0; i < blendings.length; i ++ ) { + + var blending = blendings[ i ]; + + var material = new THREE.MeshBasicMaterial( { map: map } ); + material.transparent = true; + material.blending = THREE[ blending ]; + + var x = ( i - blendings.length / 2 ) * 110; + var z = 0; + + var mesh = new THREE.Mesh( geo1, material ); + mesh.position.set( x, y, z ); + scene.add( mesh ); + + + var mesh = new THREE.Mesh( geo2, generateLabelMaterial( blending.replace( "Blending", "" ) ) ); + mesh.position.set( x, y - 75, z ); + scene.add( mesh ); + + } + + } + + // RENDERER + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1 } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + // EVENTS + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + // + + function onWindowResize( event ) { + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + } + + + function generateLabelMaterial( text ) { + + var x = document.createElement( "canvas" ); + var xc = x.getContext( "2d" ); + x.width = 128; + x.height = 32; + + xc.fillStyle = "rgba( 0, 0, 0, 0.95 )"; + xc.fillRect( 0, 0, 128, 32 ); + + xc.fillStyle = "white"; + xc.font = "12pt arial bold"; + xc.fillText( text, 10, 22 ); + + var map = new THREE.Texture( x ); + map.needsUpdate = true; + + var material = new THREE.MeshBasicMaterial( { map: map, transparent: true } ); + return material; + + } + + function animate() { + + requestAnimationFrame( animate ); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_blending_custom.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_bumpmap.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_bumpmap_skin.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cars.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var STATS_ENABLED = false; + + var CARS = { + + "veyron": { + + name: "Bugatti Veyron", + url: "obj/veyron/VeyronNoUv_bin.js", + author: 'Troyano', + init_rotation: [ 0, 0, 0 ], + scale: 5.5, + init_material: 4, + body_materials: [ 2 ], + + object: null, + buttons: null, + materials: null + + }, + + "gallardo": { + + name: "Lamborghini Gallardo", + url: "obj/gallardo/GallardoNoUv_bin.js", + author: 'machman_3d', + init_rotation: [ 0, 0, 0 ], + scale: 3.7, + init_material: 9, + body_materials: [ 3 ], + + object: null, + buttons: null, + materials: null + + }, + + "f50": { + + name: "Ferrari F50", + url: "obj/f50/F50NoUv_bin.js", + author: 'daniel sathya', + init_rotation: [ 0, 0, 0 ], + scale: 0.175, + init_material: 2, + body_materials: [ 3, 6, 7, 8, 9, 10, 23, 24 ], + + object: null, + buttons: null, + materials: null + + }, + + "camaro": { + + name: "Chevrolet Camaro", + url: "obj/camaro/CamaroNoUv_bin.js", + author: 'dskfnwn', + init_rotation: [ 0.0, 0.0, 0.0 /*0, 1, 0*/ ], + scale: 75, + init_material: 0, + body_materials: [ 0 ], + + object: null, + buttons: null, + materials: null + + } + + }; + + + var container, stats; + + var camera, scene, renderer; + var cameraCube, sceneCube; + + var m, mi; + + var directionalLight, pointLight; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var loader = new THREE.BinaryLoader( true ); + document.body.appendChild( loader.statusDomElement ); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + // CAMERAS + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 100000 ); + cameraCube = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 100000 ); + + // SCENE + + scene = new THREE.Scene(); + sceneCube = new THREE.Scene(); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x050505 ); + scene.add( ambient ); + + directionalLight = new THREE.DirectionalLight( 0xffffff, 2 ); + directionalLight.position.set( 2, 1.2, 10 ).normalize(); + scene.add( directionalLight ); + + directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ); + directionalLight.position.set( -2, 1.2, -10 ).normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffaa00, 2 ); + pointLight.position.set( 2000, 1200, 10000 ); + scene.add( pointLight ); + + // Skybox + + var shader = THREE.ShaderLib[ "cube" ]; + shader.uniforms[ "tCube" ].value = textureCube; + + var material = new THREE.ShaderMaterial( { + + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: shader.uniforms, + depthWrite: false, + side: THREE.BackSide + + } ), + + mesh = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material ); + sceneCube.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.setFaceCulling( THREE.CullFaceNone ); + renderer.autoClear = false; + + container.appendChild( renderer.domElement ); + + if ( STATS_ENABLED ) { + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + } + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + + var r = "textures/cube/Bridge2/"; + var urls = [ r + "posx.jpg", r + "negx.jpg", + r + "posy.jpg", r + "negy.jpg", + r + "posz.jpg", r + "negz.jpg" ]; + + var textureCube = THREE.ImageUtils.loadTextureCube( urls ); + textureCube.format = THREE.RGBFormat; + + // common materials + + var mlib = { + + "Orange": new THREE.MeshLambertMaterial( { color: 0xff6600, ambient: 0xff2200, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.3 } ), + "Blue": new THREE.MeshLambertMaterial( { color: 0x001133, ambient: 0x001133, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.3 } ), + "Red": new THREE.MeshLambertMaterial( { color: 0x660000, ambient: 0x330000, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.25 } ), + "Black": new THREE.MeshLambertMaterial( { color: 0x000000, ambient: 0x000000, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.15 } ), + "White": new THREE.MeshLambertMaterial( { color: 0xffffff, ambient: 0x666666, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.25 } ), + + "Carmine": new THREE.MeshPhongMaterial( { color: 0x770000, specular:0xffaaaa, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Gold": new THREE.MeshPhongMaterial( { color: 0xaa9944, specular:0xbbaa99, shininess:50, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Bronze": new THREE.MeshPhongMaterial( { color: 0x150505, specular:0xee6600, shininess:10, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.25 } ), + "Chrome": new THREE.MeshPhongMaterial( { color: 0xffffff, specular:0xffffff, envMap: textureCube, combine: THREE.MultiplyOperation } ), + + "Orange metal": new THREE.MeshLambertMaterial( { color: 0xff6600, ambient: 0xff2200, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Blue metal": new THREE.MeshLambertMaterial( { color: 0x001133, ambient: 0x002266, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Red metal": new THREE.MeshLambertMaterial( { color: 0x770000, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Green metal": new THREE.MeshLambertMaterial( { color: 0x007711, envMap: textureCube, combine: THREE.MultiplyOperation } ), + "Black metal": new THREE.MeshLambertMaterial( { color: 0x222222, envMap: textureCube, combine: THREE.MultiplyOperation } ), + + "Pure chrome": new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: textureCube } ), + "Dark chrome": new THREE.MeshLambertMaterial( { color: 0x444444, envMap: textureCube } ), + "Darker chrome":new THREE.MeshLambertMaterial( { color: 0x222222, envMap: textureCube } ), + + "Black glass": new THREE.MeshLambertMaterial( { color: 0x101016, envMap: textureCube, opacity: 0.975, transparent: true } ), + "Dark glass": new THREE.MeshLambertMaterial( { color: 0x101046, envMap: textureCube, opacity: 0.25, transparent: true } ), + "Blue glass": new THREE.MeshLambertMaterial( { color: 0x668899, envMap: textureCube, opacity: 0.75, transparent: true } ), + "Light glass": new THREE.MeshBasicMaterial( { color: 0x223344, envMap: textureCube, opacity: 0.25, transparent: true, combine: THREE.MixOperation, reflectivity: 0.25 } ), + + "Red glass": new THREE.MeshLambertMaterial( { color: 0xff0000, opacity: 0.75, transparent: true } ), + "Yellow glass": new THREE.MeshLambertMaterial( { color: 0xffffaa, opacity: 0.75, transparent: true } ), + "Orange glass": new THREE.MeshLambertMaterial( { color: 0x995500, opacity: 0.75, transparent: true } ), + + "Orange glass 50": new THREE.MeshLambertMaterial( { color: 0xffbb00, opacity: 0.5, transparent: true } ), + "Red glass 50": new THREE.MeshLambertMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } ), + + "Fullblack rough": new THREE.MeshLambertMaterial( { color: 0x000000 } ), + "Black rough": new THREE.MeshLambertMaterial( { color: 0x050505 } ), + "Darkgray rough": new THREE.MeshLambertMaterial( { color: 0x090909 } ), + "Red rough": new THREE.MeshLambertMaterial( { color: 0x330500 } ), + + "Darkgray shiny": new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x050505 } ), + "Gray shiny": new THREE.MeshPhongMaterial( { color: 0x050505, shininess: 20 } ) + + } + + // Gallardo materials + + CARS[ "gallardo" ].materials = { + + body: [ + + [ "Orange", mlib[ "Orange" ] ], + [ "Blue", mlib[ "Blue" ] ], + [ "Red", mlib[ "Red" ] ], + [ "Black", mlib[ "Black" ] ], + [ "White", mlib[ "White" ] ], + + [ "Orange metal", mlib[ "Orange metal" ] ], + [ "Blue metal", mlib[ "Blue metal" ] ], + [ "Green metal", mlib[ "Green metal" ] ], + [ "Black metal", mlib[ "Black metal" ] ], + + [ "Carmine", mlib[ "Carmine" ] ], + [ "Gold", mlib[ "Gold" ] ], + [ "Bronze", mlib[ "Bronze" ] ], + [ "Chrome", mlib[ "Chrome" ] ] + + ] + + } + + m = CARS[ "gallardo" ].materials; + mi = CARS[ "gallardo" ].init_material; + + CARS[ "gallardo" ].mmap = { + + 0: mlib[ "Pure chrome" ], // wheels chrome + 1: mlib[ "Black rough" ], // tire + 2: mlib[ "Black glass" ], // windshield + 3: m.body[ mi ][ 1 ], // body + 4: mlib[ "Red glass" ], // back lights + 5: mlib[ "Yellow glass" ], // front lights + 6: mlib[ "Dark chrome" ] // windshield rim + + } + + // Veyron materials + + CARS[ "veyron" ].materials = { + + body: [ + + [ "Orange metal", mlib[ "Orange metal" ] ], + [ "Blue metal", mlib[ "Blue metal" ] ], + [ "Red metal", mlib[ "Red metal" ] ], + [ "Green metal", mlib[ "Green metal" ] ], + [ "Black metal", mlib[ "Black metal" ] ], + + [ "Gold", mlib[ "Gold" ] ], + [ "Bronze", mlib[ "Bronze" ] ], + [ "Chrome", mlib[ "Chrome" ] ] + + ], + + } + + m = CARS[ "veyron" ].materials; + mi = CARS[ "veyron" ].init_material; + + CARS[ "veyron" ].mmap = { + + 0: mlib[ "Black rough" ], // tires + inside + 1: mlib[ "Pure chrome" ], // wheels + extras chrome + 2: m.body[ mi ][ 1 ], // back / top / front torso + 3: mlib[ "Dark glass" ], // glass + 4: mlib[ "Pure chrome" ], // sides torso + 5: mlib[ "Pure chrome" ], // engine + 6: mlib[ "Red glass 50" ], // backlights + 7: mlib[ "Orange glass 50" ] // backsignals + + } + + // F50 materials + + CARS[ "f50" ].materials = { + + body: [ + + [ "Orange", mlib[ "Orange" ] ], + [ "Blue", mlib[ "Blue" ] ], + [ "Red", mlib[ "Red" ] ], + [ "Black", mlib[ "Black" ] ], + [ "White", mlib[ "White" ] ], + + [ "Orange metal", mlib[ "Orange metal" ] ], + [ "Blue metal", mlib[ "Blue metal" ] ], + [ "Black metal", mlib[ "Black metal" ] ], + + [ "Carmine", mlib[ "Carmine" ] ], + [ "Gold", mlib[ "Gold" ] ], + [ "Bronze", mlib[ "Bronze" ] ], + [ "Chrome", mlib[ "Chrome" ] ] + + ], + + } + + m = CARS[ "f50" ].materials; + mi = CARS[ "f50" ].init_material; + + CARS[ "f50" ].mmap = { + + 0: mlib[ "Dark chrome" ], // interior + rim + 1: mlib[ "Pure chrome" ], // wheels + gears chrome + 2: mlib[ "Blue glass" ], // glass + 3: m.body[ mi ][ 1 ], // torso mid + front spoiler + 4: mlib[ "Darkgray shiny" ], // interior + behind seats + 5: mlib[ "Darkgray shiny" ], // tiny dots in interior + 6: m.body[ mi ][ 1 ], // back torso + 7: m.body[ mi ][ 1 ], // right mirror decal + 8: m.body[ mi ][ 1 ], // front decal + 9: m.body[ mi ][ 1 ], // front torso + 10: m.body[ mi ][ 1 ], // left mirror decal + 11: mlib[ "Pure chrome" ], // engine + 12: mlib[ "Darkgray rough" ], // tires side + 13: mlib[ "Darkgray rough" ], // tires bottom + 14: mlib[ "Darkgray shiny" ], // bottom + 15: mlib[ "Black rough" ], // ??? + 16: mlib[ "Orange glass" ], // front signals + 17: mlib[ "Dark chrome" ], // wheels center + 18: mlib[ "Red glass" ], // back lights + 19: mlib[ "Black rough" ], // ??? + 20: mlib[ "Red rough" ], // seats + 21: mlib[ "Black rough" ], // back plate + 22: mlib[ "Black rough" ], // front light dots + 23: m.body[ mi ][ 1 ], // back torso + 24: m.body[ mi ][ 1 ] // back torso center + + } + + + // Camero materials + + CARS[ "camaro" ].materials = { + + body: [ + + [ "Orange", mlib[ "Orange" ] ], + [ "Blue", mlib[ "Blue" ] ], + [ "Red", mlib[ "Red" ] ], + [ "Black", mlib[ "Black" ] ], + [ "White", mlib[ "White" ] ], + + [ "Orange metal", mlib[ "Orange metal" ] ], + [ "Blue metal", mlib[ "Blue metal" ] ], + [ "Red metal", mlib[ "Red metal" ] ], + [ "Green metal", mlib[ "Green metal" ] ], + [ "Black metal", mlib[ "Black metal" ] ], + + [ "Gold", mlib[ "Gold" ] ], + [ "Bronze", mlib[ "Bronze" ] ], + [ "Chrome", mlib[ "Chrome" ] ] + + ], + + } + + m = CARS[ "camaro" ].materials; + mi = CARS[ "camaro" ].init_material; + + CARS[ "camaro" ].mmap = { + + 0: m.body[ mi ][ 1 ], // car body + 1: mlib[ "Pure chrome" ], // wheels chrome + 2: mlib[ "Pure chrome" ], // grille chrome + 3: mlib[ "Dark chrome" ], // door lines + 4: mlib[ "Light glass" ], // windshield + 5: mlib[ "Gray shiny" ], // interior + 6: mlib[ "Black rough" ], // tire + 7: mlib[ "Fullblack rough" ], // tireling + 8: mlib[ "Fullblack rough" ] // behind grille + + } + + loader.load( CARS[ "veyron" ].url, function( geometry ) { createScene( geometry, "veyron" ) } ); + + for( var c in CARS ) initCarButton( c ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + cameraCube.aspect = window.innerWidth / window.innerHeight; + cameraCube.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function initCarButton( car ) { + + $( car ).addEventListener( 'click', function() { + + if ( ! CARS[ car ].object ) { + + loader.statusDomElement.style.display = "block"; + loader.load( CARS[ car ].url, function( geometry ) { createScene( geometry, car ) } ); + + } else { + + switchCar( car ); + + } + + }, false ); + + } + + function $( id ) { return document.getElementById( id ) } + function button_name( car, index ) { return "m_" + car + "_" + index } + + function switchCar( car ) { + + for ( var c in CARS ) { + + if ( c != car && CARS[ c ].object ) { + + CARS[ c ].object.visible = false; + CARS[ c ].buttons.style.display = "none"; + + } + } + + CARS[ car ].object.visible = true; + CARS[ car ].buttons.style.display = "block"; + + $( "car_name" ).innerHTML = CARS[ car ].name + " model"; + $( "car_author" ).innerHTML = CARS[ car ].author; + + } + + function createButtons( materials, car ) { + + var buttons, i, src = ""; + + for( i = 0; i < materials.length; i ++ ) { + + src += ' '; + + } + + buttons = document.createElement( "div" ); + buttons.innerHTML = src; + + $( "buttons_materials" ).appendChild( buttons ); + + return buttons; + + } + + function attachButtonMaterials( materials, faceMaterial, material_indices, car ) { + + for( var i = 0; i < materials.length; i ++ ) { + + $( button_name( car, i ) )["counter"] = i; + $( button_name( car, i ) ).addEventListener( 'click', function() { + + for ( var j = 0; j < material_indices.length; j ++ ) { + + faceMaterial.materials[ material_indices [ j ] ] = materials[ this.counter ][ 1 ]; + + } + + }, false ); + + } + + } + + function createScene( geometry, car ) { + + loader.statusDomElement.innerHTML = "Creating model ..."; + + var m = new THREE.MeshFaceMaterial(), + s = CARS[ car ].scale * 1, + r = CARS[ car ].init_rotation, + materials = CARS[ car ].materials, + mi = CARS[ car ].init_material, + bm = CARS[ car ].body_materials; + + for ( var i in CARS[ car ].mmap ) { + + m.materials[ i ] = CARS[ car ].mmap[ i ]; + + } + + var mesh = new THREE.Mesh( geometry, m ); + + mesh.rotation.x = r[ 0 ]; + mesh.rotation.y = r[ 1 ]; + mesh.rotation.z = r[ 2 ]; + + mesh.scale.x = mesh.scale.y = mesh.scale.z = s; + + scene.add( mesh ); + + CARS[ car ].object = mesh; + + CARS[ car ].buttons = createButtons( materials.body, car ); + attachButtonMaterials( materials.body, m, bm, car ); + + switchCar( car ); + + loader.statusDomElement.style.display = "none"; + loader.statusDomElement.innerHTML = "Loading model ..."; + + } + + function onDocumentMouseMove(event) { + + mouseY = ( event.clientY - window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + var timer = -0.0002 * Date.now(); + + camera.position.x = 1000 * Math.cos( timer ); + camera.position.y += ( - mouseY - camera.position.y ) * .05; + camera.position.z = 1000 * Math.sin( timer ); + + camera.lookAt( scene.position ); + cameraCube.rotation.copy( camera.rotation ); + + renderer.render( sceneCube, cameraCube ); + renderer.render( scene, camera ); + + if ( STATS_ENABLED ) stats.update(); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cars_anaglyph.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cars_camaro.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cars_camaro_crosseyed.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cars_parallaxbarrier.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + var cameraCube, sceneCube; + + var mesh, lightMesh, geometry; + + var loader; + + var directionalLight, pointLight; + + var mouseX = 0; + var mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + document.addEventListener('mousemove', onDocumentMouseMove, false); + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 ); + camera.position.z = 2000; + + cameraCube = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 100 ); + + scene = new THREE.Scene(); + sceneCube = new THREE.Scene(); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0xffffff ); + scene.add( ambient ); + + pointLight = new THREE.PointLight( 0xffffff, 2 ); + scene.add( pointLight ); + + // light representation + + var sphere = new THREE.SphereGeometry( 100, 16, 8 ); + lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color: 0xffaa00 } ) ); + lightMesh.position = pointLight.position; + lightMesh.scale.x = lightMesh.scale.y = lightMesh.scale.z = 0.05; + scene.add( lightMesh ); + + var path = "textures/cube/SwedishRoyalCastle/"; + var format = '.jpg'; + var urls = [ + path + 'px' + format, path + 'nx' + format, + path + 'py' + format, path + 'ny' + format, + path + 'pz' + format, path + 'nz' + format + ]; + + var reflectionCube = THREE.ImageUtils.loadTextureCube( urls ); + reflectionCube.format = THREE.RGBFormat; + + var refractionCube = new THREE.Texture( reflectionCube.image, new THREE.CubeRefractionMapping() ); + refractionCube.format = THREE.RGBFormat; + + //var cubeMaterial3 = new THREE.MeshPhongMaterial( { color: 0x000000, specular:0xaa0000, envMap: reflectionCube, combine: THREE.MixOperation, reflectivity: 0.25 } ); + var cubeMaterial3 = new THREE.MeshLambertMaterial( { color: 0xff6600, ambient: 0x993300, envMap: reflectionCube, combine: THREE.MixOperation, reflectivity: 0.3 } ); + var cubeMaterial2 = new THREE.MeshLambertMaterial( { color: 0xffee00, ambient: 0x996600, envMap: refractionCube, refractionRatio: 0.95 } ); + var cubeMaterial1 = new THREE.MeshLambertMaterial( { color: 0xffffff, ambient: 0xaaaaaa, envMap: reflectionCube } ) + + // Skybox + + var shader = THREE.ShaderLib[ "cube" ]; + shader.uniforms[ "tCube" ].value = reflectionCube; + + var material = new THREE.ShaderMaterial( { + + fragmentShader: shader.fragmentShader, + vertexShader: shader.vertexShader, + uniforms: shader.uniforms, + depthWrite: false, + side: THREE.BackSide + + } ), + + mesh = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material ); + sceneCube.add( mesh ); + + // + + renderer = new THREE.WebGLRenderer(); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.autoClear = false; + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + loader = new THREE.BinaryLoader( true ); + document.body.appendChild( loader.statusDomElement ); + + loader.load( "obj/walt/WaltHead_bin.js", function( geometry ) { createScene( geometry, cubeMaterial1, cubeMaterial2, cubeMaterial3 ) } ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + cameraCube.aspect = window.innerWidth / window.innerHeight; + cameraCube.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function createScene( geometry, m1, m2, m3 ) { + + var s = 15; + + var mesh = new THREE.Mesh( geometry, m1 ); + mesh.position.z = - 100; + mesh.scale.x = mesh.scale.y = mesh.scale.z = s; + scene.add( mesh ); + + var mesh = new THREE.Mesh( geometry, m2 ); + mesh.position.x = - 900; + mesh.position.z = - 100; + mesh.scale.x = mesh.scale.y = mesh.scale.z = s; + scene.add( mesh ); + + var mesh = new THREE.Mesh( geometry, m3 ); + mesh.position.x = 900; + mesh.position.z = - 100; + mesh.scale.x = mesh.scale.y = mesh.scale.z = s; + scene.add( mesh ); + + loader.statusDomElement.style.display = "none"; + + } + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ) * 4; + mouseY = ( event.clientY - windowHalfY ) * 4; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = -0.0002 * Date.now(); + + lightMesh.position.x = 1500 * Math.cos( timer ); + lightMesh.position.z = 1500 * Math.sin( timer ); + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + cameraCube.rotation.copy( camera.rotation ); + + renderer.render( sceneCube, cameraCube ); + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_balls_reflection.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_balls_reflection_anaglyph.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_balls_refraction.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_balls_refraction_crosseyed.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_dynamic.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_dynamic2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_escher.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_cubemap_refraction.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_grass.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var camera, scene, renderer, + mesh, levels = []; + + init(); + animate(); + + function init() { + + camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); + camera.position.set( 0, 75, 100 ); + + scene = new THREE.Scene(); + + var geometry = new THREE.PlaneGeometry( 100, 100 ); + + var bitmap = generateTextureBase(); + + for ( var i = 0; i < 15; i ++ ) { + + mesh = levels[ i ] = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: new THREE.Texture( generateTextureLevel( bitmap ) ), transparent: true, depthWrite: false, depthTest: false } ) ); + mesh.material.map.needsUpdate = true; + + mesh.position.y = i * 0.25; + mesh.rotation.x = - Math.PI / 2; + + scene.add( mesh ); + + } + + renderer = new THREE.WebGLRenderer(); + renderer.sortObjects = false; + renderer.setSize( window.innerWidth, window.innerHeight ); + document.body.appendChild( renderer.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function generateTextureBase() { + + var canvas = document.createElement( 'canvas' ); + canvas.width = 512; + canvas.height = 512; + + var context = canvas.getContext( '2d' ); + + for ( var i = 0; i < 20000; i ++ ) { + + context.fillStyle = 'rgba(0,' + Math.floor( Math.random() * 64 + 32 ) + ',16,1)'; + context.beginPath(); + context.arc( Math.random() * canvas.width, Math.random() * canvas.height, Math.random() * 1 + 0.5, 0, Math.PI * 2, true ); + context.closePath(); + context.fill(); + + } + + context.globalAlpha = 0.075; + context.globalCompositeOperation = 'lighter'; + + return canvas; + + } + + function generateTextureLevel( texture ) { + + texture.getContext( '2d' ).drawImage( texture, 0, 0 ); + + var canvas = document.createElement( 'canvas' ); + canvas.width = texture.width; + canvas.height = texture.height; + + canvas.getContext( '2d' ).drawImage( texture, 0, 0 ); + + return canvas; + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + + } + + function render() { + + var time = Date.now() / 6000; + + camera.position.x = 80 * Math.cos( time ); + camera.position.z = 80 * Math.sin( time ); + + camera.lookAt( scene.position ); + + for ( var i = 0, l = levels.length; i < l; i ++ ) { + + mesh = levels[ i ]; + mesh.position.x = Math.sin( time * 4 ) * i * i * 0.005; + mesh.position.z = Math.cos( time * 6 ) * i * i * 0.005; + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_lightmap.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_normalmap.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_normalmap2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_shaders.html + +()=>{ + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight; + var FLOOR = -250; + + var container, stats; + + var camera, scene, canvasRenderer, webglRenderer; + + var mesh, zmesh, lightMesh, geometry; + + var directionalLight, pointLight; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var render_canvas = false, render_gl = true; + var has_gl = false; + + var bcanvas = document.getElementById( "rcanvas" ); + var bwebgl = document.getElementById( "rwebgl" ); + + init(); + animate(); + + render_canvas = !has_gl; + bwebgl.style.display = has_gl ? "inline" : "none"; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + function addMesh( geometry, scale, x, y, z, rx, ry, rz, material ) { + + mesh = new THREE.Mesh( geometry, material ); + + mesh.scale.set( scale, scale, scale ); + mesh.position.set( x, y, z ); + mesh.rotation.set( rx, ry, rz ); + + scene.add( mesh ); + + } + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 ); + camera.position.z = 1000; + + scene = new THREE.Scene(); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x101010 ); + scene.add( ambient ); + + directionalLight = new THREE.DirectionalLight( 0xffffff ); + directionalLight.position.set( 1, 1, 2 ).normalize(); + scene.add( directionalLight ); + + pointLight = new THREE.PointLight( 0xffffff ); + scene.add( pointLight ); + + // light representation + + var sphere = new THREE.SphereGeometry( 100, 16, 8 ); + lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color: 0xffaa00 } ) ); + lightMesh.scale.set( 0.05, 0.05, 0.05 ); + lightMesh.position = pointLight.position; + scene.add( lightMesh ); + + // material samples + + sphere = new THREE.SphereGeometry( 100, 32, 32 ); + + var y1 = 0, y2 = - 200; + + addMesh( sphere, 1, -600, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x050505, color: 0x000000, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, -600, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0x050505 } ) ); + + addMesh( sphere, 1, -400, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0xffffff, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, -400, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0xffffff } ) ); + + addMesh( sphere, 1, -200, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0xff5500, specular: 0x555555, shininess: 10 } ) ); + addMesh( sphere, 1, -200, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0xff5500 } ) ); + + addMesh( sphere, 1, 0, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0xffaa00, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, 0, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0xffaa00 } ) ); + + addMesh( sphere, 1, 200, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0x55ff00, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, 200, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0x55ff00 } ) ); + + addMesh( sphere, 1, 400, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0x0055ff, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, 400, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0x0055ff } ) ); + + addMesh( sphere, 1, 600, y1, 0, 0,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0x5500ff, specular: 0x555555, shininess: 30 } ) ); + addMesh( sphere, 1, 600, y2, 0, 0,0,0, new THREE.MeshLambertMaterial( { color: 0x5500ff } ) ); + + addToruses( new THREE.TorusGeometry( 100, 20, 32, 32 ) ); + + // + + if ( render_gl ) { + + try { + + webglRenderer = new THREE.WebGLRenderer(); + webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + webglRenderer.domElement.style.position = "relative"; + container.appendChild( webglRenderer.domElement ); + has_gl = true; + + } catch (e) { + + } + + } + + canvasRenderer = new THREE.CanvasRenderer(); + canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + container.appendChild( canvasRenderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + bcanvas.addEventListener("click", toggleCanvas, false); + bwebgl.addEventListener("click", toggleWebGL, false); + + document.addEventListener('mousemove', onDocumentMouseMove, false); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + if ( webglRenderer ) webglRenderer.setSize( window.innerWidth, window.innerHeight ); + if ( canvasRenderer ) canvasRenderer.setSize( window.innerWidth, window.innerHeight ); + + } + + function addToruses( geometry ) { + + var s = 0.85, t = s + 100, y = 200, rx = 0; + + addMesh( geometry, s, -6*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x000000, color: 0x000000, specular: 0x333333, shininess: 10 } ) ); + addMesh( geometry, s, -4*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x888888, specular: 0x333333, shininess: 10 } ) ); + addMesh( geometry, s, -2*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0xff5500, shininess: 10 } ) ); + addMesh( geometry, s, 0, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0xffaa00, shininess: 10 } ) ); + addMesh( geometry, s, 2*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0x55ff00, shininess: 10 } ) ); + addMesh( geometry, s, 4*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0x0055ff, shininess: 10 } ) ); + addMesh( geometry, s, 6*t, y, 0, rx,0,0, new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0x030303, specular: 0x5500ff, shininess: 10 } ) ); + + } + + + function onDocumentMouseMove(event) { + + mouseX = ( event.clientX - windowHalfX ); + mouseY = ( event.clientY - windowHalfY ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var timer = -0.0002 * Date.now(); + + camera.position.x += ( mouseX - camera.position.x ) * .05; + camera.position.y += ( - mouseY - camera.position.y ) * .05; + + camera.lookAt( scene.position ); + + lightMesh.position.x = 700 * Math.cos( timer ); + lightMesh.position.z = 700 * Math.sin( timer ); + + if ( render_canvas ) canvasRenderer.render( scene, camera ); + if ( render_gl && has_gl ) webglRenderer.render( scene, camera ); + + } + + function toggleCanvas() { + + render_canvas = !render_canvas; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + render_gl = !render_canvas; + bwebgl.className = render_gl ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } + + function toggleWebGL() { + + render_gl = !render_gl; + bwebgl.className = render_gl ? "button" : "button inactive"; + + render_canvas = !render_gl; + bcanvas.className = render_canvas ? "button" : "button inactive"; + + if( has_gl ) + webglRenderer.domElement.style.display = render_gl ? "block" : "none"; + + canvasRenderer.domElement.style.display = render_canvas ? "block" : "none"; + + } +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_shaders_fresnel.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_skin.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_texture_anisotropy.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_texture_compressed.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_texture_filters.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_texture_manualmipmap.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_video.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_materials_wireframe.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_morphnormals.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_morphtargets.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_morphtargets_horse.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_morphtargets_md2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_morphtargets_md2_control.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_multiple_canvases_circle.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_multiple_canvases_complex.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_multiple_canvases_grid.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_multiple_views.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_panorama_equirectangular.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_billboards.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_billboards_colors.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_dynamic.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_random.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_shapes.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_particles_sprites.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_performance.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_performance_doublesided.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_performance_static.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_postprocessing.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_postprocessing2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_postprocessing_advanced.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_postprocessing_dof.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_postprocessing_godrays.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_ribbons.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + var camera, scene, renderer, ribbon, geometry, geometry2, ribbons = [], + parameters, i, i2, h, color, x, y, z, z2, s, n, n2, nribbons, grid; + + var mouseX = 0, mouseY = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var postprocessing = { enabled : true }; + + var composer; + + init(); + animate(); + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 3000 ); + camera.position.z = 1200; + + scene = new THREE.Scene(); + scene.fog = new THREE.FogExp2( 0x000000, 0.0016 ); + + geometry = new THREE.Geometry(); + geometry2 = new THREE.Geometry(); + + n = 1000; + n2 = 2 * n; + + for ( i = -n; i < n; i++ ) { + + i2 = i + n; + + x = i * 1.175; + y = ( i2 % 2 ) * 5; + + if ( i2 % 2 ) { + + z = 10 * Math.sin( i2 * 0.3 ) * Math.cos( i2 * 0.1 ); + + } + + geometry.vertices.push( new THREE.Vector3( x, y, z ) ); + geometry2.vertices.push( new THREE.Vector3( x, y, z ) ); + + h = i2 % 2 ? 1 : 0.15; + if( i2 % 4 <= 2 ) h -= 0.15; + + color = new THREE.Color( 0xffffff ); + color.setHSL( 0.1, 0, h ); + geometry.colors.push( color ); + geometry2.colors.push( color ); + + } + + var tmpRot = new THREE.Matrix4(); + tmpRot.makeRotationAxis( new THREE.Vector3( 1, 0, 0 ), Math.PI/2 ); + + var xgrid = 34; + var ygrid = 15; + var nribbons = xgrid * ygrid; + + var c = 0; + for (var i = 0; i < xgrid; i ++ ) + for (var j = 0; j < ygrid; j ++ ) { + + var material = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors, side: THREE.DoubleSide } ); + + ribbon = new THREE.Ribbon( i % 2 ? geometry : geometry2, material ); + ribbon.rotation.x = 0; + ribbon.rotation.y = Math.PI / 2; + ribbon.rotation.z = Math.PI; + + x = 40 * ( i - xgrid/2 ); + y = 40 * ( j - ygrid/2 ); + z = 0; + + ribbon.position.set( x, y, z ); + + ribbon.matrixAutoUpdate = false; + + // manually create local matrix + + ribbon.matrix.setPosition( ribbon.position ); + ribbon.matrixRotationWorld.setRotationFromEuler( ribbon.rotation ); + + ribbon.matrix.elements[ 0 ] = ribbon.matrixRotationWorld.elements[ 0 ]; + ribbon.matrix.elements[ 4 ] = ribbon.matrixRotationWorld.elements[ 4 ]; + ribbon.matrix.elements[ 8 ] = ribbon.matrixRotationWorld.elements[ 8 ]; + + ribbon.matrix.elements[ 1 ] = ribbon.matrixRotationWorld.elements[ 1 ]; + ribbon.matrix.elements[ 5 ] = ribbon.matrixRotationWorld.elements[ 5 ]; + ribbon.matrix.elements[ 9 ] = ribbon.matrixRotationWorld.elements[ 9 ]; + + ribbon.matrix.elements[ 2 ] = ribbon.matrixRotationWorld.elements[ 2 ]; + ribbon.matrix.elements[ 6 ] = ribbon.matrixRotationWorld.elements[ 6 ]; + ribbon.matrix.elements[ 10 ] = ribbon.matrixRotationWorld.elements[ 10 ]; + + ribbon.matrix.multiply( tmpRot ); + + ribbon.matrix.scale( ribbon.scale ); + + ribbons.push( ribbon ); + scene.add( ribbon ); + + c ++; + + } + + scene.matrixAutoUpdate = false; + + // + + renderer = new THREE.WebGLRenderer( { antialias: false } ); + renderer.setSize( window.innerWidth, window.innerHeight ); + renderer.autoClear = false; + renderer.setClearColor( scene.fog.color, 1 ); + + container.appendChild( renderer.domElement ); + + // + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + // + + document.addEventListener( 'mousemove', onDocumentMouseMove, false ); + document.addEventListener( 'touchstart', onDocumentTouchStart, false ); + document.addEventListener( 'touchmove', onDocumentTouchMove, false ); + + // + + var renderModel = new THREE.RenderPass( scene, camera ); + var effectBloom = new THREE.BloomPass( 1.0 ); + var effectCopy = new THREE.ShaderPass( THREE.CopyShader ); + + effectCopy.renderToScreen = true; + + composer = new THREE.EffectComposer( renderer ); + + composer.addPass( renderModel ); + composer.addPass( effectBloom ); + composer.addPass( effectCopy ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + windowHalfX = window.innerWidth / 2; + windowHalfY = window.innerHeight / 2; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + composer.reset(); + + } + + function onDocumentMouseMove( event ) { + + mouseX = event.clientX - windowHalfX; + mouseY = event.clientY - windowHalfY; + + } + + function onDocumentTouchStart( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + function onDocumentTouchMove( event ) { + + if ( event.touches.length === 1 ) { + + event.preventDefault(); + + mouseX = event.touches[ 0 ].pageX - windowHalfX; + mouseY = event.touches[ 0 ].pageY - windowHalfY; + + } + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var time = Date.now() * 0.00005; + + camera.position.x += ( mouseX - camera.position.x ) * 0.036; + camera.position.y += ( - mouseY - camera.position.y ) * 0.036; + + camera.lookAt( scene.position ); + + for ( i = -n; i < n; i ++ ) { + + i2 = i + n; + + z = 10 * Math.sin( i2 * 0.1 + time*30 ); + z2 = 20 * Math.cos( Math.sin( i2 * 0.1 + time * 20 ) ); + + geometry.vertices[ i2 ].z = z; + geometry2.vertices[ i2 ].z = z2; + + } + + geometry.verticesNeedUpdate = true; + geometry2.verticesNeedUpdate = true; + + for ( i = 0; i < nribbons; i++ ) { + + h = ( 360 * ( i / nribbons + time ) % 360 ) / 360; + ribbons[ i ].material.color.setHSL( h, ( i % 20 / 20 ) * 0.3 + 0.7, 0.6 ); + + } + + renderer.clear(); + composer.render( 0.1 ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_rtt.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_sandbox.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shader.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var camera, scene, renderer; + + var uniforms, material, mesh; + + var mouseX = 0, mouseY = 0, + lat = 0, lon = 0, phy = 0, theta = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.Camera(); + camera.position.z = 1; + + scene = new THREE.Scene(); + + uniforms = { + time: { type: "f", value: 1.0 }, + resolution: { type: "v2", value: new THREE.Vector2() } + }; + + material = new THREE.ShaderMaterial( { + + uniforms: uniforms, + vertexShader: document.getElementById( 'vertexShader' ).textContent, + fragmentShader: document.getElementById( 'fragmentShader' ).textContent + + } ); + + mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), material ); + scene.add( mesh ); + + renderer = new THREE.WebGLRenderer(); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + onWindowResize(); + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize( event? ) { + + uniforms.resolution.value.x = window.innerWidth; + uniforms.resolution.value.y = window.innerHeight; + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + uniforms.time.value += 0.05; + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shader2.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var container, stats; + + var start_time; + + var camera, scene, renderer; + + var uniforms1, uniforms2, material1, material2, mesh, meshes = []; + + var mouseX = 0, mouseY = 0, + lat = 0, lon = 0, phy = 0, theta = 0; + + var windowHalfX = window.innerWidth / 2; + var windowHalfY = window.innerHeight / 2; + + var clock = new THREE.Clock(); + + init(); + animate(); + + function init() { + + container = document.getElementById( 'container' ); + + camera = new THREE.PerspectiveCamera( 40, windowHalfX / windowHalfY, 1, 3000 ); + camera.position.z = 4; + + scene = new THREE.Scene(); + + start_time = Date.now(); + + uniforms1 = { + time: { type: "f", value: 1.0 }, + resolution: { type: "v2", value: new THREE.Vector2() } + }; + + uniforms2 = { + time: { type: "f", value: 1.0 }, + resolution: { type: "v2", value: new THREE.Vector2() }, + texture: { type: "t", value: THREE.ImageUtils.loadTexture( "textures/disturb.jpg" ) } + }; + + uniforms2.texture.value.wrapS = uniforms2.texture.value.wrapT = THREE.RepeatWrapping; + + var size = 0.75, mlib = [], + params = [ [ 'fragment_shader1', uniforms1 ], [ 'fragment_shader2', uniforms2 ], [ 'fragment_shader3', uniforms1 ], [ 'fragment_shader4', uniforms1 ] ]; + + for( var i = 0; i < params.length; i++ ) { + + var material = new THREE.ShaderMaterial( { + + uniforms: params[ i ][ 1 ], + vertexShader: document.getElementById( 'vertexShader' ).textContent, + fragmentShader: document.getElementById( params[ i ][ 0 ] ).textContent + + } ); + + mlib[ i ] = material; + + mesh = new THREE.Mesh( new THREE.CubeGeometry( size, size, size ), new THREE.MeshFaceMaterial( [ mlib[ i ], mlib[ i ], mlib[ i ], mlib[ i ], mlib[ i ], mlib[ i ] ] ) ); + mesh.position.x = i - ( params.length - 1 ) / 2; + mesh.position.y = i % 2 - 0.5; + scene.add( mesh ); + + meshes[ i ] = mesh; + + } + + renderer = new THREE.WebGLRenderer(); + container.appendChild( renderer.domElement ); + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + container.appendChild( stats.domElement ); + + onWindowResize(); + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize( event? ) { + + uniforms1.resolution.value.x = window.innerWidth; + uniforms1.resolution.value.y = window.innerHeight; + + uniforms2.resolution.value.x = window.innerWidth; + uniforms2.resolution.value.y = window.innerHeight; + + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + renderer.setSize( window.innerWidth, window.innerHeight ); + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + uniforms1.time.value += delta * 5; + uniforms2.time.value = clock.elapsedTime; + + for( var i = 0; i < meshes.length; ++ i ) { + + meshes[ i ].rotation.y += delta * 0.5 * ( i % 2 ? 1 : -1 ); + meshes[ i ].rotation.x += delta * 0.5 * ( i % 2 ? -1 : 1 ); + + } + + renderer.render( scene, camera ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shader_lava.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shading_physical.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shadowmap.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var SHADOW_MAP_WIDTH = 2048, SHADOW_MAP_HEIGHT = 1024; + + var MARGIN = 100; + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN; + var FLOOR = -250; + + var camera, controls, scene, renderer; + var container, stats; + + var NEAR = 5, FAR = 3000; + + var sceneHUD, cameraOrtho, hudMaterial; + + var morph, morphs = []; + + var light; + + var clock = new THREE.Clock(); + + init(); + animate(); + + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + // SCENE CAMERA + + camera = new THREE.PerspectiveCamera( 23, SCREEN_WIDTH / SCREEN_HEIGHT, NEAR, FAR ); + camera.position.set( 700, 50, 1900 ); + + controls = new THREE.FirstPersonControls( camera ); + + controls.lookSpeed = 0.0125; + controls.movementSpeed = 500; + controls.noFly = false; + controls.lookVertical = true; + controls.constrainVertical = true; + controls.verticalMin = 1.5; + controls.verticalMax = 2.0; + + controls.lon = -110; + + // SCENE + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x59472b, 1000, FAR ); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x444444 ); + scene.add( ambient ); + + light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI, 1 ); + light.position.set( 0, 1500, 1000 ); + light.target.position.set( 0, 0, 0 ); + + light.castShadow = true; + + light.shadowCameraNear = 700; + light.shadowCameraFar = camera.far; + light.shadowCameraFov = 50; + + //light.shadowCameraVisible = true; + + light.shadowBias = 0.0001; + light.shadowDarkness = 0.5; + + light.shadowMapWidth = SHADOW_MAP_WIDTH; + light.shadowMapHeight = SHADOW_MAP_HEIGHT; + + scene.add( light ); + + createHUD(); + createScene(); + + // RENDERER + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1, antialias: false } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + renderer.domElement.style.top = MARGIN + 'px'; + container.appendChild( renderer.domElement ); + + renderer.setClearColor( scene.fog.color, 1 ); + renderer.autoClear = false; + + // + + renderer.shadowMapEnabled = true; + renderer.shadowMapType = THREE.PCFShadowMap; + + // STATS + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + //container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + SCREEN_WIDTH = window.innerWidth; + SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN; + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + controls.handleResize(); + + } + + function createHUD() { + + cameraOrtho = new THREE.OrthographicCamera( SCREEN_WIDTH / - 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, -10, 1000 ); + cameraOrtho.position.z = 10; + + var shader = THREE.UnpackDepthRGBAShader; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + hudMaterial = new THREE.ShaderMaterial( { vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader, uniforms: uniforms } ); + + var hudGeo = new THREE.PlaneGeometry( SHADOW_MAP_WIDTH / 2, SHADOW_MAP_HEIGHT / 2 ); + var hudMesh = new THREE.Mesh( hudGeo, hudMaterial ); + hudMesh.position.x = ( SCREEN_WIDTH - SHADOW_MAP_WIDTH / 2 ) * -0.5; + hudMesh.position.y = ( SCREEN_HEIGHT - SHADOW_MAP_HEIGHT / 2 ) * -0.5; + hudMesh.rotation.x = Math.PI / 2; + + sceneHUD = new THREE.Scene(); + sceneHUD.add( hudMesh ); + + cameraOrtho.lookAt( sceneHUD.position ); + + } + + function createScene( ) { + + // GROUND + + var geometry = new THREE.PlaneGeometry( 100, 100 ); + var planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffdd99 } ); + planeMaterial.ambient = planeMaterial.color; + + var ground = new THREE.Mesh( geometry, planeMaterial ); + + ground.position.set( 0, FLOOR, 0 ); + ground.rotation.x = - Math.PI / 2; + ground.scale.set( 100, 100, 100 ); + + ground.castShadow = false; + ground.receiveShadow = true; + + scene.add( ground ); + + // TEXT + + var textGeo = new THREE.TextGeometry( "THREE.JS", { + + size: 200, + height: 50, + curveSegments: 12, + + font: "helvetiker", + weight: "bold", + style: "normal", + + bevelThickness: 2, + bevelSize: 5, + bevelEnabled: true + + }); + + textGeo.computeBoundingBox(); + var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x ); + + var textMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff, ambient: 0xaa0000 } ); + + var mesh = new THREE.Mesh( textGeo, textMaterial ); + mesh.position.x = centerOffset; + mesh.position.y = FLOOR + 67; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + // CUBES + + var mesh = new THREE.Mesh( new THREE.CubeGeometry( 1500, 220, 150 ), planeMaterial ); + + mesh.position.y = FLOOR - 50; + mesh.position.z = 20; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + var mesh = new THREE.Mesh( new THREE.CubeGeometry( 1600, 170, 250 ), planeMaterial ); + + mesh.position.y = FLOOR - 50; + mesh.position.z = 20; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + // MORPHS + + function addMorph( geometry, speed, duration, x, y, z, fudgeColor ) { + + var material = new THREE.MeshLambertMaterial( { color: 0xffaa55, morphTargets: true, vertexColors: THREE.FaceColors } ); + + if ( fudgeColor ) { + + material.color.offsetHSL( 0, Math.random() * 0.5 - 0.25, Math.random() * 0.5 - 0.25 ); + material.ambient = material.color; + + } + + var meshAnim = new THREE.MorphAnimMesh( geometry, material ); + + (meshAnim).speed = speed; + meshAnim.duration = duration; + meshAnim.time = 600 * Math.random(); + + meshAnim.position.set( x, y, z ); + meshAnim.rotation.y = Math.PI/2; + + meshAnim.castShadow = true; + meshAnim.receiveShadow = true; + + scene.add( meshAnim ); + + morphs.push( meshAnim ); + + } + + function morphColorsToFaceColors( geometry ) { + + if ( geometry.morphColors && geometry.morphColors.length ) { + + var colorMap = geometry.morphColors[ 0 ]; + + for ( var i = 0; i < colorMap.colors.length; i ++ ) { + + geometry.faces[ i ].color = colorMap.colors[ i ]; + + } + + } + + } + + var loader = new THREE.JSONLoader(); + + loader.load( "models/animated/horse.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, 300, true ); + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, 450, true ); + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, 600, true ); + + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, -300, true ); + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, -450, true ); + addMorph( geometry, 550, 1000, 100 - Math.random() * 1000, FLOOR, -600, true ); + + } ); + + /* + loader.load( "obj/morphs/fox.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 200, 1000, 100 - Math.random() * 500, FLOOR - 5, 600 ); + + } ); + + loader.load( "obj/morphs/shdw3walk.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 40, 2000, -500, FLOOR + 60, 245 ); + + } ); + + loader.load( "obj/morphs/flamingo.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 500, 1000, 500 - Math.random() * 500, FLOOR + 350, 40 ); + + } ); + + loader.load( "obj/morphs/stork.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 350, 1000, 500 - Math.random() * 500, FLOOR + 350, 340 ); + + } ); + + loader.load( "obj/morphs/mountainlion.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 400, 1000, 500 - Math.random() * 500, FLOOR - 5, 700 ); + + } ); + + loader.load( "obj/morphs/bearBrown.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 300, 2500, -500, FLOOR - 5, -750 ); + + } ); + + loader.load( "obj/morphs/parrot.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 450, 500, 500 - Math.random() * 500, FLOOR + 300, 700 ); + + } ); + */ + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + for ( var i = 0; i < morphs.length; i ++ ) { + + morph = morphs[ i ]; + + morph.updateAnimation( 1000 * delta ); + + morph.position.x += morph.speed * delta; + + if ( morph.position.x > 2000 ) { + + morph.position.x = -1000 - Math.random() * 500; + + } + + } + + controls.update( delta ); + + renderer.clear(); + renderer.render( scene, camera ); + + // Render debug HUD with shadow map + + //hudMaterial.uniforms.tDiffuse.texture = light.shadowMap; + //renderer.render( sceneHUD, cameraOrtho ); + + } +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_shadowmap_performance.html + +()=>{ + + if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); + + var SHADOW_MAP_WIDTH = 2048, SHADOW_MAP_HEIGHT = 1024; + + var MARGIN = 100; + + var SCREEN_WIDTH = window.innerWidth; + var SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN; + var FLOOR = -250; + + var camera, controls, scene, renderer; + var container, stats; + + var NEAR = 5, FAR = 3000; + + var sceneHUD, cameraOrtho, hudMaterial; + + var morph, morphs = []; + + var light; + + var clock = new THREE.Clock(); + + init(); + animate(); + + + function init() { + + container = document.createElement( 'div' ); + document.body.appendChild( container ); + + // SCENE CAMERA + + camera = new THREE.PerspectiveCamera( 23, SCREEN_WIDTH / SCREEN_HEIGHT, NEAR, FAR ); + camera.position.set( 700, 50, 1900 ); + + controls = new THREE.FirstPersonControls( camera ); + + controls.lookSpeed = 0.0125; + controls.movementSpeed = 500; + controls.noFly = false; + controls.lookVertical = true; + controls.constrainVertical = true; + controls.verticalMin = 1.5; + controls.verticalMax = 2.0; + + controls.lon = -110; + + // SCENE + + scene = new THREE.Scene(); + scene.fog = new THREE.Fog( 0x59472b, 1000, FAR ); + + // LIGHTS + + var ambient = new THREE.AmbientLight( 0x444444 ); + scene.add( ambient ); + + light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI, 1 ); + light.position.set( 0, 1500, 1000 ); + light.target.position.set( 0, 0, 0 ); + + light.castShadow = true; + + light.shadowCameraNear = 700; + light.shadowCameraFar = camera.far; + light.shadowCameraFov = 50; + + //light.shadowCameraVisible = true; + + light.shadowBias = 0.0001; + light.shadowDarkness = 0.5; + + light.shadowMapWidth = SHADOW_MAP_WIDTH; + light.shadowMapHeight = SHADOW_MAP_HEIGHT; + + scene.add( light ); + + createHUD(); + createScene(); + + // RENDERER + + renderer = new THREE.WebGLRenderer( { clearColor: 0x000000, clearAlpha: 1, antialias: false } ); + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + renderer.domElement.style.position = "relative"; + renderer.domElement.style.top = MARGIN + 'px'; + container.appendChild( renderer.domElement ); + + renderer.setClearColor( scene.fog.color, 1 ); + renderer.autoClear = false; + + // + + renderer.shadowMapEnabled = true; + renderer.shadowMapType = THREE.PCFSoftShadowMap; + + // STATS + + stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.zIndex = 100; + container.appendChild( stats.domElement ); + + // + + window.addEventListener( 'resize', onWindowResize, false ); + + } + + function onWindowResize() { + + SCREEN_WIDTH = window.innerWidth; + SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN; + + camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT; + camera.updateProjectionMatrix(); + + renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); + + controls.handleResize(); + + } + + function createHUD() { + + cameraOrtho = new THREE.OrthographicCamera( SCREEN_WIDTH / - 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, -10, 1000 ); + cameraOrtho.position.z = 10; + + var shader = THREE.UnpackDepthRGBAShader; + var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); + + hudMaterial = new THREE.ShaderMaterial( { vertexShader: shader.vertexShader, fragmentShader: shader.fragmentShader, uniforms: uniforms } ); + + var hudGeo = new THREE.PlaneGeometry( SHADOW_MAP_WIDTH / 2, SHADOW_MAP_HEIGHT / 2 ); + var hudMesh = new THREE.Mesh( hudGeo, hudMaterial ); + hudMesh.position.x = ( SCREEN_WIDTH - SHADOW_MAP_WIDTH / 2 ) * -0.5; + hudMesh.position.y = ( SCREEN_HEIGHT - SHADOW_MAP_HEIGHT / 2 ) * -0.5; + hudMesh.rotation.x = Math.PI / 2; + + sceneHUD = new THREE.Scene(); + sceneHUD.add( hudMesh ); + + cameraOrtho.lookAt( sceneHUD.position ); + + } + + function createScene( ) { + + // GROUND + + var geometry = new THREE.PlaneGeometry( 100, 100 ); + var planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffdd99 } ); + planeMaterial.ambient = planeMaterial.color; + + var ground = new THREE.Mesh( geometry, planeMaterial ); + + ground.position.set( 0, FLOOR, 0 ); + ground.rotation.x = - Math.PI / 2; + ground.scale.set( 100, 100, 100 ); + + ground.castShadow = false; + ground.receiveShadow = true; + + scene.add( ground ); + + // TEXT + + var textGeo = new THREE.TextGeometry( "THREE.JS", { + + size: 200, + height: 50, + curveSegments: 12, + + font: "helvetiker", + weight: "bold", + style: "normal", + + bevelThickness: 2, + bevelSize: 5, + bevelEnabled: true + + }); + + textGeo.computeBoundingBox(); + var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x ); + + var textMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff, ambient: 0xaa0000 } ); + + var mesh = new THREE.Mesh( textGeo, textMaterial ); + mesh.position.x = centerOffset; + mesh.position.y = FLOOR + 67; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + // CUBES + + var mesh = new THREE.Mesh( new THREE.CubeGeometry( 1500, 220, 150 ), planeMaterial ); + + mesh.position.y = FLOOR - 50; + mesh.position.z = 20; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + var mesh = new THREE.Mesh( new THREE.CubeGeometry( 1600, 170, 250 ), planeMaterial ); + + mesh.position.y = FLOOR - 50; + mesh.position.z = 20; + + mesh.castShadow = true; + mesh.receiveShadow = true; + + scene.add( mesh ); + + // MORPHS + + function addMorph( geometry, speed, duration, x, y, z, fudgeColor ) { + + var material = new THREE.MeshLambertMaterial( { color: 0xffaa55, morphTargets: true, vertexColors: THREE.FaceColors } ); + + if ( fudgeColor ) { + + material.color.offsetHSL( 0, Math.random() * 0.5 - 0.25, Math.random() * 0.5 - 0.25 ); + material.ambient = material.color; + + } + + var meshAnim = new THREE.MorphAnimMesh( geometry, material ); + + (meshAnim).speed = speed; + meshAnim.duration = duration; + meshAnim.time = 600 * Math.random(); + + meshAnim.position.set( x, y, z ); + meshAnim.rotation.y = Math.PI/2; + + meshAnim.castShadow = true; + meshAnim.receiveShadow = true; + + scene.add( meshAnim ); + + morphs.push( meshAnim ); + + } + + function morphColorsToFaceColors( geometry ) { + + if ( geometry.morphColors && geometry.morphColors.length ) { + + var colorMap = geometry.morphColors[ 0 ]; + + for ( var i = 0; i < colorMap.colors.length; i ++ ) { + + geometry.faces[ i ].color = colorMap.colors[ i ]; + + } + + } + + } + + var loader = new THREE.JSONLoader(); + + loader.load( "models/animated/horse.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + + + var i = -600; + while (i < 601){ + addMorph( geometry, 550, 1000, 100 - Math.random() * 3000, FLOOR, i, true ); + i += 2; + } + + } ); + + /* + loader.load( "obj/morphs/fox.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 200, 1000, 100 - Math.random() * 500, FLOOR - 5, 600 ); + + } ); + + loader.load( "obj/morphs/shdw3walk.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 40, 2000, -500, FLOOR + 60, 245 ); + + } ); + + loader.load( "obj/morphs/flamingo.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 500, 1000, 500 - Math.random() * 500, FLOOR + 350, 40 ); + + } ); + + loader.load( "obj/morphs/stork.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 350, 1000, 500 - Math.random() * 500, FLOOR + 350, 340 ); + + } ); + + loader.load( "obj/morphs/mountainlion.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 400, 1000, 500 - Math.random() * 500, FLOOR - 5, 700 ); + + } ); + + loader.load( "obj/morphs/bearBrown.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 300, 2500, -500, FLOOR - 5, -750 ); + + } ); + + loader.load( "obj/morphs/parrot.js", function( geometry ) { + + morphColorsToFaceColors( geometry ); + addMorph( geometry, 450, 500, 500 - Math.random() * 500, FLOOR + 300, 700 ); + + } ); + */ + + } + + // + + function animate() { + + requestAnimationFrame( animate ); + + render(); + stats.update(); + + } + + function render() { + + var delta = clock.getDelta(); + + for ( var i = 0; i < morphs.length; i ++ ) { + + morph = morphs[ i ]; + + morph.updateAnimation( 1000 * delta ); + + morph.position.x += morph.speed * delta; + + if ( morph.position.x > 2000 ) { + + morph.position.x = -1000 - Math.random() * 500; + + } + + } + + controls.update( delta ); + + renderer.clear(); + renderer.render( scene, camera ); + + // Render debug HUD with shadow map + + //hudMaterial.uniforms.tDiffuse.texture = light.shadowMap; + //renderer.render( sceneHUD, cameraOrtho ); + + } + +}; + +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_sprites.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_terrain_dynamic.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_test_memory.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_test_memory2.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgl_trails.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgldeferred_animation.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgldeferred_arealights.html +// https://github.com/mrdoob/three.js/tree/master/examples/webgldeferred_pointlights.html \ No newline at end of file diff --git a/threejs/three.d.ts b/threejs/three.d.ts index 12eae5de8..0ae2bc67e 100644 --- a/threejs/three.d.ts +++ b/threejs/three.d.ts @@ -89,11 +89,14 @@ module THREE { // Mapping modes export enum Mapping { } - export var UVMapping: Mapping; - export var CubeReflectionMapping: Mapping; - export var CubeRefractionMapping: Mapping; - export var SphericalReflectionMapping: Mapping; - export var SphericalRefractionMapping: Mapping; + export interface MappingConstructor { + new(): Mapping; + } + export var UVMapping: MappingConstructor; + export var CubeReflectionMapping: MappingConstructor; + export var CubeRefractionMapping: MappingConstructor; + export var SphericalReflectionMapping: MappingConstructor; + export var SphericalRefractionMapping: MappingConstructor; // Wrapping modes export enum Wrapping { } @@ -183,6 +186,24 @@ module THREE { // Core /////////////////////////////////////////////////////////////////////////////////////////////// + interface BufferGeometryAttributeArray extends ArrayBufferView{ + length: number; + } + + interface BufferGeometryAttribute{ + itemSize: number; + array: BufferGeometryAttributeArray; + numItems: number; + } + + interface BufferGeometryAttributes{ + [name: string]: BufferGeometryAttribute; + index?: BufferGeometryAttribute; + position?: BufferGeometryAttribute; + normal?: BufferGeometryAttribute; + color?: BufferGeometryAttribute; + } + /** * This is a superefficent class for geometries because it saves all data in buffers. * It reduces memory costs and cpu cycles. But it is not as easy to work with because of all the nessecary buffer calculations. @@ -204,7 +225,7 @@ module THREE { /** * This hashmap has as id the name of the attribute to be set and as value the buffer to set it to. */ - attributes: { [name: string]: any; }; + attributes: BufferGeometryAttributes; /** * When set, it holds certain buffers in memory to have faster updates for this object. When unset, it deletes those buffers and saves memory. @@ -224,6 +245,8 @@ module THREE { hasTangents: bool; morphTargets: any[]; + offsets: { start: number; count: number; index: number; }[]; + /** * Bakes matrix transform directly into vertex coordinates. */ @@ -861,7 +884,7 @@ module THREE { * Frustums are used to determine what is inside the camera's field of view. They help speed up the rendering process. */ export class Frustum { - constructor(p0?: number, p1?: number, p2?: number, p3?: number, p4?: number, p5?: number); + constructor(p0?: Plane, p1?: Plane, p2?: Plane, p3?: Plane, p4?: Plane, p5?: Plane); /** * Array of 6 vectors. @@ -884,13 +907,15 @@ module THREE { export class Line3{ constructor(start?:Vector3, end?:Vector3); + start: Vector3; + end: Vector3; set(start?:Vector3, end?:Vector3):Line3; copy(line:Line3):Line3; center(optionalTarget?:Vector3):Vector3; delta(optionalTarget?:Vector3):Vector3; distanceSq():number; distance():number; - at(t:number, optionalTarget:Vector3):Vector3; + at(t:number, optionalTarget?: Vector3):Vector3; closestPointToPointParameter(point:Vector3, clampToLine?:bool):number; closestPointToPoint(point:Vector3, clampToLine?:bool, optionalTarget?:Vector3):Vector3; applyMatrix4(matrix:Matrix4):Line3; @@ -913,9 +938,10 @@ module THREE { distanceToSphere(sphere: Sphere): number; projectPoint(point: Vector3, optionalTarget?: Vector3): Vector3; orthoPoint(point: Vector3, optionalTarget?: Vector3): Vector3; - isIntersectionLine(startPoint: Vector3, endPoint: Vector3): bool; + isIntersectionLine(line: Line3): bool; + intersectLine(line: Line3, optionalTarget?: Vector3): Vector3; coplanarPoint(optionalTarget?: bool): Vector3; - applyMatrix4(matrix: Matrix3, optionalNormalMatrix?: Matrix3): Plane; + applyMatrix4(matrix: Matrix4, optionalNormalMatrix?: Matrix3): Plane; translate(offset: Vector3): Plane; equals(plane: Plane): bool; clone(): Plane; @@ -932,8 +958,8 @@ module THREE { containsPoint(point: Vector3): bool; distanceToPoint(point: Vector3): number; intersectsSphere(sphere: Sphere): bool; - clampPoint(point: Vector3, optionalTarget?: Vector3): Sphere; - getBoundingBox(optionalTarget: Box3): Box3; + clampPoint(point: Vector3, optionalTarget?: Vector3): Vector3; + getBoundingBox(optionalTarget?: Box3): Box3; applyMatrix4(matrix: Matrix): Sphere; translate(offset: Vector3): Sphere; equals(sphere: Sphere): bool; @@ -1247,6 +1273,10 @@ module THREE { * Returns -1 if x is less than 0, 1 if x is greater than 0, and 0 if x is zero. */ sign(x: number): number; + + degToRad(degrees: number): number; + + radToDeg(radians: number): number; }; /** @@ -1325,6 +1355,7 @@ module THREE { multiplyScalar(s: number): Matrix3; determinant(): number; getInverse(matrix: Matrix3, throwOnInvertible?: bool): Matrix3; + getInverse(matrix: Matrix4, throwOnInvertible?: bool): Matrix3; /** * Transposes this matrix in place. @@ -1398,7 +1429,7 @@ module THREE { * * @param v Rotation vector. order — The order of rotations. Eg. "XYZ". */ - setRotationFromEuler(v: Vector3, order: string): Matrix4; + setRotationFromEuler(v: Vector3, order?: string): Matrix4; /** * Sets the rotation submatrix of this matrix to the rotation specified by q. @@ -1593,7 +1624,7 @@ module THREE { set (origin: Vector3, direction: Vector3): Ray; copy(ray: Ray): Ray; at(t: number, optionalTarget?: Vector3): Vector3; - recastSelf(t: number): Ray; + recast(t: number): Ray; closestPointToPoint(point: Vector3, optionalTarget?: Vector3): Vector3; distanceToPoint(point: Vector3): number; isIntersectionSphere(sphere: Sphere): bool; @@ -2029,6 +2060,29 @@ module THREE { reparametrizeByArcLength(samplingCoef: number): void; } + class Triangle{ + constructor(a?: Vector3, b?: Vector3, c?: Vector3 ); + a: Vector3; + b: Vector3; + c: Vector3; + set(a: Vector3, b: Vector3, c: Vector3): Triangle; + setFromPointsAndIndices( points: Vector3[], i0: number, i1: number, i2: number ): Triangle; + copy(triangle: Triangle): Triangle; + area(): number; + midpoint(optionalTarget?: Vector3): Vector3; + normal(optionalTarget?: Vector3): Vector3; + plane(optionalTarget?: Vector3): Plane; + barycoordFromPoint(point: Vector3, optionalTarget?: Vector3): Vector3; + containsPoint(point: Vector3): bool; + equals(triangle: Triangle): bool; + clone(): Triangle; + static normal(a: Vector3, b: Vector3, c: Vector3, optionalTarget?: Vector3): Vector3; + // static/instance method to calculate barycoordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static barycoordFromPoint(point: Vector3, a: Vector3, b: Vector3, c: Vector3, optionalTarget: Vector3 ): Vector3; + static containsPoint(point: Vector3, a: Vector3, b: Vector3, c: Vector3): bool; + } + /** * ( interface Vector<T> ) @@ -2042,6 +2096,10 @@ module THREE { * v.addVectors(new THREE.Vector2(0, 1), new THREE.Vector2(2, 3)); // invalid but compiled successfully */ export interface Vector { + setComponent(index: number, value: number): void; + + getComponent(index: number): number; + /** * copy(v:T):T; */ @@ -2155,6 +2213,26 @@ module THREE { */ set (x: number, y: number): Vector2; + /** + * Sets X component of this vector. + */ + setX (x: number): Vector2; + + /** + * Sets Y component of this vector. + */ + setY(y: number): Vector2; + + /** + * Sets a component of this vector. + */ + setComponent(index: number, value: number): void; + + /** + * Gets a component of this vector. + */ + getComponent(index: number): number; + /** * Copies value of v to this vector. */ @@ -2191,6 +2269,12 @@ module THREE { */ divideScalar(s: number): Vector2; + min(v: Vector2): Vector2; + + max(v: Vector2): Vector2; + + clamp(min: Vector2, max: Vector2): Vector2; + /** * Inverts this vector. */ @@ -2461,6 +2545,30 @@ module THREE { */ set (x: number, y: number, z: number, w: number): Vector4; + /** + * Sets X component of this vector. + */ + setX (x: number): Vector2; + + /** + * Sets Y component of this vector. + */ + setY(y: number): Vector2; + + /** + * Sets Z component of this vector. + */ + setZ(z: number): Vector2; + + /** + * Sets w component of this vector. + */ + setW(w: number): Vector2; + + setComponent(index: number, value: number): void; + + getComponent(index: number): number; + /** * Copies value of v to this vector. */ @@ -2497,6 +2605,12 @@ module THREE { */ divideScalar(s: number): Vector4; + min(v: Vector4): Vector4; + + max(v: Vector4): Vector4; + + clamp(min: Vector4, max: Vector4): Vector4; + /** * Inverts this vector. */ @@ -2512,11 +2626,6 @@ module THREE { */ lengthSq(): number; - /** - * Computes dot product of this vector and v. - */ - dot(v: Vector4): Vector4; - /** * Computes length of this vector. */ @@ -2579,6 +2688,8 @@ module THREE { export class Box2 { constructor(min?: Vector2, max?: Vector2); + min: Vector2; + max: Vector2; set (min: Vector2, max: Vector2): Box2; setFromPoints(points: Vector2[]): Box2; setFromCenterAndSize(center: Vector2, size: number): Box2; @@ -2595,7 +2706,7 @@ module THREE { getParameter(point: Vector2): Vector2; isIntersectionBox(box: Box2): bool; clampPoint(point: Vector2, optionalTarget?: Vector2): Vector2; - distanceToPoint(point: Vector2): Vector2; + distanceToPoint(point: Vector2): number; intersect(box: Box2): Box2; union(box: Box2): Box2; translate(offset: Vector2): Box2; @@ -2605,6 +2716,8 @@ module THREE { export class Box3 { constructor(min?: Vector3, max?: Vector3); + min: Vector3; + max: Vector3; set (min: Vector3, max: Vector3): Box3; setFromPoints(points: Vector3[]): Box3; setFromCenterAndSize(center: Vector3, size: number): Box3; @@ -2621,7 +2734,8 @@ module THREE { getParameter(point: Vector3): Vector3; isIntersectionBox(box: Box3): bool; clampPoint(point: Vector3, optionalTarget?: Vector3): Vector3; - distanceToPoint(point: Vector3): Vector3; + distanceToPoint(point: Vector3): number; + getBoundingSphere(): Sphere; intersect(box: Box3): Box3; union(box: Box3): Box3; applyMatrix4(matrix: Matrix4): Box3; @@ -3286,6 +3400,27 @@ module THREE { add(loader: Loader): void; } + interface SceneLoaderResult{ + scene: Scene; + geometries: {[id:string]:Geometry;}; + face_materials: {[id:string]:Material;}; + materials: {[id:string]:Material;}; + textures: {[id:string]:Texture;}; + objects: {[id:string]:Object3D;}; + cameras: {[id:string]:Camera;}; + lights: {[id:string]:Light;}; + fogs: {[id:string]:IFog;}; + empties: {[id:string]:any;}; + groups: {[id:string]:any;}; + } + + interface SceneLoaderProgress{ + totalModels: number; + totalTextures: number; + loadedModels: number; + loadedTextures: number; + } + /** * A loader for loading a complete scene out of a JSON file. */ @@ -3314,19 +3449,29 @@ module THREE { * Will be called when load completes. * The default is a function with empty body. */ - callbackSync: () => void; + callbackSync: (result: SceneLoaderResult) => void; /** * Will be called as load progresses. * The default is a function with empty body. */ - callbackProgress: () => void; + callbackProgress: (progress: SceneLoaderProgress, result: SceneLoaderResult) => void; + + geometryHandlerMap: any; + hierarchyHandlerMap: any; + /** * @param url * @param callbackFinished This function will be called with the loaded model as an instance of scene when the load is completed. */ load(url: string, callbackFinished: (scene: Scene) => void ): void; + + addGeometryHandler(typeID: string, loaderClass: Object): void; + + addHierarchyHandler(typeID: string, loaderClass: Object): void; + + static parse(json: any, callbackFinished:(result: SceneLoaderResult)=>void, url: string): void; } /** @@ -3462,7 +3607,7 @@ module THREE { linewidth?: number; linecap?: string; linejoin?: string; - vertexColors?: bool; + vertexColors?: Colors; fog?: bool; } @@ -3781,8 +3926,9 @@ module THREE { export interface Uniforms { - [name: string]: { type: string; value: Object; }; + [name: string]: { type: string; value: any; }; //[name:string]:{type:UniformType;value:Object;}; + color?: { type: string; value: THREE.Color; }; } export interface ShaderMaterialParameters { @@ -3835,12 +3981,19 @@ module THREE { constructor(geometry?: Geometry, material?: LineDashedMaterial, type?: number); constructor(geometry?: Geometry, material?: LineBasicMaterial, type?: number); constructor(geometry?: Geometry, material?: ShaderMaterial, type?: number); + constructor(geometry?: BufferGeometry, material?: LineDashedMaterial, type?: number); + constructor(geometry?: BufferGeometry, material?: LineBasicMaterial, type?: number); + constructor(geometry?: BufferGeometry, material?: ShaderMaterial, type?: number); geometry: Geometry; material: Material; - type: number; + type: LineType; clone(object?: Line): Line; } + enum LineType{} + var LineStrip: LineType; + var LinePieces: LineType; + export class LOD extends Object3D { constructor(); LODs: Object3D[]; @@ -3857,6 +4010,15 @@ module THREE { constructor(geometry?: Geometry, material?: MeshNormalMaterial); constructor(geometry?: Geometry, material?: MeshPhongMaterial); constructor(geometry?: Geometry, material?: ShaderMaterial); + + constructor(geometry?: BufferGeometry , material?: MeshBasicMaterial); + constructor(geometry?: BufferGeometry , material?: MeshDepthMaterial); + constructor(geometry?: BufferGeometry , material?: MeshFaceMaterial); + constructor(geometry?: BufferGeometry , material?: MeshLambertMaterial); + constructor(geometry?: BufferGeometry , material?: MeshNormalMaterial); + constructor(geometry?: BufferGeometry , material?: MeshPhongMaterial); + constructor(geometry?: BufferGeometry , material?: ShaderMaterial); + geometry: Geometry; material: Material; morphTargetBase: number; @@ -3913,6 +4075,10 @@ module THREE { constructor(geometry: Geometry, material?: ParticleCanvasMaterial); constructor(geometry: Geometry, material?: ParticleDOMMaterial); constructor(geometry: Geometry, material?: ShaderMaterial); + constructor(geometry: BufferGeometry, material?: ParticleBasicMaterial); + constructor(geometry: BufferGeometry, material?: ParticleCanvasMaterial); + constructor(geometry: BufferGeometry, material?: ParticleDOMMaterial); + constructor(geometry: BufferGeometry, material?: ShaderMaterial); /** * An instance of Geometry, where each vertex designates the position of a particle in the system. @@ -3940,13 +4106,13 @@ module THREE { } export class SkinnedMesh extends Mesh { - constructor(geometry?: Geometry, material?: MeshBasicMaterial); - constructor(geometry?: Geometry, material?: MeshDepthMaterial); - constructor(geometry?: Geometry, material?: MeshFaceMaterial); - constructor(geometry?: Geometry, material?: MeshLambertMaterial); - constructor(geometry?: Geometry, material?: MeshNormalMaterial); - constructor(geometry?: Geometry, material?: MeshPhongMaterial); - constructor(geometry?: Geometry, material?: ShaderMaterial); + constructor(geometry?: Geometry, material?: MeshBasicMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: MeshDepthMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: MeshFaceMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: MeshLambertMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: MeshNormalMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: MeshPhongMaterial, useVertexTexture?: bool); + constructor(geometry?: Geometry, material?: ShaderMaterial, useVertexTexture?: bool); useVertexTexture: bool; identityMatrix: Matrix4; bones: Bone[]; @@ -4692,6 +4858,17 @@ module THREE { type?: TextureDataType, anisotropy?: number ); + constructor( + image: HTMLCanvasElement, + mapping?: Mapping, + wrapS?: Wrapping, + wrapT?: Wrapping, + magFilter?: TextureFilter, + minFilter?: TextureFilter, + format?: PixelFormat, + type?: TextureDataType, + anisotropy?: number + ); id: number; name: string; image: Object; // HTMLImageElement or ImageData ; @@ -4831,6 +5008,8 @@ module THREE { getNextKeyWith(type: string, h: number, key: number): KeyFrame; // ???? getPrevKeyWith(type: string, h: number, key: number): KeyFrame; + + JITCompile: bool; // https://github.com/mrdoob/three.js/blob/master/examples/webgl_animation_skinning_morph.html#L251 } export class AnimationInterpolation { } @@ -5291,8 +5470,8 @@ module THREE { * Defines a 2d shape plane using paths. */ export class Shape extends Path { - constructor(); - holes: Vector2[][]; + constructor(points?: Vector2[]); + holes: Path[]; extrude(options?: any): ExtrudeGeometry; makeGeometry(options?: any): ShapeGeometry; getPointsHoles(divisions: number): Vector2[][]; @@ -5341,7 +5520,7 @@ module THREE { } export class ConvexGeometry extends Geometry { - constructor(vertices: Vector3); + constructor(vertices: Vector3[]); } /** @@ -5415,8 +5594,8 @@ module THREE { } export class ShapeGeometry extends Geometry { - constructor(shape: Shape, options: any); - constructor(shapes: Shape[], options: any); + constructor(shape: Shape, options?: any); + constructor(shapes: Shape[], options?: any); shapebb: BoundingBox; addShapeList(shapes: Shape[], options: any): ShapeGeometry; addShape(shape: Shape, options?: any): void; @@ -5489,7 +5668,12 @@ module THREE { } export class TubeGeometry extends Geometry { - constructor(path: Path, segments?: number, radius?: number, radiusSegments?: number, closed?: bool, debug?: ArrowHelper[]); + constructor(path: Path, segments?: number, radius?: number, radiusSegments?: number, closed?: bool, debug?: Object3D); + + // https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_extrude_shapes.html#L208 + // Hmmm? + constructor(path: SplineCurve3, segments?: number, radius?: number, radiusSegments?: number, closed?: bool, debug?: bool); + path: Path; segments: number; radius: number; @@ -5591,11 +5775,11 @@ module THREE { } export class LensFlare extends Object3D { - constructor(texture?: Texture, size?: number, distance?: number, blending?: Blending, color?: number); + constructor(texture?: Texture, size?: number, distance?: number, blending?: Blending, color?: Color); lensFlares: LensFlareProperty[]; positionScreen: Vector3; - customUpdateCallback: () => void; - add(texture?: Texture, size?: number, distance?: number, blending?: Blending, color?: number, opacity?: number): void; + customUpdateCallback: (object:LensFlare) => void; + add(texture?: Texture, size?: number, distance?: number, blending?: Blending, color?: Color, opacity?: number): void; updateLensFlares(): void; } @@ -5679,7 +5863,7 @@ module THREE { export var UniformsUtils: { merge(uniforms: Object[]): Uniforms; merge(uniforms: Uniforms[]): Uniforms; - clone(uniforms_src: Object[][]): Object[][]; + clone(uniforms_src: Uniforms): Uniforms; }; export var UniformsLib: { diff --git a/toastr/toastr.d.ts b/toastr/toastr.d.ts index f1a038704..8d3047ad7 100644 --- a/toastr/toastr.d.ts +++ b/toastr/toastr.d.ts @@ -62,6 +62,10 @@ interface ToastrOptions { */ positionClass?: string; /** + * Where toast should be displayed - background + */ + backgroundpositionClass?: string; + /** * Time in milliseconds that the toast should be displayed */ timeOut?: number; @@ -146,4 +150,4 @@ interface Toastr { version: string; } -declare var toastr: Toastr; \ No newline at end of file +declare var toastr: Toastr; diff --git a/trunk8/trunk8.d.ts b/trunk8/trunk8.d.ts new file mode 100644 index 000000000..a736a27b6 --- /dev/null +++ b/trunk8/trunk8.d.ts @@ -0,0 +1,51 @@ +// Type definitions for trunk8 +// Project: https://github.com/rviscomi/trunk8 +// Definitions by: Blake Niemyjski +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +interface Trunk8Options { + /** + (Default: '…') The string to insert in place of the omitted text. This value may include HTML. + @param {string} fill + */ + fill?: string; + /** + (Default: 1) The number of lines of text-wrap to tolerate before truncating. This value must be an integer greater than or equal to 1. + @param {number} lines + */ + lines?: number; + /** + (Default: 'right') The side of the text from which to truncate. Valid values include 'center', 'left', and 'right'. + @param {string} side + */ + side?: string; + /** + (Default: true) When true, the title attribute of the targeted HTML element will be set to the original, untruncated string. Valid values include true and false. + @param {bool} tooltip + */ + tooltip?: bool; + /** + (Default: 'auto') The width, in characters, of the desired text. When set to 'auto', trunk8 will maximize the amount of text without spilling over. + @param {string} width + */ + width?: string; +} + +interface JQuery { + /** + Creates a trunk8 instance and calls a method. + @constructor + @param {string} method + @param {string} value + */ + trunk8(method: string, value?: string): any; + + /** + Creates a trunk8 instance with default options. + @constructor + @param {Trunk8Options} options + */ + trunk8(options?: Trunk8Options): any; +} \ No newline at end of file diff --git a/tweenjs/tweenjs.d.ts b/tweenjs/tweenjs.d.ts index 82e9fd25c..7ab5cf350 100644 --- a/tweenjs/tweenjs.d.ts +++ b/tweenjs/tweenjs.d.ts @@ -12,10 +12,10 @@ module createjs { - export class TweenJS { - // properties - version: string; - buildDate: string; + export class TweenJS { + // properties + version: string; + buildDate: string; } @@ -120,7 +120,7 @@ module createjs { // methods call(callback: (tweenObject: Tween) => any, params?: any[], scope?: Object); // when 'params' isn't given, the callback receives a tweenObject call(callback: (...params: any[]) => any, params?: any[], scope?: Object); // otherwise, it receives the params only - static get(target, props: Object): Tween; + static get(target, props?: Object, pluginData?: Object, override?: bool): Tween; static hasActiveTweens(target? ): void; static installPlugin(plugin: Object, properties: Object): void; pause(tween: Tween): void; @@ -137,24 +137,23 @@ module createjs { // events change: (event) => any; - // EventDispatcher mixins - addEventListener(type: string, listener: (eventObj: Object) => bool): Function; - addEventListener(type: string, listener: (eventObj: Object) => bool): Object; - removeEventListener(type: string, listener: (eventObj: Function) => bool): void; - removeEventListener(type: string, listener: (eventObj: Object) => bool): void; - removeAllEventListeners(type: string): void; - dispatchEvent(eventObj: string, target: Object): bool; - dispatchEvent(eventObj: Object, target: Object): bool; - hasEventListener(type: string): bool; + // EventDispatcher mixins + addEventListener(type: string, listener: (eventObj: Object) => bool): Function; + addEventListener(type: string, listener: (eventObj: Object) => bool): Object; + removeEventListener(type: string, listener: (eventObj: Function) => bool): void; + removeEventListener(type: string, listener: (eventObj: Object) => bool): void; + removeAllEventListeners(type: string): void; + dispatchEvent(eventObj: string, target: Object): bool; + dispatchEvent(eventObj: Object, target: Object): bool; + hasEventListener(type: string): bool; } - export class MotionGuidePlugin { - // properties - static priority: number; + export class MotionGuidePlugin { + // properties + static priority: number; - //methods - static install(): Object; - - } + //methods + static install(): Object; + } } diff --git a/underscore-ko/underscore-ko.d.ts b/underscore-ko/underscore-ko.d.ts new file mode 100644 index 000000000..c10b49d43 --- /dev/null +++ b/underscore-ko/underscore-ko.d.ts @@ -0,0 +1,101 @@ +// Type definitions for Underscore-ko 1.2.2 with underscore 1.4 +// Project: https://github.com/kamranayub/UnderscoreKO +// Definitions by: Maurits Elbers +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// +/// + +interface KnockoutObservableArrayFunctions { + + /**** + Collections + *****/ + each(iterator: ListIterator, context?: any): any[]; + each(iterator: ObjectIterator, context?: any): any[]; + forEach(iterator: ObjectIterator, context?: any): any[]; + forEach(iterator: ListIterator, context?: any): any[]; + + map(iterator: ListIterator, context?: any): any[]; + map(iterator: ObjectIterator, context?: any): any[]; + collect(iterator: ListIterator, context?: any): any[]; + collect(iterator: ObjectIterator, context?: any): any[]; + + reduce(iterator: any, memo: any, context?: any): any; + inject(iterator: any, memo: any, context?: any): any; + foldl(iterator: any, memo: any, context?: any): any; + + reduceRight(iterator: any, memo: any, context?: any): any[]; + foldr(iterator: any, memo: any, context?: any): any[]; + + find(iterator: any, context?: any): any; + detect(iterator: any, context?: any): any; + + filter(iterator: any, context?: any): any[]; + select(iterator: any, context?: any): any[]; + + where(properties: any): any[]; + + reject(iterator: any, context?: any): any[]; + + all(iterator: any, context?: any): bool; + every(iterator: any, context?: any): bool; + + any(iterator?: any, context?: any): bool; + some(iterator?: any, context?: any): bool; + + contains(list: any, value: any): bool; + contains(value: any): bool; + include(list: any, value: any): bool; + include(value: any): bool; + + invoke(methodName: string, arguments: any[]): any; + invoke(methodName: string, ...arguments: any[]): any; + + pluck(propertyName: string): string[]; + max(iterator?: any, context?: any): any; + min(iterator?: any, context?: any): any; + sortBy(iterator?: any, context?: any): any; + groupBy(iterator: any): any; + countBy(iterator: any): any; + shuffle(): any[]; + size(): number; + + /**** + Arrays + *****/ + first(n?: number): any; + head(n?: number): any; + take(n?: number): any; + + initial(n?: number): any[]; + + last(n?: number): any; + + rest(n?: number): any[]; + tail(n?: number): any[]; + drop(n?: number): any[]; + + compact(): any[]; + flatten(shallow?: bool): any[]; + without(...values: any[]): any[]; + union(...arrays: any[][]): any[]; + intersection(...arrays: any[][]): any[]; + difference(...others: any[][]): any[]; + + uniq(isSorted?: bool, iterator?: any): any[]; + unique(isSorted?: bool, iterator?: any): any[]; + + zip(...arrays: any[]): any[]; + object(values?: any[]): any; + indexOf(value: any, isSorted?: bool): number; + lastIndexOf(value: any, fromIndex?: number): number; + sortedIndex(valueL: any, iterator?: any): number; + range(stop: number): any[]; + range(start: number, stop: number, step?: number): any[]; + + /**** + Chaining + *****/ + chain(object: any): UnderscoreWrappedObject; +} diff --git a/underscore/underscore-typed.d.ts b/underscore/underscore-typed.d.ts index 86077aa18..941066920 100644 --- a/underscore/underscore-typed.d.ts +++ b/underscore/underscore-typed.d.ts @@ -1197,7 +1197,7 @@ interface Underscore { * @param obj Object to chain. * @return Wrapped `obj`. **/ - chain(obj: any): UnderscoreOOPWrapper; + chain(obj: any): UnderscoreChain; /** * Extracts the value of a wrapped object. @@ -2048,7 +2048,825 @@ interface UnderscoreOOPWrapper { * Wrapped type `any`. * @see _.chain **/ - chain(): any; + chain(): UnderscoreChain; + + /** + * Wrapped type `any`. + * @see _.value + **/ + value(): any; +} + +interface UnderscoreChain { + + /************** + * Collections * + **************/ + + /** + * Wrapped type `any[]`. + * @see _.each + **/ + each( + iterator: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Wrapped type `object`. + * @see _.each + **/ + each( + iterator: (value: any, key?: string, object?: Object) => any, + context?: any): UnderscoreChain; + + /** + * Alias for 'each'. + * @see each + **/ + forEach( + iterator: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Alias for 'each'. + * @see each + **/ + forEach( + iterator: (value: any, key?: string, object?: Object) => any, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.map + **/ + map( + iterator: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Wrapped type `object`. + * @see _.map + **/ + map( + iterator: (value: any, key?: string, object?: Object) => any, + context?: any): UnderscoreChain; + + /** + * Alias for 'map'. + * @see map + **/ + collect( + iterator: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Alias for 'map'. + * @see map + **/ + collect( + iterator: (value: any, key?: string, object?: Object) => any, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.reduce + **/ + reduce( + iterator: (memo: any, element: any, index?: number, list?: any[]) => any, + memo: any, + context?: any): UnderscoreChain; + + /** + * Alias for 'reduce'. + * @see reduce + **/ + inject( + iterator: (memo: any, element: any, index?: number, list?: any[]) => any, + memo: any, + context?: any): UnderscoreChain; + + /** + * Alias for 'reduce'. + * @see reduce + **/ + foldl( + iterator: (memo: any, element: any, index?: number, list?: any[]) => any, + memo: any, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.reduceRight + **/ + reduceRight( + iterator: (memo: any, element: any, index?: number, list?: any[]) => any, + memo: any, + context?: any): UnderscoreChain; + + /** + * Alias for 'reduceRight'. + * @see reduceRight + **/ + foldr( + iterator: (memo: any, element: any, index?: number, list?: any[]) => any, + memo: any, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.find + **/ + find( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Alias for 'find'. + * @see find + **/ + detect( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + + /** + * Wrapped type `any[]`. + * @see _.filter + **/ + filter( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Alias for 'filter'. + * @see filter + **/ + select( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.where + **/ + where(list: any[], properties: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.findWhere + **/ + findWhere(properties: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.reject + **/ + reject( + list: any[], + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.all + **/ + all( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Alias for 'all'. + * @see all + **/ + every( + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.any + **/ + any( + list: any[], + iterator?: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Alias for 'any'. + * @see any + **/ + some( + list: any[], + iterator: (element: any, index?: number, list?: any[]) => bool, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.contains + **/ + contains(value: any): UnderscoreChain; + + /** + * Alias for 'contains'. + * @see contains + **/ + include(value: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.invoke + **/ + invoke(methodName: string, ...arguments: any[]): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.pluck + **/ + pluck(propertyName: string): UnderscoreChain; + + /** + * Wrapped type `number[]`. + * @see _.max + **/ + max(): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.max + **/ + max( + iterator: (element: any, index?: number, list?: any[]) => number, + context?: any): UnderscoreChain; + + /** + * Wrapped type `number[]`. + * @see _.min + **/ + min(): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.min + **/ + min( + iterator: (obj: any, index?: number, list?: any[]) => number, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.sortBy + **/ + sortBy( + iterator: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.sortBy + **/ + sortBy( + iterator: string, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.groupBy + **/ + groupBy( + iterator: (element: any, index?: number, list?: any[]) => string, + context?: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.groupBy + **/ + groupBy( + iterator: string, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.countBy + **/ + countBy( + iterator: (element: any, index?: number, list?: any[]) => string, + context?: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.countBy + **/ + countBy( + iterator: string, + context?: any): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.shuffle + **/ + shuffle(): UnderscoreChain; + + /** + * Wrapped type `any`. + * @see _.toArray + **/ + toArray(): UnderscoreChain; + + /** + * Wrapped type `any`. + * @see _.size + **/ + size(): UnderscoreChain; + + /********* + * Arrays * + **********/ + + /** + * Wrapped type `any[]`. + * @see _.first + **/ + first(): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.first + **/ + first(n: number): UnderscoreChain; + + /** + * Alias for 'first'. + * @see first + **/ + head(): UnderscoreChain; + /** + * Alias for 'first'. + * @see first + **/ + head(n: number): UnderscoreChain; + + /** + * Alias for 'first'. + * @see first + **/ + take(): UnderscoreChain; + /** + * Alias for 'first'. + * @see first + **/ + take(n: number): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.initial + **/ + initial(n?: number): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.last + **/ + last(): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.last + **/ + last(n: number): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.rest + **/ + rest(index?: number): UnderscoreChain; + + /** + * Alias for 'rest'. + * @see rest + **/ + tail(index?: number): UnderscoreChain; + + /** + * Alias for 'rest'. + * @see rest + **/ + drop(index?: number): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.compact + **/ + compact(): UnderscoreChain; + + /** + * Wrapped type `any`. + * @see _.flatten + **/ + flatten(shallow?: bool): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.without + **/ + without(...values: any[]): UnderscoreChain; + + /** + * Wrapped type `any[][]`. + * @see _.union + **/ + union(...arrays: any[][]): UnderscoreChain; + + /** + * Wrapped type `any[][]`. + * @see _.intersection + **/ + intersection(...arrays: any[][]): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.difference + **/ + difference(...others: any[]): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.uniq + **/ + uniq( + isSorted?: bool, + iterator?: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.uniq + **/ + uniq( + iterator?: (element: any, index?: number, list?: any[]) => any, + context?: any): UnderscoreChain; + + /** + * Alias for 'uniq'. + * @see uniq + **/ + unique( + isSorted?: bool, + iterator?: (element: any, index?: number, list?: any[]) => any): UnderscoreChain; + + /** + * Wrapped type `any[][]`. + * @see _.zip + **/ + zip(...arrays: any[][]): UnderscoreChain; + + /** + * Wrapped type `any[][]`. + * @see _.object + **/ + object(...keyValuePairs: any[][]): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.indexOf + **/ + indexOf(value: any, isSorted?: bool): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.lastIndexOf + **/ + lastIndexOf(value: any, from?: number): UnderscoreChain; + + /** + * Wrapped type `any[]`. + * @see _.sortedIndex + **/ + sortedIndex(value: any, iterator?: (element: any) => number): UnderscoreChain; + + /** + * Wrapped type `number`. + * @see _.range + **/ + range(stop: number, step?: number): UnderscoreChain; + /** + * Wrapped type `number`. + * @see _.range + **/ + range(): UnderscoreChain; + + /************ + * Functions * + *************/ + + /** + * Wrapped type `Function`. + * @see _.bind + **/ + bind(object: any, ...arguments: any[]): UnderscoreChain; + + + /** + * Wrapped type `object`. + * @see _.bindAll + **/ + bindAll(...methodNames: string[]): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.partial + **/ + partial(...arguments: any[]): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.memoize + **/ + memoize(hashFn?: (n: any) => string): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.delay + **/ + delay(waitMS: number, ...arguments: any[]): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.defer + **/ + defer(...arguments: any[]): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.throttle + **/ + throttle(waitMS: number): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.debounce + **/ + debounce(waitMS: number, immediate?: bool): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.once + **/ + once(): UnderscoreChain; + + /** + * Wrapped type `number`. + * @see _.after + **/ + after(fn: Function): UnderscoreChain; + + /** + * Wrapped type `Function`. + * @see _.wrap + **/ + wrap(wrapper: (fn: Function, ...args: any[]) => any): UnderscoreChain; + + /** + * Wrapped type `Function[]`. + * @see _.compose + **/ + compose(...functions: Function[]): UnderscoreChain; + + /********** + * Objects * + ***********/ + + /** + * Wrapped type `object`. + * @see _.keys + **/ + keys(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.values + **/ + values(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.pairs + **/ + pairs(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.invert + **/ + invert(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.functions + **/ + functions(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.extend + **/ + extend(...sources: any[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.pick + **/ + pick(...keys: string[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.omit + **/ + omit(...keys: string[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.defaults + **/ + defaults(...defaults: any[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.clone + **/ + clone(object: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.clone + **/ + clone(list: any[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.tap + **/ + tap(intercepter: Function): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.has + **/ + has(key: string): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isEqual + **/ + isEqual(other: any): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isEmpty + **/ + isEmpty(object: any): UnderscoreChain; + /** + * Wrapped type `any[]`. + * @see _.isEmpty + **/ + isEmpty(list: any[]): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isElement + **/ + isElement(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isArray + **/ + isArray(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isObject + **/ + isObject(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isArguments + **/ + isArguments(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isFunction + **/ + isFunction(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isString + **/ + isString(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isNumber + **/ + isNumber(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isFinite + **/ + isFinite(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isBoolean + **/ + isBoolean(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isDate + **/ + isDate(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isRegExp + **/ + isRegExp(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isNaN + **/ + isNaN(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isNull + **/ + isNull(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.isUndefined + **/ + isUndefined(): UnderscoreChain; + + /********** + * Utility * + ***********/ + + /** + * Wrapped type `any`. + * @see _.identity + **/ + identity(): UnderscoreChain; + + /** + * Wrapped type `number`. + * @see _.times + **/ + times(iterator: (n: number) => any, context?: any): UnderscoreChain; + + /** + * Wrapped type `number`. + * @see _.random + **/ + random(): UnderscoreChain; + /** + * Wrapped type `number`. + * @see _.random + **/ + random(max: number): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.mixin + **/ + mixin(): UnderscoreChain; + + /** + * Wrapped type `string`. + * @see _.uniqueId + **/ + uniqueId(): UnderscoreChain; + + /** + * Wrapped type `string`. + * @see _.escape + **/ + escape(): UnderscoreChain; + + /** + * Wrapped type `object`. + * @see _.result + **/ + result(property: string): UnderscoreChain; + + /** + * Wrapped type `string`. + * @see _.template + **/ + template(data?: any, settings?: UnderscoreTemplateSettings): UnderscoreChain; + + /*********** + * Chaining * + ************/ + + /** + * Wrapped type `any`. + * @see _.chain + **/ + chain(): UnderscoreChain; /** * Wrapped type `any`. diff --git a/underscore/underscore.d.ts b/underscore/underscore.d.ts index 811913958..42d4abeb5 100644 --- a/underscore/underscore.d.ts +++ b/underscore/underscore.d.ts @@ -1,232 +1,232 @@ -// Type definitions for Underscore 1.4 -// Project: http://underscorejs.org/ -// Definitions by: Boris Yankov -// Definitions: https://github.com/borisyankov/DefinitelyTyped - - -interface UnderscoreWrappedObject { - value () : any; - filter(arg?) : any; -} - -interface TemplateSettings { - evaluate?: RegExp; - interpolate?: RegExp; - escape?: RegExp; -} - -interface ListIterator { - (value, key, list?): void; -} - -interface ObjectIterator { - (element, index, list?): void; -} - -// Common interface between Arrays and jQuery objects -interface List { - [index: number]: any; - length: number; -} - -interface UnderscoreStatic { - (arg?:any) : any; - - /**** - Collections - *****/ - each(list: List, iterator: ListIterator, context?: any): any[]; - each(object: any, iterator: ObjectIterator, context?: any): any[]; - forEach(list: List, iterator: ObjectIterator, context?: any): any[]; - forEach(object: any, iterator: ListIterator, context?: any): any[]; - - map(list: List, iterator: ListIterator, context?: any): any[]; - map(object: any, iterator: ObjectIterator, context?: any): any[]; - collect(list: List, iterator: ListIterator, context?: any): any[]; - collect(object: any, iterator: ObjectIterator, context?: any): any[]; - - reduce(list: List, iterator: any, memo: any, context?: any): any[]; - reduce(list: any[], iterator: any, memo: any, context?: any): any[]; - inject(list: List, iterator: any, memo: any, context?: any): any[]; - inject(list: any[], iterator: any, memo: any, context?: any): any[]; - foldl(list: List, iterator: any, memo: any, context?: any): any[]; - foldl(list: any[], iterator: any, memo: any, context?: any): any[]; - - reduceRight(list: List, iterator: any, memo: any, context?: any): any[]; - reduceRight(list: any[], iterator: any, memo: any, context?: any): any[]; - foldr(list: List, iterator: any, memo: any, context?: any): any[]; - foldr(list: any[], iterator: any, memo: any, context?: any): any[]; - - find(list: List, iterator: any, context?: any): any; - find(list: any[], iterator: any, context?: any): any; - detect(list: List, iterator: any, context?: any): any; - detect(list: any[], iterator: any, context?: any): any; - - filter(list: List, iterator: any, context?: any): any[]; - filter(list: any[], iterator: any, context?: any): any[]; - select(list: List, iterator: any, context?: any): any[]; - select(list: any[], iterator: any, context?: any): any[]; - - where(list: List, properties: any): any[]; - where(list: any[], properties: any): any[]; - - reject(list: List, iterator: any, context?: any): any[]; - reject(list: any[], iterator: any, context?: any): any[]; - - all(list: List, iterator: any, context?: any): bool; - all(list: any[], iterator: any, context?: any): bool; - every(list: List, iterator: any, context?: any): bool; - every(list: any[], iterator: any, context?: any): bool; - - any(list: List, iterator?: any, context?: any): bool; - any(list: any[], iterator?: any, context?: any): bool; - some(list: List, iterator?: any, context?: any): bool; - some(list: any[], iterator?: any, context?: any): bool; - - contains(list: any, value: any): bool; - contains(list: List, value: any): bool; - include(list: any, value: any): bool; - include(list: List, value: any): bool; - - invoke(list: List, methodName: string, arguments: any[]): any; - invoke(object: any, methodName: string, ...arguments: any[]): any; - - pluck(list: List, propertyName: string): string[]; - pluck(list: any[], propertyName: string): string[]; - max(list: List, iterator?: any, context?: any): any; - max(list: any[], iterator?: any, context?: any): any; - min(list: List, iterator?: any, context?: any): any; - min(list: any[], iterator?: any, context?: any): any; - sortBy(list: List, iterator?: any, context?: any): any; - sortBy(list: any[], iterator?: any, context?: any): any; - groupBy(list: List, iterator: any): any; - groupBy(list: any[], iterator: any): any; - countBy(list: List, iterator: any): any; - countBy(list: any[], iterator: any): any; - shuffle(list: any[]): any[]; - toArray(list: any): any[]; - size(list: any): number; - - /**** - Arrays - *****/ - first(array: List, n?: number): any; - first(array: any[], n?: number): any; - head(array: List, n?: number): any; - head(array: any[], n?: number): any; - take(array: List, n?: number): any; - take(array: any[], n?: number): any; - - initial(array: List, n?: number): any[]; - initial(array: any[], n?: number): any[]; - - last(array: List, n?: number): any; - last(array: any[], n?: number): any; - - rest(array: List, n?: number): any[]; - rest(array: any[], n?: number): any[]; - tail(array: List, n?: number): any[]; - tail(array: any[], n?: number): any[]; - drop(array: List, n?: number): any[]; - drop(array: any[], n?: number): any[]; - - compact(array: any[]): any[]; - flatten(array: List, shallow?: bool): any[]; - flatten(array: any[], shallow?: bool): any[]; - without(array: List, ...values: any[]): any[]; - without(array: any[], ...values: any[]): any[]; - union(...arrays: any[][]): any[]; - intersection(...arrays: any[][]): any[]; - difference(array: List, ...others: any[][]): any[]; - difference(array: any[], ...others: any[][]): any[]; - - uniq(array: List, isSorted?: bool, iterator?: any): any[]; - uniq(array: any[], isSorted?: bool, iterator?: any): any[]; - unique(array: List, isSorted?: bool, iterator?: any): any[]; - unique(array: any[], isSorted?: bool, iterator?: any): any[]; - - zip(...arrays: any[]): any[]; - object(list: List, values?: any[]): any; - object(list: any[], values?: any[]): any; - indexOf(array: List, value: any, isSorted?: bool): number; - indexOf(array: any[], value: any, isSorted?: bool): number; - lastIndexOf(array: List, value: any, fromIndex?: number): number; - lastIndexOf(array: any[], value: any, fromIndex?: number): number; - sortedIndex(list: List, valueL: any, iterator?: any): number; - sortedIndex(list: any[], valueL: any, iterator?: any): number; - range(stop: number): any[]; - range(start: number, stop: number, step?: number): any[]; - - /**** - Functions - *****/ - bind(func: (...as : any[]) => any, context: any, ...arguments: any[]): () => any; - bindAll(object: any, ...methodNames: string[]): any; - memoize(func: any, hashFunction?: any): any; - defer(func: () => any); - delay(func: any, wait: number, ...arguments: any[]): any; - delay(func: any, ...arguments: any[]): any; - throttle(func: any, wait: number): any; - debounce(func: any, wait: number, immediate?: bool): any; - once(func: any): any; - after(count: number, func: any): any; - wrap(func: (...as : any[]) => any, wrapper: any): () => any; - compose(...functions: any[]): any; - - /**** - Objects - *****/ - keys(object: any): any[]; - values(object: any): any[]; - pairs(object: any): any[]; - invert(object: any): any; - - functions(object: any): string[]; - methods(object: any): string[]; - - extend(destination: any, ...sources: any[]): any; - pick(object: any, ...keys: string[]): any; - omit(object: any, ...keys: string[]): any; - defaults(object: any, ...defaults: any[]): any; - clone(object: any): any; - tap(object: any, interceptor: (...as : any[]) => any): any; - has(object: any, key: string): bool; - isEqual(object: any, other: any): bool; - isEmpty(object: any): bool; - isElement(object: any): bool; - isArray(object: any): bool; - isObject(value: any): bool; - isArguments(object: any): bool; - isFunction(object: any): bool; - isString(object: any): bool; - isNumber(object: any): bool; - isFinite(object: any): bool; - isBoolean(object: any): bool; - isDate(object: any): bool; - isRegExp(object: any): bool; - isNaN(object: any): bool; - isNull(object: any): bool; - isUndefined(value: any): bool; - - /**** - Utility - *****/ - noConflict(): any; - identity(value: any): any; - times(n: number, iterator: (index : number) => void, context?: any): void; - random(min: number, max: number): number; - mixin(object: any): void; - uniqueId(prefix: string): string; - uniqueId(): number; - escape(str: string): string; - result(object: any, property: string): any; - templateSettings: TemplateSettings; - template(templateString: string, data?: any, settings?: any): (...data: any[]) => string; - - /**** - Chaining - *****/ - chain(object: any): UnderscoreWrappedObject; -} - +// Type definitions for Underscore 1.4 +// Project: http://underscorejs.org/ +// Definitions by: Boris Yankov +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +interface UnderscoreWrappedObject { + value () : any; + filter(arg?) : any; +} + +interface TemplateSettings { + evaluate?: RegExp; + interpolate?: RegExp; + escape?: RegExp; +} + +interface ListIterator { + (value, key, list?): void; +} + +interface ObjectIterator { + (element, index, list?): void; +} + +// Common interface between Arrays and jQuery objects +interface List { + [index: number]: any; + length: number; +} + +interface UnderscoreStatic { + (arg?:any) : any; + + /**** + Collections + *****/ + each(list: List, iterator: ListIterator, context?: any): any[]; + each(object: any, iterator: ObjectIterator, context?: any): any[]; + forEach(list: List, iterator: ObjectIterator, context?: any): any[]; + forEach(object: any, iterator: ListIterator, context?: any): any[]; + + map(list: List, iterator: ListIterator, context?: any): any[]; + map(object: any, iterator: ObjectIterator, context?: any): any[]; + collect(list: List, iterator: ListIterator, context?: any): any[]; + collect(object: any, iterator: ObjectIterator, context?: any): any[]; + + reduce(list: List, iterator: any, memo: any, context?: any): any; + reduce(list: any[], iterator: any, memo: any, context?: any): any; + inject(list: List, iterator: any, memo: any, context?: any): any; + inject(list: any[], iterator: any, memo: any, context?: any): any; + foldl(list: List, iterator: any, memo: any, context?: any): any; + foldl(list: any[], iterator: any, memo: any, context?: any): any; + + reduceRight(list: List, iterator: any, memo: any, context?: any): any[]; + reduceRight(list: any[], iterator: any, memo: any, context?: any): any[]; + foldr(list: List, iterator: any, memo: any, context?: any): any[]; + foldr(list: any[], iterator: any, memo: any, context?: any): any[]; + + find(list: List, iterator: any, context?: any): any; + find(list: any[], iterator: any, context?: any): any; + detect(list: List, iterator: any, context?: any): any; + detect(list: any[], iterator: any, context?: any): any; + + filter(list: List, iterator: any, context?: any): any[]; + filter(list: any[], iterator: any, context?: any): any[]; + select(list: List, iterator: any, context?: any): any[]; + select(list: any[], iterator: any, context?: any): any[]; + + where(list: List, properties: any): any[]; + where(list: any[], properties: any): any[]; + + reject(list: List, iterator: any, context?: any): any[]; + reject(list: any[], iterator: any, context?: any): any[]; + + all(list: List, iterator: any, context?: any): bool; + all(list: any[], iterator: any, context?: any): bool; + every(list: List, iterator: any, context?: any): bool; + every(list: any[], iterator: any, context?: any): bool; + + any(list: List, iterator?: any, context?: any): bool; + any(list: any[], iterator?: any, context?: any): bool; + some(list: List, iterator?: any, context?: any): bool; + some(list: any[], iterator?: any, context?: any): bool; + + contains(list: any, value: any): bool; + contains(list: List, value: any): bool; + include(list: any, value: any): bool; + include(list: List, value: any): bool; + + invoke(list: List, methodName: string, arguments: any[]): any; + invoke(object: any, methodName: string, ...arguments: any[]): any; + + pluck(list: List, propertyName: string): string[]; + pluck(list: any[], propertyName: string): string[]; + max(list: List, iterator?: any, context?: any): any; + max(list: any[], iterator?: any, context?: any): any; + min(list: List, iterator?: any, context?: any): any; + min(list: any[], iterator?: any, context?: any): any; + sortBy(list: List, iterator?: any, context?: any): any; + sortBy(list: any[], iterator?: any, context?: any): any; + groupBy(list: List, iterator: any): any; + groupBy(list: any[], iterator: any): any; + countBy(list: List, iterator: any): any; + countBy(list: any[], iterator: any): any; + shuffle(list: any[]): any[]; + toArray(list: any): any[]; + size(list: any): number; + + /**** + Arrays + *****/ + first(array: List, n?: number): any; + first(array: any[], n?: number): any; + head(array: List, n?: number): any; + head(array: any[], n?: number): any; + take(array: List, n?: number): any; + take(array: any[], n?: number): any; + + initial(array: List, n?: number): any[]; + initial(array: any[], n?: number): any[]; + + last(array: List, n?: number): any; + last(array: any[], n?: number): any; + + rest(array: List, n?: number): any[]; + rest(array: any[], n?: number): any[]; + tail(array: List, n?: number): any[]; + tail(array: any[], n?: number): any[]; + drop(array: List, n?: number): any[]; + drop(array: any[], n?: number): any[]; + + compact(array: any[]): any[]; + flatten(array: List, shallow?: bool): any[]; + flatten(array: any[], shallow?: bool): any[]; + without(array: List, ...values: any[]): any[]; + without(array: any[], ...values: any[]): any[]; + union(...arrays: any[][]): any[]; + intersection(...arrays: any[][]): any[]; + difference(array: List, ...others: any[][]): any[]; + difference(array: any[], ...others: any[][]): any[]; + + uniq(array: List, isSorted?: bool, iterator?: any): any[]; + uniq(array: any[], isSorted?: bool, iterator?: any): any[]; + unique(array: List, isSorted?: bool, iterator?: any): any[]; + unique(array: any[], isSorted?: bool, iterator?: any): any[]; + + zip(...arrays: any[]): any[]; + object(list: List, values?: any[]): any; + object(list: any[], values?: any[]): any; + indexOf(array: List, value: any, isSorted?: bool): number; + indexOf(array: any[], value: any, isSorted?: bool): number; + lastIndexOf(array: List, value: any, fromIndex?: number): number; + lastIndexOf(array: any[], value: any, fromIndex?: number): number; + sortedIndex(list: List, valueL: any, iterator?: any): number; + sortedIndex(list: any[], valueL: any, iterator?: any): number; + range(stop: number): any[]; + range(start: number, stop: number, step?: number): any[]; + + /**** + Functions + *****/ + bind(func: (...as : any[]) => any, context: any, ...arguments: any[]): () => any; + bindAll(object: any, ...methodNames: string[]): any; + memoize(func: any, hashFunction?: any): any; + defer(func: () => any); + delay(func: any, wait: number, ...arguments: any[]): any; + delay(func: any, ...arguments: any[]): any; + throttle(func: any, wait: number): any; + debounce(func: any, wait: number, immediate?: bool): any; + once(func: any): any; + after(count: number, func: any): any; + wrap(func: (...as : any[]) => any, wrapper: any): () => any; + compose(...functions: any[]): any; + + /**** + Objects + *****/ + keys(object: any): any[]; + values(object: any): any[]; + pairs(object: any): any[]; + invert(object: any): any; + + functions(object: any): string[]; + methods(object: any): string[]; + + extend(destination: any, ...sources: any[]): any; + pick(object: any, ...keys: string[]): any; + omit(object: any, ...keys: string[]): any; + defaults(object: any, ...defaults: any[]): any; + clone(object: any): any; + tap(object: any, interceptor: (...as : any[]) => any): any; + has(object: any, key: string): bool; + isEqual(object: any, other: any): bool; + isEmpty(object: any): bool; + isElement(object: any): bool; + isArray(object: any): bool; + isObject(value: any): bool; + isArguments(object: any): bool; + isFunction(object: any): bool; + isString(object: any): bool; + isNumber(object: any): bool; + isFinite(object: any): bool; + isBoolean(object: any): bool; + isDate(object: any): bool; + isRegExp(object: any): bool; + isNaN(object: any): bool; + isNull(object: any): bool; + isUndefined(value: any): bool; + + /**** + Utility + *****/ + noConflict(): any; + identity(value: any): any; + times(n: number, iterator: (index : number) => void, context?: any): void; + random(min: number, max: number): number; + mixin(object: any): void; + uniqueId(prefix: string): string; + uniqueId(): number; + escape(str: string): string; + result(object: any, property: string): any; + templateSettings: TemplateSettings; + template(templateString: string, data?: any, settings?: any): (...data: any[]) => string; + + /**** + Chaining + *****/ + chain(object: any): UnderscoreWrappedObject; +} + declare var _: UnderscoreStatic; \ No newline at end of file diff --git a/webaudioapi/waa-20120802.d.ts b/webaudioapi/waa-20120802.d.ts new file mode 100644 index 000000000..b90c4b959 --- /dev/null +++ b/webaudioapi/waa-20120802.d.ts @@ -0,0 +1,247 @@ +// Type definitions for the Web Audio API, currently only implemented in WebKit browsers +// Conforms to the: http://www.w3.org/TR/2012/WD-webaudio-20120802/ specification +// Definitions by: Baruch Berger (https://github.com/bbss) +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +interface webkitAudioContext { + destination: AudioDestinationNode; + sampleRate: number; + currentTime: number; + listener: AudioListener; + activeSourceCount: number; + + createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer; + createBuffer(buffer: ArrayBuffer, mixToMono: bool): AudioBuffer; + + decodeAudioData(audioData: ArrayBuffer, successCallback: any, errorCallback?: any): void; + + createBufferSource(): AudioBufferSourceNode; + + createMediaElementSource(mediaElement: HTMLMediaElement): MediaElementAudioSourceNode; + + createMediaStreamSource(mediaStream: any): MediaStreamAudioSourceNode; + + createAnalyser(): RealtimeAnalyserNode; + createGainNode(): AudioGainNode; + createDelayNode(maxDelayTime?: number): DelayNode; + createBiquadFilter(): BiquadFilterNode; + createPanner():AudioPannerNode; + createConvolver(): ConvolverNode; + + createChannelSplitter(numberOfOutputs?: number):AudioChannelSplitter; + createChannelMerger(numberOfInputs?: number): AudioChannelMerger; + + createDynamicsCompressor(): DynamicsCompressorNode; + + createOscillator(): Oscillator; + createWaveTable(real: any,imag: any): WaveTable; +} + +declare var webkitAudioContext: { + + new (): webkitAudioContext; + +} + +interface Oscillator extends AudioSourceNode { + + type: number; + playbackState: number; + frequency: AudioParam; + detune: AudioParam; + noteOn(when: number): void; + noteOff(when: number): void; + setWaveTable(waveTable: WaveTable): void; + +} + +interface AudioDestinationNode extends AudioNode { + + maxNumberOfChannels: number; + numberOfChannels: number; + +} + +interface AudioNode { + + connect(destination: AudioNode, output?: number, input?: number): void; + connect(destination: AudioParam, output?: number): void; + disconnect(output?: number): void; + context: webkitAudioContext; + numberOfInputs: number; + numberOfOutputs: number; + +}; + +interface AudioSourceNode extends AudioNode { + +} + + + +interface AudioParam { + + value: number; + minValue: number; + maxValue: number; + defaultValue: number; + setValueAtTime(value: number, time: number): void; + linearRampToValueAtTime(value: number, time: number): void; + exponentialRampToValueAtTime(value: number, time: number): void; + setTargetValueAtTime(targetValue: number,time: number, timeConstant: number): void; + setValueCurveAtTime(values: number[], time: number, duration: number): void; + cancelScheduledValues(startTime: number): void; + +} + +interface AudioGain extends AudioParam { + +} + +interface AudioGainNode extends AudioNode { + + gain: AudioGain; + +} + +interface DelayNode extends AudioNode { + + delayTime: AudioParam; + +} + +interface AudioBuffer { + + sampleRate: number; + length: number; + duration: number; + numberOfChannels: number; + getChannelData(channel: number): any; + +} + +interface AudioBufferSourceNode extends AudioSourceNode { + + playbackState: number; + buffer: AudioBuffer; + playbackRate: AudioParam; + loop: bool; + noteOn(when: number): void; + noteGrainOn(when: number, grainOffset: number, grainDuration: number): void; + noteOff(when: number): void; + +} + +interface MediaElementAudioSourceNode extends AudioSourceNode { + +} + +interface JavaScriptAudioNode extends AudioNode { + + onaudioprocess: EventListener; + bufferSize: number; + +} + +interface AudioProcessingEvent extends Event { + + node: JavaScriptAudioNode; + playbackTime: number; + inputBuffer: AudioBuffer; + outputBuffer: AudioBuffer; + +} + +interface AudioPannerNode extends AudioNode { + + panningModel: number; + setPosition(x: number, y: number, z: number): void; + setOrientation(x: number, y: number, z: number): void; + setVelocity(x: number, y: number, z: number): void; + distanceModel: number; + refDistance: number; + maxDistance: number; + rolloffFactor: number; + coneInnerAngle: number; + coneOuterAngle: number; + coneOuterGain: number; + distanceGain: AudioGain; + coneGain: AudioGain; + +} + +interface AudioListener { + + dopplerFactor: number; + speedOfSound: number; + setPosition(x: number, y: number, z: number): void; + setOrientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): void; + setVelocity(x: number, y: number, z: number): void; + +} + +interface RealtimeAnalyserNode extends AudioNode { + + getFloatFrequencyData(array: any): void; + getByteFrequencyData(array: any): void; + getByteTimeDomainData(array: any): void; + fftSize: number; + frequencyBinCount: number; + minDecibels: number; + maxDecibels: number; + smoothingTimeConstant: number; + +} + +interface AudioChannelSplitter extends AudioNode { + +} + +interface AudioChannelMerger extends AudioNode { + +} + +interface DynamicsCompressorNode extends AudioNode { + + threshold: AudioParam; + knee: AudioParam; + ratio: AudioParam; + reduction: AudioParam; + attack: AudioParam; + release: AudioParam; + +} + +interface BiquadFilterNode extends AudioNode { + + type: number; + frequency: AudioParam; + Q: AudioParam; + gain: AudioParam; + + getFrequencyResponse(frequencyHz: any, magResponse: any, phaseResponse: any): void; + +} + +interface WaveShaperNode extends AudioNode { + + curve: any; + +} + +interface MediaStreamAudioSourceNode extends AudioSourceNode { + + + +} + +interface ConvolverNode extends AudioNode { + + buffer: AudioBuffer; + normalize: bool; + +} + +interface WaveTable { + +} diff --git a/webaudioapi/waa-tests.ts b/webaudioapi/waa-tests.ts new file mode 100644 index 000000000..39d7549e3 --- /dev/null +++ b/webaudioapi/waa-tests.ts @@ -0,0 +1,305 @@ +// http://www.w3.org/TR/2012/WD-webaudio-20121213/ + +/// + +declare var dogBarkingBuffer: any; + +()=>{ + var context = new AudioContext(); + + function playSound() { + var source = context.createBufferSource(); + source.buffer = dogBarkingBuffer; + source.connect(context.destination); + source.start(0); + } +}; + +declare var manTalkingBuffer: any; +declare var footstepsBuffer: any; + +()=>{ + + var context = new AudioContext(); + + // Create the effects nodes. + var lowpassFilter = context.createBiquadFilter(); + var waveShaper = context.createWaveShaper(); + var panner = context.createPanner(); + var compressor = context.createDynamicsCompressor(); + var reverb = context.createConvolver(); + + // Create master wet and dry. + var masterDry = context.createGain(); + var masterWet = context.createGain(); + + // Connect final compressor to final destination. + compressor.connect(context.destination); + + // Connect master dry and wet to compressor. + masterDry.connect(compressor); + masterWet.connect(compressor); + + // Connect reverb to master wet. + reverb.connect(masterWet); + + // Create a few sources. + var source1 = context.createBufferSource(); + var source2 = context.createBufferSource(); + var source3 = context.createOscillator(); + + source1.buffer = manTalkingBuffer; + source2.buffer = footstepsBuffer; + source3.frequency.value = 440; + + // Connect source1 + var dry1 = context.createGain(); + var wet1 = context.createGain(); + source1.connect(lowpassFilter); + lowpassFilter.connect(dry1); + lowpassFilter.connect(wet1); + dry1.connect(masterDry); + wet1.connect(reverb); + + // Connect source2 + var dry2 = context.createGain(); + var wet2 = context.createGain(); + source2.connect(waveShaper); + waveShaper.connect(dry2); + waveShaper.connect(wet2); + dry2.connect(masterDry); + wet2.connect(reverb); + + // Connect source3 + var dry3 = context.createGain(); + var wet3 = context.createGain(); + source3.connect(panner); + panner.connect(dry3); + panner.connect(wet3); + dry3.connect(masterDry); + wet3.connect(reverb); + + // Start the sources now. + source1.start(0); + source2.start(0); + source3.start(0); +}; + +()=>{ + var context: AudioContext; + var compressor: DynamicsCompressorNode; + var gainNode1: GainNode; + var streamingAudioSource: MediaElementAudioSourceNode; + + // Initial setup of the "long-lived" part of the routing graph + function setupAudioContext() { + context = new AudioContext(); + + compressor = context.createDynamicsCompressor(); + gainNode1 = context.createGain(); + + // Create a streaming audio source. + var audioElement = document.getElementById('audioTagID'); + streamingAudioSource = context.createMediaElementSource(audioElement); + streamingAudioSource.connect(gainNode1); + + gainNode1.connect(compressor); + compressor.connect(context.destination); + } + + // Later in response to some user action (typically mouse or key event) + // a one-shot sound can be played. + function playSound() { + var oneShotSound = context.createBufferSource(); + oneShotSound.buffer = dogBarkingBuffer; + + // Create a filter, panner, and gain node. + var lowpass = context.createBiquadFilter(); + var panner = context.createPanner(); + var gainNode2 = context.createGain(); + + // Make connections + oneShotSound.connect(lowpass); + lowpass.connect(panner); + panner.connect(gainNode2); + gainNode2.connect(compressor); + + // Play 0.75 seconds from now (to play immediately pass in 0) + oneShotSound.start(context.currentTime + 0.75); + } +}; + + +()=>{ + var param:AudioParam; + + var t0 = 0; + var t1 = 0.1; + var t2 = 0.2; + var t3 = 0.3; + var t4 = 0.4; + var t5 = 0.6; + var t6 = 0.7; + var t7 = 1.0; + + var curveLength = 44100; + var curve = new Float32Array(curveLength); + for (var i = 0; i < curveLength; ++i) + curve[i] = Math.sin(Math.PI * i / curveLength); + + param.setValueAtTime(0.2, t0); + param.setValueAtTime(0.3, t1); + param.setValueAtTime(0.4, t2); + param.linearRampToValueAtTime(1, t3); + param.linearRampToValueAtTime(0.15, t4); + param.exponentialRampToValueAtTime(0.75, t5); + param.exponentialRampToValueAtTime(0.05, t6); + param.setValueCurveAtTime(curve, t6, t7 - t6); + +}; + +()=>{ + var param: AudioParam; + + var t0 = 0; + var t1 = 0.1; + var t2 = 0.2; + var t3 = 0.3; + var t4 = 0.4; + var t5 = 0.6; + var t6 = 0.7; + var t7 = 1.0; + + var curveLength = 44100; + var curve = new Float32Array(curveLength); + for (var i = 0; i < curveLength; ++i) + curve[i] = Math.sin(Math.PI * i / curveLength); + + param.setValueAtTime(0.2, t0); + param.setValueAtTime(0.3, t1); + param.setValueAtTime(0.4, t2); + param.linearRampToValueAtTime(1, t3); + param.linearRampToValueAtTime(0.15, t4); + param.exponentialRampToValueAtTime(0.75, t5); + param.exponentialRampToValueAtTime(0.05, t6); + param.setValueCurveAtTime(curve, t6, t7 - t6); +}; + + +()=>{ + var context: AudioContext; + var filterNode: AudioNode; + + var mediaElement = document.getElementById('mediaElementID'); + var sourceNode = context.createMediaElementSource(mediaElement); + sourceNode.connect(filterNode); +}; + +()=>{ + + // Setup routing graph + function setupRoutingGraph() { + var context = new AudioContext(); + + var compressor = context.createDynamicsCompressor(); + + // Send1 effect + var reverb = context.createConvolver(); + // Convolver impulse response may be set here or later + + // Send2 effect + var delay = context.createDelay(); + + // Connect final compressor to final destination + compressor.connect(context.destination); + + // Connect sends 1 & 2 through effects to main mixer + var s1 = context.createGain(); + reverb.connect(s1); + s1.connect(compressor); + + var s2 = context.createGain(); + delay.connect(s2); + s2.connect(compressor); + + // Create a couple of sources + var source1 = context.createBufferSource(); + var source2 = context.createBufferSource(); + source1.buffer = manTalkingBuffer; + source2.buffer = footstepsBuffer; + + // Connect source1 + var g1_1 = context.createGain(); + var g2_1 = context.createGain(); + var g3_1 = context.createGain(); + source1.connect(g1_1); + source1.connect(g2_1); + source1.connect(g3_1); + g1_1.connect(compressor); + g2_1.connect(reverb); + g3_1.connect(delay); + + // Connect source2 + var g1_2 = context.createGain(); + var g2_2 = context.createGain(); + var g3_2 = context.createGain(); + source2.connect(g1_2); + source2.connect(g2_2); + source2.connect(g3_2); + g1_2.connect(compressor); + g2_2.connect(reverb); + g3_2.connect(delay); + + // We now have explicit control over all the volumes g1_1, g2_1, ..., s1, s2 + g2_1.gain.value = 0.2; // For example, set source1 reverb gain + + // Because g2_1.gain is an "AudioParam", + // an automation curve could also be attached to it. + // A "mixing board" UI could be created in canvas or WebGL controlling these gains. + } +}; + +()=>{ + var context: AudioContext; + var compressor: DynamicsCompressorNode; + var gainNode1: GainNode; + var streamingAudioSource: MediaElementAudioSourceNode; + + // Initial setup of the "long-lived" part of the routing graph + function setupAudioContext() { + context = new AudioContext(); + + compressor = context.createDynamicsCompressor(); + gainNode1 = context.createGain(); + + // Create a streaming audio source. + var audioElement = document.getElementById('audioTagID'); + streamingAudioSource = context.createMediaElementSource(audioElement); + streamingAudioSource.connect(gainNode1); + + gainNode1.connect(compressor); + compressor.connect(context.destination); + } + + // Later in response to some user action (typically mouse or key event) + // a one-shot sound can be played. + function playSound() { + var oneShotSound = context.createBufferSource(); + oneShotSound.buffer = dogBarkingBuffer; + + // Create a filter, panner, and gain node. + var lowpass = context.createBiquadFilter(); + var panner = context.createPanner(); + var gainNode2 = context.createGain(); + + // Make connections + oneShotSound.connect(lowpass); + lowpass.connect(panner); + panner.connect(gainNode2); + gainNode2.connect(compressor); + + // Play 0.75 seconds from now (to play immediately pass in 0) + oneShotSound.start(context.currentTime + 0.75); + } +}; + diff --git a/webaudioapi/waa.d.ts b/webaudioapi/waa.d.ts index b90c4b959..be6898d39 100644 --- a/webaudioapi/waa.d.ts +++ b/webaudioapi/waa.d.ts @@ -1,247 +1,1126 @@ -// Type definitions for the Web Audio API, currently only implemented in WebKit browsers -// Conforms to the: http://www.w3.org/TR/2012/WD-webaudio-20120802/ specification -// Definitions by: Baruch Berger (https://github.com/bbss) +// Type definitions for the Web Audio API +// Project: http://www.w3.org/TR/2012/WD-webaudio-20121213/ +// Definitions by: Baruch Berger (https://github.com/bbss), Kon (http://phyzkit.net/) // Definitions: https://github.com/borisyankov/DefinitelyTyped -interface webkitAudioContext { +/** + * This interface represents a set of AudioNode objects and their connections. It allows for arbitrary routing of signals to the AudioDestinationNode (what the user ultimately hears). Nodes are created from the context and are then connected together. In most use cases, only a single AudioContext is used per document. An AudioContext is constructed as follows: + * + * var context = new AudioContext(); + */ +interface AudioContext { + /** + * An AudioDestinationNode with a single input representing the final destination for all audio (to be rendered to the audio hardware). All AudioNodes actively rendering audio will directly or indirectly connect to destination. + */ destination: AudioDestinationNode; + + /** + * The sample rate (in sample-frames per second) at which the AudioContext handles audio. It is assumed that all AudioNodes in the context run at this rate. In making this assumption, sample-rate converters or "varispeed" processors are not supported in real-time processing. + */ sampleRate: number; + + /** + * This is a time in seconds which starts at zero when the context is created and increases in real-time. All scheduled times are relative to it. This is not a "transport" time which can be started, paused, and re-positioned. It is always moving forward. A GarageBand-like timeline transport system can be very easily built on top of this (in JavaScript). This time corresponds to an ever-increasing hardware timestamp. + */ currentTime: number; + + /** + * An AudioListener which is used for 3D spatialization. + */ listener: AudioListener; + + /** + * The number of AudioBufferSourceNodes that are currently playing. + */ activeSourceCount: number; + /** + * Creates an AudioBuffer of the given size. The audio data in the buffer will be zero-initialized (silent). An exception will be thrown if the numberOfChannels or sampleRate are out-of-bounds. + * @param numberOfChannels how many channels the buffer will have. An implementation must support at least 32 channels. + * @param length the size of the buffer in sample-frames. + * @param sampleRate the sample-rate of the linear PCM audio data in the buffer in sample-frames per second. An implementation must support sample-rates in at least the range 22050 to 96000. + */ createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer; + + /** + * Creates an AudioBuffer given the audio file data contained in the ArrayBuffer. The ArrayBuffer can, for example, be loaded from an XMLHttpRequest's response attribute after setting the responseType to "arraybuffer". Audio file data can be in any of the formats supported by the audio element. + * The following steps must be performed: + * 1. Decode the encoded buffer from the AudioBuffer into linear PCM. If a decoding error is encountered due to the audio format not being recognized or supported, or because of corrupted/unexpected/inconsistent data then return NULL (and these steps will be terminated). + * 2. If mixToMono is true, then mixdown the decoded linear PCM data to mono. + * 3. Take the decoded (possibly mixed-down) linear PCM audio data, and resample it to the sample-rate of the AudioContext if it is different from the sample-rate of buffer. The final result will be stored in an AudioBuffer and returned as the result of this method. + * @param buffer the audio file data (for example from a .wav file). + * @param mixToMono if a mixdown to mono will be performed. Normally, this would not be set. + */ createBuffer(buffer: ArrayBuffer, mixToMono: bool): AudioBuffer; + /** + * Asynchronously decodes the audio file data contained in the ArrayBuffer. The ArrayBuffer can, for example, be loaded from an XMLHttpRequest's response attribute after setting the responseType to "arraybuffer". Audio file data can be in any of the formats supported by the audio element. + * The decodeAudioData() method is preferred over the createBuffer() from ArrayBuffer method because it is asynchronous and does not block the main JavaScript thread. + * + * The following steps must be performed: + * 1. Temporarily neuter the audioData ArrayBuffer in such a way that JavaScript code may not access or modify the data. + * 2. Queue a decoding operation to be performed on another thread. + * 3. The decoding thread will attempt to decode the encoded audioData into linear PCM. If a decoding error is encountered due to the audio format not being recognized or supported, or because of corrupted/unexpected/inconsistent data then the audioData neutered state will be restored to normal and the errorCallback will be scheduled to run on the main thread's event loop and these steps will be terminated. + * 4. The decoding thread will take the result, representing the decoded linear PCM audio data, and resample it to the sample-rate of the AudioContext if it is different from the sample-rate of audioData. The final result (after possibly sample-rate converting) will be stored in an AudioBuffer. + * 5. The audioData neutered state will be restored to normal + * 6. The successCallback function will be scheduled to run on the main thread's event loop given the AudioBuffer from step (4) as an argument. + * + * @param ArrayBuffer containing audio file data. + * @param callback function which will be invoked when the decoding is finished. The single argument to this callback is an AudioBuffer representing the decoded PCM audio data. + * @param callback function which will be invoked if there is an error decoding the audio file data. + */ decodeAudioData(audioData: ArrayBuffer, successCallback: any, errorCallback?: any): void; - + + /** + * Creates an AudioBufferSourceNode. + */ createBufferSource(): AudioBufferSourceNode; + /** + * Creates a MediaElementAudioSourceNode given an HTMLMediaElement. As a consequence of calling this method, audio playback from the HTMLMediaElement will be re-routed into the processing graph of the AudioContext. + */ createMediaElementSource(mediaElement: HTMLMediaElement): MediaElementAudioSourceNode; - + + /** + * Creates a MediaStreamAudioSourceNode given a MediaStream. As a consequence of calling this method, audio playback from the MediaStream will be re-routed into the processing graph of the AudioContext. + */ createMediaStreamSource(mediaStream: any): MediaStreamAudioSourceNode; - createAnalyser(): RealtimeAnalyserNode; - createGainNode(): AudioGainNode; - createDelayNode(maxDelayTime?: number): DelayNode; - createBiquadFilter(): BiquadFilterNode; - createPanner():AudioPannerNode; - createConvolver(): ConvolverNode; + /** + * Creates a ScriptProcessorNode for direct audio processing using JavaScript. An exception will be thrown if bufferSize or numberOfInputChannels or numberOfOutputChannels are outside the valid range. + * It is invalid for both numberOfInputChannels and numberOfOutputChannels to be zero. + * @param bufferSize the buffer size in units of sample-frames. It must be one of the following values: 256, 512, 1024, 2048, 4096, 8192, 16384. This value controls how frequently the onaudioprocess event handler is called and how many sample-frames need to be processed each call. Lower values for bufferSize will result in a lower (better) latency. Higher values will be necessary to avoid audio breakup and glitches. The value chosen must carefully balance between latency and audio quality. + * @param numberOfInputChannels (defaults to 2) the number of channels for this node's input. Values of up to 32 must be supported. + * @param numberOfOutputChannels (defaults to 2) the number of channels for this node's output. Values of up to 32 must be supported. + */ + createScriptProcessor(bufferSize: number, numberOfInputChannels?: number, numberOfOutputChannels?: number): ScriptProcessorNode; - createChannelSplitter(numberOfOutputs?: number):AudioChannelSplitter; - createChannelMerger(numberOfInputs?: number): AudioChannelMerger; + /** + * Creates a AnalyserNode. + */ + createAnalyser(): AnalyserNode; + /** + * Creates a GainNode. + */ + createGain(): GainNode; + + /** + * Creates a DelayNode representing a variable delay line. The initial default delay time will be 0 seconds. + * @param maxDelayTime the maximum delay time in seconds allowed for the delay line. If specified, this value must be greater than zero and less than three minutes or a NOT_SUPPORTED_ERR exception will be thrown. + */ + createDelay(maxDelayTime?: number): DelayNode; + //createDelayNode(maxDelayTime?: number): DelayNode; + + /** + * Creates a BiquadFilterNode representing a second order filter which can be configured as one of several common filter types. + */ + createBiquadFilter(): BiquadFilterNode; + + /** + * Creates a WaveShaperNode representing a non-linear distortion. + */ + createWaveShaper(): WaveShaperNode; + + /** + * Creates an PannerNode. + */ + createPanner(): PannerNode; + + /** + * Creates a ConvolverNode. + */ + createConvolver(): ConvolverNode; + + /** + * Creates an ChannelSplitterNode representing a channel splitter. An exception will be thrown for invalid parameter values. + * @param numberOfOutputs the number of outputs. Values of up to 32 must be supported. If not specified, then 6 will be used. + */ + createChannelSplitter(numberOfOutputs?: number): ChannelSplitterNode; + + /** + * Creates an ChannelMergerNode representing a channel merger. An exception will be thrown for invalid parameter values. + * @param numberOfInputs the number of inputs. Values of up to 32 must be supported. If not specified, then 6 will be used. + */ + createChannelMerger(numberOfInputs?: number): ChannelMergerNode; + + /** + * Creates a DynamicsCompressorNode. + */ createDynamicsCompressor(): DynamicsCompressorNode; - createOscillator(): Oscillator; + /** + * Creates an OscillatorNode. + */ + createOscillator(): OscillatorNode; + + /** + * Creates a WaveTable representing a waveform containing arbitrary harmonic content. The real and imag parameters must be of type Float32Array of equal lengths greater than zero and less than or equal to 4096 or an exception will be thrown. These parameters specify the Fourier coefficients of a Fourier series representing the partials of a periodic waveform. The created WaveTable will be used with an OscillatorNode and will represent a normalized time-domain waveform having maximum absolute peak value of 1. Another way of saying this is that the generated waveform of an OscillatorNode will have maximum peak value at 0dBFS. Conveniently, this corresponds to the full-range of the signal values used by the Web Audio API. Because the WaveTable will be normalized on creation, the real and imag parameters represent relative values. + * @param real an array of cosine terms (traditionally the A terms). In audio terminology, the first element (index 0) is the DC-offset of the periodic waveform and is usually set to zero. The second element (index 1) represents the fundamental frequency. The third element represents the first overtone, and so on. + * @param imag an array of sine terms (traditionally the B terms). The first element (index 0) should be set to zero (and will be ignored) since this term does not exist in the Fourier series. The second element (index 1) represents the fundamental frequency. The third element represents the first overtone, and so on. + */ createWaveTable(real: any,imag: any): WaveTable; } +declare var AudioContext: { + new (): AudioContext; +} + declare var webkitAudioContext: { - - new (): webkitAudioContext; - + new (): AudioContext; } -interface Oscillator extends AudioSourceNode { - - type: number; - playbackState: number; - frequency: AudioParam; - detune: AudioParam; - noteOn(when: number): void; - noteOff(when: number): void; - setWaveTable(waveTable: WaveTable): void; - +interface OfflineRenderSuccessCallback{ + (renderedData: AudioBuffer): void; } -interface AudioDestinationNode extends AudioNode { - - maxNumberOfChannels: number; - numberOfChannels: number; - +/** + * OfflineAudioContext is a particular type of AudioContext for rendering/mixing-down (potentially) faster than real-time. It does not render to the audio hardware, but instead renders as quickly as possible, calling a render callback function upon completion with the result provided as an AudioBuffer. It is constructed by specifying the numberOfChannels, length, and sampleRate as follows: + * + * var offlineContext = new OfflineAudioContext(unsigned long numberOfChannels, unsigned long length, float sampleRate); + */ +interface OfflineAudioContext extends AudioContext{ + constructor(); + startRendering(): void; + oncomplete: OfflineRenderSuccessCallback; } +/** + * AudioNodes are the building blocks of an AudioContext. This interface represents audio sources, the audio destination, and intermediate processing modules. These modules can be connected together to form processing graphs for rendering audio to the audio hardware. Each node can have inputs and/or outputs. An AudioSourceNode has no inputs and a single output. An AudioDestinationNode has one input and no outputs and represents the final destination to the audio hardware. Most processing nodes such as filters will have one input and one output. Each type of AudioNode differs in the details of how it processes or synthesizes audio. But, in general, AudioNodes will process its inputs (if it has any), and generate audio for its outputs (if it has any). + * + * An output may connect to one or more AudioNode inputs, thus fanout is supported. An input may be connected from one or more AudioNode outputs, thus fanin is supported. + * + * In order to handle this fanin, any AudioNode with inputs performs an up-mixing of all connections for each input: + * + * 1. Calculate N: the maximum number of channels of all the connections to the input. For example, if an input has a mono connection and a stereo connection then this number will be 2. + * 2. For each connection to the input, up-mix to N channels. + * 3. Mix together all the up-mixed streams from (2). This is a straight-forward mixing together of each of the corresponding channels from each connection. + * + * Please see Mixer Gain Structure for more informative details. + * + * For performance reasons, practical implementations will need to use block processing, with each AudioNode processing a fixed number of sample-frames of size block-size. In order to get uniform behavior across implementations, we will define this value explicitly. block-size is defined to be 128 sample-frames which corresponds to roughly 3ms at a sample-rate of 44.1KHz. + */ interface AudioNode { - + /** + * Connects the AudioNode to another AudioNode. + * + * It is possible to connect an AudioNode output to more than one input with multiple calls to connect(). Thus, "fanout" is supported. + * + * It is possible to connect an AudioNode to another AudioNode which creates a cycle. In other words, an AudioNode may connect to another AudioNode, which in turn connects back to the first AudioNode. This is allowed only if there is at least one DelayNode in the cycle or an exception will be thrown. + * + * There can only be one connection between a given output of one specific node and a given input of another specific node. Multiple connections with the same termini are ignored. For example: + * + * nodeA.connect(nodeB); + * nodeA.connect(nodeB); + * + * will have the same effect as + * + * nodeA.connect(nodeB); + * + * @param destination the AudioNode to connect to. + * @param output an index describing which output of the AudioNode from which to connect. An out-of-bound value throws an exception. + * @param input an index describing which input of the destination AudioNode to connect to. An out-of-bound value throws an exception. + */ connect(destination: AudioNode, output?: number, input?: number): void; + + /** + * Connects the AudioNode to an AudioParam, controlling the parameter value with an audio-rate signal. + * + * It is possible to connect an AudioNode output to more than one AudioParam with multiple calls to connect(). Thus, "fanout" is supported. + * + * It is possible to connect more than one AudioNode output to a single AudioParam with multiple calls to connect(). Thus, "fanin" is supported. + * + * An AudioParam will take the rendered audio data from any AudioNode output connected to it and convert it to mono by down-mixing if it is not already mono, then mix it together with other such outputs and finally will mix with the intrinsic parameter value (the value the AudioParam would normally have without any audio connections), including any timeline changes scheduled for the parameter. + * + * There can only be one connection between a given output of one specific node and a specific AudioParam. Multiple connections with the same termini are ignored. For example: + * + * nodeA.connect(param); + * nodeA.connect(param); + * + * will have the same effect as + * + * nodeA.connect(param); + * + * @param destination the AudioParam to connect to. + * @param output an index describing which output of the AudioNode from which to connect. An out-of-bound value throws an exception. + */ connect(destination: AudioParam, output?: number): void; + + /** + * Disconnects an AudioNode's output. + * @param output an index describing which output of the AudioNode to disconnect. An out-of-bound value throws an exception. + */ disconnect(output?: number): void; - context: webkitAudioContext; + + /** + * The AudioContext which owns this AudioNode. + */ + context: AudioContext; + + /** + * The number of inputs feeding into the AudioNode. This will be 0 for an AudioSourceNode. + */ numberOfInputs: number; + + /** + * The number of outputs coming out of the AudioNode. This will be 0 for an AudioDestinationNode. + */ numberOfOutputs: number; +} -}; +/** + * This is an abstract interface representing an audio source, an AudioNode which has no inputs and a single output: + * + * numberOfInputs : 0 + * numberOfOutputs : 1 + * + * Subclasses of AudioSourceNode will implement specific types of audio sources. + */ interface AudioSourceNode extends AudioNode { } +/** + * This is an AudioNode representing the final audio destination and is what the user will ultimately hear. It can be considered as an audio output device which is connected to speakers. All rendered audio to be heard will be routed to this node, a "terminal" node in the AudioContext's routing graph. There is only a single AudioDestinationNode per AudioContext, provided through the destination attribute of AudioContext. + * + * numberOfInputs : 1 + * numberOfOutputs : 0 + */ +interface AudioDestinationNode extends AudioNode { + /** + * The maximum number of channels that the numberOfChannels attribute can be set to. An AudioDestinationNode representing the audio hardware end-point (the normal case) can potentially output more than 2 channels of audio if the audio hardware is multi-channel. maxNumberOfChannels is the maximum number of channels that this hardware is capable of supporting. If this value is 0, then this indicates that maxNumberOfChannels may not be changed. This will be the case for an AudioDestinationNode in an OfflineAudioContext. + * @readonly + */ + maxNumberOfChannels: number; - -interface AudioParam { - - value: number; - minValue: number; - maxValue: number; - defaultValue: number; - setValueAtTime(value: number, time: number): void; - linearRampToValueAtTime(value: number, time: number): void; - exponentialRampToValueAtTime(value: number, time: number): void; - setTargetValueAtTime(targetValue: number,time: number, timeConstant: number): void; - setValueCurveAtTime(values: number[], time: number, duration: number): void; - cancelScheduledValues(startTime: number): void; - -} - -interface AudioGain extends AudioParam { - -} - -interface AudioGainNode extends AudioNode { - - gain: AudioGain; - -} - -interface DelayNode extends AudioNode { - - delayTime: AudioParam; - -} - -interface AudioBuffer { - - sampleRate: number; - length: number; - duration: number; + /** + * The number of channels of the destination's input. This value will default to 2, and may be set to any non-zero value less than or equal to maxNumberOfChannels. An exception will be thrown if this value is not within the valid range. Giving a concrete example, if the audio hardware supports 8-channel output, then we may set numberOfChannels to 8, and render 8-channels of output. + */ numberOfChannels: number; - getChannelData(channel: number): any; +} + +/** + * AudioParam controls an individual aspect of an AudioNode's functioning, such as volume. The parameter can be set immediately to a particular value using the "value" attribute. Or, value changes can be scheduled to happen at very precise times (in the coordinate system of AudioContext.currentTime), for envelopes, volume fades, LFOs, filter sweeps, grain windows, etc. In this way, arbitrary timeline-based automation curves can be set on any AudioParam. Additionally, audio signals from the outputs of AudioNodes can be connected to an AudioParam, summing with the intrinsic parameter value. + * + * Some synthesis and processing AudioNodes have AudioParams as attributes whose values must be taken into account on a per-audio-sample basis. For other AudioParams, sample-accuracy is not important and the value changes can be sampled more coarsely. Each individual AudioParam will specify that it is either an a-rate parameter which means that its values must be taken into account on a per-audio-sample basis, or it is a k-rate parameter. + * + * Implementations must use block processing, with each AudioNode processing 128 sample-frames in each block. + * + * For each 128 sample-frame block, the value of a k-rate parameter must be sampled at the time of the very first sample-frame, and that value must be used for the entire block. a-rate parameters must be sampled for each sample-frame of the block. + */ +interface AudioParam { + /** + * The parameter's floating-point value. This attribute is initialized to the defaultValue. If a value is set outside the allowable range described by minValue and maxValue no exception is thrown, because these limits are just nominal and may be exceeded. If a value is set during a time when there are any automation events scheduled then it will be ignored and no exception will be thrown. + */ + value: number; + + /** + * Nominal minimum value. This attribute is informational and value may be set lower than this value. + */ + minValue: number; + + /** + * Nominal maximum value. This attribute is informational and value may be set higher than this value. + */ + maxValue: number; + + /** + * Initial value for the value attribute + */ + defaultValue: number; + + /** + * Schedules a parameter value change at the given time. + * + * If there are no more events after this SetValue event, then for t >= startTime, v(t) = value. In other words, the value will remain constant. + * + * If the next event (having time T1) after this SetValue event is not of type LinearRampToValue or ExponentialRampToValue, then, for t: startTime <= t < T1, v(t) = value. In other words, the value will remain constant during this time interval, allowing the creation of "step" functions. + * + * If the next event after this SetValue event is of type LinearRampToValue or ExponentialRampToValue then please see details below. + * + * @param value the value the parameter will change to at the given time + * @param startTime parameter is the time in the same time coordinate system as AudioContext.currentTime. + */ + setValueAtTime(value: number, startTime: number): void; + + /** + * Schedules a linear continuous change in parameter value from the previous scheduled parameter value to the given value. + * + * The value during the time interval T0 <= t < T1 (where T0 is the time of the previous event and T1 is the endTime parameter passed into this method) will be calculated as: + * + * v(t) = V0 + (V1 - V0) * ((t - T0) / (T1 - T0)) + * + * Where V0 is the value at the time T0 and V1 is the value parameter passed into this method. + * + * If there are no more events after this LinearRampToValue event then for t >= T1, v(t) = V1 + * + * @param value the value the parameter will linearly ramp to at the given time. + * @param endTime the time in the same time coordinate system as AudioContext.currentTime. + */ + linearRampToValueAtTime(value: number, time: number): void; + + /** + * Schedules an exponential continuous change in parameter value from the previous scheduled parameter value to the given value. Parameters representing filter frequencies and playback rate are best changed exponentially because of the way humans perceive sound. + * + * The value during the time interval T0 <= t < T1 (where T0 is the time of the previous event and T1 is the endTime parameter passed into this method) will be calculated as: + * + * v(t) = V0 * (V1 / V0) ^ ((t - T0) / (T1 - T0)) + * + * Where V0 is the value at the time T0 and V1 is the value parameter passed into this method. + * + * If there are no more events after this ExponentialRampToValue event then for t >= T1, v(t) = V1 + * + * @param value the value the parameter will exponentially ramp to at the given time. An exception will be thrown if this value is less than or equal to 0, or if the value at the time of the previous event is less than or equal to 0. + * @param endTime the time in the same time coordinate system as AudioContext.currentTime. + */ + exponentialRampToValueAtTime(value: number, endTime: number): void; + + /** + * Start exponentially approaching the target value at the given time with a rate having the given time constant. Among other uses, this is useful for implementing the "decay" and "release" portions of an ADSR envelope. Please note that the parameter value does not immediately change to the target value at the given time, but instead gradually changes to the target value. + * + * More precisely, timeConstant is the time it takes a first-order linear continuous time-invariant system to reach the value 1 - 1/e (around 63.2%) given a step input response (transition from 0 to 1 value). + * + * During the time interval: T0 <= t < T1, where T0 is the startTime parameter and T1 represents the time of the event following this event (or infinity if there are no following events): + * + * v(t) = V1 + (V0 - V1) * exp(-(t - T0) / timeConstant) + * + * Where V0 is the initial value (the .value attribute) at T0 (the startTime parameter) and V1 is equal to the target parameter. + * + * @param target the value the parameter will start changing to at the given time. + * @param startTime the time in the same time coordinate system as AudioContext.currentTime. + * @param timeConstant the time-constant value of first-order filter (exponential) approach to the target value. The larger this value is, the slower the transition will be. + */ + setTargetValueAtTime(target: number, startTime: number, timeConstant: number): void; + + /** + * Sets an array of arbitrary parameter values starting at the given time for the given duration. The number of values will be scaled to fit into the desired duration. + * + * During the time interval: startTime <= t < startTime + duration, values will be calculated: + * + * v(t) = values[N * (t - startTime) / duration], where N is the length of the values array. + * + * After the end of the curve time interval (t >= startTime + duration), the value will remain constant at the final curve value, until there is another automation event (if any). + * + * @param values a Float32Array representing a parameter value curve. These values will apply starting at the given time and lasting for the given duration. + * @param startTime the time in the same time coordinate system as AudioContext.currentTime. + * @param duration the amount of time in seconds (after the time parameter) where values will be calculated according to the values parameter.. + * + */ + setValueCurveAtTime(values: Float32Array, time: number, duration: number): void; + + /** + * Cancels all scheduled parameter changes with times greater than or equal to startTime. + * + * @param startTime the starting time at and after which any previously scheduled parameter changes will be cancelled. It is a time in the same time coordinate system as AudioContext.currentTime. + */ + cancelScheduledValues(startTime: number): void; +} + +/** + * Changing the gain of an audio signal is a fundamental operation in audio applications. The GainNode is one of the building blocks for creating mixers. This interface is an AudioNode with a single input and single output: + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + * + * which multiplies the input audio signal by the (possibly time-varying) gain attribute, copying the result to the output. By default, it will take the input and pass it through to the output unchanged, which represents a constant gain change of 1. + * + * As with other AudioParams, the gain parameter represents a mapping from time (in the coordinate system of AudioContext.currentTime) to floating-point value. Every PCM audio sample in the input is multiplied by the gain parameter's value for the specific time corresponding to that audio sample. This multiplied value represents the PCM audio sample for the output. + * + * The number of channels of the output will always equal the number of channels of the input, with each channel of the input being multiplied by the gain values and being copied into the corresponding channel of the output. + * + * The implementation must make gain changes to the audio stream smoothly, without introducing noticeable clicks or glitches. This process is called "de-zippering". + */ +interface GainNode extends AudioNode { + /** + * Represents the amount of gain to apply. Its default value is 1 (no gain change). The nominal minValue is 0, but may be set negative for phase inversion. The nominal maxValue is 1, but higher values are allowed (no exception thrown).This parameter is a-rate + */ + gain: AudioParam; +} + +/** + * A delay-line is a fundamental building block in audio applications. This interface is an AudioNode with a single input and single output: + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + * + * which delays the incoming audio signal by a certain amount. The default amount is 0 seconds (no delay). When the delay time is changed, the implementation must make the transition smoothly, without introducing noticeable clicks or glitches to the audio stream. + */ +interface DelayNode extends AudioNode { + /** + * An AudioParam object representing the amount of delay (in seconds) to apply. The default value (delayTime.value) is 0 (no delay). The minimum value is 0 and the maximum value is determined by the maxDelayTime argument to the AudioContext method createDelay. This parameter is k-rate + */ + delayTime: AudioParam; +} + +/** + * This interface represents a memory-resident audio asset (for one-shot sounds and other short audio clips). Its format is non-interleaved IEEE 32-bit linear PCM with a nominal range of -1 -> +1. It can contain one or more channels. It is analogous to a WebGL texture. Typically, it would be expected that the length of the PCM data would be fairly short (usually somewhat less than a minute). For longer sounds, such as music soundtracks, streaming should be used with the audio element and MediaElementAudioSourceNode. + * + * An AudioBuffer may be used by one or more AudioContexts. + */ +interface AudioBuffer { + /** + * The sample-rate for the PCM audio data in samples per second. + * @readonly + */ + sampleRate: number; + + /** + * Length of the PCM audio data in sample-frames. + * @readonly + */ + length: number; + + /** + * Duration of the PCM audio data in seconds. + * @readonly + */ + duration: number; + + /** + * The number of discrete audio channels. + * @readonly + */ + numberOfChannels: number; + + /** + * Returns the Float32Array representing the PCM audio data for the specific channel. + * + * The channel parameter is an index representing the particular channel to get data for. An index value of 0 represents the first channel. This index value MUST be less than numberOfChannels or an exception will be thrown. + */ + getChannelData(channel: number): Float32Array; } +/** + * This interface represents an audio source from an in-memory audio asset in an AudioBuffer. It generally will be used for short audio assets which require a high degree of scheduling flexibility (can playback in rhythmically perfect ways). The playback state of an AudioBufferSourceNode goes through distinct stages during its lifetime in this order: UNSCHEDULED_STATE, SCHEDULED_STATE, PLAYING_STATE, FINISHED_STATE. The start() method causes a transition from the UNSCHEDULED_STATE to SCHEDULED_STATE. Depending on the time argument passed to start(), a transition is made from the SCHEDULED_STATE to PLAYING_STATE, at which time sound is first generated. Following this, a transition from the PLAYING_STATE to FINISHED_STATE happens when either the buffer's audio data has been completely played (if the loop attribute is false), or when the stop() method has been called and the specified time has been reached. Please see more details in the start() and stop() description. Once an AudioBufferSourceNode has reached the FINISHED state it will no longer emit any sound. Thus start() and stop() may not be issued multiple times for a given AudioBufferSourceNode. + * + * numberOfInputs : 0 + * numberOfOutputs : 1 + */ interface AudioBufferSourceNode extends AudioSourceNode { + /** + * The playback state, initialized to UNSCHEDULED_STATE. + */ playbackState: number; + + /** + * Represents the audio asset to be played. + */ buffer: AudioBuffer; + + /** + * The speed at which to render the audio stream. The default playbackRate.value is 1. This parameter is a-rate + */ playbackRate: AudioParam; + + /** + * Indicates if the audio data should play in a loop. The default value is false. + */ loop: bool; - noteOn(when: number): void; - noteGrainOn(when: number, grainOffset: number, grainDuration: number): void; - noteOff(when: number): void; + /** + * Schedules a sound to playback at an exact time. + * + * @param when time (in seconds) the sound should start playing. It is in the same time coordinate system as AudioContext.currentTime. If 0 is passed in for this value or if the value is less than currentTime, then the sound will start playing immediately. start may only be called one time and must be called before stop is called or an exception will be thrown. + * @param offset the offset time in the buffer (in seconds) where playback will begin. This parameter is optional with a default value of 0 (playing back from the beginning of the buffer). + * @param duration the duration of the portion (in seconds) to be played. This parameter is optional, with the default value equal to the total duration of the AudioBuffer minus the offset parameter. Thus if neither offset nor duration are specified then the implied duration is the total duration of the AudioBuffer. + */ + start(when: number, offset?: number, duration?: number): void; + + /** + * Schedules a sound to stop playback at an exact time. Please see deprecation section for the old method name. + * + * The when parameter describes at what time (in seconds) the sound should stop playing. It is in the same time coordinate system as AudioContext.currentTime. If 0 is passed in for this value or if the value is less than currentTime, then the sound will stop playing immediately. stop must only be called one time and only after a call to start or stop, or an exception will be thrown. + */ + stop(when: number): void; } +/* + * This interface represents an audio source from an audio or video element. + * + * numberOfInputs : 0 + * numberOfOutputs : 1 + */ interface MediaElementAudioSourceNode extends AudioSourceNode { - } -interface JavaScriptAudioNode extends AudioNode { - +/** + * This interface is an AudioNode which can generate, process, or analyse audio directly using JavaScript. + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + * + * The ScriptProcessorNode is constructed with a bufferSize which must be one of the following values: 256, 512, 1024, 2048, 4096, 8192, 16384. This value controls how frequently the onaudioprocess event handler is called and how many sample-frames need to be processed each call. Lower numbers for bufferSize will result in a lower (better) latency. Higher numbers will be necessary to avoid audio breakup and glitches. The value chosen must carefully balance between latency and audio quality. + * + * numberOfInputChannels and numberOfOutputChannels determine the number of input and output channels. It is invalid for both numberOfInputChannels and numberOfOutputChannels to be zero. + * + * var node = context.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels); + */ +interface ScriptProcessorNode extends AudioNode { + /** + * An event listener which is called periodically for audio processing. An event of type AudioProcessingEvent will be passed to the event handler. + */ onaudioprocess: EventListener; + + /** + * The size of the buffer (in sample-frames) which needs to be processed each time onprocessaudio is called. Legal values are (256, 512, 1024, 2048, 4096, 8192, 16384). + */ bufferSize: number; - } +/** + * This interface is a type of Event which is passed to the onaudioprocess event handler used by ScriptProcessorNode. + * + * The event handler processes audio from the input (if any) by accessing the audio data from the inputBuffer attribute. The audio data which is the result of the processing (or the synthesized data if there are no inputs) is then placed into the outputBuffer. + */ interface AudioProcessingEvent extends Event { - - node: JavaScriptAudioNode; - playbackTime: number; - inputBuffer: AudioBuffer; - outputBuffer: AudioBuffer; - -} - -interface AudioPannerNode extends AudioNode { - - panningModel: number; - setPosition(x: number, y: number, z: number): void; - setOrientation(x: number, y: number, z: number): void; - setVelocity(x: number, y: number, z: number): void; - distanceModel: number; - refDistance: number; - maxDistance: number; - rolloffFactor: number; - coneInnerAngle: number; - coneOuterAngle: number; - coneOuterGain: number; - distanceGain: AudioGain; - coneGain: AudioGain; - -} - -interface AudioListener { - - dopplerFactor: number; - speedOfSound: number; - setPosition(x: number, y: number, z: number): void; - setOrientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): void; - setVelocity(x: number, y: number, z: number): void; - -} - -interface RealtimeAnalyserNode extends AudioNode { + /** + * The ScriptProcessorNode associated with this processing event. + */ + node: ScriptProcessorNode; + /** + * The time when the audio will be played in the same time coordinate system as AudioContext.currentTime. playbackTime allows for very tight synchronization between processing directly in JavaScript with the other events in the context's rendering graph. + */ + playbackTime: number; + + /** + * An AudioBuffer containing the input audio data. It will have a number of channels equal to the numberOfInputChannels parameter of the createScriptProcessor() method. This AudioBuffer is only valid while in the scope of the onaudioprocess function. Its values will be meaningless outside of this scope. + */ + inputBuffer: AudioBuffer; + + /** + * An AudioBuffer where the output audio data should be written. It will have a number of channels equal to the numberOfOutputChannels parameter of the createScriptProcessor() method. Script code within the scope of the onaudioprocess function is expected to modify the Float32Array arrays representing channel data in this AudioBuffer. Any script modifications to this AudioBuffer outside of this scope will not produce any audible effects. + */ + outputBuffer: AudioBuffer; +} + +enum PanningModelType { + /** + * A simple and efficient spatialization algorithm using equal-power panning. + */ + equalpower, + + /** + * A higher quality spatialization algorithm using a convolution with measured impulse responses from human subjects. This panning method renders stereo output. + */ + HRTF, + + /** + * An algorithm which spatializes multi-channel audio using sound field algorithms. + */ + soundfield +} + +enum DistanceModelType { + /** + * A linear distance model which calculates distanceGain according to: + * 1 - rolloffFactor * (distance - refDistance) / (maxDistance - refDistance) + */ + linear, + + /** + * An inverse distance model which calculates distanceGain according to: + * refDistance / (refDistance + rolloffFactor * (distance - refDistance)) + */ + inverse, + + /** + * An exponential distance model which calculates distanceGain according to: + * pow(distance / refDistance, -rolloffFactor) + */ + exponential +} + +/** + * This interface represents a processing node which positions / spatializes an incoming audio stream in three-dimensional space. The spatialization is in relation to the AudioContext's AudioListener (listener attribute). + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + * + * The audio stream from the input will be either mono or stereo, depending on the connection(s) to the input. + * + * The output of this node is hard-coded to stereo (2 channels) and currently cannot be configured. + */ +interface PannerNode extends AudioNode { + /** + * Determines which spatialization algorithm will be used to position the audio in 3D space. The default is "HRTF". + */ + panningModel: PanningModelType; + + /** + * Sets the position of the audio source relative to the listener attribute. A 3D cartesian coordinate system is used. + * + * The default value is (0,0,0) + * + * @param x the x coordinates in 3D space. + * @param y the y coordinates in 3D space. + * @param z the z coordinates in 3D space. + */ + setPosition(x: number, y: number, z: number): void; + + /** + * Describes which direction the audio source is pointing in the 3D cartesian coordinate space. Depending on how directional the sound is (controlled by the cone attributes), a sound pointing away from the listener can be very quiet or completely silent. + * + * The default value is (1,0,0) + * + * @param x + * @param y + * @param z + */ + setOrientation(x: number, y: number, z: number): void; + + /** + * Sets the velocity vector of the audio source. This vector controls both the direction of travel and the speed in 3D space. This velocity relative to the listener's velocity is used to determine how much doppler shift (pitch change) to apply. The units used for this vector is meters / second and is independent of the units used for position and orientation vectors. + * + * The default value is (0,0,0) + * + * @param x a direction vector indicating direction of travel and intensity. + * @param y + * @param z + */ + setVelocity(x: number, y: number, z: number): void; + + /** + * Determines which algorithm will be used to reduce the volume of an audio source as it moves away from the listener. The default is "inverse". + */ + distanceModel: DistanceModelType; + + /** + * A reference distance for reducing volume as source move further from the listener. The default value is 1. + */ + refDistance: number; + + /** + * The maximum distance between source and listener, after which the volume will not be reduced any further. The default value is 10000. + */ + maxDistance: number; + + /** + * Describes how quickly the volume is reduced as source moves away from listener. The default value is 1. + */ + rolloffFactor: number; + + /** + * A parameter for directional audio sources, this is an angle, inside of which there will be no volume reduction. The default value is 360. + */ + coneInnerAngle: number; + + /** + * A parameter for directional audio sources, this is an angle, outside of which the volume will be reduced to a constant value of coneOuterGain. The default value is 360. + */ + coneOuterAngle: number; + + /** + * A parameter for directional audio sources, this is the amount of volume reduction outside of the coneOuterAngle. The default value is 0. + */ + coneOuterGain: number; +} + +/** + * This interface represents the position and orientation of the person listening to the audio scene. All PannerNode objects spatialize in relation to the AudioContext's listener. See this section for more details about spatialization. + */ +interface AudioListener { + /** + * A constant used to determine the amount of pitch shift to use when rendering a doppler effect. The default value is 1. + */ + dopplerFactor: number; + + /** + * The speed of sound used for calculating doppler shift. The default value is 343.3 meters / second. + */ + speedOfSound: number; + + /** + * Sets the position of the listener in a 3D cartesian coordinate space. PannerNode objects use this position relative to individual audio sources for spatialization. + * + * The default value is (0,0,0) + * + * @param x + * @param y + * @param z + */ + setPosition(x: number, y: number, z: number): void; + + /** + * Describes which direction the listener is pointing in the 3D cartesian coordinate space. Both a front vector and an up vector are provided. In simple human terms, the front vector represents which direction the person's nose is pointing. The up vector represents the direction the top of a person's head is pointing. These values are expected to be linearly independent (at right angles to each other). For normative requirements of how these values are to be interpreted, see the spatialization section. + * + * @param x x coordinate of a front direction vector in 3D space, with the default value being 0 + * @param y y coordinate of a front direction vector in 3D space, with the default value being 0 + * @param z z coordinate of a front direction vector in 3D space, with the default value being -1 + * @param xUp x coodinate of an up direction vector in 3D space, with the default value being 0 + * @param yUp y coodinate of an up direction vector in 3D space, with the default value being 1 + * @param zUp z coodinate of an up direction vector in 3D space, with the default value being 0 + */ + setOrientation(x: number, y: number, z: number, xUp: number, yUp: number, zUp: number): void; + + /** + * Sets the velocity vector of the listener. This vector controls both the direction of travel and the speed in 3D space. This velocity relative to an audio source's velocity is used to determine how much doppler shift (pitch change) to apply. The units used for this vector is meters / second and is independent of the units used for position and orientation vectors. + * + * @param x x coordinate of a direction vector indicating direction of travel and intensity. The default value is 0 + * @param y y coordinate of a direction vector indicating direction of travel and intensity. The default value is 0 + * @param z z coordinate of a direction vector indicating direction of travel and intensity. The default value is 0 + */ + setVelocity(x: number, y: number, z: number): void; +} + + +/** + * This interface represents a processing node which applies a linear convolution effect given an impulse response. Normative requirements for multi-channel convolution matrixing are described [here](http://www.w3.org/TR/2012/WD-webaudio-20121213/#Convolution-reverb-effect). + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + */ +interface ConvolverNode extends AudioNode { + /** + * A mono, stereo, or 4-channel AudioBuffer containing the (possibly multi-channel) impulse response used by the ConvolverNode. At the time when this attribute is set, the buffer and the state of the normalize attribute will be used to configure the ConvolverNode with this impulse response having the given normalization. + */ + buffer: AudioBuffer; + + /** + * Controls whether the impulse response from the buffer will be scaled by an equal-power normalization when the buffer atttribute is set. Its default value is true in order to achieve a more uniform output level from the convolver when loaded with diverse impulse responses. If normalize is set to false, then the convolution will be rendered with no pre-processing/scaling of the impulse response. Changes to this value do not take effect until the next time the buffer attribute is set. + */ + normalize: bool; +} + +/** + * This interface represents a node which is able to provide real-time frequency and time-domain analysis information. The audio stream will be passed un-processed from input to output. + * + * numberOfInputs : 1 + * numberOfOutputs : 1 Note that this output may be left unconnected. + */ +interface AnalyserNode extends AudioNode { + /** + * Copies the current frequency data into the passed floating-point array. If the array has fewer elements than the frequencyBinCount, the excess elements will be dropped. + * @param array where frequency-domain analysis data will be copied. + */ getFloatFrequencyData(array: any): void; + + /** + * Copies the current frequency data into the passed unsigned byte array. If the array has fewer elements than the frequencyBinCount, the excess elements will be dropped. + * @param Tarray where frequency-domain analysis data will be copied. + */ getByteFrequencyData(array: any): void; + + /** + * Copies the current time-domain (waveform) data into the passed unsigned byte array. If the array has fewer elements than the frequencyBinCount, the excess elements will be dropped. + * @param array where time-domain analysis data will be copied. + */ getByteTimeDomainData(array: any): void; + + /** + * The size of the FFT used for frequency-domain analysis. This must be a power of two. + */ fftSize: number; + + /** + * Half the FFT size. + */ frequencyBinCount: number; + + /** + * The minimum power value in the scaling range for the FFT analysis data for conversion to unsigned byte values. + */ minDecibels: number; + + /** + * The maximum power value in the scaling range for the FFT analysis data for conversion to unsigned byte values. + */ maxDecibels: number; + + /** + * A value from 0 -> 1 where 0 represents no time averaging with the last analysis frame. + */ smoothingTimeConstant: number; - } -interface AudioChannelSplitter extends AudioNode { - +/** + * The ChannelSplitterNode is for use in more advanced applications and would often be used in conjunction with ChannelMergerNode. + * + * numberOfInputs : 1 + * numberOfOutputs : Variable N (defaults to 6) // number of "active" (non-silent) outputs is determined by number of channels in the input + */ +interface ChannelSplitterNode extends AudioNode { } -interface AudioChannelMerger extends AudioNode { - +/** + * The ChannelMergerNode is for use in more advanced applications and would often be used in conjunction with ChannelSplitterNode. + * + * numberOfInputs : Variable N (default to 6) // number of connected inputs may be less than this + * numberOfOutputs : 1 + */ +interface ChannelMergerNode extends AudioNode { } +/** + * DynamicsCompressorNode is an AudioNode processor implementing a dynamics compression effect. + * + * Dynamics compression is very commonly used in musical production and game audio. It lowers the volume of the loudest parts of the signal and raises the volume of the softest parts. Overall, a louder, richer, and fuller sound can be achieved. It is especially important in games and musical applications where large numbers of individual sounds are played simultaneous to control the overall signal level and help avoid clipping (distorting) the audio output to the speakers. + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + */ interface DynamicsCompressorNode extends AudioNode { - + /** + * The decibel value above which the compression will start taking effect. Its default value is -24, with a nominal range of -100 to 0. + */ threshold: AudioParam; + + /** + * A decibel value representing the range above the threshold where the curve smoothly transitions to the "ratio" portion. Its default value is 30, with a nominal range of 0 to 40. + */ knee: AudioParam; + + /** + * The amount of dB change in input for a 1 dB change in output. Its default value is 12, with a nominal range of 1 to 20. + */ ratio: AudioParam; + + /** + * A read-only decibel value for metering purposes, representing the current amount of gain reduction that the compressor is applying to the signal. If fed no signal the value will be 0 (no gain reduction). The nominal range is -20 to 0. + */ reduction: AudioParam; + + /** + * The amount of time (in seconds) to reduce the gain by 10dB. Its default value is 0.003, with a nominal range of 0 to 1. + */ attack: AudioParam; + + /** + * The amount of time (in seconds) to increase the gain by 10dB. Its default value is 0.250, with a nominal range of 0 to 1. + */ release: AudioParam; } +enum BiquadFilterType { + /** + * A lowpass filter allows frequencies below the cutoff frequency to pass through and attenuates frequencies above the cutoff. It implements a standard second-order resonant lowpass filter with 12dB/octave rolloff. + * + * ## frequency + * The cutoff frequency + * ## Q + * Controls how peaked the response will be at the cutoff frequency. A large value makes the response more peaked. Please note that for this filter type, this value is not a traditional Q, but is a resonance value in decibels. + * ## gain + * Not used in this filter type + */ + lowpass, + + /** + * A highpass filter is the opposite of a lowpass filter. Frequencies above the cutoff frequency are passed through, but frequencies below the cutoff are attenuated. It implements a standard second-order resonant highpass filter with 12dB/octave rolloff. + * + * ## frequency + * The cutoff frequency below which the frequencies are attenuated + * ## Q + * Controls how peaked the response will be at the cutoff frequency. A large value makes the response more peaked. Please note that for this filter type, this value is not a traditional Q, but is a resonance value in decibels. + * ## gain + * Not used in this filter type + */ + highpass, + + /** + * A bandpass filter allows a range of frequencies to pass through and attenuates the frequencies below and above this frequency range. It implements a second-order bandpass filter. + * + * ## frequency + * The center of the frequency band + * ## Q + * Controls the width of the band. The width becomes narrower as the Q value increases. + * ## gain + * Not used in this filter type + */ + bandpass, + + /** + * The lowshelf filter allows all frequencies through, but adds a boost (or attenuation) to the lower frequencies. It implements a second-order lowshelf filter. + * + * ## frequency + * The upper limit of the frequences where the boost (or attenuation) is applied. + * ## Q + * Not used in this filter type. + * ## gain + * The boost, in dB, to be applied. If the value is negative, the frequencies are attenuated. + */ + lowshelf, + + /** + * The highshelf filter is the opposite of the lowshelf filter and allows all frequencies through, but adds a boost to the higher frequencies. It implements a second-order highshelf filter + * + * ## frequency + * The lower limit of the frequences where the boost (or attenuation) is applied. + * ## Q + * Not used in this filter type. + * ## gain + * The boost, in dB, to be applied. If the value is negative, the frequencies are attenuated. + */ + highshelf, + + /** + * The peaking filter allows all frequencies through, but adds a boost (or attenuation) to a range of frequencies. + * + * ## frequency + * The center frequency of where the boost is applied. + * ## Q + * Controls the width of the band of frequencies that are boosted. A large value implies a narrow width. + * ## gain + * The boost, in dB, to be applied. If the value is negative, the frequencies are attenuated. + */ + peaking, + + /** + * The notch filter (also known as a band-stop or band-rejection filter) is the opposite of a bandpass filter. It allows all frequencies through, except for a set of frequencies. + * + * ## frequency + * The center frequency of where the notch is applied. + * ## Q + * Controls the width of the band of frequencies that are attenuated. A large value implies a narrow width. + * ## gain + * Not used in this filter type. + */ + notch, + + /** + * An allpass filter allows all frequencies through, but changes the phase relationship between the various frequencies. It implements a second-order allpass filter + * + * ## frequency + * The frequency where the center of the phase transition occurs. Viewed another way, this is the frequency with maximal group delay. + * ## Q + * Controls how sharp the phase transition is at the center frequency. A larger value implies a sharper transition and a larger group delay. + * ## gain + * Not used in this filter type. + */ + allpass +} + +/** + * BiquadFilterNode is an AudioNode processor implementing very common low-order filters. + * + * Low-order filters are the building blocks of basic tone controls (bass, mid, treble), graphic equalizers, and more advanced filters. Multiple BiquadFilterNode filters can be combined to form more complex filters. The filter parameters such as "frequency" can be changed over time for filter sweeps, etc. Each BiquadFilterNode can be configured as one of a number of common filter types as shown in the IDL below. The default filter type is "lowpass" + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + * + * The filter types are briefly described below. We note that all of these filters are very commonly used in audio processing. In terms of implementation, they have all been derived from standard analog filter prototypes. For more technical details, we refer the reader to the excellent reference by Robert Bristow-Johnson. + * + * All parameters are k-rate with the following default parameter values: + * + * ## frequency + * 350Hz, with a nominal range of 10 to the Nyquist frequency (half the sample-rate). + * ## Q + * 1, with a nominal range of 0.0001 to 1000. + * ## gain + * 0, with a nominal range of -40 to 40. + */ interface BiquadFilterNode extends AudioNode { - type: number; + type: BiquadFilterType; frequency: AudioParam; Q: AudioParam; gain: AudioParam; + /** + * Given the current filter parameter settings, calculates the frequency response for the specified frequencies. + * @param frequencyHz an array of frequencies at which the response values will be calculated. + * @param magResponse an output array receiving the linear magnitude response values. + * @param phaseResponse an output array receiving the phase response values in radians. + */ getFrequencyResponse(frequencyHz: any, magResponse: any, phaseResponse: any): void; - } +/** + * WaveShaperNode is an AudioNode processor implementing non-linear distortion effects. + * + * Non-linear waveshaping distortion is commonly used for both subtle non-linear warming, or more obvious distortion effects. Arbitrary non-linear shaping curves may be specified. + * + * numberOfInputs : 1 + * numberOfOutputs : 1 + */ interface WaveShaperNode extends AudioNode { - - curve: any; - + /** + * The shaping curve used for the waveshaping effect. The input signal is nominally within the range -1 -> +1. Each input sample within this range will index into the shaping curve with a signal level of zero corresponding to the center value of the curve array. Any sample value less than -1 will correspond to the first value in the curve array. Any sample value less greater than +1 will correspond to the last value in the curve array. + */ + curve: Float32Array; } -interface MediaStreamAudioSourceNode extends AudioSourceNode { - - - +enum OscillatorType { + sine, + square, + sawtooth, + triangle, + custom } -interface ConvolverNode extends AudioNode { +/** + * OscillatorNode represents an audio source generating a periodic waveform. It can be set to a few commonly used waveforms. Additionally, it can be set to an arbitrary periodic waveform through the use of a WaveTable object. + * + * Oscillators are common foundational building blocks in audio synthesis. An OscillatorNode will start emitting sound at the time specified by the start() method. + * + * Mathematically speaking, a continuous-time periodic waveform can have very high (or infinitely high) frequency information when considered in the frequency domain. When this waveform is sampled as a discrete-time digital audio signal at a particular sample-rate, then care must be taken to discard (filter out) the high-frequency information higher than the Nyquist frequency (half the sample-rate) before converting the waveform to a digital form. If this is not done, then aliasing of higher frequencies (than the Nyquist frequency) will fold back as mirror images into frequencies lower than the Nyquist frequency. In many cases this will cause audibly objectionable artifacts. This is a basic and well understood principle of audio DSP. + * + * There are several practical approaches that an implementation may take to avoid this aliasing. But regardless of approach, the idealized discrete-time digital audio signal is well defined mathematically. The trade-off for the implementation is a matter of implementation cost (in terms of CPU usage) versus fidelity to achieving this ideal. + * + * It is expected that an implementation will take some care in achieving this ideal, but it is reasonable to consider lower-quality, less-costly approaches on lower-end hardware. + * + * Both .frequency and .detune are a-rate parameters and are used together to determine a computedFrequency value: + * + * computedFrequency(t) = frequency(t) * pow(2, detune(t) / 1200) + * + * The OscillatorNode's instantaneous phase at each time is the time integral of computedFrequency. + * + * numberOfInputs : 0 + * numberOfOutputs : 1 (mono output) + */ +interface OscillatorNode extends AudioSourceNode { + /** + * The shape of the periodic waveform. It may directly be set to any of the type constant values except for "custom". The setWaveTable() method can be used to set a custom waveform, which results in this attribute being set to "custom". The default value is "sine". + */ + type: OscillatorType; - buffer: AudioBuffer; - normalize: bool; + /** + * defined as in AudioBufferSourceNode. + * @readonly + */ + playbackState: number; + /** + * The frequency (in Hertz) of the periodic waveform. This parameter is a-rate + * @readonly + */ + frequency: AudioParam; + + /** + * A detuning value (in Cents) which will offset the frequency by the given amount. This parameter is a-rate + */ + detune: AudioParam; // in Cents + + /** + * defined as in AudioBufferSourceNode. + */ + start(when: number): void; + + /** + * defined as in AudioBufferSourceNode. + */ + stop(when: number): void; + + /** + * Sets an arbitrary custom periodic waveform given a WaveTable. + */ + setWaveTable(waveTable: WaveTable): void; } +/** + * WaveTable represents an arbitrary periodic waveform to be used with an OscillatorNode. Please see createWaveTable() and setWaveTable() and for more details. + */ interface WaveTable { +} +/** + * This interface represents an audio source from a MediaStream. The first AudioMediaStreamTrack from the MediaStream will be used as a source of audio. + * + * numberOfInputs : 0 + * numberOfOutputs : 1 + */ +interface MediaStreamAudioSourceNode extends AudioSourceNode { }