/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

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