├── .gitignore ├── Landscape.rscd ├── README.md ├── css ├── light.css └── main.css ├── img ├── 11.png ├── 11v.png ├── 14.png ├── 14v.png ├── 3221.png ├── 3222.png ├── 3222v.png ├── 3222vw.png ├── 3222w.png ├── 3223.png ├── 3226.png ├── 3230.png ├── 3230v.png ├── 3241.png ├── 3241v.png ├── 3241vw.png ├── 3241w.png ├── 3243.png ├── 3243v.png ├── 35.bmp ├── 35v.bmp ├── 42.png ├── 42v.png ├── 6.png ├── 6v.png ├── 7.bmp └── 7v.bmp ├── index.html ├── js ├── CanvasRenderer.js ├── OrbitControls.js ├── Projector.js ├── TrackballControls.js ├── dat.gui.js ├── jszip-utils.js ├── jszip.js ├── stats.js ├── three.js ├── ui.js └── ui.three.js └── src ├── Editor.js ├── Materials.js ├── Tile.js ├── Util.js └── ui ├── Menubar.Edit.js ├── Menubar.File.js ├── Menubar.Sector.js ├── Menubar.js ├── Sidebar.EditMode.js ├── Sidebar.Settings.js ├── Sidebar.ViewMode.js ├── Sidebar.js └── Toolbar.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/modules.xml 2 | .idea/vcs.xml 3 | *.xml 4 | .idea/Starter.iml -------------------------------------------------------------------------------- /Landscape.rscd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/Landscape.rscd -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSC-Landscape-Editor-HTML5 2 | A 3D Landscape Editor for RuneScape Classic using WebGL/HTML5 3 | 4 | You will need to host these files under a web server, due to HTML5's permissions of reading local files 5 | 6 | ![alt tag](http://i.imgur.com/pLEKwr6.png) 7 | 8 | Credits to Fish for helping. 9 | -------------------------------------------------------------------------------- /css/light.css: -------------------------------------------------------------------------------- 1 | .Outliner { 2 | color: #444; 3 | background: #fff; 4 | padding: 0; 5 | width: 100%; 6 | height: 140px; 7 | font-size: 12px; 8 | cursor: default; 9 | overflow: auto; 10 | outline: none; 11 | } 12 | 13 | .Outliner .option { 14 | padding: 4px; 15 | color: #666; 16 | white-space: nowrap; 17 | } 18 | 19 | .Outliner .option:hover { 20 | background-color: rgba(0,0,0,0.02); 21 | } 22 | 23 | .Outliner .option.active { 24 | background-color: rgba(0,0,0,0.04); 25 | } 26 | 27 | input.Number { 28 | color: #0080f0!important; 29 | font-size: 12px; 30 | border: 0px; 31 | padding: 2px; 32 | cursor: col-resize; 33 | } 34 | 35 | #viewport { 36 | position: absolute; 37 | top: 32px; 38 | left: 0; 39 | right: 300px; 40 | bottom: 32px; 41 | } 42 | 43 | #viewport #info { 44 | text-shadow: 1px 1px 0 rgba(0,0,0,0.25); 45 | pointer-events: none; 46 | } 47 | 48 | #script { 49 | position: absolute; 50 | top: 32px; 51 | left: 0; 52 | right: 300px; 53 | bottom: 32px; 54 | opacity: 0.9; 55 | } 56 | 57 | #player { 58 | position: absolute; 59 | top: 32px; 60 | left: 0; 61 | right: 300px; 62 | bottom: 32px; 63 | } 64 | 65 | #menubar { 66 | position: absolute; 67 | width: 100%; 68 | height: 32px; 69 | background: #eee; 70 | padding: 0; 71 | margin: 0; 72 | right: 0; 73 | top: 0; 74 | } 75 | 76 | #menubar .menu { 77 | float: left; 78 | cursor: pointer; 79 | padding-right: 8px; 80 | } 81 | 82 | #menubar .menu.right { 83 | float: right; 84 | cursor: auto; 85 | padding-right: 0; 86 | text-align: right; 87 | } 88 | 89 | #menubar .menu .title { 90 | display: inline-block; 91 | color: #888; 92 | margin: 0; 93 | padding: 8px; 94 | } 95 | 96 | #menubar .menu .options { 97 | position: absolute; 98 | display: none; 99 | padding: 5px 0; 100 | background: #eee; 101 | width: 150px; 102 | } 103 | 104 | #menubar .menu:hover .options { 105 | display: block; 106 | } 107 | 108 | #menubar .menu .options hr { 109 | border-color: #ddd; 110 | } 111 | 112 | #menubar .menu .options .option { 113 | color: #666; 114 | background-color: transparent; 115 | padding: 5px 10px; 116 | margin: 0 !important; 117 | } 118 | 119 | #menubar .menu .options .option:hover { 120 | color: #fff; 121 | background-color: #08f; 122 | } 123 | 124 | #menubar .menu .options .option:active { 125 | color: #666; 126 | background: transparent; 127 | } 128 | 129 | #menubar .menu .options .inactive { 130 | color: #bbb; 131 | background-color: transparent; 132 | padding: 5px 10px; 133 | margin: 0 !important; 134 | } 135 | 136 | #sidebar { 137 | position: absolute; 138 | right: 0; 139 | top: 32px; 140 | bottom: 0; 141 | width: 300px; 142 | background: #eee; 143 | overflow: auto; 144 | } 145 | 146 | #sidebar * { 147 | vertical-align: middle; 148 | } 149 | 150 | #sidebar input, 151 | #sidebar textarea, 152 | #sidebar select { 153 | border: 1px solid transparent; 154 | color: #444; 155 | } 156 | 157 | #sidebar .Panel { 158 | color: #888; 159 | padding: 10px; 160 | border-top: 1px solid #ccc; 161 | } 162 | 163 | #sidebar .Panel.collapsed { 164 | margin-bottom: 0; 165 | } 166 | 167 | #sidebar .Row { 168 | min-height: 20px; 169 | margin-bottom: 10px; 170 | } 171 | 172 | #tabs { 173 | background-color: #ddd; 174 | border-top: 1px solid #ccc; 175 | } 176 | 177 | #tabs span { 178 | color: #aaa; 179 | border-right: 1px solid #ccc; 180 | padding: 10px; 181 | } 182 | 183 | #tabs span.selected { 184 | color: #888; 185 | background-color: #eee; 186 | } 187 | 188 | #toolbar { 189 | position: absolute; 190 | left: 0; 191 | right: 300px; 192 | bottom: 0; 193 | height: 32px; 194 | background: #eee; 195 | color: #333; 196 | } 197 | 198 | #toolbar * { 199 | vertical-align: middle; 200 | } 201 | 202 | #toolbar .Panel { 203 | padding: 4px; 204 | color: #888; 205 | } 206 | 207 | #toolbar button { 208 | margin-right: 6px; 209 | } 210 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Helvetica, Arial, sans-serif; 3 | font-size: 14px; 4 | margin: 0; 5 | overflow: hidden; 6 | } 7 | 8 | hr { 9 | border: 0; 10 | border-top: 1px solid #ccc; 11 | } 12 | 13 | button { 14 | position: relative; 15 | } 16 | 17 | textarea { 18 | tab-size: 4; 19 | white-space: pre; 20 | word-wrap: normal; 21 | } 22 | 23 | textarea.success { 24 | border-color: #8b8 !important; 25 | } 26 | 27 | textarea.fail { 28 | border-color: #f00 !important; 29 | background-color: rgba(255,0,0,0.05); 30 | } 31 | 32 | textarea, input { outline: none; } /* osx */ 33 | 34 | .Panel { 35 | -moz-user-select: none; 36 | -webkit-user-select: none; 37 | -ms-user-select: none; 38 | 39 | /* No support for these yet */ 40 | -o-user-select: none; 41 | user-select: none; 42 | } 43 | 44 | .Panel.Collapsible .Static { 45 | margin: 0; 46 | } 47 | 48 | .Panel.Collapsible .Static .Button { 49 | float: left; 50 | margin-right: 6px; 51 | width: 0; 52 | height: 0; 53 | border: 6px solid transparent; 54 | } 55 | 56 | .Panel.Collapsible.collapsed .Static .Button { 57 | margin-top: 2px; 58 | border-left-color: #bbb; 59 | } 60 | 61 | .Panel.Collapsible:not(.collapsed) .Static .Button { 62 | margin-top: 6px; 63 | border-top-color: #bbb; 64 | } 65 | 66 | .Panel.Collapsible.collapsed .Content { 67 | display: none; 68 | } 69 | 70 | /* CodeMirror */ 71 | 72 | .CodeMirror { 73 | 74 | position: absolute !important; 75 | top: 37px; 76 | width: 100% !important; 77 | height: calc(100% - 37px) !important; 78 | 79 | } 80 | 81 | .CodeMirror .errorLine { 82 | 83 | background: rgba(255,0,0,0.25); 84 | 85 | } 86 | 87 | .CodeMirror .esprima-error { 88 | 89 | color: #f00; 90 | text-align: right; 91 | padding: 0 20px; 92 | 93 | } 94 | 95 | /* outliner */ 96 | 97 | #outliner .option { 98 | 99 | border: 1px solid transparent; 100 | } 101 | 102 | #outliner .option.drag { 103 | 104 | border: 1px dashed #999; 105 | 106 | } 107 | 108 | #outliner .option.dragTop { 109 | 110 | border-top: 1px dashed #999; 111 | 112 | } 113 | 114 | #outliner .option.dragBottom { 115 | 116 | border-bottom: 1px dashed #999; 117 | 118 | } 119 | 120 | #outliner .type { 121 | position:relative; 122 | top:-2px; 123 | padding: 0 2px; 124 | color: #ddd; 125 | } 126 | 127 | #outliner .type:after { 128 | content: '■'; 129 | } 130 | 131 | #outliner .Scene { 132 | color: #ccccff; 133 | } 134 | 135 | #outliner .Object3D { 136 | color: #aaaaee; 137 | } 138 | 139 | #outliner .Mesh { 140 | color: #8888ee; 141 | } 142 | 143 | #outliner .Line { 144 | color: #88ee88; 145 | } 146 | 147 | #outliner .LineSegments { 148 | color: #88ee88; 149 | } 150 | 151 | #outliner .Points { 152 | color: #ee8888; 153 | } 154 | 155 | /* */ 156 | 157 | #outliner .PointLight { 158 | color: #dddd00; 159 | } 160 | 161 | /* */ 162 | 163 | #outliner .Geometry { 164 | color: #88ff88; 165 | } 166 | 167 | #outliner .BoxGeometry { 168 | color: #bbeebb; 169 | } 170 | 171 | #outliner .TorusGeometry { 172 | color: #aaeeaa; 173 | } 174 | 175 | /* */ 176 | 177 | #outliner .Material { 178 | color: #ff8888; 179 | } 180 | 181 | #outliner .MeshPhongMaterial { 182 | color: #ffaa88; 183 | } 184 | 185 | /* */ 186 | 187 | #outliner .Script:after { 188 | content: '{...}' /* ❮/❯ */ 189 | } 190 | -------------------------------------------------------------------------------- /img/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/11.png -------------------------------------------------------------------------------- /img/11v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/11v.png -------------------------------------------------------------------------------- /img/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/14.png -------------------------------------------------------------------------------- /img/14v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/14v.png -------------------------------------------------------------------------------- /img/3221.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3221.png -------------------------------------------------------------------------------- /img/3222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3222.png -------------------------------------------------------------------------------- /img/3222v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3222v.png -------------------------------------------------------------------------------- /img/3222vw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3222vw.png -------------------------------------------------------------------------------- /img/3222w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3222w.png -------------------------------------------------------------------------------- /img/3223.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3223.png -------------------------------------------------------------------------------- /img/3226.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3226.png -------------------------------------------------------------------------------- /img/3230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3230.png -------------------------------------------------------------------------------- /img/3230v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3230v.png -------------------------------------------------------------------------------- /img/3241.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3241.png -------------------------------------------------------------------------------- /img/3241v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3241v.png -------------------------------------------------------------------------------- /img/3241vw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3241vw.png -------------------------------------------------------------------------------- /img/3241w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3241w.png -------------------------------------------------------------------------------- /img/3243.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3243.png -------------------------------------------------------------------------------- /img/3243v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/3243v.png -------------------------------------------------------------------------------- /img/35.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/35.bmp -------------------------------------------------------------------------------- /img/35v.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/35v.bmp -------------------------------------------------------------------------------- /img/42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/42.png -------------------------------------------------------------------------------- /img/42v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/42v.png -------------------------------------------------------------------------------- /img/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/6.png -------------------------------------------------------------------------------- /img/6v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/6v.png -------------------------------------------------------------------------------- /img/7.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/7.bmp -------------------------------------------------------------------------------- /img/7v.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unravl/RSC-Landscape-Editor-HTML5/cca5b1f9f7da15ede04fb645d845c28bf1372d05/img/7v.bmp -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Editor 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /js/CanvasRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | THREE.SpriteCanvasMaterial = function ( parameters ) { 6 | 7 | THREE.Material.call( this ); 8 | 9 | this.type = 'SpriteCanvasMaterial'; 10 | 11 | this.color = new THREE.Color( 0xffffff ); 12 | this.program = function ( context, color ) {}; 13 | 14 | this.setValues( parameters ); 15 | 16 | }; 17 | 18 | THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); 19 | THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial; 20 | 21 | THREE.SpriteCanvasMaterial.prototype.clone = function () { 22 | 23 | var material = new THREE.SpriteCanvasMaterial(); 24 | 25 | material.copy( this ); 26 | material.color.copy( this.color ); 27 | material.program = this.program; 28 | 29 | return material; 30 | 31 | }; 32 | 33 | // 34 | 35 | THREE.CanvasRenderer = function ( parameters ) { 36 | 37 | console.log( 'THREE.CanvasRenderer', THREE.REVISION ); 38 | 39 | parameters = parameters || {}; 40 | 41 | var _this = this, 42 | _renderData, _elements, _lights, 43 | _projector = new THREE.Projector(), 44 | 45 | _canvas = parameters.canvas !== undefined 46 | ? parameters.canvas 47 | : document.createElement( 'canvas' ), 48 | 49 | _canvasWidth = _canvas.width, 50 | _canvasHeight = _canvas.height, 51 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), 52 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), 53 | 54 | _viewportX = 0, 55 | _viewportY = 0, 56 | _viewportWidth = _canvasWidth, 57 | _viewportHeight = _canvasHeight, 58 | 59 | _pixelRatio = 1, 60 | 61 | _context = _canvas.getContext( '2d', { 62 | alpha: parameters.alpha === true 63 | } ), 64 | 65 | _clearColor = new THREE.Color( 0x000000 ), 66 | _clearAlpha = parameters.alpha === true ? 0 : 1, 67 | 68 | _contextGlobalAlpha = 1, 69 | _contextGlobalCompositeOperation = 0, 70 | _contextStrokeStyle = null, 71 | _contextFillStyle = null, 72 | _contextLineWidth = null, 73 | _contextLineCap = null, 74 | _contextLineJoin = null, 75 | _contextLineDash = [], 76 | 77 | _camera, 78 | 79 | _v1, _v2, _v3, _v4, 80 | _v5 = new THREE.RenderableVertex(), 81 | _v6 = new THREE.RenderableVertex(), 82 | 83 | _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 84 | _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, 85 | 86 | _color = new THREE.Color(), 87 | _color1 = new THREE.Color(), 88 | _color2 = new THREE.Color(), 89 | _color3 = new THREE.Color(), 90 | _color4 = new THREE.Color(), 91 | 92 | _diffuseColor = new THREE.Color(), 93 | _emissiveColor = new THREE.Color(), 94 | 95 | _lightColor = new THREE.Color(), 96 | 97 | _patterns = {}, 98 | 99 | _image, _uvs, 100 | _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, 101 | 102 | _clipBox = new THREE.Box2(), 103 | _clearBox = new THREE.Box2(), 104 | _elemBox = new THREE.Box2(), 105 | 106 | _ambientLight = new THREE.Color(), 107 | _directionalLights = new THREE.Color(), 108 | _pointLights = new THREE.Color(), 109 | 110 | _vector3 = new THREE.Vector3(), // Needed for PointLight 111 | _centroid = new THREE.Vector3(), 112 | _normal = new THREE.Vector3(), 113 | _normalViewMatrix = new THREE.Matrix3(); 114 | 115 | /* TODO 116 | _canvas.mozImageSmoothingEnabled = false; 117 | _canvas.webkitImageSmoothingEnabled = false; 118 | _canvas.msImageSmoothingEnabled = false; 119 | _canvas.imageSmoothingEnabled = false; 120 | */ 121 | 122 | // dash+gap fallbacks for Firefox and everything else 123 | 124 | if ( _context.setLineDash === undefined ) { 125 | 126 | _context.setLineDash = function () {}; 127 | 128 | } 129 | 130 | this.domElement = _canvas; 131 | 132 | this.autoClear = true; 133 | this.sortObjects = true; 134 | this.sortElements = true; 135 | 136 | this.info = { 137 | 138 | render: { 139 | 140 | vertices: 0, 141 | faces: 0 142 | 143 | } 144 | 145 | }; 146 | 147 | // WebGLRenderer compatibility 148 | 149 | this.supportsVertexTextures = function () {}; 150 | this.setFaceCulling = function () {}; 151 | 152 | // API 153 | 154 | this.getContext = function () { 155 | 156 | return _context; 157 | 158 | }; 159 | 160 | this.getContextAttributes = function () { 161 | 162 | return _context.getContextAttributes(); 163 | 164 | }; 165 | 166 | this.getPixelRatio = function () { 167 | 168 | return _pixelRatio; 169 | 170 | }; 171 | 172 | this.setPixelRatio = function ( value ) { 173 | 174 | if ( value !== undefined ) _pixelRatio = value; 175 | 176 | }; 177 | 178 | this.setSize = function ( width, height, updateStyle ) { 179 | 180 | _canvasWidth = width * _pixelRatio; 181 | _canvasHeight = height * _pixelRatio; 182 | 183 | _canvas.width = _canvasWidth; 184 | _canvas.height = _canvasHeight; 185 | 186 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); 187 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); 188 | 189 | if ( updateStyle !== false ) { 190 | 191 | _canvas.style.width = width + 'px'; 192 | _canvas.style.height = height + 'px'; 193 | 194 | } 195 | 196 | _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); 197 | _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 198 | 199 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); 200 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 201 | 202 | _contextGlobalAlpha = 1; 203 | _contextGlobalCompositeOperation = 0; 204 | _contextStrokeStyle = null; 205 | _contextFillStyle = null; 206 | _contextLineWidth = null; 207 | _contextLineCap = null; 208 | _contextLineJoin = null; 209 | 210 | this.setViewport( 0, 0, width, height ); 211 | 212 | }; 213 | 214 | this.setViewport = function ( x, y, width, height ) { 215 | 216 | _viewportX = x * _pixelRatio; 217 | _viewportY = y * _pixelRatio; 218 | 219 | _viewportWidth = width * _pixelRatio; 220 | _viewportHeight = height * _pixelRatio; 221 | 222 | }; 223 | 224 | this.setScissor = function () {}; 225 | this.setScissorTest = function () {}; 226 | 227 | this.setClearColor = function ( color, alpha ) { 228 | 229 | _clearColor.set( color ); 230 | _clearAlpha = alpha !== undefined ? alpha : 1; 231 | 232 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); 233 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); 234 | 235 | }; 236 | 237 | this.setClearColorHex = function ( hex, alpha ) { 238 | 239 | console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); 240 | this.setClearColor( hex, alpha ); 241 | 242 | }; 243 | 244 | this.getClearColor = function () { 245 | 246 | return _clearColor; 247 | 248 | }; 249 | 250 | this.getClearAlpha = function () { 251 | 252 | return _clearAlpha; 253 | 254 | }; 255 | 256 | this.getMaxAnisotropy = function () { 257 | 258 | return 0; 259 | 260 | }; 261 | 262 | this.clear = function () { 263 | 264 | if ( _clearBox.isEmpty() === false ) { 265 | 266 | _clearBox.intersect( _clipBox ); 267 | _clearBox.expandByScalar( 2 ); 268 | 269 | _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf; 270 | _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value ! 271 | _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf; 272 | _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value ! 273 | 274 | if ( _clearAlpha < 1 ) { 275 | 276 | _context.clearRect( 277 | _clearBox.min.x | 0, 278 | _clearBox.max.y | 0, 279 | ( _clearBox.max.x - _clearBox.min.x ) | 0, 280 | ( _clearBox.min.y - _clearBox.max.y ) | 0 281 | ); 282 | 283 | } 284 | 285 | if ( _clearAlpha > 0 ) { 286 | 287 | setBlending( THREE.NormalBlending ); 288 | setOpacity( 1 ); 289 | 290 | setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); 291 | 292 | _context.fillRect( 293 | _clearBox.min.x | 0, 294 | _clearBox.max.y | 0, 295 | ( _clearBox.max.x - _clearBox.min.x ) | 0, 296 | ( _clearBox.min.y - _clearBox.max.y ) | 0 297 | ); 298 | 299 | } 300 | 301 | _clearBox.makeEmpty(); 302 | 303 | } 304 | 305 | }; 306 | 307 | // compatibility 308 | 309 | this.clearColor = function () {}; 310 | this.clearDepth = function () {}; 311 | this.clearStencil = function () {}; 312 | 313 | this.render = function ( scene, camera ) { 314 | 315 | if ( camera instanceof THREE.Camera === false ) { 316 | 317 | console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); 318 | return; 319 | 320 | } 321 | 322 | if ( this.autoClear === true ) this.clear(); 323 | 324 | _this.info.render.vertices = 0; 325 | _this.info.render.faces = 0; 326 | 327 | _context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY ); 328 | _context.translate( _canvasWidthHalf, _canvasHeightHalf ); 329 | 330 | _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); 331 | _elements = _renderData.elements; 332 | _lights = _renderData.lights; 333 | _camera = camera; 334 | 335 | _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); 336 | 337 | /* DEBUG 338 | setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); 339 | _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); 340 | */ 341 | 342 | calculateLights(); 343 | 344 | for ( var e = 0, el = _elements.length; e < el; e ++ ) { 345 | 346 | var element = _elements[ e ]; 347 | 348 | var material = element.material; 349 | 350 | if ( material === undefined || material.opacity === 0 ) continue; 351 | 352 | _elemBox.makeEmpty(); 353 | 354 | if ( element instanceof THREE.RenderableSprite ) { 355 | 356 | _v1 = element; 357 | _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; 358 | 359 | renderSprite( _v1, element, material ); 360 | 361 | } else if ( element instanceof THREE.RenderableLine ) { 362 | 363 | _v1 = element.v1; _v2 = element.v2; 364 | 365 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; 366 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; 367 | 368 | _elemBox.setFromPoints( [ 369 | _v1.positionScreen, 370 | _v2.positionScreen 371 | ] ); 372 | 373 | if ( _clipBox.intersectsBox( _elemBox ) === true ) { 374 | 375 | renderLine( _v1, _v2, element, material ); 376 | 377 | } 378 | 379 | } else if ( element instanceof THREE.RenderableFace ) { 380 | 381 | _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; 382 | 383 | if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue; 384 | if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue; 385 | if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue; 386 | 387 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; 388 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; 389 | _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; 390 | 391 | if ( material.overdraw > 0 ) { 392 | 393 | expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); 394 | expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); 395 | expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); 396 | 397 | } 398 | 399 | _elemBox.setFromPoints( [ 400 | _v1.positionScreen, 401 | _v2.positionScreen, 402 | _v3.positionScreen 403 | ] ); 404 | 405 | if ( _clipBox.intersectsBox( _elemBox ) === true ) { 406 | 407 | renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); 408 | 409 | } 410 | 411 | } 412 | 413 | /* DEBUG 414 | setLineWidth( 1 ); 415 | setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); 416 | _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); 417 | */ 418 | 419 | _clearBox.union( _elemBox ); 420 | 421 | } 422 | 423 | /* DEBUG 424 | setLineWidth( 1 ); 425 | setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); 426 | _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); 427 | */ 428 | 429 | _context.setTransform( 1, 0, 0, 1, 0, 0 ); 430 | 431 | }; 432 | 433 | // 434 | 435 | function calculateLights() { 436 | 437 | _ambientLight.setRGB( 0, 0, 0 ); 438 | _directionalLights.setRGB( 0, 0, 0 ); 439 | _pointLights.setRGB( 0, 0, 0 ); 440 | 441 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { 442 | 443 | var light = _lights[ l ]; 444 | var lightColor = light.color; 445 | 446 | if ( light instanceof THREE.AmbientLight ) { 447 | 448 | _ambientLight.add( lightColor ); 449 | 450 | } else if ( light instanceof THREE.DirectionalLight ) { 451 | 452 | // for sprites 453 | 454 | _directionalLights.add( lightColor ); 455 | 456 | } else if ( light instanceof THREE.PointLight ) { 457 | 458 | // for sprites 459 | 460 | _pointLights.add( lightColor ); 461 | 462 | } 463 | 464 | } 465 | 466 | } 467 | 468 | function calculateLight( position, normal, color ) { 469 | 470 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { 471 | 472 | var light = _lights[ l ]; 473 | 474 | _lightColor.copy( light.color ); 475 | 476 | if ( light instanceof THREE.DirectionalLight ) { 477 | 478 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); 479 | 480 | var amount = normal.dot( lightPosition ); 481 | 482 | if ( amount <= 0 ) continue; 483 | 484 | amount *= light.intensity; 485 | 486 | color.add( _lightColor.multiplyScalar( amount ) ); 487 | 488 | } else if ( light instanceof THREE.PointLight ) { 489 | 490 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); 491 | 492 | var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); 493 | 494 | if ( amount <= 0 ) continue; 495 | 496 | amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); 497 | 498 | if ( amount == 0 ) continue; 499 | 500 | amount *= light.intensity; 501 | 502 | color.add( _lightColor.multiplyScalar( amount ) ); 503 | 504 | } 505 | 506 | } 507 | 508 | } 509 | 510 | function renderSprite( v1, element, material ) { 511 | 512 | setOpacity( material.opacity ); 513 | setBlending( material.blending ); 514 | 515 | var scaleX = element.scale.x * _canvasWidthHalf; 516 | var scaleY = element.scale.y * _canvasHeightHalf; 517 | 518 | var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite 519 | _elemBox.min.set( v1.x - dist, v1.y - dist ); 520 | _elemBox.max.set( v1.x + dist, v1.y + dist ); 521 | 522 | if ( material instanceof THREE.SpriteMaterial ) { 523 | 524 | var texture = material.map; 525 | 526 | if ( texture !== null ) { 527 | 528 | var pattern = _patterns[ texture.id ]; 529 | 530 | if ( pattern === undefined || pattern.version !== texture.version ) { 531 | 532 | pattern = textureToPattern( texture ); 533 | _patterns[ texture.id ] = pattern; 534 | 535 | } 536 | 537 | if ( pattern.canvas !== undefined ) { 538 | 539 | setFillStyle( pattern.canvas ); 540 | 541 | var bitmap = texture.image; 542 | 543 | var ox = bitmap.width * texture.offset.x; 544 | var oy = bitmap.height * texture.offset.y; 545 | 546 | var sx = bitmap.width * texture.repeat.x; 547 | var sy = bitmap.height * texture.repeat.y; 548 | 549 | var cx = scaleX / sx; 550 | var cy = scaleY / sy; 551 | 552 | _context.save(); 553 | _context.translate( v1.x, v1.y ); 554 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 555 | _context.translate( - scaleX / 2, - scaleY / 2 ); 556 | _context.scale( cx, cy ); 557 | _context.translate( - ox, - oy ); 558 | _context.fillRect( ox, oy, sx, sy ); 559 | _context.restore(); 560 | 561 | } 562 | 563 | } else { 564 | 565 | // no texture 566 | 567 | setFillStyle( material.color.getStyle() ); 568 | 569 | _context.save(); 570 | _context.translate( v1.x, v1.y ); 571 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 572 | _context.scale( scaleX, - scaleY ); 573 | _context.fillRect( - 0.5, - 0.5, 1, 1 ); 574 | _context.restore(); 575 | 576 | } 577 | 578 | } else if ( material instanceof THREE.SpriteCanvasMaterial ) { 579 | 580 | setStrokeStyle( material.color.getStyle() ); 581 | setFillStyle( material.color.getStyle() ); 582 | 583 | _context.save(); 584 | _context.translate( v1.x, v1.y ); 585 | if ( material.rotation !== 0 ) _context.rotate( material.rotation ); 586 | _context.scale( scaleX, scaleY ); 587 | 588 | material.program( _context ); 589 | 590 | _context.restore(); 591 | 592 | } 593 | 594 | /* DEBUG 595 | setStrokeStyle( 'rgb(255,255,0)' ); 596 | _context.beginPath(); 597 | _context.moveTo( v1.x - 10, v1.y ); 598 | _context.lineTo( v1.x + 10, v1.y ); 599 | _context.moveTo( v1.x, v1.y - 10 ); 600 | _context.lineTo( v1.x, v1.y + 10 ); 601 | _context.stroke(); 602 | */ 603 | 604 | } 605 | 606 | function renderLine( v1, v2, element, material ) { 607 | 608 | setOpacity( material.opacity ); 609 | setBlending( material.blending ); 610 | 611 | _context.beginPath(); 612 | _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); 613 | _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); 614 | 615 | if ( material instanceof THREE.LineBasicMaterial ) { 616 | 617 | setLineWidth( material.linewidth ); 618 | setLineCap( material.linecap ); 619 | setLineJoin( material.linejoin ); 620 | 621 | if ( material.vertexColors !== THREE.VertexColors ) { 622 | 623 | setStrokeStyle( material.color.getStyle() ); 624 | 625 | } else { 626 | 627 | var colorStyle1 = element.vertexColors[ 0 ].getStyle(); 628 | var colorStyle2 = element.vertexColors[ 1 ].getStyle(); 629 | 630 | if ( colorStyle1 === colorStyle2 ) { 631 | 632 | setStrokeStyle( colorStyle1 ); 633 | 634 | } else { 635 | 636 | try { 637 | 638 | var grad = _context.createLinearGradient( 639 | v1.positionScreen.x, 640 | v1.positionScreen.y, 641 | v2.positionScreen.x, 642 | v2.positionScreen.y 643 | ); 644 | grad.addColorStop( 0, colorStyle1 ); 645 | grad.addColorStop( 1, colorStyle2 ); 646 | 647 | } catch ( exception ) { 648 | 649 | grad = colorStyle1; 650 | 651 | } 652 | 653 | setStrokeStyle( grad ); 654 | 655 | } 656 | 657 | } 658 | 659 | _context.stroke(); 660 | _elemBox.expandByScalar( material.linewidth * 2 ); 661 | 662 | } else if ( material instanceof THREE.LineDashedMaterial ) { 663 | 664 | setLineWidth( material.linewidth ); 665 | setLineCap( material.linecap ); 666 | setLineJoin( material.linejoin ); 667 | setStrokeStyle( material.color.getStyle() ); 668 | setLineDash( [ material.dashSize, material.gapSize ] ); 669 | 670 | _context.stroke(); 671 | 672 | _elemBox.expandByScalar( material.linewidth * 2 ); 673 | 674 | setLineDash( [] ); 675 | 676 | } 677 | 678 | } 679 | 680 | function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { 681 | 682 | _this.info.render.vertices += 3; 683 | _this.info.render.faces ++; 684 | 685 | setOpacity( material.opacity ); 686 | setBlending( material.blending ); 687 | 688 | _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; 689 | _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; 690 | _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; 691 | 692 | drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); 693 | 694 | if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { 695 | 696 | _diffuseColor.copy( material.color ); 697 | _emissiveColor.copy( material.emissive ); 698 | 699 | if ( material.vertexColors === THREE.FaceColors ) { 700 | 701 | _diffuseColor.multiply( element.color ); 702 | 703 | } 704 | 705 | _color.copy( _ambientLight ); 706 | 707 | _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 ); 708 | 709 | calculateLight( _centroid, element.normalModel, _color ); 710 | 711 | _color.multiply( _diffuseColor ).add( _emissiveColor ); 712 | 713 | material.wireframe === true 714 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 715 | : fillPath( _color ); 716 | 717 | } else if ( material instanceof THREE.MeshBasicMaterial || 718 | material instanceof THREE.MeshLambertMaterial || 719 | material instanceof THREE.MeshPhongMaterial ) { 720 | 721 | if ( material.map !== null ) { 722 | 723 | var mapping = material.map.mapping; 724 | 725 | if ( mapping === THREE.UVMapping ) { 726 | 727 | _uvs = element.uvs; 728 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); 729 | 730 | } 731 | 732 | } else if ( material.envMap !== null ) { 733 | 734 | if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) { 735 | 736 | _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); 737 | _uv1x = 0.5 * _normal.x + 0.5; 738 | _uv1y = 0.5 * _normal.y + 0.5; 739 | 740 | _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); 741 | _uv2x = 0.5 * _normal.x + 0.5; 742 | _uv2y = 0.5 * _normal.y + 0.5; 743 | 744 | _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); 745 | _uv3x = 0.5 * _normal.x + 0.5; 746 | _uv3y = 0.5 * _normal.y + 0.5; 747 | 748 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); 749 | 750 | } 751 | 752 | } else { 753 | 754 | _color.copy( material.color ); 755 | 756 | if ( material.vertexColors === THREE.FaceColors ) { 757 | 758 | _color.multiply( element.color ); 759 | 760 | } 761 | 762 | material.wireframe === true 763 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 764 | : fillPath( _color ); 765 | 766 | } 767 | 768 | } else if ( material instanceof THREE.MeshNormalMaterial ) { 769 | 770 | _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); 771 | 772 | _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); 773 | 774 | material.wireframe === true 775 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 776 | : fillPath( _color ); 777 | 778 | } else { 779 | 780 | _color.setRGB( 1, 1, 1 ); 781 | 782 | material.wireframe === true 783 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) 784 | : fillPath( _color ); 785 | 786 | } 787 | 788 | } 789 | 790 | // 791 | 792 | function drawTriangle( x0, y0, x1, y1, x2, y2 ) { 793 | 794 | _context.beginPath(); 795 | _context.moveTo( x0, y0 ); 796 | _context.lineTo( x1, y1 ); 797 | _context.lineTo( x2, y2 ); 798 | _context.closePath(); 799 | 800 | } 801 | 802 | function strokePath( color, linewidth, linecap, linejoin ) { 803 | 804 | setLineWidth( linewidth ); 805 | setLineCap( linecap ); 806 | setLineJoin( linejoin ); 807 | setStrokeStyle( color.getStyle() ); 808 | 809 | _context.stroke(); 810 | 811 | _elemBox.expandByScalar( linewidth * 2 ); 812 | 813 | } 814 | 815 | function fillPath( color ) { 816 | 817 | setFillStyle( color.getStyle() ); 818 | _context.fill(); 819 | 820 | } 821 | 822 | function textureToPattern( texture ) { 823 | 824 | if ( texture.version === 0 || 825 | texture instanceof THREE.CompressedTexture || 826 | texture instanceof THREE.DataTexture ) { 827 | 828 | return { 829 | canvas: undefined, 830 | version: texture.version 831 | }; 832 | 833 | } 834 | 835 | var image = texture.image; 836 | 837 | if ( image.complete === false ) { 838 | 839 | return { 840 | canvas: undefined, 841 | version: 0 842 | }; 843 | 844 | } 845 | 846 | var canvas = document.createElement( 'canvas' ); 847 | canvas.width = image.width; 848 | canvas.height = image.height; 849 | 850 | var context = canvas.getContext( '2d' ); 851 | context.setTransform( 1, 0, 0, - 1, 0, image.height ); 852 | context.drawImage( image, 0, 0 ); 853 | 854 | var repeatX = texture.wrapS === THREE.RepeatWrapping; 855 | var repeatY = texture.wrapT === THREE.RepeatWrapping; 856 | 857 | var repeat = 'no-repeat'; 858 | 859 | if ( repeatX === true && repeatY === true ) { 860 | 861 | repeat = 'repeat'; 862 | 863 | } else if ( repeatX === true ) { 864 | 865 | repeat = 'repeat-x'; 866 | 867 | } else if ( repeatY === true ) { 868 | 869 | repeat = 'repeat-y'; 870 | 871 | } 872 | 873 | var pattern = _context.createPattern( canvas, repeat ); 874 | 875 | if ( texture.onUpdate ) texture.onUpdate( texture ); 876 | 877 | return { 878 | canvas: pattern, 879 | version: texture.version 880 | }; 881 | 882 | } 883 | 884 | function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { 885 | 886 | var pattern = _patterns[ texture.id ]; 887 | 888 | if ( pattern === undefined || pattern.version !== texture.version ) { 889 | 890 | pattern = textureToPattern( texture ); 891 | _patterns[ texture.id ] = pattern; 892 | 893 | } 894 | 895 | if ( pattern.canvas !== undefined ) { 896 | 897 | setFillStyle( pattern.canvas ); 898 | 899 | } else { 900 | 901 | setFillStyle( 'rgba( 0, 0, 0, 1)' ); 902 | _context.fill(); 903 | return; 904 | 905 | } 906 | 907 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 908 | 909 | var a, b, c, d, e, f, det, idet, 910 | offsetX = texture.offset.x / texture.repeat.x, 911 | offsetY = texture.offset.y / texture.repeat.y, 912 | width = texture.image.width * texture.repeat.x, 913 | height = texture.image.height * texture.repeat.y; 914 | 915 | u0 = ( u0 + offsetX ) * width; 916 | v0 = ( v0 + offsetY ) * height; 917 | 918 | u1 = ( u1 + offsetX ) * width; 919 | v1 = ( v1 + offsetY ) * height; 920 | 921 | u2 = ( u2 + offsetX ) * width; 922 | v2 = ( v2 + offsetY ) * height; 923 | 924 | x1 -= x0; y1 -= y0; 925 | x2 -= x0; y2 -= y0; 926 | 927 | u1 -= u0; v1 -= v0; 928 | u2 -= u0; v2 -= v0; 929 | 930 | det = u1 * v2 - u2 * v1; 931 | 932 | if ( det === 0 ) return; 933 | 934 | idet = 1 / det; 935 | 936 | a = ( v2 * x1 - v1 * x2 ) * idet; 937 | b = ( v2 * y1 - v1 * y2 ) * idet; 938 | c = ( u1 * x2 - u2 * x1 ) * idet; 939 | d = ( u1 * y2 - u2 * y1 ) * idet; 940 | 941 | e = x0 - a * u0 - c * v0; 942 | f = y0 - b * u0 - d * v0; 943 | 944 | _context.save(); 945 | _context.transform( a, b, c, d, e, f ); 946 | _context.fill(); 947 | _context.restore(); 948 | 949 | } 950 | 951 | function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { 952 | 953 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 954 | 955 | var a, b, c, d, e, f, det, idet, 956 | width = image.width - 1, 957 | height = image.height - 1; 958 | 959 | u0 *= width; v0 *= height; 960 | u1 *= width; v1 *= height; 961 | u2 *= width; v2 *= height; 962 | 963 | x1 -= x0; y1 -= y0; 964 | x2 -= x0; y2 -= y0; 965 | 966 | u1 -= u0; v1 -= v0; 967 | u2 -= u0; v2 -= v0; 968 | 969 | det = u1 * v2 - u2 * v1; 970 | 971 | idet = 1 / det; 972 | 973 | a = ( v2 * x1 - v1 * x2 ) * idet; 974 | b = ( v2 * y1 - v1 * y2 ) * idet; 975 | c = ( u1 * x2 - u2 * x1 ) * idet; 976 | d = ( u1 * y2 - u2 * y1 ) * idet; 977 | 978 | e = x0 - a * u0 - c * v0; 979 | f = y0 - b * u0 - d * v0; 980 | 981 | _context.save(); 982 | _context.transform( a, b, c, d, e, f ); 983 | _context.clip(); 984 | _context.drawImage( image, 0, 0 ); 985 | _context.restore(); 986 | 987 | } 988 | 989 | // Hide anti-alias gaps 990 | 991 | function expand( v1, v2, pixels ) { 992 | 993 | var x = v2.x - v1.x, y = v2.y - v1.y, 994 | det = x * x + y * y, idet; 995 | 996 | if ( det === 0 ) return; 997 | 998 | idet = pixels / Math.sqrt( det ); 999 | 1000 | x *= idet; y *= idet; 1001 | 1002 | v2.x += x; v2.y += y; 1003 | v1.x -= x; v1.y -= y; 1004 | 1005 | } 1006 | 1007 | // Context cached methods. 1008 | 1009 | function setOpacity( value ) { 1010 | 1011 | if ( _contextGlobalAlpha !== value ) { 1012 | 1013 | _context.globalAlpha = value; 1014 | _contextGlobalAlpha = value; 1015 | 1016 | } 1017 | 1018 | } 1019 | 1020 | function setBlending( value ) { 1021 | 1022 | if ( _contextGlobalCompositeOperation !== value ) { 1023 | 1024 | if ( value === THREE.NormalBlending ) { 1025 | 1026 | _context.globalCompositeOperation = 'source-over'; 1027 | 1028 | } else if ( value === THREE.AdditiveBlending ) { 1029 | 1030 | _context.globalCompositeOperation = 'lighter'; 1031 | 1032 | } else if ( value === THREE.SubtractiveBlending ) { 1033 | 1034 | _context.globalCompositeOperation = 'darker'; 1035 | 1036 | } else if ( value === THREE.MultiplyBlending ) { 1037 | 1038 | _context.globalCompositeOperation = 'multiply'; 1039 | 1040 | } 1041 | 1042 | _contextGlobalCompositeOperation = value; 1043 | 1044 | } 1045 | 1046 | } 1047 | 1048 | function setLineWidth( value ) { 1049 | 1050 | if ( _contextLineWidth !== value ) { 1051 | 1052 | _context.lineWidth = value; 1053 | _contextLineWidth = value; 1054 | 1055 | } 1056 | 1057 | } 1058 | 1059 | function setLineCap( value ) { 1060 | 1061 | // "butt", "round", "square" 1062 | 1063 | if ( _contextLineCap !== value ) { 1064 | 1065 | _context.lineCap = value; 1066 | _contextLineCap = value; 1067 | 1068 | } 1069 | 1070 | } 1071 | 1072 | function setLineJoin( value ) { 1073 | 1074 | // "round", "bevel", "miter" 1075 | 1076 | if ( _contextLineJoin !== value ) { 1077 | 1078 | _context.lineJoin = value; 1079 | _contextLineJoin = value; 1080 | 1081 | } 1082 | 1083 | } 1084 | 1085 | function setStrokeStyle( value ) { 1086 | 1087 | if ( _contextStrokeStyle !== value ) { 1088 | 1089 | _context.strokeStyle = value; 1090 | _contextStrokeStyle = value; 1091 | 1092 | } 1093 | 1094 | } 1095 | 1096 | function setFillStyle( value ) { 1097 | 1098 | if ( _contextFillStyle !== value ) { 1099 | 1100 | _context.fillStyle = value; 1101 | _contextFillStyle = value; 1102 | 1103 | } 1104 | 1105 | } 1106 | 1107 | function setLineDash( value ) { 1108 | 1109 | if ( _contextLineDash.length !== value.length ) { 1110 | 1111 | _context.setLineDash( value ); 1112 | _contextLineDash = value; 1113 | 1114 | } 1115 | 1116 | } 1117 | 1118 | }; -------------------------------------------------------------------------------- /js/OrbitControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author qiao / https://github.com/qiao 3 | * @author mrdoob / http://mrdoob.com 4 | * @author alteredq / http://alteredqualia.com/ 5 | * @author WestLangley / http://github.com/WestLangley 6 | * @author erich666 / http://erichaines.com 7 | * @author mrflix / http://felixniklas.de 8 | * 9 | * released under MIT License (MIT) 10 | */ 11 | /*global THREE, console */ 12 | 13 | // This set of controls performs orbiting, dollying (zooming), and panning. It maintains 14 | // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is 15 | // supported. 16 | // 17 | // Orbit - left mouse / touch: one finger move 18 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish 19 | // Pan - right mouse, or arrow keys / touch: three finter swipe 20 | // 21 | // This is a drop-in replacement for (most) TrackballControls used in examples. 22 | // That is, include this js file and wherever you see: 23 | // controls = new THREE.TrackballControls( camera ); 24 | // controls.target.z = 150; 25 | // Simple substitute "OrbitControls" and the control should work as-is. 26 | 27 | THREE.OrbitControls = function ( object, domElement, localElement ) { 28 | 29 | this.object = object; 30 | this.domElement = ( domElement !== undefined ) ? domElement : document; 31 | this.localElement = ( localElement !== undefined ) ? localElement : document; 32 | 33 | // API 34 | 35 | // Set to false to disable this control 36 | this.enabled = true; 37 | 38 | // "target" sets the location of focus, where the control orbits around 39 | // and where it pans with respect to. 40 | this.target = new THREE.Vector3(); 41 | // center is old, deprecated; use "target" instead 42 | this.center = this.target; 43 | 44 | // This option actually enables dollying in and out; left as "zoom" for 45 | // backwards compatibility 46 | this.noZoom = false; 47 | this.zoomSpeed = 1.0; 48 | // Limits to how far you can dolly in and out 49 | this.minDistance = 0; 50 | this.maxDistance = Infinity; 51 | 52 | // Set to true to disable this control 53 | this.noRotate = false; 54 | this.rotateSpeed = 1.0; 55 | 56 | // Set to true to disable this control 57 | this.noPan = false; 58 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push 59 | 60 | // Set to true to automatically rotate around the target 61 | this.autoRotate = false; 62 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 63 | 64 | // How far you can orbit vertically, upper and lower limits. 65 | // Range is 0 to Math.PI radians. 66 | this.minPolarAngle = 0; // radians 67 | this.maxPolarAngle = Math.PI; // radians 68 | 69 | // Set to true to disable use of the keys 70 | this.noKeys = false; 71 | // The four arrow keys 72 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; 73 | 74 | //////////// 75 | // internals 76 | 77 | var scope = this; 78 | 79 | var EPS = 0.000001; 80 | 81 | var rotateStart = new THREE.Vector2(); 82 | var rotateEnd = new THREE.Vector2(); 83 | var rotateDelta = new THREE.Vector2(); 84 | 85 | var panStart = new THREE.Vector2(); 86 | var panEnd = new THREE.Vector2(); 87 | var panDelta = new THREE.Vector2(); 88 | 89 | var dollyStart = new THREE.Vector2(); 90 | var dollyEnd = new THREE.Vector2(); 91 | var dollyDelta = new THREE.Vector2(); 92 | 93 | var phiDelta = 0; 94 | var thetaDelta = 0; 95 | var scale = 1; 96 | var pan = new THREE.Vector3(); 97 | 98 | var lastPosition = new THREE.Vector3(); 99 | 100 | var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 }; 101 | var state = STATE.NONE; 102 | 103 | // events 104 | 105 | var changeEvent = { type: 'change' }; 106 | 107 | 108 | this.rotateLeft = function ( angle ) { 109 | 110 | if ( angle === undefined ) { 111 | 112 | angle = getAutoRotationAngle(); 113 | 114 | } 115 | 116 | thetaDelta -= angle; 117 | 118 | }; 119 | 120 | this.rotateUp = function ( angle ) { 121 | 122 | if ( angle === undefined ) { 123 | 124 | angle = getAutoRotationAngle(); 125 | 126 | } 127 | 128 | phiDelta -= angle; 129 | 130 | }; 131 | 132 | // pass in distance in world space to move left 133 | this.panLeft = function ( distance ) { 134 | 135 | var panOffset = new THREE.Vector3(); 136 | var te = this.object.matrix.elements; 137 | // get X column of matrix 138 | panOffset.set( te[0], te[1], te[2] ); 139 | panOffset.multiplyScalar(-distance); 140 | 141 | pan.add( panOffset ); 142 | 143 | }; 144 | 145 | // pass in distance in world space to move up 146 | this.panUp = function ( distance ) { 147 | 148 | var panOffset = new THREE.Vector3(); 149 | var te = this.object.matrix.elements; 150 | // get Y column of matrix 151 | panOffset.set( te[4], te[5], te[6] ); 152 | panOffset.multiplyScalar(distance); 153 | 154 | pan.add( panOffset ); 155 | }; 156 | 157 | // main entry point; pass in Vector2 of change desired in pixel space, 158 | // right and down are positive 159 | this.pan = function ( delta ) { 160 | 161 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 162 | 163 | if ( scope.object.fov !== undefined ) { 164 | 165 | // perspective 166 | var position = scope.object.position; 167 | var offset = position.clone().sub( scope.target ); 168 | var targetDistance = offset.length(); 169 | 170 | // half of the fov is center to top of screen 171 | targetDistance *= Math.tan( (scope.object.fov/2) * Math.PI / 180.0 ); 172 | // we actually don't use screenWidth, since perspective camera is fixed to screen height 173 | scope.panLeft( 2 * delta.x * targetDistance / element.clientHeight ); 174 | scope.panUp( 2 * delta.y * targetDistance / element.clientHeight ); 175 | 176 | } else if ( scope.object.top !== undefined ) { 177 | 178 | // orthographic 179 | scope.panLeft( delta.x * (scope.object.right - scope.object.left) / element.clientWidth ); 180 | scope.panUp( delta.y * (scope.object.top - scope.object.bottom) / element.clientHeight ); 181 | 182 | } else { 183 | 184 | // camera neither orthographic or perspective - warn user 185 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); 186 | 187 | } 188 | 189 | }; 190 | 191 | this.dollyIn = function ( dollyScale ) { 192 | 193 | if ( dollyScale === undefined ) { 194 | 195 | dollyScale = getZoomScale(); 196 | 197 | } 198 | 199 | scale /= dollyScale; 200 | 201 | }; 202 | 203 | this.dollyOut = function ( dollyScale ) { 204 | 205 | if ( dollyScale === undefined ) { 206 | 207 | dollyScale = getZoomScale(); 208 | 209 | } 210 | 211 | scale *= dollyScale; 212 | 213 | }; 214 | 215 | this.update = function () { 216 | 217 | var position = this.object.position; 218 | var offset = position.clone().sub( this.target ); 219 | 220 | // angle from z-axis around y-axis 221 | 222 | var theta = Math.atan2( offset.x, offset.z ); 223 | 224 | // angle from y-axis 225 | 226 | var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y ); 227 | 228 | if ( this.autoRotate ) { 229 | 230 | this.rotateLeft( getAutoRotationAngle() ); 231 | 232 | } 233 | 234 | theta += thetaDelta; 235 | phi += phiDelta; 236 | 237 | // restrict phi to be between desired limits 238 | phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) ); 239 | 240 | // restrict phi to be betwee EPS and PI-EPS 241 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) ); 242 | 243 | var radius = offset.length() * scale; 244 | 245 | // restrict radius to be between desired limits 246 | radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) ); 247 | 248 | // move target to panned location 249 | this.target.add( pan ); 250 | 251 | offset.x = radius * Math.sin( phi ) * Math.sin( theta ); 252 | offset.y = radius * Math.cos( phi ); 253 | offset.z = radius * Math.sin( phi ) * Math.cos( theta ); 254 | 255 | position.copy( this.target ).add( offset ); 256 | 257 | this.object.lookAt( this.target ); 258 | 259 | thetaDelta = 0; 260 | phiDelta = 0; 261 | scale = 1; 262 | pan.set(0,0,0); 263 | 264 | if ( lastPosition.distanceTo( this.object.position ) > 0 ) { 265 | 266 | this.dispatchEvent( changeEvent ); 267 | 268 | lastPosition.copy( this.object.position ); 269 | 270 | } 271 | 272 | }; 273 | 274 | 275 | function getAutoRotationAngle() { 276 | 277 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; 278 | 279 | } 280 | 281 | function getZoomScale() { 282 | 283 | return Math.pow( 0.95, scope.zoomSpeed ); 284 | 285 | } 286 | 287 | function onMouseDown( event ) { 288 | 289 | if ( scope.enabled === false ) { return; } 290 | event.preventDefault(); 291 | 292 | if ( event.button === 0 ) { 293 | if ( scope.noRotate === true ) { return; } 294 | 295 | state = STATE.ROTATE; 296 | 297 | rotateStart.set( event.clientX, event.clientY ); 298 | 299 | } else if ( event.button === 1 ) { 300 | if ( scope.noZoom === true ) { return; } 301 | 302 | state = STATE.DOLLY; 303 | 304 | dollyStart.set( event.clientX, event.clientY ); 305 | 306 | } else if ( event.button === 2 ) { 307 | if ( scope.noPan === true ) { return; } 308 | 309 | state = STATE.PAN; 310 | 311 | panStart.set( event.clientX, event.clientY ); 312 | 313 | } 314 | 315 | // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be 316 | scope.domElement.addEventListener( 'mousemove', onMouseMove, false ); 317 | scope.domElement.addEventListener( 'mouseup', onMouseUp, false ); 318 | 319 | } 320 | 321 | function onMouseMove( event ) { 322 | 323 | if ( scope.enabled === false ) return; 324 | 325 | event.preventDefault(); 326 | 327 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 328 | 329 | if ( state === STATE.ROTATE ) { 330 | 331 | if ( scope.noRotate === true ) return; 332 | 333 | rotateEnd.set( event.clientX, event.clientY ); 334 | rotateDelta.subVectors( rotateEnd, rotateStart ); 335 | 336 | // rotating across whole screen goes 360 degrees around 337 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 338 | // rotating up and down along whole screen attempts to go 360, but limited to 180 339 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 340 | 341 | rotateStart.copy( rotateEnd ); 342 | 343 | } else if ( state === STATE.DOLLY ) { 344 | 345 | if ( scope.noZoom === true ) return; 346 | 347 | dollyEnd.set( event.clientX, event.clientY ); 348 | dollyDelta.subVectors( dollyEnd, dollyStart ); 349 | 350 | if ( dollyDelta.y > 0 ) { 351 | 352 | scope.dollyIn(); 353 | 354 | } else { 355 | 356 | scope.dollyOut(); 357 | 358 | } 359 | 360 | dollyStart.copy( dollyEnd ); 361 | 362 | } else if ( state === STATE.PAN ) { 363 | 364 | if ( scope.noPan === true ) return; 365 | 366 | panEnd.set( event.clientX, event.clientY ); 367 | panDelta.subVectors( panEnd, panStart ); 368 | 369 | scope.pan( panDelta ); 370 | 371 | panStart.copy( panEnd ); 372 | 373 | } 374 | 375 | // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be 376 | scope.update(); 377 | 378 | } 379 | 380 | function onMouseUp( /* event */ ) { 381 | 382 | if ( scope.enabled === false ) return; 383 | 384 | // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be 385 | scope.domElement.removeEventListener( 'mousemove', onMouseMove, false ); 386 | scope.domElement.removeEventListener( 'mouseup', onMouseUp, false ); 387 | 388 | state = STATE.NONE; 389 | 390 | } 391 | 392 | function onMouseWheel( event ) { 393 | 394 | if ( scope.enabled === false || scope.noZoom === true ) return; 395 | 396 | var delta = 0; 397 | 398 | if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9 399 | 400 | delta = event.wheelDelta; 401 | 402 | } else if ( event.detail ) { // Firefox 403 | 404 | delta = - event.detail; 405 | 406 | } 407 | 408 | if ( delta > 0 ) { 409 | 410 | scope.dollyOut(); 411 | 412 | } else { 413 | 414 | scope.dollyIn(); 415 | 416 | } 417 | 418 | } 419 | 420 | function onKeyDown( event ) { 421 | 422 | if ( scope.enabled === false ) { return; } 423 | if ( scope.noKeys === true ) { return; } 424 | if ( scope.noPan === true ) { return; } 425 | 426 | // pan a pixel - I guess for precise positioning? 427 | // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be 428 | var needUpdate = false; 429 | 430 | switch ( event.keyCode ) { 431 | 432 | case scope.keys.UP: 433 | scope.pan( new THREE.Vector2( 0, scope.keyPanSpeed ) ); 434 | needUpdate = true; 435 | break; 436 | case scope.keys.BOTTOM: 437 | scope.pan( new THREE.Vector2( 0, -scope.keyPanSpeed ) ); 438 | needUpdate = true; 439 | break; 440 | case scope.keys.LEFT: 441 | scope.pan( new THREE.Vector2( scope.keyPanSpeed, 0 ) ); 442 | needUpdate = true; 443 | break; 444 | case scope.keys.RIGHT: 445 | scope.pan( new THREE.Vector2( -scope.keyPanSpeed, 0 ) ); 446 | needUpdate = true; 447 | break; 448 | } 449 | 450 | // Greggman fix: https://github.com/greggman/three.js/commit/fde9f9917d6d8381f06bf22cdff766029d1761be 451 | if ( needUpdate ) { 452 | 453 | scope.update(); 454 | 455 | } 456 | 457 | } 458 | 459 | function touchstart( event ) { 460 | 461 | if ( scope.enabled === false ) { return; } 462 | 463 | switch ( event.touches.length ) { 464 | 465 | case 1: // one-fingered touch: rotate 466 | if ( scope.noRotate === true ) { return; } 467 | 468 | state = STATE.TOUCH_ROTATE; 469 | 470 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 471 | break; 472 | 473 | case 2: // two-fingered touch: dolly 474 | if ( scope.noZoom === true ) { return; } 475 | 476 | state = STATE.TOUCH_DOLLY; 477 | 478 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 479 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 480 | var distance = Math.sqrt( dx * dx + dy * dy ); 481 | dollyStart.set( 0, distance ); 482 | break; 483 | 484 | case 3: // three-fingered touch: pan 485 | if ( scope.noPan === true ) { return; } 486 | 487 | state = STATE.TOUCH_PAN; 488 | 489 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 490 | break; 491 | 492 | default: 493 | state = STATE.NONE; 494 | 495 | } 496 | } 497 | 498 | function touchmove( event ) { 499 | 500 | if ( scope.enabled === false ) { return; } 501 | 502 | event.preventDefault(); 503 | event.stopPropagation(); 504 | 505 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement; 506 | 507 | switch ( event.touches.length ) { 508 | 509 | case 1: // one-fingered touch: rotate 510 | if ( scope.noRotate === true ) { return; } 511 | if ( state !== STATE.TOUCH_ROTATE ) { return; } 512 | 513 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 514 | rotateDelta.subVectors( rotateEnd, rotateStart ); 515 | 516 | // rotating across whole screen goes 360 degrees around 517 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed ); 518 | // rotating up and down along whole screen attempts to go 360, but limited to 180 519 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed ); 520 | 521 | rotateStart.copy( rotateEnd ); 522 | break; 523 | 524 | case 2: // two-fingered touch: dolly 525 | if ( scope.noZoom === true ) { return; } 526 | if ( state !== STATE.TOUCH_DOLLY ) { return; } 527 | 528 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 529 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 530 | var distance = Math.sqrt( dx * dx + dy * dy ); 531 | 532 | dollyEnd.set( 0, distance ); 533 | dollyDelta.subVectors( dollyEnd, dollyStart ); 534 | 535 | if ( dollyDelta.y > 0 ) { 536 | 537 | scope.dollyOut(); 538 | 539 | } else { 540 | 541 | scope.dollyIn(); 542 | 543 | } 544 | 545 | dollyStart.copy( dollyEnd ); 546 | break; 547 | 548 | case 3: // three-fingered touch: pan 549 | if ( scope.noPan === true ) { return; } 550 | if ( state !== STATE.TOUCH_PAN ) { return; } 551 | 552 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 553 | panDelta.subVectors( panEnd, panStart ); 554 | 555 | scope.pan( panDelta ); 556 | 557 | panStart.copy( panEnd ); 558 | break; 559 | 560 | default: 561 | state = STATE.NONE; 562 | 563 | } 564 | 565 | } 566 | 567 | function touchend( /* event */ ) { 568 | 569 | if ( scope.enabled === false ) { return; } 570 | 571 | state = STATE.NONE; 572 | } 573 | 574 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false ); 575 | this.localElement.addEventListener( 'mousedown', onMouseDown, false ); 576 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false ); 577 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox 578 | 579 | this.domElement.addEventListener( 'keydown', onKeyDown, false ); 580 | 581 | this.localElement.addEventListener( 'touchstart', touchstart, false ); 582 | this.domElement.addEventListener( 'touchend', touchend, false ); 583 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 584 | 585 | }; 586 | 587 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype ); -------------------------------------------------------------------------------- /js/Projector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | * @author supereggbert / http://www.paulbrunt.co.uk/ 4 | * @author julianwa / https://github.com/julianwa 5 | */ 6 | 7 | THREE.RenderableObject = function () { 8 | 9 | this.id = 0; 10 | 11 | this.object = null; 12 | this.z = 0; 13 | this.renderOrder = 0; 14 | 15 | }; 16 | 17 | // 18 | 19 | THREE.RenderableFace = function () { 20 | 21 | this.id = 0; 22 | 23 | this.v1 = new THREE.RenderableVertex(); 24 | this.v2 = new THREE.RenderableVertex(); 25 | this.v3 = new THREE.RenderableVertex(); 26 | 27 | this.normalModel = new THREE.Vector3(); 28 | 29 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; 30 | this.vertexNormalsLength = 0; 31 | 32 | this.color = new THREE.Color(); 33 | this.material = null; 34 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; 35 | 36 | this.z = 0; 37 | this.renderOrder = 0; 38 | 39 | }; 40 | 41 | // 42 | 43 | THREE.RenderableVertex = function () { 44 | 45 | this.position = new THREE.Vector3(); 46 | this.positionWorld = new THREE.Vector3(); 47 | this.positionScreen = new THREE.Vector4(); 48 | 49 | this.visible = true; 50 | 51 | }; 52 | 53 | THREE.RenderableVertex.prototype.copy = function ( vertex ) { 54 | 55 | this.positionWorld.copy( vertex.positionWorld ); 56 | this.positionScreen.copy( vertex.positionScreen ); 57 | 58 | }; 59 | 60 | // 61 | 62 | THREE.RenderableLine = function () { 63 | 64 | this.id = 0; 65 | 66 | this.v1 = new THREE.RenderableVertex(); 67 | this.v2 = new THREE.RenderableVertex(); 68 | 69 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; 70 | this.material = null; 71 | 72 | this.z = 0; 73 | this.renderOrder = 0; 74 | 75 | }; 76 | 77 | // 78 | 79 | THREE.RenderableSprite = function () { 80 | 81 | this.id = 0; 82 | 83 | this.object = null; 84 | 85 | this.x = 0; 86 | this.y = 0; 87 | this.z = 0; 88 | 89 | this.rotation = 0; 90 | this.scale = new THREE.Vector2(); 91 | 92 | this.material = null; 93 | this.renderOrder = 0; 94 | 95 | }; 96 | 97 | // 98 | 99 | THREE.Projector = function () { 100 | 101 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, 102 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, 103 | _face, _faceCount, _facePool = [], _facePoolLength = 0, 104 | _line, _lineCount, _linePool = [], _linePoolLength = 0, 105 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, 106 | 107 | _renderData = { objects: [], lights: [], elements: [] }, 108 | 109 | _vector3 = new THREE.Vector3(), 110 | _vector4 = new THREE.Vector4(), 111 | 112 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), 113 | _boundingBox = new THREE.Box3(), 114 | _points3 = new Array( 3 ), 115 | _points4 = new Array( 4 ), 116 | 117 | _viewMatrix = new THREE.Matrix4(), 118 | _viewProjectionMatrix = new THREE.Matrix4(), 119 | 120 | _modelMatrix, 121 | _modelViewProjectionMatrix = new THREE.Matrix4(), 122 | 123 | _normalMatrix = new THREE.Matrix3(), 124 | 125 | _frustum = new THREE.Frustum(), 126 | 127 | _clippedVertex1PositionScreen = new THREE.Vector4(), 128 | _clippedVertex2PositionScreen = new THREE.Vector4(); 129 | 130 | // 131 | 132 | this.projectVector = function ( vector, camera ) { 133 | 134 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); 135 | vector.project( camera ); 136 | 137 | }; 138 | 139 | this.unprojectVector = function ( vector, camera ) { 140 | 141 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); 142 | vector.unproject( camera ); 143 | 144 | }; 145 | 146 | this.pickingRay = function ( vector, camera ) { 147 | 148 | console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); 149 | 150 | }; 151 | 152 | // 153 | 154 | var RenderList = function () { 155 | 156 | var normals = []; 157 | var uvs = []; 158 | 159 | var object = null; 160 | var material = null; 161 | 162 | var normalMatrix = new THREE.Matrix3(); 163 | 164 | function setObject( value ) { 165 | 166 | object = value; 167 | material = object.material; 168 | 169 | normalMatrix.getNormalMatrix( object.matrixWorld ); 170 | 171 | normals.length = 0; 172 | uvs.length = 0; 173 | 174 | } 175 | 176 | function projectVertex( vertex ) { 177 | 178 | var position = vertex.position; 179 | var positionWorld = vertex.positionWorld; 180 | var positionScreen = vertex.positionScreen; 181 | 182 | positionWorld.copy( position ).applyMatrix4( _modelMatrix ); 183 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); 184 | 185 | var invW = 1 / positionScreen.w; 186 | 187 | positionScreen.x *= invW; 188 | positionScreen.y *= invW; 189 | positionScreen.z *= invW; 190 | 191 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 && 192 | positionScreen.y >= - 1 && positionScreen.y <= 1 && 193 | positionScreen.z >= - 1 && positionScreen.z <= 1; 194 | 195 | } 196 | 197 | function pushVertex( x, y, z ) { 198 | 199 | _vertex = getNextVertexInPool(); 200 | _vertex.position.set( x, y, z ); 201 | 202 | projectVertex( _vertex ); 203 | 204 | } 205 | 206 | function pushNormal( x, y, z ) { 207 | 208 | normals.push( x, y, z ); 209 | 210 | } 211 | 212 | function pushUv( x, y ) { 213 | 214 | uvs.push( x, y ); 215 | 216 | } 217 | 218 | function checkTriangleVisibility( v1, v2, v3 ) { 219 | 220 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; 221 | 222 | _points3[ 0 ] = v1.positionScreen; 223 | _points3[ 1 ] = v2.positionScreen; 224 | _points3[ 2 ] = v3.positionScreen; 225 | 226 | return _clipBox.intersectsBox( _boundingBox.setFromPoints( _points3 ) ); 227 | 228 | } 229 | 230 | function checkBackfaceCulling( v1, v2, v3 ) { 231 | 232 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) * 233 | ( v2.positionScreen.y - v1.positionScreen.y ) - 234 | ( v3.positionScreen.y - v1.positionScreen.y ) * 235 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; 236 | 237 | } 238 | 239 | function pushLine( a, b ) { 240 | 241 | var v1 = _vertexPool[ a ]; 242 | var v2 = _vertexPool[ b ]; 243 | 244 | _line = getNextLineInPool(); 245 | 246 | _line.id = object.id; 247 | _line.v1.copy( v1 ); 248 | _line.v2.copy( v2 ); 249 | _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; 250 | _line.renderOrder = object.renderOrder; 251 | 252 | _line.material = object.material; 253 | 254 | _renderData.elements.push( _line ); 255 | 256 | } 257 | 258 | function pushTriangle( a, b, c ) { 259 | 260 | var v1 = _vertexPool[ a ]; 261 | var v2 = _vertexPool[ b ]; 262 | var v3 = _vertexPool[ c ]; 263 | 264 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; 265 | 266 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { 267 | 268 | _face = getNextFaceInPool(); 269 | 270 | _face.id = object.id; 271 | _face.v1.copy( v1 ); 272 | _face.v2.copy( v2 ); 273 | _face.v3.copy( v3 ); 274 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; 275 | _face.renderOrder = object.renderOrder; 276 | 277 | // use first vertex normal as face normal 278 | 279 | _face.normalModel.fromArray( normals, a * 3 ); 280 | _face.normalModel.applyMatrix3( normalMatrix ).normalize(); 281 | 282 | for ( var i = 0; i < 3; i ++ ) { 283 | 284 | var normal = _face.vertexNormalsModel[ i ]; 285 | normal.fromArray( normals, arguments[ i ] * 3 ); 286 | normal.applyMatrix3( normalMatrix ).normalize(); 287 | 288 | var uv = _face.uvs[ i ]; 289 | uv.fromArray( uvs, arguments[ i ] * 2 ); 290 | 291 | } 292 | 293 | _face.vertexNormalsLength = 3; 294 | 295 | _face.material = object.material; 296 | 297 | _renderData.elements.push( _face ); 298 | 299 | } 300 | 301 | } 302 | 303 | return { 304 | setObject: setObject, 305 | projectVertex: projectVertex, 306 | checkTriangleVisibility: checkTriangleVisibility, 307 | checkBackfaceCulling: checkBackfaceCulling, 308 | pushVertex: pushVertex, 309 | pushNormal: pushNormal, 310 | pushUv: pushUv, 311 | pushLine: pushLine, 312 | pushTriangle: pushTriangle 313 | } 314 | 315 | }; 316 | 317 | var renderList = new RenderList(); 318 | 319 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) { 320 | 321 | _faceCount = 0; 322 | _lineCount = 0; 323 | _spriteCount = 0; 324 | 325 | _renderData.elements.length = 0; 326 | 327 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); 328 | if ( camera.parent === null ) camera.updateMatrixWorld(); 329 | 330 | _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); 331 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); 332 | 333 | _frustum.setFromMatrix( _viewProjectionMatrix ); 334 | 335 | // 336 | 337 | _objectCount = 0; 338 | 339 | _renderData.objects.length = 0; 340 | _renderData.lights.length = 0; 341 | 342 | function addObject( object ) { 343 | 344 | _object = getNextObjectInPool(); 345 | _object.id = object.id; 346 | _object.object = object; 347 | 348 | _vector3.setFromMatrixPosition( object.matrixWorld ); 349 | _vector3.applyProjection( _viewProjectionMatrix ); 350 | _object.z = _vector3.z; 351 | _object.renderOrder = object.renderOrder; 352 | 353 | _renderData.objects.push( _object ); 354 | 355 | } 356 | 357 | scene.traverseVisible( function ( object ) { 358 | 359 | if ( object instanceof THREE.Light ) { 360 | 361 | _renderData.lights.push( object ); 362 | 363 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) { 364 | 365 | if ( object.material.visible === false ) return; 366 | if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return; 367 | 368 | addObject( object ); 369 | 370 | } else if ( object instanceof THREE.Sprite ) { 371 | 372 | if ( object.material.visible === false ) return; 373 | if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return; 374 | 375 | addObject( object ); 376 | 377 | } 378 | 379 | } ); 380 | 381 | if ( sortObjects === true ) { 382 | 383 | _renderData.objects.sort( painterSort ); 384 | 385 | } 386 | 387 | // 388 | 389 | for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { 390 | 391 | var object = _renderData.objects[ o ].object; 392 | var geometry = object.geometry; 393 | 394 | renderList.setObject( object ); 395 | 396 | _modelMatrix = object.matrixWorld; 397 | 398 | _vertexCount = 0; 399 | 400 | if ( object instanceof THREE.Mesh ) { 401 | 402 | if ( geometry instanceof THREE.BufferGeometry ) { 403 | 404 | var attributes = geometry.attributes; 405 | var groups = geometry.groups; 406 | 407 | if ( attributes.position === undefined ) continue; 408 | 409 | var positions = attributes.position.array; 410 | 411 | for ( var i = 0, l = positions.length; i < l; i += 3 ) { 412 | 413 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); 414 | 415 | } 416 | 417 | if ( attributes.normal !== undefined ) { 418 | 419 | var normals = attributes.normal.array; 420 | 421 | for ( var i = 0, l = normals.length; i < l; i += 3 ) { 422 | 423 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); 424 | 425 | } 426 | 427 | } 428 | 429 | if ( attributes.uv !== undefined ) { 430 | 431 | var uvs = attributes.uv.array; 432 | 433 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) { 434 | 435 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); 436 | 437 | } 438 | 439 | } 440 | 441 | if ( geometry.index !== null ) { 442 | 443 | var indices = geometry.index.array; 444 | 445 | if ( groups.length > 0 ) { 446 | 447 | for ( var o = 0; o < groups.length; o ++ ) { 448 | 449 | var group = groups[ o ]; 450 | 451 | for ( var i = group.start, l = group.start + group.count; i < l; i += 3 ) { 452 | 453 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); 454 | 455 | } 456 | 457 | } 458 | 459 | } else { 460 | 461 | for ( var i = 0, l = indices.length; i < l; i += 3 ) { 462 | 463 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); 464 | 465 | } 466 | 467 | } 468 | 469 | } else { 470 | 471 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { 472 | 473 | renderList.pushTriangle( i, i + 1, i + 2 ); 474 | 475 | } 476 | 477 | } 478 | 479 | } else if ( geometry instanceof THREE.Geometry ) { 480 | 481 | var vertices = geometry.vertices; 482 | var faces = geometry.faces; 483 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; 484 | 485 | _normalMatrix.getNormalMatrix( _modelMatrix ); 486 | 487 | var material = object.material; 488 | 489 | var isFaceMaterial = material instanceof THREE.MultiMaterial; 490 | var objectMaterials = isFaceMaterial === true ? object.material : null; 491 | 492 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { 493 | 494 | var vertex = vertices[ v ]; 495 | 496 | _vector3.copy( vertex ); 497 | 498 | if ( material.morphTargets === true ) { 499 | 500 | var morphTargets = geometry.morphTargets; 501 | var morphInfluences = object.morphTargetInfluences; 502 | 503 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { 504 | 505 | var influence = morphInfluences[ t ]; 506 | 507 | if ( influence === 0 ) continue; 508 | 509 | var target = morphTargets[ t ]; 510 | var targetVertex = target.vertices[ v ]; 511 | 512 | _vector3.x += ( targetVertex.x - vertex.x ) * influence; 513 | _vector3.y += ( targetVertex.y - vertex.y ) * influence; 514 | _vector3.z += ( targetVertex.z - vertex.z ) * influence; 515 | 516 | } 517 | 518 | } 519 | 520 | renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z ); 521 | 522 | } 523 | 524 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) { 525 | 526 | var face = faces[ f ]; 527 | 528 | material = isFaceMaterial === true 529 | ? objectMaterials.materials[ face.materialIndex ] 530 | : object.material; 531 | 532 | if ( material === undefined ) continue; 533 | 534 | var side = material.side; 535 | 536 | var v1 = _vertexPool[ face.a ]; 537 | var v2 = _vertexPool[ face.b ]; 538 | var v3 = _vertexPool[ face.c ]; 539 | 540 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; 541 | 542 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); 543 | 544 | if ( side !== THREE.DoubleSide ) { 545 | 546 | if ( side === THREE.FrontSide && visible === false ) continue; 547 | if ( side === THREE.BackSide && visible === true ) continue; 548 | 549 | } 550 | 551 | _face = getNextFaceInPool(); 552 | 553 | _face.id = object.id; 554 | _face.v1.copy( v1 ); 555 | _face.v2.copy( v2 ); 556 | _face.v3.copy( v3 ); 557 | 558 | _face.normalModel.copy( face.normal ); 559 | 560 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { 561 | 562 | _face.normalModel.negate(); 563 | 564 | } 565 | 566 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); 567 | 568 | var faceVertexNormals = face.vertexNormals; 569 | 570 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { 571 | 572 | var normalModel = _face.vertexNormalsModel[ n ]; 573 | normalModel.copy( faceVertexNormals[ n ] ); 574 | 575 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { 576 | 577 | normalModel.negate(); 578 | 579 | } 580 | 581 | normalModel.applyMatrix3( _normalMatrix ).normalize(); 582 | 583 | } 584 | 585 | _face.vertexNormalsLength = faceVertexNormals.length; 586 | 587 | var vertexUvs = faceVertexUvs[ f ]; 588 | 589 | if ( vertexUvs !== undefined ) { 590 | 591 | for ( var u = 0; u < 3; u ++ ) { 592 | 593 | _face.uvs[ u ].copy( vertexUvs[ u ] ); 594 | 595 | } 596 | 597 | } 598 | 599 | _face.color = face.color; 600 | _face.material = material; 601 | 602 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; 603 | _face.renderOrder = object.renderOrder; 604 | 605 | _renderData.elements.push( _face ); 606 | 607 | } 608 | 609 | } 610 | 611 | } else if ( object instanceof THREE.Line ) { 612 | 613 | if ( geometry instanceof THREE.BufferGeometry ) { 614 | 615 | var attributes = geometry.attributes; 616 | 617 | if ( attributes.position !== undefined ) { 618 | 619 | var positions = attributes.position.array; 620 | 621 | for ( var i = 0, l = positions.length; i < l; i += 3 ) { 622 | 623 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); 624 | 625 | } 626 | 627 | if ( geometry.index !== null ) { 628 | 629 | var indices = geometry.index.array; 630 | 631 | for ( var i = 0, l = indices.length; i < l; i += 2 ) { 632 | 633 | renderList.pushLine( indices[ i ], indices[ i + 1 ] ); 634 | 635 | } 636 | 637 | } else { 638 | 639 | var step = object instanceof THREE.LineSegments ? 2 : 1; 640 | 641 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) { 642 | 643 | renderList.pushLine( i, i + 1 ); 644 | 645 | } 646 | 647 | } 648 | 649 | } 650 | 651 | } else if ( geometry instanceof THREE.Geometry ) { 652 | 653 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); 654 | 655 | var vertices = object.geometry.vertices; 656 | 657 | if ( vertices.length === 0 ) continue; 658 | 659 | v1 = getNextVertexInPool(); 660 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); 661 | 662 | var step = object instanceof THREE.LineSegments ? 2 : 1; 663 | 664 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { 665 | 666 | v1 = getNextVertexInPool(); 667 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); 668 | 669 | if ( ( v + 1 ) % step > 0 ) continue; 670 | 671 | v2 = _vertexPool[ _vertexCount - 2 ]; 672 | 673 | _clippedVertex1PositionScreen.copy( v1.positionScreen ); 674 | _clippedVertex2PositionScreen.copy( v2.positionScreen ); 675 | 676 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { 677 | 678 | // Perform the perspective divide 679 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); 680 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); 681 | 682 | _line = getNextLineInPool(); 683 | 684 | _line.id = object.id; 685 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); 686 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); 687 | 688 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); 689 | _line.renderOrder = object.renderOrder; 690 | 691 | _line.material = object.material; 692 | 693 | if ( object.material.vertexColors === THREE.VertexColors ) { 694 | 695 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); 696 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); 697 | 698 | } 699 | 700 | _renderData.elements.push( _line ); 701 | 702 | } 703 | 704 | } 705 | 706 | } 707 | 708 | } else if ( object instanceof THREE.Sprite ) { 709 | 710 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); 711 | _vector4.applyMatrix4( _viewProjectionMatrix ); 712 | 713 | var invW = 1 / _vector4.w; 714 | 715 | _vector4.z *= invW; 716 | 717 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { 718 | 719 | _sprite = getNextSpriteInPool(); 720 | _sprite.id = object.id; 721 | _sprite.x = _vector4.x * invW; 722 | _sprite.y = _vector4.y * invW; 723 | _sprite.z = _vector4.z; 724 | _sprite.renderOrder = object.renderOrder; 725 | _sprite.object = object; 726 | 727 | _sprite.rotation = object.rotation; 728 | 729 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); 730 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); 731 | 732 | _sprite.material = object.material; 733 | 734 | _renderData.elements.push( _sprite ); 735 | 736 | } 737 | 738 | } 739 | 740 | } 741 | 742 | if ( sortElements === true ) { 743 | 744 | _renderData.elements.sort( painterSort ); 745 | 746 | } 747 | 748 | return _renderData; 749 | 750 | }; 751 | 752 | // Pools 753 | 754 | function getNextObjectInPool() { 755 | 756 | if ( _objectCount === _objectPoolLength ) { 757 | 758 | var object = new THREE.RenderableObject(); 759 | _objectPool.push( object ); 760 | _objectPoolLength ++; 761 | _objectCount ++; 762 | return object; 763 | 764 | } 765 | 766 | return _objectPool[ _objectCount ++ ]; 767 | 768 | } 769 | 770 | function getNextVertexInPool() { 771 | 772 | if ( _vertexCount === _vertexPoolLength ) { 773 | 774 | var vertex = new THREE.RenderableVertex(); 775 | _vertexPool.push( vertex ); 776 | _vertexPoolLength ++; 777 | _vertexCount ++; 778 | return vertex; 779 | 780 | } 781 | 782 | return _vertexPool[ _vertexCount ++ ]; 783 | 784 | } 785 | 786 | function getNextFaceInPool() { 787 | 788 | if ( _faceCount === _facePoolLength ) { 789 | 790 | var face = new THREE.RenderableFace(); 791 | _facePool.push( face ); 792 | _facePoolLength ++; 793 | _faceCount ++; 794 | return face; 795 | 796 | } 797 | 798 | return _facePool[ _faceCount ++ ]; 799 | 800 | 801 | } 802 | 803 | function getNextLineInPool() { 804 | 805 | if ( _lineCount === _linePoolLength ) { 806 | 807 | var line = new THREE.RenderableLine(); 808 | _linePool.push( line ); 809 | _linePoolLength ++; 810 | _lineCount ++; 811 | return line; 812 | 813 | } 814 | 815 | return _linePool[ _lineCount ++ ]; 816 | 817 | } 818 | 819 | function getNextSpriteInPool() { 820 | 821 | if ( _spriteCount === _spritePoolLength ) { 822 | 823 | var sprite = new THREE.RenderableSprite(); 824 | _spritePool.push( sprite ); 825 | _spritePoolLength ++; 826 | _spriteCount ++; 827 | return sprite; 828 | 829 | } 830 | 831 | return _spritePool[ _spriteCount ++ ]; 832 | 833 | } 834 | 835 | // 836 | 837 | function painterSort( a, b ) { 838 | 839 | if ( a.renderOrder !== b.renderOrder ) { 840 | 841 | return a.renderOrder - b.renderOrder; 842 | 843 | } else if ( a.z !== b.z ) { 844 | 845 | return b.z - a.z; 846 | 847 | } else if ( a.id !== b.id ) { 848 | 849 | return a.id - b.id; 850 | 851 | } else { 852 | 853 | return 0; 854 | 855 | } 856 | 857 | } 858 | 859 | function clipLine( s1, s2 ) { 860 | 861 | var alpha1 = 0, alpha2 = 1, 862 | 863 | // Calculate the boundary coordinate of each vertex for the near and far clip planes, 864 | // Z = -1 and Z = +1, respectively. 865 | bc1near = s1.z + s1.w, 866 | bc2near = s2.z + s2.w, 867 | bc1far = - s1.z + s1.w, 868 | bc2far = - s2.z + s2.w; 869 | 870 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { 871 | 872 | // Both vertices lie entirely within all clip planes. 873 | return true; 874 | 875 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) { 876 | 877 | // Both vertices lie entirely outside one of the clip planes. 878 | return false; 879 | 880 | } else { 881 | 882 | // The line segment spans at least one clip plane. 883 | 884 | if ( bc1near < 0 ) { 885 | 886 | // v1 lies outside the near plane, v2 inside 887 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); 888 | 889 | } else if ( bc2near < 0 ) { 890 | 891 | // v2 lies outside the near plane, v1 inside 892 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); 893 | 894 | } 895 | 896 | if ( bc1far < 0 ) { 897 | 898 | // v1 lies outside the far plane, v2 inside 899 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); 900 | 901 | } else if ( bc2far < 0 ) { 902 | 903 | // v2 lies outside the far plane, v2 inside 904 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); 905 | 906 | } 907 | 908 | if ( alpha2 < alpha1 ) { 909 | 910 | // The line segment spans two boundaries, but is outside both of them. 911 | // (This can't happen when we're only clipping against just near/far but good 912 | // to leave the check here for future usage if other clip planes are added.) 913 | return false; 914 | 915 | } else { 916 | 917 | // Update the s1 and s2 vertices to match the clipped line segment. 918 | s1.lerp( s2, alpha1 ); 919 | s2.lerp( s1, 1 - alpha2 ); 920 | 921 | return true; 922 | 923 | } 924 | 925 | } 926 | 927 | } 928 | 929 | }; -------------------------------------------------------------------------------- /js/TrackballControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eberhard Graether / http://egraether.com/ 3 | * @author Mark Lundin / http://mark-lundin.com 4 | * @author Simone Manini / http://daron1337.github.io 5 | * @author Luca Antiga / http://lantiga.github.io 6 | */ 7 | 8 | THREE.TrackballControls = function ( object, domElement ) { 9 | 10 | var _this = this; 11 | var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 12 | 13 | this.object = object; 14 | this.domElement = ( domElement !== undefined ) ? domElement : document; 15 | 16 | // API 17 | 18 | this.enabled = true; 19 | 20 | this.screen = { left: 0, top: 0, width: 0, height: 0 }; 21 | 22 | this.rotateSpeed = 1.0; 23 | this.zoomSpeed = 1.2; 24 | this.panSpeed = 0.3; 25 | 26 | this.noRotate = false; 27 | this.noZoom = false; 28 | this.noPan = false; 29 | 30 | this.staticMoving = false; 31 | this.dynamicDampingFactor = 0.2; 32 | 33 | this.minDistance = 0; 34 | this.maxDistance = Infinity; 35 | 36 | this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 37 | 38 | // internals 39 | 40 | this.target = new THREE.Vector3(); 41 | 42 | var EPS = 0.000001; 43 | 44 | var lastPosition = new THREE.Vector3(); 45 | 46 | var _state = STATE.NONE, 47 | _prevState = STATE.NONE, 48 | 49 | _eye = new THREE.Vector3(), 50 | 51 | _movePrev = new THREE.Vector2(), 52 | _moveCurr = new THREE.Vector2(), 53 | 54 | _lastAxis = new THREE.Vector3(), 55 | _lastAngle = 0, 56 | 57 | _zoomStart = new THREE.Vector2(), 58 | _zoomEnd = new THREE.Vector2(), 59 | 60 | _touchZoomDistanceStart = 0, 61 | _touchZoomDistanceEnd = 0, 62 | 63 | _panStart = new THREE.Vector2(), 64 | _panEnd = new THREE.Vector2(); 65 | 66 | // for reset 67 | 68 | this.target0 = this.target.clone(); 69 | this.position0 = this.object.position.clone(); 70 | this.up0 = this.object.up.clone(); 71 | 72 | // events 73 | 74 | var changeEvent = { type: 'change' }; 75 | var startEvent = { type: 'start' }; 76 | var endEvent = { type: 'end' }; 77 | 78 | 79 | // methods 80 | 81 | this.handleResize = function () { 82 | 83 | if ( this.domElement === document ) { 84 | 85 | this.screen.left = 0; 86 | this.screen.top = 0; 87 | this.screen.width = window.innerWidth; 88 | this.screen.height = window.innerHeight; 89 | 90 | } else { 91 | 92 | var box = this.domElement.getBoundingClientRect(); 93 | // adjustments come from similar code in the jquery offset() function 94 | var d = this.domElement.ownerDocument.documentElement; 95 | this.screen.left = box.left + window.pageXOffset - d.clientLeft; 96 | this.screen.top = box.top + window.pageYOffset - d.clientTop; 97 | this.screen.width = box.width; 98 | this.screen.height = box.height; 99 | 100 | } 101 | 102 | }; 103 | 104 | this.handleEvent = function ( event ) { 105 | 106 | if ( typeof this[ event.type ] == 'function' ) { 107 | 108 | this[ event.type ]( event ); 109 | 110 | } 111 | 112 | }; 113 | 114 | var getMouseOnScreen = ( function () { 115 | 116 | var vector = new THREE.Vector2(); 117 | 118 | return function getMouseOnScreen( pageX, pageY ) { 119 | 120 | vector.set( 121 | ( pageX - _this.screen.left ) / _this.screen.width, 122 | ( pageY - _this.screen.top ) / _this.screen.height 123 | ); 124 | 125 | return vector; 126 | 127 | }; 128 | 129 | }() ); 130 | 131 | var getMouseOnCircle = ( function () { 132 | 133 | var vector = new THREE.Vector2(); 134 | 135 | return function getMouseOnCircle( pageX, pageY ) { 136 | 137 | vector.set( 138 | ( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ), 139 | ( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional 140 | ); 141 | 142 | return vector; 143 | 144 | }; 145 | 146 | }() ); 147 | 148 | this.rotateCamera = ( function() { 149 | 150 | var axis = new THREE.Vector3(), 151 | quaternion = new THREE.Quaternion(), 152 | eyeDirection = new THREE.Vector3(), 153 | objectUpDirection = new THREE.Vector3(), 154 | objectSidewaysDirection = new THREE.Vector3(), 155 | moveDirection = new THREE.Vector3(), 156 | angle; 157 | 158 | return function rotateCamera() { 159 | 160 | moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); 161 | angle = moveDirection.length(); 162 | 163 | if ( angle ) { 164 | 165 | _eye.copy( _this.object.position ).sub( _this.target ); 166 | 167 | eyeDirection.copy( _eye ).normalize(); 168 | objectUpDirection.copy( _this.object.up ).normalize(); 169 | objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); 170 | 171 | objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); 172 | objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); 173 | 174 | moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); 175 | 176 | axis.crossVectors( moveDirection, _eye ).normalize(); 177 | 178 | angle *= _this.rotateSpeed; 179 | quaternion.setFromAxisAngle( axis, angle ); 180 | 181 | _eye.applyQuaternion( quaternion ); 182 | _this.object.up.applyQuaternion( quaternion ); 183 | 184 | _lastAxis.copy( axis ); 185 | _lastAngle = angle; 186 | 187 | } else if ( ! _this.staticMoving && _lastAngle ) { 188 | 189 | _lastAngle *= Math.sqrt( 1.0 - _this.dynamicDampingFactor ); 190 | _eye.copy( _this.object.position ).sub( _this.target ); 191 | quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); 192 | _eye.applyQuaternion( quaternion ); 193 | _this.object.up.applyQuaternion( quaternion ); 194 | 195 | } 196 | 197 | _movePrev.copy( _moveCurr ); 198 | 199 | }; 200 | 201 | }() ); 202 | 203 | 204 | this.zoomCamera = function () { 205 | 206 | var factor; 207 | 208 | if ( _state === STATE.TOUCH_ZOOM_PAN ) { 209 | 210 | factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; 211 | _touchZoomDistanceStart = _touchZoomDistanceEnd; 212 | _eye.multiplyScalar( factor ); 213 | 214 | } else { 215 | 216 | factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * _this.zoomSpeed; 217 | 218 | if ( factor !== 1.0 && factor > 0.0 ) { 219 | 220 | _eye.multiplyScalar( factor ); 221 | 222 | } 223 | 224 | if ( _this.staticMoving ) { 225 | 226 | _zoomStart.copy( _zoomEnd ); 227 | 228 | } else { 229 | 230 | _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; 231 | 232 | } 233 | 234 | } 235 | 236 | }; 237 | 238 | this.panCamera = ( function() { 239 | 240 | var mouseChange = new THREE.Vector2(), 241 | objectUp = new THREE.Vector3(), 242 | pan = new THREE.Vector3(); 243 | 244 | return function panCamera() { 245 | 246 | mouseChange.copy( _panEnd ).sub( _panStart ); 247 | 248 | if ( mouseChange.lengthSq() ) { 249 | 250 | mouseChange.multiplyScalar( _eye.length() * _this.panSpeed ); 251 | 252 | pan.copy( _eye ).cross( _this.object.up ).setLength( mouseChange.x ); 253 | pan.add( objectUp.copy( _this.object.up ).setLength( mouseChange.y ) ); 254 | 255 | _this.object.position.add( pan ); 256 | _this.target.add( pan ); 257 | 258 | if ( _this.staticMoving ) { 259 | 260 | _panStart.copy( _panEnd ); 261 | 262 | } else { 263 | 264 | _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( _this.dynamicDampingFactor ) ); 265 | 266 | } 267 | 268 | } 269 | 270 | }; 271 | 272 | }() ); 273 | 274 | this.checkDistances = function () { 275 | 276 | if ( ! _this.noZoom || ! _this.noPan ) { 277 | 278 | if ( _eye.lengthSq() > _this.maxDistance * _this.maxDistance ) { 279 | 280 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.maxDistance ) ); 281 | _zoomStart.copy( _zoomEnd ); 282 | 283 | } 284 | 285 | if ( _eye.lengthSq() < _this.minDistance * _this.minDistance ) { 286 | 287 | _this.object.position.addVectors( _this.target, _eye.setLength( _this.minDistance ) ); 288 | _zoomStart.copy( _zoomEnd ); 289 | 290 | } 291 | 292 | } 293 | 294 | }; 295 | 296 | this.update = function () { 297 | 298 | _eye.subVectors( _this.object.position, _this.target ); 299 | 300 | if ( ! _this.noRotate ) { 301 | 302 | _this.rotateCamera(); 303 | 304 | } 305 | 306 | if ( ! _this.noZoom ) { 307 | 308 | _this.zoomCamera(); 309 | 310 | } 311 | 312 | if ( ! _this.noPan ) { 313 | 314 | _this.panCamera(); 315 | 316 | } 317 | 318 | _this.object.position.addVectors( _this.target, _eye ); 319 | 320 | _this.checkDistances(); 321 | 322 | _this.object.lookAt( _this.target ); 323 | 324 | if ( lastPosition.distanceToSquared( _this.object.position ) > EPS ) { 325 | 326 | _this.dispatchEvent( changeEvent ); 327 | 328 | lastPosition.copy( _this.object.position ); 329 | 330 | } 331 | 332 | }; 333 | 334 | this.reset = function () { 335 | 336 | _state = STATE.NONE; 337 | _prevState = STATE.NONE; 338 | 339 | _this.target.copy( _this.target0 ); 340 | _this.object.position.copy( _this.position0 ); 341 | _this.object.up.copy( _this.up0 ); 342 | 343 | _eye.subVectors( _this.object.position, _this.target ); 344 | 345 | _this.object.lookAt( _this.target ); 346 | 347 | _this.dispatchEvent( changeEvent ); 348 | 349 | lastPosition.copy( _this.object.position ); 350 | 351 | }; 352 | 353 | // listeners 354 | 355 | function keydown( event ) { 356 | 357 | if ( _this.enabled === false ) return; 358 | 359 | window.removeEventListener( 'keydown', keydown ); 360 | 361 | _prevState = _state; 362 | 363 | if ( _state !== STATE.NONE ) { 364 | 365 | return; 366 | 367 | } else if ( event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate ) { 368 | 369 | _state = STATE.ROTATE; 370 | 371 | } else if ( event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom ) { 372 | 373 | _state = STATE.ZOOM; 374 | 375 | } else if ( event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan ) { 376 | 377 | _state = STATE.PAN; 378 | 379 | } 380 | 381 | } 382 | 383 | function keyup( event ) { 384 | 385 | if ( _this.enabled === false ) return; 386 | 387 | _state = _prevState; 388 | 389 | window.addEventListener( 'keydown', keydown, false ); 390 | 391 | } 392 | 393 | function mousedown( event ) { 394 | 395 | if ( _this.enabled === false ) return; 396 | 397 | event.preventDefault(); 398 | event.stopPropagation(); 399 | 400 | if ( _state === STATE.NONE ) { 401 | 402 | _state = event.button; 403 | 404 | } 405 | 406 | if ( _state === STATE.ROTATE && ! _this.noRotate ) { 407 | 408 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 409 | _movePrev.copy( _moveCurr ); 410 | 411 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 412 | 413 | _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 414 | _zoomEnd.copy( _zoomStart ); 415 | 416 | } else if ( _state === STATE.PAN && ! _this.noPan ) { 417 | 418 | _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 419 | _panEnd.copy( _panStart ); 420 | 421 | } 422 | 423 | document.addEventListener( 'mousemove', mousemove, false ); 424 | document.addEventListener( 'mouseup', mouseup, false ); 425 | 426 | _this.dispatchEvent( startEvent ); 427 | 428 | } 429 | 430 | function mousemove( event ) { 431 | 432 | if ( _this.enabled === false ) return; 433 | 434 | event.preventDefault(); 435 | event.stopPropagation(); 436 | 437 | if ( _state === STATE.ROTATE && ! _this.noRotate ) { 438 | 439 | _movePrev.copy( _moveCurr ); 440 | _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); 441 | 442 | } else if ( _state === STATE.ZOOM && ! _this.noZoom ) { 443 | 444 | _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 445 | 446 | } else if ( _state === STATE.PAN && ! _this.noPan ) { 447 | 448 | _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); 449 | 450 | } 451 | 452 | } 453 | 454 | function mouseup( event ) { 455 | 456 | if ( _this.enabled === false ) return; 457 | 458 | event.preventDefault(); 459 | event.stopPropagation(); 460 | 461 | _state = STATE.NONE; 462 | 463 | document.removeEventListener( 'mousemove', mousemove ); 464 | document.removeEventListener( 'mouseup', mouseup ); 465 | _this.dispatchEvent( endEvent ); 466 | 467 | } 468 | 469 | function mousewheel( event ) { 470 | 471 | if ( _this.enabled === false ) return; 472 | 473 | event.preventDefault(); 474 | event.stopPropagation(); 475 | 476 | _zoomStart.y -= event.deltaY * 0.01; 477 | 478 | _this.dispatchEvent( startEvent ); 479 | _this.dispatchEvent( endEvent ); 480 | 481 | } 482 | 483 | function touchstart( event ) { 484 | 485 | if ( _this.enabled === false ) return; 486 | 487 | switch ( event.touches.length ) { 488 | 489 | case 1: 490 | _state = STATE.TOUCH_ROTATE; 491 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 492 | _movePrev.copy( _moveCurr ); 493 | break; 494 | 495 | default: // 2 or more 496 | _state = STATE.TOUCH_ZOOM_PAN; 497 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 498 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 499 | _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); 500 | 501 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 502 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 503 | _panStart.copy( getMouseOnScreen( x, y ) ); 504 | _panEnd.copy( _panStart ); 505 | break; 506 | 507 | } 508 | 509 | _this.dispatchEvent( startEvent ); 510 | 511 | } 512 | 513 | function touchmove( event ) { 514 | 515 | if ( _this.enabled === false ) return; 516 | 517 | event.preventDefault(); 518 | event.stopPropagation(); 519 | 520 | switch ( event.touches.length ) { 521 | 522 | case 1: 523 | _movePrev.copy( _moveCurr ); 524 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 525 | break; 526 | 527 | default: // 2 or more 528 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 529 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 530 | _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); 531 | 532 | var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; 533 | var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; 534 | _panEnd.copy( getMouseOnScreen( x, y ) ); 535 | break; 536 | 537 | } 538 | 539 | } 540 | 541 | function touchend( event ) { 542 | 543 | if ( _this.enabled === false ) return; 544 | 545 | switch ( event.touches.length ) { 546 | 547 | case 0: 548 | _state = STATE.NONE; 549 | break; 550 | 551 | case 1: 552 | _state = STATE.TOUCH_ROTATE; 553 | _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); 554 | _movePrev.copy( _moveCurr ); 555 | break; 556 | 557 | } 558 | 559 | _this.dispatchEvent( endEvent ); 560 | 561 | } 562 | 563 | function contextmenu( event ) { 564 | 565 | event.preventDefault(); 566 | 567 | } 568 | 569 | this.dispose = function() { 570 | 571 | this.domElement.removeEventListener( 'contextmenu', contextmenu, false ); 572 | this.domElement.removeEventListener( 'mousedown', mousedown, false ); 573 | this.domElement.removeEventListener( 'wheel', mousewheel, false ); 574 | 575 | this.domElement.removeEventListener( 'touchstart', touchstart, false ); 576 | this.domElement.removeEventListener( 'touchend', touchend, false ); 577 | this.domElement.removeEventListener( 'touchmove', touchmove, false ); 578 | 579 | document.removeEventListener( 'mousemove', mousemove, false ); 580 | document.removeEventListener( 'mouseup', mouseup, false ); 581 | 582 | window.removeEventListener( 'keydown', keydown, false ); 583 | window.removeEventListener( 'keyup', keyup, false ); 584 | 585 | }; 586 | 587 | this.domElement.addEventListener( 'contextmenu', contextmenu, false ); 588 | this.domElement.addEventListener( 'mousedown', mousedown, false ); 589 | this.domElement.addEventListener( 'wheel', mousewheel, false ); 590 | 591 | this.domElement.addEventListener( 'touchstart', touchstart, false ); 592 | this.domElement.addEventListener( 'touchend', touchend, false ); 593 | this.domElement.addEventListener( 'touchmove', touchmove, false ); 594 | 595 | window.addEventListener( 'keydown', keydown, false ); 596 | window.addEventListener( 'keyup', keyup, false ); 597 | 598 | this.handleResize(); 599 | 600 | // force an update at start 601 | this.update(); 602 | 603 | }; 604 | 605 | THREE.TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 606 | THREE.TrackballControls.prototype.constructor = THREE.TrackballControls; -------------------------------------------------------------------------------- /js/jszip-utils.js: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | JSZipUtils - A collection of cross-browser utilities to go along with JSZip. 4 | 5 | 6 | (c) 2014 Stuart Knightley, David Duponchel 7 | Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown. 8 | 9 | */ 10 | !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oe+1E3&&(r.update(1E3*a/(c-e),100),e=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){g=this.end()},domElement:c,setMode:k}}; 4 | Stats.Panel=function(h,k,l){var c=Infinity,g=0,e=Math.round,a=e(window.devicePixelRatio||1),r=80*a,f=48*a,t=3*a,u=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=f;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,f);b.fillStyle=k;b.fillText(h,t,u);b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(f, 5 | v){c=Math.min(c,f);g=Math.max(g,f);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=k;b.fillText(e(f)+" "+h+" ("+e(c)+"-"+e(g)+")",t,u);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,e((1-f/v)*p))}}};"object"===typeof module&&(module.exports=Stats); -------------------------------------------------------------------------------- /js/ui.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | var UI = {}; 6 | 7 | UI.Element = function ( dom ) { 8 | 9 | this.dom = dom; 10 | 11 | }; 12 | 13 | UI.Element.prototype = { 14 | 15 | add: function () { 16 | 17 | for ( var i = 0; i < arguments.length; i ++ ) { 18 | 19 | var argument = arguments[ i ]; 20 | 21 | if ( argument instanceof UI.Element ) { 22 | 23 | this.dom.appendChild( argument.dom ); 24 | 25 | } else { 26 | 27 | console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' ); 28 | 29 | } 30 | 31 | } 32 | 33 | return this; 34 | 35 | }, 36 | 37 | remove: function () { 38 | 39 | for ( var i = 0; i < arguments.length; i ++ ) { 40 | 41 | var argument = arguments[ i ]; 42 | 43 | if ( argument instanceof UI.Element ) { 44 | 45 | this.dom.removeChild( argument.dom ); 46 | 47 | } else { 48 | 49 | console.error( 'UI.Element:', argument, 'is not an instance of UI.Element.' ); 50 | 51 | } 52 | 53 | } 54 | 55 | return this; 56 | 57 | }, 58 | 59 | clear: function () { 60 | 61 | while ( this.dom.children.length ) { 62 | 63 | this.dom.removeChild( this.dom.lastChild ); 64 | 65 | } 66 | 67 | }, 68 | 69 | setId: function ( id ) { 70 | 71 | this.dom.id = id; 72 | 73 | return this; 74 | 75 | }, 76 | 77 | setClass: function ( name ) { 78 | 79 | this.dom.className = name; 80 | 81 | return this; 82 | 83 | }, 84 | 85 | setStyle: function ( style, array ) { 86 | 87 | for ( var i = 0; i < array.length; i ++ ) { 88 | 89 | this.dom.style[ style ] = array[ i ]; 90 | 91 | } 92 | 93 | return this; 94 | 95 | }, 96 | 97 | setDisabled: function ( value ) { 98 | 99 | this.dom.disabled = value; 100 | 101 | return this; 102 | 103 | }, 104 | 105 | setTextContent: function ( value ) { 106 | 107 | this.dom.textContent = value; 108 | 109 | return this; 110 | 111 | } 112 | 113 | }; 114 | 115 | // properties 116 | 117 | var properties = [ 'position', 'left', 'top', 'right', 'bottom', 'width', 'height', 'border', 'borderLeft', 118 | 'borderTop', 'borderRight', 'borderBottom', 'borderColor', 'display', 'overflow', 'margin', 'marginLeft', 'marginTop', 'marginRight', 'marginBottom', 'padding', 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom', 'color', 119 | 'background', 'backgroundColor', 'opacity', 'fontSize', 'fontWeight', 'textAlign', 'textDecoration', 'textTransform', 'cursor', 'zIndex' ]; 120 | 121 | properties.forEach( function ( property ) { 122 | 123 | var method = 'set' + property.substr( 0, 1 ).toUpperCase() + property.substr( 1, property.length ); 124 | 125 | UI.Element.prototype[ method ] = function () { 126 | 127 | this.setStyle( property, arguments ); 128 | 129 | return this; 130 | 131 | }; 132 | 133 | } ); 134 | 135 | // events 136 | 137 | var events = [ 'KeyUp', 'KeyDown', 'MouseOver', 'MouseOut', 'Click', 'DblClick', 'Change' ]; 138 | 139 | events.forEach( function ( event ) { 140 | 141 | var method = 'on' + event; 142 | 143 | UI.Element.prototype[ method ] = function ( callback ) { 144 | 145 | this.dom.addEventListener( event.toLowerCase(), callback.bind( this ), false ); 146 | 147 | return this; 148 | 149 | }; 150 | 151 | } ); 152 | 153 | // Span 154 | 155 | UI.Span = function () { 156 | 157 | UI.Element.call( this ); 158 | 159 | this.dom = document.createElement( 'span' ); 160 | 161 | return this; 162 | 163 | }; 164 | 165 | UI.Span.prototype = Object.create( UI.Element.prototype ); 166 | UI.Span.prototype.constructor = UI.Span; 167 | 168 | // Div 169 | 170 | UI.Div = function () { 171 | 172 | UI.Element.call( this ); 173 | 174 | this.dom = document.createElement( 'div' ); 175 | 176 | return this; 177 | 178 | }; 179 | 180 | UI.Div.prototype = Object.create( UI.Element.prototype ); 181 | UI.Div.prototype.constructor = UI.Div; 182 | 183 | // Row 184 | 185 | UI.Row = function () { 186 | 187 | UI.Element.call( this ); 188 | 189 | var dom = document.createElement( 'div' ); 190 | dom.className = 'Row'; 191 | 192 | this.dom = dom; 193 | 194 | return this; 195 | 196 | }; 197 | 198 | UI.Row.prototype = Object.create( UI.Element.prototype ); 199 | UI.Row.prototype.constructor = UI.Row; 200 | 201 | // Panel 202 | 203 | UI.Panel = function () { 204 | 205 | UI.Element.call( this ); 206 | 207 | var dom = document.createElement( 'div' ); 208 | dom.className = 'Panel'; 209 | 210 | this.dom = dom; 211 | 212 | return this; 213 | 214 | }; 215 | 216 | UI.Panel.prototype = Object.create( UI.Element.prototype ); 217 | UI.Panel.prototype.constructor = UI.Panel; 218 | 219 | 220 | // Collapsible Panel 221 | 222 | UI.CollapsiblePanel = function () { 223 | 224 | UI.Panel.call( this ); 225 | 226 | this.setClass( 'Panel Collapsible' ); 227 | 228 | var scope = this; 229 | 230 | this.static = new UI.Panel(); 231 | this.static.setClass( 'Static' ); 232 | this.static.onClick( function () { 233 | 234 | scope.toggle(); 235 | 236 | } ); 237 | this.dom.appendChild( this.static.dom ); 238 | 239 | this.contents = new UI.Panel(); 240 | this.contents.setClass( 'Content' ); 241 | this.dom.appendChild( this.contents.dom ); 242 | 243 | var button = new UI.Panel(); 244 | button.setClass( 'Button' ); 245 | this.static.add( button ); 246 | 247 | this.isCollapsed = false; 248 | 249 | return this; 250 | 251 | }; 252 | 253 | UI.CollapsiblePanel.prototype = Object.create( UI.Panel.prototype ); 254 | UI.CollapsiblePanel.prototype.constructor = UI.CollapsiblePanel; 255 | 256 | UI.CollapsiblePanel.prototype.addStatic = function () { 257 | 258 | this.static.add.apply( this.static, arguments ); 259 | return this; 260 | 261 | }; 262 | 263 | UI.CollapsiblePanel.prototype.removeStatic = function () { 264 | 265 | this.static.remove.apply( this.static, arguments ); 266 | return this; 267 | 268 | }; 269 | 270 | UI.CollapsiblePanel.prototype.clearStatic = function () { 271 | 272 | this.static.clear(); 273 | return this; 274 | 275 | }; 276 | 277 | UI.CollapsiblePanel.prototype.add = function () { 278 | 279 | this.contents.add.apply( this.contents, arguments ); 280 | return this; 281 | 282 | }; 283 | 284 | UI.CollapsiblePanel.prototype.remove = function () { 285 | 286 | this.contents.remove.apply( this.contents, arguments ); 287 | return this; 288 | 289 | }; 290 | 291 | UI.CollapsiblePanel.prototype.clear = function () { 292 | 293 | this.contents.clear(); 294 | return this; 295 | 296 | }; 297 | 298 | UI.CollapsiblePanel.prototype.toggle = function() { 299 | 300 | this.setCollapsed( ! this.isCollapsed ); 301 | 302 | }; 303 | 304 | UI.CollapsiblePanel.prototype.collapse = function() { 305 | 306 | this.setCollapsed( true ); 307 | 308 | }; 309 | 310 | UI.CollapsiblePanel.prototype.expand = function() { 311 | 312 | this.setCollapsed( false ); 313 | 314 | }; 315 | 316 | UI.CollapsiblePanel.prototype.setCollapsed = function( boolean ) { 317 | 318 | if ( boolean ) { 319 | 320 | this.dom.classList.add( 'collapsed' ); 321 | 322 | } else { 323 | 324 | this.dom.classList.remove( 'collapsed' ); 325 | 326 | } 327 | 328 | this.isCollapsed = boolean; 329 | 330 | if ( this.onCollapsedChangeCallback !== undefined ) { 331 | 332 | this.onCollapsedChangeCallback( boolean ); 333 | 334 | } 335 | 336 | }; 337 | 338 | UI.CollapsiblePanel.prototype.onCollapsedChange = function ( callback ) { 339 | 340 | this.onCollapsedChangeCallback = callback; 341 | 342 | }; 343 | 344 | // Text 345 | 346 | UI.Text = function ( text ) { 347 | 348 | UI.Element.call( this ); 349 | 350 | var dom = document.createElement( 'span' ); 351 | dom.className = 'Text'; 352 | dom.style.cursor = 'default'; 353 | dom.style.display = 'inline-block'; 354 | dom.style.verticalAlign = 'middle'; 355 | 356 | this.dom = dom; 357 | this.setValue( text ); 358 | 359 | return this; 360 | 361 | }; 362 | 363 | UI.Text.prototype = Object.create( UI.Element.prototype ); 364 | UI.Text.prototype.constructor = UI.Text; 365 | 366 | UI.Text.prototype.getValue = function () { 367 | 368 | return this.dom.textContent; 369 | 370 | }; 371 | 372 | UI.Text.prototype.setValue = function ( value ) { 373 | 374 | if ( value !== undefined ) { 375 | 376 | this.dom.textContent = value; 377 | 378 | } 379 | 380 | return this; 381 | 382 | }; 383 | 384 | 385 | // Input 386 | 387 | UI.Input = function ( text ) { 388 | 389 | UI.Element.call( this ); 390 | 391 | var scope = this; 392 | 393 | var dom = document.createElement( 'input' ); 394 | dom.className = 'Input'; 395 | dom.style.padding = '2px'; 396 | dom.style.border = '1px solid transparent'; 397 | 398 | dom.addEventListener( 'keydown', function ( event ) { 399 | 400 | event.stopPropagation(); 401 | 402 | }, false ); 403 | 404 | this.dom = dom; 405 | this.setValue( text ); 406 | 407 | return this; 408 | 409 | }; 410 | 411 | UI.Input.prototype = Object.create( UI.Element.prototype ); 412 | UI.Input.prototype.constructor = UI.Input; 413 | 414 | UI.Input.prototype.getValue = function () { 415 | 416 | return this.dom.value; 417 | 418 | }; 419 | 420 | UI.Input.prototype.setValue = function ( value ) { 421 | 422 | this.dom.value = value; 423 | 424 | return this; 425 | 426 | }; 427 | 428 | 429 | // TextArea 430 | 431 | UI.TextArea = function () { 432 | 433 | UI.Element.call( this ); 434 | 435 | var scope = this; 436 | 437 | var dom = document.createElement( 'textarea' ); 438 | dom.className = 'TextArea'; 439 | dom.style.padding = '2px'; 440 | dom.spellcheck = false; 441 | 442 | dom.addEventListener( 'keydown', function ( event ) { 443 | 444 | event.stopPropagation(); 445 | 446 | if ( event.keyCode === 9 ) { 447 | 448 | event.preventDefault(); 449 | 450 | var cursor = dom.selectionStart; 451 | 452 | dom.value = dom.value.substring( 0, cursor ) + '\t' + dom.value.substring( cursor ); 453 | dom.selectionStart = cursor + 1; 454 | dom.selectionEnd = dom.selectionStart; 455 | 456 | } 457 | 458 | }, false ); 459 | 460 | this.dom = dom; 461 | 462 | return this; 463 | 464 | }; 465 | 466 | UI.TextArea.prototype = Object.create( UI.Element.prototype ); 467 | UI.TextArea.prototype.constructor = UI.TextArea; 468 | 469 | UI.TextArea.prototype.getValue = function () { 470 | 471 | return this.dom.value; 472 | 473 | }; 474 | 475 | UI.TextArea.prototype.setValue = function ( value ) { 476 | 477 | this.dom.value = value; 478 | 479 | return this; 480 | 481 | }; 482 | 483 | 484 | // Select 485 | 486 | UI.Select = function () { 487 | 488 | UI.Element.call( this ); 489 | 490 | var scope = this; 491 | 492 | var dom = document.createElement( 'select' ); 493 | dom.className = 'Select'; 494 | dom.style.padding = '2px'; 495 | 496 | this.dom = dom; 497 | 498 | return this; 499 | 500 | }; 501 | 502 | UI.Select.prototype = Object.create( UI.Element.prototype ); 503 | UI.Select.prototype.constructor = UI.Select; 504 | 505 | UI.Select.prototype.setMultiple = function ( boolean ) { 506 | 507 | this.dom.multiple = boolean; 508 | 509 | return this; 510 | 511 | }; 512 | 513 | UI.Select.prototype.setOptions = function ( options ) { 514 | 515 | var selected = this.dom.value; 516 | 517 | while ( this.dom.children.length > 0 ) { 518 | 519 | this.dom.removeChild( this.dom.firstChild ); 520 | 521 | } 522 | 523 | for ( var key in options ) { 524 | 525 | var option = document.createElement( 'option' ); 526 | option.value = key; 527 | option.innerHTML = options[ key ]; 528 | this.dom.appendChild( option ); 529 | 530 | } 531 | 532 | this.dom.value = selected; 533 | 534 | return this; 535 | 536 | }; 537 | 538 | UI.Select.prototype.getValue = function () { 539 | 540 | return this.dom.value; 541 | 542 | }; 543 | 544 | UI.Select.prototype.setValue = function ( value ) { 545 | 546 | value = String( value ); 547 | 548 | if ( this.dom.value !== value ) { 549 | 550 | this.dom.value = value; 551 | 552 | } 553 | 554 | return this; 555 | 556 | }; 557 | 558 | // Checkbox 559 | 560 | UI.Checkbox = function ( boolean ) { 561 | 562 | UI.Element.call( this ); 563 | 564 | var scope = this; 565 | 566 | var dom = document.createElement( 'input' ); 567 | dom.className = 'Checkbox'; 568 | dom.type = 'checkbox'; 569 | 570 | this.dom = dom; 571 | this.setValue( boolean ); 572 | 573 | return this; 574 | 575 | }; 576 | 577 | UI.Checkbox.prototype = Object.create( UI.Element.prototype ); 578 | UI.Checkbox.prototype.constructor = UI.Checkbox; 579 | 580 | UI.Checkbox.prototype.getValue = function () { 581 | 582 | return this.dom.checked; 583 | 584 | }; 585 | 586 | UI.Checkbox.prototype.setValue = function ( value ) { 587 | 588 | if ( value !== undefined ) { 589 | 590 | this.dom.checked = value; 591 | 592 | } 593 | 594 | return this; 595 | 596 | }; 597 | 598 | 599 | // Color 600 | 601 | UI.Color = function () { 602 | 603 | UI.Element.call( this ); 604 | 605 | var scope = this; 606 | 607 | var dom = document.createElement( 'input' ); 608 | dom.className = 'Color'; 609 | dom.style.width = '64px'; 610 | dom.style.height = '17px'; 611 | dom.style.border = '0px'; 612 | dom.style.padding = '2px'; 613 | dom.style.backgroundColor = 'transparent'; 614 | 615 | try { 616 | 617 | dom.type = 'color'; 618 | dom.value = '#ffffff'; 619 | 620 | } catch ( exception ) {} 621 | 622 | this.dom = dom; 623 | 624 | return this; 625 | 626 | }; 627 | 628 | UI.Color.prototype = Object.create( UI.Element.prototype ); 629 | UI.Color.prototype.constructor = UI.Color; 630 | 631 | UI.Color.prototype.getValue = function () { 632 | 633 | return this.dom.value; 634 | 635 | }; 636 | 637 | UI.Color.prototype.getHexValue = function () { 638 | 639 | return parseInt( this.dom.value.substr( 1 ), 16 ); 640 | 641 | }; 642 | 643 | UI.Color.prototype.setValue = function ( value ) { 644 | 645 | this.dom.value = value; 646 | 647 | return this; 648 | 649 | }; 650 | 651 | UI.Color.prototype.setHexValue = function ( hex ) { 652 | 653 | this.dom.value = '#' + ( '000000' + hex.toString( 16 ) ).slice( - 6 ); 654 | 655 | return this; 656 | 657 | }; 658 | 659 | 660 | // Number 661 | 662 | UI.Number = function ( number ) { 663 | 664 | UI.Element.call( this ); 665 | 666 | var scope = this; 667 | 668 | var dom = document.createElement( 'input' ); 669 | dom.className = 'Number'; 670 | dom.value = '0.00'; 671 | 672 | dom.addEventListener( 'keydown', function ( event ) { 673 | 674 | event.stopPropagation(); 675 | 676 | if ( event.keyCode === 13 ) dom.blur(); 677 | 678 | }, false ); 679 | 680 | this.value = 0; 681 | 682 | this.min = - Infinity; 683 | this.max = Infinity; 684 | 685 | this.precision = 2; 686 | this.step = 1; 687 | this.unit = ''; 688 | 689 | this.dom = dom; 690 | 691 | this.setValue( number ); 692 | 693 | var changeEvent = document.createEvent( 'HTMLEvents' ); 694 | changeEvent.initEvent( 'change', true, true ); 695 | 696 | var distance = 0; 697 | var onMouseDownValue = 0; 698 | 699 | var pointer = [ 0, 0 ]; 700 | var prevPointer = [ 0, 0 ]; 701 | 702 | function onMouseDown( event ) { 703 | 704 | event.preventDefault(); 705 | 706 | distance = 0; 707 | 708 | onMouseDownValue = scope.value; 709 | 710 | prevPointer = [ event.clientX, event.clientY ]; 711 | 712 | document.addEventListener( 'mousemove', onMouseMove, false ); 713 | document.addEventListener( 'mouseup', onMouseUp, false ); 714 | 715 | } 716 | 717 | function onMouseMove( event ) { 718 | 719 | var currentValue = scope.value; 720 | 721 | pointer = [ event.clientX, event.clientY ]; 722 | 723 | distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); 724 | 725 | var value = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; 726 | value = Math.min( scope.max, Math.max( scope.min, value ) ); 727 | 728 | if ( currentValue !== value ) { 729 | 730 | scope.setValue( value ); 731 | dom.dispatchEvent( changeEvent ); 732 | 733 | } 734 | 735 | prevPointer = [ event.clientX, event.clientY ]; 736 | 737 | } 738 | 739 | function onMouseUp( event ) { 740 | 741 | document.removeEventListener( 'mousemove', onMouseMove, false ); 742 | document.removeEventListener( 'mouseup', onMouseUp, false ); 743 | 744 | if ( Math.abs( distance ) < 2 ) { 745 | 746 | dom.focus(); 747 | dom.select(); 748 | 749 | } 750 | 751 | } 752 | 753 | function onChange( event ) { 754 | 755 | scope.setValue( dom.value ); 756 | 757 | } 758 | 759 | function onFocus( event ) { 760 | 761 | dom.style.backgroundColor = ''; 762 | dom.style.cursor = ''; 763 | 764 | } 765 | 766 | function onBlur( event ) { 767 | 768 | dom.style.backgroundColor = 'transparent'; 769 | dom.style.cursor = 'col-resize'; 770 | 771 | } 772 | 773 | onBlur(); 774 | 775 | dom.addEventListener( 'mousedown', onMouseDown, false ); 776 | dom.addEventListener( 'change', onChange, false ); 777 | dom.addEventListener( 'focus', onFocus, false ); 778 | dom.addEventListener( 'blur', onBlur, false ); 779 | 780 | return this; 781 | 782 | }; 783 | 784 | UI.Number.prototype = Object.create( UI.Element.prototype ); 785 | UI.Number.prototype.constructor = UI.Number; 786 | 787 | UI.Number.prototype.getValue = function () { 788 | 789 | return this.value; 790 | 791 | }; 792 | 793 | UI.Number.prototype.setValue = function ( value ) { 794 | 795 | if ( value !== undefined ) { 796 | 797 | value = parseFloat( value ); 798 | 799 | if ( value < this.min ) value = this.min; 800 | if ( value > this.max ) value = this.max; 801 | 802 | this.value = value; 803 | this.dom.value = value.toFixed( this.precision ) + ' ' + this.unit; 804 | 805 | } 806 | 807 | return this; 808 | 809 | }; 810 | 811 | UI.Number.prototype.setPrecision = function ( precision ) { 812 | 813 | this.precision = precision; 814 | 815 | return this; 816 | 817 | }; 818 | 819 | UI.Number.prototype.setStep = function ( step ) { 820 | 821 | this.step = step; 822 | 823 | return this; 824 | 825 | }; 826 | 827 | UI.Number.prototype.setRange = function ( min, max ) { 828 | 829 | this.min = min; 830 | this.max = max; 831 | 832 | return this; 833 | 834 | }; 835 | 836 | UI.Number.prototype.setUnit = function ( unit ) { 837 | 838 | this.unit = unit; 839 | 840 | return this; 841 | 842 | }; 843 | 844 | // Integer 845 | 846 | UI.Integer = function ( number ) { 847 | 848 | UI.Element.call( this ); 849 | 850 | var scope = this; 851 | 852 | var dom = document.createElement( 'input' ); 853 | dom.className = 'Number'; 854 | dom.value = '0'; 855 | 856 | dom.addEventListener( 'keydown', function ( event ) { 857 | 858 | event.stopPropagation(); 859 | 860 | }, false ); 861 | 862 | this.value = 0; 863 | 864 | this.min = - Infinity; 865 | this.max = Infinity; 866 | 867 | this.step = 1; 868 | 869 | this.dom = dom; 870 | 871 | this.setValue( number ); 872 | 873 | var changeEvent = document.createEvent( 'HTMLEvents' ); 874 | changeEvent.initEvent( 'change', true, true ); 875 | 876 | var distance = 0; 877 | var onMouseDownValue = 0; 878 | 879 | var pointer = [ 0, 0 ]; 880 | var prevPointer = [ 0, 0 ]; 881 | 882 | function onMouseDown( event ) { 883 | 884 | event.preventDefault(); 885 | 886 | distance = 0; 887 | 888 | onMouseDownValue = scope.value; 889 | 890 | prevPointer = [ event.clientX, event.clientY ]; 891 | 892 | document.addEventListener( 'mousemove', onMouseMove, false ); 893 | document.addEventListener( 'mouseup', onMouseUp, false ); 894 | 895 | } 896 | 897 | function onMouseMove( event ) { 898 | 899 | var currentValue = scope.value; 900 | 901 | pointer = [ event.clientX, event.clientY ]; 902 | 903 | distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); 904 | 905 | var value = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; 906 | value = Math.min( scope.max, Math.max( scope.min, value ) ) | 0; 907 | 908 | if ( currentValue !== value ) { 909 | 910 | scope.setValue( value ); 911 | dom.dispatchEvent( changeEvent ); 912 | 913 | } 914 | 915 | prevPointer = [ event.clientX, event.clientY ]; 916 | 917 | } 918 | 919 | function onMouseUp( event ) { 920 | 921 | document.removeEventListener( 'mousemove', onMouseMove, false ); 922 | document.removeEventListener( 'mouseup', onMouseUp, false ); 923 | 924 | if ( Math.abs( distance ) < 2 ) { 925 | 926 | dom.focus(); 927 | dom.select(); 928 | 929 | } 930 | 931 | } 932 | 933 | function onChange( event ) { 934 | 935 | scope.setValue( dom.value ); 936 | 937 | } 938 | 939 | function onFocus( event ) { 940 | 941 | dom.style.backgroundColor = ''; 942 | dom.style.cursor = ''; 943 | 944 | } 945 | 946 | function onBlur( event ) { 947 | 948 | dom.style.backgroundColor = 'transparent'; 949 | dom.style.cursor = 'col-resize'; 950 | 951 | } 952 | 953 | onBlur(); 954 | 955 | dom.addEventListener( 'mousedown', onMouseDown, false ); 956 | dom.addEventListener( 'change', onChange, false ); 957 | dom.addEventListener( 'focus', onFocus, false ); 958 | dom.addEventListener( 'blur', onBlur, false ); 959 | 960 | return this; 961 | 962 | }; 963 | 964 | UI.Integer.prototype = Object.create( UI.Element.prototype ); 965 | UI.Integer.prototype.constructor = UI.Integer; 966 | 967 | UI.Integer.prototype.getValue = function () { 968 | 969 | return this.value; 970 | 971 | }; 972 | 973 | UI.Integer.prototype.setValue = function ( value ) { 974 | 975 | if ( value !== undefined ) { 976 | 977 | value = parseInt( value ); 978 | 979 | this.value = value; 980 | this.dom.value = value; 981 | 982 | } 983 | 984 | return this; 985 | 986 | }; 987 | 988 | UI.Number.prototype.setStep = function ( step ) { 989 | 990 | this.step = step; 991 | 992 | return this; 993 | 994 | }; 995 | 996 | UI.Integer.prototype.setRange = function ( min, max ) { 997 | 998 | this.min = min; 999 | this.max = max; 1000 | 1001 | return this; 1002 | 1003 | }; 1004 | 1005 | 1006 | // Break 1007 | 1008 | UI.Break = function () { 1009 | 1010 | UI.Element.call( this ); 1011 | 1012 | var dom = document.createElement( 'br' ); 1013 | dom.className = 'Break'; 1014 | 1015 | this.dom = dom; 1016 | 1017 | return this; 1018 | 1019 | }; 1020 | 1021 | UI.Break.prototype = Object.create( UI.Element.prototype ); 1022 | UI.Break.prototype.constructor = UI.Break; 1023 | 1024 | 1025 | // HorizontalRule 1026 | 1027 | UI.HorizontalRule = function () { 1028 | 1029 | UI.Element.call( this ); 1030 | 1031 | var dom = document.createElement( 'hr' ); 1032 | dom.className = 'HorizontalRule'; 1033 | 1034 | this.dom = dom; 1035 | 1036 | return this; 1037 | 1038 | }; 1039 | 1040 | UI.HorizontalRule.prototype = Object.create( UI.Element.prototype ); 1041 | UI.HorizontalRule.prototype.constructor = UI.HorizontalRule; 1042 | 1043 | 1044 | // Button 1045 | 1046 | UI.Button = function ( value ) { 1047 | 1048 | UI.Element.call( this ); 1049 | 1050 | var dom = document.createElement( 'button' ); 1051 | dom.className = 'Button'; 1052 | 1053 | this.dom = dom; 1054 | this.dom.textContent = value; 1055 | 1056 | return this; 1057 | 1058 | }; 1059 | 1060 | UI.Button.prototype = Object.create( UI.Element.prototype ); 1061 | UI.Button.prototype.constructor = UI.Button; 1062 | 1063 | UI.Button.prototype.setLabel = function ( value ) { 1064 | 1065 | this.dom.textContent = value; 1066 | 1067 | return this; 1068 | 1069 | }; 1070 | 1071 | 1072 | // Modal 1073 | 1074 | UI.Modal = function ( value ) { 1075 | 1076 | var scope = this; 1077 | 1078 | var dom = document.createElement( 'div' ); 1079 | 1080 | dom.style.position = 'absolute'; 1081 | dom.style.width = '100%'; 1082 | dom.style.height = '100%'; 1083 | dom.style.backgroundColor = 'rgba(0,0,0,0.5)'; 1084 | dom.style.display = 'none'; 1085 | dom.style.alignItems = 'center'; 1086 | dom.style.justifyContent = 'center'; 1087 | dom.addEventListener( 'click', function ( event ) { 1088 | 1089 | scope.hide(); 1090 | 1091 | } ); 1092 | 1093 | this.dom = dom; 1094 | 1095 | this.container = new UI.Panel(); 1096 | this.container.dom.style.width = '200px'; 1097 | this.container.dom.style.padding = '20px'; 1098 | this.container.dom.style.backgroundColor = '#ffffff'; 1099 | this.container.dom.style.boxShadow = '0px 5px 10px rgba(0,0,0,0.5)'; 1100 | 1101 | this.add( this.container ); 1102 | 1103 | return this; 1104 | 1105 | }; 1106 | 1107 | UI.Modal.prototype = Object.create( UI.Element.prototype ); 1108 | UI.Modal.prototype.constructor = UI.Modal; 1109 | 1110 | UI.Modal.prototype.show = function ( content ) { 1111 | 1112 | this.container.clear(); 1113 | this.container.add( content ); 1114 | 1115 | this.dom.style.display = 'flex'; 1116 | 1117 | return this; 1118 | 1119 | }; 1120 | 1121 | UI.Modal.prototype.hide = function () { 1122 | 1123 | this.dom.style.display = 'none'; 1124 | 1125 | return this; 1126 | 1127 | }; -------------------------------------------------------------------------------- /js/ui.three.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | */ 4 | 5 | UI.Texture = function ( mapping ) { 6 | 7 | UI.Element.call( this ); 8 | 9 | var scope = this; 10 | 11 | var dom = document.createElement( 'span' ); 12 | 13 | var form = document.createElement( 'form' ); 14 | 15 | var input = document.createElement( 'input' ); 16 | input.type = 'file'; 17 | input.addEventListener( 'change', function ( event ) { 18 | 19 | loadFile( event.target.files[ 0 ] ); 20 | 21 | } ); 22 | form.appendChild( input ); 23 | 24 | var canvas = document.createElement( 'canvas' ); 25 | canvas.width = 32; 26 | canvas.height = 16; 27 | canvas.style.cursor = 'pointer'; 28 | canvas.style.marginRight = '5px'; 29 | canvas.style.border = '1px solid #888'; 30 | canvas.addEventListener( 'click', function ( event ) { 31 | 32 | input.click(); 33 | 34 | }, false ); 35 | canvas.addEventListener( 'drop', function ( event ) { 36 | 37 | event.preventDefault(); 38 | event.stopPropagation(); 39 | loadFile( event.dataTransfer.files[ 0 ] ); 40 | 41 | }, false ); 42 | dom.appendChild( canvas ); 43 | 44 | var name = document.createElement( 'input' ); 45 | name.disabled = true; 46 | name.style.width = '64px'; 47 | name.style.border = '1px solid #ccc'; 48 | dom.appendChild( name ); 49 | 50 | function loadFile( file ) { 51 | 52 | if ( file.type.match( 'image.*' ) ) { 53 | 54 | var reader = new FileReader(); 55 | 56 | if ( file.type === 'image/targa' ) { 57 | 58 | reader.addEventListener( 'load', function ( event ) { 59 | 60 | var canvas = new THREE.TGALoader().parse( event.target.result ); 61 | 62 | var texture = new THREE.CanvasTexture( canvas, mapping ); 63 | texture.sourceFile = file.name; 64 | 65 | scope.setValue( texture ); 66 | 67 | if ( scope.onChangeCallback ) scope.onChangeCallback(); 68 | 69 | }, false ); 70 | 71 | reader.readAsArrayBuffer( file ); 72 | 73 | } else { 74 | 75 | reader.addEventListener( 'load', function ( event ) { 76 | 77 | var image = document.createElement( 'img' ); 78 | image.addEventListener( 'load', function( event ) { 79 | 80 | var texture = new THREE.Texture( this, mapping ); 81 | texture.sourceFile = file.name; 82 | texture.needsUpdate = true; 83 | 84 | scope.setValue( texture ); 85 | 86 | if ( scope.onChangeCallback ) scope.onChangeCallback(); 87 | 88 | }, false ); 89 | 90 | image.src = event.target.result; 91 | 92 | }, false ); 93 | 94 | reader.readAsDataURL( file ); 95 | 96 | } 97 | 98 | } 99 | 100 | form.reset(); 101 | 102 | } 103 | 104 | this.dom = dom; 105 | this.texture = null; 106 | this.onChangeCallback = null; 107 | 108 | return this; 109 | 110 | }; 111 | 112 | UI.Texture.prototype = Object.create( UI.Element.prototype ); 113 | UI.Texture.prototype.constructor = UI.Texture; 114 | 115 | UI.Texture.prototype.getValue = function () { 116 | 117 | return this.texture; 118 | 119 | }; 120 | 121 | UI.Texture.prototype.setValue = function ( texture ) { 122 | 123 | var canvas = this.dom.children[ 0 ]; 124 | var name = this.dom.children[ 1 ]; 125 | var context = canvas.getContext( '2d' ); 126 | 127 | if ( texture !== null ) { 128 | 129 | var image = texture.image; 130 | 131 | if ( image !== undefined && image.width > 0 ) { 132 | 133 | name.value = texture.sourceFile; 134 | 135 | var scale = canvas.width / image.width; 136 | context.drawImage( image, 0, 0, image.width * scale, image.height * scale ); 137 | 138 | } else { 139 | 140 | name.value = texture.sourceFile + ' (error)'; 141 | context.clearRect( 0, 0, canvas.width, canvas.height ); 142 | 143 | } 144 | 145 | } else { 146 | 147 | name.value = ''; 148 | 149 | if ( context !== null ) { 150 | 151 | // Seems like context can be null if the canvas is not visible 152 | 153 | context.clearRect( 0, 0, canvas.width, canvas.height ); 154 | 155 | } 156 | 157 | } 158 | 159 | this.texture = texture; 160 | 161 | }; 162 | 163 | UI.Texture.prototype.onChange = function ( callback ) { 164 | 165 | this.onChangeCallback = callback; 166 | 167 | return this; 168 | 169 | }; 170 | 171 | // Outliner 172 | 173 | UI.Outliner = function ( editor ) { 174 | 175 | UI.Element.call( this ); 176 | 177 | var scope = this; 178 | 179 | var dom = document.createElement( 'div' ); 180 | dom.className = 'Outliner'; 181 | dom.tabIndex = 0; // keyup event is ignored without setting tabIndex 182 | 183 | // hack 184 | this.scene = editor.scene; 185 | 186 | // Prevent native scroll behavior 187 | dom.addEventListener( 'keydown', function ( event ) { 188 | 189 | switch ( event.keyCode ) { 190 | case 38: // up 191 | case 40: // down 192 | event.preventDefault(); 193 | event.stopPropagation(); 194 | break; 195 | } 196 | 197 | }, false ); 198 | 199 | // Keybindings to support arrow navigation 200 | dom.addEventListener( 'keyup', function ( event ) { 201 | 202 | switch ( event.keyCode ) { 203 | case 38: // up 204 | scope.selectIndex( scope.selectedIndex - 1 ); 205 | break; 206 | case 40: // down 207 | scope.selectIndex( scope.selectedIndex + 1 ); 208 | break; 209 | } 210 | 211 | }, false ); 212 | 213 | this.dom = dom; 214 | 215 | this.options = []; 216 | this.selectedIndex = - 1; 217 | this.selectedValue = null; 218 | 219 | return this; 220 | 221 | }; 222 | 223 | UI.Outliner.prototype = Object.create( UI.Element.prototype ); 224 | UI.Outliner.prototype.constructor = UI.Outliner; 225 | 226 | UI.Outliner.prototype.selectIndex = function ( index ) { 227 | 228 | if ( index >= 0 && index < this.options.length ) { 229 | 230 | this.setValue( this.options[ index ].value ); 231 | 232 | var changeEvent = document.createEvent( 'HTMLEvents' ); 233 | changeEvent.initEvent( 'change', true, true ); 234 | this.dom.dispatchEvent( changeEvent ); 235 | 236 | } 237 | 238 | }; 239 | 240 | UI.Outliner.prototype.setOptions = function ( options ) { 241 | 242 | var scope = this; 243 | 244 | while ( scope.dom.children.length > 0 ) { 245 | 246 | scope.dom.removeChild( scope.dom.firstChild ); 247 | 248 | } 249 | 250 | function onClick() { 251 | 252 | scope.setValue( this.value ); 253 | 254 | var changeEvent = document.createEvent( 'HTMLEvents' ); 255 | changeEvent.initEvent( 'change', true, true ); 256 | scope.dom.dispatchEvent( changeEvent ); 257 | 258 | } 259 | 260 | // Drag 261 | 262 | var currentDrag; 263 | 264 | function onDrag( event ) { 265 | 266 | currentDrag = this; 267 | 268 | } 269 | 270 | function onDragStart( event ) { 271 | 272 | event.dataTransfer.setData( 'text', 'foo' ); 273 | 274 | } 275 | 276 | function onDragOver( event ) { 277 | 278 | if ( this === currentDrag ) return; 279 | 280 | var area = event.offsetY / this.clientHeight; 281 | 282 | if ( area < 0.25 ) { 283 | 284 | this.className = 'option dragTop'; 285 | 286 | } else if ( area > 0.75 ) { 287 | 288 | this.className = 'option dragBottom'; 289 | 290 | } else { 291 | 292 | this.className = 'option drag'; 293 | 294 | } 295 | 296 | } 297 | 298 | function onDragLeave() { 299 | 300 | if ( this === currentDrag ) return; 301 | 302 | this.className = 'option'; 303 | 304 | } 305 | 306 | function onDrop( event ) { 307 | 308 | if ( this === currentDrag ) return; 309 | 310 | this.className = 'option'; 311 | 312 | var scene = scope.scene; 313 | var object = scene.getObjectById( currentDrag.value ); 314 | 315 | var area = event.offsetY / this.clientHeight; 316 | 317 | if ( area < 0.25 ) { 318 | 319 | var nextObject = scene.getObjectById( this.value ); 320 | moveObject( object, nextObject.parent, nextObject ); 321 | 322 | } else if ( area > 0.75 ) { 323 | 324 | var nextObject = scene.getObjectById( this.nextSibling.value ); 325 | moveObject( object, nextObject.parent, nextObject ); 326 | 327 | } else { 328 | 329 | var parentObject = scene.getObjectById( this.value ); 330 | moveObject( object, parentObject ); 331 | 332 | } 333 | 334 | } 335 | 336 | function moveObject( object, newParent, nextObject ) { 337 | 338 | if ( nextObject === null ) nextObject = undefined; 339 | 340 | var newParentIsChild = false; 341 | 342 | object.traverse( function ( child ) { 343 | 344 | if ( child === newParent ) newParentIsChild = true; 345 | 346 | } ); 347 | 348 | if ( newParentIsChild ) return; 349 | 350 | editor.execute( new MoveObjectCommand( object, newParent, nextObject ) ); 351 | 352 | var changeEvent = document.createEvent( 'HTMLEvents' ); 353 | changeEvent.initEvent( 'change', true, true ); 354 | scope.dom.dispatchEvent( changeEvent ); 355 | 356 | } 357 | 358 | // 359 | 360 | scope.options = []; 361 | 362 | for ( var i = 0; i < options.length; i ++ ) { 363 | 364 | var div = options[ i ]; 365 | div.className = 'option'; 366 | scope.dom.appendChild( div ); 367 | 368 | scope.options.push( div ); 369 | 370 | div.addEventListener( 'click', onClick, false ); 371 | 372 | if ( div.draggable === true ) { 373 | 374 | div.addEventListener( 'drag', onDrag, false ); 375 | div.addEventListener( 'dragstart', onDragStart, false ); // Firefox needs this 376 | 377 | div.addEventListener( 'dragover', onDragOver, false ); 378 | div.addEventListener( 'dragleave', onDragLeave, false ); 379 | div.addEventListener( 'drop', onDrop, false ); 380 | 381 | } 382 | 383 | 384 | } 385 | 386 | return scope; 387 | 388 | }; 389 | 390 | UI.Outliner.prototype.getValue = function () { 391 | 392 | return this.selectedValue; 393 | 394 | }; 395 | 396 | UI.Outliner.prototype.setValue = function ( value ) { 397 | 398 | for ( var i = 0; i < this.options.length; i ++ ) { 399 | 400 | var element = this.options[ i ]; 401 | 402 | if ( element.value === value ) { 403 | 404 | element.classList.add( 'active' ); 405 | 406 | // scroll into view 407 | 408 | var y = element.offsetTop - this.dom.offsetTop; 409 | var bottomY = y + element.offsetHeight; 410 | var minScroll = bottomY - this.dom.offsetHeight; 411 | 412 | if ( this.dom.scrollTop > y ) { 413 | 414 | this.dom.scrollTop = y; 415 | 416 | } else if ( this.dom.scrollTop < minScroll ) { 417 | 418 | this.dom.scrollTop = minScroll; 419 | 420 | } 421 | 422 | this.selectedIndex = i; 423 | 424 | } else { 425 | 426 | element.classList.remove( 'active' ); 427 | 428 | } 429 | 430 | } 431 | 432 | this.selectedValue = value; 433 | 434 | return this; 435 | 436 | }; 437 | 438 | UI.THREE = {}; 439 | 440 | UI.THREE.Boolean = function ( boolean, text ) { 441 | 442 | UI.Span.call( this ); 443 | 444 | this.setMarginRight( '10px' ); 445 | 446 | this.checkbox = new UI.Checkbox( boolean ); 447 | this.text = new UI.Text( text ).setMarginLeft( '3px' ); 448 | 449 | this.add( this.checkbox ); 450 | this.add( this.text ); 451 | 452 | }; 453 | 454 | UI.THREE.Boolean.prototype = Object.create( UI.Span.prototype ); 455 | UI.THREE.Boolean.prototype.constructor = UI.THREE.Boolean; 456 | 457 | UI.THREE.Boolean.prototype.getValue = function () { 458 | 459 | return this.checkbox.getValue(); 460 | 461 | }; 462 | 463 | UI.THREE.Boolean.prototype.setValue = function ( value ) { 464 | 465 | return this.checkbox.setValue( value ); 466 | 467 | }; -------------------------------------------------------------------------------- /src/Editor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Unravel with help from Fish on 12/1/2016. 3 | */ 4 | 5 | var TILE_COUNT = 48; 6 | var TILE_MESH_SIZE = 1; 7 | var SectorX = 51; 8 | var SectorY = 47; 9 | var sectorsLoaded = false; 10 | var container; 11 | var camera, scene, renderer, controls; 12 | var mouse, raycaster, isShiftDown = false; 13 | var camera, stats; 14 | var Sectors = new Array(); 15 | var selected; 16 | var overlay_map = {}; 17 | var Tiles; 18 | var mesh; 19 | var masterGeometry; 20 | var offsets = [[-1, -1],[0, -1],[1, -1], [-1, 0],[0, 0],[1, 0], [-1, 1],[0, 1],[1, 1]]; 21 | var gui = new dat.GUI(); 22 | var guiItems = 23 | { 24 | localXY: "0, 0", 25 | sectorName: "0", 26 | sectorIdx: 0, 27 | tileIdx: 0, 28 | rscXY: "0", 29 | tile_elevation: 0, 30 | tile_texture: 0, 31 | tile_overlay: 0, 32 | tile_horizontal: 0, 33 | tile_vertical: 0, 34 | tile_diagonal: 0, 35 | tile_roof: 0 36 | 37 | }; 38 | 39 | 40 | function initEditor() { 41 | try { 42 | setup(); 43 | html(); 44 | animate(); 45 | } catch(err) { 46 | alert(err); 47 | } 48 | } 49 | 50 | function openFile(event) { 51 | var file = event.target.files[0]; 52 | var jsZip = new JSZip() 53 | jsZip.loadAsync(file).then(function (zip) { 54 | 55 | for(var i=0; i < offsets.length; i++) { 56 | var name = "h0x" + (SectorX + offsets[i][0]) + "y" + (SectorY + offsets[i][1]); 57 | console.error("reading " + name); 58 | zip.file(name).async('arraybuffer').then(function (fileData) { 59 | var view = new DataView(fileData); 60 | Sectors.push(view); 61 | }) 62 | } 63 | }) 64 | var timer = setInterval(load_timer, 500); 65 | function load_timer() { 66 | if(sectorsLoaded) { 67 | clearInterval(timer); 68 | sectorsLoaded = false; 69 | unpackSectors(); 70 | updateSectors(); 71 | camera.position.set(0,0,200); 72 | //camera.target.set(0, 0, 0); 73 | camera.rotation.set(-200, 0, 0); 74 | controls = new THREE.OrbitControls( camera, renderer.domElement ); 75 | controls.enableDamping = true; 76 | controls.dampingFactor = 0.25; 77 | controls.zoomSpeed = 0.5; 78 | //controls.target..x -= 100; 79 | //controls.target.set(50, (48/2*3), -100); 80 | 81 | controls.enabled = true; 82 | controls.enablePan = true; 83 | controls.enableZoom = true; 84 | controls.update(); 85 | animate(); 86 | } 87 | } 88 | 89 | } 90 | 91 | 92 | function unpackSectors() { 93 | Tiles = new Array((TILE_COUNT*TILE_COUNT) * Sectors.length); 94 | var sectX = 0; 95 | var sectY = 0; 96 | for(var s=0; s < Sectors.length; s++) { 97 | if (sectX == Math.sqrt(Sectors.length)) { 98 | sectX = 0; 99 | sectY++; 100 | } 101 | var sectorIndex = s; 102 | var idx = 0; 103 | var view = Sectors[s]; 104 | for (var x = 0; x < TILE_COUNT; x++) { 105 | for (var y = 0; y < TILE_COUNT; y++) { 106 | var tile = new Tile(sectorIndex, sectX, sectY, x, y, view.getUint8(idx), view.getUint8(idx + 1), view.getUint8(idx + 2), view.getUint8(idx + 3), view.getUint8(idx + 4), view.getUint8(idx + 5), view.getUint32(idx + 6), s, (SectorX + offsets[sectorIndex][0]),(SectorY + offsets[sectorIndex][1]) ); 107 | 108 | Tiles[((x * 48) + y) + 48 * 48 * sectorIndex] = tile; 109 | idx += 10; 110 | } 111 | } 112 | sectX++; 113 | } 114 | sectorsLoaded = true; 115 | } 116 | 117 | 118 | <<<<<<< HEAD 119 | ======= 120 | function updateSectors() { 121 | 122 | 123 | //scene.remove(mesh); 124 | masterGeometry = new THREE.PlaneGeometry(0 , 0 , 0, 0); 125 | 126 | var sectX = 0; 127 | var sectY = 0; 128 | 129 | for(var s=0; s < Sectors.length; s++) { 130 | if (sectX == Math.sqrt(Sectors.length)) { 131 | sectX = 0; 132 | sectY++; 133 | } 134 | var sectorIndex = s; 135 | var idx = 0; 136 | var view = Sectors[s]; 137 | var tmesh = drawSector(sectorIndex); 138 | tmesh.position.set(-(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * sectX, -(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * sectY, 0); 139 | tmesh.rotation.z = -Math.PI / 2; 140 | 141 | tmesh.updateMatrix(); 142 | masterGeometry.merge(tmesh.geometry, tmesh.matrix); 143 | sectX++; 144 | 145 | } 146 | 147 | 148 | 149 | 150 | //if(mesh != null) { 151 | mesh = new THREE.Mesh(masterGeometry, new THREE.MeshFaceMaterial(materials)); 152 | 153 | /// var geo = new THREE.WireframeGeometry( masterGeometry); // or WireframeGeometry 154 | //var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } ); 155 | //var wireframe = new THREE.LineSegments( geo, mat ); 156 | //mesh.add( wireframe ); 157 | scene.add(mesh); 158 | // } 159 | 160 | } 161 | 162 | >>>>>>> origin/master 163 | function drawSector(sectorIndex) { 164 | 165 | var geometry = new THREE.PlaneGeometry((TILE_MESH_SIZE * TILE_COUNT), (TILE_MESH_SIZE * TILE_COUNT), TILE_COUNT, TILE_COUNT); 166 | 167 | /** 168 | * 169 | * Tile Elevations 170 | * 171 | */ 172 | 173 | for (var xx = 0; xx < 48; xx++) { 174 | for (var yy = 0; yy < 48; yy++) { 175 | t = (xx * 48 + yy) + 48 * 48 * sectorIndex; 176 | v = (xx * 49 + yy); 177 | if (Tiles[t] == null) continue; 178 | 179 | var base = 0; 180 | var multi = 0.025; 181 | if(Tiles[t].groundElevation < 128) { 182 | base -= multi * (128 - Tiles[t].groundElevation); 183 | } else { 184 | base += multi * Math.abs((128 - Tiles[t].groundElevation)); 185 | } 186 | geometry.vertices[v].z = base; 187 | } 188 | } 189 | 190 | 191 | 192 | /** 193 | * 194 | * Tile gradients & overlays 195 | * 196 | */ 197 | l = geometry.faces.length / 2; 198 | for (var i = 0; i < l; i++) { 199 | var j = 2 * i; 200 | var tmpIdx = i + 48 * 48 * sectorIndex; 201 | var til = Tiles[tmpIdx]; 202 | 203 | if (til == null) 204 | continue; 205 | 206 | if (til.groundTexture > 0) { // tile gradient 207 | geometry.faces[j].materialIndex = til.groundTexture + 500; 208 | geometry.faces[j + 1].materialIndex = til.groundTexture + 500; 209 | } 210 | til.faceIdx = j; 211 | // fix all this BS 212 | var obj = overlay_map[til.groundOverlay]; 213 | if(obj != null) { 214 | if(til.groundOverlay != 1111) { // change this to 1, to work with roads 215 | // var tempTil = Tiles[tmpIdx - 1]; 216 | // var tempTil2 = Tiles[tmpIdx + 1]; 217 | var tempTil = Tiles[tmpIdx - 1]; 218 | var tempTil2 = Tiles[tmpIdx - (TILE_COUNT * 1)]; 219 | 220 | var top = Tiles[tmpIdx - (TILE_COUNT * 1)]; 221 | var topRight = Tiles[tmpIdx - (TILE_COUNT * 1) - 1]; 222 | var topLeft = Tiles[tmpIdx - (TILE_COUNT * 1) + 1]; 223 | var right = Tiles[tmpIdx - 1]; 224 | var left = Tiles[tmpIdx + 1]; 225 | 226 | var bottom = Tiles[tmpIdx + (TILE_COUNT * 1)]; 227 | var bottomRight = Tiles[tmpIdx + (TILE_COUNT * 1) - 1]; 228 | var bottomLeft = Tiles[tmpIdx + (TILE_COUNT * 1) + 1]; 229 | 230 | if(til.groundOverlay != 1) { 231 | geometry.faces[j].materialIndex = til.groundOverlay; 232 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 233 | continue; 234 | 235 | } 236 | if(top != null && topRight != null && right != null && bottom != null && bottomRight != null) { 237 | geometry.faces[j].materialIndex = til.groundOverlay; 238 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 239 | /*if(top.groundOverlay != til.groundOverlay && topRight.groundOverlay != til.groundOverlay && right.groundOverlay != til.groundOverlay && bottom.groundOverlay == til.groundOverlay && bottomRight.groundOverlay == til.groundOverlay) { 240 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 241 | continue; 242 | } else if(bottom.groundOverlay != til.groundOverlay && left.groundOverlay != til.groundOverlay && bottomLeft.groundOverlay != til.groundOverlay && top.groundOverlay == til.groundOverlay && topRight.groundOverlay == til.groundOverlay) { 243 | 244 | 245 | geometry.faces[j].materialIndex = til.groundOverlay; 246 | continue; 247 | }*/ 248 | /* if(left.horizontalWall > 0 || til.horizontalWall > 0) { 249 | geometry.faces[j].materialIndex = til.groundOverlay; 250 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 251 | 252 | 253 | } 254 | else*/ 255 | 256 | 257 | if(top.groundOverlay != til.groundOverlay && right.groundOverlay != til.groundOverlay) { 258 | 259 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 260 | } else if(bottom.groundOverlay != til.groundOverlay && left.groundOverlay != til.groundOverlay) { 261 | geometry.faces[j].materialIndex = til.groundOverlay; 262 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 263 | } 264 | else { 265 | geometry.faces[j].materialIndex = til.groundOverlay; 266 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 267 | } 268 | } 269 | 270 | if(tempTil != null && tempTil2 != null) { 271 | /* if(tempTil.groundOverlay == til.groundOverlay && tempTil2.groundOverlay == til.groundOverlay) { 272 | geometry.faces[j].materialIndex = til.groundOverlay; 273 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 274 | } else if(tempTil.groundOverlay == til.groundOverlay && tempTil2.groundOverlay != til.groundOverlay) { 275 | geometry.faces[j].materialIndex = til.groundOverlay; 276 | 277 | } else if(tempTil.groundOverlay != til.groundOverlay && tempTil2.groundOverlay == til.groundOverlay) { 278 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 279 | }*/ 280 | } 281 | 282 | var tempTil = Tiles[tmpIdx + 1]; 283 | var tempTil2 = Tiles[tmpIdx + (TILE_COUNT * 1)]; 284 | if(tempTil != null && tempTil2 != null) { 285 | /* if(tempTil.groundOverlay == til.groundOverlay && tempTil2.groundOverlay == til.groundOverlay) { 286 | geometry.faces[j].materialIndex = til.groundOverlay; 287 | geometry.faces[j + 1].materialIndex = til.groundOverlay; 288 | } else if(tempTil.groundOverlay == til.groundOverlay && tempTil2.groundOverlay != til.groundOverlay) { 289 | // geometry.faces[j].materialIndex = til.groundOverlay; 290 | } else if(tempTil.groundOverlay != til.groundOverlay && tempTil2.groundOverlay == til.groundOverlay) { 291 | // geometry.faces[j + 1].materialIndex = til.groundOverlay; 292 | }*/ 293 | } 294 | // geometry.faces[j].materialIndex = til.groundOverlay; // top right face 295 | } else { 296 | geometry.faces[j].materialIndex = til.groundOverlay; 297 | geometry.faces[j + 1].materialIndex = til.groundOverlay; // bottom left face 298 | } 299 | 300 | } 301 | } 302 | /** 303 | * 304 | * Walls 305 | * 306 | */ 307 | var tempGeom = new THREE.PlaneGeometry(0, 0); 308 | var tempMesh = new THREE.Mesh(tempGeom, new THREE.MeshFaceMaterial(materials)); 309 | l = geometry.faces.length / 2; 310 | 311 | 312 | 313 | 314 | for (var i = 0; i < l; i++) { 315 | var j = 2 * i; 316 | var til = Tiles[i + 48 * 48 * sectorIndex]; 317 | if (til == null) 318 | continue; 319 | 320 | var base = 0; 321 | var multi = 0.025; 322 | if(til.groundElevation < 128) { 323 | base -= multi * (128 - til.groundElevation); 324 | } else { 325 | base += multi * Math.abs((128 - til.groundElevation)); 326 | } 327 | if (til.verticalWall > 0) { 328 | var overlayGeom = new THREE.PlaneGeometry(1, 1); 329 | var obj = overlay_map[til.verticalWall + 300]; 330 | if(obj != null) { 331 | overlayGeom.faces[0].materialIndex = til.verticalWall + 300; 332 | overlayGeom.faces[1].materialIndex = til.verticalWall + 300; 333 | var wall = new THREE.Mesh(overlayGeom, new THREE.MeshFaceMaterial(materials)); 334 | wall.rotation.x = Math.PI / 2; 335 | wall.position.x = til.x - (TILE_COUNT / 2) + 0.5; 336 | wall.position.y = til.y - (TILE_COUNT / 2); 337 | wall.position.z = base + 0.5; 338 | wall.updateMatrix(); 339 | tempGeom.merge(wall.geometry, wall.matrix); 340 | } 341 | } 342 | 343 | if (til.horizontalWall > 0) { 344 | var overlayGeom = new THREE.PlaneGeometry(1, 1); 345 | var obj = overlay_map[til.horizontalWall + 350]; 346 | if(obj != null) { 347 | overlayGeom.faces[0].materialIndex = til.horizontalWall + 350; 348 | overlayGeom.faces[1].materialIndex = til.horizontalWall + 350; 349 | 350 | var wall = new THREE.Mesh(overlayGeom, new THREE.MeshFaceMaterial(materials)); 351 | wall.rotation.y = Math.PI / 2; 352 | wall.position.x = til.x - (TILE_COUNT / 2); 353 | wall.position.y = til.y - (TILE_COUNT / 2) + 0.5; 354 | wall.position.z = base + 0.5; 355 | wall.updateMatrix(); 356 | tempGeom.merge(wall.geometry, wall.matrix); 357 | } 358 | } 359 | 360 | if (til.diagonalWall > 0) { 361 | var overlayGeom = new THREE.PlaneGeometry(1, 1); 362 | 363 | var obj = overlay_map[(til.diagonalWall >= 12000 ? (til.diagonalWall - 12000) : til.diagonalWall) + 300]; 364 | if(obj != null) { 365 | 366 | overlayGeom.faces[0].materialIndex = (til.diagonalWall >= 12000 ? (til.diagonalWall - 12000) : til.diagonalWall) + 300; 367 | overlayGeom.faces[1].materialIndex = (til.diagonalWall >= 12000 ? (til.diagonalWall - 12000) : til.diagonalWall) + 300; 368 | 369 | var wall = new THREE.Mesh(overlayGeom, new THREE.MeshFaceMaterial(materials)); 370 | wall.scale.set(1.42,1.42,1) 371 | var left = til.diagonalWall >= 12000; 372 | 373 | wall.position.y = til.y - (TILE_COUNT / 2) + 0.5; 374 | wall.position.z = base + 0.5; 375 | wall.position.x = til.x - (TILE_COUNT / 2) + 0.5; 376 | if(left) { 377 | wall.rotation.y = -(Math.PI / 4); 378 | wall.rotation.x = -(-1 * Math.PI / 2); 379 | 380 | } else { 381 | wall.rotation.y = (Math.PI / 4); 382 | wall.rotation.x = (1 * Math.PI / 2); 383 | 384 | } 385 | 386 | wall.updateMatrix(); 387 | tempGeom.merge(wall.geometry, wall.matrix); 388 | } else { 389 | console.log("null diagonal wall: " + til.diagonalWall + " : " + (til.diagonalWall >= 12000 ? (til.diagonalWall - 12000) : til.diagonalWall) + 400); 390 | } 391 | } 392 | } 393 | 394 | tempMesh.rotation.z = -Math.PI / 2; 395 | tempMesh.updateMatrix(); 396 | geometry.merge(tempMesh.geometry, tempMesh.matrix); 397 | 398 | var tmesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials)); 399 | return tmesh; 400 | 401 | } 402 | 403 | function updateSectors() { 404 | console.time('someFunction'); 405 | 406 | //scene.remove(mesh); 407 | masterGeometry = new THREE.PlaneGeometry(0 , 0 , 0, 0); 408 | 409 | var sectX = 0; 410 | var sectY = 0; 411 | 412 | for(var s=0; s < Sectors.length; s++) { 413 | if (sectX == Math.sqrt(Sectors.length)) { 414 | sectX = 0; 415 | sectY++; 416 | } 417 | var sectorIndex = s; 418 | var idx = 0; 419 | var view = Sectors[s]; 420 | var tmesh = drawSector(sectorIndex); 421 | tmesh.position.set(-(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * sectX, -(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * sectY, 0); 422 | tmesh.rotation.z = -Math.PI / 2; 423 | 424 | tmesh.updateMatrix(); 425 | masterGeometry.merge(tmesh.geometry, tmesh.matrix); 426 | sectX++; 427 | 428 | } 429 | 430 | 431 | 432 | console.timeEnd('someFunction'); 433 | var add = mesh == null; 434 | mesh = new THREE.Mesh(masterGeometry, new THREE.MeshFaceMaterial(materials)); 435 | 436 | var geo = new THREE.WireframeGeometry( masterGeometry); // or WireframeGeometry 437 | var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } ); 438 | var wireframe = new THREE.LineSegments( geo, mat ); 439 | //mesh.add( wireframe ); 440 | scene.add(mesh); 441 | 442 | } 443 | 444 | function setup() { 445 | 446 | prepMaterials(); 447 | scene = new THREE.Scene(); 448 | camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 ); 449 | var light = new THREE.AmbientLight( 0x404040 ); // soft white light 450 | // scene.add( light ); 451 | raycaster = new THREE.Raycaster(); 452 | mouse = new THREE.Vector2(); 453 | renderer = new THREE.WebGLRenderer({ alpha: true } ); 454 | renderer.setClearColor( 0x000000 ); 455 | scene.background = new THREE.Color( 0xaaaaaa ); 456 | renderer.setPixelRatio( window.devicePixelRatio ); 457 | renderer.setSize( window.innerWidth, window.innerHeight ); 458 | // var axisHelper = new THREE.AxisHelper( 5 ); 459 | // scene.add( axisHelper ); 460 | 461 | camera.updateProjectionMatrix(); 462 | 463 | // controls.update(); 464 | document.addEventListener( 'mousedown', onDocumentMouseDown, false ); 465 | // document.addEventListener( 'keydown', onDocumentKeyDown, false ); 466 | // document.addEventListener( 'keyup', onDocumentKeyUp, false ); 467 | 468 | } 469 | 470 | function animate() { 471 | stats.begin(); 472 | 473 | 474 | requestAnimationFrame(animate); 475 | renderer.render(scene, camera); 476 | 477 | if(controls != null) 478 | controls.update(); 479 | stats.end(); 480 | } 481 | 482 | function html() { 483 | stats = new Stats(); 484 | stats.showPanel( 0 ); 485 | // document.body.appendChild( stats.dom ); 486 | //var top = document.createElement('div'); 487 | //top.innerHTML = '

'; 488 | //document.body.appendChild(top); 489 | container = document.createElement('div'); 490 | document.body.appendChild(container); 491 | var info = document.createElement('div'); 492 | info.style.position = 'absolute'; 493 | info.style.top = '10px'; 494 | info.style.width = '100%'; 495 | info.style.textAlign = 'center'; 496 | // info.innerHTML = '

'; 497 | 498 | //container.appendChild(info); 499 | container.appendChild(renderer.domElement); 500 | window.addEventListener( 'resize', onWindowResize, false ); 501 | 502 | 503 | /* var button = document.getElementById("rendButton"); 504 | button.addEventListener("click",function(e){ 505 | unpackSectors(); 506 | updateSectors(); 507 | controls = new THREE.OrbitControls( camera, renderer.domElement ); 508 | controls.enableDamping = true; 509 | controls.dampingFactor = 0.25; 510 | controls.zoomSpeed = 0.5; 511 | camera.position.set(0, 0, 200); 512 | controls.enabled = false; 513 | controls.enabled = true; 514 | controls.enablePan = true; 515 | controls.enableZoom = true; 516 | controls.update(); 517 | animate(); 518 | 519 | },false);*/ 520 | } 521 | 522 | function onWindowResize() { 523 | console.error(camera.position.x + ", " + camera.position.y + ", " +camera.position.z); 524 | console.error(camera.rotation.x + ", " + camera.rotation.y + ", " +camera.rotation.z); 525 | console.error("tgt: " + controls.target.x + ", " + controls.target.y + ", " + controls.target.z); 526 | console.error("obj: " + controls.object.position.x + ", " + controls.object.position.y + ", " + controls.object.position.z); 527 | console.error(controls.zoom); 528 | camera.aspect = window.innerWidth / window.innerHeight; 529 | camera.updateProjectionMatrix(); 530 | renderer.setSize(window.innerWidth, window.innerHeight); 531 | animate(); 532 | } 533 | 534 | function onDocumentMouseDown( event ) { 535 | 536 | if(event.button != 0) 537 | return; 538 | event.preventDefault(); 539 | mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1; 540 | mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1; 541 | raycaster.setFromCamera( mouse, camera ); 542 | 543 | var intersects = raycaster.intersectObjects(scene.children ); 544 | if ( intersects.length > 0 ) { 545 | 546 | var intersect = intersects[ 0 ]; 547 | 548 | var x = Math.floor(Math.abs(intersect.point.x)); 549 | var y = Math.floor(Math.abs(intersect.point.y)); 550 | 551 | var tempSectX = 0; 552 | var tempSectY = 0; 553 | while(x >= 48){ 554 | x -= 48; 555 | tempSectX++; 556 | } 557 | while(y >= 48){ 558 | y -= 48; 559 | tempSectY++; 560 | } 561 | 562 | var sectorIndex = 3 * tempSectY + tempSectX; 563 | 564 | //console.log(" X: " + x + " Y: " + y + " SX: " + tempSectX + " SY: " + tempSectY + " sectorIndex: " + sectorIndex) ; 565 | 566 | var tile = ((x * 48) + y) + 48 * 48 * sectorIndex; 567 | if(Tiles == null) 568 | return; 569 | var tt = Tiles[tile]; 570 | if(tt == null) 571 | return; 572 | 573 | if (tt.x == x && tt.y == y) { 574 | 575 | // selected.open(); 576 | tt.groundElevation = 255; 577 | // updateSectors(); 578 | console.log("SUCCESS"); 579 | 580 | var sectName = "h0x" + (SectorX + offsets[tt.sector][0]) + "y" + (SectorY + offsets[tt.sector][1]); 581 | guiItems.localXY = tt.x + ", " + tt.y; 582 | var rscX = ((tt.absoluteSectorX - 48) * 48) + tt.x; 583 | var rscY = ((((tt.absoluteSectorY - 36) * 48) + tt.y + 96) - 144) + (0 * 944) + 48 - 48; 584 | guiItems.rscXY = rscX + ", " + rscY; 585 | ui_coords.setValue("RSC XY: " + rscX + ", " + rscY); 586 | ui_local_coords.setValue("Local XY: " + tt.x + ", " + tt.y); 587 | sectorIdx.setValue("Sector Index: " + tt.sector); 588 | sectorName.setValue("Sector Name: " + sectName); 589 | tileIdx.setValue("Tile Index: " + tile); 590 | tile_elevation.setValue("Elevation: " + tt.groundElevation); 591 | tile_overlay.setValue("Overlay: " + tt.groundOverlay); 592 | tile_texture.setValue("Texture: " + tt.groundTexture); 593 | tile_horizontal.setValue("Horizontal Wall: " + tt.horizontalWall); 594 | tile_vertical.setValue("Vertical Wall: " + tt.verticalWall); 595 | tile_diagonal.setValue("Diagonal Wall: " + tt.diagonalWall); 596 | tile_roof.setValue("Roof Texture: " + tt.roofTexture); 597 | 598 | // tt.groundElevation = 255; 599 | masterGeometry.faces[j].materialIndex = til.groundTexture + 500; 600 | masterGeometry.faces[j + 1].materialIndex = til.groundTexture + 500; 601 | 602 | /* // scene.remove(mesh); 603 | var tmesh = drawSector(sectorIndex); 604 | tmesh.position.set(-(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * tt.sectX, -(TILE_MESH_SIZE * TILE_COUNT / 2) - 48 * tt.sectY, 0); 605 | tmesh.rotation.z = -Math.PI / 2; 606 | 607 | tmesh.updateMatrix(); 608 | masterGeometry.merge(tmesh.geometry, tmesh.matrix); 609 | mesh.geometry.computeFaceNormals(); 610 | mesh.geometry.computeVertexNormals(); 611 | mesh.geometry.normalsNeedUpdate = true; 612 | mesh.geometry.verticesNeedUpdate = true; 613 | mesh.geometry.dynamic = true; 614 | //scene.add(mesh); 615 | animate();*/ 616 | 617 | 618 | } 619 | else console.log("FAIL"); 620 | // var voxel = new THREE.Mesh( cubeGeometry, cubeMaterial ); 621 | // voxel.position.copy( intersect.point ).add( intersect.face.normal ); 622 | // voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 ); 623 | //scene.add( voxel ); 624 | 625 | //objects.push( voxel ); 626 | 627 | 628 | } 629 | 630 | } 631 | 632 | function onDocumentKeyDown( event ) { 633 | /*switch( event.keyCode ) { 634 | case 16: isShiftDown = true; break; 635 | }*/ 636 | } 637 | 638 | function onDocumentKeyUp( event ) { 639 | /* switch( event.keyCode ) { 640 | case 16: isShiftDown = false; break; 641 | }*/ 642 | } -------------------------------------------------------------------------------- /src/Materials.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Hayden on 12/10/2016. 3 | */ 4 | 5 | var materials = []; 6 | 7 | function prepMaterials() { 8 | 9 | // ground textures start at 500, to give room for other materials 10 | materials[0] = new THREE.MeshBasicMaterial({color: 0xffffff}); 11 | for (var i = 0; i < tileColors.length; i++) { 12 | materials[500 + i] = new THREE.MeshBasicMaterial({ 13 | color: tileColors[i] 14 | }); 15 | } 16 | 17 | var floor = new THREE.ImageUtils.loadTexture('img/3223.png'); 18 | floor.wrapS = floor.wrapT = THREE.RepeatWrapping; 19 | floor.repeat.set(64, 64); 20 | 21 | var water = new THREE.ImageUtils.loadTexture('img/3221.png'); 22 | water.wrapS = water.wrapT = THREE.RepeatWrapping; 23 | water.repeat.set(64, 64); 24 | 25 | 26 | // index is the overlay ID. 27 | overlay_map[1] = new THREE.MeshBasicMaterial({color: 0x404040}); // grey tile 28 | 29 | overlay_map[5] = new THREE.MeshBasicMaterial({color: 0x404040}); //grey tile 30 | overlay_map[6] = new THREE.MeshBasicMaterial({color: 0x6F0410}); // red tile 31 | overlay_map[16] = new THREE.MeshBasicMaterial({color: 0x000000}); // black tile 32 | overlay_map[8] = new THREE.MeshBasicMaterial({color: 0x000000}); // black tile 33 | overlay_map[9] = new THREE.MeshBasicMaterial({color: 0xA9A9A9}); // grey mountain side surface 34 | // new THREE.MeshBasicMaterial({color: 0x367f23}); 35 | 36 | overlay_map[3] = new THREE.MeshBasicMaterial({map: floor}); // floor wooden 37 | overlay_map[2] = new THREE.MeshBasicMaterial({map: water}); // water 38 | // vertical walls starts at 300 39 | overlay_map[300 + 1] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222.png'), side: THREE.DoubleSide}); 40 | overlay_map[300 + 8] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222.png'), side: THREE.DoubleSide}); 41 | overlay_map[300 + 4] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222w.png'), side: THREE.DoubleSide}); 42 | overlay_map[300 + 5] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3230.png'), side: THREE.DoubleSide, transparent: true}); 43 | overlay_map[300 + 128] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3230.png'), side: THREE.DoubleSide, transparent: true}); 44 | overlay_map[300 + 15] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3241.png'), side: THREE.DoubleSide}); 45 | overlay_map[300 + 16] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3241w.png'), side: THREE.DoubleSide}); 46 | overlay_map[300 + 6] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/6.png'), side: THREE.DoubleSide, transparent: true}); 47 | overlay_map[300 + 7] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/7.bmp'), side: THREE.DoubleSide}); 48 | overlay_map[300 + 14] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/14.png'), side: THREE.DoubleSide}); 49 | overlay_map[300 + 35] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/35.bmp'), side: THREE.DoubleSide}); 50 | overlay_map[300 + 19] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3243.png'), side: THREE.DoubleSide}); 51 | overlay_map[300 + 42] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/42.png'), side: THREE.DoubleSide, transparent: true}); 52 | overlay_map[300 + 11] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/11.png'), side: THREE.DoubleSide, transparent: true}); 53 | 54 | 55 | // horizontal walls start at 350 56 | overlay_map[350 + 1] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222v.png'), side: THREE.DoubleSide}); 57 | overlay_map[350 + 11] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/11v.png'), side: THREE.DoubleSide, transparent: true}); 58 | overlay_map[350 + 6] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/6v.png'), side: THREE.DoubleSide, transparent: true}); 59 | overlay_map[350 + 7] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/7v.bmp'), side: THREE.DoubleSide}); 60 | overlay_map[350 + 14] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/14v.png'), side: THREE.DoubleSide}); 61 | overlay_map[350 + 35] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/35v.bmp'), side: THREE.DoubleSide}); 62 | overlay_map[350 + 19] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3243v.png'), side: THREE.DoubleSide}); 63 | overlay_map[350 + 8] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222v.png'), side: THREE.DoubleSide}); 64 | overlay_map[350 + 4] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3222vw.png'), side: THREE.DoubleSide}); 65 | overlay_map[350 + 5] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3230v.png'), side: THREE.DoubleSide, transparent: true}); 66 | overlay_map[350 + 128] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3230v.png'), side: THREE.DoubleSide, transparent: true}); 67 | overlay_map[350 + 42] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/42v.png'), side: THREE.DoubleSide, transparent: true}); 68 | overlay_map[350 + 15] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3241v.png'), side: THREE.DoubleSide}); 69 | overlay_map[350 + 16] = new THREE.MeshBasicMaterial({map: new THREE.ImageUtils.loadTexture('img/3241vw.png'), side: THREE.DoubleSide}); 70 | 71 | 72 | 73 | // dump into materials 74 | for (var i = 0; i < 500; i++) { 75 | var obj = overlay_map[i]; 76 | if (obj != null) { 77 | materials[i] = obj; 78 | } 79 | } 80 | materials[0] = new THREE.MeshBasicMaterial({color: 0xffffff}); 81 | 82 | } 83 | 84 | 85 | 86 | var tileColors = new Array(new THREE.Color("rgb(255, 255, 255)"), new THREE.Color("rgb(251, 254, 251)"), new THREE.Color("rgb(247, 252, 247)"), 87 | new THREE.Color("rgb(243, 250, 243)"), new THREE.Color("rgb(239, 248, 239)"), new THREE.Color("rgb(235, 247, 235)"), new THREE.Color("rgb(231, 245, 231)"), 88 | new THREE.Color("rgb(227, 243, 227)"), new THREE.Color("rgb(223, 241, 223)"), new THREE.Color("rgb(219, 240, 219)"), new THREE.Color("rgb(215, 238, 215)"), 89 | new THREE.Color("rgb(211, 236, 211)"), new THREE.Color("rgb(207, 234, 207)"), new THREE.Color("rgb(203, 233, 203)"), new THREE.Color("rgb(199, 231, 199)"), 90 | new THREE.Color("rgb(195, 229, 195)"), new THREE.Color("rgb(191, 227, 191)"), new THREE.Color("rgb(187, 226, 187)"), new THREE.Color("rgb(183, 224, 183)"), 91 | new THREE.Color("rgb(179, 222, 179)"), new THREE.Color("rgb(175, 220, 175)"), new THREE.Color("rgb(171, 219, 171)"), new THREE.Color("rgb(167, 217, 167)"), 92 | new THREE.Color("rgb(163, 215, 163)"), new THREE.Color("rgb(159, 213, 159)"), new THREE.Color("rgb(155, 212, 155)"), new THREE.Color("rgb(151, 210, 151)"), 93 | new THREE.Color("rgb(147, 208, 147)"), new THREE.Color("rgb(143, 206, 143)"), new THREE.Color("rgb(139, 205, 139)"), new THREE.Color("rgb(135, 203, 135)"), 94 | new THREE.Color("rgb(131, 201, 131)"), new THREE.Color("rgb(127, 199, 127)"), new THREE.Color("rgb(123, 198, 123)"), new THREE.Color("rgb(119, 196, 119)"), 95 | new THREE.Color("rgb(115, 194, 115)"), new THREE.Color("rgb(111, 192, 111)"), new THREE.Color("rgb(107, 191, 107)"), new THREE.Color("rgb(103, 189, 103)"), 96 | new THREE.Color("rgb(99, 187, 99)"), new THREE.Color("rgb(95, 185, 95)"), new THREE.Color("rgb(91, 184, 91)"), new THREE.Color("rgb(87, 182, 87)"), 97 | new THREE.Color("rgb(83, 180, 83)"), new THREE.Color("rgb(79, 178, 79)"), new THREE.Color("rgb(75, 177, 75)"), new THREE.Color("rgb(71, 175, 71)"), 98 | new THREE.Color("rgb(67, 173, 67)"), new THREE.Color("rgb(63, 171, 63)"), new THREE.Color("rgb(59, 170, 59)"), new THREE.Color("rgb(55, 168, 55)"), 99 | new THREE.Color("rgb(51, 166, 51)"), new THREE.Color("rgb(47, 164, 47)"), new THREE.Color("rgb(43, 163, 43)"), new THREE.Color("rgb(39, 161, 39)"), 100 | new THREE.Color("rgb(35, 159, 35)"), new THREE.Color("rgb(31, 157, 31)"), new THREE.Color("rgb(27, 156, 27)"), new THREE.Color("rgb(23, 154, 23)"), 101 | new THREE.Color("rgb(19, 152, 19)"), new THREE.Color("rgb(15, 150, 15)"), new THREE.Color("rgb(11, 149, 11)"), new THREE.Color("rgb(7, 147, 7)"), 102 | new THREE.Color("rgb(3, 145, 3)"), new THREE.Color("rgb(0, 144, 0)"), new THREE.Color("rgb(3, 144, 0)"), new THREE.Color("rgb(6, 144, 0)"), 103 | new THREE.Color("rgb(9, 144, 0)"), new THREE.Color("rgb(12, 144, 0)"), new THREE.Color("rgb(15, 144, 0)"), new THREE.Color("rgb(18, 144, 0)"), 104 | new THREE.Color("rgb(21, 144, 0)"), new THREE.Color("rgb(24, 144, 0)"), new THREE.Color("rgb(27, 144, 0)"), new THREE.Color("rgb(30, 144, 0)"), 105 | new THREE.Color("rgb(33, 144, 0)"), new THREE.Color("rgb(36, 144, 0)"), new THREE.Color("rgb(39, 144, 0)"), new THREE.Color("rgb(42, 144, 0)"), 106 | new THREE.Color("rgb(45, 144, 0)"), new THREE.Color("rgb(48, 144, 0)"), new THREE.Color("rgb(51, 144, 0)"), new THREE.Color("rgb(54, 144, 0)"), 107 | new THREE.Color("rgb(57, 144, 0)"), new THREE.Color("rgb(60, 144, 0)"), new THREE.Color("rgb(63, 144, 0)"), new THREE.Color("rgb(66, 144, 0)"), 108 | new THREE.Color("rgb(69, 144, 0)"), new THREE.Color("rgb(72, 144, 0)"), new THREE.Color("rgb(75, 144, 0)"), new THREE.Color("rgb(78, 144, 0)"), 109 | new THREE.Color("rgb(81, 144, 0)"), new THREE.Color("rgb(84, 144, 0)"), new THREE.Color("rgb(87, 144, 0)"), new THREE.Color("rgb(90, 144, 0)"), 110 | new THREE.Color("rgb(93, 144, 0)"), new THREE.Color("rgb(96, 144, 0)"), new THREE.Color("rgb(99, 144, 0)"), new THREE.Color("rgb(102, 144, 0)"), 111 | new THREE.Color("rgb(105, 144, 0)"), new THREE.Color("rgb(108, 144, 0)"), new THREE.Color("rgb(111, 144, 0)"), new THREE.Color("rgb(114, 144, 0)"), 112 | new THREE.Color("rgb(117, 144, 0)"), new THREE.Color("rgb(120, 144, 0)"), new THREE.Color("rgb(123, 144, 0)"), new THREE.Color("rgb(126, 144, 0)"), 113 | new THREE.Color("rgb(129, 144, 0)"), new THREE.Color("rgb(132, 144, 0)"), new THREE.Color("rgb(135, 144, 0)"), new THREE.Color("rgb(138, 144, 0)"), 114 | new THREE.Color("rgb(141, 144, 0)"), new THREE.Color("rgb(144, 144, 0)"), new THREE.Color("rgb(147, 144, 0)"), new THREE.Color("rgb(150, 144, 0)"), 115 | new THREE.Color("rgb(153, 144, 0)"), new THREE.Color("rgb(156, 144, 0)"), new THREE.Color("rgb(159, 144, 0)"), new THREE.Color("rgb(162, 144, 0)"), 116 | new THREE.Color("rgb(165, 144, 0)"), new THREE.Color("rgb(168, 144, 0)"), new THREE.Color("rgb(171, 144, 0)"), new THREE.Color("rgb(174, 144, 0)"), 117 | new THREE.Color("rgb(177, 144, 0)"), new THREE.Color("rgb(180, 144, 0)"), new THREE.Color("rgb(183, 144, 0)"), new THREE.Color("rgb(186, 144, 0)"), 118 | new THREE.Color("rgb(189, 144, 0)"), new THREE.Color("rgb(192, 144, 0)"), new THREE.Color("rgb(191, 143, 0)"), new THREE.Color("rgb(189, 141, 0)"), 119 | new THREE.Color("rgb(188, 140, 0)"), new THREE.Color("rgb(186, 138, 0)"), new THREE.Color("rgb(185, 137, 0)"), new THREE.Color("rgb(183, 135, 0)"), 120 | new THREE.Color("rgb(182, 134, 0)"), new THREE.Color("rgb(180, 132, 0)"), new THREE.Color("rgb(179, 131, 0)"), new THREE.Color("rgb(177, 129, 0)"), 121 | new THREE.Color("rgb(176, 128, 0)"), new THREE.Color("rgb(174, 126, 0)"), new THREE.Color("rgb(173, 125, 0)"), new THREE.Color("rgb(171, 123, 0)"), 122 | new THREE.Color("rgb(170, 122, 0)"), new THREE.Color("rgb(168, 120, 0)"), new THREE.Color("rgb(167, 119, 0)"), new THREE.Color("rgb(165, 117, 0)"), 123 | new THREE.Color("rgb(164, 116, 0)"), new THREE.Color("rgb(162, 114, 0)"), new THREE.Color("rgb(161, 113, 0)"), new THREE.Color("rgb(159, 111, 0)"), 124 | new THREE.Color("rgb(158, 110, 0)"), new THREE.Color("rgb(156, 108, 0)"), new THREE.Color("rgb(155, 107, 0)"), new THREE.Color("rgb(153, 105, 0)"), 125 | new THREE.Color("rgb(152, 104, 0)"), new THREE.Color("rgb(150, 102, 0)"), new THREE.Color("rgb(149, 101, 0)"), new THREE.Color("rgb(147, 99, 0)"), 126 | new THREE.Color("rgb(146, 98, 0)"), new THREE.Color("rgb(144, 96, 0)"), new THREE.Color("rgb(143, 95, 0)"), new THREE.Color("rgb(141, 93, 0)"), 127 | new THREE.Color("rgb(140, 92, 0)"), new THREE.Color("rgb(138, 90, 0)"), new THREE.Color("rgb(137, 89, 0)"), new THREE.Color("rgb(135, 87, 0)"), 128 | new THREE.Color("rgb(134, 86, 0)"), new THREE.Color("rgb(132, 84, 0)"), new THREE.Color("rgb(131, 83, 0)"), new THREE.Color("rgb(129, 81, 0)"), 129 | new THREE.Color("rgb(128, 80, 0)"), new THREE.Color("rgb(126, 78, 0)"), new THREE.Color("rgb(125, 77, 0)"), new THREE.Color("rgb(123, 75, 0)"), 130 | new THREE.Color("rgb(122, 74, 0)"), new THREE.Color("rgb(120, 72, 0)"), new THREE.Color("rgb(119, 71, 0)"), new THREE.Color("rgb(117, 69, 0)"), 131 | new THREE.Color("rgb(116, 68, 0)"), new THREE.Color("rgb(114, 66, 0)"), new THREE.Color("rgb(113, 65, 0)"), new THREE.Color("rgb(111, 63, 0)"), 132 | new THREE.Color("rgb(110, 62, 0)"), new THREE.Color("rgb(108, 60, 0)"), new THREE.Color("rgb(107, 59, 0)"), new THREE.Color("rgb(105, 57, 0)"), 133 | new THREE.Color("rgb(104, 56, 0)"), new THREE.Color("rgb(102, 54, 0)"), new THREE.Color("rgb(101, 53, 0)"), new THREE.Color("rgb(99, 51, 0)"), 134 | new THREE.Color("rgb(98, 50, 0)"), new THREE.Color("rgb(96, 48, 0)"), new THREE.Color("rgb(95, 49, 0)"), new THREE.Color("rgb(93, 51, 0)"), 135 | new THREE.Color("rgb(92, 52, 0)"), new THREE.Color("rgb(90, 54, 0)"), new THREE.Color("rgb(89, 55, 0)"), new THREE.Color("rgb(87, 57, 0)"), 136 | new THREE.Color("rgb(86, 58, 0)"), new THREE.Color("rgb(84, 60, 0)"), new THREE.Color("rgb(83, 61, 0)"), new THREE.Color("rgb(81, 63, 0)"), 137 | new THREE.Color("rgb(80, 64, 0)"), new THREE.Color("rgb(78, 66, 0)"), new THREE.Color("rgb(77, 67, 0)"), new THREE.Color("rgb(75, 69, 0)"), 138 | new THREE.Color("rgb(74, 70, 0)"), new THREE.Color("rgb(72, 72, 0)"), new THREE.Color("rgb(71, 73, 0)"), new THREE.Color("rgb(69, 75, 0)"), 139 | new THREE.Color("rgb(68, 76, 0)"), new THREE.Color("rgb(66, 78, 0)"), new THREE.Color("rgb(65, 79, 0)"), new THREE.Color("rgb(63, 81, 0)"), 140 | new THREE.Color("rgb(62, 82, 0)"), new THREE.Color("rgb(60, 84, 0)"), new THREE.Color("rgb(59, 85, 0)"), new THREE.Color("rgb(57, 87, 0)"), 141 | new THREE.Color("rgb(56, 88, 0)"), new THREE.Color("rgb(54, 90, 0)"), new THREE.Color("rgb(53, 91, 0)"), new THREE.Color("rgb(51, 93, 0)"), 142 | new THREE.Color("rgb(50, 94, 0)"), new THREE.Color("rgb(48, 96, 0)"), new THREE.Color("rgb(47, 97, 0)"), new THREE.Color("rgb(45, 99, 0)"), 143 | new THREE.Color("rgb(44, 100, 0)"), new THREE.Color("rgb(42, 102, 0)"), new THREE.Color("rgb(41, 103, 0)"), new THREE.Color("rgb(39, 105, 0)"), 144 | new THREE.Color("rgb(38, 106, 0)"), new THREE.Color("rgb(36, 108, 0)"), new THREE.Color("rgb(35, 109, 0)"), new THREE.Color("rgb(33, 111, 0)"), 145 | new THREE.Color("rgb(32, 112, 0)"), new THREE.Color("rgb(30, 114, 0)"), new THREE.Color("rgb(29, 115, 0)"), new THREE.Color("rgb(27, 117, 0)"), 146 | new THREE.Color("rgb(26, 118, 0)"), new THREE.Color("rgb(24, 120, 0)"), new THREE.Color("rgb(23, 121, 0)"), new THREE.Color("rgb(21, 123, 0)"), 147 | new THREE.Color("rgb(20, 124, 0)"), new THREE.Color("rgb(18, 126, 0)"), new THREE.Color("rgb(17, 127, 0)"), new THREE.Color("rgb(15, 129, 0)"), 148 | new THREE.Color("rgb(14, 130, 0)"), new THREE.Color("rgb(12, 132, 0)"), new THREE.Color("rgb(11, 133, 0)"), new THREE.Color("rgb(9, 135, 0)"), 149 | new THREE.Color("rgb(8, 136, 0)"), new THREE.Color("rgb(6, 138, 0)"), new THREE.Color("rgb(5, 139, 0)"), new THREE.Color("rgb(3, 141, 0)"), 150 | new THREE.Color("rgb(2, 142, 0)") 151 | ); -------------------------------------------------------------------------------- /src/Tile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Hayden on 12/1/2016. 3 | */ 4 | 5 | function Tile(sector, sectX, sectY, x, y, groundElevation, groundTexture, groundOverlay, roofTexture, horizontalWall, verticalWall, diagonalWall, sect, absoluteSectorX, absoluteSectorY) { 6 | 7 | this.x = x; 8 | this.y = y; 9 | this.sector = sector; 10 | this.sectX = sectX; 11 | this.sectY = sectY; 12 | this.absoluteSectorX = absoluteSectorX; 13 | this.absoluteSectorY = absoluteSectorY; 14 | this.faceIdx = -1; 15 | 16 | 17 | 18 | this.groundElevation = groundElevation; 19 | this.groundTexture = groundTexture; 20 | this.groundOverlay = groundOverlay; 21 | this.roofTexture = roofTexture; 22 | this.horizontalWall = horizontalWall; 23 | this.verticalWall = verticalWall; 24 | this.diagonalWall = diagonalWall; 25 | this.meshColor = tileColors[this.groundTexture].getHex(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/Util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Hayden on 12/1/2016. 3 | */ 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/ui/Menubar.Edit.js: -------------------------------------------------------------------------------- 1 | 2 | Menubar.Edit = function ( editor ) { 3 | 4 | var container = new UI.Panel(); 5 | container.setClass( 'menu' ); 6 | 7 | var title = new UI.Panel(); 8 | title.setClass( 'title' ); 9 | title.setTextContent( 'Edit' ); 10 | container.add( title ); 11 | 12 | var options = new UI.Panel(); 13 | options.setClass( 'options' ); 14 | container.add( options ); 15 | 16 | 17 | var open = new UI.Row(); 18 | open.setClass( 'option' ); 19 | open.setTextContent( 'Undo' ); 20 | open.onClick( function () { 21 | 22 | var fileInput = document.createElement( 'input' ); 23 | fileInput.type = 'file'; 24 | fileInput.addEventListener( 'change', function ( event ) { 25 | 26 | 27 | 28 | } ); 29 | fileInput.click(); 30 | 31 | 32 | } ); 33 | 34 | options.add(open); 35 | var open = new UI.Row(); 36 | open.setClass( 'option' ); 37 | open.setTextContent( 'Redo' ); 38 | open.onClick( function () { 39 | 40 | var fileInput = document.createElement( 'input' ); 41 | fileInput.type = 'file'; 42 | fileInput.addEventListener( 'change', function ( event ) { 43 | 44 | 45 | 46 | } ); 47 | fileInput.click(); 48 | 49 | 50 | } ); 51 | 52 | options.add(open); 53 | // 54 | 55 | options.add( new UI.HorizontalRule() ); 56 | 57 | 58 | var open = new UI.Row(); 59 | open.setClass( 'option' ); 60 | open.setTextContent( 'Copy Tile' ); 61 | open.onClick( function () { 62 | var fileInput = document.createElement( 'input' ); 63 | fileInput.type = 'file'; 64 | fileInput.addEventListener( 'change', function ( event ) { 65 | 66 | 67 | 68 | } ); 69 | fileInput.click(); 70 | } ); 71 | options.add(open); 72 | 73 | var open = new UI.Row(); 74 | open.setClass( 'option' ); 75 | open.setTextContent( 'Paste Tile' ); 76 | open.onClick( function () { 77 | var fileInput = document.createElement( 'input' ); 78 | fileInput.type = 'file'; 79 | fileInput.addEventListener( 'change', function ( event ) { 80 | 81 | 82 | 83 | } ); 84 | fileInput.click(); 85 | } ); 86 | options.add(open); 87 | 88 | 89 | 90 | var link = document.createElement( 'a' ); 91 | link.style.display = 'none'; 92 | document.body.appendChild( link ); // Firefox workaround, see #6594 93 | 94 | function save( blob, filename ) { 95 | 96 | link.href = URL.createObjectURL( blob ); 97 | link.download = filename || 'data.json'; 98 | link.click(); 99 | 100 | // URL.revokeObjectURL( url ); breaks Firefox... 101 | 102 | } 103 | 104 | function saveString( text, filename ) { 105 | 106 | save( new Blob( [ text ], { type: 'text/plain' } ), filename ); 107 | 108 | } 109 | 110 | return container; 111 | 112 | }; -------------------------------------------------------------------------------- /src/ui/Menubar.File.js: -------------------------------------------------------------------------------- 1 | 2 | Menubar.File = function ( editor ) { 3 | 4 | var container = new UI.Panel(); 5 | container.setClass( 'menu' ); 6 | 7 | var title = new UI.Panel(); 8 | title.setClass( 'title' ); 9 | title.setTextContent( 'File' ); 10 | container.add( title ); 11 | 12 | var options = new UI.Panel(); 13 | options.setClass( 'options' ); 14 | container.add( options ); 15 | 16 | // New 17 | 18 | var open = new UI.Row(); 19 | open.setClass( 'option' ); 20 | open.setTextContent( 'Load .RSCD' ); 21 | open.onClick( function () { 22 | 23 | var fileInput = document.createElement( 'input' ); 24 | fileInput.type = 'file'; 25 | fileInput.addEventListener( 'change', function ( event ) { 26 | 27 | openFile( event ); 28 | unpackSectors(); 29 | updateSectors(); 30 | controls = new THREE.OrbitControls( camera, renderer.domElement ); 31 | controls.enableDamping = true; 32 | controls.dampingFactor = 0.25; 33 | controls.zoomSpeed = 0.5; 34 | camera.position.set(0, 0, 200); 35 | controls.enabled = false; 36 | controls.enabled = true; 37 | controls.enablePan = true; 38 | controls.enableZoom = true; 39 | controls.update(); 40 | animate(); 41 | 42 | } ); 43 | fileInput.click(); 44 | 45 | 46 | } ); 47 | 48 | options.add(open); 49 | 50 | var open = new UI.Row(); 51 | open.setClass( 'option' ); 52 | open.setTextContent( 'Load .JAG' ); 53 | open.onClick( function () { 54 | var fileInput = document.createElement( 'input' ); 55 | fileInput.type = 'file'; 56 | fileInput.addEventListener( 'change', function ( event ) { 57 | 58 | 59 | 60 | } ); 61 | fileInput.click(); 62 | } ); 63 | options.add(open); 64 | 65 | // 66 | 67 | options.add( new UI.HorizontalRule() ); 68 | 69 | 70 | var open = new UI.Row(); 71 | open.setClass( 'option' ); 72 | open.setTextContent( 'Export .RSCD' ); 73 | open.onClick( function () { 74 | var fileInput = document.createElement( 'input' ); 75 | fileInput.type = 'file'; 76 | fileInput.addEventListener( 'change', function ( event ) { 77 | 78 | 79 | 80 | } ); 81 | fileInput.click(); 82 | } ); 83 | options.add(open); 84 | 85 | var open = new UI.Row(); 86 | open.setClass( 'option' ); 87 | open.setTextContent( 'Export .JAG' ); 88 | open.onClick( function () { 89 | var fileInput = document.createElement( 'input' ); 90 | fileInput.type = 'file'; 91 | fileInput.addEventListener( 'change', function ( event ) { 92 | 93 | 94 | 95 | } ); 96 | fileInput.click(); 97 | } ); 98 | options.add(open); 99 | 100 | var open = new UI.Row(); 101 | open.setClass( 'option' ); 102 | open.setTextContent( 'Export Sector' ); 103 | open.onClick( function () { 104 | var fileInput = document.createElement( 'input' ); 105 | fileInput.type = 'file'; 106 | fileInput.addEventListener( 'change', function ( event ) { 107 | 108 | 109 | 110 | } ); 111 | fileInput.click(); 112 | } ); 113 | options.add(open); 114 | 115 | 116 | 117 | 118 | var link = document.createElement( 'a' ); 119 | link.style.display = 'none'; 120 | document.body.appendChild( link ); // Firefox workaround, see #6594 121 | 122 | function save( blob, filename ) { 123 | 124 | link.href = URL.createObjectURL( blob ); 125 | link.download = filename || 'data.json'; 126 | link.click(); 127 | 128 | // URL.revokeObjectURL( url ); breaks Firefox... 129 | 130 | } 131 | 132 | function saveString( text, filename ) { 133 | 134 | save( new Blob( [ text ], { type: 'text/plain' } ), filename ); 135 | 136 | } 137 | 138 | return container; 139 | 140 | }; -------------------------------------------------------------------------------- /src/ui/Menubar.Sector.js: -------------------------------------------------------------------------------- 1 | 2 | Menubar.Sector = function ( editor ) { 3 | 4 | var container = new UI.Panel(); 5 | container.setClass( 'menu' ); 6 | 7 | var title = new UI.Panel(); 8 | title.setClass( 'title' ); 9 | title.setTextContent( 'Sector' ); 10 | container.add( title ); 11 | 12 | var options = new UI.Panel(); 13 | options.setClass( 'options' ); 14 | container.add( options ); 15 | 16 | // New 17 | var open = new UI.Row(); 18 | open.setClass( 'option' ); 19 | open.setTextContent( 'Sector ->' ); 20 | open.onClick( function () { 21 | 22 | var fileInput = document.createElement( 'input' ); 23 | fileInput.type = 'file'; 24 | fileInput.addEventListener( 'change', function ( event ) { 25 | 26 | 27 | 28 | } ); 29 | fileInput.click(); 30 | } ); 31 | 32 | options.add(open); 33 | 34 | options.add( new UI.HorizontalRule() ); 35 | 36 | var open = new UI.Row(); 37 | open.setClass( 'option' ); 38 | open.setTextContent( 'Varrock' ); 39 | open.onClick( function () { 40 | 41 | var fileInput = document.createElement( 'input' ); 42 | fileInput.type = 'file'; 43 | fileInput.addEventListener( 'change', function ( event ) { 44 | 45 | 46 | 47 | } ); 48 | fileInput.click(); 49 | } ); 50 | 51 | options.add(open); 52 | 53 | var open = new UI.Row(); 54 | open.setClass( 'option' ); 55 | open.setTextContent( 'Falador' ); 56 | open.onClick( function () { 57 | 58 | var fileInput = document.createElement( 'input' ); 59 | fileInput.type = 'file'; 60 | fileInput.addEventListener( 'change', function ( event ) { 61 | 62 | 63 | 64 | } ); 65 | fileInput.click(); 66 | } ); 67 | 68 | options.add(open); 69 | 70 | var open = new UI.Row(); 71 | open.setClass( 'option' ); 72 | open.setTextContent( 'Lumbridge' ); 73 | open.onClick( function () { 74 | 75 | var fileInput = document.createElement( 'input' ); 76 | fileInput.type = 'file'; 77 | fileInput.addEventListener( 'change', function ( event ) { 78 | 79 | 80 | 81 | } ); 82 | fileInput.click(); 83 | } ); 84 | 85 | options.add(open); 86 | 87 | var open = new UI.Row(); 88 | open.setClass( 'option' ); 89 | open.setTextContent( 'Edgeville' ); 90 | open.onClick( function () { 91 | 92 | var fileInput = document.createElement( 'input' ); 93 | fileInput.type = 'file'; 94 | fileInput.addEventListener( 'change', function ( event ) { 95 | 96 | 97 | 98 | } ); 99 | fileInput.click(); 100 | } ); 101 | 102 | options.add(open); 103 | 104 | var open = new UI.Row(); 105 | open.setClass( 'option' ); 106 | open.setTextContent( 'Draynor' ); 107 | open.onClick( function () { 108 | 109 | var fileInput = document.createElement( 'input' ); 110 | fileInput.type = 'file'; 111 | fileInput.addEventListener( 'change', function ( event ) { 112 | 113 | 114 | 115 | } ); 116 | fileInput.click(); 117 | } ); 118 | 119 | options.add(open); 120 | 121 | var open = new UI.Row(); 122 | open.setClass( 'option' ); 123 | open.setTextContent( 'Karamja' ); 124 | open.onClick( function () { 125 | 126 | var fileInput = document.createElement( 'input' ); 127 | fileInput.type = 'file'; 128 | fileInput.addEventListener( 'change', function ( event ) { 129 | 130 | 131 | 132 | } ); 133 | fileInput.click(); 134 | } ); 135 | 136 | options.add(open); 137 | 138 | var open = new UI.Row(); 139 | open.setClass( 'option' ); 140 | open.setTextContent( 'Al Kharid' ); 141 | open.onClick( function () { 142 | 143 | var fileInput = document.createElement( 'input' ); 144 | fileInput.type = 'file'; 145 | fileInput.addEventListener( 'change', function ( event ) { 146 | 147 | 148 | 149 | } ); 150 | fileInput.click(); 151 | } ); 152 | 153 | options.add(open); 154 | 155 | var open = new UI.Row(); 156 | open.setClass( 'option' ); 157 | open.setTextContent( 'Ardougne' ); 158 | open.onClick( function () { 159 | 160 | var fileInput = document.createElement( 'input' ); 161 | fileInput.type = 'file'; 162 | fileInput.addEventListener( 'change', function ( event ) { 163 | 164 | 165 | 166 | } ); 167 | fileInput.click(); 168 | } ); 169 | 170 | options.add(open); 171 | 172 | var open = new UI.Row(); 173 | open.setClass( 'option' ); 174 | open.setTextContent( 'Catherby' ); 175 | open.onClick( function () { 176 | 177 | var fileInput = document.createElement( 'input' ); 178 | fileInput.type = 'file'; 179 | fileInput.addEventListener( 'change', function ( event ) { 180 | 181 | 182 | 183 | } ); 184 | fileInput.click(); 185 | } ); 186 | 187 | options.add(open); 188 | 189 | var link = document.createElement( 'a' ); 190 | link.style.display = 'none'; 191 | document.body.appendChild( link ); // Firefox workaround, see #6594 192 | 193 | function save( blob, filename ) { 194 | 195 | link.href = URL.createObjectURL( blob ); 196 | link.download = filename || 'data.json'; 197 | link.click(); 198 | 199 | // URL.revokeObjectURL( url ); breaks Firefox... 200 | 201 | } 202 | 203 | function saveString( text, filename ) { 204 | 205 | save( new Blob( [ text ], { type: 'text/plain' } ), filename ); 206 | 207 | } 208 | 209 | return container; 210 | 211 | }; -------------------------------------------------------------------------------- /src/ui/Menubar.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var Menubar = function ( editor ) { 4 | 5 | var container = new UI.Panel(); 6 | container.setId( 'menubar' ); 7 | 8 | container.add( new Menubar.File( null ) ); 9 | container.add( new Menubar.Edit(null ) ); 10 | container.add( new Menubar.Sector( null ) ); 11 | 12 | //var wireframe = new UI.THREE.Boolean( false, 'Edit Mode' ).setWidth(100); 13 | //container.add( wireframe ); 14 | //container.add( new Menubar.Edit( editor ) ); 15 | //container.add( new Menubar.Add( editor ) ); 16 | //container.add( new Menubar.Play( editor ) ); 17 | //container.add( new Menubar.View( editor ) ); 18 | // container.add( new Menubar.Examples( editor ) ); 19 | //container.add( new Menubar.Help( editor ) ); 20 | 21 | //container.add( new Menubar.Status( editor ) ); 22 | 23 | return container; 24 | 25 | }; -------------------------------------------------------------------------------- /src/ui/Sidebar.EditMode.js: -------------------------------------------------------------------------------- 1 | Sidebar.EditMode = function ( editor ) { 2 | 3 | // var signals = editor.signals; 4 | 5 | var container = new UI.Span(); 6 | var buttons = new UI.Panel(); 7 | // container.add( buttons ); 8 | // buttons.add( new UI.Text( 'X: 444 ' ) ); 9 | // buttons.add( new UI.Text( 'Y: 544 ' ) ); 10 | 11 | /* var objectTab = new UI.Text( 'OBJECT' ).onClick( onClick ); 12 | var geometryTab = new UI.Text( 'GEOMETRY' ).onClick( onClick ); 13 | var materialTab = new UI.Text( 'MATERIAL' ).onClick( onClick ); 14 | 15 | var tabs = new UI.Div(); 16 | tabs.setId( 'tabs' ); 17 | tabs.add( objectTab, geometryTab, materialTab ); 18 | container.add( tabs ); 19 | 20 | function onClick( event ) { 21 | select( event.target.textContent ); 22 | } 23 | 24 | // 25 | 26 | var object = new UI.Span().add( 27 | new Sidebar.Object( editor ) 28 | ); 29 | container.add( object ); 30 | 31 | var geometry = new UI.Span().add( 32 | new Sidebar.Geometry( editor ) 33 | ); 34 | container.add( geometry ); 35 | 36 | var material = new UI.Span().add( 37 | new Sidebar.Material( editor ) 38 | ); 39 | container.add( material ); 40 | 41 | // 42 | 43 | function select( section ) { 44 | 45 | objectTab.setClass( '' ); 46 | geometryTab.setClass( '' ); 47 | materialTab.setClass( '' ); 48 | 49 | object.setDisplay( 'none' ); 50 | geometry.setDisplay( 'none' ); 51 | material.setDisplay( 'none' ); 52 | 53 | switch ( section ) { 54 | case 'OBJECT': 55 | objectTab.setClass( 'selected' ); 56 | object.setDisplay( '' ); 57 | break; 58 | case 'GEOMETRY': 59 | geometryTab.setClass( 'selected' ); 60 | geometry.setDisplay( '' ); 61 | break; 62 | case 'MATERIAL': 63 | materialTab.setClass( 'selected' ); 64 | material.setDisplay( '' ); 65 | break; 66 | } 67 | 68 | } 69 | 70 | select( 'OBJECT' ); 71 | */ 72 | 73 | return container; 74 | 75 | }; -------------------------------------------------------------------------------- /src/ui/Sidebar.Settings.js: -------------------------------------------------------------------------------- 1 | Sidebar.Settings = function ( editor ) { 2 | 3 | // var signals = editor.signals; 4 | 5 | var container = new UI.Span(); 6 | var buttons = new UI.Panel(); 7 | // container.add( buttons ); 8 | // buttons.add( new UI.Text( 'X: 444 ' ) ); 9 | // buttons.add( new UI.Text( 'Y: 544 ' ) ); 10 | 11 | /* var objectTab = new UI.Text( 'OBJECT' ).onClick( onClick ); 12 | var geometryTab = new UI.Text( 'GEOMETRY' ).onClick( onClick ); 13 | var materialTab = new UI.Text( 'MATERIAL' ).onClick( onClick ); 14 | 15 | var tabs = new UI.Div(); 16 | tabs.setId( 'tabs' ); 17 | tabs.add( objectTab, geometryTab, materialTab ); 18 | container.add( tabs ); 19 | 20 | function onClick( event ) { 21 | select( event.target.textContent ); 22 | } 23 | 24 | // 25 | 26 | var object = new UI.Span().add( 27 | new Sidebar.Object( editor ) 28 | ); 29 | container.add( object ); 30 | 31 | var geometry = new UI.Span().add( 32 | new Sidebar.Geometry( editor ) 33 | ); 34 | container.add( geometry ); 35 | 36 | var material = new UI.Span().add( 37 | new Sidebar.Material( editor ) 38 | ); 39 | container.add( material ); 40 | 41 | // 42 | 43 | function select( section ) { 44 | 45 | objectTab.setClass( '' ); 46 | geometryTab.setClass( '' ); 47 | materialTab.setClass( '' ); 48 | 49 | object.setDisplay( 'none' ); 50 | geometry.setDisplay( 'none' ); 51 | material.setDisplay( 'none' ); 52 | 53 | switch ( section ) { 54 | case 'OBJECT': 55 | objectTab.setClass( 'selected' ); 56 | object.setDisplay( '' ); 57 | break; 58 | case 'GEOMETRY': 59 | geometryTab.setClass( 'selected' ); 60 | geometry.setDisplay( '' ); 61 | break; 62 | case 'MATERIAL': 63 | materialTab.setClass( 'selected' ); 64 | material.setDisplay( '' ); 65 | break; 66 | } 67 | 68 | } 69 | 70 | select( 'OBJECT' ); 71 | */ 72 | 73 | return container; 74 | 75 | }; -------------------------------------------------------------------------------- /src/ui/Sidebar.ViewMode.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var ui_coords = new UI.Text( "" ); 4 | var ui_local_coords = new UI.Text( "" ); 5 | var sectorIdx = new UI.Text( "" ); 6 | var sectorName = new UI.Text( "" ); 7 | var tileIdx = new UI.Text( "" ); 8 | var tile_elevation = new UI.Text( "" ); 9 | var tile_overlay = new UI.Text( "" ); 10 | var tile_texture = new UI.Text( "" ); 11 | var tile_vertical = new UI.Text( "" ); 12 | var tile_diagonal = new UI.Text( "" ); 13 | var tile_horizontal = new UI.Text( "" ); 14 | var tile_roof = new UI.Text( "" ); 15 | 16 | Sidebar.ViewMode = function ( editor ) { 17 | 18 | 19 | var buttons = new UI.Panel(); 20 | 21 | buttons.add(new UI.Row().add( ui_coords )); 22 | buttons.add(new UI.Row().add( ui_local_coords )); 23 | buttons.add(new UI.Row().add(sectorName )); 24 | buttons.add(new UI.Row().add(tileIdx )); 25 | buttons.add(new UI.Row().add( tile_elevation)); 26 | buttons.add(new UI.Row().add(tile_overlay )); 27 | buttons.add(new UI.Row().add(tile_texture )); 28 | buttons.add(new UI.Row().add(tile_vertical)); 29 | buttons.add(new UI.Row().add( tile_horizontal )); 30 | buttons.add(new UI.Row().add( tile_diagonal )); 31 | buttons.add(new UI.Row().add( tile_roof)); 32 | 33 | 34 | /* var objectTab = new UI.Text( 'OBJECT' ).onClick( onClick ); 35 | var geometryTab = new UI.Text( 'GEOMETRY' ).onClick( onClick ); 36 | var materialTab = new UI.Text( 'MATERIAL' ).onClick( onClick ); 37 | 38 | var tabs = new UI.Div(); 39 | tabs.setId( 'tabs' ); 40 | tabs.add( objectTab, geometryTab, materialTab ); 41 | container.add( tabs ); 42 | 43 | function onClick( event ) { 44 | select( event.target.textContent ); 45 | } 46 | 47 | // 48 | 49 | var object = new UI.Span().add( 50 | new Sidebar.Object( editor ) 51 | ); 52 | container.add( object ); 53 | 54 | var geometry = new UI.Span().add( 55 | new Sidebar.Geometry( editor ) 56 | ); 57 | container.add( geometry ); 58 | 59 | var material = new UI.Span().add( 60 | new Sidebar.Material( editor ) 61 | ); 62 | container.add( material ); 63 | 64 | // 65 | 66 | function select( section ) { 67 | 68 | objectTab.setClass( '' ); 69 | geometryTab.setClass( '' ); 70 | materialTab.setClass( '' ); 71 | 72 | object.setDisplay( 'none' ); 73 | geometry.setDisplay( 'none' ); 74 | material.setDisplay( 'none' ); 75 | 76 | switch ( section ) { 77 | case 'OBJECT': 78 | objectTab.setClass( 'selected' ); 79 | object.setDisplay( '' ); 80 | break; 81 | case 'GEOMETRY': 82 | geometryTab.setClass( 'selected' ); 83 | geometry.setDisplay( '' ); 84 | break; 85 | case 'MATERIAL': 86 | materialTab.setClass( 'selected' ); 87 | material.setDisplay( '' ); 88 | break; 89 | } 90 | 91 | } 92 | 93 | select( 'OBJECT' ); 94 | */ 95 | 96 | return buttons; 97 | 98 | }; -------------------------------------------------------------------------------- /src/ui/Sidebar.js: -------------------------------------------------------------------------------- 1 | 2 | var Sidebar = function ( editor ) { 3 | 4 | var container = new UI.Panel(); 5 | container.setId( 'sidebar' ); 6 | 7 | // 8 | 9 | var viewTab = new UI.Text( 'VIEW MODE' ).onClick( onClick ); 10 | var editTab = new UI.Text( 'EDIT MODE' ).onClick( onClick ); 11 | var settingsTab = new UI.Text( 'SETTINGS' ).onClick( onClick ); 12 | 13 | var tabs = new UI.Div(); 14 | tabs.setId( 'tabs' ); 15 | tabs.add( viewTab, editTab, settingsTab ); 16 | container.add( tabs ); 17 | 18 | function onClick( event ) { 19 | 20 | select( event.target.textContent ); 21 | 22 | } 23 | 24 | // 25 | 26 | var view = new UI.Span().add( 27 | new Sidebar.ViewMode(null) 28 | ); 29 | var edit = new UI.Span().add( 30 | new Sidebar.EditMode(null) 31 | ); 32 | var settings = new UI.Span().add( 33 | new Sidebar.Settings(null) 34 | ); 35 | container.add( view ); 36 | container.add( edit ); 37 | container.add( settings ); 38 | /* 39 | var project = new UI.Span().add( 40 | new Sidebar.Project( editor ) 41 | ); 42 | container.add( project ); 43 | 44 | var settings = new UI.Span().add( 45 | new Sidebar.Settings( editor ), 46 | new Sidebar.History( editor ) 47 | ); 48 | container.add( settings ); 49 | */ 50 | // 51 | 52 | function select( section ) { 53 | 54 | viewTab.setClass( '' ); 55 | editTab.setClass( '' ); 56 | settingsTab.setClass( '' ); 57 | 58 | view.setDisplay( 'none' ); 59 | edit.setDisplay( 'none' ); 60 | settings.setDisplay( 'none' ); 61 | 62 | switch ( section ) { 63 | case 'VIEW MODE': 64 | viewTab.setClass( 'selected' ); 65 | view.setDisplay( '' ); 66 | break; 67 | case 'EDIT MODE': 68 | editTab.setClass( 'selected' ); 69 | edit.setDisplay( '' ); 70 | break; 71 | case 'SETTINGS': 72 | settingsTab.setClass( 'selected' ); 73 | settings.setDisplay( '' ); 74 | break; 75 | } 76 | 77 | 78 | } 79 | 80 | select( 'VIEW MODE' ); 81 | 82 | return container; 83 | 84 | }; -------------------------------------------------------------------------------- /src/ui/Toolbar.js: -------------------------------------------------------------------------------- 1 | 2 | var Toolbar = function ( editor ) { 3 | 4 | 5 | 6 | var container = new UI.Panel(); 7 | container.setId( 'toolbar' ); 8 | 9 | var buttons = new UI.Panel(); 10 | container.add( buttons ); 11 | 12 | //buttons.add( new UI.Text( 'FPS: 60 ' ).setWidth('80px') ); 13 | 14 | 15 | //buttons.add( grid ); 16 | var wireframe = new UI.THREE.Boolean( false, 'Wireframe' ).onChange( update ); 17 | buttons.add( wireframe ); 18 | var axis = new UI.THREE.Boolean( false, 'Axis' ).onChange( update ); 19 | buttons.add( axis ); 20 | var sects = new UI.THREE.Boolean( false, 'Surrounding Sectors' ).onChange( update ); 21 | buttons.add( sects ); 22 | sects.setValue(true); 23 | 24 | var roofs = new UI.THREE.Boolean( false, 'Roofs' ).onChange( update ); 25 | buttons.add( roofs ); 26 | 27 | 28 | /* 29 | 30 | var local = new UI.THREE.Boolean( false, 'local' ).onChange( update ); 31 | buttons.add( local ); 32 | 33 | var showGrid = new UI.THREE.Boolean( true, 'show' ).onChange( update ); 34 | buttons.add( showGrid );*/ 35 | 36 | function update() { 37 | 38 | //signals.snapChanged.dispatch( snap.getValue() === true ? grid.getValue() : null ); 39 | //signals.spaceChanged.dispatch( local.getValue() === true ? "local" : "world" ); 40 | //signals.showGridChanged.dispatch( showGrid.getValue() ); 41 | 42 | } 43 | 44 | return container; 45 | 46 | }; --------------------------------------------------------------------------------