polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
246 lines (245 loc) • 8.76 kB
JavaScript
import {VideoTexture as VideoTexture2} from "three/src/textures/VideoTexture";
import {TextureLoader as TextureLoader2} from "three/src/loaders/TextureLoader";
import {UnsignedByteType} from "three/src/constants";
import {CoreWalker} from "../Walker";
import {BaseCopNodeClass} from "../../engine/nodes/cop/_Base";
import {Poly as Poly2} from "../../engine/Poly";
import {ModuleName} from "../../engine/poly/registers/modules/_BaseRegister";
import {CoreUserAgent} from "../UserAgent";
var Extension;
(function(Extension2) {
Extension2["EXR"] = "exr";
Extension2["BASIS"] = "basis";
Extension2["HDR"] = "hdr";
})(Extension || (Extension = {}));
const CoreTextureLoader2 = class {
constructor(_node, _param) {
this._node = _node;
this._param = _param;
}
async load_texture_from_url_or_op(url) {
let texture = null;
let found_node;
if (url.substring(0, 3) == "op:") {
const node_path = url.substring(3);
found_node = CoreWalker.find_node(this._node, node_path);
if (found_node) {
if (found_node instanceof BaseCopNodeClass) {
const container = await found_node.requestContainer();
texture = container.texture();
} else {
this._node.states.error.set(`found node is not a texture node`);
}
} else {
this._node.states.error.set(`no node found in path '${node_path}'`);
}
} else {
texture = await this.load_url(url);
if (texture) {
if (this._param.options.texture_as_env()) {
} else {
texture = CoreTextureLoader2.set_texture_for_mapping(texture);
}
} else {
this._node.states.error.set(`could not load texture ${url}`);
}
}
if (found_node && this._param.graphPredecessors()[0] != found_node) {
this._param.graphDisconnectPredecessors();
this._param.addGraphInput(found_node);
}
return texture;
}
async load_url(url) {
return new Promise(async (resolve, reject) => {
const ext = CoreTextureLoader2.get_extension(url);
if (url[0] != "h") {
const assets_root = this._node.scene().assets.root();
if (assets_root) {
url = `${assets_root}${url}`;
}
}
if (CoreTextureLoader2.VIDEO_EXTENSIONS.includes(ext)) {
const texture = await this._load_as_video(url);
resolve(texture);
} else {
this.loader_for_ext(ext).then(async (loader) => {
if (loader) {
CoreTextureLoader2.increment_in_progress_loads_count();
await CoreTextureLoader2.wait_for_max_concurrent_loads_queue_freed();
loader.load(url, (texture) => {
CoreTextureLoader2.decrement_in_progress_loads_count();
resolve(texture);
}, void 0, (error) => {
CoreTextureLoader2.decrement_in_progress_loads_count();
Poly2.warn("error", error);
reject();
});
} else {
reject();
}
});
}
});
}
static module_names(ext) {
switch (ext) {
case Extension.EXR:
return [ModuleName.EXRLoader];
case Extension.HDR:
return [ModuleName.RGBELoader];
case Extension.BASIS:
return [ModuleName.BasisTextureLoader];
}
}
async loader_for_ext(ext) {
const ext_lowercase = ext.toLowerCase();
switch (ext_lowercase) {
case Extension.EXR: {
return await this._exr_loader();
}
case Extension.HDR: {
return await this._hdr_loader();
}
case Extension.BASIS: {
return await this._basis_loader();
}
}
return new TextureLoader2();
}
async _exr_loader() {
const module = await Poly2.modulesRegister.module(ModuleName.EXRLoader);
if (module) {
return new module.EXRLoader();
}
}
async _hdr_loader() {
const module = await Poly2.modulesRegister.module(ModuleName.RGBELoader);
if (module) {
const loader = new module.RGBELoader();
loader.setDataType(UnsignedByteType);
return loader;
}
}
async _basis_loader() {
const module = await Poly2.modulesRegister.module(ModuleName.BasisTextureLoader);
if (module) {
const loader = new module.BasisTextureLoader();
loader.setTranscoderPath("/three/js/libs/basis/");
const renderer = await Poly2.renderersController.waitForRenderer();
if (renderer) {
loader.detectSupport(renderer);
} else {
Poly2.warn("texture loader found no renderer for basis texture loader");
}
return loader;
}
}
_load_as_video(url) {
return new Promise((resolve, reject) => {
const video = document.createElement("video");
video.setAttribute("crossOrigin", "anonymous");
video.setAttribute("autoplay", `${true}`);
video.setAttribute("loop", `${true}`);
video.onloadedmetadata = function() {
video.pause();
const texture = new VideoTexture2(video);
resolve(texture);
};
const original_source = document.createElement("source");
const original_ext = CoreTextureLoader2.get_extension(url);
let type = CoreTextureLoader2.VIDEO_SOURCE_TYPE_BY_EXT[original_ext];
type = type || CoreTextureLoader2._default_video_source_type(url);
original_source.setAttribute("type", type);
original_source.setAttribute("src", url);
video.appendChild(original_source);
let secondary_url = url;
if (original_ext == "mp4") {
secondary_url = CoreTextureLoader2.replace_extension(url, "ogv");
} else {
secondary_url = CoreTextureLoader2.replace_extension(url, "mp4");
}
const secondary_source = document.createElement("source");
const secondary_ext = CoreTextureLoader2.get_extension(secondary_url);
type = CoreTextureLoader2.VIDEO_SOURCE_TYPE_BY_EXT[secondary_ext];
type = type || CoreTextureLoader2._default_video_source_type(url);
secondary_source.setAttribute("type", type);
secondary_source.setAttribute("src", url);
video.appendChild(secondary_source);
});
}
static _default_video_source_type(url) {
const ext = this.get_extension(url);
return `video/${ext}`;
}
static pixel_data(texture) {
const img = texture.image;
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const context = canvas.getContext("2d");
if (context) {
context.drawImage(img, 0, 0, img.width, img.height);
return context.getImageData(0, 0, img.width, img.height);
}
}
static get_extension(url) {
const elements = url.split(".");
return elements[elements.length - 1].toLowerCase();
}
static replace_extension(url, new_extension) {
const elements = url.split("?");
const url_without_params = elements[0];
const url_elements = url_without_params.split(".");
url_elements.pop();
url_elements.push(new_extension);
return [url_elements.join("."), elements[1]].join("?");
}
static set_texture_for_mapping(texture) {
return texture;
}
static _init_max_concurrent_loads_count() {
return CoreUserAgent.is_chrome() ? 10 : 4;
}
static _init_concurrent_loads_delay() {
return CoreUserAgent.is_chrome() ? 0 : 10;
}
static override_max_concurrent_loads_count(count) {
this.MAX_CONCURRENT_LOADS_COUNT = count;
}
static increment_in_progress_loads_count() {
this.in_progress_loads_count++;
}
static decrement_in_progress_loads_count() {
this.in_progress_loads_count--;
const queued_resolve = this._queue.pop();
if (queued_resolve) {
const delay = this.CONCURRENT_LOADS_DELAY;
setTimeout(() => {
queued_resolve();
}, delay);
}
}
static async wait_for_max_concurrent_loads_queue_freed() {
if (this.in_progress_loads_count <= this.MAX_CONCURRENT_LOADS_COUNT) {
return;
} else {
return new Promise((resolve) => {
this._queue.push(resolve);
});
}
}
};
export let CoreTextureLoader = CoreTextureLoader2;
CoreTextureLoader.PARAM_DEFAULT = "/examples/textures/uv.jpg";
CoreTextureLoader.PARAM_ENV_DEFAULT = "/examples/textures/piz_compressed.exr";
CoreTextureLoader.VIDEO_EXTENSIONS = ["mp4", "webm", "ogv"];
CoreTextureLoader.VIDEO_SOURCE_TYPE_BY_EXT = {
ogg: 'video/ogg; codecs="theora, vorbis"',
ogv: 'video/ogg; codecs="theora, vorbis"',
mp4: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
};
CoreTextureLoader.MAX_CONCURRENT_LOADS_COUNT = CoreTextureLoader2._init_max_concurrent_loads_count();
CoreTextureLoader.CONCURRENT_LOADS_DELAY = CoreTextureLoader2._init_concurrent_loads_delay();
CoreTextureLoader.in_progress_loads_count = 0;
CoreTextureLoader._queue = [];