PageRenderTime 49ms CodeModel.GetById 24ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/aerys/minko/render/Viewport.as

https://bitbucket.org/HopeSky/mars_nd2d
ActionScript | 450 lines | 316 code | 74 blank | 60 comment | 53 complexity | e17fe920b317aca58f70142c9e185ced MD5 | raw file
  1package aerys.minko.render
  2{
  3	import aerys.minko.ns.minko_render;
  4	import aerys.minko.render.resource.Context3DResource;
  5	import aerys.minko.type.KeyboardManager;
  6	import aerys.minko.type.MouseManager;
  7	import aerys.minko.type.Signal;
  8	
  9	import flash.display.DisplayObject;
 10	import flash.display.Graphics;
 11	import flash.display.Shape;
 12	import flash.display.Sprite;
 13	import flash.display.Stage;
 14	import flash.display.Stage3D;
 15	import flash.display.StageAlign;
 16	import flash.display.StageScaleMode;
 17	import flash.events.Event;
 18	import flash.events.MouseEvent;
 19	import flash.events.TouchEvent;
 20	import flash.geom.Point;
 21
 22	/**
 23	 * The Viewport is the display area where a 3D scene can be rendered.
 24	 *  
 25	 * @author Jean-Marc Le Roux
 26	 * 
 27	 */
 28	public class Viewport extends Sprite
 29	{
 30		private static const ZERO2		: Point				= new Point();
 31		
 32		private var _stage3d			: Stage3D			= null;
 33		private var _context3d			: Context3DResource	= null;
 34		
 35		private var _width				: uint				= 0;
 36		private var _height				: uint				= 0;
 37		private var _autoResize			: Boolean			= false;
 38		private var _antiAliasing		: uint				= 0;
 39		private var _backgroundColor	: uint				= 0;
 40		private var _backBuffer			: RenderTarget		= null;
 41		private var _invalidBackBuffer	: Boolean			= false;
 42		
 43		private var _alwaysOnTop		: Boolean			= false;
 44		private var _mask				: Shape				= new Shape();
 45		
 46		private var _mouseManager		: MouseManager		= new MouseManager();
 47		private var _keyboardManager	: KeyboardManager	= new KeyboardManager();
 48		
 49		private var _resized			: Signal			= new Signal('Viewport.resized');
 50		
 51		minko_render function get context3D() : Context3DResource
 52		{
 53			return _context3d;
 54		}
 55		
 56		minko_render function get backBuffer() : RenderTarget
 57		{
 58			var positionOnStage	: Point	= localToGlobal(ZERO2);
 59			
 60			if (_stage3d.x != positionOnStage.x || _stage3d.y != positionOnStage.y)
 61				updateStage3D()
 62			
 63			return _backBuffer;
 64		}
 65		
 66		public function get ready() : Boolean
 67		{
 68			return _stage3d != null && _stage3d.context3D != null && _backBuffer != null;
 69		}
 70		
 71		/**
 72		 * Whether the viewport is visible or not. 
 73		 * @return 
 74		 * 
 75		 */
 76		override public function set visible(value : Boolean) : void
 77		{
 78			if (_stage3d)
 79				_stage3d.visible = value;
 80			
 81			super.visible = value;
 82		}
 83		
 84		override public function set x(value : Number) : void
 85		{
 86			super.x = value;
 87			updateStage3D();
 88		}
 89		
 90		override public function set y(value : Number) : void
 91		{
 92			super.y = value;
 93			updateStage3D();
 94		}
 95		
 96		/**
 97		 * The width of the display area. 
 98		 * @return 
 99		 * 
100		 */
101		override public function get width() : Number
102		{
103			return _width;
104		}
105		override public function set width(value : Number) : void
106		{
107			resize(value, _height);
108		}
109		
110		/**
111		 * The height of the display area. 
112		 * @return 
113		 * 
114		 */
115		override public function get height() : Number
116		{
117			return _height;
118		}
119		override public function set height(value : Number) : void
120		{
121			resize(_width, value);
122		}
123		
124		public function get alwaysOnTop() : Boolean
125		{
126			return _alwaysOnTop;
127		}
128		public function set alwaysOnTop(value : Boolean) : void
129		{
130			_alwaysOnTop = value;
131		}
132		
133		public function get keyboardManager() : KeyboardManager
134		{
135			return _keyboardManager;
136		}
137		
138		public function get mouseManager() : MouseManager
139		{
140			return _mouseManager;
141		}
142		
143		/**
144		 * The signal executed when the viewport is resized.
145		 * Callback functions for this signal should accept the following
146		 * arguments:
147		 * <ul>
148		 * <li>viewport : Viewport, the viewport executing the signal</li>
149		 * <li>width : Number, the new width of the viewport</li>
150		 * <li>height : Number, the new height of the viewport</li>
151		 * </ul> 
152		 * @return 
153		 * 
154		 */
155		public function get resized() : Signal
156		{
157			return _resized;
158		}
159		
160		/**
161		 * The background color of the display area. This value must use the
162		 * RGB format.
163		 * @return 
164		 * 
165		 */
166		public function get backgroundColor() : uint
167		{
168			return _backgroundColor;
169		}
170		public function set backgroundColor(value : uint) : void
171		{
172			_backgroundColor = value;
173			updateBackBuffer();
174		}
175		
176		/**
177		 * The anti-aliasing to use (0, 2, 4, 8 or 16). The actual anti-aliasing
178		 * used for rendering depends on the hardware capabilities. If the specified
179		 * anti-aliasing value is not supported, the value 0 will be used.
180		 * @return 
181		 * 
182		 */
183		public function get antiAliasing() : uint
184		{
185			return _antiAliasing;
186		}
187		public function set antiAliasing(value : uint) : void
188		{
189			_antiAliasing = value;
190			updateStage3D();
191		}
192		
193		/**
194		 * The driver informations provided by the Stage3D API. 
195		 */
196		public function get driverInfo() : String
197		{
198			return _stage3d && _stage3d.context3D
199				? _stage3d.context3D.driverInfo
200				: null;
201		}
202		
203		public function Viewport(antiAliasing	: uint	= 0,
204								 width			: uint 	= 0,
205								 height			: uint	= 0)
206		{
207			_antiAliasing = antiAliasing;
208			
209			if (width == 0 && height == 0)
210				_autoResize = true;
211			
212			_width = width;
213			_height = height;
214			
215			initialize();
216		}
217		
218		private function initialize() : void
219		{
220			_mouseManager.bind(this);
221			
222			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
223			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
224		}
225		
226		private function addedToStageHandler(event : Event) : void
227		{
228			_keyboardManager.bind(stage);
229
230			parent.addEventListener(Event.RESIZE, parentResizedHandler);
231			
232			stage.addEventListener(Event.ADDED_TO_STAGE, displayObjectAddedToStageHandler);
233			stage.addEventListener(Event.REMOVED_FROM_STAGE, displayObjectRemovedFromStageHandler);
234			
235			setupOnStage(stage);
236		}
237		
238		private function removedFromStageHandler(event : Event) : void
239		{
240			_keyboardManager.unbind(stage);
241			
242			parent.removeEventListener(Event.RESIZE, parentResizedHandler);
243			
244			stage.removeEventListener(Event.ADDED_TO_STAGE, displayObjectAddedToStageHandler);
245			stage.removeEventListener(Event.REMOVED_FROM_STAGE, displayObjectRemovedFromStageHandler);
246			
247			if (_stage3d != null)
248				_stage3d.visible = false;
249		}
250		
251		private function setupOnStage(stage : Stage, stage3dId : uint = 0) : void
252		{
253			if (_autoResize)
254			{
255				_width = stage.stageWidth;
256				_height = stage.stageHeight;
257			}
258			
259			if (!_stage3d)
260			{
261				_stage3d = stage.stage3Ds[stage3dId];
262				_stage3d.addEventListener(Event.CONTEXT3D_CREATE, context3dCreatedHandler);
263				_stage3d.requestContext3D();
264			}
265			else
266			{
267				_stage3d.visible = visible;
268			}
269			
270			stage.scaleMode = StageScaleMode.NO_SCALE;
271			stage.align = StageAlign.TOP_LEFT;
272		}
273		
274		/**
275		 * Dispose the Viewport and all the Stage3D related objects. After this operation,
276		 * the Viewport cannot be used anymore and is ready for garbage collection.
277		 */
278		public function dispose():void
279		{
280			if (_stage3d != null)
281			{
282				_stage3d.removeEventListener(Event.CONTEXT3D_CREATE, context3dCreatedHandler);
283				_stage3d = null;
284			}
285			
286			if (_context3d != null)
287			{
288				_context3d.dispose();
289				_context3d = null;
290			}
291			
292			return ;
293		}
294		
295		/**
296		 * Resize the display area. The "resized" signal is executed when the new width and
297		 * height have be set. 
298		 * @param width
299		 * @param height
300		 * 
301		 */
302		public function resize(width : Number, height : Number) : void
303		{
304			_autoResize = false;
305			
306			setSize(width, height);
307		}
308		
309		private function setSize(width : Number, height : Number) : void
310		{
311			if (width == _width && _height == height)
312				return ;
313			
314			_width = width;
315			_height = height;
316			
317			updateStage3D();
318			updateBackBuffer();
319			_resized.execute(this, width, height);
320		}
321		
322		private function stageResizedHandler(event : Event) : void
323		{
324			updateMask();
325		}
326		
327		private function parentResizedHandler(event : Event) : void
328		{
329			if (_autoResize)
330			{
331				if (parent == stage)
332					setSize(stage.stageWidth, stage.stageHeight);
333				else
334					setSize(parent.width, parent.height);
335			}
336		}
337		
338		private function context3dCreatedHandler(event : Event) : void
339		{
340			_context3d = new Context3DResource(_stage3d.context3D);
341			
342			updateStage3D();
343			updateBackBuffer();
344			
345			dispatchEvent(new Event(Event.INIT));
346		}
347		
348		private function updateBackBuffer() : void
349		{
350			if (_width == 0 || _height == 0 || _stage3d == null || _stage3d.context3D == null)
351				return ;
352			
353			_invalidBackBuffer = false;
354			_stage3d.context3D.configureBackBuffer(_width, _height, _antiAliasing, true);
355			_backBuffer = new RenderTarget(_width, _height, null, 0, _backgroundColor);
356			
357			graphics.clear();
358			graphics.beginFill(0, 0);
359			graphics.drawRect(0, 0, _width, _height);
360		}
361		
362		private function updateStage3D() : void
363		{
364			if (_stage3d == null)
365				return ;
366			
367			var upperLeft	: Point	= localToGlobal(ZERO2);
368			
369			_stage3d.x = upperLeft.x;
370			_stage3d.y = upperLeft.y;
371			
372			if (_width > 2048)
373			{
374				_stage3d.x = (_width - 2048) * 0.5;
375				_width = 2048;
376			}
377			else
378				_stage3d.x = upperLeft.x;
379			
380			if (_height > 2048)
381			{
382				_stage3d.y = (_height - 2048) * 0.5;
383				_height = 2048;
384			}
385			else
386				_stage3d.y = upperLeft.y;
387
388			updateMask();
389		}
390		
391		private function updateMask() : void
392		{
393			if (!stage)
394				return ;
395			
396			var numChildren : uint = stage.numChildren;
397			var i 			: uint = 0;
398			
399			if (_alwaysOnTop)
400			{
401				var gfx			: Graphics	= _mask.graphics;
402				var stageWidth	: int		= stage.stageWidth;
403				var stageHeight	: int		= stage.stageHeight;
404				
405				gfx.clear();
406				gfx.beginFill(0);
407				gfx.moveTo(0, 0);
408				gfx.lineTo(stageWidth, 0);
409				gfx.lineTo(stageWidth, stageHeight);
410				gfx.lineTo(0., stageHeight);
411				gfx.lineTo(0, 0);
412				gfx.moveTo(_stage3d.x, _stage3d.y);
413				gfx.lineTo(_stage3d.x, _stage3d.y + height);
414				gfx.lineTo(_stage3d.x + width, _stage3d.y + height);
415				gfx.lineTo(_stage3d.x + width, _stage3d.y);
416				gfx.lineTo(_stage3d.x, _stage3d.y);
417				gfx.endFill();
418				
419				for (i = 0; i < numChildren; ++i)
420					stage.getChildAt(i).mask = _mask;
421			}
422			else
423			{
424				for (i = 0; i < numChildren; ++i)
425				{
426					var child : DisplayObject = stage.getChildAt(i);
427					
428					if (child.mask == _mask)
429						child.mask = null;
430				}
431			}
432		}
433		
434		private function displayObjectAddedToStageHandler(event : Event) : void
435		{
436			var displayObject : DisplayObject	= event.target as DisplayObject;
437			
438			if (displayObject.parent == stage)
439				updateMask();
440		}
441		
442		private function displayObjectRemovedFromStageHandler(event : Event) : void
443		{
444			var displayObject : DisplayObject	= event.target as DisplayObject;
445			
446			if (_autoResize && displayObject.parent == stage)
447				displayObject.mask = null;
448		}
449	}
450}