/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

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