PageRenderTime 42ms CodeModel.GetById 3ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/away3d/core/managers/Stage3DProxy.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 616 lines | 381 code | 99 blank | 136 comment | 56 complexity | 295c24c90b943c5f8ef80a5a1d185875 MD5 | raw file
  1package away3d.core.managers
  2{
  3	import away3d.arcane;
  4	import away3d.debug.Debug;
  5	import away3d.events.Stage3DEvent;
  6	
  7	import flash.display.Shape;
  8	import flash.display.Stage3D;
  9	import flash.display3D.Context3D;
 10	import flash.display3D.Context3DClearMask;
 11	import flash.display3D.Context3DRenderMode;
 12	import flash.display3D.Program3D;
 13	import flash.display3D.textures.TextureBase;
 14	import flash.events.Event;
 15	import flash.events.EventDispatcher;
 16	import flash.geom.Rectangle;
 17
 18	use namespace arcane;
 19	
 20	[Event(name="enterFrame", type="flash.events.Event")]
 21	[Event(name="exitFrame", type="flash.events.Event")]
 22	
 23	/**
 24	 * Stage3DProxy provides a proxy class to manage a single Stage3D instance as well as handling the creation and
 25	 * attachment of the Context3D (and in turn the back buffer) is uses. Stage3DProxy should never be created directly,
 26	 * but requested through Stage3DManager.
 27	 *
 28	 * @see away3d.core.managers.Stage3DProxy
 29	 *
 30	 * todo: consider moving all creation methods (createVertexBuffer etc) in here, so that disposal can occur here
 31	 * along with the context, instead of scattered throughout the framework
 32	 */
 33	public class Stage3DProxy extends EventDispatcher
 34	{
 35		private static var _frameEventDriver:Shape = new Shape();
 36
 37		arcane var _context3D:Context3D;
 38		arcane var _stage3DIndex:int = -1;
 39		
 40		private var _usesSoftwareRendering:Boolean;
 41		private var _profile:String;
 42		private var _stage3D:Stage3D;
 43		private var _activeProgram3D:Program3D;
 44		private var _stage3DManager:Stage3DManager;
 45		private var _backBufferWidth:int;
 46		private var _backBufferHeight:int;
 47		private var _antiAlias:int;
 48		private var _enableDepthAndStencil:Boolean;
 49		private var _backBufferEnableDepthAndStencil:Boolean = true;
 50		private var _contextRequested:Boolean;
 51		//private var _activeVertexBuffers : Vector.<VertexBuffer3D> = new Vector.<VertexBuffer3D>(8, true);
 52		//private var _activeTextures : Vector.<TextureBase> = new Vector.<TextureBase>(8, true);
 53		private var _renderTarget:TextureBase;
 54		private var _renderSurfaceSelector:int;
 55		private var _scissorRect:Rectangle;
 56		private var _color:uint;
 57		private var _backBufferDirty:Boolean;
 58		private var _viewPort:Rectangle;
 59		private var _enterFrame:Event;
 60		private var _exitFrame:Event;
 61		private var _viewportUpdated:Stage3DEvent;
 62		private var _viewportDirty:Boolean;
 63		private var _bufferClear:Boolean;
 64		private var _mouse3DManager:Mouse3DManager;
 65		private var _touch3DManager:Touch3DManager;
 66		
 67		private function notifyViewportUpdated():void
 68		{
 69			if (_viewportDirty)
 70				return;
 71			
 72			_viewportDirty = true;
 73			
 74			if (!hasEventListener(Stage3DEvent.VIEWPORT_UPDATED))
 75				return;
 76			
 77			//TODO: investigate bug causing coercion error
 78			//if (!_viewportUpdated)
 79			_viewportUpdated = new Stage3DEvent(Stage3DEvent.VIEWPORT_UPDATED);
 80			
 81			dispatchEvent(_viewportUpdated);
 82		}
 83		
 84		private function notifyEnterFrame():void
 85		{
 86			if (!hasEventListener(Event.ENTER_FRAME))
 87				return;
 88			
 89			if (!_enterFrame)
 90				_enterFrame = new Event(Event.ENTER_FRAME);
 91			
 92			dispatchEvent(_enterFrame);
 93		}
 94		
 95		private function notifyExitFrame():void
 96		{
 97			if (!hasEventListener(Event.EXIT_FRAME))
 98				return;
 99			
100			if (!_exitFrame)
101				_exitFrame = new Event(Event.EXIT_FRAME);
102			
103			dispatchEvent(_exitFrame);
104		}
105		
106		/**
107		 * Creates a Stage3DProxy object. This method should not be called directly. Creation of Stage3DProxy objects should
108		 * be handled by Stage3DManager.
109		 * @param stage3DIndex The index of the Stage3D to be proxied.
110		 * @param stage3D The Stage3D to be proxied.
111		 * @param stage3DManager
112		 * @param forceSoftware Whether to force software mode even if hardware acceleration is available.
113		 */
114		public function Stage3DProxy(stage3DIndex:int, stage3D:Stage3D, stage3DManager:Stage3DManager, forceSoftware:Boolean = false, profile:String = "baseline")
115		{
116			_stage3DIndex = stage3DIndex;
117			_stage3D = stage3D;
118			_stage3D.x = 0;
119			_stage3D.y = 0;
120			_stage3D.visible = true;
121			_stage3DManager = stage3DManager;
122			_viewPort = new Rectangle();
123			_enableDepthAndStencil = true;
124
125			// whatever happens, be sure this has highest priority
126			_stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DUpdate, false, 1000, false);
127			requestContext(forceSoftware, profile);
128		}
129		
130		public function get profile():String
131		{
132			return _profile;
133		}
134		
135		/**
136		 * Disposes the Stage3DProxy object, freeing the Context3D attached to the Stage3D.
137		 */
138		public function dispose():void
139		{
140			_stage3DManager.removeStage3DProxy(this);
141			_stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContext3DUpdate);
142			freeContext3D();
143			_stage3D = null;
144			_stage3DManager = null;
145			_stage3DIndex = -1;
146		}
147
148		/**
149		 * Configures the back buffer associated with the Stage3D object.
150		 * @param backBufferWidth The width of the backbuffer.
151		 * @param backBufferHeight The height of the backbuffer.
152		 * @param antiAlias The amount of anti-aliasing to use.
153		 * @param enableDepthAndStencil Indicates whether the back buffer contains a depth and stencil buffer.
154		 */
155		public function configureBackBuffer(backBufferWidth:int, backBufferHeight:int, antiAlias:int):void
156		{
157			if(backBufferWidth<50) backBufferWidth = 50;
158			if(backBufferHeight<50) backBufferHeight = 50;
159			var oldWidth:uint = _backBufferWidth;
160			var oldHeight:uint = _backBufferHeight;
161			
162			_backBufferWidth = _viewPort.width = backBufferWidth;
163			_backBufferHeight = _viewPort.height = backBufferHeight;
164			
165			if (oldWidth != _backBufferWidth || oldHeight != _backBufferHeight)
166				notifyViewportUpdated();
167			
168			_antiAlias = antiAlias;
169
170			if (_context3D)
171				_context3D.configureBackBuffer(backBufferWidth, backBufferHeight, antiAlias, _backBufferEnableDepthAndStencil);
172		}
173		
174		/*
175		 * Indicates whether the depth and stencil buffer is used
176		 */
177		public function get enableDepthAndStencil():Boolean
178		{
179			return _enableDepthAndStencil;
180		}
181		
182		public function set enableDepthAndStencil(enableDepthAndStencil:Boolean):void
183		{
184			_enableDepthAndStencil = enableDepthAndStencil;
185			_backBufferDirty = true;
186		}
187		
188		public function get renderTarget():TextureBase
189		{
190			return _renderTarget;
191		}
192		
193		public function get renderSurfaceSelector():int
194		{
195			return _renderSurfaceSelector;
196		}
197		
198		public function setRenderTarget(target:TextureBase, enableDepthAndStencil:Boolean = false, surfaceSelector:int = 0):void
199		{
200			if (_renderTarget == target && surfaceSelector == _renderSurfaceSelector && _enableDepthAndStencil == enableDepthAndStencil)
201				return;
202			_renderTarget = target;
203			_renderSurfaceSelector = surfaceSelector;
204			_enableDepthAndStencil = enableDepthAndStencil;
205			
206			if (target)
207				_context3D.setRenderToTexture(target, enableDepthAndStencil, _antiAlias, surfaceSelector);
208			else
209				_context3D.setRenderToBackBuffer();
210		}
211		
212		/*
213		 * Clear and reset the back buffer when using a shared context
214		 */
215		public function clear():void
216		{
217			if (!_context3D)
218				return;
219			
220			if (_backBufferDirty) {
221				configureBackBuffer(_backBufferWidth, _backBufferHeight, _antiAlias);
222				_backBufferDirty = false;
223			}
224			
225			_context3D.clear(
226				((_color >> 16) & 0xff)/255.0,
227				((_color >> 8) & 0xff)/255.0,
228				(_color & 0xff)/255.0,
229				((_color >> 24) & 0xff)/255.0);
230			
231			_bufferClear = true;
232		}
233		
234		/*
235		 * Display the back rendering buffer
236		 */
237		public function present():void
238		{
239			if (!_context3D)
240				return;
241			
242			_context3D.present();
243			
244			_activeProgram3D = null;
245			
246			if (_mouse3DManager)
247				_mouse3DManager.fireMouseEvents();
248		}
249		
250		/**
251		 * Registers an event listener object with an EventDispatcher object so that the listener receives notification of an event. Special case for enterframe and exitframe events - will switch Stage3DProxy into automatic render mode.
252		 * You can register event listeners on all nodes in the display list for a specific type of event, phase, and priority.
253		 *
254		 * @param type The type of event.
255		 * @param listener The listener function that processes the event.
256		 * @param useCapture Determines whether the listener works in the capture phase or the target and bubbling phases. If useCapture is set to true, the listener processes the event only during the capture phase and not in the target or bubbling phase. If useCapture is false, the listener processes the event only during the target or bubbling phase. To listen for the event in all three phases, call addEventListener twice, once with useCapture set to true, then again with useCapture set to false.
257		 * @param priority The priority level of the event listener. The priority is designated by a signed 32-bit integer. The higher the number, the higher the priority. All listeners with priority n are processed before listeners of priority n-1. If two or more listeners share the same priority, they are processed in the order in which they were added. The default priority is 0.
258		 * @param useWeakReference Determines whether the reference to the listener is strong or weak. A strong reference (the default) prevents your listener from being garbage-collected. A weak reference does not.
259		 */
260		public override function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
261		{
262			super.addEventListener(type, listener, useCapture, priority, useWeakReference);
263			
264			if ((type == Event.ENTER_FRAME || type == Event.EXIT_FRAME) && !_frameEventDriver.hasEventListener(Event.ENTER_FRAME))
265				_frameEventDriver.addEventListener(Event.ENTER_FRAME, onEnterFrame, useCapture, priority, useWeakReference);
266		}
267		
268		/**
269		 * Removes a listener from the EventDispatcher object. Special case for enterframe and exitframe events - will switch Stage3DProxy out of automatic render mode.
270		 * If there is no matching listener registered with the EventDispatcher object, a call to this method has no effect.
271		 *
272		 * @param type The type of event.
273		 * @param listener The listener object to remove.
274		 * @param useCapture Specifies whether the listener was registered for the capture phase or the target and bubbling phases. If the listener was registered for both the capture phase and the target and bubbling phases, two calls to removeEventListener() are required to remove both, one call with useCapture() set to true, and another call with useCapture() set to false.
275		 */
276		public override function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
277		{
278			super.removeEventListener(type, listener, useCapture);
279			
280			// Remove the main rendering listener if no EnterFrame listeners remain
281			if (!hasEventListener(Event.ENTER_FRAME) && !hasEventListener(Event.EXIT_FRAME) && _frameEventDriver.hasEventListener(Event.ENTER_FRAME))
282				_frameEventDriver.removeEventListener(Event.ENTER_FRAME, onEnterFrame, useCapture);
283		}
284		
285		public function get scissorRect():Rectangle
286		{
287			return _scissorRect;
288		}
289		
290		public function set scissorRect(value:Rectangle):void
291		{
292			_scissorRect = value;
293			_context3D.setScissorRectangle(_scissorRect);
294		}
295		
296		/**
297		 * The index of the Stage3D which is managed by this instance of Stage3DProxy.
298		 */
299		public function get stage3DIndex():int
300		{
301			return _stage3DIndex;
302		}
303		
304		/**
305		 * The base Stage3D object associated with this proxy.
306		 */
307		public function get stage3D():Stage3D
308		{
309			return _stage3D;
310		}
311		
312		/**
313		 * The Context3D object associated with the given Stage3D object.
314		 */
315		public function get context3D():Context3D
316		{
317			return _context3D;
318		}
319		
320		/**
321		 * The driver information as reported by the Context3D object (if any)
322		 */
323		public function get driverInfo():String
324		{
325			return _context3D? _context3D.driverInfo : null;
326		}
327		
328		/**
329		 * Indicates whether the Stage3D managed by this proxy is running in software mode.
330		 * Remember to wait for the CONTEXT3D_CREATED event before checking this property,
331		 * as only then will it be guaranteed to be accurate.
332		 */
333		public function get usesSoftwareRendering():Boolean
334		{
335			return _usesSoftwareRendering;
336		}
337		
338		/**
339		 * The x position of the Stage3D.
340		 */
341		public function get x():Number
342		{
343			return _stage3D.x;
344		}
345		
346		public function set x(value:Number):void
347		{
348			if (_viewPort.x == value)
349				return;
350			
351			_stage3D.x = _viewPort.x = value;
352			
353			notifyViewportUpdated();
354		}
355		
356		/**
357		 * The y position of the Stage3D.
358		 */
359		public function get y():Number
360		{
361			return _stage3D.y;
362		}
363		
364		public function set y(value:Number):void
365		{
366			if (_viewPort.y == value)
367				return;
368			
369			_stage3D.y = _viewPort.y = value;
370			
371			notifyViewportUpdated();
372		}
373		
374		/**
375		 * The width of the Stage3D.
376		 */
377		public function get width():int
378		{
379			return _backBufferWidth;
380		}
381		
382		public function set width(width:int):void
383		{
384			if (_viewPort.width == width)
385				return;
386
387			if(width<50) width = 50;
388			_backBufferWidth = _viewPort.width = width;
389			_backBufferDirty = true;
390
391			notifyViewportUpdated();
392		}
393		
394		/**
395		 * The height of the Stage3D.
396		 */
397		public function get height():int
398		{
399			return _backBufferHeight;
400		}
401		
402		public function set height(height:int):void
403		{
404			if (_viewPort.height == height)
405				return;
406
407			if(height<50) height = 50;
408			_backBufferHeight = _viewPort.height = height;
409			_backBufferDirty = true;
410			
411			notifyViewportUpdated();
412		}
413		
414		/**
415		 * The antiAliasing of the Stage3D.
416		 */
417		public function get antiAlias():int
418		{
419			return _antiAlias;
420		}
421		
422		public function set antiAlias(antiAlias:int):void
423		{
424			_antiAlias = antiAlias;
425			_backBufferDirty = true;
426		}
427		
428		/**
429		 * A viewPort rectangle equivalent of the Stage3D size and position.
430		 */
431		public function get viewPort():Rectangle
432		{
433			_viewportDirty = false;
434			
435			return _viewPort;
436		}
437		
438		/**
439		 * The background color of the Stage3D.
440		 */
441		public function get color():uint
442		{
443			return _color;
444		}
445		
446		public function set color(color:uint):void
447		{
448			_color = color;
449		}
450		
451		/**
452		 * The visibility of the Stage3D.
453		 */
454		public function get visible():Boolean
455		{
456			return _stage3D.visible;
457		}
458		
459		public function set visible(value:Boolean):void
460		{
461			_stage3D.visible = value;
462		}
463		
464		/**
465		 * The freshly cleared state of the backbuffer before any rendering
466		 */
467		public function get bufferClear():Boolean
468		{
469			return _bufferClear;
470		}
471		
472		public function set bufferClear(newBufferClear:Boolean):void
473		{
474			_bufferClear = newBufferClear;
475		}
476		
477		/*
478		 * Access to fire mouseevents across multiple layered view3D instances
479		 */
480		public function get mouse3DManager():Mouse3DManager
481		{
482			return _mouse3DManager;
483		}
484		
485		public function set mouse3DManager(value:Mouse3DManager):void
486		{
487			_mouse3DManager = value;
488		}
489		
490		public function get touch3DManager():Touch3DManager
491		{
492			return _touch3DManager;
493		}
494		
495		public function set touch3DManager(value:Touch3DManager):void
496		{
497			_touch3DManager = value;
498		}
499		
500		/**
501		 * Frees the Context3D associated with this Stage3DProxy.
502		 */
503		private function freeContext3D():void
504		{
505			if (_context3D) {
506				_context3D.dispose();
507				dispatchEvent(new Stage3DEvent(Stage3DEvent.CONTEXT3D_DISPOSED));
508			}
509			_context3D = null;
510		}
511		
512		/*
513		 * Called whenever the Context3D is retrieved or lost.
514		 * @param event The event dispatched.
515		 */
516		private function onContext3DUpdate(event:Event):void
517		{
518			if (_stage3D.context3D) {
519				var hadContext:Boolean = (_context3D != null);
520				_context3D = _stage3D.context3D;
521				_context3D.enableErrorChecking = Debug.active;
522				
523				_usesSoftwareRendering = (_context3D.driverInfo.indexOf('Software') == 0);
524
525				// Only configure back buffer if width and height have been set,
526				// which they may not have been if View3D.render() has yet to be
527				// invoked for the first time.
528				if (_backBufferWidth && _backBufferHeight)
529					_context3D.configureBackBuffer(_backBufferWidth, _backBufferHeight, _antiAlias, _backBufferEnableDepthAndStencil);
530				
531				// Dispatch the appropriate event depending on whether context was
532				// created for the first time or recreated after a device loss.
533				dispatchEvent(new Stage3DEvent(hadContext? Stage3DEvent.CONTEXT3D_RECREATED : Stage3DEvent.CONTEXT3D_CREATED));
534				
535			} else
536				throw new Error("Rendering context lost!");
537		}
538		
539		/**
540		 * Requests a Context3D object to attach to the managed Stage3D.
541		 */
542		private function requestContext(forceSoftware:Boolean = false, profile:String = "baseline"):void
543		{
544			// If forcing software, we can be certain that the
545			// returned Context3D will be running software mode.
546			// If not, we can't be sure and should stick to the
547			// old value (will likely be same if re-requesting.)
548			_usesSoftwareRendering ||= forceSoftware;
549			_profile = profile;
550			
551			// ugly stuff for backward compatibility
552			var renderMode:String = forceSoftware? Context3DRenderMode.SOFTWARE : Context3DRenderMode.AUTO;
553			if (profile == "baseline")
554				_stage3D.requestContext3D(renderMode);
555			else {
556				try {
557					_stage3D["requestContext3D"](renderMode, profile);
558				} catch (error:Error) {
559					throw "An error occurred creating a context using the given profile. Profiles are not supported for the SDK this was compiled with.";
560				}
561			}
562			
563			_contextRequested = true;
564		}
565		
566		/**
567		 * The Enter_Frame handler for processing the proxy.ENTER_FRAME and proxy.EXIT_FRAME event handlers.
568		 * Typically the proxy.ENTER_FRAME listener would render the layers for this Stage3D instance.
569		 */
570		private function onEnterFrame(event:Event):void
571		{
572			if (!_context3D)
573				return;
574			
575			// Clear the stage3D instance
576			clear();
577			
578			//notify the enterframe listeners
579			notifyEnterFrame();
580			
581			// Call the present() to render the frame
582			present();
583			
584			//notify the exitframe listeners
585			notifyExitFrame();
586		}
587		
588		public function recoverFromDisposal():Boolean
589		{
590			if (!_context3D)
591				return false;
592			if (_context3D.driverInfo == "Disposed") {
593				_context3D = null;
594				dispatchEvent(new Stage3DEvent(Stage3DEvent.CONTEXT3D_DISPOSED));
595				return false;
596			}
597			return true;
598		}
599		
600		public function clearDepthBuffer():void
601		{
602			if (!_context3D)
603				return;
604			_context3D.clear(0, 0, 0, 1, 1, 0, Context3DClearMask.DEPTH);
605		}
606
607		public function get backBufferEnableDepthAndStencil():Boolean {
608			return _backBufferEnableDepthAndStencil;
609		}
610
611		public function set backBufferEnableDepthAndStencil(value:Boolean):void {
612			_backBufferEnableDepthAndStencil = value;
613			_backBufferDirty = true;
614		}
615	}
616}