This commit is contained in:
Maurice Grönwoldt 2020-08-08 21:58:15 +02:00
parent 07b35b9667
commit 4c4afe3bdf
29 changed files with 595 additions and 139 deletions

View file

@ -16,10 +16,12 @@ const config = {
src: [ src: [
basePath + 'utils.js', basePath + 'utils.js',
basePath + 'gl/glUtils.js', basePath + 'gl/glUtils.js',
basePath + 'gl/Camera.js',
basePath + 'template.js', basePath + 'template.js',
basePath + 'gl/handler.js', basePath + 'gl/handler.js',
basePath + 'audio.js', basePath + 'audio.js',
basePath + 'FileHandler.js', basePath + 'FileHandler.js',
basePath + 'FetchHandler.js',
basePath + 'playerConfigHandler.js', basePath + 'playerConfigHandler.js',
basePath + 'player.js', basePath + 'player.js',
basePath + 'gui.js', basePath + 'gui.js',
@ -42,7 +44,7 @@ function build() {
.pipe(concat('scripts.js')) .pipe(concat('scripts.js'))
.pipe(gulp.dest(config.dest)) .pipe(gulp.dest(config.dest))
.pipe(rename('scripts.min.js')) .pipe(rename('scripts.min.js'))
.pipe(terser()) .pipe(terser().on('error', console.error))
.pipe(gulp.dest(config.dest)); .pipe(gulp.dest(config.dest));
} }

0
empty.txt Normal file
View file

BIN
favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
favicon/apple-touch-icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
favicon/favicon-16x16.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

BIN
favicon/favicon-32x32.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

BIN
favicon/mstile-150x150.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

1
favicon/safari-pinned-tab.svg Executable file
View file

@ -0,0 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="893.333" height="893.333" viewBox="0 0 670.000000 670.000000"><path d="M48 256.8c0 .4 10.7 23.9 23.9 52.2 13.1 28.3 25.5 55.1 27.5 59.5l3.7 7.9 5.8-12.7 5.9-12.7L93 303.7l-21.9-47.2-11.5-.3c-6.4-.1-11.6.1-11.6.6zM178.2 262.2c-4.6 10-42.4 91.1-53.8 115.5L114 399.8l5.7 12.4c3.1 6.7 5.8 12.5 5.9 12.7.2.2 1.6-2.3 3.1-5.5 1.4-3.2 18.8-40.6 38.6-82.9 19.7-42.4 36.1-77.8 36.4-78.8.5-1.5-.5-1.7-11.1-1.7H181l-2.8 6.2zM255 257.9c-8.2 2.6-11.8 4.8-18.3 10.9-10.9 10.4-15.2 21.4-14.5 37.1.3 8.6.7 10.5 4.1 17.4 6.5 13.7 18.8 23.5 33.5 26.6 2.9.6 9.5 1.1 14.6 1.1 11.4 0 17.1 1.8 22.6 7.2 5.7 5.4 8 10.8 8 18.8 0 11.1-5.4 19.5-15.5 24.1-3.6 1.7-7.2 1.9-35.7 1.9H222v22h31.3c24.9 0 32.5-.3 37.2-1.5 23.9-6.3 39.7-30 35.7-53.8-2.7-15.8-11.6-27.9-25.6-34.7-9-4.4-16.6-6-29.6-6-9.7 0-14.5-1.7-19.8-7.1-5.8-5.7-7.7-10.4-7.6-18.9 0-9 2.2-14 8.5-19.3 7.4-6.4 9.6-6.7 44.1-6.7H327v-21l-33.2.1c-29.1 0-34 .2-38.8 1.8zM360 266.5V277h113v-21H360v10.5zM495 266.5V277h62.5l5.8-9.9c3.1-5.4 5.7-10.1 5.7-10.5 0-.3-16.6-.6-37-.6h-37v10.5zM575.1 286.3c-9.6 16.6-31.4 54.2-48.3 83.5-16.9 29.4-30.8 53.8-30.8 54.3s24.3.8 60.8.7l60.7-.3v-21l-42.2-.3c-23.3-.1-42.3-.6-42.3-1s.6-1.6 1.4-2.7c.7-1.1 8.7-14.8 17.6-30.5 9-15.7 26.7-46.5 39.5-68.5s23.7-41 24.4-42.3l1.2-2.2h-12.3l-12.3.1-17.4 30.2zM407 361v64h21V297h-21v64z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -2,7 +2,18 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>VS3D-Vis</title> <meta name="viewport"
content="width=device-width, user-scalable=yes, initial-scale=1.0, maximum-scale=5.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="WebAudio Player created by VersusTuneZ"/>
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#3949ab">
<meta name="theme-color" content="#3949ab">
<title>VIS3D</title>
<link rel="stylesheet" href="out/theme/style.css"> <link rel="stylesheet" href="out/theme/style.css">
</head> </head>
<body> <body>

21
manifest.json Executable file
View file

@ -0,0 +1,21 @@
{
"name": "VIS3D by VersusTuneZ",
"short_name": "VIS3D",
"icons": [
{
"src": "/favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/favicon/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#3949ab",
"background_color": "#212121",
"display": "standalone",
"start_url": "/index.html",
"orientation": "landscape-primary"
}

View file

@ -1 +1 @@
[{"group":"","name":"fftSize","showName":"FFT-Size","options":[2048,4096,8192,16384,32768],"value":16384,"type":"select","tooltip":"How Many Items should the FFT Capture and Render","dataType":"int"},{"group":"rotation","name":["X","Y","Z"],"props":["x","y","z"],"type":"slider","max":360,"min":-360,"value":0,"dataType":"int"},{"group":"rotation","name":["X-Inc","Y-Inc","Z-Inc"],"props":["x-inc","y-inc","z-inc"],"type":"slider","max":1,"min":-1,"value":0,"stepSize":0.01,"dataType":"float"},{"group":"","name":"baseColor","showName":"Base Color","type":"color","value":"#0089ff","dataType":"rgb","tooltip":"Base Color!"},{"group":"","name":"gradientToColor","showName":"Second Color","type":"color","value":"#ff0000","dataType":"rgb","tooltip":"Second Color!"}] [{"group":"","name":"fftSize","showName":"FFT-Size","options":[2048,4096,8192,16384,32768],"value":16384,"type":"select","tooltip":"How Many Items should the FFT Capture and Render","dataType":"int"},{"group":"rotation","name":["X","Y","Z"],"props":["x","y","z"],"type":"slider","max":360,"min":-360,"value":0,"dataType":"int"},{"group":"rotation","name":["X-Inc","Y-Inc","Z-Inc"],"props":["x-inc","y-inc","z-inc"],"type":"slider","max":1,"min":-1,"value":0,"stepSize":0.01,"dataType":"float"},{"group":"translate","name":["X","Y","Z"],"props":["x","y","z"],"type":"slider","max":1,"min":-1,"value":0,"stepSize":0.01,"dataType":"float"},{"group":"","name":"fudgeFactor","showName":"Fudge Factor","type":"slider","value":1,"max":2,"min":0,"tooltip":"z to w Fudge","stepSize":0.1,"dataType":"float"},{"group":"","name":"baseColor","showName":"Base Color","type":"color","value":"#0089ff","dataType":"rgb","tooltip":"Base Color!"},{"group":"","name":"gradientToColor","showName":"Second Color","type":"color","value":"#ff0000","dataType":"rgb","tooltip":"Second Color!"}]

View file

@ -479,6 +479,15 @@ class TDUtils {
return dst; return dst;
} }
static projection(width, height, depth) {
return [
2 / width, 0, 0, 0,
0, -2 / height, 0, 0,
0, 0, 2 / depth, 0,
-1, 1, 0, 1,
];
}
static inverse(m, dst) { static inverse(m, dst) {
dst = dst || new Float32Array(16); dst = dst || new Float32Array(16);
let m00 = m[0], let m00 = m[0],
@ -567,42 +576,13 @@ class TDUtils {
static aspectView(aspect) { static aspectView(aspect) {
return [ return [
1 * aspect, 0, 0, 0, 1 / aspect, 0, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1 0, 0, 0, 1
] ]
} }
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;
}
static updateRotate(rotation, def) { static updateRotate(rotation, def) {
let value = vConf.get(rotation, def) + vConf.get(rotation + '-inc', 0) let value = vConf.get(rotation, def) + vConf.get(rotation + '-inc', 0)
if (value > 360) { if (value > 360) {
@ -612,6 +592,149 @@ class TDUtils {
} }
vConf.set(rotation, value); vConf.set(rotation, value);
} }
static makeZToWMatrix(fudgeFactor) {
return [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, fudgeFactor,
0, 0, 0, 1,
];
}
}
class GLHelper {
constructor(program) {
this.matrix = new Float32Array(16);
this.program = program;
}
static uniform4fv(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform4fv(uniform, data);
}
static uniform3fv(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform3fv(uniform, data);
}
static uniform1f(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform1f(uniform, data);
}
rotateX(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.xRotation(deg));
}
rotateY(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.yRotation(deg));
}
rotateZ(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.zRotation(deg));
}
scale(scaling) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.scale(scaling[0], scaling[1], scaling[2]))
}
project(depth) {
depth = depth || (c.width > c.height) ? c.width : c.height;
this.matrix = TDUtils.projection(c.width, c.height, depth)
}
translate(t) {
this.matrix = TDUtils.translate(this.matrix, t[0] || 0, t[1] || 0, t[2] || 0);
}
addFudgeFactor(fudgeFactor) {
this.matrix = TDUtils.multiply(TDUtils.makeZToWMatrix(fudgeFactor), this.matrix);
}
applyMatrix() {
let matrix = gl.getUniformLocation(this.program, "u_matrix");
gl.uniformMatrix4fv(matrix, false, this.matrix);
}
}
class Camera {
constructor() {
this.mouse;
this.rotation = {
x: 0,
y: 0
}
this.lastMouse;
this.mousePressed = false;
this.translate = {
x: 0,
y: 0,
z: 0
}
}
async init() {
this.mouse = {
x: 0,
y: 0
}
window.addEventListener('mousedown', this.mouseDown.bind(this));
window.addEventListener('mouseup', this.mouseUp.bind(this));
window.addEventListener('mousemove', this.mouseMove.bind(this), {passive: true});
eventHandler.addEvent('keys-ArrowUp, keys-ArrowDown, keys-ArrowLeft, keys-ArrowRight, keys-KeyQ, keys-KeyE', this.keyPressed.bind(this));
}
mouseDown() {
this.mousePressed = true;
this.lastMouse = null;
}
mouseUp() {
this.mousePressed = false;
this.lastMouse = null;
}
mouseMove(event) {
if (!this.mousePressed || gui.modal.open) {
return;
}
if (this.lastMouse) {
let mouse = this.mouse,
rotate = this.rotation;
mouse.x += (this.lastMouse.x - event.clientX) * 0.2;
mouse.y += (this.lastMouse.y - event.clientY) * 0.2;
rotate.x = VTUtils.map(mouse.x, -c.width, c.width, 180, -180, false);
rotate.y = VTUtils.map(mouse.y, -c.height, c.height, 180, -180, false);
}
this.lastMouse = {
x: event.clientX,
y: event.clientY
}
}
keyPressed(data) {
switch (data) {
case 'keys-ArrowUp':
this.translate.z += 10;
break;
case 'keys-ArrowDown':
this.translate.z -= 10;
break;
case 'keys-ArrowLeft':
this.translate.x -= 10;
break;
case 'keys-ArrowRight':
this.translate.x += 10;
break;
case 'keys-KeyQ':
this.translate.y += 10;
break;
case 'keys-KeyE':
this.translate.y -= 10;
break;
}
}
} }
class Template { class Template {
constructor() { constructor() {
@ -621,9 +744,7 @@ class Template {
async loadTemplate(name) { async loadTemplate(name) {
let self = this; let self = this;
if (!this.tpl[name]) { if (!this.tpl[name]) {
await fetch(templateDir + name + ".tpl").then((r) => r.text()).then(c => { self.tpl[name] = await FetchHandler.loadFile(templateDir + name + '.tpl', false)
self.tpl[name] = c;
})
} }
} }
@ -651,16 +772,10 @@ class Template {
} }
return d; return d;
} }
parseFromAPI(url, name, cb) {
fetch(url).then((r) => r.json()).then(d => {
cb(this.parseTemplate(name, d))
}).catch(console.error)
}
} }
const templateEx = /\$(.*?)\$/gm; const templateEx = /\$(.*?)\$/gm;
const templateDir = "out/tpl/" const templateDir = "/out/tpl/"
class ShaderHandler { class ShaderHandler {
constructor(gl) { constructor(gl) {
this.gl = gl; this.gl = gl;
@ -682,8 +797,8 @@ class ShaderHandler {
async load(name, url, type) { async load(name, url, type) {
let realName = name + "_" + type; let realName = name + "_" + type;
if (!this.shaders[realName]) { if (!this.shaders[realName]) {
let data = await fetch(url); let data = await FetchHandler.loadFile(url, false);
let shader = this.createShader(await data.text(), type); let shader = this.createShader(data, type);
if (shader) { if (shader) {
this.shaders[realName] = shader; this.shaders[realName] = shader;
} }
@ -733,8 +848,7 @@ class ShaderHandler {
gl.attachShader(pro, this.getShader(shaders[i], gl.FRAGMENT_SHADER)); gl.attachShader(pro, this.getShader(shaders[i], gl.FRAGMENT_SHADER));
} }
gl.linkProgram(pro); gl.linkProgram(pro);
var success = gl.getProgramParameter(pro, gl.LINK_STATUS); if (gl.getProgramParameter(pro, gl.LINK_STATUS)) {
if (success) {
this.programs[name] = pro; this.programs[name] = pro;
return pro; return pro;
} }
@ -883,6 +997,42 @@ class AudioPlayerFile {
return template.parseTemplate('audio-information', tag); return template.parseTemplate('audio-information', tag);
} }
} }
class FetchHandler {
static files = {};
static async loadFiles(array, isJSON) {
let content = [];
for (let i = 0; i < array; i++) {
content.push(await FetchHandler.loadFile(array[i], isJSON));
}
return content;
}
static async loadFile(filename, isJSON) {
filename += '?v=' + version;
let files = FetchHandler.files;
if (files[filename]) {
return files[filename];
}
let data = await FetchHandler.tryFromCache(filename);
if (isJSON) {
data = JSON.parse(data);
}
files[filename] = data;
return data;
}
static async tryFromCache(filename) {
if (caches) {
let cache = await caches.open('vis3d-pwa-1');
let data = await cache.match(filename);
if (!data) {
data = await fetch(filename);
}
return await data.text();
}
}
}
class PlayerConfigHandler { class PlayerConfigHandler {
async init() { async init() {
await template.loadArray([ await template.loadArray([
@ -984,7 +1134,7 @@ class VisualConfig {
let tem = VisualConfig.visualTemplates; let tem = VisualConfig.visualTemplates;
if (!tem[name]) { if (!tem[name]) {
//load config and save it //load config and save it
tem[name] = await fetch('/out/gui/' + name + ".json").then((res) => res.json()); tem[name] = await FetchHandler.loadFile('/out/gui/' + name + ".json", true);
} }
return tem[name]; return tem[name];
} }
@ -1020,6 +1170,16 @@ class Player {
window.dispatchEvent(new CustomEvent('playSong')); window.dispatchEvent(new CustomEvent('playSong'));
} }
stop() {
if (!audioHandler.lastSong) {
return;
}
let audioFile = audioHandler.audioFile;
audioFile.pause();
audioFile.currentTime = 0;
window.dispatchEvent(new CustomEvent('playSong'));
}
playByID(number) { playByID(number) {
this.playlist.index = number; this.playlist.index = number;
let next = this.playlist.getCurrent(); let next = this.playlist.getCurrent();
@ -1378,6 +1538,7 @@ class Modal {
let self = this; let self = this;
self.currentModal = ''; self.currentModal = '';
self.modal = $('#modal'); self.modal = $('#modal');
self.open = false;
self.parent = self.modal.parentNode; self.parent = self.modal.parentNode;
self.modal.addDelegatedEventListener('click', 'header .close', this.closeModal.bind(this)); self.modal.addDelegatedEventListener('click', 'header .close', this.closeModal.bind(this));
} }
@ -1411,6 +1572,7 @@ class Modal {
closeModal() { closeModal() {
this.parent.addClass("hide") this.parent.addClass("hide")
this.open = false;
} }
isCurrent(title) { isCurrent(title) {
@ -1419,6 +1581,7 @@ class Modal {
showModal() { showModal() {
this.parent.removeClass("hide") this.parent.removeClass("hide")
this.open = true;
} }
} }
class Visual { class Visual {
@ -1843,13 +2006,15 @@ class Wave2D extends Visual {
updateData() { updateData() {
let data = audioHandler.getFloatArray(); let data = audioHandler.getFloatArray();
let add = 2 / data.length, let add = c.width / data.length,
x = -1; x = 0,
y = c.height / 2,
goTrough = y / 2;
let outerLoop = 0; let outerLoop = 0;
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
//first //first
this.data[outerLoop] = x; this.data[outerLoop] = x;
this.data[outerLoop + 1] = data[i]; this.data[outerLoop + 1] = y + (data[i] * goTrough);
this.data[outerLoop + 2] = data[i]; this.data[outerLoop + 2] = data[i];
outerLoop += 3; outerLoop += 3;
x += add; x += add;
@ -1872,17 +2037,18 @@ class Wave2D extends Visual {
} }
rotate(program) { rotate(program) {
let matrix = [ let glHelper = new GLHelper(program);
1, 0, 0, 0, glHelper.project();
0, 0.6, 0, 0, glHelper.addFudgeFactor(vConf.get("fudgeFactor", 1));
0, 0, 1, 0, glHelper.translate([
0, 0, 0, 1 camera.translate.x,
] camera.translate.y,
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(vConf.get("rotation-x", 0))); camera.translate.z
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(vConf.get("rotation-y", 0))); ]);
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(vConf.get("rotation-z", 0))); glHelper.rotateX(camera.mouse.x);
let rotate = gl.getUniformLocation(program, "u_matrix"); glHelper.rotateY(camera.mouse.y);
gl.uniformMatrix4fv(rotate, false, matrix); glHelper.rotateZ(vConf.get("rotation-z", 0));
glHelper.applyMatrix();
} }
setup() { setup() {
@ -1896,9 +2062,8 @@ class Wave2D extends Visual {
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"); //GLHelper.uniform1f(program, "u_fudgeFactor", vConf.get("fudgeFactor", 1));
let lightPos = gl.getUniformLocation(program, "u_lightPos"); GLHelper.uniform3fv(program, "u_lightPos", vConf.get("light", [0, 5, -56]));
gl.uniform3fv(lightPos, vConf.get("light", [0, 5, -56]));
} }
afterDraw() { afterDraw() {
@ -2186,7 +2351,8 @@ class KeyHandler {
media.setActionHandler('play', player.playStop.bind(player)); media.setActionHandler('play', player.playStop.bind(player));
media.setActionHandler('pause', player.playStop.bind(player)); media.setActionHandler('pause', player.playStop.bind(player));
media.setActionHandler('previoustrack', player.prevSong.bind(player)); media.setActionHandler('previoustrack', player.prevSong.bind(player));
media.setActionHandler('nexttrack', player.prevSong.bind(player)); media.setActionHandler('nexttrack', player.nextSong.bind(player));
media.setActionHandler('stop', player.stop.bind(player));
} }
} }
@ -2224,7 +2390,8 @@ class KeyHandler {
if (eventHandler.handleEvent({ if (eventHandler.handleEvent({
data: { data: {
cmd: name cmd: name,
data: name
} }
})) { })) {
event.preventDefault(); event.preventDefault();
@ -2267,9 +2434,11 @@ const shaderHandler = new ShaderHandler(null),
startup = new Startup(), startup = new Startup(),
eventHandler = new EventHandler(), eventHandler = new EventHandler(),
playerConf = new PlayerConfigHandler(), playerConf = new PlayerConfigHandler(),
keyHandler = new KeyHandler(); keyHandler = new KeyHandler(),
version = 1,
camera = new Camera();
let c, gl, cInfo, ctx; let c, gl, cInfo, ctx, sw;
worker.addEventListener('message', e => { worker.addEventListener('message', e => {
if (e.data.status === 'startup') { if (e.data.status === 'startup') {
@ -2286,6 +2455,9 @@ window.addEventListener('startupFin', e => {
}) })
async function startUP() { async function startUP() {
if ('serviceWorker' in navigator) {
sw = await navigator.serviceWorker.register('/sw.js');
}
pConf.loadConfigByName('default'); pConf.loadConfigByName('default');
c = $('#c'), c = $('#c'),
gl = c.getContext("webgl2"), gl = c.getContext("webgl2"),
@ -2296,10 +2468,11 @@ async function startUP() {
return false; return false;
} }
shaderHandler.setGL(gl) shaderHandler.setGL(gl)
await shaderHandler.loadArray(["wave", "sphere", "water", "wave2d"], 'shaders/'); await shaderHandler.loadArray(["wave", "sphere", "water", "wave2d"], '/shaders/');
await NotificationHandler.instance.init(); await NotificationHandler.instance.init();
await audioHandler.init(); await audioHandler.init();
await player.init(); await player.init();
await camera.init();
await visual.init(); await visual.init();
await gui.init(); await gui.init();
await imageUploader.init(); await imageUploader.init();

File diff suppressed because one or more lines are too long

View file

@ -52,6 +52,37 @@
"stepSize": 0.01, "stepSize": 0.01,
"dataType": "float" "dataType": "float"
}, },
{
"group": "translate",
"name": [
"X",
"Y",
"Z"
],
"props": [
"x",
"y",
"z"
],
"type": "slider",
"max": 1,
"min": -1,
"value": 0,
"stepSize": 0.01,
"dataType": "float"
},
{
"group": "",
"name": "fudgeFactor",
"showName": "Fudge Factor",
"type": "slider",
"value": 1,
"max": 2,
"min": 0,
"tooltip": "z to w Fudge",
"stepSize": 0.1,
"dataType": "float"
},
{ {
"group": "", "group": "",
"name": "baseColor", "name": "baseColor",

View file

@ -0,0 +1,36 @@
class FetchHandler {
static files = {};
static async loadFiles(array, isJSON) {
let content = [];
for (let i = 0; i < array; i++) {
content.push(await FetchHandler.loadFile(array[i], isJSON));
}
return content;
}
static async loadFile(filename, isJSON) {
filename += '?v=' + version;
let files = FetchHandler.files;
if (files[filename]) {
return files[filename];
}
let data = await FetchHandler.tryFromCache(filename);
if (isJSON) {
data = JSON.parse(data);
}
files[filename] = data;
return data;
}
static async tryFromCache(filename) {
if (caches) {
let cache = await caches.open('vis3d-pwa-1');
let data = await cache.match(filename);
if (!data) {
data = await fetch(filename);
}
return await data.text();
}
}
}

View file

@ -10,9 +10,11 @@ const shaderHandler = new ShaderHandler(null),
startup = new Startup(), startup = new Startup(),
eventHandler = new EventHandler(), eventHandler = new EventHandler(),
playerConf = new PlayerConfigHandler(), playerConf = new PlayerConfigHandler(),
keyHandler = new KeyHandler(); keyHandler = new KeyHandler(),
version = 1,
camera = new Camera();
let c, gl, cInfo, ctx; let c, gl, cInfo, ctx, sw;
worker.addEventListener('message', e => { worker.addEventListener('message', e => {
if (e.data.status === 'startup') { if (e.data.status === 'startup') {
@ -29,6 +31,9 @@ window.addEventListener('startupFin', e => {
}) })
async function startUP() { async function startUP() {
if ('serviceWorker' in navigator) {
sw = await navigator.serviceWorker.register('/sw.js');
}
pConf.loadConfigByName('default'); pConf.loadConfigByName('default');
c = $('#c'), c = $('#c'),
gl = c.getContext("webgl2"), gl = c.getContext("webgl2"),
@ -39,10 +44,11 @@ async function startUP() {
return false; return false;
} }
shaderHandler.setGL(gl) shaderHandler.setGL(gl)
await shaderHandler.loadArray(["wave", "sphere", "water", "wave2d"], 'shaders/'); await shaderHandler.loadArray(["wave", "sphere", "water", "wave2d"], '/shaders/');
await NotificationHandler.instance.init(); await NotificationHandler.instance.init();
await audioHandler.init(); await audioHandler.init();
await player.init(); await player.init();
await camera.init();
await visual.init(); await visual.init();
await gui.init(); await gui.init();
await imageUploader.init(); await imageUploader.init();

View file

@ -0,0 +1,78 @@
class Camera {
constructor() {
this.mouse;
this.rotation = {
x: 0,
y: 0
}
this.lastMouse;
this.mousePressed = false;
this.translate = {
x: 0,
y: 0,
z: 0
}
}
async init() {
this.mouse = {
x: 0,
y: 0
}
window.addEventListener('mousedown', this.mouseDown.bind(this));
window.addEventListener('mouseup', this.mouseUp.bind(this));
window.addEventListener('mousemove', this.mouseMove.bind(this), {passive: true});
eventHandler.addEvent('keys-ArrowUp, keys-ArrowDown, keys-ArrowLeft, keys-ArrowRight, keys-KeyQ, keys-KeyE', this.keyPressed.bind(this));
}
mouseDown() {
this.mousePressed = true;
this.lastMouse = null;
}
mouseUp() {
this.mousePressed = false;
this.lastMouse = null;
}
mouseMove(event) {
if (!this.mousePressed || gui.modal.open) {
return;
}
if (this.lastMouse) {
let mouse = this.mouse,
rotate = this.rotation;
mouse.x += (this.lastMouse.x - event.clientX) * 0.2;
mouse.y += (this.lastMouse.y - event.clientY) * 0.2;
rotate.x = VTUtils.map(mouse.x, -c.width, c.width, 180, -180, false);
rotate.y = VTUtils.map(mouse.y, -c.height, c.height, 180, -180, false);
}
this.lastMouse = {
x: event.clientX,
y: event.clientY
}
}
keyPressed(data) {
switch (data) {
case 'keys-ArrowUp':
this.translate.z += 10;
break;
case 'keys-ArrowDown':
this.translate.z -= 10;
break;
case 'keys-ArrowLeft':
this.translate.x -= 10;
break;
case 'keys-ArrowRight':
this.translate.x += 10;
break;
case 'keys-KeyQ':
this.translate.y += 10;
break;
case 'keys-KeyE':
this.translate.y -= 10;
break;
}
}
}

View file

@ -210,6 +210,15 @@ class TDUtils {
return dst; return dst;
} }
static projection(width, height, depth) {
return [
2 / width, 0, 0, 0,
0, -2 / height, 0, 0,
0, 0, 2 / depth, 0,
-1, 1, 0, 1,
];
}
static inverse(m, dst) { static inverse(m, dst) {
dst = dst || new Float32Array(16); dst = dst || new Float32Array(16);
let m00 = m[0], let m00 = m[0],
@ -298,42 +307,13 @@ class TDUtils {
static aspectView(aspect) { static aspectView(aspect) {
return [ return [
1 * aspect, 0, 0, 0, 1 / aspect, 0, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1 0, 0, 0, 1
] ]
} }
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;
}
static updateRotate(rotation, def) { static updateRotate(rotation, def) {
let value = vConf.get(rotation, def) + vConf.get(rotation + '-inc', 0) let value = vConf.get(rotation, def) + vConf.get(rotation + '-inc', 0)
if (value > 360) { if (value > 360) {
@ -343,4 +323,69 @@ class TDUtils {
} }
vConf.set(rotation, value); vConf.set(rotation, value);
} }
static makeZToWMatrix(fudgeFactor) {
return [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, fudgeFactor,
0, 0, 0, 1,
];
}
}
class GLHelper {
constructor(program) {
this.matrix = new Float32Array(16);
this.program = program;
}
static uniform4fv(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform4fv(uniform, data);
}
static uniform3fv(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform3fv(uniform, data);
}
static uniform1f(program, name, data) {
let uniform = gl.getUniformLocation(program, name);
gl.uniform1f(uniform, data);
}
rotateX(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.xRotation(deg));
}
rotateY(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.yRotation(deg));
}
rotateZ(deg) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.zRotation(deg));
}
scale(scaling) {
this.matrix = TDUtils.multiply(this.matrix, TDUtils.scale(scaling[0], scaling[1], scaling[2]))
}
project(depth) {
depth = depth || (c.width > c.height) ? c.width : c.height;
this.matrix = TDUtils.projection(c.width, c.height, depth)
}
translate(t) {
this.matrix = TDUtils.translate(this.matrix, t[0] || 0, t[1] || 0, t[2] || 0);
}
addFudgeFactor(fudgeFactor) {
this.matrix = TDUtils.multiply(TDUtils.makeZToWMatrix(fudgeFactor), this.matrix);
}
applyMatrix() {
let matrix = gl.getUniformLocation(this.program, "u_matrix");
gl.uniformMatrix4fv(matrix, false, this.matrix);
}
} }

View file

@ -19,8 +19,8 @@ class ShaderHandler {
async load(name, url, type) { async load(name, url, type) {
let realName = name + "_" + type; let realName = name + "_" + type;
if (!this.shaders[realName]) { if (!this.shaders[realName]) {
let data = await fetch(url); let data = await FetchHandler.loadFile(url, false);
let shader = this.createShader(await data.text(), type); let shader = this.createShader(data, type);
if (shader) { if (shader) {
this.shaders[realName] = shader; this.shaders[realName] = shader;
} }
@ -70,8 +70,7 @@ class ShaderHandler {
gl.attachShader(pro, this.getShader(shaders[i], gl.FRAGMENT_SHADER)); gl.attachShader(pro, this.getShader(shaders[i], gl.FRAGMENT_SHADER));
} }
gl.linkProgram(pro); gl.linkProgram(pro);
var success = gl.getProgramParameter(pro, gl.LINK_STATUS); if (gl.getProgramParameter(pro, gl.LINK_STATUS)) {
if (success) {
this.programs[name] = pro; this.programs[name] = pro;
return pro; return pro;
} }

View file

@ -159,6 +159,7 @@ class Modal {
let self = this; let self = this;
self.currentModal = ''; self.currentModal = '';
self.modal = $('#modal'); self.modal = $('#modal');
self.open = false;
self.parent = self.modal.parentNode; self.parent = self.modal.parentNode;
self.modal.addDelegatedEventListener('click', 'header .close', this.closeModal.bind(this)); self.modal.addDelegatedEventListener('click', 'header .close', this.closeModal.bind(this));
} }
@ -192,6 +193,7 @@ class Modal {
closeModal() { closeModal() {
this.parent.addClass("hide") this.parent.addClass("hide")
this.open = false;
} }
isCurrent(title) { isCurrent(title) {
@ -200,5 +202,6 @@ class Modal {
showModal() { showModal() {
this.parent.removeClass("hide") this.parent.removeClass("hide")
this.open = true;
} }
} }

View file

@ -11,7 +11,8 @@ class KeyHandler {
media.setActionHandler('play', player.playStop.bind(player)); media.setActionHandler('play', player.playStop.bind(player));
media.setActionHandler('pause', player.playStop.bind(player)); media.setActionHandler('pause', player.playStop.bind(player));
media.setActionHandler('previoustrack', player.prevSong.bind(player)); media.setActionHandler('previoustrack', player.prevSong.bind(player));
media.setActionHandler('nexttrack', player.prevSong.bind(player)); media.setActionHandler('nexttrack', player.nextSong.bind(player));
media.setActionHandler('stop', player.stop.bind(player));
} }
} }
@ -49,7 +50,8 @@ class KeyHandler {
if (eventHandler.handleEvent({ if (eventHandler.handleEvent({
data: { data: {
cmd: name cmd: name,
data: name
} }
})) { })) {
event.preventDefault(); event.preventDefault();

View file

@ -28,6 +28,16 @@ class Player {
window.dispatchEvent(new CustomEvent('playSong')); window.dispatchEvent(new CustomEvent('playSong'));
} }
stop() {
if (!audioHandler.lastSong) {
return;
}
let audioFile = audioHandler.audioFile;
audioFile.pause();
audioFile.currentTime = 0;
window.dispatchEvent(new CustomEvent('playSong'));
}
playByID(number) { playByID(number) {
this.playlist.index = number; this.playlist.index = number;
let next = this.playlist.getCurrent(); let next = this.playlist.getCurrent();

View file

@ -99,7 +99,7 @@ class VisualConfig {
let tem = VisualConfig.visualTemplates; let tem = VisualConfig.visualTemplates;
if (!tem[name]) { if (!tem[name]) {
//load config and save it //load config and save it
tem[name] = await fetch('/out/gui/' + name + ".json").then((res) => res.json()); tem[name] = await FetchHandler.loadFile('/out/gui/' + name + ".json", true);
} }
return tem[name]; return tem[name];
} }

View file

@ -6,9 +6,7 @@ class Template {
async loadTemplate(name) { async loadTemplate(name) {
let self = this; let self = this;
if (!this.tpl[name]) { if (!this.tpl[name]) {
await fetch(templateDir + name + ".tpl").then((r) => r.text()).then(c => { self.tpl[name] = await FetchHandler.loadFile(templateDir + name + '.tpl', false)
self.tpl[name] = c;
})
} }
} }
@ -36,13 +34,7 @@ class Template {
} }
return d; return d;
} }
parseFromAPI(url, name, cb) {
fetch(url).then((r) => r.json()).then(d => {
cb(this.parseTemplate(name, d))
}).catch(console.error)
}
} }
const templateEx = /\$(.*?)\$/gm; const templateEx = /\$(.*?)\$/gm;
const templateDir = "out/tpl/" const templateDir = "/out/tpl/"

View file

@ -6,13 +6,15 @@ class Wave2D extends Visual {
updateData() { updateData() {
let data = audioHandler.getFloatArray(); let data = audioHandler.getFloatArray();
let add = 2 / data.length, let add = c.width / data.length,
x = -1; x = 0,
y = c.height / 2,
goTrough = y / 2;
let outerLoop = 0; let outerLoop = 0;
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
//first //first
this.data[outerLoop] = x; this.data[outerLoop] = x;
this.data[outerLoop + 1] = data[i]; this.data[outerLoop + 1] = y + (data[i] * goTrough);
this.data[outerLoop + 2] = data[i]; this.data[outerLoop + 2] = data[i];
outerLoop += 3; outerLoop += 3;
x += add; x += add;
@ -35,17 +37,18 @@ class Wave2D extends Visual {
} }
rotate(program) { rotate(program) {
let matrix = [ let glHelper = new GLHelper(program);
1, 0, 0, 0, glHelper.project();
0, 0.6, 0, 0, glHelper.addFudgeFactor(vConf.get("fudgeFactor", 1));
0, 0, 1, 0, glHelper.translate([
0, 0, 0, 1 camera.translate.x,
] camera.translate.y,
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(vConf.get("rotation-x", 0))); camera.translate.z
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(vConf.get("rotation-y", 0))); ]);
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(vConf.get("rotation-z", 0))); glHelper.rotateX(camera.mouse.x);
let rotate = gl.getUniformLocation(program, "u_matrix"); glHelper.rotateY(camera.mouse.y);
gl.uniformMatrix4fv(rotate, false, matrix); glHelper.rotateZ(vConf.get("rotation-z", 0));
glHelper.applyMatrix();
} }
setup() { setup() {
@ -59,9 +62,8 @@ class Wave2D extends Visual {
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"); //GLHelper.uniform1f(program, "u_fudgeFactor", vConf.get("fudgeFactor", 1));
let lightPos = gl.getUniformLocation(program, "u_lightPos"); GLHelper.uniform3fv(program, "u_lightPos", vConf.get("light", [0, 5, -56]));
gl.uniform3fv(lightPos, vConf.get("light", [0, 5, -56]));
} }
afterDraw() { afterDraw() {

View file

@ -2,11 +2,11 @@
in vec3 a_position; in vec3 a_position;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform float u_fudgeFactor;
out vec4 pos; out vec4 pos;
void main() { void main() {
pos = u_matrix * vec4(a_position, 1); pos = u_matrix * vec4(a_position, 1);
pos.y = pos.y * 0.6;
gl_Position = pos; gl_Position = pos;
} }

44
sw.js Normal file
View file

@ -0,0 +1,44 @@
const cacheName = 'vis3d-pwa-1',
FILES_TO_CACHE = [
'/index.html',
'/empty.txt'
];
self.addEventListener('install', function (e) {
e.waitUntil(
caches.open(cacheName).then(function (cache) {
return cache.addAll(FILES_TO_CACHE);
})
);
});
self.addEventListener('fetch', function (event) {
if (event.request.method !== 'GET') return;
event.respondWith(handle.bind(event).call().then(r => {
return r
}))
});
async function handle() {
let event = this,
url = event.request.url;
if (url === self.registration.scope) {
url += 'index.html';
}
const cache = await caches.open(cacheName);
let response = await fetch(url).then((r) => {
return r
}).catch(async err => {
let cachedResponse = await cache.match(url);
if (cachedResponse) {
return cachedResponse;
}
cachedResponse = await cache.match('/empty.txt');
return cachedResponse;
});
if (response) {
await cache.put(event.request, response.clone());
return response;
}
}