modern/js/loader.js
2021-01-17 17:17:19 +01:00

383 lines
9.6 KiB
JavaScript
Executable File

import {
Vector2,
Geometry,
Mesh,
BufferGeometry,
LoadingManager,
JSONLoader,
TextureLoader,
MeshBasicMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
AmbientLight,
RepeatWrapping,
EquirectangularReflectionMapping
} from "./three_modules";
var loadingtextFrame = document.getElementById("loadingtext-frame");
function outputLog(log) {
loadingtextFrame.innerHTML = log;
}
function finishedLoading() {
loadingtextFrame.classList.add("loadingtextframe-out");
window.setTimeout(function () {
loadingtextFrame.remove();
}, 500);
}
const Lazyloader = (function () {
"use strict";
let stack = [];
let loader = new TextureLoader();
let started = false;
const loadAll = () => {
if (!started && stack.length > 0) {
let obj = stack[0];
stack.splice(0, 1);
loader.load(obj.url, (tex) => {
if (obj.scale !== 1) {
tex.repeat.set(obj.scale, obj.scale);
tex.wrapT = tex.wrapS = RepeatWrapping;
}
obj.material[obj.texture] = tex;
requestAnimationFrame(loadAll);
});
}
};
return {
add: function (url, texture, material, scale) {
stack.push({
url: url,
material: material,
texture: texture,
scale: scale || 1
});
},
start: loadAll
};
})();
class cLoader {
constructor(scene, callback) {
"use strict";
this.callback = callback;
this.scene = scene;
this.manager = new LoadingManager();
this.texloader = new TextureLoader(this.manager);
this.jsonloader = new JSONLoader(this.manager);
this.manager.onProgress = function (item) {
outputLog("Loading: " + item.replace("./data/", ""));
};
this.manager.onLoad = function () {
scene.updateMatrixWorld();
finishedLoading();
var ambientLight = new AmbientLight(0xffffff, 1.1);
scene.add(ambientLight);
};
}
}
cLoader.prototype.final = function () {
"use strict";
setTimeout(Lazyloader.start, 500);
this.callback();
};
cLoader.prototype.load = function (jsonpath, callback) {
"use strict";
outputLog("Loading Scene Config");
//Load the entire JSON File
this.callback = callback;
fetch(jsonpath)
.then(response => {
return response.json();
})
.then(json => {
this.json = json;
})
.then(() => {
fetch("./data/" + this.json.name + "/" + this.json.name + "_objects.json")
.then(response => {
return response.json();
})
.then(json => {
this.objects = json;
this.createScene();
});
});
};
cLoader.prototype.looper = (function () {
"use strict";
let looperCount = 0;
return function (array, callback, finished) {
array.forEach((item, index, array) => {
callback(item, () => {
looperCount++;
if (looperCount === array.length) {
looperCount = 0;
finished();
}
});
});
}
})();
cLoader.prototype.createScene = function () {
"use strict";
this.name = this.json.name;
this.scene.name = this.name;
let hdris = {};
let materialArray = [];
let materials = {};
let staticmeshes = [];
let staticMesh = new Geometry();
const mergingMeshes = (item, callback) => {
staticMesh.merge(item.mesh, item.matrix, item.materialIndex);
callback();
};
const buildMaterial = (material, callback) => {
let _material;
//Creating the basic material
switch (material.type) {
case "basic":
_material = new MeshBasicMaterial();
break;
case "physical":
_material = new MeshPhysicalMaterial();
break;
default:
_material = new MeshStandardMaterial();
}
//Go through all properties of the material
//and assign it to the new _material created above
for (var key in material) {
//Filter out Properties that arent values or textures
if (key === "type" || key === "scale") {
//Do nothing, type is set above, scale is set below
} else if (key === "shading") {
_material.flatShading = true;
}
//Filter out envMap property
else if (key === "envMap") {
_material.envMap = hdris[material.envMap];
}
//Filter out the color attribute
else if (key === "color") {
_material.color.setHex(material[key]);
} else if (key === "normalScale") {
_material.normalScale = new Vector2(material[key][0], material[key][1]);
}
//If the property is a texture
else if (isNaN(material[key])) {
_material[key] = this.texloader.load("./data/" + this.name + "/textures/small/" + material[key]);
if (material.scale && key !== "lightMap") {
_material[key].repeat.set(material.scale, material.scale);
_material[key].wrapT = _material[key].wrapS = RepeatWrapping;
Lazyloader.add("./data/" + this.name + "/textures/" + material[key], key, _material, material.scale);
} else {
Lazyloader.add("./data/" + this.name + "/textures/" + material[key], key, _material);
}
}
//If the property is a value
else {
_material[key] = material[key];
}
}
callback(_material);
};
const buildGeometry = (item, callback) => {
if (!this.json.materials[item.material]) {
console.error("Material for " + item.name.toUpperCase() + " is missing");
}
let geometry = this.jsonloader.parse(this.objects[item.name]).geometry;
geometry.computeBoundingBox();
if (item.type === "static") {
if (item.size) {
geometry.scale(item.size);
}
if (item.rot) {
geometry.rotateX(item.rot[0] * Math.PI / 180);
geometry.rotateY(item.rot[1] * Math.PI / 180);
geometry.rotateZ(item.rot[2] * Math.PI / 180);
}
if (item.pos) {
geometry.translate(item.pos[0], item.pos[1], item.pos[2]);
}
}
if (materials[item.material] === undefined) {
buildMaterial(this.json.materials[item.material], function (material) {
material.name = item.material;
buildMesh(item, geometry, material, callback)
});
} else {
buildMesh(item, geometry, materials[item.material], callback)
}
};
const buildMesh = (item, geometry, material, callback) => {
switch (item.type) {
case "static":
if (!materials[item.material]) {
materialArray.push(material);
materials[item.material] = materialArray.length - 1;
staticmeshes.push({
"name": item.name,
"mesh": geometry,
"materialIndex": materialArray.length - 1
});
} else {
staticmeshes.push({
"name": item.name,
"mesh": geometry,
"materialIndex": materials[item.material]
});
}
break;
case "instanced":
for (let i = 0; i < item.duplicates.length; i++) {
let mesh = new Mesh(geometry, material);
mesh.name = item.name;
if (item.duplicates[i].pos) {
mesh.position.set(item.duplicates[i].pos[0], item.duplicates[i].pos[1], item.duplicates[i].pos[2]);
}
if (item.duplicates[i].size) {
mesh.scale.set(item.duplicates[i].size, item.duplicates[i].size, item.duplicates[i].size);
}
if (item.duplicates[i].rot) {
mesh.rotation.set(item.duplicates[i].rot[0] * Math.PI / 180, item.duplicates[i].rot[1] * Math.PI / 180, item.duplicates[i].rot[2] * Math.PI / 180);
}
this.scene.add(mesh);
}
break;
default:
let mesh = new Mesh(geometry, material);
mesh.name = item.name;
if (item.pos) {
mesh.position.set(item.pos[0], item.pos[1], item.pos[2]);
}
if (item.size) {
mesh.scale.set(item.size, item.size, item.size);
}
if (item.rot) {
mesh.rotation.set(item.rot[0] * Math.PI / 180, item.rot[1] * Math.PI / 180, item.rot[2] * Math.PI / 180);
}
if (item.fpos) {
mesh.userData.fpos = item.fpos;
}
if (item.type === "clickable") {
mesh.userData.clickable = true;
}
if (item.camAngle) {
mesh.userData.camAngle = item.camAngle;
}
if (item.text) {
mesh.userData.text = item.text;
}
this.scene.add(mesh);
break;
}
callback();
};
const loadHdri = (item, callback) => {
this.texloader.load(
"./data/" + this.name + "/hdris/" + item.path,
function (texture) {
texture.mapping = EquirectangularReflectionMapping;
hdris[item.name] = texture;
callback();
}
);
};
//Loops through the hdris, loading every single one
//and setting it as a new child of the hdris variable
//when finished runs the load meshes function
this.looper(this.json.hdris, loadHdri, () => {
//Loop through the objects, create a new material if panorama_nature
//exist for the mesh. If the mesh is static put it in the staticmeshes array
//else just add it to the scene
this.looper(this.json.objects, buildGeometry, () => {
//Merge the meshes in the static meshes array
this.looper(staticmeshes, mergingMeshes, () => {
//Convert to Buffergeometry
staticMesh.computeVertexNormals();
let tempGeometry = new BufferGeometry().fromGeometry(staticMesh);
//Create mesh from the geometry
let tempMesh = new Mesh(tempGeometry, materialArray);
tempMesh.name = "staticMesh";
tempMesh.userData.clickable = false;
this.scene.add(tempMesh);
this.final();
});
});
});
};
export default cLoader;