├── .gitignore ├── .project ├── README.md ├── css ├── common.css └── zero.css ├── index.html ├── screenshots ├── index.png └── subway.png └── scripts ├── g3d ├── layer │ ├── FeatureLayer3D.js │ ├── Layer3D.js │ └── TileLayer3D.js ├── map │ ├── MapProvider.js │ └── MapScale.js ├── res │ ├── MapScene3DView.css │ ├── ToolBarView.css │ └── images │ │ ├── 3d-on.png │ │ ├── 3d.png │ │ ├── compass.png │ │ ├── rotate.png │ │ ├── view-perspective.png │ │ ├── view.png │ │ ├── zoom-in.png │ │ └── zoom-out.png ├── util │ └── GeoJSONUtil.js └── view │ ├── MapScene3DView.js │ └── ToolBarView.js ├── lib ├── jquery │ └── jquery.js ├── threejs │ ├── controls │ │ └── TrackballControls.js │ ├── csg │ │ └── ThreeBSP.js │ ├── effects │ │ └── AnaglyphEffect.js │ ├── helvetiker_regular_typeface.js │ ├── plugins │ │ ├── DepthPassPlugin.js │ │ └── stats.js │ ├── postprocessing │ │ ├── BokehPass.js │ │ ├── EffectComposer.js │ │ ├── MaskPass.js │ │ ├── RenderPass.js │ │ ├── SavePass.js │ │ └── ShaderPass.js │ ├── shaders │ │ ├── BlendShader.js │ │ ├── BokehShader.js │ │ ├── ColorCorrectionShader.js │ │ ├── CopyShader.js │ │ ├── DotScreenShader.js │ │ ├── FXAAShader.js │ │ ├── HorizontalTiltShiftShader.js │ │ ├── RGBShiftShader.js │ │ ├── SSAOShader.js │ │ ├── ShaderExtras.js │ │ ├── VerticalTiltShiftShader.js │ │ └── VignetteShader.js │ ├── three.js │ └── typeface-15.js ├── transit │ └── transit.js └── tween │ └── Tween.js ├── mx ├── .gitignore ├── .project ├── MXComponent.js ├── MXEvent.js ├── MXObject.js ├── README.md ├── app │ └── Application.js ├── debug.js ├── framework-base.js ├── framework-core.js ├── javascript-extensions.js ├── mx.build ├── res │ └── locales │ │ ├── en │ │ └── language.js │ │ └── zh-cn │ │ └── language.js ├── scn │ └── Scene.js ├── util │ └── ObjectPool.js └── view │ └── View.js └── mx3d ├── res ├── Scene3DView.css ├── images │ ├── 3d-glasses-enabled.png │ └── 3d-glasses.png └── materials │ └── alphaGradient.xml ├── util └── ShaderMaterialBuilder.js └── view ├── AnimatedScene3DView.js ├── LabelView.js ├── MXComponent3D.js ├── MXObject3D.js └── Scene3DView.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | min.js 3 | min.css 4 | /.settings -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | g3d 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.validation.validationbuilder 20 | 21 | 22 | 23 | 24 | org.magiccube.mxtool.eclipse.builders.mxBuilder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.wst.common.project.facet.core.nature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.wst.jsdt.core.jsNature 33 | org.magiccube.mxtool.eclipse.builders.mxNature 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VIDEO DEMOS 2 | https://www.youtube.com/watch?v=fFMc5P8F7SY 3 | 4 | https://www.youtube.com/watch?v=9rUGYhHJJ6E 5 | 6 | https://www.youtube.com/watch?v=PQuNo-mrLKU 7 | 8 | https://www.youtube.com/watch?v=DNW6VwIxl4w 9 | 10 | # MagicCube g3d Framework 11 | MagicCube g3D Framework is a web GIS library for 3D visualization using WebGL technology. In this early version, it supports 12 | * Designed for geo-based big data visualization 13 | * Powered by [MagicCube MXFramework](https://github.com/MagicCube/mxframework-core) 14 | * High-performance real-time 3D rendering and animations based on Three.js and WebGL 15 | * [Open Street Map](http://www.openstreetmap.org/) / [MapBox](http://www.mapbox.com) / [Google Map](https://maps.google.com/) / [Nokia HERE Map](http://here.com/) / [Baidu Map](http://map.baidu.com/) / [AutoNavi](http://www.autonavi.com/) supported 16 | * Multi-layer supported 17 | * Basic 2D/3D geometries and features supported 18 | * GeoJSON supported 19 | * Cache tile images using HTML5 LocalStorage 20 | * Build-in ToolBar and Compass 21 | * Anaglyph Effect (Red/Blue 3D Glasses are needed) 22 | 23 | ## [Live Demo](http://magiccube.github.io/g3d/) 24 | 25 | ![](https://raw.githubusercontent.com/MagicCube/g3d/master/screenshots/subway.png) 26 | 27 | Open the [live demo page](http://magiccube.github.io/g3d/) with Chrome, Safari or any other Webkit-based modern browser. 28 | 29 | How to Use 30 | * Drag with left button to pan. 31 | * Drag with right button to rotate. 32 | * Scroll to zoom in and out. 33 | 34 | If you have a multi-finger touchable device, you can 35 | * Touch with one finger to pan. 36 | * Touch with two fingers to rotate. 37 | * Pinch with two fingers to zoom in and out. 38 | 39 | If you have a Red/Blue 3D Glasses 40 | * Click the glasses button of the toolbar on the left side to switch between 2D and 3D mode. 41 | 42 | ## Screenshots 43 | ![](https://raw.githubusercontent.com/MagicCube/g3d/master/screenshots/index.png) 44 | 45 | ## Dependencies 46 | The g3d Framework is built on top of [MagicCube MXFramework](https://github.com/MagicCube/mxframework-core), [Three.js](threejs.org/), [Tween.js](https://github.com/sole/tween.js), [jQuery](http://jquery.com) and [jquery.transit](https://github.com/rstacruz/jquery.transit). 47 | 48 | ## Usage 49 | Create a new 3D map view with an OSM-based layer. 50 | ```javascript 51 | $import("g3d.view.MapScene3DView"); 52 | 53 | var mapView = null; 54 | mx.whenReady(function() 55 | { 56 | // Create a new MapProvider using MapBox tiles. 57 | var mapProvider = new g3d.map.MapProvider({ 58 | urlFormat: "http://{s}.tiles.mapbox.com/v3/nicki.uxdh1tt9/{z}/{x}/{y}.png32", 59 | tileSize: 256, // Normally the tile size is always 256 in OSM and Google 60 | }); 61 | 62 | 63 | // Create an instance of MapScene3DView 64 | mapView = new g3d.view.MapScene3DView({ 65 | $element: $("#map"), 66 | mapProvider: mapProvider, 67 | centerLocation: [118.778845, 32.04386], 68 | zoom: 12, // The same 'zoom level' rules as Google Map. 69 | statsVisible: true, // Whether display the WebGL status bar. 70 | displayCompass: true, // Whether the compass should be displayed. 71 | displayToolBar: true, // Whether the tool bar should be displayed. 72 | onzooming: function(e) 73 | { 74 | console.log("Zooming from %d to %d.", e.zoomFrom, e.zoomTo); 75 | }, 76 | onzoomed: function(e) 77 | { 78 | console.log("Zoom level is now set to %d.", e.zoomTo); 79 | } 80 | }); 81 | 82 | // Add a OSM-based tile layer. 83 | var tileLayer = new g3d.layer.TileLayer3D({ 84 | useLocalStorage: true // Use HTML5 Local Storage to cache the tiles. 85 | }); 86 | mapView.addLayer(tileLayer); 87 | 88 | // Start animation, so the user can interactive with the map. 89 | mapView.startAnimation(); 90 | }); 91 | ``` 92 | 93 | 94 | Now let's add a polygon mesh to display 'Zifeng Tower'. 95 | Please refer to http://www.openstreetmap.org/way/140809508 96 | ```javascript 97 | // Add a feature layer to diaplay buildings. 98 | var buildingLayer = new g3d.layer.FeatureLayer3D(); 99 | mapView.addLayer(buildingLayer); 100 | 101 | buildingLayer.addPolygon( 102 | [ 103 | [ 118.7781014, 32.062422 ], 104 | [ 118.7777385, 32.0627166 ], 105 | [ 118.7777183, 32.0627721 ], 106 | [ 118.7779384, 32.0628862 ], 107 | [ 118.7782096, 32.0629544 ], 108 | [ 118.7782587, 32.0629002 ], 109 | [ 118.7782337, 32.0624534 ], 110 | [ 118.7781786, 32.0624179 ] 111 | ], 112 | 200, // Height of the polygon mesh in pixels. 113 | { 114 | color : 0xff0000, 115 | opacity : 0.8 116 | } // Alternatively you can use any THREE.Material instead 117 | ); 118 | ``` 119 | -------------------------------------------------------------------------------- /css/common.css: -------------------------------------------------------------------------------- 1 | html, body 2 | { 3 | background: black; 4 | } -------------------------------------------------------------------------------- /css/zero.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video 2 | { 3 | margin: 0; 4 | padding: 0; 5 | border: 0; 6 | font-size: 100%; 7 | font-family: 'Microsoft Yahei', Verdana, 'Helvetica Neue', 'BBAlpha Sans', 'S60 Sans', Arial, sans-serif; 8 | vertical-align: baseline; 9 | box-sizing: border-box; 10 | -webkit-font-smoothing: antialiased; 11 | -webkit-text-size-adjust: none; 12 | } 13 | /* HTML5 display-role reset for older browsers */ 14 | article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section 15 | { 16 | display: block; 17 | } 18 | 19 | body { 20 | line-height: 1; 21 | } 22 | 23 | ol,ul { 24 | list-style: none; 25 | } 26 | 27 | blockquote,q { 28 | quotes: none; 29 | } 30 | 31 | blockquote:before,blockquote:after,q:before,q:after { 32 | content: ''; 33 | content: none; 34 | } 35 | 36 | table { 37 | border-collapse: collapse; 38 | border-spacing: 0; 39 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MagicCube G3d Framework Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 85 | 86 | -------------------------------------------------------------------------------- /screenshots/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/screenshots/index.png -------------------------------------------------------------------------------- /screenshots/subway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/screenshots/subway.png -------------------------------------------------------------------------------- /scripts/g3d/layer/FeatureLayer3D.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.layer"); 2 | 3 | $import("g3d.layer.Layer3D"); 4 | 5 | g3d.layer.FeatureLayer3D = function() 6 | { 7 | var me = $extend(g3d.layer.Layer3D); 8 | var base = {}; 9 | 10 | me.color = 0xffffff; 11 | 12 | base.init = me.init; 13 | me.init = function(p_options) 14 | { 15 | base.init(p_options); 16 | }; 17 | 18 | me.addCircle = function(p_coordinate, p_radius, p_material) 19 | { 20 | if (!isNumber(p_radius)) 21 | { 22 | throw new Error("p_radius must be a number."); 23 | } 24 | 25 | var geometry = new THREE.CircleGeometry(p_radius ? p_radius : 2); 26 | 27 | var material = me.translateMaterial(p_material, THREE.MeshBasicMaterial); 28 | var mesh = new THREE.Mesh(geometry, material); 29 | var position = me.translatePoint(p_coordinate); 30 | mesh.position.copy(position); 31 | me.addObject(mesh); 32 | return mesh; 33 | }; 34 | 35 | me.addPolygon = function(p_coordinates, p_height, p_material) 36 | { 37 | if (!isNumber(p_height)) 38 | { 39 | throw new Error("p_height must be a number."); 40 | } 41 | 42 | var height = p_height ? p_height : 1; 43 | var points = me.translatePoints(p_coordinates); 44 | var shape = null; 45 | if (points.length > 2) 46 | { 47 | shape = new THREE.Shape(points); 48 | if (shape.curves.length <= 1) 49 | { 50 | return null; 51 | } 52 | } 53 | else 54 | { 55 | return null; 56 | } 57 | var geometry = new THREE.ExtrudeGeometry(shape, { 58 | bevelEnabled : false, 59 | amount : height 60 | }); 61 | 62 | var material = me.translateMaterial(p_material, THREE.MeshBasicMaterial); 63 | var mesh = new THREE.Mesh(geometry, material); 64 | mesh.position.z = -height / 2; 65 | me.addObject(mesh); 66 | return mesh; 67 | }; 68 | 69 | me.addSpline = function(p_spline, p_pointCount, p_material) 70 | { 71 | var points = p_spline.getPoints(p_pointCount); 72 | return me.addLineString(points, p_material); 73 | }; 74 | 75 | me.addLineString = function(p_coordinates, p_material) 76 | { 77 | var lineGeometry = new THREE.Geometry(); 78 | var vertices = me.translatePoints(p_coordinates); 79 | lineGeometry.vertices.addAll(vertices); 80 | 81 | var material = me.translateMaterial(p_material, THREE.LineBasicMaterial); 82 | var line = new THREE.Line(lineGeometry, material); 83 | me.addObject(line); 84 | return line; 85 | }; 86 | 87 | me.addPolyline = function(p_coordinates, p_material) 88 | { 89 | var coordinates = p_coordinates.clone(); 90 | coordinates.add(p_coordinates[0]); 91 | return me.addLineString(coordinates, p_material); 92 | }; 93 | 94 | me.translatePoint = function(p_coordinate) 95 | { 96 | var isCoordinateNumber = isNumber(p_coordinate.lon) && isNumber(p_coordinate.Lat); 97 | var isCoordinateArray = isArray(p_coordinate) && p_coordinate.length === 2; 98 | var isCoordinatesNumber = isNumber(p_coordinate[0]) && isNumber(p_coordinate[1]); 99 | 100 | if (isNumber(p_coordinate.x) && isNumber(p_coordinate.y)) 101 | { 102 | if (p_coordinate.z == null) 103 | { 104 | p_coordinate.z = 0; 105 | } 106 | if (isPlainObject(p_coordinate) || p_coordinate.constructor === THREE.Vector2) 107 | { 108 | return new THREE.Vector3(p_coordinate.x, p_coordinate.y, p_coordinate.z); 109 | } 110 | else 111 | { 112 | return p_coordinate; 113 | } 114 | } 115 | else if (isCoordinateNumber || isCoordinateArray && isCoordinatesNumber) 116 | { 117 | var v = me.scale.locationToVector3(p_coordinate); 118 | return v; 119 | } 120 | else 121 | { 122 | throw new Error(p_coordinate + " is not a validate format of coordinate. A coordinate could be a LonLat, Vector2 or Vector3."); 123 | } 124 | }; 125 | 126 | me.translatePoints = function(p_coordinates) 127 | { 128 | return p_coordinates.map(function(p_coordinate) 129 | { 130 | return me.translatePoint(p_coordinate); 131 | }); 132 | }; 133 | 134 | me.translateMaterial = function(p_material, p_materialClass, p_defaultParams) 135 | { 136 | var material = null; 137 | if (notEmpty(p_material)) 138 | { 139 | if (isPlainObject(p_material)) 140 | { 141 | var defaultParams = $.extend({ 142 | color : me.color 143 | }, p_defaultParams); 144 | var materialParams = $.extend(defaultParams, p_material); 145 | material = new p_materialClass(materialParams); 146 | } 147 | else if (isObject(p_material)) 148 | { 149 | material = p_material; 150 | } 151 | else 152 | { 153 | throw new Error("p_material '" + p_material + "' can not be translated into Material."); 154 | } 155 | } 156 | else 157 | { 158 | throw new Error("p_material can not be null or empty"); 159 | } 160 | return material; 161 | }; 162 | 163 | return me.endOfClass(arguments); 164 | }; 165 | g3d.layer.FeatureLayer3D.className = "g3d.layer.FeatureLayer3D"; 166 | -------------------------------------------------------------------------------- /scripts/g3d/layer/Layer3D.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.layer"); 2 | 3 | $import("mx3d.view.MXComponent3D"); 4 | 5 | g3d.layer.Layer3D = function() 6 | { 7 | var me = $extend(mx3d.view.MXComponent3D); 8 | var base = {}; 9 | 10 | me.scale = null; 11 | me.geoJSONUtil = null; 12 | 13 | me.onaddedtomap = null; 14 | me.onremovedfrommap == null; 15 | 16 | base.init = me.init; 17 | me.init = function(p_options) 18 | { 19 | base.init(p_options); 20 | }; 21 | 22 | return me.endOfClass(arguments); 23 | }; 24 | g3d.layer.Layer3D.className = "g3d.layer.Layer3D"; 25 | -------------------------------------------------------------------------------- /scripts/g3d/layer/TileLayer3D.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.layer"); 2 | 3 | $import("g3d.layer.Layer3D"); 4 | 5 | g3d.layer.TileLayer3D = function() 6 | { 7 | var me = $extend(g3d.layer.Layer3D); 8 | var base = {}; 9 | 10 | me.zoomMin = 0; 11 | me.zoomMax = 0; 12 | 13 | me.useLocalStorage = false; 14 | 15 | me.mapProvider = null; 16 | me.zoomInfo = null; 17 | 18 | var _loaded = false; 19 | var _zooming = false; 20 | 21 | base.init = me.init; 22 | me.init = function(p_options) 23 | { 24 | base.init(p_options); 25 | me.on("addedtomap", _onaddedtomap); 26 | me.on("removedfrommap", _onremovedfrommap); 27 | }; 28 | 29 | function _onaddedtomap() 30 | { 31 | if (!_loaded) 32 | { 33 | me.zoomMin = me.parentView.zoomMin; 34 | me.zoomMax = me.parentView.zoomMax; 35 | me.mapProvider = me.parentView.mapProvider; 36 | me.zoomInfo = me.parentView.zoomInfo; 37 | _loadZooms(); 38 | _switchZoom(me.zoomMin, me.parentView.zoom); 39 | me.parentView.on("zooming", _mapScene3DView_onzooming); 40 | _loaded = true; 41 | } 42 | } 43 | 44 | function _onremovedfrommap() 45 | { 46 | if (_loaded) 47 | { 48 | me.parentView.off("zooming", _mapScene3DView_onzooming); 49 | } 50 | } 51 | 52 | function _mapScene3DView_onzooming(e) 53 | { 54 | if (_zooming) 55 | { 56 | e.cancel = true; 57 | return; 58 | } 59 | 60 | _switchZoom(e.zoomFrom, e.zoomTo); 61 | } 62 | 63 | function _loadZoom(p_zoom, p_cols, p_rows) 64 | { 65 | var zoomInfo = me.zoomInfo[p_zoom]; 66 | var tileSize = zoomInfo.tileSize; 67 | 68 | var width = tileSize * p_cols * 2 + tileSize; 69 | var height = tileSize * p_rows * 2 + tileSize; 70 | var geometry = new THREE.PlaneGeometry(width, height); 71 | 72 | var material = _loadZoomMaterial(p_zoom, p_cols, p_rows); 73 | material.opacity = (p_zoom === me.zoomMin ? 1 : 0); 74 | 75 | var mesh = new THREE.Mesh(geometry, material); 76 | mesh.position = zoomInfo.centerPosition; 77 | zoomInfo.tileMesh = mesh; 78 | if (p_zoom === me.zoomMin) 79 | { 80 | me.addObject(zoomInfo.tileMesh); 81 | } 82 | } 83 | ; 84 | 85 | function _loadZooms() 86 | { 87 | for (var i = me.zoomMin; i <= me.zoomMax; i++) 88 | { 89 | if (i === me.zoomMin || i === me.zoomMax) 90 | { 91 | _loadZoom(i, 4, 4); 92 | } 93 | else 94 | { 95 | _loadZoom(i, 3, 3); 96 | } 97 | } 98 | } 99 | 100 | function _switchZoom(p_zoomFrom, p_zoomTo) 101 | { 102 | _zooming = true; 103 | 104 | console.log("Zooming from " + p_zoomFrom + " to " + p_zoomTo); 105 | 106 | var zoomIn = false; 107 | if (p_zoomFrom < p_zoomTo) 108 | { 109 | // 13 - 14 110 | zoomIn = true; 111 | zoomOut = false; 112 | } 113 | 114 | for (var i = me.zoomMin + 1; i <= me.zoomMax; i++) 115 | { 116 | if (i > p_zoomTo) 117 | { 118 | _hideTileMesh(i, (!zoomIn && i === p_zoomFrom), _hideOrShowTileMesh_callback); 119 | } 120 | else 121 | { 122 | _showTileMesh(i, (zoomIn && i === p_zoomTo), _hideOrShowTileMesh_callback); 123 | } 124 | } 125 | } 126 | 127 | function _hideOrShowTileMesh_callback() 128 | { 129 | _zooming = false; 130 | } 131 | 132 | function _calculateTileIndex(a, b, z) 133 | { 134 | var centerIndex = me.zoomInfo[z].centerIndex; 135 | var index = { 136 | x : centerIndex.x + a, 137 | y : centerIndex.y - b, 138 | z : z 139 | }; 140 | return index; 141 | } 142 | 143 | function _showTileMesh(p_zoom, p_animation, p_callback) 144 | { 145 | var tileMesh = me.zoomInfo[p_zoom].tileMesh; 146 | me.addObject(tileMesh); 147 | if (p_animation && tileMesh.material.opacity !== 1) 148 | { 149 | var duration = 400; 150 | // 看不见 151 | new TWEEN.Tween(tileMesh.material).to({ 152 | opacity : 1 153 | }, duration).onUpdate(function() 154 | { 155 | this.needsUpdate = true; 156 | }).onComplete(function() 157 | { 158 | if (isFunction(p_callback)) 159 | { 160 | p_callback(); 161 | } 162 | }).start(); 163 | } 164 | else 165 | { 166 | if (isFunction(p_callback)) 167 | { 168 | p_callback(); 169 | } 170 | } 171 | } 172 | 173 | function _hideTileMesh(p_zoom, p_animation, p_callback) 174 | { 175 | var tileMesh = me.zoomInfo[p_zoom].tileMesh; 176 | if (p_animation && tileMesh.material.opacity !== 0) 177 | { 178 | var duration = 400; 179 | // 看不见 180 | new TWEEN.Tween(tileMesh.material).to({ 181 | opacity : 0 182 | }, duration).onUpdate(function() 183 | { 184 | this.needsUpdate = true; 185 | }).onComplete(function() 186 | { 187 | me.removeObject(tileMesh); 188 | if (isFunction(p_callback)) 189 | { 190 | p_callback(); 191 | } 192 | }).start(); 193 | } 194 | else 195 | { 196 | me.removeObject(tileMesh); 197 | if (isFunction(p_callback)) 198 | { 199 | p_callback(); 200 | } 201 | } 202 | } 203 | 204 | function _loadZoomMaterial(p_zoom, p_cols, p_rows) 205 | { 206 | var material = null; 207 | var key = _getKey(p_zoom, p_cols, p_rows); 208 | var cachedImage = me.useLocalStorage ? localStorage.getItem(key) : null; 209 | 210 | if (cachedImage == null) 211 | { 212 | var tileSize = me.mapProvider.tileSize; 213 | var canvas = document.createElement("canvas"); 214 | var width = tileSize * p_cols * 2 + tileSize; 215 | var height = tileSize * p_rows * 2 + tileSize; 216 | canvas.width = width; 217 | canvas.height = height; 218 | 219 | var texture = new THREE.Texture(canvas); 220 | texture.needsUpdate = true; 221 | material = new THREE.MeshBasicMaterial({ 222 | map : texture, 223 | transparent : true 224 | }); 225 | 226 | var canvasContext = canvas.getContext("2d"); 227 | canvasContext.clearRect(0, 0, width, height); 228 | canvas.loading = 0; 229 | for (var b = -p_rows; b <= p_rows; b++) 230 | { 231 | for (var a = -p_cols; a <= p_cols; a++) 232 | { 233 | var index = _calculateTileIndex(a, b, p_zoom); 234 | canvas.loading++; 235 | _loadTileImage(index, { 236 | index : index, 237 | a : a, 238 | b : b 239 | }, function(p_image, p_context) 240 | { 241 | canvasContext.drawImage(p_image, (p_context.a + p_cols) * tileSize, height - (p_context.b + p_rows + 1) * tileSize, tileSize, tileSize); 242 | texture.needsUpdate = true; 243 | canvas.loading--; 244 | if (canvas.loading === 0 && me.useLocalStorage) 245 | { 246 | localStorage.setItem(key, canvas.toDataURL("image/jpeg")); 247 | console.log("Saved tiles to cache. " + key); 248 | } 249 | }); 250 | } 251 | } 252 | } 253 | else 254 | { 255 | material = new THREE.MeshBasicMaterial({ 256 | map : THREE.ImageUtils.loadTexture(cachedImage), 257 | transparent : true 258 | }); 259 | console.log("Load tiles from cache. " + key); 260 | } 261 | 262 | return material; 263 | } 264 | 265 | function _loadImage(p_url, p_context, p_callback) 266 | { 267 | var image = new Image(); 268 | image.crossOrigin = "anonymous"; 269 | image.onload = function(e) 270 | { 271 | image.onload = null; 272 | if (isFunction(p_callback)) 273 | { 274 | p_callback(image, p_context); 275 | } 276 | }; 277 | image.src = p_url; 278 | } 279 | 280 | function _loadTileImage(p_index, p_context, p_callback) 281 | { 282 | var url = me.mapProvider.getTileUrl(p_index); 283 | return _loadImage(url, p_context, p_callback); 284 | } 285 | 286 | function _getKey(p_zoom, p_cols, p_rows) 287 | { 288 | return $format("{url:{0}, zoom:{1}, cols:{2}, rows:{3}}", [me.mapProvider.urlFormat, p_zoom, p_cols, p_rows]); 289 | } 290 | 291 | return me.endOfClass(arguments); 292 | }; 293 | g3d.layer.TileLayer3D.className = "g3d.layer.TileLayer3D"; 294 | -------------------------------------------------------------------------------- /scripts/g3d/map/MapProvider.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.map"); 2 | 3 | g3d.map.MapProvider = function() 4 | { 5 | var me = $extend(MXObject); 6 | var base = {}; 7 | 8 | me.urlFormat = "http://{s}.tiles.mapbox.com/v3/nicki.uxdh1tt9/{z}/{x}/{y}.png32"; 9 | 10 | /** 11 | * Open Street Map (OSM) 12 | * http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png 13 | * 14 | * AutoNavi (高德) 15 | * http://webrd0{n}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z} 16 | * 17 | * MapBox 18 | * http://{s}.tiles.mapbox.com/v3/nicki.uxdh1tt9/{z}/{x}/{y}.png32 19 | * 20 | * Google Satellite 21 | * https://earthbuilder.googleapis.com/10446176163891957399-03098191120537720121-4/2/maptile/maps?v=3&authToken=CgiZD3q-khVBTBDahK2bBQ==&x={x}&y={y}&z={z}&s= 22 | * 23 | * Nokia Map 24 | * http://{n}.aerial.maps.cit.api.here.com/maptile/2.1/maptile/newest/terrain.day/{z}/{x}/{y}/256/jpg?app_id=yyMGGSFl4Py1t71zw69y&app_code=GM8TDhPhXdmVYhxFzbOABg 25 | */ 26 | 27 | me.tileSize = 256; 28 | 29 | base._ = me._; 30 | me._ = function(p_options) 31 | { 32 | if (me.canConstruct()) 33 | { 34 | base._(p_options); 35 | } 36 | }; 37 | 38 | var _serverIndex = 0; 39 | me.getTileUrl = function(p_index) 40 | { 41 | _serverIndex++; 42 | if (_serverIndex >= 4) 43 | { 44 | _serverIndex = 1; 45 | } 46 | var params = { 47 | x : p_index.x, 48 | y : p_index.y, 49 | z : p_index.z, 50 | s : ["a", "b", "c"][_serverIndex - 1], 51 | n : _serverIndex 52 | }; 53 | var url = $format(me.urlFormat, params); 54 | return url; 55 | }; 56 | 57 | me.getTileIndex = function(p_lonLat, p_zoom, p_useFloat) 58 | { 59 | if (p_useFloat == null) 60 | { 61 | p_useFloat = false; 62 | } 63 | var pow = Math.pow(2, p_zoom); 64 | var pos = { 65 | x : (p_lonLat.lon + 180) / 360 * pow, 66 | y : (1 - Math.log(Math.tan(p_lonLat.lat * Math.PI / 180) + 1 / Math.cos(p_lonLat.lat * Math.PI / 180)) / Math.PI) / 2 * pow, 67 | z : p_zoom 68 | }; 69 | if (!p_useFloat) 70 | { 71 | pos.x = Math.floor(pos.x); 72 | pos.y = Math.floor(pos.y); 73 | } 74 | return pos; 75 | }; 76 | 77 | me.getTileLonLat = function(p_index) 78 | { 79 | var pow = Math.pow(2, p_index.z); 80 | var n = Math.PI - 2 * Math.PI * p_index.y / pow; 81 | var lonLat = { 82 | lon : p_index.x / pow * 360 - 180, 83 | lat : 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))) 84 | }; 85 | return lonLat; 86 | }; 87 | 88 | return me.endOfClass(arguments); 89 | }; 90 | g3d.map.MapProvider.className = "g3d.map.MapProvider"; 91 | -------------------------------------------------------------------------------- /scripts/g3d/map/MapScale.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.map"); 2 | 3 | g3d.map.MapScale = function() 4 | { 5 | var me = $extend(MXObject); 6 | var base = {}; 7 | 8 | me.centerLocation = { 9 | lon : 0, 10 | lat : 0 11 | }; 12 | 13 | me.zoomMin = 0; 14 | me.zoomMax = 0; 15 | me.zoomInfo = null; 16 | me.mapProvider = null; 17 | 18 | base._ = me._; 19 | me._ = function(p_options) 20 | { 21 | if (me.canConstruct()) 22 | { 23 | base._(p_options); 24 | } 25 | }; 26 | 27 | me.locationToPoint = function(p_location) 28 | { 29 | var location = g3d.util.GeoJSONUtil.normalizeLocation(p_location); 30 | if (location != null) 31 | { 32 | var centerIndex = me.zoomInfo[me.zoomMax].centerIndex; 33 | var centerPosition = me.zoomInfo[me.zoomMax].centerPosition; 34 | var indexFloat = me.mapProvider.getTileIndex(location, me.zoomMax, true); 35 | return { 36 | x : centerPosition.x + (indexFloat.x - centerIndex.x) * me.mapProvider.tileSize - me.mapProvider.tileSize / 2, 37 | y : centerPosition.y - (indexFloat.y - centerIndex.y) * me.mapProvider.tileSize + me.mapProvider.tileSize / 2 38 | }; 39 | } 40 | return null; 41 | }; 42 | 43 | me.locationsToPoints = function(p_locations) 44 | { 45 | var results = p_locations.map(function(p_location) 46 | { 47 | return me.locationToPoint(p_location); 48 | }); 49 | return results; 50 | }; 51 | 52 | me.locationToVector3 = function(p_location) 53 | { 54 | var location = g3d.util.GeoJSONUtil.normalizeLocation(p_location); 55 | if (location != null) 56 | { 57 | var p = me.locationToPoint(p_location); 58 | var vector3 = new THREE.Vector3(p.x, p.y, 0); 59 | return vector3; 60 | } 61 | return null; 62 | }; 63 | 64 | me.locationsToPath = function(p_locations) 65 | { 66 | var results = p_locations.map(function(p_location) 67 | { 68 | return me.locationToVector3(p_location); 69 | }); 70 | return results; 71 | }; 72 | 73 | me.locationsToLine = function(p_locations) 74 | { 75 | var points = me.locationsToPath(p_locations); 76 | var geometry = new THREE.Geometry(); 77 | geometry.vertices.addAll(points); 78 | var line = new THREE.Line(geometry); 79 | return line; 80 | }; 81 | 82 | me.locationsToSplinePath = function(p_locations, p_count) 83 | { 84 | var points = me.locationsToPath(p_locations); 85 | var splineCurve3 = new THREE.SplineCurve3(points); 86 | points = splineCurve3.getPoints(p_count); 87 | return points; 88 | }; 89 | 90 | me.locationsToSpline = function(p_locations, p_count) 91 | { 92 | var points = me.locationsToSplinePath(p_locations, p_count); 93 | 94 | var geometry = new THREE.Geometry(); 95 | geometry.vertices.addAll(points); 96 | var line = new THREE.Line(geometry); 97 | return line; 98 | }; 99 | 100 | return me.endOfClass(arguments); 101 | }; 102 | g3d.map.MapScale.className = "g3d.map.MapScale"; 103 | -------------------------------------------------------------------------------- /scripts/g3d/res/MapScene3DView.css: -------------------------------------------------------------------------------- 1 | .MapScene3DView 2 | { 3 | position: relative; 4 | } 5 | 6 | .MapScene3DView .LabelView 7 | { 8 | font-size: 12px; 9 | position: absolute; 10 | color: white; 11 | background: rgba(0, 0, 0, 0.1); 12 | border: 1px solid rgba(255, 255, 255, 0.5); 13 | padding: 6px 6px; 14 | -webkit-transform: translate(-50%, -50%); 15 | -webkit-transform-origin: center center; 16 | text-shadow: 0 0 2px black; 17 | white-space: nowrap; 18 | } 19 | 20 | .MapScene3DView img#compass 21 | { 22 | position: absolute; 23 | left: 10px; 24 | top: 60px; 25 | cursor: pointer; 26 | } -------------------------------------------------------------------------------- /scripts/g3d/res/ToolBarView.css: -------------------------------------------------------------------------------- 1 | .MapScene3DView .ToolBarView 2 | { 3 | display: block; 4 | list-style: none; 5 | position: relative; 6 | width: 46px; 7 | margin: 0; 8 | padding: 0; 9 | z-index: 1; 10 | } 11 | 12 | .MapScene3DView .ToolBarView li 13 | { 14 | display: block; 15 | width: 46px; 16 | height: 46px; 17 | border-radius: 4px; 18 | background: rgba(0,0,0,0.5); 19 | background-rpeat: no-repeat; 20 | background-position: center center; 21 | margin: 0; 22 | margin-left: 18px; 23 | margin-bottom: 18px; 24 | padding: 0; 25 | cursor: pointer; 26 | } 27 | 28 | .MapScene3DView .ToolBarView li.checked, .ToolBarView li:ACTIVE 29 | { 30 | background: rgba(87, 200, 232, 0.4); 31 | } 32 | 33 | 34 | 35 | 36 | 37 | .MapScene3DView .ToolBarView li#anaglyph 38 | { 39 | background-image: url(images/3d.png); 40 | } 41 | .MapScene3DView .ToolBarView li#anaglyph.checked 42 | { 43 | background-image: url(images/3d-on.png); 44 | } 45 | 46 | .MapScene3DView .ToolBarView li#view 47 | { 48 | background-image: url(images/view-perspective.png); 49 | } 50 | .MapScene3DView .ToolBarView li#view.checked 51 | { 52 | background-image: url(images/view.png); 53 | background-color: rgba(0, 0, 0, 0.5); 54 | } 55 | 56 | .MapScene3DView .ToolBarView li#rotate 57 | { 58 | background-image: url(images/rotate.png); 59 | } 60 | 61 | .MapScene3DView .ToolBarView li#zoomIn 62 | { 63 | background-image: url(images/zoom-in.png); 64 | margin-bottom: 0; 65 | border-radius: 4px 4px 0 0; 66 | } 67 | 68 | .MapScene3DView .ToolBarView li#zoomOut 69 | { 70 | background-image: url(images/zoom-out.png); 71 | border-radius: 0 0 4px 4px; 72 | } -------------------------------------------------------------------------------- /scripts/g3d/res/images/3d-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/3d-on.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/3d.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/compass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/compass.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/rotate.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/view-perspective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/view-perspective.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/view.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/zoom-in.png -------------------------------------------------------------------------------- /scripts/g3d/res/images/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/g3d/res/images/zoom-out.png -------------------------------------------------------------------------------- /scripts/g3d/util/GeoJSONUtil.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.util"); 2 | 3 | g3d.util.GeoJSONUtil = function() 4 | { 5 | var me = $extend(MXObject); 6 | var base = {}; 7 | 8 | me.scale = null; 9 | 10 | base._ = me._; 11 | me._ = function(p_options) 12 | { 13 | if (me.canConstruct()) 14 | { 15 | base._(p_options); 16 | 17 | if (!$instanceof(me.scale, g3d.map.MapScale)) 18 | { 19 | throw new Error("constructor param 'scale' must be an instance of g3d.map.MapScale."); 20 | } 21 | } 22 | }; 23 | 24 | me.parse = function(p_json) 25 | { 26 | if (p_json.type === "FeatureCollection") 27 | { 28 | return me.createFromFeatureCollection(p_json); 29 | } 30 | else if (p_json.type === "Feature") 31 | { 32 | return me.createFromFeature(p_json); 33 | } 34 | else if (p_json.type === "LineString" || p_json.type === "Polygon") 35 | { 36 | return me.createFromGeometry(p_json); 37 | } 38 | else 39 | { 40 | throw new Error("GeoJSON type '" + p_json.type + "' has not been supported yet."); 41 | } 42 | }; 43 | 44 | me.createFromFeatureCollection = function(p_featureCollection) 45 | { 46 | if (p_featureCollection.type !== "FeatureCollection") 47 | { 48 | throw new Error("The type of p_featureCollection must be FeatureCollection."); 49 | } 50 | var shapes = []; 51 | var features = p_featureCollection.features; 52 | 53 | features.forEach(function(p_feature) 54 | { 55 | var shape = me.createFromFeature(p_feature); 56 | if (shape != null) 57 | { 58 | shapes.add(shape); 59 | } 60 | }); 61 | return shapes; 62 | }; 63 | 64 | me.createFromFeature = function(p_feature) 65 | { 66 | if (p_feature.type !== "Feature") 67 | { 68 | throw new Error("The type of p_feature must be Feature."); 69 | } 70 | var shape = me.createFromGeometry(p_feature.geometry); 71 | return shape; 72 | }; 73 | 74 | me.createFromGeometry = function(p_geometry) 75 | { 76 | if (p_geometry.type !== "LineString" && p_geometry.type !== "Polygon") 77 | { 78 | throw new Error("The type of p_geometry must be LineString or Polygon."); 79 | } 80 | 81 | var result = null; 82 | 83 | if (p_geometry.type === "Polygon") 84 | { 85 | result = me.createShapeFromCoordinates(p_geometry.coordinates); 86 | } 87 | else if (p_geometry.type === "LineString") 88 | { 89 | result = me.createLineFromCoordinates(p_geometry.coordinates); 90 | } 91 | return result; 92 | }; 93 | 94 | me.createLineFromCoordinates = function(p_coordinates) 95 | { 96 | var geometry = null; 97 | 98 | var points = me.scale.locationsToPoints(p_coordinates); 99 | 100 | if (points.length > 1) 101 | { 102 | geometry = new THREE.Geometry(); 103 | points.forEach(function(p_point) 104 | { 105 | geometry.vertices.add(new THREE.Vector3(p_point.x, p_point.y, 0)); 106 | }); 107 | } 108 | 109 | return geometry; 110 | }; 111 | 112 | me.createShapeFromCoordinates = function(p_coordinates) 113 | { 114 | var shape = null; 115 | 116 | var points = me.scale.locationsToPoints(p_coordinates[0]); 117 | 118 | if (points.length > 2) 119 | { 120 | shape = new THREE.Shape(points); 121 | if (shape.curves.length > 1) 122 | { 123 | return shape; 124 | } 125 | else 126 | { 127 | return null; 128 | } 129 | } 130 | else 131 | { 132 | return null; 133 | } 134 | }; 135 | 136 | return me.endOfClass(arguments); 137 | }; 138 | g3d.util.GeoJSONUtil.className = "g3d.util.GeoJSONUtil"; 139 | 140 | g3d.util.GeoJSONUtil.normalizeLocation = function(p_location) 141 | { 142 | if (isArray(p_location)) 143 | { 144 | return { 145 | lon : p_location[0], 146 | lat : p_location[1] 147 | }; 148 | } 149 | else if (isPlainObject(p_location)) 150 | { 151 | if (p_location.lon != null && p_location.lat != null) 152 | { 153 | return p_location; 154 | } 155 | else if (p_location.lng != null && p_location.lat != null) 156 | { 157 | return { 158 | lon : p_location.lng, 159 | lat : p_location.lat 160 | }; 161 | } 162 | } 163 | }; 164 | -------------------------------------------------------------------------------- /scripts/g3d/view/MapScene3DView.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.view"); 2 | 3 | $import("lib.transit.transit"); 4 | 5 | $import("mx3d.view.AnimatedScene3DView"); 6 | 7 | $import("g3d.util.GeoJSONUtil"); 8 | $import("g3d.layer.FeatureLayer3D"); 9 | $import("g3d.layer.TileLayer3D"); 10 | $import("g3d.map.MapScale"); 11 | $import("g3d.map.MapProvider"); 12 | $import("g3d.view.ToolBarView"); 13 | 14 | $include("g3d.res.MapScene3DView.css"); 15 | 16 | g3d.view.MapScene3DView = function() 17 | { 18 | var me = $extend(mx3d.view.AnimatedScene3DView); 19 | me.cameraParams = { 20 | fov : 60, 21 | near : 100, 22 | far : 1000000, 23 | position : {} 24 | }; 25 | me.cameraControlsEnabled = true; 26 | me.statsVisible = false; 27 | var base = {}; 28 | 29 | me.centerLocation = { 30 | lon : 0, 31 | lat : 0 32 | }; 33 | me.zoom = 12; 34 | me.zoomMin = 11; // 最远 35 | me.zoomMax = 15; // 最近 36 | 37 | me.displayCompass = true; 38 | 39 | me.landMesh = null; // 为了兼容性,暂时保留 40 | me.layers = []; 41 | me.materials = {}; 42 | 43 | me.mapProvider = null; 44 | me.scale = null; 45 | me.geoJSONUtil = null; 46 | me.zoomInfo = []; 47 | 48 | me.displayToolBar = true; 49 | me.toolBarView = null; 50 | me.toolButtons = [{ 51 | id : "anaglyph", 52 | autoCheck : true 53 | }, { 54 | id : "rotate", 55 | autoCheck : true 56 | }, { 57 | id : "view", 58 | autoCheck : true 59 | }, { 60 | id : "zoomIn" 61 | }, { 62 | id : "zoomOut" 63 | }]; 64 | 65 | me.onzooming = null; 66 | me.onzoomed = null; 67 | 68 | var _$compass = null; 69 | 70 | base.init = me.init; 71 | me.init = function(p_options) 72 | { 73 | me.initMapProvider(); 74 | 75 | base.init(p_options); 76 | me.$element.addClass("MapScene3DView"); 77 | 78 | me.setCenterLocation(me.centerLocation); 79 | me.initScale(); 80 | me.initMaterials(); 81 | 82 | if (me.displayCompass) 83 | { 84 | me.initCompass(); 85 | } 86 | if (me.displayToolBar) 87 | { 88 | me.initToolBarView(); 89 | } 90 | 91 | me.landMesh = new THREE.Object3D(); 92 | me.addObject(me.landMesh); 93 | 94 | me.initLayers(); 95 | }; 96 | 97 | me.setCenterLocation = function(p_location) 98 | { 99 | me.centerLocation = g3d.util.GeoJSONUtil.normalizeLocation(p_location); 100 | me.initZoomInfo(); 101 | }; 102 | 103 | base.initScene = me.initScene; 104 | me.initScene = function() 105 | { 106 | base.initScene(); 107 | var fogWeight = Math.pow((20 - me.zoomMax), 2) / 2; 108 | me.scene.fog = new THREE.FogExp2(0x000000, fogWeight / 100000); 109 | }; 110 | 111 | base.initCamera = me.initCamera; 112 | me.initCamera = function() 113 | { 114 | if (me.cameraParams.position == null || me.cameraParams.position.z == null) 115 | { 116 | me.cameraParams.position.z = _calculateCameraZ(me.zoom); 117 | } 118 | else 119 | { 120 | if (me.cameraParams.position.z != null) 121 | { 122 | me.zoom = _calculateZoom(me.cameraParams.position.z); 123 | } 124 | } 125 | base.initCamera(); 126 | }; 127 | 128 | me.initCameraControls = function() 129 | { 130 | if (me.cameraControlsEnabled && me.cameraControls == null) 131 | { 132 | me.cameraControls = new THREE.TrackballControls(me.camera, me.$element.find("canvas")[0]); 133 | me.cameraControls.minDistance = _calculateCameraZ(me.zoomMax) / 1.2; 134 | me.cameraControls.maxDistance = _calculateCameraZ(me.zoomMin) * 1.2; 135 | } 136 | }; 137 | 138 | me.initCompass = function() 139 | { 140 | _$compass = $(""); 141 | me.$container.append(_$compass); 142 | _$compass.on("click", function() 143 | { 144 | me.resetCamera(); 145 | }); 146 | }; 147 | 148 | me.initToolBarView = function() 149 | { 150 | me.toolBarView = new g3d.view.ToolBarView({ 151 | elementStyle : { 152 | position : "absolute" 153 | }, 154 | id : "toolBar", 155 | buttons : me.toolButtons 156 | }); 157 | me.addSubview(me.toolBarView); 158 | 159 | me.toolBarView.setFrame({ 160 | left : 0, 161 | top : (window.innerHeight - me.toolButtons.length * 48) / 2 162 | }); 163 | 164 | me.toolBarView.on("buttonclick", me.ontoolbuttonclick); 165 | }; 166 | 167 | me.initMaterials = function() 168 | { 169 | 170 | }; 171 | 172 | me.ontoolbuttonclick = function(e) 173 | { 174 | switch (e.id) 175 | { 176 | case "anaglyph": 177 | me.anaglyphEffectEnabled = e.button.checked; 178 | break; 179 | case "rotate": 180 | me.cameraControls.controlMode = e.button.checked ? "rotate" : "auto"; 181 | break; 182 | case "view": 183 | me.resetCamera(null, e.button.checked); 184 | break; 185 | case "zoomIn": 186 | me.zoomIn(); 187 | break; 188 | case "zoomOut": 189 | me.zoomOut(); 190 | break; 191 | default: 192 | break; 193 | } 194 | }; 195 | 196 | me.initMapProvider = function() 197 | { 198 | if (me.mapProvider === null) 199 | { 200 | me.mapProvider = new g3d.map.MapProvider(); 201 | } 202 | }; 203 | 204 | me.initZoomInfo = function() 205 | { 206 | for (var z = me.zoomMax; z >= me.zoomMin; z--) 207 | { 208 | var pos = null; 209 | if (z === me.zoomMax) 210 | { 211 | var centerIndexFloat = me.mapProvider.getTileIndex(me.centerLocation, me.zoomMax, true); 212 | var offset = { 213 | x : centerIndexFloat.x - Math.floor(centerIndexFloat.x), 214 | y : centerIndexFloat.y - Math.floor(centerIndexFloat.y) 215 | }; 216 | pos = { 217 | x : -(offset.x - 0.5) * me.mapProvider.tileSize, 218 | y : (offset.y - 0.5) * me.mapProvider.tileSize, 219 | z : -0.5 220 | }; 221 | } 222 | else 223 | { 224 | var centerIndex = me.zoomInfo[z + 1].centerIndex; 225 | var offsetX = centerIndex.x % 2; 226 | var offsetY = centerIndex.y % 2; 227 | pos = { 228 | x : me.zoomInfo[z + 1].centerPosition.x + (offsetX === 0 ? 1 : -1) * me.zoomInfo[z + 1].tileSize / 2, 229 | y : me.zoomInfo[z + 1].centerPosition.y + (offsetY === 0 ? -1 : 1) * me.zoomInfo[z + 1].tileSize / 2, 230 | z : (z - me.zoomMax) + me.zoomInfo[me.zoomMax].centerPosition.z 231 | }; 232 | } 233 | var info = { 234 | zoom : z, 235 | centerIndex : me.mapProvider.getTileIndex(me.centerLocation, z), 236 | centerPosition : pos, 237 | tileSize : _calculateTileSize(z), 238 | cameraZ : _calculateCameraZ(z) 239 | }; 240 | me.zoomInfo[z] = info; 241 | } 242 | }; 243 | 244 | me.initScale = function() 245 | { 246 | me.scale = new g3d.map.MapScale({ 247 | mapProvider : me.mapProvider, 248 | zoomInfo : me.zoomInfo, 249 | zoomMin : me.zoomMin, 250 | zoomMax : me.zoomMax 251 | }); 252 | me.geoJSONUtil = new g3d.util.GeoJSONUtil({ 253 | scale : me.scale 254 | }); 255 | }; 256 | 257 | me.initLayers = function() 258 | { 259 | if (me.layers.length > 0) 260 | { 261 | var layers = me.layers.clone(); 262 | me.layers.clear(); 263 | 264 | layers.forEach(function(p_layer) 265 | { 266 | me.addLayer(p_layer); 267 | }); 268 | } 269 | }; 270 | 271 | base.update = me.update; 272 | me.update = function(p_forceUpdate) 273 | { 274 | base.update(p_forceUpdate); 275 | if (me.camera != null) 276 | { 277 | me.updateZooming(p_forceUpdate); 278 | me.updateLayers(p_forceUpdate); 279 | me.updateCompass(p_forceUpdate); 280 | } 281 | }; 282 | 283 | me.updateZooming = function(p_forceUpdate) 284 | { 285 | var zoomTo = _calculateZoom(me.camera.position.z); 286 | if (zoomTo !== me.zoom) 287 | { 288 | var zoomFrom = me.zoom; 289 | var args = { 290 | zoomFrom : zoomFrom, 291 | zoomTo : zoomTo, 292 | cancel : false 293 | }; 294 | me.trigger("zooming", args); 295 | if (args.cancel) 296 | { 297 | return; 298 | } 299 | me.zoom = zoomTo; 300 | me.trigger("zoomed", { 301 | zoomFrom : zoomFrom, 302 | zoomTo : zoomTo 303 | }); 304 | } 305 | }; 306 | 307 | me.updateLayers = function(p_forceUpdate) 308 | { 309 | me.layers.forEach(function(p_layer) 310 | { 311 | if (p_layer.needsUpdate) 312 | { 313 | p_layer.update(p_forceUpdate); 314 | } 315 | }); 316 | }; 317 | 318 | me.updateCompass = function(p_forceUpdate) 319 | { 320 | if (_$compass != null) 321 | { 322 | var degree = Math.round(me.camera.rotation.z * 180 / Math.PI); 323 | _$compass.css("webkitTransform", "rotate(" + degree + "deg)"); 324 | } 325 | }; 326 | 327 | me.setZoom = function(p_zoom, p_animation) 328 | { 329 | var zoom = p_zoom; 330 | if (zoom > me.zoomMax) 331 | { 332 | zoom = me.zoomMax; 333 | } 334 | else if (zoom < me.zoomMin) 335 | { 336 | zoom = me.zoomMin; 337 | } 338 | 339 | if (p_animation === false) 340 | { 341 | me.camera.position.z = _calculateCameraZ(zoom); 342 | } 343 | else 344 | { 345 | var position = { 346 | x : 0, 347 | y : 0, 348 | z : _calculateCameraZ(zoom) 349 | }; 350 | var rotation = { 351 | x : 0, 352 | y : 0, 353 | z : 0 354 | }; 355 | me.moveCamera(position, rotation, 500); 356 | } 357 | }; 358 | 359 | me.zoomIn = function(p_delta) 360 | { 361 | var delta = 1; 362 | if (p_delta != null) 363 | { 364 | delta = Math.abs(p_delta); 365 | } 366 | var zoom = me.zoom + delta; 367 | me.setZoom(zoom); 368 | 369 | if (me.toolBarView != null) 370 | { 371 | me.toolBarView.setButtonCheckState("view", false); 372 | } 373 | }; 374 | 375 | me.zoomOut = function(p_delta) 376 | { 377 | var delta = 1; 378 | if (p_delta != null) 379 | { 380 | delta = Math.abs(p_delta); 381 | } 382 | var zoom = me.zoom - delta; 383 | me.setZoom(zoom); 384 | 385 | if (me.toolBarView != null) 386 | { 387 | me.toolBarView.setButtonCheckState("view", false); 388 | } 389 | }; 390 | 391 | me.addLayer = function(p_layer) 392 | { 393 | if (!$instanceof(p_layer, g3d.layer.Layer3D)) 394 | { 395 | throw new Error("p_layer must be an instance of g3d.view.Layer3D"); 396 | } 397 | me.layers.add(p_layer); 398 | if (p_layer.id != null) 399 | { 400 | me.layers[p_layer.id] = p_layer; 401 | } 402 | 403 | var parentObject3D = me.landMesh; 404 | parentObject3D.add(p_layer.object3D); 405 | 406 | $.extend(p_layer, { 407 | parentView : me, 408 | parentObject3D : parentObject3D, 409 | scale : me.scale, 410 | geoJSONUtil : me.geoJSONUtil 411 | }); 412 | 413 | p_layer.trigger("addedtomap"); 414 | }; 415 | 416 | me.removeLayer = function(p_layer) 417 | { 418 | if (!$instanceof(p_layer, g3d.layer.Layer3D)) 419 | { 420 | throw new Error("p_layer must be an instance of g3d.view.Layer3D"); 421 | } 422 | 423 | me.layers.remove(p_layer); 424 | if (p_layer.id != null) 425 | { 426 | delete me.layers[p_layer.id]; 427 | } 428 | 429 | var parentObject3D = me.landMesh; 430 | parentObject3D.remove(p_layer.object3D); 431 | 432 | p_layer.trigger("removedfrommap"); 433 | }; 434 | 435 | me.resetCamera = function(p_duration, p_perspective) 436 | { 437 | if (me.cameraControls != null) 438 | { 439 | var position = null; 440 | var rotation = null; 441 | var duration = p_duration != null ? p_duration : 2000; 442 | 443 | if (!p_perspective) 444 | { 445 | var params = me.cameraParams; 446 | position = { 447 | x : 0, 448 | y : 0, 449 | z : 0 450 | }; 451 | rotation = { 452 | x : 0, 453 | y : 0, 454 | z : 0 455 | }; 456 | if (isArray(params.position)) 457 | { 458 | position.x = params.position[0]; 459 | position.y = params.position[1]; 460 | position.z = params.position[2]; 461 | } 462 | else 463 | { 464 | position = $.extend(position, params.position); 465 | } 466 | } 467 | else 468 | { 469 | position = { 470 | x : -50.9760365348891, 471 | y : -1750.5946134789813, 472 | z : 2470.697634926914 473 | }; 474 | rotation = { 475 | x : 0.6164362891923738, 476 | y : -0.01683316387367657, 477 | z : 0.01192588582967832 478 | }; 479 | } 480 | if (me.toolBarView != null) 481 | { 482 | me.toolBarView.setButtonCheckState("view", p_perspective === true); 483 | } 484 | return me.moveCamera(position, rotation, duration); 485 | } 486 | return null; 487 | }; 488 | 489 | function _calculateCameraZ(p_zoom) 490 | { 491 | var zoom = p_zoom; 492 | if (p_zoom < me.zoomMin) 493 | { 494 | zoom = me.zoomMin; 495 | } 496 | else if (p_zoom > me.zoomMax) 497 | { 498 | zoom = me.zoomMax; 499 | } 500 | else 501 | { 502 | zoom = p_zoom; 503 | } 504 | return Math.pow(2, me.zoomMax - zoom + 1) * me.mapProvider.tileSize; 505 | } 506 | 507 | function _calculateZoom(p_z) 508 | { 509 | for (var i = me.zoomMin; i < me.zoomMax; i++) 510 | { 511 | if (p_z >= me.zoomInfo[i].cameraZ) 512 | { 513 | return i; 514 | } 515 | } 516 | return me.zoomMax; 517 | } 518 | 519 | function _calculateTileSize(p_zoom) 520 | { 521 | return Math.pow(2, me.zoomMax - p_zoom) * me.mapProvider.tileSize; 522 | } 523 | 524 | return me.endOfClass(arguments); 525 | }; 526 | g3d.view.MapScene3DView.className = "g3d.view.MapScene3DView"; 527 | -------------------------------------------------------------------------------- /scripts/g3d/view/ToolBarView.js: -------------------------------------------------------------------------------- 1 | $ns("g3d.view"); 2 | 3 | $include("g3d.res.ToolBarView.css"); 4 | 5 | g3d.view.ToolBarView = function() 6 | { 7 | var me = $extend(mx.view.View); 8 | me.elementClass = "ToolBarView"; 9 | me.elementTag = "ul"; 10 | var base = {}; 11 | 12 | me.buttons = []; 13 | 14 | me.onbuttonclick = null; 15 | 16 | base.init = me.init; 17 | me.init = function(p_options) 18 | { 19 | base.init(p_options); 20 | if (me.buttons.length > 0) 21 | { 22 | var buttons = me.buttons.clone(); 23 | me.buttons.clear(); 24 | me.addButtons(buttons); 25 | } 26 | 27 | me.$container.on("click", "li", _li_onclick); 28 | }; 29 | 30 | me.addButton = function(p_button) 31 | { 32 | var id = p_button.id; 33 | if (id == null) 34 | { 35 | throw new Error("Button ID can not be empty or null."); 36 | } 37 | 38 | var button = $.extend({ 39 | autoCheck : false, 40 | checked : false, 41 | text : "", 42 | type : "button" 43 | }, p_button); 44 | var $li = $("
  • "); 45 | 46 | $li.addClass("button"); 47 | $li.attr("id", id); 48 | if (button.checked) 49 | { 50 | $li.addClass("checked"); 51 | } 52 | $li.text(button.text); 53 | button.$element = $li; 54 | me.$container.append($li); 55 | me.buttons.add(button); 56 | me.buttons[button.id] = button; 57 | return button; 58 | }; 59 | 60 | me.addButtons = function(p_buttons) 61 | { 62 | p_buttons.forEach(function(p_button) 63 | { 64 | me.addButton(p_button); 65 | }); 66 | }; 67 | 68 | me.removeButton = function(p_id) 69 | { 70 | var button = me.buttons[p_id]; 71 | if (button != null) 72 | { 73 | me.buttons.remove(button); 74 | delete me.buttons[p_id]; 75 | } 76 | }; 77 | 78 | me.setButtonText = function(p_id, p_text) 79 | { 80 | var button = me.buttons[p_id]; 81 | if (button != null) 82 | { 83 | button.text = p_text; 84 | button.$element.text(p_text); 85 | } 86 | }; 87 | 88 | me.setButtonCheckState = function(p_id, p_state) 89 | { 90 | var button = me.buttons[p_id]; 91 | if (button != null) 92 | { 93 | button.checked = p_state; 94 | if (button.checked) 95 | { 96 | button.$element.addClass("checked"); 97 | } 98 | else 99 | { 100 | button.$element.removeClass("checked"); 101 | } 102 | } 103 | }; 104 | 105 | function _li_onclick(e) 106 | { 107 | var target = e.currentTarget; 108 | var id = target.id; 109 | var button = me.buttons[id]; 110 | if (button.autoCheck) 111 | { 112 | me.setButtonCheckState(id, !button.checked); 113 | } 114 | me.trigger("buttonclick", { 115 | id : id, 116 | button : button 117 | }); 118 | } 119 | 120 | return me.endOfClass(arguments); 121 | }; 122 | g3d.view.ToolBarView.className = "g3d.view.ToolBarView"; 123 | -------------------------------------------------------------------------------- /scripts/lib/threejs/csg/ThreeBSP.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | window.ThreeBSP = (function() { 3 | 4 | var ThreeBSP, 5 | EPSILON = 1e-5, 6 | COPLANAR = 0, 7 | FRONT = 1, 8 | BACK = 2, 9 | SPANNING = 3; 10 | 11 | ThreeBSP = function( geometry ) { 12 | // Convert THREE.Geometry to ThreeBSP 13 | var i, _length_i, 14 | face, vertex, faceVertexUvs, 15 | polygon, 16 | polygons = [], 17 | tree; 18 | 19 | if ( geometry instanceof THREE.Geometry ) { 20 | this.matrix = new THREE.Matrix4; 21 | } else if ( geometry instanceof THREE.Mesh ) { 22 | // #todo: add hierarchy support 23 | geometry.updateMatrix(); 24 | this.matrix = geometry.matrix.clone(); 25 | geometry = geometry.geometry; 26 | } else if ( geometry instanceof ThreeBSP.Node ) { 27 | this.tree = geometry; 28 | this.matrix = new THREE.Matrix4; 29 | return this; 30 | } else { 31 | throw 'ThreeBSP: Given geometry is unsupported'; 32 | } 33 | 34 | for ( i = 0, _length_i = geometry.faces.length; i < _length_i; i++ ) { 35 | face = geometry.faces[i]; 36 | faceVertexUvs = geometry.faceVertexUvs[0][i]; 37 | polygon = new ThreeBSP.Polygon; 38 | 39 | if ( face instanceof THREE.Face3 ) { 40 | vertex = geometry.vertices[ face.a ]; 41 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) ); 42 | vertex.applyMatrix4(this.matrix); 43 | polygon.vertices.push( vertex ); 44 | 45 | vertex = geometry.vertices[ face.b ]; 46 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) ); 47 | vertex.applyMatrix4(this.matrix); 48 | polygon.vertices.push( vertex ); 49 | 50 | vertex = geometry.vertices[ face.c ]; 51 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) ); 52 | vertex.applyMatrix4(this.matrix); 53 | polygon.vertices.push( vertex ); 54 | } else if ( typeof THREE.Face4 ) { 55 | vertex = geometry.vertices[ face.a ]; 56 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[0], new THREE.Vector2( faceVertexUvs[0].x, faceVertexUvs[0].y ) ); 57 | vertex.applyMatrix4(this.matrix); 58 | polygon.vertices.push( vertex ); 59 | 60 | vertex = geometry.vertices[ face.b ]; 61 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1], new THREE.Vector2( faceVertexUvs[1].x, faceVertexUvs[1].y ) ); 62 | vertex.applyMatrix4(this.matrix); 63 | polygon.vertices.push( vertex ); 64 | 65 | vertex = geometry.vertices[ face.c ]; 66 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[2], new THREE.Vector2( faceVertexUvs[2].x, faceVertexUvs[2].y ) ); 67 | vertex.applyMatrix4(this.matrix); 68 | polygon.vertices.push( vertex ); 69 | 70 | vertex = geometry.vertices[ face.d ]; 71 | vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[3], new THREE.Vector2( faceVertexUvs[3].x, faceVertexUvs[3].y ) ); 72 | vertex.applyMatrix4(this.matrix); 73 | polygon.vertices.push( vertex ); 74 | } else { 75 | throw 'Invalid face type at index ' + i; 76 | } 77 | 78 | polygon.calculateProperties(); 79 | polygons.push( polygon ); 80 | }; 81 | 82 | this.tree = new ThreeBSP.Node( polygons ); 83 | }; 84 | ThreeBSP.prototype.subtract = function( other_tree ) { 85 | var a = this.tree.clone(), 86 | b = other_tree.tree.clone(); 87 | 88 | a.invert(); 89 | a.clipTo( b ); 90 | b.clipTo( a ); 91 | b.invert(); 92 | b.clipTo( a ); 93 | b.invert(); 94 | a.build( b.allPolygons() ); 95 | a.invert(); 96 | a = new ThreeBSP( a ); 97 | a.matrix = this.matrix; 98 | return a; 99 | }; 100 | ThreeBSP.prototype.union = function( other_tree ) { 101 | var a = this.tree.clone(), 102 | b = other_tree.tree.clone(); 103 | 104 | a.clipTo( b ); 105 | b.clipTo( a ); 106 | b.invert(); 107 | b.clipTo( a ); 108 | b.invert(); 109 | a.build( b.allPolygons() ); 110 | a = new ThreeBSP( a ); 111 | a.matrix = this.matrix; 112 | return a; 113 | }; 114 | ThreeBSP.prototype.intersect = function( other_tree ) { 115 | var a = this.tree.clone(), 116 | b = other_tree.tree.clone(); 117 | 118 | a.invert(); 119 | b.clipTo( a ); 120 | b.invert(); 121 | a.clipTo( b ); 122 | b.clipTo( a ); 123 | a.build( b.allPolygons() ); 124 | a.invert(); 125 | a = new ThreeBSP( a ); 126 | a.matrix = this.matrix; 127 | return a; 128 | }; 129 | ThreeBSP.prototype.toGeometry = function() { 130 | var i, j, 131 | matrix = new THREE.Matrix4().getInverse( this.matrix ), 132 | geometry = new THREE.Geometry(), 133 | polygons = this.tree.allPolygons(), 134 | polygon_count = polygons.length, 135 | polygon, polygon_vertice_count, 136 | vertice_dict = {}, 137 | vertex_idx_a, vertex_idx_b, vertex_idx_c, 138 | vertex, face, 139 | verticeUvs; 140 | 141 | for ( i = 0; i < polygon_count; i++ ) { 142 | polygon = polygons[i]; 143 | polygon_vertice_count = polygon.vertices.length; 144 | 145 | for ( j = 2; j < polygon_vertice_count; j++ ) { 146 | verticeUvs = []; 147 | 148 | vertex = polygon.vertices[0]; 149 | verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); 150 | vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); 151 | vertex.applyMatrix4(matrix); 152 | 153 | if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { 154 | vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; 155 | } else { 156 | geometry.vertices.push( vertex ); 157 | vertex_idx_a = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; 158 | } 159 | 160 | vertex = polygon.vertices[j-1]; 161 | verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); 162 | vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); 163 | vertex.applyMatrix4(matrix); 164 | if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { 165 | vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; 166 | } else { 167 | geometry.vertices.push( vertex ); 168 | vertex_idx_b = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; 169 | } 170 | 171 | vertex = polygon.vertices[j]; 172 | verticeUvs.push( new THREE.Vector2( vertex.uv.x, vertex.uv.y ) ); 173 | vertex = new THREE.Vector3( vertex.x, vertex.y, vertex.z ); 174 | vertex.applyMatrix4(matrix); 175 | if ( typeof vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] !== 'undefined' ) { 176 | vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ]; 177 | } else { 178 | geometry.vertices.push( vertex ); 179 | vertex_idx_c = vertice_dict[ vertex.x + ',' + vertex.y + ',' + vertex.z ] = geometry.vertices.length - 1; 180 | } 181 | 182 | face = new THREE.Face3( 183 | vertex_idx_a, 184 | vertex_idx_b, 185 | vertex_idx_c, 186 | new THREE.Vector3( polygon.normal.x, polygon.normal.y, polygon.normal.z ) 187 | ); 188 | 189 | geometry.faces.push( face ); 190 | geometry.faceVertexUvs[0].push( verticeUvs ); 191 | } 192 | 193 | } 194 | return geometry; 195 | }; 196 | ThreeBSP.prototype.toMesh = function( material ) { 197 | var geometry = this.toGeometry(), 198 | mesh = new THREE.Mesh( geometry, material ); 199 | 200 | mesh.position.getPositionFromMatrix( this.matrix ); 201 | mesh.rotation.setFromRotationMatrix( this.matrix ); 202 | 203 | return mesh; 204 | }; 205 | 206 | 207 | ThreeBSP.Polygon = function( vertices, normal, w ) { 208 | if ( !( vertices instanceof Array ) ) { 209 | vertices = []; 210 | } 211 | 212 | this.vertices = vertices; 213 | if ( vertices.length > 0 ) { 214 | this.calculateProperties(); 215 | } else { 216 | this.normal = this.w = undefined; 217 | } 218 | }; 219 | ThreeBSP.Polygon.prototype.calculateProperties = function() { 220 | var a = this.vertices[0], 221 | b = this.vertices[1], 222 | c = this.vertices[2]; 223 | 224 | this.normal = b.clone().subtract( a ).cross( 225 | c.clone().subtract( a ) 226 | ).normalize(); 227 | 228 | this.w = this.normal.clone().dot( a ); 229 | 230 | return this; 231 | }; 232 | ThreeBSP.Polygon.prototype.clone = function() { 233 | var i, vertice_count, 234 | polygon = new ThreeBSP.Polygon; 235 | 236 | for ( i = 0, vertice_count = this.vertices.length; i < vertice_count; i++ ) { 237 | polygon.vertices.push( this.vertices[i].clone() ); 238 | }; 239 | polygon.calculateProperties(); 240 | 241 | return polygon; 242 | }; 243 | 244 | ThreeBSP.Polygon.prototype.flip = function() { 245 | var i, vertices = []; 246 | 247 | this.normal.multiplyScalar( -1 ); 248 | this.w *= -1; 249 | 250 | for ( i = this.vertices.length - 1; i >= 0; i-- ) { 251 | vertices.push( this.vertices[i] ); 252 | }; 253 | this.vertices = vertices; 254 | 255 | return this; 256 | }; 257 | ThreeBSP.Polygon.prototype.classifyVertex = function( vertex ) { 258 | var side_value = this.normal.dot( vertex ) - this.w; 259 | 260 | if ( side_value < -EPSILON ) { 261 | return BACK; 262 | } else if ( side_value > EPSILON ) { 263 | return FRONT; 264 | } else { 265 | return COPLANAR; 266 | } 267 | }; 268 | ThreeBSP.Polygon.prototype.classifySide = function( polygon ) { 269 | var i, vertex, classification, 270 | num_positive = 0, 271 | num_negative = 0, 272 | vertice_count = polygon.vertices.length; 273 | 274 | for ( i = 0; i < vertice_count; i++ ) { 275 | vertex = polygon.vertices[i]; 276 | classification = this.classifyVertex( vertex ); 277 | if ( classification === FRONT ) { 278 | num_positive++; 279 | } else if ( classification === BACK ) { 280 | num_negative++; 281 | } 282 | } 283 | 284 | if ( num_positive > 0 && num_negative === 0 ) { 285 | return FRONT; 286 | } else if ( num_positive === 0 && num_negative > 0 ) { 287 | return BACK; 288 | } else if ( num_positive === 0 && num_negative === 0 ) { 289 | return COPLANAR; 290 | } else { 291 | return SPANNING; 292 | } 293 | }; 294 | ThreeBSP.Polygon.prototype.splitPolygon = function( polygon, coplanar_front, coplanar_back, front, back ) { 295 | var classification = this.classifySide( polygon ); 296 | 297 | if ( classification === COPLANAR ) { 298 | 299 | ( this.normal.dot( polygon.normal ) > 0 ? coplanar_front : coplanar_back ).push( polygon ); 300 | 301 | } else if ( classification === FRONT ) { 302 | 303 | front.push( polygon ); 304 | 305 | } else if ( classification === BACK ) { 306 | 307 | back.push( polygon ); 308 | 309 | } else { 310 | 311 | var vertice_count, 312 | i, j, ti, tj, vi, vj, 313 | t, v, 314 | f = [], 315 | b = []; 316 | 317 | for ( i = 0, vertice_count = polygon.vertices.length; i < vertice_count; i++ ) { 318 | 319 | j = (i + 1) % vertice_count; 320 | vi = polygon.vertices[i]; 321 | vj = polygon.vertices[j]; 322 | ti = this.classifyVertex( vi ); 323 | tj = this.classifyVertex( vj ); 324 | 325 | if ( ti != BACK ) f.push( vi ); 326 | if ( ti != FRONT ) b.push( vi ); 327 | if ( (ti | tj) === SPANNING ) { 328 | t = ( this.w - this.normal.dot( vi ) ) / this.normal.dot( vj.clone().subtract( vi ) ); 329 | v = vi.interpolate( vj, t ); 330 | f.push( v ); 331 | b.push( v ); 332 | } 333 | } 334 | 335 | 336 | if ( f.length >= 3 ) front.push( new ThreeBSP.Polygon( f ).calculateProperties() ); 337 | if ( b.length >= 3 ) back.push( new ThreeBSP.Polygon( b ).calculateProperties() ); 338 | } 339 | }; 340 | 341 | ThreeBSP.Vertex = function( x, y, z, normal, uv ) { 342 | this.x = x; 343 | this.y = y; 344 | this.z = z; 345 | this.normal = normal || new THREE.Vector3; 346 | this.uv = uv || new THREE.Vector2; 347 | }; 348 | ThreeBSP.Vertex.prototype.clone = function() { 349 | return new ThreeBSP.Vertex( this.x, this.y, this.z, this.normal.clone(), this.uv.clone() ); 350 | }; 351 | ThreeBSP.Vertex.prototype.add = function( vertex ) { 352 | this.x += vertex.x; 353 | this.y += vertex.y; 354 | this.z += vertex.z; 355 | return this; 356 | }; 357 | ThreeBSP.Vertex.prototype.subtract = function( vertex ) { 358 | this.x -= vertex.x; 359 | this.y -= vertex.y; 360 | this.z -= vertex.z; 361 | return this; 362 | }; 363 | ThreeBSP.Vertex.prototype.multiplyScalar = function( scalar ) { 364 | this.x *= scalar; 365 | this.y *= scalar; 366 | this.z *= scalar; 367 | return this; 368 | }; 369 | ThreeBSP.Vertex.prototype.cross = function( vertex ) { 370 | var x = this.x, 371 | y = this.y, 372 | z = this.z; 373 | 374 | this.x = y * vertex.z - z * vertex.y; 375 | this.y = z * vertex.x - x * vertex.z; 376 | this.z = x * vertex.y - y * vertex.x; 377 | 378 | return this; 379 | }; 380 | ThreeBSP.Vertex.prototype.normalize = function() { 381 | var length = Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); 382 | 383 | this.x /= length; 384 | this.y /= length; 385 | this.z /= length; 386 | 387 | return this; 388 | }; 389 | ThreeBSP.Vertex.prototype.dot = function( vertex ) { 390 | return this.x * vertex.x + this.y * vertex.y + this.z * vertex.z; 391 | }; 392 | ThreeBSP.Vertex.prototype.lerp = function( a, t ) { 393 | this.add( 394 | a.clone().subtract( this ).multiplyScalar( t ) 395 | ); 396 | 397 | this.normal.add( 398 | a.normal.clone().sub( this.normal ).multiplyScalar( t ) 399 | ); 400 | 401 | this.uv.add( 402 | a.uv.clone().sub( this.uv ).multiplyScalar( t ) 403 | ); 404 | 405 | return this; 406 | }; 407 | ThreeBSP.Vertex.prototype.interpolate = function( other, t ) { 408 | return this.clone().lerp( other, t ); 409 | }; 410 | ThreeBSP.Vertex.prototype.applyMatrix4 = function ( m ) { 411 | 412 | // input: THREE.Matrix4 affine matrix 413 | 414 | var x = this.x, y = this.y, z = this.z; 415 | 416 | var e = m.elements; 417 | 418 | this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; 419 | this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; 420 | this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; 421 | 422 | return this; 423 | 424 | } 425 | 426 | 427 | ThreeBSP.Node = function( polygons ) { 428 | var i, polygon_count, 429 | front = [], 430 | back = []; 431 | 432 | this.polygons = []; 433 | this.front = this.back = undefined; 434 | 435 | if ( !(polygons instanceof Array) || polygons.length === 0 ) return; 436 | 437 | this.divider = polygons[0].clone(); 438 | 439 | for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { 440 | this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); 441 | } 442 | 443 | if ( front.length > 0 ) { 444 | this.front = new ThreeBSP.Node( front ); 445 | } 446 | 447 | if ( back.length > 0 ) { 448 | this.back = new ThreeBSP.Node( back ); 449 | } 450 | }; 451 | ThreeBSP.Node.isConvex = function( polygons ) { 452 | var i, j; 453 | for ( i = 0; i < polygons.length; i++ ) { 454 | for ( j = 0; j < polygons.length; j++ ) { 455 | if ( i !== j && polygons[i].classifySide( polygons[j] ) !== BACK ) { 456 | return false; 457 | } 458 | } 459 | } 460 | return true; 461 | }; 462 | ThreeBSP.Node.prototype.build = function( polygons ) { 463 | var i, polygon_count, 464 | front = [], 465 | back = []; 466 | 467 | if ( !this.divider ) { 468 | this.divider = polygons[0].clone(); 469 | } 470 | 471 | for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { 472 | this.divider.splitPolygon( polygons[i], this.polygons, this.polygons, front, back ); 473 | } 474 | 475 | if ( front.length > 0 ) { 476 | if ( !this.front ) this.front = new ThreeBSP.Node(); 477 | this.front.build( front ); 478 | } 479 | 480 | if ( back.length > 0 ) { 481 | if ( !this.back ) this.back = new ThreeBSP.Node(); 482 | this.back.build( back ); 483 | } 484 | }; 485 | ThreeBSP.Node.prototype.allPolygons = function() { 486 | var polygons = this.polygons.slice(); 487 | if ( this.front ) polygons = polygons.concat( this.front.allPolygons() ); 488 | if ( this.back ) polygons = polygons.concat( this.back.allPolygons() ); 489 | return polygons; 490 | }; 491 | ThreeBSP.Node.prototype.clone = function() { 492 | var node = new ThreeBSP.Node(); 493 | 494 | node.divider = this.divider.clone(); 495 | node.polygons = this.polygons.map( function( polygon ) { return polygon.clone(); } ); 496 | node.front = this.front && this.front.clone(); 497 | node.back = this.back && this.back.clone(); 498 | 499 | return node; 500 | }; 501 | ThreeBSP.Node.prototype.invert = function() { 502 | var i, polygon_count, temp; 503 | 504 | for ( i = 0, polygon_count = this.polygons.length; i < polygon_count; i++ ) { 505 | this.polygons[i].flip(); 506 | } 507 | 508 | this.divider.flip(); 509 | if ( this.front ) this.front.invert(); 510 | if ( this.back ) this.back.invert(); 511 | 512 | temp = this.front; 513 | this.front = this.back; 514 | this.back = temp; 515 | 516 | return this; 517 | }; 518 | ThreeBSP.Node.prototype.clipPolygons = function( polygons ) { 519 | var i, polygon_count, 520 | front, back; 521 | 522 | if ( !this.divider ) return polygons.slice(); 523 | 524 | front = [], back = []; 525 | 526 | for ( i = 0, polygon_count = polygons.length; i < polygon_count; i++ ) { 527 | this.divider.splitPolygon( polygons[i], front, back, front, back ); 528 | } 529 | 530 | if ( this.front ) front = this.front.clipPolygons( front ); 531 | if ( this.back ) back = this.back.clipPolygons( back ); 532 | else back = []; 533 | 534 | return front.concat( back ); 535 | }; 536 | 537 | ThreeBSP.Node.prototype.clipTo = function( node ) { 538 | this.polygons = node.clipPolygons( this.polygons ); 539 | if ( this.front ) this.front.clipTo( node ); 540 | if ( this.back ) this.back.clipTo( node ); 541 | }; 542 | 543 | 544 | return ThreeBSP; 545 | })(); -------------------------------------------------------------------------------- /scripts/lib/threejs/effects/AnaglyphEffect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author mrdoob / http://mrdoob.com/ 3 | * @author marklundin / http://mark-lundin.com/ 4 | * @author alteredq / http://alteredqualia.com/ 5 | */ 6 | 7 | THREE.AnaglyphEffect = function ( renderer, width, height ) { 8 | 9 | var eyeRight = new THREE.Matrix4(); 10 | var eyeLeft = new THREE.Matrix4(); 11 | var focalLength = 125; 12 | var _aspect, _near, _far, _fov; 13 | 14 | var _cameraL = new THREE.PerspectiveCamera(); 15 | _cameraL.matrixAutoUpdate = false; 16 | 17 | var _cameraR = new THREE.PerspectiveCamera(); 18 | _cameraR.matrixAutoUpdate = false; 19 | 20 | var _camera = new THREE.OrthographicCamera( -1, 1, 1, - 1, 0, 1 ); 21 | 22 | var _scene = new THREE.Scene(); 23 | 24 | var _params = { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat }; 25 | 26 | if ( width === undefined ) width = 512; 27 | if ( height === undefined ) height = 512; 28 | 29 | var _renderTargetL = new THREE.WebGLRenderTarget( width, height, _params ); 30 | var _renderTargetR = new THREE.WebGLRenderTarget( width, height, _params ); 31 | 32 | var _material = new THREE.ShaderMaterial( { 33 | 34 | uniforms: { 35 | 36 | "mapLeft": { type: "t", value: _renderTargetL }, 37 | "mapRight": { type: "t", value: _renderTargetR } 38 | 39 | }, 40 | 41 | vertexShader: [ 42 | 43 | "varying vec2 vUv;", 44 | 45 | "void main() {", 46 | 47 | " vUv = vec2( uv.x, uv.y );", 48 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 49 | 50 | "}" 51 | 52 | ].join("\n"), 53 | 54 | fragmentShader: [ 55 | 56 | "uniform sampler2D mapLeft;", 57 | "uniform sampler2D mapRight;", 58 | "varying vec2 vUv;", 59 | 60 | "void main() {", 61 | 62 | " vec4 colorL, colorR;", 63 | " vec2 uv = vUv;", 64 | 65 | " colorL = texture2D( mapLeft, uv );", 66 | " colorR = texture2D( mapRight, uv );", 67 | 68 | // http://3dtv.at/Knowhow/AnaglyphComparison_en.aspx 69 | 70 | " gl_FragColor = vec4( colorL.g * 0.7 + colorL.b * 0.3, colorR.g, colorR.b, colorL.a + colorR.a ) * 1.1;", 71 | 72 | "}" 73 | 74 | ].join("\n") 75 | 76 | } ); 77 | 78 | var mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), _material ); 79 | _scene.add( mesh ); 80 | 81 | this.setSize = function ( width, height ) { 82 | 83 | if ( _renderTargetL ) _renderTargetL.dispose(); 84 | if ( _renderTargetR ) _renderTargetR.dispose(); 85 | _renderTargetL = new THREE.WebGLRenderTarget( width, height, _params ); 86 | _renderTargetR = new THREE.WebGLRenderTarget( width, height, _params ); 87 | 88 | _material.uniforms[ "mapLeft" ].value = _renderTargetL; 89 | _material.uniforms[ "mapRight" ].value = _renderTargetR; 90 | 91 | renderer.setSize( width, height ); 92 | 93 | }; 94 | 95 | /* 96 | * Renderer now uses an asymmetric perspective projection 97 | * (http://paulbourke.net/miscellaneous/stereographics/stereorender/). 98 | * 99 | * Each camera is offset by the eye seperation and its projection matrix is 100 | * also skewed asymetrically back to converge on the same projection plane. 101 | * Added a focal length parameter to, this is where the parallax is equal to 0. 102 | */ 103 | 104 | this.render = function ( scene, camera ) { 105 | 106 | scene.updateMatrixWorld(); 107 | 108 | if ( camera.parent === undefined ) camera.updateMatrixWorld(); 109 | 110 | var hasCameraChanged = ( _aspect !== camera.aspect ) || ( _near !== camera.near ) || ( _far !== camera.far ) || ( _fov !== camera.fov ); 111 | 112 | if ( hasCameraChanged ) { 113 | 114 | _aspect = camera.aspect; 115 | _near = camera.near; 116 | _far = camera.far; 117 | _fov = camera.fov; 118 | 119 | var projectionMatrix = camera.projectionMatrix.clone(); 120 | var eyeSep = focalLength / 30 * 0.5; 121 | var eyeSepOnProjection = eyeSep * _near / focalLength; 122 | var ymax = _near * Math.tan( THREE.Math.degToRad( _fov * 0.5 ) ); 123 | var xmin, xmax; 124 | 125 | // translate xOffset 126 | 127 | eyeRight.elements[12] = eyeSep; 128 | eyeLeft.elements[12] = -eyeSep; 129 | 130 | // for left eye 131 | 132 | xmin = -ymax * _aspect + eyeSepOnProjection; 133 | xmax = ymax * _aspect + eyeSepOnProjection; 134 | 135 | projectionMatrix.elements[0] = 2 * _near / ( xmax - xmin ); 136 | projectionMatrix.elements[8] = ( xmax + xmin ) / ( xmax - xmin ); 137 | 138 | _cameraL.projectionMatrix.copy( projectionMatrix ); 139 | 140 | // for right eye 141 | 142 | xmin = -ymax * _aspect - eyeSepOnProjection; 143 | xmax = ymax * _aspect - eyeSepOnProjection; 144 | 145 | projectionMatrix.elements[0] = 2 * _near / ( xmax - xmin ); 146 | projectionMatrix.elements[8] = ( xmax + xmin ) / ( xmax - xmin ); 147 | 148 | _cameraR.projectionMatrix.copy( projectionMatrix ); 149 | 150 | } 151 | 152 | _cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); 153 | _cameraL.position.copy( camera.position ); 154 | _cameraL.near = camera.near; 155 | _cameraL.far = camera.far; 156 | 157 | renderer.render( scene, _cameraL, _renderTargetL, true ); 158 | 159 | _cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); 160 | _cameraR.position.copy( camera.position ); 161 | _cameraR.near = camera.near; 162 | _cameraR.far = camera.far; 163 | 164 | renderer.render( scene, _cameraR, _renderTargetR, true ); 165 | 166 | renderer.render( _scene, _camera ); 167 | 168 | }; 169 | 170 | this.dispose = function() { 171 | if ( _renderTargetL ) _renderTargetL.dispose(); 172 | if ( _renderTargetR ) _renderTargetR.dispose(); 173 | } 174 | 175 | }; 176 | -------------------------------------------------------------------------------- /scripts/lib/threejs/plugins/DepthPassPlugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.DepthPassPlugin = function () { 6 | 7 | this.enabled = false; 8 | this.renderTarget = null; 9 | 10 | var _gl, 11 | _renderer, 12 | _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, 13 | 14 | _frustum = new THREE.Frustum(), 15 | _projScreenMatrix = new THREE.Matrix4(); 16 | 17 | this.init = function ( renderer ) { 18 | 19 | _gl = renderer.context; 20 | _renderer = renderer; 21 | 22 | var depthShader = THREE.ShaderLib[ "depthRGBA" ]; 23 | var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); 24 | 25 | _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); 26 | _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); 27 | _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); 28 | _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); 29 | 30 | _depthMaterial._shadowPass = true; 31 | _depthMaterialMorph._shadowPass = true; 32 | _depthMaterialSkin._shadowPass = true; 33 | _depthMaterialMorphSkin._shadowPass = true; 34 | 35 | }; 36 | 37 | this.render = function ( scene, camera ) { 38 | 39 | if ( ! this.enabled ) return; 40 | 41 | this.update( scene, camera ); 42 | 43 | }; 44 | 45 | this.update = function ( scene, camera ) { 46 | 47 | var i, il, j, jl, n, 48 | 49 | program, buffer, material, 50 | webglObject, object, light, 51 | renderList, 52 | 53 | fog = null; 54 | 55 | // set GL state for depth map 56 | 57 | _gl.clearColor( 1, 1, 1, 1 ); 58 | _gl.disable( _gl.BLEND ); 59 | 60 | _renderer.setDepthTest( true ); 61 | 62 | // update scene 63 | 64 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); 65 | 66 | // update camera matrices and frustum 67 | 68 | camera.matrixWorldInverse.getInverse( camera.matrixWorld ); 69 | 70 | _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 71 | _frustum.setFromMatrix( _projScreenMatrix ); 72 | 73 | // render depth map 74 | 75 | _renderer.setRenderTarget( this.renderTarget ); 76 | _renderer.clear(); 77 | 78 | // set object matrices & frustum culling 79 | 80 | renderList = scene.__webglObjects; 81 | 82 | for ( j = 0, jl = renderList.length; j < jl; j ++ ) { 83 | 84 | webglObject = renderList[ j ]; 85 | object = webglObject.object; 86 | 87 | webglObject.render = false; 88 | 89 | if ( object.visible ) { 90 | 91 | if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { 92 | 93 | object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); 94 | 95 | webglObject.render = true; 96 | 97 | } 98 | 99 | } 100 | 101 | } 102 | 103 | // render regular objects 104 | 105 | var objectMaterial, useMorphing, useSkinning; 106 | 107 | for ( j = 0, jl = renderList.length; j < jl; j ++ ) { 108 | 109 | webglObject = renderList[ j ]; 110 | 111 | if ( webglObject.render ) { 112 | 113 | object = webglObject.object; 114 | buffer = webglObject.buffer; 115 | 116 | // todo: create proper depth material for particles 117 | 118 | if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; 119 | 120 | objectMaterial = getObjectMaterial( object ); 121 | 122 | if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); 123 | 124 | useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; 125 | useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; 126 | 127 | if ( object.customDepthMaterial ) { 128 | 129 | material = object.customDepthMaterial; 130 | 131 | } else if ( useSkinning ) { 132 | 133 | material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; 134 | 135 | } else if ( useMorphing ) { 136 | 137 | material = _depthMaterialMorph; 138 | 139 | } else { 140 | 141 | material = _depthMaterial; 142 | 143 | } 144 | 145 | if ( buffer instanceof THREE.BufferGeometry ) { 146 | 147 | _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); 148 | 149 | } else { 150 | 151 | _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); 152 | 153 | } 154 | 155 | } 156 | 157 | } 158 | 159 | // set matrices and render immediate objects 160 | 161 | renderList = scene.__webglObjectsImmediate; 162 | 163 | for ( j = 0, jl = renderList.length; j < jl; j ++ ) { 164 | 165 | webglObject = renderList[ j ]; 166 | object = webglObject.object; 167 | 168 | if ( object.visible ) { 169 | 170 | object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); 171 | 172 | _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); 173 | 174 | } 175 | 176 | } 177 | 178 | // restore GL state 179 | 180 | var clearColor = _renderer.getClearColor(), 181 | clearAlpha = _renderer.getClearAlpha(); 182 | 183 | _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); 184 | _gl.enable( _gl.BLEND ); 185 | 186 | }; 187 | 188 | // For the moment just ignore objects that have multiple materials with different animation methods 189 | // Only the first material will be taken into account for deciding which depth material to use 190 | 191 | function getObjectMaterial( object ) { 192 | 193 | return object.material instanceof THREE.MeshFaceMaterial 194 | ? object.material.materials[ 0 ] 195 | : object.material; 196 | 197 | }; 198 | 199 | }; 200 | 201 | -------------------------------------------------------------------------------- /scripts/lib/threejs/plugins/stats.js: -------------------------------------------------------------------------------- 1 | // stats.js - http://github.com/mrdoob/stats.js 2 | var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px"; 3 | i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); 4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= 5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:11,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= 6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}}; 7 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/BokehPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Depth-of-field post-process with bokeh shader 3 | */ 4 | 5 | 6 | THREE.BokehPass = function ( scene, camera, params ) { 7 | 8 | this.scene = scene; 9 | this.camera = camera; 10 | 11 | var focus = ( params.focus !== undefined ) ? params.focus : 1.0; 12 | var aspect = ( params.aspect !== undefined ) ? params.aspect : camera.aspect; 13 | var aperture = ( params.aperture !== undefined ) ? params.aperture : 0.025; 14 | var maxblur = ( params.maxblur !== undefined ) ? params.maxblur : 1.0; 15 | 16 | // render targets 17 | 18 | var width = params.width || window.innerWidth || 1; 19 | var height = params.height || window.innerHeight || 1; 20 | 21 | this.renderTargetColor = new THREE.WebGLRenderTarget( width, height, { 22 | minFilter: THREE.LinearFilter, 23 | magFilter: THREE.LinearFilter, 24 | format: THREE.RGBFormat 25 | } ); 26 | 27 | this.renderTargetDepth = this.renderTargetColor.clone(); 28 | 29 | // depth material 30 | 31 | this.materialDepth = new THREE.MeshDepthMaterial(); 32 | 33 | // bokeh material 34 | 35 | if ( THREE.BokehShader === undefined ) { 36 | console.error( "THREE.BokehPass relies on THREE.BokehShader" ); 37 | } 38 | 39 | var bokehShader = THREE.BokehShader; 40 | var bokehUniforms = THREE.UniformsUtils.clone( bokehShader.uniforms ); 41 | 42 | bokehUniforms[ "tDepth" ].value = this.renderTargetDepth; 43 | 44 | bokehUniforms[ "focus" ].value = focus; 45 | bokehUniforms[ "aspect" ].value = aspect; 46 | bokehUniforms[ "aperture" ].value = aperture; 47 | bokehUniforms[ "maxblur" ].value = maxblur; 48 | 49 | this.materialBokeh = new THREE.ShaderMaterial({ 50 | uniforms: bokehUniforms, 51 | vertexShader: bokehShader.vertexShader, 52 | fragmentShader: bokehShader.fragmentShader 53 | }); 54 | 55 | this.uniforms = bokehUniforms; 56 | this.enabled = true; 57 | this.needsSwap = false; 58 | this.renderToScreen = false; 59 | this.clear = false; 60 | 61 | }; 62 | 63 | THREE.BokehPass.prototype = { 64 | 65 | render: function ( renderer, writeBuffer, readBuffer, delta, maskActive ) { 66 | 67 | var composer = THREE.EffectComposer; 68 | 69 | composer.quad.material = this.materialBokeh; 70 | 71 | // Render depth into texture 72 | 73 | this.scene.overrideMaterial = this.materialDepth; 74 | 75 | renderer.render( this.scene, this.camera, this.renderTargetDepth, true ); 76 | 77 | // Render bokeh composite 78 | 79 | this.uniforms[ "tColor" ].value = readBuffer; 80 | 81 | if ( this.renderToScreen ) { 82 | 83 | renderer.render( composer.scene, composer.camera ); 84 | 85 | } else { 86 | 87 | renderer.render( composer.scene, composer.camera, writeBuffer, this.clear ); 88 | 89 | } 90 | 91 | this.scene.overrideMaterial = null; 92 | 93 | } 94 | 95 | }; 96 | 97 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/EffectComposer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.EffectComposer = function ( renderer, renderTarget ) { 6 | 7 | this.renderer = renderer; 8 | 9 | if ( renderTarget === undefined ) { 10 | 11 | var width = window.innerWidth || 1; 12 | var height = window.innerHeight || 1; 13 | var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; 14 | 15 | renderTarget = new THREE.WebGLRenderTarget( width, height, parameters ); 16 | 17 | } 18 | 19 | this.renderTarget1 = renderTarget; 20 | this.renderTarget2 = renderTarget.clone(); 21 | 22 | this.writeBuffer = this.renderTarget1; 23 | this.readBuffer = this.renderTarget2; 24 | 25 | this.passes = []; 26 | 27 | if ( THREE.CopyShader === undefined ) 28 | console.error( "THREE.EffectComposer relies on THREE.CopyShader" ); 29 | 30 | this.copyPass = new THREE.ShaderPass( THREE.CopyShader ); 31 | 32 | }; 33 | 34 | THREE.EffectComposer.prototype = { 35 | 36 | swapBuffers: function() { 37 | 38 | var tmp = this.readBuffer; 39 | this.readBuffer = this.writeBuffer; 40 | this.writeBuffer = tmp; 41 | 42 | }, 43 | 44 | addPass: function ( pass ) { 45 | 46 | this.passes.push( pass ); 47 | 48 | }, 49 | 50 | insertPass: function ( pass, index ) { 51 | 52 | this.passes.splice( index, 0, pass ); 53 | 54 | }, 55 | 56 | render: function ( delta ) { 57 | 58 | this.writeBuffer = this.renderTarget1; 59 | this.readBuffer = this.renderTarget2; 60 | 61 | var maskActive = false; 62 | 63 | var pass, i, il = this.passes.length; 64 | 65 | for ( i = 0; i < il; i ++ ) { 66 | 67 | pass = this.passes[ i ]; 68 | 69 | if ( !pass.enabled ) continue; 70 | 71 | pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive ); 72 | 73 | if ( pass.needsSwap ) { 74 | 75 | if ( maskActive ) { 76 | 77 | var context = this.renderer.context; 78 | 79 | context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff ); 80 | 81 | this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta ); 82 | 83 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); 84 | 85 | } 86 | 87 | this.swapBuffers(); 88 | 89 | } 90 | 91 | if ( pass instanceof THREE.MaskPass ) { 92 | 93 | maskActive = true; 94 | 95 | } else if ( pass instanceof THREE.ClearMaskPass ) { 96 | 97 | maskActive = false; 98 | 99 | } 100 | 101 | } 102 | 103 | }, 104 | 105 | reset: function ( renderTarget ) { 106 | 107 | if ( renderTarget === undefined ) { 108 | 109 | renderTarget = this.renderTarget1.clone(); 110 | 111 | renderTarget.width = window.innerWidth; 112 | renderTarget.height = window.innerHeight; 113 | 114 | } 115 | 116 | this.renderTarget1 = renderTarget; 117 | this.renderTarget2 = renderTarget.clone(); 118 | 119 | this.writeBuffer = this.renderTarget1; 120 | this.readBuffer = this.renderTarget2; 121 | 122 | }, 123 | 124 | setSize: function ( width, height ) { 125 | 126 | var renderTarget = this.renderTarget1.clone(); 127 | 128 | renderTarget.width = width; 129 | renderTarget.height = height; 130 | 131 | this.reset( renderTarget ); 132 | 133 | } 134 | 135 | }; 136 | 137 | // shared ortho camera 138 | 139 | THREE.EffectComposer.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 ); 140 | 141 | THREE.EffectComposer.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null ); 142 | 143 | THREE.EffectComposer.scene = new THREE.Scene(); 144 | THREE.EffectComposer.scene.add( THREE.EffectComposer.quad ); 145 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/MaskPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.MaskPass = function ( scene, camera ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.enabled = true; 11 | this.clear = true; 12 | this.needsSwap = false; 13 | 14 | this.inverse = false; 15 | 16 | }; 17 | 18 | THREE.MaskPass.prototype = { 19 | 20 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 21 | 22 | var context = renderer.context; 23 | 24 | // don't update color or depth 25 | 26 | context.colorMask( false, false, false, false ); 27 | context.depthMask( false ); 28 | 29 | // set up stencil 30 | 31 | var writeValue, clearValue; 32 | 33 | if ( this.inverse ) { 34 | 35 | writeValue = 0; 36 | clearValue = 1; 37 | 38 | } else { 39 | 40 | writeValue = 1; 41 | clearValue = 0; 42 | 43 | } 44 | 45 | context.enable( context.STENCIL_TEST ); 46 | context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE ); 47 | context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff ); 48 | context.clearStencil( clearValue ); 49 | 50 | // draw into the stencil buffer 51 | 52 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 53 | renderer.render( this.scene, this.camera, writeBuffer, this.clear ); 54 | 55 | // re-enable update of color and depth 56 | 57 | context.colorMask( true, true, true, true ); 58 | context.depthMask( true ); 59 | 60 | // only render where stencil is set to 1 61 | 62 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1 63 | context.stencilOp( context.KEEP, context.KEEP, context.KEEP ); 64 | 65 | } 66 | 67 | }; 68 | 69 | 70 | THREE.ClearMaskPass = function () { 71 | 72 | this.enabled = true; 73 | 74 | }; 75 | 76 | THREE.ClearMaskPass.prototype = { 77 | 78 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 79 | 80 | var context = renderer.context; 81 | 82 | context.disable( context.STENCIL_TEST ); 83 | 84 | } 85 | 86 | }; 87 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/RenderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) { 6 | 7 | this.scene = scene; 8 | this.camera = camera; 9 | 10 | this.overrideMaterial = overrideMaterial; 11 | 12 | this.clearColor = clearColor; 13 | this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1; 14 | 15 | this.oldClearColor = new THREE.Color(); 16 | this.oldClearAlpha = 1; 17 | 18 | this.enabled = true; 19 | this.clear = true; 20 | this.needsSwap = false; 21 | 22 | }; 23 | 24 | THREE.RenderPass.prototype = { 25 | 26 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 27 | 28 | this.scene.overrideMaterial = this.overrideMaterial; 29 | 30 | if ( this.clearColor ) { 31 | 32 | this.oldClearColor.copy( renderer.getClearColor() ); 33 | this.oldClearAlpha = renderer.getClearAlpha(); 34 | 35 | renderer.setClearColor( this.clearColor, this.clearAlpha ); 36 | 37 | } 38 | 39 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 40 | 41 | if ( this.clearColor ) { 42 | 43 | renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); 44 | 45 | } 46 | 47 | this.scene.overrideMaterial = null; 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/SavePass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.SavePass = function ( renderTarget ) { 6 | 7 | if ( THREE.CopyShader === undefined ) 8 | console.error( "THREE.SavePass relies on THREE.CopyShader" ); 9 | 10 | var shader = THREE.CopyShader; 11 | 12 | this.textureID = "tDiffuse"; 13 | 14 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 15 | 16 | this.material = new THREE.ShaderMaterial( { 17 | 18 | uniforms: this.uniforms, 19 | vertexShader: shader.vertexShader, 20 | fragmentShader: shader.fragmentShader 21 | 22 | } ); 23 | 24 | this.renderTarget = renderTarget; 25 | 26 | if ( this.renderTarget === undefined ) { 27 | 28 | this.renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false }; 29 | this.renderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, this.renderTargetParameters ); 30 | 31 | } 32 | 33 | this.enabled = true; 34 | this.needsSwap = false; 35 | this.clear = false; 36 | 37 | }; 38 | 39 | THREE.SavePass.prototype = { 40 | 41 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 42 | 43 | if ( this.uniforms[ this.textureID ] ) { 44 | 45 | this.uniforms[ this.textureID ].value = readBuffer; 46 | 47 | } 48 | 49 | THREE.EffectComposer.quad.material = this.material; 50 | 51 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, this.renderTarget, this.clear ); 52 | 53 | } 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /scripts/lib/threejs/postprocessing/ShaderPass.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | */ 4 | 5 | THREE.ShaderPass = function ( shader, textureID ) { 6 | 7 | this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; 8 | 9 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 10 | 11 | this.material = new THREE.ShaderMaterial( { 12 | 13 | uniforms: this.uniforms, 14 | vertexShader: shader.vertexShader, 15 | fragmentShader: shader.fragmentShader 16 | 17 | } ); 18 | 19 | this.renderToScreen = false; 20 | 21 | this.enabled = true; 22 | this.needsSwap = true; 23 | this.clear = false; 24 | 25 | }; 26 | 27 | THREE.ShaderPass.prototype = { 28 | 29 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 30 | 31 | if ( this.uniforms[ this.textureID ] ) { 32 | 33 | this.uniforms[ this.textureID ].value = readBuffer; 34 | 35 | } 36 | 37 | THREE.EffectComposer.quad.material = this.material; 38 | 39 | if ( this.renderToScreen ) { 40 | 41 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera ); 42 | 43 | } else { 44 | 45 | renderer.render( THREE.EffectComposer.scene, THREE.EffectComposer.camera, writeBuffer, this.clear ); 46 | 47 | } 48 | 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/BlendShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Blend two textures 5 | */ 6 | 7 | THREE.BlendShader = { 8 | 9 | uniforms: { 10 | 11 | "tDiffuse1": { type: "t", value: null }, 12 | "tDiffuse2": { type: "t", value: null }, 13 | "mixRatio": { type: "f", value: 0.5 }, 14 | "opacity": { type: "f", value: 1.0 } 15 | 16 | }, 17 | 18 | vertexShader: [ 19 | 20 | "varying vec2 vUv;", 21 | 22 | "void main() {", 23 | 24 | "vUv = uv;", 25 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 26 | 27 | "}" 28 | 29 | ].join("\n"), 30 | 31 | fragmentShader: [ 32 | 33 | "uniform float opacity;", 34 | "uniform float mixRatio;", 35 | 36 | "uniform sampler2D tDiffuse1;", 37 | "uniform sampler2D tDiffuse2;", 38 | 39 | "varying vec2 vUv;", 40 | 41 | "void main() {", 42 | 43 | "vec4 texel1 = texture2D( tDiffuse1, vUv );", 44 | "vec4 texel2 = texture2D( tDiffuse2, vUv );", 45 | "gl_FragColor = opacity * mix( texel1, texel2, mixRatio );", 46 | 47 | "}" 48 | 49 | ].join("\n") 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/BokehShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Depth-of-field shader with bokeh 5 | * ported from GLSL shader by Martins Upitis 6 | * http://artmartinsh.blogspot.com/2010/02/glsl-lens-blur-filter-with-bokeh.html 7 | */ 8 | 9 | THREE.BokehShader = { 10 | 11 | uniforms: { 12 | 13 | "tColor": { type: "t", value: null }, 14 | "tDepth": { type: "t", value: null }, 15 | "focus": { type: "f", value: 1.0 }, 16 | "aspect": { type: "f", value: 1.0 }, 17 | "aperture": { type: "f", value: 0.025 }, 18 | "maxblur": { type: "f", value: 1.0 } 19 | 20 | }, 21 | 22 | vertexShader: [ 23 | 24 | "varying vec2 vUv;", 25 | 26 | "void main() {", 27 | 28 | "vUv = uv;", 29 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 30 | 31 | "}" 32 | 33 | ].join("\n"), 34 | 35 | fragmentShader: [ 36 | 37 | "varying vec2 vUv;", 38 | 39 | "uniform sampler2D tColor;", 40 | "uniform sampler2D tDepth;", 41 | 42 | "uniform float maxblur;", // max blur amount 43 | "uniform float aperture;", // aperture - bigger values for shallower depth of field 44 | 45 | "uniform float focus;", 46 | "uniform float aspect;", 47 | 48 | "void main() {", 49 | 50 | "vec2 aspectcorrect = vec2( 1.0, aspect );", 51 | 52 | "vec4 depth1 = texture2D( tDepth, vUv );", 53 | 54 | "float factor = depth1.x - focus;", 55 | 56 | "vec2 dofblur = vec2 ( clamp( factor * aperture, -maxblur, maxblur ) );", 57 | 58 | "vec2 dofblur9 = dofblur * 0.9;", 59 | "vec2 dofblur7 = dofblur * 0.7;", 60 | "vec2 dofblur4 = dofblur * 0.4;", 61 | 62 | "vec4 col = vec4( 0.0 );", 63 | 64 | "col += texture2D( tColor, vUv.xy );", 65 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur );", 66 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.15, 0.37 ) * aspectcorrect ) * dofblur );", 67 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur );", 68 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.37, 0.15 ) * aspectcorrect ) * dofblur );", 69 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.40, 0.0 ) * aspectcorrect ) * dofblur );", 70 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.37, -0.15 ) * aspectcorrect ) * dofblur );", 71 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur );", 72 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur );", 73 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur );", 74 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.15, 0.37 ) * aspectcorrect ) * dofblur );", 75 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur );", 76 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.37, 0.15 ) * aspectcorrect ) * dofblur );", 77 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur );", 78 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur );", 79 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur );", 80 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.15, -0.37 ) * aspectcorrect ) * dofblur );", 81 | 82 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.15, 0.37 ) * aspectcorrect ) * dofblur9 );", 83 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.37, 0.15 ) * aspectcorrect ) * dofblur9 );", 84 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.37, -0.15 ) * aspectcorrect ) * dofblur9 );", 85 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.15, -0.37 ) * aspectcorrect ) * dofblur9 );", 86 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.15, 0.37 ) * aspectcorrect ) * dofblur9 );", 87 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.37, 0.15 ) * aspectcorrect ) * dofblur9 );", 88 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.37, -0.15 ) * aspectcorrect ) * dofblur9 );", 89 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.15, -0.37 ) * aspectcorrect ) * dofblur9 );", 90 | 91 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur7 );", 92 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.40, 0.0 ) * aspectcorrect ) * dofblur7 );", 93 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur7 );", 94 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur7 );", 95 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur7 );", 96 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur7 );", 97 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur7 );", 98 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur7 );", 99 | 100 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, 0.29 ) * aspectcorrect ) * dofblur4 );", 101 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.4, 0.0 ) * aspectcorrect ) * dofblur4 );", 102 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.29, -0.29 ) * aspectcorrect ) * dofblur4 );", 103 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, -0.4 ) * aspectcorrect ) * dofblur4 );", 104 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, 0.29 ) * aspectcorrect ) * dofblur4 );", 105 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.4, 0.0 ) * aspectcorrect ) * dofblur4 );", 106 | "col += texture2D( tColor, vUv.xy + ( vec2( -0.29, -0.29 ) * aspectcorrect ) * dofblur4 );", 107 | "col += texture2D( tColor, vUv.xy + ( vec2( 0.0, 0.4 ) * aspectcorrect ) * dofblur4 );", 108 | 109 | "gl_FragColor = col / 41.0;", 110 | "gl_FragColor.a = 1.0;", 111 | 112 | "}" 113 | 114 | ].join("\n") 115 | 116 | }; 117 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/ColorCorrectionShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Color correction 5 | */ 6 | 7 | THREE.ColorCorrectionShader = { 8 | 9 | uniforms: { 10 | 11 | "tDiffuse": { type: "t", value: null }, 12 | "powRGB": { type: "v3", value: new THREE.Vector3( 2, 2, 2 ) }, 13 | "mulRGB": { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } 14 | 15 | }, 16 | 17 | vertexShader: [ 18 | 19 | "varying vec2 vUv;", 20 | 21 | "void main() {", 22 | 23 | "vUv = uv;", 24 | 25 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 26 | 27 | "}" 28 | 29 | ].join("\n"), 30 | 31 | fragmentShader: [ 32 | 33 | "uniform sampler2D tDiffuse;", 34 | "uniform vec3 powRGB;", 35 | "uniform vec3 mulRGB;", 36 | 37 | "varying vec2 vUv;", 38 | 39 | "void main() {", 40 | 41 | "gl_FragColor = texture2D( tDiffuse, vUv );", 42 | "gl_FragColor.rgb = mulRGB * pow( gl_FragColor.rgb, powRGB );", 43 | 44 | "}" 45 | 46 | ].join("\n") 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/CopyShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Full-screen textured quad shader 5 | */ 6 | 7 | THREE.CopyShader = { 8 | 9 | uniforms: { 10 | 11 | "tDiffuse": { type: "t", value: null }, 12 | "opacity": { type: "f", value: 1.0 } 13 | 14 | }, 15 | 16 | vertexShader: [ 17 | 18 | "varying vec2 vUv;", 19 | 20 | "void main() {", 21 | 22 | "vUv = uv;", 23 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 24 | 25 | "}" 26 | 27 | ].join("\n"), 28 | 29 | fragmentShader: [ 30 | 31 | "uniform float opacity;", 32 | 33 | "uniform sampler2D tDiffuse;", 34 | 35 | "varying vec2 vUv;", 36 | 37 | "void main() {", 38 | 39 | "vec4 texel = texture2D( tDiffuse, vUv );", 40 | "gl_FragColor = opacity * texel;", 41 | 42 | "}" 43 | 44 | ].join("\n") 45 | 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/DotScreenShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Dot screen shader 5 | * based on glfx.js sepia shader 6 | * https://github.com/evanw/glfx.js 7 | */ 8 | 9 | THREE.DotScreenShader = { 10 | 11 | uniforms: { 12 | 13 | "tDiffuse": { type: "t", value: null }, 14 | "tSize": { type: "v2", value: new THREE.Vector2( 256, 256 ) }, 15 | "center": { type: "v2", value: new THREE.Vector2( 0.5, 0.5 ) }, 16 | "angle": { type: "f", value: 1.57 }, 17 | "scale": { type: "f", value: 1.0 } 18 | 19 | }, 20 | 21 | vertexShader: [ 22 | 23 | "varying vec2 vUv;", 24 | 25 | "void main() {", 26 | 27 | "vUv = uv;", 28 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 29 | 30 | "}" 31 | 32 | ].join("\n"), 33 | 34 | fragmentShader: [ 35 | 36 | "uniform vec2 center;", 37 | "uniform float angle;", 38 | "uniform float scale;", 39 | "uniform vec2 tSize;", 40 | 41 | "uniform sampler2D tDiffuse;", 42 | 43 | "varying vec2 vUv;", 44 | 45 | "float pattern() {", 46 | 47 | "float s = sin( angle ), c = cos( angle );", 48 | 49 | "vec2 tex = vUv * tSize - center;", 50 | "vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;", 51 | 52 | "return ( sin( point.x ) * sin( point.y ) ) * 4.0;", 53 | 54 | "}", 55 | 56 | "void main() {", 57 | 58 | "vec4 color = texture2D( tDiffuse, vUv );", 59 | 60 | "float average = ( color.r + color.g + color.b ) / 3.0;", 61 | 62 | "gl_FragColor = vec4( vec3( average * 10.0 - 5.0 + pattern() ), color.a );", 63 | 64 | "}" 65 | 66 | ].join("\n") 67 | 68 | }; 69 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/FXAAShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * @author davidedc / http://www.sketchpatch.net/ 4 | * 5 | * NVIDIA FXAA by Timothy Lottes 6 | * http://timothylottes.blogspot.com/2011/06/fxaa3-source-released.html 7 | * - WebGL port by @supereggbert 8 | * http://www.glge.org/demos/fxaa/ 9 | */ 10 | 11 | THREE.FXAAShader = { 12 | 13 | uniforms: { 14 | 15 | "tDiffuse": { type: "t", value: null }, 16 | "resolution": { type: "v2", value: new THREE.Vector2( 1 / 1024, 1 / 512 ) } 17 | 18 | }, 19 | 20 | vertexShader: [ 21 | 22 | "varying vec2 vUv;", 23 | 24 | "void main() {", 25 | 26 | "vUv = uv;", 27 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 28 | 29 | "}" 30 | 31 | ].join("\n"), 32 | 33 | fragmentShader: [ 34 | 35 | "uniform sampler2D tDiffuse;", 36 | "uniform vec2 resolution;", 37 | 38 | "varying vec2 vUv;", 39 | 40 | "#define FXAA_REDUCE_MIN (1.0/128.0)", 41 | "#define FXAA_REDUCE_MUL (1.0/8.0)", 42 | "#define FXAA_SPAN_MAX 8.0", 43 | 44 | "void main() {", 45 | 46 | "vec3 rgbNW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ).xyz;", 47 | "vec3 rgbNE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ).xyz;", 48 | "vec3 rgbSW = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ).xyz;", 49 | "vec3 rgbSE = texture2D( tDiffuse, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ).xyz;", 50 | "vec4 rgbaM = texture2D( tDiffuse, gl_FragCoord.xy * resolution );", 51 | "vec3 rgbM = rgbaM.xyz;", 52 | "float opacity = rgbaM.w;", 53 | 54 | "vec3 luma = vec3( 0.299, 0.587, 0.114 );", 55 | 56 | "float lumaNW = dot( rgbNW, luma );", 57 | "float lumaNE = dot( rgbNE, luma );", 58 | "float lumaSW = dot( rgbSW, luma );", 59 | "float lumaSE = dot( rgbSE, luma );", 60 | "float lumaM = dot( rgbM, luma );", 61 | "float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );", 62 | "float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );", 63 | 64 | "vec2 dir;", 65 | "dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));", 66 | "dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));", 67 | 68 | "float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );", 69 | 70 | "float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );", 71 | "dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),", 72 | "max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),", 73 | "dir * rcpDirMin)) * resolution;", 74 | 75 | "vec3 rgbA = texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ).xyz;", 76 | "rgbA += texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ).xyz;", 77 | "rgbA *= 0.5;", 78 | 79 | "vec3 rgbB = texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * -0.5 ).xyz;", 80 | "rgbB += texture2D( tDiffuse, gl_FragCoord.xy * resolution + dir * 0.5 ).xyz;", 81 | "rgbB *= 0.25;", 82 | "rgbB += rgbA * 0.5;", 83 | 84 | "float lumaB = dot( rgbB, luma );", 85 | 86 | "if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) {", 87 | 88 | "gl_FragColor = vec4( rgbA, opacity );", 89 | 90 | "} else {", 91 | 92 | "gl_FragColor = vec4( rgbB, opacity );", 93 | 94 | "}", 95 | 96 | "}" 97 | 98 | ].join("\n") 99 | 100 | }; 101 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/HorizontalTiltShiftShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Simple fake tilt-shift effect, modulating two pass Gaussian blur (see above) by vertical position 5 | * 6 | * - 9 samples per pass 7 | * - standard deviation 2.7 8 | * - "h" and "v" parameters should be set to "1 / width" and "1 / height" 9 | * - "r" parameter control where "focused" horizontal line lies 10 | */ 11 | 12 | THREE.HorizontalTiltShiftShader = { 13 | 14 | uniforms: { 15 | 16 | "tDiffuse": { type: "t", value: null }, 17 | "h": { type: "f", value: 1.0 / 512.0 }, 18 | "r": { type: "f", value: 0.35 } 19 | 20 | }, 21 | 22 | vertexShader: [ 23 | 24 | "varying vec2 vUv;", 25 | 26 | "void main() {", 27 | 28 | "vUv = uv;", 29 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 30 | 31 | "}" 32 | 33 | ].join("\n"), 34 | 35 | fragmentShader: [ 36 | 37 | "uniform sampler2D tDiffuse;", 38 | "uniform float h;", 39 | "uniform float r;", 40 | 41 | "varying vec2 vUv;", 42 | 43 | "void main() {", 44 | 45 | "vec4 sum = vec4( 0.0 );", 46 | 47 | "float hh = h * abs( r - vUv.y );", 48 | 49 | "sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * hh, vUv.y ) ) * 0.051;", 50 | "sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * hh, vUv.y ) ) * 0.0918;", 51 | "sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * hh, vUv.y ) ) * 0.12245;", 52 | "sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * hh, vUv.y ) ) * 0.1531;", 53 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;", 54 | "sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * hh, vUv.y ) ) * 0.1531;", 55 | "sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * hh, vUv.y ) ) * 0.12245;", 56 | "sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * hh, vUv.y ) ) * 0.0918;", 57 | "sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * hh, vUv.y ) ) * 0.051;", 58 | 59 | "gl_FragColor = sum;", 60 | 61 | "}" 62 | 63 | ].join("\n") 64 | 65 | }; 66 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/RGBShiftShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author felixturner / http://airtight.cc/ 3 | * 4 | * RGB Shift Shader 5 | * Shifts red and blue channels from center in opposite directions 6 | * Ported from http://kriss.cx/tom/2009/05/rgb-shift/ 7 | * by Tom Butterworth / http://kriss.cx/tom/ 8 | * 9 | * amount: shift distance (1 is width of input) 10 | * angle: shift angle in radians 11 | */ 12 | 13 | THREE.RGBShiftShader = { 14 | 15 | uniforms: { 16 | 17 | "tDiffuse": { type: "t", value: null }, 18 | "amount": { type: "f", value: 0.005 }, 19 | "angle": { type: "f", value: 0.0 } 20 | 21 | }, 22 | 23 | vertexShader: [ 24 | 25 | "varying vec2 vUv;", 26 | 27 | "void main() {", 28 | 29 | "vUv = uv;", 30 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 31 | 32 | "}" 33 | 34 | ].join("\n"), 35 | 36 | fragmentShader: [ 37 | 38 | "uniform sampler2D tDiffuse;", 39 | "uniform float amount;", 40 | "uniform float angle;", 41 | 42 | "varying vec2 vUv;", 43 | 44 | "void main() {", 45 | 46 | "vec2 offset = amount * vec2( cos(angle), sin(angle));", 47 | "vec4 cr = texture2D(tDiffuse, vUv + offset);", 48 | "vec4 cga = texture2D(tDiffuse, vUv);", 49 | "vec4 cb = texture2D(tDiffuse, vUv - offset);", 50 | "gl_FragColor = vec4(cr.r, cga.g, cb.b, cga.a);", 51 | 52 | "}" 53 | 54 | ].join("\n") 55 | 56 | }; 57 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/SSAOShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Screen-space ambient occlusion shader 5 | * - ported from 6 | * SSAO GLSL shader v1.2 7 | * assembled by Martins Upitis (martinsh) (http://devlog-martinsh.blogspot.com) 8 | * original technique is made by ArKano22 (http://www.gamedev.net/topic/550699-ssao-no-halo-artifacts/) 9 | * - modifications 10 | * - modified to use RGBA packed depth texture (use clear color 1,1,1,1 for depth pass) 11 | * - made fog more compatible with three.js linear fog 12 | * - refactoring and optimizations 13 | */ 14 | 15 | THREE.SSAOShader = { 16 | 17 | uniforms: { 18 | 19 | "tDiffuse": { type: "t", value: null }, 20 | "tDepth": { type: "t", value: null }, 21 | "size": { type: "v2", value: new THREE.Vector2( 512, 512 ) }, 22 | "cameraNear": { type: "f", value: 1 }, 23 | "cameraFar": { type: "f", value: 100 }, 24 | "fogNear": { type: "f", value: 5 }, 25 | "fogFar": { type: "f", value: 100 }, 26 | "fogEnabled": { type: "i", value: 0 }, 27 | "onlyAO": { type: "i", value: 0 }, 28 | "aoClamp": { type: "f", value: 0.3 }, 29 | "lumInfluence": { type: "f", value: 0.9 } 30 | 31 | }, 32 | 33 | vertexShader: [ 34 | 35 | "varying vec2 vUv;", 36 | 37 | "void main() {", 38 | 39 | "vUv = uv;", 40 | 41 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 42 | 43 | "}" 44 | 45 | ].join("\n"), 46 | 47 | fragmentShader: [ 48 | 49 | "uniform float cameraNear;", 50 | "uniform float cameraFar;", 51 | 52 | "uniform float fogNear;", 53 | "uniform float fogFar;", 54 | 55 | "uniform bool fogEnabled;", // attenuate AO with linear fog 56 | "uniform bool onlyAO;", // use only ambient occlusion pass? 57 | 58 | "uniform vec2 size;", // texture width, height 59 | "uniform float aoClamp;", // depth clamp - reduces haloing at screen edges 60 | 61 | "uniform float lumInfluence;", // how much luminance affects occlusion 62 | 63 | "uniform sampler2D tDiffuse;", 64 | "uniform sampler2D tDepth;", 65 | 66 | "varying vec2 vUv;", 67 | 68 | // "#define PI 3.14159265", 69 | "#define DL 2.399963229728653", // PI * ( 3.0 - sqrt( 5.0 ) ) 70 | "#define EULER 2.718281828459045", 71 | 72 | // helpers 73 | 74 | "float width = size.x;", // texture width 75 | "float height = size.y;", // texture height 76 | 77 | "float cameraFarPlusNear = cameraFar + cameraNear;", 78 | "float cameraFarMinusNear = cameraFar - cameraNear;", 79 | "float cameraCoef = 2.0 * cameraNear;", 80 | 81 | // user variables 82 | 83 | "const int samples = 8;", // ao sample count 84 | "const float radius = 5.0;", // ao radius 85 | 86 | "const bool useNoise = false;", // use noise instead of pattern for sample dithering 87 | "const float noiseAmount = 0.0003;", // dithering amount 88 | 89 | "const float diffArea = 0.4;", // self-shadowing reduction 90 | "const float gDisplace = 0.4;", // gauss bell center 91 | 92 | "const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );", 93 | // "const vec3 onlyAOColor = vec3( 1.0, 1.0, 1.0 );", 94 | 95 | 96 | // RGBA depth 97 | 98 | "float unpackDepth( const in vec4 rgba_depth ) {", 99 | 100 | "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", 101 | "float depth = dot( rgba_depth, bit_shift );", 102 | "return depth;", 103 | 104 | "}", 105 | 106 | // generating noise / pattern texture for dithering 107 | 108 | "vec2 rand( const vec2 coord ) {", 109 | 110 | "vec2 noise;", 111 | 112 | "if ( useNoise ) {", 113 | 114 | "float nx = dot ( coord, vec2( 12.9898, 78.233 ) );", 115 | "float ny = dot ( coord, vec2( 12.9898, 78.233 ) * 2.0 );", 116 | 117 | "noise = clamp( fract ( 43758.5453 * sin( vec2( nx, ny ) ) ), 0.0, 1.0 );", 118 | 119 | "} else {", 120 | 121 | "float ff = fract( 1.0 - coord.s * ( width / 2.0 ) );", 122 | "float gg = fract( coord.t * ( height / 2.0 ) );", 123 | 124 | "noise = vec2( 0.25, 0.75 ) * vec2( ff ) + vec2( 0.75, 0.25 ) * gg;", 125 | 126 | "}", 127 | 128 | "return ( noise * 2.0 - 1.0 ) * noiseAmount;", 129 | 130 | "}", 131 | 132 | "float doFog() {", 133 | 134 | "float zdepth = unpackDepth( texture2D( tDepth, vUv ) );", 135 | "float depth = -cameraFar * cameraNear / ( zdepth * cameraFarMinusNear - cameraFar );", 136 | 137 | "return smoothstep( fogNear, fogFar, depth );", 138 | 139 | "}", 140 | 141 | "float readDepth( const in vec2 coord ) {", 142 | 143 | // "return ( 2.0 * cameraNear ) / ( cameraFar + cameraNear - unpackDepth( texture2D( tDepth, coord ) ) * ( cameraFar - cameraNear ) );", 144 | "return cameraCoef / ( cameraFarPlusNear - unpackDepth( texture2D( tDepth, coord ) ) * cameraFarMinusNear );", 145 | 146 | 147 | "}", 148 | 149 | "float compareDepths( const in float depth1, const in float depth2, inout int far ) {", 150 | 151 | "float garea = 2.0;", // gauss bell width 152 | "float diff = ( depth1 - depth2 ) * 100.0;", // depth difference (0-100) 153 | 154 | // reduce left bell width to avoid self-shadowing 155 | 156 | "if ( diff < gDisplace ) {", 157 | 158 | "garea = diffArea;", 159 | 160 | "} else {", 161 | 162 | "far = 1;", 163 | 164 | "}", 165 | 166 | "float dd = diff - gDisplace;", 167 | "float gauss = pow( EULER, -2.0 * dd * dd / ( garea * garea ) );", 168 | "return gauss;", 169 | 170 | "}", 171 | 172 | "float calcAO( float depth, float dw, float dh ) {", 173 | 174 | "float dd = radius - depth * radius;", 175 | "vec2 vv = vec2( dw, dh );", 176 | 177 | "vec2 coord1 = vUv + dd * vv;", 178 | "vec2 coord2 = vUv - dd * vv;", 179 | 180 | "float temp1 = 0.0;", 181 | "float temp2 = 0.0;", 182 | 183 | "int far = 0;", 184 | "temp1 = compareDepths( depth, readDepth( coord1 ), far );", 185 | 186 | // DEPTH EXTRAPOLATION 187 | 188 | "if ( far > 0 ) {", 189 | 190 | "temp2 = compareDepths( readDepth( coord2 ), depth, far );", 191 | "temp1 += ( 1.0 - temp1 ) * temp2;", 192 | 193 | "}", 194 | 195 | "return temp1;", 196 | 197 | "}", 198 | 199 | "void main() {", 200 | 201 | "vec2 noise = rand( vUv );", 202 | "float depth = readDepth( vUv );", 203 | 204 | "float tt = clamp( depth, aoClamp, 1.0 );", 205 | 206 | "float w = ( 1.0 / width ) / tt + ( noise.x * ( 1.0 - noise.x ) );", 207 | "float h = ( 1.0 / height ) / tt + ( noise.y * ( 1.0 - noise.y ) );", 208 | 209 | "float pw;", 210 | "float ph;", 211 | 212 | "float ao;", 213 | 214 | "float dz = 1.0 / float( samples );", 215 | "float z = 1.0 - dz / 2.0;", 216 | "float l = 0.0;", 217 | 218 | "for ( int i = 0; i <= samples; i ++ ) {", 219 | 220 | "float r = sqrt( 1.0 - z );", 221 | 222 | "pw = cos( l ) * r;", 223 | "ph = sin( l ) * r;", 224 | "ao += calcAO( depth, pw * w, ph * h );", 225 | "z = z - dz;", 226 | "l = l + DL;", 227 | 228 | "}", 229 | 230 | "ao /= float( samples );", 231 | "ao = 1.0 - ao;", 232 | 233 | "if ( fogEnabled ) {", 234 | 235 | "ao = mix( ao, 1.0, doFog() );", 236 | 237 | "}", 238 | 239 | "vec3 color = texture2D( tDiffuse, vUv ).rgb;", 240 | 241 | "vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );", 242 | "float lum = dot( color.rgb, lumcoeff );", 243 | "vec3 luminance = vec3( lum );", 244 | 245 | "vec3 final = vec3( color * mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // mix( color * ao, white, luminance ) 246 | 247 | "if ( onlyAO ) {", 248 | 249 | "final = onlyAOColor * vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // ambient occlusion only 250 | 251 | "}", 252 | 253 | "gl_FragColor = vec4( final, 1.0 );", 254 | 255 | "}" 256 | 257 | ].join("\n") 258 | 259 | }; 260 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/VerticalTiltShiftShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Simple fake tilt-shift effect, modulating two pass Gaussian blur (see above) by vertical position 5 | * 6 | * - 9 samples per pass 7 | * - standard deviation 2.7 8 | * - "h" and "v" parameters should be set to "1 / width" and "1 / height" 9 | * - "r" parameter control where "focused" horizontal line lies 10 | */ 11 | 12 | THREE.VerticalTiltShiftShader = { 13 | 14 | uniforms: { 15 | 16 | "tDiffuse": { type: "t", value: null }, 17 | "v": { type: "f", value: 1.0 / 512.0 }, 18 | "r": { type: "f", value: 0.35 } 19 | 20 | }, 21 | 22 | vertexShader: [ 23 | 24 | "varying vec2 vUv;", 25 | 26 | "void main() {", 27 | 28 | "vUv = uv;", 29 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 30 | 31 | "}" 32 | 33 | ].join("\n"), 34 | 35 | fragmentShader: [ 36 | 37 | "uniform sampler2D tDiffuse;", 38 | "uniform float v;", 39 | "uniform float r;", 40 | 41 | "varying vec2 vUv;", 42 | 43 | "void main() {", 44 | 45 | "vec4 sum = vec4( 0.0 );", 46 | 47 | "float vv = v * abs( r - vUv.y );", 48 | 49 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * vv ) ) * 0.051;", 50 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * vv ) ) * 0.0918;", 51 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * vv ) ) * 0.12245;", 52 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * vv ) ) * 0.1531;", 53 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633;", 54 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * vv ) ) * 0.1531;", 55 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * vv ) ) * 0.12245;", 56 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * vv ) ) * 0.0918;", 57 | "sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * vv ) ) * 0.051;", 58 | 59 | "gl_FragColor = sum;", 60 | 61 | "}" 62 | 63 | ].join("\n") 64 | 65 | }; 66 | -------------------------------------------------------------------------------- /scripts/lib/threejs/shaders/VignetteShader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author alteredq / http://alteredqualia.com/ 3 | * 4 | * Vignette shader 5 | * based on PaintEffect postprocess from ro.me 6 | * http://code.google.com/p/3-dreams-of-black/source/browse/deploy/js/effects/PaintEffect.js 7 | */ 8 | 9 | THREE.VignetteShader = { 10 | 11 | uniforms: { 12 | 13 | "tDiffuse": { type: "t", value: null }, 14 | "offset": { type: "f", value: 1.0 }, 15 | "darkness": { type: "f", value: 1.0 } 16 | 17 | }, 18 | 19 | vertexShader: [ 20 | 21 | "varying vec2 vUv;", 22 | 23 | "void main() {", 24 | 25 | "vUv = uv;", 26 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 27 | 28 | "}" 29 | 30 | ].join("\n"), 31 | 32 | fragmentShader: [ 33 | 34 | "uniform float offset;", 35 | "uniform float darkness;", 36 | 37 | "uniform sampler2D tDiffuse;", 38 | 39 | "varying vec2 vUv;", 40 | 41 | "void main() {", 42 | 43 | // Eskil's vignette 44 | 45 | "vec4 texel = texture2D( tDiffuse, vUv );", 46 | "vec2 uv = ( vUv - vec2( 0.5 ) ) * vec2( offset );", 47 | "gl_FragColor = vec4( mix( texel.rgb, vec3( 1.0 - darkness ), dot( uv, uv ) ), texel.a );", 48 | 49 | /* 50 | // alternative version from glfx.js 51 | // this one makes more "dusty" look (as opposed to "burned") 52 | 53 | "vec4 color = texture2D( tDiffuse, vUv );", 54 | "float dist = distance( vUv, vec2( 0.5 ) );", 55 | "color.rgb *= smoothstep( 0.8, offset * 0.799, dist *( darkness + offset ) );", 56 | "gl_FragColor = color;", 57 | */ 58 | 59 | "}" 60 | 61 | ].join("\n") 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /scripts/lib/transit/transit.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Transit - CSS3 transitions and transformations 3 | * (c) 2011-2012 Rico Sta. Cruz 4 | * MIT Licensed. 5 | * 6 | * http://ricostacruz.com/jquery.transit 7 | * http://github.com/rstacruz/jquery.transit 8 | */ 9 | (function(k){k.transit={version:"0.9.9",propertyMap:{marginLeft:"margin",marginRight:"margin",marginBottom:"margin",marginTop:"margin",paddingLeft:"padding",paddingRight:"padding",paddingBottom:"padding",paddingTop:"padding"},enabled:true,useTransitionEnd:false};var d=document.createElement("div");var q={};function b(v){if(v in d.style){return v}var u=["Moz","Webkit","O","ms"];var r=v.charAt(0).toUpperCase()+v.substr(1);if(v in d.style){return v}for(var t=0;t-1;q.transition=b("transition");q.transitionDelay=b("transitionDelay");q.transform=b("transform");q.transformOrigin=b("transformOrigin");q.transform3d=e();var i={transition:"transitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",WebkitTransition:"webkitTransitionEnd",msTransition:"MSTransitionEnd"};var f=q.transitionEnd=i[q.transition]||null;for(var p in q){if(q.hasOwnProperty(p)&&typeof k.support[p]==="undefined"){k.support[p]=q[p]}}d=null;k.cssEase={_default:"ease","in":"ease-in",out:"ease-out","in-out":"ease-in-out",snap:"cubic-bezier(0,1,.5,1)",easeOutCubic:"cubic-bezier(.215,.61,.355,1)",easeInOutCubic:"cubic-bezier(.645,.045,.355,1)",easeInCirc:"cubic-bezier(.6,.04,.98,.335)",easeOutCirc:"cubic-bezier(.075,.82,.165,1)",easeInOutCirc:"cubic-bezier(.785,.135,.15,.86)",easeInExpo:"cubic-bezier(.95,.05,.795,.035)",easeOutExpo:"cubic-bezier(.19,1,.22,1)",easeInOutExpo:"cubic-bezier(1,0,0,1)",easeInQuad:"cubic-bezier(.55,.085,.68,.53)",easeOutQuad:"cubic-bezier(.25,.46,.45,.94)",easeInOutQuad:"cubic-bezier(.455,.03,.515,.955)",easeInQuart:"cubic-bezier(.895,.03,.685,.22)",easeOutQuart:"cubic-bezier(.165,.84,.44,1)",easeInOutQuart:"cubic-bezier(.77,0,.175,1)",easeInQuint:"cubic-bezier(.755,.05,.855,.06)",easeOutQuint:"cubic-bezier(.23,1,.32,1)",easeInOutQuint:"cubic-bezier(.86,0,.07,1)",easeInSine:"cubic-bezier(.47,0,.745,.715)",easeOutSine:"cubic-bezier(.39,.575,.565,1)",easeInOutSine:"cubic-bezier(.445,.05,.55,.95)",easeInBack:"cubic-bezier(.6,-.28,.735,.045)",easeOutBack:"cubic-bezier(.175, .885,.32,1.275)",easeInOutBack:"cubic-bezier(.68,-.55,.265,1.55)"};k.cssHooks["transit:transform"]={get:function(r){return k(r).data("transform")||new j()},set:function(s,r){var t=r;if(!(t instanceof j)){t=new j(t)}if(q.transform==="WebkitTransform"&&!a){s.style[q.transform]=t.toString(true)}else{s.style[q.transform]=t.toString()}k(s).data("transform",t)}};k.cssHooks.transform={set:k.cssHooks["transit:transform"].set};if(k.fn.jquery<"1.8"){k.cssHooks.transformOrigin={get:function(r){return r.style[q.transformOrigin]},set:function(r,s){r.style[q.transformOrigin]=s}};k.cssHooks.transition={get:function(r){return r.style[q.transition]},set:function(r,s){r.style[q.transition]=s}}}n("scale");n("translate");n("rotate");n("rotateX");n("rotateY");n("rotate3d");n("perspective");n("skewX");n("skewY");n("x",true);n("y",true);function j(r){if(typeof r==="string"){this.parse(r)}return this}j.prototype={setFromString:function(t,s){var r=(typeof s==="string")?s.split(","):(s.constructor===Array)?s:[s];r.unshift(t);j.prototype.set.apply(this,r)},set:function(s){var r=Array.prototype.slice.apply(arguments,[1]);if(this.setter[s]){this.setter[s].apply(this,r)}else{this[s]=r.join(",")}},get:function(r){if(this.getter[r]){return this.getter[r].apply(this)}else{return this[r]||0}},setter:{rotate:function(r){this.rotate=o(r,"deg")},rotateX:function(r){this.rotateX=o(r,"deg")},rotateY:function(r){this.rotateY=o(r,"deg")},scale:function(r,s){if(s===undefined){s=r}this.scale=r+","+s},skewX:function(r){this.skewX=o(r,"deg")},skewY:function(r){this.skewY=o(r,"deg")},perspective:function(r){this.perspective=o(r,"px")},x:function(r){this.set("translate",r,null)},y:function(r){this.set("translate",null,r)},translate:function(r,s){if(this._translateX===undefined){this._translateX=0}if(this._translateY===undefined){this._translateY=0}if(r!==null&&r!==undefined){this._translateX=o(r,"px")}if(s!==null&&s!==undefined){this._translateY=o(s,"px")}this.translate=this._translateX+","+this._translateY}},getter:{x:function(){return this._translateX||0},y:function(){return this._translateY||0},scale:function(){var r=(this.scale||"1,1").split(",");if(r[0]){r[0]=parseFloat(r[0])}if(r[1]){r[1]=parseFloat(r[1])}return(r[0]===r[1])?r[0]:r},rotate3d:function(){var t=(this.rotate3d||"0,0,0,0deg").split(",");for(var r=0;r<=3;++r){if(t[r]){t[r]=parseFloat(t[r])}}if(t[3]){t[3]=o(t[3],"deg")}return t}},parse:function(s){var r=this;s.replace(/([a-zA-Z0-9]+)\((.*?)\)/g,function(t,v,u){r.setFromString(v,u)})},toString:function(t){var s=[];for(var r in this){if(this.hasOwnProperty(r)){if((!q.transform3d)&&((r==="rotateX")||(r==="rotateY")||(r==="perspective")||(r==="transformOrigin"))){continue}if(r[0]!=="_"){if(t&&(r==="scale")){s.push(r+"3d("+this[r]+",1)")}else{if(t&&(r==="translate")){s.push(r+"3d("+this[r]+",0)")}else{s.push(r+"("+this[r]+")")}}}}}return s.join(" ")}};function m(s,r,t){if(r===true){s.queue(t)}else{if(r){s.queue(r,t)}else{t()}}}function h(s){var r=[];k.each(s,function(t){t=k.camelCase(t);t=k.transit.propertyMap[t]||k.cssProps[t]||t;t=c(t);if(k.inArray(t,r)===-1){r.push(t)}});return r}function g(s,v,x,r){var t=h(s);if(k.cssEase[x]){x=k.cssEase[x]}var w=""+l(v)+" "+x;if(parseInt(r,10)>0){w+=" "+l(r)}var u=[];k.each(t,function(z,y){u.push(y+" "+w)});return u.join(", ")}k.fn.transition=k.fn.transit=function(z,s,y,C){var D=this;var u=0;var w=true;if(typeof s==="function"){C=s;s=undefined}if(typeof y==="function"){C=y;y=undefined}if(typeof z.easing!=="undefined"){y=z.easing;delete z.easing}if(typeof z.duration!=="undefined"){s=z.duration;delete z.duration}if(typeof z.complete!=="undefined"){C=z.complete;delete z.complete}if(typeof z.queue!=="undefined"){w=z.queue;delete z.queue}if(typeof z.delay!=="undefined"){u=z.delay;delete z.delay}if(typeof s==="undefined"){s=k.fx.speeds._default}if(typeof y==="undefined"){y=k.cssEase._default}s=l(s);var E=g(z,s,y,u);var B=k.transit.enabled&&q.transition;var t=B?(parseInt(s,10)+parseInt(u,10)):0;if(t===0){var A=function(F){D.css(z);if(C){C.apply(D)}if(F){F()}};m(D,w,A);return D}var x={};var r=function(H){var G=false;var F=function(){if(G){D.unbind(f,F)}if(t>0){D.each(function(){this.style[q.transition]=(x[this]||null)})}if(typeof C==="function"){C.apply(D)}if(typeof H==="function"){H()}};if((t>0)&&(f)&&(k.transit.useTransitionEnd)){G=true;D.bind(f,F)}else{window.setTimeout(F,t)}D.each(function(){if(t>0){this.style[q.transition]=E}k(this).css(z)})};var v=function(F){this.offsetWidth;r(F)};m(D,w,v);return this};function n(s,r){if(!r){k.cssNumber[s]=true}k.transit.propertyMap[s]=q.transform;k.cssHooks[s]={get:function(v){var u=k(v).css("transit:transform");return u.get(s)},set:function(v,w){var u=k(v).css("transit:transform");u.setFromString(s,w);k(v).css({"transit:transform":u})}}}function c(r){return r.replace(/([A-Z])/g,function(s){return"-"+s.toLowerCase()})}function o(s,r){if((typeof s==="string")&&(!s.match(/^[\-0-9\.]+$/))){return s}else{return""+s+r}}function l(s){var r=s;if(k.fx.speeds[r]){r=k.fx.speeds[r]}return o(r,"ms")}k.transit.getTransitionValue=g})(jQuery); -------------------------------------------------------------------------------- /scripts/lib/tween/Tween.js: -------------------------------------------------------------------------------- 1 | // tween.js - http://github.com/sole/tween.js 2 | 'use strict';void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()}); 3 | var TWEEN=TWEEN||function(){var a=[];return{REVISION:"11dev",getAll:function(){return a},removeAll:function(){a=[]},add:function(c){a.push(c)},remove:function(c){c=a.indexOf(c);-1!==c&&a.splice(c,1)},update:function(c){if(0===a.length)return!1;for(var b=0,d=a.length,c=void 0!==c?c:"undefined"!==typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();b(a*=2)?0.5*a*a:-0.5*(--a*(a-2)-1)}},Cubic:{In:function(a){return a*a*a},Out:function(a){return--a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a:0.5*((a-=2)*a*a+2)}},Quartic:{In:function(a){return a*a*a*a},Out:function(a){return 1- --a*a*a*a},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)}},Quintic:{In:function(a){return a*a*a* 9 | a*a},Out:function(a){return--a*a*a*a*a+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)}},Sinusoidal:{In:function(a){return 1-Math.cos(a*Math.PI/2)},Out:function(a){return Math.sin(a*Math.PI/2)},InOut:function(a){return 0.5*(1-Math.cos(Math.PI*a))}},Exponential:{In:function(a){return 0===a?0:Math.pow(1024,a-1)},Out:function(a){return 1===a?1:1-Math.pow(2,-10*a)},InOut:function(a){return 0===a?0:1===a?1:1>(a*=2)?0.5*Math.pow(1024,a-1):0.5*(-Math.pow(2,-10*(a-1))+2)}},Circular:{In:function(a){return 1- 10 | Math.sqrt(1-a*a)},Out:function(a){return Math.sqrt(1- --a*a)},InOut:function(a){return 1>(a*=2)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)}},Elastic:{In:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4))},Out:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return b*Math.pow(2,-10*a)*Math.sin((a-c)* 11 | 2*Math.PI/0.4)+1},InOut:function(a){var c,b=0.1;if(0===a)return 0;if(1===a)return 1;!b||1>b?(b=1,c=0.1):c=0.4*Math.asin(1/b)/(2*Math.PI);return 1>(a*=2)?-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4):0.5*b*Math.pow(2,-10*(a-=1))*Math.sin((a-c)*2*Math.PI/0.4)+1}},Back:{In:function(a){return a*a*(2.70158*a-1.70158)},Out:function(a){return--a*a*(2.70158*a+1.70158)+1},InOut:function(a){return 1>(a*=2)?0.5*a*a*(3.5949095*a-2.5949095):0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)}},Bounce:{In:function(a){return 1- 12 | TWEEN.Easing.Bounce.Out(1-a)},Out:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},InOut:function(a){return 0.5>a?0.5*TWEEN.Easing.Bounce.In(2*a):0.5*TWEEN.Easing.Bounce.Out(2*a-1)+0.5}}}; 13 | TWEEN.Interpolation={Linear:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.Linear;return 0>c?g(a[0],a[1],d):1b?b:e+1],d-e)},Bezier:function(a,c){var b=0,d=a.length-1,e=Math.pow,g=TWEEN.Interpolation.Utils.Bernstein,h;for(h=0;h<=d;h++)b+=e(1-c,d-h)*e(c,h)*a[h]*g(d,h);return b},CatmullRom:function(a,c){var b=a.length-1,d=b*c,e=Math.floor(d),g=TWEEN.Interpolation.Utils.CatmullRom;return a[0]===a[b]?(0>c&&(e=Math.floor(d=b*(1+c))),g(a[(e- 14 | 1+b)%b],a[e],a[(e+1)%b],a[(e+2)%b],d-e)):0>c?a[0]-(g(a[0],a[0],a[1],a[1],-d)-a[0]):1 2 | 3 | mxframework-core 4 | 5 | 6 | 7 | 8 | 9 | com.googlecode.jslint4java.eclipse.jsLintBuilder 10 | 11 | 12 | 13 | 14 | 15 | com.googlecode.jslint4java.eclipse.jsLintNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /scripts/mx/MXComponent.js: -------------------------------------------------------------------------------- 1 | MXComponent = function() 2 | { 3 | var me = $extend(MXObject); 4 | var base = {}; 5 | 6 | me.autoInit = true; 7 | me.initialized = false; 8 | 9 | base._ = me._; 10 | me._ = function(p_options) 11 | { 12 | if (me.canConstruct()) 13 | { 14 | base._(p_options); 15 | if (me.autoInit) 16 | { 17 | me.init(p_options); 18 | } 19 | } 20 | }; 21 | 22 | me.init = function(p_options) 23 | { 24 | me.initialized = true; 25 | }; 26 | 27 | me.bind = function(p_eventType, p_function, p_once) 28 | { 29 | var eventType = "on" + p_eventType; 30 | if (typeof (me[eventType]) === "undefined") 31 | { 32 | return me; 33 | } 34 | if (isEmpty(me[eventType])) 35 | { 36 | me[eventType] = new MXEvent(); 37 | } 38 | me[eventType].addEventListener(p_function, p_once); 39 | return me; 40 | }; 41 | me.on = me.bind; 42 | 43 | me.bindOnce = function(p_eventType, p_function) 44 | { 45 | me.bind(p_eventType, p_function, true); 46 | return me; 47 | }; 48 | me.once = me.bindOnce; 49 | 50 | me.unbind = function(p_eventType, p_function) 51 | { 52 | if (isEmpty(p_eventType) && isEmpty(p_function)) 53 | { 54 | for ( var name in me) 55 | { 56 | if (notEmpty(me[name]) && me[name].constructor === MXEvent) 57 | { 58 | me[name].clear(); 59 | me[name] = null; 60 | } 61 | } 62 | } 63 | else 64 | { 65 | var eventType = "on" + p_eventType; 66 | if (typeof (me[eventType]) === "undefined") 67 | { 68 | return me; 69 | } 70 | 71 | if (notEmpty(me[eventType])) 72 | { 73 | if (notEmpty(p_function)) 74 | { 75 | me[eventType].removeEventListener(p_function); 76 | } 77 | else 78 | { 79 | me[eventType].clear(); 80 | } 81 | } 82 | } 83 | return me; 84 | }; 85 | me.off = me.unbind; 86 | 87 | me.hasBound = function(p_eventType) 88 | { 89 | var eventType = "on" + p_eventType; 90 | if (typeof (me[eventType]) === "undefined") 91 | { 92 | return false; 93 | } 94 | if (notEmpty(me[eventType])) 95 | { 96 | return me[eventType].listeners.length > 0; 97 | } 98 | else 99 | { 100 | return false; 101 | } 102 | }; 103 | 104 | me.trigger = function(p_eventType, p_args) 105 | { 106 | var eventType = "on" + p_eventType; 107 | if (typeof (me[eventType]) === "undefined") 108 | { 109 | return me; 110 | } 111 | if (notEmpty(me[eventType])) 112 | { 113 | var e = null; 114 | if (notEmpty(p_args)) 115 | { 116 | e = p_args; 117 | } 118 | else 119 | { 120 | e = {}; 121 | } 122 | e.target = me; 123 | 124 | e.type = p_eventType; 125 | 126 | me[eventType].fire(e); 127 | } 128 | return me; 129 | }; 130 | 131 | base.instanceOf = me.instanceOf; 132 | me.instanceOf = function(p_class) 133 | { 134 | if (p_class === MXComponent) 135 | { 136 | return true; 137 | } 138 | return base.instanceOf(p_class); 139 | }; 140 | 141 | base.dispose = me.dispose; 142 | me.dispose = function() 143 | { 144 | me.unbind(); 145 | base.dispose(); 146 | }; 147 | 148 | return me.endOfClass(arguments); 149 | }; 150 | MXComponent.className = "MXComponent"; 151 | -------------------------------------------------------------------------------- /scripts/mx/MXEvent.js: -------------------------------------------------------------------------------- 1 | MXEvent = function() 2 | { 3 | var me = this; 4 | 5 | me.listeners = []; 6 | 7 | var _onceListeners = null; 8 | 9 | me.addEventListener = function(p_listener, p_once) 10 | { 11 | if (typeof (p_listener) === "function" && !me.listeners.contains(p_listener)) 12 | { 13 | me.listeners.add(p_listener); 14 | if (p_once === true) 15 | { 16 | if (isEmpty(_onceListeners)) 17 | { 18 | _onceListeners = []; 19 | } 20 | _onceListeners.add(p_listener); 21 | } 22 | } 23 | }; 24 | 25 | me.insertEventListener = function(p_index, p_listener, p_once) 26 | { 27 | if (typeof (p_listener) === "function" && !me.listeners.contains(p_listener)) 28 | { 29 | me.listeners.insert(p_index, p_listener); 30 | if (p_once === true) 31 | { 32 | if (isEmpty(_onceListeners)) 33 | { 34 | _onceListeners = []; 35 | } 36 | _onceListeners.add(p_listener); 37 | } 38 | } 39 | }; 40 | 41 | me.removeEventListener = function(p_listener) 42 | { 43 | if (notEmpty(_onceListeners)) 44 | { 45 | _onceListeners.remove(p_listener); 46 | } 47 | return me.listeners.remove(p_listener); 48 | }; 49 | 50 | me.clear = function() 51 | { 52 | if (notEmpty(_onceListeners)) 53 | { 54 | _onceListeners.clear(); 55 | _onceListeners = null; 56 | } 57 | me.listeners.clear(); 58 | }; 59 | 60 | me.fire = function(e) 61 | { 62 | if (notEmpty(me.listeners) && me.listeners.length > 0) 63 | { 64 | var listeners = me.listeners.clone(); 65 | var toBeRemoved = []; 66 | var i = 0; 67 | for (i = 0; i < listeners.length; i++) 68 | { 69 | var listener = listeners[i]; 70 | listener(e); 71 | 72 | if (notEmpty(_onceListeners) && _onceListeners.contains(listener)) 73 | { 74 | toBeRemoved.add(listener); 75 | _onceListeners.remove(listener); 76 | if (_onceListeners.length === 0) 77 | { 78 | _onceListeners = null; 79 | } 80 | } 81 | } 82 | for (i = 0; i < toBeRemoved.length; i++) 83 | { 84 | me.listeners.remove(toBeRemoved[i]); 85 | } 86 | listeners = null; 87 | } 88 | }; 89 | 90 | return me; 91 | }; 92 | MXEvent.className = "MXEvent"; 93 | -------------------------------------------------------------------------------- /scripts/mx/MXObject.js: -------------------------------------------------------------------------------- 1 | MXObject = function() 2 | { 3 | var me = this; 4 | 5 | me.__class__ = MXObject; 6 | me.__superClasses__ = []; 7 | 8 | me.constructed = false; 9 | me.disposed = false; 10 | 11 | me._ = function(p_options) 12 | { 13 | if (me.canConstruct()) 14 | { 15 | if (isPlainObject(p_options)) 16 | { 17 | var isEventDispatcher = typeof (me.on) === "function"; 18 | for ( var key in p_options) 19 | { 20 | if (p_options.hasOwnProperty(key)) 21 | { 22 | var option = p_options[key]; 23 | if (isEventDispatcher && typeof (me[key] === "object") && typeof (option) === "function" && key.startsWith("on")) 24 | { 25 | me.on(key.substr(2), option); 26 | } 27 | else 28 | { 29 | me[key] = option; 30 | } 31 | 32 | option = null; 33 | } 34 | } 35 | } 36 | me.constructed = true; 37 | 38 | p_options = null; 39 | } 40 | }; 41 | 42 | me.getClass = function() 43 | { 44 | return me.__class__; 45 | }; 46 | 47 | me.getClassName = function() 48 | { 49 | var cls = me.getClass(); 50 | if (notEmpty(cls)) 51 | { 52 | return cls.className; 53 | } 54 | return null; 55 | }; 56 | 57 | me.getNamespace = function() 58 | { 59 | var clsName = me.getClassName(); 60 | if (notEmpty(clsName)) 61 | { 62 | var parts = clsName.split("."); 63 | if (parts.length > 1) 64 | { 65 | parts = parts.slice(0, parts.length - 1); 66 | return parts.join("."); 67 | } 68 | } 69 | return null; 70 | }; 71 | 72 | me.getModuleName = function() 73 | { 74 | var ns = me.getNamespace(); 75 | if (notEmpty(ns)) 76 | { 77 | var parts = ns.split("."); 78 | if (parts.length > 0) 79 | { 80 | return parts[0]; 81 | } 82 | else 83 | { 84 | return ns; 85 | } 86 | } 87 | return null; 88 | }; 89 | 90 | me.getResourcePath = function(p_name, p_ext, p_auto2x) 91 | { 92 | var path = me.getModuleName() + ".res." + p_name; 93 | return mx.getResourcePath(path, p_ext, p_auto2x); 94 | }; 95 | 96 | me.set = function() 97 | { 98 | var p_options = null; 99 | if (arguments.length === 2 && isString(arguments[0])) 100 | { 101 | var func = "set" + arguments[0].toUpperCamelCase(); 102 | if (isFunction(me[func])) 103 | { 104 | me[func](arguments[1]); 105 | } 106 | else 107 | { 108 | me[arguments[0]] = arguments[1]; 109 | } 110 | } 111 | else if (arguments.length === 1 && isPlainObject(arguments[0])) 112 | { 113 | p_options = arguments[0]; 114 | for ( var key in p_options) 115 | { 116 | if (p_options.hasOwnProperty(key)) 117 | { 118 | me.set(key, p_options[key]); 119 | } 120 | } 121 | } 122 | else if (arguments.length === 2 && isPlainObject(arguments[0]) && isPlainObject(arguments[1])) 123 | { 124 | p_options = arguments[0]; 125 | var p_defaultOptions = arguments[1]; 126 | var options = $.extend({}, p_defaultOptions, p_options); 127 | me.set(options); 128 | } 129 | return me; 130 | }; 131 | 132 | me.canConstruct = function() 133 | { 134 | return !me.constructed; 135 | }; 136 | 137 | me.instanceOf = function(p_class) 138 | { 139 | if (p_class === me.__class__) 140 | { 141 | return true; 142 | } 143 | else if (p_class === Object || p_class === MXObject) 144 | { 145 | return true; 146 | } 147 | else 148 | { 149 | return me.__superClasses__.indexOf(p_class) !== -1; 150 | } 151 | }; 152 | 153 | me.endOfClass = function(p_arguments) 154 | { 155 | if (me.__class__.caller !== $extend) 156 | { 157 | me._(p_arguments[0]); 158 | } 159 | return me; 160 | }; 161 | 162 | me.dispose = function() 163 | { 164 | me.disposed = true; 165 | }; 166 | 167 | return me.endOfClass(arguments); 168 | }; 169 | MXObject.className = "MXObject"; 170 | -------------------------------------------------------------------------------- /scripts/mx/README.md: -------------------------------------------------------------------------------- 1 | # MXFramework 2 | MagicCube MXFramework is a lightweight Object-Oriented JavaScript framework. 3 | 4 | # Quick Examples 5 | Like many other JavaScript frameworks, MXFramework has its own way to define namespace, class and component. 6 | In this quick example, we will demonstrate how to define classes using MXFramework. 7 | 8 | Firstly, let's create a new class named Animal. 9 | ```javascript 10 | scripts/my/namespace/Animal.js 11 | 12 | /* 13 | * Define a namespace. 14 | */ 15 | $ns("my.namespace"); 16 | 17 | /** 18 | * Define a class which extends MXComponent. 19 | * A MXComponent is a very popular super class. 20 | * Actually, in this case, we can also use MXObject instead. 21 | * MXObject is the super class of MXComponent. 22 | */ 23 | my.namespace.Animal = function() 24 | { 25 | /** 26 | * In MXFramework, it always use 'me' instead of 'this'. 27 | */ 28 | var me = $extend(MXComponent); 29 | /** 30 | * 'base' is almost the same as 'super' in Java. 31 | */ 32 | var base = {}; 33 | 34 | 35 | /** 36 | * Define a public field. 37 | * Every public member should under 'me'. 38 | */ 39 | me.name = null; 40 | 41 | /** 42 | * Define a private field. 43 | * The names of a private members always start with an underline. 44 | */ 45 | var _something = null; 46 | var _someVariable = 0; 47 | 48 | 49 | /** 50 | * Override a public method. 51 | * 'init' method will be automatically called immediately after the instance is created. 52 | * Even though, you can also set the 'autoInit' field to false if you need lazy intialization. 53 | */ 54 | base.init = me.init; 55 | me.init = function(p_options) 56 | { 57 | base.init(p_options); 58 | }; 59 | 60 | 61 | /** 62 | * Define a public function. 63 | */ 64 | me.sayHi = function() 65 | { 66 | if (_canSayHi()) 67 | { 68 | /* 69 | String.format provides ability to substitute string with JSON object or array. 70 | In MXFramework you can use the following format methods. 71 | - String.format String.format("Hi, {name}!", { name: "Henry" }); String.format("Hi, {0}", [ "Henry" ]) 72 | - Date.format Date.format(new Date(), "yyyy-MM-dd HH:mm:ss"); Date.format(new Date(), "yy年M月d日"); 73 | - Number.format Number.format(12.53212, "0.00"); Number.format(123, "00000000"); 74 | */ 75 | return String.format("Hi, I'm a {name}", { name: me.name }); 76 | } 77 | }; 78 | 79 | 80 | /** 81 | * Define a private function. 82 | */ 83 | function _canSayHi() 84 | { 85 | // MXFramework has a series of methods for type assertions. 86 | return isString(me.name); 87 | } 88 | 89 | 90 | /** 91 | * This is the end of class. 92 | */ 93 | return me.endOfClass(arguments); 94 | }; 95 | ``` 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | Let's have a class inherits from Animal. 106 | 107 | ```javascript 108 | scripts/your/namespace/Cat.js 109 | 110 | $ns("your.namespace"); 111 | 112 | // Import the super class. 113 | $import("my.namespace.Animal"); 114 | 115 | /** 116 | * Cat inherits from Animal. 117 | */ 118 | your.namespace.Cat = function() 119 | { 120 | var me = $extend(my.namespace.Animal); 121 | /* 122 | * Change the initial value of name. 123 | */ 124 | me.name = "Cat"; 125 | var base = {}; 126 | 127 | me.nickName = "kitty"; 128 | 129 | base.init = me.init; 130 | me.init = function(p_options) 131 | { 132 | base.init(p_options); 133 | if (isEmptyString(me.nickName) && isString(me.name)) 134 | { 135 | me.nickName = me.name; 136 | } 137 | }; 138 | 139 | /** 140 | * Override 'sayHi' method. 141 | */ 142 | base.sayHi = me.sayHi; 143 | me.sayHi = function() 144 | { 145 | // $format is a shortcut to String.format, Date.format and Number.format. 146 | return base.sayHi() + $format(" You can call me {0}", [ me.nickName ]); 147 | }; 148 | 149 | return me.endOfClass(arguments); 150 | }; 151 | ``` 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Now we need to instantialize the class. 160 | ```JavaScript 161 | // Import Cat class. The Animal class will be automatically imported with Cat. 162 | $import("your.namespace.Cat"); 163 | 164 | // Create a new instance with default values. 165 | var cat = new your.namespace.Cat(); 166 | alert(cat.sayHi()); 167 | 168 | // Create a new instance with initial values using JSON. 169 | // In MXFramework, class only accepts JSON object as constructure parameter. 170 | var tomCat = new your.namespace.Cat({ 171 | nickName: "Tom" 172 | }); 173 | alert(tomCat.sayHi()); 174 | ``` 175 | 176 | Finally, build the code with mxbuild or mxtool to generate min.js and min.css 177 | ``` 178 | jar mxbuild.jar your;my 179 | ``` 180 | 181 | 182 | # Source Code Repository 183 | The source is available for download from GitHub 184 | https://github.com/MagicCube/mxframework-core 185 | 186 | # Documents 187 | For documents, see https://github.com/MagicCube/mxframework-core/wiki 188 | 189 | # Related Projects 190 | * [mxframework-node](https://github.com/MagicCube/mxframework-node) - MagicCube MXFramework for Node.js 191 | * [mxtool](https://github.com/MagicCube/mxtool) - Development tools for MagicCube MXFramework 192 | * [g3d](https://github.com/MagicCube/g3d) - A web GIS library for 3D visualization using WebGL technology 193 | -------------------------------------------------------------------------------- /scripts/mx/app/Application.js: -------------------------------------------------------------------------------- 1 | $ns("mx.app"); 2 | 3 | mx.app.Application = function() 4 | { 5 | var me = $extend(mx.view.View); 6 | var base = {}; 7 | 8 | me.$element = null; 9 | 10 | me.appId = null; 11 | me.appDisplayName = null; 12 | 13 | base.init = me.init; 14 | me.init = function(p_options) 15 | { 16 | if (isEmpty(me.$element)) 17 | { 18 | me.$element = $(document.body); 19 | } 20 | 21 | if (isEmpty(me.id)) 22 | { 23 | me.id = me.appId; 24 | } 25 | base.init(p_options); 26 | if (notEmpty(me.appDisplayName)) 27 | { 28 | document.title = me.appDisplayName; 29 | } 30 | 31 | me.frame = { 32 | width : me.$element.width(), 33 | height : me.$element.height() 34 | }; 35 | 36 | me.$element.addClass("mx-app"); 37 | 38 | mx.app.Application.singleton = me; 39 | }; 40 | 41 | me.run = function(p_options) 42 | { 43 | 44 | }; 45 | 46 | return me.endOfClass(arguments); 47 | }; 48 | mx.app.Application.className = "mx.app.Application"; 49 | 50 | mx.app.Application.singleton = null; 51 | -------------------------------------------------------------------------------- /scripts/mx/debug.js: -------------------------------------------------------------------------------- 1 | (function() 2 | { 3 | var lang = null; 4 | if (typeof ($mx_language) === "undefined") 5 | { 6 | lang = (navigator.language || navigator.userLanguage).toString().toLowerCase(); 7 | } 8 | else 9 | { 10 | lang = $mx_language; 11 | } 12 | 13 | var scripts = document.getElementsByTagName("script"); 14 | var src = scripts[scripts.length - 1].src; 15 | var srcPath = src.substr(0, src.lastIndexOf("/mx/") + 1); 16 | 17 | function include(p_src) 18 | { 19 | document.write(""); 20 | } 21 | 22 | if (typeof (jQuery) === "undefined") 23 | { 24 | include("lib/jquery/jquery.js"); 25 | } 26 | 27 | include("mx/javascript-extensions.js"); 28 | include("mx/framework-base.js"); 29 | include("mx/framework-core.js"); 30 | 31 | })(); 32 | -------------------------------------------------------------------------------- /scripts/mx/framework-base.js: -------------------------------------------------------------------------------- 1 | // 判断类型 2 | 3 | function isBoolean(p_value) 4 | { 5 | return typeof (p_value) === "boolean"; 6 | } 7 | 8 | function isString(p_value) 9 | { 10 | return typeof (p_value) === "string"; 11 | } 12 | 13 | function isNumber(p_value) 14 | { 15 | return typeof (p_value) === "number"; 16 | } 17 | 18 | function isDate(p_value) 19 | { 20 | return notEmpty(p_value) && p_value.constructor === Date; 21 | } 22 | 23 | function isArray(p_value) 24 | { 25 | if (typeof(Array.isArray) === "function") 26 | { 27 | return Array.isArray(p_value); 28 | } 29 | else 30 | { 31 | return notEmpty(p_value) && (typeof (p_value) === "object" && typeof (p_value.length) === "number"); 32 | } 33 | } 34 | 35 | function isObject(p_value) 36 | { 37 | return notEmpty(p_value) && typeof (p_value) === "object"; 38 | } 39 | 40 | function isPlainObject(p_value) 41 | { 42 | return $.isPlainObject(p_value); 43 | } 44 | 45 | function isFunction(p_value) 46 | { 47 | return typeof (p_value) === "function"; 48 | } 49 | 50 | function isClass(p_value) 51 | { 52 | return typeof (p_value) === "function"; 53 | } 54 | 55 | // 类型转换 56 | function parseBoolean(p_text) 57 | { 58 | if (typeof (p_text) === "boolean") 59 | { 60 | return p_text; 61 | } 62 | else if (typeof(p_text) === "number") 63 | { 64 | return p_text !== 0; 65 | } 66 | else if (typeof(p_text) === "string") 67 | { 68 | var t = p_text.toLowerCase(); 69 | return (t === "true") || (t === "t"); 70 | } 71 | } 72 | 73 | var __regex_Hms = /^(\S*):(\S*):(\S*)$/; 74 | var __regex_Hm = /^(\S*):(\S*)$/; 75 | function parseTimeString(p_timeString) 76 | { 77 | var value = { 78 | hours : 0, 79 | minutes : 0, 80 | seconds : 0 81 | }; 82 | 83 | var matches = p_timeString.match(__regex_Hms); 84 | if (isEmpty(matches)) 85 | { 86 | matches = p_timeString.match(__regex_Hm); 87 | if (isEmpty(matches)) 88 | { 89 | matches = [p_timeString, p_timeString]; 90 | } 91 | } 92 | 93 | if (matches.length >= 2) 94 | { 95 | value.hours = parseInt(matches[1], 10); 96 | if (isNaN(value.hours) || value.hours > 23 || value.hours < 0) 97 | { 98 | value.hours = 0; 99 | } 100 | } 101 | 102 | if (matches.length >= 3) 103 | { 104 | value.minutes = parseInt(matches[2], 10); 105 | if (isNaN(value.minutes) || value.minutes > 60 || value.minutes < 0) 106 | { 107 | value.minutes = 0; 108 | } 109 | } 110 | 111 | if (matches.length >= 4) 112 | { 113 | value.seconds = parseInt(matches[3], 10); 114 | if (isNaN(value.seconds) || value.seconds > 60 || value.seconds < 0) 115 | { 116 | value.seconds = 0; 117 | } 118 | } 119 | 120 | return value; 121 | } 122 | 123 | var __regex_yyyyM = /^(\S*)-(\S*)$/; 124 | var __regex_yyyyMD = /^(\S*)-(\S*)-(\S*)$/; 125 | function parseDateString(p_dateString) 126 | { 127 | var value = { 128 | year : 1900, 129 | month : 1, 130 | date : 1 131 | }; 132 | 133 | var matches = p_dateString.match(__regex_yyyyMD); 134 | if (isEmpty(matches)) 135 | { 136 | matches = p_dateString.match(__regex_yyyyM); 137 | if (isEmpty(matches)) 138 | { 139 | matches = [p_dateString, p_dateString]; 140 | } 141 | } 142 | if (notEmpty(matches)) 143 | { 144 | if (matches.length >= 2) 145 | { 146 | value.year = parseInt(matches[1], 10); 147 | if (isNaN(value.year)) 148 | { 149 | value.year = 1900; 150 | } 151 | } 152 | 153 | if (matches.length >= 3) 154 | { 155 | value.month = parseInt(matches[2], 10); 156 | if (isNaN(value.month) || value.month > 12 || value.month <= 0) 157 | { 158 | value.month = 1; 159 | } 160 | } 161 | 162 | if (matches.length >= 4) 163 | { 164 | var d_max = Date.getDaysInMonth(value.year, value.month - 1); 165 | value.date = parseInt(matches[3], 10); 166 | if (isNaN(value.date) || value.date <= 0) 167 | { 168 | value.date = 1; 169 | } 170 | else if (value.date > d_max) 171 | { 172 | value.date = d_max; 173 | } 174 | } 175 | } 176 | value.month -= 1; 177 | return value; 178 | } 179 | 180 | function parseDate(p_text) 181 | { 182 | if (isEmpty(p_text)) 183 | { 184 | return null; 185 | } 186 | if (isDate(p_text)) 187 | { 188 | return p_text; 189 | } 190 | 191 | var parts = null; 192 | var datePart = null; 193 | var timePart = null; 194 | p_text = p_text.trim(); 195 | if (p_text.indexOf(" ") !== -1) 196 | { 197 | parts = p_text.split(" "); 198 | } 199 | else if (p_text.indexOf("T") !== -1) 200 | { 201 | parts = p_text.split("T"); 202 | } 203 | 204 | if (isEmpty(parts)) 205 | { 206 | parts = [p_text]; 207 | } 208 | 209 | if (parts.length === 1) 210 | { 211 | if (parts[0].indexOf(":") !== -1) 212 | { 213 | timePart = parts[0]; 214 | } 215 | else 216 | { 217 | datePart = parts[0]; 218 | } 219 | } 220 | else if (parts.length === 2) 221 | { 222 | datePart = parts[0]; 223 | timePart = parts[1]; 224 | } 225 | 226 | var dateValue = { 227 | year : 1900, 228 | month : 0, 229 | date : 1 230 | }; 231 | if (notEmpty(datePart)) 232 | { 233 | dateValue = parseDateString(datePart); 234 | } 235 | 236 | var timeValue = { 237 | hours : 0, 238 | minutes : 0, 239 | seconds : 0 240 | }; 241 | if (notEmpty(timePart)) 242 | { 243 | timeValue = parseTimeString(timePart); 244 | } 245 | 246 | return new Date(dateValue.year, dateValue.month, dateValue.date, timeValue.hours, timeValue.minutes, timeValue.seconds); 247 | } 248 | 249 | // 命名空间 250 | function $namespace(p_namespace) 251 | { 252 | if (!/^[a-z]+[a-z0-9\._\$]*[a-z0-9]$/.test(p_namespace)) 253 | { 254 | throw new Error("Invalid namespace '" + p_namespace + "'."); 255 | } 256 | var parts = p_namespace.split("."); 257 | if (parts.length === 0) 258 | { 259 | return null; 260 | } 261 | 262 | var partialNS = null; 263 | var context = window; 264 | for (var i = 0; i < parts.length; i++) 265 | { 266 | partialNS = parts[i]; 267 | if (isEmpty(context[partialNS])) 268 | { 269 | context[partialNS] = {}; 270 | } 271 | context = context[partialNS]; 272 | } 273 | return context; 274 | } 275 | $ns = $namespace; 276 | 277 | // 继承 278 | function $extend(p_baseClass) 279 | { 280 | if (typeof (p_baseClass) === "function") 281 | { 282 | var inst = new p_baseClass(); 283 | inst.__class__ = $extend.caller; 284 | if (p_baseClass !== MXObject && p_baseClass !== MXComponent) 285 | { 286 | inst.__superClasses__.push(p_baseClass); 287 | } 288 | return inst; 289 | } 290 | } 291 | 292 | // 获取实例的类型。 293 | function $getclass(p_inst) 294 | { 295 | if (isEmpty(p_inst)) 296 | { 297 | return null; 298 | } 299 | switch (typeof (p_inst)) 300 | { 301 | case "boolean": 302 | return Boolean; 303 | 304 | case "number": 305 | return Number; 306 | 307 | case "string": 308 | return String; 309 | 310 | case "function": 311 | return Function; 312 | 313 | case "object": 314 | if (typeof (p_inst.getClass) === "function") 315 | { 316 | return p_inst.getClass(); 317 | } 318 | else if (isDate(p_inst)) 319 | { 320 | return Date; 321 | } 322 | else if (isArray(p_inst)) 323 | { 324 | return Array; 325 | } 326 | else 327 | { 328 | return Object; 329 | } 330 | break; 331 | default: 332 | return null; 333 | } 334 | } 335 | 336 | // 判断 p_inst 是否是 p_class 的实例。 337 | function $instanceof(p_inst, p_class) 338 | { 339 | if (isEmpty(p_inst)) 340 | { 341 | return false; 342 | } 343 | switch (typeof (p_inst)) 344 | { 345 | case "boolean": 346 | return p_class === Boolean; 347 | 348 | case "number": 349 | return p_class === Number; 350 | 351 | case "string": 352 | return p_class === String; 353 | 354 | case "function": 355 | return p_class === Function; 356 | 357 | case "object": 358 | if (typeof (p_inst.instanceOf) === "function") 359 | { 360 | return p_inst.instanceOf(p_class); 361 | } 362 | else if (isDate(p_inst)) 363 | { 364 | return p_class === Date; 365 | } 366 | else if (isArray(p_inst)) 367 | { 368 | return p_class === Array; 369 | } 370 | else 371 | { 372 | return true; 373 | } 374 | break; 375 | default: 376 | return false; 377 | } 378 | } 379 | 380 | // 格式化 381 | function $format(p_value, p_format) 382 | { 383 | if (isString(p_value) && (isArray(p_format) || isNumber(p_format) || isPlainObject(p_format))) 384 | { 385 | return String.format(p_value, p_format); 386 | } 387 | if (isNumber(p_value)) 388 | { 389 | return Number.format(p_value, p_format); 390 | } 391 | else if (isDate(p_value)) 392 | { 393 | return Date.format(p_value, p_format); 394 | } 395 | else 396 | { 397 | return notEmpty(p_value) ? p_value.toString() : ""; 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /scripts/mx/mx.build: -------------------------------------------------------------------------------- 1 | javascript-extensions.js 2 | framework-base.js 3 | framework-core.js -------------------------------------------------------------------------------- /scripts/mx/res/locales/en/language.js: -------------------------------------------------------------------------------- 1 | mx.locales["mx"] = { 2 | "language" : "en", 3 | 4 | "day_0" : "Sunday", 5 | "day_1" : "Monday", 6 | "day_2" : "Tuesday", 7 | "day_3" : "Wednesday", 8 | "day_4" : "Thursday", 9 | "day_5" : "Friday", 10 | "day_6" : "Saturday", 11 | 12 | "day_0_short" : "Sun", 13 | "day_1_short" : "Mon", 14 | "day_2_short" : "Tue", 15 | "day_3_short" : "Wed", 16 | "day_4_short" : "Thu", 17 | "day_5_short" : "Fri", 18 | "day_6_short" : "Sat", 19 | 20 | "day_0_shortest" : "S", 21 | "day_1_shortest" : "M", 22 | "day_2_shortest" : "T", 23 | "day_3_shortest" : "W", 24 | "day_4_shortest" : "T", 25 | "day_5_shortest" : "F", 26 | "day_6_shortest" : "S", 27 | 28 | "month_1" : "January", 29 | "month_2" : "February", 30 | "month_3" : "March", 31 | "month_4" : "April", 32 | "month_5" : "May", 33 | "month_6" : "June", 34 | "month_7" : "July", 35 | "month_8" : "August", 36 | "month_9" : "September", 37 | "month_10" : "October", 38 | "month_11" : "November", 39 | "month_12" : "December", 40 | 41 | "month_1_short" : "Jan", 42 | "month_2_short" : "Feb", 43 | "month_3_short" : "Mar", 44 | "month_4_short" : "Apr", 45 | "month_5_short" : "May", 46 | "month_6_short" : "Jun", 47 | "month_7_short" : "Jul", 48 | "month_8_short" : "Oct", 49 | "month_9_short" : "Sep", 50 | "month_10_short" : "Oct", 51 | "month_11_short" : "Nov", 52 | "month_12_short" : "Dec", 53 | 54 | "ok" : "OK", 55 | "cancel" : "Cancel", 56 | "yes" : "Yes", 57 | "no" : "No" 58 | }; 59 | -------------------------------------------------------------------------------- /scripts/mx/res/locales/zh-cn/language.js: -------------------------------------------------------------------------------- 1 | mx.locales["mx"] = { 2 | "language" : "zh-cn", 3 | 4 | "day_0" : "星期日", 5 | "day_1" : "星期一", 6 | "day_2" : "星期二", 7 | "day_3" : "星期三", 8 | "day_4" : "星期四", 9 | "day_5" : "星期五", 10 | "day_6" : "星期六", 11 | 12 | "day_0_short" : "周日", 13 | "day_1_short" : "周一", 14 | "day_2_short" : "周二", 15 | "day_3_short" : "周三", 16 | "day_4_short" : "周四", 17 | "day_5_short" : "周五", 18 | "day_6_short" : "周六", 19 | 20 | "day_0_shortest" : "日", 21 | "day_1_shortest" : "一", 22 | "day_2_shortest" : "二", 23 | "day_3_shortest" : "三", 24 | "day_4_shortest" : "四", 25 | "day_5_shortest" : "五", 26 | "day_6_shortest" : "六", 27 | 28 | "month_0" : "一月", 29 | "month_1" : "二月", 30 | "month_2" : "三月", 31 | "month_3" : "四月", 32 | "month_4" : "五月", 33 | "month_5" : "六月", 34 | "month_6" : "七月", 35 | "month_7" : "八月", 36 | "month_8" : "九月", 37 | "month_9" : "十月", 38 | "month_10" : "十一月", 39 | "month_11" : "十二月", 40 | 41 | "month_0_short" : "一月", 42 | "month_1_short" : "二月", 43 | "month_2_short" : "三月", 44 | "month_3_short" : "四月", 45 | "month_4_short" : "五月", 46 | "month_5_short" : "六月", 47 | "month_6_short" : "七月", 48 | "month_7_short" : "八月", 49 | "month_8_short" : "九月", 50 | "month_9_short" : "十月", 51 | "month_10_short" : "十一月", 52 | "month_11_short" : "十二月", 53 | 54 | "ok" : "确定", 55 | "cancel" : "取消", 56 | "yes" : "是", 57 | "no" : "否" 58 | }; 59 | -------------------------------------------------------------------------------- /scripts/mx/scn/Scene.js: -------------------------------------------------------------------------------- 1 | $ns("mx.scn"); 2 | 3 | mx.scn.Scene = function() 4 | { 5 | var me = $extend(mx.view.View); 6 | var base = {}; 7 | 8 | me.title = null; 9 | me.isActive = false; 10 | 11 | me.ontitlechanged = null; 12 | me.onactivate = null; 13 | me.ondeactivate = null; 14 | 15 | base.init = me.init; 16 | me.init = function(p_options) 17 | { 18 | base.init(p_options); 19 | me.$element.addClass("Scene"); 20 | }; 21 | 22 | me.setTitle = function(p_title) 23 | { 24 | if (me.title !== p_title) 25 | { 26 | me.title = p_title; 27 | me.trigger("titlechanged"); 28 | } 29 | }; 30 | 31 | me.activate = function(p_args, p_isBack) 32 | { 33 | me.isActive = true; 34 | me.trigger("activate", { 35 | args : p_args, 36 | isBack : p_isBack ? true : false 37 | }); 38 | }; 39 | 40 | me.deactivate = function() 41 | { 42 | me.isActive = false; 43 | me.trigger("deactivate"); 44 | }; 45 | 46 | me.toString = function() 47 | { 48 | return "Scene[" + me.id + "]"; 49 | }; 50 | 51 | return me.endOfClass(arguments); 52 | }; 53 | mx.scn.Scene.className = "mx.scn.Scene"; 54 | -------------------------------------------------------------------------------- /scripts/mx/util/ObjectPool.js: -------------------------------------------------------------------------------- 1 | $ns("mx.util"); 2 | 3 | mx.util.ObjectPool = function() 4 | { 5 | var me = $extend(MXComponent); 6 | var base = {}; 7 | 8 | me.initialSize = 0; 9 | me.maxSize = 0; 10 | me.stack = []; 11 | 12 | base.init = me.init; 13 | me.init = function(p_options) 14 | { 15 | base.init(p_options); 16 | if (me.initialSize > 0 && me.stack.length < me.initialSize) 17 | { 18 | while (me.stack.length < me.initialSize) 19 | { 20 | var obj = me.createObject(); 21 | me.addObject(obj); 22 | } 23 | } 24 | }; 25 | 26 | me.borrowObject = function() 27 | { 28 | if (me.stack.length === 0) 29 | { 30 | var obj = me.createObject(); 31 | return obj; 32 | } 33 | else 34 | { 35 | return me.stack.pop(); 36 | } 37 | }; 38 | 39 | me.returnObject = function(p_object) 40 | { 41 | if (notEmpty(p_object) && (me.maxSize === 0 || me.stack.length < me.maxSize)) 42 | { 43 | me.addObject(p_object); 44 | } 45 | }; 46 | 47 | me.addObject = function(p_object) 48 | { 49 | me.stack.push(p_object); 50 | }; 51 | 52 | me.removeObject = function(p_object) 53 | { 54 | me.stack.remove(p_object); 55 | }; 56 | 57 | me.createObject = function() 58 | { 59 | throw new Error("Must implement 'createObject()' function of the ObjectPool."); 60 | }; 61 | 62 | me.clear = function() 63 | { 64 | me.stack.clear(); 65 | }; 66 | 67 | return me.endOfClass(arguments); 68 | }; 69 | mx.util.ObjectPool.className = "mx.util.ObjectPool"; 70 | -------------------------------------------------------------------------------- /scripts/mx/view/View.js: -------------------------------------------------------------------------------- 1 | $ns("mx.view"); 2 | 3 | mx.view.View = function() 4 | { 5 | var me = $extend(MXComponent); 6 | var base = {}; 7 | 8 | me.id = null; 9 | me.$element = null; 10 | me.$container = null; 11 | me.elementTag = "div"; 12 | me.elementClass = null; 13 | me.elementStyle = null; 14 | me.elementPositionMode = "relative"; 15 | 16 | me.frame = null; 17 | 18 | me.parentView = null; 19 | me.subviews = []; 20 | 21 | base._ = me._; 22 | me._ = function(p_options) 23 | { 24 | if (notEmpty(me.frame) && notEmpty(p_options) && notEmpty(p_options.frame)) 25 | { 26 | p_options.frame = $.extend(me.frame, p_options.frame); 27 | } 28 | base._(p_options); 29 | }; 30 | 31 | base.init = me.init; 32 | me.init = function(p_options) 33 | { 34 | base.init(p_options); 35 | 36 | if (isEmpty(me.$element)) 37 | { 38 | me.$element = $("<" + me.elementTag + "/>"); 39 | } 40 | if (isEmpty(me.$container)) 41 | { 42 | me.$container = me.$element; 43 | } 44 | 45 | if (notEmpty(me.$element.attr("id")) && isEmpty(me.id)) 46 | { 47 | me.id = me.$element.attr("id"); 48 | } 49 | 50 | if (isEmpty(me.id) && isEmpty(me.$element.attr("id"))) 51 | { 52 | me.id = String.newGuid(); 53 | } 54 | me.$element.attr("id", me.id); 55 | if (mx.debugMode) 56 | { 57 | me.$element.data("view", me); 58 | } 59 | 60 | me.$element.css({ 61 | "position" : me.elementPositionMode 62 | }); 63 | 64 | if (notEmpty(me.elementClass)) 65 | { 66 | me.$element.addClass(me.elementClass); 67 | } 68 | 69 | if (isPlainObject(me.elementStyle)) 70 | { 71 | me.css(me.elementStyle); 72 | } 73 | 74 | me.setFrame(me.frame); 75 | 76 | if (me.subviews.length > 0) 77 | { 78 | var subviews = me.subviews.clone(); 79 | me.subviews.clear(); 80 | me.addSubviews(subviews); 81 | } 82 | }; 83 | 84 | me.setFrame = function(p_frame, p_animated) 85 | { 86 | if (notEmpty(p_frame)) 87 | { 88 | if (notEmpty(me.frame)) 89 | { 90 | me.frame = $.extend(me.frame, p_frame); 91 | } 92 | else 93 | { 94 | me.frame = p_frame; 95 | } 96 | 97 | if (p_animated) 98 | { 99 | me.$element.animate(me.frame, p_animated); 100 | } 101 | else 102 | { 103 | me.$element.css(me.frame); 104 | } 105 | 106 | if (notEmpty(me.frame.left) || notEmpty(me.frame.right) || notEmpty(me.frame.top) || notEmpty(me.frame.bottom)) 107 | { 108 | me.$element.css("position", "absolute"); 109 | } 110 | } 111 | }; 112 | 113 | me.addSubview = function(p_view, $p_element) 114 | { 115 | if (typeof ($p_element) === "undefined") 116 | { 117 | $p_element = me.$container; 118 | } 119 | 120 | if (isFunction(p_view.placeAt)) 121 | { 122 | var $container = $("
    "); 123 | p_view.placeAt($container); 124 | $p_element.append($container); 125 | return; 126 | } 127 | 128 | if ($instanceof(p_view, mx.view.View)) 129 | { 130 | if (p_view.parentView === me) 131 | { 132 | return; 133 | } 134 | 135 | if (notEmpty(p_view.parentView)) 136 | { 137 | p_view.parentView.removeSubview(p_view); 138 | } 139 | 140 | if (notEmpty($p_element)) 141 | { 142 | $p_element.append(p_view.$element); 143 | } 144 | me.subviews.add(p_view); 145 | 146 | if (notEmpty(p_view.id)) 147 | { 148 | me.subviews[p_view.id] = p_view; 149 | } 150 | p_view.parentView = me; 151 | } 152 | }; 153 | 154 | me.addSubviews = function(p_views, $p_element) 155 | { 156 | if (isArray(p_views)) 157 | { 158 | p_views.forEach(function(p_view) 159 | { 160 | me.addSubview(p_view, $p_element); 161 | }); 162 | } 163 | }; 164 | 165 | me.removeSubview = function(p_view) 166 | { 167 | if ($instanceof(p_view, mx.view.View)) 168 | { 169 | p_view.$element.detach(); 170 | me.subviews.remove(p_view); 171 | if (notEmpty(p_view.id)) 172 | { 173 | me.subviews[p_view.id] = null; 174 | delete me.subviews[p_view.id]; 175 | } 176 | p_view.parentView = null; 177 | p_view = null; 178 | } 179 | }; 180 | 181 | me.clearSubviews = function() 182 | { 183 | while (me.subviews.length > 0) 184 | { 185 | me.removeSubview(me.subviews[0]); 186 | } 187 | }; 188 | 189 | me.css = function(p_attrName, p_attrValue) 190 | { 191 | if (arguments.length === 1) 192 | { 193 | return me.$element.css(p_attrName); 194 | } 195 | else if (arguments.length >= 2) 196 | { 197 | return me.$element.css(p_attrName, p_attrValue); 198 | } 199 | }; 200 | 201 | me.show = function(p_options) 202 | { 203 | me.$element.show(p_options); 204 | }; 205 | 206 | me.hide = function(p_options) 207 | { 208 | me.$element.hide(p_options); 209 | }; 210 | 211 | me.toString = function() 212 | { 213 | return "View[" + me.id + "]"; 214 | }; 215 | 216 | return me.endOfClass(arguments); 217 | }; 218 | mx.view.View.className = "mx.view.View"; 219 | 220 | $view = function(p_element) 221 | { 222 | var $e = $(p_element); 223 | while ($e.length !== 0 && isEmpty($e.data("view"))) 224 | { 225 | $e = $e.parent(); 226 | } 227 | return $e.data("view"); 228 | }; 229 | -------------------------------------------------------------------------------- /scripts/mx3d/res/Scene3DView.css: -------------------------------------------------------------------------------- 1 | .Scene3DView > #analyphEffect 2 | { 3 | position: absolute; 4 | background: url(images/3d-glasses.png); 5 | width: 48px; 6 | height: 48px; 7 | bottom: 10px; 8 | left: 10px; 9 | cursor: pointer; 10 | } 11 | 12 | .Scene3DView > #analyphEffect.enabled 13 | { 14 | background: url(images/3d-glasses-enabled.png); 15 | } -------------------------------------------------------------------------------- /scripts/mx3d/res/images/3d-glasses-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/mx3d/res/images/3d-glasses-enabled.png -------------------------------------------------------------------------------- /scripts/mx3d/res/images/3d-glasses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MagicCube/g3d/f0e26e25f28b0bf7095643a077a5d20b5fe867f8/scripts/mx3d/res/images/3d-glasses.png -------------------------------------------------------------------------------- /scripts/mx3d/res/materials/alphaGradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /scripts/mx3d/util/ShaderMaterialBuilder.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.util"); 2 | 3 | mx3d.util.ShaderMaterialBuilder = function() 4 | { 5 | var me = $extend(MXObject); 6 | var base = {}; 7 | 8 | me.url = null; 9 | me.parameters = {}; 10 | me.attributes = {}; 11 | me.uniforms = {}; 12 | 13 | var _vertexShader = null; 14 | var _fragmentShader = null; 15 | 16 | base._ = me._; 17 | me._ = function(p_options) 18 | { 19 | if (me.canConstruct()) 20 | { 21 | base._(p_options); 22 | 23 | if (p_options != null && p_options.uniforms != null) 24 | { 25 | me.uniforms = $.extend(p_options.uniforms, me.uniforms); 26 | } 27 | if (p_options != null && p_options.attributes != null) 28 | { 29 | me.attributes = $.extend(p_options.attributes, me.attributes); 30 | } 31 | 32 | if (me.url != null) 33 | { 34 | me.loadXML(me.url); 35 | } 36 | } 37 | }; 38 | 39 | me.loadXML = function(p_url) 40 | { 41 | me.url = p_url; 42 | $.ajax({ 43 | dataType : "xml", 44 | url : p_url, 45 | async : false 46 | }).success(function(p_result) 47 | { 48 | var $xml = $(p_result); 49 | _vertexShader = $xml.find("material > script[id=vertexShader]").text(); 50 | _fragmentShader = $xml.find("material > script[id=fragmentShader]").text(); 51 | $xml = null; 52 | p_result = null; 53 | }); 54 | }; 55 | 56 | me.setAttributeValues = function(p_name, p_values, p_type) 57 | { 58 | var type = p_type; 59 | if (p_type == null) 60 | { 61 | type = _getType(p_values[0]); 62 | } 63 | me.attributes[p_name] = { 64 | t : type, 65 | value : p_values 66 | }; 67 | }; 68 | 69 | me.setAttributeValue = function(p_name, p_value, p_type) 70 | { 71 | if (me.attributes[p_name] == null) 72 | { 73 | var values = []; 74 | me.setAttributeValues(p_name, values, _getType(p_value, p_type)); 75 | } 76 | var attr = me.attributes[p_name]; 77 | attr.value.add(p_value); 78 | }; 79 | 80 | me.setUniformValue = function(p_name, p_value, p_type) 81 | { 82 | var type = p_type; 83 | if (p_type == null) 84 | { 85 | type = _getType(p_value); 86 | } 87 | var uniform = { 88 | type : type, 89 | value : p_value 90 | }; 91 | me.uniforms[p_name] = uniform; 92 | return uniform; 93 | }; 94 | 95 | me.build = function() 96 | { 97 | var params = $.extend({}, me.parameters); 98 | params.attributes = $.extend({}, me.attributes); 99 | params.uniforms = $.extend({}, me.uniforms); 100 | params.vertexShader = _vertexShader; 101 | params.fragmentShader = _fragmentShader; 102 | var shaderMaterial = new THREE.ShaderMaterial(params); 103 | return shaderMaterial; 104 | }; 105 | 106 | function _getType(p_value, p_type) 107 | { 108 | if (typeof (p_value) === "number") 109 | { 110 | return "f"; 111 | } 112 | else if (p_value instanceof THREE.Color) 113 | { 114 | return "c"; 115 | } 116 | else if (p_value instanceof THREE.Texture) 117 | { 118 | return "t"; 119 | } 120 | return p_type; 121 | } 122 | 123 | return me.endOfClass(arguments); 124 | }; 125 | mx3d.util.ShaderMaterialBuilder.className = "mx3d.util.ShaderMaterialBuilder"; 126 | -------------------------------------------------------------------------------- /scripts/mx3d/view/AnimatedScene3DView.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.view"); 2 | 3 | $import("lib.tween.Tween"); 4 | $import("lib.threejs.three", function() 5 | { 6 | $import("lib.threejs.plugins.stats"); 7 | $import("lib.threejs.controls.TrackballControls"); 8 | }); 9 | 10 | $import("mx3d.view.Scene3DView"); 11 | 12 | mx3d.view.AnimatedScene3DView = function() 13 | { 14 | var me = $extend(mx3d.view.Scene3DView); 15 | var base = {}; 16 | 17 | me.cameraControlsEnabled = false; 18 | me.statsVisible = false; 19 | me.animating = true; 20 | me.playState = null; 21 | me.frameIndex = 0; 22 | me.stats = null; 23 | me.cameraControls = null; 24 | me.onframing = null; 25 | 26 | base.init = me.init; 27 | me.init = function(p_options) 28 | { 29 | base.init(p_options); 30 | me.$element.addClass("AnimatedScene3DView"); 31 | }; 32 | 33 | base.init3D = me.init3D; 34 | me.init3D = function() 35 | { 36 | base.init3D(); 37 | me.initStats(); 38 | me.initControls(); 39 | }; 40 | 41 | me.initControls = function() 42 | { 43 | me.initCameraControls(); 44 | }; 45 | 46 | me.initCameraControls = function() 47 | { 48 | if (me.cameraControlsEnabled && me.cameraControls == null) 49 | { 50 | me.cameraControls = new THREE.TrackballControls(me.camera, me.$element.find("canvas")[0]); 51 | } 52 | }; 53 | 54 | me.initStats = function() 55 | { 56 | if (me.statsVisible && me.stats == null) 57 | { 58 | me.stats = new Stats(); 59 | me.stats.domElement.style.position = 'absolute'; 60 | me.stats.domElement.style.right = '5px'; 61 | me.stats.domElement.style.bottom = '5px'; 62 | me.stats.domElement.style.whiteSpace = "nowrap"; 63 | me.$container.append(me.stats.domElement); 64 | } 65 | }; 66 | 67 | me.startAnimation = function() 68 | { 69 | me.animating = true; 70 | me.renderLoop(); 71 | }; 72 | 73 | me.stopAnimation = function() 74 | { 75 | me.animating = false; 76 | }; 77 | 78 | me.renderLoop = function() 79 | { 80 | me.trigger("framing"); 81 | if (me.cameraControlsEnabled) 82 | { 83 | if (me.cameraControls == null) 84 | { 85 | me.initCameraControls(); 86 | } 87 | if (!me.cameraControls.enabled) 88 | { 89 | me.cameraControls.enabled = true; 90 | } 91 | me.cameraControls.update(); 92 | } 93 | else 94 | { 95 | if (me.cameraControls != null && me.cameraControls.enabled) 96 | { 97 | me.cameraControls.enabled = false; 98 | } 99 | } 100 | 101 | me.update(); 102 | me.render(); 103 | 104 | if (me.statsVisible) 105 | { 106 | if (me.stats == null) 107 | { 108 | me.initStats(); 109 | } 110 | me.stats.update(); 111 | } 112 | 113 | if (me.animating) 114 | { 115 | requestAnimationFrame(me.renderLoop); 116 | } 117 | }; 118 | 119 | me.moveCamera = function(p_position, p_rotation, p_duration, p_up) 120 | { 121 | var deferred = $.Deferred(); 122 | 123 | var duration = p_duration; 124 | if (duration == null) 125 | { 126 | duration = 1000; 127 | } 128 | 129 | me.cameraControlsEnabled = false; 130 | 131 | if (p_position != null) 132 | { 133 | new TWEEN.Tween(me.camera.position).to(p_position, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 134 | } 135 | 136 | if (p_rotation != null) 137 | { 138 | new TWEEN.Tween(me.camera.rotation).to(p_rotation, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 139 | } 140 | 141 | if (p_up != null) 142 | { 143 | new TWEEN.Tween(me.cameraControls.object.up).to(p_up, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 144 | } 145 | else 146 | { 147 | me.cameraControls.reset(); 148 | } 149 | 150 | setTimeout(function() 151 | { 152 | me.cameraControlsEnabled = true; 153 | deferred.resolve(); 154 | }, duration); 155 | return deferred; 156 | }; 157 | 158 | me.moveCameraTarget = function(p_position, p_duration) 159 | { 160 | var deferred = $.Deferred(); 161 | 162 | if (p_position != null) 163 | { 164 | var duration = p_duration; 165 | if (duration == null) 166 | { 167 | duration = 1000; 168 | } 169 | 170 | me.cameraControlsEnabled = false; 171 | new TWEEN.Tween(me.cameraControls.target).to(p_position, duration).easing(TWEEN.Easing.Sinusoidal.Out).onComplete(function() 172 | { 173 | me.cameraControlsEnabled = true; 174 | deferred.resolve(); 175 | }).start(); 176 | } 177 | else 178 | { 179 | deferred.resolve(); 180 | } 181 | return deferred; 182 | }; 183 | 184 | me.focusLine = function(p_vector1, p_vector2, p_overlookDegree, p_duration, p_debug) 185 | { 186 | var deferred = $.Deferred(); 187 | 188 | var material = null; 189 | var geometry = null; 190 | var line = null; 191 | 192 | if (p_duration == null) 193 | { 194 | p_duration = 1000; 195 | } 196 | 197 | if (p_debug == null) 198 | { 199 | p_debug = false; 200 | } 201 | 202 | if (p_debug) 203 | { 204 | material = new THREE.LineBasicMaterial({ 205 | color : 0xffffff 206 | }); 207 | geometry = new THREE.Geometry(); 208 | geometry.vertices.push(p_vector1); 209 | geometry.vertices.push(p_vector2); 210 | line = new THREE.Line(geometry, material); 211 | me.addObject(line); 212 | var arrowGeometry = new THREE.CubeGeometry(80, 80, 80); 213 | var arrow = new THREE.Mesh(arrowGeometry); 214 | arrow.position.copy(p_vector2); 215 | me.addObject(arrow); 216 | } 217 | 218 | var mVector = p_vector1.clone(); 219 | mVector = mVector.lerp(p_vector2, 0.5); 220 | 221 | var cVector = new THREE.Vector3(); 222 | cVector.subVectors(p_vector2, p_vector1); 223 | var vLength = cVector.length(); 224 | 225 | var quaternion = new THREE.Quaternion(); 226 | var axis = new THREE.Vector3(0, 0, 1); 227 | quaternion.setFromAxisAngle(axis, -Math.PI / 2); 228 | cVector.applyQuaternion(quaternion); 229 | 230 | var angle = (90 - me.camera.fov / 2) * Math.PI / 180; 231 | var focusLength = vLength * 0.5 * Math.tan(angle); 232 | cVector.normalize().multiplyScalar(focusLength); 233 | 234 | var overlookAngle = p_overlookDegree * Math.PI / 180; 235 | cVector.z = focusLength * Math.tan(overlookAngle); 236 | cVector.add(mVector); 237 | 238 | if (p_debug) 239 | { 240 | material = new THREE.LineBasicMaterial({ 241 | color : 0xffffff 242 | }); 243 | geometry = new THREE.Geometry(); 244 | geometry.vertices.push(mVector); 245 | geometry.vertices.push(cVector); 246 | line = new THREE.Line(geometry, material); 247 | me.addObject(line); 248 | } 249 | 250 | if (me.cameraControlsEnabled && me.cameraControls != null) 251 | { 252 | me.cameraControlsEnabled = false; 253 | 254 | var duration = p_duration; 255 | new TWEEN.Tween(me.cameraControls.target).to(mVector, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 256 | new TWEEN.Tween(me.camera.position).to(cVector, duration).easing(TWEEN.Easing.Sinusoidal.Out).onUpdate(function() 257 | { 258 | me.camera.lookAt(me.cameraControls.target); 259 | }).start(); 260 | new TWEEN.Tween(me.cameraControls.object.up).to({ 261 | x : 0, 262 | y : 0, 263 | z : 1 264 | }, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 265 | 266 | setTimeout(function() 267 | { 268 | me.cameraControlsEnabled = true; 269 | deferred.resolve(); 270 | }, duration); 271 | } 272 | 273 | return deferred; 274 | }; 275 | 276 | me.focusTriangle = function(p_vector1, p_vector2, p_vector3, p_overlookDegree, p_duration, p_debug) 277 | { 278 | var deferred = $.Deferred(); 279 | 280 | var material = null; 281 | var geometry = null; 282 | var line = null; 283 | 284 | if (p_duration == null) 285 | { 286 | p_duration = 1000; 287 | } 288 | 289 | if (p_debug == null) 290 | { 291 | p_debug = false; 292 | } 293 | 294 | if (p_debug) 295 | { 296 | material = new THREE.LineBasicMaterial({ 297 | color : 0xffffff 298 | }); 299 | geometry = new THREE.Geometry(); 300 | geometry.vertices.push(p_vector1); 301 | geometry.vertices.push(p_vector2); 302 | geometry.vertices.push(p_vector3); 303 | geometry.vertices.push(p_vector1); 304 | line = new THREE.Line(geometry, material); 305 | me.addObject(line); 306 | var arrowGeometry = new THREE.CubeGeometry(80, 80, 80); 307 | var arrow = new THREE.Mesh(arrowGeometry); 308 | arrow.position.copy(p_vector2); 309 | me.addObject(arrow); 310 | } 311 | 312 | var mVector = p_vector1.clone(); 313 | mVector = mVector.lerp(p_vector2, 0.5); 314 | 315 | var cVector = new THREE.Vector3(); 316 | cVector.subVectors(p_vector2, p_vector1); 317 | var vLength = cVector.length(); 318 | 319 | var quaternion = new THREE.Quaternion(); 320 | var axis = new THREE.Vector3(0, 0, 1); 321 | quaternion.setFromAxisAngle(axis, -Math.PI / 2); 322 | cVector.applyQuaternion(quaternion); 323 | 324 | var angle = (90 - me.camera.fov / 2) * Math.PI / 180; 325 | var overlookAngle = p_overlookDegree * Math.PI / 180; 326 | 327 | var focusLength1 = vLength * 0.5 * Math.tan(angle); 328 | var height = Math.abs(p_vector3.z) + 100; 329 | var focusLength2 = height * (Math.sin(overlookAngle) + Math.cos(overlookAngle) * Math.tan(angle)) * Math.cos(overlookAngle); 330 | var focusLength = focusLength1 > focusLength2 ? focusLength1 : focusLength2; 331 | 332 | cVector.normalize().multiplyScalar(focusLength); 333 | cVector.z = focusLength * Math.tan(overlookAngle); 334 | cVector.add(mVector); 335 | 336 | if (p_debug) 337 | { 338 | material = new THREE.LineBasicMaterial({ 339 | color : 0xffffff 340 | }); 341 | geometry = new THREE.Geometry(); 342 | geometry.vertices.push(mVector); 343 | geometry.vertices.push(cVector); 344 | line = new THREE.Line(geometry, material); 345 | me.addObject(line); 346 | } 347 | 348 | if (me.cameraControlsEnabled && me.cameraControls != null) 349 | { 350 | me.cameraControlsEnabled = false; 351 | 352 | var duration = p_duration; 353 | new TWEEN.Tween(me.cameraControls.target).to(mVector, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 354 | new TWEEN.Tween(me.camera.position).to(cVector, duration).easing(TWEEN.Easing.Sinusoidal.Out).onUpdate(function() 355 | { 356 | me.camera.lookAt(me.cameraControls.target); 357 | }).start(); 358 | new TWEEN.Tween(me.cameraControls.object.up).to({ 359 | x : 0, 360 | y : 0, 361 | z : 1 362 | }, duration).easing(TWEEN.Easing.Sinusoidal.Out).start(); 363 | 364 | setTimeout(function() 365 | { 366 | me.cameraControlsEnabled = true; 367 | deferred.resolve(); 368 | }, duration); 369 | } 370 | 371 | return deferred; 372 | }; 373 | 374 | base.update = me.update; 375 | me.update = function(p_forceUpdate) 376 | { 377 | TWEEN.update(); 378 | base.update(p_forceUpdate); 379 | }; 380 | 381 | return me.endOfClass(arguments); 382 | }; 383 | mx3d.view.AnimatedScene3DView.className = "mx3d.view.AnimatedScene3DView"; 384 | -------------------------------------------------------------------------------- /scripts/mx3d/view/LabelView.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.view"); 2 | 3 | mx3d.view.LabelView = function() 4 | { 5 | var me = $extend(mx.view.View); 6 | var base = {}; 7 | 8 | me.position = null; 9 | me.text = null; 10 | me.fontSize = 16; 11 | 12 | me.camera = null; 13 | me.projector = null; 14 | 15 | me.clickable = false; 16 | 17 | base.init = me.init; 18 | me.init = function(p_options) 19 | { 20 | base.init(p_options); 21 | me.$container.addClass("LabelView"); 22 | me.$container.css({ 23 | position : "absolute" 24 | }); 25 | 26 | if (me.clickable) 27 | { 28 | me.$container.css("cursor", "pointer"); 29 | } 30 | 31 | if (me.text != null) 32 | { 33 | me.setText(me.text); 34 | } 35 | }; 36 | 37 | me.setText = function(p_text) 38 | { 39 | me.text = p_text; 40 | me.$container.text(me.text != null ? me.text : ""); 41 | }; 42 | 43 | me.setHtml = function(p_html) 44 | { 45 | me.$container.html(p_html != null ? p_html : ""); 46 | me.text = me.$container.text(); 47 | }; 48 | 49 | me.update = function() 50 | { 51 | var position = me.position.clone(); 52 | me.projector.projectVector(position, me.camera); 53 | var position2D = { 54 | x : (position.x + 1) / 2 * me.projector.frame.width, 55 | y : -(position.y - 1) / 2 * me.projector.frame.height, 56 | z : position.z 57 | }; 58 | 59 | me.setFrame({ 60 | left : position2D.x, 61 | top : position2D.y 62 | }); 63 | 64 | if (position2D.z < 1) 65 | { 66 | var scale = (1 - position2D.z) * 50; 67 | 68 | var fontSize = me.fontSize / 4 * scale; 69 | me.$container.css({ 70 | display : "block", 71 | fontSize : fontSize 72 | }); 73 | } 74 | else 75 | { 76 | me.$container.css({ 77 | display : "none" 78 | }); 79 | } 80 | }; 81 | 82 | return me.endOfClass(arguments); 83 | }; 84 | mx3d.view.LabelView.className = "mx3d.view.LabelView"; 85 | -------------------------------------------------------------------------------- /scripts/mx3d/view/MXComponent3D.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.view"); 2 | 3 | mx3d.view.MXComponent3D = function() 4 | { 5 | var me = $extend(MXComponent); 6 | var base = {}; 7 | 8 | me.id = null; 9 | me.object3D = null; 10 | me.parentView = null; 11 | me.parentObject3D = null; 12 | 13 | me.needsUpdate = false; 14 | 15 | base.init = me.init; 16 | me.init = function(p_options) 17 | { 18 | base.init(p_options); 19 | 20 | if (me.object3D == null) 21 | { 22 | me.initObject3D(); 23 | } 24 | 25 | if (me.object3D != null) 26 | { 27 | me.object3D.id = me.id; 28 | } 29 | }; 30 | 31 | me.initObject3D = function() 32 | { 33 | me.object3D = new THREE.Object3D(); 34 | }; 35 | 36 | me.addObject = function(p_object) 37 | { 38 | me.object3D.add(p_object); 39 | }; 40 | me.removeObject = function(p_object) 41 | { 42 | me.object3D.remove(p_object); 43 | }; 44 | 45 | me.update = function(p_forceUpdate) 46 | { 47 | 48 | }; 49 | 50 | return me.endOfClass(arguments); 51 | }; 52 | mx3d.view.MXComponent3D.className = "mx3d.view.MXComponent3D"; 53 | -------------------------------------------------------------------------------- /scripts/mx3d/view/MXObject3D.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.view"); 2 | 3 | mx3d.view.MXObject3D = function() 4 | { 5 | var me = $extend(MXComponent); 6 | var base = {}; 7 | 8 | me.id = null; 9 | me.object3D = null; 10 | me.parentView = null; 11 | me.parentObject3D = null; 12 | 13 | me.needsUpdate = false; 14 | 15 | base.init = me.init; 16 | me.init = function(p_options) 17 | { 18 | base.init(p_options); 19 | 20 | if (me.object3D == null) 21 | { 22 | me.initObject3D(); 23 | } 24 | 25 | if (me.object3D != null) 26 | { 27 | me.object3D.id = me.id; 28 | } 29 | }; 30 | 31 | me.initObject3D = function() 32 | { 33 | me.object3D = new THREE.Object3D(); 34 | }; 35 | 36 | me.addObject = function(p_object) 37 | { 38 | me.object3D.add(p_object); 39 | }; 40 | me.removeObject = function(p_object) 41 | { 42 | me.object3D.remove(p_object); 43 | }; 44 | 45 | me.update = function(p_forceUpdate) 46 | { 47 | 48 | }; 49 | 50 | return me.endOfClass(arguments); 51 | }; 52 | mx3d.view.MXObject3D.className = "mx3d.view.MXObject3D"; 53 | -------------------------------------------------------------------------------- /scripts/mx3d/view/Scene3DView.js: -------------------------------------------------------------------------------- 1 | $ns("mx3d.view"); 2 | 3 | $import("lib.threejs.three", function() 4 | { 5 | $import("lib.threejs.effects.AnaglyphEffect"); 6 | 7 | $import("lib.threejs.shaders.ColorCorrectionShader"); 8 | $import("lib.threejs.shaders.CopyShader"); 9 | $import("lib.threejs.shaders.BokehShader"); 10 | $import("lib.threejs.shaders.DotScreenShader"); 11 | $import("lib.threejs.shaders.FXAAShader"); 12 | $import("lib.threejs.shaders.HorizontalTiltShiftShader"); 13 | $import("lib.threejs.shaders.RGBShiftShader"); 14 | $import("lib.threejs.shaders.ShaderExtras"); 15 | $import("lib.threejs.shaders.SSAOShader"); 16 | $import("lib.threejs.shaders.VerticalTiltShiftShader"); 17 | $import("lib.threejs.shaders.VignetteShader"); 18 | 19 | $import("lib.threejs.postprocessing.EffectComposer"); 20 | $import("lib.threejs.postprocessing.BokehPass"); 21 | $import("lib.threejs.postprocessing.MaskPass"); 22 | $import("lib.threejs.postprocessing.RenderPass"); 23 | $import("lib.threejs.postprocessing.SavePass"); 24 | $import("lib.threejs.postprocessing.ShaderPass"); 25 | 26 | $import("lib.threejs.plugins.DepthPassPlugin"); 27 | }); 28 | 29 | $import("mx3d.view.LabelView"); 30 | 31 | $include("mx3d.res.Scene3DView.css"); 32 | 33 | mx3d.view.Scene3DView = function() 34 | { 35 | var me = $extend(mx.view.View); 36 | me.frame = { 37 | width : window.innerWidth, 38 | height : window.innerHeight 39 | }; 40 | var base = {}; 41 | 42 | me.scene = null; 43 | 44 | me.camera = null; 45 | me.cameraParams = null; 46 | 47 | me.renderMode = "renderer"; 48 | me.renderer = null; 49 | me.rendererParams = null; 50 | 51 | me.clickable = false; 52 | me.clickableObjects = []; 53 | 54 | me.anaglyphEffectEnabled = false; 55 | me.displayAnalyphEffectButton = false; 56 | 57 | me.labelViews = []; 58 | 59 | me.$anaglyphEffectButton = null; 60 | 61 | me.onobjectclick = null; 62 | me.onlabelviewclick = null; 63 | 64 | base.init = me.init; 65 | me.init = function(p_options) 66 | { 67 | base.init(p_options); 68 | me.init3D(); 69 | 70 | me.$element.addClass("Scene3DView"); 71 | me.$element.css("overflow", "hidden"); 72 | me.$element.on("mouseup", _onmouseup); 73 | me.$element.on("click", ".LabelView", _labelView_onclick); 74 | }; 75 | 76 | me.init3D = function() 77 | { 78 | me.initScene(); 79 | me.initCamera(); 80 | me.initRenderer(); 81 | me.initEffects(); 82 | me.initObjects(); 83 | me.initLights(); 84 | 85 | if (me.displayAnalyphEffectButton) 86 | { 87 | me.initAnalyEffectButton(); 88 | } 89 | }; 90 | 91 | me.initScene = function() 92 | { 93 | me.scene = new THREE.Scene(); 94 | }; 95 | 96 | me.initCamera = function() 97 | { 98 | var params = $.extend({ 99 | fov : 45, 100 | aspect : me.frame.width / me.frame.height, 101 | near : 0.01, 102 | far : 10000 103 | }, me.cameraParams); 104 | me.camera = new THREE.PerspectiveCamera(params.fov, params.aspect, params.near, params.far); 105 | if (params.position != null) 106 | { 107 | if (isArray(params.position)) 108 | { 109 | me.camera.position.fromArray(params.position); 110 | } 111 | else 112 | { 113 | var position = $.extend({ 114 | x : 0, 115 | y : 0, 116 | z : 0 117 | }, params.position); 118 | me.camera.position.copy(position); 119 | } 120 | } 121 | if (params.rotation != null) 122 | { 123 | if (isArray(params.rotation)) 124 | { 125 | me.camera.rotation.fromArray(params.rotation); 126 | } 127 | else 128 | { 129 | var rotation = $.extend({ 130 | x : 0, 131 | y : 0, 132 | z : 0 133 | }, params.rotation); 134 | me.camera.rotation.copy(rotation); 135 | } 136 | } 137 | me.addObject(me.camera); 138 | }; 139 | 140 | me.initRenderer = function() 141 | { 142 | var params = $.extend({ 143 | antialias : true 144 | }, me.rendererParams); 145 | me.renderer = new THREE.WebGLRenderer(params); 146 | me.renderer.setSize(me.frame.width, me.frame.height); 147 | me.renderer.gammaInput = true; 148 | me.renderer.gammaOutput = true; 149 | me.renderer.physicallyBasedShading = true; 150 | me.renderer.shadowMapEnabled = true; 151 | me.renderer.shadowMapSoft = true; 152 | me.$container.append(me.renderer.domElement); 153 | 154 | if (me.renderMode === "composer") 155 | { 156 | me.initComposer(); 157 | } 158 | }; 159 | 160 | me.initComposer = function() 161 | { 162 | me.composer = new THREE.EffectComposer(me.renderer); 163 | }; 164 | 165 | me.initEffects = function() 166 | { 167 | if (me.anaglyphEffectEnabled && me.anaglyphEffect == null) 168 | { 169 | me.anaglyphEffect = new THREE.AnaglyphEffect(me.renderer); 170 | me.anaglyphEffect.setSize(me.frame.width, me.frame.height); 171 | } 172 | }; 173 | 174 | me.initAnalyEffectButton = function() 175 | { 176 | me.$anaglyphEffectButton = $("
    "); 177 | me.$anaglyphEffectButton.on("click", function(e) 178 | { 179 | if (e.button !== 0) 180 | { 181 | return; 182 | } 183 | e.preventDefault(); 184 | me.anaglyphEffectEnabled = !me.anaglyphEffectEnabled; 185 | me.$anaglyphEffectButton.toggleClass("enabled", me.anaglyphEffectEnabled); 186 | }); 187 | me.$container.append(me.$anaglyphEffectButton); 188 | }; 189 | 190 | me.initObjects = function() 191 | { 192 | 193 | }; 194 | 195 | me.initLights = function() 196 | { 197 | 198 | }; 199 | 200 | me.addObject = function(p_object) 201 | { 202 | me.scene.add(p_object); 203 | }; 204 | me.removeObject = function(p_object) 205 | { 206 | me.scene.remove(p_object); 207 | }; 208 | 209 | me.addLight = function(p_light, p_helperClass) 210 | { 211 | me.scene.add(p_light); 212 | 213 | if (p_helperClass != null) 214 | { 215 | var helper = null; 216 | helper = new p_helperClass(p_light); 217 | me.addObject(helper); 218 | } 219 | }; 220 | me.removeLight = function(p_light) 221 | { 222 | me.scene.remove(p_light); 223 | }; 224 | 225 | me.render = function() 226 | { 227 | if (me.anaglyphEffectEnabled) 228 | { 229 | if (me.anaglyphEffect == null) 230 | { 231 | me.initEffects(); 232 | } 233 | me.anaglyphEffect.render(me.scene, me.camera); 234 | } 235 | else if (me.renderMode === "composer" && me.composer != null) 236 | { 237 | me.composer.render(); 238 | } 239 | else 240 | { 241 | me.renderer.render(me.scene, me.camera); 242 | } 243 | }; 244 | 245 | me.update = function(p_forceUpdate) 246 | { 247 | me.updateLabels(p_forceUpdate); 248 | }; 249 | 250 | me.updateLabels = function(p_forceUpdate) 251 | { 252 | me.labelViews.forEach(function(p_labelView) 253 | { 254 | p_labelView.update(p_forceUpdate); 255 | }); 256 | }; 257 | 258 | base.setFrame = me.setFrame; 259 | me.setFrame = function(p_frame) 260 | { 261 | base.setFrame(p_frame); 262 | if (typeof (p_frame.width) === "number" || typeof (p_frame.height) === "number") 263 | { 264 | if (me.camera != null) 265 | { 266 | me.camera.aspect = me.frame.width / me.frame.height; 267 | me.camera.updateProjectionMatrix(); 268 | } 269 | 270 | me.update(); 271 | 272 | if (me.renderer != null) 273 | { 274 | me.renderer.setSize(me.frame.width, me.frame.height); 275 | } 276 | 277 | if (me.anaglyphEffect != null) 278 | { 279 | me.anaglyphEffect.setSize(me.frame.width, me.frame.height); 280 | } 281 | } 282 | }; 283 | 284 | var _labelProjector = null; 285 | me.addLabelView = function(p_options) 286 | { 287 | if (_labelProjector == null) 288 | { 289 | _labelProjector = new THREE.Projector(); 290 | _labelProjector.frame = me.frame; 291 | } 292 | var options = $.extend({ 293 | camera : me.camera, 294 | projector : _labelProjector 295 | }, p_options); 296 | var labelView = new mx3d.view.LabelView(options); 297 | me.addSubview(labelView); 298 | me.labelViews.add(labelView); 299 | labelView.update(); 300 | return labelView; 301 | }; 302 | 303 | me.removeLabelView = function(p_labelView) 304 | { 305 | me.removeSubview(p_labelView); 306 | p_labelView.camera = null; 307 | p_labelView.projector = null; 308 | me.labelViews.remove(p_labelView); 309 | }; 310 | 311 | me.clearLabelViews = function() 312 | { 313 | me.labelViews.forEach(function(p_labelView) 314 | { 315 | me.removeSubview(p_labelView); 316 | }); 317 | }; 318 | 319 | function _onmouseup(event) 320 | { 321 | if (!me.clickable) 322 | { 323 | return; 324 | } 325 | 326 | if (event.target !== me.renderer.domElement) 327 | { 328 | return; 329 | } 330 | 331 | event.preventDefault(); 332 | 333 | if (event.button === 0) 334 | { 335 | // update the mouse variable 336 | var mouse = { 337 | x : 0, 338 | y : 0, 339 | z : 0 340 | }; 341 | mouse.x = (event.clientX / me.frame.width) * 2 - 1; 342 | mouse.y = -(event.clientY / me.frame.height) * 2 + 1; 343 | mouse.z = 1; 344 | 345 | // create a Ray with origin at the mouse position 346 | // and direction into the scene (camera direction) 347 | var vector = new THREE.Vector3(mouse.x, mouse.y, mouse.z); 348 | var projector = new THREE.Projector(); 349 | projector.unprojectVector(vector, me.camera); 350 | 351 | var origin = me.camera.position; 352 | var dir = vector.sub(me.camera.position).normalize(); 353 | var ray = new THREE.Raycaster(); 354 | ray.set(origin, dir); 355 | 356 | // create an array containing all objects in the scene with which 357 | // the ray intersects 358 | var intersects = ray.intersectObjects(me.clickableObjects); 359 | if (intersects.length > 0) 360 | { 361 | var objects = intersects.map(function(p_intersect) 362 | { 363 | return p_intersect.object; 364 | }); 365 | me.trigger("objectclick", { 366 | objects : objects, 367 | intersects : intersects 368 | }); 369 | } 370 | 371 | } 372 | 373 | } 374 | 375 | function _labelView_onclick(e) 376 | { 377 | if (e.button === 0) 378 | { 379 | var id = e.currentTarget.id; 380 | me.trigger("labelviewclick", { 381 | labelView : me.subviews[id] 382 | }); 383 | } 384 | } 385 | 386 | return me.endOfClass(arguments); 387 | }; 388 | mx3d.view.Scene3DView.className = "mx3d.view.Scene3DView"; 389 | --------------------------------------------------------------------------------