├── prettierrc.json ├── README.md ├── webvr ├── aframe-demo │ ├── metal003.png │ ├── package.json │ ├── .gitignore │ ├── index.html │ ├── LICENSE │ └── README.md ├── raw-webgl-example │ ├── metal003.png │ ├── cubetexture.png │ ├── webgl.css │ ├── index.html │ ├── glUtils.js │ ├── sylvester.js │ └── webgl-demo.js ├── raw-webgl-controller-example │ ├── metal003.png │ ├── cubetexture.png │ ├── webgl.css │ ├── index.html │ ├── glUtils.js │ ├── sylvester.js │ └── webgl-demo.js ├── stage-parameters-test │ └── index.html ├── README.md ├── field-of-view-test │ └── index.html ├── basic-display-info │ └── index.html └── vr-controller-basic-info │ └── index.html ├── canvas-raycaster ├── Player.js ├── trace.css ├── trace.js ├── input.js ├── Level.js ├── index.html └── RayCaster.js ├── .github ├── dependabot.yml ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE ├── ISSUE_TEMPLATE │ ├── config.yml │ └── bug.yml └── labels.json ├── .editorconfig ├── CODE_OF_CONDUCT.md ├── REVIEWING.md ├── SECURITY.md ├── CONTRIBUTING.md └── LICENSE /prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # museum 2 | A historic collection of MDN Web Docs content and examples 3 | -------------------------------------------------------------------------------- /webvr/aframe-demo/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/museum/main/webvr/aframe-demo/metal003.png -------------------------------------------------------------------------------- /webvr/raw-webgl-example/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/museum/main/webvr/raw-webgl-example/metal003.png -------------------------------------------------------------------------------- /webvr/raw-webgl-example/cubetexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/museum/main/webvr/raw-webgl-example/cubetexture.png -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/metal003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/museum/main/webvr/raw-webgl-controller-example/metal003.png -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/cubetexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/museum/main/webvr/raw-webgl-controller-example/cubetexture.png -------------------------------------------------------------------------------- /canvas-raycaster/Player.js: -------------------------------------------------------------------------------- 1 | function Player(s) { 2 | this.health = 100; 3 | this.speed = { 4 | forward : s, 5 | backward: .8 * s, 6 | turn : 2 * s 7 | }; 8 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: weekly 7 | commit-message: 8 | prefix: "ci(deps): " 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /canvas-raycaster/trace.css: -------------------------------------------------------------------------------- 1 | .window { 2 | z-index: 10; 3 | position: absolute; 4 | left: 10px; 5 | top: 10px; 6 | width: 30%; 7 | color: #00FF00; 8 | background-color: #001100; 9 | opacity: .80; 10 | border: 2px solid #000000; 11 | font-family: "Lucida Console", "Monaco", "Courier New", Courier, mono; 12 | font-size: small; 13 | } 14 | ul { 15 | margin: 0px; 16 | padding: 0px; 17 | } 18 | li { 19 | list-style-type: none; 20 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, read [Mozilla's Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 5 | 6 | ## Reporting violations 7 | 8 | For more information on how to report violations of the Community Participation Guidelines, read the [How to report](https://www.mozilla.org/about/governance/policies/participation/reporting/) page. 9 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------------------------------- 2 | # CODEOWNERS 3 | # ---------------------------------------------------------------------------- 4 | # Order is important. The last matching pattern takes precedence. 5 | # See: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 6 | # ---------------------------------------------------------------------------- 7 | 8 | /.github/workflows/ @mdn/engineering 9 | /.github/CODEOWNERS @mdn/engineering 10 | /SECURITY.md @mdn/engineering 11 | -------------------------------------------------------------------------------- /webvr/aframe-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-hello-world-boilerplate", 3 | "description": "Boilerplate with A-Frame's 'Hello, World!' of WebVR.", 4 | "version": "0.3.0", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "budo --live --verbose --port 3000 --open", 8 | "deploy": "ghpages", 9 | "ghpages": "ghpages" 10 | }, 11 | "devDependencies": { 12 | "budo": "^7.0.0", 13 | "ghpages": "0.0.3" 14 | }, 15 | "keywords": [ 16 | "aframe", 17 | "aframe-example", 18 | "aframe-boilerplate", 19 | "aframe-scene", 20 | "webvr", 21 | "vr" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /REVIEWING.md: -------------------------------------------------------------------------------- 1 | # Reviewing guide 2 | 3 | All reviewers must abide by the [code of conduct](CODE_OF_CONDUCT.md); they are also protected by the code of conduct. 4 | A reviewer should not tolerate poor behavior and is encouraged to [report any behavior](CODE_OF_CONDUCT.md#Reporting_violations) that violates the code of conduct. 5 | 6 | ## Review process 7 | 8 | The MDN Web Docs team has a well-defined review process that must be followed by reviewers in all repositories under the GitHub MDN organization. 9 | This process is described in detail on the [Pull request guidelines](https://developer.mozilla.org/en-US/docs/MDN/Community/Pull_requests) page. 10 | -------------------------------------------------------------------------------- /canvas-raycaster/trace.js: -------------------------------------------------------------------------------- 1 | var MAX_LINES = 12; 2 | var begin = ''; 5 | 6 | function trace(msg) { 7 | var output_window = document.getElementById("trace"); 8 | var lines = output_window.innerHTML.toLowerCase(); 9 | var lineList; 10 | 11 | if (lines.length > 0) { 12 | lineList = lines.substring(begin.length, lines.length - end.length).split(middle); 13 | while (lineList.length >= MAX_LINES) { lineList.shift(); } 14 | lineList.push(msg); 15 | } 16 | else { 17 | lineList = [ msg ]; 18 | } 19 | 20 | output_window.innerHTML = begin +lineList.join(middle) +end; 21 | } -------------------------------------------------------------------------------- /webvr/raw-webgl-example/webgl.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | font-family: sans-serif; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | height: inherit; 9 | overflow: hidden; 10 | } 11 | 12 | canvas { 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | button { 18 | position: absolute; 19 | top: 3px; 20 | } 21 | 22 | .stop-start { 23 | right: 3px; 24 | } 25 | 26 | .pose-stats { 27 | right: 120px; 28 | } 29 | 30 | section { 31 | position: absolute; 32 | background-color: rgb(255,255,255,0.5); 33 | color: black; 34 | bottom: 3px; 35 | right: 3px; 36 | display: flex; 37 | } 38 | 39 | section p { 40 | padding: 5px 10px; 41 | margin: 0; 42 | font-size: 11px; 43 | width: 230px; 44 | text-align: center; 45 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Description 4 | 5 | 6 | 7 | ### Motivation 8 | 9 | 10 | 11 | ### Additional details 12 | 13 | 14 | 15 | ### Related issues and pull requests 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/webgl.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | font-family: sans-serif; 4 | } 5 | 6 | body { 7 | margin: 0; 8 | height: inherit; 9 | overflow: hidden; 10 | } 11 | 12 | canvas { 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | button { 18 | position: absolute; 19 | top: 3px; 20 | } 21 | 22 | .stop-start { 23 | right: 3px; 24 | } 25 | 26 | .pose-stats { 27 | right: 120px; 28 | } 29 | 30 | section { 31 | position: absolute; 32 | background-color: rgb(255,255,255,0.5); 33 | color: black; 34 | bottom: 3px; 35 | right: 3px; 36 | display: flex; 37 | } 38 | 39 | section p { 40 | padding: 5px 10px; 41 | margin: 0; 42 | font-size: 11px; 43 | width: 230px; 44 | text-align: center; 45 | } -------------------------------------------------------------------------------- /webvr/aframe-demo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sw[mnop] 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (http://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules 35 | jspm_packages 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional REPL history 41 | .node_repl_history 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Content or feature request 4 | url: https://github.com/mdn/mdn/issues/new/choose 5 | about: Propose new content for MDN Web Docs or submit a feature request using this link. 6 | - name: MDN GitHub Discussions 7 | url: https://github.com/orgs/mdn/discussions 8 | about: Does the issue involve a lot of changes, or is it hard to split it into actionable tasks? Start a discussion before opening an issue. 9 | - name: MDN Web Docs on Discourse 10 | url: https://discourse.mozilla.org/c/mdn/learn/250 11 | about: Need help with assessments on MDN Web Docs? We have a support community for this purpose on Discourse. 12 | - name: Help with code 13 | url: https://stackoverflow.com/ 14 | about: If you are stuck and need help with code, StackOverflow is a great resource. 15 | -------------------------------------------------------------------------------- /webvr/aframe-demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | A-Frame demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /webvr/aframe-demo/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright © 2015 A-Frame. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /canvas-raycaster/input.js: -------------------------------------------------------------------------------- 1 | var KEY = { 2 | D: 68, 3 | W: 87, 4 | A: 65, 5 | S:83, 6 | RIGHT:39, 7 | UP:38, 8 | LEFT:37, 9 | DOWN:40, 10 | Q:81 11 | }; 12 | 13 | var input = { 14 | right: false, 15 | up: false, 16 | left: false, 17 | down: false, 18 | quit: false 19 | }; 20 | 21 | function press(evt) { 22 | evt.preventDefault(); 23 | var code = evt.keyCode; 24 | switch(code) { 25 | case KEY.RIGHT: 26 | case KEY.D: input.right = true; break; 27 | 28 | case KEY.UP: 29 | case KEY.W: input.up = true; break; 30 | 31 | case KEY.LEFT: 32 | case KEY.A: input.left = true; break; 33 | 34 | case KEY.DOWN: 35 | case KEY.S: input.down = true; break; 36 | 37 | case KEY.Q: input.quit = true; break; 38 | } 39 | } 40 | 41 | function release(evt) { 42 | var code = evt.keyCode; 43 | switch(code) { 44 | case KEY.RIGHT: 45 | case KEY.D: input.right = false; break; 46 | 47 | case KEY.UP: 48 | case KEY.W: input.up = false; break; 49 | 50 | case KEY.LEFT: 51 | case KEY.A: input.left = false; break; 52 | 53 | case KEY.DOWN: 54 | case KEY.S: input.down = false; break; 55 | 56 | case KEY.Q: break; 57 | 58 | default: trace('unrecognized key code: ' +code); break; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: "Issue report" 2 | description: Report an unexpected problem or unintended behavior. 3 | labels: ["needs triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | ### Before you start 9 | 10 | **Want to fix the problem yourself?** This project is open source and we welcome fixes and improvements from the community! 11 | 12 | ↩ Check the project [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md) guide to see how to get started. 13 | 14 | --- 15 | - type: textarea 16 | id: problem 17 | attributes: 18 | label: What information was incorrect, unhelpful, or incomplete? 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: expected 23 | attributes: 24 | label: What did you expect to see? 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: references 29 | attributes: 30 | label: Do you have any supporting links, references, or citations? 31 | description: Link to information that helps us confirm your issue. 32 | - type: textarea 33 | id: more-info 34 | attributes: 35 | label: Do you have anything more you want to share? 36 | description: For example, steps to reproduce, screenshots, screen recordings, or sample code. 37 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Overview 4 | 5 | This policy applies to MDN's website (`developer.mozilla.org`), backend services, and GitHub repositories in the [`mdn`](https://github.com/mdn) organization. Issues affecting other Mozilla products or services should be reported through the [Mozilla Security Bug Bounty Program](https://www.mozilla.org/en-US/security/bug-bounty/). 6 | 7 | For non-security issues, please file a [content bug](https://github.com/mdn/content/issues/new/choose), a [website bug](https://github.com/mdn/fred/issues/new/choose) or a [content/feature suggestion](https://github.com/mdn/mdn/issues/new/choose). 8 | 9 | ## Reporting a Vulnerability 10 | 11 | If you discover a potential security issue, please report it privately via . 12 | 13 | If you prefer not to use HackerOne, you can report it via . 14 | 15 | ## Bounty Program 16 | 17 | Vulnerabilities in MDN may qualify for Mozilla's Bug Bounty Program. Eligibility and reward amounts are described on . 18 | 19 | Please use the above channels even if you are not interested in a bounty reward. 20 | 21 | ## Responsible Disclosure 22 | 23 | Please do not publicly disclose details until Mozilla's security team and the MDN engineering team have verified and fixed the issue. 24 | 25 | We appreciate your efforts to keep MDN and its users safe. 26 | -------------------------------------------------------------------------------- /webvr/stage-parameters-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRStageParameters basic test 9 | 10 | 11 | 12 | 13 |

VRStageParameters basic test

14 | 15 |

16 | 17 | 44 | 45 | -------------------------------------------------------------------------------- /webvr/README.md: -------------------------------------------------------------------------------- 1 | # webvr-tests 2 | Simple tests for testing WebVR functionality. See [https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API](https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API) for the latest on the documentation. 3 | 4 | The tests are as follows: 5 | 6 | * [basic-display-info](https://mdn.github.io/museum/webvr/basic-display-info/) — Demo that detects all VRDisplays connected to the computer and displays all their basic capabilities. 7 | * [field-of-view-test](https://mdn.github.io/museum/webvr/field-of-view-test/) — Demo that detects the first VRDisplay connected to the computer and displays its field of view information. 8 | * [stage-parameters-test](https://mdn.github.io/museum/webvr/stage-parameters-test/) — Demo that detects the first VRDisplay connected to the computer and displays its stage parameterss. 9 | * [raw-webgl-example](https://mdn.github.io/museum/webvr/raw-webgl-example/) — A quick 'n' dirty example that shows the basics of how to use the WebVR API. 10 | * [vr-controller-basic-info](https://mdn.github.io/museum/webvr/vr-controller-basic-info/) — Demo that detects and outputs information about VRDisplays and associated controllers connected to your computer. 11 | * [raw-webgl-controller-example](https://mdn.github.io/museum/webvr/raw-webgl-controller-example/) — A quick 'n' dirty example that shows the basics of how to use the WebVR API along with the Gamepad API to control objects in 3D space. 12 | * [aframe-demo](https://mdn.github.io/museum/webvr/aframe-demo/) — A simple WebVR demo that uses [Mozilla's A-Frame](https://aframe.io/) framework to create a scene. 13 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Raw WebGL/WebVR Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | Your browser doesn't appear to support the <canvas> element. 12 | 13 | 14 | 15 | 16 |
17 |
18 |

 

19 |

 

20 |
21 |
22 |

 

23 |

 

24 |
25 |
26 |

 

27 |

 

28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 46 | 47 | 48 | 49 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Raw WebGL/WebVR Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | Your browser doesn't appear to support the <canvas> element. 12 | 13 | 14 | 15 | 16 |
17 |
18 |

 

19 |

 

20 |
21 |
22 |

 

23 |

 

24 |
25 |
26 |

 

27 |

 

28 |
29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 46 | 47 | 48 | 49 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /canvas-raycaster/Level.js: -------------------------------------------------------------------------------- 1 | function Level() { 2 | this.CELLTYPE_OPEN = -1; 3 | this.CELL_SIZE = 64; // using multiple of 2 for optimization 4 | this.CELL_SIZE_SHIFT = 6; // x >> 6 = Math.floor(x/64) 5 | this.CELL_HALF = this.CELL_SIZE >> 1; // must be integer 6 | 7 | this.cellCount = { _x:0, _y:0 }; 8 | this.dimension = { _x:0, _y:0 }; 9 | this.spawnPoint = { _x:0, _y:0 }; 10 | this.colors = { ground:'#000000', sky:'#FFFFFF', wallsNear:0, wallsFar:0 }; 11 | 12 | this.map; 13 | this.viewExtent; 14 | this.walltypes; 15 | 16 | this.parseMap = function(mapString, cols, rows) { 17 | this.cellCount._x = cols; 18 | this.cellCount._y = rows; 19 | this.dimension._x = this.cellCount._x * this.CELL_SIZE; 20 | this.dimension._y = this.cellCount._y * this.CELL_SIZE; 21 | 22 | var parsedOk = false; 23 | 24 | if (mapString.length != this.cellCount._x * this.cellCount._y) { 25 | trace("map size not equal to level dimensions"); 26 | } 27 | 28 | else { 29 | this.walltypes = "@#%&"; 30 | this.colors.ground = '#444455'; 31 | this.colors.sky = '#66AAFF'; 32 | this.colors.wallsNear = new Array(0xDD1111, 0x11DD11, 0x1111DD, 0x6611CC); 33 | this.colors.wallsFar = new Array(0x110000, 0x001100, 0x000011, 0x110022); 34 | this.viewExtent = this.CELL_SIZE * 3; 35 | var spawnChar = "P"; 36 | 37 | this.map = new Array(); 38 | for (var row = 0; row < this.cellCount._y; row++) { 39 | var r = new Array(); 40 | for (var col = 0; col < this.cellCount._x; col++) { 41 | var type = this.CELLTYPE_OPEN; 42 | var c = mapString.charAt(row * this.cellCount._x + col); 43 | if (c == spawnChar) { 44 | type = this.CELLTYPE_OPEN; 45 | this.spawnPoint._x = col * this.CELL_SIZE + this.CELL_HALF; 46 | this.spawnPoint._y = row * this.CELL_SIZE + this.CELL_HALF; 47 | } 48 | else { 49 | var i = this.walltypes.indexOf(c); 50 | if (i > -1) { type = i; } 51 | } 52 | r.push(type); 53 | } 54 | this.map.push(r); 55 | } 56 | parsedOk = true; 57 | } 58 | 59 | return parsedOk; 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /webvr/field-of-view-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRFieldOfView basic test 9 | 10 | 11 | 12 | 13 |

VRFieldOfView basic test

14 | 15 |

16 | 17 |
    18 |
19 | 20 | 21 | 22 | 70 | 71 | -------------------------------------------------------------------------------- /.github/labels.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "good first issue", 4 | "color": "028c46", 5 | "description": "A good issue for newcomers to get started with." 6 | }, 7 | { 8 | "name": "help wanted", 9 | "color": "028c46", 10 | "description": "If you know something about this, we would love your help!" 11 | }, 12 | { 13 | "name": "needs info", 14 | "color": "028c46", 15 | "description": "This needs more information to review or act on." 16 | }, 17 | { 18 | "name": "needs triage", 19 | "color": "028c46", 20 | "description": "Triage needed by staff and/or partners. Automatically applied when an issue is opened." 21 | }, 22 | { 23 | "name": "expert help needed", 24 | "color": "028c46", 25 | "description": "This needs more information from a subject matter expert (SME)." 26 | }, 27 | { 28 | "name": "idle", 29 | "color": "028c46", 30 | "description": "Issues and pull requests with no activity for three months." 31 | }, 32 | { 33 | "name": "on hold", 34 | "color": "028c46", 35 | "description": "Waiting on something else before this can be moved forward." 36 | }, 37 | { 38 | "name": "for later", 39 | "color": "028c46", 40 | "description": "Not planned at this time." 41 | }, 42 | { 43 | "name": "needs content update", 44 | "color": "028c46", 45 | "description": "Needs update to the content to support this change." 46 | }, 47 | { 48 | "name": "chore", 49 | "color": "028c46", 50 | "description": "A routine task." 51 | }, 52 | { 53 | "name": "enhancement", 54 | "color": "028c46", 55 | "description": "Improves an existing feature." 56 | }, 57 | { 58 | "name": "bug", 59 | "color": "c05964", 60 | "description": "Indicates an unexpected problem or unintended behavior." 61 | }, 62 | { 63 | "name": "wontfix", 64 | "color": "c05964", 65 | "description": "Deemed to be outside the scope of the project or would require significant time and resources to fix." 66 | }, 67 | { 68 | "name": "effort: small", 69 | "color": "866dc1", 70 | "description": "Task is a small effort." 71 | }, 72 | { 73 | "name": "effort: medium", 74 | "color": "866dc1", 75 | "description": "Task is a medium effort." 76 | }, 77 | { 78 | "name": "effort: large", 79 | "color": "866dc1", 80 | "description": "Task is large effort." 81 | }, 82 | { 83 | "name": "p0", 84 | "color": "6e8bc1", 85 | "description": "Urgent. We will address this as soon as possible." 86 | }, 87 | { 88 | "name": "p1", 89 | "color": "6e8bc1", 90 | "description": "We will address this soon and will provide capacity from our team for it in the next few releases." 91 | }, 92 | { 93 | "name": "p2", 94 | "color": "6e8bc1", 95 | "description": "We want to address this but may have other higher priority items." 96 | }, 97 | { 98 | "name": "p3", 99 | "color": "6e8bc1", 100 | "description": "We don't have visibility when this will be addressed." 101 | } 102 | ] 103 | -------------------------------------------------------------------------------- /canvas-raycaster/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ray-caster 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 93 | 94 | 102 | 103 | 104 | 105 |
  • RayCaster v.0.0.1
106 | 107 | 108 | -------------------------------------------------------------------------------- /webvr/basic-display-info/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VRDisplay basic test 9 | 10 | 11 | 12 | 13 |

VRDisplay basic test

14 | 15 |

16 | 17 |
    18 |
19 | 20 | 21 | 22 | 112 | 113 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guide 2 | 3 | ![github-profile](https://user-images.githubusercontent.com/10350960/166113119-629295f6-c282-42c9-9379-af2de5ad4338.png) 4 | 5 | - [Ways to contribute](#ways-to-contribute) 6 | - [Finding an issue](#finding-an-issue) 7 | - [Asking for help](#asking-for-help) 8 | - [Pull request process](#pull-request-process) 9 | - [Forking and cloning the project](#forking-and-cloning-the-project) 10 | - [Signing commits](#signing-commits) 11 | 12 | Welcome 👋 Thank you for your interest in contributing to MDN Web Docs. We are happy to have you join us! 💖 13 | 14 | As you get started, you are in the best position to give us feedback on project areas we might have forgotten about or assumed to work well. 15 | These include, but are not limited to: 16 | 17 | - Problems found while setting up a new developer environment 18 | - Gaps in our documentation 19 | - Bugs in our automation scripts 20 | 21 | If anything doesn't make sense or work as expected, please open an issue and let us know! 22 | 23 | ## Ways to contribute 24 | 25 | We welcome many different types of contributions including: 26 | 27 | - New features and content suggestions. 28 | - Identifying and filing issues. 29 | - Providing feedback on existing issues. 30 | - Engaging with the community and answering questions. 31 | - Contributing documentation or code. 32 | - Promoting the project in personal circles and social media. 33 | 34 | ## Finding an issue 35 | 36 | We have issues labeled `good first issue` for new contributors and `help wanted` suitable for any contributor. 37 | Good first issues have extra information to help you make your first contribution a success. 38 | Help wanted issues are ideal when you feel a bit more comfortable with the project details. 39 | 40 | Sometimes there won't be any issues with these labels, but there is likely still something for you to work on. 41 | If you want to contribute but don't know where to start or can't find a suitable issue, speak to us on [Matrix](https://matrix.to/#/#mdn:mozilla.org), and we will be happy to help. 42 | 43 | Once you find an issue you'd like to work on, please post a comment saying you want to work on it. 44 | Something like "I want to work on this" is fine. 45 | Also, mention the community team using the `@mdn/community` handle to ensure someone will get back to you. 46 | 47 | ## Asking for help 48 | 49 | The best way to reach us with a question when contributing is to use the following channels in the following order of precedence: 50 | 51 | - [Start a discussion](https://github.com/orgs/mdn/discussions) 52 | - Ask your question or highlight your discussion on [Matrix](https://matrix.to/#/#mdn:mozilla.org). 53 | - File an issue and tag the community team using the `@mdn/community` handle. 54 | 55 | ## Pull request process 56 | 57 | The MDN Web Docs project has a well-defined pull request process which is documented in the [Pull request guidelines](https://developer.mozilla.org/en-US/docs/MDN/Community/Pull_requests). 58 | Make sure you read and understand this process before you start working on a pull request. 59 | 60 | ### Forking and cloning the project 61 | 62 | The first step in setting up your development environment is to [fork the repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) and [clone](https://docs.github.com/en/get-started/quickstart/fork-a-repo#cloning-your-forked-repository) the repository to your local machine. 63 | 64 | ## Signing commits 65 | 66 | We require all commits to be signed to verify the author's identity. 67 | GitHub has a detailed guide on [setting up signed commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits). 68 | If you get stuck, please [ask for help](#asking-for-help). 69 | -------------------------------------------------------------------------------- /webvr/aframe-demo/README.md: -------------------------------------------------------------------------------- 1 | # A-Frame Boilerplate 2 | 3 | Boilerplate for creating WebVR scenes with [A-Frame](https://aframe.io). 4 | 5 | Alternatively, check out the [A-Frame Starter on 6 | glitch.com](https://glitch.com/~aframe) for a more interactive way on getting 7 | started. 8 | 9 | ## Getting Started 10 | 11 | There are two easy options for obtaining this A-Frame scene. It's then up to you to make it your own! 12 | 13 | ### Option 1: Download the ZIP kit 📦 14 | 15 | [](https://github.com/aframevr/aframe-boilerplate/archive/master.zip) 16 | 17 | After you have __[downloaded and extracted this `.zip` file](https://github.com/aframevr/aframe-boilerplate/archive/master.zip)__ containing the contents of this repo, open the resulting directory, and you'll be have your scene ready in these few steps: 18 | 19 | npm install && npm start 20 | open http://localhost:3000/ 21 | 22 |
23 | 24 | ### Option 2: Fork this Git repo 🍴🐙 25 | 26 | Alternatively, you can __[fork this repo](https://github.com/aframevr/aframe-boilerplate/fork)__ to get started, if you'd like to maintain a Git workflow. 27 | 28 | After you have __[forked this repo](https://github.com/aframevr/aframe-boilerplate/fork)__, clone a copy of your fork locally and you'll be have your scene ready in these few steps: 29 | 30 | git clone https://github.com/aframevr/aframe-boilerplate.git 31 | cd aframe-boilerplate && rm -rf .git && npm install && npm start 32 | open http://localhost:3000/ 33 | 34 | > :iphone: **Mobile pro tip:** Upon starting the development server, the URL will be logged to the console. Load that URL from a browser on your mobile device. (If your mobile phone and computer are not on the same LAN, consider using [ngrok](https://ngrok.com/) for local development and testing. [Browsersync](https://www.browsersync.io/) is also worth a gander.) 35 | 36 |
37 | 38 | ### Option 3: Fork this CodePen example 🍴💾✒️ 39 | 40 | Or, you can simply __[fork this CodePen example](http://codepen.io/team/mozvr/pen/BjygdO?editors=100)__ to dive right in. Enjoy! 41 | 42 | 43 | ## Publishing your scene 44 | 45 | If you don't already know, GitHub offers free and awesome publishing of static sites through __[https://pages.github.com/](GitHub Pages)__. 46 | 47 | To publish your scene to your personal GitHub Pages: 48 | 49 | npm run deploy 50 | 51 | And, it'll now be live at __http://`your_username`.github.io/__ :) 52 | 53 |
54 | 55 | To know which GitHub repo to deploy to, the `deploy` script first looks at the optional [`repository` key](https://docs.npmjs.com/files/package.json#repository) in the [`package.json` file](package.json) (see [npm docs](https://docs.npmjs.com/files/package.json#repository) for sample usage). If the `repository` key is missing, the script falls back to using the local git repo's remote origin URL (you can run the local command `git remote -v` to see all your remotes; also, you may refer to the [GitHub docs](https://help.github.com/articles/about-remote-repositories/) for more information). 56 | 57 |
58 | 59 | ## Still need Help? 60 | 61 | ### Installation 62 | 63 | First make sure you have Node installed. 64 | 65 | On Mac OS X, it's recommended to use [Homebrew](http://brew.sh/) to install Node + [npm](https://www.npmjs.com): 66 | 67 | brew install node 68 | 69 | To install the Node dependencies: 70 | 71 | npm install 72 | 73 | 74 | ### Local Development 75 | 76 | To serve the site from a simple Node development server: 77 | 78 | npm start 79 | 80 | Then launch the site from your favourite browser: 81 | 82 | [__http://localhost:3000/__](http://localhost:3000/) 83 | 84 | If you wish to serve the site from a different port: 85 | 86 | PORT=8000 npm start 87 | 88 | 89 | ## License 90 | 91 | This program is free software and is distributed under an [MIT License](LICENSE). 92 | -------------------------------------------------------------------------------- /webvr/vr-controller-basic-info/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | VR Gamepads basic test 9 | 10 | 11 | 12 | 13 |

VR Gamepads basic test

14 | 15 |

16 | 17 |
    18 |
19 | 20 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/glUtils.js: -------------------------------------------------------------------------------- 1 | // augment Sylvester some 2 | Matrix.Translation = function (v) 3 | { 4 | if (v.elements.length == 2) { 5 | var r = Matrix.I(3); 6 | r.elements[2][0] = v.elements[0]; 7 | r.elements[2][1] = v.elements[1]; 8 | return r; 9 | } 10 | 11 | if (v.elements.length == 3) { 12 | var r = Matrix.I(4); 13 | r.elements[0][3] = v.elements[0]; 14 | r.elements[1][3] = v.elements[1]; 15 | r.elements[2][3] = v.elements[2]; 16 | return r; 17 | } 18 | 19 | throw "Invalid length for Translation"; 20 | } 21 | 22 | Matrix.prototype.flatten = function () 23 | { 24 | var result = []; 25 | if (this.elements.length == 0) 26 | return []; 27 | 28 | 29 | for (var j = 0; j < this.elements[0].length; j++) 30 | for (var i = 0; i < this.elements.length; i++) 31 | result.push(this.elements[i][j]); 32 | return result; 33 | } 34 | 35 | Matrix.prototype.ensure4x4 = function() 36 | { 37 | if (this.elements.length == 4 && 38 | this.elements[0].length == 4) 39 | return this; 40 | 41 | if (this.elements.length > 4 || 42 | this.elements[0].length > 4) 43 | return null; 44 | 45 | for (var i = 0; i < this.elements.length; i++) { 46 | for (var j = this.elements[i].length; j < 4; j++) { 47 | if (i == j) 48 | this.elements[i].push(1); 49 | else 50 | this.elements[i].push(0); 51 | } 52 | } 53 | 54 | for (var i = this.elements.length; i < 4; i++) { 55 | if (i == 0) 56 | this.elements.push([1, 0, 0, 0]); 57 | else if (i == 1) 58 | this.elements.push([0, 1, 0, 0]); 59 | else if (i == 2) 60 | this.elements.push([0, 0, 1, 0]); 61 | else if (i == 3) 62 | this.elements.push([0, 0, 0, 1]); 63 | } 64 | 65 | return this; 66 | }; 67 | 68 | Matrix.prototype.make3x3 = function() 69 | { 70 | if (this.elements.length != 4 || 71 | this.elements[0].length != 4) 72 | return null; 73 | 74 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]], 75 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]], 76 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]); 77 | }; 78 | 79 | Vector.prototype.flatten = function () 80 | { 81 | return this.elements; 82 | }; 83 | 84 | function mht(m) { 85 | var s = ""; 86 | if (m.length == 16) { 87 | for (var i = 0; i < 4; i++) { 88 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
"; 89 | } 90 | } else if (m.length == 9) { 91 | for (var i = 0; i < 3; i++) { 92 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
"; 93 | } 94 | } else { 95 | return m.toString(); 96 | } 97 | return s; 98 | } 99 | 100 | // 101 | // gluLookAt 102 | // 103 | function makeLookAt(ex, ey, ez, 104 | cx, cy, cz, 105 | ux, uy, uz) 106 | { 107 | var eye = $V([ex, ey, ez]); 108 | var center = $V([cx, cy, cz]); 109 | var up = $V([ux, uy, uz]); 110 | 111 | var mag; 112 | 113 | var z = eye.subtract(center).toUnitVector(); 114 | var x = up.cross(z).toUnitVector(); 115 | var y = z.cross(x).toUnitVector(); 116 | 117 | var m = $M([[x.e(1), x.e(2), x.e(3), 0], 118 | [y.e(1), y.e(2), y.e(3), 0], 119 | [z.e(1), z.e(2), z.e(3), 0], 120 | [0, 0, 0, 1]]); 121 | 122 | var t = $M([[1, 0, 0, -ex], 123 | [0, 1, 0, -ey], 124 | [0, 0, 1, -ez], 125 | [0, 0, 0, 1]]); 126 | return m.x(t); 127 | } 128 | 129 | // 130 | // glOrtho 131 | // 132 | function makeOrtho(left, right, 133 | bottom, top, 134 | znear, zfar) 135 | { 136 | var tx = -(right+left)/(right-left); 137 | var ty = -(top+bottom)/(top-bottom); 138 | var tz = -(zfar+znear)/(zfar-znear); 139 | 140 | return $M([[2/(right-left), 0, 0, tx], 141 | [0, 2/(top-bottom), 0, ty], 142 | [0, 0, -2/(zfar-znear), tz], 143 | [0, 0, 0, 1]]); 144 | } 145 | 146 | // 147 | // gluPerspective 148 | // 149 | function makePerspective(fovy, aspect, znear, zfar) 150 | { 151 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 152 | var ymin = -ymax; 153 | var xmin = ymin * aspect; 154 | var xmax = ymax * aspect; 155 | 156 | return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); 157 | } 158 | 159 | // 160 | // glFrustum 161 | // 162 | function makeFrustum(left, right, 163 | bottom, top, 164 | znear, zfar) 165 | { 166 | var X = 2*znear/(right-left); 167 | var Y = 2*znear/(top-bottom); 168 | var A = (right+left)/(right-left); 169 | var B = (top+bottom)/(top-bottom); 170 | var C = -(zfar+znear)/(zfar-znear); 171 | var D = -2*zfar*znear/(zfar-znear); 172 | 173 | return $M([[X, 0, A, 0], 174 | [0, Y, B, 0], 175 | [0, 0, C, D], 176 | [0, 0, -1, 0]]); 177 | } 178 | 179 | // 180 | // glOrtho 181 | // 182 | function makeOrtho(left, right, bottom, top, znear, zfar) 183 | { 184 | var tx = - (right + left) / (right - left); 185 | var ty = - (top + bottom) / (top - bottom); 186 | var tz = - (zfar + znear) / (zfar - znear); 187 | 188 | return $M([[2 / (right - left), 0, 0, tx], 189 | [0, 2 / (top - bottom), 0, ty], 190 | [0, 0, -2 / (zfar - znear), tz], 191 | [0, 0, 0, 1]]); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/glUtils.js: -------------------------------------------------------------------------------- 1 | // augment Sylvester some 2 | Matrix.Translation = function (v) 3 | { 4 | if (v.elements.length == 2) { 5 | var r = Matrix.I(3); 6 | r.elements[2][0] = v.elements[0]; 7 | r.elements[2][1] = v.elements[1]; 8 | return r; 9 | } 10 | 11 | if (v.elements.length == 3) { 12 | var r = Matrix.I(4); 13 | r.elements[0][3] = v.elements[0]; 14 | r.elements[1][3] = v.elements[1]; 15 | r.elements[2][3] = v.elements[2]; 16 | return r; 17 | } 18 | 19 | throw "Invalid length for Translation"; 20 | } 21 | 22 | Matrix.prototype.flatten = function () 23 | { 24 | var result = []; 25 | if (this.elements.length == 0) 26 | return []; 27 | 28 | 29 | for (var j = 0; j < this.elements[0].length; j++) 30 | for (var i = 0; i < this.elements.length; i++) 31 | result.push(this.elements[i][j]); 32 | return result; 33 | } 34 | 35 | Matrix.prototype.ensure4x4 = function() 36 | { 37 | if (this.elements.length == 4 && 38 | this.elements[0].length == 4) 39 | return this; 40 | 41 | if (this.elements.length > 4 || 42 | this.elements[0].length > 4) 43 | return null; 44 | 45 | for (var i = 0; i < this.elements.length; i++) { 46 | for (var j = this.elements[i].length; j < 4; j++) { 47 | if (i == j) 48 | this.elements[i].push(1); 49 | else 50 | this.elements[i].push(0); 51 | } 52 | } 53 | 54 | for (var i = this.elements.length; i < 4; i++) { 55 | if (i == 0) 56 | this.elements.push([1, 0, 0, 0]); 57 | else if (i == 1) 58 | this.elements.push([0, 1, 0, 0]); 59 | else if (i == 2) 60 | this.elements.push([0, 0, 1, 0]); 61 | else if (i == 3) 62 | this.elements.push([0, 0, 0, 1]); 63 | } 64 | 65 | return this; 66 | }; 67 | 68 | Matrix.prototype.make3x3 = function() 69 | { 70 | if (this.elements.length != 4 || 71 | this.elements[0].length != 4) 72 | return null; 73 | 74 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]], 75 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]], 76 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]); 77 | }; 78 | 79 | Vector.prototype.flatten = function () 80 | { 81 | return this.elements; 82 | }; 83 | 84 | function mht(m) { 85 | var s = ""; 86 | if (m.length == 16) { 87 | for (var i = 0; i < 4; i++) { 88 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
"; 89 | } 90 | } else if (m.length == 9) { 91 | for (var i = 0; i < 3; i++) { 92 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
"; 93 | } 94 | } else { 95 | return m.toString(); 96 | } 97 | return s; 98 | } 99 | 100 | // 101 | // gluLookAt 102 | // 103 | function makeLookAt(ex, ey, ez, 104 | cx, cy, cz, 105 | ux, uy, uz) 106 | { 107 | var eye = $V([ex, ey, ez]); 108 | var center = $V([cx, cy, cz]); 109 | var up = $V([ux, uy, uz]); 110 | 111 | var mag; 112 | 113 | var z = eye.subtract(center).toUnitVector(); 114 | var x = up.cross(z).toUnitVector(); 115 | var y = z.cross(x).toUnitVector(); 116 | 117 | var m = $M([[x.e(1), x.e(2), x.e(3), 0], 118 | [y.e(1), y.e(2), y.e(3), 0], 119 | [z.e(1), z.e(2), z.e(3), 0], 120 | [0, 0, 0, 1]]); 121 | 122 | var t = $M([[1, 0, 0, -ex], 123 | [0, 1, 0, -ey], 124 | [0, 0, 1, -ez], 125 | [0, 0, 0, 1]]); 126 | return m.x(t); 127 | } 128 | 129 | // 130 | // glOrtho 131 | // 132 | function makeOrtho(left, right, 133 | bottom, top, 134 | znear, zfar) 135 | { 136 | var tx = -(right+left)/(right-left); 137 | var ty = -(top+bottom)/(top-bottom); 138 | var tz = -(zfar+znear)/(zfar-znear); 139 | 140 | return $M([[2/(right-left), 0, 0, tx], 141 | [0, 2/(top-bottom), 0, ty], 142 | [0, 0, -2/(zfar-znear), tz], 143 | [0, 0, 0, 1]]); 144 | } 145 | 146 | // 147 | // gluPerspective 148 | // 149 | function makePerspective(fovy, aspect, znear, zfar) 150 | { 151 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0); 152 | var ymin = -ymax; 153 | var xmin = ymin * aspect; 154 | var xmax = ymax * aspect; 155 | 156 | return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar); 157 | } 158 | 159 | // 160 | // glFrustum 161 | // 162 | function makeFrustum(left, right, 163 | bottom, top, 164 | znear, zfar) 165 | { 166 | var X = 2*znear/(right-left); 167 | var Y = 2*znear/(top-bottom); 168 | var A = (right+left)/(right-left); 169 | var B = (top+bottom)/(top-bottom); 170 | var C = -(zfar+znear)/(zfar-znear); 171 | var D = -2*zfar*znear/(zfar-znear); 172 | 173 | return $M([[X, 0, A, 0], 174 | [0, Y, B, 0], 175 | [0, 0, C, D], 176 | [0, 0, -1, 0]]); 177 | } 178 | 179 | // 180 | // glOrtho 181 | // 182 | function makeOrtho(left, right, bottom, top, znear, zfar) 183 | { 184 | var tx = - (right + left) / (right - left); 185 | var ty = - (top + bottom) / (top - bottom); 186 | var tz = - (zfar + znear) / (zfar - znear); 187 | 188 | return $M([[2 / (right - left), 0, 0, tx], 189 | [0, 2 / (top - bottom), 0, ty], 190 | [0, 0, -2 / (zfar - znear), tz], 191 | [0, 0, 0, 1]]); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/sylvester.js: -------------------------------------------------------------------------------- 1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/sylvester.js: -------------------------------------------------------------------------------- 1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{})) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /webvr/raw-webgl-example/webgl-demo.js: -------------------------------------------------------------------------------- 1 | var canvas; // The canvas element 2 | var gl; // The WebGL context 3 | 4 | var cubeVerticesBuffer; 5 | var cubeVerticesTextureCoordBuffer; 6 | var cubeVerticesIndexBuffer; 7 | var cubeVerticesIndexBuffer; 8 | var cubeRotation = 0.0; 9 | var lastCubeUpdateTime = 0; 10 | 11 | var cubeImage; 12 | var cubeTexture; 13 | 14 | var mvMatrix; 15 | var shaderProgram; // The WebGLProgram we will create, which will render the cube 16 | var vertexPositionAttribute; 17 | var textureCoordAttribute; 18 | var perspectiveMatrix; 19 | 20 | // WebVR variables 21 | 22 | var frameData = new VRFrameData(); 23 | var vrDisplay; 24 | var btn = document.querySelector('.stop-start'); 25 | var normalSceneFrame; 26 | var vrSceneFrame; 27 | 28 | var poseStatsBtn = document.querySelector('.pose-stats'); 29 | var poseStatsSection = document.querySelector('section'); 30 | poseStatsSection.style.visibility = 'hidden'; // hide it initially 31 | 32 | var posStats = document.querySelector('.pos'); 33 | var orientStats = document.querySelector('.orient'); 34 | var linVelStats = document.querySelector('.lin-vel'); 35 | var linAccStats = document.querySelector('.lin-acc'); 36 | var angVelStats = document.querySelector('.ang-vel'); 37 | var angAccStats = document.querySelector('.ang-acc'); 38 | var poseStatsDisplayed = false; 39 | 40 | // 41 | // start 42 | // 43 | // Called when the body has loaded is created to get the ball rolling. 44 | 45 | document.body.onload = start; 46 | 47 | function start() { 48 | canvas = document.getElementById("glcanvas"); 49 | 50 | initWebGL(canvas); // Initialize the GL context 51 | 52 | // Only continue if WebGL is available and working 53 | 54 | if (gl) { 55 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque 56 | gl.clearDepth(1.0); // Clear everything 57 | gl.enable(gl.DEPTH_TEST); // Enable depth testing 58 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things 59 | 60 | // Initialize the shaders; this is where all the lighting for the 61 | // vertices and so forth is established. 62 | 63 | initShaders(); 64 | 65 | // Here's where we call the routine that builds all the objects 66 | // we'll be drawing. 67 | 68 | initBuffers(); 69 | 70 | // Next, load and set up the textures we'll be using. 71 | 72 | initTextures(); 73 | 74 | // draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser 75 | 76 | canvas.width = window.innerWidth; 77 | canvas.height = window.innerHeight; 78 | drawScene(); 79 | 80 | // WebVR: Check to see if WebVR is supported 81 | if(navigator.getVRDisplays) { 82 | console.log('WebVR 1.1 supported'); 83 | // Then get the displays attached to the computer 84 | navigator.getVRDisplays().then(function(displays) { 85 | // If a display is available, use it to present the scene 86 | if(displays.length > 0) { 87 | vrDisplay = displays[0]; 88 | console.log('Display found'); 89 | // Starting the presentation when the button is clicked: It can only be called in response to a user gesture 90 | btn.addEventListener('click', function() { 91 | if(btn.textContent === 'Start VR display') { 92 | vrDisplay.requestPresent([{ source: canvas }]).then(function() { 93 | console.log('Presenting to WebVR display'); 94 | 95 | // Set the canvas size to the size of the vrDisplay viewport 96 | 97 | var leftEye = vrDisplay.getEyeParameters('left'); 98 | var rightEye = vrDisplay.getEyeParameters('right'); 99 | 100 | canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2; 101 | canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight); 102 | 103 | // stop the normal presentation, and start the vr presentation 104 | window.cancelAnimationFrame(normalSceneFrame); 105 | drawVRScene(); 106 | 107 | btn.textContent = 'Exit VR display'; 108 | }); 109 | } else { 110 | vrDisplay.exitPresent(); 111 | console.log('Stopped presenting to WebVR display'); 112 | 113 | btn.textContent = 'Start VR display'; 114 | 115 | // Stop the VR presentation, and start the normal presentation 116 | vrDisplay.cancelAnimationFrame(vrSceneFrame); 117 | drawScene(); 118 | } 119 | }); 120 | } 121 | }); 122 | } else { 123 | console.log('WebVR API not supported by this browser.'); 124 | } 125 | } 126 | } 127 | 128 | // 129 | // initWebGL 130 | // 131 | // Initialize WebGL, returning the GL context or null if 132 | // WebGL isn't available or could not be initialized. 133 | // 134 | function initWebGL() { 135 | gl = null; 136 | 137 | try { 138 | gl = canvas.getContext("experimental-webgl"); 139 | } 140 | catch(e) { 141 | } 142 | 143 | // If we don't have a GL context, give up now 144 | 145 | if (!gl) { 146 | alert("Unable to initialize WebGL. Your browser may not support it."); 147 | } 148 | } 149 | 150 | // 151 | // initBuffers 152 | // 153 | // Initialize the buffers we'll need. For this demo, we just have 154 | // one object -- a simple two-dimensional cube. 155 | // 156 | function initBuffers() { 157 | 158 | // Create a buffer for the cube's vertices. 159 | 160 | cubeVerticesBuffer = gl.createBuffer(); 161 | 162 | // Select the cubeVerticesBuffer as the one to apply vertex 163 | // operations to from here out. 164 | 165 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 166 | 167 | // Now create an array of vertices for the cube. 168 | 169 | var vertices = [ 170 | // Front face 171 | -1.0, -1.0, 1.0, 172 | 1.0, -1.0, 1.0, 173 | 1.0, 1.0, 1.0, 174 | -1.0, 1.0, 1.0, 175 | 176 | // Back face 177 | -1.0, -1.0, -1.0, 178 | -1.0, 1.0, -1.0, 179 | 1.0, 1.0, -1.0, 180 | 1.0, -1.0, -1.0, 181 | 182 | // Top face 183 | -1.0, 1.0, -1.0, 184 | -1.0, 1.0, 1.0, 185 | 1.0, 1.0, 1.0, 186 | 1.0, 1.0, -1.0, 187 | 188 | // Bottom face 189 | -1.0, -1.0, -1.0, 190 | 1.0, -1.0, -1.0, 191 | 1.0, -1.0, 1.0, 192 | -1.0, -1.0, 1.0, 193 | 194 | // Right face 195 | 1.0, -1.0, -1.0, 196 | 1.0, 1.0, -1.0, 197 | 1.0, 1.0, 1.0, 198 | 1.0, -1.0, 1.0, 199 | 200 | // Left face 201 | -1.0, -1.0, -1.0, 202 | -1.0, -1.0, 1.0, 203 | -1.0, 1.0, 1.0, 204 | -1.0, 1.0, -1.0 205 | ]; 206 | 207 | // Now pass the list of vertices into WebGL to build the shape. We 208 | // do this by creating a Float32Array from the JavaScript array, 209 | // then use it to fill the current vertex buffer. 210 | 211 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 212 | 213 | // Map the texture onto the cube's faces. 214 | 215 | cubeVerticesTextureCoordBuffer = gl.createBuffer(); 216 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 217 | 218 | var textureCoordinates = [ 219 | // Front 220 | 0.0, 0.0, 221 | 1.0, 0.0, 222 | 1.0, 1.0, 223 | 0.0, 1.0, 224 | // Back 225 | 0.0, 0.0, 226 | 1.0, 0.0, 227 | 1.0, 1.0, 228 | 0.0, 1.0, 229 | // Top 230 | 0.0, 0.0, 231 | 1.0, 0.0, 232 | 1.0, 1.0, 233 | 0.0, 1.0, 234 | // Bottom 235 | 0.0, 0.0, 236 | 1.0, 0.0, 237 | 1.0, 1.0, 238 | 0.0, 1.0, 239 | // Right 240 | 0.0, 0.0, 241 | 1.0, 0.0, 242 | 1.0, 1.0, 243 | 0.0, 1.0, 244 | // Left 245 | 0.0, 0.0, 246 | 1.0, 0.0, 247 | 1.0, 1.0, 248 | 0.0, 1.0 249 | ]; 250 | 251 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), 252 | gl.STATIC_DRAW); 253 | 254 | // Build the element array buffer; this specifies the indices 255 | // into the vertex array for each face's vertices. 256 | 257 | cubeVerticesIndexBuffer = gl.createBuffer(); 258 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 259 | 260 | // This array defines each face as two triangles, using the 261 | // indices into the vertex array to specify each triangle's 262 | // position. 263 | 264 | var cubeVertexIndices = [ 265 | 0, 1, 2, 0, 2, 3, // front 266 | 4, 5, 6, 4, 6, 7, // back 267 | 8, 9, 10, 8, 10, 11, // top 268 | 12, 13, 14, 12, 14, 15, // bottom 269 | 16, 17, 18, 16, 18, 19, // right 270 | 20, 21, 22, 20, 22, 23 // left 271 | ]; 272 | 273 | // Now send the element array to GL 274 | 275 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 276 | new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 277 | } 278 | 279 | // 280 | // initTextures 281 | // 282 | // Initialize the textures we'll be using, then initiate a load of 283 | // the texture images. The handleTextureLoaded() callback will finish 284 | // the job; it gets called each time a texture finishes loading. 285 | // 286 | function initTextures() { 287 | cubeTexture = gl.createTexture(); 288 | cubeImage = new Image(); 289 | cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }; 290 | cubeImage.src = "metal003.png"; 291 | } 292 | 293 | function handleTextureLoaded(image, texture) { 294 | console.log("handleTextureLoaded, image = " + image); 295 | gl.bindTexture(gl.TEXTURE_2D, texture); 296 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, 297 | gl.UNSIGNED_BYTE, image); 298 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 299 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 300 | gl.generateMipmap(gl.TEXTURE_2D); 301 | gl.bindTexture(gl.TEXTURE_2D, null); 302 | } 303 | 304 | // 305 | // drawScene 306 | 307 | 308 | function drawScene() { 309 | // Request the next frame of the animation 310 | normalSceneFrame = window.requestAnimationFrame(drawScene); 311 | 312 | // Clear the canvas before we start drawing on it. 313 | 314 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 315 | 316 | gl.viewport(0, 0, canvas.width, canvas.height); 317 | 318 | // Establish the perspective with which we want to view the 319 | // scene. Our field of view is 45 degrees, with a width/height 320 | // ratio of 640:480, and we only want to see objects between 0.1 units 321 | // and 100 units away from the camera. 322 | 323 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 324 | 325 | // Set the drawing position to the "identity" point, which is 326 | // the center of the scene. 327 | 328 | loadIdentity(); 329 | 330 | // Now move the drawing position a bit to where we want to start 331 | // drawing the cube. 332 | 333 | mvTranslate([-0.0, 0.0, -9.0]); 334 | 335 | // Save the current matrix, then rotate before we draw. 336 | 337 | mvPushMatrix(); 338 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 339 | 340 | // Draw the cube by binding the array buffer to the cube's vertices 341 | // array, setting attributes, and pushing it to GL. 342 | 343 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 344 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 345 | 346 | // Set the texture coordinates attribute for the vertices. 347 | 348 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 349 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 350 | 351 | // Specify the texture to map onto the faces. 352 | 353 | gl.activeTexture(gl.TEXTURE0); 354 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 355 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 356 | 357 | // Draw the cube. 358 | 359 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 360 | setMatrixUniforms(); 361 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 362 | 363 | // Restore the original matrix 364 | 365 | mvPopMatrix(); 366 | 367 | // Update the rotation for the next draw, if it's time to do so. 368 | 369 | var currentTime = (new Date).getTime(); 370 | if (lastCubeUpdateTime) { 371 | var delta = currentTime - lastCubeUpdateTime; 372 | 373 | cubeRotation += (30 * delta) / 1000.0; 374 | } 375 | 376 | lastCubeUpdateTime = currentTime; 377 | } 378 | 379 | 380 | // 381 | // WebVR: Draw the scene for the WebVR display. 382 | // 383 | function drawVRScene() { 384 | // WebVR: Request the next frame of the animation 385 | vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene); 386 | 387 | // Populate frameData with the data of the next frame to display 388 | vrDisplay.getFrameData(frameData); 389 | 390 | // You can get the position, orientation, etc. of the display from the current frame's pose 391 | 392 | var curFramePose = frameData.pose; 393 | var curPos = curFramePose.position; 394 | var curOrient = curFramePose.orientation; 395 | if(poseStatsDisplayed) { 396 | displayPoseStats(curFramePose); 397 | } 398 | 399 | // Clear the canvas before we start drawing on it. 400 | 401 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 402 | 403 | // WebVR: Create the required projection and view matrix locations needed 404 | // for passing into the uniformMatrix4fv methods below 405 | 406 | var projectionMatrixLocation = gl.getUniformLocation(shaderProgram, "projMatrix"); 407 | var viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix"); 408 | 409 | // WebVR: Render the left eye’s view to the left half of the canvas 410 | gl.viewport(0, 0, canvas.width * 0.5, canvas.height); 411 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.leftProjectionMatrix); 412 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix); 413 | drawGeometry(); 414 | 415 | // WebVR: Render the right eye’s view to the right half of the canvas 416 | gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); 417 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.rightProjectionMatrix); 418 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix); 419 | drawGeometry(); 420 | 421 | function drawGeometry() { 422 | // Establish the perspective with which we want to view the 423 | // scene. Our field of view is 45 degrees, with a width/height 424 | // ratio of 640:480, and we only want to see objects between 0.1 units 425 | // and 100 units away from the camera. 426 | 427 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 428 | 429 | // Set the drawing position to the "identity" point, which is 430 | // the center of the scene. 431 | 432 | loadIdentity(); 433 | 434 | // Now move the drawing position a bit to where we want to start 435 | // drawing the cube. 436 | 437 | mvTranslate([ 438 | 0.0 - (curPos[0] * 25) + (curOrient[1] * 25), 439 | 5.0 - (curPos[1] * 25) - (curOrient[0] * 25), 440 | -15.0 - (curPos[2] * 25) 441 | ]); 442 | 443 | // Save the current matrix, then rotate before we draw. 444 | 445 | mvPushMatrix(); 446 | mvRotate(cubeRotation, [0.25, 0, 0.25 - curOrient[2] * 0.5]); 447 | 448 | // Draw the cube by binding the array buffer to the cube's vertices 449 | // array, setting attributes, and pushing it to GL. 450 | 451 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 452 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 453 | 454 | // Set the texture coordinates attribute for the vertices. 455 | 456 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 457 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 458 | 459 | // Specify the texture to map onto the faces. 460 | 461 | gl.activeTexture(gl.TEXTURE0); 462 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 463 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 464 | 465 | // Draw the cube. 466 | 467 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 468 | setMatrixUniforms(); 469 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 470 | 471 | // Restore the original matrix 472 | 473 | mvPopMatrix(); 474 | } 475 | 476 | // Update the rotation for the next draw, if it's time to do so. 477 | 478 | var currentTime = (new Date).getTime(); 479 | if (lastCubeUpdateTime) { 480 | var delta = currentTime - lastCubeUpdateTime; 481 | 482 | cubeRotation += (30 * delta) / 1000.0; 483 | } 484 | 485 | lastCubeUpdateTime = currentTime; 486 | 487 | // WebVR: Indicate that we are ready to present the rendered frame to the VR display 488 | vrDisplay.submitFrame(); 489 | } 490 | 491 | // 492 | // initShaders 493 | // 494 | // Initialize the shaders, so WebGL knows how to light our scene. 495 | // 496 | function initShaders() { 497 | var fragmentShader = getShader(gl, "shader-fs"); 498 | var vertexShader = getShader(gl, "shader-vs"); 499 | 500 | // Create the shader program 501 | 502 | shaderProgram = gl.createProgram(); // Create our program, set it to be the value of shaderProgram 503 | gl.attachShader(shaderProgram, vertexShader); 504 | gl.attachShader(shaderProgram, fragmentShader); 505 | gl.linkProgram(shaderProgram); 506 | 507 | // If creating the shader program failed, alert 508 | 509 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 510 | alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shader)); 511 | } 512 | 513 | gl.useProgram(shaderProgram); // Specify the WebGL program we want to use for the rendering 514 | 515 | vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 516 | gl.enableVertexAttribArray(vertexPositionAttribute); 517 | 518 | textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 519 | gl.enableVertexAttribArray(textureCoordAttribute); 520 | } 521 | 522 | // 523 | // getShader 524 | // 525 | // Loads a shader program by scouring the current document, 526 | // looking for a script with the specified ID. 527 | // 528 | function getShader(gl, id) { 529 | var shaderScript = document.getElementById(id); 530 | 531 | // Didn't find an element with the specified ID; abort. 532 | 533 | if (!shaderScript) { 534 | return null; 535 | } 536 | 537 | // Walk through the source element's children, building the 538 | // shader source string. 539 | 540 | var theSource = ""; 541 | var currentChild = shaderScript.firstChild; 542 | 543 | while(currentChild) { 544 | if (currentChild.nodeType == 3) { 545 | theSource += currentChild.textContent; 546 | } 547 | 548 | currentChild = currentChild.nextSibling; 549 | } 550 | 551 | // Now figure out what type of shader script we have, 552 | // based on its MIME type. 553 | 554 | var shader; 555 | 556 | if (shaderScript.type == "x-shader/x-fragment") { 557 | shader = gl.createShader(gl.FRAGMENT_SHADER); 558 | } else if (shaderScript.type == "x-shader/x-vertex") { 559 | shader = gl.createShader(gl.VERTEX_SHADER); 560 | } else { 561 | return null; // Unknown shader type 562 | } 563 | 564 | // Send the source to the shader object 565 | 566 | gl.shaderSource(shader, theSource); 567 | 568 | // Compile the shader program 569 | 570 | gl.compileShader(shader); 571 | 572 | // See if it compiled successfully 573 | 574 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 575 | alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); 576 | return null; 577 | } 578 | 579 | return shader; 580 | } 581 | 582 | // 583 | // Matrix utility functions 584 | // 585 | 586 | function loadIdentity() { 587 | mvMatrix = Matrix.I(4); 588 | } 589 | 590 | function multMatrix(m) { 591 | mvMatrix = mvMatrix.x(m); 592 | } 593 | 594 | function mvTranslate(v) { 595 | multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4()); 596 | } 597 | 598 | function setMatrixUniforms() { 599 | var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 600 | gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten())); 601 | 602 | var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); 603 | gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten())); 604 | } 605 | 606 | var mvMatrixStack = []; 607 | 608 | function mvPushMatrix(m) { 609 | if (m) { 610 | mvMatrixStack.push(m.dup()); 611 | mvMatrix = m.dup(); 612 | } else { 613 | mvMatrixStack.push(mvMatrix.dup()); 614 | } 615 | } 616 | 617 | function mvPopMatrix() { 618 | if (!mvMatrixStack.length) { 619 | throw("Can't pop from an empty matrix stack."); 620 | } 621 | 622 | mvMatrix = mvMatrixStack.pop(); 623 | return mvMatrix; 624 | } 625 | 626 | function mvRotate(angle, v) { 627 | var inRadians = angle * Math.PI / 180.0; 628 | var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); 629 | multMatrix(m); 630 | } 631 | 632 | // WebVR: Sample event handler 633 | 634 | window.addEventListener('vrdisplaypresentchange', function(e) { 635 | console.log('Display ' + e.display.displayId + ' presentation has changed. Reason given: ' + e.reason + '.'); 636 | }); 637 | 638 | // WebVR: Controls readout of pose stats panel 639 | 640 | poseStatsBtn.addEventListener('click', function() { 641 | if(!poseStatsDisplayed) { 642 | poseStatsDisplayed = true; 643 | poseStatsSection.style.visibility = 'visible'; 644 | poseStatsBtn.textContent = 'Hide pose stats'; 645 | } else { 646 | poseStatsDisplayed = false; 647 | poseStatsSection.style.visibility = 'hidden'; 648 | poseStatsBtn.textContent = 'Show pose stats'; 649 | } 650 | }); 651 | 652 | function displayPoseStats(pose) { 653 | var pos = pose.position; 654 | var orient = pose.orientation; 655 | var linVel = pose.linearVelocity; 656 | var linAcc = pose.linearAcceleration; 657 | var angVel = pose.angularVelocity; 658 | var angAcc = pose.angularAcceleration; 659 | 660 | posStats.textContent = 'Position: x ' + pos[0].toFixed(3) + ', y ' + pos[1].toFixed(3) + ', z ' + pos[2].toFixed(3); 661 | orientStats.textContent = 'Orientation: x ' + orient[0].toFixed(3) + ', y ' + orient[1].toFixed(3) + ', z ' + orient[2].toFixed(3); 662 | linVelStats.textContent = 'Linear velocity: x ' + linVel[0].toFixed(3) + ', y ' + linVel[1].toFixed(3) + ', z ' + linVel[2].toFixed(3); 663 | angVelStats.textContent = 'Angular velocity: x ' + angVel[0].toFixed(3) + ', y ' + angVel[1].toFixed(3) + ', z ' + angVel[2].toFixed(3); 664 | 665 | if(linAcc) { 666 | linAccStats.textContent = 'Linear acceleration: x ' + linAcc[0].toFixed(3) + ', y ' + linAcc[1].toFixed(3) + ', z ' + linAcc[2].toFixed(3); 667 | } else { 668 | linAccStats.textContent = 'Linear acceleration not reported'; 669 | } 670 | 671 | if(angAcc) { 672 | angAccStats.textContent = 'Angular acceleration: x ' + angAcc[0].toFixed(3) + ', y ' + angAcc[1].toFixed(3) + ', z ' + angAcc[2].toFixed(3); 673 | } else { 674 | angAccStats.textContent = 'Angular acceleration not reported'; 675 | } 676 | } 677 | -------------------------------------------------------------------------------- /webvr/raw-webgl-controller-example/webgl-demo.js: -------------------------------------------------------------------------------- 1 | var canvas; // The canvas element 2 | var gl; // The WebGL context 3 | 4 | var cubeVerticesBuffer; 5 | var cubeVerticesTextureCoordBuffer; 6 | var cubeVerticesIndexBuffer; 7 | var cubeVerticesIndexBuffer; 8 | var cubeRotation = 0.0; 9 | var lastCubeUpdateTime = 0; 10 | 11 | var cubeImage; 12 | var cubeTexture; 13 | 14 | var mvMatrix; 15 | var shaderProgram; // The WebGLProgram we will create, which will render the cube 16 | var vertexPositionAttribute; 17 | var textureCoordAttribute; 18 | var perspectiveMatrix; 19 | 20 | // WebVR variables 21 | 22 | var frameData = new VRFrameData(); 23 | var vrDisplay; 24 | var btn = document.querySelector('.stop-start'); 25 | var normalSceneFrame; 26 | var vrSceneFrame; 27 | 28 | var poseStatsBtn = document.querySelector('.pose-stats'); 29 | var poseStatsSection = document.querySelector('section'); 30 | poseStatsSection.style.visibility = 'hidden'; // hide it initially 31 | 32 | var posStats = document.querySelector('.pos'); 33 | var orientStats = document.querySelector('.orient'); 34 | var linVelStats = document.querySelector('.lin-vel'); 35 | var linAccStats = document.querySelector('.lin-acc'); 36 | var angVelStats = document.querySelector('.ang-vel'); 37 | var angAccStats = document.querySelector('.ang-acc'); 38 | var poseStatsDisplayed = false; 39 | 40 | // 41 | // start 42 | // 43 | // Called when the body has loaded is created to get the ball rolling. 44 | 45 | document.body.onload = start; 46 | 47 | function start() { 48 | canvas = document.getElementById("glcanvas"); 49 | 50 | initWebGL(canvas); // Initialize the GL context 51 | 52 | // Only continue if WebGL is available and working 53 | 54 | if (gl) { 55 | gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque 56 | gl.clearDepth(1.0); // Clear everything 57 | gl.enable(gl.DEPTH_TEST); // Enable depth testing 58 | gl.depthFunc(gl.LEQUAL); // Near things obscure far things 59 | 60 | // Initialize the shaders; this is where all the lighting for the 61 | // vertices and so forth is established. 62 | 63 | initShaders(); 64 | 65 | // Here's where we call the routine that builds all the objects 66 | // we'll be drawing. 67 | 68 | initBuffers(); 69 | 70 | // Next, load and set up the textures we'll be using. 71 | 72 | initTextures(); 73 | 74 | // draw the scene normally, without WebVR - for those who don't have it and want to see the scene in their browser 75 | 76 | canvas.width = window.innerWidth; 77 | canvas.height = window.innerHeight; 78 | drawScene(); 79 | 80 | // WebVR: Check to see if WebVR is supported 81 | if(navigator.getVRDisplays) { 82 | console.log('WebVR 1.1 supported'); 83 | // Then get the displays attached to the computer 84 | navigator.getVRDisplays().then(function(displays) { 85 | // If a display is available, use it to present the scene 86 | if(displays.length > 0) { 87 | vrDisplay = displays[0]; 88 | console.log('Display found'); 89 | // Starting the presentation when the button is clicked: It can only be called in response to a user gesture 90 | btn.addEventListener('click', function() { 91 | if(btn.textContent === 'Start VR display') { 92 | vrDisplay.requestPresent([{ source: canvas }]).then(function() { 93 | console.log('Presenting to WebVR display'); 94 | 95 | // Set the canvas size to the size of the vrDisplay viewport 96 | 97 | var leftEye = vrDisplay.getEyeParameters('left'); 98 | var rightEye = vrDisplay.getEyeParameters('right'); 99 | 100 | canvas.width = Math.max(leftEye.renderWidth, rightEye.renderWidth) * 2; 101 | canvas.height = Math.max(leftEye.renderHeight, rightEye.renderHeight); 102 | 103 | // stop the normal presentation, and start the vr presentation 104 | window.cancelAnimationFrame(normalSceneFrame); 105 | drawVRScene(); 106 | 107 | btn.textContent = 'Exit VR display'; 108 | }); 109 | } else { 110 | vrDisplay.exitPresent(); 111 | console.log('Stopped presenting to WebVR display'); 112 | 113 | btn.textContent = 'Start VR display'; 114 | 115 | // Stop the VR presentation, and start the normal presentation 116 | vrDisplay.cancelAnimationFrame(vrSceneFrame); 117 | drawScene(); 118 | } 119 | }); 120 | } 121 | }); 122 | } else { 123 | info.textContent = 'WebVR API not supported by this browser.'; 124 | } 125 | } 126 | } 127 | 128 | // 129 | // initWebGL 130 | // 131 | // Initialize WebGL, returning the GL context or null if 132 | // WebGL isn't available or could not be initialized. 133 | // 134 | function initWebGL() { 135 | gl = null; 136 | 137 | try { 138 | gl = canvas.getContext("experimental-webgl"); 139 | } 140 | catch(e) { 141 | } 142 | 143 | // If we don't have a GL context, give up now 144 | 145 | if (!gl) { 146 | alert("Unable to initialize WebGL. Your browser may not support it."); 147 | } 148 | } 149 | 150 | // 151 | // initBuffers 152 | // 153 | // Initialize the buffers we'll need. For this demo, we just have 154 | // one object -- a simple two-dimensional cube. 155 | // 156 | function initBuffers() { 157 | 158 | // Create a buffer for the cube's vertices. 159 | 160 | cubeVerticesBuffer = gl.createBuffer(); 161 | 162 | // Select the cubeVerticesBuffer as the one to apply vertex 163 | // operations to from here out. 164 | 165 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 166 | 167 | // Now create an array of vertices for the cube. 168 | 169 | var vertices = [ 170 | // Front face 171 | -1.0, -1.0, 1.0, 172 | 1.0, -1.0, 1.0, 173 | 1.0, 1.0, 1.0, 174 | -1.0, 1.0, 1.0, 175 | 176 | // Back face 177 | -1.0, -1.0, -1.0, 178 | -1.0, 1.0, -1.0, 179 | 1.0, 1.0, -1.0, 180 | 1.0, -1.0, -1.0, 181 | 182 | // Top face 183 | -1.0, 1.0, -1.0, 184 | -1.0, 1.0, 1.0, 185 | 1.0, 1.0, 1.0, 186 | 1.0, 1.0, -1.0, 187 | 188 | // Bottom face 189 | -1.0, -1.0, -1.0, 190 | 1.0, -1.0, -1.0, 191 | 1.0, -1.0, 1.0, 192 | -1.0, -1.0, 1.0, 193 | 194 | // Right face 195 | 1.0, -1.0, -1.0, 196 | 1.0, 1.0, -1.0, 197 | 1.0, 1.0, 1.0, 198 | 1.0, -1.0, 1.0, 199 | 200 | // Left face 201 | -1.0, -1.0, -1.0, 202 | -1.0, -1.0, 1.0, 203 | -1.0, 1.0, 1.0, 204 | -1.0, 1.0, -1.0 205 | ]; 206 | 207 | // Now pass the list of vertices into WebGL to build the shape. We 208 | // do this by creating a Float32Array from the JavaScript array, 209 | // then use it to fill the current vertex buffer. 210 | 211 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 212 | 213 | // Map the texture onto the cube's faces. 214 | 215 | cubeVerticesTextureCoordBuffer = gl.createBuffer(); 216 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 217 | 218 | var textureCoordinates = [ 219 | // Front 220 | 0.0, 0.0, 221 | 1.0, 0.0, 222 | 1.0, 1.0, 223 | 0.0, 1.0, 224 | // Back 225 | 0.0, 0.0, 226 | 1.0, 0.0, 227 | 1.0, 1.0, 228 | 0.0, 1.0, 229 | // Top 230 | 0.0, 0.0, 231 | 1.0, 0.0, 232 | 1.0, 1.0, 233 | 0.0, 1.0, 234 | // Bottom 235 | 0.0, 0.0, 236 | 1.0, 0.0, 237 | 1.0, 1.0, 238 | 0.0, 1.0, 239 | // Right 240 | 0.0, 0.0, 241 | 1.0, 0.0, 242 | 1.0, 1.0, 243 | 0.0, 1.0, 244 | // Left 245 | 0.0, 0.0, 246 | 1.0, 0.0, 247 | 1.0, 1.0, 248 | 0.0, 1.0 249 | ]; 250 | 251 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), 252 | gl.STATIC_DRAW); 253 | 254 | // Build the element array buffer; this specifies the indices 255 | // into the vertex array for each face's vertices. 256 | 257 | cubeVerticesIndexBuffer = gl.createBuffer(); 258 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 259 | 260 | // This array defines each face as two triangles, using the 261 | // indices into the vertex array to specify each triangle's 262 | // position. 263 | 264 | var cubeVertexIndices = [ 265 | 0, 1, 2, 0, 2, 3, // front 266 | 4, 5, 6, 4, 6, 7, // back 267 | 8, 9, 10, 8, 10, 11, // top 268 | 12, 13, 14, 12, 14, 15, // bottom 269 | 16, 17, 18, 16, 18, 19, // right 270 | 20, 21, 22, 20, 22, 23 // left 271 | ]; 272 | 273 | // Now send the element array to GL 274 | 275 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 276 | new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 277 | } 278 | 279 | // 280 | // initTextures 281 | // 282 | // Initialize the textures we'll be using, then initiate a load of 283 | // the texture images. The handleTextureLoaded() callback will finish 284 | // the job; it gets called each time a texture finishes loading. 285 | // 286 | function initTextures() { 287 | cubeTexture = gl.createTexture(); 288 | cubeImage = new Image(); 289 | cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }; 290 | cubeImage.src = "metal003.png"; 291 | } 292 | 293 | function handleTextureLoaded(image, texture) { 294 | console.log("handleTextureLoaded, image = " + image); 295 | gl.bindTexture(gl.TEXTURE_2D, texture); 296 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, 297 | gl.UNSIGNED_BYTE, image); 298 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 299 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 300 | gl.generateMipmap(gl.TEXTURE_2D); 301 | gl.bindTexture(gl.TEXTURE_2D, null); 302 | } 303 | 304 | // 305 | // drawScene 306 | 307 | 308 | function drawScene() { 309 | // Request the next frame of the animation 310 | normalSceneFrame = window.requestAnimationFrame(drawScene); 311 | 312 | // Clear the canvas before we start drawing on it. 313 | 314 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 315 | 316 | gl.viewport(0, 0, canvas.width, canvas.height); 317 | 318 | // Establish the perspective with which we want to view the 319 | // scene. Our field of view is 45 degrees, with a width/height 320 | // ratio of 640:480, and we only want to see objects between 0.1 units 321 | // and 100 units away from the camera. 322 | 323 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 324 | 325 | // Set the drawing position to the "identity" point, which is 326 | // the center of the scene. 327 | 328 | loadIdentity(); 329 | 330 | // Now move the drawing position a bit to where we want to start 331 | // drawing the cube. 332 | 333 | mvTranslate([-0.0, 0.0, -9.0]); 334 | 335 | // Save the current matrix, then rotate before we draw. 336 | 337 | mvPushMatrix(); 338 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 339 | 340 | // Draw the cube by binding the array buffer to the cube's vertices 341 | // array, setting attributes, and pushing it to GL. 342 | 343 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 344 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 345 | 346 | // Set the texture coordinates attribute for the vertices. 347 | 348 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 349 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 350 | 351 | // Specify the texture to map onto the faces. 352 | 353 | gl.activeTexture(gl.TEXTURE0); 354 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 355 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 356 | 357 | // Draw the cube. 358 | 359 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 360 | setMatrixUniforms(); 361 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 362 | 363 | // Restore the original matrix 364 | 365 | mvPopMatrix(); 366 | 367 | // Update the rotation for the next draw, if it's time to do so. 368 | 369 | var currentTime = (new Date).getTime(); 370 | if (lastCubeUpdateTime) { 371 | var delta = currentTime - lastCubeUpdateTime; 372 | 373 | cubeRotation += (30 * delta) / 1000.0; 374 | } 375 | 376 | lastCubeUpdateTime = currentTime; 377 | } 378 | 379 | 380 | // 381 | // WebVR: Draw the scene for the WebVR display. 382 | // 383 | function drawVRScene() { 384 | // WebVR: Request the next frame of the animation 385 | vrSceneFrame = vrDisplay.requestAnimationFrame(drawVRScene); 386 | 387 | // Populate frameData with the data of the next frame to display 388 | vrDisplay.getFrameData(frameData); 389 | 390 | // Get the position, orientation, etc. of the gamepads 391 | 392 | var gamepads = navigator.getGamepads(); 393 | var gp = gamepads[0]; 394 | 395 | if(gp) { 396 | var gpPose = gp.pose; 397 | var curPos = gpPose.position; 398 | var curOrient = gpPose.orientation; 399 | if(poseStatsDisplayed) { 400 | displayPoseStats(gpPose); 401 | } 402 | } 403 | 404 | // Clear the canvas before we start drawing on it. 405 | 406 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 407 | 408 | // WebVR: Create the required projection and view matrix locations needed 409 | // for passing into the uniformMatrix4fv methods below 410 | 411 | var projectionMatrixLocation = gl.getUniformLocation(shaderProgram, "projMatrix"); 412 | var viewMatrixLocation = gl.getUniformLocation(shaderProgram, "viewMatrix"); 413 | 414 | // WebVR: Render the left eye’s view to the left half of the canvas 415 | gl.viewport(0, 0, canvas.width * 0.5, canvas.height); 416 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.leftProjectionMatrix); 417 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.leftViewMatrix); 418 | drawGeometry(); 419 | 420 | // WebVR: Render the right eye’s view to the right half of the canvas 421 | gl.viewport(canvas.width * 0.5, 0, canvas.width * 0.5, canvas.height); 422 | gl.uniformMatrix4fv(projectionMatrixLocation, false, frameData.rightProjectionMatrix); 423 | gl.uniformMatrix4fv(viewMatrixLocation, false, frameData.rightViewMatrix); 424 | drawGeometry(); 425 | 426 | function drawGeometry() { 427 | // Establish the perspective with which we want to view the 428 | // scene. Our field of view is 45 degrees, with a width/height 429 | // ratio of 640:480, and we only want to see objects between 0.1 units 430 | // and 100 units away from the camera. 431 | 432 | perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 433 | 434 | // Set the drawing position to the "identity" point, which is 435 | // the center of the scene. 436 | 437 | loadIdentity(); 438 | 439 | // Now move the drawing position a bit to where we want to start 440 | // drawing the cube. 441 | 442 | if(gp && gpPose.hasPosition) { 443 | mvTranslate([ 444 | 0.0 + (curPos[0] * 15) - (curOrient[1] * 15), 445 | 0.0 + (curPos[1] * 15) + (curOrient[0] * 15), 446 | -15.0 + (curPos[2] * 25) 447 | ]); 448 | } else if(gp) { 449 | mvTranslate([ 450 | 0.0 + (curOrient[1] * 15), 451 | 0.0 + (curOrient[0] * 15), 452 | -15.0 453 | ]); 454 | } else { 455 | mvTranslate([ 456 | 0.0, 457 | 0.0, 458 | -15.0 459 | ]); 460 | } 461 | 462 | // Save the current matrix, then rotate before we draw. 463 | 464 | mvPushMatrix(); 465 | 466 | mvRotate(cubeRotation, [0.25, 0, 0.25]); 467 | 468 | // Draw the cube by binding the array buffer to the cube's vertices 469 | // array, setting attributes, and pushing it to GL. 470 | 471 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesBuffer); 472 | gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 473 | 474 | // Set the texture coordinates attribute for the vertices. 475 | 476 | gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); 477 | gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); 478 | 479 | // Specify the texture to map onto the faces. 480 | 481 | gl.activeTexture(gl.TEXTURE0); 482 | gl.bindTexture(gl.TEXTURE_2D, cubeTexture); 483 | gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0); 484 | 485 | // Draw the cube. 486 | 487 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); 488 | setMatrixUniforms(); 489 | gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); 490 | 491 | // Restore the original matrix 492 | 493 | mvPopMatrix(); 494 | } 495 | 496 | // Update the rotation for the next draw, if it's time to do so. 497 | 498 | var currentTime = (new Date).getTime(); 499 | if (lastCubeUpdateTime) { 500 | var delta = currentTime - lastCubeUpdateTime; 501 | 502 | cubeRotation += (30 * delta) / 1000.0; 503 | } 504 | 505 | lastCubeUpdateTime = currentTime; 506 | 507 | // WebVR: Indicate that we are ready to present the rendered frame to the VR display 508 | vrDisplay.submitFrame(); 509 | } 510 | 511 | // 512 | // initShaders 513 | // 514 | // Initialize the shaders, so WebGL knows how to light our scene. 515 | // 516 | function initShaders() { 517 | var fragmentShader = getShader(gl, "shader-fs"); 518 | var vertexShader = getShader(gl, "shader-vs"); 519 | 520 | // Create the shader program 521 | 522 | shaderProgram = gl.createProgram(); // Create our program, set it to be the value of shaderProgram 523 | gl.attachShader(shaderProgram, vertexShader); 524 | gl.attachShader(shaderProgram, fragmentShader); 525 | gl.linkProgram(shaderProgram); 526 | 527 | // If creating the shader program failed, alert 528 | 529 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 530 | alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shader)); 531 | } 532 | 533 | gl.useProgram(shaderProgram); // Specify the WebGL program we want to use for the rendering 534 | 535 | vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 536 | gl.enableVertexAttribArray(vertexPositionAttribute); 537 | 538 | textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 539 | gl.enableVertexAttribArray(textureCoordAttribute); 540 | } 541 | 542 | // 543 | // getShader 544 | // 545 | // Loads a shader program by scouring the current document, 546 | // looking for a script with the specified ID. 547 | // 548 | function getShader(gl, id) { 549 | var shaderScript = document.getElementById(id); 550 | 551 | // Didn't find an element with the specified ID; abort. 552 | 553 | if (!shaderScript) { 554 | return null; 555 | } 556 | 557 | // Walk through the source element's children, building the 558 | // shader source string. 559 | 560 | var theSource = ""; 561 | var currentChild = shaderScript.firstChild; 562 | 563 | while(currentChild) { 564 | if (currentChild.nodeType == 3) { 565 | theSource += currentChild.textContent; 566 | } 567 | 568 | currentChild = currentChild.nextSibling; 569 | } 570 | 571 | // Now figure out what type of shader script we have, 572 | // based on its MIME type. 573 | 574 | var shader; 575 | 576 | if (shaderScript.type == "x-shader/x-fragment") { 577 | shader = gl.createShader(gl.FRAGMENT_SHADER); 578 | } else if (shaderScript.type == "x-shader/x-vertex") { 579 | shader = gl.createShader(gl.VERTEX_SHADER); 580 | } else { 581 | return null; // Unknown shader type 582 | } 583 | 584 | // Send the source to the shader object 585 | 586 | gl.shaderSource(shader, theSource); 587 | 588 | // Compile the shader program 589 | 590 | gl.compileShader(shader); 591 | 592 | // See if it compiled successfully 593 | 594 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 595 | alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); 596 | return null; 597 | } 598 | 599 | return shader; 600 | } 601 | 602 | // 603 | // Matrix utility functions 604 | // 605 | 606 | function loadIdentity() { 607 | mvMatrix = Matrix.I(4); 608 | } 609 | 610 | function multMatrix(m) { 611 | mvMatrix = mvMatrix.x(m); 612 | } 613 | 614 | function mvTranslate(v) { 615 | multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4()); 616 | } 617 | 618 | function setMatrixUniforms() { 619 | var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 620 | gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten())); 621 | 622 | var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); 623 | gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten())); 624 | } 625 | 626 | var mvMatrixStack = []; 627 | 628 | function mvPushMatrix(m) { 629 | if (m) { 630 | mvMatrixStack.push(m.dup()); 631 | mvMatrix = m.dup(); 632 | } else { 633 | mvMatrixStack.push(mvMatrix.dup()); 634 | } 635 | } 636 | 637 | function mvPopMatrix() { 638 | if (!mvMatrixStack.length) { 639 | throw("Can't pop from an empty matrix stack."); 640 | } 641 | 642 | mvMatrix = mvMatrixStack.pop(); 643 | return mvMatrix; 644 | } 645 | 646 | function mvRotate(angle, v) { 647 | var inRadians = angle * Math.PI / 180.0; 648 | var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); 649 | multMatrix(m); 650 | } 651 | 652 | // WebVR: Sample event handler 653 | 654 | window.addEventListener('vrdisplaypresentchange', function(e) { 655 | console.log('Display ' + e.display.displayId + ' presentation has changed. Reason given: ' + e.reason + '.'); 656 | }); 657 | 658 | // WebVR: Controls readout of pose stats panel 659 | 660 | poseStatsBtn.addEventListener('click', function() { 661 | if(!poseStatsDisplayed) { 662 | poseStatsDisplayed = true; 663 | poseStatsSection.style.visibility = 'visible'; 664 | poseStatsBtn.textContent = 'Hide pose stats'; 665 | } else { 666 | poseStatsDisplayed = false; 667 | poseStatsSection.style.visibility = 'hidden'; 668 | poseStatsBtn.textContent = 'Show pose stats'; 669 | } 670 | }); 671 | 672 | function displayPoseStats(pose) { 673 | var pos = pose.position; 674 | var orient = pose.orientation; 675 | var linVel = pose.linearVelocity; 676 | var linAcc = pose.linearAcceleration; 677 | var angVel = pose.angularVelocity; 678 | var angAcc = pose.angularAcceleration; 679 | 680 | if(pose.hasPosition) { 681 | posStats.textContent = 'Position: x ' + pos[0].toFixed(3) + ', y ' + pos[1].toFixed(3) + ', z ' + pos[2].toFixed(3); 682 | } else { 683 | posStats.textContent = 'Position not reported'; 684 | } 685 | 686 | if(pose.hasOrientation) { 687 | orientStats.textContent = 'Orientation: x ' + orient[0].toFixed(3) + ', y ' + orient[1].toFixed(3) + ', z ' + orient[2].toFixed(3); 688 | } else { 689 | orientStats.textContent = 'Orientation not reported'; 690 | } 691 | 692 | linVelStats.textContent = 'Linear velocity: x ' + linVel[0].toFixed(3) + ', y ' + linVel[1].toFixed(3) + ', z ' + linVel[2].toFixed(3); 693 | angVelStats.textContent = 'Angular velocity: x ' + angVel[0].toFixed(3) + ', y ' + angVel[1].toFixed(3) + ', z ' + angVel[2].toFixed(3); 694 | 695 | if(linAcc) { 696 | linAccStats.textContent = 'Linear acceleration: x ' + linAcc[0].toFixed(3) + ', y ' + linAcc[1].toFixed(3) + ', z ' + linAcc[2].toFixed(3); 697 | } else { 698 | linAccStats.textContent = 'Linear acceleration not reported'; 699 | } 700 | 701 | if(angAcc) { 702 | angAccStats.textContent = 'Angular acceleration: x ' + angAcc[0].toFixed(3) + ', y ' + angAcc[1].toFixed(3) + ', z ' + angAcc[2].toFixed(3); 703 | } else { 704 | angAccStats.textContent = 'Angular acceleration not reported'; 705 | } 706 | } 707 | -------------------------------------------------------------------------------- /canvas-raycaster/RayCaster.js: -------------------------------------------------------------------------------- 1 | 2 | function RayCaster(canvas, w, h, z, level, player, inputBuffer) { 3 | 4 | this.QUAD_I = Math.PI * .5; 5 | this.QUAD_II = Math.PI; 6 | this.QUAD_III = Math.PI * 1.5; 7 | this.TO_RADS = Math.PI / 180; 8 | this.TO_DEGS = 180 / Math.PI; 9 | this.INFINITY = 10000; 10 | this.RES = { w:w, h:h, hh:h * .5 }; 11 | this.FOV = 60 * this.TO_RADS; 12 | this.SLIVER_ARC = this.FOV / this.RES.w; 13 | this.TABLE_ENTRIES = Math.ceil(Math.PI * 2 / this.SLIVER_ARC); 14 | 15 | this.TABLE_INV_SIN; 16 | this.TABLE_INV_COS; 17 | this.TABLE_TAN; 18 | this.TABLE_INV_TAN; 19 | this.QUAD_BOUNDARIES; 20 | this.TABLE_VIEW_CORRECTION; 21 | this.TABLE_REFLECTANCE_LATITUDE; 22 | this.TABLE_REFLECTANCE_LONGITUDE; 23 | this.TABLE_HEX = [ 24 | '00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f', 25 | '10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f', 26 | '20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f', 27 | '30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f', 28 | '40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f', 29 | '50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f', 30 | '60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f', 31 | '70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f', 32 | '80','81','82','83','84','85','86','87','88','89','8a','8b','8c','8d','8e','8f', 33 | '90','91','92','93','94','95','96','97','98','99','9a','9b','9c','9d','9e','9f', 34 | 'a0','a1','a2','a3','a4','a5','a6','a7','a8','a9','aa','ab','ac','ad','ae','af', 35 | 'b0','b1','b2','b3','b4','b5','b6','b7','b8','b9','ba','bb','bc','bd','be','bf', 36 | 'c0','c1','c2','c3','c4','c5','c6','c7','c8','c9','ca','cb','cc','cd','ce','cf', 37 | 'd0','d1','d2','d3','d4','d5','d6','d7','d8','d9','da','db','dc','dd','de','df', 38 | 'e0','e1','e2','e3','e4','e5','e6','e7','e8','e9','ea','eb','ec','ed','ee','ef', 39 | 'f0','f1','f2','f3','f4','f5','f6','f7','f8','f9','fa','fb','fc','fd','fe','ff']; 40 | this.PALETTE; 41 | this.CENTERLINE_SHIFT = 0; 42 | 43 | this.camera = { position: { _x:-1, _y:-1}, direction: 0 } 44 | this.idle = false; 45 | this.sliverWidth = z * 2; 46 | this.canvas = canvas; 47 | this.canvas.lineWidth = this.sliverWidth; 48 | this.level = level; //new Level(); 49 | this.player = player; //new Player(8); 50 | this.keysPressed = inputBuffer;//new Array(false, false, false, false); 51 | 52 | this.update = function() { 53 | if (!this.idle) { 54 | this.blank(this.RES.w, this.RES.h, this.RES.hh, this.level.colors.sky, this.level.colors.ground); 55 | this.cast(); 56 | } 57 | this.processInput(); 58 | } 59 | 60 | this.loadMap = function(m, x, y) { 61 | var parseOk = this.level.parseMap(m, x, y); 62 | if (parseOk) { 63 | this.buildPalette(); 64 | this.camera.position._x = this.level.spawnPoint._x; 65 | this.camera.position._y = this.level.spawnPoint._y; 66 | this.camera.direction = 0; 67 | trace("player spawned at [" +this.camera.position._x +" " +this.camera.position._y +"]"); 68 | } 69 | return parseOk; 70 | } 71 | 72 | this.cast = function() { 73 | var hit_latitude = { _x:0, _y:0, type:this.level.CELLTYPE_OPEN }; 74 | var hit_longitude = { _x:0, _y:0, type:this.level.CELLTYPE_OPEN }; 75 | var distance = { _x:0, _y:0 }; 76 | var step = { _x:0, _y:0 }; 77 | var mapScale = this.RES.h / this.level.dimension._y; 78 | var wallHeight = this.RES.h; 79 | 80 | var wallHalfHeight; 81 | var wallScale; 82 | var wallTop; 83 | var wallCenter; 84 | var wallBottom; 85 | 86 | var brightness; 87 | var rlu; 88 | var C; 89 | var sliverColor; 90 | 91 | // cast a ray for every sliver of our Field Of View (from -this.FOV/2 to this.FOV/2), 92 | // looking for both latitudinal (E-W) and longitudinal (N-S) intersections. 93 | // the closest intersection will determine how to render the sliver. 94 | var rayDirection = this.camera.direction - Math.round(this.RES.w * .5) + 1; 95 | if (rayDirection < 0) { rayDirection += this.TABLE_ENTRIES; } 96 | for (var currentSliver = 0; currentSliver < this.RES.w; currentSliver += this.sliverWidth) { 97 | rayDirection += this.sliverWidth; 98 | if (rayDirection >= this.TABLE_ENTRIES) { rayDirection = 0; } 99 | 100 | // look for intersections with latitudinal boundaries (running east-west) 101 | if (rayDirection >= this.QUAD_BOUNDARIES[0] && rayDirection < this.QUAD_BOUNDARIES[2]) { 102 | this.cast_north(hit_latitude, distance, step, rayDirection); 103 | } 104 | else { 105 | this.cast_south(hit_latitude, distance, step, rayDirection); 106 | } 107 | 108 | // look for intersections with longitudinal boundaries (running north-south) 109 | if (rayDirection >= this.QUAD_BOUNDARIES[1] && rayDirection < this.QUAD_BOUNDARIES[3]) { 110 | this.cast_west(hit_longitude, distance, step, rayDirection); 111 | } 112 | else { 113 | this.cast_east(hit_longitude, distance, step, rayDirection); 114 | } 115 | 116 | // compare distances and draw nearest intersection 117 | if (distance._x < distance._y) { 118 | // draw a latitudinal wall sliver (east-west wall) 119 | distance._x *= this.TABLE_VIEW_CORRECTION[currentSliver]; 120 | wallScale = this.level.CELL_SIZE / distance._x; 121 | rlu = rayDirection - this.camera.direction; 122 | if (rlu < 0) { rlu += this.TABLE_ENTRIES; } 123 | else if (rlu >= this.TABLE_ENTRIES) { rlu -= this.TABLE_ENTRIES; } 124 | brightness = 1 - Math.min(1, distance._x / this.level.viewExtent); 125 | brightness *= this.TABLE_REFLECTANCE_LATITUDE[rlu]; 126 | C = this.PALETTE[hit_latitude.type]; 127 | sliverColor = '#' + 128 | this.TABLE_HEX[ Math.round(C.r.delta * brightness + C.r.far) ] + 129 | this.TABLE_HEX[ Math.round(C.g.delta * brightness + C.g.far) ] + 130 | this.TABLE_HEX[ Math.round(C.b.delta * brightness + C.b.far) ]; 131 | } 132 | else { 133 | // draw a longitudinal wall sliver (north-south wall) 134 | distance._y *= this.TABLE_VIEW_CORRECTION[currentSliver]; 135 | wallScale = this.level.CELL_SIZE / distance._y; 136 | rlu = rayDirection - this.camera.direction; 137 | if (rlu < 0) { rlu += this.TABLE_ENTRIES; } 138 | else if (rlu >= this.TABLE_ENTRIES) { rlu -= this.TABLE_ENTRIES; } 139 | brightness = 1 - Math.min(1, distance._y / this.level.viewExtent); 140 | brightness *= this.TABLE_REFLECTANCE_LONGITUDE[rlu]; 141 | C = this.PALETTE[hit_longitude.type]; 142 | sliverColor = '#' + 143 | this.TABLE_HEX[ Math.round(C.r.delta * brightness + C.r.far) ] + 144 | this.TABLE_HEX[ Math.round(C.g.delta * brightness + C.g.far) ] + 145 | this.TABLE_HEX[ Math.round(C.b.delta * brightness + C.b.far) ]; 146 | } 147 | wallCenter = Math.round(this.RES.hh + this.CENTERLINE_SHIFT*wallScale); 148 | wallHalfHeight = (wallHeight * wallScale) >> 1; 149 | wallTop = Math.max(0, wallCenter - wallHalfHeight); 150 | wallBottom = Math.min(this.RES.h, wallCenter + wallHalfHeight); 151 | this.drawSliver(currentSliver, wallTop, wallBottom, sliverColor); 152 | } 153 | 154 | } 155 | 156 | this.cast_north = function(hit, distance, step, ray) { 157 | // casting northward (0 - 180 degrees), Y is increasing 158 | var cellBoundY = this.camera.position._y >> this.level.CELL_SIZE_SHIFT; 159 | hit._y = (cellBoundY+1) << this.level.CELL_SIZE_SHIFT; 160 | hit._x = this.camera.position._x + ((hit._y - this.camera.position._y) * this.TABLE_INV_TAN[ray]); 161 | step._x = this.level.CELL_SIZE * this.TABLE_INV_TAN[ray]; 162 | step._y = this.level.CELL_SIZE; 163 | 164 | var casting = true; 165 | while (casting) { 166 | // is current hit point out of bounds? 167 | if ( (hit._x < 0) || (hit._x >= this.level.dimension._x) ) { 168 | distance._x = this.INFINITY; 169 | casting = false; 170 | } 171 | else { 172 | // is there a wall at the cell boundary north of the hitpoint? 173 | // walltype = this.level.map[row][col]; 174 | hit.type = this.level.map[((hit._y + this.level.CELL_HALF) >> this.level.CELL_SIZE_SHIFT)][(hit._x >> this.level.CELL_SIZE_SHIFT)]; 175 | if (hit.type != this.level.CELLTYPE_OPEN) { 176 | distance._x = (hit._y - this.camera.position._y) * this.TABLE_INV_SIN[ray]; 177 | casting = false; 178 | } 179 | // if still in bounds but south of an empty cell, then cast further north 180 | else { 181 | hit._x += step._x; 182 | hit._y += step._y; 183 | } 184 | } 185 | } 186 | } 187 | 188 | this.cast_south = function(hit, distance, step, ray) { 189 | // casting southward (180 - 360 degrees), Y is decreasing 190 | var cellBoundY = this.camera.position._y >> this.level.CELL_SIZE_SHIFT; 191 | hit._y = cellBoundY << this.level.CELL_SIZE_SHIFT; 192 | hit._x = this.camera.position._x + ((hit._y - this.camera.position._y) * this.TABLE_INV_TAN[ray]); 193 | step._x = -this.level.CELL_SIZE * this.TABLE_INV_TAN[ray]; 194 | step._y = -this.level.CELL_SIZE; 195 | 196 | var casting = true; 197 | while (casting) { 198 | // is current hit point out of bounds? 199 | if ( (hit._x < 0) || (hit._x >= this.level.dimension._x) ) { 200 | distance._x = this.INFINITY; 201 | casting = false; 202 | } 203 | else { 204 | // is there a wall at the cell boundary south of the hitpoint? 205 | // walltype = this.level.map[row][col]; 206 | hit.type = this.level.map[((hit._y - this.level.CELL_HALF) >> this.level.CELL_SIZE_SHIFT)][(hit._x >> this.level.CELL_SIZE_SHIFT)]; 207 | if (hit.type != this.level.CELLTYPE_OPEN) { 208 | distance._x = (hit._y - this.camera.position._y) * this.TABLE_INV_SIN[ray]; 209 | casting = false; 210 | } 211 | // if still in bounds but north of an empty cell, then cast further south 212 | else { 213 | hit._x += step._x; 214 | hit._y += step._y; 215 | } 216 | } 217 | } 218 | } 219 | 220 | this.cast_west = function(hit, distance, step, ray) { 221 | // casting westward (90 - 270 degrees), X is decreasing 222 | var cellBoundX = this.camera.position._x >> this.level.CELL_SIZE_SHIFT; 223 | hit._x = cellBoundX << this.level.CELL_SIZE_SHIFT; 224 | hit._y = this.camera.position._y + ((hit._x - this.camera.position._x) * this.TABLE_TAN[ray]); 225 | step._x = -this.level.CELL_SIZE; 226 | step._y = -this.level.CELL_SIZE * this.TABLE_TAN[ray]; 227 | 228 | var casting = true; 229 | while (casting) { 230 | // is current hit point out of bounds? 231 | if ( (hit._y < 0) || (hit._y >= this.level.dimension._y) ) { 232 | distance._y = this.INFINITY; 233 | casting = false; 234 | } 235 | else { 236 | // is there a wall at the cell boundary west of the hitpoint? 237 | // walltype = this.level.map[row][col]; 238 | hit.type = this.level.map[(hit._y >> this.level.CELL_SIZE_SHIFT)][((hit._x - this.level.CELL_HALF) >> this.level.CELL_SIZE_SHIFT)]; 239 | if (hit.type != this.level.CELLTYPE_OPEN) { 240 | distance._y = (hit._x - this.camera.position._x) * this.TABLE_INV_COS[ray]; 241 | casting = false; 242 | } 243 | // if still in bounds but east of an empty cell, then cast further west 244 | else { 245 | hit._x += step._x; 246 | hit._y += step._y; 247 | } 248 | } 249 | } 250 | } 251 | 252 | this.cast_east = function(hit, distance, step, ray) { 253 | // casting eastward (0-90, 270-360 degrees), X is increasing 254 | var cellBoundX = this.camera.position._x >> this.level.CELL_SIZE_SHIFT; 255 | hit._x = (cellBoundX+1) << this.level.CELL_SIZE_SHIFT; 256 | hit._y = this.camera.position._y + ((hit._x - this.camera.position._x) * this.TABLE_TAN[ray]); 257 | step._x = this.level.CELL_SIZE; 258 | step._y = this.level.CELL_SIZE * this.TABLE_TAN[ray]; 259 | 260 | var casting = true; 261 | while (casting) { 262 | // is current hit point out of bounds? 263 | if ( (hit._y < 0) || (hit._y >= this.level.dimension._y) ) { 264 | distance._y = this.INFINITY; 265 | casting = false; 266 | } 267 | else { 268 | // is there a wall at the cell boundary east of the hitpoint? 269 | // walltype = this.level.map[row][col]; 270 | hit.type = this.level.map[hit._y >> this.level.CELL_SIZE_SHIFT][(hit._x + this.level.CELL_HALF) >> this.level.CELL_SIZE_SHIFT]; 271 | if (hit.type != this.level.CELLTYPE_OPEN) { 272 | distance._y = (hit._x - this.camera.position._x) * this.TABLE_INV_COS[ray]; 273 | casting = false; 274 | } 275 | // if still in bounds but west of an empty cell, then cast further east 276 | else { 277 | hit._x += step._x; 278 | hit._y += step._y; 279 | } 280 | } 281 | } 282 | } 283 | 284 | this.blank = function(w, h, hh, sky, ground) { 285 | // clear drawings from previous update (pen resets to [0, 0]), 286 | this.canvas.clearRect(0, 0, w, h); 287 | // draw fresh background of sky and ground 288 | this.canvas.fillStyle = sky; 289 | this.canvas.fillRect(0, 0, w, hh); 290 | this.canvas.fillStyle = ground; 291 | this.canvas.fillRect(0, hh, w, h); 292 | } 293 | 294 | this.drawSliver = function(x, t, b, c) { 295 | // draw a vertical 1-pixel wide sliver of wall 296 | var xc = x + this.sliverWidth * .5; 297 | this.canvas.beginPath(); 298 | this.canvas.strokeStyle = c; 299 | this.canvas.moveTo(xc, t); 300 | this.canvas.lineTo(xc, b); 301 | this.canvas.closePath(); 302 | this.canvas.stroke(); 303 | } 304 | 305 | this.processInput = function() { 306 | this.idle = true; 307 | 308 | if (this.keysPressed.left) { 309 | // rotate this.camera counter-clockwise 310 | this.idle = false; 311 | trace('turning left'); 312 | this.camera.direction -= this.player.speed.turn; 313 | if (this.camera.direction < 0) { this.camera.direction += this.TABLE_ENTRIES; } 314 | } 315 | if (this.keysPressed.right) { 316 | // rotate this.camera clockwise 317 | this.idle = false; 318 | trace('turning right'); 319 | this.camera.direction += this.player.speed.turn; 320 | if (this.camera.direction >= this.TABLE_ENTRIES) { this.camera.direction -= this.TABLE_ENTRIES; } 321 | } 322 | if (this.keysPressed.up) { 323 | // ensure next step will take this.camera into empty cell 324 | this.idle = false; 325 | trace('moving forward'); 326 | var newX = this.camera.position._x + this.player.speed.forward / this.TABLE_INV_COS[this.camera.direction]; 327 | var newY = this.camera.position._y + this.player.speed.forward / this.TABLE_INV_SIN[this.camera.direction]; 328 | var row = newY >> this.level.CELL_SIZE_SHIFT; 329 | var col = newX >> this.level.CELL_SIZE_SHIFT; 330 | if (this.level.map[row][col] == this.level.CELLTYPE_OPEN) { 331 | this.camera.position._x = newX; 332 | this.camera.position._y = newY; 333 | } 334 | } 335 | if (this.keysPressed.down) { 336 | // ensure next step will take this.camera into empty cell 337 | this.idle = false; 338 | trace('moving backward'); 339 | var newX = this.camera.position._x - this.player.speed.backward / this.TABLE_INV_COS[this.camera.direction]; 340 | var newY = this.camera.position._y - this.player.speed.backward / this.TABLE_INV_SIN[this.camera.direction]; 341 | var row = newY >> this.level.CELL_SIZE_SHIFT; 342 | var col = newX >> this.level.CELL_SIZE_SHIFT; 343 | if (this.level.map[row][col] == this.level.CELLTYPE_OPEN) { 344 | this.camera.position._x = newX; 345 | this.camera.position._y = newY; 346 | } 347 | } 348 | } 349 | 350 | this.buildPalette = function() { 351 | // for each walltype color pair, 352 | // extract the r,g,b components for shading use later 353 | // 354 | // 24-bit color: 355 | // rrrrrrrrggggggggbbbbbbbb 356 | // 24 16 8 0 357 | // 358 | // extraction: 359 | // r = c >> 16 : shift out the green and blue 360 | // g = (c & 0x00FF00) >> 8 : mask out the red, shift out the blue 361 | // b = c & 0x0000FF : mask out the red and green 362 | // combination: 363 | // c = (r << 16) + (g << 8) + b : shift the components into place and combine 364 | 365 | this.PALETTE = new Array(); 366 | // the palette will be used to interp from dark to light (far to near), 367 | // so delta is set in this direction 368 | for (var i = 0; i < this.level.walltypes.length; i++) { 369 | // grab wallcolor near and wallcolor far 370 | var wcn = this.level.colors.wallsNear[i]; 371 | var wcf = this.level.colors.wallsFar[i]; 372 | 373 | // extract rgb components for near and far 374 | var rn = (wcn & 0xff0000) >> 16; 375 | var rf = (wcf & 0xff0000) >> 16; 376 | //var rn = wcn >> 16; 377 | //var rf = wcf >> 16; 378 | var gn = (wcn & 0x00ff00) >> 8; 379 | var gf = (wcf & 0x00ff00) >> 8; 380 | var bn = wcn & 0x0000ff; 381 | var bf = wcf & 0x0000ff; 382 | 383 | // assemble object and store in lookup table for use later 384 | var C = { 385 | r : { near:rn, far:rf, delta:rn-rf}, 386 | g : { near:gn, far:gf, delta:gn-gf}, 387 | b : { near:bn, far:bf, delta:bn-bf} 388 | }; 389 | this.PALETTE[i] = C; 390 | } 391 | } 392 | 393 | this.buildTables = function() { 394 | // precompute values for expensive math ops 395 | // we already know the field of view and horizontal screen res, 396 | // and thus the degrees of view spanned by a single sliver of res, 397 | // so we compute the trig values for enough slivers to cover 360 deg. 398 | 399 | // initialize the tables 400 | this.TABLE_INV_SIN = new Array(); 401 | this.TABLE_INV_COS = new Array(); 402 | this.TABLE_TAN = new Array(); 403 | this.TABLE_INV_TAN = new Array(); 404 | this.QUAD_BOUNDARIES = new Array(); 405 | this.TABLE_REFLECTANCE_LATITUDE = new Array(); 406 | this.TABLE_REFLECTANCE_LONGITUDE = new Array(); 407 | 408 | // define some unit circle constants 409 | var PI_1over2 = Math.PI * 1 / 2; // 90 degrees 410 | var PI_1over1 = Math.PI * 1; // 180 degrees 411 | var PI_3over2 = Math.PI * 3 / 2; // 270 degrees 412 | var PI_2over1 = Math.PI * 2; // 360 degrees 413 | 414 | // walk around the unit circle, jotting down trig values along the way. 415 | // we need to look out for horizontal and vertical asymptotes, where tangent 416 | // goes to infinity, and substitute a grossly underestimated value that 417 | // won't break our calculations. 418 | // also, when we cross an asymptote, we'll record the index i 419 | // QUAD_ 420 | var quadrant = 0; 421 | var angle = 0; 422 | for (var i = 0; i < this.TABLE_ENTRIES; i++) { 423 | var cosine = Math.cos(angle); 424 | var sine = Math.sin(angle); 425 | var absCosine = Math.abs(cosine); 426 | var absSine = Math.abs(sine); 427 | 428 | if (absCosine == 0 || absSine == 1) { 429 | // 90 or 270 degrees 430 | this.TABLE_TAN[i] = -this.INFINITY; 431 | this.TABLE_INV_TAN[i] = 0; 432 | if (quadrant == 1) { this.TABLE_INV_COS[i] = -this.INFINITY; } 433 | else { this.TABLE_INV_COS[i] = this.INFINITY; } 434 | this.TABLE_INV_SIN[i] = 1 / sine; 435 | this.QUAD_BOUNDARIES[quadrant] = i; 436 | quadrant++; 437 | } 438 | else if (absCosine == 1 || absSine == 0) { 439 | // 0 or 180 degrees 440 | this.TABLE_TAN[i] = 0; 441 | this.TABLE_INV_TAN[i] = this.INFINITY; 442 | if (quadrant == 0) { this.TABLE_INV_SIN[i] = this.INFINITY; } 443 | else { this.TABLE_INV_SIN[i] = -this.INFINITY; } 444 | this.TABLE_INV_COS[i] = 1 / cosine; 445 | this.QUAD_BOUNDARIES[quadrant] = i; 446 | quadrant++; 447 | } 448 | else { 449 | // no asymptotes to worry about 450 | this.TABLE_TAN[i] = sine / cosine; 451 | this.TABLE_INV_TAN[i] = cosine / sine; 452 | this.TABLE_INV_COS[i] = 1 / cosine; 453 | this.TABLE_INV_SIN[i] = 1 / sine; 454 | } 455 | 456 | // for specular lighting, 457 | // precalculate the cosine of the angle between 458 | // every ray and the surface normal of: 459 | // 1) a latitudinal (horizontal) surface 460 | // 2) a longitudinal (vertical) surface 461 | // the calculation requires that the angle be [0,PI/2] 462 | var h = 0; 463 | var v = 0; 464 | switch (quadrant-1) { 465 | case 0: 466 | h = PI_1over2 - angle; 467 | v = angle; 468 | break; 469 | 470 | case 1: 471 | h = angle - PI_1over2; 472 | v = PI_1over1 - angle; 473 | break; 474 | 475 | case 2: 476 | h = PI_3over2 - angle; 477 | v = angle - PI_1over1; 478 | break; 479 | 480 | case 3: 481 | h = angle - PI_3over2; 482 | v = PI_2over1 - angle; 483 | break; 484 | } 485 | this.TABLE_REFLECTANCE_LATITUDE[i] = Math.sin( Math.min(PI_1over2, Math.max(0, h)) ); 486 | this.TABLE_REFLECTANCE_LONGITUDE[i] = Math.cos( Math.min(PI_1over2, Math.max(0, v)) ); 487 | 488 | angle += this.SLIVER_ARC; 489 | } 490 | 491 | // pre-compute view correction values for each sliver 492 | this.TABLE_VIEW_CORRECTION = new Array(); 493 | var FOVangle = this.SLIVER_ARC * (-Math.round(this.FOV*.5)); 494 | for (var sliver = 0; sliver < this.RES.w; sliver++) { 495 | this.TABLE_VIEW_CORRECTION[sliver] = Math.cos(FOVangle); // minimal fish-eye 496 | //this.TABLE_VIEW_CORRECTION[sliver] = 1 / Math.cos(FOVangle); // extra fish-eye! cool. 497 | FOVangle += this.SLIVER_ARC; 498 | } 499 | } 500 | 501 | this.buildTables(); 502 | 503 | } --------------------------------------------------------------------------------