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