mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-01-15 07:21:07 +00:00
339 lines
10 KiB
JavaScript
339 lines
10 KiB
JavaScript
import Texture from './texture';
|
|
import { enums, glFilter, glTextureFmt } from './enums';
|
|
import { isPow2 } from './misc';
|
|
|
|
export default class TextureCube extends Texture {
|
|
/**
|
|
* @constructor
|
|
* @param {Device} device
|
|
* @param {Object} options
|
|
* @param {Array} options.images
|
|
* @param {Boolean} options.genMipmaps
|
|
* @param {Number} options.width
|
|
* @param {Number} options.height
|
|
* @param {TEXTURE_FMT_*} options.format
|
|
* @param {Number} options.anisotropy
|
|
* @param {FILTER_*} options.minFilter
|
|
* @param {FILTER_*} options.magFilter
|
|
* @param {FILTER_*} options.mipFilter
|
|
* @param {WRAP_*} options.wrapS
|
|
* @param {WRAP_*} options.wrapT
|
|
* @param {WRAP_*} options.wrapR
|
|
* @param {Boolean} options.flipY
|
|
* @param {Boolean} options.premultiplyAlpha
|
|
*/
|
|
constructor(device, options) {
|
|
super(device);
|
|
let gl = this._device._gl;
|
|
this._target = gl.TEXTURE_CUBE_MAP;
|
|
this._glID = gl.createTexture();
|
|
this.update(options);
|
|
}
|
|
|
|
/**
|
|
* @method update
|
|
* @param {Object} options
|
|
* @param {Array} options.images
|
|
* @param {Boolean} options.genMipmaps
|
|
* @param {Number} options.width
|
|
* @param {Number} options.height
|
|
* @param {TEXTURE_FMT_*} options.format
|
|
* @param {Number} options.anisotropy
|
|
* @param {FILTER_*} options.minFilter
|
|
* @param {FILTER_*} options.magFilter
|
|
* @param {FILTER_*} options.mipFilter
|
|
* @param {WRAP_*} options.wrapS
|
|
* @param {WRAP_*} options.wrapT
|
|
* @param {WRAP_*} options.wrapR
|
|
* @param {Boolean} options.flipY
|
|
* @param {Boolean} options.premultiplyAlpha
|
|
*/
|
|
update(options) {
|
|
let gl = this._device._gl;
|
|
let genMipmaps = this._genMipmaps;
|
|
|
|
if (options) {
|
|
if (options.width !== undefined) {
|
|
this._width = options.width;
|
|
}
|
|
if (options.height !== undefined) {
|
|
this._height = options.height;
|
|
}
|
|
if (options.anisotropy !== undefined) {
|
|
this._anisotropy = options.anisotropy;
|
|
}
|
|
if (options.minFilter !== undefined) {
|
|
this._minFilter = options.minFilter;
|
|
}
|
|
if (options.magFilter !== undefined) {
|
|
this._magFilter = options.magFilter;
|
|
}
|
|
if (options.mipFilter !== undefined) {
|
|
this._mipFilter = options.mipFilter;
|
|
}
|
|
if (options.wrapS !== undefined) {
|
|
this._wrapS = options.wrapS;
|
|
}
|
|
if (options.wrapT !== undefined) {
|
|
this._wrapT = options.wrapT;
|
|
}
|
|
// wrapR available in webgl2
|
|
// if (options.wrapR !== undefined) {
|
|
// this._wrapR = options.wrapR;
|
|
// }
|
|
if (options.format !== undefined) {
|
|
this._format = options.format;
|
|
this._compressed =
|
|
(this._format >= enums.TEXTURE_FMT_RGB_DXT1 && this._format <= enums.TEXTURE_FMT_RGBA_PVRTC_4BPPV1) ||
|
|
(this._format >= enums.TEXTURE_FMT_RGB_ETC2 && this._format <= enums.TEXTURE_FMT_RGBA_ETC2)
|
|
;
|
|
}
|
|
|
|
// check if generate mipmap
|
|
if (options.genMipmaps !== undefined) {
|
|
this._genMipmaps = options.genMipmaps;
|
|
genMipmaps = options.genMipmaps;
|
|
}
|
|
|
|
if (options.images !== undefined) {
|
|
if (options.images.length > 1) {
|
|
genMipmaps = false;
|
|
if (options.width !== options.height) {
|
|
console.warn('texture-cube width and height should be identical.');
|
|
}
|
|
if (options.width >> (options.images.length - 1) !== 1) {
|
|
console.error('texture-cube mipmap is invalid. please set mipmap as 1x1, 2x2, 4x4 ... nxn');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// NOTE: get pot after this._width, this._height has been assigned.
|
|
let pot = isPow2(this._width) && isPow2(this._height);
|
|
if (!pot) {
|
|
genMipmaps = false;
|
|
}
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
|
|
if (options.images !== undefined && options.images.length > 0) {
|
|
this._setMipmap(options.images, options.flipY, options.premultiplyAlpha);
|
|
if (options.images.length > 1) this._genMipmaps = true;
|
|
}
|
|
if (genMipmaps) {
|
|
gl.hint(gl.GENERATE_MIPMAP_HINT, gl.NICEST);
|
|
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
this._genMipmaps = true;
|
|
}
|
|
|
|
this._setTexInfo();
|
|
|
|
this._device._restoreTexture(0);
|
|
}
|
|
|
|
/**
|
|
* @method updateSubImage
|
|
* @param {Object} options
|
|
* @param {Number} options.x
|
|
* @param {Number} options.y
|
|
* @param {Number} options.width
|
|
* @param {Number} options.height
|
|
* @param {Number} options.level
|
|
* @param {Number} options.faceIndex
|
|
* @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
|
|
* @param {Boolean} options.flipY
|
|
* @param {Boolean} options.premultiplyAlpha
|
|
*/
|
|
updateSubImage(options) {
|
|
let gl = this._device._gl;
|
|
let glFmt = glTextureFmt(this._format);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
|
|
this._setSubImage(glFmt, options);
|
|
|
|
this._device._restoreTexture(0);
|
|
}
|
|
|
|
/**
|
|
* @method updateImage
|
|
* @param {Object} options
|
|
* @param {Number} options.width
|
|
* @param {Number} options.height
|
|
* @param {Number} options.level
|
|
* @param {Number} options.faceIndex
|
|
* @param {HTMLCanvasElement | HTMLImageElement | HTMLVideoElement | ArrayBufferView} options.image
|
|
* @param {Boolean} options.flipY
|
|
* @param {Boolean} options.premultiplyAlpha
|
|
*/
|
|
updateImage(options) {
|
|
let gl = this._device._gl;
|
|
let glFmt = glTextureFmt(this._format);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_CUBE_MAP, this._glID);
|
|
this._setImage(glFmt, options);
|
|
this._device._restoreTexture(0);
|
|
}
|
|
|
|
_setSubImage(glFmt, options) {
|
|
let gl = this._device._gl;
|
|
let flipY = options.flipY;
|
|
let premultiplyAlpha = options.premultiplyAlpha;
|
|
let faceIndex = options.faceIndex;
|
|
let img = options.image;
|
|
|
|
if (flipY === undefined) {
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
} else {
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
|
|
}
|
|
|
|
if (premultiplyAlpha === undefined) {
|
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
} else {
|
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
|
|
}
|
|
|
|
if (img && !ArrayBuffer.isView(img) && !(img instanceof ArrayBuffer)) {
|
|
gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, options.level, options.x, options.y, glFmt.format, glFmt.pixelType, img);
|
|
} else {
|
|
if (this._compressed) {
|
|
gl.compressedTexSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
|
|
options.level,
|
|
options.x,
|
|
options.y,
|
|
options.width,
|
|
options.height,
|
|
glFmt.format,
|
|
img
|
|
);
|
|
} else {
|
|
gl.texSubImage2D(
|
|
gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
|
|
options.level,
|
|
options.x,
|
|
options.y,
|
|
options.width,
|
|
options.height,
|
|
glFmt.format,
|
|
glFmt.pixelType,
|
|
img
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
_setImage(glFmt, options) {
|
|
let gl = this._device._gl;
|
|
let flipY = options.flipY;
|
|
let premultiplyAlpha = options.premultiplyAlpha;
|
|
let faceIndex = options.faceIndex;
|
|
let img = options.image;
|
|
|
|
if (flipY === undefined) {
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
} else {
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
|
|
}
|
|
|
|
if (premultiplyAlpha === undefined) {
|
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
} else {
|
|
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
|
|
}
|
|
if (img && !ArrayBuffer.isView(img) && !(img instanceof ArrayBuffer)) {
|
|
gl.texImage2D(
|
|
gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
|
|
options.level,
|
|
glFmt.internalFormat,
|
|
glFmt.format,
|
|
glFmt.pixelType,
|
|
img
|
|
);
|
|
} else {
|
|
if (this._compressed) {
|
|
gl.compressedTexImage2D(
|
|
gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
|
|
options.level,
|
|
glFmt.internalFormat,
|
|
options.width,
|
|
options.height,
|
|
0,
|
|
img
|
|
);
|
|
} else {
|
|
gl.texImage2D(
|
|
gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
|
|
options.level,
|
|
glFmt.internalFormat,
|
|
options.width,
|
|
options.height,
|
|
0,
|
|
glFmt.format,
|
|
glFmt.pixelType,
|
|
img
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// levelImages = [imagePosX, imageNegX, imagePosY, imageNegY, imagePosZ, imageNegz]
|
|
// images = [levelImages0, levelImages1, ...]
|
|
_setMipmap(images, flipY, premultiplyAlpha) {
|
|
let glFmt = glTextureFmt(this._format);
|
|
let options = {
|
|
width: this._width,
|
|
height: this._height,
|
|
faceIndex: 0,
|
|
flipY: flipY,
|
|
premultiplyAlpha: premultiplyAlpha,
|
|
level: 0,
|
|
image: null
|
|
};
|
|
|
|
for (let i = 0; i < images.length; ++i) {
|
|
let levelImages = images[i];
|
|
options.level = i;
|
|
options.width = this._width >> i;
|
|
options.height = this._height >> i;
|
|
|
|
for (let face = 0; face < 6; ++face) {
|
|
options.faceIndex = face;
|
|
options.image = levelImages[face];
|
|
this._setImage(glFmt, options);
|
|
}
|
|
}
|
|
}
|
|
|
|
_setTexInfo() {
|
|
let gl = this._device._gl;
|
|
let pot = isPow2(this._width) && isPow2(this._height);
|
|
|
|
// WebGL1 doesn't support all wrap modes with NPOT textures
|
|
if (!pot && (this._wrapS !== enums.WRAP_CLAMP || this._wrapT !== enums.WRAP_CLAMP)) {
|
|
console.warn('WebGL1 doesn\'t support all wrap modes with NPOT textures');
|
|
this._wrapS = enums.WRAP_CLAMP;
|
|
this._wrapT = enums.WRAP_CLAMP;
|
|
}
|
|
|
|
let mipFilter = this._genMipmaps ? this._mipFilter : -1;
|
|
if (!pot && mipFilter !== -1) {
|
|
console.warn('NPOT textures do not support mipmap filter');
|
|
mipFilter = -1;
|
|
}
|
|
|
|
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, glFilter(gl, this._minFilter, mipFilter));
|
|
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, glFilter(gl, this._magFilter, -1));
|
|
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, this._wrapS);
|
|
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, this._wrapT);
|
|
// wrapR available in webgl2
|
|
// gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, this._wrapR);
|
|
|
|
let ext = this._device.ext('EXT_texture_filter_anisotropic');
|
|
if (ext) {
|
|
gl.texParameteri(gl.TEXTURE_CUBE_MAP, ext.TEXTURE_MAX_ANISOTROPY_EXT, this._anisotropy);
|
|
}
|
|
}
|
|
}
|