2020-04-07 21:44:46 +02:00
class VTUtils {
static random ( min , max ) {
let rand = Math . random ( ) ;
if ( typeof min === 'undefined' ) {
return rand ;
} else if ( typeof max === 'undefined' ) {
if ( min instanceof Array ) {
return min [ Math . floor ( rand * min . length ) ] ;
} else {
return rand * min ;
}
} else {
if ( min > max ) {
let tmp = min ;
min = max ;
max = tmp ;
}
return rand * ( max - min ) + min ;
}
} ;
static randomInt ( min , max ) {
return Math . floor ( VTUtils . random ( min , max ) ) ;
}
static normalize ( val , max , min ) {
return ( val - min ) / ( max - min ) ;
} ;
static distance ( x , y , x2 , y2 ) {
let a = x - x2 ;
let b = y - y2 ;
return Math . sqrt ( a * a + b * b ) ;
}
static map ( n , start1 , stop1 , start2 , stop2 , withinBounds ) {
let newVal = ( n - start1 ) / ( stop1 - start1 ) * ( stop2 - start2 ) + start2 ;
if ( ! withinBounds ) {
return newVal ;
}
if ( start2 < stop2 ) {
return this . constrain ( newVal , start2 , stop2 ) ;
} else {
return this . constrain ( newVal , stop2 , start2 ) ;
}
} ;
static constrain ( n , low , high ) {
return Math . max ( Math . min ( n , high ) , low ) ;
}
static hsvToRgb ( h , s , v ) {
2020-08-05 11:24:59 +02:00
let r , g , b ,
i = Math . floor ( h * 6 ) ,
f = h * 6 - i ,
p = v * ( 1 - s ) ,
q = v * ( 1 - f * s ) ,
t = v * ( 1 - ( 1 - f ) * s ) ;
2020-04-07 21:44:46 +02:00
switch ( i % 6 ) {
case 0 :
r = v , g = t , b = p ;
break ;
case 1 :
r = q , g = v , b = p ;
break ;
case 2 :
r = p , g = v , b = t ;
break ;
case 3 :
r = p , g = q , b = v ;
break ;
case 4 :
r = t , g = p , b = v ;
break ;
case 5 :
r = v , g = p , b = q ;
break ;
}
return { r : r , g : g , b : b } ;
}
static peakRGB ( peak ) {
return {
r : peak ,
g : 1 - peak ,
b : 0
} ;
}
}
class VTVector {
constructor ( x , y , z ) {
this . x = x || 0 ;
this . y = y || 0 ;
this . z = z || 0 ;
}
//helper
static createRandom ( x , y , z ) {
x = x || 1 ;
y = y || 1 ;
z = z || 0 ;
return new VTVector ( VTUtils . random ( - x , x ) , VTUtils . random ( - y , y ) , VTUtils . random ( - z , z ) ) ;
}
mult ( times ) {
this . x *= times ;
this . y *= times ;
this . z *= times ;
}
set ( vector ) {
this . x = vector . x ;
this . y = vector . y ;
this . z = vector . z ;
}
add ( vector ) {
this . x = this . x + vector . x ;
this . y = this . y + vector . y ;
this . z = this . z + vector . z ;
}
addXYZ ( x , y , z ) {
this . x += x ;
this . y += y ;
this . z += z ;
}
setXYZ ( x , y , z ) {
this . x = x || 0 ;
this . y = y || 0 ;
this . z = z || 0 ;
}
clone ( ) {
return new VTVector ( this . x , this . y , this . z ) ;
}
}
2020-08-05 11:24:59 +02:00
function $ ( sel , s ) {
s = s || document ;
return s . querySelector ( sel ) ;
}
function $$ ( sel , s ) {
s = s || document ;
return s . querySelectorAll ( sel ) ;
}
Node . prototype . addDelegatedEventListener = function ( type , aim , cb ) {
this . addEventListener ( type , ( event ) => {
let target = event . target ;
if ( target . matches ( aim ) ) {
cb ( event , target ) ;
} else {
let parent = target . closest ( aim ) ;
if ( parent ) {
cb ( event , parent ) ;
}
}
} )
} ;
Node . prototype . hasClass = function ( className ) {
let items = className . split ( ',' ) ,
has = null ;
for ( let item of items ) {
if ( has === false ) {
break ;
}
has = this . classList . contains ( item . trim ( ) ) ;
}
return has === true ;
}
Node . prototype . addClass = function ( className ) {
let items = className . split ( ',' ) ;
for ( let item of items ) {
this . classList . add ( item . trim ( ) ) ;
}
return this ;
}
Node . prototype . removeClass = function ( className ) {
let items = className . split ( ',' ) ;
for ( let item of items ) {
this . classList . remove ( item . trim ( ) ) ;
}
return this ;
}
Node . prototype . toggleClass = function ( className , force ) {
let items = className . split ( ',' ) ;
for ( let item of items ) {
this . classList . toggle ( item . trim ( ) , force ) ;
}
}
Node . prototype . switchClass = function ( clOne , clTwo , twoOne ) {
let cl = this . classList ;
if ( twoOne ) {
cl . remove ( clOne ) ;
cl . add ( clTwo )
} else {
cl . remove ( clTwo )
cl . add ( clOne )
}
}
Node . prototype . toggleCheck = function ( className , force ) {
let cl = this . classList ;
let items = className . split ( ',' ) ;
for ( let item of items ) {
let clOne = item . trim ( ) ;
if ( force ) {
cl . add ( clOne ) ;
} else {
cl . remove ( clOne )
}
}
}
File . prototype . toBase64 = function ( cb ) {
const reader = new FileReader ( ) ;
reader . onloadend = cb ;
reader . readAsDataURL ( this ) ;
}
function b64toBlob ( b64Data , type ) {
const byteCharacters = atob ( b64Data ) ;
const byteNumbers = new Array ( byteCharacters . length ) ;
for ( let i = 0 ; i < byteCharacters . length ; i ++ ) {
byteNumbers [ i ] = byteCharacters . charCodeAt ( i ) ;
}
const byteArray = new Uint8Array ( byteNumbers ) ;
return new Blob ( [ byteArray ] , { type : type } ) ;
}
function create ( name , content ) {
let d = document . createElement ( name ) ;
if ( content ) {
d . innerHTML = content ;
}
return d ;
}
function append ( to , array ) {
for ( let item of array ) {
to . appendChild ( item ) ;
}
}
function loadFromJSONToVisualData ( useKeys ) {
fetch ( '/audio-vis/out/showCase.json' ) . then ( ( res ) => {
return res . json ( )
} ) . then ( e => {
let floatArray ;
if ( useKeys ) {
let keys = Object . keys ( e ) ;
floatArray = new Float32Array ( keys . length ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
floatArray [ i ] = e [ keys [ i ] ] ;
}
} else {
floatArray = new Float32Array ( e . length ) ;
for ( let i = 0 ; i < e . length ; i ++ ) {
floatArray [ i ] = e [ i ] ;
}
}
visual . visuals [ visual . c ] . data = floatArray ;
} )
}
// most of the functions are from https://webglfundamentals.org/webgl/resources/m4.js! but i doesnt want to use them all and make some adjustment to them!
2020-04-07 21:44:46 +02:00
class TDUtils {
static multiply ( a , b ) {
2020-08-05 11:24:59 +02:00
let b00 = b [ 0 ] ;
let b01 = b [ 1 ] ;
let b02 = b [ 2 ] ;
let b03 = b [ 3 ] ;
let b10 = b [ 4 ] ;
let b11 = b [ 5 ] ;
let b12 = b [ 6 ] ;
let b13 = b [ 7 ] ;
let b20 = b [ 8 ] ;
let b21 = b [ 9 ] ;
let b22 = b [ 10 ] ;
let b23 = b [ 11 ] ;
let b30 = b [ 12 ] ;
let b31 = b [ 13 ] ;
let b32 = b [ 14 ] ;
let b33 = b [ 15 ] ;
let a00 = a [ 0 ] ;
let a01 = a [ 1 ] ;
let a02 = a [ 2 ] ;
let a03 = a [ 3 ] ;
let a10 = a [ 4 ] ;
let a11 = a [ 5 ] ;
let a12 = a [ 6 ] ;
let a13 = a [ 7 ] ;
let a20 = a [ 8 ] ;
let a21 = a [ 9 ] ;
let a22 = a [ 10 ] ;
let a23 = a [ 11 ] ;
let a30 = a [ 12 ] ;
let a31 = a [ 13 ] ;
let a32 = a [ 14 ] ;
let a33 = a [ 15 ] ;
return [
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30 ,
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31 ,
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32 ,
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33 ,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30 ,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31 ,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32 ,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33 ,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30 ,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31 ,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32 ,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33 ,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30 ,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31 ,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32 ,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
] ;
}
static translate ( m , tx , ty , tz , dst ) {
dst = dst || new Float32Array ( 16 ) ;
let m00 = m [ 0 ] ,
m01 = m [ 1 ] ,
m02 = m [ 2 ] ,
m03 = m [ 3 ] ,
m10 = m [ 4 ] ,
m11 = m [ 5 ] ,
m12 = m [ 6 ] ,
m13 = m [ 7 ] ,
m20 = m [ 8 ] ,
m21 = m [ 9 ] ,
m22 = m [ 10 ] ,
m23 = m [ 11 ] ,
m30 = m [ 12 ] ,
m31 = m [ 13 ] ,
m32 = m [ 14 ] ,
m33 = m [ 15 ] ;
dst [ 0 ] = m00 ;
dst [ 1 ] = m01 ;
dst [ 2 ] = m02 ;
dst [ 3 ] = m03 ;
dst [ 4 ] = m10 ;
dst [ 5 ] = m11 ;
dst [ 6 ] = m12 ;
dst [ 7 ] = m13 ;
dst [ 8 ] = m20 ;
dst [ 9 ] = m21 ;
dst [ 10 ] = m22 ;
dst [ 11 ] = m23 ;
dst [ 12 ] = m00 * tx + m10 * ty + m20 * tz + m30 ;
dst [ 13 ] = m01 * tx + m11 * ty + m21 * tz + m31 ;
dst [ 14 ] = m02 * tx + m12 * ty + m22 * tz + m32 ;
dst [ 15 ] = m03 * tx + m13 * ty + m23 * tz + m33 ;
2020-04-07 21:44:46 +02:00
return dst ;
}
static xRotation ( angleInRadians ) {
let c = Math . cos ( angleInRadians ) ;
let s = Math . sin ( angleInRadians ) ;
return [
1 , 0 , 0 , 0 ,
0 , c , s , 0 ,
0 , - s , c , 0 ,
0 , 0 , 0 , 1 ,
] ;
}
static yRotation ( angleInRadians ) {
let c = Math . cos ( angleInRadians ) ;
let s = Math . sin ( angleInRadians ) ;
return [
c , 0 , - s , 0 ,
0 , 1 , 0 , 0 ,
s , 0 , c , 0 ,
0 , 0 , 0 , 1 ,
] ;
}
static zRotation ( angleInRadians ) {
let c = Math . cos ( angleInRadians ) ;
let s = Math . sin ( angleInRadians ) ;
return [
c , s , 0 , 0 ,
- s , c , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ,
] ;
}
static degToRad ( d ) {
return d * Math . PI / 180 ;
}
2020-08-05 11:24:59 +02:00
static scale ( sx , sy , sz , dst ) {
dst = dst || new Float32Array ( 16 ) ;
dst [ 0 ] = sx ;
dst [ 5 ] = sy ;
dst [ 10 ] = sz ;
return dst ;
}
2020-04-07 21:44:46 +02:00
2020-08-05 11:24:59 +02:00
static lookAt ( cameraPosition , target , up , dst ) {
dst = dst || new Float32Array ( 16 ) ;
let zAxis = TDUtils . normalize (
TDUtils . subtractVectors ( cameraPosition , target ) ) ;
let xAxis = TDUtils . normalize ( TDUtils . cross ( up , zAxis ) ) ;
let yAxis = TDUtils . normalize ( TDUtils . cross ( zAxis , xAxis ) ) ;
dst [ 0 ] = xAxis [ 0 ] ;
dst [ 1 ] = xAxis [ 1 ] ;
dst [ 2 ] = xAxis [ 2 ] ;
dst [ 4 ] = yAxis [ 0 ] ;
dst [ 5 ] = yAxis [ 1 ] ;
dst [ 6 ] = yAxis [ 2 ] ;
dst [ 8 ] = zAxis [ 0 ] ;
dst [ 9 ] = zAxis [ 1 ] ;
dst [ 10 ] = zAxis [ 2 ] ;
dst [ 12 ] = cameraPosition [ 0 ] ;
dst [ 13 ] = cameraPosition [ 1 ] ;
dst [ 14 ] = cameraPosition [ 2 ] ;
dst [ 15 ] = 1 ;
2020-04-07 21:44:46 +02:00
2020-08-05 11:24:59 +02:00
return dst ;
}
static cross ( a , b , dst ) {
dst = dst || new Float32Array ( 3 ) ;
dst [ 0 ] = a [ 1 ] * b [ 2 ] - a [ 2 ] * b [ 1 ] ;
dst [ 1 ] = a [ 2 ] * b [ 0 ] - a [ 0 ] * b [ 2 ] ;
dst [ 2 ] = a [ 0 ] * b [ 1 ] - a [ 1 ] * b [ 0 ] ;
return dst ;
}
static normalize ( v , dst ) {
dst = dst || new Float32Array ( 3 ) ;
let length = Math . sqrt ( v [ 0 ] * v [ 0 ] + v [ 1 ] * v [ 1 ] + v [ 2 ] * v [ 2 ] ) ;
if ( length > 0.00001 ) {
dst [ 0 ] = v [ 0 ] / length ;
dst [ 1 ] = v [ 1 ] / length ;
dst [ 2 ] = v [ 2 ] / length ;
2020-04-07 21:44:46 +02:00
}
2020-08-05 11:24:59 +02:00
return dst ;
}
2020-04-07 21:44:46 +02:00
2020-08-05 11:24:59 +02:00
static subtractVectors ( a , b , dst ) {
dst = dst || new Float32Array ( 3 ) ;
dst [ 0 ] = a [ 0 ] - b [ 0 ] ;
dst [ 1 ] = a [ 1 ] - b [ 1 ] ;
dst [ 2 ] = a [ 2 ] - b [ 2 ] ;
return dst ;
}
2020-08-01 21:51:54 +02:00
2020-08-05 11:24:59 +02:00
static perspective ( fieldOfViewInRadians , aspect , near , far , dst ) {
dst = dst || new Float32Array ( 16 ) ;
let f = Math . tan ( Math . PI * 0.5 - 0.5 * fieldOfViewInRadians ) ,
rangeInv = 1.0 / ( near - far ) ;
dst [ 0 ] = f / aspect ;
dst [ 5 ] = f ;
dst [ 10 ] = ( near + far ) * rangeInv ;
dst [ 11 ] = - 1 ;
dst [ 14 ] = near * far * rangeInv * 2 ;
return dst ;
2020-04-07 21:44:46 +02:00
}
2020-08-05 11:24:59 +02:00
static inverse ( m , dst ) {
dst = dst || new Float32Array ( 16 ) ;
let m00 = m [ 0 ] ,
m01 = m [ 1 ] ,
m02 = m [ 2 ] ,
m03 = m [ 3 ] ,
m10 = m [ 4 ] ,
m11 = m [ 5 ] ,
m12 = m [ 6 ] ,
m13 = m [ 7 ] ,
m20 = m [ 8 ] ,
m21 = m [ 9 ] ,
m22 = m [ 10 ] ,
m23 = m [ 11 ] ,
m30 = m [ 12 ] ,
m31 = m [ 13 ] ,
m32 = m [ 14 ] ,
m33 = m [ 15 ] ,
tmp _0 = m22 * m33 ,
tmp _1 = m32 * m23 ,
tmp _2 = m12 * m33 ,
tmp _3 = m32 * m13 ,
tmp _4 = m12 * m23 ,
tmp _5 = m22 * m13 ,
tmp _6 = m02 * m33 ,
tmp _7 = m32 * m03 ,
tmp _8 = m02 * m23 ,
tmp _9 = m22 * m03 ,
tmp _10 = m02 * m13 ,
tmp _11 = m12 * m03 ,
tmp _12 = m20 * m31 ,
tmp _13 = m30 * m21 ,
tmp _14 = m10 * m31 ,
tmp _15 = m30 * m11 ,
tmp _16 = m10 * m21 ,
tmp _17 = m20 * m11 ,
tmp _18 = m00 * m31 ,
tmp _19 = m30 * m01 ,
tmp _20 = m00 * m21 ,
tmp _21 = m20 * m01 ,
tmp _22 = m00 * m11 ,
tmp _23 = m10 * m01 ,
t0 = ( tmp _0 * m11 + tmp _3 * m21 + tmp _4 * m31 ) -
( tmp _1 * m11 + tmp _2 * m21 + tmp _5 * m31 ) ,
t1 = ( tmp _1 * m01 + tmp _6 * m21 + tmp _9 * m31 ) -
( tmp _0 * m01 + tmp _7 * m21 + tmp _8 * m31 ) ,
t2 = ( tmp _2 * m01 + tmp _7 * m11 + tmp _10 * m31 ) -
( tmp _3 * m01 + tmp _6 * m11 + tmp _11 * m31 ) ,
t3 = ( tmp _5 * m01 + tmp _8 * m11 + tmp _11 * m21 ) -
( tmp _4 * m01 + tmp _9 * m11 + tmp _10 * m21 ) ,
d = 1.0 / ( m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3 ) ;
dst [ 0 ] = d * t0 ;
dst [ 1 ] = d * t1 ;
dst [ 2 ] = d * t2 ;
dst [ 3 ] = d * t3 ;
dst [ 4 ] = d * ( ( tmp _1 * m10 + tmp _2 * m20 + tmp _5 * m30 ) -
( tmp _0 * m10 + tmp _3 * m20 + tmp _4 * m30 ) ) ;
dst [ 5 ] = d * ( ( tmp _0 * m00 + tmp _7 * m20 + tmp _8 * m30 ) -
( tmp _1 * m00 + tmp _6 * m20 + tmp _9 * m30 ) ) ;
dst [ 6 ] = d * ( ( tmp _3 * m00 + tmp _6 * m10 + tmp _11 * m30 ) -
( tmp _2 * m00 + tmp _7 * m10 + tmp _10 * m30 ) ) ;
dst [ 7 ] = d * ( ( tmp _4 * m00 + tmp _9 * m10 + tmp _10 * m20 ) -
( tmp _5 * m00 + tmp _8 * m10 + tmp _11 * m20 ) ) ;
dst [ 8 ] = d * ( ( tmp _12 * m13 + tmp _15 * m23 + tmp _16 * m33 ) -
( tmp _13 * m13 + tmp _14 * m23 + tmp _17 * m33 ) ) ;
dst [ 9 ] = d * ( ( tmp _13 * m03 + tmp _18 * m23 + tmp _21 * m33 ) -
( tmp _12 * m03 + tmp _19 * m23 + tmp _20 * m33 ) ) ;
dst [ 10 ] = d * ( ( tmp _14 * m03 + tmp _19 * m13 + tmp _22 * m33 ) -
( tmp _15 * m03 + tmp _18 * m13 + tmp _23 * m33 ) ) ;
dst [ 11 ] = d * ( ( tmp _17 * m03 + tmp _20 * m13 + tmp _23 * m23 ) -
( tmp _16 * m03 + tmp _21 * m13 + tmp _22 * m23 ) ) ;
dst [ 12 ] = d * ( ( tmp _14 * m22 + tmp _17 * m32 + tmp _13 * m12 ) -
( tmp _16 * m32 + tmp _12 * m12 + tmp _15 * m22 ) ) ;
dst [ 13 ] = d * ( ( tmp _20 * m32 + tmp _12 * m02 + tmp _19 * m22 ) -
( tmp _18 * m22 + tmp _21 * m32 + tmp _13 * m02 ) ) ;
dst [ 14 ] = d * ( ( tmp _18 * m12 + tmp _23 * m32 + tmp _15 * m02 ) -
( tmp _22 * m32 + tmp _14 * m02 + tmp _19 * m12 ) ) ;
dst [ 15 ] = d * ( ( tmp _22 * m22 + tmp _16 * m02 + tmp _21 * m12 ) -
( tmp _20 * m12 + tmp _23 * m22 + tmp _17 * m02 ) ) ;
return dst ;
}
static aspectView ( aspect ) {
return [
1 * aspect , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1
]
}
static lastMatrix = { m : null } ;
static getMatrix ( fov , aspect , near , far , camAngle , radius ) {
let lMat = this . lastMatrix ,
u = TDUtils ;
if ( ! u . isSame ( 'fov' , fov )
|| ! u . isSame ( 'aspect' , aspect )
|| ! u . isSame ( 'near' , near )
|| ! u . isSame ( 'far' , far )
|| ! u . isSame ( 'cam' , camAngle )
|| ! u . isSame ( 'radius' , radius )
) {
let matrix = TDUtils . perspective ( TDUtils . degToRad ( fov ) , aspect , near , far ) ,
cameraMatrix = TDUtils . yRotation ( TDUtils . degToRad ( camAngle ) ) ;
cameraMatrix = TDUtils . translate ( cameraMatrix , 0 , 0 , radius * 1.5 ) ;
let viewMatrix = TDUtils . inverse ( cameraMatrix ) ;
matrix = TDUtils . multiply ( matrix , viewMatrix )
lMat . m = matrix ;
}
return lMat . m ;
}
static isSame ( key , value ) {
let lMat = this . lastMatrix ;
if ( lMat [ key ] !== value ) {
lMat [ key ] = value ;
return false ;
}
return true ;
2020-04-07 21:44:46 +02:00
}
}
2020-08-01 21:51:54 +02:00
class Template {
constructor ( ) {
this . tpl = { } ;
}
async loadTemplate ( name ) {
let self = this ;
if ( ! this . tpl [ name ] ) {
await fetch ( templateDir + name + ".tpl" ) . then ( ( r ) => r . text ( ) ) . then ( c => {
self . tpl [ name ] = c ;
} )
}
}
async loadArray ( names ) {
for ( let name of names ) {
await this . loadTemplate ( name ) ;
}
}
parseTemplate ( name , data ) {
if ( ! this . tpl [ name ] ) {
return ""
}
let m , d = this . tpl [ name ] ;
while ( ( m = templateEx . exec ( d ) ) !== null ) {
if ( m . index === templateEx . lastIndex ) {
templateEx . lastIndex ++ ;
}
let key = m [ 0 ] ;
d = d . replace ( key , data [ m [ 1 ] ] || "" )
}
return d ;
}
parseFromAPI ( url , name , cb ) {
fetch ( url ) . then ( ( r ) => r . json ( ) ) . then ( d => {
cb ( this . parseTemplate ( name , d ) )
} ) . catch ( console . error )
}
}
const templateEx = /\$(.*?)\$/gm ;
const templateDir = "out/tpl/"
2020-04-07 21:44:46 +02:00
class ShaderHandler {
constructor ( gl ) {
this . gl = gl ;
this . shaderNames = [ ] ;
this . shaders = { } ;
this . programs = { } ;
}
setGL ( gl ) {
this . gl = gl ;
}
async loadShader ( name , path ) {
this . shaderNames . push ( name ) ;
await this . load ( name , path + name + ".vert" , this . gl . VERTEX _SHADER ) ;
await this . load ( name , path + name + ".frag" , this . gl . FRAGMENT _SHADER ) ;
}
async load ( name , url , type ) {
let realName = name + "_" + type ;
if ( ! this . shaders [ realName ] ) {
let data = await fetch ( url ) ;
let shader = this . createShader ( await data . text ( ) , type ) ;
if ( shader ) {
this . shaders [ realName ] = shader ;
}
}
return ! ! this . shaders [ realName ] ;
}
getShader ( name , type ) {
let realName = name + "_" + type ;
return this . shaders [ realName ] ;
}
getAllShaders ( ) {
return this . shaderNames ;
}
async createProgramForEach ( arr ) {
arr = arr || this . shaderNames ;
for ( let i = 0 ; i < arr . length ; i ++ ) {
let shader = arr [ i ] ;
let v = await shaderHandler . createProgram ( shader , [ shader ] )
if ( ! v ) {
return false ;
}
}
return true ;
}
createShader ( source , type ) {
let gl = this . gl ;
let shader = gl . createShader ( type ) ;
gl . shaderSource ( shader , source ) ;
gl . compileShader ( shader ) ;
if ( gl . getShaderParameter ( shader , gl . COMPILE _STATUS ) ) {
return shader ;
}
console . error ( gl . getShaderInfoLog ( shader ) ) ;
gl . deleteShader ( shader ) ;
return null ;
}
createProgram ( name , shaders ) {
let gl = this . gl ;
let pro = gl . createProgram ( ) ;
for ( let i = 0 ; i < shaders . length ; i ++ ) {
gl . attachShader ( pro , this . getShader ( shaders [ i ] , gl . VERTEX _SHADER ) ) ;
gl . attachShader ( pro , this . getShader ( shaders [ i ] , gl . FRAGMENT _SHADER ) ) ;
}
gl . linkProgram ( pro ) ;
var success = gl . getProgramParameter ( pro , gl . LINK _STATUS ) ;
if ( success ) {
this . programs [ name ] = pro ;
return pro ;
}
console . log ( gl . getProgramInfoLog ( pro ) ) ;
gl . deleteProgram ( pro ) ;
return null ;
}
getProgram ( name ) {
return this . programs [ name ] ;
}
2020-08-01 21:51:54 +02:00
use ( name ) {
let pro = this . programs [ name ] ;
this . gl . useProgram ( pro ) ;
return pro ;
}
2020-04-07 21:44:46 +02:00
async loadArray ( list , path ) {
let self = this ;
for ( const e of list ) {
await self . loadShader ( e , path )
}
await self . createProgramForEach ( list )
}
}
2020-08-01 21:51:54 +02:00
const AudioContext = window . AudioContext || window . webkitAudioContext ;
2020-04-07 21:44:46 +02:00
class AudioHandler {
async init ( ) {
2020-08-01 21:51:54 +02:00
let self = this ;
self . isStarted = false ;
self . audioFile = new Audio ( ) ;
2020-08-05 11:24:59 +02:00
self . actx = new AudioContext ( ) ;
self . analyser = self . actx . createAnalyser ( ) ;
2020-08-01 21:51:54 +02:00
self . analyser . fftSize = 4096 ;
self . lastSong = null ;
await self . connectAll ( ) ;
}
async connectAll ( ) {
let self = this ;
self . source = self . actx . createMediaElementSource ( self . audioFile ) ;
self . source . connect ( self . analyser ) ;
self . analyser . connect ( self . actx . destination ) ;
self . audioFile . addEventListener ( 'ended' , player . nextSong . bind ( player ) ) ;
}
async start ( ) {
if ( this . audioFile . src === '' ) {
return ;
}
if ( ! this . isStarted ) {
this . isStarted = true ;
await this . actx . resume ( ) ;
}
}
async stop ( ) {
if ( this . isStarted ) {
this . isStarted = false ;
await this . actx . suspend ( ) ;
}
}
fftSize ( size ) {
this . analyser . fftSize = size ;
}
smoothing ( float ) {
this . analyser . smoothingTimeConstant = float ;
}
loadSong ( src ) {
let self = this ;
if ( self . lastSong ) {
URL . revokeObjectURL ( self . lastSong ) ;
}
self . lastSong = this . audioFile . src = URL . createObjectURL ( src ) ;
if ( ! this . isStarted ) {
2020-08-05 11:24:59 +02:00
this . start ( ) . catch ( alert ) ;
2020-08-01 21:51:54 +02:00
}
2020-08-05 11:24:59 +02:00
this . audioFile . play ( ) . then ( e => {
window . dispatchEvent ( new CustomEvent ( 'playSong' ) ) ;
} ) . catch ( e => {
player . nextSong ( ) ;
} ) ;
2020-08-01 21:51:54 +02:00
}
getIntArray ( steps ) {
let dataArray = new Uint8Array ( steps ) ;
this . analyser . getByteFrequencyData ( dataArray ) ;
return dataArray ;
}
getFloatArray ( ) {
2020-08-05 11:24:59 +02:00
let dataArray = new Float32Array ( this . analyser . fftSize ) ;
2020-08-01 21:51:54 +02:00
this . analyser . getFloatTimeDomainData ( dataArray ) ;
return dataArray ;
2020-04-07 21:44:46 +02:00
}
}
class Player {
async init ( ) {
2020-08-01 21:51:54 +02:00
this . playlist = new Playlist ( ) ;
}
nextSong ( ) {
let next = this . playlist . getNext ( ) ;
audioHandler . loadSong ( next . file ) ;
}
2020-04-07 21:44:46 +02:00
2020-08-01 21:51:54 +02:00
prevSong ( ) {
let next = this . playlist . getPrevious ( ) ;
audioHandler . loadSong ( next . file ) ;
}
playStop ( ) {
if ( ! audioHandler . lastSong ) {
let next = this . playlist . getCurrent ( ) ;
audioHandler . loadSong ( next . file ) ;
2020-08-05 11:24:59 +02:00
return ;
2020-08-01 21:51:54 +02:00
}
let audioFile = audioHandler . audioFile ;
if ( audioFile . paused ) {
audioFile . play ( ) ;
} else {
audioFile . pause ( ) ;
}
2020-08-05 11:24:59 +02:00
window . dispatchEvent ( new CustomEvent ( 'playSong' ) ) ;
2020-08-01 21:51:54 +02:00
}
playByID ( number ) {
2020-08-05 11:24:59 +02:00
this . playlist . index = number ;
let next = this . playlist . getCurrent ( ) ;
2020-08-01 21:51:54 +02:00
audioHandler . loadSong ( next . file ) ;
}
}
const PAGINATIONLIMIT = 50 ;
class Playlist {
constructor ( ) {
this . list = [ ] ;
this . shuffled = [ ] ;
this . index = 0 ;
this . page = 0 ;
this . isShuffle = false ;
$ ( 'body' ) . addDelegatedEventListener ( 'change' , 'input[type="file"]' , this . changeFiles . bind ( this ) ) ;
$ ( 'body' ) . addDelegatedEventListener ( 'click' , '.pagination .item' , this . handlePagination . bind ( this ) ) ;
}
shuffle ( ) {
// only shuffle if more then 2 elements are in
let len = this . list . length ;
if ( len < 3 ) {
this . shuffled = this . list ;
}
// the current-list need to be shuffled...
for ( let i = 0 ; i < len ; i ++ ) {
let random = VTUtils . randomInt ( 0 , len - 1 ) ;
this . swap ( i , random ) ;
}
}
swap ( a , b ) {
this . shuffled [ a ] = this . list [ b ] ;
this . shuffled [ b ] = this . list [ a ] ;
}
getNext ( ) {
let items = this . isShuffle ? this . shuffled : this . list ,
len = items . length - 1 ,
next = this . index + 1 ;
if ( next > len ) {
next = 0 ;
}
this . index = next ;
return items [ next ] ;
}
getPrevious ( ) {
let items = this . isShuffle ? this . shuffled : this . list ,
len = items . length - 1 ,
next = this . index - 1 ;
if ( next < 0 ) {
next = len ;
}
this . index = next ;
return items [ next ] ;
}
getCurrent ( ) {
let items = this . isShuffle ? this . shuffled : this . list ;
return items [ this . index ] ;
}
// on new upload... this has to be an array!
setPlaylist ( files ) {
this . index = 0 ;
this . list = files ;
this . shuffle ( ) ;
}
handlePagination ( event , el ) {
if ( el . hasClass ( 'inactive' ) ) {
return ;
}
if ( el . hasClass ( 'next-site' ) ) {
this . renderPagination ( this . page + 1 ) ;
} else {
this . renderPagination ( this . page - 1 ) ;
}
}
renderPagination ( page ) {
let length = this . list . length ,
maxSite = Math . ceil ( length / PAGINATIONLIMIT ) - 1 ;
if ( page < 0 ) {
page = 0 ;
}
if ( page > maxSite ) {
page = maxSite ;
}
let s = page * PAGINATIONLIMIT ,
e = s + PAGINATIONLIMIT ,
data = "" ;
this . page = page ;
if ( e >= length ) {
e = length ;
}
if ( length > 0 ) {
let items = this . isShuffle ? this . shuffled : this . list ;
for ( let i = s ; i < e ; i ++ ) {
let obj = {
2020-08-05 11:24:59 +02:00
index : i . toString ( ) ,
2020-08-01 21:51:54 +02:00
nr : i + 1 ,
2020-08-05 11:24:59 +02:00
title : items [ i ] . name ,
active : ! audioHandler . audioFile . paused && i === this . index ? 'active' : ''
2020-08-01 21:51:54 +02:00
}
data += template . parseTemplate ( "playlist-item" , obj ) ;
}
} else {
data = "<h1>No Songs uploaded!</h1>" ;
}
let hasNext = maxSite > 1 && page < maxSite ;
gui . modal . renderModal (
"Playlist" ,
template . parseTemplate ( "playlist" , {
content : data ,
} ) ,
template . parseTemplate ( 'playlist-footer' , {
prevActive : page > 0 ? 'active' : 'inactive' ,
nextActive : hasNext ? 'active' : 'inactive' ,
page : ( page + 1 ) + ' / ' + parseInt ( maxSite + 1 ) ,
} )
) ;
}
//playlist handler for file input!
changeFiles ( e , el ) {
2020-08-05 11:24:59 +02:00
if ( el . id !== 'upload-dir' ) {
return ;
}
2020-08-01 21:51:54 +02:00
let files = [ ] ;
let i = 0 ;
for ( let file of el . files ) {
if ( file && file . type . indexOf ( 'audio' ) !== - 1 && file . name . match ( ".m3u" ) === null ) {
let name = file . name . split ( "." ) ;
name . pop ( ) ;
name = name . join ( "." ) ;
files . push ( {
file : file ,
name : name ,
index : i ++
} ) ;
}
}
this . setPlaylist ( files ) ;
if ( files . length > 0 ) {
this . renderPagination ( 0 ) ;
} else {
alert ( "No Valid AudioFiles found!" ) ;
}
2020-04-07 21:44:46 +02:00
}
}
class GUI {
2020-08-01 21:51:54 +02:00
async init ( ) {
this . data = { } ;
this . modal = new Modal ( ) ;
// load first vis window!
await this . loadForVis ( ) ;
await template . loadArray ( [
'playlist-item' ,
'playlist' ,
'playlist-footer'
] ) ;
this . initDropZone ( ) ;
}
async loadForVis ( ) {
let c = visual . c ,
d = this . data [ c ] ;
if ( d == null ) {
this . data [ c ] = await fetch ( "out/gui/" + c + ".json" ) . then ( ( r ) => r . json ( ) ) ;
}
}
initDropZone ( ) {
let items = 'drag dragstart dragend dragover dragenter dragleave drop' . split ( ' ' ) ;
items . forEach ( el => {
window . addEventListener ( el , async e => {
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
if ( e . type === 'drop' ) {
if ( e . dataTransfer . files . length > 0 ) {
2020-08-05 11:24:59 +02:00
e . dataTransfer . id = 'upload-dir' ;
2020-08-01 21:51:54 +02:00
player . playlist . changeFiles ( e , e . dataTransfer ) ;
} else {
alert ( "Sorry you need to upload files!" ) ;
}
}
} ) ;
} ) ;
} ;
}
class Modal {
constructor ( ) {
let self = this ;
self . currentModal = '' ;
self . modal = $ ( '#modal' ) ;
self . parent = self . modal . parentNode ;
self . modal . addDelegatedEventListener ( 'click' , 'header .close' , this . closeModal . bind ( this ) ) ;
}
resetModal ( ) {
this . renderModal ( '' , '' , '' ) ;
}
renderModal ( title , content , footer ) {
this . currentModal = title ;
this . renderHeader ( title ) ;
this . renderContent ( content ) ;
this . renderFooter ( footer ) ;
}
renderHeader ( header ) {
let h = $ ( 'header .headline' , this . modal ) ;
h . innerHTML = header ;
}
renderContent ( content ) {
let con = $ ( 'modal-content' , this . modal ) ;
con . innerHTML = content ;
}
renderFooter ( footer ) {
let con = $ ( 'modal-footer' , this . modal ) ;
con . innerHTML = footer ;
}
closeModal ( ) {
this . parent . addClass ( "hide" )
}
isCurrent ( title ) {
return title === this . currentModal ;
}
2020-04-07 21:44:46 +02:00
2020-08-01 21:51:54 +02:00
showModal ( ) {
this . parent . removeClass ( "hide" )
2020-04-07 21:44:46 +02:00
}
}
class Visual {
constructor ( ) {
this . data = [ ] ; //for drawing
this . dataArray = [ ] ;
}
2020-08-01 21:51:54 +02:00
updateData ( ) {
}
2020-04-07 21:44:46 +02:00
draw ( ) {
}
setup ( ) {
}
}
class VisualDrawer {
2020-08-01 21:51:54 +02:00
constructor ( ) {
this . visuals = {
"sphere" : new Sphere ( ) ,
"wave" : new Wave ( ) ,
"water" : new Water ( )
}
}
init ( ) {
2020-08-05 11:24:59 +02:00
this . switch ( 'wave' ) ;
2020-08-01 21:51:54 +02:00
this . updateLoop ( ) ;
}
2020-04-07 21:44:46 +02:00
2020-08-01 21:51:54 +02:00
switch ( visual ) {
if ( this . visuals [ visual ] != null ) {
this . c = visual ;
2020-08-05 11:24:59 +02:00
vConf . loadConfigByName ( this . c ) ;
2020-08-01 21:51:54 +02:00
this . visuals [ this . c ] . setup ( ) ;
}
}
updateLoop ( ) {
let self = this ;
let pro = shaderHandler . use ( self . c ) ;
let vis = self . visuals [ self . c ] ;
vis . updateData ( ) ;
2020-08-05 11:24:59 +02:00
this . prepare ( ) ;
2020-08-01 21:51:54 +02:00
vis . draw ( pro ) ;
requestAnimationFrame ( self . updateLoop . bind ( self ) )
}
2020-08-05 11:24:59 +02:00
prepare ( ) {
c . width = window . innerWidth ;
c . height = window . innerHeight ;
gl . viewport ( 0 , 0 , gl . canvas . width , gl . canvas . height ) ;
gl . clearColor ( 0 , 0 , 0 , parseFloat ( pConf . get ( "alphaValue" , 0 ) ) ) ;
gl . clear ( gl . COLOR _BUFFER _BIT | gl . DEPTH _BUFFER _BIT ) ;
gl . enable ( gl . DEPTH _TEST ) ;
gl . depthFunc ( gl . LEQUAL ) ;
gl . enable ( gl . CULL _FACE ) ;
}
}
class ImageUploader {
async init ( ) {
this . image = pConf . get ( "bgURL" , "" ) ;
this . color = pConf . get ( "bgColour" , "#000000" ) ;
this . alpha = pConf . get ( "alphaValue" , 0.5 ) ;
this . getRealImage ( ) ;
this . applyValues ( ) ;
$ ( '#modal' ) . addDelegatedEventListener ( 'change' , '#image-upload input:not([type="color"])' , this . changeHandler . bind ( this ) ) ;
$ ( '#modal' ) . addDelegatedEventListener ( 'input' , '#image-upload input#color' , this . changeHandler . bind ( this ) ) ;
}
async renderModal ( ) {
await template . loadTemplate ( "image" ) ;
gui . modal . resetModal ( ) ;
gui . modal . renderModal ( "Background-Image" ,
template . parseTemplate ( "image" , {
value : this . image ,
bgValue : this . color ,
alphaValue : this . alpha
} ) , "" ) ;
gui . modal . showModal ( ) ;
}
changeHandler ( e , el ) {
if ( el . id === 'color' ) {
this . color = el . value ;
} else if ( el . id === "alphaValue" ) {
this . alpha = el . value ;
} else {
pConf . set ( 'bgMode' , el . id ) ;
if ( el . id === 'image' ) {
el . files [ 0 ] . toBase64 ( ( e , b ) => {
if ( b ) {
alert ( "Error converting image!" ) ;
return ;
}
pConf . set ( 'bgURL' , e . currentTarget . result ) ;
pConf . save ( ) ;
} )
this . image = URL . createObjectURL ( el . files [ 0 ] ) ;
} else {
this . image = el . value ;
pConf . set ( 'bgURL' , this . image ) ;
}
}
pConf . set ( 'bgColour' , this . color ) ;
pConf . set ( 'alphaValue' , this . alpha ) ;
this . applyValues ( ) ;
pConf . save ( ) ;
}
applyValues ( ) {
let body = $ ( 'body' ) ;
body . style . backgroundImage = 'url(' + this . image + ')' ;
body . style . backgroundColor = this . color ;
let blob = $ ( '#colorBlob' ) ;
if ( blob ) {
blob . style . backgroundColor = this . color ;
}
}
getRealImage ( ) {
let mode = pConf . get ( 'bgMode' ) ,
value = pConf . get ( "bgURL" , "" ) ;
if ( mode === 'image' ) {
if ( value !== '' && value . startsWith ( 'data:image' ) ) {
let split = value . split ( ";" ) ,
type = split . shift ( ) ,
message = split . join ( ";" ) . replace ( "base64," , "" ) ;
this . image = URL . createObjectURL ( b64toBlob ( message , type ) ) ;
}
} else {
this . image = value ;
}
}
}
const imageUploader = new ImageUploader ( ) ;
class Notification {
constructor ( ) {
}
2020-08-01 21:51:54 +02:00
}
class Config {
constructor ( ) {
this . config = { } ;
this . name = ''
}
loadConfigByName ( name ) {
2020-08-05 11:24:59 +02:00
this . save ( ) ;
2020-08-01 21:51:54 +02:00
this . name = 'config-' + name ;
2020-08-05 11:24:59 +02:00
let item = localStorage . getItem ( this . name ) ;
if ( item ) {
this . config = JSON . parse ( item ) ;
}
2020-08-01 21:51:54 +02:00
}
2020-08-05 11:24:59 +02:00
save ( ) {
2020-08-01 21:51:54 +02:00
if ( this . name !== '' ) {
localStorage . setItem ( this . name , JSON . stringify ( this . config ) ) ;
}
}
2020-08-05 11:24:59 +02:00
set ( name , value ) {
2020-08-01 21:51:54 +02:00
this . config [ name ] = value ;
}
2020-08-05 11:24:59 +02:00
remove ( name ) {
2020-08-01 21:51:54 +02:00
delete this . config [ name ] ;
}
2020-08-05 11:24:59 +02:00
get ( name , def ) {
2020-08-01 21:51:54 +02:00
let value = this . config [ name ] ;
if ( value === undefined || value === null ) {
this . config [ name ] = def ;
value = def ;
}
return value ;
}
2020-04-07 21:44:46 +02:00
}
class Sphere extends Visual {
draw ( ) {
}
setup ( ) {
}
}
2020-08-01 21:51:54 +02:00
// 3D Audio-Waves -> maybe also 2D?
class Wave extends Visual {
updateData ( ) {
2020-08-05 11:24:59 +02:00
//only for debug! remove pls
if ( window . stopUpdate ) {
return ;
}
2020-08-01 21:51:54 +02:00
let data = audioHandler . getFloatArray ( ) ;
let add = 2 / data . length ,
x = - 1 ;
2020-08-05 11:24:59 +02:00
let outerLoop = 0 ;
2020-08-01 21:51:54 +02:00
for ( let i = 0 ; i < data . length ; i ++ ) {
2020-08-05 11:24:59 +02:00
//first
this . data [ outerLoop ] = x ;
this . data [ outerLoop + 1 ] = data [ i ] ;
this . data [ outerLoop + 2 ] = 0 ;
//second
this . data [ outerLoop + 3 ] = x ;
//third
this . data [ outerLoop + 6 ] = x ;
this . data [ outerLoop + 8 ] = data [ i + 1 ] || 0 ;
outerLoop += 9 ;
2020-08-01 21:51:54 +02:00
x += add ;
}
}
draw ( program ) {
this . prepare ( program ) ;
let position = this . position ,
positionBuffer = gl . createBuffer ( ) ;
this . rotate ( program ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , positionBuffer ) ;
gl . bufferData ( gl . ARRAY _BUFFER , new Float32Array ( this . data ) , gl . DYNAMIC _DRAW ) ;
let vao = gl . createVertexArray ( ) ;
gl . bindVertexArray ( vao ) ;
gl . enableVertexAttribArray ( position ) ;
gl . vertexAttribPointer ( position , 3 , gl . FLOAT , true , 0 , 0 ) ;
2020-08-05 11:24:59 +02:00
gl . drawArrays ( vConf . get ( "waveForm" , gl . TRIANGLES ) , 0 , this . data . length / 3 ) ;
2020-08-01 21:51:54 +02:00
}
rotate ( program ) {
2020-08-05 11:24:59 +02:00
let aspect = c . width / c . height ,
2020-08-01 21:51:54 +02:00
matrix = [
2020-08-05 11:24:59 +02:00
1 / aspect , 0 , 0 , 0 ,
0 , 0.6 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1
]
matrix = TDUtils . multiply ( matrix , TDUtils . xRotation ( vConf . get ( "xRotate" , 0 ) ) ) ;
matrix = TDUtils . multiply ( matrix , TDUtils . yRotation ( vConf . get ( "yRotate" , 0 ) ) ) ;
matrix = TDUtils . multiply ( matrix , TDUtils . zRotation ( vConf . get ( "zRotate" , 0 ) ) ) ;
2020-08-01 21:51:54 +02:00
let rotate = gl . getUniformLocation ( program , "u_matrix" ) ;
gl . uniformMatrix4fv ( rotate , false , matrix ) ;
}
setup ( ) {
audioHandler . fftSize ( 16384 )
2020-08-05 11:24:59 +02:00
this . data = new Float32Array ( 16384 * 9 ) ;
vConf . get ( "zRotate" , TDUtils . degToRad ( - 30 ) ) ;
vConf . get ( "yRotate" , TDUtils . degToRad ( 50 ) ) ;
vConf . get ( "xRotate" , TDUtils . degToRad ( 10 ) ) ;
2020-08-01 21:51:54 +02:00
}
prepare ( program ) {
this . position = gl . getAttribLocation ( program , "a_position" ) ;
this . color = gl . getUniformLocation ( program , "u_color" ) ;
2020-08-05 11:24:59 +02:00
let lightPos = gl . getUniformLocation ( program , "u_lightPos" ) ,
matrix = gl . getUniformLocation ( program , "u_matrix" ) ;
gl . uniform3fv ( lightPos , vConf . get ( "light" , [ 0 , 5 , - 56 ] ) ) ;
//gl.uniformMatrix4fv(matrix, false, TDUtils.getMatrix(90, c.width / c.height, 1, 2000, 200, 200));
2020-08-01 21:51:54 +02:00
}
}
//animate Water the way like the Audio is Coming... 256FFT-Size max!
class Water extends Visual {
draw ( ) {
}
setup ( ) {
audioHandler . fftSize ( 256 )
}
}
async function initHandler ( ) {
let body = $ ( 'body' ) ;
$ ( '.playlist.menu-icon' ) . addEventListener ( 'click' , e => {
player . playlist . renderPagination ( player . playlist . page ) ;
2020-08-05 11:24:59 +02:00
gui . modal . showModal ( ) ;
2020-08-01 21:51:54 +02:00
} ) ;
body . addDelegatedEventListener ( 'click' , '.playlist-item' , ( e , el ) => {
let number = el . dataset . index ;
player . playByID ( parseInt ( number ) ) ;
togglePlayButton ( 'pause' ) ;
} ) ;
body . addDelegatedEventListener ( 'click' , '.controls button' , ( e , el ) => {
switch ( el . id ) {
case 'previous' :
player . prevSong ( ) ;
break ;
case 'next' :
player . nextSong ( )
break ;
case 'play' :
player . playStop ( ) ;
break ;
2020-08-05 11:24:59 +02:00
case 'shuffle' :
player . playlist . isShuffle = ! player . playlist . isShuffle ;
toggleShuffle ( ) ;
break ;
2020-08-01 21:51:54 +02:00
}
togglePlayButton ( audioHandler . audioFile . paused ? 'play' : 'pause' ) ;
} ) ;
2020-08-05 11:24:59 +02:00
window . addEventListener ( 'playSong' , setActiveOnPlaylist ) ;
$ ( '.upload-image' ) . addEventListener ( 'click' , imageUploader . renderModal . bind ( imageUploader ) ) ;
2020-08-01 21:51:54 +02:00
}
2020-08-05 11:24:59 +02:00
function setActiveOnPlaylist ( e ) {
let item = $ ( '.playlist-item[data-index="' + player . playlist . index + '"]' ) ,
active = $ ( '.playlist-item.active' ) ;
if ( active ) {
active . removeClass ( 'active' ) ;
}
if ( item ) {
item . addClass ( 'active' ) ;
}
}
function toggleShuffle ( ) {
let active = player . playlist . isShuffle ;
$ ( '#shuffle' ) . toggleCheck ( 'active' , active ) ;
}
2020-08-01 21:51:54 +02:00
function togglePlayButton ( status ) {
let icons = $$ ( '#play .icon' ) ;
icons . forEach ( el => {
2020-08-05 11:24:59 +02:00
if ( el . dataset . name === status ) {
2020-08-01 21:51:54 +02:00
el . removeClass ( 'hide' ) ;
} else {
el . addClass ( 'hide' ) ;
}
} )
}
2020-04-07 21:44:46 +02:00
const shaderHandler = new ShaderHandler ( null ) ,
audioHandler = new AudioHandler ( ) ,
gui = new GUI ( ) ,
2020-08-01 21:51:54 +02:00
visual = new VisualDrawer ( ) ,
template = new Template ( ) ,
player = new Player ( ) ,
2020-08-05 11:24:59 +02:00
vConf = new Config ( ) ,
pConf = new Config ( ) ;
2020-08-01 21:51:54 +02:00
let c = null ,
gl = null ;
2020-04-07 21:44:46 +02:00
async function startUP ( ) {
2020-08-05 11:24:59 +02:00
pConf . loadConfigByName ( 'default' ) ;
2020-08-01 21:51:54 +02:00
c = document . body . querySelector ( '#c' ) ,
2020-04-07 21:44:46 +02:00
gl = c . getContext ( "webgl2" ) ;
if ( ! gl ) {
alert ( "SORRY THE BROWSER DOESN'T SUPPORT WEBGL2" ) ;
return false ;
}
shaderHandler . setGL ( gl )
2020-08-01 21:51:54 +02:00
await shaderHandler . loadArray ( [ "wave" , "sphere" , "water" ] , 'shaders/' ) ;
2020-04-07 21:44:46 +02:00
await audioHandler . init ( ) ;
await player . init ( ) ;
2020-08-01 21:51:54 +02:00
await visual . init ( ) ;
await gui . init ( ) ;
2020-08-05 11:24:59 +02:00
await imageUploader . init ( ) ;
2020-08-01 21:51:54 +02:00
await initHandler ( ) ;
2020-04-07 21:44:46 +02:00
}
startUP ( ) . then ( r => {
setTimeout ( e => {
$ ( '.loading-screen' ) . remove ( ) ;
} , 100 )
} ) ;