Source: resources/BaseImageTexture.js

import { Utils } from '../common/Utils'
import { BaseTexture } from './BaseTexture';
import { ImageColorFormat, ImageFilterType, ImageCompressionType } from '../const';

/**
 * @class BaseImageTexture
 * The image texture resource.
 * @memberof THING
 * @extends THING.BaseTexture
 */
class BaseImageTexture extends BaseTexture {

	/**
	 * The image texture that load image resource and use by style.
	 * @param {Object} param The initial parameters.
	 */
	constructor(param = {}) {
		super(param);

		this._onUpdateUrl = param['onUpdateUrl'];

		this.onLoad(param);
	}

	// #region Private

	/**
	 * Called when update the url.
	 * @private
	 */
	_updateUrl() {
		let onUpdateUrl = this._onUpdateUrl;
		if (onUpdateUrl) {
			onUpdateUrl(this, this._url);
		}
	}

	/**
	 * Check whether it is a compressed texture.
	 * @returns {Boolean}
	 * @private
	 */
	_isCompressed(url) {
		let image = this._image;
		if (image) {
			return image.format !== undefined && !!ImageCompressionType[image.format]
		}

		let isBasis = (_url_) => {
			let extension = _url_._getExtension();
			return extension == 'basis'
		}

		if (url) {
			if (Utils.isArray(url)) {
				for (let i = 0; i < url.length; i++) {
					if (!isBasis(url[i])) {
						return false;
					}
				}

				return true;
			}
			else {
				return isBasis(url);
			}
		}
		else {
			return false
		}
	}

	/**
	 * Load texture.
	 * @param {Object} param The texture param.
	 * @private
	 */
	onLoad(param) { }

	/**
	 * Set the urls.
	 * @param {Array<String>} value
	 * @private
	 */
	_setUrl(value) {
		if (!value) {
			return;
		}

		this.unloadResource();

		this._url = value;

		this._updateUrl();

		// Break the previous loading
		if (this.pendingPromise) {
			this.pendingPromise.reject();
			this.pendingPromise = null;
		}

		// Load resource
		this.onLoad({
			url: value,
			onLoad: () => {
				if (this.textureResource) {
					if (Utils.isArray(value)) {
						this.textureResource.setImages(this._image);
					}
					else {
						this.textureResource.setImage(this._image);
					}
				}
			}
		});
	}

	_fixColorFomat(image) {
		if (image.format) {
			this.colorFormat = image.format;
		}
	}

	_fixMinFilterType(image) {
		// It's compressed texture
		if (image.format === ImageColorFormat.BC7_M6_OPAQUE_ONLY) {
			let mipmaps = image.mipmaps;
			if (mipmaps && mipmaps.length !== 1) {
				return;
			}
			this.minFilterType = ImageFilterType.LinearFilter;
		}
		else {
			if (this.generateMipmaps) {
				return;
			}

			// If we do not have any mipmaps then we can not use mipmaps filter
			let mipmaps = image.mipmaps;
			if (mipmaps && mipmaps.length !== 1) {
				return;
			}

			if (this.minFilterType != ImageFilterType.NearestFilter || this.minFilterType != ImageFilterType.LinearFilter) {
				this.minFilterType = ImageFilterType.LinearFilter;
			}
		}
	}

	// #endregion

	// #region Override

	onTriggerErrorEvent(ev) {
		if (!ev) {
			return;
		}

		let err;

		let target = ev.target;
		if (target) {
			let src = ev.target.src;

			err = {
				desc: `Load '${src}' image texture failed`
			}
		}
		else {
			err = ev;
		}

		this.onNotifyError(err);
	}

	onFixupFromImage(image) {
		this._fixColorFomat(image);
		this._fixMinFilterType(image);
	}

	// #endregion

	/**
	 * Copy from image.
	 * @param {THING.ImageTexture} source The image.
	 * @returns {THING.ImageTexture}
	 * @private
	 */
	copy(source) {
		super.copy(source);

		this._setUrl(source.url);

		return this;
	}

	/**
	 * Clone image.
	 * @returns {THING.ImageTexture}
	 * @private
	 */
	clone() {
		let resource = new ImageTexture();
		resource.copy(this);

		return resource;
	}

	/**
	 * Convert to uniform data.
	 * @returns {Object}
	 * @private
	 */
	toUniform() {
		return {
			key: this._url,
			value: this.getTextureResource()
		};
	}

	// #region Accessors

	/**
	 * Get/Set the update url callback function.
	 * @type {Function}
	 * @private
	 */
	get onUpdateUrl() {
		return this._onUpdateUrl;
	}
	set onUpdateUrl(value) {
		if (!value) return
		this._onUpdateUrl = value;
	}


	/**
	 * Get/Set url.
	 * @type {String}
	 */
	get url() {
		return this._url;
	}
	set url(value) {
		this._setUrl(value);
	}

	// #endregion

}

export { BaseImageTexture }