Files
alternativa3d-archive/Alternativa3D7/7.0/alternativa/engine3d/loaders/TextureLoader.as
Pyogenics c2b65211bd Add A3D7
2024-09-28 17:35:38 +01:00

268 lines
9.4 KiB
ActionScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package alternativa.engine3d.loaders {
import alternativa.engine3d.loaders.events.LoaderEvent;
import alternativa.engine3d.loaders.events.LoaderProgressEvent;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.BlendMode;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.system.LoaderContext;
/**
* Событие посылается, когда начинается загрузка ресурса.
*
* @eventType flash.events.Event.OPEN
*/
[Event (name="open", type="flash.events.Event")]
/**
* Событие посылается, когда загрузка ресурса успешно завершена.
*
* @eventType flash.events.Event.COMPLETE
*/
[Event (name="complete", type="flash.events.Event")]
/**
* Событие посылается при возникновении ошибки загрузки.
*
* @eventType flash.events.IOErrorEvent.IO_ERROR
*/
[Event (name="ioError", type="flash.events.IOErrorEvent")]
/**
* Событие посылается, когда начинается загрузка очередной части ресурса.
*
* @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_OPEN
*/
[Event (name="partOpen", type="alternativa.engine3d.loaders.events.LoaderEvent")]
/**
* Событие посылается, когда загрузка очередной части ресурса успешно завершена.
*
* @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_COMPLETE
*/
[Event (name="partComplete", type="alternativa.engine3d.loaders.events.LoaderEvent")]
/**
* Событие посылается для отображения прогресса загрузки.
*
* @eventType alternativa.engine3d.loaders.events.LoaderProgressEvent.LOADER_PROGRESS
*/
[Event (name="loaderProgress", type="alternativa.engine3d.loaders.events.LoaderProgressEvent")]
/**
* Загрузчик текстуры, состоящей из одного или двух файлов. В случае, если указан второй файл, он используется для заполнения альфа-канала
* получаемой текстуры.
*/
public class TextureLoader extends EventDispatcher {
private static const IDLE:int = -1;
private static const LOADING_DIFFUSE_MAP:int = 0;
private static const LOADING_ALPHA_MAP:int = 1;
private var state:int = IDLE;
private var bitmapLoader:Loader;
private var loaderContext:LoaderContext;
private var alphaTextureUrl:String;
private var _bitmapData:BitmapData;
/**
* Создаёт новый экземпляр. Если указан URL диффузной части текстуры, то сразу начинается загрузка.
*
* @param diffuseTextureUrl URL диффузной части текстуры
* @param alphaTextureUrl URL карты прозрачности
* @param loaderContext LoaderContext, используемый при загрузке
*/
public function TextureLoader() {
}
/**
* Загруженная текстура.
*/
public function get bitmapData():BitmapData {
return _bitmapData;
}
/**
* Загрузка текстурных карт. При успешной загрузке посылается сообщение <code>Event.COMPLETE</code>.
*
* @param diffuseTextureUrl URL файла диффузной карты
* @param alphaTextureUrl URL файла карты прозрачности
* @param loaderContext LoaderContext, используемый при загрузке
*/
public function load(diffuseTextureUrl:String, alphaTextureUrl:String = null, loaderContext:LoaderContext = null):void {
unload();
this.alphaTextureUrl = alphaTextureUrl == "" ? null : alphaTextureUrl;
this.loaderContext = loaderContext;
loadPart(LOADING_DIFFUSE_MAP, diffuseTextureUrl);
}
/**
* Прекращвет текущую загрузку. Если нет активных загрузок, не происходит ничего.
*/
public function close():void {
if (state == IDLE) return;
state = IDLE;
bitmapLoader.unload();
destroyLoader();
alphaTextureUrl = null;
loaderContext = null;
}
/**
* Очищает внутренние ссылки на загруженные объекты, чтобы сборщик мусора смог их удалить.
*/
public function unload():void {
close();
_bitmapData = null;
}
/**
* Очищает временные внутренние ссылки.
*/
private function cleanup():void {
destroyLoader();
alphaTextureUrl = null;
loaderContext = null;
}
/**
* Запускает загрузку части текстуры.
*
* @param state фаза загрузки
* @param url URL загружаемого файла
*/
private function loadPart(state:int, url:String):void {
this.state = state;
createLoader();
bitmapLoader.load(new URLRequest(url), loaderContext);
}
/**
* Обрабатывает начало загрузки очередной части текстуры.
*/
private function onPartLoadingOpen(e:Event):void {
if (_bitmapData == null && hasEventListener(Event.OPEN)) {
dispatchEvent(new Event(Event.OPEN));
}
if (hasEventListener(LoaderEvent.PART_OPEN)) {
dispatchEvent(new LoaderEvent(LoaderEvent.PART_OPEN, 2, state == LOADING_DIFFUSE_MAP ? 0 : 1));
}
}
/**
*
*/
private function onPartLoadingProgress(e:ProgressEvent):void {
if (hasEventListener(LoaderProgressEvent.LOADER_PROGRESS)) {
var partNumber:int = state == LOADING_DIFFUSE_MAP ? 0 : 1;
var totalProgress:Number = 0.5*(partNumber + e.bytesLoaded/e.bytesTotal);
dispatchEvent(new LoaderProgressEvent(LoaderProgressEvent.LOADER_PROGRESS, 2, partNumber, totalProgress, e.bytesLoaded, e.bytesTotal));
}
}
/**
*
*/
private function onPartLoadingComplete(e:Event):void {
switch (state) {
case LOADING_DIFFUSE_MAP: {
// Загрузилась диффузная текстура. При необходимости загружается карта прозрачности.
_bitmapData = Bitmap(bitmapLoader.content).bitmapData;
destroyLoader();
dispatchPartComplete(0);
if (alphaTextureUrl != null) {
loadPart(LOADING_ALPHA_MAP, alphaTextureUrl);
} else {
complete();
}
break;
}
case LOADING_ALPHA_MAP: {
// Загрузилась карта прозрачности. Выполняется копирование прозрачности в альфа-канал диффузной текстуры.
var pt:Point = new Point();
var tmpBmd:BitmapData = _bitmapData;
_bitmapData = new BitmapData(_bitmapData.width, _bitmapData.height);
_bitmapData.copyPixels(tmpBmd, tmpBmd.rect, pt);
var alpha:BitmapData = Bitmap(bitmapLoader.content).bitmapData;
destroyLoader();
if (_bitmapData.width != alpha.width || _bitmapData.height != alpha.height) {
tmpBmd.draw(alpha, new Matrix(_bitmapData.width/alpha.width, 0, 0, _bitmapData.height/alpha.height), null, BlendMode.NORMAL, null, true);
alpha.dispose();
alpha = tmpBmd;
} else {
tmpBmd.dispose();
}
_bitmapData.copyChannel(alpha, alpha.rect, pt, BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
alpha.dispose();
dispatchPartComplete(1);
complete();
break;
}
}
}
/**
* Создаёт событие завершения загрузки части текстуры.
*
* @param partnNumber номер загруженной части текстуры
*/
private function dispatchPartComplete(partNumber:int):void {
if (hasEventListener(LoaderEvent.PART_COMPLETE)) {
dispatchEvent(new LoaderEvent(LoaderEvent.PART_COMPLETE, 2, partNumber));
}
}
/**
*
*/
private function onLoadError(e:Event):void {
state = IDLE;
cleanup();
dispatchEvent(e);
}
/**
*
*/
private function complete():void {
state = IDLE;
cleanup();
if (hasEventListener(Event.COMPLETE)) {
dispatchEvent(new Event(Event.COMPLETE));
}
}
/**
*
*/
private function createLoader():void {
bitmapLoader = new Loader();
var loaderInfo:LoaderInfo = bitmapLoader.contentLoaderInfo;
loaderInfo.addEventListener(Event.OPEN, onPartLoadingOpen);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, onPartLoadingProgress);
loaderInfo.addEventListener(Event.COMPLETE, onPartLoadingComplete);
loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
}
/**
*
*/
private function destroyLoader():void {
if (bitmapLoader == null) return;
bitmapLoader.unload();
var loaderInfo:LoaderInfo = bitmapLoader.contentLoaderInfo;
loaderInfo.removeEventListener(Event.OPEN, onPartLoadingOpen);
loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onPartLoadingProgress);
loaderInfo.removeEventListener(Event.COMPLETE, onPartLoadingComplete);
loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onLoadError);
bitmapLoader = null;
}
}
}