├── .gitignore ├── .idea └── vcs.xml ├── README.md └── sw-engineering-candies-webgl-examples ├── .classpath ├── .gitignore ├── .project ├── .settings ├── .jsdtscope ├── com.google.appengine.eclipse.core.prefs ├── com.google.cloud.tools.eclipse.appengine.deploy.prefs ├── com.google.gdt.eclipse.core.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.wst.jsdt.ui.superType.name ├── org.eclipse.wst.validation.prefs └── org.eclipse.wst.xml.core.prefs ├── WebContent ├── .DS_Store ├── META-INF │ └── MANIFEST.MF ├── WEB-INF │ ├── appengine-web.xml │ ├── lib │ │ ├── appengine-api-1.0-sdk-1.9.30.jar │ │ ├── appengine-api-labs.jar │ │ ├── appengine-endpoints-deps.jar │ │ ├── appengine-endpoints.jar │ │ ├── appengine-jsr107cache-1.9.30.jar │ │ └── jsr107cache-1.1.jar │ ├── logging.properties │ └── web.xml ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── index.html ├── simple-webgl-gui-oculus-rift │ ├── .gitignore │ ├── README.md │ ├── THREE.OculusRiftControls.js │ ├── THREE.OculusRiftMouse.js │ ├── THREE.SimpleDatGui.js │ ├── THREE.SimpleDatGuiOculusRiftDemo.html │ ├── lib │ │ ├── AxisHelper.js │ │ ├── OculusRiftEffect.js │ │ ├── TrackballControls.js │ │ ├── hashmap.js │ │ ├── helvetiker_regular.typeface.js │ │ ├── stats.min.js │ │ └── three.min.js │ └── textures │ │ ├── .gitignore │ │ ├── high │ │ ├── Parc_de_Belleville_Paris.jpg │ │ ├── Place_Dauphine_Paris.jpg │ │ └── Place_de_la_Concorde_Paris.jpg │ │ ├── low │ │ ├── Parc_de_Belleville_Paris.jpg │ │ ├── Place_Dauphine_Paris.jpg │ │ └── Place_de_la_Concorde_Paris.jpg │ │ ├── medium │ │ ├── Parc_de_Belleville_Paris.jpg │ │ ├── Place_Dauphine_Paris.jpg │ │ └── Place_de_la_Concorde_Paris.jpg │ │ ├── mouse_default.png │ │ ├── mouse_pointer.png │ │ ├── mouse_resize.png │ │ └── mouse_text.png ├── simple-webgl-gui │ ├── .gitignore │ ├── THREE.SimpleDatGui.js │ ├── THREE.SimpleDatGuiDemo.html │ ├── font │ │ ├── gentilis_regular.typeface.json │ │ ├── helvetiker_regular.typeface.json │ │ └── optimer_regular.typeface.json │ └── lib │ │ ├── TrackballControls.js │ │ ├── stats.min.js │ │ └── three.js ├── square-melon │ ├── lib │ │ ├── dat.gui.min.js │ │ ├── detector.js │ │ ├── hashmap.js │ │ ├── stats.min.js │ │ ├── three.min.js │ │ └── trackballcontrols.js │ ├── melon.html │ ├── melon.jpg │ ├── melon.main.js │ └── melon.simulator.js └── teddy-regards-you │ ├── bendModifier.js │ ├── blanket.js │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── bootstrap.min.js │ ├── camera.png │ ├── dat.gui.min.js │ ├── detector.js │ ├── fonts │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── github.png │ ├── glfx-lean.js │ ├── index-tests.html │ ├── index.html │ ├── jquery.min.js │ ├── move-head.png │ ├── moving-averager.js │ ├── orbitControls.js │ ├── qunit-1.23.1.css │ ├── qunit-1.23.1.js │ ├── request-animation-frame.js │ ├── simple-motion-detector.js │ ├── startHTTPServer.sh │ ├── subdivisionmodifier.js │ ├── teddy.js │ ├── three.min.js │ ├── webgl-motion-detector.iml │ ├── webgl_motion_detector.css │ └── webgl_motion_detector.js ├── src ├── META-INF │ ├── jdoconfig.xml │ └── persistence.xml ├── log4j.properties └── main │ └── appengine │ └── app.yaml └── war └── WEB-INF └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebGL Examples 2 | -------------- 3 | 4 | * Teddy Regards You! 5 | 6 | https://webgl-examples.appspot.com/teddy-regards-you/index.html 7 | 8 | * THREE.SimpleDatGuiDemo.html 9 | 10 | https://webgl-examples.appspot.com/simple-webgl-gui/THREE.SimpleDatGuiDemo.html 11 | 12 | * THREE.SimpleDatGuiOculusRiftDemo.html 13 | 14 | https://webgl-examples.appspot.com/simple-webgl-gui-oculus-rift/THREE.SimpleDatGuiOculusRiftDemo.html 15 | 16 | * Motion Detector 17 | 18 | https://webgl-examples.appspot.com/webgl-motion-detector/webgl_motion_detector.html 19 | 20 | * Growing Water Melon 21 | 22 | https://webgl-examples.appspot.com/square-melon/melon.html 23 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | /build/ 3 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | webgl-examples 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | com.google.gdt.eclipse.core.webAppProjectValidator 20 | 21 | 22 | 23 | 24 | com.google.appengine.eclipse.core.gaeProjectChangeNotifier 25 | 26 | 27 | 28 | 29 | com.google.appengine.eclipse.core.projectValidator 30 | 31 | 32 | 33 | 34 | org.eclipse.wst.validation.validationbuilder 35 | 36 | 37 | 38 | 39 | com.google.cloud.tools.eclipse.appengine.standard.java8.appengineWeb 40 | 41 | 42 | 43 | 44 | 45 | org.eclipse.jem.workbench.JavaEMFNature 46 | org.eclipse.wst.common.modulecore.ModuleCoreNature 47 | com.google.appengine.eclipse.core.gaeNature 48 | org.eclipse.wst.common.project.facet.core.nature 49 | org.eclipse.wst.jsdt.core.jsNature 50 | org.eclipse.jdt.core.javanature 51 | 52 | 53 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/com.google.appengine.eclipse.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.9.30.jar|appengine-api-labs.jar|appengine-endpoints-deps.jar|appengine-endpoints.jar|appengine-jsr107cache-1.9.30.jar|jsr107cache-1.1.jar 3 | gaeDatanucleusEnabled=false 4 | gaeDatanucleusVersion=v2 5 | gaeDeployDialogSettings= 6 | gaeHrdEnabled=false 7 | gaeLaunchAppInBrowser=true 8 | googleCloudSqlEnabled=false 9 | localDevMySqlEnabled=true 10 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/com.google.cloud.tools.eclipse.appengine.deploy.prefs: -------------------------------------------------------------------------------- 1 | account.email=sprunck.markus@gmail.com 2 | app.yaml.path=src/main/appengine/app.yaml 3 | eclipse.preferences.version=1 4 | include.optional.configuration.files=true 5 | project.bucket= 6 | project.id=webgl-examples 7 | project.previousVersion.stop=true 8 | project.promote=true 9 | project.version=21 10 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/com.google.gdt.eclipse.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | warSrcDir=war 3 | warSrcDirIsOutput=true 4 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.8 8 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | DELEGATES_PREFERENCE=delegateValidatorList 2 | USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator; 3 | USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator; 4 | USER_PREFERENCE=overrideGlobalPreferencestruedisableAllValidationfalseversion1.2.701.v201707142105 5 | eclipse.preferences.version=1 6 | override=true 7 | suspend=false 8 | vf.version=3 9 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/.settings/org.eclipse.wst.xml.core.prefs: -------------------------------------------------------------------------------- 1 | attributeHasNoValue=2 2 | eclipse.preferences.version=1 3 | endTagWithAttributes=2 4 | honourAllSchemaLocations=true 5 | indicateNoGrammar=-1 6 | indicateReferencedFileContainsErrors=2 7 | indiciateNoDocumentElement=-1 8 | markupValidation=false 9 | missingClosingBracket=2 10 | missingClosingQuote=2 11 | missingEndTag=2 12 | missingQuotes=2 13 | missingStartTag=2 14 | missingTagName=2 15 | namespaceInPITarget=2 16 | use-project-settings=true 17 | whitespaceAtStart=2 18 | whitespaceBeforeTagName=2 19 | xinclude=false 20 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/.DS_Store -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 28 | 29 | java8 30 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-api-1.0-sdk-1.9.30.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-api-1.0-sdk-1.9.30.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-api-labs.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-api-labs.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-endpoints-deps.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-endpoints-deps.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-endpoints.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-endpoints.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-jsr107cache-1.9.30.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/appengine-jsr107cache-1.9.30.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/jsr107cache-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/WEB-INF/lib/jsr107cache-1.1.jar -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/logging.properties: -------------------------------------------------------------------------------- 1 | # A default java.util.logging configuration. 2 | # (All App Engine logging is through java.util.logging by default). 3 | # 4 | # To use this configuration, copy it into your application's WEB-INF 5 | # folder and add the following to your appengine-web.xml: 6 | # 7 | # 8 | # 9 | # 10 | # 11 | 12 | # Set the default logging level for all loggers to WARNING 13 | .level = WARNING 14 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SystemServiceServlet 5 | com.google.api.server.spi.SystemServiceServlet 6 | 7 | services 8 | 9 | 10 | 11 | 12 | SystemServiceServlet 13 | /_ah/spi/* 14 | 15 | 16 | 17 | 18 | 19 | index.html 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/favicon.ico -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkusSprunck/webgl-examples/a1fb7b84e598c480df5a2a23f2959af9ed1906ff/sw-engineering-candies-webgl-examples/WebContent/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /sw-engineering-candies-webgl-examples/WebContent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebGL Examples 6 | 92 | 93 | 94 | Fork me on GitHub 95 |

WebGL Examples

96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
WebGL Teddy Regards You updated to three.js v89
WebGL Growing Water Melon updated to three.js v89
WebGL THREE.SimpleDatGuiDemo.html updated to three.js v89
WebGL THREE.SimpleDatGuiOculusRiftDemo.html
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 | 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 | --------------------------------------------------------------------------------