New versions of OpenFL, Away3D and Starling

We have a new release of OpenFL, with minor releases of Away3D and Starling to match, as well as updated OpenFL and Away3D samples. You can get them all now on Haxelib, or OpenFL and Starling on NPM.

Here’s the OpenFL changelog:

8.4.0 (08/08/2018)

  • Updated to Lime 7.0.0 (with backward support for Lime 6.4)
  • Merged doc sources into runtime sources for better display server support
  • Removed generated documentation from NPM releases to make them smaller
  • Added support for readObject and writeObject in openfl.net.Socket
  • Improved native font auto-hinting (disabled when sharpness = 400)
  • Improved performance by dispatching mouse move events more sparingly
  • Improved state management between Stage3D and display list rendering
  • Improved object cleanup when removing children and using DOM rendering
  • Improved OpenGL rendering when mask objects are on a half-pixel
  • Fixed support for multiple BitmapData inputs in a custom shader
  • Fixed GL cacheAsBitmap and bitmapData.draw rendering that uses masks
  • Fixed openfl.net.Socket to not block while connecting
  • Fixed support for MouseEvent.ROLL_OVER events when not using ROLL_OUT
  • Fixed renderer support for bitmap.opaqueBackground
  • Fixed FullScreenEvent to dispatch with the proper boolean value
  • Fixed the behavior of copyColumn and copyRow in Matrix
  • Fixed a small memory leak when using multiple textures in GL Tilemap
  • Fixed ability to preventDefault on TextEvent.TEXT_INPUT events
  • Fixed missing dispatch of TextEvent.TEXT_INPUT in some cases
  • Fixed minor issues in textField.getFirstCharInParagraph
  • Fixed minor issues in textField.getParagraphLength
  • Fixed optimizations in EventDispatcher if dispatch is re-entrant
  • Fixed missing Event.ADDED_TO_STAGE event for SWF-based children
  • Fixed fullscreen exit event to properly dispatch on HTML5 target
  • Fixed minor issues in the behavior of bitmapData.draw
  • Fixed -Dtelemetry to properly enabled advanced-telemetry on Flash
  • Fixed loader.loaderInfo.width and height values when loading bitmaps
  • Fixed a regression in setting stage.color to 0
  • Fixed the orientation of cube textures in Stage3D
  • Fixed “JPEG-XR+LZMA” warning to output instead of causing an error
8 Likes

OpenFL 8.4.1 has been released, with a patch for a minor regression in SWF processing tools

8.4.1 (08/13/2018)

  • Fixed an issue where the Flash preloader could dispatch complete multiple times
  • Fixed a regression in processing SWF assets for Haxelib releases
  • Fixed an issue with stenciling on Stage3D projects that use display list masks
  • Fixed the value of ExternalInterface.objectID on single HTML5 embeds
4 Likes

If the movie clip class adds a stop command in the last frame, as long as the frame rate changes greatly, it will cause a stop command error. I added a new decision to fix this in the example below.:

public override function __enterFrame (deltaTime:Int):Void {

		// if(deltaTime != 0)
		// 	deltaTime = 120;
		// 	// deltaTime = Std.int(1000/60);
		
		if (__symbol != null && __playing) {
			
			var nextFrame = __getNextFrame (deltaTime);
			trace("nextFrame="+nextFrame);
			
			if (__lastFrameScriptEval == nextFrame) {
				
				super.__enterFrame (deltaTime);
				return;
				
			}
			
			if (__frameScripts != null) {
				
				if (nextFrame < __currentFrame) {
					
					if (!__evaluateFrameScripts (__totalFrames)) {
						
						super.__enterFrame (deltaTime);
						return;
						
					}

					//If there is a stop command, it should stay until the last frame
					if(__playing)
						__currentFrame = 1;
					
				}
				
				if (!__evaluateFrameScripts (nextFrame)) {
					
					super.__enterFrame (deltaTime);
					return;
					
				}
				
			} else {
				
				__currentFrame = nextFrame;
				
			}
			
		}
...

I also found that the implementation of the frame action is to execute the script and then render. If I use the callback event, it may cause the render object to be unreachable. Again, do some of the following optimizations: Delay the callback event.

//回调事件延迟处理
	private var _dispatchEvents:Array<Event> = [];
	//是否在__enterFrame事件中进行回调处理,如果是,需要延迟
	private var _isEnterFrameDispatch:Bool = false;

	override public function dispatchEvent(e:Event):Bool{
		if(_isEnterFrameDispatch)
		{
			_dispatchEvents.push(e);
			return false;
		}
		else
			return super.dispatchEvent(e);
	}

	/**
	 * 延迟调用
	 */
	private function enterFrameDispatchEvent():Void
	{
		_isEnterFrameDispatch = false;
		if(_dispatchEvents.length > 0)
		{
			for(event in _dispatchEvents)
			{
				this.dispatchEvent(event);
			}
			_dispatchEvents = [];
		}
	}
	
	public override function __enterFrame (deltaTime:Int):Void {

		// if(deltaTime != 0)
		// 	deltaTime = 120;

		_isEnterFrameDispatch = true;
		if (__symbol != null && __playing) {
			
			var nextFrame = __getNextFrame (deltaTime);
			
			if (__lastFrameScriptEval == nextFrame) {
				
				enterFrameDispatchEvent();
				super.__enterFrame (deltaTime);
				return;
				
			}
			
			if (__frameScripts != null) {
				
				if (nextFrame < __currentFrame) {
					
					if (!__evaluateFrameScripts (__totalFrames)) {
						enterFrameDispatchEvent();
						super.__enterFrame (deltaTime);
						return;
						
					}
					
					if(__playing)
						__currentFrame = 1;
					
				}
				
				if (!__evaluateFrameScripts (nextFrame)) {
					enterFrameDispatchEvent();
					super.__enterFrame (deltaTime);
					return;
					
				}
				
			} else {
				
				__currentFrame = nextFrame;
				
			}
			
		}
		
		if (__symbol != null && __currentFrame != __lastFrameUpdate) {
			
			__updateFrameLabel ();
			
			var currentInstancesByFrameObjectID = new Map<Int, FrameSymbolInstance> ();
			
			var frame:Int;
			var frameData:Frame;
			var instance:FrameSymbolInstance;
			
			// TODO: Handle updates only from previous frame?
			
			for (i in 0...__currentFrame) {
				
				frame = i + 1;
				frameData = __symbol.frames[i];
				
				if (frameData.objects == null) continue;
				
				for (frameObject in frameData.objects) {
					
					switch (frameObject.type) {
						
						case CREATE:
							
							instance = __activeInstancesByFrameObjectID.get (frameObject.id);
							
							if (instance != null) {
								
								currentInstancesByFrameObjectID.set (frameObject.id, instance);
								__updateDisplayObject (instance.displayObject, frameObject, true);
								
							}
						
						case UPDATE:
							
							instance = currentInstancesByFrameObjectID.get (frameObject.id);
							
							if (instance != null && instance.displayObject != null) {
								
								__updateDisplayObject (instance.displayObject, frameObject);
								
							}
						
						case DESTROY:
							
							currentInstancesByFrameObjectID.remove (frameObject.id);
						
					}
					
				}
				
			}
			
			// TODO: Less garbage?
			
			var currentInstances = new Array<FrameSymbolInstance> ();
			var currentMasks = new Array<FrameSymbolInstance> ();
			
			for (instance in currentInstancesByFrameObjectID) {
				
				if (currentInstances.indexOf (instance) == -1) {
					
					currentInstances.push (instance);
					
					if (instance.clipDepth > 0) {
						
						currentMasks.push (instance);
						
					}
					
				}
				
			}
			
			currentInstances.sort (__sortDepths);
			
			var existingChild:DisplayObject;
			var targetDepth:Int;
			var targetChild:DisplayObject;
			var child:DisplayObject;
			var maskApplied:Bool;
			
			for (i in 0...currentInstances.length) {
				
				existingChild = __children[i];
				instance = currentInstances[i];
				
				targetDepth = instance.depth;
				targetChild = instance.displayObject;
				
				if (existingChild != targetChild) {
					
					child = targetChild;
					addChildAt (targetChild, i);
					
				} else {
					
					child = __children[i];
					
				}
				
				maskApplied = false;
				
				for (mask in currentMasks) {
					
					if (targetDepth > mask.depth && targetDepth <= mask.clipDepth) {
						
						child.mask = mask.displayObject;
						maskApplied = true;
						break;
						
					}
					
				}
				
				if (currentMasks.length > 0 && !maskApplied && child.mask != null) {
					
					child.mask = null;
					
				}
				
			}
			
			var child;
			var i = currentInstances.length;
			var length = __children.length;
			
			while (i < length) {
				
				child = __children[i];
				
				// TODO: Faster method of determining if this was automatically added?
				
				for (instance in __activeInstances) {
					
					if (instance.displayObject == child) {
						
						//set MovieClips back to initial state (autoplay)
						if (Std.is(child, MovieClip))
						{
							var movie : MovieClip = cast child;
							movie.gotoAndPlay(1);
						}
						
						removeChild (child);
						i--;
						length--;
						
					}
					
				}
				
				i++;
				
			}
			
			__lastFrameUpdate = __currentFrame;
			
		}
		enterFrameDispatchEvent();
		super.__enterFrame (deltaTime);
		
	}

It seems that this scheme is not feasible. If there is a jump frame, it will lead to an infinite loop. I don’t know if there is a better way, let me get a way to render the script first. :disappointed_relieved:

8.4.4 It is easy to crash during the loading process, 8.2.0 is normal.