112 |
113 |
114 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/.gitignore:
--------------------------------------------------------------------------------
1 | /.DS_Store
2 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/README.md:
--------------------------------------------------------------------------------
1 | THREE.SimpleDatGuiOculusRiftDemo.html
2 | -------------------------------------
3 | Demonstrates the use of *THREE.SimpleDatGui* for Oculus Rift DK2.
4 |
5 | *Just open http://webgl-examples.appspot.com/simple-webgl-gui-oculus-rift/THREE.SimpleDatGuiOculusRiftDemo.html and/or install this project locally.*
6 |
7 | Motivation
8 | ----------
9 | For simple WebGL applications with THREE.js the Google's Chrome Experiment DAT.GUI is a good choice to render a minimal user interface, but there is no simple and reliable way to render DAT.GUI inside the WebGL scene. Oculus Rift Applications need to render the user interface inside the scene to display for both eyes.
10 |
11 | At the moment I know no support of a simple GUI in THREE.js. This was my motivation to develop a simple GUI based on THREE.js which should be as good as reasonable API compatible with DAT.GUI and has the same Look & Feel. The following article describes THREE.SimpleDatGui the result of these experiments. THREE.SimpleDatGui can serve as Heads-Up Display (HUD) in WebGL and/or in Oculus Rift applications.
12 |
13 | Main Components
14 | ---------------
15 | * **THREE.SimpleDatGuiOculusRiftDemo.html** (321 sloc) - renders a simple skydome with Oculus Rift style
16 | * **THREE.SimpleDatGui.js** (1584 sloc) - renders the GUI
17 | * **THREE.OculusRiftMouse.js** (90 sloc) - renders two mouse cursors
18 | * **THREE.OculusRiftControls.js** (101 sloc) - gets sensor data from Oculus Rift Data at http:\\localhost:8444
19 | * **OculusRiftSensorConnector.jar** - fetches Oculus Rift Data from USB port and provides at http:\\localhost:8444
20 |
21 | Use of Oculus Rift Sensor Connector
22 | -----------------------------------
23 | The *Oculus Rift Sensor Connector* provides sensor data at http://localhost:8444 and the access from *THREE.OculusRiftControls.js* happens with JSONP. The performance of this integration is not as fast as some other implementations based on web sockets, but is works without additional browser plug-in. Execute the following five steps to run with Oculus Rift Sensor:
24 |
25 | * **Get the project:**
26 | Fork project on GitHub (https://github.com/MarkusSprunck/oculus-rift-sensor-connector.git) or download the zip (https://github.com/MarkusSprunck/oculus-rift-sensor-connector).
27 | * **Connect your Oculus Rift DK2 to your computer:**
28 | Use the *Oculus Configuration Utility* to set the *Rift Display Mode* to *Extended Desktop to the HMD*.
29 | * **Start ./target/OculusRiftSensorConnector.jar:**
30 | You may use _OculusRiftSensorConnector.cmd_ on Windows. The compiled version expects Java 8 runtime, but it should work also with elder Java versions (maybe you have to change some lines).
31 | * **Open ./client/THREE.SimpleDatGuiOculusRiftDemo.html:**
32 | Chrome Options for Local Development - The Google Chrome browser will not load local file by default due to security reason. When you fork the project and open from file system, start with the command line option _--allow-file-access-from-files_ to load the textures. See also http://www.chrome-allow-file-access-from-file.com/
33 | * **Activate Connection to Oculus Rift:** The Oculus Control is not active by default, because most visitors will not have the Oculus Rift hardware connected when opening. In this case you may use the standard trackbar control to move the scene. To connect to Oculus Rift, just open folder _Advanced Options_ and check _Oculus Control Active_.
34 |
35 | Tested Configurations
36 | ---------------------
37 | The demo THREE.SimpleDatGuiOculusRiftDemo.html has been tested with the following browsers on Windows 7 with Oculus Rift DK2:
38 | * Chrome 41 (60 FPS)
39 | * Firefox 36 (60 FPS)
40 | * Internet Explorer 11 (8 FPS, definitely to slow for Oculus Rift)
41 |
42 | The component THREE.SimpleDatGui has been tested additionally on iOS 8.2 with iPad II with the following configurations:
43 | * Safari (30 FPS)
44 | * Chrome (30 FPS)
45 |
46 | Just open THREE.SimpleDatGuiDemo.html:
47 | * http://webgl-examples.appspot.com/simple-webgl-gui/THREE.SimpleDatGuiDemo.html?hud=false
48 | * http://webgl-examples.appspot.com/simple-webgl-gui/THREE.SimpleDatGuiDemo.html?hud=true
49 |
50 | Open Issues and Missing Features
51 | --------------------------------
52 | * THREE.SimpleDatGui.js - Compared to DAT.GUI the color picker control is missing and the save & restore of values
53 | * THREE.SimpleDatGui.js - No copy & paste support in text and value controls
54 | * THREE.SimpleDatGui.js - value control - slider just accepts mouse click - no mouse drag
55 | * THREE.SimpleDatGui.js - in the case the scene is rotated in non fixed mode the location of the cursor in the text control is wrong
56 | * THREE.OculusRiftControls.js - performance and robustness should be improved
57 |
58 | Credits for Equirectangular Pictures
59 | ------------------------------------
60 | The tree scenes in this demo are licensed under the Creative Commons Attribution-Share Alike 2.0 Generic license.
61 |
62 | * http://commons.wikimedia.org/wiki/File:Place_Dauphine,_Paris_November_2011.jpg
63 | * http://commons.wikimedia.org/wiki/File:Place_de_la_Concorde,_Paris_March_2007.jpg
64 | * http://commons.wikimedia.org/wiki/File:Parc_de_Belleville,_Paris_June_2007.jpg
65 |
66 | Many thanks to the author Alexandre Duret-Lutz (https://www.flickr.com/people/24183489@N00) from Paris, France.
67 |
68 | Credits for Libraries
69 | ---------------------
70 | * Ricardo Cabello for three.js (see https://github.com/mrdoob)
71 | * Daniel Kwiecinski for hashmap.js
72 |
73 | Read More
74 | ---------
75 | http://www.sw-engineering-candies.com
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/THREE.OculusRiftControls.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (C) 2015, Markus Sprunck All rights reserved. Redistribution and
3 | * use in source and binary forms, with or without modification, are permitted
4 | * provided that the following conditions are met: - Redistributions of source
5 | * code must retain the above copyright notice, this list of conditions and the
6 | * following disclaimer. - Redistributions in binary form must reproduce the
7 | * above copyright notice, this list of conditions and the following disclaimer
8 | * in the documentation and/or other materials provided with the distribution. -
9 | * The name of its contributor may be used to endorse or promote products
10 | * derived from this software without specific prior written permission. THIS
11 | * SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
12 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
15 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
19 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 | ******************************************************************************/
22 |
23 | var g_oculusRiftSensorData = [0, 0, 0, 0, 0, 0, 0, 0];
24 |
25 | function oculus_rift_callback(input_model) {
26 | "use strict";
27 | g_oculusRiftSensorData = input_model.values;
28 | }
29 |
30 | THREE.OculusRiftRotationControls = function(camera, scale, position) {
31 |
32 | console.log('THREE.OculusRiftRotationControls 2');
33 |
34 | var that = this;
35 | this.camera = camera;
36 | this.lastId = -1;
37 | this.scale = scale;
38 | this.position = position;
39 | this.url = "http:\\\\localhost:8444";
40 | this.isConnected = false;
41 | this.lastUpdate = new Date().getTime();
42 | this.tryConnection = false;
43 |
44 | this.controller = new THREE.Object3D();
45 | this.headPos = new THREE.Vector3();
46 | this.headQuat = new THREE.Quaternion();
47 |
48 | this.update = function() {
49 |
50 | // update within the last milliseconds
51 | this.isConnected = (new Date().getTime() < this.lastUpdate + 500);
52 |
53 | if (g_oculusRiftSensorData) {
54 |
55 | // UPDATE IF NEW DATA ARE AVAILABLE
56 | var id = g_oculusRiftSensorData[0];
57 | if (id > this.lastId) {
58 |
59 | this.headPos.set(g_oculusRiftSensorData[1] * this.scale + this.position.x, g_oculusRiftSensorData[2]
60 | * this.scale + this.position.y, g_oculusRiftSensorData[3] * this.scale + this.position.z);
61 | this.headQuat.set(g_oculusRiftSensorData[4], g_oculusRiftSensorData[5], g_oculusRiftSensorData[6],
62 | g_oculusRiftSensorData[7]);
63 |
64 | this.camera.setRotationFromQuaternion(this.headQuat);
65 | this.controller.setRotationFromMatrix(this.camera.matrix);
66 | this.camera.position.addVectors(this.controller.position, this.headPos);
67 |
68 | this.lastUpdate = new Date().getTime();
69 | }
70 | this.lastId = id;
71 |
72 | // Request new data
73 | if (this.tryConnection) {
74 | this.importData();
75 | }
76 | }
77 |
78 | };
79 |
80 | var g_lastUpdateRequest = new Date().getTime();
81 |
82 | this.importData = function() {
83 | "use strict";
84 |
85 | g_lastUpdateRequest = new Date().getTime();
86 | var script = document.createElement("script");
87 | script.setAttribute("type", "application/javascript");
88 | script.id = 'JSONP';
89 | var url = this.url;
90 | url += "?" + g_lastUpdateRequest;
91 | script.setAttribute("src", url);
92 | document.body.appendChild(script);
93 | setTimeout(function() {
94 | var script;
95 | while (script = document.getElementById('JSONP')) {
96 | script.parentNode.removeChild(script);
97 | for ( var prop in script) {
98 | delete script[prop];
99 | }
100 | }
101 | }, 20);
102 |
103 | }
104 |
105 | this.getUrl = function() {
106 | "use strict";
107 |
108 | return this.url;
109 | }
110 |
111 | this.setUrl = function(url) {
112 | "use strict";
113 |
114 | this.url = url;
115 | }
116 |
117 | this.setActive = function(tryConnection) {
118 | "use strict";
119 |
120 | this.tryConnection = tryConnection;
121 | }
122 |
123 | this.isOculusRiftConnected = function() {
124 | "use strict";
125 |
126 | return this.isConnected;
127 | }
128 |
129 | };
130 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/THREE.OculusRiftMouse.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (C) 2015, Markus Sprunck All rights reserved. Redistribution and
3 | * use in source and binary forms, with or without modification, are permitted
4 | * provided that the following conditions are met: - Redistributions of source
5 | * code must retain the above copyright notice, this list of conditions and the
6 | * following disclaimer. - Redistributions in binary form must reproduce the
7 | * above copyright notice, this list of conditions and the following disclaimer
8 | * in the documentation and/or other materials provided with the distribution. -
9 | * The name of its contributor may be used to endorse or promote products
10 | * derived from this software without specific prior written permission. THIS
11 | * SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
12 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
15 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
18 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
19 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
20 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 | ******************************************************************************/
22 |
23 | THREE.OculusRiftMousePointerHelper = function(scene, parameters) {
24 |
25 | console.log('THREE.OculusRiftMousePointerHelper 1');
26 |
27 | var that = this;
28 |
29 | this.style = "default";
30 |
31 | parameters = parameters || {};
32 |
33 | // MANDATORY PARAMETERS
34 | this.initSucceeded = true;
35 | this.camera = (parameters.camera !== undefined) ? parameters.camera : null;
36 | if (null === this.camera) {
37 | console.warn('THREE.OculusRiftMousePointerHelper missing parameter \'camera\'');
38 | this.initSucceeded = false;
39 | }
40 | var domElement = (parameters.domElement !== undefined) ? parameters.domElement : null;
41 | if (null === this.domElement) {
42 | console.warn('THREE.OculusRiftMousePointerHelper missing parameter \'domElement\'');
43 | this.initSucceeded = false;
44 | }
45 | this.distance = (parameters.distance !== undefined) ? parameters.distance : 0.95;
46 |
47 | // Create mouse pointers
48 | this.sprite_default = this.loadMouseCursorSprite("textures/mouse_default.png");
49 | scene.add(this.sprite_default);
50 |
51 | this.sprite_resize = this.loadMouseCursorSprite("textures/mouse_resize.png");
52 | scene.add(this.sprite_resize);
53 |
54 | this.sprite_pointer = this.loadMouseCursorSprite("textures/mouse_pointer.png");
55 | scene.add(this.sprite_pointer);
56 |
57 | this.sprite_text = this.loadMouseCursorSprite("textures/mouse_text.png");
58 | scene.add(this.sprite_text);
59 |
60 | if (this.initSucceeded) {
61 |
62 | // HIDE STANDARD CURSOR OF BROWSER
63 | domElement.style.cursor = "none";
64 |
65 | // TRACK MOUSE MOVEMENT
66 | this.mouse = new THREE.Vector2();
67 | function mousemove(event) {
68 | that.mouse.x = +(event.clientX / window.innerWidth) * 2 - 1;
69 | that.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
70 | }
71 |
72 | domElement.addEventListener('mousemove', mousemove.bind(this), false);
73 | }
74 | };
75 |
76 | THREE.OculusRiftMousePointerHelper.prototype.loadMouseCursorSprite = function(path) {
77 | var texture = THREE.ImageUtils.loadTexture(path);
78 | texture.minFilter = THREE.LinearFilter;
79 | texture.magFilter = THREE.LinearFilter;
80 | var sprite = new THREE.Sprite(new THREE.SpriteMaterial({
81 | map: texture,
82 | color: 0xffffff
83 | }));
84 | return sprite;
85 | }
86 |
87 | THREE.OculusRiftMousePointerHelper.prototype.setMouse = function(style) {
88 | this.style = style;
89 | }
90 |
91 | THREE.OculusRiftMousePointerHelper.prototype.update = function() {
92 |
93 | if (this.initSucceeded) {
94 |
95 | var vector = new THREE.Vector3();
96 | vector.set(this.mouse.x, this.mouse.y, this.distance).unproject(this.camera);
97 |
98 | this.sprite_text.visible = (this.style === "text");
99 | this.sprite_resize.visible = (this.style === "w-resize");
100 | this.sprite_pointer.visible = (this.style === "pointer");
101 | this.sprite_default.visible = (this.style !== "text") && (this.style !== "pointer")
102 | && (this.style !== "w-resize");
103 |
104 | var x_delta = 21 / window.innerWidth;
105 | var y_delta = 21 / window.innerHeight;
106 | this.sprite_text.position.set(vector.x + x_delta, vector.y + y_delta, vector.z);
107 | this.sprite_resize.position.set(vector.x + x_delta, vector.y + y_delta, vector.z);
108 | this.sprite_pointer.position.set(vector.x + x_delta, vector.y + y_delta, vector.z);
109 | this.sprite_default.position.set(vector.x + x_delta, vector.y + y_delta, vector.z);
110 | }
111 |
112 | };
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/THREE.SimpleDatGuiOculusRiftDemo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | THREE.SimpleDatGui - Oculus Rift Demo
5 |
6 |
87 |
88 |
89 |
90 | Fork me on GitHub
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
367 |
368 |
369 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/lib/AxisHelper.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author sroucheray / http://sroucheray.org/
3 | * @author mrdoob / http://mrdoob.com/
4 | */
5 |
6 | THREE.AxisHelper = function ( size ) {
7 |
8 | size = size || 1;
9 |
10 | var vertices = new Float32Array( [
11 | 0, 0, 0, size, 0, 0,
12 | 0, 0, 0, 0, size, 0,
13 | 0, 0, 0, 0, 0, size
14 | ] );
15 |
16 | var colors = new Float32Array( [
17 | 1, 0, 0, 1, 0.6, 0,
18 | 0, 1, 0, 0.6, 1, 0,
19 | 0, 0, 1, 0, 0.6, 1
20 | ] );
21 |
22 | var geometry = new THREE.BufferGeometry();
23 | geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
24 | geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
25 |
26 | var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
27 |
28 | THREE.Line.call( this, geometry, material, THREE.LinePieces );
29 |
30 | };
31 |
32 | THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype );
33 | THREE.AxisHelper.prototype.constructor = THREE.AxisHelper;
34 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/lib/OculusRiftEffect.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author troffmo5 / http://github.com/troffmo5
3 | *
4 | * Effect to render the scene in stereo 3d side by side with lens distortion.
5 | * It is written to be used with the Oculus Rift (http://www.oculusvr.com/) but
6 | * it works also with other HMD using the same technology
7 | */
8 |
9 | THREE.OculusRiftEffect = function ( renderer, options ) {
10 | // worldFactor indicates how many units is 1 meter
11 | var worldFactor = (options && options.worldFactor) ? options.worldFactor: 1.0;
12 |
13 | // Specific HMD parameters
14 | var HMD = (options && options.HMD) ? options.HMD: {
15 | // DK1
16 | /*
17 | hResolution: 1280,
18 | vResolution: 800,
19 | hScreenSize: 0.14976,
20 | vScreenSize: 0.0936,
21 | interpupillaryDistance: 0.064,
22 | lensSeparationDistance: 0.064,
23 | eyeToScreenDistance: 0.041,
24 | distortionK : [1.0, 0.22, 0.24, 0.0],
25 | chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
26 | */
27 | // DK2
28 | hResolution: 1920,
29 | vResolution: 1080,
30 | hScreenSize: 0.12576,
31 | vScreenSize: 0.07074,
32 | interpupillaryDistance: 0.0635,
33 | lensSeparationDistance: 0.0635,
34 | eyeToScreenDistance: 0.041,
35 | distortionK : [1.0, 0.22, 0.24, 0.0],
36 | chromaAbParameter: [ 0.996, -0.004, 1.014, 0.0]
37 | };
38 | this.HMD = HMD;
39 |
40 | // Perspective camera
41 | var pCamera = new THREE.PerspectiveCamera();
42 | pCamera.matrixAutoUpdate = false;
43 | pCamera.target = new THREE.Vector3();
44 |
45 | // Orthographic camera
46 | var oCamera = new THREE.OrthographicCamera( -1, 1, 1, -1, 1, 1000 );
47 | oCamera.position.z = 1;
48 |
49 | // pre-render hooks
50 | this.preLeftRender = function() {};
51 | this.preRightRender = function() {};
52 |
53 | renderer.autoClear = false;
54 | var emptyColor = new THREE.Color("black");
55 |
56 | // Render target
57 | var RTParams = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat };
58 | var renderTarget = new THREE.WebGLRenderTarget( 640, 800, RTParams );
59 | var RTMaterial = new THREE.ShaderMaterial( {
60 | uniforms: {
61 | "texid": { type: "t", value: renderTarget },
62 | "scale": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
63 | "scaleIn": { type: "v2", value: new THREE.Vector2(1.0,1.0) },
64 | "lensCenter": { type: "v2", value: new THREE.Vector2(0.0,0.0) },
65 | "hmdWarpParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) },
66 | "chromAbParam": { type: "v4", value: new THREE.Vector4(1.0,0.0,0.0,0.0) }
67 | },
68 | vertexShader: [
69 | "varying vec2 vUv;",
70 | "void main() {",
71 | " vUv = uv;",
72 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
73 | "}"
74 | ].join("\n"),
75 |
76 | fragmentShader: [
77 | "uniform vec2 scale;",
78 | "uniform vec2 scaleIn;",
79 | "uniform vec2 lensCenter;",
80 | "uniform vec4 hmdWarpParam;",
81 | 'uniform vec4 chromAbParam;',
82 | "uniform sampler2D texid;",
83 | "varying vec2 vUv;",
84 | "void main()",
85 | "{",
86 | " vec2 uv = (vUv*2.0)-1.0;", // range from [0,1] to [-1,1]
87 | " vec2 theta = (uv-lensCenter)*scaleIn;",
88 | " float rSq = theta.x*theta.x + theta.y*theta.y;",
89 | " vec2 rvector = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq);",
90 | ' vec2 rBlue = rvector * (chromAbParam.z + chromAbParam.w * rSq);',
91 | " vec2 tcBlue = (lensCenter + scale * rBlue);",
92 | " tcBlue = (tcBlue+1.0)/2.0;", // range from [-1,1] to [0,1]
93 | " if (any(bvec2(clamp(tcBlue, vec2(0.0,0.0), vec2(1.0,1.0))-tcBlue))) {",
94 | " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);",
95 | " return;}",
96 | " vec2 tcGreen = lensCenter + scale * rvector;",
97 | " tcGreen = (tcGreen+1.0)/2.0;", // range from [-1,1] to [0,1]
98 | " vec2 rRed = rvector * (chromAbParam.x + chromAbParam.y * rSq);",
99 | " vec2 tcRed = lensCenter + scale * rRed;",
100 | " tcRed = (tcRed+1.0)/2.0;", // range from [-1,1] to [0,1]
101 | " gl_FragColor = vec4(texture2D(texid, tcRed).r, texture2D(texid, tcGreen).g, texture2D(texid, tcBlue).b, 1);",
102 | "}"
103 | ].join("\n")
104 | } );
105 |
106 | var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), RTMaterial );
107 |
108 | // Final scene
109 | var finalScene = new THREE.Scene();
110 | finalScene.add( oCamera );
111 | finalScene.add( mesh );
112 |
113 | var left = {}, right = {};
114 | var distScale = 1.0;
115 | this.setHMD = function(v) {
116 | HMD = v;
117 | // Compute aspect ratio and FOV
118 | var aspect = HMD.hResolution / (2*HMD.vResolution);
119 |
120 | // Fov is normally computed with:
121 | // THREE.Math.radToDeg( 2*Math.atan2(HMD.vScreenSize,2*HMD.eyeToScreenDistance) );
122 | // But with lens distortion it is increased (see Oculus SDK Documentation)
123 | var r = -1.0 - (4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize);
124 | distScale = (HMD.distortionK[0] + HMD.distortionK[1] * Math.pow(r,2) + HMD.distortionK[2] * Math.pow(r,4) + HMD.distortionK[3] * Math.pow(r,6));
125 | var fov = THREE.Math.radToDeg(2*Math.atan2(HMD.vScreenSize*distScale, 2*HMD.eyeToScreenDistance));
126 |
127 | // Compute camera projection matrices
128 | var proj = (new THREE.Matrix4()).makePerspective( fov, aspect, 0.3, 10000 );
129 | var h = 4 * (HMD.hScreenSize/4 - HMD.interpupillaryDistance/2) / HMD.hScreenSize;
130 | left.proj = ((new THREE.Matrix4()).makeTranslation( h, 0.0, 0.0 )).multiply(proj);
131 | right.proj = ((new THREE.Matrix4()).makeTranslation( -h, 0.0, 0.0 )).multiply(proj);
132 |
133 | // Compute camera transformation matrices
134 | left.tranform = (new THREE.Matrix4()).makeTranslation( -worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
135 | right.tranform = (new THREE.Matrix4()).makeTranslation( worldFactor * HMD.interpupillaryDistance/2, 0.0, 0.0 );
136 |
137 | // Compute Viewport
138 | left.viewport = [0, 0, HMD.hResolution/2, HMD.vResolution];
139 | right.viewport = [HMD.hResolution/2, 0, HMD.hResolution/2, HMD.vResolution];
140 |
141 | // Distortion shader parameters
142 | var lensShift = 4 * (HMD.hScreenSize/4 - HMD.lensSeparationDistance/2) / HMD.hScreenSize;
143 | left.lensCenter = new THREE.Vector2(lensShift, 0.0);
144 | right.lensCenter = new THREE.Vector2(-lensShift, 0.0);
145 |
146 | RTMaterial.uniforms['hmdWarpParam'].value = new THREE.Vector4(HMD.distortionK[0], HMD.distortionK[1], HMD.distortionK[2], HMD.distortionK[3]);
147 | RTMaterial.uniforms['chromAbParam'].value = new THREE.Vector4(HMD.chromaAbParameter[0], HMD.chromaAbParameter[1], HMD.chromaAbParameter[2], HMD.chromaAbParameter[3]);
148 | RTMaterial.uniforms['scaleIn'].value = new THREE.Vector2(1.0,1.0/aspect);
149 | RTMaterial.uniforms['scale'].value = new THREE.Vector2(1.0/distScale, 1.0*aspect/distScale);
150 |
151 | // Create render target
152 | if ( renderTarget ) renderTarget.dispose();
153 | renderTarget = new THREE.WebGLRenderTarget( HMD.hResolution * distScale / 2, HMD.vResolution * distScale, RTParams );
154 | RTMaterial.uniforms[ "texid" ].value = renderTarget;
155 |
156 | }
157 | this.getHMD = function() {return HMD};
158 |
159 | this.setHMD(HMD);
160 |
161 | this.setSize = function ( width, height ) {
162 | left.viewport = [width/2 - HMD.hResolution/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
163 | right.viewport = [width/2, height/2 - HMD.vResolution/2, HMD.hResolution/2, HMD.vResolution];
164 |
165 | renderer.setSize( width, height );
166 | };
167 |
168 | this.render = function ( scene, camera ) {
169 | var cc = renderer.getClearColor().clone();
170 |
171 | // Clear
172 | renderer.setClearColor(emptyColor);
173 | renderer.clear();
174 | renderer.setClearColor(cc);
175 |
176 | // camera parameters
177 | if (camera.matrixAutoUpdate) camera.updateMatrix();
178 |
179 | // Render left
180 | this.preLeftRender();
181 |
182 | pCamera.projectionMatrix.copy(left.proj);
183 |
184 | pCamera.matrix.copy(camera.matrix).multiply(left.tranform);
185 | pCamera.matrixWorldNeedsUpdate = true;
186 |
187 | renderer.setViewport(left.viewport[0], left.viewport[1], left.viewport[2], left.viewport[3]);
188 |
189 | RTMaterial.uniforms['lensCenter'].value = left.lensCenter;
190 | renderer.render( scene, pCamera, renderTarget, true );
191 |
192 | renderer.render( finalScene, oCamera );
193 |
194 | // Render right
195 | this.preRightRender();
196 |
197 | pCamera.projectionMatrix.copy(right.proj);
198 |
199 | pCamera.matrix.copy(camera.matrix).multiply(right.tranform);
200 | pCamera.matrixWorldNeedsUpdate = true;
201 |
202 | renderer.setViewport(right.viewport[0], right.viewport[1], right.viewport[2], right.viewport[3]);
203 |
204 | RTMaterial.uniforms['lensCenter'].value = right.lensCenter;
205 |
206 | renderer.render( scene, pCamera, renderTarget, true );
207 | renderer.render( finalScene, oCamera );
208 |
209 | };
210 |
211 | this.dispose = function() {
212 | if ( RTMaterial ) {
213 | RTMaterial.dispose();
214 | }
215 | if ( renderTarget ) {
216 | renderTarget.dispose();
217 | }
218 | };
219 |
220 | };
221 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/lib/TrackballControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eberhard Graether / http://egraether.com/
3 | * @author Mark Lundin / http://mark-lundin.com
4 | */
5 |
6 | THREE.TrackballControls = function ( object, domElement ) {
7 |
8 | var _this = this;
9 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
10 |
11 | this.object = object;
12 | this.domElement = ( domElement !== undefined ) ? domElement : document;
13 |
14 | // API
15 |
16 | this.enabled = true;
17 |
18 | this.screen = { left: 0, top: 0, width: 0, height: 0 };
19 |
20 | this.rotateSpeed = 1.0;
21 | this.zoomSpeed = 1.2;
22 | this.panSpeed = 0.3;
23 |
24 | this.noRotate = false;
25 | this.noZoom = false;
26 | this.noPan = false;
27 | this.noRoll = false;
28 |
29 | this.staticMoving = false;
30 | this.dynamicDampingFactor = 0.2;
31 |
32 | this.minDistance = 0;
33 | this.maxDistance = Infinity;
34 |
35 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
36 |
37 | // internals
38 |
39 | this.target = new THREE.Vector3();
40 |
41 | var EPS = 0.000001;
42 |
43 | var lastPosition = new THREE.Vector3();
44 |
45 | var _state = STATE.NONE,
46 | _prevState = STATE.NONE,
47 |
48 | _eye = new THREE.Vector3(),
49 |
50 | _rotateStart = new THREE.Vector3(),
51 | _rotateEnd = new THREE.Vector3(),
52 |
53 | _zoomStart = new THREE.Vector2(),
54 | _zoomEnd = new THREE.Vector2(),
55 |
56 | _touchZoomDistanceStart = 0,
57 | _touchZoomDistanceEnd = 0,
58 |
59 | _panStart = new THREE.Vector2(),
60 | _panEnd = new THREE.Vector2();
61 |
62 | // for reset
63 |
64 | this.target0 = this.target.clone();
65 | this.position0 = this.object.position.clone();
66 | this.up0 = this.object.up.clone();
67 |
68 | // events
69 |
70 | var changeEvent = { type: 'change' };
71 | var startEvent = { type: 'start'};
72 | var endEvent = { type: 'end'};
73 |
74 |
75 | // methods
76 |
77 | this.handleResize = function () {
78 |
79 | if ( this.domElement === document ) {
80 |
81 | this.screen.left = 0;
82 | this.screen.top = 0;
83 | this.screen.width = window.innerWidth;
84 | this.screen.height = window.innerHeight;
85 |
86 | } else {
87 |
88 | var box = this.domElement.getBoundingClientRect();
89 | // adjustments come from similar code in the jquery offset() function
90 | var d = this.domElement.ownerDocument.documentElement;
91 | this.screen.left = box.left + window.pageXOffset - d.clientLeft;
92 | this.screen.top = box.top + window.pageYOffset - d.clientTop;
93 | this.screen.width = box.width;
94 | this.screen.height = box.height;
95 |
96 | }
97 |
98 | };
99 |
100 | this.handleEvent = function ( event ) {
101 |
102 | if ( typeof this[ event.type ] == 'function' ) {
103 |
104 | this[ event.type ]( event );
105 |
106 | }
107 |
108 | };
109 |
110 | var getMouseOnScreen = ( function () {
111 |
112 | var vector = new THREE.Vector2();
113 |
114 | return function ( pageX, pageY ) {
115 |
116 | vector.set(
117 | ( pageX - _this.screen.left ) / _this.screen.width,
118 | ( pageY - _this.screen.top ) / _this.screen.height
119 | );
120 |
121 | return vector;
122 |
123 | };
124 |
125 | }() );
126 |
127 | var getMouseProjectionOnBall = ( function () {
128 |
129 | var vector = new THREE.Vector3();
130 | var objectUp = new THREE.Vector3();
131 | var mouseOnBall = new THREE.Vector3();
132 |
133 | return function ( pageX, pageY ) {
134 |
135 | mouseOnBall.set(
136 | ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
137 | ( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5),
138 | 0.0
139 | );
140 |
141 | var length = mouseOnBall.length();
142 |
143 | if ( _this.noRoll ) {
144 |
145 | if ( length < Math.SQRT1_2 ) {
146 |
147 | mouseOnBall.z = Math.sqrt( 1.0 - length*length );
148 |
149 | } else {
150 |
151 | mouseOnBall.z = .5 / length;
152 |
153 | }
154 |
155 | } else if ( length > 1.0 ) {
156 |
157 | mouseOnBall.normalize();
158 |
159 | } else {
160 |
161 | mouseOnBall.z = Math.sqrt( 1.0 - length * length );
162 |
163 | }
164 |
165 | _eye.copy( _this.object.position ).sub( _this.target );
166 |
167 | vector.copy( _this.object.up ).setLength( mouseOnBall.y )
168 | vector.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );
169 | vector.add( _eye.setLength( mouseOnBall.z ) );
170 |
171 | return vector;
172 |
173 | };
174 |
175 | }() );
176 |
177 | this.rotateCamera = (function(){
178 |
179 | var axis = new THREE.Vector3(),
180 | quaternion = new THREE.Quaternion();
181 |
182 |
183 | return function () {
184 |
185 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
186 |
187 | if ( angle ) {
188 |
189 | axis.crossVectors( _rotateStart, _rotateEnd ).normalize();
190 |
191 | angle *= _this.rotateSpeed;
192 |
193 | quaternion.setFromAxisAngle( axis, -angle );
194 |
195 | _eye.applyQuaternion( quaternion );
196 | _this.object.up.applyQuaternion( quaternion );
197 |
198 | _rotateEnd.applyQuaternion( quaternion );
199 |
200 | if ( _this.staticMoving ) {
201 |
202 | _rotateStart.copy( _rotateEnd );
203 |
204 | } else {
205 |
206 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
207 | _rotateStart.applyQuaternion( quaternion );
208 |
209 | }
210 |
211 | }
212 | }
213 |
214 | }());
215 |
216 | this.zoomCamera = function () {
217 |
218 | if ( _state === STATE.TOUCH_ZOOM_PAN ) {
219 |
220 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
221 | _touchZoomDistanceStart = _touchZoomDistanceEnd;
222 | _eye.multiplyScalar( factor );
223 |
224 | } else {
225 |
226 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
227 |
228 | if ( factor !== 1.0 && factor > 0.0 ) {
229 |
230 | _eye.multiplyScalar( factor );
231 |
232 | if ( _this.staticMoving ) {
233 |
234 | _zoomStart.copy( _zoomEnd );
235 |
236 | } else {
237 |
238 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
239 |
240 | }
241 |
242 | }
243 |
244 | }
245 |
246 | };
247 |
248 | this.panCamera = (function(){
249 |
250 | var mouseChange = new THREE.Vector2(),
251 | objectUp = new THREE.Vector3(),
252 | pan = new THREE.Vector3();
253 |
254 | return function () {
255 |
256 | mouseChange.copy( _panEnd ).sub( _panStart );
257 |
258 | if ( mouseChange.lengthSq() ) {
259 |
260 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
261 |
262 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
263 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );
264 |
265 | _this.object.position.add( pan );
266 | _this.target.add( pan );
267 |
268 | if ( _this.staticMoving ) {
269 |
270 | _panStart.copy( _panEnd );
271 |
272 | } else {
273 |
274 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
275 |
276 | }
277 |
278 | }
279 | }
280 |
281 | }());
282 |
283 | this.checkDistances = function () {
284 |
285 | if ( !_this.noZoom || !_this.noPan ) {
286 |
287 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {
288 |
289 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );
290 |
291 | }
292 |
293 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
294 |
295 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
296 |
297 | }
298 |
299 | }
300 |
301 | };
302 |
303 | this.update = function () {
304 |
305 | _eye.subVectors( _this.object.position, _this.target );
306 |
307 | if ( !_this.noRotate ) {
308 |
309 | _this.rotateCamera();
310 |
311 | }
312 |
313 | if ( !_this.noZoom ) {
314 |
315 | _this.zoomCamera();
316 |
317 | }
318 |
319 | if ( !_this.noPan ) {
320 |
321 | _this.panCamera();
322 |
323 | }
324 |
325 | _this.object.position.addVectors( _this.target, _eye );
326 |
327 | _this.checkDistances();
328 |
329 | _this.object.lookAt( _this.target );
330 |
331 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {
332 |
333 | _this.dispatchEvent( changeEvent );
334 |
335 | lastPosition.copy( _this.object.position );
336 |
337 | }
338 |
339 | };
340 |
341 | this.reset = function () {
342 |
343 | _state = STATE.NONE;
344 | _prevState = STATE.NONE;
345 |
346 | _this.target.copy( _this.target0 );
347 | _this.object.position.copy( _this.position0 );
348 | _this.object.up.copy( _this.up0 );
349 |
350 | _eye.subVectors( _this.object.position, _this.target );
351 |
352 | _this.object.lookAt( _this.target );
353 |
354 | _this.dispatchEvent( changeEvent );
355 |
356 | lastPosition.copy( _this.object.position );
357 |
358 | };
359 |
360 | // listeners
361 |
362 | function keydown( event ) {
363 |
364 | if ( _this.enabled === false ) return;
365 |
366 | window.removeEventListener( 'keydown', keydown );
367 |
368 | _prevState = _state;
369 |
370 | if ( _state !== STATE.NONE ) {
371 |
372 | return;
373 |
374 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {
375 |
376 | _state = STATE.ROTATE;
377 |
378 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {
379 |
380 | _state = STATE.ZOOM;
381 |
382 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {
383 |
384 | _state = STATE.PAN;
385 |
386 | }
387 |
388 | }
389 |
390 | function keyup( event ) {
391 |
392 | if ( _this.enabled === false ) return;
393 |
394 | _state = _prevState;
395 |
396 | window.addEventListener( 'keydown', keydown, false );
397 |
398 | }
399 |
400 | function mousedown( event ) {
401 |
402 | if ( _this.enabled === false ) return;
403 |
404 | event.preventDefault();
405 | event.stopPropagation();
406 |
407 | if ( _state === STATE.NONE ) {
408 |
409 | _state = event.button;
410 |
411 | }
412 |
413 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
414 |
415 | _rotateStart.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );
416 | _rotateEnd.copy( _rotateStart );
417 |
418 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
419 |
420 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
421 | _zoomEnd.copy(_zoomStart);
422 |
423 | } else if ( _state === STATE.PAN && !_this.noPan ) {
424 |
425 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
426 | _panEnd.copy(_panStart)
427 |
428 | }
429 |
430 | document.addEventListener( 'mousemove', mousemove, false );
431 | document.addEventListener( 'mouseup', mouseup, false );
432 |
433 | _this.dispatchEvent( startEvent );
434 |
435 | }
436 |
437 | function mousemove( event ) {
438 |
439 | if ( _this.enabled === false ) return;
440 |
441 | event.preventDefault();
442 | event.stopPropagation();
443 |
444 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
445 |
446 | _rotateEnd.copy( getMouseProjectionOnBall( event.pageX, event.pageY ) );
447 |
448 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
449 |
450 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
451 |
452 | } else if ( _state === STATE.PAN && !_this.noPan ) {
453 |
454 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
455 |
456 | }
457 |
458 | }
459 |
460 | function mouseup( event ) {
461 |
462 | if ( _this.enabled === false ) return;
463 |
464 | event.preventDefault();
465 | event.stopPropagation();
466 |
467 | _state = STATE.NONE;
468 |
469 | document.removeEventListener( 'mousemove', mousemove );
470 | document.removeEventListener( 'mouseup', mouseup );
471 | _this.dispatchEvent( endEvent );
472 |
473 | }
474 |
475 | function mousewheel( event ) {
476 |
477 | if ( _this.enabled === false ) return;
478 |
479 | event.preventDefault();
480 | event.stopPropagation();
481 |
482 | var delta = 0;
483 |
484 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
485 |
486 | delta = event.wheelDelta / 40;
487 |
488 | } else if ( event.detail ) { // Firefox
489 |
490 | delta = - event.detail / 3;
491 |
492 | }
493 |
494 | _zoomStart.y += delta * 0.01;
495 | _this.dispatchEvent( startEvent );
496 | _this.dispatchEvent( endEvent );
497 |
498 | }
499 |
500 | function touchstart( event ) {
501 |
502 | if ( _this.enabled === false ) return;
503 |
504 | switch ( event.touches.length ) {
505 |
506 | case 1:
507 | _state = STATE.TOUCH_ROTATE;
508 | _rotateStart.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
509 | _rotateEnd.copy( _rotateStart );
510 | break;
511 |
512 | case 2:
513 | _state = STATE.TOUCH_ZOOM_PAN;
514 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
515 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
516 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
517 |
518 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
519 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
520 | _panStart.copy( getMouseOnScreen( x, y ) );
521 | _panEnd.copy( _panStart );
522 | break;
523 |
524 | default:
525 | _state = STATE.NONE;
526 |
527 | }
528 | _this.dispatchEvent( startEvent );
529 |
530 |
531 | }
532 |
533 | function touchmove( event ) {
534 |
535 | if ( _this.enabled === false ) return;
536 |
537 | event.preventDefault();
538 | event.stopPropagation();
539 |
540 | switch ( event.touches.length ) {
541 |
542 | case 1:
543 | _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
544 | break;
545 |
546 | case 2:
547 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
548 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
549 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
550 |
551 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
552 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
553 | _panEnd.copy( getMouseOnScreen( x, y ) );
554 | break;
555 |
556 | default:
557 | _state = STATE.NONE;
558 |
559 | }
560 |
561 | }
562 |
563 | function touchend( event ) {
564 |
565 | if ( _this.enabled === false ) return;
566 |
567 | switch ( event.touches.length ) {
568 |
569 | case 1:
570 | _rotateEnd.copy( getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
571 | _rotateStart.copy( _rotateEnd );
572 | break;
573 |
574 | case 2:
575 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
576 |
577 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
578 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
579 | _panEnd.copy( getMouseOnScreen( x, y ) );
580 | _panStart.copy( _panEnd );
581 | break;
582 |
583 | }
584 |
585 | _state = STATE.NONE;
586 | _this.dispatchEvent( endEvent );
587 |
588 | }
589 |
590 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
591 |
592 | this.domElement.addEventListener( 'mousedown', mousedown, false );
593 |
594 | this.domElement.addEventListener( 'mousewheel', mousewheel, false );
595 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
596 |
597 | this.domElement.addEventListener( 'touchstart', touchstart, false );
598 | this.domElement.addEventListener( 'touchend', touchend, false );
599 | this.domElement.addEventListener( 'touchmove', touchmove, false );
600 |
601 | window.addEventListener( 'keydown', keydown, false );
602 | window.addEventListener( 'keyup', keyup, false );
603 |
604 | this.handleResize();
605 |
606 | // force an update at start
607 | this.update();
608 |
609 | };
610 |
611 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
612 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls;
613 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/lib/hashmap.js:
--------------------------------------------------------------------------------
1 | /*
2 | * =====================================================================
3 | * Redistribution and use in source and binary forms, with or without
4 | * modification, are permitted provided that the following conditions are met:
5 | *
6 | * 1. Redistributions of source code must retain the above copyright notice,
7 | * this list of conditions and the following disclaimer.
8 | *
9 | * 2. Redistributions in binary form must reproduce the above copyright notice,
10 | * this list of conditions and the following disclaimer in the documentation
11 | * and/or other materials provided with the distribution.
12 | *
13 | * 3. The name of the author may not be used to endorse or promote products
14 | * derived from this software without specific prior written permission.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | *
27 | * @author Daniel Kwiecinski @copyright 2009
28 | * Daniel Kwiecinski. @end
29 | * =====================================================================
30 | */
31 | var HashMap = function() {
32 | this.initialize();
33 | }
34 |
35 | HashMap.prototype = {
36 | hashkey_prefix: "<#HashMapHashkeyPerfix>",
37 | hashcode_field: "<#HashMapHashcodeField>",
38 | hashmap_instance_id: 0,
39 |
40 | initialize: function() {
41 | this.backing_hash = {};
42 | this.code = 0;
43 | this.hashmap_instance_id += 1;
44 | this.instance_id = this.hashmap_instance_id;
45 | },
46 |
47 | hashcodeField: function() {
48 | return this.hashcode_field + this.instance_id;
49 | },
50 | /*
51 | * maps value to key returning previous assocciation
52 | */
53 | put: function(key, value) {
54 | var prev;
55 |
56 | if (key && value) {
57 | var hashCode;
58 | if (typeof (key) === "number" || typeof (key) === "string") {
59 | hashCode = key;
60 | } else {
61 | hashCode = key[this.hashcodeField()];
62 | }
63 | if (hashCode) {
64 | prev = this.backing_hash[hashCode];
65 | } else {
66 | this.code += 1;
67 | hashCode = this.hashkey_prefix + this.code;
68 | key[this.hashcodeField()] = hashCode;
69 | }
70 | this.backing_hash[hashCode] = [key, value];
71 | }
72 | return prev === undefined ? undefined : prev[1];
73 | },
74 | /*
75 | * returns value associated with given key
76 | */
77 | get: function(key) {
78 | var value;
79 | if (key) {
80 | var hashCode;
81 | if (typeof (key) === "number" || typeof (key) === "string") {
82 | hashCode = key;
83 | } else {
84 | hashCode = key[this.hashcodeField()];
85 | }
86 | if (hashCode) {
87 | value = this.backing_hash[hashCode];
88 | }
89 | }
90 | return value === undefined ? undefined : value[1];
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/lib/stats.min.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
3 | i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};
7 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/.gitignore:
--------------------------------------------------------------------------------
1 | /.DS_Store
2 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Parc_de_Belleville_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Parc_de_Belleville_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Place_Dauphine_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Place_Dauphine_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Place_de_la_Concorde_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/high/Place_de_la_Concorde_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Parc_de_Belleville_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Parc_de_Belleville_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Place_Dauphine_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Place_Dauphine_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Place_de_la_Concorde_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/low/Place_de_la_Concorde_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Parc_de_Belleville_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Parc_de_Belleville_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Place_Dauphine_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Place_Dauphine_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Place_de_la_Concorde_Paris.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/medium/Place_de_la_Concorde_Paris.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_default.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_pointer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_pointer.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_resize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_resize.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui-oculus-rift/textures/mouse_text.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui/.gitignore:
--------------------------------------------------------------------------------
1 | /.DS_Store
2 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui/THREE.SimpleDatGuiDemo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | THREE.SimpleDatGui Demo
5 |
6 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | Fork me on GitHub
101 |
335 |
336 |
337 |
338 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui/lib/TrackballControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eberhard Graether / http://egraether.com/
3 | * @author Mark Lundin / http://mark-lundin.com
4 | * @author Simone Manini / http://daron1337.github.io
5 | * @author Luca Antiga / http://lantiga.github.io
6 | */
7 |
8 | THREE.TrackballControls = function ( object, domElement ) {
9 |
10 | var _this = this;
11 | var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
12 |
13 | this.object = object;
14 | this.domElement = ( domElement !== undefined ) ? domElement : document;
15 |
16 | // API
17 |
18 | this.enabled = true;
19 |
20 | this.screen = { left: 0, top: 0, width: 0, height: 0 };
21 |
22 | this.rotateSpeed = 1.0;
23 | this.zoomSpeed = 1.2;
24 | this.panSpeed = 0.3;
25 |
26 | this.noRotate = false;
27 | this.noZoom = false;
28 | this.noPan = false;
29 |
30 | this.staticMoving = false;
31 | this.dynamicDampingFactor = 0.2;
32 |
33 | this.minDistance = 0;
34 | this.maxDistance = Infinity;
35 |
36 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
37 |
38 | // internals
39 |
40 | this.target = new THREE.Vector3();
41 |
42 | var EPS = 0.000001;
43 |
44 | var lastPosition = new THREE.Vector3();
45 |
46 | var _state = STATE.NONE,
47 | _prevState = STATE.NONE,
48 |
49 | _eye = new THREE.Vector3(),
50 |
51 | _movePrev = new THREE.Vector2(),
52 | _moveCurr = new THREE.Vector2(),
53 |
54 | _lastAxis = new THREE.Vector3(),
55 | _lastAngle = 0,
56 |
57 | _zoomStart = new THREE.Vector2(),
58 | _zoomEnd = new THREE.Vector2(),
59 |
60 | _touchZoomDistanceStart = 0,
61 | _touchZoomDistanceEnd = 0,
62 |
63 | _panStart = new THREE.Vector2(),
64 | _panEnd = new THREE.Vector2();
65 |
66 | // for reset
67 |
68 | this.target0 = this.target.clone();
69 | this.position0 = this.object.position.clone();
70 | this.up0 = this.object.up.clone();
71 |
72 | // events
73 |
74 | var changeEvent = { type: 'change' };
75 | var startEvent = { type: 'start' };
76 | var endEvent = { type: 'end' };
77 |
78 |
79 | // methods
80 |
81 | this.handleResize = function () {
82 |
83 | if ( this.domElement === document ) {
84 |
85 | this.screen.left = 0;
86 | this.screen.top = 0;
87 | this.screen.width = window.innerWidth;
88 | this.screen.height = window.innerHeight;
89 |
90 | } else {
91 |
92 | var box = this.domElement.getBoundingClientRect();
93 | // adjustments come from similar code in the jquery offset() function
94 | var d = this.domElement.ownerDocument.documentElement;
95 | this.screen.left = box.left + window.pageXOffset - d.clientLeft;
96 | this.screen.top = box.top + window.pageYOffset - d.clientTop;
97 | this.screen.width = box.width;
98 | this.screen.height = box.height;
99 |
100 | }
101 |
102 | };
103 |
104 | var getMouseOnScreen = ( function () {
105 |
106 | var vector = new THREE.Vector2();
107 |
108 | return function getMouseOnScreen( pageX, pageY ) {
109 |
110 | vector.set(
111 | ( pageX - _this.screen.left ) / _this.screen.width,
112 | ( pageY - _this.screen.top ) / _this.screen.height
113 | );
114 |
115 | return vector;
116 |
117 | };
118 |
119 | }() );
120 |
121 | var getMouseOnCircle = ( function () {
122 |
123 | var vector = new THREE.Vector2();
124 |
125 | return function getMouseOnCircle( pageX, pageY ) {
126 |
127 | vector.set(
128 | ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ),
129 | ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
130 | );
131 |
132 | return vector;
133 |
134 | };
135 |
136 | }() );
137 |
138 | this.rotateCamera = ( function () {
139 |
140 | var axis = new THREE.Vector3(),
141 | quaternion = new THREE.Quaternion(),
142 | eyeDirection = new THREE.Vector3(),
143 | objectUpDirection = new THREE.Vector3(),
144 | objectSidewaysDirection = new THREE.Vector3(),
145 | moveDirection = new THREE.Vector3(),
146 | angle;
147 |
148 | return function rotateCamera() {
149 |
150 | moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 );
151 | angle = moveDirection.length();
152 |
153 | if ( angle ) {
154 |
155 | _eye.copy( _this.object.position ).sub( _this.target );
156 |
157 | eyeDirection.copy( _eye ).normalize();
158 | objectUpDirection.copy( _this.object.up ).normalize();
159 | objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize();
160 |
161 | objectUpDirection.setLength( _moveCurr.y - _movePrev.y );
162 | objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x );
163 |
164 | moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) );
165 |
166 | axis.crossVectors( moveDirection, _eye ).normalize();
167 |
168 | angle *= _this.rotateSpeed;
169 | quaternion.setFromAxisAngle( axis, angle );
170 |
171 | _eye.applyQuaternion( quaternion );
172 | _this.object.up.applyQuaternion( quaternion );
173 |
174 | _lastAxis.copy( axis );
175 | _lastAngle = angle;
176 |
177 | } else if ( ! _this.staticMoving && _lastAngle ) {
178 |
179 | _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor );
180 | _eye.copy( _this.object.position ).sub( _this.target );
181 | quaternion.setFromAxisAngle( _lastAxis, _lastAngle );
182 | _eye.applyQuaternion( quaternion );
183 | _this.object.up.applyQuaternion( quaternion );
184 |
185 | }
186 |
187 | _movePrev.copy( _moveCurr );
188 |
189 | };
190 |
191 | }() );
192 |
193 |
194 | this.zoomCamera = function () {
195 |
196 | var factor;
197 |
198 | if ( _state === STATE.TOUCH_ZOOM_PAN ) {
199 |
200 | factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
201 | _touchZoomDistanceStart = _touchZoomDistanceEnd;
202 | _eye.multiplyScalar( factor );
203 |
204 | } else {
205 |
206 | factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
207 |
208 | if ( factor !== 1.0 && factor > 0.0 ) {
209 |
210 | _eye.multiplyScalar( factor );
211 |
212 | }
213 |
214 | if ( _this.staticMoving ) {
215 |
216 | _zoomStart.copy( _zoomEnd );
217 |
218 | } else {
219 |
220 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
221 |
222 | }
223 |
224 | }
225 |
226 | };
227 |
228 | this.panCamera = ( function () {
229 |
230 | var mouseChange = new THREE.Vector2(),
231 | objectUp = new THREE.Vector3(),
232 | pan = new THREE.Vector3();
233 |
234 | return function panCamera() {
235 |
236 | mouseChange.copy( _panEnd ).sub( _panStart );
237 |
238 | if ( mouseChange.lengthSq() ) {
239 |
240 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
241 |
242 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x );
243 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) );
244 |
245 | _this.object.position.add( pan );
246 | _this.target.add( pan );
247 |
248 | if ( _this.staticMoving ) {
249 |
250 | _panStart.copy( _panEnd );
251 |
252 | } else {
253 |
254 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
255 |
256 | }
257 |
258 | }
259 |
260 | };
261 |
262 | }() );
263 |
264 | this.checkDistances = function () {
265 |
266 | if ( ! _this.noZoom || ! _this.noPan ) {
267 |
268 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {
269 |
270 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );
271 | _zoomStart.copy( _zoomEnd );
272 |
273 | }
274 |
275 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
276 |
277 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
278 | _zoomStart.copy( _zoomEnd );
279 |
280 | }
281 |
282 | }
283 |
284 | };
285 |
286 | this.update = function () {
287 |
288 | _eye.subVectors( _this.object.position, _this.target );
289 |
290 | if ( ! _this.noRotate ) {
291 |
292 | _this.rotateCamera();
293 |
294 | }
295 |
296 | if ( ! _this.noZoom ) {
297 |
298 | _this.zoomCamera();
299 |
300 | }
301 |
302 | if ( ! _this.noPan ) {
303 |
304 | _this.panCamera();
305 |
306 | }
307 |
308 | _this.object.position.addVectors( _this.target, _eye );
309 |
310 | _this.checkDistances();
311 |
312 | _this.object.lookAt( _this.target );
313 |
314 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) {
315 |
316 | _this.dispatchEvent( changeEvent );
317 |
318 | lastPosition.copy( _this.object.position );
319 |
320 | }
321 |
322 | };
323 |
324 | this.reset = function () {
325 |
326 | _state = STATE.NONE;
327 | _prevState = STATE.NONE;
328 |
329 | _this.target.copy( _this.target0 );
330 | _this.object.position.copy( _this.position0 );
331 | _this.object.up.copy( _this.up0 );
332 |
333 | _eye.subVectors( _this.object.position, _this.target );
334 |
335 | _this.object.lookAt( _this.target );
336 |
337 | _this.dispatchEvent( changeEvent );
338 |
339 | lastPosition.copy( _this.object.position );
340 |
341 | };
342 |
343 | // listeners
344 |
345 | function keydown( event ) {
346 |
347 | if ( _this.enabled === false ) return;
348 |
349 | window.removeEventListener( 'keydown', keydown );
350 |
351 | _prevState = _state;
352 |
353 | if ( _state !== STATE.NONE ) {
354 |
355 | return;
356 |
357 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) {
358 |
359 | _state = STATE.ROTATE;
360 |
361 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) {
362 |
363 | _state = STATE.ZOOM;
364 |
365 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) {
366 |
367 | _state = STATE.PAN;
368 |
369 | }
370 |
371 | }
372 |
373 | function keyup( event ) {
374 |
375 | if ( _this.enabled === false ) return;
376 |
377 | _state = _prevState;
378 |
379 | window.addEventListener( 'keydown', keydown, false );
380 |
381 | }
382 |
383 | function mousedown( event ) {
384 |
385 | if ( _this.enabled === false ) return;
386 |
387 | event.preventDefault();
388 | event.stopPropagation();
389 |
390 | if ( _state === STATE.NONE ) {
391 |
392 | _state = event.button;
393 |
394 | }
395 |
396 | if ( _state === STATE.ROTATE && ! _this.noRotate ) {
397 |
398 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
399 | _movePrev.copy( _moveCurr );
400 |
401 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
402 |
403 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
404 | _zoomEnd.copy( _zoomStart );
405 |
406 | } else if ( _state === STATE.PAN && ! _this.noPan ) {
407 |
408 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
409 | _panEnd.copy( _panStart );
410 |
411 | }
412 |
413 | document.addEventListener( 'mousemove', mousemove, false );
414 | document.addEventListener( 'mouseup', mouseup, false );
415 |
416 | _this.dispatchEvent( startEvent );
417 |
418 | }
419 |
420 | function mousemove( event ) {
421 |
422 | if ( _this.enabled === false ) return;
423 |
424 | event.preventDefault();
425 | event.stopPropagation();
426 |
427 | if ( _state === STATE.ROTATE && ! _this.noRotate ) {
428 |
429 | _movePrev.copy( _moveCurr );
430 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
431 |
432 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) {
433 |
434 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
435 |
436 | } else if ( _state === STATE.PAN && ! _this.noPan ) {
437 |
438 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
439 |
440 | }
441 |
442 | }
443 |
444 | function mouseup( event ) {
445 |
446 | if ( _this.enabled === false ) return;
447 |
448 | event.preventDefault();
449 | event.stopPropagation();
450 |
451 | _state = STATE.NONE;
452 |
453 | document.removeEventListener( 'mousemove', mousemove );
454 | document.removeEventListener( 'mouseup', mouseup );
455 | _this.dispatchEvent( endEvent );
456 |
457 | }
458 |
459 | function mousewheel( event ) {
460 |
461 | if ( _this.enabled === false ) return;
462 |
463 | if ( _this.noZoom === true ) return;
464 |
465 | event.preventDefault();
466 | event.stopPropagation();
467 |
468 | switch ( event.deltaMode ) {
469 |
470 | case 2:
471 | // Zoom in pages
472 | _zoomStart.y -= event.deltaY * 0.025;
473 | break;
474 |
475 | case 1:
476 | // Zoom in lines
477 | _zoomStart.y -= event.deltaY * 0.01;
478 | break;
479 |
480 | default:
481 | // undefined, 0, assume pixels
482 | _zoomStart.y -= event.deltaY * 0.00025;
483 | break;
484 |
485 | }
486 |
487 | _this.dispatchEvent( startEvent );
488 | _this.dispatchEvent( endEvent );
489 |
490 | }
491 |
492 | function touchstart( event ) {
493 |
494 | if ( _this.enabled === false ) return;
495 |
496 | event.preventDefault();
497 |
498 | switch ( event.touches.length ) {
499 |
500 | case 1:
501 | _state = STATE.TOUCH_ROTATE;
502 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
503 | _movePrev.copy( _moveCurr );
504 | break;
505 |
506 | default: // 2 or more
507 | _state = STATE.TOUCH_ZOOM_PAN;
508 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
509 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
510 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
511 |
512 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
513 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
514 | _panStart.copy( getMouseOnScreen( x, y ) );
515 | _panEnd.copy( _panStart );
516 | break;
517 |
518 | }
519 |
520 | _this.dispatchEvent( startEvent );
521 |
522 | }
523 |
524 | function touchmove( event ) {
525 |
526 | if ( _this.enabled === false ) return;
527 |
528 | event.preventDefault();
529 | event.stopPropagation();
530 |
531 | switch ( event.touches.length ) {
532 |
533 | case 1:
534 | _movePrev.copy( _moveCurr );
535 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
536 | break;
537 |
538 | default: // 2 or more
539 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
540 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
541 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
542 |
543 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2;
544 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2;
545 | _panEnd.copy( getMouseOnScreen( x, y ) );
546 | break;
547 |
548 | }
549 |
550 | }
551 |
552 | function touchend( event ) {
553 |
554 | if ( _this.enabled === false ) return;
555 |
556 | switch ( event.touches.length ) {
557 |
558 | case 0:
559 | _state = STATE.NONE;
560 | break;
561 |
562 | case 1:
563 | _state = STATE.TOUCH_ROTATE;
564 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) );
565 | _movePrev.copy( _moveCurr );
566 | break;
567 |
568 | }
569 |
570 | _this.dispatchEvent( endEvent );
571 |
572 | }
573 |
574 | function contextmenu( event ) {
575 |
576 | if ( _this.enabled === false ) return;
577 |
578 | event.preventDefault();
579 |
580 | }
581 |
582 | this.dispose = function () {
583 |
584 | this.domElement.removeEventListener( 'contextmenu', contextmenu, false );
585 | this.domElement.removeEventListener( 'mousedown', mousedown, false );
586 | this.domElement.removeEventListener( 'wheel', mousewheel, {passive: true} );
587 |
588 | this.domElement.removeEventListener( 'touchstart', touchstart, {passive: true} );
589 | this.domElement.removeEventListener( 'touchend', touchend, {passive: true} );
590 | this.domElement.removeEventListener( 'touchmove', touchmove, {passive: true} );
591 |
592 | document.removeEventListener( 'mousemove', mousemove, false );
593 | document.removeEventListener( 'mouseup', mouseup, false );
594 |
595 | window.removeEventListener( 'keydown', keydown, false );
596 | window.removeEventListener( 'keyup', keyup, false );
597 |
598 | };
599 |
600 | this.domElement.addEventListener( 'contextmenu', contextmenu, false );
601 | this.domElement.addEventListener( 'mousedown', mousedown, false );
602 | this.domElement.addEventListener( 'wheel', mousewheel, {passive: true} );
603 |
604 | this.domElement.addEventListener( 'touchstart', touchstart, {passive: true} );
605 | this.domElement.addEventListener( 'touchend', touchend, {passive: true} );
606 | this.domElement.addEventListener( 'touchmove', touchmove, {passive: true} );
607 |
608 | window.addEventListener( 'keydown', keydown, false );
609 | window.addEventListener( 'keyup', keyup, false );
610 |
611 | this.handleResize();
612 |
613 | // force an update at start
614 | this.update();
615 |
616 | };
617 |
618 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
619 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls;
620 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/simple-webgl-gui/lib/stats.min.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
3 | i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};
7 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/lib/detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 |
8 | canvas: !! window.CanvasRenderingContext2D,
9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
10 | workers: !! window.Worker,
11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
12 |
13 | getWebGLErrorMessage: function () {
14 |
15 | var element = document.createElement( 'div' );
16 | element.id = 'webgl-error-message';
17 | element.style.fontFamily = 'monospace';
18 | element.style.fontSize = '13px';
19 | element.style.fontWeight = 'normal';
20 | element.style.textAlign = 'center';
21 | element.style.background = '#fff';
22 | element.style.color = '#000';
23 | element.style.padding = '1.5em';
24 | element.style.width = '400px';
25 | element.style.margin = '5em auto 0';
26 |
27 | if ( ! this.webgl ) {
28 |
29 | element.innerHTML = window.WebGLRenderingContext ? [
30 | 'Your graphics card does not seem to support WebGL. ',
31 | 'Find out how to get it here.'
32 | ].join( '\n' ) : [
33 | 'Your browser does not seem to support WebGL. ',
34 | 'Find out how to get it here.'
35 | ].join( '\n' );
36 |
37 | }
38 |
39 | return element;
40 |
41 | },
42 |
43 | addGetWebGLMessage: function ( parameters ) {
44 |
45 | var parent, id, element;
46 |
47 | parameters = parameters || {};
48 |
49 | parent = parameters.parent !== undefined ? parameters.parent : document.body;
50 | id = parameters.id !== undefined ? parameters.id : 'oldie';
51 |
52 | element = Detector.getWebGLErrorMessage();
53 | element.id = id;
54 |
55 | parent.appendChild( element );
56 |
57 | }
58 |
59 | };
60 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/lib/hashmap.js:
--------------------------------------------------------------------------------
1 | /*
2 | =====================================================================
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions
5 | are met:
6 |
7 | 1. Redistributions of source code must retain the above
8 | copyright notice, this list of conditions and the following
9 | disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | 3. The name of the author may not be used to endorse or promote
17 | products derived from this software without specific prior
18 | written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
21 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | @author Daniel Kwiecinski
33 | @copyright 2009 Daniel Kwiecinski.
34 | @end
35 | =====================================================================
36 | */
37 | var HashMap = function() {
38 | this.initialize();
39 | }
40 |
41 | HashMap.prototype = {
42 | hashkey_prefix : "<#HashMapHashkeyPerfix>",
43 | hashcode_field : "<#HashMapHashcodeField>",
44 | hashmap_instance_id : 0,
45 |
46 | initialize : function() {
47 | this.backing_hash = {};
48 | this.code = 0;
49 | this.hashmap_instance_id += 1;
50 | this.instance_id = this.hashmap_instance_id;
51 | },
52 |
53 | hashcodeField : function() {
54 | return this.hashcode_field + this.instance_id;
55 | },
56 | /*
57 | * maps value to key returning previous assocciation
58 | */
59 | put : function(key, value) {
60 | var prev;
61 |
62 | if (key && value) {
63 | var hashCode;
64 | if (typeof (key) === "number" || typeof (key) === "string") {
65 | hashCode = key;
66 | } else {
67 | hashCode = key[this.hashcodeField()];
68 | }
69 | if (hashCode) {
70 | prev = this.backing_hash[hashCode];
71 | } else {
72 | this.code += 1;
73 | hashCode = this.hashkey_prefix + this.code;
74 | key[this.hashcodeField()] = hashCode;
75 | }
76 | this.backing_hash[hashCode] = [ key, value ];
77 | }
78 | return prev === undefined ? undefined : prev[1];
79 | },
80 | /*
81 | * returns value associated with given key
82 | */
83 | get : function(key) {
84 | var value;
85 | if (key) {
86 | var hashCode;
87 | if (typeof (key) === "number" || typeof (key) === "string") {
88 | hashCode = key;
89 | } else {
90 | hashCode = key[this.hashcodeField()];
91 | }
92 | if (hashCode) {
93 | value = this.backing_hash[hashCode];
94 | }
95 | }
96 | return value === undefined ? undefined : value[1];
97 | },
98 | /*
99 | * deletes association by given key. Returns true if the assocciation
100 | * existed, false otherwise
101 | */
102 | del : function(key) {
103 | var success = false;
104 | if (key) {
105 | var hashCode;
106 | if (typeof (key) === "number" || typeof (key) === "string") {
107 | hashCode = key;
108 | } else {
109 | hashCode = key[this.hashcodeField()];
110 | }
111 | if (hashCode) {
112 | var prev = this.backing_hash[hashCode];
113 | this.backing_hash[hashCode] = undefined;
114 | if (prev !== undefined) {
115 | key[this.hashcodeField()] = undefined; // let's clean the
116 | // key object
117 | success = true;
118 | }
119 | }
120 | }
121 | return success;
122 | },
123 | /*
124 | * iterate over key-value pairs passing them to provided callback the
125 | * iteration process is interrupted when the callback returns false. the
126 | * execution context of the callback is the value of the key-value pair @
127 | * returns the HashMap (so we can chain) (
128 | */
129 | each : function(callback, args) {
130 | var key;
131 | for (key in this.backing_hash) {
132 | if (callback.call(this.backing_hash[key][1], this.backing_hash[key][0], this.backing_hash[key][1]) === false)
133 | break;
134 | }
135 | return this;
136 | },
137 | toString : function() {
138 | return "HashMapJS"
139 | }
140 |
141 | }
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/lib/stats.min.js:
--------------------------------------------------------------------------------
1 | // stats.js - http://github.com/mrdoob/stats.js
2 | var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
3 | i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};
7 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/lib/trackballcontrols.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eberhard Graether / http://egraether.com/
3 | */
4 |
5 | THREE.TrackballControls = function ( object, domElement ) {
6 |
7 | var _this = this;
8 | var STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5 };
9 |
10 | this.object = object;
11 | this.domElement = ( domElement !== undefined ) ? domElement : document;
12 |
13 | // API
14 |
15 | this.enabled = true;
16 |
17 | this.screen = { left: 0, top: 0, width: 0, height: 0 };
18 |
19 | this.rotateSpeed = 1.0;
20 | this.zoomSpeed = 1.2;
21 | this.panSpeed = 0.3;
22 |
23 | this.noRotate = false;
24 | this.noZoom = false;
25 | this.noPan = false;
26 | this.noRoll = false;
27 |
28 | this.staticMoving = false;
29 | this.dynamicDampingFactor = 0.2;
30 |
31 | this.minDistance = 0;
32 | this.maxDistance = Infinity;
33 |
34 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
35 |
36 | // internals
37 |
38 | this.target = new THREE.Vector3();
39 |
40 | var lastPosition = new THREE.Vector3();
41 |
42 | var _state = STATE.NONE,
43 | _prevState = STATE.NONE,
44 |
45 | _eye = new THREE.Vector3(),
46 |
47 | _rotateStart = new THREE.Vector3(),
48 | _rotateEnd = new THREE.Vector3(),
49 |
50 | _zoomStart = new THREE.Vector2(),
51 | _zoomEnd = new THREE.Vector2(),
52 |
53 | _touchZoomDistanceStart = 0,
54 | _touchZoomDistanceEnd = 0,
55 |
56 | _panStart = new THREE.Vector2(),
57 | _panEnd = new THREE.Vector2();
58 |
59 | // for reset
60 |
61 | this.target0 = this.target.clone();
62 | this.position0 = this.object.position.clone();
63 | this.up0 = this.object.up.clone();
64 |
65 | // events
66 |
67 | var changeEvent = { type: 'change' };
68 |
69 |
70 | // methods
71 |
72 | this.handleResize = function () {
73 |
74 | if ( this.domElement === document ) {
75 |
76 | this.screen.left = 0;
77 | this.screen.top = 0;
78 | this.screen.width = window.innerWidth;
79 | this.screen.height = window.innerHeight;
80 |
81 | } else {
82 |
83 | this.screen = this.domElement.getBoundingClientRect();
84 |
85 | }
86 |
87 | };
88 |
89 | this.handleEvent = function ( event ) {
90 |
91 | if ( typeof this[ event.type ] == 'function' ) {
92 |
93 | this[ event.type ]( event );
94 |
95 | }
96 |
97 | };
98 |
99 | this.getMouseOnScreen = function ( clientX, clientY ) {
100 |
101 | return new THREE.Vector2(
102 | ( clientX - _this.screen.left ) / _this.screen.width,
103 | ( clientY - _this.screen.top ) / _this.screen.height
104 | );
105 |
106 | };
107 |
108 | this.getMouseProjectionOnBall = function ( clientX, clientY ) {
109 |
110 | var mouseOnBall = new THREE.Vector3(
111 | ( clientX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
112 | ( _this.screen.height * 0.5 + _this.screen.top - clientY ) / (_this.screen.height*.5),
113 | 0.0
114 | );
115 |
116 | var length = mouseOnBall.length();
117 |
118 | if ( _this.noRoll ) {
119 |
120 | if ( length < Math.SQRT1_2 ) {
121 |
122 | mouseOnBall.z = Math.sqrt( 1.0 - length*length );
123 |
124 | } else {
125 |
126 | mouseOnBall.z = .5 / length;
127 |
128 | }
129 |
130 | } else if ( length > 1.0 ) {
131 |
132 | mouseOnBall.normalize();
133 |
134 | } else {
135 |
136 | mouseOnBall.z = Math.sqrt( 1.0 - length * length );
137 |
138 | }
139 |
140 | _eye.copy( _this.object.position ).sub( _this.target );
141 |
142 | var projection = _this.object.up.clone().setLength( mouseOnBall.y );
143 | projection.add( _this.object.up.clone().cross( _eye ).setLength( mouseOnBall.x ) );
144 | projection.add( _eye.setLength( mouseOnBall.z ) );
145 |
146 | return projection;
147 |
148 | };
149 |
150 | this.rotateCamera = function () {
151 |
152 | var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
153 |
154 | if ( angle ) {
155 |
156 | var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize(),
157 | quaternion = new THREE.Quaternion();
158 |
159 | angle *= _this.rotateSpeed;
160 |
161 | quaternion.setFromAxisAngle( axis, -angle );
162 |
163 | _eye.applyQuaternion( quaternion );
164 | _this.object.up.applyQuaternion( quaternion );
165 |
166 | _rotateEnd.applyQuaternion( quaternion );
167 |
168 | if ( _this.staticMoving ) {
169 |
170 | _rotateStart.copy( _rotateEnd );
171 |
172 | } else {
173 |
174 | quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
175 | _rotateStart.applyQuaternion( quaternion );
176 |
177 | }
178 |
179 | }
180 |
181 | };
182 |
183 | this.zoomCamera = function () {
184 |
185 | if ( _state === STATE.TOUCH_ZOOM ) {
186 |
187 | var factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
188 | _touchZoomDistanceStart = _touchZoomDistanceEnd;
189 | _eye.multiplyScalar( factor );
190 |
191 | } else {
192 |
193 | var factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed;
194 |
195 | if ( factor !== 1.0 && factor > 0.0 ) {
196 |
197 | _eye.multiplyScalar( factor );
198 |
199 | if ( _this.staticMoving ) {
200 |
201 | _zoomStart.copy( _zoomEnd );
202 |
203 | } else {
204 |
205 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
206 |
207 | }
208 |
209 | }
210 |
211 | }
212 |
213 | };
214 |
215 | this.panCamera = function () {
216 |
217 | var mouseChange = _panEnd.clone().sub( _panStart );
218 |
219 | if ( mouseChange.lengthSq() ) {
220 |
221 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed );
222 |
223 | var pan = _eye.clone().cross( _this.object.up ).setLength( mouseChange.x );
224 | pan.add( _this.object.up.clone().setLength( mouseChange.y ) );
225 |
226 | _this.object.position.add( pan );
227 | _this.target.add( pan );
228 |
229 | if ( _this.staticMoving ) {
230 |
231 | _panStart = _panEnd;
232 |
233 | } else {
234 |
235 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
236 |
237 | }
238 |
239 | }
240 |
241 | };
242 |
243 | this.checkDistances = function () {
244 |
245 | if ( !_this.noZoom || !_this.noPan ) {
246 |
247 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) {
248 |
249 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) );
250 |
251 | }
252 |
253 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) {
254 |
255 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) );
256 |
257 | }
258 |
259 | }
260 |
261 | };
262 |
263 | this.update = function () {
264 |
265 | _eye.subVectors( _this.object.position, _this.target );
266 |
267 | if ( !_this.noRotate ) {
268 |
269 | _this.rotateCamera();
270 |
271 | }
272 |
273 | if ( !_this.noZoom ) {
274 |
275 | _this.zoomCamera();
276 |
277 | }
278 |
279 | if ( !_this.noPan ) {
280 |
281 | _this.panCamera();
282 |
283 | }
284 |
285 | _this.object.position.addVectors( _this.target, _eye );
286 |
287 | _this.checkDistances();
288 |
289 | _this.object.lookAt( _this.target );
290 |
291 | if ( lastPosition.distanceToSquared( _this.object.position ) > 0 ) {
292 |
293 | _this.dispatchEvent( changeEvent );
294 |
295 | lastPosition.copy( _this.object.position );
296 |
297 | }
298 |
299 | };
300 |
301 | this.reset = function () {
302 |
303 | _state = STATE.NONE;
304 | _prevState = STATE.NONE;
305 |
306 | _this.target.copy( _this.target0 );
307 | _this.object.position.copy( _this.position0 );
308 | _this.object.up.copy( _this.up0 );
309 |
310 | _eye.subVectors( _this.object.position, _this.target );
311 |
312 | _this.object.lookAt( _this.target );
313 |
314 | _this.dispatchEvent( changeEvent );
315 |
316 | lastPosition.copy( _this.object.position );
317 |
318 | };
319 |
320 | // listeners
321 |
322 | function keydown( event ) {
323 |
324 | if ( _this.enabled === false ) return;
325 |
326 | window.removeEventListener( 'keydown', keydown );
327 |
328 | _prevState = _state;
329 |
330 | if ( _state !== STATE.NONE ) {
331 |
332 | return;
333 |
334 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && !_this.noRotate ) {
335 |
336 | _state = STATE.ROTATE;
337 |
338 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && !_this.noZoom ) {
339 |
340 | _state = STATE.ZOOM;
341 |
342 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && !_this.noPan ) {
343 |
344 | _state = STATE.PAN;
345 |
346 | }
347 |
348 | }
349 |
350 | function keyup( event ) {
351 |
352 | if ( _this.enabled === false ) return;
353 |
354 | _state = _prevState;
355 |
356 | window.addEventListener( 'keydown', keydown, false );
357 |
358 | }
359 |
360 | function mousedown( event ) {
361 |
362 | if ( _this.enabled === false ) return;
363 |
364 | event.preventDefault();
365 | event.stopPropagation();
366 |
367 | if ( _state === STATE.NONE ) {
368 |
369 | _state = event.button;
370 |
371 | }
372 |
373 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
374 |
375 | _rotateStart = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
376 | _rotateEnd.copy(_rotateStart)
377 |
378 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
379 |
380 | _zoomStart = _this.getMouseOnScreen( event.clientX, event.clientY );
381 | _zoomEnd.copy(_zoomStart);
382 |
383 | } else if ( _state === STATE.PAN && !_this.noPan ) {
384 |
385 | _panStart = _this.getMouseOnScreen( event.clientX, event.clientY );
386 | _panEnd.copy(_panStart)
387 |
388 | }
389 |
390 | document.addEventListener( 'mousemove', mousemove, false );
391 | document.addEventListener( 'mouseup', mouseup, false );
392 |
393 | }
394 |
395 | function mousemove( event ) {
396 |
397 | if ( _this.enabled === false ) return;
398 |
399 | event.preventDefault();
400 | event.stopPropagation();
401 |
402 | if ( _state === STATE.ROTATE && !_this.noRotate ) {
403 |
404 | _rotateEnd = _this.getMouseProjectionOnBall( event.clientX, event.clientY );
405 |
406 | } else if ( _state === STATE.ZOOM && !_this.noZoom ) {
407 |
408 | _zoomEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
409 |
410 | } else if ( _state === STATE.PAN && !_this.noPan ) {
411 |
412 | _panEnd = _this.getMouseOnScreen( event.clientX, event.clientY );
413 |
414 | }
415 |
416 | }
417 |
418 | function mouseup( event ) {
419 |
420 | if ( _this.enabled === false ) return;
421 |
422 | event.preventDefault();
423 | event.stopPropagation();
424 |
425 | _state = STATE.NONE;
426 |
427 | document.removeEventListener( 'mousemove', mousemove );
428 | document.removeEventListener( 'mouseup', mouseup );
429 |
430 | }
431 |
432 | function mousewheel( event ) {
433 |
434 | if ( _this.enabled === false ) return;
435 |
436 | event.preventDefault();
437 | event.stopPropagation();
438 |
439 | var delta = 0;
440 |
441 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
442 |
443 | delta = event.wheelDelta / 40;
444 |
445 | } else if ( event.detail ) { // Firefox
446 |
447 | delta = - event.detail / 3;
448 |
449 | }
450 |
451 | _zoomStart.y += delta * 0.01;
452 |
453 | }
454 |
455 | function touchstart( event ) {
456 |
457 | if ( _this.enabled === false ) return;
458 |
459 | switch ( event.touches.length ) {
460 |
461 | case 1:
462 | _state = STATE.TOUCH_ROTATE;
463 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
464 | break;
465 |
466 | case 2:
467 | _state = STATE.TOUCH_ZOOM;
468 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
469 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
470 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
471 | break;
472 |
473 | case 3:
474 | _state = STATE.TOUCH_PAN;
475 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
476 | break;
477 |
478 | default:
479 | _state = STATE.NONE;
480 |
481 | }
482 |
483 | }
484 |
485 | function touchmove( event ) {
486 |
487 | if ( _this.enabled === false ) return;
488 |
489 | event.preventDefault();
490 | event.stopPropagation();
491 |
492 | switch ( event.touches.length ) {
493 |
494 | case 1:
495 | _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
496 | break;
497 |
498 | case 2:
499 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
500 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
501 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy )
502 | break;
503 |
504 | case 3:
505 | _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
506 | break;
507 |
508 | default:
509 | _state = STATE.NONE;
510 |
511 | }
512 |
513 | }
514 |
515 | function touchend( event ) {
516 |
517 | if ( _this.enabled === false ) return;
518 |
519 | switch ( event.touches.length ) {
520 |
521 | case 1:
522 | _rotateStart = _rotateEnd = _this.getMouseProjectionOnBall( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
523 | break;
524 |
525 | case 2:
526 | _touchZoomDistanceStart = _touchZoomDistanceEnd = 0;
527 | break;
528 |
529 | case 3:
530 | _panStart = _panEnd = _this.getMouseOnScreen( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
531 | break;
532 |
533 | }
534 |
535 | _state = STATE.NONE;
536 |
537 | }
538 |
539 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
540 |
541 | this.domElement.addEventListener( 'mousedown', mousedown, false );
542 |
543 | this.domElement.addEventListener( 'mousewheel', mousewheel, false );
544 | this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
545 |
546 | this.domElement.addEventListener( 'touchstart', touchstart, false );
547 | this.domElement.addEventListener( 'touchend', touchend, false );
548 | this.domElement.addEventListener( 'touchmove', touchmove, false );
549 |
550 | window.addEventListener( 'keydown', keydown, false );
551 | window.addEventListener( 'keyup', keyup, false );
552 |
553 | this.handleResize();
554 |
555 | };
556 |
557 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
558 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/melon.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
85 | Square Watermelon
86 |
87 |
88 |
89 |
90 | Fork me on GitHub
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/melon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/square-melon/melon.jpg
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/square-melon/melon.main.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (C) 2013-2018, Markus Sprunck
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | * - Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * - Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | * - The name of its contributor may be used to endorse or promote products
14 | * derived from this software without specific prior written permission.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | * POSSIBILITY OF SUCH DAMAGE.
27 | *
28 | ******************************************************************************/
29 | /**
30 | * Global constants
31 | */
32 | var BORDER_LEFT = 10;
33 | var BORDER_TOP = 10;
34 | var BORDER_RIGHT = 10;
35 | var BORDER_BOTTOM = 10;
36 |
37 | /**
38 | * Global variables for rendering
39 | */
40 | var g_panelWidthWebGL;
41 | var g_panelHeightWebGL;
42 | var g_scene;
43 | var g_camera;
44 | var g_renderer;
45 | var g_control;
46 | var g_gui;
47 | var g_melon;
48 |
49 | /**
50 | * Initialize WebGL
51 | */
52 | function initWebGL() {
53 | "use strict";
54 | // Container for WebGL rendering
55 | var container = document.getElementById('graphic-container');
56 | container.style.background = "#444444";
57 | initDatGui(container);
58 |
59 | // Size of drawing
60 | g_panelWidthWebGL = window.innerWidth - BORDER_RIGHT - BORDER_LEFT;
61 | g_panelHeightWebGL = window.innerHeight - BORDER_BOTTOM - BORDER_TOP;
62 |
63 | // Create g_camera
64 | g_camera = new THREE.PerspectiveCamera(40, g_panelWidthWebGL
65 | / g_panelHeightWebGL, 1, 40000);
66 | resetCamera();
67 |
68 | // Create g_scene
69 | g_scene = new THREE.Scene();
70 | g_scene.add(g_camera);
71 |
72 | // Create g_renderer
73 | if (Detector.webgl) {
74 | g_renderer = new THREE.WebGLRenderer({
75 | antialias : true
76 | });
77 | } else {
78 | container.appendChild(Detector.getWebGLErrorMessage());
79 | return;
80 | }
81 | g_renderer.setSize(g_panelWidthWebGL, g_panelHeightWebGL);
82 | g_renderer.setClearColor(0x444444);
83 | container.appendChild(g_renderer.domElement);
84 |
85 |
86 | // LIGHTS
87 | var light = new THREE.DirectionalLight( 0xffffff, 1.475 );
88 | light.position.set( -1000, 1000, 1000 );
89 | g_scene.add( light );
90 |
91 | var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.3 );
92 | hemiLight.position.set( 0, 5000, 0 );
93 | g_scene.add( hemiLight );
94 |
95 | // Support window resize
96 | var resizeCallback = function() {
97 | g_panelWidthWebGL = window.innerWidth - BORDER_RIGHT - BORDER_LEFT;
98 | g_panelHeightWebGL = window.innerHeight - BORDER_BOTTOM - BORDER_TOP;
99 | var devicePixelRatio = window.devicePixelRatio || 1;
100 | g_renderer.setSize(g_panelWidthWebGL * devicePixelRatio,
101 | g_panelHeightWebGL * devicePixelRatio);
102 | g_renderer.domElement.style.width = g_panelWidthWebGL + 'px';
103 | g_renderer.domElement.style.height = g_panelHeightWebGL + 'px';
104 | resetCamera();
105 | g_camera.updateProjectionMatrix();
106 | g_gui.domElement.style.position = 'absolute';
107 | g_gui.domElement.style.right = '' + (BORDER_RIGHT) + 'px';
108 | g_gui.domElement.style.top = '' + (BORDER_TOP) + 'px';
109 | };
110 | window.addEventListener('resize', resizeCallback, false);
111 | resizeCallback();
112 |
113 | g_control = new THREE.TrackballControls(g_camera, g_renderer.domElement);
114 | g_control.target.set(0, 0, 0);
115 | g_control.rotateSpeed = 1.0;
116 | g_control.zoomSpeed = 1.2;
117 | g_control.panSpeed = 0.8;
118 | g_control.noZoom = false;
119 | g_control.noPan = false;
120 | g_control.staticMoving = false;
121 | g_control.dynamicDampingFactor = 0.15;
122 | g_control.keys = [ 65, 83, 68 ];
123 | g_control.addEventListener('change', renderer);
124 |
125 | // create melone with texture
126 | var loader = new THREE.TextureLoader();
127 | loader.load('melon.jpg', function(texture) {
128 | var geometry = new THREE.SphereGeometry(800, 16, 20);
129 | var material = new THREE.MeshLambertMaterial({
130 | map : texture,
131 | depthTest : true
132 | });
133 | g_melon = new THREE.Mesh(geometry, material);
134 | g_melon.geometry.dynamic = true;
135 | if (MELONE_SimulationOptions.SHOW_MELON_TEXTURE) {
136 | g_scene.add(g_melon);
137 | }
138 | MELONE_NBodySimulator.createModelFromSphere(g_melon);
139 | });
140 |
141 | // Start animation
142 | animate();
143 | }
144 |
145 | /**
146 | * Render WebGL with about 60 fames per second if possible
147 | */
148 |
149 | function animate() {
150 | "use strict";
151 | requestAnimationFrame(animate);
152 |
153 | g_control.update();
154 |
155 | // simulate forces
156 | if (MELONE_SimulationOptions.RUN_SIMULATION) {
157 | for (var i = 0; i < 3; i++) {
158 | MELONE_NBodySimulator.simulateAllForces();
159 | }
160 | }
161 |
162 | // update position of the melone
163 | if (null != g_melon) {
164 | MELONE_NBodySimulator.updateMelon(g_melon);
165 | }
166 |
167 | // update wire frame
168 | var nodes = MELONE_NBodySimulator.node_list;
169 | for ( var i = 0; i < nodes.length; i++) {
170 | renderNodeSphere(nodes[i]);
171 | }
172 | var links = MELONE_NBodySimulator.link_list;
173 | for (i = 0; i < links.length; i++) {
174 | renderLineElementForLink(links[i]);
175 | }
176 |
177 | renderer();
178 | }
179 |
180 | function renderer() {
181 | "use strict";
182 | g_renderer.render(g_scene, g_camera);
183 | }
184 |
185 |
186 |
187 | /**
188 | * Renders sphere for the node
189 | */
190 |
191 | function renderNodeSphere(node) {
192 | "use strict";
193 | if (node.sphereCreated) {
194 | // Update position
195 | node.sphere.position.x = node.x;
196 | node.sphere.position.z = node.z;
197 | node.sphere.position.y = node.y;
198 | node.sphere.visible = !MELONE_SimulationOptions.SHOW_MELON_TEXTURE;
199 | } else {
200 | // Create sphere
201 | var material = new THREE.MeshLambertMaterial({
202 | reflectivity : 0.9,
203 | depthTest : true,
204 | transparent : true,
205 | color : 0x444444
206 | });
207 | node.sphere = new THREE.Mesh(new THREE.SphereGeometry(
208 | MELONE_SimulationOptions.SPHERE_RADIUS_MINIMUM), material);
209 | node.sphere.position.x = node.x;
210 | node.sphere.position.z = node.z;
211 | node.sphere.position.y = node.y;
212 | node.sphere.visible = false;
213 | g_scene.add(node.sphere);
214 | node.sphereCreated = true;
215 | }
216 | }
217 |
218 | /**
219 | * Renders a link - optional with arrow head
220 | */
221 |
222 | function renderLineElementForLink(link) {
223 | "use strict";
224 |
225 | // Center position of the nodes
226 | var source_position = new THREE.Vector3(link.source.x, link.source.y,
227 | link.source.z);
228 | var target_position = new THREE.Vector3(link.target.x, link.target.y,
229 | link.target.z);
230 |
231 | if (link.linkWebGLCreated) {
232 | // Move existing line
233 | link.threeElement.geometry.vertices[0] = source_position;
234 | link.threeElement.geometry.vertices[1] = target_position;
235 | link.threeElement.geometry.verticesNeedUpdate = true;
236 | link.threeElement.visible = !MELONE_SimulationOptions.SHOW_MELON_TEXTURE;
237 | } else {
238 | // Create line
239 | var line_geometry = new THREE.Geometry();
240 | line_geometry.vertices.push(source_position);
241 | line_geometry.vertices.push(target_position);
242 | var line_material = new THREE.LineBasicMaterial({
243 | depthTest : true,
244 | transparent : true,
245 | opacity : 1.0,
246 | color: 0xAAAAAA
247 | });
248 | line_material.transparent = true;
249 | var line = new THREE.Line(line_geometry, line_material);
250 | line.visible = false;
251 | link.threeElement = line;
252 | link.linkWebGLCreated = true;
253 | g_scene.add(line);
254 | }
255 | }
256 |
257 | function resetCamera() {
258 | "use strict";
259 | g_camera.position.x = MELONE_SimulationOptions.SPHERE_RADIUS * 2.5;
260 | g_camera.position.y = MELONE_SimulationOptions.SPHERE_RADIUS * 2.5;
261 | g_camera.position.z = MELONE_SimulationOptions.SPHERE_RADIUS * 4;
262 | g_camera.lookAt(new THREE.Vector3(0, 0, 0));
263 | }
264 |
265 | /**
266 | * User interface to change parameters
267 | */
268 | function initDatGui(container) {
269 | g_gui = new dat.GUI({
270 | autoPlace : false
271 | });
272 |
273 | f1 = g_gui.addFolder('Render Options');
274 | f1.add(MELONE_SimulationOptions, 'SHOW_MELON_TEXTURE').name('Show Texture')
275 | .onChange(function(value) {
276 | if (value) {
277 | g_scene.add(g_melon);
278 | } else {
279 | g_scene.remove(g_melon);
280 | }
281 | });
282 | f1.open();
283 |
284 | f3 = g_gui.addFolder('N-Body Simulation');
285 | f3.add(MELONE_SimulationOptions, 'RUN_SIMULATION').name('Run');
286 | f3.add(MELONE_SimulationOptions, 'SPRING', 5.0, 20.0).step(1.0).name(
287 | 'Spring Link');
288 | f3.add(MELONE_SimulationOptions, 'CHARGE', 5, 40).step(1.0).name('Charge');
289 | f3.open();
290 |
291 | container.appendChild(g_gui.domElement);
292 | }
293 |
294 | /**
295 | * Call initialization
296 | */
297 | initWebGL();
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/bendModifier.js:
--------------------------------------------------------------------------------
1 | /** The Bend modifier lets you bend the current selection up to 90 degrees about a single axis,
2 | * producing a uniform bend in an object's geometry.
3 | * You can control the angle and direction of the bend on any of three axes.
4 | * The geometry has to have rather large number of polygons!
5 | * options:
6 | * direction - deformation direction (in local coordinates!).
7 | * axis - deformation axis (in local coordinates!). Vector of direction and axis are perpendicular.
8 | * angle - deformation angle.
9 | * @author Vildanov Almaz / alvild@gmail.com
10 | * The algorithm of a bend is based on the chain line cosh: y = 1/b * cosh(b*x) - 1/b. It can be used only in three.js.
11 | */
12 |
13 | THREE.BendModifier = function () {
14 |
15 | };
16 |
17 | THREE.BendModifier.prototype = {
18 |
19 | constructor: THREE.BendModifier,
20 |
21 | set: function ( direction, axis, angle ) {
22 | this.direction = new THREE.Vector3(); this.direction.copy( direction );
23 | this.axis = new THREE.Vector3(); this.axis.copy( axis );
24 | this.angle = angle;
25 | return this
26 | },
27 |
28 | _sign: function (a) {
29 | return 0 > a ? -1 : 0 < a ? 1 : 0
30 | },
31 |
32 | _cosh: function( x ) {
33 | return ( Math.exp( x ) + Math.exp( -x ) ) / 2;
34 | },
35 |
36 | _sinhInverse: function( x ) {
37 | return Math.log( Math.abs( x ) + Math.sqrt( x * x + 1 ) );
38 | },
39 |
40 | modify: function ( geometry ) {
41 |
42 | var thirdAxis = new THREE.Vector3(); thirdAxis.crossVectors( this.direction, this.axis );
43 |
44 | // P - matrices of the change-of-coordinates
45 | var P = new THREE.Matrix4();
46 | P.set ( thirdAxis.x, thirdAxis.y, thirdAxis.z, 0,
47 | this.direction.x, this.direction.y, this.direction.z, 0,
48 | this.axis.x, this.axis.y, this.axis.z, 0,
49 | 0, 0, 0, 1 ).transpose();
50 |
51 | var InverseP = new THREE.Matrix3().getInverse( P );
52 | var newVertices = []; var oldVertices = []; var anglesBetweenOldandNewVertices = [];
53 |
54 | var meshGeometryBoundingBoxMaxx = 0; var meshGeometryBoundingBoxMinx = 0;
55 | var meshGeometryBoundingBoxMaxy = 0; var meshGeometryBoundingBoxMiny = 0;
56 |
57 | for (var i = 0; i < geometry.vertices.length; i++) {
58 |
59 | newVertices[i] = new THREE.Vector3(); newVertices[i].copy( geometry.vertices[i] ).applyMatrix3( InverseP );
60 | if ( newVertices[i].x > meshGeometryBoundingBoxMaxx ) { meshGeometryBoundingBoxMaxx = newVertices[i].x; }
61 | if ( newVertices[i].x < meshGeometryBoundingBoxMinx ) { meshGeometryBoundingBoxMinx = newVertices[i].x; }
62 | if ( newVertices[i].y > meshGeometryBoundingBoxMaxy ) { meshGeometryBoundingBoxMaxy = newVertices[i].y; }
63 | if ( newVertices[i].y < meshGeometryBoundingBoxMiny ) { meshGeometryBoundingBoxMiny = newVertices[i].y; }
64 |
65 | }
66 |
67 | var meshWidthold = meshGeometryBoundingBoxMaxx - meshGeometryBoundingBoxMinx;
68 | var meshDepth = meshGeometryBoundingBoxMaxy - meshGeometryBoundingBoxMiny;
69 | var ParamB = 2 * this._sinhInverse( Math.tan( this.angle ) ) / meshWidthold;
70 | var oldMiddlex = (meshGeometryBoundingBoxMaxx + meshGeometryBoundingBoxMinx) / 2;
71 | var oldMiddley = (meshGeometryBoundingBoxMaxy + meshGeometryBoundingBoxMiny) / 2;
72 |
73 | for (var i = 0; i < geometry.vertices.length; i++ ) {
74 |
75 | oldVertices[i] = new THREE.Vector3(); oldVertices[i].copy( newVertices[i] );
76 | newVertices[i].x = this._sign( newVertices[i].x - oldMiddlex ) * 1 / ParamB * this._sinhInverse( ( newVertices[i].x - oldMiddlex ) * ParamB );
77 |
78 | }
79 |
80 | var meshWidth = 2 / ParamB * this._sinhInverse( meshWidthold / 2 * ParamB );
81 |
82 | var NewParamB = 2 * this._sinhInverse( Math.tan( this.angle ) ) / meshWidth;
83 |
84 | var rightEdgePos = new THREE.Vector3( meshWidth / 2, -meshDepth / 2, 0 );
85 | rightEdgePos.y = 1 / NewParamB * this._cosh( NewParamB * rightEdgePos.x ) - 1 / NewParamB - meshDepth / 2;
86 |
87 | var bendCenter = new THREE.Vector3( 0, rightEdgePos.y + rightEdgePos.x / Math.tan( this.angle ), 0 );
88 |
89 | for ( var i = 0; i < geometry.vertices.length; i++ ) {
90 |
91 | var x0 = this._sign( oldVertices[i].x - oldMiddlex ) * 1 / ParamB * this._sinhInverse( ( oldVertices[i].x - oldMiddlex ) * ParamB );
92 | var y0 = 1 / NewParamB * this._cosh( NewParamB * x0 ) - 1 / NewParamB;
93 |
94 | var k = new THREE.Vector3( bendCenter.x - x0, bendCenter.y - ( y0 - meshDepth / 2 ), bendCenter.z ).normalize();
95 |
96 | var Q = new THREE.Vector3();
97 | Q.addVectors( new THREE.Vector3( x0, y0 - meshDepth / 2, oldVertices[i].z ), k.multiplyScalar( oldVertices[i].y + meshDepth / 2 ) );
98 | newVertices[i].x = Q.x; newVertices[i].y = Q.y;
99 |
100 | }
101 |
102 | middle = oldMiddlex * meshWidth / meshWidthold;
103 |
104 | for ( var i = 0; i < geometry.vertices.length; i++ ) {
105 |
106 | var O = new THREE.Vector3( oldMiddlex, oldMiddley, oldVertices[i].z );
107 | var p = new THREE.Vector3(); p.subVectors( oldVertices[i], O );
108 | var q = new THREE.Vector3(); q.subVectors( newVertices[i], O );
109 |
110 | anglesBetweenOldandNewVertices[i] = Math.acos( 1 / this._cosh( ParamB * newVertices[i].x ) ) * this._sign( newVertices[i].x );
111 |
112 | newVertices[i].x = newVertices[i].x + middle;
113 | geometry.vertices[i].copy( newVertices[i].applyMatrix4( P ) );
114 |
115 | }
116 |
117 | geometry.computeFaceNormals();
118 | geometry.verticesNeedUpdate = true;
119 | geometry.normalsNeedUpdate = true;
120 |
121 | // compute Vertex Normals
122 | var fvNames = [ 'a', 'b', 'c', 'd' ];
123 |
124 | for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
125 |
126 | var face = geometry.faces[ f ];
127 | if ( face.vertexNormals === undefined ) {
128 | continue;
129 | }
130 | for ( var v = 0, vl = face.vertexNormals.length; v < vl; v ++ ) {
131 |
132 | var angle = anglesBetweenOldandNewVertices[ face[ fvNames[ v ] ] ];
133 | x = this.axis.x; y = this.axis.y; z = this.axis.z;
134 |
135 | var rotateMatrix = new THREE.Matrix3();
136 | rotateMatrix.set ( Math.cos(angle) + (1-Math.cos(angle))*x*x, (1-Math.cos(angle))*x*y - Math.sin(angle)*z, (1-Math.cos(angle))*x*z + Math.sin(angle)*y,
137 | (1-Math.cos(angle))*y*x + Math.sin(angle)*z, Math.cos(angle) + (1-Math.cos(angle))*y*y, (1-Math.cos(angle))*y*z - Math.sin(angle)*x,
138 | (1-Math.cos(angle))*z*x - Math.sin(angle)*y, (1-Math.cos(angle))*z*y + Math.sin(angle)*x, Math.cos(angle) + (1-Math.cos(angle))*z*z );
139 |
140 | face.vertexNormals[ v ].applyMatrix3( rotateMatrix );
141 |
142 | }
143 |
144 | }
145 | // end compute Vertex Normals
146 |
147 | return this
148 | }
149 | }
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/camera.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 |
8 | canvas: !! window.CanvasRenderingContext2D,
9 | webgl: ( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )(),
10 | workers: !! window.Worker,
11 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
12 |
13 | getWebGLErrorMessage: function () {
14 |
15 | var element = document.createElement( 'div' );
16 | element.id = 'webgl-error-message';
17 | element.style.fontFamily = 'monospace';
18 | element.style.fontSize = '13px';
19 | element.style.fontWeight = 'normal';
20 | element.style.textAlign = 'center';
21 | element.style.background = '#fff';
22 | element.style.color = '#000';
23 | element.style.padding = '1.5em';
24 | element.style.width = '400px';
25 | element.style.margin = '5em auto 0';
26 |
27 | if ( ! this.webgl ) {
28 |
29 | element.innerHTML = window.WebGLRenderingContext ? [
30 | 'Your graphics card does not seem to support WebGL. ',
31 | 'Find out how to get it here.'
32 | ].join( '\n' ) : [
33 | 'Your browser does not seem to support WebGL. ',
34 | 'Find out how to get it here.'
35 | ].join( '\n' );
36 |
37 | }
38 |
39 | return element;
40 |
41 | },
42 |
43 | addGetWebGLMessage: function ( parameters ) {
44 |
45 | var parent, id, element;
46 |
47 | parameters = parameters || {};
48 |
49 | parent = parameters.parent !== undefined ? parameters.parent : document.body;
50 | id = parameters.id !== undefined ? parameters.id : 'oldie';
51 |
52 | element = Detector.getWebGLErrorMessage();
53 | element.id = id;
54 |
55 | parent.appendChild( element );
56 |
57 | }
58 |
59 | };
60 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/github.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/glfx-lean.js:
--------------------------------------------------------------------------------
1 | /*
2 | * This class is based on glfx.js
3 | */
4 |
5 | /*
6 | * glfx.js
7 | * http://evanw.github.com/glfx.js/
8 | *
9 | * Copyright 2011 Evan Wallace
10 | * Released under the MIT license
11 | */
12 | var fx = (function() {
13 |
14 | var exports = {};
15 |
16 | // src/core/canvas.js
17 | var gl;
18 |
19 | function wrapTexture(texture) {
20 | return {
21 | _ : texture,
22 | loadContentsOf : function(element) {
23 | // Make sure that we're using the correct global WebGL context
24 | gl = this._.gl;
25 | this._.loadContentsOf(element);
26 | }
27 | };
28 | }
29 |
30 | function texture(element) {
31 | return wrapTexture(Texture.fromElement(element));
32 | }
33 |
34 | function initialize(width, height) {
35 | var type = gl.UNSIGNED_BYTE;
36 | this.width = width;
37 | this.height = height;
38 | this._.texture = new Texture(width, height, gl.RGBA, type);
39 | this._.spareTexture = new Texture(width, height, gl.RGBA, type);
40 | this._.flippedShader = this._.flippedShader
41 | || new Shader(
42 | null,
43 | '\
44 | uniform sampler2D texture;\
45 | varying vec2 texCoord;\
46 | void main() {\
47 | gl_FragColor = texture2D(texture, vec2(texCoord.x, 1.0 - texCoord.y));\
48 | }\
49 | ');
50 | this._.isInitialized = true;
51 | }
52 |
53 | /*
54 | * Draw a texture to the canvas, with an optional width and height to scale
55 | * to. If no width and height are given then the original texture width and
56 | * height are used.
57 | */
58 | function draw(texture, width, height) {
59 | if (!this._.isInitialized || texture._.width != this.width || texture._.height != this.height) {
60 | initialize.call(this, width ? width : texture._.width, height ? height : texture._.height);
61 | }
62 |
63 | texture._.use();
64 | this._.texture.drawTo(function() {
65 | Shader.getDefaultShader().drawRect();
66 | });
67 |
68 | return this;
69 | }
70 |
71 | function update() {
72 | this._.texture.use();
73 | this._.flippedShader.drawRect();
74 | return this;
75 | }
76 |
77 | function simpleShader(shader, uniforms, textureIn, textureOut) {
78 | (textureIn || this._.texture).use();
79 | this._.spareTexture.drawTo(function() {
80 | shader.uniforms(uniforms).drawRect();
81 | });
82 | this._.spareTexture.swapWith(textureOut || this._.texture);
83 | }
84 |
85 | function wrap(func) {
86 | return function() {
87 | // Make sure that we're using the correct global WebGL context
88 | gl = this._.gl;
89 |
90 | // Now that the context has been switched, we can call the wrapped
91 | // function
92 | return func.apply(this, arguments);
93 | };
94 | }
95 |
96 | exports.canvas = function() {
97 | var canvas = document.createElement('canvas');
98 | gl = canvas.getContext('experimental-webgl', {
99 | premultipliedAlpha : false
100 | });
101 |
102 | canvas._ = {
103 | gl : gl,
104 | isInitialized : false,
105 | texture : null,
106 | spareTexture : null,
107 | flippedShader : null
108 | };
109 |
110 | // Methods
111 | canvas.texture = wrap(texture);
112 | canvas.draw = wrap(draw);
113 | canvas.update = wrap(update);
114 | canvas.move = wrap(move);
115 | canvas.mirror = wrap(mirror);
116 | return canvas;
117 | };
118 |
119 | function mirror() {
120 | gl.mirror = gl.mirror
121 | || new Shader(
122 | null,
123 | ' \
124 | uniform sampler2D texture; \
125 | uniform float brightness; \
126 | varying vec2 texCoord; \
127 | void main() { \
128 | vec4 color = texture2D(texture, vec2(1.0 - texCoord.x,texCoord.y)); \
129 | gl_FragColor = color; \
130 | } \
131 | ');
132 |
133 | simpleShader.call(this, gl.mirror, {});
134 | return this;
135 | }
136 |
137 | function move() {
138 | gl.move = gl.move
139 | || new Shader(
140 | null,
141 | ' \
142 | uniform sampler2D texture; \
143 | uniform float brightness; \
144 | varying vec2 texCoord; \
145 | void main() { \
146 | vec4 color = texture2D(texture, texCoord); \
147 | if (texCoord.y < 0.5) { \
148 | vec4 color2 = texture2D(texture, vec2(texCoord.x, texCoord.y + 0.5)); \
149 | float d = abs(color2.r - color.r) + abs(color2.g - color.g) + abs(color2.b - color.b); \
150 | d = d * 1.5; \
151 | color = vec4(d,d,d,1.0); \
152 | if (d < 0.5) { \
153 | color = vec4(0.0,0.0,0.0,1.0); \
154 | } \
155 | } \
156 | gl_FragColor = color; \
157 | }\
158 | ');
159 |
160 | simpleShader.call(this, gl.move, {});
161 | return this;
162 | }
163 |
164 | var Shader = (function() {
165 |
166 | function compileSource(type, source) {
167 | var shader = gl.createShader(type);
168 | gl.shaderSource(shader, source);
169 | gl.compileShader(shader);
170 | return shader;
171 | }
172 |
173 | var defaultVertexSource = '\
174 | attribute vec2 vertex;\
175 | attribute vec2 _texCoord;\
176 | varying vec2 texCoord;\
177 | void main() {\
178 | texCoord = _texCoord;\
179 | gl_Position = vec4(vertex * 2.0 - 1.0, 0.0, 1.0);\
180 | }';
181 |
182 | var defaultFragmentSource = '\
183 | uniform sampler2D texture;\
184 | varying vec2 texCoord;\
185 | void main() {\
186 | gl_FragColor = texture2D(texture, texCoord);\
187 | }';
188 |
189 | function Shader(vertexSource, fragmentSource) {
190 | this.vertexAttribute = null;
191 | this.texCoordAttribute = null;
192 | this.program = gl.createProgram();
193 | vertexSource = vertexSource || defaultVertexSource;
194 | fragmentSource = fragmentSource || defaultFragmentSource;
195 | fragmentSource = 'precision lowp float;' + fragmentSource;
196 | gl.attachShader(this.program, compileSource(gl.VERTEX_SHADER, vertexSource));
197 | gl.attachShader(this.program, compileSource(gl.FRAGMENT_SHADER, fragmentSource));
198 | gl.linkProgram(this.program);
199 | }
200 |
201 | Shader.prototype.uniforms = function(uniforms) {
202 | gl.useProgram(this.program);
203 | return this;
204 | };
205 |
206 | Shader.prototype.drawRect = function(left, top, right, bottom) {
207 | var undefined;
208 | var viewport = gl.getParameter(gl.VIEWPORT);
209 | top = top !== undefined ? (top - viewport[1]) / viewport[3] : 0;
210 | left = left !== undefined ? (left - viewport[0]) / viewport[2] : 0;
211 | right = right !== undefined ? (right - viewport[0]) / viewport[2] : 1;
212 | bottom = bottom !== undefined ? (bottom - viewport[1]) / viewport[3] : 1;
213 | if (gl.vertexBuffer == null) {
214 | gl.vertexBuffer = gl.createBuffer();
215 | }
216 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
217 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ left, top, left, bottom, right, top, right, bottom ]), gl.STATIC_DRAW);
218 | if (gl.texCoordBuffer == null) {
219 | gl.texCoordBuffer = gl.createBuffer();
220 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.texCoordBuffer);
221 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0, 0, 0, 1, 1, 0, 1, 1 ]), gl.STATIC_DRAW);
222 | }
223 | if (this.vertexAttribute == null) {
224 | this.vertexAttribute = gl.getAttribLocation(this.program, 'vertex');
225 | gl.enableVertexAttribArray(this.vertexAttribute);
226 | }
227 | if (this.texCoordAttribute == null) {
228 | this.texCoordAttribute = gl.getAttribLocation(this.program, '_texCoord');
229 | gl.enableVertexAttribArray(this.texCoordAttribute);
230 | }
231 | gl.useProgram(this.program);
232 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer);
233 | gl.vertexAttribPointer(this.vertexAttribute, 2, gl.FLOAT, false, 0, 0);
234 | gl.bindBuffer(gl.ARRAY_BUFFER, gl.texCoordBuffer);
235 | gl.vertexAttribPointer(this.texCoordAttribute, 2, gl.FLOAT, false, 0, 0);
236 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
237 | };
238 |
239 | Shader.getDefaultShader = function() {
240 | gl.defaultShader = gl.defaultShader || new Shader();
241 | return gl.defaultShader;
242 | };
243 |
244 | return Shader;
245 | })();
246 |
247 | var Texture = (function() {
248 | Texture.fromElement = function(element) {
249 | var texture = new Texture(0, 0, gl.RGBA, gl.UNSIGNED_BYTE);
250 | texture.loadContentsOf(element);
251 | return texture;
252 | };
253 |
254 | function Texture(width, height, format, type) {
255 | this.gl = gl;
256 | this.id = gl.createTexture();
257 | this.width = width;
258 | this.height = height;
259 | this.format = format;
260 | this.type = type;
261 |
262 | gl.bindTexture(gl.TEXTURE_2D, this.id);
263 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
264 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
265 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
266 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
267 | if (width && height)
268 | gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, this.type, null);
269 | }
270 |
271 | Texture.prototype.loadContentsOf = function(element) {
272 | this.width = element.width || element.videoWidth;
273 | this.height = element.height || element.videoHeight;
274 | gl.bindTexture(gl.TEXTURE_2D, this.id);
275 | gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, element);
276 | };
277 |
278 | Texture.prototype.use = function(unit) {
279 | gl.activeTexture(gl.TEXTURE0 + (unit || 0));
280 | gl.bindTexture(gl.TEXTURE_2D, this.id);
281 | };
282 |
283 | Texture.prototype.drawTo = function(callback) {
284 | // start rendering to this texture
285 | gl.framebuffer = gl.framebuffer || gl.createFramebuffer();
286 | gl.bindFramebuffer(gl.FRAMEBUFFER, gl.framebuffer);
287 | gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.id, 0);
288 | gl.viewport(0, 0, this.width, this.height);
289 |
290 | // do the drawing
291 | callback();
292 |
293 | // stop rendering to this texture
294 | gl.bindFramebuffer(gl.FRAMEBUFFER, null);
295 | };
296 |
297 | Texture.prototype.swapWith = function(other) {
298 | var temp;
299 | temp = other.id;
300 | other.id = this.id;
301 | this.id = temp;
302 | temp = other.width;
303 | other.width = this.width;
304 | this.width = temp;
305 | temp = other.height;
306 | other.height = this.height;
307 | this.height = temp;
308 | temp = other.format;
309 | other.format = this.format;
310 | this.format = temp;
311 | };
312 |
313 | return Texture;
314 | })();
315 |
316 | return exports;
317 | })();
318 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/index-tests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 | WebGL Motion Detector
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
25 |
26 |
27 |
28 |
29 |
31 |
32 |
33 |
34 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebGL Motion Detector
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
Teddy Regards You!
30 |
31 |
32 |
33 |
34 |
35 |
36 |
Grant camera permission for the page
37 |
38 |
39 |
40 |
42 |
43 |
This page uses the browsers video signal as input for a
44 | simple motion detector to move the teddy bear. Please enable the
45 | capture of video signal in your browser.
46 |
47 |
48 |
49 |
50 |
51 |
Move your head in front of camera.
52 |
53 |
54 |
55 |
57 |
The motion detector calculates the average movement for
58 | several frames and teddy bear looks in this direction. To fine
59 | tune the detection parameter and control the video signal you
60 | may 'Open Controls' on the right top of the page.
61 |
62 |
63 |
64 |
Fork on GitHub
65 |
66 |
67 |
68 |
70 |
This experiment has been developed by
72 | Markus Sprunck. The complete source code is available. It is
73 | implemented in Javascript based on three.ja and glfx.js
74 | libraries. You may fork me at GitHub and visit my blog www.sw-engineering-candies.com
78 |
79 |
80 |
81 |
82 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/move-head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/move-head.png
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/moving-averager.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013, Markus Sprunck
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or
7 | * without modification, are permitted provided that the following
8 | * conditions are met:
9 | *
10 | * - Redistributions of source code must retain the above copyright
11 | * notice, this list of conditions and the following disclaimer.
12 | *
13 | * - Redistributions in binary form must reproduce the above
14 | * copyright notice, this list of conditions and the following
15 | * disclaimer in the documentation and/or other materials provided
16 | * with the distribution.
17 | *
18 | * - The name of its contributor may be used to endorse or promote
19 | * products derived from this software without specific prior
20 | * written permission.
21 | *
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 | *
36 | *
37 | * MovingAverager:
38 | *
39 | * Calculates the moving average of a number of data
40 | * points.
41 | *
42 | */
43 | function MovingAverager(length) {
44 | this.maxLength = length;
45 | this.nums = [];
46 | }
47 |
48 | MovingAverager.prototype.setValue = function(num) {
49 | this.nums.push(num);
50 | if (this.nums.length > this.maxLength) {
51 | this.nums.splice(0, this.nums.length - this.maxLength);
52 | }
53 | }
54 |
55 | MovingAverager.prototype.getValue = function() {
56 | var sum = 0.0;
57 | for (var i in this.nums) {
58 | sum += this.nums[i];
59 | }
60 | return (sum / this.nums.length);
61 | };
62 |
63 | MovingAverager.prototype.getStandardDeviation = function() {
64 | var sum = 0.0;
65 | var mean = this.getValue();
66 | for (var i in this.nums) {
67 | sum += Math.pow(mean - this.nums[i], 2);
68 | }
69 | return Math.pow(sum / this.nums.length, 0.5);
70 | };
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/qunit-1.23.1.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * QUnit 1.23.1
3 | * https://qunitjs.com/
4 | *
5 | * Copyright jQuery Foundation and other contributors
6 | * Released under the MIT license
7 | * https://jquery.org/license
8 | *
9 | * Date: 2016-04-12T17:29Z
10 | */
11 |
12 | /** Font Family and Sizes */
13 |
14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult {
15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
16 | }
17 |
18 | #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
19 | #qunit-tests { font-size: smaller; }
20 |
21 |
22 | /** Resets */
23 |
24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 |
30 | /** Header */
31 |
32 | #qunit-header {
33 | padding: 0.5em 0 0.5em 1em;
34 |
35 | color: #8699A4;
36 | background-color: #0D3349;
37 |
38 | font-size: 1.5em;
39 | line-height: 1em;
40 | font-weight: 400;
41 |
42 | border-radius: 5px 5px 0 0;
43 | }
44 |
45 | #qunit-header a {
46 | text-decoration: none;
47 | color: #C2CCD1;
48 | }
49 |
50 | #qunit-header a:hover,
51 | #qunit-header a:focus {
52 | color: #FFF;
53 | }
54 |
55 | #qunit-testrunner-toolbar label {
56 | display: inline-block;
57 | padding: 0 0.5em 0 0.1em;
58 | }
59 |
60 | #qunit-banner {
61 | height: 5px;
62 | }
63 |
64 | #qunit-testrunner-toolbar {
65 | padding: 0.5em 1em 0.5em 1em;
66 | color: #5E740B;
67 | background-color: #EEE;
68 | overflow: hidden;
69 | }
70 |
71 | #qunit-filteredTest {
72 | padding: 0.5em 1em 0.5em 1em;
73 | background-color: #F4FF77;
74 | color: #366097;
75 | }
76 |
77 | #qunit-userAgent {
78 | padding: 0.5em 1em 0.5em 1em;
79 | background-color: #2B81AF;
80 | color: #FFF;
81 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
82 | }
83 |
84 | #qunit-modulefilter-container {
85 | float: right;
86 | padding: 0.2em;
87 | }
88 |
89 | .qunit-url-config {
90 | display: inline-block;
91 | padding: 0.1em;
92 | }
93 |
94 | .qunit-filter {
95 | display: block;
96 | float: right;
97 | margin-left: 1em;
98 | }
99 |
100 | /** Tests: Pass/Fail */
101 |
102 | #qunit-tests {
103 | list-style-position: inside;
104 | }
105 |
106 | #qunit-tests li {
107 | padding: 0.4em 1em 0.4em 1em;
108 | border-bottom: 1px solid #FFF;
109 | list-style-position: inside;
110 | }
111 |
112 | #qunit-tests > li {
113 | display: none;
114 | }
115 |
116 | #qunit-tests li.running,
117 | #qunit-tests li.pass,
118 | #qunit-tests li.fail,
119 | #qunit-tests li.skipped {
120 | display: list-item;
121 | }
122 |
123 | #qunit-tests.hidepass {
124 | position: relative;
125 | }
126 |
127 | #qunit-tests.hidepass li.running,
128 | #qunit-tests.hidepass li.pass {
129 | visibility: hidden;
130 | position: absolute;
131 | width: 0;
132 | height: 0;
133 | padding: 0;
134 | border: 0;
135 | margin: 0;
136 | }
137 |
138 | #qunit-tests li strong {
139 | cursor: pointer;
140 | }
141 |
142 | #qunit-tests li.skipped strong {
143 | cursor: default;
144 | }
145 |
146 | #qunit-tests li a {
147 | padding: 0.5em;
148 | color: #C2CCD1;
149 | text-decoration: none;
150 | }
151 |
152 | #qunit-tests li p a {
153 | padding: 0.25em;
154 | color: #6B6464;
155 | }
156 | #qunit-tests li a:hover,
157 | #qunit-tests li a:focus {
158 | color: #000;
159 | }
160 |
161 | #qunit-tests li .runtime {
162 | float: right;
163 | font-size: smaller;
164 | }
165 |
166 | .qunit-assert-list {
167 | margin-top: 0.5em;
168 | padding: 0.5em;
169 |
170 | background-color: #FFF;
171 |
172 | border-radius: 5px;
173 | }
174 |
175 | .qunit-source {
176 | margin: 0.6em 0 0.3em;
177 | }
178 |
179 | .qunit-collapsed {
180 | display: none;
181 | }
182 |
183 | #qunit-tests table {
184 | border-collapse: collapse;
185 | margin-top: 0.2em;
186 | }
187 |
188 | #qunit-tests th {
189 | text-align: right;
190 | vertical-align: top;
191 | padding: 0 0.5em 0 0;
192 | }
193 |
194 | #qunit-tests td {
195 | vertical-align: top;
196 | }
197 |
198 | #qunit-tests pre {
199 | margin: 0;
200 | white-space: pre-wrap;
201 | word-wrap: break-word;
202 | }
203 |
204 | #qunit-tests del {
205 | background-color: #E0F2BE;
206 | color: #374E0C;
207 | text-decoration: none;
208 | }
209 |
210 | #qunit-tests ins {
211 | background-color: #FFCACA;
212 | color: #500;
213 | text-decoration: none;
214 | }
215 |
216 | /*** Test Counts */
217 |
218 | #qunit-tests b.counts { color: #000; }
219 | #qunit-tests b.passed { color: #5E740B; }
220 | #qunit-tests b.failed { color: #710909; }
221 |
222 | #qunit-tests li li {
223 | padding: 5px;
224 | background-color: #FFF;
225 | border-bottom: none;
226 | list-style-position: inside;
227 | }
228 |
229 | /*** Passing Styles */
230 |
231 | #qunit-tests li li.pass {
232 | color: #3C510C;
233 | background-color: #FFF;
234 | border-left: 10px solid #C6E746;
235 | }
236 |
237 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
238 | #qunit-tests .pass .test-name { color: #366097; }
239 |
240 | #qunit-tests .pass .test-actual,
241 | #qunit-tests .pass .test-expected { color: #999; }
242 |
243 | #qunit-banner.qunit-pass { background-color: #C6E746; }
244 |
245 | /*** Failing Styles */
246 |
247 | #qunit-tests li li.fail {
248 | color: #710909;
249 | background-color: #FFF;
250 | border-left: 10px solid #EE5757;
251 | white-space: pre;
252 | }
253 |
254 | #qunit-tests > li:last-child {
255 | border-radius: 0 0 5px 5px;
256 | }
257 |
258 | #qunit-tests .fail { color: #000; background-color: #EE5757; }
259 | #qunit-tests .fail .test-name,
260 | #qunit-tests .fail .module-name { color: #000; }
261 |
262 | #qunit-tests .fail .test-actual { color: #EE5757; }
263 | #qunit-tests .fail .test-expected { color: #008000; }
264 |
265 | #qunit-banner.qunit-fail { background-color: #EE5757; }
266 |
267 | /*** Skipped tests */
268 |
269 | #qunit-tests .skipped {
270 | background-color: #EBECE9;
271 | }
272 |
273 | #qunit-tests .qunit-skipped-label {
274 | background-color: #F4FF77;
275 | display: inline-block;
276 | font-style: normal;
277 | color: #366097;
278 | line-height: 1.8em;
279 | padding: 0 0.5em;
280 | margin: -0.4em 0.4em -0.4em 0;
281 | }
282 |
283 | /** Result */
284 |
285 | #qunit-testresult {
286 | padding: 0.5em 1em 0.5em 1em;
287 |
288 | color: #2B81AF;
289 | background-color: #D2E0E6;
290 |
291 | border-bottom: 1px solid #FFF;
292 | }
293 | #qunit-testresult .module-name {
294 | font-weight: 700;
295 | }
296 |
297 | /** Fixture */
298 |
299 | #qunit-fixture {
300 | position: absolute;
301 | top: -10000px;
302 | left: -10000px;
303 | width: 1000px;
304 | height: 1000px;
305 | }
306 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/request-animation-frame.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Provides requestAnimationFrame in a cross browser way.
3 | * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
4 | */
5 |
6 | if ( !window.requestAnimationFrame ) {
7 |
8 | window.requestAnimationFrame = ( function() {
9 |
10 | return window.webkitRequestAnimationFrame ||
11 | window.mozRequestAnimationFrame ||
12 | window.oRequestAnimationFrame ||
13 | window.msRequestAnimationFrame ||
14 | function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
15 |
16 | window.setTimeout( callback, 1000 / 60 );
17 |
18 | };
19 |
20 | } )();
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/simple-motion-detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013-2017, Markus Sprunck
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met: -
8 | * Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer. - Redistributions in binary
10 | * form must reproduce the above copyright notice, this list of conditions and
11 | * the following disclaimer in the documentation and/or other materials provided
12 | * with the distribution. - The name of its contributor may be used to endorse
13 | * or promote products derived from this software without specific prior written
14 | * permission.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | * POSSIBILITY OF SUCH DAMAGE.
27 | *
28 | *
29 | * SimpleMotionDetector:
30 | *
31 | * Captures the video signal and compares single frames to detect motion. The
32 | * center of this motion is used to find the viewpoint of the user. With this
33 | * viewpoint the g_camera position will be rotated.
34 | *
35 | */
36 | function SimpleMotionDetector(object) {
37 |
38 | // number of pixels for analysis
39 | var PIXELS_HORIZONTAL = 16 * 4;
40 | var PIXELS_VERTICAL = 10 * 4;
41 |
42 | // size of info window
43 | var WIDTH = 16 * 19;
44 | var HEIGHT = 10 * 19;
45 |
46 | // expected to be THREE.g_camera object
47 | this.object = object;
48 |
49 | // amplification factor for rotation (one is almost natural)
50 | this.amplificationAlpha = 0.25;
51 | this.amplificationGamma = 0.25;
52 |
53 | // in degrees
54 | this.offsetAlpha = -35.0;
55 | this.offsetGamma = -12.0;
56 |
57 | // just the upper part of the video should be detected
58 | this.detectionBorder = 0.85;
59 |
60 | // threshold of detected pixels
61 | this.pixelThreshold = 128;
62 |
63 | // average of all x positions of detected motion
64 | this.averageX = new MovingAverager(250);
65 | this.averageX.setValue(WIDTH / 2);
66 |
67 | // average of all y positions of detected motion
68 | this.averageY = new MovingAverager(250);
69 | this.averageY.setValue(HEIGHT / 2);
70 |
71 | // show canvas
72 | this.showCanvas = true;
73 |
74 | this.isVideoRunning = false;
75 |
76 | this.stop = false;
77 |
78 | this.videoCanvas = document.createElement('canvas');
79 | this.videoCanvas.width = PIXELS_HORIZONTAL;
80 | this.videoCanvas.height = PIXELS_VERTICAL;
81 |
82 | var canvas = document.createElement('canvas');
83 | canvas.width = WIDTH;
84 | canvas.height = HEIGHT;
85 | canvas.style.position = 'absolute';
86 | canvas.style.right = '10px';
87 | canvas.style.bottom = '10px';
88 | canvas.style.opacity = 1.0;
89 | canvas.hidden = !this.showCanvas;
90 | canvas.id = "video_canvas";
91 |
92 | var videoContext = this.videoCanvas.getContext('2d');
93 | var APP = {};
94 | var simpleMotionDetector;
95 | var texture = null;
96 | var ctx = canvas.getContext('2d');
97 | var video;
98 | this.stream;
99 | document.body.appendChild(canvas);
100 |
101 | SimpleMotionDetector.prototype.init = function () {
102 |
103 | simpleMotionDetector = this;
104 |
105 | var _that = this;
106 | video = document.createElement('video');
107 |
108 | if (navigator.mediaDevices) {
109 |
110 | navigator.mediaDevices.getUserMedia({
111 | audio: false,
112 | video: true
113 | }).then(
114 | function (stream) {
115 | video.srcObject = stream;
116 | _that.stream = stream;
117 |
118 | APP.videoWidth = PIXELS_HORIZONTAL;
119 | APP.videoHeight = PIXELS_VERTICAL;
120 | APP.frontCanvas = document.createElement('canvas');
121 | APP.frontCanvas.width = APP.videoWidth;
122 | APP.frontCanvas.height = APP.videoHeight * 2;
123 | APP.ctx = APP.frontCanvas.getContext('2d');
124 | APP.comp = [];
125 | simpleMotionDetector.run();
126 | },
127 | function (err) {
128 | $("#error-message").text("The following error occurred: " + err.name);
129 | }
130 | )
131 | } else {
132 | $("#error-message").text("Your browser does not seem to support UserMedia (video).");
133 | }
134 | }
135 |
136 | SimpleMotionDetector.prototype.analyisMotionPicture = function() {
137 | videoContext.drawImage(canvas, 0, 0);
138 | var data = videoContext.getImageData(0, 0, PIXELS_HORIZONTAL, PIXELS_VERTICAL).data;
139 |
140 | ctx.fillStyle = '#FFFFFF';
141 | ctx.fillRect(0, 0, WIDTH, HEIGHT);
142 | ctx.globalAlpha = 0.2;
143 |
144 | var cubeWidth = WIDTH / PIXELS_HORIZONTAL - 1 | 0;
145 | var cubeHeight = HEIGHT / PIXELS_VERTICAL - 1 | 0;
146 |
147 | // draw movements with blue and green color
148 | var yTopPosition = Number.MAX_VALUE;
149 | for (var y = 0; y < PIXELS_VERTICAL - 1; y++) {
150 | for (var x = 0; x < PIXELS_HORIZONTAL; x++) {
151 | if (data[x * 4 + y * PIXELS_HORIZONTAL * 4] > this.pixelThreshold) {
152 | var xPos = x * WIDTH / PIXELS_HORIZONTAL;
153 | var yPos = y * HEIGHT / PIXELS_VERTICAL;
154 | if (y < PIXELS_VERTICAL * this.detectionBorder) {
155 | if (yTopPosition >= Math.min(yTopPosition, yPos)) {
156 | yTopPosition = yPos;
157 | this.averageX.setValue(xPos);
158 | this.averageY.setValue(yPos);
159 | ctx.fillStyle = '#000000';
160 | ctx.fillRect(xPos, yPos, cubeWidth, cubeHeight);
161 | }
162 | ctx.fillStyle = '#0000FF';
163 | ctx.fillRect(xPos, yPos, cubeWidth, cubeHeight);
164 | } else {
165 | ctx.fillStyle = '#00FF00';
166 | ctx.fillRect(xPos, yPos, cubeWidth, cubeHeight);
167 | }
168 | }
169 | }
170 | }
171 |
172 | // draw orange ellipse for two times empirical standard deviation around
173 | // center
174 | var valueX = simpleMotionDetector.averageX.getValue();
175 | var stddevX = simpleMotionDetector.averageX.getStandardDeviation();
176 | var varianceX = stddevX * stddevX * 4;
177 | var valueY = simpleMotionDetector.averageY.getValue();
178 | var stddevY = simpleMotionDetector.averageY.getStandardDeviation();
179 | var varianceY = stddevY * stddevY * 4;
180 | for (var y = 0; y < PIXELS_VERTICAL - 1; y++) {
181 | for (var x = 0; x < PIXELS_HORIZONTAL; x++) {
182 | var xPos = x * WIDTH / PIXELS_HORIZONTAL;
183 | var yPos = y * HEIGHT / PIXELS_VERTICAL;
184 | if ((xPos - valueX) * (xPos - valueX) / varianceX + (yPos - valueY) * (yPos - valueY) / varianceY < 1) {
185 | ctx.fillStyle = '#F87217';
186 | ctx.fillRect(xPos, yPos, cubeWidth, cubeHeight);
187 | }
188 | }
189 | }
190 |
191 | // draw red cross on center
192 | ctx.fillStyle = '#AA0000';
193 | ctx.fillRect(simpleMotionDetector.averageX.getValue() - cubeWidth * 0.5, simpleMotionDetector.averageY.getValue(), cubeWidth * 1.5, cubeHeight * 0.5);
194 | ctx.fillRect(simpleMotionDetector.averageX.getValue(), simpleMotionDetector.averageY.getValue() - cubeHeight * 0.5, cubeWidth * 0.5, cubeHeight * 1.5);
195 | }
196 |
197 | SimpleMotionDetector.prototype.terminate = function() {
198 | var stream = this.stream;
199 | if (typeof stream !== "undefined") {
200 | var track = stream.getTracks()[0];
201 | track.stop();
202 | }
203 | }
204 |
205 | SimpleMotionDetector.prototype.analyseVideo = function() {
206 | videoContext.drawImage(video, 0, 0, PIXELS_HORIZONTAL, PIXELS_VERTICAL);
207 | APP.ctx.drawImage(this.videoCanvas, 0, 0);
208 | texture.loadContentsOf(APP.frontCanvas);
209 | canvas.draw(texture);
210 | canvas.mirror();
211 | canvas.move();
212 | canvas.update();
213 | APP.ctx.drawImage(this.videoCanvas, 0, PIXELS_VERTICAL);
214 | simpleMotionDetector.analyisMotionPicture();
215 |
216 | var _that = this;
217 | if (!this.stop) {
218 | setTimeout(function() {
219 | _that.analyseVideo();
220 | }, 20);
221 | }
222 | this.isVideoRunning = true;
223 | }
224 |
225 | SimpleMotionDetector.prototype.run = function() {
226 | canvas = fx.canvas();
227 | texture = canvas.texture(APP.frontCanvas);
228 |
229 | var r = confirm("Allow video preview");
230 | if (r == true) {
231 | var promise = video.play();
232 | if (promise !== undefined) {
233 | promise.catch(error => {
234 | console.log("Auto-play was prevented");
235 | }).then(() => {
236 | console.log("Video started");
237 | });
238 | }
239 | }
240 |
241 |
242 | this.analyseVideo();
243 | }
244 |
245 | SimpleMotionDetector.prototype.domElement = canvas;
246 | }
247 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/startHTTPServer.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | python -m SimpleHTTPServer
3 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/subdivisionmodifier.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
3 | * @author centerionware / http://www.centerionware.com
4 | *
5 | * Subdivision Geometry Modifier
6 | * using Loop Subdivision Scheme
7 | *
8 | * References:
9 | * http://graphics.stanford.edu/~mdfisher/subdivision.html
10 | * http://www.holmes3d.net/graphics/subdivision/
11 | * http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
12 | *
13 | * Known Issues:
14 | * - currently doesn't handle "Sharp Edges"
15 | */
16 |
17 | THREE.SubdivisionModifier = function ( subdivisions ) {
18 |
19 | this.subdivisions = ( subdivisions === undefined ) ? 1 : subdivisions;
20 |
21 | };
22 |
23 | // Applies the "modify" pattern
24 | THREE.SubdivisionModifier.prototype.modify = function ( geometry ) {
25 |
26 | var repeats = this.subdivisions;
27 |
28 | while ( repeats -- > 0 ) {
29 |
30 | this.smooth( geometry );
31 |
32 | }
33 |
34 | geometry.computeFaceNormals();
35 | geometry.computeVertexNormals();
36 |
37 | };
38 |
39 | ( function() {
40 |
41 | // Some constants
42 | var WARNINGS = ! true; // Set to true for development
43 | var ABC = [ 'a', 'b', 'c' ];
44 |
45 |
46 | function getEdge( a, b, map ) {
47 |
48 | var vertexIndexA = Math.min( a, b );
49 | var vertexIndexB = Math.max( a, b );
50 |
51 | var key = vertexIndexA + "_" + vertexIndexB;
52 |
53 | return map[ key ];
54 |
55 | }
56 |
57 |
58 | function processEdge( a, b, vertices, map, face, metaVertices ) {
59 |
60 | var vertexIndexA = Math.min( a, b );
61 | var vertexIndexB = Math.max( a, b );
62 |
63 | var key = vertexIndexA + "_" + vertexIndexB;
64 |
65 | var edge;
66 |
67 | if ( key in map ) {
68 |
69 | edge = map[ key ];
70 |
71 | } else {
72 |
73 | var vertexA = vertices[ vertexIndexA ];
74 | var vertexB = vertices[ vertexIndexB ];
75 |
76 | edge = {
77 |
78 | a: vertexA, // pointer reference
79 | b: vertexB,
80 | newEdge: null,
81 | // aIndex: a, // numbered reference
82 | // bIndex: b,
83 | faces: [] // pointers to face
84 |
85 | };
86 |
87 | map[ key ] = edge;
88 |
89 | }
90 |
91 | edge.faces.push( face );
92 |
93 | metaVertices[ a ].edges.push( edge );
94 | metaVertices[ b ].edges.push( edge );
95 |
96 |
97 | }
98 |
99 | function generateLookups( vertices, faces, metaVertices, edges ) {
100 |
101 | var i, il, face, edge;
102 |
103 | for ( i = 0, il = vertices.length; i < il; i ++ ) {
104 |
105 | metaVertices[ i ] = { edges: [] };
106 |
107 | }
108 |
109 | for ( i = 0, il = faces.length; i < il; i ++ ) {
110 |
111 | face = faces[ i ];
112 |
113 | processEdge( face.a, face.b, vertices, edges, face, metaVertices );
114 | processEdge( face.b, face.c, vertices, edges, face, metaVertices );
115 | processEdge( face.c, face.a, vertices, edges, face, metaVertices );
116 |
117 | }
118 |
119 | }
120 |
121 | function newFace( newFaces, a, b, c ) {
122 |
123 | newFaces.push( new THREE.Face3( a, b, c ) );
124 |
125 | }
126 |
127 | function midpoint( a, b ) {
128 |
129 | return ( Math.abs( b - a ) / 2 ) + Math.min( a, b );
130 |
131 | }
132 |
133 | function newUv( newUvs, a, b, c ) {
134 |
135 | newUvs.push( [ a.clone(), b.clone(), c.clone() ] );
136 |
137 | }
138 |
139 | /////////////////////////////
140 |
141 | // Performs one iteration of Subdivision
142 | THREE.SubdivisionModifier.prototype.smooth = function ( geometry ) {
143 |
144 | var tmp = new THREE.Vector3();
145 |
146 | var oldVertices, oldFaces, oldUvs;
147 | var newVertices, newFaces, newUVs = [];
148 |
149 | var n, l, i, il, j, k;
150 | var metaVertices, sourceEdges;
151 |
152 | // new stuff.
153 | var sourceEdges, newEdgeVertices, newSourceVertices;
154 |
155 | oldVertices = geometry.vertices; // { x, y, z}
156 | oldFaces = geometry.faces; // { a: oldVertex1, b: oldVertex2, c: oldVertex3 }
157 | oldUvs = geometry.faceVertexUvs[ 0 ];
158 |
159 | var hasUvs = oldUvs !== undefined && oldUvs.length > 0;
160 |
161 | /******************************************************
162 | *
163 | * Step 0: Preprocess Geometry to Generate edges Lookup
164 | *
165 | *******************************************************/
166 |
167 | metaVertices = new Array( oldVertices.length );
168 | sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[] }
169 |
170 | generateLookups( oldVertices, oldFaces, metaVertices, sourceEdges );
171 |
172 |
173 | /******************************************************
174 | *
175 | * Step 1.
176 | * For each edge, create a new Edge Vertex,
177 | * then position it.
178 | *
179 | *******************************************************/
180 |
181 | newEdgeVertices = [];
182 | var other, currentEdge, newEdge, face;
183 | var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
184 |
185 | for ( i in sourceEdges ) {
186 |
187 | currentEdge = sourceEdges[ i ];
188 | newEdge = new THREE.Vector3();
189 |
190 | edgeVertexWeight = 3 / 8;
191 | adjacentVertexWeight = 1 / 8;
192 |
193 | connectedFaces = currentEdge.faces.length;
194 |
195 | // check how many linked faces. 2 should be correct.
196 | if ( connectedFaces != 2 ) {
197 |
198 | // if length is not 2, handle condition
199 | edgeVertexWeight = 0.5;
200 | adjacentVertexWeight = 0;
201 |
202 | if ( connectedFaces != 1 ) {
203 |
204 | if ( WARNINGS ) console.warn( 'Subdivision Modifier: Number of connected faces != 2, is: ', connectedFaces, currentEdge );
205 |
206 | }
207 |
208 | }
209 |
210 | newEdge.addVectors( currentEdge.a, currentEdge.b ).multiplyScalar( edgeVertexWeight );
211 |
212 | tmp.set( 0, 0, 0 );
213 |
214 | for ( j = 0; j < connectedFaces; j ++ ) {
215 |
216 | face = currentEdge.faces[ j ];
217 |
218 | for ( k = 0; k < 3; k ++ ) {
219 |
220 | other = oldVertices[ face[ ABC[ k ] ] ];
221 | if ( other !== currentEdge.a && other !== currentEdge.b ) break;
222 |
223 | }
224 |
225 | tmp.add( other );
226 |
227 | }
228 |
229 | tmp.multiplyScalar( adjacentVertexWeight );
230 | newEdge.add( tmp );
231 |
232 | currentEdge.newEdge = newEdgeVertices.length;
233 | newEdgeVertices.push( newEdge );
234 |
235 | // console.log(currentEdge, newEdge);
236 |
237 | }
238 |
239 | /******************************************************
240 | *
241 | * Step 2.
242 | * Reposition each source vertices.
243 | *
244 | *******************************************************/
245 |
246 | var beta, sourceVertexWeight, connectingVertexWeight;
247 | var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
248 | newSourceVertices = [];
249 |
250 | for ( i = 0, il = oldVertices.length; i < il; i ++ ) {
251 |
252 | oldVertex = oldVertices[ i ];
253 |
254 | // find all connecting edges (using lookupTable)
255 | connectingEdges = metaVertices[ i ].edges;
256 | n = connectingEdges.length;
257 |
258 | if ( n == 3 ) {
259 |
260 | beta = 3 / 16;
261 |
262 | } else if ( n > 3 ) {
263 |
264 | beta = 3 / ( 8 * n ); // Warren's modified formula
265 |
266 | }
267 |
268 | // Loop's original beta formula
269 | // beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
270 |
271 | sourceVertexWeight = 1 - n * beta;
272 | connectingVertexWeight = beta;
273 |
274 | if ( n <= 2 ) {
275 |
276 | // crease and boundary rules
277 | // console.warn('crease and boundary rules');
278 |
279 | if ( n == 2 ) {
280 |
281 | if ( WARNINGS ) console.warn( '2 connecting edges', connectingEdges );
282 | sourceVertexWeight = 3 / 4;
283 | connectingVertexWeight = 1 / 8;
284 |
285 | // sourceVertexWeight = 1;
286 | // connectingVertexWeight = 0;
287 |
288 | } else if ( n == 1 ) {
289 |
290 | if ( WARNINGS ) console.warn( 'only 1 connecting edge' );
291 |
292 | } else if ( n == 0 ) {
293 |
294 | if ( WARNINGS ) console.warn( '0 connecting edges' );
295 |
296 | }
297 |
298 | }
299 |
300 | newSourceVertex = oldVertex.clone().multiplyScalar( sourceVertexWeight );
301 |
302 | tmp.set( 0, 0, 0 );
303 |
304 | for ( j = 0; j < n; j ++ ) {
305 |
306 | connectingEdge = connectingEdges[ j ];
307 | other = connectingEdge.a !== oldVertex ? connectingEdge.a : connectingEdge.b;
308 | tmp.add( other );
309 |
310 | }
311 |
312 | tmp.multiplyScalar( connectingVertexWeight );
313 | newSourceVertex.add( tmp );
314 |
315 | newSourceVertices.push( newSourceVertex );
316 |
317 | }
318 |
319 |
320 | /******************************************************
321 | *
322 | * Step 3.
323 | * Generate Faces between source vertices
324 | * and edge vertices.
325 | *
326 | *******************************************************/
327 |
328 | newVertices = newSourceVertices.concat( newEdgeVertices );
329 | var sl = newSourceVertices.length, edge1, edge2, edge3;
330 | newFaces = [];
331 |
332 | var uv, x0, x1, x2;
333 | var x3 = new THREE.Vector2();
334 | var x4 = new THREE.Vector2();
335 | var x5 = new THREE.Vector2();
336 |
337 | for ( i = 0, il = oldFaces.length; i < il; i ++ ) {
338 |
339 | face = oldFaces[ i ];
340 |
341 | // find the 3 new edges vertex of each old face
342 |
343 | edge1 = getEdge( face.a, face.b, sourceEdges ).newEdge + sl;
344 | edge2 = getEdge( face.b, face.c, sourceEdges ).newEdge + sl;
345 | edge3 = getEdge( face.c, face.a, sourceEdges ).newEdge + sl;
346 |
347 | // create 4 faces.
348 |
349 | newFace( newFaces, edge1, edge2, edge3 );
350 | newFace( newFaces, face.a, edge1, edge3 );
351 | newFace( newFaces, face.b, edge2, edge1 );
352 | newFace( newFaces, face.c, edge3, edge2 );
353 |
354 | // create 4 new uv's
355 |
356 | if ( hasUvs ) {
357 |
358 | uv = oldUvs[ i ];
359 |
360 | x0 = uv[ 0 ];
361 | x1 = uv[ 1 ];
362 | x2 = uv[ 2 ];
363 |
364 | x3.set( midpoint( x0.x, x1.x ), midpoint( x0.y, x1.y ) );
365 | x4.set( midpoint( x1.x, x2.x ), midpoint( x1.y, x2.y ) );
366 | x5.set( midpoint( x0.x, x2.x ), midpoint( x0.y, x2.y ) );
367 |
368 | newUv( newUVs, x3, x4, x5 );
369 | newUv( newUVs, x0, x3, x5 );
370 |
371 | newUv( newUVs, x1, x4, x3 );
372 | newUv( newUVs, x2, x5, x4 );
373 |
374 | }
375 |
376 | }
377 |
378 | // Overwrite old arrays
379 | geometry.vertices = newVertices;
380 | geometry.faces = newFaces;
381 | if ( hasUvs ) geometry.faceVertexUvs[ 0 ] = newUVs;
382 |
383 | // console.log('done');
384 |
385 | };
386 |
387 | } )();
388 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/webgl-motion-detector.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/webgl_motion_detector.css:
--------------------------------------------------------------------------------
1 | .main {
2 | background: #cbcc9e;
3 | padding: 0px;
4 | border: 0px;
5 | margin: 0px
6 | }
7 |
8 | .div {
9 | background: #554433;
10 | padding: 10px;
11 | }
12 |
13 | .text {
14 | color: #CCC;
15 | font: 14px 'Lucida Grande', sans-serif;
16 | padding-left: 10px;
17 | padding-right: 10px;
18 | padding-top: 4px;
19 | }
20 |
21 | .text-red {
22 | color: #F00;
23 | font: 14px 'Lucida Grande', sans-serif;
24 | padding-left: 10px;
25 | padding-right: 10px;
26 | padding-top: 4px;
27 | }
28 |
29 | .info-box {
30 | width: 100%;
31 | }
32 |
33 | td, th {
34 | padding: 5px !important;
35 | }
36 |
37 | a {
38 | color: #009de9;
39 | font: 14px 'Lucida Grande', sans-serif;
40 | text-align: right;
41 | }
42 |
43 | span.glyphicon {
44 | font-size: 1.3em;
45 | }
46 |
47 | .btn-circle-on-top {
48 | top: 10px;
49 | left: 10px;
50 | position: absolute;
51 | }
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/WebContent/teddy-regards-you/webgl_motion_detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (C) 2013-2016, Markus Sprunck
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met: -
8 | * Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer. - Redistributions in binary
10 | * form must reproduce the above copyright notice, this list of conditions and
11 | * the following disclaimer in the documentation and/or other materials provided
12 | * with the distribution. - The name of its contributor may be used to endorse
13 | * or promote products derived from this software without specific prior written
14 | * permission.
15 | *
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | * POSSIBILITY OF SUCH DAMAGE.
27 | *
28 | */
29 |
30 | /**
31 | * Global constants
32 | */
33 | var BORDER_BOTTOM = 30;
34 |
35 | /**
36 | * Just for development to rotate scene
37 | */
38 | var USE_ORBIT_CONTROLS = (document.location.search === "?orbitControls=true");
39 | ;
40 |
41 | /**
42 | * Global variables for rendering
43 | */
44 | var g_panelWidthWebGL;
45 | var g_panelHeightWebGL;
46 | var g_scene;
47 | var g_cube_wireframe;
48 | var g_controls;
49 | var g_gui;
50 | var detectorPosition = {
51 | x : 0,
52 | y : 0
53 | };
54 | var g_stats, g_camera, g_scene, g_renderer;
55 | var g_motionDetector;
56 | var g_teddy;
57 |
58 | function init() {
59 |
60 | console.log('THREE.MotionDetector 2');
61 |
62 | // Add container
63 | g_scene = new THREE.Scene();
64 | g_scene.fog = new THREE.FogExp2(0xffffff, 0.0004);
65 | var container = document.getElementById('drawingArea');
66 |
67 | // Add camera
68 | var HEIGHT = window.innerHeight;
69 | var WIDTH = window.innerWidth;
70 | g_camera = new THREE.PerspectiveCamera(50, WIDTH / HEIGHT, 1, 3000);
71 | g_scene.add(g_camera);
72 |
73 | // Add renderer
74 | g_renderer = new THREE.WebGLRenderer({
75 | alpha : true,
76 | antialias : true
77 | });
78 | g_renderer.shadowMap.enabled = true;
79 | g_renderer.setClearColor(0xbbd7e9, 1);
80 | container.appendChild(g_renderer.domElement);
81 |
82 | // Add motion detector
83 | g_motionDetector = new SimpleMotionDetector(g_camera);
84 | g_motionDetector.init();
85 | container.appendChild(g_motionDetector.domElement);
86 |
87 | if (USE_ORBIT_CONTROLS) {
88 | g_controls = new THREE.OrbitControls(g_camera, g_renderer.domElement);
89 | g_controls.enableDamping = true;
90 | g_controls.dampingFactor = 0.25;
91 | g_controls.enableZoom = true;
92 | g_camera.position.set(g_camera.position.x, g_camera.position.y + 100, g_camera.position.z + 600);
93 | } else {
94 | g_camera.position.set(0, 150, 500);
95 | g_camera.lookAt(0, 150, 0);
96 | }
97 |
98 | // Add dialog to change parameters
99 | g_gui = new dat.GUI({
100 | autoPlace : false,
101 | width : 312
102 | });
103 | var folder = g_gui.addFolder('Motion Detector Settings');
104 | folder.add(g_motionDetector, 'offsetAlpha', -60.0, 20.0, 10).name('Offset α');
105 | folder.add(g_motionDetector, 'offsetGamma', -60.0, 20.0, 10).name('Offset γ');
106 | folder.add(g_motionDetector, 'amplificationAlpha', 0.1, 0.4, 0.1).name('Amplification α');
107 | folder.add(g_motionDetector, 'amplificationGamma', 0.1, 0.4, 0.1).name('Amplification γ');
108 | folder.add(g_motionDetector, 'detectionBorder', 0.25, 1.0, 0.05).name('Detection border');
109 | folder.add(g_motionDetector, 'pixelThreshold', 0, 250, 10).name('Pixel threshold');
110 | folder.add(g_motionDetector.averageX, 'maxLength', 50, 500, 50).name('Averager X');
111 | folder.add(g_motionDetector.averageY, 'maxLength', 50, 500, 50).name('Averager Y');
112 | folder.open();
113 |
114 | g_gui.domElement.style.position = 'absolute';
115 | g_gui.domElement.style.right = '10px';
116 | g_gui.domElement.style.top = '10px';
117 | container.appendChild(g_gui.domElement);
118 |
119 | // Support window resize
120 | var resizeCallback = function() {
121 | g_panelWidthWebGL = window.innerWidth ;
122 | g_panelHeightWebGL = window.innerHeight - BORDER_BOTTOM;
123 |
124 | var devicePixelRatio = window.devicePixelRatio || 1;
125 | g_renderer.setSize(g_panelWidthWebGL * devicePixelRatio, g_panelHeightWebGL * devicePixelRatio);
126 | g_renderer.domElement.style.width = g_panelWidthWebGL + 'px';
127 | g_renderer.domElement.style.height = g_panelHeightWebGL + 'px';
128 | g_camera.aspect = window.innerWidth / window.innerHeight;
129 | g_camera.updateProjectionMatrix();
130 | };
131 | window.addEventListener('resize', resizeCallback, false);
132 | resizeCallback();
133 |
134 | createLights();
135 | createFloor();
136 | createTeddy();
137 | }
138 |
139 | function createLights() {
140 |
141 | var hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x101010, 0.9)
142 | g_scene.add(hemisphereLight);
143 |
144 | var ambientLight = new THREE.AmbientLight(0x2f2f2f)
145 | g_scene.add(ambientLight);
146 |
147 | var sunLight = new THREE.DirectionalLight(0x606060, 0.30);
148 | sunLight.position.set(300, 600, 500);
149 | sunLight.castShadow = true;
150 | sunLight.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera());
151 | g_scene.add(sunLight);
152 | }
153 |
154 | function createFloor() {
155 |
156 | var groundMaterial = new THREE.MeshPhongMaterial({
157 | shininess : 80,
158 | color : 0xadafad,
159 | specular : 0xadafad
160 | });
161 |
162 | var floor = new THREE.Mesh(new THREE.PlaneBufferGeometry(6000, 3000), groundMaterial);
163 | floor.rotation.x = -Math.PI / 2;
164 | floor.position.y = -45;
165 | floor.receiveShadow = true;
166 | g_scene.add(floor);
167 | }
168 |
169 | function createTeddy() {
170 |
171 | g_teddy = new Teddy();
172 | g_scene.add(g_teddy.allGroup);
173 | }
174 |
175 | function animate() {
176 |
177 | document.getElementById('video_canvas').hidden = g_gui.closed;
178 |
179 | if (USE_ORBIT_CONTROLS) {
180 | g_controls.update();
181 | }
182 |
183 | // Move the bear
184 | detectorPosition.x = g_motionDetector.offsetAlpha + g_motionDetector.amplificationAlpha * g_motionDetector.averageX.getValue();
185 | detectorPosition.y = g_motionDetector.offsetGamma + g_motionDetector.amplificationGamma * g_motionDetector.averageY.getValue();
186 | g_teddy.move(detectorPosition.x, detectorPosition.y, 100, 100);
187 |
188 | // Render scene
189 | requestAnimationFrame(animate);
190 | g_renderer.render(g_scene, g_camera);
191 | }
192 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/src/META-INF/jdoconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/src/META-INF/persistence.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | org.datanucleus.api.jpa.PersistenceProviderImpl
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/src/log4j.properties:
--------------------------------------------------------------------------------
1 | # A default log4j configuration for log4j users.
2 | #
3 | # To use this configuration, deploy it into your application's WEB-INF/classes
4 | # directory. You are also encouraged to edit it as you like.
5 |
6 | # Configure the console as our one appender
7 | log4j.appender.A1=org.apache.log4j.ConsoleAppender
8 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout
9 | log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
10 |
11 | # tighten logging on the DataNucleus Categories
12 | log4j.category.DataNucleus.JDO=WARN, A1
13 | log4j.category.DataNucleus.Persistence=WARN, A1
14 | log4j.category.DataNucleus.Cache=WARN, A1
15 | log4j.category.DataNucleus.MetaData=WARN, A1
16 | log4j.category.DataNucleus.General=WARN, A1
17 | log4j.category.DataNucleus.Utility=WARN, A1
18 | log4j.category.DataNucleus.Transaction=WARN, A1
19 | log4j.category.DataNucleus.Datastore=WARN, A1
20 | log4j.category.DataNucleus.ClassLoading=WARN, A1
21 | log4j.category.DataNucleus.Plugin=WARN, A1
22 | log4j.category.DataNucleus.ValueGeneration=WARN, A1
23 | log4j.category.DataNucleus.Enhancer=WARN, A1
24 | log4j.category.DataNucleus.SchemaTool=WARN, A1
25 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/src/main/appengine/app.yaml:
--------------------------------------------------------------------------------
1 | runtime: java
2 | env: flex
3 |
--------------------------------------------------------------------------------
/sw-engineering-candies-webgl-examples/war/WEB-INF/.gitignore:
--------------------------------------------------------------------------------
1 | /classes/
2 |
--------------------------------------------------------------------------------