import { Utils } from '../common/Utils'
import { BaseImageTexture } from './BaseImageTexture';
import { ImageWrapType, ImageMappingType } from '../const';
import { CubeTexture } from './CubeTexture';
/**
* @class ImageTexture
* The image texture resource.
* @memberof THING
* @extends THING.BaseImageTexture
* @public
*/
class ImageTexture extends BaseImageTexture {
/**
* The pixel buffer with size.
* @typedef {Object} PixelBuffer
* @property {Object} data The pixel buffer data.
* @property {Number} width The buffer width.
* @property {Number} height The buffer height.
*/
/**
* The pixel buffer with size.
* @typedef {Object} CanvasResource
* @property {HTMLElement} resource The pixel buffer data.
*/
/**
* The image texture that load image resource and use by style.
* @param {Object|PixelBuffer|CanvasResource} param The initial parameters.
* @example
* // Create image texture from pixel buffer with size
* let imageTexture = new THING.ImageTexture({
* data: pixelBuffer,
* width: 128,
* height: 128
* });
*
* // Create image texture from canvas
* let imageTexture = new THING.ImageTexture({
* resource: canvas
* });
*/
constructor(param = {}) {
// Check whether it is cube texture.
if (Utils.isArray(param) || Utils.isArray(param['url'])) {
console.warn('Please create cube texture with THING.CubeTexture instead of THING.ImageTexture');
return new CubeTexture(param);
}
super(param);
}
// #region Private
/**
* Load texture resource.
* @param {Object} param The texture param.
* @private
*/
onLoad(param) {
// Parse arguments
if (Utils.isString(param)) {
param = { url: param };
}
else if (param.width !== undefined && param.height !== undefined) {
param = { resource: param };
}
let url = param['url'];
// Load from data(could be compressed image data)
if (param['type'] && param['data']) {
// We can keep url as key even though it come from data
this._url = url;
this._loadFromData(param);
}
// Load from url
else if (url) {
this._loadFromURL(param);
}
// Start to load from resource by data(pixels), width and height
else {
let wrapType = param['wrapType'];
if (wrapType) {
this.wrapType = wrapType;
}
else {
this.wrapTypeS = Utils.parseValue(param['wrapTypeS'], this.wrapTypeS);
this.wrapTypeT = Utils.parseValue(param['wrapTypeT'], this.wrapTypeT);
}
this.mappingType = Utils.parseValue(param['mappingType'], this.mappingType);
this.flipY = Utils.parseValue(param['flipY'], this.flipY);
// Save image resource directly
let data = param['data'];
if (data) {
let width = param['width'];
let height = param['height'];
this._image = {
width,
height,
data,
};
}
else {
this._image = Utils.parseValue(param['resource'], null);
}
// Only set loaded flag when image resource is ready
if (this._image) {
this.onNotifyComplete();
}
}
}
_loadFromURL(param) {
let onLoad = Utils.parseValue(param['onLoad'], null);
this._url = param['url'];
this._updateUrl();
// Set options
if (param['wrapType']) {
this.wrapType = param['wrapType'];
}
this.mappingType = Utils.parseValue(param['mappingType'], ImageMappingType.UV);
this.flipY = Utils.parseValue(param['flipY'], true);
Utils.loadImageFile(this._url,
// Load
(image) => {
this._image = image;
this.onFixupFromImage(image);
if (onLoad) {
onLoad({ image: this });
}
this.onNotifyComplete();
},
// Progress
(ev) => {
},
// Error
(ev) => {
this.onTriggerErrorEvent(ev);
},
{
flipY: this.flipY,
premultiplyAlpha: this.premultiplyAlpha,
generateMipmaps: this.generateMipmaps,
extensions: Utils.getCurrentApp().view.getExtensions()
}
);
}
_loadFromData(param) {
let { type, data } = param
let onLoad = Utils.parseValue(param['onLoad'], null);
this.wrapType = Utils.parseValue(param['wrapType'], ImageWrapType.Repeat);
this.mappingType = Utils.parseValue(param['mappingType'], ImageMappingType.UV);
this.flipY = Utils.parseValue(param['flipY'], true);
Utils.loadImageFileFromData(type, data,
// Load
(image) => {
this._image = image;
this.onFixupFromImage(image);
if (onLoad) {
onLoad({ image: this });
}
this.onNotifyComplete();
},
// Progress
(ev) => {
},
// Error
(ev) => {
Utils.error(ev);
},
{
extensions: Utils.getCurrentApp().view.getExtensions()
}
);
}
// #endregion
// #region Overrides
onDispose() {
this._image = null;
super.onDispose();
}
onCreateTextureResource() {
// Some features do not support in compressed texture
if (this._isCompressed(this._url)) {
this.flipY = false;
this.generateMipmaps = false;
}
let image = this._image;
if (image) {
// Image had been loaded
return Utils.createObject('ImageTextureResource', { data: image, external: this.external });
}
else {
// Image is still loading, we would replace it when it finished
let textureResource = Utils.createObject('ImageTextureResource', { textureType: 'HTMLElement', external: this.external });
this.waitForComplete().then((image) => {
// Replace texture image
textureResource.setImage(image.resource);
}).catch(ev => {
this.onTriggerErrorEvent(ev);
});
return textureResource;
}
}
// #endregion
// #region Accessors
/**
* Get source url or base64 data.
* @type {String}
* @public
*/
get src() {
let image = this._image;
if (image) {
if (image.src) {
return image.src;
}
}
return this._url;
}
/**
* Set the dirty flag.
* @type {Boolean}
* @private
*/
set dirty(value) {
let textureResource = this.textureResource;
if (!textureResource) {
return;
}
textureResource.refresh();
}
/**
* Get width in pixel.
* @type {Number}
* @public
*/
get width() {
let resource = this._image;
if (!resource) {
return 0;
}
if (resource.width) {
return resource.width;
}
else if (resource.complete !== undefined) {
return resource.width;
}
else if (Utils.isArray(resource)) {
for (let i = 0; i < resource.length; i++) {
if (resource[i].complete) {
return resource[i].width;
}
}
}
return 0;
}
/**
* Get height in pixel.
* @type {Number}
* @public
*/
get height() {
let resource = this._image;
if (!resource) {
return 0;
}
if (resource.height) {
return resource.height;
}
else if (resource.complete !== undefined) {
return resource.height;
}
else if (Utils.isArray(resource)) {
for (let i = 0; i < resource.length; i++) {
if (resource[i].complete) {
return resource[i].height;
}
}
}
return 0;
}
/**
* Get/Set resource.
* @type {*}
* @private
*/
get resource() {
return this._image;
}
set resource(value) {
this._image = value;
if (this.textureResource) {
this.textureResource.setImage(value);
}
this.onNotifyComplete();
}
/**
* Enable/Disable flipY.
* @type {Boolean}
* @public
*/
get flipY() {
// Compressed texture do not support flipY
if (this._isCompressed(this._url)) {
return false;
}
return super.flipY;
}
set flipY(value) {
// Compressed texture do not support flipY
if (value && this._isCompressed(this._url)) {
return;
}
super.flipY = value;
}
/**
* Enable/Disable generate mipmaps.
* The minFilterType property will auto set to THING.ImageFilterType.LinearMipmapLinearFilter when generate mipmaps is enabled.
* @type {Boolean}
* @public
*/
get generateMipmaps() {
// Compressed texture do not support generateMipmaps
if (this._isCompressed(this._url)) {
return false;
}
return super.generateMipmaps;
}
set generateMipmaps(value) {
// Compressed texture do not support generateMipmaps
if (value && this._isCompressed(this._url)) {
return;
}
super.generateMipmaps = value;
}
// #endregion
/**
* Check class type.
* @type {Boolean}
* @example
* if (texture.isImageTexture) {
* console.log(`It's image texture`);
* }
* @public
*/
get isImageTexture() {
return true;
}
}
export { ImageTexture }