/** * Base class for all textures like compressed texture, texture2d, texturecube * TODO mapping */ import Base from './core/Base'; import glenum from './core/glenum'; import Cache from './core/Cache'; /** * @constructor * @alias clay.Texture * @extends clay.core.Base */ var Texture = Base.extend( /** @lends clay.Texture# */ { /** * Texture width, readonly when the texture source is image * @type {number} */ width: 512, /** * Texture height, readonly when the texture source is image * @type {number} */ height: 512, /** * Texel data type. * Possible values: * + {@link clay.Texture.UNSIGNED_BYTE} * + {@link clay.Texture.HALF_FLOAT} * + {@link clay.Texture.FLOAT} * + {@link clay.Texture.UNSIGNED_INT_24_8_WEBGL} * + {@link clay.Texture.UNSIGNED_INT} * @type {number} */ type: glenum.UNSIGNED_BYTE, /** * Format of texel data * Possible values: * + {@link clay.Texture.RGBA} * + {@link clay.Texture.DEPTH_COMPONENT} * + {@link clay.Texture.DEPTH_STENCIL} * @type {number} */ format: glenum.RGBA, /** * Texture wrap. Default to be REPEAT. * Possible values: * + {@link clay.Texture.CLAMP_TO_EDGE} * + {@link clay.Texture.REPEAT} * + {@link clay.Texture.MIRRORED_REPEAT} * @type {number} */ wrapS: glenum.REPEAT, /** * Texture wrap. Default to be REPEAT. * Possible values: * + {@link clay.Texture.CLAMP_TO_EDGE} * + {@link clay.Texture.REPEAT} * + {@link clay.Texture.MIRRORED_REPEAT} * @type {number} */ wrapT: glenum.REPEAT, /** * Possible values: * + {@link clay.Texture.NEAREST} * + {@link clay.Texture.LINEAR} * + {@link clay.Texture.NEAREST_MIPMAP_NEAREST} * + {@link clay.Texture.LINEAR_MIPMAP_NEAREST} * + {@link clay.Texture.NEAREST_MIPMAP_LINEAR} * + {@link clay.Texture.LINEAR_MIPMAP_LINEAR} * @type {number} */ minFilter: glenum.LINEAR_MIPMAP_LINEAR, /** * Possible values: * + {@link clay.Texture.NEAREST} * + {@link clay.Texture.LINEAR} * @type {number} */ magFilter: glenum.LINEAR, /** * If enable mimap. * @type {boolean} */ useMipmap: true, /** * Anisotropic filtering, enabled if value is larger than 1 * @see https://developer.mozilla.org/en-US/docs/Web/API/EXT_texture_filter_anisotropic * @type {number} */ anisotropic: 1, // pixelStorei parameters, not available when texture is used as render target // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml /** * If flip in y axis for given image source * @type {boolean} * @default true */ flipY: true, /** * A flag to indicate if texture source is sRGB */ sRGB: true, /** * @type {number} * @default 4 */ unpackAlignment: 4, /** * @type {boolean} * @default false */ premultiplyAlpha: false, /** * Dynamic option for texture like video * @type {boolean} */ dynamic: false, NPOT: false, // PENDING // Init it here to avoid deoptimization when it's assigned in application dynamically __used: 0 }, function () { this._cache = new Cache(); }, /** @lends clay.Texture.prototype */ { getWebGLTexture: function (renderer) { var _gl = renderer.gl; var cache = this._cache; cache.use(renderer.__uid__); if (cache.miss('webgl_texture')) { // In a new gl context, create new texture and set dirty true cache.put('webgl_texture', _gl.createTexture()); } if (this.dynamic) { this.update(renderer); } else if (cache.isDirty()) { this.update(renderer); cache.fresh(); } return cache.get('webgl_texture'); }, bind: function () {}, unbind: function () {}, /** * Mark texture is dirty and update in the next frame */ dirty: function () { if (this._cache) { this._cache.dirtyAll(); } }, update: function (renderer) {}, // Update the common parameters of texture updateCommon: function (renderer) { var _gl = renderer.gl; _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, this.flipY); _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, this.unpackAlignment); // Use of none-power of two texture // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences if (this.format === glenum.DEPTH_COMPONENT) { this.useMipmap = false; } var sRGBExt = renderer.getGLExtension('EXT_sRGB'); // Fallback if (this.format === Texture.SRGB && !sRGBExt) { this.format = Texture.RGB; } if (this.format === Texture.SRGB_ALPHA && !sRGBExt) { this.format = Texture.RGBA; } this.NPOT = !this.isPowerOfTwo(); }, getAvailableWrapS: function () { if (this.NPOT) { return glenum.CLAMP_TO_EDGE; } return this.wrapS; }, getAvailableWrapT: function () { if (this.NPOT) { return glenum.CLAMP_TO_EDGE; } return this.wrapT; }, getAvailableMinFilter: function () { var minFilter = this.minFilter; if (this.NPOT || !this.useMipmap) { if (minFilter === glenum.NEAREST_MIPMAP_NEAREST || minFilter === glenum.NEAREST_MIPMAP_LINEAR ) { return glenum.NEAREST; } else if (minFilter === glenum.LINEAR_MIPMAP_LINEAR || minFilter === glenum.LINEAR_MIPMAP_NEAREST ) { return glenum.LINEAR; } else { return minFilter; } } else { return minFilter; } }, getAvailableMagFilter: function () { return this.magFilter; }, nextHighestPowerOfTwo: function (x) { --x; for (var i = 1; i < 32; i <<= 1) { x = x | x >> i; } return x + 1; }, /** * @param {clay.Renderer} renderer */ dispose: function (renderer) { var cache = this._cache; cache.use(renderer.__uid__); var webglTexture = cache.get('webgl_texture'); if (webglTexture){ renderer.gl.deleteTexture(webglTexture); } cache.deleteContext(renderer.__uid__); }, /** * Test if image of texture is valid and loaded. * @return {boolean} */ isRenderable: function () {}, /** * Test if texture size is power of two * @return {boolean} */ isPowerOfTwo: function () {} }); Object.defineProperty(Texture.prototype, 'width', { get: function () { return this._width; }, set: function (value) { this._width = value; } }); Object.defineProperty(Texture.prototype, 'height', { get: function () { return this._height; }, set: function (value) { this._height = value; } }); /* DataType */ /** * @type {number} */ Texture.BYTE = glenum.BYTE; /** * @type {number} */ Texture.UNSIGNED_BYTE = glenum.UNSIGNED_BYTE; /** * @type {number} */ Texture.SHORT = glenum.SHORT; /** * @type {number} */ Texture.UNSIGNED_SHORT = glenum.UNSIGNED_SHORT; /** * @type {number} */ Texture.INT = glenum.INT; /** * @type {number} */ Texture.UNSIGNED_INT = glenum.UNSIGNED_INT; /** * @type {number} */ Texture.FLOAT = glenum.FLOAT; /** * @type {number} */ Texture.HALF_FLOAT = 0x8D61; /** * UNSIGNED_INT_24_8_WEBGL for WEBGL_depth_texture extension * @type {number} */ Texture.UNSIGNED_INT_24_8_WEBGL = 34042; /* PixelFormat */ /** * @type {number} */ Texture.DEPTH_COMPONENT = glenum.DEPTH_COMPONENT; /** * @type {number} */ Texture.DEPTH_STENCIL = glenum.DEPTH_STENCIL; /** * @type {number} */ Texture.ALPHA = glenum.ALPHA; /** * @type {number} */ Texture.RGB = glenum.RGB; /** * @type {number} */ Texture.RGBA = glenum.RGBA; /** * @type {number} */ Texture.LUMINANCE = glenum.LUMINANCE; /** * @type {number} */ Texture.LUMINANCE_ALPHA = glenum.LUMINANCE_ALPHA; /** * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ * @type {number} */ Texture.SRGB = 0x8C40; /** * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ * @type {number} */ Texture.SRGB_ALPHA = 0x8C42; /* Compressed Texture */ Texture.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; /* TextureMagFilter */ /** * @type {number} */ Texture.NEAREST = glenum.NEAREST; /** * @type {number} */ Texture.LINEAR = glenum.LINEAR; /* TextureMinFilter */ /** * @type {number} */ Texture.NEAREST_MIPMAP_NEAREST = glenum.NEAREST_MIPMAP_NEAREST; /** * @type {number} */ Texture.LINEAR_MIPMAP_NEAREST = glenum.LINEAR_MIPMAP_NEAREST; /** * @type {number} */ Texture.NEAREST_MIPMAP_LINEAR = glenum.NEAREST_MIPMAP_LINEAR; /** * @type {number} */ Texture.LINEAR_MIPMAP_LINEAR = glenum.LINEAR_MIPMAP_LINEAR; /* TextureWrapMode */ /** * @type {number} */ Texture.REPEAT = glenum.REPEAT; /** * @type {number} */ Texture.CLAMP_TO_EDGE = glenum.CLAMP_TO_EDGE; /** * @type {number} */ Texture.MIRRORED_REPEAT = glenum.MIRRORED_REPEAT; export default Texture;