BasePV3DContainer.as
上传用户:chuer333
上传日期:2022-06-13
资源大小:906k
文件大小:13k
源码类别:

FlashMX/Flex源码

开发平台:

Flex

  1. package com.dougmccune.containers
  2. {
  3. import caurina.transitions.Tweener;
  4. import com.dougmccune.containers.materials.FlexMaterial;
  5. import com.dougmccune.containers.materials.ReflectionFlexMaterial;
  6. import flash.display.DisplayObject;
  7. import flash.display.Sprite;
  8. import flash.events.Event;
  9. import flash.events.MouseEvent;
  10. import flash.events.TimerEvent;
  11. import flash.geom.Rectangle;
  12. import flash.utils.Dictionary;
  13. import flash.utils.Timer;
  14. import mx.containers.ViewStack;
  15. import mx.core.ContainerCreationPolicy;
  16. import mx.core.UIComponent;
  17. import mx.core.mx_internal;
  18. import mx.events.FlexEvent;
  19. import org.papervision3d.Papervision3D;
  20. import org.papervision3d.cameras.Camera3D;
  21. import org.papervision3d.core.culling.RectangleTriangleCuller;
  22. import org.papervision3d.core.proto.CameraObject3D;
  23. import org.papervision3d.materials.BitmapMaterial;
  24. import org.papervision3d.materials.MovieMaterial;
  25. import org.papervision3d.objects.DisplayObject3D;
  26. import org.papervision3d.objects.Plane;
  27. import org.papervision3d.scenes.MovieScene3D;
  28. import org.papervision3d.scenes.Scene3D;
  29. use namespace mx_internal;
  30. [Style(name="horizontalSpacing", type="Number", format="Length", inherit="no")]
  31. [Style(name="verticalSpacing", type="Number", format="Length", inherit="no")]
  32. public class BasePV3DContainer extends ViewStack
  33. {
  34. /**
  35.  * The time for each tween. Setting this lower will make the animations faster (but maybe choppier if the
  36.  * CPU can't keep up).
  37.  */
  38. public var tweenDuration:Number = 1;
  39. /**
  40.  * Is the reflection enabled? If so we create two 3D planes for each child. This effectively means that
  41.  * PaperVision has to render twice as many polygons if you enable the reflection, whch will slow performance. 
  42.  * But it looks nice.
  43.  */
  44. public function get reflectionEnabled():Boolean {
  45. return _reflectionEnabled;
  46. }
  47. public function set reflectionEnabled(value:Boolean):void {
  48. _reflectionEnabled = value;
  49. }
  50. private var _reflectionEnabled:Boolean = false;
  51. /**
  52.  * The number of segments used for the PaperVision Planes that are created. The lower the number the better
  53.  * the performance, but you'll notice distortion in your images when they are rotated. For some types of images 
  54.  * a value as low as 1 or 2 will work fine, but for things wil horizontal lines or text, you'll have to go higher.
  55.  */
  56. public var segments:Number = 6;
  57. /**
  58.  * @private
  59.  * 
  60.  * We're going to have a sprite that contains our PV3D scene added to the
  61.  * display list, which falls outside of the stuff that gets clipped normally by
  62.  * the container. So if we want to clip the content like you would expect from a 
  63.  * Container then we have to do our own clipping.
  64.  */
  65. private var clippingMask:Sprite;
  66. /**
  67.  * @private
  68.  * 
  69.  * This is the main Sprite that will get rendered with our 3D scene.
  70.  */
  71. private var pv3dSprite:Sprite;
  72. /**
  73.  * @private
  74.  * 
  75.  * The Scene3D that PaperVision will render. This will get rendered to the pv3dSprite object.
  76.  */
  77. protected var scene:Scene3D;
  78. /**
  79.  * @private
  80.  * 
  81.  * The Camera3D object that controls how we render the scene.
  82.  */
  83. protected var camera:CameraObject3D;
  84. /**
  85.  * @private
  86.  * 
  87.  * A Dictionary we'll use to store a reference to the Plane object we create. The key will be the DisplayObject and the
  88.  * value will be the Plane, that way we can take any child DIsplayObject and look up the 3D Plane.
  89.  */
  90. private var objectsToPlanes:Dictionary;
  91. /**
  92.  * @private
  93.  * 
  94.  * Same thing for the reflection Planes. Gotta be able to take any DIsplayObject and look up the reflection
  95.  * for that object.
  96.  */
  97. private var objectsToReflections:Dictionary;
  98. /**
  99.  * @private
  100.  * 
  101.  * We want to detect clicks on the 3D Planes, but we don't want to use the complex interactivity crap in PV3D.
  102.  * (It's not actually crap, it's awesome, but it's slow). So instead, since we're using a MovieScene3D, we can 
  103.  * simply access the container proeprty of any 3D object to get access to the DisplayObjec that it is in. Then
  104.  * we can use this container for our mouse click detection. So we need to be able take any of those container DIsplayObjects
  105.  * and look up the original child that it's associated with.
  106.  */
  107. private var containersToObjects:Dictionary;
  108. /**
  109.  * @private
  110.  * 
  111.  * When the 3D transition is complete and the selected child faces the user face on, then we want to substitute
  112.  * the real child in it's place, so that the user can interact with it. To do this we use a timer that gets reset 
  113.  * everytime a tween is started. Then once the tween has successfully completed, which means the selected child is
  114.  * directly facing the user, we do the old switcheroo.
  115.  */
  116. private var timer:Timer;
  117. public var autoUpdateFlexMaterials:Boolean = false;
  118. public function BasePV3DContainer():void {
  119. super();
  120. //since we need to show all the children we have to make sure that
  121. //creationPolicy is set to all. Otherwise the other non-selected 
  122. //children would be blank until they were selected and that would look lame.
  123. this.creationPolicy = ContainerCreationPolicy.ALL;
  124. //crate our dictionaries, using weak keys
  125. objectsToPlanes = new Dictionary(true);
  126. objectsToReflections = new Dictionary(true);
  127. containersToObjects = new Dictionary(true);
  128. timer = new Timer(tweenDuration*1000, 1);
  129. timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerComplete);
  130. pv3dSprite = new Sprite();
  131. setupScene();
  132. }
  133. override protected function createChildren():void {
  134. super.createChildren();
  135. clippingMask = new Sprite();
  136. rawChildren.addChild(clippingMask);
  137. rawChildren.addChildAt(pv3dSprite, 0);
  138. //we're just going to render the 3D scene on every frame
  139. this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
  140. }
  141. protected function setupScene():void {
  142. //turn off the debugging trace statements for PV3D
  143. Papervision3D.VERBOSE = false;
  144. //create a new MovieScene3D and tell it to draw to pv3dSprite
  145. scene = new MovieScene3D(pv3dSprite);
  146. scene.triangleCuller = new RectangleTriangleCuller();
  147. //create a new Camera3D
  148. camera = new Camera3D();
  149. camera.z = -200;
  150. }
  151. protected function enterFrameHandler(event:Event):void {
  152. try {
  153. if(selectedChild != null){
  154. var plane:Plane = objectsToPlanes[selectedChild];
  155. if(Tweener.isTweening(plane)){
  156. scene.renderCamera(camera);
  157. }
  158. }
  159. }
  160. catch(e:Error) { }
  161. }
  162. override public function addChild(child:DisplayObject):DisplayObject {
  163. var child:DisplayObject = super.addChild(child);
  164. if(child.width > 0 && child.height > 0) {
  165. createPlaneForChild(child);
  166. }
  167. if(child is UIComponent && autoUpdateFlexMaterials) {
  168. UIComponent(child).addEventListener(FlexEvent.UPDATE_COMPLETE, child_renderHandler);
  169. }
  170. return child;
  171. }
  172. private function replacePlaneForChild(child:DisplayObject):void {
  173. var oldPlane:Plane = lookupPlane(child) as Plane;
  174. var oldX:Number = oldPlane.x;
  175. var oldY:Number = oldPlane.y;
  176. var oldZ:Number = oldPlane.z;
  177. var oldRotationX:Number = oldPlane.rotationX;
  178. var oldRotationY:Number = oldPlane.rotationY;
  179. var oldRotationZ:Number = oldPlane.rotationZ;
  180. destroyPlane(child);
  181. var plane:Plane = createPlane(child);
  182. plane.x = oldX;
  183. plane.y = oldY;
  184. plane.z = oldZ;
  185. plane.rotationX = oldRotationX;
  186. plane.rotationY = oldRotationY;
  187. plane.rotationZ = oldRotationZ;
  188. scene.addChild(plane);
  189. containersToObjects[plane.container] = child;
  190. //once the Plane is added to the scene we can access the container property, which we use to handle
  191. //mouse clicks
  192. plane.container.addEventListener(MouseEvent.CLICK, containerClicked);
  193. objectsToPlanes[child] = plane;
  194. }
  195. protected function createPlaneForChild(child:DisplayObject):void {
  196. var plane:Plane = createPlane(child);
  197. scene.addChild(plane);
  198. containersToObjects[plane.container] = child;
  199. //once the Plane is added to the scene we can access the container property, which we use to handle
  200. //mouse clicks
  201. plane.container.addEventListener(MouseEvent.CLICK, containerClicked);
  202. objectsToPlanes[child] = plane;
  203. }
  204. private function createPlane(child:DisplayObject):Plane {
  205. var childWidth:Number = child is UIComponent ? UIComponent(child).getExplicitOrMeasuredWidth() : child.width;
  206. var childHeight:Number = child is UIComponent ? UIComponent(child).getExplicitOrMeasuredHeight() : child.height;
  207. if(reflectionEnabled) {
  208. var reflMaterial:MovieMaterial = new ReflectionFlexMaterial(child);
  209. var reflection:Plane = new Plane(reflMaterial, childWidth, childHeight, segments, segments);
  210. scene.addChild(reflection);
  211. objectsToReflections[child] = reflection;
  212. }
  213. child.width = childWidth;
  214. child.height = childHeight;
  215. var material:MovieMaterial = new FlexMaterial(child, true);
  216. material.smooth = true;
  217. var plane:Plane = new Plane(material, childWidth, childHeight, segments, segments);
  218. return plane;
  219. }
  220. private function child_renderHandler(event:Event):void {
  221. var child:UIComponent = event.currentTarget as UIComponent;
  222. var plane:Plane = lookupPlane(child) as Plane;
  223. var material:BitmapMaterial = plane ? plane.material as BitmapMaterial : null;
  224. var childWidth:Number = child is UIComponent ? UIComponent(child).getExplicitOrMeasuredWidth() : child.width;
  225. var childHeight:Number = child is UIComponent ? UIComponent(child).getExplicitOrMeasuredHeight() : child.height;
  226. childWidth = Math.round(childWidth);
  227. childHeight = Math.round(childHeight);
  228. if(material == null || material.bitmap.width != childWidth || material.bitmap.height != childHeight) {
  229. if(childWidth > 0 && childHeight > 0) {
  230. replacePlaneForChild(child);
  231. }
  232. }
  233. else {
  234. plane.material.updateBitmap();
  235. }
  236. layoutChildren(width, height);
  237. }
  238. override public function removeAllChildren():void {
  239. super.removeAllChildren();
  240. objectsToPlanes = new Dictionary(true);
  241. objectsToReflections = new Dictionary(true);
  242. containersToObjects = new Dictionary(true);
  243. }
  244. /**
  245.  * Whenever we remove a child we also remove the planes that we had created for it.
  246.  */
  247. override public function removeChild(child:DisplayObject):DisplayObject {
  248. child = super.removeChild(child);
  249. destroyPlane(child);
  250. return child;
  251. }
  252. protected function destroyPlane(child:DisplayObject):void {
  253. var plane:DisplayObject3D = lookupPlane(child);
  254. if(plane) {
  255. plane.material.bitmap.dispose();
  256. plane.material.bitmap = null;
  257. objectsToPlanes[child] = null;
  258. containersToObjects[plane.container] = null;
  259. plane.geometry.vertices = null;
  260. plane.faces = null;
  261. scene.removeChild(plane);
  262. }
  263. destroyReflection(child);
  264. }
  265. protected function destroyReflection(child:DisplayObject):void {
  266. var reflection:DisplayObject3D = lookupReflection(child);
  267. if(reflection) {
  268. reflection.material.bitmap.dispose();
  269. reflection.material.bitmap = null;
  270. objectsToReflections[child] = null;
  271. reflection.geometry.vertices = null;
  272. reflection.faces = null;
  273. scene.removeChild(reflection);
  274. }
  275. }
  276. protected function lookupPlane(child:DisplayObject):DisplayObject3D {
  277. return objectsToPlanes[child];
  278. }
  279. protected function lookupReflection(child:DisplayObject):DisplayObject3D {
  280. return objectsToReflections[child];
  281. }
  282. private function containerClicked(event:MouseEvent):void {
  283. var child:DisplayObject = containersToObjects[event.currentTarget];
  284. var index:int = getChildIndex(child);
  285. selectedIndex = index;
  286. }
  287. override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
  288. super.updateDisplayList(unscaledWidth, unscaledHeight);
  289. //sometimes our child ordering gets jacked. Make sure our pv3d sprite is below the actual children
  290. //which is important once we show the real child display object
  291. if(rawChildren.contains(pv3dSprite)) {
  292. if(border) {
  293. rawChildren.setChildIndex(pv3dSprite, 0);
  294. rawChildren.setChildIndex(DisplayObject(border), 0);
  295. }
  296. else {
  297. rawChildren.setChildIndex(pv3dSprite, 0);
  298. }
  299. }
  300. clippingMask.graphics.clear();
  301. if(clipContent) {
  302. clippingMask.graphics.beginFill(0x000000);
  303. clippingMask.graphics.drawRect(0,0, unscaledWidth, unscaledHeight);
  304. pv3dSprite.mask = clippingMask;
  305. }
  306. pv3dSprite.y = unscaledHeight/2;
  307. pv3dSprite.x = unscaledWidth/2;
  308. if(scene.triangleCuller is RectangleTriangleCuller) {
  309. (scene.triangleCuller as RectangleTriangleCuller).cullingRectangle = new Rectangle(-unscaledWidth/2,-unscaledHeight/2,unscaledWidth, unscaledHeight);
  310. }
  311. layoutChildren(unscaledWidth, unscaledHeight);
  312. }
  313. protected function layoutChildren(unscaledWidth:Number, unscaledHeight:Number):void {
  314. if(timer.running) {
  315. timer.reset();
  316. }
  317. timer.start();
  318. }
  319. private function timerComplete(event:TimerEvent):void {
  320. showVisibleChild();
  321. }
  322. private function showVisibleChild():void {
  323. if(selectedChild != null) {
  324. selectedChild.visible = true;
  325. var plane:DisplayObject3D = lookupPlane(selectedChild);
  326. if(plane) {
  327. plane.container.visible = false;
  328. }
  329. if(border) {
  330. rawChildren.setChildIndex(pv3dSprite, 0);
  331. rawChildren.setChildIndex(DisplayObject(border), 0);
  332. }
  333. else {
  334. rawChildren.setChildIndex(pv3dSprite, 0);
  335. }
  336. }
  337. }
  338. }
  339. }