UNPKG

@xeokit/xeokit-sdk

Version:

3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision

156 lines (138 loc) 5.02 kB
import {Component} from '../Component.js'; import {RenderState} from '../webgl/RenderState.js'; import {Texture2D} from '../webgl/Texture2D.js'; import {stats} from '../stats.js'; import {ClampToEdgeWrapping, LinearEncoding, LinearFilter, LinearMipmapLinearFilter, sRGBEncoding} from "../constants/constants.js"; function ensureImageSizePowerOfTwo(image) { if (!isPowerOfTwo(image.width) || !isPowerOfTwo(image.height)) { const canvas = document.createElement("canvas"); canvas.width = nextHighestPowerOfTwo(image.width); canvas.height = nextHighestPowerOfTwo(image.height); const ctx = canvas.getContext("2d"); ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height); image = canvas; } return image; } function isPowerOfTwo(x) { return (x & (x - 1)) === 0; } function nextHighestPowerOfTwo(x) { --x; for (let i = 1; i < 32; i <<= 1) { x = x | x >> i; } return x + 1; } /** * @desc A cube texture map. */ class CubeTexture extends Component { /** @private */ get type() { return "CubeTexture"; } /** * @constructor * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. * @param {*} [cfg] Configs * @param {String} [cfg.id] Optional ID for this CubeTexture, unique among all components in the parent scene, generated automatically when omitted. * @param {String[]} [cfg.src=null] Paths to six image files to load into this CubeTexture. * @param {Boolean} [cfg.flipY=false] Flips this CubeTexture's source data along its vertical axis when true. * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. */ constructor(owner, cfg = {}) { super(owner, cfg); const gl = this.scene.canvas.gl; this._state = new RenderState({ texture: new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}), flipY: this._checkFlipY(cfg.minFilter), encoding: this._checkEncoding(cfg.encoding), minFilter: LinearMipmapLinearFilter, magFilter: LinearFilter, wrapS: ClampToEdgeWrapping, wrapT: ClampToEdgeWrapping, mipmaps: true }); this._src = cfg.src; this._images = []; this._loadSrc(cfg.src); stats.memory.textures++; } _checkFlipY(value) { return !!value; } _checkEncoding(value) { value = value || LinearEncoding; if (value !== LinearEncoding && value !== sRGBEncoding) { this.error("Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); value = LinearEncoding; } return value; } _webglContextRestored() { const gl = this.scene.canvas.gl; this._state.texture = null; // if (this._images.length > 0) { // this._state.texture = new xeokit.renderer.Texture2D(gl, gl.TEXTURE_CUBE_MAP); // this._state.texture.setImage(this._images, this._state); // this._state.texture.setProps(this._state); // } else if (this._src) { this._loadSrc(this._src); } } _loadSrc(src) { const self = this; const gl = this.scene.canvas.gl; this._images = []; let loadFailed = false; let numLoaded = 0; for (let i = 0; i < src.length; i++) { const image = new Image(); image.onload = (function () { let _image = image; const index = i; return function () { if (loadFailed) { return; } _image = ensureImageSizePowerOfTwo(_image); self._images[index] = _image; numLoaded++; if (numLoaded === 6) { let texture = self._state.texture; if (!texture) { texture = new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}); self._state.texture = texture; } texture.setImage(self._images, self._state); self.fire("loaded", self._src, false); self.glRedraw(); } }; })(); image.onerror = function () { loadFailed = true; }; image.src = src[i]; } } /** * Destroys this CubeTexture * */ destroy() { super.destroy(); if (this._state.texture) { this._state.texture.destroy(); } stats.memory.textures--; this._state.destroy(); } } export {CubeTexture};