Notes around Starling and the Display List

I learned a couple of neat things while working on TelemetryEASY that have to do with some limitations of Starling and also communication between Starling and the traditional display list. You might wonder… why bother using Stage3D frameworks at all for a simple utility app? Mostly to increase my familiarity with Starling and especially to discover some of the little trouble points I’m writing about here, along with some solutions.

Problem #1: NativeDragManager

TelemtryEASY allows for a user to drag and drop files onto the utility app from the desktop or file system. Using AIR, this is pretty easy using flash.desktop.NativeDragManager. The problem comes into play when you are using a Stage3D rendering view like Starling though; because when using the acceptDragDrop() method, you must pass in an object which extends flash.display.InteractiveObject… and there seems to be no equivalent for Starling.

So what I ended up doing was mixing the display list and Starling and using a normal Flash Sprite to accept the drag and drop procedure. Now, you are not supposed to mix Stage3D and the display list for performance reasons… but nothing much is really going on here – so it is  suitable concession.

private function addedToStage(e:Event):void
{
	this.removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
	
	_dragTarget = new Sprite();
	_dragTarget.graphics.beginFill(0x00000, 0);
	_dragTarget.graphics.drawRect(0,0,stage.stageWidth,stage.stageWidth);
	_dragTarget.graphics.endFill();
	this.addChild(_dragTarget);
	_dragTarget.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragEnter);
	_dragTarget.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDragDrop);
			
	if(this.stage)
	{
		this.stage.align = StageAlign.TOP_LEFT;
		this.stage.scaleMode = StageScaleMode.NO_SCALE;
	}
			
	DeviceCapabilities.dpi = 200;
	DeviceCapabilities.screenPixelWidth = stage.stageWidth;
	DeviceCapabilities.screenPixelHeight = stage.stageHeight;
			
	this.loaderInfo.addEventListener(Event.COMPLETE, loaderInfo_completeHandler);
}

So we have a basic Sprite serving as a drop target overlaying the Starling render view. Problem solved.

Problem #2: Stage3D Communication

The second problem was also a bit tricky and I’m sure there is probably more than one way to handle this. I need to be able to pass a modified string variable from my document class (where all of the processing is occurring) down through my Starling classes in order to update a status message view (Feathers component) being rendered deep within the application.

To accomplish this, I created a small method within the document class which simply accepts string values to pass on through to the primary Starling class defined when we instantiate Starling itself. This was probably the most tricky bit to the entire process; figuring out how to access a member of that main Starling class, com.fracturedvisionmedia.telemetryEASY.Main, from the document class root.

private function updateMessage(s:String):void
{
	(_starling.stage.getChildAt(1) as Main).message = s;
}

We can then invoke this updateMessage() method from wherever we want in the process. In this instance, I’m invoking it whenever the native process (Python) exits in order to let the user know what’s going on.

private function onExit(e:NativeProcessExitEvent):void {
	if(e.exitCode == 0){
		updateMessage("Telemetry Tag Added!\n\nHooray :D");
	}else if(e.exitCode == 1){
		updateMessage("Looks like Telemetry is already enabled.\n\nGood for you!");
	}else{
		updateMessage("I AM ERROR");
	}
}

Within the main Starling class, com.fracturedvisionmedia.telemetryEASY.Main, we create a small public variable (or method, if you prefer that instead) to retain any changes fed in through the document class. This variable will hold the new string values to be drawn from by other Starling classes.

public var message:String;

The final piece (in this case) is to have a listener which runs every frame to update the text view by polling the root Starling class, com.fracturedvisionmedia.telemetryEASY.screens.MainMenuScreen, for changes fed in through the document class.

override protected function initialize():void
{
	status = new ScrollText();
	status.text = "Drag a SWF here to enable advanced telemetry.";
	status.addEventListener(Event.ENTER_FRAME, checkMessage);
	this.addChild(this._status);
	status.textFormat = new TextFormat("Arial", 14, 0xffb400, true, false, false, null, null, "center");
}

private function checkMessage():void
{
	status.text = (this.root as Main).message;
}

This enables any updates from the traditional Flash side of things to be pickup up on by the Starling classes and have appropriate modifications rendered on screen!

2 thoughts on “Notes around Starling and the Display List”

  1. Thanks for writing up your solutions. Just a few comments.

    The concept of “you are not supposed to mix Stage3D and the display list for performance reasons” was true before AIR 3.2 and is mentioned in alot of older docs, but this really isn’t true anymore since AIR 3.2 as now native stage drawing and Stage3D drawing are synced into one context.present() call (where before two separate rendering passes were done for each). Of course the more you put in the native stage or the more you have going on in Stage3D still means they can take longer, but a few utility simple native display objects shouldn’t be an issue.

    In your second problem, when trying to get the instance of the ‘Main’ class, (I am assuming the className that was passed as the first arg to the Starling constructor?). Latest Starling versions now can give that to you directly at any place in your code by just calling ‘Starling.current.root as Main’. This is more failsafe than doing a getChildAt in case the display list gets modified at the stage level with other objects.

    1. Thanks for writing, Jeff. This is good info!

      You are correct in your assumption about the className, and yeah… I did feel terribly dirty using getChildAt() for this but didn’t find any alternative in my research.

Leave a Comment

Your email address will not be published. Required fields are marked *