- added imageUploader
- fixed loading songs - cleanup utils - added some helper class - cleanup preparing of WEBGL2 - added 3D wave - added light-support - added configs - added gui-events for playing, shuffling and playlist
This commit is contained in:
parent
300b6c4106
commit
9d5259767c
34 changed files with 1631 additions and 418 deletions
|
@ -14,12 +14,15 @@ const visuals = [
|
||||||
const config = {
|
const config = {
|
||||||
src: [
|
src: [
|
||||||
basePath + 'utils.js',
|
basePath + 'utils.js',
|
||||||
|
basePath + 'gl/glUtils.js',
|
||||||
basePath + 'template.js',
|
basePath + 'template.js',
|
||||||
basePath + 'handler.js',
|
basePath + 'gl/handler.js',
|
||||||
basePath + 'audio.js',
|
basePath + 'audio.js',
|
||||||
basePath + 'player.js',
|
basePath + 'player.js',
|
||||||
basePath + 'gui.js',
|
basePath + 'gui.js',
|
||||||
basePath + 'visual.js',
|
basePath + 'visual.js',
|
||||||
|
basePath + 'imageUploader.js',
|
||||||
|
basePath + 'notification.js',
|
||||||
basePath + 'config.js',
|
basePath + 'config.js',
|
||||||
...visuals,
|
...visuals,
|
||||||
basePath + 'eventHandler.js',
|
basePath + 'eventHandler.js',
|
||||||
|
|
|
@ -42,7 +42,7 @@ function buildIconSprites() {
|
||||||
fal.faCogs,
|
fal.faCogs,
|
||||||
fal.faFolderUpload,
|
fal.faFolderUpload,
|
||||||
fal.faListMusic,
|
fal.faListMusic,
|
||||||
fal.faFileAudio,
|
fal.faFileImage,
|
||||||
],
|
],
|
||||||
vt: []
|
vt: []
|
||||||
};
|
};
|
||||||
|
|
15
index.html
15
index.html
|
@ -17,13 +17,10 @@
|
||||||
<use href="out/icon-sprite.svg#fal-fa-cogs"></use>
|
<use href="out/icon-sprite.svg#fal-fa-cogs"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload menu-icon">
|
<div class="upload-image menu-icon">
|
||||||
<label for="upload">
|
|
||||||
<svg role="img" class="icon">
|
<svg role="img" class="icon">
|
||||||
<use href="out/icon-sprite.svg#fal-fa-file-audio"></use>
|
<use href="out/icon-sprite.svg#fal-fa-file-image"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
|
||||||
<input type="file" multiple accept="audio/*" id="upload">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="upload menu-icon">
|
<div class="upload menu-icon">
|
||||||
<label for="upload-dir">
|
<label for="upload-dir">
|
||||||
|
@ -58,6 +55,11 @@
|
||||||
<use href="out/icon-sprite.svg#fal-fa-caret-right"></use>
|
<use href="out/icon-sprite.svg#fal-fa-caret-right"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="shuffle">
|
||||||
|
<svg role="img" class="icon">
|
||||||
|
<use href="out/icon-sprite.svg#fal-fa-random"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="c"></canvas>
|
<canvas id="c"></canvas>
|
||||||
<div class="grey-screen hide">
|
<div class="grey-screen hide">
|
||||||
|
@ -78,6 +80,9 @@
|
||||||
|
|
||||||
</modal-footer>
|
</modal-footer>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="notification">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="out/js/scripts.min.js"></script>
|
<script src="out/js/scripts.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
1
out/gui/wave.json
Normal file
1
out/gui/wave.json
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.3 KiB |
|
@ -51,13 +51,12 @@ class VTUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
static hsvToRgb(h, s, v) {
|
static hsvToRgb(h, s, v) {
|
||||||
var r, g, b;
|
let r, g, b,
|
||||||
|
i = Math.floor(h * 6),
|
||||||
var i = Math.floor(h * 6);
|
f = h * 6 - i,
|
||||||
var f = h * 6 - i;
|
p = v * (1 - s),
|
||||||
var p = v * (1 - s);
|
q = v * (1 - f * s),
|
||||||
var q = v * (1 - f * s);
|
t = v * (1 - (1 - f) * s);
|
||||||
var t = v * (1 - (1 - f) * s);
|
|
||||||
|
|
||||||
switch (i % 6) {
|
switch (i % 6) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -142,57 +141,226 @@ class VTVector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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!
|
||||||
class TDUtils {
|
class TDUtils {
|
||||||
static multiply(a, b) {
|
static multiply(a, b) {
|
||||||
let b00 = b[0 * 4 + 0];
|
let b00 = b[0];
|
||||||
let b01 = b[0 * 4 + 1];
|
let b01 = b[1];
|
||||||
let b02 = b[0 * 4 + 2];
|
let b02 = b[2];
|
||||||
let b03 = b[0 * 4 + 3];
|
let b03 = b[3];
|
||||||
let b10 = b[1 * 4 + 0];
|
let b10 = b[4];
|
||||||
let b11 = b[1 * 4 + 1];
|
let b11 = b[5];
|
||||||
let b12 = b[1 * 4 + 2];
|
let b12 = b[6];
|
||||||
let b13 = b[1 * 4 + 3];
|
let b13 = b[7];
|
||||||
let b20 = b[2 * 4 + 0];
|
let b20 = b[8];
|
||||||
let b21 = b[2 * 4 + 1];
|
let b21 = b[9];
|
||||||
let b22 = b[2 * 4 + 2];
|
let b22 = b[10];
|
||||||
let b23 = b[2 * 4 + 3];
|
let b23 = b[11];
|
||||||
let b30 = b[3 * 4 + 0];
|
let b30 = b[12];
|
||||||
let b31 = b[3 * 4 + 1];
|
let b31 = b[13];
|
||||||
let b32 = b[3 * 4 + 2];
|
let b32 = b[14];
|
||||||
let b33 = b[3 * 4 + 3];
|
let b33 = b[15];
|
||||||
let a00 = a[0 * 4 + 0];
|
let a00 = a[0];
|
||||||
let a01 = a[0 * 4 + 1];
|
let a01 = a[1];
|
||||||
let a02 = a[0 * 4 + 2];
|
let a02 = a[2];
|
||||||
let a03 = a[0 * 4 + 3];
|
let a03 = a[3];
|
||||||
let a10 = a[1 * 4 + 0];
|
let a10 = a[4];
|
||||||
let a11 = a[1 * 4 + 1];
|
let a11 = a[5];
|
||||||
let a12 = a[1 * 4 + 2];
|
let a12 = a[6];
|
||||||
let a13 = a[1 * 4 + 3];
|
let a13 = a[7];
|
||||||
let a20 = a[2 * 4 + 0];
|
let a20 = a[8];
|
||||||
let a21 = a[2 * 4 + 1];
|
let a21 = a[9];
|
||||||
let a22 = a[2 * 4 + 2];
|
let a22 = a[10];
|
||||||
let a23 = a[2 * 4 + 3];
|
let a23 = a[11];
|
||||||
let a30 = a[3 * 4 + 0];
|
let a30 = a[12];
|
||||||
let a31 = a[3 * 4 + 1];
|
let a31 = a[13];
|
||||||
let a32 = a[3 * 4 + 2];
|
let a32 = a[14];
|
||||||
let a33 = a[3 * 4 + 3];
|
let a33 = a[15];
|
||||||
let dst = [];
|
return [
|
||||||
dst[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
|
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
|
||||||
dst[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
|
b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
|
||||||
dst[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
|
b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
|
||||||
dst[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
|
b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
|
||||||
dst[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
|
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
|
||||||
dst[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
|
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
|
||||||
dst[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
|
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
|
||||||
dst[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
|
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
|
||||||
dst[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
|
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
|
||||||
dst[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
|
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
|
||||||
dst[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
|
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
|
||||||
dst[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
|
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
|
||||||
dst[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
|
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
|
||||||
dst[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
|
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
|
||||||
dst[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
|
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
|
||||||
dst[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
|
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;
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,52 +403,203 @@ class TDUtils {
|
||||||
static degToRad(d) {
|
static degToRad(d) {
|
||||||
return d * Math.PI / 180;
|
return d * Math.PI / 180;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static scale(sx, sy, sz, dst) {
|
||||||
|
dst = dst || new Float32Array(16);
|
||||||
|
dst[0] = sx;
|
||||||
|
dst[5] = sy;
|
||||||
|
dst[10] = sz;
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
function $(sel, s) {
|
static lookAt(cameraPosition, target, up, dst) {
|
||||||
return $$(sel, s)[0];
|
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;
|
||||||
|
|
||||||
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
function $$(sel, s) {
|
static cross(a, b, dst) {
|
||||||
s = s || document;
|
dst = dst || new Float32Array(3);
|
||||||
return s.querySelectorAll(sel);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.prototype.addDelegatedEventListener = function (type, aim, cb) {
|
static normalize(v, dst) {
|
||||||
this.addEventListener(type, (event) => {
|
dst = dst || new Float32Array(3);
|
||||||
let target = event.target;
|
let length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||||
if (target.matches(aim)) {
|
if (length > 0.00001) {
|
||||||
cb(event, target);
|
dst[0] = v[0] / length;
|
||||||
} else {
|
dst[1] = v[1] / length;
|
||||||
let parent = target.closest(aim);
|
dst[2] = v[2] / length;
|
||||||
if (parent) {
|
|
||||||
cb(event, parent);
|
|
||||||
}
|
}
|
||||||
}
|
return dst;
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
Node.prototype.hasClass = function (className) {
|
|
||||||
return this.classList.contains(className);
|
|
||||||
}
|
|
||||||
Node.prototype.addClass = function (className) {
|
|
||||||
return this.classList.add(className);
|
|
||||||
}
|
|
||||||
Node.prototype.removeClass = function (className) {
|
|
||||||
return this.classList.remove(className);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function create(name, content) {
|
static subtractVectors(a, b, dst) {
|
||||||
let d = document.createElement(name);
|
dst = dst || new Float32Array(3);
|
||||||
if (content) {
|
dst[0] = a[0] - b[0];
|
||||||
d.innerHTML = content;
|
dst[1] = a[1] - b[1];
|
||||||
}
|
dst[2] = a[2] - b[2];
|
||||||
return d;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
function append(to, array) {
|
static perspective(fieldOfViewInRadians, aspect, near, far, dst) {
|
||||||
for (let item in array) {
|
dst = dst || new Float32Array(16);
|
||||||
to.appendChild(array[item]);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class Template {
|
class Template {
|
||||||
|
@ -435,8 +754,8 @@ class AudioHandler {
|
||||||
let self = this;
|
let self = this;
|
||||||
self.isStarted = false;
|
self.isStarted = false;
|
||||||
self.audioFile = new Audio();
|
self.audioFile = new Audio();
|
||||||
self.actx = new AudioContext()
|
self.actx = new AudioContext();
|
||||||
self.analyser = self.actx.createAnalyser()
|
self.analyser = self.actx.createAnalyser();
|
||||||
self.analyser.fftSize = 4096;
|
self.analyser.fftSize = 4096;
|
||||||
self.lastSong = null;
|
self.lastSong = null;
|
||||||
await self.connectAll();
|
await self.connectAll();
|
||||||
|
@ -482,9 +801,13 @@ class AudioHandler {
|
||||||
}
|
}
|
||||||
self.lastSong = this.audioFile.src = URL.createObjectURL(src);
|
self.lastSong = this.audioFile.src = URL.createObjectURL(src);
|
||||||
if (!this.isStarted) {
|
if (!this.isStarted) {
|
||||||
this.start();
|
this.start().catch(alert);
|
||||||
}
|
}
|
||||||
this.audioFile.play();
|
this.audioFile.play().then(e => {
|
||||||
|
window.dispatchEvent(new CustomEvent('playSong'));
|
||||||
|
}).catch(e => {
|
||||||
|
player.nextSong();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getIntArray(steps) {
|
getIntArray(steps) {
|
||||||
|
@ -494,7 +817,7 @@ class AudioHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
getFloatArray() {
|
getFloatArray() {
|
||||||
let dataArray = new Float32Array(this.analyser.frequencyBinCount);
|
let dataArray = new Float32Array(this.analyser.fftSize);
|
||||||
this.analyser.getFloatTimeDomainData(dataArray);
|
this.analyser.getFloatTimeDomainData(dataArray);
|
||||||
return dataArray;
|
return dataArray;
|
||||||
}
|
}
|
||||||
|
@ -518,6 +841,7 @@ class Player {
|
||||||
if (!audioHandler.lastSong) {
|
if (!audioHandler.lastSong) {
|
||||||
let next = this.playlist.getCurrent();
|
let next = this.playlist.getCurrent();
|
||||||
audioHandler.loadSong(next.file);
|
audioHandler.loadSong(next.file);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
let audioFile = audioHandler.audioFile;
|
let audioFile = audioHandler.audioFile;
|
||||||
if (audioFile.paused) {
|
if (audioFile.paused) {
|
||||||
|
@ -525,10 +849,12 @@ class Player {
|
||||||
} else {
|
} else {
|
||||||
audioFile.pause();
|
audioFile.pause();
|
||||||
}
|
}
|
||||||
|
window.dispatchEvent(new CustomEvent('playSong'));
|
||||||
}
|
}
|
||||||
|
|
||||||
playByID(number) {
|
playByID(number) {
|
||||||
let next = this.playlist.getFile(number);
|
this.playlist.index = number;
|
||||||
|
let next = this.playlist.getCurrent();
|
||||||
audioHandler.loadSong(next.file);
|
audioHandler.loadSong(next.file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,11 +917,6 @@ class Playlist {
|
||||||
return items[this.index];
|
return items[this.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
getFile(index) {
|
|
||||||
let items = this.isShuffle ? this.shuffled : this.list;
|
|
||||||
return items[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// on new upload... this has to be an array!
|
// on new upload... this has to be an array!
|
||||||
setPlaylist(files) {
|
setPlaylist(files) {
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
@ -634,9 +955,10 @@ class Playlist {
|
||||||
let items = this.isShuffle ? this.shuffled : this.list;
|
let items = this.isShuffle ? this.shuffled : this.list;
|
||||||
for (let i = s; i < e; i++) {
|
for (let i = s; i < e; i++) {
|
||||||
let obj = {
|
let obj = {
|
||||||
index: i,
|
index: i.toString(),
|
||||||
nr: i + 1,
|
nr: i + 1,
|
||||||
title: items[i].name
|
title: items[i].name,
|
||||||
|
active: !audioHandler.audioFile.paused && i === this.index ? 'active' : ''
|
||||||
}
|
}
|
||||||
data += template.parseTemplate("playlist-item", obj);
|
data += template.parseTemplate("playlist-item", obj);
|
||||||
}
|
}
|
||||||
|
@ -659,6 +981,10 @@ class Playlist {
|
||||||
|
|
||||||
//playlist handler for file input!
|
//playlist handler for file input!
|
||||||
changeFiles(e, el) {
|
changeFiles(e, el) {
|
||||||
|
|
||||||
|
if (el.id !== 'upload-dir') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let files = [];
|
let files = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (let file of el.files) {
|
for (let file of el.files) {
|
||||||
|
@ -703,16 +1029,6 @@ class GUI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderModal(content, title) {
|
|
||||||
let modal = $('#modal'),
|
|
||||||
p = modal.parentNode,
|
|
||||||
h = $('header .headline', modal),
|
|
||||||
con = $('modal-content', modal);
|
|
||||||
h.innerHTML = title;
|
|
||||||
con.innerHTML = content;
|
|
||||||
p.classList.remove('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
initDropZone() {
|
initDropZone() {
|
||||||
let items = 'drag dragstart dragend dragover dragenter dragleave drop'.split(' ');
|
let items = 'drag dragstart dragend dragover dragenter dragleave drop'.split(' ');
|
||||||
items.forEach(el => {
|
items.forEach(el => {
|
||||||
|
@ -721,6 +1037,7 @@ class GUI {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.type === 'drop') {
|
if (e.type === 'drop') {
|
||||||
if (e.dataTransfer.files.length > 0) {
|
if (e.dataTransfer.files.length > 0) {
|
||||||
|
e.dataTransfer.id = 'upload-dir';
|
||||||
player.playlist.changeFiles(e, e.dataTransfer);
|
player.playlist.changeFiles(e, e.dataTransfer);
|
||||||
} else {
|
} else {
|
||||||
alert("Sorry you need to upload files!");
|
alert("Sorry you need to upload files!");
|
||||||
|
@ -749,7 +1066,6 @@ class Modal {
|
||||||
this.renderHeader(title);
|
this.renderHeader(title);
|
||||||
this.renderContent(content);
|
this.renderContent(content);
|
||||||
this.renderFooter(footer);
|
this.renderFooter(footer);
|
||||||
this.showModal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeader(header) {
|
renderHeader(header) {
|
||||||
|
@ -803,17 +1119,17 @@ class VisualDrawer {
|
||||||
"wave": new Wave(),
|
"wave": new Wave(),
|
||||||
"water": new Water()
|
"water": new Water()
|
||||||
}
|
}
|
||||||
this.c = "wave";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.visuals[this.c].setup();
|
this.switch('wave');
|
||||||
this.updateLoop();
|
this.updateLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(visual) {
|
switch(visual) {
|
||||||
if (this.visuals[visual] != null) {
|
if (this.visuals[visual] != null) {
|
||||||
this.c = visual;
|
this.c = visual;
|
||||||
|
vConf.loadConfigByName(this.c);
|
||||||
this.visuals[this.c].setup();
|
this.visuals[this.c].setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,9 +1139,104 @@ class VisualDrawer {
|
||||||
let pro = shaderHandler.use(self.c);
|
let pro = shaderHandler.use(self.c);
|
||||||
let vis = self.visuals[self.c];
|
let vis = self.visuals[self.c];
|
||||||
vis.updateData();
|
vis.updateData();
|
||||||
|
this.prepare();
|
||||||
vis.draw(pro);
|
vis.draw(pro);
|
||||||
requestAnimationFrame(self.updateLoop.bind(self))
|
requestAnimationFrame(self.updateLoop.bind(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class Config {
|
class Config {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -834,26 +1245,29 @@ class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfigByName(name) {
|
loadConfigByName(name) {
|
||||||
this.saveConfig();
|
this.save();
|
||||||
this.name = 'config-' + name;
|
this.name = 'config-' + name;
|
||||||
this.config = JSON.parse(this.name);
|
let item = localStorage.getItem(this.name);
|
||||||
|
if (item) {
|
||||||
|
this.config = JSON.parse(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig() {
|
save() {
|
||||||
if (this.name !== '') {
|
if (this.name !== '') {
|
||||||
localStorage.setItem(this.name, JSON.stringify(this.config));
|
localStorage.setItem(this.name, JSON.stringify(this.config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addItem(name, value) {
|
set(name, value) {
|
||||||
this.config[name] = value;
|
this.config[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem(name) {
|
remove(name) {
|
||||||
delete this.config[name];
|
delete this.config[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
getItem(name, def) {
|
get(name, def) {
|
||||||
let value = this.config[name];
|
let value = this.config[name];
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
this.config[name] = def;
|
this.config[name] = def;
|
||||||
|
@ -872,22 +1286,32 @@ class Sphere extends Visual {
|
||||||
// 3D Audio-Waves -> maybe also 2D?
|
// 3D Audio-Waves -> maybe also 2D?
|
||||||
class Wave extends Visual {
|
class Wave extends Visual {
|
||||||
updateData() {
|
updateData() {
|
||||||
this.data = [];
|
//only for debug! remove pls
|
||||||
|
if (window.stopUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let data = audioHandler.getFloatArray();
|
let data = audioHandler.getFloatArray();
|
||||||
let add = 2 / data.length,
|
let add = 2 / data.length,
|
||||||
x = -1;
|
x = -1;
|
||||||
|
let outerLoop = 0;
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
this.data.push(x, data[i], data[i]);
|
//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;
|
||||||
x += add;
|
x += add;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(program) {
|
draw(program) {
|
||||||
c.width = window.innerWidth;
|
|
||||||
c.height = window.innerHeight;
|
|
||||||
this.prepare(program);
|
this.prepare(program);
|
||||||
let position = this.position,
|
let position = this.position,
|
||||||
color = this.color,
|
|
||||||
positionBuffer = gl.createBuffer();
|
positionBuffer = gl.createBuffer();
|
||||||
this.rotate(program);
|
this.rotate(program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||||
|
@ -896,37 +1320,39 @@ class Wave extends Visual {
|
||||||
gl.bindVertexArray(vao);
|
gl.bindVertexArray(vao);
|
||||||
gl.enableVertexAttribArray(position);
|
gl.enableVertexAttribArray(position);
|
||||||
gl.vertexAttribPointer(position, 3, gl.FLOAT, true, 0, 0);
|
gl.vertexAttribPointer(position, 3, gl.FLOAT, true, 0, 0);
|
||||||
gl.clearColor(0, 0, 0, 1);
|
gl.drawArrays(vConf.get("waveForm", gl.TRIANGLES), 0, this.data.length / 3);
|
||||||
gl.enable(gl.DEPTH_TEST);
|
|
||||||
gl.depthFunc(gl.LEQUAL);
|
|
||||||
gl.clearDepth(2.0)
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
||||||
gl.drawArrays(gl.LINE_STRIP || gl.POINTS, 0, this.data.length / 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate(program) {
|
rotate(program) {
|
||||||
let aspect = c.height / c.width,
|
let aspect = c.width / c.height,
|
||||||
matrix = [
|
matrix = [
|
||||||
1 / aspect, 0, 0, 0,
|
1 / aspect, 0, 0, 0,
|
||||||
0, 1, 0, 0,
|
0, 0.6, 0, 0,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
]
|
]
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(config.getItem("xRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(vConf.get("xRotate", 0)));
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(config.getItem("yRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(vConf.get("yRotate", 0)));
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(config.getItem("zRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(vConf.get("zRotate", 0)));
|
||||||
let rotate = gl.getUniformLocation(program, "u_matrix");
|
let rotate = gl.getUniformLocation(program, "u_matrix");
|
||||||
gl.uniformMatrix4fv(rotate, false, matrix);
|
gl.uniformMatrix4fv(rotate, false, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
audioHandler.fftSize(16384)
|
audioHandler.fftSize(16384)
|
||||||
|
this.data = new Float32Array(16384 * 9);
|
||||||
|
vConf.get("zRotate", TDUtils.degToRad(-30));
|
||||||
|
vConf.get("yRotate", TDUtils.degToRad(50));
|
||||||
|
vConf.get("xRotate", TDUtils.degToRad(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(program) {
|
prepare(program) {
|
||||||
this.position = gl.getAttribLocation(program, "a_position");
|
this.position = gl.getAttribLocation(program, "a_position");
|
||||||
this.color = gl.getUniformLocation(program, "u_color");
|
this.color = gl.getUniformLocation(program, "u_color");
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//animate Water the way like the Audio is Coming... 256FFT-Size max!
|
//animate Water the way like the Audio is Coming... 256FFT-Size max!
|
||||||
|
@ -943,6 +1369,7 @@ async function initHandler() {
|
||||||
let body = $('body');
|
let body = $('body');
|
||||||
$('.playlist.menu-icon').addEventListener('click', e => {
|
$('.playlist.menu-icon').addEventListener('click', e => {
|
||||||
player.playlist.renderPagination(player.playlist.page);
|
player.playlist.renderPagination(player.playlist.page);
|
||||||
|
gui.modal.showModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
body.addDelegatedEventListener('click', '.playlist-item', (e, el) => {
|
body.addDelegatedEventListener('click', '.playlist-item', (e, el) => {
|
||||||
|
@ -962,11 +1389,32 @@ async function initHandler() {
|
||||||
case 'play':
|
case 'play':
|
||||||
player.playStop();
|
player.playStop();
|
||||||
break;
|
break;
|
||||||
|
case 'shuffle':
|
||||||
|
player.playlist.isShuffle = !player.playlist.isShuffle;
|
||||||
|
toggleShuffle();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
togglePlayButton(audioHandler.audioFile.paused ? 'play' : 'pause');
|
togglePlayButton(audioHandler.audioFile.paused ? 'play' : 'pause');
|
||||||
});
|
});
|
||||||
|
window.addEventListener('playSong', setActiveOnPlaylist);
|
||||||
|
$('.upload-image').addEventListener('click', imageUploader.renderModal.bind(imageUploader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
function togglePlayButton(status) {
|
function togglePlayButton(status) {
|
||||||
let icons = $$('#play .icon');
|
let icons = $$('#play .icon');
|
||||||
|
@ -984,12 +1432,14 @@ const shaderHandler = new ShaderHandler(null),
|
||||||
visual = new VisualDrawer(),
|
visual = new VisualDrawer(),
|
||||||
template = new Template(),
|
template = new Template(),
|
||||||
player = new Player(),
|
player = new Player(),
|
||||||
config = new Config();
|
vConf = new Config(),
|
||||||
|
pConf = new Config();
|
||||||
|
|
||||||
let c = null,
|
let c = null,
|
||||||
gl = null;
|
gl = null;
|
||||||
|
|
||||||
async function startUP() {
|
async function startUP() {
|
||||||
|
pConf.loadConfigByName('default');
|
||||||
c = document.body.querySelector('#c'),
|
c = document.body.querySelector('#c'),
|
||||||
gl = c.getContext("webgl2");
|
gl = c.getContext("webgl2");
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
|
@ -1002,6 +1452,7 @@ async function startUP() {
|
||||||
await player.init();
|
await player.init();
|
||||||
await visual.init();
|
await visual.init();
|
||||||
await gui.init();
|
await gui.init();
|
||||||
|
await imageUploader.init();
|
||||||
await initHandler();
|
await initHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
out/js/scripts.min.js
vendored
2
out/js/scripts.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
27
out/tpl/image.tpl
Normal file
27
out/tpl/image.tpl
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<div id="image-upload">
|
||||||
|
<label for="image" class="button">
|
||||||
|
Image-Upload (Only Local!)
|
||||||
|
</label>
|
||||||
|
<input type="file" id="image" accept="image/*|video/*">
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<label class="input floating-label">
|
||||||
|
<input type="url" id="url" value="$value$">
|
||||||
|
<span class="input-label">URL</span>
|
||||||
|
<span class="focus"></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<p>You only want to change the color? do it!</p>
|
||||||
|
<label class="input floating-label color-picker" for="color">
|
||||||
|
<span id="colorBlob" style="background-color: $bgValue$"></span>
|
||||||
|
<input type="color" id="color" value="$bgValue$">
|
||||||
|
<span class="input-label">Color</span>
|
||||||
|
<span class="focus"></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="input">
|
||||||
|
<input class="range" type="range" id="alphaValue" min="0" max="1" value="$alphaValue$" step="0.1">
|
||||||
|
<span class="input-label">Alpha</span>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -1,4 +1,4 @@
|
||||||
<playlist-item class="playlist-item" data-index="$index$">
|
<playlist-item class="playlist-item $active$" data-index="$index$">
|
||||||
<div class="playlist-item-number">$nr$</div>
|
<div class="playlist-item-number">$nr$</div>
|
||||||
<div class="playlist-item-title">$title$</div>
|
<div class="playlist-item-title">$title$</div>
|
||||||
</playlist-item>
|
</playlist-item>
|
|
@ -4,12 +4,14 @@ const shaderHandler = new ShaderHandler(null),
|
||||||
visual = new VisualDrawer(),
|
visual = new VisualDrawer(),
|
||||||
template = new Template(),
|
template = new Template(),
|
||||||
player = new Player(),
|
player = new Player(),
|
||||||
config = new Config();
|
vConf = new Config(),
|
||||||
|
pConf = new Config();
|
||||||
|
|
||||||
let c = null,
|
let c = null,
|
||||||
gl = null;
|
gl = null;
|
||||||
|
|
||||||
async function startUP() {
|
async function startUP() {
|
||||||
|
pConf.loadConfigByName('default');
|
||||||
c = document.body.querySelector('#c'),
|
c = document.body.querySelector('#c'),
|
||||||
gl = c.getContext("webgl2");
|
gl = c.getContext("webgl2");
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
|
@ -22,6 +24,7 @@ async function startUP() {
|
||||||
await player.init();
|
await player.init();
|
||||||
await visual.init();
|
await visual.init();
|
||||||
await gui.init();
|
await gui.init();
|
||||||
|
await imageUploader.init();
|
||||||
await initHandler();
|
await initHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ class AudioHandler {
|
||||||
let self = this;
|
let self = this;
|
||||||
self.isStarted = false;
|
self.isStarted = false;
|
||||||
self.audioFile = new Audio();
|
self.audioFile = new Audio();
|
||||||
self.actx = new AudioContext()
|
self.actx = new AudioContext();
|
||||||
self.analyser = self.actx.createAnalyser()
|
self.analyser = self.actx.createAnalyser();
|
||||||
self.analyser.fftSize = 4096;
|
self.analyser.fftSize = 4096;
|
||||||
self.lastSong = null;
|
self.lastSong = null;
|
||||||
await self.connectAll();
|
await self.connectAll();
|
||||||
|
@ -52,9 +52,13 @@ class AudioHandler {
|
||||||
}
|
}
|
||||||
self.lastSong = this.audioFile.src = URL.createObjectURL(src);
|
self.lastSong = this.audioFile.src = URL.createObjectURL(src);
|
||||||
if (!this.isStarted) {
|
if (!this.isStarted) {
|
||||||
this.start();
|
this.start().catch(alert);
|
||||||
}
|
}
|
||||||
this.audioFile.play();
|
this.audioFile.play().then(e => {
|
||||||
|
window.dispatchEvent(new CustomEvent('playSong'));
|
||||||
|
}).catch(e => {
|
||||||
|
player.nextSong();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getIntArray(steps) {
|
getIntArray(steps) {
|
||||||
|
@ -64,7 +68,7 @@ class AudioHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
getFloatArray() {
|
getFloatArray() {
|
||||||
let dataArray = new Float32Array(this.analyser.frequencyBinCount);
|
let dataArray = new Float32Array(this.analyser.fftSize);
|
||||||
this.analyser.getFloatTimeDomainData(dataArray);
|
this.analyser.getFloatTimeDomainData(dataArray);
|
||||||
return dataArray;
|
return dataArray;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,26 +5,29 @@ class Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadConfigByName(name) {
|
loadConfigByName(name) {
|
||||||
this.saveConfig();
|
this.save();
|
||||||
this.name = 'config-' + name;
|
this.name = 'config-' + name;
|
||||||
this.config = JSON.parse(this.name);
|
let item = localStorage.getItem(this.name);
|
||||||
|
if (item) {
|
||||||
|
this.config = JSON.parse(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveConfig() {
|
save() {
|
||||||
if (this.name !== '') {
|
if (this.name !== '') {
|
||||||
localStorage.setItem(this.name, JSON.stringify(this.config));
|
localStorage.setItem(this.name, JSON.stringify(this.config));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addItem(name, value) {
|
set(name, value) {
|
||||||
this.config[name] = value;
|
this.config[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem(name) {
|
remove(name) {
|
||||||
delete this.config[name];
|
delete this.config[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
getItem(name, def) {
|
get(name, def) {
|
||||||
let value = this.config[name];
|
let value = this.config[name];
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
this.config[name] = def;
|
this.config[name] = def;
|
||||||
|
|
|
@ -2,6 +2,7 @@ async function initHandler() {
|
||||||
let body = $('body');
|
let body = $('body');
|
||||||
$('.playlist.menu-icon').addEventListener('click', e => {
|
$('.playlist.menu-icon').addEventListener('click', e => {
|
||||||
player.playlist.renderPagination(player.playlist.page);
|
player.playlist.renderPagination(player.playlist.page);
|
||||||
|
gui.modal.showModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
body.addDelegatedEventListener('click', '.playlist-item', (e, el) => {
|
body.addDelegatedEventListener('click', '.playlist-item', (e, el) => {
|
||||||
|
@ -21,11 +22,32 @@ async function initHandler() {
|
||||||
case 'play':
|
case 'play':
|
||||||
player.playStop();
|
player.playStop();
|
||||||
break;
|
break;
|
||||||
|
case 'shuffle':
|
||||||
|
player.playlist.isShuffle = !player.playlist.isShuffle;
|
||||||
|
toggleShuffle();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
togglePlayButton(audioHandler.audioFile.paused ? 'play' : 'pause');
|
togglePlayButton(audioHandler.audioFile.paused ? 'play' : 'pause');
|
||||||
});
|
});
|
||||||
|
window.addEventListener('playSong', setActiveOnPlaylist);
|
||||||
|
$('.upload-image').addEventListener('click', imageUploader.renderModal.bind(imageUploader));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
function togglePlayButton(status) {
|
function togglePlayButton(status) {
|
||||||
let icons = $$('#play .icon');
|
let icons = $$('#play .icon');
|
||||||
|
|
333
raw/javascript/gl/glUtils.js
Normal file
333
raw/javascript/gl/glUtils.js
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
// 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!
|
||||||
|
class TDUtils {
|
||||||
|
static multiply(a, b) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static scale(sx, sy, sz, dst) {
|
||||||
|
dst = dst || new Float32Array(16);
|
||||||
|
dst[0] = sx;
|
||||||
|
dst[5] = sy;
|
||||||
|
dst[10] = sz;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,16 +20,6 @@ class GUI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderModal(content, title) {
|
|
||||||
let modal = $('#modal'),
|
|
||||||
p = modal.parentNode,
|
|
||||||
h = $('header .headline', modal),
|
|
||||||
con = $('modal-content', modal);
|
|
||||||
h.innerHTML = title;
|
|
||||||
con.innerHTML = content;
|
|
||||||
p.classList.remove('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
initDropZone() {
|
initDropZone() {
|
||||||
let items = 'drag dragstart dragend dragover dragenter dragleave drop'.split(' ');
|
let items = 'drag dragstart dragend dragover dragenter dragleave drop'.split(' ');
|
||||||
items.forEach(el => {
|
items.forEach(el => {
|
||||||
|
@ -38,6 +28,7 @@ class GUI {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.type === 'drop') {
|
if (e.type === 'drop') {
|
||||||
if (e.dataTransfer.files.length > 0) {
|
if (e.dataTransfer.files.length > 0) {
|
||||||
|
e.dataTransfer.id = 'upload-dir';
|
||||||
player.playlist.changeFiles(e, e.dataTransfer);
|
player.playlist.changeFiles(e, e.dataTransfer);
|
||||||
} else {
|
} else {
|
||||||
alert("Sorry you need to upload files!");
|
alert("Sorry you need to upload files!");
|
||||||
|
@ -66,7 +57,6 @@ class Modal {
|
||||||
this.renderHeader(title);
|
this.renderHeader(title);
|
||||||
this.renderContent(content);
|
this.renderContent(content);
|
||||||
this.renderFooter(footer);
|
this.renderFooter(footer);
|
||||||
this.showModal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeader(header) {
|
renderHeader(header) {
|
||||||
|
|
78
raw/javascript/imageUploader.js
Normal file
78
raw/javascript/imageUploader.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
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();
|
5
raw/javascript/notification.js
Normal file
5
raw/javascript/notification.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class Notification {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ class Player {
|
||||||
if (!audioHandler.lastSong) {
|
if (!audioHandler.lastSong) {
|
||||||
let next = this.playlist.getCurrent();
|
let next = this.playlist.getCurrent();
|
||||||
audioHandler.loadSong(next.file);
|
audioHandler.loadSong(next.file);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
let audioFile = audioHandler.audioFile;
|
let audioFile = audioHandler.audioFile;
|
||||||
if (audioFile.paused) {
|
if (audioFile.paused) {
|
||||||
|
@ -24,10 +25,12 @@ class Player {
|
||||||
} else {
|
} else {
|
||||||
audioFile.pause();
|
audioFile.pause();
|
||||||
}
|
}
|
||||||
|
window.dispatchEvent(new CustomEvent('playSong'));
|
||||||
}
|
}
|
||||||
|
|
||||||
playByID(number) {
|
playByID(number) {
|
||||||
let next = this.playlist.getFile(number);
|
this.playlist.index = number;
|
||||||
|
let next = this.playlist.getCurrent();
|
||||||
audioHandler.loadSong(next.file);
|
audioHandler.loadSong(next.file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,11 +93,6 @@ class Playlist {
|
||||||
return items[this.index];
|
return items[this.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
getFile(index) {
|
|
||||||
let items = this.isShuffle ? this.shuffled : this.list;
|
|
||||||
return items[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
// on new upload... this has to be an array!
|
// on new upload... this has to be an array!
|
||||||
setPlaylist(files) {
|
setPlaylist(files) {
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
@ -133,9 +131,10 @@ class Playlist {
|
||||||
let items = this.isShuffle ? this.shuffled : this.list;
|
let items = this.isShuffle ? this.shuffled : this.list;
|
||||||
for (let i = s; i < e; i++) {
|
for (let i = s; i < e; i++) {
|
||||||
let obj = {
|
let obj = {
|
||||||
index: i,
|
index: i.toString(),
|
||||||
nr: i + 1,
|
nr: i + 1,
|
||||||
title: items[i].name
|
title: items[i].name,
|
||||||
|
active: !audioHandler.audioFile.paused && i === this.index ? 'active' : ''
|
||||||
}
|
}
|
||||||
data += template.parseTemplate("playlist-item", obj);
|
data += template.parseTemplate("playlist-item", obj);
|
||||||
}
|
}
|
||||||
|
@ -158,6 +157,10 @@ class Playlist {
|
||||||
|
|
||||||
//playlist handler for file input!
|
//playlist handler for file input!
|
||||||
changeFiles(e, el) {
|
changeFiles(e, el) {
|
||||||
|
|
||||||
|
if (el.id !== 'upload-dir') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let files = [];
|
let files = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (let file of el.files) {
|
for (let file of el.files) {
|
||||||
|
|
|
@ -51,13 +51,12 @@ class VTUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
static hsvToRgb(h, s, v) {
|
static hsvToRgb(h, s, v) {
|
||||||
var r, g, b;
|
let r, g, b,
|
||||||
|
i = Math.floor(h * 6),
|
||||||
var i = Math.floor(h * 6);
|
f = h * 6 - i,
|
||||||
var f = h * 6 - i;
|
p = v * (1 - s),
|
||||||
var p = v * (1 - s);
|
q = v * (1 - f * s),
|
||||||
var q = v * (1 - f * s);
|
t = v * (1 - (1 - f) * s);
|
||||||
var t = v * (1 - (1 - f) * s);
|
|
||||||
|
|
||||||
switch (i % 6) {
|
switch (i % 6) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -142,103 +141,9 @@ class VTVector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TDUtils {
|
|
||||||
static multiply(a, b) {
|
|
||||||
let b00 = b[0 * 4 + 0];
|
|
||||||
let b01 = b[0 * 4 + 1];
|
|
||||||
let b02 = b[0 * 4 + 2];
|
|
||||||
let b03 = b[0 * 4 + 3];
|
|
||||||
let b10 = b[1 * 4 + 0];
|
|
||||||
let b11 = b[1 * 4 + 1];
|
|
||||||
let b12 = b[1 * 4 + 2];
|
|
||||||
let b13 = b[1 * 4 + 3];
|
|
||||||
let b20 = b[2 * 4 + 0];
|
|
||||||
let b21 = b[2 * 4 + 1];
|
|
||||||
let b22 = b[2 * 4 + 2];
|
|
||||||
let b23 = b[2 * 4 + 3];
|
|
||||||
let b30 = b[3 * 4 + 0];
|
|
||||||
let b31 = b[3 * 4 + 1];
|
|
||||||
let b32 = b[3 * 4 + 2];
|
|
||||||
let b33 = b[3 * 4 + 3];
|
|
||||||
let a00 = a[0 * 4 + 0];
|
|
||||||
let a01 = a[0 * 4 + 1];
|
|
||||||
let a02 = a[0 * 4 + 2];
|
|
||||||
let a03 = a[0 * 4 + 3];
|
|
||||||
let a10 = a[1 * 4 + 0];
|
|
||||||
let a11 = a[1 * 4 + 1];
|
|
||||||
let a12 = a[1 * 4 + 2];
|
|
||||||
let a13 = a[1 * 4 + 3];
|
|
||||||
let a20 = a[2 * 4 + 0];
|
|
||||||
let a21 = a[2 * 4 + 1];
|
|
||||||
let a22 = a[2 * 4 + 2];
|
|
||||||
let a23 = a[2 * 4 + 3];
|
|
||||||
let a30 = a[3 * 4 + 0];
|
|
||||||
let a31 = a[3 * 4 + 1];
|
|
||||||
let a32 = a[3 * 4 + 2];
|
|
||||||
let a33 = a[3 * 4 + 3];
|
|
||||||
let dst = [];
|
|
||||||
dst[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30;
|
|
||||||
dst[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31;
|
|
||||||
dst[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32;
|
|
||||||
dst[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33;
|
|
||||||
dst[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30;
|
|
||||||
dst[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31;
|
|
||||||
dst[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32;
|
|
||||||
dst[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33;
|
|
||||||
dst[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30;
|
|
||||||
dst[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31;
|
|
||||||
dst[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32;
|
|
||||||
dst[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33;
|
|
||||||
dst[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30;
|
|
||||||
dst[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31;
|
|
||||||
dst[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32;
|
|
||||||
dst[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function $(sel, s) {
|
function $(sel, s) {
|
||||||
return $$(sel, s)[0];
|
s = s || document;
|
||||||
|
return s.querySelector(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
function $$(sel, s) {
|
function $$(sel, s) {
|
||||||
|
@ -261,13 +166,73 @@ Node.prototype.addDelegatedEventListener = function (type, aim, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype.hasClass = function (className) {
|
Node.prototype.hasClass = function (className) {
|
||||||
return this.classList.contains(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) {
|
Node.prototype.addClass = function (className) {
|
||||||
return this.classList.add(className);
|
let items = className.split(',');
|
||||||
|
for (let item of items) {
|
||||||
|
this.classList.add(item.trim());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
Node.prototype.removeClass = function (className) {
|
Node.prototype.removeClass = function (className) {
|
||||||
return this.classList.remove(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) {
|
function create(name, content) {
|
||||||
|
@ -279,7 +244,28 @@ function create(name, content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function append(to, array) {
|
function append(to, array) {
|
||||||
for (let item in array) {
|
for (let item of array) {
|
||||||
to.appendChild(array[item]);
|
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;
|
||||||
|
})
|
||||||
|
}
|
|
@ -22,17 +22,17 @@ class VisualDrawer {
|
||||||
"wave": new Wave(),
|
"wave": new Wave(),
|
||||||
"water": new Water()
|
"water": new Water()
|
||||||
}
|
}
|
||||||
this.c = "wave";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.visuals[this.c].setup();
|
this.switch('wave');
|
||||||
this.updateLoop();
|
this.updateLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(visual) {
|
switch(visual) {
|
||||||
if (this.visuals[visual] != null) {
|
if (this.visuals[visual] != null) {
|
||||||
this.c = visual;
|
this.c = visual;
|
||||||
|
vConf.loadConfigByName(this.c);
|
||||||
this.visuals[this.c].setup();
|
this.visuals[this.c].setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,19 @@ class VisualDrawer {
|
||||||
let pro = shaderHandler.use(self.c);
|
let pro = shaderHandler.use(self.c);
|
||||||
let vis = self.visuals[self.c];
|
let vis = self.visuals[self.c];
|
||||||
vis.updateData();
|
vis.updateData();
|
||||||
|
this.prepare();
|
||||||
vis.draw(pro);
|
vis.draw(pro);
|
||||||
requestAnimationFrame(self.updateLoop.bind(self))
|
requestAnimationFrame(self.updateLoop.bind(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,22 +1,32 @@
|
||||||
// 3D Audio-Waves -> maybe also 2D?
|
// 3D Audio-Waves -> maybe also 2D?
|
||||||
class Wave extends Visual {
|
class Wave extends Visual {
|
||||||
updateData() {
|
updateData() {
|
||||||
this.data = [];
|
//only for debug! remove pls
|
||||||
|
if (window.stopUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let data = audioHandler.getFloatArray();
|
let data = audioHandler.getFloatArray();
|
||||||
let add = 2 / data.length,
|
let add = 2 / data.length,
|
||||||
x = -1;
|
x = -1;
|
||||||
|
let outerLoop = 0;
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
this.data.push(x, data[i], data[i]);
|
//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;
|
||||||
x += add;
|
x += add;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
draw(program) {
|
draw(program) {
|
||||||
c.width = window.innerWidth;
|
|
||||||
c.height = window.innerHeight;
|
|
||||||
this.prepare(program);
|
this.prepare(program);
|
||||||
let position = this.position,
|
let position = this.position,
|
||||||
color = this.color,
|
|
||||||
positionBuffer = gl.createBuffer();
|
positionBuffer = gl.createBuffer();
|
||||||
this.rotate(program);
|
this.rotate(program);
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||||
|
@ -25,36 +35,38 @@ class Wave extends Visual {
|
||||||
gl.bindVertexArray(vao);
|
gl.bindVertexArray(vao);
|
||||||
gl.enableVertexAttribArray(position);
|
gl.enableVertexAttribArray(position);
|
||||||
gl.vertexAttribPointer(position, 3, gl.FLOAT, true, 0, 0);
|
gl.vertexAttribPointer(position, 3, gl.FLOAT, true, 0, 0);
|
||||||
gl.clearColor(0, 0, 0, 1);
|
gl.drawArrays(vConf.get("waveForm", gl.TRIANGLES), 0, this.data.length / 3);
|
||||||
gl.enable(gl.DEPTH_TEST);
|
|
||||||
gl.depthFunc(gl.LEQUAL);
|
|
||||||
gl.clearDepth(2.0)
|
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
||||||
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
||||||
gl.drawArrays(gl.LINE_STRIP || gl.POINTS, 0, this.data.length / 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate(program) {
|
rotate(program) {
|
||||||
let aspect = c.height / c.width,
|
let aspect = c.width / c.height,
|
||||||
matrix = [
|
matrix = [
|
||||||
1 / aspect, 0, 0, 0,
|
1 / aspect, 0, 0, 0,
|
||||||
0, 1, 0, 0,
|
0, 0.6, 0, 0,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
]
|
]
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(config.getItem("xRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(vConf.get("xRotate", 0)));
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(config.getItem("yRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(vConf.get("yRotate", 0)));
|
||||||
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(config.getItem("zRotate", 0)));
|
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(vConf.get("zRotate", 0)));
|
||||||
let rotate = gl.getUniformLocation(program, "u_matrix");
|
let rotate = gl.getUniformLocation(program, "u_matrix");
|
||||||
gl.uniformMatrix4fv(rotate, false, matrix);
|
gl.uniformMatrix4fv(rotate, false, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
audioHandler.fftSize(16384)
|
audioHandler.fftSize(16384)
|
||||||
|
this.data = new Float32Array(16384 * 9);
|
||||||
|
vConf.get("zRotate", TDUtils.degToRad(-30));
|
||||||
|
vConf.get("yRotate", TDUtils.degToRad(50));
|
||||||
|
vConf.get("xRotate", TDUtils.degToRad(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare(program) {
|
prepare(program) {
|
||||||
this.position = gl.getAttribLocation(program, "a_position");
|
this.position = gl.getAttribLocation(program, "a_position");
|
||||||
this.color = gl.getUniformLocation(program, "u_color");
|
this.color = gl.getUniformLocation(program, "u_color");
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,18 +7,18 @@
|
||||||
background-color: rgba(33, 33, 33, .6);
|
background-color: rgba(33, 33, 33, .6);
|
||||||
border: none;
|
border: none;
|
||||||
font-size: 1.4em;
|
font-size: 1.4em;
|
||||||
border-top: 4px solid #089bec;
|
border-top: 4px solid $primary;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
transition: .5s;
|
transition: .5s;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
border-color: #ff066a;
|
border-color: $second;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(21, 21, 21, .7);
|
background-color: rgba(21, 21, 21, .7);
|
||||||
border-color: #aaef22;
|
border-color: $active;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -84,7 +84,7 @@ group-input {
|
||||||
height: 6px;
|
height: 6px;
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
transform-origin: left;
|
transform-origin: left;
|
||||||
background-color: #006ea8;
|
background-color: $primary;
|
||||||
animation: loadingBar 2s infinite;
|
animation: loadingBar 2s infinite;
|
||||||
|
|
||||||
&.delay {
|
&.delay {
|
||||||
|
@ -124,45 +124,9 @@ group-input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#modal {
|
#image-upload form {
|
||||||
max-width: 860px;
|
margin-top: 20px;
|
||||||
width: 90%;
|
|
||||||
min-height: 200px;
|
|
||||||
background-color: #333;
|
|
||||||
padding: unset;
|
|
||||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
|
|
||||||
|
|
||||||
header {
|
|
||||||
height: 50px;
|
|
||||||
font-size: 30px;
|
|
||||||
line-height: 50px;
|
|
||||||
padding-left: 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: #212121;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
.headline {
|
align-items: center;
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
margin-right: 10px;
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #ff3232;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modal-content {
|
|
||||||
display: block;
|
|
||||||
max-height: calc(100vh - 200px);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
modal-footer {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,39 +1,182 @@
|
||||||
input[type=range] {
|
.range {
|
||||||
|
-webkit-appearance: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
&:focus {
|
.range.center {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range.right {
|
||||||
|
margin-left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus::-webkit-slider-runnable-track {
|
.range::-webkit-slider-runnable-track {
|
||||||
background: #545454;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus::-ms-fill-lower {
|
|
||||||
background: #424242;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus::-ms-fill-upper {
|
|
||||||
background: #545454;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=range]::-webkit-slider-runnable-track {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 25.6px;
|
height: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d;
|
background: rgba(0, 0, 0, 0.12);
|
||||||
background: #424242;
|
border-radius: 15px;
|
||||||
border-radius: 0;
|
border: none;
|
||||||
border: 0 solid #010101;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=range]::-webkit-slider-thumb {
|
.range::-webkit-slider-thumb {
|
||||||
height: 25px;
|
border: 0 solid rgba(0, 0, 30, 0);
|
||||||
|
height: 15px;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
border-radius: 0;
|
border-radius: 15px;
|
||||||
|
background: #ff0089;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin-top: 0.3px;
|
-webkit-appearance: none;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range:focus::-webkit-slider-runnable-track {
|
||||||
|
background: rgba(89, 89, 89, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-moz-range-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(0, 0, 0, 0.12);
|
||||||
|
border-radius: 15px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-moz-range-thumb {
|
||||||
|
border: 0 solid rgba(0, 0, 30, 0);
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background: #ff0089;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-ms-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-ms-fill-lower {
|
||||||
|
background: rgba(0, 0, 0, 0.12);
|
||||||
|
border: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-ms-fill-upper {
|
||||||
|
background: rgba(0, 0, 0, 0.12);
|
||||||
|
border: none;
|
||||||
|
border-radius: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range::-ms-thumb {
|
||||||
|
border: 0 solid rgba(0, 0, 30, 0);
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background: #ff0089;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.range:focus::-ms-fill-lower {
|
||||||
|
background: rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.range:focus::-ms-fill-upper {
|
||||||
|
background: rgba(89, 89, 89, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 90%;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 1rem;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + .input:after {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input input:not([type=range]) {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 2px solid #dcdcdc;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 5px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input input:not([type=range]):focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.center {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input.right {
|
||||||
|
margin-left: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-label .input-label {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
|
pointer-events: none;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-label input:focus ~ .input-label,
|
||||||
|
.floating-label input:valid ~ .input-label {
|
||||||
|
transform: translateY(-0.72rem);
|
||||||
|
color: #ff0089;
|
||||||
|
font-size: .7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-label input:valid ~ .input-label {
|
||||||
|
transform: translateY(-0.72rem);
|
||||||
|
color: #3949ab;
|
||||||
|
font-size: .7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focus {
|
||||||
|
content: '';
|
||||||
|
width: 0;
|
||||||
|
background-color: #ff0a8e;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
height: 2px;
|
||||||
|
transition: 0.4s cubic-bezier(0.8, 0.4, 0.25, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus ~ .focus {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -77,3 +220,34 @@ input[type="file"] {
|
||||||
height: 1px;
|
height: 1px;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="color"] {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-picker {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute !important;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#colorBlob {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
border: 1px solid $primary;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .5s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $second;
|
||||||
|
}
|
||||||
|
}
|
49
raw/scss/_modal.scss
Normal file
49
raw/scss/_modal.scss
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#modal {
|
||||||
|
max-width: 860px;
|
||||||
|
width: 90%;
|
||||||
|
background-color: $bg;
|
||||||
|
padding: unset;
|
||||||
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
|
||||||
|
border-radius: 15px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
div {
|
||||||
|
position: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
height: 50px;
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 50px;
|
||||||
|
padding-left: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: $darker;
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
|
||||||
|
|
||||||
|
.headline {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
margin-right: 10px;
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modal-content {
|
||||||
|
display: block;
|
||||||
|
max-height: calc(100vh - 200px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
modal-footer {
|
||||||
|
display: block;
|
||||||
|
box-shadow: 0 -3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
|
||||||
|
}
|
||||||
|
}
|
6
raw/scss/_notification.scss
Normal file
6
raw/scss/_notification.scss
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.notification {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
width: 320px;
|
||||||
|
}
|
|
@ -13,11 +13,17 @@ playlist {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
||||||
|
.current {
|
||||||
|
font-size: .9em;
|
||||||
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
&.inactive {
|
&.inactive {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
|
@ -26,7 +32,7 @@ playlist {
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #006ea8;
|
color: $primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +40,20 @@ playlist {
|
||||||
.playlist-item {
|
.playlist-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-bottom: 1px solid #dcdcdc;
|
box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, .08);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: .5s;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: rgba(0, 0, 0, .2);
|
||||||
|
|
||||||
|
.playlist-item-title {
|
||||||
|
&:before {
|
||||||
|
content: '🔊 ';
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
@ -46,7 +64,6 @@ playlist {
|
||||||
|
|
||||||
&-number {
|
&-number {
|
||||||
padding: 5px 10px 5px 5px;
|
padding: 5px 10px 5px 5px;
|
||||||
border-right: 1px solid #ff3232;
|
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
42
raw/scss/_scrollbar.scss
Normal file
42
raw/scss/_scrollbar.scss
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-button {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #e1e1e1;
|
||||||
|
border: 0 none #ffffff;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:active {
|
||||||
|
background: $primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #666666;
|
||||||
|
border: 0 none #ffffff;
|
||||||
|
border-radius: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track:hover {
|
||||||
|
background: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track:active {
|
||||||
|
background: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-corner {
|
||||||
|
background: transparent;
|
||||||
|
}
|
6
raw/scss/_variables.scss
Normal file
6
raw/scss/_variables.scss
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
$bg: #303030;
|
||||||
|
$darker: #212121;
|
||||||
|
|
||||||
|
$primary: #3949ab;
|
||||||
|
$second: #ff0089;
|
||||||
|
$active: #5ff507;
|
|
@ -1,3 +1,6 @@
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +15,10 @@ html, body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
background-color: #000000;
|
background-color: $bg;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
|
@ -38,7 +44,10 @@ div {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@import "scrollbar";
|
||||||
@import "gui";
|
@import "gui";
|
||||||
@import "input";
|
@import "input";
|
||||||
@import "controls";
|
@import "controls";
|
||||||
@import "playlist";
|
@import "playlist";
|
||||||
|
@import "modal";
|
||||||
|
@import "notification";
|
|
@ -4,15 +4,23 @@
|
||||||
// to pick one. mediump is a good default. It means "medium precision"
|
// to pick one. mediump is a good default. It means "medium precision"
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
in vec3 pos;
|
in vec4 pos;
|
||||||
|
in vec3 v_surfaceToLight;
|
||||||
uniform vec4 u_color;
|
uniform vec4 u_color;
|
||||||
|
|
||||||
out vec4 outColor;
|
out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 color = pos.xyz;
|
vec4 fragNormal = normalize(pos);
|
||||||
color.z = color.z + 1.0;
|
float u_light = 0.3;
|
||||||
color.z = color.z / 2.0;
|
float light = max(dot(fragNormal.xyz, normalize(v_surfaceToLight).xyz), u_light);
|
||||||
color.z = color.z * 255.0;
|
vec3 baseColor = vec3(0, 0, 1);
|
||||||
outColor = vec4(color, 1.0);
|
vec3 maxColor = vec3(1, 0, 0);
|
||||||
|
float y = pos.z;
|
||||||
|
if (y < 0.0) {
|
||||||
|
y = y * -1.0;
|
||||||
|
}
|
||||||
|
vec3 color = mix(baseColor, maxColor, y);
|
||||||
|
outColor = vec4(color, 1.0);
|
||||||
|
outColor.rgb *= light;
|
||||||
}
|
}
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
in vec3 a_position;
|
in vec3 a_position;
|
||||||
uniform mat4 u_matrix;
|
uniform mat4 u_matrix;
|
||||||
|
uniform vec3 u_lightPos;
|
||||||
|
|
||||||
out vec3 pos;
|
out vec4 pos;
|
||||||
|
out vec3 v_surfaceToLight;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// convert the position from pixels to 0.0 to 1.0
|
pos = u_matrix * vec4(a_position, 1);
|
||||||
vec4 scale = vec4(a_position, 1) * u_matrix;
|
gl_Position = pos;
|
||||||
scale.y = scale.y * 0.85;
|
v_surfaceToLight = u_lightPos - pos.xyz;
|
||||||
gl_Position = scale;
|
|
||||||
pos = a_position;
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue