├── .gitignore
├── CHANGELOG.md
├── DEVELOPMENT.md
├── LICENSE
├── README.md
├── assets
├── icon_128.png
└── three-devtools-architecture.svg
├── examples
├── attributions.md
├── dynamic.html
├── large-data.html
├── materials.html
├── modules
│ ├── EquirectangularToCubeGenerator.js
│ ├── RGBELoader.js
│ └── TextureUtils.js
├── objects.html
├── scenes.html
└── textures
│ ├── marble
│ ├── marble_01_AO_1k.jpg
│ ├── marble_01_diff_1k.jpg
│ ├── marble_01_disp_1k.jpg
│ ├── marble_01_nor_1k.jpg
│ ├── marble_01_rough_1k.jpg
│ └── marble_01_spec_1k.jpg
│ └── studio_small_03_1k.hdr
├── manifest.json
├── package-lock.json
├── package.json
├── scripts
├── build-deps.sh
├── build-dist.sh
├── build-source.sh
├── genlicenses.sh
└── version.js
├── src
├── app
│ ├── ContentBridge.js
│ ├── assets
│ │ ├── chromeSelect.png
│ │ ├── chromeSelect_2x.png
│ │ ├── largeIcons.png
│ │ ├── largeIcons_2x.png
│ │ ├── mediumIcons.png
│ │ ├── mediumIcons_2x.png
│ │ ├── smallIcons.png
│ │ └── smallIcons_2x.png
│ ├── common-elements
│ │ ├── AccordionViewElement.js
│ │ ├── DevtoolsButtonElement.js
│ │ ├── DevtoolsIconButtonElement.js
│ │ ├── DevtoolsIconElement.js
│ │ ├── DevtoolsMessageElement.js
│ │ ├── IconElement.js
│ │ ├── NumberInputElement.js
│ │ └── TreeItemElement.js
│ ├── constants.js
│ ├── data
│ │ ├── geometry.js
│ │ ├── lights.js
│ │ ├── material-blending.js
│ │ ├── material-common.js
│ │ ├── material-line.js
│ │ ├── material-pbr.js
│ │ ├── material-polygon-offset.js
│ │ ├── material-shared.js
│ │ ├── materials.js
│ │ ├── object-renderable.js
│ │ ├── object-transform.js
│ │ ├── objects.js
│ │ ├── renderers.js
│ │ └── textures.js
│ ├── elements
│ │ ├── AppElement.js
│ │ ├── ImagePreviewElement.js
│ │ ├── ParametersViewElement.js
│ │ ├── RendererViewElement.js
│ │ ├── ResourcesViewElement.js
│ │ ├── SceneViewElement.js
│ │ ├── TabBarElement.js
│ │ ├── TitleBarElement.js
│ │ ├── shared-styles
│ │ │ └── chrome-select.js
│ │ └── values
│ │ │ ├── EnumValueElement.js
│ │ │ ├── KeyValueElement.js
│ │ │ ├── MaterialValueElement.js
│ │ │ └── TextureValueElement.js
│ ├── fonts
│ │ ├── fa-regular-400.eot
│ │ ├── fa-regular-400.svg
│ │ ├── fa-regular-400.ttf
│ │ ├── fa-regular-400.woff
│ │ ├── fa-regular-400.woff2
│ │ ├── fa-solid-900.eot
│ │ ├── fa-solid-900.svg
│ │ ├── fa-solid-900.ttf
│ │ ├── fa-solid-900.woff
│ │ └── fa-solid-900.woff2
│ ├── index.html
│ ├── index.js
│ ├── injection.js
│ ├── styles
│ │ ├── app.css
│ │ ├── devtools.css
│ │ ├── fontawesome.css
│ │ └── inspectorCommon.css
│ └── utils.js
├── content
│ ├── DevToolsScene.js
│ ├── EntityCache.js
│ ├── ThreeDevTools.js
│ ├── TransformControls.js
│ ├── three.js
│ ├── toJSON.js
│ └── utils.js
└── extension
│ ├── background.html
│ ├── background.js
│ ├── contentScript.js
│ ├── devtools.html
│ └── devtools.js
└── web_modules
├── @egjs
└── agent.js
├── common
├── lit-html-513f48c9.js
└── lit-html-d6553ed1.js
├── import-map.json
├── licenses
├── agent_LICENSE
├── lit-element_LICENSE
├── lit-html_LICENSE
└── three_LICENSE
├── lit-element.js
├── lit-html
└── directives
│ └── if-defined.js
├── three.js
├── three
├── examples
│ └── jsm
│ │ ├── geometries
│ │ └── TeapotBufferGeometry.js
│ │ ├── loaders
│ │ └── GLTFLoader.js
│ │ └── pmrem
│ │ ├── PMREMCubeUVPacker.js
│ │ └── PMREMGenerator.js
└── src
│ └── constants.js
└── webextension-polyfill
└── dist
└── browser-polyfill.js
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | **/*.sw*
4 | .DS_Store
5 | .idea
6 | *.iml
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.4.0 (2020/7/27)
2 |
3 | ### New
4 |
5 | * Added inspector view in the rendering panel to debug WebGLRenderers.
6 |
7 | ### Changes
8 |
9 | * Improve styling for the rendering panel.
10 | * Add parameters for lights.
11 | * Fixed int and radian parameters in the parameters view.
12 | * Parameters view will now display readonly parameters.
13 | * Added and updated parameters for many material types.
14 | * Added tooltips to properties in parameters view.
15 | * InstancedBufferGeometry now correctly identified as Geometry.
16 | * SkinnedMesh and InstancedMesh now correctly identified as Mesh.
17 | * Inspecting a CompressedTexture should no longer throw an error.
18 |
19 | ## 0.3.1
20 |
21 | * Fix the setting of boolean properties from an entity's parameter view.
22 |
23 | ## 0.3.0
24 |
25 | * Add several views to filter entities: Scene graph, geometry, materials, textures, and renderer.
26 | * Improved heuristics on displaying all available entities in overviews, rather than needing to refresh often.
27 | * Significant improvement to scenes with large assets/data (textures, geometry).
28 | * Entity dependencies are now shown as links in the parameter view -- select a Mesh's material, or geometry, for example.
29 | * Add ability to modify vectors in the parameters view, like position and scale.
30 |
31 | ## 0.2.1
32 |
33 | * Rejoice! Extensions now support [major.minor.patch] format in versions.
34 | * Display three.js revision found in content to console
35 | * Display correct extension version in console
36 |
37 | ## 0.2
38 |
39 | * Refresh button to get latest changes of a scene
40 | * Fixed issues in debugging scenes with unserializable objects (InterleavedBufferAttribute, WebGLRenderTarget, DataTexture, ParametricGeometry)
41 | * Style improvements (@jacobcoughenour)
42 | * Dark theme support (@jacobcoughenour)
43 |
44 | ## 0.1
45 |
46 | Initial Release
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Jordan Santell
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # three-devtools
2 |
3 | **three-devtools** is a web extension that allows inspection of three.js content.
4 |
5 | > ## 🚨 Status: Experimental
6 | > **three-devtools** is very much in an alpha/experimentation stage. Use at your own risk. Follow the [Baseline Milestone](https://github.com/jsantell/three-devtools/milestone/1) for issues and considerations that need to be solved in order for some stability.
7 |
8 | ## Installing
9 |
10 | The alpha version of the developer tools can be installed as a web extension on [Firefox Add-ons/AMO](https://addons.mozilla.org/en-US/firefox/addon/three-js-developer-tools/) and for Chrome via [Chrome Web Store](https://chrome.google.com/webstore/detail/threejs-developer-tools/ebpnegggocnnhleeicgljbedjkganaek). See [DEVELOPMENT.md](DEVELOPMENT.md) for local installation.
11 |
12 | ## Current API
13 |
14 | This API has not been thought out at all, but this will register your
15 | THREE.Scene and THREE.Renderer to be observed by the tools.
16 |
17 | ```js
18 | // Observe a scene or a renderer
19 | if (typeof __THREE_DEVTOOLS__ !== 'undefined') {
20 | __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: scene }));
21 | __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: renderer }));
22 | }
23 | ```
24 |
25 | ## Development
26 |
27 | Architecture & development notes can be found in [DEVELOPMENT.md](DEVELOPMENT.md).
28 |
--------------------------------------------------------------------------------
/assets/icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/assets/icon_128.png
--------------------------------------------------------------------------------
/examples/attributions.md:
--------------------------------------------------------------------------------
1 | textures/studio_small_03_1k.hdr
2 | https://hdrihaven.com/hdri/download.php?h=studio_small_03
3 |
4 | textures/marble/*
5 | https://texturehaven.com/tex/?t=marble_01
6 |
--------------------------------------------------------------------------------
/examples/dynamic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/examples/large-data.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/materials.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/examples/modules/EquirectangularToCubeGenerator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Richard M. / https://github.com/richardmonette
3 | * @author WestLangley / http://github.com/WestLangley
4 | */
5 | import * as THREE from '../../web_modules/three.js';
6 |
7 | const CubemapGenerator = function ( renderer ) {
8 |
9 | this.renderer = renderer;
10 |
11 | };
12 |
13 | CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) {
14 |
15 | options = options || {};
16 |
17 | var scene = new THREE.Scene();
18 |
19 | var shader = {
20 |
21 | uniforms: {
22 | tEquirect: { value: null },
23 | },
24 |
25 | vertexShader:
26 |
27 | `
28 | varying vec3 vWorldDirection;
29 |
30 | //include
31 | vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
32 |
33 | return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
34 |
35 | }
36 |
37 | void main() {
38 |
39 | vWorldDirection = transformDirection( position, modelMatrix );
40 |
41 | #include
42 | #include
43 |
44 | }
45 | `,
46 |
47 | fragmentShader:
48 |
49 | `
50 | uniform sampler2D tEquirect;
51 |
52 | varying vec3 vWorldDirection;
53 |
54 | //include
55 | #define RECIPROCAL_PI 0.31830988618
56 | #define RECIPROCAL_PI2 0.15915494
57 |
58 | void main() {
59 |
60 | vec3 direction = normalize( vWorldDirection );
61 |
62 | vec2 sampleUV;
63 |
64 | sampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;
65 |
66 | sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;
67 |
68 | gl_FragColor = texture2D( tEquirect, sampleUV );
69 |
70 | }
71 | `
72 | };
73 |
74 | var material = new THREE.ShaderMaterial( {
75 |
76 | type: 'CubemapFromEquirect',
77 |
78 | uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
79 | vertexShader: shader.vertexShader,
80 | fragmentShader: shader.fragmentShader,
81 | side: THREE.BackSide,
82 | blending: THREE.NoBlending
83 |
84 | } );
85 |
86 | material.uniforms.tEquirect.value = texture;
87 |
88 | var mesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 5, 5, 5 ), material );
89 |
90 | scene.add( mesh );
91 |
92 | var resolution = options.resolution || 512;
93 |
94 | var params = {
95 | type: texture.type,
96 | format: texture.format,
97 | encoding: texture.encoding,
98 | generateMipmaps: ( options.generateMipmaps !== undefined ) ? options.generateMipmaps : texture.generateMipmaps,
99 | minFilter: ( options.minFilter !== undefined ) ? options.minFilter : texture.minFilter,
100 | magFilter: ( options.magFilter !== undefined ) ? options.magFilter : texture.magFilter
101 | };
102 |
103 | var camera = new THREE.CubeCamera( 1, 10, resolution, params );
104 |
105 | camera.update( this.renderer, scene );
106 |
107 | mesh.geometry.dispose();
108 | mesh.material.dispose();
109 |
110 | return camera.renderTarget;
111 |
112 | };
113 |
114 | //
115 |
116 | export default ( function () {
117 |
118 | var camera = new THREE.PerspectiveCamera( 90, 1, 0.1, 10 );
119 | var scene = new THREE.Scene();
120 | var boxMesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 1, 1, 1 ), getShader() );
121 | boxMesh.material.side = THREE.BackSide;
122 | scene.add( boxMesh );
123 |
124 | var EquirectangularToCubeGenerator = function ( sourceTexture, options ) {
125 |
126 | options = options || {};
127 |
128 | this.sourceTexture = sourceTexture;
129 | this.resolution = options.resolution || 512;
130 |
131 | this.views = [
132 | { t: [ 1, 0, 0 ], u: [ 0, - 1, 0 ] },
133 | { t: [ - 1, 0, 0 ], u: [ 0, - 1, 0 ] },
134 | { t: [ 0, 1, 0 ], u: [ 0, 0, 1 ] },
135 | { t: [ 0, - 1, 0 ], u: [ 0, 0, - 1 ] },
136 | { t: [ 0, 0, 1 ], u: [ 0, - 1, 0 ] },
137 | { t: [ 0, 0, - 1 ], u: [ 0, - 1, 0 ] },
138 | ];
139 |
140 | var params = {
141 | format: options.format || this.sourceTexture.format,
142 | magFilter: this.sourceTexture.magFilter,
143 | minFilter: this.sourceTexture.minFilter,
144 | type: options.type || this.sourceTexture.type,
145 | generateMipmaps: this.sourceTexture.generateMipmaps,
146 | anisotropy: this.sourceTexture.anisotropy,
147 | encoding: this.sourceTexture.encoding
148 | };
149 |
150 | this.renderTarget = new THREE.WebGLRenderTargetCube( this.resolution, this.resolution, params );
151 |
152 | };
153 |
154 | EquirectangularToCubeGenerator.prototype = {
155 |
156 | constructor: EquirectangularToCubeGenerator,
157 |
158 | update: function ( renderer ) {
159 |
160 | var currentRenderTarget = renderer.getRenderTarget();
161 |
162 | boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture;
163 |
164 | for ( var i = 0; i < 6; i ++ ) {
165 |
166 | var v = this.views[ i ];
167 |
168 | camera.position.set( 0, 0, 0 );
169 | camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] );
170 | camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] );
171 |
172 | renderer.setRenderTarget( this.renderTarget, i );
173 | renderer.clear();
174 | renderer.render( scene, camera );
175 |
176 | }
177 |
178 | renderer.setRenderTarget( currentRenderTarget );
179 |
180 | return this.renderTarget.texture;
181 |
182 | },
183 |
184 | dispose: function () {
185 |
186 | this.renderTarget.dispose();
187 |
188 | }
189 |
190 | };
191 |
192 | function getShader() {
193 |
194 | var shaderMaterial = new THREE.ShaderMaterial( {
195 |
196 | uniforms: {
197 | "equirectangularMap": { value: null },
198 | },
199 |
200 | vertexShader:
201 | "varying vec3 localPosition;\n\
202 | \n\
203 | void main() {\n\
204 | localPosition = position;\n\
205 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
206 | }",
207 |
208 | fragmentShader:
209 | "#include \n\
210 | varying vec3 localPosition;\n\
211 | uniform sampler2D equirectangularMap;\n\
212 | \n\
213 | vec2 EquirectangularSampleUV(vec3 v) {\n\
214 | vec2 uv = vec2(atan(v.z, v.x), asin(v.y));\n\
215 | uv *= vec2(0.1591, 0.3183); // inverse atan\n\
216 | uv += 0.5;\n\
217 | return uv;\n\
218 | }\n\
219 | \n\
220 | void main() {\n\
221 | vec2 uv = EquirectangularSampleUV(normalize(localPosition));\n\
222 | gl_FragColor = texture2D(equirectangularMap, uv);\n\
223 | }",
224 |
225 | blending: THREE.NoBlending
226 |
227 | } );
228 |
229 | shaderMaterial.type = 'EquirectangularToCubeGenerator';
230 |
231 | return shaderMaterial;
232 |
233 | }
234 |
235 | return EquirectangularToCubeGenerator;
236 |
237 | } )();
238 |
--------------------------------------------------------------------------------
/examples/modules/TextureUtils.js:
--------------------------------------------------------------------------------
1 | import {Cache, CubeTexture, EventDispatcher, GammaEncoding, NearestFilter, RGBEEncoding, TextureLoader} from '../../web_modules/three.js';
2 |
3 | import EquirectangularToCubeGenerator from './EquirectangularToCubeGenerator.js';
4 | import { PMREMCubeUVPacker } from '../../web_modules/three/examples/jsm/pmrem/PMREMCubeUVPacker.js';
5 | import { PMREMGenerator } from '../../web_modules/three/examples/jsm/pmrem/PMREMGenerator.js';
6 | import RGBELoader from './RGBELoader.js';
7 |
8 | const loader = new RGBELoader();
9 |
10 | export default (async (renderer, url) => {
11 | const texture = await new Promise(resolve => loader.load(url, resolve));
12 | texture.encoding = RGBEEncoding;
13 | texture.minFilter = NearestFilter;
14 | texture.magFilter = NearestFilter;
15 | texture.flipY = true;
16 |
17 | const cubemapGenerator = new EquirectangularToCubeGenerator(texture, {
18 | resolution: 1024,
19 | });
20 | const cubemapTexture = cubemapGenerator.update(renderer);
21 | const pmremGenerator = new PMREMGenerator(cubemapTexture);
22 | pmremGenerator.update(renderer);
23 | const pmremPacker = new PMREMCubeUVPacker(pmremGenerator.cubeLods);
24 | pmremPacker.update(renderer);
25 |
26 | texture.dispose();
27 | pmremGenerator.dispose();
28 | pmremPacker.dispose();
29 |
30 | return pmremPacker.CubeUVRenderTarget.texture;
31 | });
32 |
--------------------------------------------------------------------------------
/examples/objects.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/examples/scenes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_AO_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_AO_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_diff_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_diff_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_disp_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_disp_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_nor_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_nor_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_rough_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_rough_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/marble/marble_01_spec_1k.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/marble/marble_01_spec_1k.jpg
--------------------------------------------------------------------------------
/examples/textures/studio_small_03_1k.hdr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/examples/textures/studio_small_03_1k.hdr
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Three.js Developer Tools",
3 | "version": "0.4.0",
4 | "description": "Developer tools for 3D library three.js.",
5 | "devtools_page": "src/extension/devtools.html",
6 | "background": {
7 | "page": "src/extension/background.html"
8 | },
9 | "icons": {
10 | "128": "assets/icon_128.png"
11 | },
12 | "content_scripts": [
13 | {
14 | "matches": [
15 | "http://*/*",
16 | "https://*/*"
17 | ],
18 | "js": [
19 | "src/extension/contentScript.js"
20 | ],
21 | "run_at": "document_start"
22 | }
23 | ],
24 | "permissions": [
25 | "storage",
26 | "webNavigation",
27 | "http://*/*",
28 | "https://*/*"
29 | ],
30 | "web_accessible_resources": [
31 | "src/content/*.js"
32 | ],
33 | "manifest_version": 2,
34 | "author": "Jordan Santell",
35 | "browser_specific_settings": {
36 | "gecko": {
37 | "id": "three-devtools@jsantell.com"
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three-devtools",
3 | "private": true,
4 | "version": "0.4.0",
5 | "description": "three.js developer tools web extension",
6 | "scripts": {
7 | "build:source": "./scripts/build-source.sh",
8 | "build:deps": "./scripts/build-deps.sh",
9 | "build:dist": "./scripts/build-dist.sh",
10 | "build:dist:chrome": "./scripts/build-dist.sh chrome",
11 | "serve": "http-server . -c-1",
12 | "version": "node ./scripts/version.js && git add *.json",
13 | "postversion": "git push && git push --tags"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/jsantell/three-devtools.git"
18 | },
19 | "author": "Jordan Santell ",
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/jsantell/three-devtools/issues"
23 | },
24 | "homepage": "https://github.com/jsantell/three-devtools#readme",
25 | "dependencies": {
26 | "@egjs/agent": "2.1.5",
27 | "lit-element": "2.2.1",
28 | "lit-html": "1.1.2",
29 | "three": "0.137.0",
30 | "webextension-polyfill": "0.4.0"
31 | },
32 | "devDependencies": {
33 | "http-server": "^14.1.1",
34 | "json": "10.0.0"
35 | },
36 | "@pika/web": {
37 | "webDependencies": [
38 | "webextension-polyfill/dist/browser-polyfill.js",
39 | "lit-element",
40 | "lit-html/directives/if-defined.js",
41 | "@egjs/agent",
42 | "three",
43 | "three/src/constants.js",
44 | "three/examples/jsm/loaders/GLTFLoader.js",
45 | "three/examples/jsm/geometries/TeapotBufferGeometry.js"
46 | ]
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/scripts/build-deps.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | npm install
4 | npx @pika/web --dest web_modules/
5 | ./scripts/genlicenses.sh
6 |
7 | # Copy over the non-module form of three.js for injection
8 | # in the content. This beautiful hack fakes a CommonJS
9 | # environment so that:
10 | # 1) No global scope pollution or clobbering content's version of three.js
11 | # 2) Can be stringified and lazily injected along with the other content
12 | # side objects (src/content/). Need access to the full context in order
13 | # for Function.prototype.toString to work.
14 | # 3) Content-side devtools code can use its own private instance of three.js
15 | # to do things like injecting a bounding box visual.
16 | echo 'export default () => {' > src/content/three.js
17 | echo ' var exports = {};' >> src/content/three.js
18 | echo ' var module = { exports };' >> src/content/three.js
19 | cat node_modules/three/build/three.min.js >> src/content/three.js
20 | echo ' return exports;' >> src/content/three.js
21 | echo '};' >> src/content/three.js
22 |
23 | # Replace all instances of __THREE_DEVTOOLS__ in
24 | # the internal three.js so we're not recursively
25 | # complicating things, for example, we get a 'registration'
26 | # event from the internal version and can't determine
27 | # whether its the internal version, or a content version
28 | # that should be debugged.
29 | sed -i -e 's/__THREE_DEVTOOLS__/__INTERNAL_THREE_DEVTOOLS__/g' src/content/three.js
30 |
31 | # Copy over the non-modified version of TransformControls
32 | echo 'export default (THREE) => {' > src/content/TransformControls.js
33 | cat node_modules/three/examples/js/controls/TransformControls.js >> src/content/TransformControls.js
34 | echo '};' >> src/content/TransformControls.js
35 |
--------------------------------------------------------------------------------
/scripts/build-dist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | rm -rf three-devtools
4 | mkdir three-devtools
5 |
6 | cp -r src three-devtools
7 | cp -r web_modules three-devtools
8 | cp -r assets three-devtools
9 | cp package.json three-devtools
10 | cp manifest.json three-devtools
11 | cp README.md three-devtools
12 | cp LICENSE three-devtools
13 |
14 | if [ ! -z "$1" ] && [ $1 == 'chrome' ] ;
15 | then
16 | echo "Building Chrome variation."
17 | cat manifest.json | \
18 | json -e 'delete this.browser_specific_settings' > \
19 | three-devtools/manifest.json
20 | fi
21 |
22 | npx web-ext build \
23 | --source-dir three-devtools \
24 | --artifacts-dir dist \
25 | --overwrite-dest
26 |
27 | rm -r three-devtools
28 |
--------------------------------------------------------------------------------
/scripts/build-source.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Zips up the necessary files and docs, sans dependencies from
4 | # npm, to build the add-on, necessary for AMO's reviewal of code
5 | # since @pika/web transforms the source code.
6 |
7 | zip -r dist/three-devtools-source.zip \
8 | assets examples src scripts web_modules \
9 | manifest.json package.json package-lock.json \
10 | LICENSE DEVELOPMENT.md README.md
11 |
--------------------------------------------------------------------------------
/scripts/genlicenses.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | mkdir -p web_modules/licenses
4 | cp node_modules/@egjs/agent/LICENSE web_modules/licenses/agent_LICENSE
5 | cp node_modules/three/LICENSE web_modules/licenses/three_LICENSE
6 | cp node_modules/lit-html/LICENSE web_modules/licenses/lit-html_LICENSE
7 | cp node_modules/lit-element/LICENSE web_modules/licenses/lit-element_LICENSE
8 |
--------------------------------------------------------------------------------
/scripts/version.js:
--------------------------------------------------------------------------------
1 | #!/bin/node
2 |
3 | // Called after the version as been incremented
4 | // via `npm version [major | minor | patch]`
5 | // https://docs.npmjs.com/cli/version
6 | const fs = require('fs');
7 | const path = require('path');
8 | const packageJSON = require('../package.json');
9 | const version = packageJSON.version;
10 | const manifestJSON = require('../manifest.json');
11 |
12 | manifestJSON.version = version;
13 |
14 | const manifestJSONPath = path.join(__dirname, '..', 'manifest.json');
15 | const manifestString = JSON.stringify(manifestJSON, null, 2);
16 | console.log(`Updating manifest.json with version ${version}`);
17 | fs.writeFileSync(manifestJSONPath, manifestString);
18 |
--------------------------------------------------------------------------------
/src/app/ContentBridge.js:
--------------------------------------------------------------------------------
1 | import injection from './injection.js';
2 | import { isUUID } from './utils.js';
3 | const $db = Symbol('db');
4 | const $sceneGraphs = Symbol('sceneGraphs');
5 | const $overviews = Symbol('overviews');
6 | const $update = Symbol('update');
7 | const $onMessage = Symbol('onMessage');
8 | const $log = Symbol('log');
9 | const $eval = Symbol('eval');
10 | const $dispatchToContent = Symbol('dispatchToContent');
11 | const $renderers = Symbol('renderers');
12 | const $renderingInfo = Symbol('renderingInfo');
13 |
14 | const VERBOSE_CONTENT_BRIDGE = false;
15 |
16 | export default class ContentBridge extends EventTarget {
17 | /**
18 | * Events:
19 | * 'load'
20 | * 'entity-update' { entity, uuid }
21 | * 'scene-graph-update' { uuid, graph }
22 | * 'overview-update' { type, entities }
23 | * 'rendering-info-update' {}
24 | * 'renderer-update' { renderer, id }
25 | */
26 | constructor() {
27 | super();
28 |
29 | this[$db] = new Map();
30 | this[$overviews] = new Map();
31 | this[$sceneGraphs] = new Map();
32 | this[$renderers] = new Map();
33 | this[$renderingInfo] = new Map();
34 |
35 | this.port = browser.runtime.connect({
36 | name: 'three-devtools',
37 | });
38 |
39 | // Notify background port that the tools panel is open
40 | this.port.postMessage({
41 | name: 'connect',
42 | tabId: browser.devtools.inspectedWindow.tabId,
43 | });
44 |
45 | this.port.onDisconnect.addListener(request => {
46 | console.error('disconnected from background', request);
47 | });
48 |
49 | this.port.onMessage.addListener(e => this[$onMessage](e));
50 |
51 | document.addEventListener('keydown', e => {
52 | let mode, space;
53 | switch (e.key) {
54 | case 'q': space = true; break;
55 | case 'w': mode = 'translate'; break;
56 | case 'e': mode = 'rotate'; break;
57 | case 'r': mode = 'scale'; break;
58 | }
59 |
60 | if (mode || space) {
61 | this[$dispatchToContent]('_transform-controls-update', { mode, space });
62 | }
63 | }, { passive: true })
64 | }
65 |
66 | reload() {
67 | browser.devtools.inspectedWindow.reload();
68 | }
69 |
70 | getEntity(uuid) {
71 | return /renderer/.test(uuid) ? this[$renderers].get(uuid) : this[$db].get(uuid);
72 | }
73 |
74 | getEntityAndDependencies(rootUUID) {
75 | const data = {};
76 | const uuids = [rootUUID];
77 | while (uuids.length) {
78 | const uuid = uuids.shift();
79 | const entity = this.getEntity(uuid);
80 | // In renderers case, uuid is an id.
81 | // @TODO should probably abstract away the differences
82 | // between UUID and synthesized renderer ids.
83 | if (entity && !data[uuid]) {
84 | data[uuid] = entity;
85 |
86 | // entities can have several dependencies, like textures on materials,
87 | // or a Mesh's geometry
88 | for (let value of Object.values(entity)) {
89 | if (isUUID(value)) {
90 | uuids.push(value);
91 | }
92 | }
93 | }
94 | }
95 |
96 | return data;
97 | }
98 |
99 | getRenderingInfo(uuid) {
100 | return this[$renderingInfo].get(uuid);
101 | }
102 |
103 | getResourcesOverview(type) {
104 | return this[$overviews].get(type);
105 | }
106 |
107 | getSceneGraph(uuid) {
108 | return this[$sceneGraphs].get(uuid);
109 | }
110 |
111 | updateProperty(uuid, property, value, dataType) {
112 | const object = this.getEntity(uuid);
113 | this[$dispatchToContent]('entity-update', {
114 | uuid,
115 | property,
116 | value,
117 | dataType,
118 | });
119 |
120 | // Updating property won't trigger a data flush, instead update
121 | // the local state so that elements' values are in sync with their
122 | // HTML input state, important when switching between different items
123 | // with LitElement.
124 |
125 | object[property] = value;
126 | this[$update](object);
127 | }
128 |
129 | /**
130 | * Request latest data from content for the object
131 | * with UUID.
132 | */
133 | requestEntity(uuid) {
134 | this[$dispatchToContent]('_request-entity', { uuid });
135 | }
136 |
137 | requestOverview(type) {
138 | this[$dispatchToContent]('_request-overview', { type });
139 | }
140 |
141 | requestSceneGraph(uuid) {
142 | this[$dispatchToContent]('_request-scene-graph', { uuid });
143 | }
144 |
145 | requestRenderingInfo(uuid) {
146 | this[$dispatchToContent]('_request-rendering-info', { uuid });
147 | }
148 |
149 | select(uuid) {
150 | if (!uuid) {
151 | return;
152 | }
153 | this[$dispatchToContent]('select', { uuid });
154 | }
155 |
156 | [$onMessage](request) {
157 | const { id, type, data } = request;
158 |
159 | this[$log]('>>', type, data);
160 | switch (type) {
161 | case 'error':
162 | this.dispatchEvent(new CustomEvent('error', {
163 | detail: data,
164 | }));
165 | break;
166 | case 'register':
167 | this.revision = data.revision;
168 | this[$eval](`console.log("three-devtools: debugging three.js r${this.revision}")`);
169 | break;
170 | case 'committed':
171 | this[$db].clear();
172 | this[$overviews].clear();
173 | this[$sceneGraphs].clear();
174 | this[$renderers].clear();
175 | this[$renderingInfo].clear();
176 |
177 | this[$eval](injection);
178 | this.dispatchEvent(new CustomEvent('load'));
179 | break;
180 | case 'observe':
181 | this.dispatchEvent(new CustomEvent('observe', {
182 | detail: {
183 | uuids: data.uuids,
184 | },
185 | }));
186 | break;
187 | case 'scene-graph':
188 | this[$sceneGraphs].set(data.uuid, data.graph);
189 | this.dispatchEvent(new CustomEvent('scene-graph-update', {
190 | detail: {
191 | uuid: data.uuid,
192 | graph: data.graph,
193 | },
194 | }));
195 | break;
196 | case 'overview':
197 | this[$overviews].set(data.type, data.entities);
198 | this.dispatchEvent(new CustomEvent('overview-update', {
199 | detail: {
200 | type: data.type,
201 | entities: data.entities,
202 | },
203 | }));
204 | break;
205 | case 'rendering-info':
206 | this.dispatchEvent(new CustomEvent('rendering-info-update', {
207 | detail: data,
208 | }));
209 | this[$renderingInfo].set(data.uuid, data);
210 | break;
211 | case 'entity':
212 | if (data.type === 'renderer') {
213 | this[$renderers].set(data.uuid, data);
214 | this.dispatchEvent(new CustomEvent('renderer-update', {
215 | detail: {
216 | renderer: data,
217 | uuid: data.uuid,
218 | },
219 | }));
220 | } else if (Array.isArray(data)) {
221 | for (let entity of data) {
222 | this[$update](entity);
223 | }
224 | }
225 | break;
226 | }
227 | }
228 |
229 | [$update](entity) {
230 | this[$db].set(entity.uuid, entity);
231 | this.dispatchEvent(new CustomEvent('entity-update', {
232 | detail: {
233 | entity,
234 | uuid: entity.uuid,
235 | },
236 | }));
237 | }
238 |
239 | [$dispatchToContent](type, detail) {
240 | this[$eval](`
241 | __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('${type}', {
242 | detail: ${JSON.stringify(detail)},
243 | }));`
244 | );
245 | }
246 |
247 | _contentLog(string) {
248 | this[$eval](`console.log("${string}")`);
249 | }
250 |
251 | async [$eval](string) {
252 | this[$log]('EVAL', string);
253 | const [result, error] = await browser.devtools.inspectedWindow.eval(string);
254 | if (error) {
255 | console.warn(error);
256 | }
257 | return result;
258 | }
259 |
260 | [$log](...message) {
261 | if (VERBOSE_CONTENT_BRIDGE) {
262 | console.log('ContentBridge:', ...message);
263 | }
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/src/app/assets/chromeSelect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/chromeSelect.png
--------------------------------------------------------------------------------
/src/app/assets/chromeSelect_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/chromeSelect_2x.png
--------------------------------------------------------------------------------
/src/app/assets/largeIcons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/largeIcons.png
--------------------------------------------------------------------------------
/src/app/assets/largeIcons_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/largeIcons_2x.png
--------------------------------------------------------------------------------
/src/app/assets/mediumIcons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/mediumIcons.png
--------------------------------------------------------------------------------
/src/app/assets/mediumIcons_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/mediumIcons_2x.png
--------------------------------------------------------------------------------
/src/app/assets/smallIcons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/smallIcons.png
--------------------------------------------------------------------------------
/src/app/assets/smallIcons_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/assets/smallIcons_2x.png
--------------------------------------------------------------------------------
/src/app/common-elements/AccordionViewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | const $onVisibilityToggle = Symbol('onVisibilityToggle');
4 | const $onClick = Symbol('onClick');
5 |
6 | export default class AccordionViewElement extends LitElement {
7 | static get properties() {
8 | return {
9 | open: {type: Boolean, reflect: true},
10 | }
11 | }
12 |
13 | render() {
14 | return html`
15 |
90 |
92 |
93 |
94 |
95 |
96 |
97 | `;
98 | }
99 |
100 | [$onVisibilityToggle](e) {
101 | e.stopPropagation();
102 | this.open = !this.open;
103 | }
104 |
105 | [$onClick](e) {
106 | e.stopPropagation();
107 | this.open = !this.open;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/app/common-elements/DevtoolsButtonElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | export default class DevtoolsButtonElement extends LitElement {
4 | render() {
5 | return html`
6 |
21 |
22 | `;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/app/common-elements/DevtoolsIconButtonElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | export default class DevtoolsIconButtonElement extends LitElement {
4 | static get properties() {
5 | return {
6 | "icon": { type: String, reflect: true }
7 | }
8 | }
9 |
10 | render() {
11 | return html`
12 |
36 |
39 | `;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/common-elements/DevtoolsIconElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | const icons = {
4 | "close": { sheet: "large", position: "-84px 0px" },
5 | "visibility": { sheet: "large", position: "28px 0px" },
6 | "add": { sheet: "large", position: "0px -24px" },
7 | "check": { sheet: "large", position: "-54px -24px" },
8 | "shadow": { sheet: "large", position: "0px -48px" },
9 | "camera": { sheet: "large", position: "-28px -48px" },
10 | "settings": { sheet: "large", position: "56px -48px" },
11 | "undo": { sheet: "large", position: "28px -48px" },
12 | "edit": { sheet: "large", position: "0px -96px" },
13 | "filter": { sheet: "large", position: "-56px -96px" },
14 | "menu": { sheet: "large", position: "-56px -120px" },
15 | "search": { sheet: "large", position: "28px -120px" },
16 | "refresh": { sheet: "large", position: "-84px 48px" },
17 | };
18 |
19 | const sizes = {
20 | "large": "width: 28px; height: 24px"
21 | }
22 |
23 | export default class DevtoolsIconElement extends LitElement {
24 | static get properties() {
25 | return {
26 | "icon": { type: String, reflect: true }
27 | }
28 | }
29 |
30 | render() {
31 | const icon = icons[this.icon || "refresh"];
32 | return html`
33 |
45 | `;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/app/common-elements/DevtoolsMessageElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | export default class DevtoolsMessageElement extends LitElement {
4 | render() {
5 | return html`
6 |
25 |
26 |
27 |
28 | `;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/app/common-elements/IconElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, svg, html } from '../../../web_modules/lit-element.js'
2 |
3 | // cube
4 | // cubes
5 | // flask (experiments)
6 | // globe-africa, globe-americas, globe-asia, globe-europe (scene graph?)
7 | // sitemap (scene graph?)
8 | // sliders-h
9 | // vr-cardboard
10 | // dice-d20, dice-d6
11 | // sync
12 | // magic
13 | // lightbulb (lights)
14 | // search
15 | // box/box-open (grouping?)
16 | // brush (material?)
17 | // chess-board (textures)
18 | // eye (visibility)
19 | export default class IconElement extends LitElement {
20 | static get properties() {
21 | return {
22 | "icon": { type: String, },
23 | "fill": { type: Boolean, }
24 | }
25 | }
26 |
27 | render() {
28 | const iconName = `${this.icon}${this.fill ? '' : '-outline'}`;
29 | return html`
30 |
31 |
45 |
46 | `;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/app/common-elements/NumberInputElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js';
2 | //import { LitElement, html } from '../examples/web_modules/lit-element.js'
3 |
4 | const $onActivate = Symbol('onActivate');
5 |
6 | /**
7 | * A LitElement form of A-Frame Inspector's number widget
8 | * https://github.com/aframevr/aframe-inspector/blob/master/src/components/widgets/NumberWidget.js
9 | */
10 | class NumberInputElement extends LitElement {
11 | static get properties() {
12 | return {
13 | min: { type: Number },
14 | max: { type: Number },
15 | step: { type: Number },
16 | value: { type: Number },
17 | precision: { type: Number },
18 | }
19 | }
20 |
21 | constructor() {
22 | super();
23 | this.min = -Infinity;
24 | this.max = Infinity;
25 | this.value = 0;
26 | this.precision = 3;
27 | this.step = 1;
28 |
29 | this.onMouseMove = this.onMouseMove.bind(this);
30 | this.onMouseUp = this.onMouseUp.bind(this);
31 | };
32 |
33 | firstUpdated() {
34 | this.distance = 0;
35 | this.onMouseDownValue = 0;
36 | this.prevPointer = [0, 0];
37 | this.$input = this.shadowRoot.querySelector('input');
38 | this.setValue(this.value);
39 | this.onBlur();
40 | }
41 |
42 | onMouseMove(event) {
43 | const currentValue = parseFloat(this.value);
44 | const pointer = [event.clientX, event.clientY];
45 | const delta =
46 | pointer[0] - this.prevPointer[0] - (pointer[1] - this.prevPointer[1]);
47 | this.distance += delta;
48 |
49 | // Add minimum tolerance to reduce unintentional drags when clicking on input.
50 | if (Math.abs(delta) <= 2) {
51 | return;
52 | }
53 |
54 | let value = this.onMouseDownValue;
55 | const accel = event.shiftKey ? 10 : 1;
56 | value = parseInt(this.distance / 2) * accel * this.step;
57 | value += currentValue;
58 | value = Math.min(this.max, Math.max(this.min, value));
59 | if (currentValue !== value) {
60 | this.setValue(value);
61 | }
62 | this.prevPointer = [event.clientX, event.clientY];
63 | }
64 |
65 | onMouseDown(event) {
66 | event.preventDefault();
67 | this.distance = 0;
68 | this.onMouseDownValue = this.value;
69 | this.prevPointer = [event.clientX, event.clientY];
70 | document.addEventListener('mousemove', this.onMouseMove, false);
71 | document.addEventListener('mouseup', this.onMouseUp, false);
72 | };
73 |
74 | onMouseUp(event) {
75 | document.removeEventListener('mousemove', this.onMouseMove, false);
76 | document.removeEventListener('mouseup', this.onMouseUp, false);
77 |
78 | if (Math.abs(this.distance) < 2) {
79 | this.$input.focus();
80 | this.$input.select();
81 | }
82 | };
83 |
84 | setValue(value) {
85 | if (value === this.value) return;
86 |
87 | if (value !== undefined) {
88 | if (this.precision === 0) {
89 | value = parseInt(value);
90 | } else {
91 | value = parseFloat(value);
92 | }
93 |
94 | if (value < this.min) {
95 | value = this.min;
96 | }
97 | if (value > this.max) {
98 | value = this.max;
99 | }
100 |
101 | this.value = value;
102 | this.dispatchEvent(new CustomEvent('change', {
103 | detail: {
104 | value: parseFloat(value.toFixed(5)),
105 | },
106 | bubbles: true,
107 | composed: true,
108 | }));
109 | }
110 | }
111 |
112 | shouldUpdate(changed) {
113 | // This will be triggered typically when the element is changed directly with
114 | // element.setAttribute.
115 | if (changed.has('value') && changed.get('value') !== this.value) {
116 | return true;
117 | }
118 | return true;
119 | }
120 |
121 | onBlur() {
122 | this.setValue(parseFloat(this.$input.value));
123 | }
124 |
125 | onChange(e) {
126 | this.setValue(e.target.value);
127 | };
128 |
129 | onKeyDown(event) {
130 | event.stopPropagation();
131 |
132 | // enter.
133 | if (event.keyCode === 13) {
134 | this.setValue(parseFloat(this.$input.value));
135 | this.$input.blur();
136 | return;
137 | }
138 |
139 | // up.
140 | if (event.keyCode === 38) {
141 | this.setValue(parseFloat(this.value) + this.step);
142 | return;
143 | }
144 |
145 | // down.
146 | if (event.keyCode === 40) {
147 | this.setValue(parseFloat(this.value) - this.step);
148 | return;
149 | }
150 | };
151 |
152 | render() {
153 | const displayValue = this.value.toFixed(this.precision);
154 | return html`
155 |
163 |
172 | `;
173 | }
174 | }
175 | export default NumberInputElement;
176 |
--------------------------------------------------------------------------------
/src/app/constants.js:
--------------------------------------------------------------------------------
1 | export const MaterialTypes = [
2 | 'Material',
3 | 'LineBasicMaterial',
4 | 'LineDashedMaterial',
5 | 'MeshBasicMaterial',
6 | 'MeshDepthMaterial',
7 | 'MeshDistanceMaterial',
8 | 'MeshLambertMaterial',
9 | 'MeshMatcapMaterial',
10 | 'MeshNormalMaterial',
11 | 'MeshPhongMaterial',
12 | 'MeshPhysicalMaterial',
13 | 'MeshStandardMaterial',
14 | 'MeshToonMaterial',
15 | 'PointsMaterial',
16 | 'RawShaderMaterial',
17 | 'ShaderMaterial',
18 | 'ShadowMaterial',
19 | 'SpriteMaterial'
20 | ];
21 |
22 | export const ObjectTypes = [
23 | 'Mesh',
24 | 'Line',
25 | 'LineLoop',
26 | 'LineSegments',
27 | 'AmbientLight',
28 | 'DirectionalLight',
29 | 'HemisphereLight',
30 | 'PointLight',
31 | 'RectAreaLight',
32 | 'SpotLight',
33 | 'ArrowHelper',
34 | 'AxesHelper',
35 | 'BoxHelper',
36 | 'Box3Helper',
37 | 'CameraHelper',
38 | 'DirectionalLightHelper',
39 | 'FaceNormalsHelper',
40 | 'GridHelper',
41 | 'PolarGridHelper',
42 | 'PositionalAudioHelper',
43 | 'HemisphereLightHelper',
44 | 'PlaneHelper',
45 | 'PointLightHelper',
46 | 'RectAreaLightHelper',
47 | 'SkeletonHelper',
48 | 'SpotLightHelper',
49 | 'VertexNormalsHelper',
50 | 'Skeleton',
51 | 'Bone',
52 | 'Group'
53 | ];
54 |
55 | // Defaults go first, and applied if undefined
56 | const ConstantTypes = {
57 | mapping: [
58 | 'UVMapping',
59 | 'CubeReflectionMapping',
60 | 'CubeRefractionMapping',
61 | 'EquirectangularReflectionMapping',
62 | 'EquirectangularRefractionMapping',
63 | 'SphericalReflectionMapping',
64 | 'CubeUVReflectionMapping',
65 | 'CubeUVRefractionMapping',
66 | ],
67 | drawMode: [
68 | 'TrianglesDrawMode',
69 | 'TriangleStripDrawMode',
70 | 'TriangleFanDrawMode'
71 | ],
72 | side: [
73 | 'FrontSide',
74 | 'BackSide',
75 | 'DoubleSide'
76 | ],
77 | colors: [
78 | 'NoColors',
79 | 'FaceColors',
80 | 'VertexColors'
81 | ],
82 | blending:[
83 | 'NormalBlending',
84 | 'NoBlending',
85 | 'AdditiveBlending',
86 | 'SubtractiveBlending',
87 | 'MultiplyBlending',
88 | 'CustomBlending'
89 | ],
90 | blendEquation: [
91 | 'AddEquation',
92 | 'SubtractEquation',
93 | 'ReverseSubtractEquation',
94 | 'MinEquation',
95 | 'MaxEquation'
96 | ],
97 | blendDst: [
98 | 'OneMinusSrcAlphaFactor',
99 | 'ZeroFactor',
100 | 'OneFactor',
101 | 'SrcColorFactor',
102 | 'OneMinusSrcColorFactor',
103 | 'SrcAlphaFactor',
104 | 'DstAlphaFactor',
105 | 'OneMinusDstAlphaFactor',
106 | 'DstColorFactor',
107 | 'OneMinusDstColorFactor'
108 | ],
109 | blendSrc: [
110 | 'OneMinusSrcAlphaFactor',
111 | 'ZeroFactor',
112 | 'OneFactor',
113 | 'SrcColorFactor',
114 | 'OneMinusSrcColorFactor',
115 | 'SrcAlphaFactor',
116 | 'DstAlphaFactor',
117 | 'OneMinusDstAlphaFactor',
118 | 'DstColorFactor',
119 | 'OneMinusDstColorFactor',
120 | 'SrcAlphaSaturateFactor'
121 | ],
122 | depthFunc: [
123 | 'LessEqualDepth',
124 | 'NeverDepth',
125 | 'AlwaysDepth',
126 | 'LessDepth',
127 | 'GreaterEqualDepth',
128 | 'GreaterDepth',
129 | 'NotEqualDepth'
130 | ],
131 | combine: [
132 | 'MultiplyOperation',
133 | 'MixOperation',
134 | 'AddOperation',
135 | ],
136 | vertexColors: [
137 | 'NoColors',
138 | 'VertexColors',
139 | 'FaceColors',
140 | ],
141 | normalMapType: [
142 | 'TangentSpaceNormalMap',
143 | 'ObjectSpaceNormalMap',
144 | ],
145 | encoding: [
146 | 'LinearEncoding',
147 | 'sRGBEncoding',
148 | 'GammaEncoding',
149 | 'RGBEEncoding',
150 | 'LogLuvEncoding',
151 | 'RGBM7Encoding',
152 | 'RGBM16Encoding',
153 | 'RGBDEncoding',
154 | 'BasicDepthPacking',
155 | 'RGBADepthPacking'
156 | ],
157 | format: [
158 | 'RGBAFormat',
159 | 'AlphaFormat',
160 | 'RGBFormat',
161 | 'LuminanceFormat',
162 | 'LuminanceAlphaFormat',
163 | 'RGBEFormat',
164 | 'DepthFormat',
165 | 'DepthStencilFormat'
166 | ],
167 | type: [
168 | 'UnsignedByteType',
169 | 'ByteType',
170 | 'ShortType',
171 | 'UnsignedShortType',
172 | 'IntType',
173 | 'UnsignedIntType',
174 | 'FloatType',
175 | 'HalfFloatType',
176 | 'UnsignedShort4444Type',
177 | 'UnsignedShort5551Type',
178 | 'UnsignedShort565Type',
179 | 'UnsignedInt248Type',
180 | ],
181 | wrapping: [
182 | 'ClampToEdgeWrapping',
183 | 'RepeatWrapping',
184 | 'MirroredRepeatWrapping',
185 | ],
186 | magFilter: [
187 | 'LinearFilter',
188 | 'NearestFilter',
189 | ],
190 | minFilter: [
191 | 'LinearMipMapLinearFilter',
192 | 'NearestFilter',
193 | 'NearestMipMapNearestFilter',
194 | 'NearestMipMapLinearFilter',
195 | 'LinearFilter',
196 | 'LinearMipMapNearestFilter',
197 | ],
198 | toneMapping: [
199 | 'NoToneMapping',
200 | 'LinearToneMapping',
201 | 'ReinhardToneMapping',
202 | 'Uncharted2ToneMapping',
203 | 'CineonToneMapping',
204 | 'ACESFilmicToneMapping',
205 | ],
206 | shadowMap: [
207 | 'BasicShadowMap',
208 | 'PCFShadowMap',
209 | 'PCFSoftShadowMap',
210 | 'VSMShadowMap',
211 | ],
212 | };
213 |
214 | // Copy some over since the constant type is found
215 | // by property name.
216 | ConstantTypes.shadowSide = ConstantTypes.side;
217 | ConstantTypes.blendSrcAlpha = ['null', ...ConstantTypes.blendSrc];
218 | ConstantTypes.blendDstAlpha = ['null', ...ConstantTypes.blendDst];
219 | ConstantTypes.blendEquationAlpha = ['null', ...ConstantTypes.blendEquation];
220 | // Change default (first in order) when encoding is used as `depthPacking`
221 | ConstantTypes.depthPacking = [...ConstantTypes.encoding];
222 | ConstantTypes.depthPacking[ConstantTypes.depthPacking.indexOf('BasicDepthPacking')] =
223 | ConstantTypes.depthPacking[0];
224 | ConstantTypes.depthPacking[0] = 'BasicDepthPacking';
225 |
226 | export { ConstantTypes };
227 |
--------------------------------------------------------------------------------
/src/app/data/geometry.js:
--------------------------------------------------------------------------------
1 | const BufferAttributes = (entity) => {
2 | const attributes = entity.data && entity.data.attributes;
3 | if (!attributes) {
4 | return;
5 | }
6 | const attrType = 'array'; // { name, itemSize, type, array, normalized }
7 | const attrs = Object.keys(attributes).map(key => {
8 | return {
9 | name: key,
10 | type: attrType,
11 | prop: `data.attributes.${key}`
12 | }
13 | });
14 | return {
15 | name: 'Attributes',
16 | type: 'group',
17 | props: attrs,
18 | }
19 | };
20 |
21 | // boundingBox
22 | // boundingSphere
23 | const Geometry = {
24 | type: 'geometry',
25 | props: [{
26 | name: 'Vertices',
27 | type: 'array',
28 | prop: 'data.vertices',
29 | }, {
30 | name: 'Colors',
31 | type: 'array',
32 | prop: 'colors',
33 | }, {
34 | name: 'Faces',
35 | type: 'array',
36 | prop: 'faces',
37 | }, {
38 | name: 'Faces Vertex UVs',
39 | type: 'array',
40 | prop: 'faceVertexUvs',
41 | }, {
42 | name: 'Morph Targets',
43 | type: 'array', // { name: ..., vertices: [new Vector3()]}
44 | prop: 'morphTargets',
45 | }, {
46 | name: 'Morph Normals',
47 | type: 'array', // { name: ..., normals: [new Vector3()]}
48 | prop: 'morphNormals',
49 | }, {
50 | name: 'Skin Weights',
51 | type: 'array',
52 | prop: 'skinWeights',
53 | }, {
54 | name: 'Skin Indices',
55 | type: 'array',
56 | prop: 'skinIndices',
57 | }, {
58 | name: 'Line Distances',
59 | type: 'array',
60 | prop: 'faceVertexUvs',
61 | }]
62 | }
63 |
64 | // boundingBox
65 | // boundingSphere
66 | // morphAttributes
67 | const bufferGeometryProps = [{
68 | name: 'Index',
69 | type: 'attribute',
70 | prop: 'data.index',
71 | }, {
72 | name: 'Groups',
73 | type: 'array', // { start, count, materialIndex }
74 | prop: 'data.groups',
75 | },
76 | /*
77 | {
78 | name: 'Draw Range',
79 | type: 'group',
80 | props: [{
81 | name: 'Start',
82 | type: 'number',
83 | prop: 'drawRange.start',
84 | default: 0,
85 | }, {
86 | name: 'Count',
87 | type: 'number',
88 | prop: 'drawRange.count',
89 | default: Infinity,
90 | }]
91 | },
92 | */
93 | {
94 | name: 'Morph Targets Relative',
95 | type: 'boolean',
96 | prop: 'data.morphTargetsRelative',
97 | default: false,
98 | }];
99 |
100 | const BufferGeometry = {
101 | type: 'geometry',
102 | props: [
103 | ...bufferGeometryProps
104 | ],
105 | BufferAttributes,
106 | }
107 |
108 | const InstancedBufferGeometry = {
109 | type: 'geometry',
110 | props: [
111 | ...bufferGeometryProps, {
112 | name: 'Instance Count',
113 | type: 'int',
114 | prop: 'instanceCount',
115 | }
116 | ],
117 | BufferAttributes,
118 | }
119 |
120 | export default {
121 | BufferGeometry: BufferGeometry,
122 | Geometry: Geometry,
123 |
124 | InstancedBufferGeometry: InstancedBufferGeometry,
125 |
126 | BoxBufferGeometry: BufferGeometry,
127 | BoxGeometry: Geometry,
128 | CircleBufferGeometry: BufferGeometry,
129 | CircleGeometry: Geometry,
130 | ConeBufferGeometry: BufferGeometry,
131 | ConeGeometry: Geometry,
132 | CylinderBufferGeometry: BufferGeometry,
133 | CylinderGeometry: Geometry,
134 | DodecahedronBufferGeometry: BufferGeometry,
135 | DodecahedronGeometry: Geometry,
136 | EdgesGeometry: Geometry,
137 | ExtrudeBufferGeometry: BufferGeometry,
138 | ExtrudeGeometry: Geometry,
139 | IcosahedronBufferGeometry: BufferGeometry,
140 | IcosahedronGeometry: Geometry,
141 | LatheBufferGeometry: BufferGeometry,
142 | LatheGeometry: Geometry,
143 | OctahedronBufferGeometry: BufferGeometry,
144 | OctahedronGeometry: Geometry,
145 | ParametricBufferGeometry: BufferGeometry,
146 | ParametricGeometry: Geometry,
147 | PlaneBufferGeometry: BufferGeometry,
148 | PlaneGeometry: Geometry,
149 | PolyhedronBufferGeometry: BufferGeometry,
150 | PolyhedronGeometry: Geometry,
151 | RingBufferGeometry: BufferGeometry,
152 | RingGeometry: Geometry,
153 | ShapeBufferGeometry: BufferGeometry,
154 | ShapeGeometry: Geometry,
155 | SphereBufferGeometry: BufferGeometry,
156 | SphereGeometry: Geometry,
157 | TetrahedronBufferGeometry: BufferGeometry,
158 | TetrahedronGeometry: Geometry,
159 | TextBufferGeometry: BufferGeometry,
160 | TextGeometry: Geometry,
161 | TorusBufferGeometry: BufferGeometry,
162 | TorusGeometry: Geometry,
163 | TorusKnotBufferGeometry: BufferGeometry,
164 | TorusKnotGeometry: Geometry,
165 | TubeBufferGeometry: BufferGeometry,
166 | TubeGeometry: Geometry,
167 | WireframeGeometry: Geometry,
168 | }
169 |
--------------------------------------------------------------------------------
/src/app/data/lights.js:
--------------------------------------------------------------------------------
1 | import transform from './object-transform.js';
2 | import renderable from './object-renderable.js';
3 |
4 | const base = [{
5 | name: 'Color',
6 | prop: 'color',
7 | type: 'color',
8 | }, {
9 | name: 'Intensity',
10 | prop: 'intensity',
11 | type: 'number',
12 | }];
13 |
14 | const objectProps = [
15 | transform,
16 | renderable,
17 | ];
18 |
19 | const castShadow = {
20 | name: 'Cast Shadow',
21 | prop: 'castShadow',
22 | type: 'boolean',
23 | default: false,
24 | };
25 |
26 | const target = {
27 | name: 'Target',
28 | prop: 'target',
29 | type: 'vec3',
30 | };
31 |
32 | const decay = {
33 | name: 'Decay',
34 | prop: 'decay',
35 | type: 'number',
36 | default: 1,
37 | };
38 | const distance = {
39 | name: 'Distance',
40 | prop: 'distance',
41 | type: 'number',
42 | default: 0,
43 | };
44 | const power = {
45 | name: 'Power',
46 | prop: 'power',
47 | type: 'number',
48 | default: Math.PI * 4,
49 | };
50 |
51 | const Light = {
52 | type: 'light',
53 | props: [
54 | ...base,
55 | ...objectProps
56 | ],
57 | }
58 |
59 | export default {
60 | Light: Light,
61 | AmbientLight: Light,
62 | DirectionalLight: {
63 | type: 'object',
64 | props: [
65 | ...base,
66 | castShadow,
67 | target,
68 | ...objectProps,
69 | ],
70 | },
71 | HemisphereLight: {
72 | type: 'object',
73 | props: [
74 | ...base,
75 | castShadow,
76 | {
77 | name: 'Ground Color',
78 | prop: 'groundColor',
79 | type: 'color'
80 | },
81 | ...objectProps,
82 | ],
83 | },
84 | PointLight: {
85 | type: 'object',
86 | props: [
87 | ...base,
88 | castShadow,
89 | decay,
90 | distance,
91 | power,
92 | ...objectProps,
93 | ],
94 | },
95 | RectAreaLight: {
96 | type: 'object',
97 | props: [
98 | ...base,
99 | castShadow,
100 | {
101 | name: 'Width',
102 | prop: 'width',
103 | type: 'number'
104 | }, {
105 | name: 'Height',
106 | prop: 'height',
107 | type: 'number'
108 | },
109 | ...objectProps,
110 | ],
111 | },
112 | SpotLight: {
113 | type: 'object',
114 | props: [
115 | ...base,
116 | castShadow,
117 | {
118 | name: 'Angle',
119 | prop: 'angle',
120 | type: 'angle',
121 | default: Math.PI/3,
122 | min: 0,
123 | max: Math.PI/2,
124 | },
125 | decay,
126 | distance,
127 | power,
128 | {
129 | name: 'Penumbra',
130 | prop: 'penumbra',
131 | type: 'number',
132 | default: 0,
133 | min: 0,
134 | max: 1,
135 | },
136 | target,
137 | ...objectProps,
138 | ],
139 | },
140 | };
141 |
--------------------------------------------------------------------------------
/src/app/data/material-blending.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'Blending',
3 | type: 'group',
4 | props: [{
5 | name: 'Blending',
6 | prop: 'blending',
7 | type: 'enum',
8 | }, {
9 | name: 'Alpha Test',
10 | prop: 'alphaTest',
11 | type: 'number',
12 | default: 0,
13 | }, {
14 | name: 'Source',
15 | prop: 'blendSrc',
16 | type: 'enum',
17 | }, {
18 | name: 'Source Alpha',
19 | prop: 'blendSrcAlpha',
20 | type: 'enum',
21 | default: 0,
22 | }, {
23 | name: 'Destination',
24 | prop: 'blendDst',
25 | type: 'enum',
26 | }, {
27 | name: 'Destination Alpha',
28 | prop: 'blendDstAlpha',
29 | type: 'enum',
30 | default: 0,
31 | }, {
32 | name: 'Blend Equation',
33 | prop: 'blendEquation',
34 | type: 'enum',
35 | }, {
36 | name: 'Blend Equation Alpha',
37 | prop: 'blendEquationAlpha',
38 | type: 'enum',
39 | default: 0,
40 | }, {
41 | name: 'Premultiplied Alpha',
42 | prop: 'premultipliedAlpha',
43 | type: 'boolean',
44 | default: false,
45 | }],
46 | };
47 |
--------------------------------------------------------------------------------
/src/app/data/material-common.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'Properties',
3 | type: 'group',
4 | props: [{
5 | name: 'Side',
6 | prop: 'side',
7 | type: 'enum',
8 | default: 0,
9 | }, {
10 | name: 'Transparent',
11 | prop: 'transparent',
12 | type: 'boolean',
13 | default: false,
14 | }, {
15 | name: 'Visible',
16 | prop: 'visible',
17 | type: 'boolean',
18 | default: true,
19 | }, {
20 | name: 'Opacity',
21 | prop: 'opacity',
22 | type: 'number',
23 | min: 0,
24 | max: 1,
25 | default: 1,
26 | }, {
27 | name: 'Color Write',
28 | prop: 'colorWrite',
29 | type: 'boolean',
30 | default: true,
31 | }, {
32 | name: 'Depth Func',
33 | prop: 'depthFunc',
34 | type: 'enum',
35 | }, {
36 | name: 'Depth Test',
37 | prop: 'depthTest',
38 | type: 'boolean',
39 | default: true,
40 | }, {
41 | name: 'Depth Write',
42 | prop: 'depthWrite',
43 | type: 'boolean',
44 | default: true,
45 | }, {
46 | name: 'Lights',
47 | prop: 'lights',
48 | type: 'boolean',
49 | default: false,
50 | }, {
51 | name: 'Flat Shading',
52 | prop: 'flatShading',
53 | type: 'boolean',
54 | default: false,
55 | }, {
56 | name: 'Fog',
57 | prop: 'fog',
58 | type: 'boolean',
59 | default: false,
60 | }, {
61 | name: 'Dithering',
62 | prop: 'dithering',
63 | type: 'boolean',
64 | default: false,
65 | }, {
66 | name: 'Clip Intersection',
67 | prop: 'clipIntersection',
68 | type: 'boolean',
69 | default: false,
70 | }, {
71 | name: 'Clip Shadows',
72 | prop: 'clipShadows',
73 | type: 'boolean',
74 | default: false,
75 | }, {
76 | name: 'Shadow Side',
77 | prop: 'shadowSide',
78 | type: 'enum',
79 | default: 0,
80 | }, {
81 | name: 'Tone Mapped',
82 | prop: 'toneMapped',
83 | type: 'boolean',
84 | default: true,
85 | }, {
86 | name: 'Vertex Colors',
87 | prop: 'vertexColors',
88 | type: 'enum',
89 | }, {
90 | name: 'Vertex Tangents',
91 | prop: 'vertexTangents',
92 | type: 'boolean',
93 | default: false,
94 | }]
95 | }
96 |
--------------------------------------------------------------------------------
/src/app/data/material-line.js:
--------------------------------------------------------------------------------
1 | export const line = {
2 | name: 'Line Width',
3 | type: 'number',
4 | prop: 'linewidth',
5 | default: 1,
6 | };
7 |
8 | export const lineDashed = [{
9 | name: 'Dash Size',
10 | type: 'number',
11 | prop: 'dashSize',
12 | default: 3,
13 | }, {
14 | name: 'Dash Scale',
15 | type: 'number',
16 | prop: 'scale',
17 | default: 1,
18 | }, {
19 | name: 'Gap Size',
20 | type: 'number',
21 | prop: 'gapSize',
22 | default: 1,
23 | }];
24 |
--------------------------------------------------------------------------------
/src/app/data/material-pbr.js:
--------------------------------------------------------------------------------
1 | export const metalness = {
2 | type: 'group',
3 | name: 'Metalness',
4 | props: [{
5 | name: 'Map',
6 | type: 'texture',
7 | prop: 'metalnessMap',
8 | }, {
9 | name: 'Metalness',
10 | type: 'number',
11 | prop: 'metalness',
12 | min: 0,
13 | max: 1,
14 | }],
15 | }
16 |
17 | export const roughness = {
18 | type: 'group',
19 | name: 'Roughness',
20 | props: [{
21 | name: 'Roughness Map',
22 | type: 'texture',
23 | prop: 'roughnessMap',
24 | }, {
25 | name: 'Roughness',
26 | type: 'number',
27 | prop: 'roughness',
28 | min: 0,
29 | max: 1,
30 | }],
31 | };
32 |
33 | export const clearCoat = {
34 | type: 'group',
35 | name: 'Clear Coat',
36 | props: [{
37 | name: 'Clear Coat',
38 | type: 'number',
39 | prop: 'clearCoat',
40 | min: 0,
41 | max: 1,
42 | default: 0,
43 | }, {
44 | name: 'Clear Coat Roughness',
45 | type: 'number',
46 | prop: 'clearCoatRoughness',
47 | min: 0,
48 | max: 1,
49 | default: 0,
50 | }],
51 | };
52 |
--------------------------------------------------------------------------------
/src/app/data/material-polygon-offset.js:
--------------------------------------------------------------------------------
1 | export default {
2 | type: 'group',
3 | name: 'Polygon Offset',
4 | props: [{
5 | name: 'Enabled',
6 | type: 'boolean',
7 | prop: 'polygonOffset',
8 | default: false,
9 | }, {
10 | name: 'Offset Factor',
11 | type: 'int',
12 | prop: 'polygonOffsetFactor',
13 | default: 0,
14 | }, {
15 | name: 'Offset Units',
16 | type: 'int',
17 | prop: 'polygonOffsetUnits',
18 | default: 0,
19 | }]
20 | };
21 |
--------------------------------------------------------------------------------
/src/app/data/material-shared.js:
--------------------------------------------------------------------------------
1 | export const color = {
2 | name: 'Color',
3 | prop: 'color',
4 | type: 'color',
5 | };
6 |
7 | export const gradientMap = {
8 | name: 'Gradient Map',
9 | prop: 'gradientMap',
10 | type: 'texture',
11 | };
12 |
13 | export const combine = {
14 | name: 'Combine',
15 | prop: 'combine',
16 | type: 'enum',
17 | };
18 |
19 | export const depthPacking = {
20 | name: 'Depth Packing',
21 | prop: 'depthPacking',
22 | type: 'enum',
23 | };
24 |
25 | export const alphaMap = {
26 | name: 'Alpha Map',
27 | prop: 'alphaMap',
28 | type: 'texture',
29 | };
30 |
31 | export const matcap = {
32 | name: 'matcap',
33 | prop: 'matcap',
34 | type: 'texture',
35 | }
36 |
37 | export const normalMap = {
38 | type: 'group',
39 | name: 'Normal Map',
40 | props: [{
41 | name: 'Map',
42 | type: 'texture',
43 | prop: 'normalMap',
44 | }, {
45 | name: 'Scale',
46 | type: 'vec2',
47 | prop: 'normalScale',
48 | default: [1, 1],
49 | }, {
50 | name: 'Type',
51 | type: 'enum',
52 | prop: 'normalMapType',
53 | }]
54 | };
55 |
56 | export const bumpMap = {
57 | type: 'group',
58 | name: 'Bump Map',
59 | props: [{
60 | name: 'Map',
61 | type: 'texture',
62 | prop: 'bumpMap',
63 | }, {
64 | name: 'Scale',
65 | type: 'texture',
66 | prop: 'bumpScale',
67 | default: 1,
68 | }],
69 | };
70 |
71 | export const distance = {
72 | name: 'Distance',
73 | type: 'group',
74 | props: [{
75 | name: 'referencePosition',
76 | prop: 'referencePosition',
77 | type: 'vec3',
78 | }, {
79 | name: 'Near Distance',
80 | prop: 'nearDistance',
81 | type: 'number',
82 | }, {
83 | name: 'Far Distance',
84 | prop: 'farDistance',
85 | type: 'number',
86 | }]
87 | }
88 |
89 | export const displacement = {
90 | type: 'group',
91 | name: 'Displacement Map',
92 | props: [{
93 | name: 'Map',
94 | type: 'texture',
95 | prop: 'displacementMap',
96 | }, {
97 | name: 'Scale',
98 | type: 'number',
99 | prop: 'displacementScale',
100 | min: 0,
101 | default: 1,
102 | }, {
103 | name: 'Bias',
104 | type: 'number',
105 | prop: 'displacementBias',
106 | min: 0,
107 | default: 0,
108 | }]
109 | };
110 |
111 | export const diffuseMap = {
112 | name: 'Diffuse Map',
113 | prop: 'map',
114 | type: 'texture',
115 | };
116 |
117 | export const ao = {
118 | name: 'Ambient Occlusion',
119 | type: 'group',
120 | props: [{
121 | name: 'Map',
122 | prop: 'aoMap',
123 | type: 'texture',
124 | }, {
125 | name: 'Intensity',
126 | prop: 'aoMapIntensity',
127 | type: 'number',
128 | min: 0,
129 | default: 1,
130 | }],
131 | };
132 |
133 | export const envMap = {
134 | name: 'Environment Map',
135 | type: 'texture',
136 | prop: 'envMap',
137 | };
138 |
139 | export const envMapIntensity = {
140 | name: 'Environment Intensity',
141 | type: 'number',
142 | prop: 'envMapIntensity',
143 | default: 1,
144 | min: 0,
145 | };
146 |
147 | export const lightMap = {
148 | name: 'Light Map',
149 | type: 'group',
150 | props: [{
151 | name: 'Map',
152 | prop: 'lightMap',
153 | type: 'texture',
154 | }, {
155 | name: 'Intensity',
156 | prop: 'lightMapIntensity',
157 | type: 'number',
158 | min: 0,
159 | default: 1,
160 | }],
161 | };
162 |
163 | export const morphNormals = {
164 | name: 'Morph Normals',
165 | type: 'boolean',
166 | prop: 'morphNormals',
167 | default: false,
168 | }
169 |
170 | export const morphTargets = {
171 | name: 'Morph Targets',
172 | type: 'boolean',
173 | prop: 'morphTargets',
174 | default: false,
175 | }
176 |
177 | export const reflectivity = {
178 | name: 'Reflectivity',
179 | type: 'number',
180 | prop: 'reflectivity',
181 | min: 0,
182 | max: 1,
183 | default: 1,
184 | }
185 |
186 | export const refractionRatio = {
187 | name: 'Refraction Ratio',
188 | type: 'number',
189 | prop: 'refractionRatio',
190 | default: 0.98,
191 | min: 0,
192 | }
193 |
194 | export const skinning = {
195 | name: 'Skinning',
196 | type: 'boolean',
197 | prop: 'skinning',
198 | default: false,
199 | }
200 |
201 | export const specularMap = {
202 | name: 'Specular Map',
203 | type: 'texture',
204 | prop: 'specularMap',
205 | }
206 |
207 | export const specular = {
208 | name: 'Specular',
209 | type: 'group',
210 | props: [{
211 | name: 'Color',
212 | type: 'color',
213 | prop: 'specular',
214 | }, {
215 | name: 'Map',
216 | type: 'texture',
217 | prop: 'specularMap',
218 | }],
219 | };
220 |
221 | export const clipping = {
222 | name: 'Clipping',
223 | type: 'boolean',
224 | prop: 'clipping',
225 | default: false,
226 | }
227 |
228 | export const wireframe = {
229 | name: 'Wireframe',
230 | type: 'group',
231 | props: [{
232 | name: 'Enabled',
233 | type: 'boolean',
234 | prop: 'wireframe',
235 | default: false,
236 | }, {
237 | name: 'Line Width',
238 | type: 'number',
239 | prop: 'wireframeLinewidth',
240 | default: 1,
241 | }, {
242 | name: 'Line Cap',
243 | type: 'string',
244 | prop: 'wireframeLinecap',
245 | default: 'round',
246 | }, {
247 | name: 'Line Join',
248 | type: 'string',
249 | prop: 'wireframeLinejoin',
250 | default: 'round',
251 | }]
252 | }
253 |
254 | export const sizeAttenuation = {
255 | name: 'Attenuation',
256 | type: 'boolean',
257 | prop: 'sizeAttenuation',
258 | default: true,
259 | }
260 |
261 | export const rotation = {
262 | name: 'Rotation',
263 | type: 'radians',
264 | prop: 'rotation',
265 | default: 0,
266 | }
267 |
268 | export const point = {
269 | name: 'Points',
270 | type: 'group',
271 | props: [{
272 | name: 'Size',
273 | type: 'number',
274 | prop: 'size',
275 | default: 1,
276 | }, {
277 | name: 'Attenuation',
278 | type: 'boolean',
279 | prop: 'sizeAttenuation',
280 | default: true,
281 | }]
282 | }
283 |
284 | export const emissive = {
285 | name: 'Emissive',
286 | type: 'group',
287 | props: [{
288 | name: 'Color',
289 | type: 'color',
290 | prop: 'emissive',
291 | }, {
292 | name: 'Emissive Map ',
293 | type: 'texture',
294 | prop: 'emissiveMap',
295 | }, {
296 | name: 'Emissive Intensity',
297 | prop: 'emissiveIntensity',
298 | type: 'number',
299 | default: 1,
300 | }]
301 | };
302 |
--------------------------------------------------------------------------------
/src/app/data/materials.js:
--------------------------------------------------------------------------------
1 | import common from './material-common.js';
2 | import * as prop from './material-shared.js';
3 | import blending from './material-blending.js';
4 | import polygonOffset from './material-polygon-offset.js';
5 | import { line, lineDashed } from './material-line.js';
6 | import { metalness, roughness, clearCoat } from './material-pbr.js';
7 |
8 | const standard = [
9 | {
10 | name: 'Environment',
11 | type: 'group',
12 | props: [prop.envMap, prop.envMapIntensity].map(p => {
13 | return Object.assign({}, p, {
14 | name: p.name.replace(/Environment /, ''),
15 | });
16 | }),
17 | },
18 | metalness,
19 | roughness,
20 | prop.normalMap,
21 | prop.bumpMap,
22 | prop.displacement,
23 | prop.ao,
24 | prop.lightMap,
25 | prop.emissive,
26 | ];
27 |
28 | const base = [
29 | common,
30 | blending,
31 | polygonOffset
32 | ];
33 |
34 | const lineBase = [
35 | // Remove 'side', 'shadowSide' from line materials
36 | Object.assign({}, common, {
37 | props: [...common.props.filter(({ prop }) => ['side', 'shadowSide'].indexOf(prop) === -1)],
38 | }),
39 | blending,
40 | polygonOffset
41 | ];
42 |
43 | const GenericMaterial = {
44 | type: 'material',
45 | props: base,
46 | }
47 |
48 | export default {
49 | Material: GenericMaterial,
50 | MeshBasicMaterial: {
51 | type: 'material',
52 | props: [
53 | prop.color,
54 | prop.diffuseMap,
55 | prop.combine,
56 | prop.alphaMap,
57 | prop.envMap,
58 | prop.reflectivity,
59 | prop.refractionRatio,
60 | prop.specularMap,
61 | prop.morphTargets,
62 | prop.skinning,
63 | prop.wireframe,
64 | prop.ao,
65 | prop.lightMap,
66 | ...base
67 | ],
68 | },
69 | MeshDepthMaterial: {
70 | type: 'material',
71 | props: [
72 | prop.depthPacking,
73 | prop.diffuseMap,
74 | prop.alphaMap,
75 | prop.wireframe,
76 | prop.displacement,
77 | ...base
78 | ],
79 | },
80 | MeshDistanceMaterial: {
81 | type: 'material',
82 | props: [
83 | prop.diffuseMap,
84 | prop.alphaMap,
85 | prop.morphTargets,
86 | prop.skinning,
87 | prop.distance,
88 | prop.displacement,
89 | ...base
90 | ],
91 | },
92 | MeshLambertMaterial: {
93 | type: 'material',
94 | props: [
95 | prop.color,
96 | prop.diffuseMap,
97 | prop.alphaMap,
98 | prop.envMap,
99 | prop.reflectivity,
100 | prop.refractionRatio,
101 | prop.morphNormals,
102 | prop.morphTargets,
103 | prop.skinning,
104 | prop.specularMap,
105 | prop.wireframe,
106 | prop.emissive,
107 | prop.ao,
108 | prop.lightMap,
109 | ...base
110 | ],
111 | },
112 | MeshMatcapMaterial: {
113 | type: 'material',
114 | props: [
115 | prop.color,
116 | prop.matcap,
117 | prop.diffuseMap,
118 | prop.alphaMap,
119 | prop.morphNormals,
120 | prop.morphTargets,
121 | prop.skinning,
122 | prop.normalMap,
123 | prop.bumpMap,
124 | prop.displacement,
125 | ...base
126 | ],
127 | },
128 | MeshNormalMaterial: {
129 | type: 'material',
130 | props: [
131 | prop.morphNormals,
132 | prop.morphTargets,
133 | prop.skinning,
134 | prop.wireframe,
135 | prop.normalMap,
136 | prop.bumpMap,
137 | prop.displacement,
138 | ...base
139 | ],
140 | },
141 | MeshPhongMaterial: {
142 | type: 'material',
143 | props: [
144 | prop.color,
145 | prop.alphaMap,
146 | prop.envMap,
147 | prop.diffuseMap,
148 | prop.combine,
149 | prop.refractionRatio,
150 | prop.reflectivity,
151 | prop.morphNormals,
152 | prop.morphTargets,
153 | prop.skinning,
154 | prop.ao,
155 | prop.specular,
156 | prop.lightMap,
157 | prop.wireframe,
158 | prop.emissive,
159 | prop.normalMap,
160 | prop.bumpMap,
161 | prop.displacement,
162 | ...base
163 | ],
164 | },
165 | MeshPhysicalMaterial: {
166 | type: 'material',
167 | props: [
168 | prop.diffuseMap,
169 | prop.color,
170 | prop.refractionRatio,
171 | prop.reflectivity,
172 | prop.skinning,
173 | prop.wireframe,
174 | ...standard,
175 | clearCoat,
176 | ...base
177 | ],
178 | },
179 | MeshStandardMaterial: {
180 | type: 'material',
181 | props: [
182 | prop.diffuseMap,
183 | prop.color,
184 | prop.refractionRatio,
185 | prop.skinning,
186 | prop.wireframe,
187 | ...standard,
188 | ...base
189 | ],
190 | },
191 | MeshToonMaterial: {
192 | type: 'material',
193 | props: [
194 | prop.color,
195 | prop.diffuseMap,
196 | prop.combine,
197 | prop.gradientMap,
198 | prop.alphaMap,
199 | prop.refractionRatio,
200 | prop.reflectivity,
201 | prop.envMap,
202 | prop.morphNormals,
203 | prop.morphTargets,
204 | prop.skinning,
205 | prop.specular,
206 | prop.ao,
207 | prop.lightMap,
208 | prop.wireframe,
209 | prop.emissive,
210 | prop.normalMap,
211 | prop.bumpMap,
212 | prop.displacement,
213 | ...base
214 | ],
215 | },
216 | PointsMaterial: {
217 | type: 'material',
218 | props: [
219 | prop.color,
220 | prop.alphaMap,
221 | prop.diffuseMap,
222 | prop.morphTargets,
223 | prop.point,
224 | ...base
225 | ]
226 | },
227 | RawShaderMaterial: {
228 | type: 'material',
229 | props: [
230 | prop.clipping,
231 | prop.morphNormals,
232 | prop.morphTargets,
233 | prop.skinning,
234 | prop.wireframe,
235 | ...base
236 | ],
237 | },
238 | ShaderMaterial: {
239 | type: 'material',
240 | props: [
241 | prop.clipping,
242 | prop.morphNormals,
243 | prop.morphTargets,
244 | prop.skinning,
245 | prop.wireframe,
246 | ...base
247 | ],
248 | },
249 | ShadowMaterial: GenericMaterial,
250 | SpriteMaterial: {
251 | type: 'material',
252 | props: [
253 | prop.color,
254 | prop.diffuseMap,
255 | prop.rotation,
256 | prop.sizeAttenuation,
257 | ...base
258 | ],
259 | },
260 | LineBasicMaterial: {
261 | type: 'material',
262 | props: [
263 | prop.color,
264 | line,
265 | ...lineBase
266 | ],
267 | },
268 | LineDashedMaterial: {
269 | type: 'material',
270 | props: [
271 | prop.color,
272 | line,
273 | ...lineDashed,
274 | ...lineBase
275 | ],
276 | },
277 | };
278 |
--------------------------------------------------------------------------------
/src/app/data/object-renderable.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'Rendering',
3 | type: 'group',
4 | props: [{
5 | name: 'Render Order',
6 | prop: 'renderOrder',
7 | type: 'int',
8 | default: 0,
9 | }, {
10 | name: 'Visible',
11 | prop: 'visible',
12 | type: 'boolean',
13 | default: true,
14 | }, {
15 | name: 'Receive Shadow',
16 | prop: 'receiveShadow',
17 | type: 'boolean',
18 | default: false,
19 | },{
20 | name: 'Cast Shadow',
21 | prop: 'castShadow',
22 | type: 'boolean',
23 | default: false,
24 | },{
25 | name: 'Frustum Culled',
26 | prop: 'frustumCulled',
27 | type: 'boolean',
28 | default: true,
29 | }],
30 | }
31 |
--------------------------------------------------------------------------------
/src/app/data/object-transform.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'Transform',
3 | type: 'group',
4 | props: [{
5 | name: 'Position',
6 | prop: 'position',
7 | type: 'vec3',
8 | step: 0.01,
9 | precision: 3,
10 | }, {
11 | name: 'Rotation',
12 | prop: 'rotation',
13 | type: 'vec3',
14 | step: 0.01,
15 | precision: 3,
16 | }, {
17 | name: 'Scale',
18 | prop: 'scale',
19 | type: 'vec3',
20 | step: 0.01,
21 | precision: 3,
22 | }, {
23 | name: 'Matrix Auto Update',
24 | prop: 'matrixAutoUpdate',
25 | type: 'boolean',
26 | default: true,
27 | }]
28 | }
29 |
--------------------------------------------------------------------------------
/src/app/data/objects.js:
--------------------------------------------------------------------------------
1 | import transform from './object-transform.js';
2 | import renderable from './object-renderable.js';
3 |
4 | const geometry = {
5 | name: 'Geometry',
6 | prop: 'geometry',
7 | type: 'geometry',
8 | }
9 | const material = {
10 | name: 'Material',
11 | prop: 'material',
12 | type: 'material',
13 | }
14 |
15 | const object = [
16 | transform,
17 | renderable,
18 | ];
19 |
20 | const GeometryRenderable = {
21 | type: 'object',
22 | props: [
23 | geometry,
24 | material,
25 | transform,
26 | renderable,
27 | ]
28 | }
29 |
30 | const Scene = {
31 | type: 'scene',
32 | props: object,
33 | }
34 |
35 | const Helper = {
36 | type: 'helper',
37 | props: object,
38 | }
39 |
40 | const Bone = {
41 | type: 'bone',
42 | props: object,
43 | }
44 |
45 | // Does not have a further classification yet
46 | const Object3D = {
47 | type: 'object',
48 | props: object,
49 | }
50 |
51 | export default {
52 | Mesh: GeometryRenderable,
53 | Line: GeometryRenderable,
54 | LineLoop: GeometryRenderable,
55 | LineSegments: GeometryRenderable,
56 | Points: GeometryRenderable,
57 | SkinnedMesh: GeometryRenderable,
58 | InstancedMesh: GeometryRenderable,
59 |
60 | AxesHelper: Helper,
61 | BoxHelper: Helper,
62 | Box3Helper: Helper,
63 | CameraHelper: Helper,
64 | DirectionalLightHelper: Helper,
65 | FaceNormalsHelper: Helper,
66 | GridHelper: Helper,
67 | PolarGridHelper: Helper,
68 | PositionalAudioHelper: Helper,
69 | HemisphereLightHelper: Helper,
70 | PlaneHelper: Helper,
71 | PointLightHelper: Helper,
72 | RectAreaLightHelper: Helper,
73 | SkeletonHelper: Helper,
74 | SpotLightHelper: Helper,
75 | VertexNormalsHelper: Helper,
76 |
77 | Scene: Scene,
78 |
79 | Skeleton: Bone,
80 | Bone: Bone,
81 |
82 | Object3D: Object3D,
83 | Group: Object3D,
84 | PerspectiveCamera: Object3D,
85 | OrthographicCamera: Object3D,
86 | Camera: Object3D,
87 | };
88 |
--------------------------------------------------------------------------------
/src/app/data/renderers.js:
--------------------------------------------------------------------------------
1 | const ToneMapping = {
2 | name: 'Tone Mapping',
3 | type: 'group',
4 | props: [{
5 | // @TODO
6 | name: 'Type',
7 | prop: 'toneMapping',
8 | type: 'enum',
9 | enumType: 'toneMapping',
10 | }, {
11 | name: 'Exposure',
12 | prop: 'toneMappingExposure',
13 | type: 'number',
14 | default: 1,
15 | }],
16 | };
17 |
18 | const ShadowMap = {
19 | name: 'Shadow Map',
20 | type: 'group',
21 | props: [{
22 | name: 'Enabled',
23 | prop: 'shadowMap.enabled',
24 | type: 'boolean',
25 | default: false,
26 | }, {
27 | name: 'Auto Update',
28 | prop: 'shadowMap.autoUpdate',
29 | type: 'boolean',
30 | default: true,
31 | }, {
32 | // @TODO enum
33 | name: 'Shadow Type',
34 | prop: 'shadowMap.type',
35 | type: 'enum',
36 | enumType: 'shadowMap',
37 | }],
38 | };
39 |
40 | const BufferClearing = {
41 | name: 'Buffer Clearing',
42 | type: 'group',
43 | props: [{
44 | name: 'Auto Clear',
45 | prop: 'autoClear',
46 | type: 'boolean',
47 | default: true,
48 | }, {
49 | name: 'Auto Clear Color',
50 | prop: 'autoClearColor',
51 | type: 'boolean',
52 | default: true,
53 | }, {
54 | name: 'Auto Clear Depth',
55 | prop: 'autoClearDepth',
56 | type: 'boolean',
57 | default: true,
58 | }, {
59 | name: 'Auto Clear Stencil',
60 | prop: 'autoClearStencil',
61 | type: 'boolean',
62 | default: true,
63 | }]
64 | };
65 |
66 |
67 | // Does not have a further classification yet
68 | const Capabilities = {
69 | name: 'Capabilities',
70 | type: 'group',
71 | props: [{
72 | name: 'Is WebGL2',
73 | prop: 'capabilities.isWebGL2',
74 | type: 'boolean',
75 | readonly: true,
76 | }, {
77 | name: 'Precision',
78 | prop: 'capabilities.precision',
79 | type: 'string',
80 | readonly: true,
81 | }, {
82 | name: 'Float Fragment Textures',
83 | prop: 'capabilities.floatFragmentTextures',
84 | type: 'boolean',
85 | readonly: true,
86 | }, {
87 | name: 'Float Vertex Textures',
88 | prop: 'capabilities.floatVertexTextures',
89 | type: 'boolean',
90 | readonly: true,
91 | }, {
92 | name: 'Logarithmic Depth Buffer',
93 | prop: 'capabilities.logarithmicDepthBuffer',
94 | type: 'boolean',
95 | readonly: true,
96 | }, {
97 | name: 'Max Anisotropy',
98 | prop: 'capabilities.maxAnisotropy',
99 | type: 'number',
100 | readonly: true,
101 | }, {
102 | name: 'Max Precision',
103 | prop: 'capabilities.maxPrecision',
104 | type: 'string',
105 | readonly: true,
106 | }, {
107 | name: 'Max Attributes',
108 | prop: 'capabilities.maxAttributes',
109 | type: 'int',
110 | readonly: true,
111 | }, {
112 | name: 'Max Cubemap Size',
113 | prop: 'capabilities.maxCubemapSize',
114 | type: 'int',
115 | readonly: true,
116 | }, {
117 | name: 'Max Fragment Uniforms',
118 | prop: 'capabilities.maxFragmentUniforms',
119 | type: 'int',
120 | readonly: true,
121 | }, {
122 | name: 'Max Texture Size',
123 | prop: 'capabilities.maxTextureSize',
124 | type: 'int',
125 | readonly: true,
126 | }, {
127 | name: 'Max Textures',
128 | prop: 'capabilities.maxTextures',
129 | type: 'int',
130 | readonly: true,
131 | }, {
132 | name: 'Max Varyings',
133 | prop: 'capabilities.maxVaryings',
134 | type: 'int',
135 | readonly: true,
136 | }, {
137 | name: 'Max Vertex Textures',
138 | prop: 'capabilities.maxVertexTextures',
139 | type: 'int',
140 | readonly: true,
141 | }, {
142 | name: 'Max Vertex Uniforms',
143 | prop: 'capabilities.maxVertexUniforms',
144 | type: 'int',
145 | readonly: true,
146 | }, {
147 | name: 'Vertex Textures',
148 | prop: 'capabilities.vertexTextures',
149 | type: 'boolean',
150 | readonly: true,
151 | }]
152 | };
153 |
154 | // @TODO clippingPlanes
155 | const Clipping = {
156 | name: 'Clipping',
157 | type: 'group',
158 | props: [{
159 | name: 'Local Clipping',
160 | prop: 'localClippingEnabled',
161 | type: 'boolean',
162 | default: false,
163 | }],
164 | };
165 |
166 | const Scene = {
167 | name: 'Scene',
168 | type: 'group',
169 | props: [{
170 | name: 'Sort Objects',
171 | prop: 'sortObjects',
172 | type: 'boolean',
173 | default: true,
174 | }],
175 | };
176 |
177 | const MorphLimits = {
178 | name: 'Morph Limits',
179 | type: 'group',
180 | props: [{
181 | name: 'Max Morph Targets',
182 | prop: 'maxMorphTargets',
183 | type: 'int',
184 | default: 8,
185 | min: 0,
186 | max: 8,
187 | }, {
188 | name: 'Max Morph Normals',
189 | prop: 'maxMorphNormals',
190 | type: 'int',
191 | default: 4,
192 | min: 0,
193 | max: 4,
194 | }],
195 | };
196 |
197 | const WebGLRenderer = {
198 | type: 'renderer',
199 | props: [
200 | {
201 | name: 'Check Shader Errors',
202 | prop: 'debug.checkShaderErrors',
203 | type: 'boolean',
204 | default: true,
205 | }, {
206 | name: 'Physically Correct Lights',
207 | prop: 'physicallyCorrectLights',
208 | type: 'boolean',
209 | default: false,
210 | }, {
211 | name: 'Gamma',
212 | prop: 'gammaFactor',
213 | type: 'number',
214 | default: 2,
215 | }, {
216 | name: 'Output Encoding',
217 | prop: 'outputEncoding',
218 | type: 'enum',
219 | enumType: 'encoding',
220 | },
221 | ToneMapping,
222 | ShadowMap,
223 | BufferClearing,
224 | Capabilities,
225 | Clipping,
226 | Scene,
227 | MorphLimits,
228 | ],
229 | };
230 |
231 | export default {
232 | WebGLRenderer: WebGLRenderer,
233 | WebGL1Renderer: WebGLRenderer,
234 | };
235 |
--------------------------------------------------------------------------------
/src/app/data/textures.js:
--------------------------------------------------------------------------------
1 | const Filters = {
2 | name: 'Filters',
3 | type: 'group',
4 | props: [{
5 | name: 'Min Filter',
6 | prop: 'minFilter',
7 | type: 'enum',
8 | }, {
9 | name: 'Mag Filter',
10 | prop: 'magFilter',
11 | type: 'enum',
12 | }]
13 | };
14 |
15 | const Wrapping = object => ({
16 | name: 'Wrapping',
17 | type: 'group',
18 | // wrapR is currently used with DataTexture3D but not serialized,
19 | // let's not display it for now.
20 | props: [{
21 | name: 'Wrap S',
22 | prop: 'wrap[0]',
23 | type: 'enum',
24 | enumType: 'wrapping',
25 | }, {
26 | name: 'Wrap T',
27 | prop: 'wrap[1]',
28 | type: 'enum',
29 | enumType: 'wrapping',
30 | }]
31 | });
32 |
33 | const Transform = {
34 | name: 'Transform',
35 | type: 'group',
36 | props: [{
37 | name: 'Offset',
38 | prop: 'offset',
39 | type: 'vec2',
40 | }, {
41 | name: 'Repeat',
42 | prop: 'repeat',
43 | type: 'vec2',
44 | }, {
45 | name: 'Rotation',
46 | prop: 'rotation',
47 | type: 'radians',
48 | }, {
49 | name: 'Center',
50 | prop: 'center',
51 | type: 'vec2',
52 | }, {
53 | name: 'matrixAutoUpdate',
54 | prop: 'matrixAutoUpdate',
55 | type: 'boolean',
56 | default: true,
57 | }, {
58 | name: 'Matrix',
59 | prop: 'matrix',
60 | type: 'mat3',
61 | }]
62 | };
63 |
64 | const Texture = {
65 | type: 'texture',
66 | props: [{
67 | name: 'Mapping',
68 | prop: 'mapping',
69 | type: 'enum',
70 | }, {
71 | name: 'Encoding',
72 | prop: 'encoding',
73 | type: 'enum',
74 | }, {
75 | name: 'Format',
76 | prop: 'format',
77 | type: 'enum',
78 | }, {
79 | name: 'Byte Type',
80 | prop: 'type',
81 | type: 'enum',
82 | }, {
83 | name: 'Anisotropy',
84 | prop: 'anisotropy',
85 | type: 'number',
86 | min: 0,
87 | }, {
88 | name: 'Flip Y',
89 | prop: 'flipY',
90 | type: 'boolean',
91 | default: true,
92 | }, {
93 | name: 'Generate Mipmaps',
94 | prop: 'generateMipmaps',
95 | type: 'boolean',
96 | default: true,
97 | }, {
98 | name: 'Premultiply Alpha',
99 | prop: 'premultiplyAlpha',
100 | type: 'boolean',
101 | default: false,
102 | },
103 | Filters,
104 | Wrapping,
105 | Transform,
106 | ]
107 | }
108 |
109 | export default {
110 | Texture: Texture,
111 | CanvasTexture: Texture,
112 | CompressedTexture: Texture,
113 | CubeTexture: Texture,
114 | DataTexture: Texture,
115 | DataTexture2DArray: Texture,
116 | DataTexture3D: Texture,
117 | DepthTexture: Texture,
118 | VideoTexture: Texture,
119 | }
120 |
--------------------------------------------------------------------------------
/src/app/elements/ImagePreviewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../../web_modules/lit-element.js'
2 |
3 | const $onActivate = Symbol('onActivate');
4 | const $onLoad = Symbol('onLoad');
5 |
6 | export default class ImagePreviewElement extends LitElement {
7 | static get properties() {
8 | return {
9 | width: { type: Number, reflect: true },
10 | height: { type: Number, reflect: true },
11 | }
12 | }
13 |
14 | constructor() {
15 | super();
16 | this.width = 0;
17 | this.height = 0;
18 | }
19 |
20 | render() {
21 | const image = null;//this.getEntity();
22 |
23 | if (!image) {
24 | return html`None`;
25 | }
26 |
27 | console.log('render imagepreview',image);
28 | return html`
29 |
43 |
44 | ${this.width + ' x ' + this.height}
45 | `;
46 | }
47 |
48 | [$onLoad](e) {
49 | const image = e.composedPath()[0];
50 | this.width = image.naturalWidth;
51 | this.height = image.naturalHeight;
52 | }
53 |
54 | [$onActivate](e) {
55 | this.dispatchEvent(new CustomEvent('select-entity', {
56 | detail: {
57 | uuid: this.uuid,
58 | },
59 | bubbles: true,
60 | composed: true,
61 | }));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/app/elements/ParametersViewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 | import RendererTypes from '../data/renderers.js';
3 | import ObjectTypes from '../data/objects.js';
4 | import LightTypes from '../data/lights.js';
5 | import MaterialTypes from '../data/materials.js';
6 | import GeometryTypes from '../data/geometry.js';
7 | import TextureTypes from '../data/textures.js';
8 | import { getEntityName } from '../utils.js';
9 |
10 | // https://stackoverflow.com/a/6491621
11 | const propByString = function(o, s) {
12 | s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
13 | s = s.replace(/^\./, ''); // strip a leading dot
14 | var a = s.split('.');
15 | for (var i = 0, n = a.length; i < n; ++i) {
16 | var k = a[i];
17 | if (k in o) {
18 | o = o[k];
19 | } else {
20 | return;
21 | }
22 | }
23 | return o;
24 | }
25 |
26 | const $onRefresh = Symbol('onRefresh');
27 | const CommonProps = {
28 | Type: {
29 | name: 'Type',
30 | type: 'string',
31 | prop: 'baseType',
32 | },
33 | UUID: {
34 | name: 'UUID',
35 | type: 'string',
36 | prop: 'uuid',
37 | },
38 | Name: {
39 | name: 'Name',
40 | type: 'string',
41 | prop: 'name',
42 | }
43 | };
44 |
45 | function propsToElements(entity, elements, props, entities) {
46 | for (let prop of props) {
47 | if (typeof prop === 'function') {
48 | const result = prop(entity);
49 | if (result) {
50 | prop = result;
51 | } else {
52 | continue;
53 | }
54 | }
55 |
56 | if (prop.type === 'group') {
57 | const subProps = [];
58 | propsToElements(entity, subProps, [...prop.props]);
59 | elements.push(html`
60 | ${prop.name}
61 | ${subProps}
62 | `);
63 | continue;
64 | } else {
65 | const { name, type, prop: propName, enumType, default: def, readonly } = prop;
66 |
67 | let value = propByString(entity, propName);
68 | if (value === undefined) {
69 | value = def;
70 | }
71 |
72 | // For number/int types
73 | let min = 'min' in prop ? prop.min : -Infinity;
74 | let max = 'max' in prop ? prop.max : Infinity;
75 | let step = 'step' in prop ? prop.step :
76 | type === 'int' ? 1 : 0.01;
77 | let precision = 'precision' in prop ? prop.precision :
78 | type === 'int' ? 0 : 3;
79 |
80 | // For object types (geometry, material, texture)
81 | let associatedData = {};
82 | if (value && entities && ['geometry', 'material', 'texture'].indexOf(prop.type) !== -1) {
83 | associatedData = entities[value] || {};
84 | }
85 |
86 | elements.push(html`
87 |
100 | `);
101 | }
102 | }
103 | }
104 |
105 | export default class ParametersViewElement extends LitElement {
106 | static get properties() {
107 | return {
108 | uuid: { type: String },
109 | // Object with uuids as keys to entity data. Most objects will
110 | // only contain the selected entity's data (matching the uuid),
111 | // however things like Mesh will also contain any associated
112 | // material or geometry, etc.
113 | entities: { type: Object },
114 | }
115 | }
116 |
117 | [$onRefresh](e) {
118 | this.dispatchEvent(new CustomEvent('command', {
119 | detail: {
120 | type: 'refresh',
121 | },
122 | bubbles: true,
123 | composed: true,
124 | }));
125 | }
126 |
127 | render() {
128 | const entityData = (this.entities && this.entities[this.uuid]) || null;
129 | const entityTitle = entityData ? getEntityName(entityData) : '';
130 | const elements = [];
131 |
132 | if (entityData) {
133 | let definition = RendererTypes[entityData.baseType] ||
134 | ObjectTypes[entityData.baseType] ||
135 | LightTypes[entityData.baseType] ||
136 | MaterialTypes[entityData.baseType] ||
137 | GeometryTypes[entityData.baseType] ||
138 | TextureTypes[entityData.baseType];
139 | if (!definition) {
140 | definition = ObjectTypes.Object3D;
141 | }
142 |
143 | const commonProps = entityData.type === 'renderer' ? [CommonProps.Type, CommonProps.Name] :
144 | [CommonProps.Type, CommonProps.UUID, CommonProps.Name];
145 | propsToElements(entityData, elements, [...commonProps, ...definition.props], this.entities);
146 | }
147 |
148 | return html`
149 |
189 |
190 |
191 |
192 |
193 | ${elements}
194 |
195 | `;
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/app/elements/RendererViewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | const $onPoll = Symbol('onPoll');
4 | const RENDERER_POLL_INTERVAL = 1000; // ms
5 |
6 | export default class RendererViewElement extends LitElement {
7 | static get properties() {
8 | return {
9 | rendererId: { type: String, },
10 | renderingInfo: { type: Object, },
11 | enabled: { type: Boolean, reflect: true },
12 | };
13 | }
14 |
15 | constructor() {
16 | super();
17 | this[$onPoll] = this[$onPoll].bind(this);
18 | }
19 |
20 | disconnectedCallback() {
21 | if (this[$onPoll].timer) {
22 | window.clearInterval(this[$onPoll].timer);
23 | }
24 | super.disconnectedCallback();
25 | }
26 |
27 | [$onPoll]() {
28 | if (this.rendererId) {
29 | this.dispatchEvent(new CustomEvent('command', {
30 | detail: {
31 | type: 'request-rendering-info',
32 | uuid: this.rendererId,
33 | },
34 | bubbles: true,
35 | composed: true,
36 | }));
37 | }
38 | }
39 |
40 | shouldUpdate(props) {
41 | if (props.has('enabled')) {
42 | if (this.enabled) {
43 | this[$onPoll].timer = window.setInterval(this[$onPoll], RENDERER_POLL_INTERVAL);
44 | } else {
45 | window.clearInterval(this[$onPoll].timer);
46 | }
47 | }
48 | return true;
49 | }
50 |
51 | render() {
52 | const activeRenderer = this.rendererId;
53 | const hasRenderingInfo = !!this.renderingInfo;
54 |
55 | const info = hasRenderingInfo ? this.renderingInfo.info : {
56 | render: {
57 | frame: 0,
58 | calls: 0,
59 | triangles: 0,
60 | points: 0,
61 | lines: 0,
62 | },
63 | memory: {
64 | geometries: 0,
65 | textures: 0,
66 | },
67 | programs: 0,
68 | };
69 |
70 | return html`
71 |
97 |
98 |
99 | - frame${info.render.frame}
100 | - draw calls${info.render.calls}
101 | - triangles${info.render.triangles}
102 | - points${info.render.points}
103 | - lines${info.render.lines}
104 |
105 |
106 |
107 |
108 |
109 | - geometries${info.memory.geometries || 0}
110 | - textures${info.memory.textures || 0}
111 | - programs${info.programs || 0}
112 |
113 | `;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/app/elements/ResourcesViewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 | import { getEntityName } from '../utils.js';
3 |
4 | const $onTreeItemSelect = Symbol('onTreeItemSelect');
5 | const $onRefreshClick = Symbol('onRefreshClick');
6 |
7 | export default class ResourcesViewElement extends LitElement {
8 | static get properties() {
9 | return {
10 | title: { type: String, reflect: true },
11 | selected: { type: String, reflect: true },
12 | resources: { type: Array },
13 | }
14 | }
15 |
16 | connectedCallback() {
17 | super.connectedCallback();
18 | this.addEventListener('tree-item-select', this[$onTreeItemSelect]);
19 | }
20 |
21 | disconnectedCallback() {
22 | this.removeEventListener('tree-item-select', this[$onTreeItemSelect]);
23 | super.disconnectedCallback();
24 | }
25 |
26 | render() {
27 | const title = this.title;
28 | const resources = this.resources || [];
29 |
30 | let nodes = resources.map((obj, i) => {
31 | let selected = obj.uuid && this.selected && this.selected === obj.uuid;
32 | let name = getEntityName(obj);
33 | return html`
34 |
39 | ${name}
40 |
41 | `;
42 | });
43 |
44 | return html`
45 |
68 |
69 |
70 |
71 |
77 | ${nodes}
78 |
79 |
88 |
89 | `;
90 | }
91 |
92 | updated() {
93 | const selected = this.shadowRoot.querySelector('tree-item[selected]');
94 | if (selected && selected.parentElement) {
95 | selected.parentElement.open = true;
96 | }
97 | }
98 |
99 | [$onRefreshClick](e) {
100 | this.dispatchEvent(new CustomEvent('command', {
101 | detail: {
102 | type: 'refresh',
103 | },
104 | bubbles: true,
105 | composed: true,
106 | }));
107 | }
108 |
109 | [$onTreeItemSelect](e) {
110 | e.stopPropagation();
111 | const treeItem = e.composedPath()[0];
112 | const uuid = treeItem.getAttribute('unique');
113 | this.dispatchEvent(new CustomEvent('command', {
114 | detail: {
115 | type: 'select-entity',
116 | uuid,
117 | },
118 | bubbles: true,
119 | composed: true,
120 | }));
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/app/elements/SceneViewElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 | import { getEntityName } from '../utils.js';
3 | import ChromeSelectStyle from './shared-styles/chrome-select.js';
4 |
5 | const $createSceneGraphNode = Symbol('createSceneGraphNode');
6 | const $onRefreshClick = Symbol('onRefreshClick');
7 | const $onSceneSelect = Symbol('onSceneSelect');
8 | const $onContentUpdate = Symbol('onContentUpdate');
9 | const $onTreeItemSelect = Symbol('onTreeItemSelect');
10 |
11 | export default class SceneViewElement extends LitElement {
12 | static get properties() {
13 | return {
14 | graph: { type: Object},
15 | scenes: { type: Array },
16 | activeScene: { type: String, },
17 | activeEntity: { type: String, },
18 | }
19 | }
20 |
21 | constructor() {
22 | super();
23 | this[$onRefreshClick] = this[$onRefreshClick].bind(this);
24 | this[$onTreeItemSelect] = this[$onTreeItemSelect].bind(this);
25 | this[$onContentUpdate] = this[$onContentUpdate].bind(this);
26 | }
27 |
28 | connectedCallback() {
29 | super.connectedCallback();
30 | this.addEventListener('tree-item-select', this[$onTreeItemSelect]);
31 | }
32 |
33 | disconnectedCallback() {
34 | super.disconnectedCallback();
35 | this.removeEventListener('tree-item-select', this[$onTreeItemSelect]);
36 | }
37 |
38 | render() {
39 | const { activeScene, activeEntity, scenes, graph } = this;
40 |
41 | if (!scenes) {
42 | return html``;
43 | }
44 |
45 | let sceneGraphNode;
46 | if (graph && activeScene) {
47 | sceneGraphNode = this[$createSceneGraphNode](graph, activeScene, activeEntity);
48 | }
49 |
50 | return html`
51 |
72 |
73 |
76 |
77 |
78 | ${sceneGraphNode}
79 | `;
80 | }
81 |
82 | [$createSceneGraphNode](graph, uuid, selected, depth=0) {
83 | const obj = graph[uuid];
84 |
85 | return html`
86 | 0}"
93 | depth="${depth}"
94 | uuid="${obj.uuid}"
95 | >
96 | ${getEntityName(obj)}
97 | ${obj.children.map(uuid => this[$createSceneGraphNode](graph, uuid, selected, depth + 1))}
98 |
99 | `;
100 | }
101 |
102 |
103 | [$onRefreshClick](e) {
104 | if (this.activeScene) {
105 | this.dispatchEvent(new CustomEvent('command', {
106 | detail: {
107 | type: 'refresh',
108 | },
109 | bubbles: true,
110 | composed: true,
111 | }));
112 | }
113 | }
114 |
115 | [$onSceneSelect](e) {
116 | this.dispatchEvent(new CustomEvent('command', {
117 | detail: {
118 | type: 'select-scene',
119 | uuid: e.target.value,
120 | },
121 | bubbles: true,
122 | composed: true,
123 | }));
124 | }
125 |
126 | [$onContentUpdate](e) {
127 | if (this.app.content.getEntityCategory(e.detail.uuid) === 'scene') {
128 | // Maybe the selector should be pulled into its own component,
129 | // this is a bit messy.
130 | this.requestUpdate();
131 | }
132 | }
133 |
134 | [$onTreeItemSelect](e) {
135 | e.stopPropagation();
136 | const treeItem = e.composedPath()[0];
137 | const uuid = treeItem.getAttribute('uuid');
138 | this.dispatchEvent(new CustomEvent('command', {
139 | detail: {
140 | type: 'select-entity',
141 | uuid,
142 | },
143 | bubbles: true,
144 | composed: true,
145 | }));
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/app/elements/TabBarElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | export default class TitleBarElement extends LitElement {
4 |
5 | static get properties() {
6 | return {
7 | }
8 | }
9 |
10 | render() {
11 |
12 | return html`
13 |
43 |
44 | `;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/app/elements/TitleBarElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../web_modules/lit-element.js'
2 |
3 | export default class TitleBarElement extends LitElement {
4 |
5 | static get properties() {
6 | return {
7 | title: {type: String, reflect: true}
8 | }
9 | }
10 |
11 | render() {
12 |
13 | return html`
14 |
46 |
47 | ${this.title}
48 |
49 |
50 | `;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/app/elements/shared-styles/chrome-select.js:
--------------------------------------------------------------------------------
1 | export default `
2 | /*
3 | * Styling taken from css/inspectorCommon.css from chrome devtools
4 | */
5 | select {
6 | /* Form elements do not automatically inherit font style from ancestors. */
7 | font-family: inherit;
8 | font-size: inherit;
9 | }
10 |
11 | .chrome-select {
12 | -webkit-appearance: none;
13 | -webkit-user-select: none;
14 | border: 1px solid rgba(0, 0, 0, 0.2);
15 | border-radius: 2px;
16 | color: #333;
17 | font: inherit;
18 | margin: 0;
19 | outline: none;
20 | padding-right: 20px;
21 | padding-left: 6px;
22 | background-image: -webkit-image-set(url('assets/chromeSelect.png') 1x, url('assets/chromeSelect_2x.png') 2x);
23 | background-color: hsl(0, 0%, 98%);
24 | background-position: right center;
25 | background-repeat: no-repeat;
26 | min-height: 24px;
27 | min-width: 16px;
28 | background-size: 15px;
29 | }
30 |
31 | .chrome-select:enabled:active,
32 | .chrome-select:enabled:focus,
33 | .chrome-select:enabled:hover {
34 | background-color: hsl(0, 0%, 96%);
35 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
36 | }
37 |
38 | .chrome-select:enabled:active {
39 | background-color: #f2f2f2;
40 | }
41 |
42 | .chrome-select:enabled:focus {
43 | border-color: transparent;
44 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(66, 133, 244, 0.4);
45 | }
46 |
47 | .chrome-select:disabled {
48 | opacity: 0.38;
49 | }
50 |
51 | .chrome-select optgroup,
52 | .chrome-select option {
53 | background-color: #EEEEEE;
54 | color: #222;
55 | }
56 | `;
57 |
--------------------------------------------------------------------------------
/src/app/elements/values/EnumValueElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../../web_modules/lit-element.js'
2 | import { ConstantTypes } from '../../constants.js';
3 | import * as constants from '../../../../web_modules/three/src/constants.js';
4 | import ChromeSelectStyle from '../shared-styles/chrome-select.js';
5 |
6 | const $onInput = Symbol('onInput');
7 |
8 | export default class EnumValueElement extends LitElement {
9 | static get properties() {
10 | return {
11 | uuid: { type: String, reflect: true },
12 | // Type of enum, e.g. "drawMode", "side", "blendMode"
13 | type: { type: String, reflect: true },
14 | // Numerical value of enum.
15 | value: { type: String, reflect: true },
16 | }
17 | }
18 |
19 | constructor() {
20 | super();
21 | this[$onInput] = this[$onInput].bind(this);
22 | }
23 |
24 | render() {
25 |
26 | if (!ConstantTypes[this.type]) {
27 | return html``;
28 | }
29 |
30 | const options = ConstantTypes[this.type].map((c,i) => {
31 | let value = constants[c];
32 |
33 | // Let 'null' be a special enum that is -1
34 | if (c === 'null') {
35 | value = -1;
36 | }
37 |
38 | if (typeof value !== 'number') {
39 | throw new Error(`invalid constant value for ${c}`);
40 | }
41 | const selected = this.value === undefined ? i === 0 : this.value === value;
42 | return html``;
43 | });
44 |
45 | return html`
46 |
53 |
54 | `;
55 | }
56 |
57 | [$onInput](e) {
58 | const selected = [...e.target.querySelectorAll('option')].filter(o => o.selected)[0];
59 | const value = +selected.value;
60 |
61 | if (value !== null) {
62 | this.dispatchEvent(new CustomEvent('change', {
63 | detail: {
64 | value,
65 | },
66 | bubbles: true,
67 | composed: true,
68 | }));
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/app/elements/values/KeyValueElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../../web_modules/lit-element.js'
2 | import { getEntityName, cssStringToHexNumber, hexNumberToCSSString } from '../../utils.js';
3 |
4 | const $onChange = Symbol('onChange');
5 | const $onDependencyClick = Symbol('onDependencyClick');
6 | const anchor = document.createElement('a');
7 | let kvIterator = 0;
8 |
9 | export default class KeyValueElement extends LitElement {
10 | static get properties() {
11 | return {
12 | uuid: { type: String, reflect: true },
13 | // @TODO probably should use less generic/collision-y
14 | // attribute names.
15 | keyName: { type: String, reflect: true, attribute: 'key-name'},
16 | value: { type: String, reflect: true },
17 | type: { type: String, reflect: true },
18 | enumType: { type: String, reflect: true, attribute: 'enum-type' },
19 | property: { type: String, reflect: true },
20 | readonly: { type: Boolean },
21 | // For number types only
22 | min: { type: Number, reflect: true },
23 | max: { type: Number, reflect: true },
24 | step: { type: Number, reflect: true },
25 | precision: { type: Number, reflect: true },
26 | // Optional data for data types (material, geometry)
27 | data: { type: Object },
28 | }
29 | }
30 |
31 | constructor() {
32 | super();
33 | // Currently no way to handle a true label/input match
34 | // across shadow boundaries? Can this be handled better?
35 | // https://github.com/whatwg/html/issues/3219
36 | this._id = `key-value-element-${kvIterator++}`;
37 | this.precision = 1;
38 | this.step = 1;
39 | this.min = -Infinity;
40 | this.max = Infinity;
41 | }
42 |
43 | onDataURLClick(e) {
44 | try {
45 | let stringified = JSON.stringify(this.value, null, 2);
46 | let blob = new Blob([stringified], { type: 'application/json' });
47 | let url = window.URL.createObjectURL(blob);
48 | anchor.setAttribute('href', url);
49 | anchor.setAttribute('target', '_window');
50 | anchor.click();
51 | // Clean it up immediately so we're not storing
52 | // large buffers for the lifetime of the tools
53 | window.URL.revokeObjectURL(url);
54 | } catch (e) {
55 | }
56 | e.preventDefault();
57 | }
58 |
59 | render() {
60 |
61 | let valueElement;
62 |
63 | if (this.value == null) {
64 | valueElement = html``;
65 | } else if (this.readonly) {
66 | valueElement = this.value;
67 | } else {
68 | switch (this.type) {
69 | case 'array':
70 | if (this.value) {
71 | valueElement = html`
72 | this.onDataURLClick(e)}>
73 | array
74 | `;
75 | }
76 | else {
77 | valueElement = html`[]`;
78 | }
79 | break;
80 | case 'enum':
81 | let enumType = this.enumType || this.property;
82 | valueElement = html``;
83 | break;
84 | case 'vec2':
85 | case 'vec3':
86 | case 'vec4':
87 | const arity = this.type === 'vec2' ? 2 :
88 | this.type === 'vec3' ? 3 : 4;
89 | valueElement = [...new Array(arity)].map((_, i) => html``);
98 | break;
99 | case 'image':
100 | case 'texture':
101 | case 'material':
102 | case 'geometry':
103 | if (this.data) {
104 | const name = getEntityName(this.data);
105 | valueElement = html`${name}
`;
106 | }
107 | break;
108 | case 'color':
109 | valueElement = html``;
110 | break;
111 | case 'boolean':
112 | valueElement = html``;
113 | break;
114 | case 'number':
115 | case 'int':
116 | case 'angle':
117 | valueElement = html``;
125 | break;
126 | case 'string':
127 | valueElement = this.value;
128 | break;
129 | default:
130 | valueElement = this.value;
131 | }
132 | }
133 |
134 | return html`
135 |
182 |
183 |
184 | ${valueElement}
185 |
186 | `;
187 | }
188 |
189 | [$onDependencyClick](e) {
190 | const target = e.composedPath()[0];
191 | const uuid = target.getAttribute('data-uuid');
192 | if (uuid !== null) {
193 | this.dispatchEvent(new CustomEvent('command', { detail: {
194 | type: 'select-entity',
195 | uuid,
196 | },
197 | bubbles: true,
198 | composed: true,
199 | }));
200 | }
201 | }
202 |
203 | [$onChange](e) {
204 |
205 | const target = e.composedPath()[0];
206 |
207 | let value = null;
208 | let dataType = null;
209 | let property = this.property;
210 | switch (this.type) {
211 | case 'color':
212 | value = target.value ? cssStringToHexNumber(target.value) : 0;
213 | dataType = 'color';
214 | break;
215 | case 'boolean':
216 | value = !!target.checked;
217 | dataType = 'boolean';
218 | break;
219 | case 'number':
220 | case 'radians':
221 | dataType = 'number';
222 | value = target.value;
223 | break;
224 | case 'enum':
225 | dataType = 'number';
226 | value = e.detail.value;
227 | break;
228 | case 'vec2':
229 | case 'vec3':
230 | case 'vec4':
231 | dataType = this.type;
232 | value = e.detail.value;
233 | // Add 'x', 'y', 'z', 'w' to the property name
234 | property = `${this.property}.${target.getAttribute('axis')}`;
235 | break;
236 | default:
237 | value = target.value;
238 | }
239 |
240 | if (value !== null) {
241 | this.dispatchEvent(new CustomEvent('command', { detail: {
242 | type: 'update-property',
243 | uuid: this.uuid,
244 | property,
245 | dataType,
246 | value,
247 | },
248 | bubbles: true,
249 | composed: true,
250 | }));
251 | }
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/src/app/elements/values/MaterialValueElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../../web_modules/lit-element.js'
2 | import { hexNumberToCSSString } from '../../utils.js';
3 |
4 | const $onActivate = Symbol('onActivate');
5 |
6 | export default class MaterialValueElement extends LitElement {
7 | static get properties() {
8 | return {
9 |
10 | }
11 | }
12 |
13 | render() {
14 | const material = null;
15 |
16 | if (!material) {
17 | return null;
18 | }
19 |
20 | const color = material.color ? hexNumberToCSSString(material.color) : 'white';
21 | return html`
22 |
48 |
49 |
50 |
${material.type}
51 |
52 | `;
53 | }
54 |
55 | [$onActivate](e) {
56 | this.app.dispatchEvent(new CustomEvent('select-entity', { detail: {
57 | uuid: this.uuid,
58 | }}));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/app/elements/values/TextureValueElement.js:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from '../../../../web_modules/lit-element.js'
2 | import { getEntityName } from '../../utils.js';
3 |
4 | const $onActivate = Symbol('onActivate');
5 |
6 | export default class TextureValueElement extends LitElement {
7 |
8 | static get properties() {
9 | return {
10 | }
11 | }
12 |
13 | render() {
14 | const texture = null;
15 |
16 | if (!texture) {
17 | return null;
18 | }
19 |
20 | const name = getEntityName(texture);
21 | return html`
22 |
48 |
52 | `;
53 | }
54 |
55 | [$onActivate](e) {
56 | this.app.dispatchEvent(new CustomEvent('select-entity', { detail: {
57 | uuid: this.uuid,
58 | }}));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/app/fonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/src/app/fonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/src/app/fonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/src/app/fonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/src/app/fonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/src/app/fonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/src/app/fonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/src/app/fonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/threejs/three-devtools/f2129475a34d32637cdc8aacea462a1fa40e5d30/src/app/fonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/src/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/app/index.js:
--------------------------------------------------------------------------------
1 | import browser from '../../web_modules/webextension-polyfill/dist/browser-polyfill.js';
2 | import getAgent from '../../web_modules/@egjs/agent.js';
3 | import AppElement from './elements/AppElement.js';
4 |
5 | import RendererViewElement from './elements/RendererViewElement.js';
6 | import SceneViewElement from './elements/SceneViewElement.js';
7 | import ResourcesViewElement from './elements/ResourcesViewElement.js';
8 | import ParametersViewElement from './elements/ParametersViewElement.js';
9 |
10 | import TitleBarElement from './elements/TitleBarElement.js';
11 |
12 | import ImagePreviewElement from './elements/ImagePreviewElement.js';
13 | import KeyValueElement from './elements/values/KeyValueElement.js';
14 | import MaterialValueElement from './elements/values/MaterialValueElement.js';
15 | import TextureValueElement from './elements/values/TextureValueElement.js';
16 | import EnumValueElement from './elements/values/EnumValueElement.js';
17 | import TabBarElement from './elements/TabBarElement.js';
18 |
19 | import NumberInputElement from './common-elements/NumberInputElement.js';
20 | import TreeItemElement from './common-elements/TreeItemElement.js';
21 | import AccordionViewElement from './common-elements/AccordionViewElement.js';
22 | import DevtoolsMessageElement from './common-elements/DevtoolsMessageElement.js';
23 | import DevtoolsIconElement from './common-elements/DevtoolsIconElement.js';
24 | import DevtoolsButtonElement from './common-elements/DevtoolsButtonElement.js';
25 | import DevtoolsIconButtonElement from './common-elements/DevtoolsIconButtonElement.js';
26 | import IconElement from './common-elements/IconElement.js';
27 |
28 | //////
29 | globalThis.browser = browser;
30 |
31 | window.customElements.define('three-devtools-app', AppElement);
32 |
33 | window.customElements.define('renderer-view', RendererViewElement);
34 | window.customElements.define('scene-view', SceneViewElement);
35 | window.customElements.define('resources-view', ResourcesViewElement);
36 | window.customElements.define('parameters-view', ParametersViewElement);
37 |
38 | window.customElements.define('title-bar', TitleBarElement);
39 |
40 | window.customElements.define('image-preview', ImagePreviewElement);
41 | window.customElements.define('key-value', KeyValueElement);
42 | window.customElements.define('material-value', MaterialValueElement);
43 | window.customElements.define('texture-value', TextureValueElement);
44 | window.customElements.define('enum-value', EnumValueElement);
45 | window.customElements.define('tab-bar', TabBarElement);
46 |
47 | window.customElements.define('number-input', NumberInputElement);
48 | window.customElements.define('tree-item', TreeItemElement);
49 | window.customElements.define('accordion-view', AccordionViewElement);
50 | window.customElements.define('devtools-message', DevtoolsMessageElement);
51 | window.customElements.define('devtools-icon', DevtoolsIconElement);
52 | window.customElements.define('devtools-button', DevtoolsButtonElement);
53 | window.customElements.define('devtools-icon-button', DevtoolsIconButtonElement);
54 | window.customElements.define('x-icon', IconElement);
55 |
56 | function changeTheme(themeName) {
57 | // chrome "default" = firefox "light"
58 | if (themeName === 'default' || themeName === 'light') {
59 | document.documentElement.classList.remove('-theme-with-dark-background');
60 | // assume dark theme for anything else (including third-party themes)
61 | } else {
62 | document.documentElement.classList.add('-theme-with-dark-background');
63 | }
64 | }
65 |
66 | // firefox devtools are not reloaded when the theme is changed
67 | // so we have to add a listener for it
68 | if (browser.devtools.panels.onThemeChanged) {
69 | browser.devtools.panels.onThemeChanged.addListener(changeTheme);
70 | }
71 |
72 | // match browser devtools theme setting
73 | changeTheme(browser.devtools.panels.themeName);
74 |
75 | const agent = getAgent(window.navigator.userAgent);
76 | console.log('Parsed agent:', agent);
77 | if (agent.os.name === 'window') {
78 | document.body.classList.add('platform-windows');
79 | } else if (agent.os.name === 'mac') {
80 | document.body.classList.add('platform-mac');
81 | } else if (agent.os.name === 'unknown') {
82 | document.body.classList.add('platform-linux');
83 | }
84 |
85 | window.addEventListener('error', e => {
86 | document.querySelector('three-devtools-app').setError(e.message);
87 | });
88 |
--------------------------------------------------------------------------------
/src/app/injection.js:
--------------------------------------------------------------------------------
1 | import browser from '../../web_modules/webextension-polyfill/dist/browser-polyfill.js';
2 | import utils from '../content/utils.js';
3 | import TransformControls from '../content/TransformControls.js';
4 | import EntityCache from '../content/EntityCache.js';
5 | import ThreeDevTools from '../content/ThreeDevTools.js';
6 | import DevToolsScene from '../content/DevToolsScene.js';
7 | import InstrumentedToJSON from '../content/toJSON.js';
8 | import THREE from '../content/three.js';
9 |
10 | const version = browser.runtime.getManifest().version;
11 | const red = 'rgb(255, 137, 137)';
12 | const green = 'rgb(190, 251, 125)'
13 | const blue = 'rgb(120, 250, 228)';
14 |
15 | export default `
16 |
17 | console.log('%c▲%cthree-devtools%cv${version}',
18 | 'font-size:150%; color:${green}; text-shadow: -10px 0px ${red}, 10px 0px ${blue}; padding: 0 15px 0 10px;',
19 | 'font-size: 110%; background-color: #666; color:white; padding: 0 5px;',
20 | 'font-size: 110%; background-color: ${blue}; color:#666; padding: 0 5px;');
21 | (() => {
22 |
23 | const DEBUG = false;
24 | const utils = (${utils})();
25 | const THREE = (${THREE})();
26 | const InstrumentedToJSON = (${InstrumentedToJSON})();
27 | (${TransformControls})(THREE);
28 | const DevToolsScene = (${DevToolsScene})(THREE);
29 | const EntityCache = (${EntityCache})();
30 | const devtools = new (${ThreeDevTools})(window.__THREE_DEVTOOLS__);
31 |
32 | window.__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('devtools-ready'));
33 | })();
34 |
35 | `;
36 |
--------------------------------------------------------------------------------
/src/app/styles/app.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --title-color: var(--tab-selected-fg-color);
3 | --title-background-color: var(--tab-selected-bg-color);
4 | --title-border-color: var(--divider-color);
5 | --view-border-color: var(--divider-color);
6 |
7 | --tree-item-hover-color: inherit;
8 | --tree-item-hover-background-color: rgba(56, 121, 217, 0.1);
9 | --tree-item-selected-color: var(--selection-fg-color);
10 | --tree-item-selected-background-color: var(--selection-bg-color);
11 | --tree-item-hover-selected-color: var(--selection-fg-color);
12 | --tree-item-hover-selected-background-color: var(--selection-bg-color);
13 | --tree-item-indent-per-level: 10px;
14 | --tree-item-row-height: 20px;
15 | --tree-item-border-color: var(--divider-color);
16 | --key-value-height: 30px;
17 | --key-value-divider-position: 40%;
18 | }
19 |
20 | body {
21 | margin: 0;
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/styles/devtools.css:
--------------------------------------------------------------------------------
1 | /**
2 | * These are mostly pulled from devtools source code
3 | */
4 |
5 | :root {
6 | --accent-color: #1a73e8;
7 | --accent-fg-color: #1a73e8;
8 | --accent-color-hover: #3b86e8;
9 | --focus-bg-color: hsl(214, 40%, 92%);
10 | --toolbar-bg-color: #f3f3f3;
11 | --toolbar-hover-bg-color: #eaeaea;
12 | --selection-fg-color: white;
13 | --selection-inactive-fg-color: #5a5a5a;
14 | --selection-inactive-bg-color: #dadada;
15 | --tab-selected-fg-color: #333;
16 | --tab-selected-bg-color: var(--toolbar-bg-color);
17 | --drop-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05),
18 | 0 2px 4px rgba(0, 0, 0, 0.2),
19 | 0 2px 6px rgba(0, 0, 0, 0.1);
20 | --divider-color: #d0d0d0;
21 | --focus-ring-inactive-shadow: 0 0 0 1px #e0e0e0;
22 | --editor-selection-bg-color: #cfe8fc;
23 | --editor-selection-inactive-bg-color: #e0e0e0;
24 | }
25 |
26 | .-theme-with-dark-background {
27 | --accent-color: #0e639c;
28 | --accent-fg-color: #cccccc;
29 | --accent-color-hover: rgb(17, 119, 187);
30 | --focus-bg-color: hsl(214, 19%, 27%);
31 | --toolbar-bg-color: #333333;
32 | --toolbar-hover-bg-color: #202020;
33 | --selection-fg-color: #cdcdcd;
34 | --selection-inactive-fg-color: #cdcdcd;
35 | --selection-inactive-bg-color: hsl(0, 0%, 28%);
36 | --tab-selected-fg-color: #eaeaea;
37 | --tab-selected-bg-color: var(--toolbar-bg-color);
38 | --drop-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2),
39 | 0 2px 4px 2px rgba(0, 0, 0, 0.2),
40 | 0 2px 6px 2px rgba(0, 0, 0, 0.1);
41 | --divider-color: #525252;
42 | --focus-ring-inactive-shadow: 0 0 0 1px #5a5a5a;
43 | --editor-selection-bg-color: hsl(207, 88%, 22%);
44 | --editor-selection-inactive-bg-color: #454545;
45 | }
46 |
47 | :root {
48 | --focus-ring-active-shadow: 0 0 0 1px var(--accent-color);
49 | --selection-bg-color: var(--accent-color);
50 | --divider-border: 1px solid var(--divider-color);
51 | }
52 |
53 |
54 | body {
55 | height: 100%;
56 | width: 100%;
57 | position: relative;
58 | overflow: hidden;
59 | margin: 0;
60 | cursor: default;
61 | font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;
62 | font-size: 12px;
63 | tab-size: 4;
64 | -webkit-user-select: none;
65 | color: #222;
66 | background: white;
67 | }
68 |
69 | html.-theme-with-dark-background > body {
70 | color: #d5d5d5;
71 | background: #242424;
72 | }
73 |
74 | .platform-linux {
75 | color: rgb(48, 57, 66);
76 | font-family: Roboto, Ubuntu, Arial, sans-serif;
77 | }
78 |
79 | .platform-mac {
80 | color: rgb(48, 57, 66);
81 | font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;
82 | }
83 |
84 | .platform-windows {
85 | font-family: 'Segoe UI', Tahoma, sans-serif;
86 | }
87 |
--------------------------------------------------------------------------------
/src/app/utils.js:
--------------------------------------------------------------------------------
1 |
2 | const uuidRegex = /^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}$/
3 | export const isUUID = str => {
4 | return typeof str === 'string' && uuidRegex.test(str);
5 | };
6 |
7 | export const getEntityName = entity => {
8 | return entity.name || entity.baseType;
9 | };
10 |
11 | // These color conversions should be way more robust..
12 | // @TODO use THREE.Color
13 | export const hexNumberToCSSString = hex =>
14 | `#${("000000" + (hex).toString(16)).slice(-6)}`;
15 |
16 | export const cssStringToHexNumber = string => +`0x${string.substr(1)}`;
17 |
18 | /**
19 | * Operates on a serialized THREE object,
20 | * recursively searching through the objects for a
21 | * matching UUID.
22 | */
23 | export const getObjectByUUID = (obj, uuid) => {
24 | if (obj.uuid === uuid) {
25 | return obj;
26 | } else if (obj.children && obj.children.length) {
27 | for (let child of obj.children) {
28 | let result = getObjectByUUID(child, uuid);
29 | if (result) {
30 | return result;
31 | }
32 | }
33 | } else {
34 | return null;
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/src/content/DevToolsScene.js:
--------------------------------------------------------------------------------
1 | export default (THREE) => {
2 |
3 | /**
4 | * `THREE` in this context is the devtools own version of three
5 | * injected into this scope only.
6 | */
7 | return class DevToolsScene extends THREE.Scene {
8 | constructor(target, domElement, camera) {
9 | super();
10 | this.onSelectedObjectRemove = this.onSelectedObjectRemove.bind(this);
11 | this.name = 'DevToolsScene';
12 | this.bbHelper = new THREE.BoxHelper();
13 | window.bbHelper = this.bbHelper;
14 | this.bbHelper.material.depthWrite = false;
15 | this.bbHelper.material.depthTest = false;
16 | this.bbHelper.visible = false;
17 | this.add(this.bbHelper);
18 |
19 | this.target = target;
20 | this.camera = camera;
21 | this.domElement = domElement;
22 | this.transformControls = new THREE.TransformControls(camera, domElement);
23 | this.transformControls.space = 'local';
24 | this.add(this.transformControls);
25 |
26 | utils.hideObjectFromTools(this);
27 | utils.hideObjectFromTools(this.bbHelper);
28 | utils.hideObjectFromTools(this.transformControls);
29 |
30 | this.transformControls.addEventListener('change', e => {
31 | // Fire an event to __THREE_DEVTOOLS__ so that content
32 | // can handle lazy rendering, indicating a rerender is necessary.
33 | this.target.dispatchEvent(new CustomEvent('visualization-change'));
34 | });
35 |
36 | this.transformControls.addEventListener('dragging-changed', e => {
37 | this.target.dispatchEvent(new CustomEvent('interaction-change', {
38 | detail: {
39 | active: e.value,
40 | },
41 | }));
42 | });
43 | }
44 |
45 | setTransformMode(mode) {
46 | if (mode && this.transformControls.mode !== mode) {
47 | this.transformControls.mode = mode;
48 | }
49 | }
50 |
51 | toggleTransformSpace() {
52 | const space = this.transformControls.space;
53 | this.transformControls.space = space === 'world' ? 'local' : 'world';
54 | }
55 |
56 | setCamera(camera) {
57 | this.camera = camera;
58 | this.transformControls.camera = camera;
59 | }
60 |
61 | selectObject(object) {
62 | if (this.selectedObject) {
63 | this.selectedObject.removeEventListener('removed', this.onSelectedObjectRemove);
64 | this.transformControls.detach();
65 | }
66 |
67 | this.selectedObject = object;
68 | this.bbHelper.visible = false;
69 |
70 | if (object && object.isObject3D && !object.isScene) {
71 | this.transformControls.attach(object);
72 | object.addEventListener('removed', this.onSelectedObjectRemove);
73 | }
74 |
75 | if (object) {
76 | const currentBBVersion = this.bbHelper.geometry.attributes.position.version;
77 | this.bbHelper.setFromObject(object);
78 | // Only way to determine if the object's bounding box is empty
79 | // or not without recomputing
80 | if (currentBBVersion !== this.bbHelper.geometry.attributes.position.version) {
81 | this.bbHelper.visible = true;
82 | }
83 | }
84 |
85 | this.target.dispatchEvent(new CustomEvent('visualization-change'));
86 | }
87 |
88 | onBeforeRender() {
89 | if (this.bbHelper.visible) {
90 | this.bbHelper.update();
91 | }
92 | }
93 |
94 | onSelectedObjectRemove() {
95 | this.selectObject(null);
96 | }
97 | }
98 | };
99 |
--------------------------------------------------------------------------------
/src/content/ThreeDevTools.js:
--------------------------------------------------------------------------------
1 | export default (() => {
2 |
3 | /**
4 | * Supported events:
5 | *
6 | * `scene`
7 | * `renderer`
8 | */
9 | return class ThreeDevTools {
10 | constructor(target) {
11 | this.USE_RENDER_OVERLAY = false;
12 | this.target = target;
13 | this.scenes = new Set();
14 | this.renderers = new Set();
15 |
16 | this.entityCache = new EntityCache();
17 | this.entitiesRecentlyObserved = new Set();
18 |
19 | this.devtoolsScene = null;
20 |
21 | this.selected = window.$t = null;
22 |
23 | // These events are dispatched by the extension, or
24 | // by the three.js library itself. Content could
25 | // also listen to these events and respond accordingly.
26 | this.target.addEventListener('observe', e => this.observe(e.detail));
27 | this.target.addEventListener('register', e => this.register(e.detail && e.detail.revision));
28 | this.target.addEventListener('select', e => this.select(e.detail && e.detail.uuid));
29 | // @TODO "update" is too general -- maybe something like "set-property"?
30 | this.target.addEventListener('entity-update', e => this.update(e.detail));
31 | window.ctor = this.target.constructor;
32 |
33 | // Underscored events are intended to be private.
34 | this.target.addEventListener('_request-rendering-info', e => this.requestRenderingInfo(e.detail && e.detail.uuid));
35 | this.target.addEventListener('_request-entity', e => this.requestEntity(e.detail && e.detail.uuid));
36 | this.target.addEventListener('_request-overview', e => this.requestOverview(e.detail && e.detail.type));
37 | this.target.addEventListener('_request-scene-graph', e => this.requestSceneGraph(e.detail && e.detail.uuid));
38 | this.target.addEventListener('_transform-controls-update', e => {
39 | if (this.devtoolsScene) {
40 | const { space, mode } = e.detail;
41 | // Space isn't a string, just a truthy value will trigger a toggle
42 | if (space) {
43 | this.devtoolsScene.toggleTransformSpace(space);
44 | }
45 | if (mode) {
46 | this.devtoolsScene.setTransformMode(mode);
47 | }
48 | }
49 | });
50 |
51 | // The 'visualization-change' event is fired by DevToolsScene, indicating
52 | // something has changed and if not rendering on a RAF loop, a render
53 | // is necessary to render the devtools content.
54 | // Noted here as documentation.
55 | // this.target.addEventListener('visualization-change', () => {});
56 |
57 | document.addEventListener('keydown', e => {
58 | if (!this.devtoolsScene) {
59 | return;
60 | }
61 | switch (e.key) {
62 | case 'q': this.devtoolsScene.toggleTransformSpace(); break;
63 | case 'w': this.devtoolsScene.setTransformMode('translate'); break;
64 | case 'e': this.devtoolsScene.setTransformMode('rotate'); break;
65 | case 'r': this.devtoolsScene.setTransformMode('scale'); break;
66 | }
67 | }, { passive: true })
68 |
69 | }
70 |
71 | /**
72 | * API for extension, should not be called by content
73 | */
74 |
75 | /**
76 | * This is the active object in the devtools viewer.
77 | */
78 | select(uuid) {
79 | this.log('select', uuid);
80 | const selected = this.entityCache.getEntity(uuid);
81 |
82 | if (selected) {
83 | if (this.devtoolsScene) {
84 | this.devtoolsScene.selectObject(selected);
85 | }
86 | this.selected = window.$t = selected;
87 | }
88 | }
89 |
90 | update({ uuid, property, value, dataType }) {
91 | this.log('update', uuid, property, value, dataType);
92 | const entity = this.entityCache.getEntity(uuid);
93 |
94 | if (!entity) {
95 | return;
96 | }
97 |
98 | const { target, key } = utils.getTargetAndKey(entity, property);
99 |
100 | if (dataType === 'color') {
101 | if (target[key] && target[key].isColor) {
102 | target[key].setHex(value);
103 | } else {
104 | // Use our own loaded version of THREE; using just
105 | // as a color data type, it shouldn't have any conflicts.
106 | target[key] = new Color((value >> 16 & 255) / 255,
107 | (value >> 8 & 255) / 255,
108 | (value & 255) / 255);
109 | }
110 | }
111 | else if (dataType === 'enum') {
112 | target[key] = value === -1 ? null : value;
113 | }
114 | else {
115 | target[key] = value;
116 | }
117 | }
118 |
119 | register(revision) {
120 | this.log('register', arguments[0]);
121 | this.send('register', {
122 | revision,
123 | });
124 | }
125 |
126 | requestSceneGraph(uuid) {
127 | this.log('requestSceneGraph', uuid);
128 | try {
129 | const data = this.entityCache.getSceneGraph(uuid);
130 | this.send('scene-graph', {
131 | uuid,
132 | graph: data,
133 | });
134 | } catch (e) {
135 | // Why must this be wrapped in a try/catch
136 | // to report errors? Where's the async??
137 | console.error(e);
138 | }
139 | }
140 |
141 | requestOverview(type) {
142 | this.log('requestOverview', type);
143 | try {
144 | const data = this.entityCache.getOverview(type);
145 | this.send('overview', {
146 | type,
147 | entities: data,
148 | });
149 | } catch (e) {
150 | // Why must this be wrapped in a try/catch
151 | // to report errors? Where's the async??
152 | console.error(e);
153 | }
154 | }
155 |
156 | requestEntity(uuid) {
157 | this.log('requestEntity', uuid);
158 | try {
159 | let data = this.entityCache.getSerializedEntity(uuid);
160 | if (data) {
161 | this.send('entity', data);
162 | }
163 | } catch (e) {
164 | // Why must this be wrapped in a try/catch
165 | // to report errors? Where's the async??
166 | console.error(e);
167 | }
168 | }
169 |
170 | requestRenderingInfo(uuid) {
171 | this.log('requestRenderingInfo', uuid);
172 | let data = this.entityCache.getRenderingInfo(uuid);
173 | if (data) {
174 | this.send('rendering-info', data);
175 | }
176 | }
177 |
178 | observe(entity) {
179 | this.log('observe', entity);
180 | const uuid = this.entityCache.add(entity);
181 |
182 | if (!uuid) {
183 | this.warn(`${uuid} is unobservable`);
184 | return;
185 | }
186 |
187 | // Fire on next tick; otherwise this is called when the scene is created,
188 | // which won't have any objects. Will have to explore more in #18.
189 | // Batch up multiple scenes added in the same tick.
190 | if (this.entitiesRecentlyObserved.size === 0) {
191 | requestAnimationFrame(() => {
192 | this.send('observe', {
193 | uuids: [...this.entitiesRecentlyObserved],
194 | });
195 | this.entitiesRecentlyObserved.clear();
196 | });
197 | }
198 |
199 | this.entitiesRecentlyObserved.add(uuid);
200 | }
201 |
202 | send(type, data) {
203 | this.log('emitting', type, data);
204 | try {
205 | window.postMessage({
206 | id: 'three-devtools',
207 | type: type,
208 | data,
209 | }, '*');
210 | } catch (e) {
211 | if (!data) {
212 | throw e;
213 | }
214 | // If this throws, it could be because of user data not being
215 | // able to be cloned. This will be much slower, but it will work.
216 | console.error('Data could not be cloned; ensure "userData" is serializable.', e);
217 | window.postMessage({
218 | id: 'three-devtools',
219 | type,
220 | data: JSON.parse(JSON.stringify(data))
221 | });
222 | }
223 | }
224 |
225 | log(...message) {
226 | if (DEBUG) {
227 | console.log('%c ThreeDevTools:', 'color:red', ...message);
228 | }
229 | }
230 |
231 | warn(...message) {
232 | if (DEBUG) {
233 | console.warn('%c ThreeDevTools:', 'color:red', ...message);
234 | }
235 | }
236 |
237 | createDevToolsScene(renderer, camera) {
238 | if (this.devtoolsScene) {
239 | return this.devtoolsScene;
240 | }
241 |
242 | this.devtoolsScene = new DevToolsScene(this.target, renderer.domElement, camera);
243 | return this.devtoolsScene;
244 | }
245 |
246 | setActiveRenderer(renderer) {
247 | // Hide the overlay rendering unless
248 | // enabled while some buggy cases are ironed out
249 | if (!this.USE_RENDER_OVERLAY) {
250 | return;
251 | }
252 | const render = renderer.render;
253 | const devtools = this;
254 |
255 | let devtoolsScene;
256 | renderer.render = function (scene, camera) {
257 | const target = renderer.getRenderTarget();
258 | render.call(this, scene, camera);
259 |
260 | if (!target) {
261 | if (!devtoolsScene) {
262 | devtoolsScene = devtools.createDevToolsScene(renderer, camera);
263 | }
264 | devtoolsScene.setCamera(camera);
265 |
266 | const autoClear = renderer.autoClear;
267 | renderer.autoClear = false;
268 | render.call(renderer, devtoolsScene, camera);
269 | renderer.autoClear = autoClear;
270 | }
271 | };
272 | }
273 | };
274 |
275 | })();
276 |
--------------------------------------------------------------------------------
/src/content/toJSON.js:
--------------------------------------------------------------------------------
1 | export default (() => {
2 |
3 | const isDevtoolsSerialization = meta => !!(meta && meta.devtoolsConfig);
4 | const isObject = o => Object.prototype.toString.call(o) === '[object Object]';
5 | const tempPosition = new THREE.Vector3();
6 | const tempRotation = new THREE.Quaternion();
7 | const tempScale = new THREE.Vector3();
8 | const tempEuler = new THREE.Euler();
9 |
10 | return function InstrumentedToJSON (meta) {
11 | /**
12 | * The instrumented version of entity's `toJSON` method,
13 | * used to patch because:
14 | * 1) entity does not have toJSON method
15 | * 2) current serialization returns insufficient information
16 | * 3) throws an error on serialization
17 | *
18 | * Additionally, this makes it possible to create
19 | * instrumentation-only options that can be attached
20 | * to the `meta` object, like smarter serialization of images.
21 | */
22 |
23 | const toJSON = this.constructor &&
24 | this.constructor.prototype &&
25 | this.constructor.prototype.toJSON;
26 |
27 | // Short circuit if this is something other than the devtools
28 | // serializing.
29 | if (toJSON && !isDevtoolsSerialization(meta)) {
30 | return toJSON.apply(this, arguments);
31 | }
32 |
33 | // Store our custom flags that are passed in via
34 | // the resources.
35 | const serializeChildren = meta && meta.devtoolsConfig.serializeChildren === false ? false : true;
36 |
37 | // First, discover the `baseType`, which for most
38 | // entities in three.js core, this is the same as
39 | // `type` -- however the `type` property can be modified
40 | // by a developer, especially common when extending a
41 | // base class.
42 | // Note, be sure to check subclasses before
43 | // base classes here.
44 | const baseType = utils.getBaseType(this);
45 |
46 | let textureData;
47 | if (this.isTexture) {
48 | // If `image` is a plain object (via DataTexture or WebGLRenderTarget)
49 | // or an array of plain objects (via CompressedTexture) hide it during
50 | // serialization so an attempt to turn it into a data URL doesn't throw.
51 | // Patch for DataTexture.toJSON (https://github.com/mrdoob/three.js/pull/17745)
52 | if (isObject(this.image) || (Array.isArray(this.image) && this.image.some(isObject))) {
53 | textureData = this.image;
54 | this.image = undefined;
55 | }
56 | }
57 |
58 | let children;
59 | if (this.isObject3D && !serializeChildren) {
60 | // Swap out the children array before serialization if
61 | // it's to be avoided.
62 | children = this.children;
63 | this.children = [];
64 | }
65 |
66 | // Call the original serialization method.
67 | // Note that this can fail if the toJSON was manually
68 | // overwritten e.g. not a part of a prototype. Check for its existence
69 | // first since some do not have any toJSON method,
70 | // like WebGLRenderTarget
71 | let data = toJSON ? toJSON.apply(this, arguments) : {};
72 |
73 | // If an image was hidden to avoid serialization,
74 | // reapply it here
75 | if (textureData) {
76 | this.image = textureData;
77 | }
78 | // Reattach children
79 | if (children) {
80 | this.children = children;
81 | }
82 |
83 | // Parametric geometry cannot be rehydrated
84 | // without introducing a vector for code injection.
85 | // For serialization, stringifying is fine,
86 | // but this geometry is unrehydratable (for good reason,
87 | // as this would then get access to privileged extension code).
88 | // https://github.com/mrdoob/three.js/issues/17381
89 | else if (data.func) {
90 | data.func = this.parameters.func ?
91 | this.parameters.func.toString() : '';
92 | }
93 | // Render targets shouldn't be in the graph directly
94 | // since their textures must be used instead, but this
95 | // may still occur in `scene.background`, where an attempt
96 | // at serialization occurs and breaks on render targets.
97 | // https://github.com/mrdoob/three.js/pull/16764
98 | else if (this.isWebGLRenderTarget) {
99 | // Would be great to actually serialize out the render target,
100 | // if given a renderer.
101 | // https://github.com/mrdoob/three.js/issues/16762
102 | }
103 | // InterleavedBufferAttributes cannot be serialized,
104 | // so once patched, this will return some very basic
105 | // data.
106 | else if (this.isInterleavedBufferAttribute) {
107 | data.count = this.count;
108 | data.itemSize = this.itemSize;
109 | data.offset = this.offset;
110 | data.normalized = this.normalized;
111 | }
112 | // Handle renderer serialization
113 | else if (baseType === 'WebGLRenderer' || baseType === 'WebGL1Renderer') {
114 | const shadowMap = this.shadowMap;
115 | const capabilities = this.capabilities;
116 | data.name = ('name' in this) ? this.name : '';
117 | data.physicallyCorrectLights = ('physicallyCorrectLights' in this) ? this.physicallyCorrectLights : false;
118 | data.gammaFactor = ('gammaFactor' in this) ? this.gammaFactor: 2;
119 | data.outputEncoding = ('outputEncoding' in this) ? this.outputEncoding : 0; // default?
120 | data.toneMapping = ('toneMapping' in this) ? this.toneMapping : 0; // default?
121 | data.toneMappingExposure = ('toneMappingExposure' in this) ? this.toneMappingExposure : 1;
122 | data.autoClear = ('autoClear' in this) ? this.autoClear : true;
123 | data.autoClearColor = ('autoClearColor' in this) ? this.autoClearColor : true;
124 | data.autoClearDepth = ('autoClearDepth' in this) ? this.autoClearDepth : true;
125 | data.autoClearStencil = ('autoClearStencil' in this) ? this.autoClearStencil : true;
126 | if (shadowMap) {
127 | data.shadowMap = {};
128 | data.shadowMap.enabled = ('enabled' in shadowMap) ? shadowMap.enabled : false;
129 | data.shadowMap.autoUpdate = ('autoUpdate' in shadowMap) ? shadowMap.autoUpdate : true;
130 | data.shadowMap.type = ('type' in shadowMap) ? shadowMap.type : 0; // default?
131 | }
132 | if (capabilities) {
133 | data.capabilities = {};
134 | data.capabilities.isWebGL2 = capabilities.isWebGL2;
135 | data.capabilities.precision = capabilities.precision;
136 | data.capabilities.floatFragmentTextures = capabilities.floatFragmentTextures;
137 | data.capabilities.floatVertexTextures = capabilities.floatVertexTextures;
138 | data.capabilities.logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
139 | data.capabilities.maxAnisotropy = capabilities.getMaxAnisotropy();
140 | data.capabilities.maxPrecision = capabilities.getMaxPrecision();
141 | data.capabilities.maxAttributes = capabilities.maxAttributes;
142 | data.capabilities.maxCubemapSize = capabilities.maxCubemapSize;
143 | data.capabilities.maxFragmentUniforms = capabilities.maxFragmentUniforms;
144 | data.capabilities.maxTextureSize = capabilities.maxTextureSize;
145 | data.capabilities.maxTextures = capabilities.maxTextures;
146 | data.capabilities.maxVaryings = capabilities.maxVaryings;
147 | data.capabilities.maxVertexTextures = capabilities.maxVertexTextures;
148 | data.capabilities.maxVertexUniforms = capabilities.maxVertexUniforms;
149 | data.capabilities.vertexTextures = capabilities.vertexTextures;
150 | }
151 | }
152 |
153 | if (data.object) {
154 | data.object.baseType = baseType;
155 |
156 | if (this.matrix) {
157 | // Objects should also decompose their matrix for editing
158 | // in the tools
159 | this.matrix.decompose(tempPosition, tempRotation, tempScale);
160 | data.object.position = tempPosition.toArray();
161 | data.object.rotation = tempEuler.setFromQuaternion(tempRotation).toArray();
162 | data.object.scale = tempScale.toArray();
163 | }
164 | } else {
165 | data.baseType = baseType;
166 | }
167 |
168 | return data;
169 | }
170 | });
171 |
--------------------------------------------------------------------------------
/src/content/utils.js:
--------------------------------------------------------------------------------
1 | export default (() => {
2 |
3 | const utils = {
4 | /**
5 | * Find the corresponding target and property given
6 | * an object and a string including object accessor's
7 | * (e.g. "."), like "position.x" to return the
8 | * "position" object as target, and "x" as the key.
9 | *
10 | * @param {THREE.*} entity
11 | * @param {String} property
12 | */
13 | getTargetAndKey: (entity, property) => {
14 | const path = property.split('.');
15 | let target = entity;
16 | let key = path.shift();
17 | while (path.length) {
18 | target = target[key];
19 | key = path.shift();
20 | }
21 | return { target, key };
22 | },
23 |
24 | hideObjectFromTools: (object) => {
25 | object.userData.fromDevtools = true;
26 | },
27 |
28 | isHiddenFromTools: (object) => {
29 | return !!(object.userData && object.userData.fromDevtools);
30 | },
31 |
32 | /**
33 | * Executes `fn` for the passed in object, and all of its dependents.
34 | * Note that an Object3D's children is not considered a dependency,
35 | * unless `options.recursive` is set.
36 | *
37 | * @param {THREE.*} entity
38 | * @param {Function} fn
39 | * @param {Object} options
40 | * @param {Function} options.recursive [false] whether or not an object should recursively iterate over
41 | * Object3D children and their dependencies.
42 | */
43 | forEachDependency(entity, fn, options={}) {
44 | fn(entity);
45 |
46 | if (entity.isObject3D) {
47 | if (entity.material && entity.material.isMaterial) {
48 | utils.forEachDependency(entity.material, fn, options);
49 | }
50 | if (entity.geometry && (entity.geometry.isGeometry || entity.geometry.isBufferGeometry)) {
51 | utils.forEachDependency(entity.geometry, fn, options);
52 | }
53 | if (entity.isScene && entity.background) {
54 | utils.forEachDependency(entity.background, fn, options);
55 | }
56 |
57 | if (options.recursive && entity.children && entity.children.length > 0) {
58 | for (let child of entity.children) {
59 | utils.forEachDependency(child, fn, options);
60 | }
61 | }
62 | }
63 | else if (entity.isBufferGeometry) {
64 | // handle attributes
65 | }
66 | else if (entity.isMaterial) {
67 | for (let key of Object.keys(entity)) {
68 | // @TODO cache textures used as uniforms here as well
69 | const texture = entity[key];
70 | if (texture && texture.isTexture) {
71 | utils.forEachDependency(texture, fn, options);
72 | }
73 | }
74 | if (entity.uniforms) {
75 | for (let name of Object.keys(entity.uniforms)) {
76 | const value = entity.uniforms[name].value;
77 | if (value && value.isTexture) {
78 | // What other "dependency" data could a material have?
79 | // more geometry/buffers?
80 | utils.forEachDependency(value, fn, options);
81 | }
82 | }
83 | }
84 | }
85 | else if (entity.isTexture) {
86 | if (entity.image && entity.image.uuid) {
87 | // maybe don't cache images as an entity
88 | //Object.prototype.toString.call(this.image) === '[object Object]';
89 | }
90 | }
91 | },
92 |
93 | /**
94 | * For most entities in three.js core, baseType is the same as
95 | * `type` -- however the `type` property can be modified
96 | * by a developer, especially common when extending a
97 | * base class.
98 | * Note, be sure to check subclasses before
99 | * base classes here.
100 | *
101 | * @param {THREE.*} entity
102 | * @return {String}
103 | */
104 | getBaseType: (entity) => {
105 | let type =
106 | // objects
107 | entity.isScene ? 'Scene' :
108 | entity.isGroup ? 'Group' :
109 | entity.isLOD ? 'LOD' :
110 | entity.isBone ? 'Bone' :
111 | entity.isSkeleton ? 'Skeleton' :
112 | entity.isPoints ? 'Points' :
113 | entity.isSprite ? 'Sprite' :
114 |
115 | entity.isSkinnedMesh ? 'SkinnedMesh' :
116 | entity.isInstancedMesh ? 'InstancedMesh' :
117 | entity.isMesh ? 'Mesh' :
118 |
119 | entity.isLineLoop ? 'LineLoop' :
120 | entity.isLineSegments ? 'LineSegments' :
121 | entity.isLine ? 'Line' :
122 |
123 | // lights
124 | entity.isAmbientLightProbe ? 'AmbientLightProbe' :
125 | entity.isHemisphereLightProbe ? 'HemisphereLightProbe' :
126 | entity.isLightProbe ? 'LightProbe' :
127 |
128 | entity.isAmbientLight ? 'AmbientLight' :
129 | entity.isDirectionalLight ? 'DirectionalLight' :
130 | entity.isHemisphereLight ? 'HemisphereLight' :
131 | entity.isPointLight ? 'PointLight' :
132 | entity.isRectAreaLight ? 'RectAreaLight' :
133 | entity.isSpotLight ? 'SpotLight' :
134 | entity.isLight ? 'Light' :
135 |
136 | // cameras
137 | entity.isArrayCamera ? 'ArrayCamera' :
138 | entity.isPerspectiveCamera ? 'PerspectiveCamera' :
139 | entity.isOrthographicCamera ? 'OrthographicCamera' :
140 | entity.isCubeCamera ? 'CubeCamera' :
141 | entity.isCamera ? 'Camera' :
142 |
143 | entity.isObject3D ? 'Object3D' :
144 |
145 | // geometries only have `type` property containing
146 | // a reference to its type if a preset like Sphere or Plane.
147 | entity.isGeometry ? 'Geometry' :
148 | //@TODO what is DirectGeometry? entity.isDirectGeometry ? 'DirectGeometry' :
149 | entity.isInstancedBufferGeometry ? 'InstancedBufferGeometry' :
150 | entity.isBufferGeometry ? 'BufferGeometry' :
151 | // buffer attributes
152 | entity.isInstancedBufferAttribute ? 'InstancedBufferAttribute' :
153 | entity.isInterleavedBufferAttribute ? 'InterleavedBufferAttribute' :
154 | entity.isBufferAttribute ? 'BufferAttribute' :
155 |
156 | // materials
157 | entity.isLineBasicMaterial ? 'LineBasicMaterial' :
158 | entity.isLineDashedMaterial ? 'LineDashedMaterial' :
159 | entity.isMeshBasicMaterial ? 'MeshBasicMaterial' :
160 | entity.isMeshDepthMaterial ? 'MeshDepthMaterial' :
161 | entity.isMeshDistanceMaterial ? 'MeshDistanceMaterial' :
162 | entity.isMeshLambertMaterial ? 'MeshLambertMaterial' :
163 | entity.isMeshMatcapMaterial ? 'MeshMatcapMaterial' :
164 | entity.isMeshNormalMaterial ? 'MeshNormalMaterial' :
165 | entity.isMeshToonMaterial ? 'MeshToonMaterial' :
166 | entity.isMeshPhongMaterial ? 'MeshPhongMaterial' :
167 | entity.isPointsMaterial ? 'PointsMaterial' :
168 | entity.isShadowMaterial ? 'ShadowMaterial' :
169 | entity.isSpriteMaterial ? 'SpriteMaterial' :
170 |
171 | entity.isMeshPhysicalMaterial ? 'MeshPhysicalMaterial' :
172 | entity.isMeshStandardMaterial ? 'MeshStandardMaterial' :
173 |
174 | entity.isRawShaderMaterial ? 'RawShaderMaterial' :
175 | entity.isShaderMaterial ? 'ShaderMaterial' :
176 | entity.isMaterial ? 'Material' :
177 |
178 | // textures
179 | entity.isCanvasTexture ? 'CanvasTexture' :
180 | entity.isCompressedTexture ? 'CompressedTexture' :
181 | entity.isCubeTexture ? 'CubeTexture' :
182 | entity.isDataTexture2DArray ? 'DataTexture2DArray' :
183 | entity.isDataTexture3D ? 'DataTexture3D' :
184 | entity.isDataTexture ? 'DataTexture' :
185 | entity.isDepthTexture ? 'DepthTexture' :
186 | entity.isVideoTexture ? 'VideoTexture' :
187 | entity.isTexture ? 'Texture' :
188 |
189 | // Not yet supported fully, but tag it accordingly
190 | entity.isWebGLRenderTarget ? 'WebGLRenderTarget' :
191 |
192 | // renderers
193 | // `WebGLRenderer` does not have a boolean prop,
194 | // test for that below.
195 | entity.isWebGL1Renderer ? 'WebGL1Renderer' :
196 |
197 | // If nothing matches...
198 | 'Unknown';
199 |
200 | if (type === 'Unknown' && typeof entity.render === 'function' && typeof entity.setPixelRatio === 'function') {
201 | type = 'WebGLRenderer';
202 | }
203 |
204 | return type;
205 | },
206 | };
207 |
208 | return utils;
209 |
210 | });
211 |
--------------------------------------------------------------------------------
/src/extension/background.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/extension/background.js:
--------------------------------------------------------------------------------
1 | import browser from '../../web_modules/webextension-polyfill/dist/browser-polyfill.js';
2 | globalThis.browser = browser;
3 |
4 | const connections = new Map();
5 |
6 | /**
7 | * When opening the three-devtools panel, store
8 | * a connection to communicate later.
9 | */
10 | browser.runtime.onConnect.addListener(port => {
11 | let tabId;
12 | const onMessage = (message) => {
13 | tabId = message.tabId;
14 | console.log('onConnect', tabId, message.name);
15 | if (message.name === 'connect') {
16 | connections.set(tabId, port);
17 | }
18 | }
19 |
20 | port.onMessage.addListener(onMessage);
21 |
22 | port.onDisconnect.addListener(port => {
23 | port.onMessage.removeListener(onMessage);
24 | connections.delete(tabId);
25 | });
26 | });
27 |
28 | /**
29 | * When receiving a message from content, pass it
30 | * along to the devtools panel.
31 | */
32 | browser.runtime.onMessage.addListener((request, sender) => {
33 | if (sender.tab) {
34 | const tabId = sender.tab.id;
35 | if (connections.has(tabId)) {
36 | connections.get(tabId).postMessage(request);
37 | }
38 | }
39 | return true;
40 | });
41 |
42 | /**
43 | * When a page has reloaded; if three-devtools are open, notify
44 | * the devtools panel so it can inject the content-side of the tools.
45 | */
46 | browser.webNavigation.onCommitted.addListener(({tabId, frameId}) => {
47 | // Only support top-level frame for now
48 | if (frameId !== 0) {
49 | return;
50 | }
51 | console.log('onCommitted', tabId, connections.has(tabId));
52 | if (connections.has(tabId)) {
53 | connections.get(tabId).postMessage({
54 | type: 'committed',
55 | id: 'three-devtools',
56 | });
57 | }
58 | });
59 |
--------------------------------------------------------------------------------
/src/extension/contentScript.js:
--------------------------------------------------------------------------------
1 | // Use `text` instead of `src` to get around Chromium bug of execution order
2 | // when using `src`, resulting in a race condition.
3 | // https://bugs.chromium.org/p/chromium/issues/detail?id=634381#c3
4 | const script = document.createElement('script');
5 | script.text = `
6 | (() => {
7 | /**
8 | * This script injected by the installed three.js developer
9 | * tools extension.
10 | * https://github.com/threejs/three-devtools
11 | */
12 |
13 | const $devtoolsReady = Symbol('devtoolsReady');
14 | const $backlog = Symbol('backlog');
15 |
16 | // The __THREE_DEVTOOLS__ target is small and light-weight, and collects
17 | // events triggered until the devtools panel is ready, which is when
18 | // the events are flushed.
19 | const target = new class ThreeDevToolsTarget extends EventTarget {
20 | constructor() {
21 | super();
22 | this[$devtoolsReady] = false;
23 | this[$backlog] = [];
24 | this.addEventListener('devtools-ready', e => {
25 | this[$devtoolsReady] = true;
26 | for (let event of this[$backlog]) {
27 | this.dispatchEvent(event);
28 | }
29 | }, { once: true });
30 | }
31 |
32 | dispatchEvent(event) {
33 | if (this[$devtoolsReady] || event.type === 'devtools-ready') {
34 | super.dispatchEvent(event);
35 | } else {
36 | this[$backlog].push(event);
37 | }
38 | }
39 | }
40 |
41 | Object.defineProperty(window, '__THREE_DEVTOOLS__', {
42 | value: target,
43 | });
44 | })();
45 | `;
46 | script.onload = () => {
47 | script.parentNode.removeChild(script);
48 | }
49 | (document.head || document.documentElement).appendChild(script);
50 |
51 | window.addEventListener('message', e => {
52 | if (e.source !== window ||
53 | typeof e.data !== 'object' ||
54 | e.data.id !== 'three-devtools') {
55 | return;
56 | }
57 |
58 | // Don't bring in the 35kb polyfill on every page
59 | // for a single command that doesn't matter if its callback
60 | // promise; handle this manually.
61 | const extRoot = globalThis.chrome ? globalThis.chrome : globalThis.browser;
62 |
63 | try {
64 | extRoot.runtime.sendMessage(e.data);
65 | } catch (error) {
66 | console.error(error);
67 | extRoot.runtime.sendMessage({
68 | type: 'error',
69 | id: 'three-devtools',
70 | data: error.toString(),
71 | });
72 | }
73 | });
74 |
--------------------------------------------------------------------------------
/src/extension/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/extension/devtools.js:
--------------------------------------------------------------------------------
1 | import browser from '../../web_modules/webextension-polyfill/dist/browser-polyfill.js';
2 | globalThis.browser = browser;
3 |
4 | if (browser.devtools.inspectedWindow.tabId) {
5 | // As of now, only inspect content windows, not when
6 | // debugging a devtools panel for example.
7 | browser.devtools.inspectedWindow.eval(`window.DevToolsAPI`).then(([result,error]) => {
8 | if (!result) {
9 | createPanel();
10 | }
11 | });
12 | }
13 |
14 |
15 | async function createPanel() {
16 | // It appears that Chrome treats URLs relative to extension root,
17 | // and Firefox treats it relative to the devtools page.
18 | // Use `/` to circumvent.
19 | const icon = '/assets/icon_128.png';
20 | const url = '/src/app/index.html';
21 | const panel = await browser.devtools.panels.create(`three`, icon, url);
22 | }
23 |
--------------------------------------------------------------------------------
/web_modules/@egjs/agent.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2017 NAVER Corp.
3 | @egjs/agent project is licensed under the MIT license
4 |
5 | @egjs/agent JavaScript library
6 |
7 |
8 | @version 2.1.5
9 | */
10 | var win = typeof window !== "undefined" && window || {};
11 | var navigator = win.navigator;
12 |
13 | var parseRules = {
14 | browser: [{
15 | criteria: "PhantomJS",
16 | identity: "PhantomJS"
17 | }, {
18 | criteria: /Whale/,
19 | identity: "Whale",
20 | versionSearch: "Whale"
21 | }, {
22 | criteria: /Edge/,
23 | identity: "Edge",
24 | versionSearch: "Edge"
25 | }, {
26 | criteria: /MSIE|Trident|Windows Phone/,
27 | identity: "IE",
28 | versionSearch: "IEMobile|MSIE|rv"
29 | }, {
30 | criteria: /MiuiBrowser/,
31 | identity: "MIUI Browser",
32 | versionSearch: "MiuiBrowser"
33 | }, {
34 | criteria: /SamsungBrowser/,
35 | identity: "Samsung Internet",
36 | versionSearch: "SamsungBrowser"
37 | }, {
38 | criteria: /SAMSUNG /,
39 | identity: "Samsung Internet",
40 | versionSearch: "Version"
41 | }, {
42 | criteria: /Chrome|CriOS/,
43 | identity: "Chrome"
44 | }, {
45 | criteria: /Android/,
46 | identity: "Android Browser",
47 | versionSearch: "Version"
48 | }, {
49 | criteria: /iPhone|iPad/,
50 | identity: "Safari",
51 | versionSearch: "Version"
52 | }, {
53 | criteria: "Apple",
54 | identity: "Safari",
55 | versionSearch: "Version"
56 | }, {
57 | criteria: "Firefox",
58 | identity: "Firefox"
59 | }],
60 | os: [{
61 | criteria: /Windows Phone/,
62 | identity: "Windows Phone",
63 | versionSearch: "Windows Phone"
64 | }, {
65 | criteria: "Windows 2000",
66 | identity: "Window",
67 | versionAlias: "5.0"
68 | }, {
69 | criteria: /Windows NT/,
70 | identity: "Window",
71 | versionSearch: "Windows NT"
72 | }, {
73 | criteria: /iPhone|iPad/,
74 | identity: "iOS",
75 | versionSearch: "iPhone OS|CPU OS"
76 | }, {
77 | criteria: "Mac",
78 | versionSearch: "OS X",
79 | identity: "MAC"
80 | }, {
81 | criteria: /Android/,
82 | identity: "Android"
83 | }, {
84 | criteria: /Tizen/,
85 | identity: "Tizen"
86 | }, {
87 | criteria: /Web0S/,
88 | identity: "WebOS"
89 | }],
90 |
91 | // Webview check condition
92 | // ios: If has no version information
93 | // Android 5.0 && chrome 40+: Presence of "; wv" in userAgent
94 | // Under android 5.0: Presence of "NAVER" or "Daum" in userAgent
95 | webview: [{
96 | criteria: /iPhone|iPad/,
97 | browserVersionSearch: "Version",
98 | webviewBrowserVersion: /-1/
99 | }, {
100 | criteria: /iPhone|iPad|Android/,
101 | webviewToken: /NAVER|DAUM|; wv/
102 |
103 | }],
104 | defaultString: {
105 | browser: {
106 | version: "-1",
107 | name: "unknown"
108 | },
109 | os: {
110 | version: "-1",
111 | name: "unknown"
112 | }
113 | }
114 | };
115 |
116 | function filter(arr, compare) {
117 | var result = [];
118 |
119 | for (var i = 0; i < arr.length; i++) {
120 | compare(arr[i]) && result.push(arr[i]);
121 | }
122 | return result;
123 | }
124 |
125 | function some(arr, compare) {
126 | for (var i = 0; i < arr.length; i++) {
127 | if (compare(arr[i])) {
128 | return true;
129 | }
130 | }
131 | return false;
132 | }
133 |
134 | var UA = void 0;
135 |
136 | function setUa(ua) {
137 | UA = ua;
138 | }
139 |
140 | function isMatched(base, target) {
141 | return target && target.test ? !!target.test(base) : base.indexOf(target) > -1;
142 | }
143 |
144 | function getIdentityStringFromArray(rules, defaultStrings) {
145 | var matchedRule = filter(rules, function (rule) {
146 | return isMatched(UA, rule.criteria);
147 | })[0];
148 |
149 | return matchedRule && matchedRule.identity || defaultStrings.name;
150 | }
151 |
152 | function getRule(rules, targetIdentity) {
153 | return filter(rules, function (rule) {
154 | var criteria = rule.criteria;
155 | var identityMatched = new RegExp(rule.identity, "i").test(targetIdentity);
156 |
157 | if (criteria ? identityMatched && isMatched(UA, criteria) : identityMatched) {
158 | return true;
159 | } else {
160 | return false;
161 | }
162 | })[0];
163 | }
164 |
165 | function getBrowserName() {
166 | return getIdentityStringFromArray(parseRules.browser, parseRules.defaultString.browser);
167 | }
168 |
169 | function getBrowserRule(browserName) {
170 | var rule = getRule(parseRules.browser, browserName);
171 |
172 | if (!rule) {
173 | rule = {
174 | criteria: browserName,
175 | versionSearch: browserName,
176 | identity: browserName
177 | };
178 | }
179 |
180 | return rule;
181 | }
182 |
183 | function extractBrowserVersion(versionToken, ua) {
184 | var browserVersion = parseRules.defaultString.browser.version;
185 | var versionRegexResult = new RegExp("(" + versionToken + ")", "i").exec(ua);
186 |
187 | if (!versionRegexResult) {
188 | return browserVersion;
189 | }
190 |
191 | var versionTokenIndex = versionRegexResult.index;
192 | var verTkn = versionRegexResult[0];
193 |
194 | if (versionTokenIndex > -1) {
195 | var versionIndex = versionTokenIndex + verTkn.length + 1;
196 |
197 | browserVersion = ua.substring(versionIndex).split(" ")[0].replace(/_/g, ".").replace(/;|\)/g, "");
198 | }
199 | return browserVersion;
200 | }
201 |
202 | function getBrowserVersion(browserName) {
203 | if (!browserName) {
204 | return undefined;
205 | }
206 |
207 | // console.log(browserRule);
208 | // const versionToken = browserRule ? browserRule.versionSearch : browserName;
209 | var browserRule = getBrowserRule(browserName);
210 | var versionToken = browserRule.versionSearch || browserName;
211 | var browserVersion = extractBrowserVersion(versionToken, UA);
212 |
213 | return browserVersion;
214 | }
215 |
216 | function isWebview() {
217 | var webviewRules = parseRules.webview;
218 | var browserVersion = void 0;
219 |
220 | return some(filter(webviewRules, function (rule) {
221 | return isMatched(UA, rule.criteria);
222 | }), function (rule) {
223 | browserVersion = extractBrowserVersion(rule.browserVersionSearch, UA);
224 | if (isMatched(UA, rule.webviewToken) || isMatched(browserVersion, rule.webviewBrowserVersion)) {
225 | return true;
226 | } else {
227 | return false;
228 | }
229 | });
230 | }
231 |
232 | function getOSRule(osName) {
233 | return getRule(parseRules.os, osName);
234 | }
235 |
236 | function getOsName() {
237 | return getIdentityStringFromArray(parseRules.os, parseRules.defaultString.os);
238 | }
239 |
240 | function getOsVersion(osName) {
241 | var osRule = getOSRule(osName) || {};
242 | var defaultOSVersion = parseRules.defaultString.os.version;
243 | var osVersion = void 0;
244 |
245 | if (!osName) {
246 | return undefined;
247 | }
248 | if (osRule.versionAlias) {
249 | return osRule.versionAlias;
250 | }
251 | var osVersionToken = osRule.versionSearch || osName;
252 | var osVersionRegex = new RegExp("(" + osVersionToken + ")\\s([\\d_\\.]+|\\d_0)", "i");
253 | var osVersionRegexResult = osVersionRegex.exec(UA);
254 |
255 | if (osVersionRegexResult) {
256 | osVersion = osVersionRegex.exec(UA)[2].replace(/_/g, ".").replace(/;|\)/g, "");
257 | }
258 | return osVersion || defaultOSVersion;
259 | }
260 |
261 | function getOs() {
262 | var name = getOsName();
263 | var version = getOsVersion(name);
264 |
265 | return { name: name, version: version };
266 | }
267 |
268 | function getBrowser() {
269 | var name = getBrowserName();
270 | var version = getBrowserVersion(name);
271 |
272 | return { name: name, version: version, webview: isWebview() };
273 | }
274 |
275 | function getIsMobile() {
276 | return UA.indexOf("Mobi") !== -1;
277 | }
278 |
279 | /**
280 | * Copyright (c) NAVER Corp.
281 | * egjs-agent projects are licensed under the MIT license
282 | */
283 |
284 | /**
285 | * @namespace eg.agent
286 | */
287 | /**
288 | * Extracts browser and operating system information from the user agent string.
289 | * @ko 유저 에이전트 문자열에서 브라우저와 운영체제 정보를 추출한다.
290 | * @function eg.agent#agent
291 | * @param {String} [userAgent=navigator.userAgent] user agent string to parse 파싱할 유저에이전트 문자열
292 | * @return {Object} agentInfo
293 | * @return {Object} agentInfo.os os Operating system information 운영체제 정보
294 | * @return {String} agentInfo.os.name Operating system name (android, ios, window, mac, unknown) 운영체제 이름 (android, ios, window, mac, unknown)
295 | * @return {String} agentInfo.os.version Operating system version 운영체제 버전
296 | * @return {String} agentInfo.browser Browser information 브라우저 정보
297 | * @return {String} agentInfo.browser.name Browser name (safari, chrome, sbrowser, ie, firefox, unknown) 브라우저 이름 (safari, chrome, sbrowser, ie, firefox, unknown)
298 | * @return {String} agentInfo.browser.version Browser version 브라우저 버전
299 | * @return {Boolean} agentInfo.browser.webview Indicates whether the browser is inapp웹뷰 브라우저 여부
300 | * @return {Boolean} agentInfo.isMobile Indicates whether the browser is for mobile모바일 브라우저 여부
301 | * @example
302 | import agent from "@egjs/agent";
303 |
304 | const {os, browser, isMobile} = agent();
305 | */
306 | function agent() {
307 | var ua = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : navigator.userAgent;
308 |
309 | setUa(ua);
310 |
311 | var agentInfo = {
312 | os: getOs(),
313 | browser: getBrowser(),
314 | isMobile: getIsMobile()
315 | };
316 |
317 | agentInfo.browser.name = agentInfo.browser.name.toLowerCase();
318 | agentInfo.os.name = agentInfo.os.name.toLowerCase();
319 | agentInfo.os.version = agentInfo.os.version.toLowerCase();
320 |
321 | if (agentInfo.os.name === "ios" && agentInfo.browser.webview) {
322 | agentInfo.browser.version = "-1";
323 | }
324 |
325 | return agentInfo;
326 | }
327 | /**
328 | * Version info string
329 | * @ko 버전정보 문자열
330 | * @name VERSION
331 | * @static
332 | * @type {String}
333 | * @example
334 | * eg.agent.VERSION; // ex) 2.2.0
335 | * @memberof eg.agent
336 | */
337 | agent.VERSION = "2.1.5";
338 |
339 | export default agent;
340 |
--------------------------------------------------------------------------------
/web_modules/import-map.json:
--------------------------------------------------------------------------------
1 | {
2 | "imports": {
3 | "webextension-polyfill/dist/browser-polyfill": "./webextension-polyfill/dist/browser-polyfill.js",
4 | "lit-element": "./lit-element.js",
5 | "lit-html/directives/if-defined": "./lit-html/directives/if-defined.js",
6 | "@egjs/agent": "./@egjs/agent.js",
7 | "three": "./three.js",
8 | "three/src/constants": "./three/src/constants.js",
9 | "three/examples/jsm/loaders/GLTFLoader": "./three/examples/jsm/loaders/GLTFLoader.js",
10 | "three/examples/jsm/geometries/TeapotBufferGeometry": "./three/examples/jsm/geometries/TeapotBufferGeometry.js"
11 | }
12 | }
--------------------------------------------------------------------------------
/web_modules/licenses/agent_LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 NAVER Corp.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/web_modules/licenses/lit-element_LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, The Polymer Authors. All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/web_modules/licenses/lit-html_LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, The Polymer Authors. All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | * Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/web_modules/licenses/three_LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright © 2010-2019 three.js authors
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 |
--------------------------------------------------------------------------------
/web_modules/lit-html/directives/if-defined.js:
--------------------------------------------------------------------------------
1 | import { d as directive, A as AttributePart } from '../../common/lit-html-513f48c9.js';
2 |
3 | /**
4 | * @license
5 | * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
6 | * This code may only be used under the BSD style license found at
7 | * http://polymer.github.io/LICENSE.txt
8 | * The complete set of authors may be found at
9 | * http://polymer.github.io/AUTHORS.txt
10 | * The complete set of contributors may be found at
11 | * http://polymer.github.io/CONTRIBUTORS.txt
12 | * Code distributed by Google as part of the polymer project is also
13 | * subject to an additional IP rights grant found at
14 | * http://polymer.github.io/PATENTS.txt
15 | */
16 | /**
17 | * For AttributeParts, sets the attribute if the value is defined and removes
18 | * the attribute if the value is undefined.
19 | *
20 | * For other part types, this directive is a no-op.
21 | */
22 | const ifDefined = directive((value) => (part) => {
23 | if (value === undefined && part instanceof AttributePart) {
24 | if (value !== part.value) {
25 | const name = part.committer.name;
26 | part.committer.element.removeAttribute(name);
27 | }
28 | }
29 | else {
30 | part.setValue(value);
31 | }
32 | });
33 |
34 | export { ifDefined };
35 |
--------------------------------------------------------------------------------
/web_modules/three/examples/jsm/pmrem/PMREMCubeUVPacker.js:
--------------------------------------------------------------------------------
1 | import { OrthographicCamera, Scene, ShaderMaterial, Vector3, NoBlending, RGBEEncoding, RGBM16Encoding, LinearFilter, WebGLRenderTarget, CubeUVReflectionMapping, PlaneBufferGeometry, Mesh, BackSide, LinearToneMapping, Vector2 } from '../../../../three.js';
2 |
3 | /**
4 | * @author Prashant Sharma / spidersharma03
5 | * @author Ben Houston / bhouston, https://clara.io
6 | *
7 | * This class takes the cube lods(corresponding to different roughness values), and creates a single cubeUV
8 | * Texture. The format for a given roughness set of faces is simply::
9 | * +X+Y+Z
10 | * -X-Y-Z
11 | * For every roughness a mip map chain is also saved, which is essential to remove the texture artifacts due to
12 | * minification.
13 | * Right now for every face a PlaneMesh is drawn, which leads to a lot of geometry draw calls, but can be replaced
14 | * later by drawing a single buffer and by sending the appropriate faceIndex via vertex attributes.
15 | * The arrangement of the faces is fixed, as assuming this arrangement, the sampling function has been written.
16 | */
17 |
18 | var PMREMCubeUVPacker = ( function () {
19 |
20 | var camera = new OrthographicCamera();
21 | var scene = new Scene();
22 | var shader = getShader();
23 |
24 | var PMREMCubeUVPacker = function ( cubeTextureLods ) {
25 |
26 | this.cubeLods = cubeTextureLods;
27 | var size = cubeTextureLods[ 0 ].width * 4;
28 |
29 | var sourceTexture = cubeTextureLods[ 0 ].texture;
30 | var params = {
31 | format: sourceTexture.format,
32 | magFilter: sourceTexture.magFilter,
33 | minFilter: sourceTexture.minFilter,
34 | type: sourceTexture.type,
35 | generateMipmaps: sourceTexture.generateMipmaps,
36 | anisotropy: sourceTexture.anisotropy,
37 | encoding: ( sourceTexture.encoding === RGBEEncoding ) ? RGBM16Encoding : sourceTexture.encoding
38 | };
39 |
40 | if ( params.encoding === RGBM16Encoding ) {
41 |
42 | params.magFilter = LinearFilter;
43 | params.minFilter = LinearFilter;
44 |
45 | }
46 |
47 | this.CubeUVRenderTarget = new WebGLRenderTarget( size, size, params );
48 | this.CubeUVRenderTarget.texture.name = "PMREMCubeUVPacker.cubeUv";
49 | this.CubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
50 |
51 | this.objects = [];
52 |
53 | var geometry = new PlaneBufferGeometry( 1, 1 );
54 |
55 | var faceOffsets = [];
56 | faceOffsets.push( new Vector2( 0, 0 ) );
57 | faceOffsets.push( new Vector2( 1, 0 ) );
58 | faceOffsets.push( new Vector2( 2, 0 ) );
59 | faceOffsets.push( new Vector2( 0, 1 ) );
60 | faceOffsets.push( new Vector2( 1, 1 ) );
61 | faceOffsets.push( new Vector2( 2, 1 ) );
62 |
63 | var textureResolution = size;
64 | size = cubeTextureLods[ 0 ].width;
65 |
66 | var offset2 = 0;
67 | var c = 4.0;
68 | this.numLods = Math.log( cubeTextureLods[ 0 ].width ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2
69 | for ( var i = 0; i < this.numLods; i ++ ) {
70 |
71 | var offset1 = ( textureResolution - textureResolution / c ) * 0.5;
72 | if ( size > 16 ) c *= 2;
73 | var nMips = size > 16 ? 6 : 1;
74 | var mipOffsetX = 0;
75 | var mipOffsetY = 0;
76 | var mipSize = size;
77 |
78 | for ( var j = 0; j < nMips; j ++ ) {
79 |
80 | // Mip Maps
81 | for ( var k = 0; k < 6; k ++ ) {
82 |
83 | // 6 Cube Faces
84 | var material = shader.clone();
85 | material.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture;
86 | material.envMap = this.cubeLods[ i ].texture;
87 | material.uniforms[ 'faceIndex' ].value = k;
88 | material.uniforms[ 'mapSize' ].value = mipSize;
89 |
90 | var planeMesh = new Mesh( geometry, material );
91 | planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX;
92 | planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY;
93 | planeMesh.material.side = BackSide;
94 | planeMesh.scale.setScalar( mipSize );
95 | this.objects.push( planeMesh );
96 |
97 | }
98 | mipOffsetY += 1.75 * mipSize;
99 | mipOffsetX += 1.25 * mipSize;
100 | mipSize /= 2;
101 |
102 | }
103 | offset2 += 2 * size;
104 | if ( size > 16 ) size /= 2;
105 |
106 | }
107 |
108 | };
109 |
110 | PMREMCubeUVPacker.prototype = {
111 |
112 | constructor: PMREMCubeUVPacker,
113 |
114 | update: function ( renderer ) {
115 |
116 | var size = this.cubeLods[ 0 ].width * 4;
117 | // top and bottom are swapped for some reason?
118 | camera.left = - size * 0.5;
119 | camera.right = size * 0.5;
120 | camera.top = - size * 0.5;
121 | camera.bottom = size * 0.5;
122 | camera.near = 0;
123 | camera.far = 1;
124 | camera.updateProjectionMatrix();
125 |
126 | for ( var i = 0; i < this.objects.length; i ++ ) {
127 |
128 | scene.add( this.objects[ i ] );
129 |
130 | }
131 |
132 | var gammaInput = renderer.gammaInput;
133 | var gammaOutput = renderer.gammaOutput;
134 | var toneMapping = renderer.toneMapping;
135 | var toneMappingExposure = renderer.toneMappingExposure;
136 | var currentRenderTarget = renderer.getRenderTarget();
137 |
138 | renderer.gammaInput = false;
139 | renderer.gammaOutput = false;
140 | renderer.toneMapping = LinearToneMapping;
141 | renderer.toneMappingExposure = 1.0;
142 | renderer.setRenderTarget( this.CubeUVRenderTarget );
143 | renderer.render( scene, camera );
144 |
145 | renderer.setRenderTarget( currentRenderTarget );
146 | renderer.toneMapping = toneMapping;
147 | renderer.toneMappingExposure = toneMappingExposure;
148 | renderer.gammaInput = gammaInput;
149 | renderer.gammaOutput = gammaOutput;
150 |
151 | for ( var i = 0; i < this.objects.length; i ++ ) {
152 |
153 | scene.remove( this.objects[ i ] );
154 |
155 | }
156 |
157 | },
158 |
159 | dispose: function () {
160 |
161 | for ( var i = 0, l = this.objects.length; i < l; i ++ ) {
162 |
163 | this.objects[ i ].material.dispose();
164 |
165 | }
166 |
167 | this.objects[ 0 ].geometry.dispose();
168 |
169 | }
170 |
171 | };
172 |
173 | function getShader() {
174 |
175 | var shaderMaterial = new ShaderMaterial( {
176 |
177 | uniforms: {
178 | "faceIndex": { value: 0 },
179 | "mapSize": { value: 0 },
180 | "envMap": { value: null },
181 | "testColor": { value: new Vector3( 1, 1, 1 ) }
182 | },
183 |
184 | vertexShader:
185 | "precision highp float;\
186 | varying vec2 vUv;\
187 | void main() {\
188 | vUv = uv;\
189 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\
190 | }",
191 |
192 | fragmentShader:
193 | "precision highp float;\
194 | varying vec2 vUv;\
195 | uniform samplerCube envMap;\
196 | uniform float mapSize;\
197 | uniform vec3 testColor;\
198 | uniform int faceIndex;\
199 | \
200 | void main() {\
201 | vec3 sampleDirection;\
202 | vec2 uv = vUv;\
203 | uv = uv * 2.0 - 1.0;\
204 | uv.y *= -1.0;\
205 | if(faceIndex == 0) {\
206 | sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\
207 | } else if(faceIndex == 1) {\
208 | sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\
209 | } else if(faceIndex == 2) {\
210 | sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\
211 | } else if(faceIndex == 3) {\
212 | sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\
213 | } else if(faceIndex == 4) {\
214 | sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\
215 | } else {\
216 | sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\
217 | }\
218 | vec4 color = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\
219 | gl_FragColor = linearToOutputTexel( color );\
220 | }",
221 |
222 | blending: NoBlending
223 |
224 | } );
225 |
226 | shaderMaterial.type = 'PMREMCubeUVPacker';
227 |
228 | return shaderMaterial;
229 |
230 | }
231 |
232 |
233 | return PMREMCubeUVPacker;
234 |
235 | } )();
236 |
237 | export { PMREMCubeUVPacker };
238 |
--------------------------------------------------------------------------------
/web_modules/three/src/constants.js:
--------------------------------------------------------------------------------
1 | var REVISION = '112';
2 | var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
3 | var TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
4 | var CullFaceNone = 0;
5 | var CullFaceBack = 1;
6 | var CullFaceFront = 2;
7 | var CullFaceFrontBack = 3;
8 | var FrontFaceDirectionCW = 0;
9 | var FrontFaceDirectionCCW = 1;
10 | var BasicShadowMap = 0;
11 | var PCFShadowMap = 1;
12 | var PCFSoftShadowMap = 2;
13 | var VSMShadowMap = 3;
14 | var FrontSide = 0;
15 | var BackSide = 1;
16 | var DoubleSide = 2;
17 | var FlatShading = 1;
18 | var SmoothShading = 2;
19 | var NoColors = 0;
20 | var FaceColors = 1;
21 | var VertexColors = 2;
22 | var NoBlending = 0;
23 | var NormalBlending = 1;
24 | var AdditiveBlending = 2;
25 | var SubtractiveBlending = 3;
26 | var MultiplyBlending = 4;
27 | var CustomBlending = 5;
28 | var AddEquation = 100;
29 | var SubtractEquation = 101;
30 | var ReverseSubtractEquation = 102;
31 | var MinEquation = 103;
32 | var MaxEquation = 104;
33 | var ZeroFactor = 200;
34 | var OneFactor = 201;
35 | var SrcColorFactor = 202;
36 | var OneMinusSrcColorFactor = 203;
37 | var SrcAlphaFactor = 204;
38 | var OneMinusSrcAlphaFactor = 205;
39 | var DstAlphaFactor = 206;
40 | var OneMinusDstAlphaFactor = 207;
41 | var DstColorFactor = 208;
42 | var OneMinusDstColorFactor = 209;
43 | var SrcAlphaSaturateFactor = 210;
44 | var NeverDepth = 0;
45 | var AlwaysDepth = 1;
46 | var LessDepth = 2;
47 | var LessEqualDepth = 3;
48 | var EqualDepth = 4;
49 | var GreaterEqualDepth = 5;
50 | var GreaterDepth = 6;
51 | var NotEqualDepth = 7;
52 | var MultiplyOperation = 0;
53 | var MixOperation = 1;
54 | var AddOperation = 2;
55 | var NoToneMapping = 0;
56 | var LinearToneMapping = 1;
57 | var ReinhardToneMapping = 2;
58 | var Uncharted2ToneMapping = 3;
59 | var CineonToneMapping = 4;
60 | var ACESFilmicToneMapping = 5;
61 |
62 | var UVMapping = 300;
63 | var CubeReflectionMapping = 301;
64 | var CubeRefractionMapping = 302;
65 | var EquirectangularReflectionMapping = 303;
66 | var EquirectangularRefractionMapping = 304;
67 | var SphericalReflectionMapping = 305;
68 | var CubeUVReflectionMapping = 306;
69 | var CubeUVRefractionMapping = 307;
70 | var RepeatWrapping = 1000;
71 | var ClampToEdgeWrapping = 1001;
72 | var MirroredRepeatWrapping = 1002;
73 | var NearestFilter = 1003;
74 | var NearestMipmapNearestFilter = 1004;
75 | var NearestMipMapNearestFilter = 1004;
76 | var NearestMipmapLinearFilter = 1005;
77 | var NearestMipMapLinearFilter = 1005;
78 | var LinearFilter = 1006;
79 | var LinearMipmapNearestFilter = 1007;
80 | var LinearMipMapNearestFilter = 1007;
81 | var LinearMipmapLinearFilter = 1008;
82 | var LinearMipMapLinearFilter = 1008;
83 | var UnsignedByteType = 1009;
84 | var ByteType = 1010;
85 | var ShortType = 1011;
86 | var UnsignedShortType = 1012;
87 | var IntType = 1013;
88 | var UnsignedIntType = 1014;
89 | var FloatType = 1015;
90 | var HalfFloatType = 1016;
91 | var UnsignedShort4444Type = 1017;
92 | var UnsignedShort5551Type = 1018;
93 | var UnsignedShort565Type = 1019;
94 | var UnsignedInt248Type = 1020;
95 | var AlphaFormat = 1021;
96 | var RGBFormat = 1022;
97 | var RGBAFormat = 1023;
98 | var LuminanceFormat = 1024;
99 | var LuminanceAlphaFormat = 1025;
100 | var RGBEFormat = RGBAFormat;
101 | var DepthFormat = 1026;
102 | var DepthStencilFormat = 1027;
103 | var RedFormat = 1028;
104 | var RedIntegerFormat = 1029;
105 | var RGFormat = 1030;
106 | var RGIntegerFormat = 1031;
107 | var RGBIntegerFormat = 1032;
108 | var RGBAIntegerFormat = 1033;
109 |
110 | var RGB_S3TC_DXT1_Format = 33776;
111 | var RGBA_S3TC_DXT1_Format = 33777;
112 | var RGBA_S3TC_DXT3_Format = 33778;
113 | var RGBA_S3TC_DXT5_Format = 33779;
114 | var RGB_PVRTC_4BPPV1_Format = 35840;
115 | var RGB_PVRTC_2BPPV1_Format = 35841;
116 | var RGBA_PVRTC_4BPPV1_Format = 35842;
117 | var RGBA_PVRTC_2BPPV1_Format = 35843;
118 | var RGB_ETC1_Format = 36196;
119 | var RGBA_ASTC_4x4_Format = 37808;
120 | var RGBA_ASTC_5x4_Format = 37809;
121 | var RGBA_ASTC_5x5_Format = 37810;
122 | var RGBA_ASTC_6x5_Format = 37811;
123 | var RGBA_ASTC_6x6_Format = 37812;
124 | var RGBA_ASTC_8x5_Format = 37813;
125 | var RGBA_ASTC_8x6_Format = 37814;
126 | var RGBA_ASTC_8x8_Format = 37815;
127 | var RGBA_ASTC_10x5_Format = 37816;
128 | var RGBA_ASTC_10x6_Format = 37817;
129 | var RGBA_ASTC_10x8_Format = 37818;
130 | var RGBA_ASTC_10x10_Format = 37819;
131 | var RGBA_ASTC_12x10_Format = 37820;
132 | var RGBA_ASTC_12x12_Format = 37821;
133 | var LoopOnce = 2200;
134 | var LoopRepeat = 2201;
135 | var LoopPingPong = 2202;
136 | var InterpolateDiscrete = 2300;
137 | var InterpolateLinear = 2301;
138 | var InterpolateSmooth = 2302;
139 | var ZeroCurvatureEnding = 2400;
140 | var ZeroSlopeEnding = 2401;
141 | var WrapAroundEnding = 2402;
142 | var TrianglesDrawMode = 0;
143 | var TriangleStripDrawMode = 1;
144 | var TriangleFanDrawMode = 2;
145 | var LinearEncoding = 3000;
146 | var sRGBEncoding = 3001;
147 | var GammaEncoding = 3007;
148 | var RGBEEncoding = 3002;
149 | var LogLuvEncoding = 3003;
150 | var RGBM7Encoding = 3004;
151 | var RGBM16Encoding = 3005;
152 | var RGBDEncoding = 3006;
153 | var BasicDepthPacking = 3200;
154 | var RGBADepthPacking = 3201;
155 | var TangentSpaceNormalMap = 0;
156 | var ObjectSpaceNormalMap = 1;
157 |
158 | var ZeroStencilOp = 0;
159 | var KeepStencilOp = 7680;
160 | var ReplaceStencilOp = 7681;
161 | var IncrementStencilOp = 7682;
162 | var DecrementStencilOp = 7683;
163 | var IncrementWrapStencilOp = 34055;
164 | var DecrementWrapStencilOp = 34056;
165 | var InvertStencilOp = 5386;
166 |
167 | var NeverStencilFunc = 512;
168 | var LessStencilFunc = 513;
169 | var EqualStencilFunc = 514;
170 | var LessEqualStencilFunc = 515;
171 | var GreaterStencilFunc = 516;
172 | var NotEqualStencilFunc = 517;
173 | var GreaterEqualStencilFunc = 518;
174 | var AlwaysStencilFunc = 519;
175 |
176 | var StaticDrawUsage = 35044;
177 | var DynamicDrawUsage = 35048;
178 | var StreamDrawUsage = 35040;
179 | var StaticReadUsage = 35045;
180 | var DynamicReadUsage = 35049;
181 | var StreamReadUsage = 35041;
182 | var StaticCopyUsage = 35046;
183 | var DynamicCopyUsage = 35050;
184 | var StreamCopyUsage = 35042;
185 |
186 | export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveBlending, AlphaFormat, AlwaysDepth, AlwaysStencilFunc, BackSide, BasicDepthPacking, BasicShadowMap, ByteType, CineonToneMapping, ClampToEdgeWrapping, CubeReflectionMapping, CubeRefractionMapping, CubeUVReflectionMapping, CubeUVRefractionMapping, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, CustomBlending, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, FaceColors, FlatShading, FloatType, FrontFaceDirectionCCW, FrontFaceDirectionCW, FrontSide, GammaEncoding, GreaterDepth, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, HalfFloatType, IncrementStencilOp, IncrementWrapStencilOp, IntType, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, LessDepth, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearToneMapping, LogLuvEncoding, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, MaxEquation, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverDepth, NeverStencilFunc, NoBlending, NoColors, NoToneMapping, NormalBlending, NotEqualDepth, NotEqualStencilFunc, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, PCFShadowMap, PCFSoftShadowMap, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBDEncoding, RGBEEncoding, RGBEFormat, RGBFormat, RGBIntegerFormat, RGBM16Encoding, RGBM7Encoding, RGB_ETC1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RedFormat, RedIntegerFormat, ReinhardToneMapping, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, ShortType, SmoothShading, SphericalReflectionMapping, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, UVMapping, Uncharted2ToneMapping, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShort565Type, UnsignedShortType, VSMShadowMap, VertexColors, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, sRGBEncoding };
187 |
--------------------------------------------------------------------------------