PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/src/as/com/threerings/flashbang/pushbutton/scene/Scene2DComponent.as

http://libdamago.googlecode.com/
ActionScript | 725 lines | 337 code | 109 blank | 279 comment | 66 complexity | 6c2e345b0708828fd509e0ab59c66935 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.threerings.flashbang.pushbutton.scene {
  2. import com.pblabs.engine.core.IAnimatedObject;
  3. import com.pblabs.engine.entity.PropertyReference;
  4. import com.threerings.util.ArrayUtil;
  5. import com.threerings.util.ClassUtil;
  6. import com.threerings.util.Log;
  7. import com.threerings.util.Map;
  8. import com.threerings.util.Maps;
  9. import com.threerings.util.MathUtil;
  10. import flash.display.Graphics;
  11. import flash.display.Sprite;
  12. import flash.events.Event;
  13. import flash.geom.*;
  14. import net.amago.pbe.base.EntityComponentListener;
  15. import net.amago.pbe.base.LocationComponent;
  16. /**
  17. * Basic Rendering2D scene; it is given a SceneView and some
  18. * DisplayObjectRenderers, and makes sure that they are drawn. Extensible
  19. * for more complex rendering scenarios. Enforces sorting order, too.
  20. */
  21. public class Scene2DComponent extends EntityComponentListener
  22. implements IAnimatedObject
  23. {
  24. public static const COMPONENT_NAME :String = ClassUtil.tinyClassName(Scene2DComponent);
  25. public var dirty :Boolean;
  26. /**
  27. * Maximum allowed zoom level.
  28. *
  29. * @see zoom
  30. */
  31. public var maxZoom :Number = 5;
  32. /**
  33. * Minimum allowed zoom level.
  34. *
  35. * @see zoom
  36. */
  37. public var minZoom :Number = .01;
  38. /**
  39. * How the scene is aligned relative to its position property.
  40. *
  41. * @see SceneAlignment
  42. * @see position
  43. */
  44. public var sceneAlignment :SceneAlignment = SceneAlignment.DEFAULT_ALIGNMENT;
  45. /**
  46. * If set, every frame, trackObject's position is read and assigned
  47. * to the scene's position, so that the scene follows the trackObject.
  48. */
  49. public var trackObject :LocationComponent;
  50. // public var sceneBoundsRef :RectangleReference;
  51. public function Scene2DComponent (sceneName :String = null)
  52. {
  53. _sceneName = sceneName;
  54. // Get ticked after all the renderers.
  55. // updatePriority = -10;
  56. _rootSprite = new Sprite();//generateRootSprite();
  57. }
  58. public function get componentReference () :PropertyReference
  59. {
  60. if (null != _selfReference) {
  61. return _selfReference;
  62. }
  63. _selfReference = new PropertyReference("#" + owner.name + "." + name);
  64. return _selfReference;
  65. }
  66. public function set debug (val :Boolean) : void
  67. {
  68. var g :Graphics = rootSprite.graphics;
  69. g.clear();
  70. if (val && sceneBounds != null) {
  71. g.lineStyle(1, 0xff0000);
  72. // g.drawRect(
  73. // DebugUtil.drawRect(this, _width, _height, 0);
  74. }
  75. }
  76. public function get layerCount () :int
  77. {
  78. return _layers.length;
  79. }
  80. override public function get name () :String
  81. {
  82. return _sceneName == null ? COMPONENT_NAME : _sceneName;
  83. }
  84. public function get position () :Point
  85. {
  86. return _rootPosition.clone();
  87. }
  88. public function set positionX (newX :Number) :void
  89. {
  90. if (_rootPosition.x == newX) {
  91. return;
  92. }
  93. _rootPosition.x = newX;
  94. _transformDirty = true;
  95. }
  96. public function set positionY (newY :Number) :void
  97. {
  98. if (_rootPosition.y == newY) {
  99. return;
  100. }
  101. _rootPosition.y = newY;
  102. _transformDirty = true;
  103. }
  104. public function set position (value :Point) :void
  105. {
  106. if (!value) {
  107. return;
  108. }
  109. var newX :Number = value.x;
  110. var newY :Number = value.y;
  111. if (_rootPosition.x == newX && _rootPosition.y == newY) {
  112. return;
  113. }
  114. // trace("Setting _rootPosition.x=" + newX);
  115. _rootPosition.x = newX;
  116. _rootPosition.y = newY;
  117. _transformDirty = true;
  118. }
  119. public function get rootSprite () :Sprite
  120. {
  121. return _rootSprite;
  122. }
  123. // public function get sceneViewBounds () :Rectangle
  124. // {
  125. // if (!sceneView) {
  126. // return null;
  127. // }
  128. //
  129. // // Make sure we are up to date with latest track.
  130. // if (trackObject) {
  131. // position = new Point(-(trackObject.x), -(trackObject.y));
  132. // }
  133. //
  134. // if (viewBounds != null) {
  135. // var centeredLimitBounds :Rectangle =
  136. // new Rectangle(viewBounds.x + sceneView.width * 0.5,
  137. // viewBounds.y + sceneView.height * 0.5,
  138. // viewBounds.width - sceneView.width,
  139. // viewBounds.height - sceneView.height);
  140. //
  141. // position = new Point(PBUtil.clamp(position.x, -centeredLimitBounds.right,
  142. // -centeredLimitBounds.left), PBUtil.clamp(position.y, -centeredLimitBounds.bottom,
  143. // -centeredLimitBounds.top));
  144. // }
  145. //
  146. // updateTransform();
  147. //
  148. // // What region of the scene are we currently viewing?
  149. // SceneAlignment.calculate(_tempPoint, sceneAlignment, sceneView.width / zoom,
  150. // sceneView.height / zoom);
  151. //
  152. // _sceneViewBoundsCache.x = -position.x - _tempPoint.x;
  153. // _sceneViewBoundsCache.y = -position.y - _tempPoint.y;
  154. // _sceneViewBoundsCache.width = sceneView.width / zoom;
  155. // _sceneViewBoundsCache.height = sceneView.height / zoom;
  156. //
  157. // return _sceneViewBoundsCache;
  158. // }
  159. // public function set sceneViewName (value :String) :void
  160. // {
  161. // _sceneViewName = value;
  162. // }
  163. /**
  164. * @inheritDoc
  165. */
  166. public function get sceneBounds () :Rectangle
  167. {
  168. // if (_sceneBounds != null) {
  169. return _sceneBounds;
  170. // }
  171. // if (sceneBoundsRef != null && sceneBoundsRef.value != null) {
  172. // return sceneBoundsRef.value;
  173. // }
  174. // return null;
  175. }
  176. public function set sceneBounds (value :Rectangle) :void
  177. {
  178. _sceneBounds = value;
  179. }
  180. public function get sceneView () :SceneView
  181. {
  182. return _sceneView;
  183. }
  184. public function set sceneView (value :SceneView) :void
  185. {
  186. if (_sceneView != null) {
  187. _sceneView.removeDisplayObject(_rootSprite);
  188. }
  189. _sceneView = value;
  190. if (_sceneView != null) {
  191. _sceneView.addDisplayObject(_rootSprite);
  192. _currentViewRect.width = _sceneView.width;
  193. _currentViewRect.height = _sceneView.height;
  194. }
  195. }
  196. public function get zoom () :Number
  197. {
  198. return _zoom;
  199. }
  200. public function set zoom (value :Number) :void
  201. {
  202. // Make sure our zoom level stays within the desired bounds
  203. value = MathUtil.clamp(value, minZoom, maxZoom);
  204. if (_zoom == value)
  205. return;
  206. _zoom = value;
  207. _transformDirty = true;
  208. }
  209. public function containsComponent (comp :SceneEntityComponent) :Boolean
  210. {
  211. return _sceneComponents.containsKey(comp);
  212. }
  213. public function getLayerContaining (comp :SceneEntityComponent) :SceneLayer
  214. {
  215. return _sceneComponents.get(comp) as SceneLayer;
  216. }
  217. public function addLayer (layer :SceneLayer, name :String = null, idx :int = -1) :void
  218. {
  219. if (null == layer) {
  220. throw new Error ("null layer");
  221. }
  222. if (null != layer._parentScene) {
  223. throw new Error ("layer already attached to a scene");
  224. }
  225. if (null != _layers[idx]) {
  226. throw new Error ("setLayer at " + idx + ", index occupied");
  227. }
  228. if (idx == -1) {
  229. idx = _layers.length;
  230. }
  231. _layers[idx] = layer;
  232. _rootSprite.addChildAt(layer, idx);
  233. if (null != name) {
  234. layer.name = name;
  235. }
  236. layer.attachedInternal();
  237. }
  238. public function addSceneComponent (obj :SceneEntityComponent) :void
  239. {
  240. if (_sceneComponents.containsKey(obj)) {
  241. throw new Error("Already contains obj " + obj);
  242. }
  243. if (null == obj) {
  244. throw new Error("obj is null");
  245. }
  246. if (null == obj.displayObject) {
  247. throw new Error("obj.displayObject is null");
  248. }
  249. var layerName :String = obj.layer;
  250. if (null == layerName) {
  251. log.warning("obj.sceneLayerName is null, using the default layer");
  252. layerName = DEFAULT_LAYER_NAME;
  253. }
  254. var layer :SceneLayer = getLayer(layerName);
  255. if (null == layer) {
  256. throw new Error("No layer named " + layerName);
  257. }
  258. _sceneComponents.put(obj, layer);
  259. layer.addObjectInternal(obj);
  260. obj._scene = this;
  261. dirty = true;
  262. }
  263. public function getDefaultLayer () :SceneLayer
  264. {
  265. if (null == _layers[0]) {
  266. var layer :SceneLayer = new SceneLayer();
  267. addLayer(layer, DEFAULT_LAYER_NAME, 0);
  268. return layer;
  269. }
  270. return _layers[0] as SceneLayer;
  271. }
  272. public function getLayer (layerName :String) :SceneLayer
  273. {
  274. for each (var layer :SceneLayer in _layers) {
  275. if (null != layer && layer.name == layerName) {
  276. return layer;
  277. }
  278. }
  279. return null;
  280. }
  281. public function getLayerAt (idx :uint) :SceneLayer
  282. {
  283. return _layers[idx] as SceneLayer;
  284. }
  285. // public function add (dor :DisplayObjectRenderer) :void
  286. // {
  287. // // Add to the appropriate layer.
  288. // var layer :SceneLayer = getLayer(dor.layerIndex, true);
  289. // layer.add(dor);
  290. // if (dor.displayObject)
  291. // _renderers[dor.displayObject] = dor;
  292. // }
  293. //
  294. // public function getLayer (index :int, allocateIfAbsent :Boolean =
  295. // false) :SceneLayer
  296. // {
  297. // // Maybe it already exists.
  298. // if (_layers[index])
  299. // return _layers[index];
  300. //
  301. // if (allocateIfAbsent == false)
  302. // return null;
  303. //
  304. // // Allocate the layer.
  305. // _layers[index] = generateLayer(index);
  306. //
  307. // // Order the layers. This is suboptimal but we are probably not going
  308. // // to be adding a lot of layers all the time.
  309. // while (_rootSprite.numChildren)
  310. // _rootSprite.removeChildAt(_rootSprite.numChildren - 1);
  311. // for (var i :int = 0; i < layerCount; i++) {
  312. // if (_layers[i])
  313. // _rootSprite.addChild(_layers[i]);
  314. // }
  315. //
  316. // // Return new layer.
  317. // return _layers[index];
  318. // }
  319. // public function getRenderersUnderPoint (screenPosition :Point, mask :ObjectType = null) :Array
  320. // {
  321. // // Query normal DO hierarchy.
  322. // var unfilteredResults :Array = _rootSprite.getObjectsUnderPoint(screenPosition);
  323. // var worldPosition :Point = transformScreenToWorld(screenPosition);
  324. //
  325. // // TODO: rewrite to splice from unfilteredResults to avoid alloc?
  326. // var results :Array = new Array();
  327. //
  328. // for each (var o :*in unfilteredResults) {
  329. // var renderer :DisplayObjectRenderer = getRendererForDisplayObject(o);
  330. //
  331. // if (!renderer)
  332. // continue;
  333. //
  334. // if (!renderer.owner)
  335. // continue;
  336. //
  337. // if (mask && !ObjectTypeManager.instance.doTypesOverlap(mask, renderer.objectMask))
  338. // continue;
  339. //
  340. // if (!renderer.pointOccupied(worldPosition))
  341. // continue;
  342. //
  343. // results.push(renderer);
  344. // }
  345. //
  346. // // Also give layers opportunity to return renderers.
  347. // var scenePosition :Point = transformScreenToScene(screenPosition);
  348. // for each (var l :SceneLayer in _layers) {
  349. // // Skip them if they don't use the interface.
  350. // if (!(l is ILayerMouseHandler))
  351. // continue;
  352. //
  353. // (l as ILayerMouseHandler).getRenderersUnderPoint(scenePosition, mask, results);
  354. // }
  355. //
  356. // return results;
  357. // }
  358. // public function invalidate (dirtyRenderer :DisplayObjectRenderer) :void
  359. // {
  360. // var layerToDirty :SceneLayer = getLayer(dirtyRenderer.layerIndex);
  361. // if (!layerToDirty)
  362. // return;
  363. //
  364. // if (layerToDirty is ICachingLayer)
  365. // ICachingLayer(layerToDirty).invalidate(dirtyRenderer);
  366. // }
  367. //
  368. // public function invalidateRectangle (dirty :Rectangle) :void
  369. // {
  370. // for each (var l :SceneLayer in _layers) {
  371. // if (l is ICachingLayer)
  372. // (l as ICachingLayer).invalidateRectangle(dirty);
  373. // }
  374. // }
  375. //
  376. // public function remove (dor :DisplayObjectRenderer) :void
  377. // {
  378. // var layer :SceneLayer = getLayer(dor.layerIndex, false);
  379. // if (!layer)
  380. // return;
  381. //
  382. // layer.remove(dor);
  383. // if (dor.displayObject)
  384. // delete _renderers[dor.displayObject];
  385. // }
  386. public function panView (deltaX :Number, deltaY :Number) :void
  387. {
  388. if (deltaX == 0 && deltaY == 0) {
  389. return;
  390. }
  391. // TODO: Take into account rotation so it's correct even when
  392. // rotating.
  393. var before :Number = _rootPosition.x;
  394. _rootPosition.x -= deltaX / _zoom;
  395. // trace("deltaX=", before, _rootPosition.x);
  396. // trace("Before/after=", before, _rootPosition.x);
  397. _rootPosition.y -= deltaY / _zoom;
  398. _transformDirty = true;
  399. }
  400. public function removeSceneComponent (obj :SceneEntityComponent) :void
  401. {
  402. if (!_sceneComponents.containsKey(obj)) {
  403. log.warning("Doesn't contain " + obj);
  404. return;
  405. }
  406. var layer :SceneLayer = _sceneComponents.get(obj) as SceneLayer;
  407. if (null == layer) {
  408. throw new Error("No associated layer for " + obj);
  409. }
  410. layer.removeObjectInternal(obj);
  411. _sceneComponents.remove(obj);
  412. obj._scene = null;
  413. }
  414. public function setWorldCenter (pos :Point) :void
  415. {
  416. if (!sceneView)
  417. throw new Error("sceneView not yet set. can't center the world.");
  418. position = transformWorldToScreen(pos);
  419. }
  420. public function transformSceneToScreen (inPos :Point) :Point
  421. {
  422. return _rootSprite.localToGlobal(inPos);
  423. }
  424. public function transformSceneToWorld (inPos :Point) :Point
  425. {
  426. return inPos;
  427. }
  428. public function transformScreenToScene (inPos :Point) :Point
  429. {
  430. return _rootSprite.globalToLocal(inPos);
  431. }
  432. public function transformScreenToWorld (inPos :Point) :Point
  433. {
  434. return _rootSprite.globalToLocal(inPos);
  435. }
  436. public function transformWorldToScene (inPos :Point) :Point
  437. {
  438. return inPos;
  439. }
  440. public function transformWorldToScreen (inPos :Point) :Point
  441. {
  442. return _rootSprite.localToGlobal(inPos);
  443. }
  444. public function onFrame (dt :Number) :void
  445. {
  446. // trace("updating scene");
  447. if (!sceneView) {
  448. log.warning(this + " sceneView is null, so we aren't rendering.");
  449. return;
  450. }
  451. if (trackObject) {
  452. position = new Point(-(trackObject.x), -(trackObject.y));
  453. }
  454. // if (sceneBounds != null) {
  455. // var centeredLimitBounds :Rectangle =
  456. // new Rectangle(sceneBounds.x + sceneView.width * 0.5,
  457. // sceneBounds.y + sceneView.height * 0.5,
  458. // sceneBounds.width - sceneView.width,
  459. // sceneBounds.height - sceneView.height);
  460. //
  461. // position = new Point(MathUtil.clamp(position.x, -centeredLimitBounds.right,
  462. // -centeredLimitBounds.left), MathUtil.clamp(position.y, -centeredLimitBounds.bottom,
  463. // -centeredLimitBounds.top));
  464. // }
  465. updateTransform();
  466. //Check layers
  467. // Give layers a chance to sort and update.
  468. for each (var l :SceneLayer in _layers) {
  469. l.renderInternal();
  470. }
  471. }
  472. // protected function get sceneBounds () :Rectangle
  473. // {
  474. //
  475. // }
  476. public function updateTransform () :void
  477. {
  478. // trace("scene updateTransform _transformDirty=", _transformDirty);
  479. if (_transformDirty == false) {
  480. return;
  481. }
  482. _transformDirty = false;
  483. if (_sceneBounds != null) {
  484. // trace("panning");
  485. //TODO: doesn't take into account zooming yet
  486. //Check that we're inside the scene bounds
  487. //Check x, starting with the right.
  488. var minViewX :Number = -(_sceneBounds.right - _sceneView.width * _zoom);
  489. // trace("minViewX=" + minViewX);
  490. // trace("_sceneBounds.right=" + _sceneBounds.right);
  491. var maxViewX :Number = -_sceneBounds.left;
  492. // trace("minmaxX=", minViewX, maxViewX);
  493. var minViewY :Number = -(_sceneBounds.bottom - _sceneView.height * _zoom);
  494. var maxViewY :Number = -_sceneBounds.top;
  495. // trace("clampedX=" + MathUtil.clamp(_rootPosition.x, minViewX, maxViewX));
  496. _rootPosition.x = MathUtil.clamp(_rootPosition.x, minViewX, maxViewX);
  497. // trace("After clamping=" + _rootPosition.x);
  498. _rootPosition.y = MathUtil.clamp(_rootPosition.y, minViewY, maxViewY);
  499. // _rootSprite.x = _rootPosition.x;
  500. // _rootSprite.y = _rootPosition.y;
  501. }
  502. // return;
  503. // trace("updating scene transform");
  504. // _transformDirty = false;
  505. // Update our transform, if required
  506. _rootTransform.identity();
  507. _rootTransform.translate(_rootPosition.x, _rootPosition.y);
  508. _rootTransform.scale(zoom, zoom);
  509. // trace("Scene zoom=" + zoom);
  510. // Center it appropriately.
  511. // SceneAlignment.calculate(_tempPoint, SceneAlignment.TOP_LEFT, sceneView.width,
  512. // sceneView.height);
  513. // _rootTransform.translate(_tempPoint.x, _tempPoint.y);
  514. _rootSprite.transform.matrix = _rootTransform;
  515. _currentViewRect.x = -_rootPosition.x;
  516. _currentViewRect.y = -_rootPosition.y;
  517. // trace("updating scene transform, scale=" + _rootSprite.scaleX);
  518. }
  519. public function get currentViewRect () :Rectangle
  520. {
  521. if (_sceneView == null) {
  522. return null;
  523. }
  524. return _currentViewRect;
  525. // return new Rectangle(-_rootPosition.x, -_rootPosition.y, _sceneView.width, _sceneView.height);
  526. }
  527. override protected function onRemove () :void
  528. {
  529. super.onRemove();
  530. // Make sure we don't leave any lingering content.
  531. if (_sceneView) {
  532. // _sceneView.clearDisplayObjects();
  533. }
  534. }
  535. // /**
  536. // * Convenience funtion for subclasses to control what class of layer
  537. // * they are using.
  538. // */
  539. // protected function generateLayer (layerIndex :int) :SceneLayer
  540. // {
  541. // var l :SceneLayer = new SceneLayer();
  542. //
  543. // //TODO: set any properties we want for our layer.
  544. //
  545. // return l;
  546. // }
  547. // /**
  548. // * Convenience function for subclasses to create a custom root sprite.
  549. // */
  550. // protected function generateRootSprite () :Sprite
  551. // {
  552. // var s :Sprite = new Sprite();
  553. //
  554. // //TODO: set any properties we want for our root host sprite
  555. //
  556. // return s;
  557. // }
  558. // protected function getRendererForDisplayObject (displayObject :DisplayObject) :DisplayObjectRenderer
  559. // {
  560. // var current :DisplayObject = displayObject;
  561. //
  562. // // Walk up the display tree looking for a DO we know about.
  563. // while (current) {
  564. // // See if it's a DOR.
  565. // var renderer :DisplayObjectRenderer = _renderers[current] as DisplayObjectRenderer;
  566. // if (renderer)
  567. // return renderer;
  568. //
  569. // // If we get to a layer, we know we're done.
  570. // if (renderer is SceneLayer)
  571. // return null;
  572. //
  573. // // Go up the tree..
  574. // current = current.parent;
  575. // }
  576. //
  577. // // No match!
  578. // return null;
  579. // }
  580. protected function sceneViewResized (event :Event) :void
  581. {
  582. _transformDirty = true;
  583. }
  584. internal function removeLayer (layer :SceneLayer) :void
  585. {
  586. if (!ArrayUtil.contains(_layers, layer)) {
  587. throw new Error("No layer: " + layer);
  588. }
  589. _layers[ArrayUtil.indexOf(_layers, layer)] = null;
  590. layer.detachedInternal();
  591. layer._parentScene = null;
  592. _rootSprite.removeChild(layer);
  593. }
  594. protected var _currentWorldCenter :Point = new Point();
  595. protected var _layers :Array = [];
  596. // protected var _renderers :Dictionary = new Dictionary(true);
  597. protected var _rootPosition :Point = new Point();
  598. // protected var _rootRotation :Number = 0;
  599. protected var _rootSprite :Sprite;
  600. protected var _rootTransform :Matrix = new Matrix();
  601. protected var _sceneBounds :Rectangle = null;
  602. /** Objects mapped to layers*/
  603. protected var _sceneComponents :Map = Maps.newMapOf(Object);
  604. // protected var _sceneViewBoundsCache :Rectangle = new Rectangle();
  605. // protected var _sceneViewName :String = null;
  606. protected var _sceneName :String = null;
  607. protected var _sceneView :SceneView;
  608. protected var _selfReference :PropertyReference;
  609. protected var _tempPoint :Point = new Point();
  610. protected var _transformDirty :Boolean = true;
  611. protected var _currentViewRect :Rectangle = new Rectangle();
  612. protected var _zoom :Number = 1;
  613. protected static const DEFAULT_LAYER_NAME :String = "defaultLayer";
  614. protected static const log :Log = Log.getLog(Scene2DComponent);
  615. }
  616. }