Initial commit
This commit is contained in:
commit
af6d73cca1
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"quotes": [
|
||||||
|
2,
|
||||||
|
"single"
|
||||||
|
],
|
||||||
|
"semi": [
|
||||||
|
2,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"no-unused-vars" : 2,
|
||||||
|
"no-undef" : 2
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"browser": true
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"parserOptions": {
|
||||||
|
"sourceType": "module"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
.idea
|
||||||
|
Iconr
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Three.js Webpack ES6 Boilerplate
|
||||||
|
A basic boilerplate for a Three.js project including the use of Webpack and ES6 syntax via Babel.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
Then
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Spins up a webpack dev server at localhost:8080 and keeps track of all js and sass changes to files and reloads upon save.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Cleans existing build folder while linting js and copies over the public folder from src. Then sets environment to production and compiles js and css into build.
|
|
@ -0,0 +1 @@
|
||||||
|
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.main{width:100%;height:100vh}
|
|
@ -0,0 +1,73 @@
|
||||||
|
.rs-base{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #222;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.2em;
|
||||||
|
width: 350px;
|
||||||
|
font-family: 'Roboto Condensed', tahoma, sans-serif;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base h1{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 1.4em;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-group{
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-group.hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-fraction{
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-fraction p{
|
||||||
|
width: 120px;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-legend{
|
||||||
|
position: absolute;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-counter-base{
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 0;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base span.rs-counter-id{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-counter-value{
|
||||||
|
position: absolute;
|
||||||
|
left: 90px;
|
||||||
|
width: 30px;
|
||||||
|
height: 1em;
|
||||||
|
top: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base canvas.rs-canvas{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,719 @@
|
||||||
|
// performance.now() polyfill from https://gist.github.com/paulirish/5438650
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
( function () {
|
||||||
|
|
||||||
|
// prepare base perf object
|
||||||
|
if ( typeof window.performance === 'undefined' ) {
|
||||||
|
window.performance = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !window.performance.now ) {
|
||||||
|
|
||||||
|
var nowOffset = Date.now();
|
||||||
|
|
||||||
|
if ( performance.timing && performance.timing.navigationStart ) {
|
||||||
|
nowOffset = performance.timing.navigationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.performance.now = function now () {
|
||||||
|
return Date.now() - nowOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !window.performance.mark ) {
|
||||||
|
window.performance.mark = function(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !window.performance.measure ) {
|
||||||
|
window.performance.measure = function(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
} )();
|
||||||
|
|
||||||
|
window.rStats = function rStats ( settings ) {
|
||||||
|
|
||||||
|
function iterateKeys ( array, callback ) {
|
||||||
|
var keys = Object.keys( array );
|
||||||
|
for ( var j = 0, l = keys.length; j < l; j++ ) {
|
||||||
|
callback( keys[ j ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importCSS ( url ) {
|
||||||
|
|
||||||
|
var element = document.createElement( 'link' );
|
||||||
|
element.href = url;
|
||||||
|
element.rel = 'stylesheet';
|
||||||
|
element.type = 'text/css';
|
||||||
|
document.getElementsByTagName( 'head' )[ 0 ].appendChild( element );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _settings = settings || {};
|
||||||
|
var _colours = _settings.colours || [ '#850700', '#c74900', '#fcb300', '#284280', '#4c7c0c' ];
|
||||||
|
|
||||||
|
var _cssFont = 'https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300';
|
||||||
|
var _cssRStats = ( _settings.CSSPath ? _settings.CSSPath : '' ) + 'rStats.css';
|
||||||
|
|
||||||
|
var _css = _settings.css || [ _cssFont, _cssRStats ];
|
||||||
|
_css.forEach(function (uri) {
|
||||||
|
importCSS( uri );
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( !_settings.values ) _settings.values = {};
|
||||||
|
|
||||||
|
var _base, _div, _elHeight = 10, _elWidth = 200;
|
||||||
|
var _perfCounters = {};
|
||||||
|
|
||||||
|
|
||||||
|
function Graph ( _dom, _id, _defArg ) {
|
||||||
|
|
||||||
|
var _def = _defArg || {};
|
||||||
|
var _canvas = document.createElement( 'canvas' ),
|
||||||
|
_ctx = _canvas.getContext( '2d' ),
|
||||||
|
_max = 0,
|
||||||
|
_current = 0;
|
||||||
|
|
||||||
|
var c = _def.color ? _def.color : '#666666';
|
||||||
|
|
||||||
|
var _dotCanvas = document.createElement( 'canvas' ),
|
||||||
|
_dotCtx = _dotCanvas.getContext( '2d' );
|
||||||
|
_dotCanvas.width = 1;
|
||||||
|
_dotCanvas.height = 2 * _elHeight;
|
||||||
|
_dotCtx.fillStyle = '#444444';
|
||||||
|
_dotCtx.fillRect( 0, 0, 1, 2 * _elHeight );
|
||||||
|
_dotCtx.fillStyle = c;
|
||||||
|
_dotCtx.fillRect( 0, _elHeight, 1, _elHeight );
|
||||||
|
_dotCtx.fillStyle = '#ffffff';
|
||||||
|
_dotCtx.globalAlpha = 0.5;
|
||||||
|
_dotCtx.fillRect( 0, _elHeight, 1, 1 );
|
||||||
|
_dotCtx.globalAlpha = 1;
|
||||||
|
|
||||||
|
var _alarmCanvas = document.createElement( 'canvas' ),
|
||||||
|
_alarmCtx = _alarmCanvas.getContext( '2d' );
|
||||||
|
_alarmCanvas.width = 1;
|
||||||
|
_alarmCanvas.height = 2 * _elHeight;
|
||||||
|
_alarmCtx.fillStyle = '#444444';
|
||||||
|
_alarmCtx.fillRect( 0, 0, 1, 2 * _elHeight );
|
||||||
|
_alarmCtx.fillStyle = '#b70000';
|
||||||
|
_alarmCtx.fillRect( 0, _elHeight, 1, _elHeight );
|
||||||
|
_alarmCtx.globalAlpha = 0.5;
|
||||||
|
_alarmCtx.fillStyle = '#ffffff';
|
||||||
|
_alarmCtx.fillRect( 0, _elHeight, 1, 1 );
|
||||||
|
_alarmCtx.globalAlpha = 1;
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
_canvas.width = _elWidth;
|
||||||
|
_canvas.height = _elHeight;
|
||||||
|
_canvas.style.width = _canvas.width + 'px';
|
||||||
|
_canvas.style.height = _canvas.height + 'px';
|
||||||
|
_canvas.className = 'rs-canvas';
|
||||||
|
_dom.appendChild( _canvas );
|
||||||
|
|
||||||
|
_ctx.fillStyle = '#444444';
|
||||||
|
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw ( v, alarm ) {
|
||||||
|
_current += ( v - _current ) * 0.1;
|
||||||
|
_max *= 0.99;
|
||||||
|
if ( _current > _max ) _max = _current;
|
||||||
|
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
|
||||||
|
if ( alarm ) {
|
||||||
|
_ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
|
||||||
|
} else {
|
||||||
|
_ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function StackGraph ( _dom, _num ) {
|
||||||
|
|
||||||
|
var _canvas = document.createElement( 'canvas' ),
|
||||||
|
_ctx = _canvas.getContext( '2d' );
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
_canvas.width = _elWidth;
|
||||||
|
_canvas.height = _elHeight * _num;
|
||||||
|
_canvas.style.width = _canvas.width + 'px';
|
||||||
|
_canvas.style.height = _canvas.height + 'px';
|
||||||
|
_canvas.className = 'rs-canvas';
|
||||||
|
_dom.appendChild( _canvas );
|
||||||
|
|
||||||
|
_ctx.fillStyle = '#444444';
|
||||||
|
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw ( v ) {
|
||||||
|
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
|
||||||
|
var th = 0;
|
||||||
|
iterateKeys( v, function ( j ) {
|
||||||
|
var h = v[ j ] * _canvas.height;
|
||||||
|
_ctx.fillStyle = _colours[ j ];
|
||||||
|
_ctx.fillRect( _canvas.width - 1, th, 1, h );
|
||||||
|
th += h;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function PerfCounter ( id, group ) {
|
||||||
|
|
||||||
|
var _id = id,
|
||||||
|
_time,
|
||||||
|
_value = 0,
|
||||||
|
_total = 0,
|
||||||
|
_averageValue = 0,
|
||||||
|
_accumValue = 0,
|
||||||
|
_accumStart = performance.now(),
|
||||||
|
_accumSamples = 0,
|
||||||
|
_dom = document.createElement( 'div' ),
|
||||||
|
_spanId = document.createElement( 'span' ),
|
||||||
|
_spanValue = document.createElement( 'div' ),
|
||||||
|
_spanValueText = document.createTextNode( '' ),
|
||||||
|
_def = _settings ? _settings.values[ _id.toLowerCase() ] : null,
|
||||||
|
_graph = new Graph( _dom, _id, _def ),
|
||||||
|
_started = false;
|
||||||
|
|
||||||
|
_dom.className = 'rs-counter-base';
|
||||||
|
|
||||||
|
_spanId.className = 'rs-counter-id';
|
||||||
|
_spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;
|
||||||
|
|
||||||
|
_spanValue.className = 'rs-counter-value';
|
||||||
|
_spanValue.appendChild( _spanValueText );
|
||||||
|
|
||||||
|
_dom.appendChild( _spanId );
|
||||||
|
_dom.appendChild( _spanValue );
|
||||||
|
if ( group ) group.div.appendChild( _dom );
|
||||||
|
else _div.appendChild( _dom );
|
||||||
|
|
||||||
|
_time = performance.now();
|
||||||
|
|
||||||
|
function _average ( v ) {
|
||||||
|
if ( _def && _def.average ) {
|
||||||
|
_accumValue += v;
|
||||||
|
_accumSamples++;
|
||||||
|
var t = performance.now();
|
||||||
|
if ( t - _accumStart >= ( _def.avgMs || 1000 ) ) {
|
||||||
|
_averageValue = _accumValue / _accumSamples;
|
||||||
|
_accumValue = 0;
|
||||||
|
_accumStart = t;
|
||||||
|
_accumSamples = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_time = performance.now();
|
||||||
|
if( _settings.userTimingAPI ) performance.mark( _id + '-start' );
|
||||||
|
_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {
|
||||||
|
_value = performance.now() - _time;
|
||||||
|
if( _settings.userTimingAPI ) {
|
||||||
|
performance.mark( _id + '-end' );
|
||||||
|
if( _started ) {
|
||||||
|
performance.measure( _id, _id + '-start', _id + '-end' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tick () {
|
||||||
|
_end();
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw () {
|
||||||
|
var v = ( _def && _def.average ) ? _averageValue : _value;
|
||||||
|
_spanValueText.nodeValue = Math.round( v * 100 ) / 100;
|
||||||
|
var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );
|
||||||
|
_graph.draw( _value, a );
|
||||||
|
_dom.style.color = a ? '#b70000' : '#ffffff';
|
||||||
|
}
|
||||||
|
|
||||||
|
function _frame () {
|
||||||
|
var t = performance.now();
|
||||||
|
var e = t - _time;
|
||||||
|
_total++;
|
||||||
|
if ( e > 1000 ) {
|
||||||
|
if ( _def && _def.interpolate === false ) {
|
||||||
|
_value = _total;
|
||||||
|
} else {
|
||||||
|
_value = _total * 1000 / e;
|
||||||
|
}
|
||||||
|
_total = 0;
|
||||||
|
_time = t;
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _set ( v ) {
|
||||||
|
_value = v;
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
set: _set,
|
||||||
|
start: _start,
|
||||||
|
tick: _tick,
|
||||||
|
end: _end,
|
||||||
|
frame: _frame,
|
||||||
|
value: function () {
|
||||||
|
return _value;
|
||||||
|
},
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample () {
|
||||||
|
|
||||||
|
var _value = 0;
|
||||||
|
|
||||||
|
function _set ( v ) {
|
||||||
|
_value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
set: _set,
|
||||||
|
value: function () {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _perf ( idArg ) {
|
||||||
|
|
||||||
|
var id = idArg.toLowerCase();
|
||||||
|
if ( id === undefined ) id = 'default';
|
||||||
|
if ( _perfCounters[ id ] ) return _perfCounters[ id ];
|
||||||
|
|
||||||
|
var group = null;
|
||||||
|
if ( _settings && _settings.groups ) {
|
||||||
|
iterateKeys( _settings.groups, function ( j ) {
|
||||||
|
var g = _settings.groups[ parseInt( j, 10 ) ];
|
||||||
|
if ( !group && g.values.indexOf( id.toLowerCase() ) !== -1 ) {
|
||||||
|
group = g;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = new PerfCounter( id, group );
|
||||||
|
_perfCounters[ id ] = p;
|
||||||
|
return p;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
if ( _settings.plugins ) {
|
||||||
|
if ( !_settings.values ) _settings.values = {};
|
||||||
|
if ( !_settings.groups ) _settings.groups = [];
|
||||||
|
if ( !_settings.fractions ) _settings.fractions = [];
|
||||||
|
for ( var j = 0; j < _settings.plugins.length; j++ ) {
|
||||||
|
_settings.plugins[ j ].attach( _perf );
|
||||||
|
iterateKeys( _settings.plugins[ j ].values, function ( k ) {
|
||||||
|
_settings.values[ k ] = _settings.plugins[ j ].values[ k ];
|
||||||
|
} );
|
||||||
|
_settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups );
|
||||||
|
_settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_settings.plugins = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_base = document.createElement( 'div' );
|
||||||
|
_base.className = 'rs-base';
|
||||||
|
_div = document.createElement( 'div' );
|
||||||
|
_div.className = 'rs-container';
|
||||||
|
_div.style.height = 'auto';
|
||||||
|
_base.appendChild( _div );
|
||||||
|
document.body.appendChild( _base );
|
||||||
|
|
||||||
|
if ( !_settings ) return;
|
||||||
|
|
||||||
|
if ( _settings.groups ) {
|
||||||
|
iterateKeys( _settings.groups, function ( j ) {
|
||||||
|
var g = _settings.groups[ parseInt( j, 10 ) ];
|
||||||
|
var div = document.createElement( 'div' );
|
||||||
|
div.className = 'rs-group';
|
||||||
|
g.div = div;
|
||||||
|
var h1 = document.createElement( 'h1' );
|
||||||
|
h1.textContent = g.caption;
|
||||||
|
h1.addEventListener( 'click', function ( e ) {
|
||||||
|
this.classList.toggle( 'hidden' );
|
||||||
|
e.preventDefault();
|
||||||
|
}.bind( div ) );
|
||||||
|
_div.appendChild( h1 );
|
||||||
|
_div.appendChild( div );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _settings.fractions ) {
|
||||||
|
iterateKeys( _settings.fractions, function ( j ) {
|
||||||
|
var f = _settings.fractions[ parseInt( j, 10 ) ];
|
||||||
|
var div = document.createElement( 'div' );
|
||||||
|
div.className = 'rs-fraction';
|
||||||
|
var legend = document.createElement( 'div' );
|
||||||
|
legend.className = 'rs-legend';
|
||||||
|
|
||||||
|
var h = 0;
|
||||||
|
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
|
||||||
|
var p = document.createElement( 'p' );
|
||||||
|
p.textContent = _settings.fractions[ j ].steps[ k ];
|
||||||
|
p.style.color = _colours[ h ];
|
||||||
|
legend.appendChild( p );
|
||||||
|
h++;
|
||||||
|
} );
|
||||||
|
div.appendChild( legend );
|
||||||
|
div.style.height = h * _elHeight + 'px';
|
||||||
|
f.div = div;
|
||||||
|
var graph = new StackGraph( div, h );
|
||||||
|
f.graph = graph;
|
||||||
|
_div.appendChild( div );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
|
||||||
|
iterateKeys( _settings.plugins, function ( j ) {
|
||||||
|
_settings.plugins[ j ].update();
|
||||||
|
} );
|
||||||
|
|
||||||
|
iterateKeys( _perfCounters, function ( j ) {
|
||||||
|
_perfCounters[ j ].draw();
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( _settings && _settings.fractions ) {
|
||||||
|
iterateKeys( _settings.fractions, function ( j ) {
|
||||||
|
var f = _settings.fractions[ parseInt( j, 10 ) ];
|
||||||
|
var v = [];
|
||||||
|
var base = _perfCounters[ f.base.toLowerCase() ];
|
||||||
|
if ( base ) {
|
||||||
|
base = base.value();
|
||||||
|
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
|
||||||
|
var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase();
|
||||||
|
var val = _perfCounters[ s ];
|
||||||
|
if ( val ) {
|
||||||
|
v.push( val.value() / base );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
f.graph.draw( v );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if( _height != _div.clientHeight ) {
|
||||||
|
_height = _div.clientHeight;
|
||||||
|
_base.style.height = _height + 2 * _elHeight + 'px';
|
||||||
|
console.log( _base.clientHeight );
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return function ( id ) {
|
||||||
|
if ( id ) return _perf( id );
|
||||||
|
return {
|
||||||
|
element: _base,
|
||||||
|
update: _update
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module === 'object') {
|
||||||
|
module.exports = window.rStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.glStats = function () {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _totalDrawArraysCalls = 0,
|
||||||
|
_totalDrawElementsCalls = 0,
|
||||||
|
_totalUseProgramCalls = 0,
|
||||||
|
_totalFaces = 0,
|
||||||
|
_totalVertices = 0,
|
||||||
|
_totalPoints = 0,
|
||||||
|
_totalBindTexures = 0;
|
||||||
|
|
||||||
|
function _h ( f, c ) {
|
||||||
|
return function () {
|
||||||
|
c.apply( this, arguments );
|
||||||
|
f.apply( this, arguments );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
|
||||||
|
_totalDrawArraysCalls++;
|
||||||
|
if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
|
||||||
|
else _totalVertices += arguments[ 2 ];
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
|
||||||
|
_totalDrawElementsCalls++;
|
||||||
|
_totalFaces += arguments[ 1 ] / 3;
|
||||||
|
_totalVertices += arguments[ 1 ];
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
|
||||||
|
_totalUseProgramCalls++;
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
|
||||||
|
_totalBindTexures++;
|
||||||
|
} );
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
allcalls: {
|
||||||
|
over: 3000,
|
||||||
|
caption: 'Calls (hook)'
|
||||||
|
},
|
||||||
|
drawelements: {
|
||||||
|
caption: 'drawElements (hook)'
|
||||||
|
},
|
||||||
|
drawarrays: {
|
||||||
|
caption: 'drawArrays (hook)'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'WebGL',
|
||||||
|
values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [ {
|
||||||
|
base: 'allcalls',
|
||||||
|
steps: [ 'drawelements', 'drawarrays' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
_rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
|
||||||
|
_rS( 'drawElements' ).set( _totalDrawElementsCalls );
|
||||||
|
_rS( 'drawArrays' ).set( _totalDrawArraysCalls );
|
||||||
|
_rS( 'bindTexture' ).set( _totalBindTexures );
|
||||||
|
_rS( 'useProgram' ).set( _totalUseProgramCalls );
|
||||||
|
_rS( 'glfaces' ).set( _totalFaces );
|
||||||
|
_rS( 'glvertices' ).set( _totalVertices );
|
||||||
|
_rS( 'glpoints' ).set( _totalPoints );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_totalDrawArraysCalls = 0;
|
||||||
|
_totalDrawElementsCalls = 0;
|
||||||
|
_totalUseProgramCalls = 0;
|
||||||
|
_totalFaces = 0;
|
||||||
|
_totalVertices = 0;
|
||||||
|
_totalPoints = 0;
|
||||||
|
_totalBindTexures = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
window.threeStats = function ( renderer ) {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
'renderer.info.memory.geometries': {
|
||||||
|
caption: 'Geometries'
|
||||||
|
},
|
||||||
|
'renderer.info.memory.textures': {
|
||||||
|
caption: 'Textures'
|
||||||
|
},
|
||||||
|
'renderer.info.programs': {
|
||||||
|
caption: 'Programs'
|
||||||
|
},
|
||||||
|
'renderer.info.render.calls': {
|
||||||
|
caption: 'Calls'
|
||||||
|
},
|
||||||
|
'renderer.info.render.faces': {
|
||||||
|
caption: 'Faces',
|
||||||
|
over: 1000
|
||||||
|
},
|
||||||
|
'renderer.info.render.points': {
|
||||||
|
caption: 'Points'
|
||||||
|
},
|
||||||
|
'renderer.info.render.vertices': {
|
||||||
|
caption: 'Vertices'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'Three.js - Memory',
|
||||||
|
values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
|
||||||
|
}, {
|
||||||
|
caption: 'Three.js - Render',
|
||||||
|
values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [];
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
|
||||||
|
_rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
|
||||||
|
//_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
|
||||||
|
_rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
|
||||||
|
_rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
|
||||||
|
_rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );
|
||||||
|
_rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
|
||||||
|
_rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From https://github.com/paulirish/memory-stats.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
window.BrowserStats = function () {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _usedJSHeapSize = 0,
|
||||||
|
_totalJSHeapSize = 0;
|
||||||
|
|
||||||
|
var memory = {
|
||||||
|
usedJSHeapSize: 0,
|
||||||
|
totalJSHeapSize: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( window.performance && performance.memory )
|
||||||
|
memory = performance.memory;
|
||||||
|
|
||||||
|
if ( memory.totalJSHeapSize === 0 ) {
|
||||||
|
console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
|
||||||
|
}
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
memory: {
|
||||||
|
caption: 'Used Memory',
|
||||||
|
average: true,
|
||||||
|
avgMs: 1000,
|
||||||
|
over: 22
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
caption: 'Total Memory'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'Browser',
|
||||||
|
values: [ 'memory', 'total' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [ {
|
||||||
|
base: 'total',
|
||||||
|
steps: [ 'memory' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var log1024 = Math.log( 1024 );
|
||||||
|
|
||||||
|
function _size ( v ) {
|
||||||
|
|
||||||
|
var precision = 100; //Math.pow(10, 2);
|
||||||
|
var i = Math.floor( Math.log( v ) / log1024 );
|
||||||
|
if( v === 0 ) i = 1;
|
||||||
|
return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
_usedJSHeapSize = _size( memory.usedJSHeapSize );
|
||||||
|
_totalJSHeapSize = _size( memory.totalJSHeapSize );
|
||||||
|
|
||||||
|
_rS( 'memory' ).set( _usedJSHeapSize );
|
||||||
|
_rS( 'total' ).set( _totalJSHeapSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_usedJSHeapSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof module === 'object') {
|
||||||
|
module.exports = {
|
||||||
|
glStats: window.glStats,
|
||||||
|
threeStats: window.threeStats,
|
||||||
|
BrowserStats: window.BrowserStats
|
||||||
|
};
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 636 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Three.js Webpack ES6 Boilerplate</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="/assets/css/app.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<div id="appContainer" class="main">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/assets/js/rStats.js"></script>
|
||||||
|
<script src="/assets/js/dat.gui.min.js"></script>
|
||||||
|
<script src="/assets/js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,44 @@
|
||||||
|
{
|
||||||
|
"name": "threejs-es6-webpack-boilerplate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Boilerplate for Three.js projects set up with Babel for ES6 and compiled with webpack",
|
||||||
|
"author": "Paul Graffam",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "run-p dev:sass webpack-server webpack-watch",
|
||||||
|
"build": "run-s prebuild build:dir build:js build:sass",
|
||||||
|
"prebuild": "run-p clean lint",
|
||||||
|
"clean": "rimraf build",
|
||||||
|
"lint": "eslint src/js/; exit 0",
|
||||||
|
"webpack-server": "set NODE_ENV=0&& webpack-dev-server --hot --inline --open",
|
||||||
|
"webpack-watch": "set NODE_ENV=0&& webpack --progress --colors --watch --cache",
|
||||||
|
"dev:sass": "node-sass -w src/css/app.scss -o src/public/assets/css/",
|
||||||
|
"dev:js": "set NODE_ENV=0&& webpack",
|
||||||
|
"build:dir": "copyfiles -u 1 src/public/**/* build/",
|
||||||
|
"build:sass": "node-sass --output-style compressed src/css/ -o build/public/assets/css/",
|
||||||
|
"build:js": "set NODE_ENV=1&& webpack"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promise": "^3.2.1",
|
||||||
|
"normalize.css": "^4.2.0",
|
||||||
|
"three": "^0.79.0",
|
||||||
|
"tween.js": "16.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.13.2",
|
||||||
|
"babel-loader": "^6.2.5",
|
||||||
|
"babel-preset-es2015": "^6.13.2",
|
||||||
|
"copyfiles": "^1.0.0",
|
||||||
|
"eslint": "^3.4.0",
|
||||||
|
"file-loader": "^0.9.0",
|
||||||
|
"node-sass": "^3.8.0",
|
||||||
|
"npm-run-all": "^3.0.0",
|
||||||
|
"rimraf": "^2.5.4",
|
||||||
|
"webpack": "^1.13.2",
|
||||||
|
"webpack-dev-middleware": "^1.6.1",
|
||||||
|
"webpack-dev-server": "^1.15.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "5.0.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,585 @@
|
||||||
|
/* ==========================================================================
|
||||||
|
Normalize.scss settings
|
||||||
|
========================================================================== */
|
||||||
|
/**
|
||||||
|
* Includes legacy browser support IE6/7
|
||||||
|
*
|
||||||
|
* Set to false if you want to drop support for IE6 and IE7
|
||||||
|
*/
|
||||||
|
|
||||||
|
$legacy_browser_support: false !default;
|
||||||
|
|
||||||
|
/* Base
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Set default font family to sans-serif.
|
||||||
|
* 2. Prevent iOS and IE text size adjust after device orientation change,
|
||||||
|
* without disabling user zoom.
|
||||||
|
* 3. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using
|
||||||
|
* `em` units.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif; /* 1 */
|
||||||
|
-ms-text-size-adjust: 100%; /* 2 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
*font-size: 100%; /* 3 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove default margin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display definitions
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||||
|
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||||
|
* and Firefox.
|
||||||
|
* Correct `block` display not defined for `main` in IE 11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
details,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
main,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
section,
|
||||||
|
summary {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
|
||||||
|
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio,
|
||||||
|
canvas,
|
||||||
|
progress,
|
||||||
|
video {
|
||||||
|
display: inline-block; /* 1 */
|
||||||
|
vertical-align: baseline; /* 2 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
*display: inline;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents modern browsers from displaying `audio` without controls.
|
||||||
|
* Remove excess height in iOS 5 devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||||
|
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden],
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background color from active links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Improve readability of focused elements when they are also in an
|
||||||
|
* active/hover state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
&:active, &:hover {
|
||||||
|
outline: 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: 1px dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address styling not present in Safari and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address variable `h1` font-size and margin within `section` and `article`
|
||||||
|
* contexts in Firefox 4+, Safari, and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin: 0.83em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.17em;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 1em;
|
||||||
|
margin: 1.33em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: 0.83em;
|
||||||
|
margin: 1.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: 0.67em;
|
||||||
|
margin: 2.33em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Addresses styling not present in IE 8/9.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Addresses margins set differently in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
p,
|
||||||
|
pre {
|
||||||
|
*margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addresses CSS quotes not supported in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
q {
|
||||||
|
*quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addresses `quotes` property not supported in Safari 4.
|
||||||
|
*/
|
||||||
|
|
||||||
|
q:before,
|
||||||
|
q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address inconsistent and variable font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
Lists
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addresses margins set differently in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dl,
|
||||||
|
menu,
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
*margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
*margin: 0 0 0 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addresses paddings set differently in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
menu,
|
||||||
|
ol,
|
||||||
|
ul {
|
||||||
|
*padding: 0 0 0 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Corrects list images handled incorrectly in IE 7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
nav ul,
|
||||||
|
nav ol {
|
||||||
|
*list-style: none;
|
||||||
|
*list-style-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove border when inside `a` element in IE 8/9/10.
|
||||||
|
* 2. Improves image quality when scaled in IE 7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
*-ms-interpolation-mode: bicubic; /* 2 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct overflow not hidden in IE 9/10/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address margin not present in IE 8/9 and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address differences between Firefox and other browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contain overflow in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address odd `em`-unit font size rendering in all browsers.
|
||||||
|
* Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
pre,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
_font-family: 'courier new', monospace;
|
||||||
|
}
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||||
|
* styling of `select`, unless a `border` property is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct color not being inherited.
|
||||||
|
* Known issue: affects color of disabled elements.
|
||||||
|
* 2. Correct font properties not being inherited.
|
||||||
|
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||||
|
* 4. Improves appearance and consistency in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
color: inherit; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
margin: 0; /* 3 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
vertical-align: baseline; /* 3 */
|
||||||
|
*vertical-align: middle; /* 3 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||||
|
* All other form control elements do not inherit `text-transform` values.
|
||||||
|
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||||
|
* Correct `select` style inheritance in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||||
|
* and `video` controls.
|
||||||
|
* 2. Correct inability to style clickable `input` types in iOS.
|
||||||
|
* 3. Improve usability and consistency of cursor style between image-type
|
||||||
|
* `input` and others.
|
||||||
|
* 4. Removes inner spacing in IE 7 without affecting normal text inputs.
|
||||||
|
* Known issue: inner spacing remains in IE 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
html input[type="button"], /* 1 */
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="submit"] {
|
||||||
|
-webkit-appearance: button; /* 2 */
|
||||||
|
cursor: pointer; /* 3 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
*overflow: visible; /* 4 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-set default cursor for disabled elements.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button[disabled],
|
||||||
|
html input[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove inner padding and border in Firefox 4+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||||
|
* the UA stylesheet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input {
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||||
|
* 2. Remove excess padding in IE 8/9/10.
|
||||||
|
* Known issue: excess padding remains in IE 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
*height: 13px; /* 3 */
|
||||||
|
*width: 13px; /* 3 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||||
|
* `font-size` values of the `input`, it causes the cursor style of the
|
||||||
|
* decrement button to change from `default` to `text`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-inner-spin-button,
|
||||||
|
input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
||||||
|
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
box-sizing: content-box; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||||
|
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||||
|
* padding (and `textfield` appearance).
|
||||||
|
*/
|
||||||
|
|
||||||
|
input[type="search"]::-webkit-search-cancel-button,
|
||||||
|
input[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define consistent border, margin, and padding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #c0c0c0;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0.35em 0.625em 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||||
|
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||||
|
* 3. Corrects text not wrapping in Firefox 3.
|
||||||
|
* 4. Corrects alignment displayed oddly in IE 6/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
border: 0; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
@if $legacy_browser_support {
|
||||||
|
white-space: normal; /* 3 */
|
||||||
|
*margin-left: -7px; /* 4 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't inherit the `font-weight` (applied by a rule above).
|
||||||
|
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||||
|
*/
|
||||||
|
|
||||||
|
optgroup {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove most spacing between table cells.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import Config from './data/config';
|
||||||
|
import Detector from './utils/detector';
|
||||||
|
import Main from './app/main';
|
||||||
|
|
||||||
|
// verify environment.
|
||||||
|
if(__ENV__ == 'dev') {
|
||||||
|
console.log('----- RUNNING IN DEV ENVIRONMENT! -----');
|
||||||
|
|
||||||
|
Config.isDev = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if(!Detector.webgl) {
|
||||||
|
Detector.addGetWebGLMessage();
|
||||||
|
} else {
|
||||||
|
const container = document.getElementById('appContainer');
|
||||||
|
new Main(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = init;
|
|
@ -0,0 +1,23 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
export default class Animation {
|
||||||
|
constructor(obj, clip) {
|
||||||
|
this.obj = obj;
|
||||||
|
|
||||||
|
this.mixer = new THREE.AnimationMixer(this.obj);
|
||||||
|
|
||||||
|
this.playClip(clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
playClip(clip) {
|
||||||
|
this.action = this.mixer.clipAction(clip);
|
||||||
|
|
||||||
|
this.action.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
update(delta) {
|
||||||
|
if(this.mixer) {
|
||||||
|
this.mixer.update(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Camera {
|
||||||
|
constructor(renderer) {
|
||||||
|
const width = renderer.domElement.width;
|
||||||
|
const height = renderer.domElement.height;
|
||||||
|
|
||||||
|
this.threeCamera = new THREE.PerspectiveCamera(Config.camera.fov, width / height, Config.camera.near, Config.camera.far);
|
||||||
|
this.threeCamera.position.set(Config.camera.posX, Config.camera.posY, Config.camera.posZ);
|
||||||
|
|
||||||
|
this.updateSize(renderer);
|
||||||
|
|
||||||
|
// listeners
|
||||||
|
window.addEventListener('resize', () => this.updateSize(renderer), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSize(renderer) {
|
||||||
|
this.threeCamera.aspect = (renderer.domElement.width * Config.dpr) / (renderer.domElement.height * Config.dpr);
|
||||||
|
this.threeCamera.updateProjectionMatrix();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import OrbitControls from '../utils/orbitControls';
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Controls {
|
||||||
|
constructor(camera, container) {
|
||||||
|
const orbitControls = new OrbitControls(THREE);
|
||||||
|
this.threeControls = new orbitControls(camera, container);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.threeControls.target.set(Config.controls.target.x, Config.controls.target.y, Config.controls.target.z);
|
||||||
|
this.threeControls.autoRotate = Config.controls.autoRotate;
|
||||||
|
this.threeControls.autoRotateSpeed = Config.controls.autoRotateSpeed;
|
||||||
|
this.threeControls.rotateSpeed = Config.controls.rotateSpeed;
|
||||||
|
this.threeControls.zoomSpeed = Config.controls.zoomSpeed;
|
||||||
|
this.threeControls.minDistance = Config.controls.minDistance;
|
||||||
|
this.threeControls.maxDistance = Config.controls.maxDistance;
|
||||||
|
this.threeControls.minPolarAngle = Config.controls.minPolarAngle;
|
||||||
|
this.threeControls.maxPolarAngle = Config.controls.maxPolarAngle;
|
||||||
|
this.threeControls.enableDamping = Config.controls.enableDamping;
|
||||||
|
this.threeControls.enableZoom = Config.controls.enableZoom;
|
||||||
|
this.threeControls.dampingFactor = Config.controls.dampingFactor;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Config from '../data/config';
|
||||||
|
|
||||||
|
export default class Geometry {
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.geo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
make(type) {
|
||||||
|
if(type == 'plane') {
|
||||||
|
return (width, height, widthSegments = 1, heightSegments = 1) => {
|
||||||
|
this.geo = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
place(position, rotation) {
|
||||||
|
const material = new THREE.MeshStandardMaterial({ color: 0xCCCCCC, side: THREE.DoubleSide });
|
||||||
|
const mesh = new THREE.Mesh(this.geo, material);
|
||||||
|
|
||||||
|
mesh.position.set(...position);
|
||||||
|
mesh.rotation.set(...rotation);
|
||||||
|
|
||||||
|
if(Config.shadow.enabled) {
|
||||||
|
mesh.receiveShadow = true;
|
||||||
|
mesh.castShadow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scene.add(mesh);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,369 @@
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class GUI {
|
||||||
|
constructor(main, mesh) {
|
||||||
|
let gui = new dat.GUI();
|
||||||
|
|
||||||
|
this.camera = main.camera.threeCamera;
|
||||||
|
this.controls = main.controls.threeControls;
|
||||||
|
this.light = main.light;
|
||||||
|
|
||||||
|
/* Global */
|
||||||
|
//gui.close();
|
||||||
|
|
||||||
|
/* Camera */
|
||||||
|
let cameraFolder = gui.addFolder('Camera');
|
||||||
|
let cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV');
|
||||||
|
cameraFOVGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.camera.fov = value;
|
||||||
|
});
|
||||||
|
cameraFOVGui.onFinishChange((value) => {
|
||||||
|
this.camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let cameraAspectGui = cameraFolder.add(Config.camera, 'aspect', 0, 4).name('Camera Aspect');
|
||||||
|
cameraAspectGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.camera.aspect = value;
|
||||||
|
});
|
||||||
|
cameraAspectGui.onFinishChange((value) => {
|
||||||
|
this.camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color');
|
||||||
|
cameraFogColorGui.onChange((value) => {
|
||||||
|
main.scene.fog.color.setHex(value);
|
||||||
|
});
|
||||||
|
let cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near');
|
||||||
|
cameraFogNearGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
main.scene.fog.density = value;
|
||||||
|
});
|
||||||
|
cameraFogNearGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* Controls */
|
||||||
|
let controlsFolder = gui.addFolder('Controls');
|
||||||
|
controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => {
|
||||||
|
this.controls.autoRotate = value;
|
||||||
|
});
|
||||||
|
let controlsAutoRotateSpeedGui = controlsFolder.add(Config.controls, 'autoRotateSpeed', -1, 1).name('Rotation Speed');
|
||||||
|
controlsAutoRotateSpeedGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
this.controls.autoRotateSpeed = value;
|
||||||
|
});
|
||||||
|
controlsAutoRotateSpeedGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* Mesh */
|
||||||
|
let meshFolder = gui.addFolder('Mesh');
|
||||||
|
meshFolder.add(Config.mesh, 'translucent', true).name('Translucent').onChange((value) => {
|
||||||
|
if(value) {
|
||||||
|
mesh.material.transparent = true;
|
||||||
|
mesh.material.opacity = 0.5;
|
||||||
|
} else {
|
||||||
|
mesh.material.opacity = 1.0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
meshFolder.add(Config.mesh, 'wireframe', true).name('Wireframe').onChange((value) => {
|
||||||
|
mesh.material.wireframe = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* Lights */
|
||||||
|
// Ambient Light
|
||||||
|
let ambientLightFolder = gui.addFolder('Ambient Light');
|
||||||
|
ambientLightFolder.add(Config.ambientLight, 'enabled').name('Enabled').onChange((value) => {
|
||||||
|
this.light.ambientLight.visible = value;
|
||||||
|
});
|
||||||
|
ambientLightFolder.addColor(Config.ambientLight, 'color').name('Color').onChange((value) => {
|
||||||
|
this.light.ambientLight.color.setHex(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Directional Light
|
||||||
|
let directionalLightFolder = gui.addFolder('Directional Light');
|
||||||
|
directionalLightFolder.add(Config.directionalLight, 'enabled').name('Enabled').onChange((value) => {
|
||||||
|
this.light.directionalLight.visible = value;
|
||||||
|
});
|
||||||
|
directionalLightFolder.addColor(Config.directionalLight, 'color').name('Color').onChange((value) => {
|
||||||
|
this.light.directionalLight.color.setHex(value);
|
||||||
|
});
|
||||||
|
let directionalLightIntensityGui = directionalLightFolder.add(Config.directionalLight, 'intensity', 0, 2).name('Intensity');
|
||||||
|
directionalLightIntensityGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.intensity = value;
|
||||||
|
});
|
||||||
|
directionalLightIntensityGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let directionalLightPositionXGui = directionalLightFolder.add(Config.directionalLight, 'x', -1000, 1000).name('Position X');
|
||||||
|
directionalLightPositionXGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.position.x = value;
|
||||||
|
});
|
||||||
|
directionalLightPositionXGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let directionalLightPositionYGui = directionalLightFolder.add(Config.directionalLight, 'y', -1000, 1000).name('Position Y');
|
||||||
|
directionalLightPositionYGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.position.y = value;
|
||||||
|
});
|
||||||
|
directionalLightPositionYGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let directionalLightPositionZGui = directionalLightFolder.add(Config.directionalLight, 'z', -1000, 1000).name('Position Z');
|
||||||
|
directionalLightPositionZGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.position.z = value;
|
||||||
|
});
|
||||||
|
directionalLightPositionZGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shadow Map
|
||||||
|
let shadowFolder = gui.addFolder('Shadow Map');
|
||||||
|
shadowFolder.add(Config.shadow, 'enabled').name('Enabled').onChange((value) => {
|
||||||
|
this.light.directionalLight.castShadow = value;
|
||||||
|
});
|
||||||
|
shadowFolder.add(Config.shadow, 'helperEnabled').name('Helper Enabled').onChange((value) => {
|
||||||
|
this.light.directionalLightHelper.visible = value;
|
||||||
|
});
|
||||||
|
let shadowNearGui = shadowFolder.add(Config.shadow, 'near', 0, 100).name('Near');
|
||||||
|
shadowNearGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.near = value;
|
||||||
|
});
|
||||||
|
shadowNearGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowFarGui = shadowFolder.add(Config.shadow, 'far', 0, 1200).name('Far');
|
||||||
|
shadowFarGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.far = value;
|
||||||
|
});
|
||||||
|
shadowFarGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowTopGui = shadowFolder.add(Config.shadow, 'top', -400, 400).name('Top');
|
||||||
|
shadowTopGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.top = value;
|
||||||
|
});
|
||||||
|
shadowTopGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowRightGui = shadowFolder.add(Config.shadow, 'right', -400, 400).name('Right');
|
||||||
|
shadowRightGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.right = value;
|
||||||
|
});
|
||||||
|
shadowRightGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowBottomGui = shadowFolder.add(Config.shadow, 'bottom', -400, 400).name('Bottom');
|
||||||
|
shadowBottomGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.bottom = value;
|
||||||
|
});
|
||||||
|
shadowBottomGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowLeftGui = shadowFolder.add(Config.shadow, 'left', -400, 400).name('Left');
|
||||||
|
shadowLeftGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.camera.left = value;
|
||||||
|
});
|
||||||
|
shadowLeftGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
let shadowBiasGui = shadowFolder.add(Config.shadow, 'bias', -0.000010, 1).name('Bias');
|
||||||
|
shadowBiasGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.directionalLight.shadow.bias = value;
|
||||||
|
});
|
||||||
|
shadowBiasGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
this.light.directionalLight.shadow.map.dispose();
|
||||||
|
this.light.directionalLight.shadow.map = null;
|
||||||
|
this.light.directionalLightHelper.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Point Light
|
||||||
|
let pointLightFolder = gui.addFolder('Point Light');
|
||||||
|
pointLightFolder.add(Config.pointLight, 'enabled').name('Enabled').onChange((value) => {
|
||||||
|
this.light.pointLight.visible = value;
|
||||||
|
});
|
||||||
|
pointLightFolder.addColor(Config.pointLight, 'color').name('Color').onChange((value) => {
|
||||||
|
this.light.pointLight.color.setHex(value);
|
||||||
|
});
|
||||||
|
let pointLightIntensityGui = pointLightFolder.add(Config.pointLight, 'intensity', 0, 2).name('Intensity');
|
||||||
|
pointLightIntensityGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.pointLight.intensity = value;
|
||||||
|
});
|
||||||
|
pointLightIntensityGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let pointLightDistanceGui = pointLightFolder.add(Config.pointLight, 'distance', 0, 1000).name('Distance');
|
||||||
|
pointLightDistanceGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.pointLight.distance = value;
|
||||||
|
});
|
||||||
|
pointLightDistanceGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let pointLightPositionXGui = pointLightFolder.add(Config.pointLight, 'x', -1000, 1000).name('Position X');
|
||||||
|
pointLightPositionXGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.pointLight.position.x = value;
|
||||||
|
});
|
||||||
|
pointLightPositionXGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let pointLightPositionYGui = pointLightFolder.add(Config.pointLight, 'y', -1000, 1000).name('Position Y');
|
||||||
|
pointLightPositionYGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.pointLight.position.y = value;
|
||||||
|
});
|
||||||
|
pointLightPositionYGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let pointLightPositionZGui = pointLightFolder.add(Config.pointLight, 'z', -1000, 1000).name('Position Z');
|
||||||
|
pointLightPositionZGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.pointLight.position.z = value;
|
||||||
|
});
|
||||||
|
pointLightPositionZGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Hemi Light
|
||||||
|
let hemiLightFolder = gui.addFolder('Hemi Light');
|
||||||
|
hemiLightFolder.add(Config.hemiLight, 'enabled').name('Enabled').onChange((value) => {
|
||||||
|
this.light.hemiLight.visible = value;
|
||||||
|
});
|
||||||
|
hemiLightFolder.addColor(Config.hemiLight, 'color').name('Color').onChange((value) => {
|
||||||
|
this.light.hemiLight.color.setHex(value);
|
||||||
|
});
|
||||||
|
hemiLightFolder.addColor(Config.hemiLight, 'groundColor').name('ground Color').onChange((value) => {
|
||||||
|
this.light.hemiLight.groundColor.setHex(value);
|
||||||
|
});
|
||||||
|
let hemiLightIntensityGui = hemiLightFolder.add(Config.hemiLight, 'intensity', 0, 2).name('Intensity');
|
||||||
|
hemiLightIntensityGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.hemiLight.intensity = value;
|
||||||
|
});
|
||||||
|
hemiLightIntensityGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let hemiLightPositionXGui = hemiLightFolder.add(Config.hemiLight, 'x', -1000, 1000).name('Position X');
|
||||||
|
hemiLightPositionXGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.hemiLight.position.x = value;
|
||||||
|
});
|
||||||
|
hemiLightPositionXGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let hemiLightPositionYGui = hemiLightFolder.add(Config.hemiLight, 'y', -500, 1000).name('Position Y');
|
||||||
|
hemiLightPositionYGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.hemiLight.position.y = value;
|
||||||
|
});
|
||||||
|
hemiLightPositionYGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
let hemiLightPositionZGui = hemiLightFolder.add(Config.hemiLight, 'z', -1000, 1000).name('Position Z');
|
||||||
|
hemiLightPositionZGui.onChange((value) => {
|
||||||
|
this.controls.enableRotate = false;
|
||||||
|
|
||||||
|
this.light.hemiLight.position.z = value;
|
||||||
|
});
|
||||||
|
hemiLightPositionZGui.onFinishChange((value) => {
|
||||||
|
this.controls.enableRotate = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleColorChange(color) {
|
||||||
|
return (value) => {
|
||||||
|
if(typeof value === 'string') {
|
||||||
|
value = value.replace('#', '0x');
|
||||||
|
}
|
||||||
|
|
||||||
|
color.setHex(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
needsUpdate(material, geometry) {
|
||||||
|
return function() {
|
||||||
|
material.shading = +material.shading; //Ensure number
|
||||||
|
material.vertexColors = +material.vertexColors; //Ensure number
|
||||||
|
material.side = +material.side; //Ensure number
|
||||||
|
material.needsUpdate = true;
|
||||||
|
geometry.verticesNeedUpdate = true;
|
||||||
|
geometry.normalsNeedUpdate = true;
|
||||||
|
geometry.colorsNeedUpdate = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTexture(material, materialKey, textures) {
|
||||||
|
return function(key) {
|
||||||
|
material[materialKey] = textures[key];
|
||||||
|
material.needsUpdate = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.needsUpdate(mesh.material, mesh.geometry);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
export default class Helper {
|
||||||
|
constructor(scene, mesh) {
|
||||||
|
let wireframe = new THREE.WireframeGeometry(mesh.geometry);
|
||||||
|
let wireLine = new THREE.LineSegments(wireframe);
|
||||||
|
wireLine.material.depthTest = false;
|
||||||
|
wireLine.material.opacity = 0.25;
|
||||||
|
wireLine.material.transparent = true;
|
||||||
|
mesh.add(wireLine);
|
||||||
|
|
||||||
|
let edges = new THREE.EdgesGeometry(mesh.geometry);
|
||||||
|
let edgesLine = new THREE.LineSegments(edges);
|
||||||
|
edgesLine.material.depthTest = false;
|
||||||
|
edgesLine.material.opacity = 0.25;
|
||||||
|
edgesLine.material.transparent = true;
|
||||||
|
mesh.add(edgesLine);
|
||||||
|
|
||||||
|
scene.add(new THREE.BoxHelper(mesh));
|
||||||
|
scene.add(new THREE.FaceNormalsHelper(mesh, 2));
|
||||||
|
scene.add(new THREE.VertexNormalsHelper(mesh, 2));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Keyboard from './../utils/keyboard';
|
||||||
|
import Helpers from './../utils/helpers';
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Interaction {
|
||||||
|
constructor(renderer, scene, camera, controls) {
|
||||||
|
this.renderer = renderer;
|
||||||
|
this.scene = scene;
|
||||||
|
this.camera = camera;
|
||||||
|
this.controls = controls;
|
||||||
|
|
||||||
|
this.keyboard = new Keyboard();
|
||||||
|
|
||||||
|
// listeners
|
||||||
|
// mouse events
|
||||||
|
this.renderer.domElement.addEventListener('mouseup', (event) => this.onMouseUp(event), false);
|
||||||
|
this.renderer.domElement.addEventListener('mousemove', (event) => Helpers.throttle(this.onMouseMove(event), 250), false);
|
||||||
|
this.renderer.domElement.addEventListener('mouseenter', (event) => this.onMouseEnter(event), false);
|
||||||
|
this.renderer.domElement.addEventListener('mouseleave', (event) => this.onMouseLeave(event), false);
|
||||||
|
this.renderer.domElement.addEventListener('mouseover', (event) => this.onMouseOver(event), false);
|
||||||
|
|
||||||
|
// keyboard events
|
||||||
|
this.keyboard.domElement.addEventListener('keydown', (event) => {
|
||||||
|
if(event.repeat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this.keyboard.eventMatches(event, 'escape')) {
|
||||||
|
console.log('Escape pressed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseEnter(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseLeave(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseMove(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseUp(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Light {
|
||||||
|
constructor(scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// ambient
|
||||||
|
this.ambientLight = new THREE.AmbientLight(Config.ambientLight.color);
|
||||||
|
this.ambientLight.visible = Config.ambientLight.enabled;
|
||||||
|
|
||||||
|
// point light
|
||||||
|
this.pointLight = new THREE.PointLight(Config.pointLight.color, Config.pointLight.intensity, Config.pointLight.distance);
|
||||||
|
this.pointLight.position.set(Config.pointLight.x, Config.pointLight.y, Config.pointLight.z);
|
||||||
|
this.pointLight.visible = Config.pointLight.enabled;
|
||||||
|
|
||||||
|
// directional light
|
||||||
|
this.directionalLight = new THREE.DirectionalLight(Config.directionalLight.color, Config.directionalLight.intensity);
|
||||||
|
this.directionalLight.position.set(Config.directionalLight.x, Config.directionalLight.y, Config.directionalLight.z);
|
||||||
|
this.directionalLight.visible = Config.directionalLight.enabled;
|
||||||
|
|
||||||
|
// shadow map
|
||||||
|
this.directionalLight.castShadow = Config.shadow.enabled;
|
||||||
|
this.directionalLight.shadow.bias = Config.shadow.bias;
|
||||||
|
this.directionalLight.shadow.camera.near = Config.shadow.near;
|
||||||
|
this.directionalLight.shadow.camera.far = Config.shadow.far;
|
||||||
|
this.directionalLight.shadow.camera.left = Config.shadow.left;
|
||||||
|
this.directionalLight.shadow.camera.right = Config.shadow.right;
|
||||||
|
this.directionalLight.shadow.camera.top = Config.shadow.top;
|
||||||
|
this.directionalLight.shadow.camera.bottom = Config.shadow.bottom;
|
||||||
|
this.directionalLight.shadow.mapSize.width = Config.shadow.mapWidth;
|
||||||
|
this.directionalLight.shadow.mapSize.height = Config.shadow.mapHeight;
|
||||||
|
|
||||||
|
// shadow camera helper
|
||||||
|
this.directionalLightHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);
|
||||||
|
this.directionalLightHelper.visible = Config.shadow.helperEnabled;
|
||||||
|
|
||||||
|
// hemisphere light
|
||||||
|
this.hemiLight = new THREE.HemisphereLight(Config.hemiLight.color, Config.hemiLight.groundColor, Config.hemiLight.intensity);
|
||||||
|
this.hemiLight.position.set(Config.hemiLight.x, Config.hemiLight.y, Config.hemiLight.z);
|
||||||
|
this.hemiLight.visible = Config.hemiLight.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
place(lightName) {
|
||||||
|
switch(lightName) {
|
||||||
|
case 'ambient':
|
||||||
|
this.scene.add(this.ambientLight);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'directional':
|
||||||
|
this.scene.add(this.directionalLight);
|
||||||
|
this.scene.add(this.directionalLightHelper);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'point':
|
||||||
|
this.scene.add(this.pointLight);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'hemi':
|
||||||
|
this.scene.add(this.hemiLight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
// global imports
|
||||||
|
import THREE from 'three';
|
||||||
|
import TWEEN from 'tween.js';
|
||||||
|
|
||||||
|
// local imports
|
||||||
|
import Renderer from './renderer';
|
||||||
|
import Camera from './camera';
|
||||||
|
import Light from './light';
|
||||||
|
import Controls from './controls';
|
||||||
|
import Geometry from './geometry';
|
||||||
|
import Texture from './texture';
|
||||||
|
import Model from './model';
|
||||||
|
import Interaction from './interaction';
|
||||||
|
import GUI from './gui';
|
||||||
|
|
||||||
|
// data
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
// stats
|
||||||
|
let rS, bS, glS, tS;
|
||||||
|
|
||||||
|
export default class Main {
|
||||||
|
constructor(container) {
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
// Start Three clock
|
||||||
|
this.clock = new THREE.Clock();
|
||||||
|
|
||||||
|
// Main scene
|
||||||
|
this.scene = new THREE.Scene();
|
||||||
|
this.scene.fog = new THREE.FogExp2(Config.fog.color, Config.fog.near);
|
||||||
|
|
||||||
|
// Get Device Pixel Ratio first
|
||||||
|
if(window.devicePixelRatio) {
|
||||||
|
Config.dpr = window.devicePixelRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main renderer
|
||||||
|
this.renderer = new Renderer(container, this.scene);
|
||||||
|
|
||||||
|
// Components
|
||||||
|
this.camera = new Camera(this.renderer.threeRenderer);
|
||||||
|
this.controls = new Controls(this.camera.threeCamera, this.container);
|
||||||
|
this.light = new Light(this.scene);
|
||||||
|
|
||||||
|
// Place lights
|
||||||
|
const lights = ['ambient', 'directional', 'point', 'hemi'];
|
||||||
|
for(let i = 0; i < lights.length; i++) {
|
||||||
|
this.light.place(lights[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place geo
|
||||||
|
this.geometry = new Geometry(this.scene);
|
||||||
|
this.geometry.make('plane')(100, 100, 10, 10);
|
||||||
|
this.geometry.place([0, -20, 0], [Math.PI/2, 0, 0]);
|
||||||
|
|
||||||
|
// Set up stats if dev
|
||||||
|
if(Config.isDev) {
|
||||||
|
bS = new BrowserStats();
|
||||||
|
glS = new glStats();
|
||||||
|
tS = new threeStats(this.renderer.threeRenderer);
|
||||||
|
|
||||||
|
rS = new rStats({
|
||||||
|
CSSPath: '/assets/css/',
|
||||||
|
userTimingAPI: true,
|
||||||
|
values: {
|
||||||
|
frame: { caption: 'Total frame time (ms)', over: 16, average: true, avgMs: 100 },
|
||||||
|
fps: { caption: 'Framerate (FPS)', below: 30 },
|
||||||
|
calls: { caption: 'Calls (three.js)', over: 3000 },
|
||||||
|
raf: { caption: 'Time since last rAF (ms)', average: true, avgMs: 100 },
|
||||||
|
rstats: { caption: 'rStats update (ms)', average: true, avgMs: 100 },
|
||||||
|
texture: { caption: 'GenTex', average: true, avgMs: 100 }
|
||||||
|
},
|
||||||
|
groups: [
|
||||||
|
{ caption: 'Framerate', values: [ 'fps', 'raf' ] },
|
||||||
|
{ caption: 'Frame Budget', values: [ 'frame', 'texture', 'setup', 'render' ] }
|
||||||
|
],
|
||||||
|
fractions: [
|
||||||
|
{ base: 'frame', steps: [ 'texture', 'setup', 'render' ] }
|
||||||
|
],
|
||||||
|
plugins: [bS, tS, glS]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.texture = new Texture();
|
||||||
|
// Start loading the textures
|
||||||
|
this.texture.load().then(() => {
|
||||||
|
this.manager = new THREE.LoadingManager();
|
||||||
|
// Textures loaded, load main model
|
||||||
|
this.model = new Model(this.scene, this.manager, this.texture.textures);
|
||||||
|
this.model.load();
|
||||||
|
|
||||||
|
// onProgress
|
||||||
|
this.manager.onProgress = (item, loaded, total) => {
|
||||||
|
console.log(`${item}: ${loaded} ${total}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// All loaders done
|
||||||
|
this.manager.onLoad = () => {
|
||||||
|
// Set up interaction with app
|
||||||
|
new Interaction(this.renderer.threeRenderer, this.scene, this.camera.threeCamera, this.controls.threeControls);
|
||||||
|
|
||||||
|
if(Config.isDev) {
|
||||||
|
new GUI(this, this.model.obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.isLoaded = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const delta = this.clock.getDelta();
|
||||||
|
|
||||||
|
if(Config.isDev) {
|
||||||
|
rS('frame').start();
|
||||||
|
glS.start();
|
||||||
|
|
||||||
|
rS('rAF').tick();
|
||||||
|
rS('FPS').frame();
|
||||||
|
|
||||||
|
rS('render').start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear renderer
|
||||||
|
this.renderer.threeRenderer.clear();
|
||||||
|
this.renderer.render(this.scene, this.camera.threeCamera);
|
||||||
|
|
||||||
|
if(Config.isDev) {
|
||||||
|
rS('render').end();
|
||||||
|
rS('frame').end();
|
||||||
|
|
||||||
|
rS('rStats').start();
|
||||||
|
rS().update();
|
||||||
|
rS('rStats').end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates
|
||||||
|
TWEEN.update();
|
||||||
|
this.controls.threeControls.update();
|
||||||
|
|
||||||
|
// raf
|
||||||
|
requestAnimationFrame(this.render.bind(this));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Material {
|
||||||
|
constructor() {
|
||||||
|
this.emissive = new THREE.MeshBasicMaterial({
|
||||||
|
color: 0xeeeeee,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
fog: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.standard = new THREE.MeshStandardMaterial({
|
||||||
|
shading: THREE.FlatShading,
|
||||||
|
roughness: 1,
|
||||||
|
metalness: 0,
|
||||||
|
side: THREE.DoubleSide,
|
||||||
|
fog: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.wire = new THREE.MeshBasicMaterial({wireframe: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Material from './material';
|
||||||
|
import Helper from './helper';
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Model {
|
||||||
|
constructor(scene, manager, textures) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.textures = textures;
|
||||||
|
|
||||||
|
this.loader = new THREE.ObjectLoader(manager);
|
||||||
|
this.obj = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
load() {
|
||||||
|
// load a resource
|
||||||
|
this.loader.load(Config.model.path, (obj) => {
|
||||||
|
obj.traverse((child) => {
|
||||||
|
if(child instanceof THREE.Mesh) {
|
||||||
|
let material = new Material().standard;
|
||||||
|
material.map = this.textures.UV;
|
||||||
|
child.material = material;
|
||||||
|
|
||||||
|
if(Config.shadow.enabled) {
|
||||||
|
child.receiveShadow = true;
|
||||||
|
child.castShadow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(Config.isDev && Config.mesh.enableHelper) {
|
||||||
|
new Helper(this.scene, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set prop to obj
|
||||||
|
this.obj = obj;
|
||||||
|
|
||||||
|
obj.scale.multiplyScalar(Config.model.scale);
|
||||||
|
|
||||||
|
// add object to scene
|
||||||
|
this.scene.add(obj);
|
||||||
|
}, Model.onProgress, Model.onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
static onProgress(xhr) {
|
||||||
|
if(xhr.lengthComputable) {
|
||||||
|
let percentComplete = xhr.loaded / xhr.total * 100;
|
||||||
|
|
||||||
|
console.log(Math.round(percentComplete, 2) + '% downloaded');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static onError(xhr) {
|
||||||
|
console.error(xhr);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Renderer {
|
||||||
|
constructor(container, scene) {
|
||||||
|
this.container = container;
|
||||||
|
this.scene = scene;
|
||||||
|
|
||||||
|
this.threeRenderer = new THREE.WebGLRenderer({antialias: true});
|
||||||
|
|
||||||
|
//this.renderer.setClearColor(0x000000, 0);
|
||||||
|
this.threeRenderer.setClearColor(scene.fog.color);
|
||||||
|
this.threeRenderer.setPixelRatio(window.devicePixelRatio);
|
||||||
|
|
||||||
|
container.appendChild(this.threeRenderer.domElement);
|
||||||
|
|
||||||
|
this.threeRenderer.gammaInput = true;
|
||||||
|
this.threeRenderer.gammaOutput = true;
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
this.threeRenderer.shadowMap.enabled = true;
|
||||||
|
this.threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||||
|
this.threeRenderer.shadowMapSoft = true;
|
||||||
|
|
||||||
|
this.threeRenderer.autoClear = false;
|
||||||
|
|
||||||
|
Config.maxAnisotropy = this.threeRenderer.getMaxAnisotropy();
|
||||||
|
|
||||||
|
this.updateSize();
|
||||||
|
|
||||||
|
// Listeners
|
||||||
|
document.addEventListener('DOMContentLoaded', () => this.updateSize(), false);
|
||||||
|
window.addEventListener('resize', () => this.updateSize(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSize() {
|
||||||
|
this.threeRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(scene, camera) {
|
||||||
|
this.threeRenderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import THREE from 'three';
|
||||||
|
import { Promise } from 'es6-promise';
|
||||||
|
|
||||||
|
import Config from './../data/config';
|
||||||
|
|
||||||
|
export default class Texture {
|
||||||
|
constructor() {
|
||||||
|
this.textures = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
load() {
|
||||||
|
const loader = new THREE.TextureLoader();
|
||||||
|
const maxAnisotropy = Config.maxAnisotropy;
|
||||||
|
const imageFiles = Config.texture.imageFiles;
|
||||||
|
|
||||||
|
let promiseArray = [];
|
||||||
|
|
||||||
|
loader.setPath(Config.texture.path);
|
||||||
|
|
||||||
|
imageFiles.forEach((imageFile) => {
|
||||||
|
promiseArray.push(new Promise((resolve, reject) => {
|
||||||
|
loader.load(imageFile.image,
|
||||||
|
|
||||||
|
function(texture) {
|
||||||
|
texture.anisotropy = maxAnisotropy;
|
||||||
|
|
||||||
|
var modelOBJ = {};
|
||||||
|
modelOBJ[imageFile.name] = texture;
|
||||||
|
if(modelOBJ[imageFile.name] instanceof THREE.Texture)
|
||||||
|
resolve(modelOBJ);
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
console.log(( xhr.loaded / xhr.total * 100 ) + '% loaded');
|
||||||
|
},
|
||||||
|
function(xhr) {
|
||||||
|
reject(new Error(xhr + 'An error occurred loading while loading ' + imageFile.image));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promiseArray).then((textures) => {
|
||||||
|
for(var i = 0; i < textures.length; i++) {
|
||||||
|
this.textures[Object.keys(textures[i])[0]] = textures[i][Object.keys(textures[i])[0]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
import TWEEN from 'tween.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
isDev: false,
|
||||||
|
isLoaded: false,
|
||||||
|
isTweening: false,
|
||||||
|
isRotating: true,
|
||||||
|
isMouseMoving: false,
|
||||||
|
isMouseOver: false,
|
||||||
|
maxAnisotropy: 1,
|
||||||
|
dpr: 1,
|
||||||
|
easing: TWEEN.Easing.Quadratic.InOut,
|
||||||
|
duration: 500,
|
||||||
|
model: {
|
||||||
|
path: '/assets/models/teapot-claraio.json',
|
||||||
|
scale: 20
|
||||||
|
},
|
||||||
|
texture: {
|
||||||
|
path: '/assets/textures/',
|
||||||
|
imageFiles: [
|
||||||
|
{name: 'UV', image: 'UV_Grid_Sm.jpg'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mesh: {
|
||||||
|
enableHelper: false,
|
||||||
|
wireframe: false,
|
||||||
|
translucent: false,
|
||||||
|
material: {
|
||||||
|
color: 0xffffff,
|
||||||
|
emissive: 0xffffff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fog: {
|
||||||
|
color: 0xffffff,
|
||||||
|
near: 0.0008
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
fov: 40,
|
||||||
|
near: 2,
|
||||||
|
far: 1000,
|
||||||
|
aspect: 1,
|
||||||
|
posX: 0,
|
||||||
|
posY: 30,
|
||||||
|
posZ: 40
|
||||||
|
},
|
||||||
|
controls: {
|
||||||
|
autoRotate: true,
|
||||||
|
autoRotateSpeed: -0.5,
|
||||||
|
rotateSpeed: 0.5,
|
||||||
|
zoomSpeed: 0.8,
|
||||||
|
minDistance: 200,
|
||||||
|
maxDistance: 600,
|
||||||
|
minPolarAngle: Math.PI / 5,
|
||||||
|
maxPolarAngle: Math.PI / 2,
|
||||||
|
minAzimuthAngle: -Infinity,
|
||||||
|
maxAzimuthAngle: Infinity,
|
||||||
|
enableDamping: true,
|
||||||
|
dampingFactor: 0.5,
|
||||||
|
enableZoom: true,
|
||||||
|
target: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ambientLight: {
|
||||||
|
enabled: false,
|
||||||
|
color: 0x141414
|
||||||
|
},
|
||||||
|
directionalLight: {
|
||||||
|
enabled: true,
|
||||||
|
color: 0xf0f0f0,
|
||||||
|
intensity: 0.4,
|
||||||
|
x: -75,
|
||||||
|
y: 280,
|
||||||
|
z: 150
|
||||||
|
},
|
||||||
|
shadow: {
|
||||||
|
enabled: true,
|
||||||
|
helperEnabled: true,
|
||||||
|
bias: -0.00025,
|
||||||
|
mapWidth: 1024,
|
||||||
|
mapHeight: 1024,
|
||||||
|
near: 200,
|
||||||
|
far: 400,
|
||||||
|
top: 150,
|
||||||
|
right: 150,
|
||||||
|
bottom: -150,
|
||||||
|
left: -150
|
||||||
|
},
|
||||||
|
pointLight: {
|
||||||
|
enabled: true,
|
||||||
|
color: 0xffffff,
|
||||||
|
intensity: 0.34,
|
||||||
|
distance: 115,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
hemiLight: {
|
||||||
|
enabled: true,
|
||||||
|
color: 0xc8c8c8,
|
||||||
|
groundColor: 0xffffff,
|
||||||
|
intensity: 0.3,
|
||||||
|
x: -275,
|
||||||
|
y: 145,
|
||||||
|
z: 0
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* @author alteredq / http://alteredqualia.com/
|
||||||
|
* @author mr.doob / http://mrdoob.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
canvas: !!window.CanvasRenderingContext2D,
|
||||||
|
webgl: (function() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
return !!( window.WebGLRenderingContext && ( canvas.getContext('webgl') || canvas.getContext('experimental-webgl') ) );
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
workers: !!window.Worker,
|
||||||
|
fileapi: window.File && window.FileReader && window.FileList && window.Blob,
|
||||||
|
|
||||||
|
getWebGLErrorMessage: function() {
|
||||||
|
|
||||||
|
var element = document.createElement('div');
|
||||||
|
element.id = 'webgl-error-message';
|
||||||
|
element.style.fontFamily = 'monospace';
|
||||||
|
element.style.fontSize = '13px';
|
||||||
|
element.style.fontWeight = 'normal';
|
||||||
|
element.style.textAlign = 'center';
|
||||||
|
element.style.background = '#fff';
|
||||||
|
element.style.color = '#000';
|
||||||
|
element.style.padding = '1.5em';
|
||||||
|
element.style.width = '400px';
|
||||||
|
element.style.margin = '5em auto 0';
|
||||||
|
|
||||||
|
if(!this.webgl) {
|
||||||
|
|
||||||
|
element.innerHTML = window.WebGLRenderingContext ? [
|
||||||
|
'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000000">WebGL</a>.<br />',
|
||||||
|
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000000">here</a>.'
|
||||||
|
].join('\n') : [
|
||||||
|
'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000000">WebGL</a>.<br/>',
|
||||||
|
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000000">here</a>.'
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
addGetWebGLMessage: function(parameters) {
|
||||||
|
|
||||||
|
var parent, id, element;
|
||||||
|
|
||||||
|
parameters = parameters || {};
|
||||||
|
|
||||||
|
parent = parameters.parent !== undefined ? parameters.parent : document.body;
|
||||||
|
id = parameters.id !== undefined ? parameters.id : 'oldie';
|
||||||
|
|
||||||
|
element = this.getWebGLErrorMessage();
|
||||||
|
element.id = id;
|
||||||
|
|
||||||
|
parent.appendChild(element);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,26 @@
|
||||||
|
export default class Helpers {
|
||||||
|
static throttle(fn, threshhold, scope) {
|
||||||
|
threshhold || (threshhold = 250);
|
||||||
|
var last, deferTimer;
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
var context = scope || this;
|
||||||
|
|
||||||
|
var now = +new Date,
|
||||||
|
args = arguments;
|
||||||
|
|
||||||
|
if(last && now < last + threshhold) {
|
||||||
|
// hold on to it
|
||||||
|
clearTimeout(deferTimer);
|
||||||
|
deferTimer = setTimeout(function() {
|
||||||
|
last = now;
|
||||||
|
fn.apply(context, args);
|
||||||
|
}, threshhold);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last = now;
|
||||||
|
fn.apply(context, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
const ALIAS = {
|
||||||
|
'left' : 37,
|
||||||
|
'up' : 38,
|
||||||
|
'right' : 39,
|
||||||
|
'down' : 40,
|
||||||
|
'space' : 32,
|
||||||
|
'pageup' : 33,
|
||||||
|
'pagedown': 34,
|
||||||
|
'tab' : 9,
|
||||||
|
'escape' : 27
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Keyboard {
|
||||||
|
constructor(domElement) {
|
||||||
|
this.domElement = domElement || document;
|
||||||
|
this.keyCodes = {};
|
||||||
|
|
||||||
|
// bind keyEvents
|
||||||
|
this.domElement.addEventListener('keydown', () => this.onKeyChange(event), false);
|
||||||
|
this.domElement.addEventListener('keyup', () => this.onKeyChange(event), false);
|
||||||
|
|
||||||
|
// bind window blur
|
||||||
|
window.addEventListener('blur', () => this.onBlur, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.domElement.removeEventListener('keydown', () => this.onKeyChange(event), false);
|
||||||
|
this.domElement.removeEventListener('keyup', () => this.onKeyChange(event), false);
|
||||||
|
|
||||||
|
// unbind window blur event
|
||||||
|
window.removeEventListener('blur', () => this.onBlur, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur() {
|
||||||
|
for(let prop in this.keyCodes)
|
||||||
|
this.keyCodes[prop] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyChange(event) {
|
||||||
|
// log to debug
|
||||||
|
//console.log('onKeyChange', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)
|
||||||
|
|
||||||
|
// update this.keyCodes
|
||||||
|
let keyCode = event.keyCode;
|
||||||
|
this.keyCodes[keyCode] = event.type === 'keydown';
|
||||||
|
}
|
||||||
|
|
||||||
|
pressed(keyDesc) {
|
||||||
|
let keys = keyDesc.split('+');
|
||||||
|
for(let i = 0; i < keys.length; i++) {
|
||||||
|
let key = keys[i];
|
||||||
|
let pressed = false;
|
||||||
|
if(Object.keys(ALIAS).indexOf(key) != -1) {
|
||||||
|
pressed = this.keyCodes[ALIAS[key]];
|
||||||
|
} else {
|
||||||
|
pressed = this.keyCodes[key.toUpperCase().charCodeAt(0)];
|
||||||
|
}
|
||||||
|
if(!pressed)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventMatches(event, keyDesc) {
|
||||||
|
let aliases = ALIAS;
|
||||||
|
let aliasKeys = Object.keys(aliases);
|
||||||
|
let keys = keyDesc.split('+');
|
||||||
|
// log to debug
|
||||||
|
// console.log('eventMatches', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)
|
||||||
|
for(let i = 0; i < keys.length; i++) {
|
||||||
|
let key = keys[i];
|
||||||
|
let pressed = false;
|
||||||
|
if(key === 'shift') {
|
||||||
|
pressed = (event.shiftKey ? true : false);
|
||||||
|
} else if(key === 'ctrl') {
|
||||||
|
pressed = (event.ctrlKey ? true : false);
|
||||||
|
} else if(key === 'alt') {
|
||||||
|
pressed = (event.altKey ? true : false);
|
||||||
|
} else if(key === 'meta') {
|
||||||
|
pressed = (event.metaKey ? true : false);
|
||||||
|
} else if(aliasKeys.indexOf(key) !== -1) {
|
||||||
|
pressed = (event.keyCode === aliases[key]);
|
||||||
|
} else if(event.keyCode === key.toUpperCase().charCodeAt(0)) {
|
||||||
|
pressed = true;
|
||||||
|
}
|
||||||
|
if(!pressed)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,4 @@
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
.rs-base{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #222;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.2em;
|
||||||
|
width: 350px;
|
||||||
|
font-family: 'Roboto Condensed', tahoma, sans-serif;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base h1{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 1.4em;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-group{
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-group.hidden{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-fraction{
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-fraction p{
|
||||||
|
width: 120px;
|
||||||
|
text-align: right;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-legend{
|
||||||
|
position: absolute;
|
||||||
|
line-height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-counter-base{
|
||||||
|
position: relative;
|
||||||
|
margin: 2px 0;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base span.rs-counter-id{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base div.rs-counter-value{
|
||||||
|
position: absolute;
|
||||||
|
left: 90px;
|
||||||
|
width: 30px;
|
||||||
|
height: 1em;
|
||||||
|
top: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rs-base canvas.rs-canvas{
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,719 @@
|
||||||
|
// performance.now() polyfill from https://gist.github.com/paulirish/5438650
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
( function () {
|
||||||
|
|
||||||
|
// prepare base perf object
|
||||||
|
if ( typeof window.performance === 'undefined' ) {
|
||||||
|
window.performance = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !window.performance.now ) {
|
||||||
|
|
||||||
|
var nowOffset = Date.now();
|
||||||
|
|
||||||
|
if ( performance.timing && performance.timing.navigationStart ) {
|
||||||
|
nowOffset = performance.timing.navigationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.performance.now = function now () {
|
||||||
|
return Date.now() - nowOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !window.performance.mark ) {
|
||||||
|
window.performance.mark = function(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !window.performance.measure ) {
|
||||||
|
window.performance.measure = function(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
} )();
|
||||||
|
|
||||||
|
window.rStats = function rStats ( settings ) {
|
||||||
|
|
||||||
|
function iterateKeys ( array, callback ) {
|
||||||
|
var keys = Object.keys( array );
|
||||||
|
for ( var j = 0, l = keys.length; j < l; j++ ) {
|
||||||
|
callback( keys[ j ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importCSS ( url ) {
|
||||||
|
|
||||||
|
var element = document.createElement( 'link' );
|
||||||
|
element.href = url;
|
||||||
|
element.rel = 'stylesheet';
|
||||||
|
element.type = 'text/css';
|
||||||
|
document.getElementsByTagName( 'head' )[ 0 ].appendChild( element );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _settings = settings || {};
|
||||||
|
var _colours = _settings.colours || [ '#850700', '#c74900', '#fcb300', '#284280', '#4c7c0c' ];
|
||||||
|
|
||||||
|
var _cssFont = 'https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300';
|
||||||
|
var _cssRStats = ( _settings.CSSPath ? _settings.CSSPath : '' ) + 'rStats.css';
|
||||||
|
|
||||||
|
var _css = _settings.css || [ _cssFont, _cssRStats ];
|
||||||
|
_css.forEach(function (uri) {
|
||||||
|
importCSS( uri );
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( !_settings.values ) _settings.values = {};
|
||||||
|
|
||||||
|
var _base, _div, _elHeight = 10, _elWidth = 200;
|
||||||
|
var _perfCounters = {};
|
||||||
|
|
||||||
|
|
||||||
|
function Graph ( _dom, _id, _defArg ) {
|
||||||
|
|
||||||
|
var _def = _defArg || {};
|
||||||
|
var _canvas = document.createElement( 'canvas' ),
|
||||||
|
_ctx = _canvas.getContext( '2d' ),
|
||||||
|
_max = 0,
|
||||||
|
_current = 0;
|
||||||
|
|
||||||
|
var c = _def.color ? _def.color : '#666666';
|
||||||
|
|
||||||
|
var _dotCanvas = document.createElement( 'canvas' ),
|
||||||
|
_dotCtx = _dotCanvas.getContext( '2d' );
|
||||||
|
_dotCanvas.width = 1;
|
||||||
|
_dotCanvas.height = 2 * _elHeight;
|
||||||
|
_dotCtx.fillStyle = '#444444';
|
||||||
|
_dotCtx.fillRect( 0, 0, 1, 2 * _elHeight );
|
||||||
|
_dotCtx.fillStyle = c;
|
||||||
|
_dotCtx.fillRect( 0, _elHeight, 1, _elHeight );
|
||||||
|
_dotCtx.fillStyle = '#ffffff';
|
||||||
|
_dotCtx.globalAlpha = 0.5;
|
||||||
|
_dotCtx.fillRect( 0, _elHeight, 1, 1 );
|
||||||
|
_dotCtx.globalAlpha = 1;
|
||||||
|
|
||||||
|
var _alarmCanvas = document.createElement( 'canvas' ),
|
||||||
|
_alarmCtx = _alarmCanvas.getContext( '2d' );
|
||||||
|
_alarmCanvas.width = 1;
|
||||||
|
_alarmCanvas.height = 2 * _elHeight;
|
||||||
|
_alarmCtx.fillStyle = '#444444';
|
||||||
|
_alarmCtx.fillRect( 0, 0, 1, 2 * _elHeight );
|
||||||
|
_alarmCtx.fillStyle = '#b70000';
|
||||||
|
_alarmCtx.fillRect( 0, _elHeight, 1, _elHeight );
|
||||||
|
_alarmCtx.globalAlpha = 0.5;
|
||||||
|
_alarmCtx.fillStyle = '#ffffff';
|
||||||
|
_alarmCtx.fillRect( 0, _elHeight, 1, 1 );
|
||||||
|
_alarmCtx.globalAlpha = 1;
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
_canvas.width = _elWidth;
|
||||||
|
_canvas.height = _elHeight;
|
||||||
|
_canvas.style.width = _canvas.width + 'px';
|
||||||
|
_canvas.style.height = _canvas.height + 'px';
|
||||||
|
_canvas.className = 'rs-canvas';
|
||||||
|
_dom.appendChild( _canvas );
|
||||||
|
|
||||||
|
_ctx.fillStyle = '#444444';
|
||||||
|
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw ( v, alarm ) {
|
||||||
|
_current += ( v - _current ) * 0.1;
|
||||||
|
_max *= 0.99;
|
||||||
|
if ( _current > _max ) _max = _current;
|
||||||
|
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
|
||||||
|
if ( alarm ) {
|
||||||
|
_ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
|
||||||
|
} else {
|
||||||
|
_ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function StackGraph ( _dom, _num ) {
|
||||||
|
|
||||||
|
var _canvas = document.createElement( 'canvas' ),
|
||||||
|
_ctx = _canvas.getContext( '2d' );
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
_canvas.width = _elWidth;
|
||||||
|
_canvas.height = _elHeight * _num;
|
||||||
|
_canvas.style.width = _canvas.width + 'px';
|
||||||
|
_canvas.style.height = _canvas.height + 'px';
|
||||||
|
_canvas.className = 'rs-canvas';
|
||||||
|
_dom.appendChild( _canvas );
|
||||||
|
|
||||||
|
_ctx.fillStyle = '#444444';
|
||||||
|
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw ( v ) {
|
||||||
|
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
|
||||||
|
var th = 0;
|
||||||
|
iterateKeys( v, function ( j ) {
|
||||||
|
var h = v[ j ] * _canvas.height;
|
||||||
|
_ctx.fillStyle = _colours[ j ];
|
||||||
|
_ctx.fillRect( _canvas.width - 1, th, 1, h );
|
||||||
|
th += h;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function PerfCounter ( id, group ) {
|
||||||
|
|
||||||
|
var _id = id,
|
||||||
|
_time,
|
||||||
|
_value = 0,
|
||||||
|
_total = 0,
|
||||||
|
_averageValue = 0,
|
||||||
|
_accumValue = 0,
|
||||||
|
_accumStart = performance.now(),
|
||||||
|
_accumSamples = 0,
|
||||||
|
_dom = document.createElement( 'div' ),
|
||||||
|
_spanId = document.createElement( 'span' ),
|
||||||
|
_spanValue = document.createElement( 'div' ),
|
||||||
|
_spanValueText = document.createTextNode( '' ),
|
||||||
|
_def = _settings ? _settings.values[ _id.toLowerCase() ] : null,
|
||||||
|
_graph = new Graph( _dom, _id, _def ),
|
||||||
|
_started = false;
|
||||||
|
|
||||||
|
_dom.className = 'rs-counter-base';
|
||||||
|
|
||||||
|
_spanId.className = 'rs-counter-id';
|
||||||
|
_spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;
|
||||||
|
|
||||||
|
_spanValue.className = 'rs-counter-value';
|
||||||
|
_spanValue.appendChild( _spanValueText );
|
||||||
|
|
||||||
|
_dom.appendChild( _spanId );
|
||||||
|
_dom.appendChild( _spanValue );
|
||||||
|
if ( group ) group.div.appendChild( _dom );
|
||||||
|
else _div.appendChild( _dom );
|
||||||
|
|
||||||
|
_time = performance.now();
|
||||||
|
|
||||||
|
function _average ( v ) {
|
||||||
|
if ( _def && _def.average ) {
|
||||||
|
_accumValue += v;
|
||||||
|
_accumSamples++;
|
||||||
|
var t = performance.now();
|
||||||
|
if ( t - _accumStart >= ( _def.avgMs || 1000 ) ) {
|
||||||
|
_averageValue = _accumValue / _accumSamples;
|
||||||
|
_accumValue = 0;
|
||||||
|
_accumStart = t;
|
||||||
|
_accumSamples = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_time = performance.now();
|
||||||
|
if( _settings.userTimingAPI ) performance.mark( _id + '-start' );
|
||||||
|
_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {
|
||||||
|
_value = performance.now() - _time;
|
||||||
|
if( _settings.userTimingAPI ) {
|
||||||
|
performance.mark( _id + '-end' );
|
||||||
|
if( _started ) {
|
||||||
|
performance.measure( _id, _id + '-start', _id + '-end' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tick () {
|
||||||
|
_end();
|
||||||
|
_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _draw () {
|
||||||
|
var v = ( _def && _def.average ) ? _averageValue : _value;
|
||||||
|
_spanValueText.nodeValue = Math.round( v * 100 ) / 100;
|
||||||
|
var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );
|
||||||
|
_graph.draw( _value, a );
|
||||||
|
_dom.style.color = a ? '#b70000' : '#ffffff';
|
||||||
|
}
|
||||||
|
|
||||||
|
function _frame () {
|
||||||
|
var t = performance.now();
|
||||||
|
var e = t - _time;
|
||||||
|
_total++;
|
||||||
|
if ( e > 1000 ) {
|
||||||
|
if ( _def && _def.interpolate === false ) {
|
||||||
|
_value = _total;
|
||||||
|
} else {
|
||||||
|
_value = _total * 1000 / e;
|
||||||
|
}
|
||||||
|
_total = 0;
|
||||||
|
_time = t;
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _set ( v ) {
|
||||||
|
_value = v;
|
||||||
|
_average( _value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
set: _set,
|
||||||
|
start: _start,
|
||||||
|
tick: _tick,
|
||||||
|
end: _end,
|
||||||
|
frame: _frame,
|
||||||
|
value: function () {
|
||||||
|
return _value;
|
||||||
|
},
|
||||||
|
draw: _draw
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample () {
|
||||||
|
|
||||||
|
var _value = 0;
|
||||||
|
|
||||||
|
function _set ( v ) {
|
||||||
|
_value = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
set: _set,
|
||||||
|
value: function () {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _perf ( idArg ) {
|
||||||
|
|
||||||
|
var id = idArg.toLowerCase();
|
||||||
|
if ( id === undefined ) id = 'default';
|
||||||
|
if ( _perfCounters[ id ] ) return _perfCounters[ id ];
|
||||||
|
|
||||||
|
var group = null;
|
||||||
|
if ( _settings && _settings.groups ) {
|
||||||
|
iterateKeys( _settings.groups, function ( j ) {
|
||||||
|
var g = _settings.groups[ parseInt( j, 10 ) ];
|
||||||
|
if ( !group && g.values.indexOf( id.toLowerCase() ) !== -1 ) {
|
||||||
|
group = g;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = new PerfCounter( id, group );
|
||||||
|
_perfCounters[ id ] = p;
|
||||||
|
return p;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _init () {
|
||||||
|
|
||||||
|
if ( _settings.plugins ) {
|
||||||
|
if ( !_settings.values ) _settings.values = {};
|
||||||
|
if ( !_settings.groups ) _settings.groups = [];
|
||||||
|
if ( !_settings.fractions ) _settings.fractions = [];
|
||||||
|
for ( var j = 0; j < _settings.plugins.length; j++ ) {
|
||||||
|
_settings.plugins[ j ].attach( _perf );
|
||||||
|
iterateKeys( _settings.plugins[ j ].values, function ( k ) {
|
||||||
|
_settings.values[ k ] = _settings.plugins[ j ].values[ k ];
|
||||||
|
} );
|
||||||
|
_settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups );
|
||||||
|
_settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_settings.plugins = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_base = document.createElement( 'div' );
|
||||||
|
_base.className = 'rs-base';
|
||||||
|
_div = document.createElement( 'div' );
|
||||||
|
_div.className = 'rs-container';
|
||||||
|
_div.style.height = 'auto';
|
||||||
|
_base.appendChild( _div );
|
||||||
|
document.body.appendChild( _base );
|
||||||
|
|
||||||
|
if ( !_settings ) return;
|
||||||
|
|
||||||
|
if ( _settings.groups ) {
|
||||||
|
iterateKeys( _settings.groups, function ( j ) {
|
||||||
|
var g = _settings.groups[ parseInt( j, 10 ) ];
|
||||||
|
var div = document.createElement( 'div' );
|
||||||
|
div.className = 'rs-group';
|
||||||
|
g.div = div;
|
||||||
|
var h1 = document.createElement( 'h1' );
|
||||||
|
h1.textContent = g.caption;
|
||||||
|
h1.addEventListener( 'click', function ( e ) {
|
||||||
|
this.classList.toggle( 'hidden' );
|
||||||
|
e.preventDefault();
|
||||||
|
}.bind( div ) );
|
||||||
|
_div.appendChild( h1 );
|
||||||
|
_div.appendChild( div );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _settings.fractions ) {
|
||||||
|
iterateKeys( _settings.fractions, function ( j ) {
|
||||||
|
var f = _settings.fractions[ parseInt( j, 10 ) ];
|
||||||
|
var div = document.createElement( 'div' );
|
||||||
|
div.className = 'rs-fraction';
|
||||||
|
var legend = document.createElement( 'div' );
|
||||||
|
legend.className = 'rs-legend';
|
||||||
|
|
||||||
|
var h = 0;
|
||||||
|
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
|
||||||
|
var p = document.createElement( 'p' );
|
||||||
|
p.textContent = _settings.fractions[ j ].steps[ k ];
|
||||||
|
p.style.color = _colours[ h ];
|
||||||
|
legend.appendChild( p );
|
||||||
|
h++;
|
||||||
|
} );
|
||||||
|
div.appendChild( legend );
|
||||||
|
div.style.height = h * _elHeight + 'px';
|
||||||
|
f.div = div;
|
||||||
|
var graph = new StackGraph( div, h );
|
||||||
|
f.graph = graph;
|
||||||
|
_div.appendChild( div );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
|
||||||
|
iterateKeys( _settings.plugins, function ( j ) {
|
||||||
|
_settings.plugins[ j ].update();
|
||||||
|
} );
|
||||||
|
|
||||||
|
iterateKeys( _perfCounters, function ( j ) {
|
||||||
|
_perfCounters[ j ].draw();
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( _settings && _settings.fractions ) {
|
||||||
|
iterateKeys( _settings.fractions, function ( j ) {
|
||||||
|
var f = _settings.fractions[ parseInt( j, 10 ) ];
|
||||||
|
var v = [];
|
||||||
|
var base = _perfCounters[ f.base.toLowerCase() ];
|
||||||
|
if ( base ) {
|
||||||
|
base = base.value();
|
||||||
|
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
|
||||||
|
var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase();
|
||||||
|
var val = _perfCounters[ s ];
|
||||||
|
if ( val ) {
|
||||||
|
v.push( val.value() / base );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
f.graph.draw( v );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if( _height != _div.clientHeight ) {
|
||||||
|
_height = _div.clientHeight;
|
||||||
|
_base.style.height = _height + 2 * _elHeight + 'px';
|
||||||
|
console.log( _base.clientHeight );
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
return function ( id ) {
|
||||||
|
if ( id ) return _perf( id );
|
||||||
|
return {
|
||||||
|
element: _base,
|
||||||
|
update: _update
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof module === 'object') {
|
||||||
|
module.exports = window.rStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.glStats = function () {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _totalDrawArraysCalls = 0,
|
||||||
|
_totalDrawElementsCalls = 0,
|
||||||
|
_totalUseProgramCalls = 0,
|
||||||
|
_totalFaces = 0,
|
||||||
|
_totalVertices = 0,
|
||||||
|
_totalPoints = 0,
|
||||||
|
_totalBindTexures = 0;
|
||||||
|
|
||||||
|
function _h ( f, c ) {
|
||||||
|
return function () {
|
||||||
|
c.apply( this, arguments );
|
||||||
|
f.apply( this, arguments );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
|
||||||
|
_totalDrawArraysCalls++;
|
||||||
|
if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
|
||||||
|
else _totalVertices += arguments[ 2 ];
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
|
||||||
|
_totalDrawElementsCalls++;
|
||||||
|
_totalFaces += arguments[ 1 ] / 3;
|
||||||
|
_totalVertices += arguments[ 1 ];
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
|
||||||
|
_totalUseProgramCalls++;
|
||||||
|
} );
|
||||||
|
|
||||||
|
WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
|
||||||
|
_totalBindTexures++;
|
||||||
|
} );
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
allcalls: {
|
||||||
|
over: 3000,
|
||||||
|
caption: 'Calls (hook)'
|
||||||
|
},
|
||||||
|
drawelements: {
|
||||||
|
caption: 'drawElements (hook)'
|
||||||
|
},
|
||||||
|
drawarrays: {
|
||||||
|
caption: 'drawArrays (hook)'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'WebGL',
|
||||||
|
values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [ {
|
||||||
|
base: 'allcalls',
|
||||||
|
steps: [ 'drawelements', 'drawarrays' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
_rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
|
||||||
|
_rS( 'drawElements' ).set( _totalDrawElementsCalls );
|
||||||
|
_rS( 'drawArrays' ).set( _totalDrawArraysCalls );
|
||||||
|
_rS( 'bindTexture' ).set( _totalBindTexures );
|
||||||
|
_rS( 'useProgram' ).set( _totalUseProgramCalls );
|
||||||
|
_rS( 'glfaces' ).set( _totalFaces );
|
||||||
|
_rS( 'glvertices' ).set( _totalVertices );
|
||||||
|
_rS( 'glpoints' ).set( _totalPoints );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_totalDrawArraysCalls = 0;
|
||||||
|
_totalDrawElementsCalls = 0;
|
||||||
|
_totalUseProgramCalls = 0;
|
||||||
|
_totalFaces = 0;
|
||||||
|
_totalVertices = 0;
|
||||||
|
_totalPoints = 0;
|
||||||
|
_totalBindTexures = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
window.threeStats = function ( renderer ) {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
'renderer.info.memory.geometries': {
|
||||||
|
caption: 'Geometries'
|
||||||
|
},
|
||||||
|
'renderer.info.memory.textures': {
|
||||||
|
caption: 'Textures'
|
||||||
|
},
|
||||||
|
'renderer.info.programs': {
|
||||||
|
caption: 'Programs'
|
||||||
|
},
|
||||||
|
'renderer.info.render.calls': {
|
||||||
|
caption: 'Calls'
|
||||||
|
},
|
||||||
|
'renderer.info.render.faces': {
|
||||||
|
caption: 'Faces',
|
||||||
|
over: 1000
|
||||||
|
},
|
||||||
|
'renderer.info.render.points': {
|
||||||
|
caption: 'Points'
|
||||||
|
},
|
||||||
|
'renderer.info.render.vertices': {
|
||||||
|
caption: 'Vertices'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'Three.js - Memory',
|
||||||
|
values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
|
||||||
|
}, {
|
||||||
|
caption: 'Three.js - Render',
|
||||||
|
values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [];
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
|
||||||
|
_rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
|
||||||
|
//_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
|
||||||
|
_rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
|
||||||
|
_rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
|
||||||
|
_rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );
|
||||||
|
_rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
|
||||||
|
_rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From https://github.com/paulirish/memory-stats.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
window.BrowserStats = function () {
|
||||||
|
|
||||||
|
var _rS = null;
|
||||||
|
|
||||||
|
var _usedJSHeapSize = 0,
|
||||||
|
_totalJSHeapSize = 0;
|
||||||
|
|
||||||
|
var memory = {
|
||||||
|
usedJSHeapSize: 0,
|
||||||
|
totalJSHeapSize: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( window.performance && performance.memory )
|
||||||
|
memory = performance.memory;
|
||||||
|
|
||||||
|
if ( memory.totalJSHeapSize === 0 ) {
|
||||||
|
console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
|
||||||
|
}
|
||||||
|
|
||||||
|
var _values = {
|
||||||
|
memory: {
|
||||||
|
caption: 'Used Memory',
|
||||||
|
average: true,
|
||||||
|
avgMs: 1000,
|
||||||
|
over: 22
|
||||||
|
},
|
||||||
|
total: {
|
||||||
|
caption: 'Total Memory'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var _groups = [ {
|
||||||
|
caption: 'Browser',
|
||||||
|
values: [ 'memory', 'total' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var _fractions = [ {
|
||||||
|
base: 'total',
|
||||||
|
steps: [ 'memory' ]
|
||||||
|
} ];
|
||||||
|
|
||||||
|
var log1024 = Math.log( 1024 );
|
||||||
|
|
||||||
|
function _size ( v ) {
|
||||||
|
|
||||||
|
var precision = 100; //Math.pow(10, 2);
|
||||||
|
var i = Math.floor( Math.log( v ) / log1024 );
|
||||||
|
if( v === 0 ) i = 1;
|
||||||
|
return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function _update () {
|
||||||
|
_usedJSHeapSize = _size( memory.usedJSHeapSize );
|
||||||
|
_totalJSHeapSize = _size( memory.totalJSHeapSize );
|
||||||
|
|
||||||
|
_rS( 'memory' ).set( _usedJSHeapSize );
|
||||||
|
_rS( 'total' ).set( _totalJSHeapSize );
|
||||||
|
}
|
||||||
|
|
||||||
|
function _start () {
|
||||||
|
_usedJSHeapSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _end () {}
|
||||||
|
|
||||||
|
function _attach ( r ) {
|
||||||
|
_rS = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update: _update,
|
||||||
|
start: _start,
|
||||||
|
end: _end,
|
||||||
|
attach: _attach,
|
||||||
|
values: _values,
|
||||||
|
groups: _groups,
|
||||||
|
fractions: _fractions
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof module === 'object') {
|
||||||
|
module.exports = {
|
||||||
|
glStats: window.glStats,
|
||||||
|
threeStats: window.threeStats,
|
||||||
|
BrowserStats: window.BrowserStats
|
||||||
|
};
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 636 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Three.js Webpack ES6 Boilerplate</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="/assets/css/app.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<div id="appContainer" class="main">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/assets/js/rStats.js"></script>
|
||||||
|
<script src="/assets/js/dat.gui.min.js"></script>
|
||||||
|
<script src="/assets/js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,95 @@
|
||||||
|
var webpack = require('webpack'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
|
var entry = './src/js/app.js',
|
||||||
|
includePath = path.join(__dirname, 'src/js'),
|
||||||
|
nodeModulesPath = path.join(__dirname, 'node_modules'),
|
||||||
|
outputPath = path.join(__dirname, 'src/public/assets/js');
|
||||||
|
|
||||||
|
var PROD = JSON.parse(process.env.NODE_ENV || 0);
|
||||||
|
|
||||||
|
var env = 'dev',
|
||||||
|
time = Date.now(),
|
||||||
|
devtool = 'eval',
|
||||||
|
debug = true,
|
||||||
|
plugins = [
|
||||||
|
new webpack.NoErrorsPlugin(),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
__ENV__: JSON.stringify(env),
|
||||||
|
___BUILD_TIME___: time
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
if(PROD) {
|
||||||
|
env = 'prod';
|
||||||
|
devtool = 'hidden-source-map';
|
||||||
|
debug = false;
|
||||||
|
outputPath = __dirname + '/build/public/assets/js';
|
||||||
|
|
||||||
|
uglifyOptions = {
|
||||||
|
sourceMap: false,
|
||||||
|
mangle: true,
|
||||||
|
compress: {
|
||||||
|
drop_console: true
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
comments: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
plugins.push(new webpack.optimize.UglifyJsPlugin(uglifyOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Webpack build - ENV: ' + env + ' V: ' + time);
|
||||||
|
console.log(' - outputPath ', outputPath);
|
||||||
|
console.log(' - includePath ', includePath);
|
||||||
|
console.log(' - nodeModulesPath ', nodeModulesPath);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
stats: {
|
||||||
|
colors: true
|
||||||
|
},
|
||||||
|
|
||||||
|
debug: debug,
|
||||||
|
|
||||||
|
devtool: devtool,
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
contentBase: 'src/public'
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: [
|
||||||
|
entry
|
||||||
|
],
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: outputPath,
|
||||||
|
publicPath: 'assets/js',
|
||||||
|
filename: 'app.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.js?$/,
|
||||||
|
loader: 'babel-loader',
|
||||||
|
query: {
|
||||||
|
presets: ['es2015']
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
includePath, nodeModulesPath
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
sassLoader: {
|
||||||
|
outputStyle: 'compressed',
|
||||||
|
outFile: __dirname + '/src/public/assets/css'
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: plugins,
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
alias: {}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue