Merge pull request #1396 from cwillisf/cache-gettimer
Flash 30 performance changes
This commit is contained in:
commit
044a5e7f50
16 changed files with 139 additions and 171 deletions
src
|
@ -75,7 +75,7 @@ import watchers.ListWatcher;
|
||||||
|
|
||||||
public class Scratch extends Sprite {
|
public class Scratch extends Sprite {
|
||||||
// Version
|
// Version
|
||||||
public static const versionString:String = 'v460.0.1';
|
public static const versionString:String = 'v461';
|
||||||
public static var app:Scratch; // static reference to the app, used for debugging
|
public static var app:Scratch; // static reference to the app, used for debugging
|
||||||
|
|
||||||
// Display modes
|
// Display modes
|
||||||
|
@ -734,6 +734,7 @@ public class Scratch extends Sprite {
|
||||||
|
|
||||||
protected function step(e:Event):void {
|
protected function step(e:Event):void {
|
||||||
// Step the runtime system and all UI components.
|
// Step the runtime system and all UI components.
|
||||||
|
CachedTimer.clearCachedTimer();
|
||||||
gh.step();
|
gh.step();
|
||||||
runtime.stepRuntime();
|
runtime.stepRuntime();
|
||||||
Transition.step(null);
|
Transition.step(null);
|
||||||
|
@ -971,10 +972,6 @@ public class Scratch extends Sprite {
|
||||||
scriptsPart.setWidthHeight(contentW, contentH);
|
scriptsPart.setWidthHeight(contentW, contentH);
|
||||||
|
|
||||||
if (mediaLibrary) mediaLibrary.setWidthHeight(topBarPart.w, fullH);
|
if (mediaLibrary) mediaLibrary.setWidthHeight(topBarPart.w, fullH);
|
||||||
if (frameRateGraph) {
|
|
||||||
frameRateGraph.y = stage.stageHeight - frameRateGraphH;
|
|
||||||
addChild(frameRateGraph); // put in front
|
|
||||||
}
|
|
||||||
|
|
||||||
SCRATCH::allow3d {
|
SCRATCH::allow3d {
|
||||||
if (isIn3D) render3D.onStageResize();
|
if (isIn3D) render3D.onStageResize();
|
||||||
|
@ -1497,76 +1494,6 @@ public class Scratch extends Sprite {
|
||||||
lp.y = int(p.y + ((stagePane.height - lp.height) / 2));
|
lp.y = int(p.y + ((stagePane.height - lp.height) / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------
|
|
||||||
// Frame rate readout (for use during development)
|
|
||||||
//------------------------------
|
|
||||||
|
|
||||||
private var frameRateReadout:TextField;
|
|
||||||
private var firstFrameTime:int;
|
|
||||||
private var frameCount:int;
|
|
||||||
|
|
||||||
protected function addFrameRateReadout(x:int, y:int, color:uint = 0):void {
|
|
||||||
frameRateReadout = new TextField();
|
|
||||||
frameRateReadout.autoSize = TextFieldAutoSize.LEFT;
|
|
||||||
frameRateReadout.selectable = false;
|
|
||||||
frameRateReadout.background = false;
|
|
||||||
frameRateReadout.defaultTextFormat = new TextFormat(CSS.font, 12, color);
|
|
||||||
frameRateReadout.x = x;
|
|
||||||
frameRateReadout.y = y;
|
|
||||||
addChild(frameRateReadout);
|
|
||||||
frameRateReadout.addEventListener(Event.ENTER_FRAME, updateFrameRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function updateFrameRate(e:Event):void {
|
|
||||||
frameCount++;
|
|
||||||
if (!frameRateReadout) return;
|
|
||||||
var now:int = getTimer();
|
|
||||||
var msecs:int = now - firstFrameTime;
|
|
||||||
if (msecs > 500) {
|
|
||||||
var fps:Number = Math.round((1000 * frameCount) / msecs);
|
|
||||||
frameRateReadout.text = fps + ' fps (' + Math.round(msecs / frameCount) + ' msecs)';
|
|
||||||
firstFrameTime = now;
|
|
||||||
frameCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove / no longer used
|
|
||||||
private const frameRateGraphH:int = 150;
|
|
||||||
private var frameRateGraph:Shape;
|
|
||||||
private var nextFrameRateX:int;
|
|
||||||
private var lastFrameTime:int;
|
|
||||||
|
|
||||||
private function addFrameRateGraph():void {
|
|
||||||
addChild(frameRateGraph = new Shape());
|
|
||||||
frameRateGraph.y = stage.stageHeight - frameRateGraphH;
|
|
||||||
clearFrameRateGraph();
|
|
||||||
stage.addEventListener(Event.ENTER_FRAME, updateFrameRateGraph);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clearFrameRateGraph():void {
|
|
||||||
var g:Graphics = frameRateGraph.graphics;
|
|
||||||
g.clear();
|
|
||||||
g.beginFill(0xFFFFFF);
|
|
||||||
g.drawRect(0, 0, stage.stageWidth, frameRateGraphH);
|
|
||||||
nextFrameRateX = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function updateFrameRateGraph(evt:*):void {
|
|
||||||
var now:int = getTimer();
|
|
||||||
var msecs:int = now - lastFrameTime;
|
|
||||||
lastFrameTime = now;
|
|
||||||
var c:int = 0x505050;
|
|
||||||
if (msecs > 40) c = 0xE0E020;
|
|
||||||
if (msecs > 50) c = 0xA02020;
|
|
||||||
|
|
||||||
if (nextFrameRateX > stage.stageWidth) clearFrameRateGraph();
|
|
||||||
var g:Graphics = frameRateGraph.graphics;
|
|
||||||
g.beginFill(c);
|
|
||||||
var barH:int = Math.min(frameRateGraphH, msecs / 2);
|
|
||||||
g.drawRect(nextFrameRateX, frameRateGraphH - barH, 1, barH);
|
|
||||||
nextFrameRateX++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Camera Dialog
|
// Camera Dialog
|
||||||
//------------------------------
|
//------------------------------
|
||||||
|
|
|
@ -403,7 +403,7 @@ public class ExtensionManager {
|
||||||
|
|
||||||
public function updateIndicator(indicator:IndicatorLight, ext:ScratchExtension, firstTime:Boolean = false):void {
|
public function updateIndicator(indicator:IndicatorLight, ext:ScratchExtension, firstTime:Boolean = false):void {
|
||||||
if(ext.port > 0) {
|
if(ext.port > 0) {
|
||||||
var msecsSinceLastResponse:uint = getTimer() - ext.lastPollResponseTime;
|
var msecsSinceLastResponse:uint = CachedTimer.getCachedTimer() - ext.lastPollResponseTime;
|
||||||
if (msecsSinceLastResponse > 500) indicator.setColorAndMsg(0xE00000, 'Cannot find helper app');
|
if (msecsSinceLastResponse > 500) indicator.setColorAndMsg(0xE00000, 'Cannot find helper app');
|
||||||
else if (ext.problem != '') indicator.setColorAndMsg(0xE0E000, ext.problem);
|
else if (ext.problem != '') indicator.setColorAndMsg(0xE0E000, ext.problem);
|
||||||
else indicator.setColorAndMsg(0x00C000, ext.success);
|
else indicator.setColorAndMsg(0x00C000, ext.success);
|
||||||
|
@ -724,7 +724,7 @@ public class ExtensionManager {
|
||||||
|
|
||||||
private function processPollResponse(ext:ScratchExtension, response:String):void {
|
private function processPollResponse(ext:ScratchExtension, response:String):void {
|
||||||
if (response == null) return;
|
if (response == null) return;
|
||||||
ext.lastPollResponseTime = getTimer();
|
ext.lastPollResponseTime = CachedTimer.getCachedTimer();
|
||||||
ext.problem = '';
|
ext.problem = '';
|
||||||
|
|
||||||
// clear the busy list unless we just started a command that waits
|
// clear the busy list unless we just started a command that waits
|
||||||
|
|
|
@ -62,7 +62,6 @@ import extensions.ExtensionManager;
|
||||||
|
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
import flash.utils.Dictionary;
|
import flash.utils.Dictionary;
|
||||||
import flash.utils.getTimer;
|
|
||||||
|
|
||||||
import primitives.*;
|
import primitives.*;
|
||||||
|
|
||||||
|
@ -70,10 +69,12 @@ import scratch.*;
|
||||||
|
|
||||||
import sound.*;
|
import sound.*;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class Interpreter {
|
public class Interpreter {
|
||||||
|
|
||||||
public var activeThread:Thread; // current thread
|
public var activeThread:Thread; // current thread
|
||||||
public var currentMSecs:int = getTimer(); // millisecond clock for the current step
|
public var currentMSecs:int; // millisecond clock for the current step
|
||||||
public var turboMode:Boolean = false;
|
public var turboMode:Boolean = false;
|
||||||
|
|
||||||
private var app:Scratch;
|
private var app:Scratch;
|
||||||
|
@ -219,12 +220,34 @@ public class Interpreter {
|
||||||
doRedraw = true;
|
doRedraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const workTimeCheckIntervalFactor:Number = 1/3.0;
|
||||||
|
private const maxIterationCountSamples: uint = 10;
|
||||||
|
private var iterationCountSamples: Vector.<uint> = new <uint>[500]; // initial guess
|
||||||
|
|
||||||
|
private function addIterationCountSample(sample:uint):void {
|
||||||
|
iterationCountSamples.push(sample);
|
||||||
|
while (iterationCountSamples.length > maxIterationCountSamples) {
|
||||||
|
iterationCountSamples.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAverageIterationCount():Number {
|
||||||
|
var total:uint = 0;
|
||||||
|
for each (var sample:uint in iterationCountSamples) {
|
||||||
|
total += sample;
|
||||||
|
}
|
||||||
|
return Number(total) / iterationCountSamples.length;
|
||||||
|
}
|
||||||
|
|
||||||
public function stepThreads():void {
|
public function stepThreads():void {
|
||||||
startTime = getTimer();
|
|
||||||
var workTime:int = (0.75 * 1000) / app.stage.frameRate; // work for up to 75% of one frame time
|
var workTime:int = (0.75 * 1000) / app.stage.frameRate; // work for up to 75% of one frame time
|
||||||
doRedraw = false;
|
doRedraw = false;
|
||||||
currentMSecs = getTimer();
|
startTime = currentMSecs = CachedTimer.getFreshTimer();
|
||||||
if (threads.length == 0) return;
|
if (threads.length == 0) return;
|
||||||
|
var currentEstimate:Number = getAverageIterationCount();
|
||||||
|
var iterationCount:uint = 0;
|
||||||
|
var checkInterval:uint = Math.round(workTimeCheckIntervalFactor * currentEstimate);
|
||||||
|
var checkCount:uint = 0;
|
||||||
while ((currentMSecs - startTime) < workTime) {
|
while ((currentMSecs - startTime) < workTime) {
|
||||||
if (warpThread && (warpThread.block == null)) clearWarpBlock();
|
if (warpThread && (warpThread.block == null)) clearWarpBlock();
|
||||||
var threadStopped:Boolean = false;
|
var threadStopped:Boolean = false;
|
||||||
|
@ -247,9 +270,18 @@ public class Interpreter {
|
||||||
threads = newThreads;
|
threads = newThreads;
|
||||||
if (threads.length == 0) return;
|
if (threads.length == 0) return;
|
||||||
}
|
}
|
||||||
currentMSecs = getTimer();
|
|
||||||
if (doRedraw || (runnableCount == 0)) return;
|
if (doRedraw || (runnableCount == 0)) return;
|
||||||
|
++iterationCount;
|
||||||
|
++checkCount;
|
||||||
|
if (checkCount >= checkInterval) {
|
||||||
|
currentMSecs = CachedTimer.getFreshTimer();
|
||||||
|
checkCount = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// if we get here, this was a frame where we needed to check the timer twice or more
|
||||||
|
// use the elapsed time and actual iteration count to generate an estimate for iterations per step
|
||||||
|
var newEstimate:uint = Math.round(workTime * iterationCount / Number(currentMSecs - startTime));
|
||||||
|
addIterationCountSample(newEstimate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function stepActiveThread():void {
|
private function stepActiveThread():void {
|
||||||
|
@ -264,13 +296,15 @@ public class Interpreter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield = false;
|
yield = false;
|
||||||
|
var warpStartTimer:int = CachedTimer.getCachedTimer();
|
||||||
while (true) {
|
while (true) {
|
||||||
if (activeThread == warpThread) currentMSecs = getTimer();
|
if (activeThread == warpThread) currentMSecs = warpStartTimer;
|
||||||
evalCmd(activeThread.block);
|
evalCmd(activeThread.block);
|
||||||
if (yield) {
|
if (yield) {
|
||||||
if (activeThread == warpThread) {
|
if (activeThread == warpThread) {
|
||||||
if ((currentMSecs - startTime) > warpMSecs) return;
|
if ((currentMSecs - startTime) > warpMSecs) return;
|
||||||
yield = false;
|
yield = false;
|
||||||
|
warpStartTimer = CachedTimer.getFreshTimer();
|
||||||
continue;
|
continue;
|
||||||
} else return;
|
} else return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
package logging {
|
package logging {
|
||||||
import flash.utils.getTimer;
|
import flash.utils.getTimer;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class LogEntry {
|
public class LogEntry {
|
||||||
public var timeStamp:Number;
|
public var timeStamp:Number;
|
||||||
public var severity:int;
|
public var severity:int;
|
||||||
|
@ -49,11 +51,11 @@ public class LogEntry {
|
||||||
return [makeTimeStampString(), LogLevel.LEVEL[severity], messageKey].join(' | ');
|
return [makeTimeStampString(), LogLevel.LEVEL[severity], messageKey].join(' | ');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static const timerOffset:Number = new Date().time - getTimer();
|
private static const timerOffset:Number = new Date().time - CachedTimer.getFreshTimer();
|
||||||
|
|
||||||
// Returns approximately the same value as "new Date().time" without GC impact
|
// Returns approximately the same value as "new Date().time" without GC impact
|
||||||
public static function getCurrentTime():Number {
|
public static function getCurrentTime():Number {
|
||||||
return getTimer() + timerOffset;
|
return CachedTimer.getCachedTimer() + timerOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1052,12 +1052,8 @@ SCRATCH::allow3d{
|
||||||
currentTexture = null;
|
currentTexture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private var drawCount:uint = 0;
|
|
||||||
//private var lastTime:int = 0;
|
|
||||||
public function onRender(e:Event):void {
|
public function onRender(e:Event):void {
|
||||||
if (!scratchStage) return;
|
if (!scratchStage) return;
|
||||||
//trace('frame was '+(getTimer() - lastTime)+'ms.');
|
|
||||||
//lastTime = getTimer();
|
|
||||||
|
|
||||||
if (scratchStage.stage.stage3Ds[0] == null || __context == null || __context.driverInfo == "Disposed") {
|
if (scratchStage.stage.stage3Ds[0] == null || __context == null || __context.driverInfo == "Disposed") {
|
||||||
if (__context) __context.dispose();
|
if (__context) __context.dispose();
|
||||||
|
@ -1068,7 +1064,6 @@ SCRATCH::allow3d{
|
||||||
|
|
||||||
draw();
|
draw();
|
||||||
__context.present();
|
__context.present();
|
||||||
++drawCount;
|
|
||||||
|
|
||||||
// Invalidate cached renders
|
// Invalidate cached renders
|
||||||
for (var o:Object in cachedOtherRenderBitmaps)
|
for (var o:Object in cachedOtherRenderBitmaps)
|
||||||
|
|
|
@ -544,7 +544,7 @@ public class ScratchObj extends Sprite {
|
||||||
public function click(evt:MouseEvent):void {
|
public function click(evt:MouseEvent):void {
|
||||||
var app:Scratch = root as Scratch;
|
var app:Scratch = root as Scratch;
|
||||||
if (!app) return;
|
if (!app) return;
|
||||||
var now:uint = getTimer();
|
var now:uint = CachedTimer.getCachedTimer();
|
||||||
app.runtime.startClickedHats(this);
|
app.runtime.startClickedHats(this);
|
||||||
if ((now - lastClickTime) < DOUBLE_CLICK_MSECS) {
|
if ((now - lastClickTime) < DOUBLE_CLICK_MSECS) {
|
||||||
if (isStage || ScratchSprite(this).isClone) return;
|
if (isStage || ScratchSprite(this).isClone) return;
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class ScratchRuntime {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ready==ReadyLabel.COUNTDOWN) {
|
if (ready==ReadyLabel.COUNTDOWN) {
|
||||||
var tR:Number = getTimer()*.001-videoSeconds;
|
var tR:Number = CachedTimer.getCachedTimer()*.001-videoSeconds;
|
||||||
while (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
while (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
||||||
saveSound();
|
saveSound();
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ public class ScratchRuntime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (recording) { // Recording a YouTube video?
|
if (recording) { // Recording a YouTube video?
|
||||||
var t:Number = getTimer()*.001-videoSeconds;
|
var t:Number = CachedTimer.getCachedTimer()*.001-videoSeconds;
|
||||||
//If, based on time and framerate, the current frame needs to be in the video, capture the frame.
|
//If, based on time and framerate, the current frame needs to be in the video, capture the frame.
|
||||||
//Will always be true if framerate is 30, as every frame is captured.
|
//Will always be true if framerate is 30, as every frame is captured.
|
||||||
if (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
if (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
||||||
|
@ -213,7 +213,7 @@ public class ScratchRuntime {
|
||||||
|
|
||||||
private function saveFrame():void {
|
private function saveFrame():void {
|
||||||
saveSound();
|
saveSound();
|
||||||
var t:Number = getTimer()*.001-videoSeconds;
|
var t:Number = CachedTimer.getCachedTimer()*.001-videoSeconds;
|
||||||
while (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
while (t>videoSounds.length/videoFramerate+1/videoFramerate) {
|
||||||
saveSound();
|
saveSound();
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ public class ScratchRuntime {
|
||||||
videoHeight = 360;
|
videoHeight = 360;
|
||||||
}
|
}
|
||||||
ready=ReadyLabel.COUNTDOWN;
|
ready=ReadyLabel.COUNTDOWN;
|
||||||
videoSeconds = getTimer()*.001;
|
videoSeconds = CachedTimer.getCachedTimer()*.001;
|
||||||
baFlvEncoder = new ByteArrayFlvEncoder(videoFramerate);
|
baFlvEncoder = new ByteArrayFlvEncoder(videoFramerate);
|
||||||
baFlvEncoder.setVideoProperties(videoWidth, videoHeight);
|
baFlvEncoder.setVideoProperties(videoWidth, videoHeight);
|
||||||
baFlvEncoder.setAudioProperties(FlvEncoder.SAMPLERATE_44KHZ, true, true, true);
|
baFlvEncoder.setAudioProperties(FlvEncoder.SAMPLERATE_44KHZ, true, true, true);
|
||||||
|
@ -433,7 +433,7 @@ public class ScratchRuntime {
|
||||||
ready=ReadyLabel.NOT_READY;
|
ready=ReadyLabel.NOT_READY;
|
||||||
app.refreshStagePart();
|
app.refreshStagePart();
|
||||||
var player:ScratchSoundPlayer, length:int;
|
var player:ScratchSoundPlayer, length:int;
|
||||||
videoSeconds = getTimer() * 0.001;
|
videoSeconds = CachedTimer.getCachedTimer() * 0.001;
|
||||||
for each (player in ScratchSoundPlayer.activeSounds) {
|
for each (player in ScratchSoundPlayer.activeSounds) {
|
||||||
length = int((player.soundChannel.position*.001)*videoFramerate);
|
length = int((player.soundChannel.position*.001)*videoFramerate);
|
||||||
player.readPosition = Math.max(Math.min(baFlvEncoder.audioFrameSize*length,player.dataBytes.length),0);
|
player.readPosition = Math.max(Math.min(baFlvEncoder.audioFrameSize*length,player.dataBytes.length),0);
|
||||||
|
|
|
@ -33,6 +33,8 @@ import flash.utils.ByteArray;
|
||||||
|
|
||||||
import scratch.ScratchSound;
|
import scratch.ScratchSound;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class ScratchSoundPlayer {
|
public class ScratchSoundPlayer {
|
||||||
|
|
||||||
static public var activeSounds:Array = [];
|
static public var activeSounds:Array = [];
|
||||||
|
@ -160,7 +162,7 @@ public class ScratchSoundPlayer {
|
||||||
|
|
||||||
private function writeSampleData(evt:SampleDataEvent):void {
|
private function writeSampleData(evt:SampleDataEvent):void {
|
||||||
var i:int;
|
var i:int;
|
||||||
if ((lastBufferTime != 0) && ((getTimer() - lastBufferTime) > 230)) {
|
if ((lastBufferTime != 0) && ((CachedTimer.getCachedTimer() - lastBufferTime) > 230)) {
|
||||||
soundChannel = null; // don't explicitly stop the sound channel in this callback; allow it to stop on its own
|
soundChannel = null; // don't explicitly stop the sound channel in this callback; allow it to stop on its own
|
||||||
stopPlaying();
|
stopPlaying();
|
||||||
return;
|
return;
|
||||||
|
@ -174,7 +176,7 @@ public class ScratchSoundPlayer {
|
||||||
}
|
}
|
||||||
dataBytes.writeBytes(data);
|
dataBytes.writeBytes(data);
|
||||||
if ((bytePosition >= endOffset) && (lastBufferTime == 0)) {
|
if ((bytePosition >= endOffset) && (lastBufferTime == 0)) {
|
||||||
lastBufferTime = getTimer();
|
lastBufferTime = CachedTimer.getCachedTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ import ui.media.*;
|
||||||
import ui.SpriteThumbnail;
|
import ui.SpriteThumbnail;
|
||||||
import uiwidgets.*;
|
import uiwidgets.*;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class LibraryPart extends UIPart {
|
public class LibraryPart extends UIPart {
|
||||||
|
|
||||||
private const smallTextFormat:TextFormat = new TextFormat(CSS.font, 10, CSS.textColor);
|
private const smallTextFormat:TextFormat = new TextFormat(CSS.font, 10, CSS.textColor);
|
||||||
|
@ -251,12 +253,12 @@ public class LibraryPart extends UIPart {
|
||||||
public function step():void {
|
public function step():void {
|
||||||
// Update thumbnails and sprite details.
|
// Update thumbnails and sprite details.
|
||||||
var viewedObj:ScratchObj = app.viewedObj();
|
var viewedObj:ScratchObj = app.viewedObj();
|
||||||
var updateThumbnails:Boolean = ((getTimer() - lastUpdate) > updateInterval);
|
var updateThumbnails:Boolean = ((CachedTimer.getCachedTimer() - lastUpdate) > updateInterval);
|
||||||
for each (var tn:SpriteThumbnail in allThumbnails()) {
|
for each (var tn:SpriteThumbnail in allThumbnails()) {
|
||||||
if (updateThumbnails) tn.updateThumbnail();
|
if (updateThumbnails) tn.updateThumbnail();
|
||||||
tn.select(tn.targetObj == viewedObj);
|
tn.select(tn.targetObj == viewedObj);
|
||||||
}
|
}
|
||||||
if (updateThumbnails) lastUpdate = getTimer();
|
if (updateThumbnails) lastUpdate = CachedTimer.getCachedTimer();
|
||||||
if (spriteDetails.visible) spriteDetails.step();
|
if (spriteDetails.visible) spriteDetails.step();
|
||||||
if (videoButton && videoButton.visible) updateVideoButton();
|
if (videoButton && videoButton.visible) updateVideoButton();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ import ui.*;
|
||||||
|
|
||||||
import uiwidgets.*;
|
import uiwidgets.*;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class ScriptsPart extends UIPart {
|
public class ScriptsPart extends UIPart {
|
||||||
|
|
||||||
private var shape:Shape;
|
private var shape:Shape;
|
||||||
|
@ -130,12 +132,12 @@ public class ScriptsPart extends UIPart {
|
||||||
private var lastUpdateTime:uint;
|
private var lastUpdateTime:uint;
|
||||||
|
|
||||||
private function updateExtensionIndicators():void {
|
private function updateExtensionIndicators():void {
|
||||||
if ((getTimer() - lastUpdateTime) < 500) return;
|
if ((CachedTimer.getCachedTimer() - lastUpdateTime) < 500) return;
|
||||||
for (var i:int = 0; i < app.palette.numChildren; i++) {
|
for (var i:int = 0; i < app.palette.numChildren; i++) {
|
||||||
var indicator:IndicatorLight = app.palette.getChildAt(i) as IndicatorLight;
|
var indicator:IndicatorLight = app.palette.getChildAt(i) as IndicatorLight;
|
||||||
if (indicator) app.extensionManager.updateIndicator(indicator, indicator.target);
|
if (indicator) app.extensionManager.updateIndicator(indicator, indicator.target);
|
||||||
}
|
}
|
||||||
lastUpdateTime = getTimer();
|
lastUpdateTime = CachedTimer.getCachedTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWidthHeight(w:int, h:int):void {
|
public function setWidthHeight(w:int, h:int):void {
|
||||||
|
|
|
@ -34,6 +34,8 @@ package uiwidgets {
|
||||||
import flash.utils.getTimer;
|
import flash.utils.getTimer;
|
||||||
import translation.TranslatableStrings;
|
import translation.TranslatableStrings;
|
||||||
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
|
||||||
public class Menu extends Sprite {
|
public class Menu extends Sprite {
|
||||||
|
|
||||||
// when stringCollectionMode is true menus are not displayed but strings are recorded for translation
|
// when stringCollectionMode is true menus are not displayed but strings are recorded for translation
|
||||||
|
@ -192,8 +194,8 @@ public class Menu extends Sprite {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((getTimer() - lastTime) < scrollMSecs) return;
|
if ((CachedTimer.getCachedTimer() - lastTime) < scrollMSecs) return;
|
||||||
lastTime = getTimer();
|
lastTime = CachedTimer.getCachedTimer();
|
||||||
|
|
||||||
var localY:int = this.globalToLocal(new Point(stage.mouseX, stage.mouseY)).y;
|
var localY:int = this.globalToLocal(new Point(stage.mouseX, stage.mouseY)).y;
|
||||||
if ((localY < (2 + scrollInset)) && (firstItemIndex > 0)) scrollBy(-1);
|
if ((localY < (2 + scrollInset)) && (firstItemIndex > 0)) scrollBy(-1);
|
||||||
|
|
55
src/util/CachedTimer.as
Normal file
55
src/util/CachedTimer.as
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Scratch Project Editor and Player
|
||||||
|
* Copyright (C) 2018 Massachusetts Institute of Technology
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package util {
|
||||||
|
import flash.utils.getTimer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calling getTimer() is much more expensive in Flash 30 than in previous versions.
|
||||||
|
* This class is meant to reduce the number of actual calls to getTimer() with minimal changes to existing code.
|
||||||
|
*/
|
||||||
|
public class CachedTimer {
|
||||||
|
private static var dirty:Boolean = true;
|
||||||
|
private static var cachedTimer:int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the last cached value of getTimer(). May return a fresh value if the cache has been invalidated.
|
||||||
|
*/
|
||||||
|
public static function getCachedTimer():int {
|
||||||
|
return dirty ? getFreshTimer() : cachedTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the timer cache, forcing getCachedTimer() to get a fresh value next time. Use this at the top of a frame.
|
||||||
|
*/
|
||||||
|
public static function clearCachedTimer():void {
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return and cache the current value of getTimer().
|
||||||
|
* Use this if you need an accurate timer value in the middle of a frame.
|
||||||
|
*/
|
||||||
|
public static function getFreshTimer():int {
|
||||||
|
cachedTimer = getTimer();
|
||||||
|
dirty = false;
|
||||||
|
return cachedTimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -123,7 +123,7 @@ public class GestureHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function step():void {
|
public function step():void {
|
||||||
if ((getTimer() - mouseDownTime) > DOUBLE_CLICK_MSECS) {
|
if ((CachedTimer.getCachedTimer() - mouseDownTime) > DOUBLE_CLICK_MSECS) {
|
||||||
if (gesture == "unknown") {
|
if (gesture == "unknown") {
|
||||||
if (mouseTarget != null) handleDrag(null);
|
if (mouseTarget != null) handleDrag(null);
|
||||||
if (gesture != 'drag') handleClick(mouseDownEvent);
|
if (gesture != 'drag') handleClick(mouseDownEvent);
|
||||||
|
@ -132,7 +132,7 @@ public class GestureHandler {
|
||||||
handleClick(mouseDownEvent);
|
handleClick(mouseDownEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (carriedObj && scrollTarget && (getTimer() - scrollStartTime) > SCROLL_MSECS && (scrollXVelocity || scrollYVelocity)) {
|
if (carriedObj && scrollTarget && (CachedTimer.getCachedTimer() - scrollStartTime) > SCROLL_MSECS && (scrollXVelocity || scrollYVelocity)) {
|
||||||
if (scrollTarget.allowHorizontalScrollbar) {
|
if (scrollTarget.allowHorizontalScrollbar) {
|
||||||
scrollTarget.contents.x = Math.min(0, Math.max(-scrollTarget.maxScrollH(), scrollTarget.contents.x + scrollXVelocity));
|
scrollTarget.contents.x = Math.min(0, Math.max(-scrollTarget.maxScrollH(), scrollTarget.contents.x + scrollXVelocity));
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ public class GestureHandler {
|
||||||
handleTool(evt);
|
handleTool(evt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mouseDownTime = getTimer();
|
mouseDownTime = CachedTimer.getCachedTimer();
|
||||||
mouseDownEvent = evt;
|
mouseDownEvent = evt;
|
||||||
gesture = "unknown";
|
gesture = "unknown";
|
||||||
mouseTarget = null;
|
mouseTarget = null;
|
||||||
|
@ -261,7 +261,7 @@ public class GestureHandler {
|
||||||
if (t is ScrollFrameContents) {
|
if (t is ScrollFrameContents) {
|
||||||
scrollTarget = t.parent as ScrollFrame;
|
scrollTarget = t.parent as ScrollFrame;
|
||||||
if (scrollTarget != oldTarget) {
|
if (scrollTarget != oldTarget) {
|
||||||
scrollStartTime = getTimer();
|
scrollStartTime = CachedTimer.getCachedTimer();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ public class GestureHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!scrollXVelocity && !scrollYVelocity) {
|
if (!scrollXVelocity && !scrollYVelocity) {
|
||||||
scrollStartTime = getTimer();
|
scrollStartTime = CachedTimer.getCachedTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bubble) {
|
if (bubble) {
|
||||||
|
@ -540,7 +540,7 @@ public class GestureHandler {
|
||||||
obj.startDrag();
|
obj.startDrag();
|
||||||
if(obj is DisplayObject) obj.cacheAsBitmap = true;
|
if(obj is DisplayObject) obj.cacheAsBitmap = true;
|
||||||
carriedObj = obj;
|
carriedObj = obj;
|
||||||
scrollStartTime = getTimer();
|
scrollStartTime = CachedTimer.getCachedTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dropHandled(droppedObj:*, evt:MouseEvent):Boolean {
|
private function dropHandled(droppedObj:*, evt:MouseEvent):Boolean {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Scratch Project Editor and Player
|
|
||||||
* Copyright (C) 2014 Massachusetts Institute of Technology
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package util {
|
|
||||||
import flash.utils.getTimer;
|
|
||||||
|
|
||||||
public class Perf {
|
|
||||||
|
|
||||||
private static var totalStart:uint;
|
|
||||||
private static var lapStart:uint;
|
|
||||||
private static var lapTotal:uint;
|
|
||||||
|
|
||||||
public static function start(msg:String = null):void {
|
|
||||||
if (!msg) msg = 'Perf.start';
|
|
||||||
Scratch.app.log(msg);
|
|
||||||
totalStart = lapStart = getTimer();
|
|
||||||
lapTotal = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function clearLap():void {
|
|
||||||
lapStart = getTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function lap(msg:String = ""):void {
|
|
||||||
if (totalStart == 0) return; // not monitoring performance
|
|
||||||
var lapMSecs:uint = getTimer() - lapStart;
|
|
||||||
Scratch.app.log(' ' + msg + ': ' + lapMSecs + ' msecs');
|
|
||||||
lapTotal += lapMSecs;
|
|
||||||
lapStart = getTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function end():void {
|
|
||||||
if (totalStart == 0) return; // not monitoring performance
|
|
||||||
var totalMSecs:uint = getTimer() - totalStart;
|
|
||||||
var unaccountedFor:uint = totalMSecs - lapTotal;
|
|
||||||
Scratch.app.log('Total: ' + totalMSecs + ' msecs; unaccounted for: ' + unaccountedFor + ' msecs (' + int((100 * unaccountedFor) / totalMSecs) + '%)');
|
|
||||||
totalStart = lapStart = lapTotal = 0;
|
|
||||||
}
|
|
||||||
}}
|
|
|
@ -48,7 +48,7 @@ public class Transition {
|
||||||
} else {
|
} else {
|
||||||
delta = endValue - startValue;
|
delta = endValue - startValue;
|
||||||
}
|
}
|
||||||
startMSecs = getTimer();
|
startMSecs = CachedTimer.getCachedTimer();
|
||||||
duration = 1000 * secs;
|
duration = 1000 * secs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ public class Transition {
|
||||||
|
|
||||||
public static function step(evt:*):void {
|
public static function step(evt:*):void {
|
||||||
if (activeTransitions.length == 0) return;
|
if (activeTransitions.length == 0) return;
|
||||||
var now:uint = getTimer();
|
var now:uint = CachedTimer.getCachedTimer();
|
||||||
var newActive:Array = [];
|
var newActive:Array = [];
|
||||||
for each (var t:Transition in activeTransitions) {
|
for each (var t:Transition in activeTransitions) {
|
||||||
if (t.apply(now)) newActive.push(t);
|
if (t.apply(now)) newActive.push(t);
|
||||||
|
|
|
@ -26,7 +26,9 @@ package watchers {
|
||||||
import interpreter.Interpreter;
|
import interpreter.Interpreter;
|
||||||
import scratch.ScratchObj;
|
import scratch.ScratchObj;
|
||||||
import translation.Translator;
|
import translation.Translator;
|
||||||
import util.JSON;
|
|
||||||
|
import util.CachedTimer;
|
||||||
|
import util.JSON;
|
||||||
import uiwidgets.*;
|
import uiwidgets.*;
|
||||||
|
|
||||||
public class ListWatcher extends Sprite {
|
public class ListWatcher extends Sprite {
|
||||||
|
@ -222,7 +224,7 @@ public class ListWatcher extends Sprite {
|
||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
adjustLastAccessSize();
|
adjustLastAccessSize();
|
||||||
if ((i < 1) || (i > lastAccess.length)) return;
|
if ((i < 1) || (i > lastAccess.length)) return;
|
||||||
lastAccess[i - 1] = getTimer();
|
lastAccess[i - 1] = CachedTimer.getCachedTimer();
|
||||||
lastActiveIndex = i - 1;
|
lastActiveIndex = i - 1;
|
||||||
interp.redraw();
|
interp.redraw();
|
||||||
}
|
}
|
||||||
|
@ -265,7 +267,7 @@ public class ListWatcher extends Sprite {
|
||||||
// Highlight the cell number of all recently accessed cells currently visible.
|
// Highlight the cell number of all recently accessed cells currently visible.
|
||||||
const fadeoutMSecs:int = 800;
|
const fadeoutMSecs:int = 800;
|
||||||
adjustLastAccessSize();
|
adjustLastAccessSize();
|
||||||
var now:int = getTimer();
|
var now:int = CachedTimer.getCachedTimer();
|
||||||
isIdle = true; // try to be idle; set to false if any non-zero lastAccess value is found
|
isIdle = true; // try to be idle; set to false if any non-zero lastAccess value is found
|
||||||
for (var i:int = 0; i < visibleCellNums.length; i++) {
|
for (var i:int = 0; i < visibleCellNums.length; i++) {
|
||||||
var lastAccessTime:int = lastAccess[firstVisibleIndex + i];
|
var lastAccessTime:int = lastAccess[firstVisibleIndex + i];
|
||||||
|
|
Reference in a new issue