Texture.js 11 KB

12345
  1. /*
  2. All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. See https://js.arcgis.com/4.24/esri/copyright.txt for details.
  4. */
  5. import"../../core/has.js";import{isPowerOfTwo as t}from"../../core/mathUtils.js";import{isSome as e,unwrap as i}from"../../core/maybe.js";import{checkWebGLError as r}from"./checkWebGLError.js";import{ContextType as a}from"./context-util.js";import{ResourceType as s,TextureType as o,TextureSamplingMode as n,TextureWrapMode as p,CompressedTextureFormat as h,PixelType as _,PixelFormat as l,SizedPixelFormat as m}from"./enums.js";import d from"./capabilities/isWebGL2Context.js";const c=4;class u{constructor(t,e,i=null){if(this._context=t,this.type="texture",this._glName=null,this._descriptor=void 0,this._samplingModeDirty=!1,this._wrapModeDirty=!1,this._wasImmutablyAllocated=!1,t.instanceCounter.increment(s.Texture,this),this._descriptor={target:o.TEXTURE_2D,samplingMode:n.LINEAR,wrapMode:p.REPEAT,flipped:!1,hasMipmap:!1,isOpaque:!1,unpackAlignment:4,preMultiplyAlpha:!1,isImmutable:!1,...e},t.type!==a.WEBGL2&&(this._descriptor.isImmutable&&(this._descriptor.isImmutable=!1),A(this._descriptor.target)))throw new Error("3D and array textures are not supported in WebGL1");this._descriptor.target===o.TEXTURE_CUBE_MAP?this._setDataCubeMap(i):this.setData(i)}get glName(){return this._glName}get descriptor(){return this._descriptor}get isDirty(){return this._samplingModeDirty||this._wrapModeDirty}dispose(){this._context.gl&&this._glName&&(this._context.unbindTexture(this),this._context.gl.deleteTexture(this._glName),this._glName=null,this._context.instanceCounter.decrement(s.Texture,this))}release(){this.dispose()}resize(t,e){const i=this._descriptor;if(i.width!==t||i.height!==e){if(this._wasImmutablyAllocated)throw new Error("Immutable textures can't be resized!");i.width=t,i.height=e,this._descriptor.target===o.TEXTURE_CUBE_MAP?this._setDataCubeMap(null):this.setData(null)}}_setDataCubeMap(t=null){for(let e=o.TEXTURE_CUBE_MAP_POSITIVE_X;e<=o.TEXTURE_CUBE_MAP_NEGATIVE_Z;e++)this._setData(t,e)}setData(t){this._setData(t)}_setData(t,i){if(!this._context||!this._context.gl)return;const a=this._context.gl;this._glName||(this._glName=a.createTexture()),void 0===t&&(t=null);const s=this._descriptor;i??(i=s.target);const o=A(i);null===t&&(s.width=s.width||c,s.height=s.height||c,o&&(s.depth=s.depth??1));const n=this._context.bindTexture(this,u.TEXTURE_UNIT_FOR_UPDATES);this._context.setActiveTexture(u.TEXTURE_UNIT_FOR_UPDATES),u._validateTexture(this._context,s),this._configurePixelStorage();const p=s.pixelFormat;let h=s.internalFormat?s.internalFormat:this._deriveInternalFormat(p,s.dataType);if(M(t)){let e=t.width,n=t.height;const p=1;t instanceof HTMLVideoElement&&(e=t.videoWidth,n=t.videoHeight),s.width&&s.height,o&&s.depth,s.isImmutable&&!this._wasImmutablyAllocated&&this._texStorage(i,h,s.hasMipmap,e,n,p),this._texImage(i,0,h,e,n,p,t),r(a),s.hasMipmap&&this.generateMipmap(),void 0===s.width&&(s.width=e),void 0===s.height&&(s.height=n),o&&void 0===s.depth&&(s.depth=p)}else{const{width:n,height:p,depth:_}=s;if(null!=n&&null!=p||console.error("Width and height must be specified!"),o&&null==_&&console.error("Depth must be specified!"),s.isImmutable&&!this._wasImmutablyAllocated&&this._texStorage(i,h,s.hasMipmap,n,p,_),a.DEPTH24_STENCIL8&&h===a.DEPTH_STENCIL&&(h=a.DEPTH24_STENCIL8),g(t)){const e=t.levels,r=I(i,n,p,_),o=Math.min(r-1,e.length-1);d(a)?a.texParameteri(s.target,a.TEXTURE_MAX_LEVEL,o):s.hasMipmap=s.hasMipmap&&r===e.length;const l=h;if(!T(l))throw new Error("Attempting to use compressed data with an umcompressed format!");this._forEachMipmapLevel(((t,r,a,s)=>{const o=e[Math.min(t,e.length-1)];this._compressedTexImage(i,t,l,r,a,s,o)}),o)}else e(t)?(this._texImage(i,0,h,n,p,_,t),r(a),s.hasMipmap&&this.generateMipmap()):this._forEachMipmapLevel(((t,e,s,o)=>{this._texImage(i,t,h,e,s,o,null),r(a)}))}u._applySamplingMode(a,this._descriptor),u._applyWrapMode(a,this._descriptor),u._applyAnisotropicFilteringParameters(this._context,this._descriptor),r(a),this._context.bindTexture(n,u.TEXTURE_UNIT_FOR_UPDATES)}updateData(t,e,i,r,a,s){s||console.error("An attempt to use uninitialized data!"),this._glName||console.error("An attempt to update uninitialized texture!");const o=this._context.gl,n=this._descriptor,{pixelFormat:p,internalFormat:h,dataType:_,isImmutable:l,target:m}=n;if(l&&!this._wasImmutablyAllocated)throw new Error("Cannot update immutable texture before allocation!");const d=this._context.bindTexture(this,u.TEXTURE_UNIT_FOR_UPDATES);(e<0||i<0||r>n.width||a>n.height||e+r>n.width||i+a>n.height)&&console.error("An attempt to update out of bounds of the texture!"),this._configurePixelStorage(),M(s)?o.texSubImage2D(m,t,e,i,p,_,s):g(s)?o.compressedTexSubImage2D(m,t,e,i,r,a,h,s.levels[t]):o.texSubImage2D(m,t,e,i,r,a,p,_,s),this._context.bindTexture(d,u.TEXTURE_UNIT_FOR_UPDATES)}updateData3D(t,e,i,r,a,s,o,n){n||console.error("An attempt to use uninitialized data!"),this._glName||console.error("An attempt to update uninitialized texture!");const p=this._context.gl;if(!d(p))throw new Error("3D textures are not supported in WebGL1");const h=this._descriptor,{pixelFormat:_,dataType:l,isImmutable:m,target:c,internalFormat:E}=h;if(m&&!this._wasImmutablyAllocated)throw new Error("Cannot update immutable texture before allocation!");A(c)||console.warn("Attempting to set 3D texture data on a non-3D texture");const T=this._context.bindTexture(this,u.TEXTURE_UNIT_FOR_UPDATES);if(this._context.setActiveTexture(u.TEXTURE_UNIT_FOR_UPDATES),(e<0||i<0||r<0||a>h.width||s>h.height||o>h.depth||e+a>h.width||i+s>h.height||r+o>h.depth)&&console.error("An attempt to update out of bounds of the texture!"),this._configurePixelStorage(),g(n))n=n.levels[t],p.compressedTexSubImage3D(c,t,e,i,r,a,s,o,E,n);else{const h=n;p.texSubImage3D(c,t,e,i,r,a,s,o,_,l,h)}this._context.bindTexture(T,u.TEXTURE_UNIT_FOR_UPDATES)}generateMipmap(){const t=this._descriptor;if(!t.hasMipmap){if(this._wasImmutablyAllocated)throw new Error("Cannot add mipmaps to immutable texture after allocation");t.hasMipmap=!0,this._samplingModeDirty=!0,u._validateTexture(this._context,t)}t.samplingMode===n.LINEAR?(this._samplingModeDirty=!0,t.samplingMode=n.LINEAR_MIPMAP_NEAREST):t.samplingMode===n.NEAREST&&(this._samplingModeDirty=!0,t.samplingMode=n.NEAREST_MIPMAP_NEAREST);const e=this._context.bindTexture(this,u.TEXTURE_UNIT_FOR_UPDATES);this._context.setActiveTexture(u.TEXTURE_UNIT_FOR_UPDATES);this._context.gl.generateMipmap(t.target),this._context.bindTexture(e,u.TEXTURE_UNIT_FOR_UPDATES)}setSamplingMode(t){t!==this._descriptor.samplingMode&&(this._descriptor.samplingMode=t,this._samplingModeDirty=!0)}setWrapMode(t){t!==this._descriptor.wrapMode&&(this._descriptor.wrapMode=t,u._validateTexture(this._context,this._descriptor),this._wrapModeDirty=!0)}applyChanges(){const t=this._context.gl,e=this._descriptor;this._samplingModeDirty&&(u._applySamplingMode(t,e),this._samplingModeDirty=!1),this._wrapModeDirty&&(u._applyWrapMode(t,e),this._wrapModeDirty=!1)}_deriveInternalFormat(t,e){if(this._context.type===a.WEBGL1)return t;switch(e){case _.FLOAT:switch(t){case l.RGBA:return m.RGBA32F;case l.RGB:return m.RGB32F;default:throw new Error("Unable to derive format")}case _.UNSIGNED_BYTE:switch(t){case l.RGBA:return m.RGBA8;case l.RGB:return m.RGB8}default:return t}}_configurePixelStorage(){const t=this._context.gl,{unpackAlignment:e,flipped:i,preMultiplyAlpha:r}=this._descriptor;t.pixelStorei(t.UNPACK_ALIGNMENT,e),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,i?1:0),t.pixelStorei(t.UNPACK_PREMULTIPLY_ALPHA_WEBGL,r?1:0)}_texStorage(t,e,i,r,a,s){const o=this._context.gl;if(!d(o))throw new Error("Immutable textures are not supported in WebGL1");if(!E(e))throw new Error("Immutable textures must have a sized internal format");if(!this._descriptor.isImmutable)return;const n=i?I(t,r,a,s):1;A(t)?o.texStorage3D(t,n,e,r,a,s):o.texStorage2D(t,n,e,r,a),this._wasImmutablyAllocated=!0}_texImage(t,r,s,o,n,p,h){const _=this._context.gl;let l=null;const m=this._context.type===a.WEBGL2,d=A(t),{isImmutable:c,pixelFormat:u,dataType:E}=this._descriptor;if(m&&(l=_),m||!M(h))if(c){if(e(h)){const e=h;d?l.texSubImage3D(t,r,0,0,0,o,n,p,u,E,e):_.texSubImage2D(t,r,0,0,o,n,u,E,e)}}else{const e=i(h);d?l.texImage3D(t,r,s,o,n,p,0,u,E,e):_.texImage2D(t,r,s,o,n,0,u,E,e)}else _.texImage2D(t,0,s,u,E,h)}_compressedTexImage(t,i,r,s,o,n,p){const h=this._context.gl;let _=null;const l=A(t),m=this._descriptor.isImmutable;if(l){if(this._context.type!==a.WEBGL2)throw new Error("3D textures are not supported in WebGL1");_=h}m?e(p)&&(l?_.compressedTexSubImage3D(t,i,0,0,0,s,o,n,r,p):h.compressedTexSubImage2D(t,i,0,0,s,o,r,p)):l?_.compressedTexImage3D(t,i,r,s,o,n,0,p):h.compressedTexImage2D(t,i,r,s,o,0,p)}_forEachMipmapLevel(t,e=1/0){let{width:i,height:r,depth:a,hasMipmap:s,target:n}=this._descriptor;const p=n===o.TEXTURE_3D;for(let o=0;t(o,i,r,a),s&&(1!==i||1!==r||p&&1!==a)&&!(o>=e);++o)i=Math.max(1,i>>1),r=Math.max(1,r>>1),p&&(a=Math.max(1,a>>1))}static _validateTexture(e,i){(i.width<0||i.height<0||i.depth<0)&&console.error("Negative dimension parameters are not allowed!");const r=d(e.gl),a=t(i.width)&&t(i.height);r||!i.isImmutable&&!A(i.target)||console.error("Immutable and 3D-like textures are not supported in WebGL1!"),r||a||("number"==typeof i.wrapMode?i.wrapMode!==p.CLAMP_TO_EDGE&&console.error("Non-power-of-two textures must have a wrap mode of CLAMP_TO_EDGE!"):i.wrapMode.s===p.CLAMP_TO_EDGE&&i.wrapMode.t===p.CLAMP_TO_EDGE||console.error("Non-power-of-two textures must have a wrap mode of CLAMP_TO_EDGE!"),i.hasMipmap&&console.error("Mipmapping requires power-of-two textures!"))}static _applySamplingMode(t,e){let i=e.samplingMode,r=e.samplingMode;i===n.LINEAR_MIPMAP_NEAREST||i===n.LINEAR_MIPMAP_LINEAR?(i=n.LINEAR,e.hasMipmap||(r=n.LINEAR)):i!==n.NEAREST_MIPMAP_NEAREST&&i!==n.NEAREST_MIPMAP_LINEAR||(i=n.NEAREST,e.hasMipmap||(r=n.NEAREST)),t.texParameteri(e.target,t.TEXTURE_MAG_FILTER,i),t.texParameteri(e.target,t.TEXTURE_MIN_FILTER,r)}static _applyWrapMode(t,e){"number"==typeof e.wrapMode?(t.texParameteri(e.target,t.TEXTURE_WRAP_S,e.wrapMode),t.texParameteri(e.target,t.TEXTURE_WRAP_T,e.wrapMode)):(t.texParameteri(e.target,t.TEXTURE_WRAP_S,e.wrapMode.s),t.texParameteri(e.target,t.TEXTURE_WRAP_T,e.wrapMode.t))}static _applyAnisotropicFilteringParameters(t,e){const i=t.capabilities.textureFilterAnisotropic;if(!i)return;t.gl.texParameterf(e.target,i.TEXTURE_MAX_ANISOTROPY,e.maxAnisotropy??1)}}function E(t){return t in m}function T(t){return t in h}function g(t){return e(t)&&"type"in t&&"compressed"===t.type}function x(t){return e(t)&&"byteLength"in t}function M(t){return e(t)&&!g(t)&&!x(t)}function A(t){return t===o.TEXTURE_3D||t===o.TEXTURE_2D_ARRAY}function I(t,e,i,r=1){let a=Math.max(e,i);return t===o.TEXTURE_3D&&(a=Math.max(a,r)),Math.round(Math.log(a)/Math.LN2)+1}u.TEXTURE_UNIT_FOR_UPDATES=0;export{u as Texture};