/* * Flickr Sphere (Sample of the ActionScript Thread Library) * * Licensed under the MIT License * * Copyright (c) 2008 BeInteractive! (www.be-interactive.org) and * Spark project (www.libspark.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package org.libspark.flickrsphere.threads { import flash.display.BitmapData; import flash.display.Loader; import flash.geom.Matrix; import flash.geom.Rectangle; import org.libspark.flickrsphere.Context; import org.libspark.flickrsphere.pv3d.ScalableBitmapParticleMaterial; import org.libspark.flickrsphere.threads.flickr.LoadFlickrPhotoImagesThread; import org.libspark.flickrsphere.threads.flickr.PhotoImageQueue; import org.libspark.thread.Thread; import org.libspark.thread.threads.tweener.TweenerThread; import org.libspark.thread.utils.ParallelExecutor; import org.papervision3d.core.data.UserData; import org.papervision3d.core.geom.Particles; import org.papervision3d.core.geom.renderables.Particle; /** * DisplayFlickrPhotoThread クラスは、指定された FlickrPhoto を画面に表示します. */ public class DisplayFlickrPhotoThread extends Thread { /** * @param context コンテキスト * @param photos 表示する FlickrPhoto の配列 */ public function DisplayFlickrPhotoThread(context:Context, photos:Array) { _context = context; _photos = photos; _tempBitmapData = new BitmapData(1, 1, false); _tempMatrix = new Matrix(); } private var _context:Context; private var _photos:Array; private var _queue:PhotoImageQueue; private var _loaders:ParallelExecutor; private var _tempBitmapData:BitmapData; private var _tempMatrix:Matrix; private var _particles:Particles; private var _imageBitmaps:Array; private var _imageParticles:Array; private var _tweens:Array; override protected function run():void { // 写真イメージを表示するための Particles _particles = Particles(_context.sphere.addChild(new Particles())); _imageParticles = []; _imageBitmaps = []; _tweens = []; // ロードされた写真を受け取るためのキュー _queue = new PhotoImageQueue(); // 写真イメージをロードするためのスレッドを 4 つ作る _loaders = new ParallelExecutor(); _loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue)); _loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue)); _loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue)); _loaders.addThread(new LoadFlickrPhotoImagesThread(_photos, _queue)); // ロード開始 _loaders.start(); // 写真表示 displayPhoto(); } private function displayPhoto():void { // 読み込まれている写真が無ければ待つ if (_queue.checkPoll()) { next(displayPhoto); interrupted(displayPhotoInterrupted); return; } // 割り込まれていたら displayInterrupted へ if (checkInterrupted()) { displayPhotoInterrupted(); return; } // 写真イメージを取得 var image:Loader = _queue.poll(); // BitmapData に転写 var imageBitmap:BitmapData = getBitmapData(image, 24); // 写真の平均色を取得 var color:uint = getAverageColor(imageBitmap); // 枠を描画 drawBorder(imageBitmap, color); // 色を座標にマッピング var x:Number = ((color >> 16) & 0xff) - 128; var y:Number = ((color >> 8) & 0xff) - 128; var z:Number = (color & 0xff) - 128; // ローダ開放 image.unload(); // 3D パーティクルを作成 var pMat:ScalableBitmapParticleMaterial = new ScalableBitmapParticleMaterial(imageBitmap); var particle:Particle = new Particle(pMat, 24, 0, 0, 0); // 初期スケールはゼロ particle.userData = new UserData({ scale: 0 }); // コンテナに追加 _particles.addParticle(particle); _imageParticles.push(particle); _imageBitmaps.push(imageBitmap); // トゥイーンさせる var tween:TweenerThread = new TweenerThread(particle, { time: 1.0, x: x, y: y, z: z, particleScale: 1.0, // particleScale プロパティは ParticleShortcuts によってスペシャルプロパティとして定義されています transition: 'easeOutCubic' }); tween.start(); _tweens.push(tween); // 次の写真イメージへ next(displayPhoto); } private function getBitmapData(image:Loader, size:uint):BitmapData { // BitmapData var bitmapData:BitmapData = new BitmapData(size, size, false); // 指定されたサイズに縮小して描画 _tempMatrix.identity(); _tempMatrix.scale(size / image.contentLoaderInfo.width, size / image.contentLoaderInfo.height); bitmapData.draw(image.content, _tempMatrix); return bitmapData; } private function drawBorder(image:BitmapData, color:uint):void { image.fillRect(new Rectangle(0, 0, image.width, 2), color); image.fillRect(new Rectangle(image.width - 2, 0, 2, image.height), color); image.fillRect(new Rectangle(0, image.height - 2, image.width, 2), color); image.fillRect(new Rectangle(0, 0, 2, image.height), color); } private function getAverageColor(image:BitmapData):uint { // 1px * 1px に縮小して BitmapData に描画 _tempMatrix.identity(); _tempMatrix.scale(1 / image.width, 1 / image.height); _tempBitmapData.fillRect(_tempBitmapData.rect, 0x000000); _tempBitmapData.draw(image, _tempMatrix); // その色を取得 return _tempBitmapData.getPixel(0, 0); } private function displayPhotoInterrupted():void { // 全てのロードをキャンセル _loaders.interrupt(); _loaders = null; // 全てのトゥイーンをキャンセル for each (var tween:TweenerThread in _tweens) { tween.cancel(); } // 全てのトゥイーンの完了を待つ var allTweens:ParallelExecutor = new ParallelExecutor(); for each (var t:TweenerThread in _tweens) { allTweens.addThread(t); } allTweens.start(); allTweens.join(); next(hidePhotoImages); } private function hidePhotoImages():void { _tweens = null; // 全てのパーティクルに対して消失アニメーションを行いその完了を待つ var tweens:ParallelExecutor = new ParallelExecutor(); for each (var p:Particle in _imageParticles) { tweens.addThread(new TweenerThread(p, { time: 0.5, x: 0, y: 0, z: 0, particleScale: 0, // particleScale プロパティは ParticleShortcuts によってスペシャルプロパティとして定義されています transition: 'easeInCubic' })); } tweens.start(); tweens.join(); } override protected function finalize():void { // パーティクルコンテナを削除 _context.sphere.removeChild(_particles); _particles = null; // パーティクル削除 _imageParticles = null; // BitmapData 開放 for each (var bitmap:BitmapData in _imageBitmaps) { bitmap.dispose(); } _imageBitmaps = null; // temp 開放 _tempBitmapData.dispose(); _tempMatrix = null; _tempMatrix = null; } } }