Performance

This benchmark tests how many frames per second the browser is able to draw for a given number of flags. You can increase the number of flags to see the effect on the frame rate. A modern desktop computer should be able to draw at least 20.000 flags (with WebGL) at a smooth frame rate of 60 fps. This benchmark depends on four important factors: The performance of your GPU for the draw calls, the performance of your CPU for the animation, the JavaScript code compiled by dart2js and last but not least the browser you are using.

Compare the benchmark numbers with the Flash Version.


Flags: 0
fps: 0.0

Credits for this beautiful flags to: www.IconDrawer.com.
library demo;

import 'dart:math';
import 'dart:html' as html;
import 'package:stagexl/stagexl.dart';

part 'performance_demo.dart';
part 'flying_flag.dart';

Stage stage = new Stage(html.querySelector('#stage'), webGL: true);
RenderLoop renderLoop = new RenderLoop();
ResourceManager resourceManager = new ResourceManager();

void main() {

  renderLoop.addStage(stage);

  resourceManager 
    ..addTextureAtlas('flags', 'images/flags.json', TextureAtlasFormat.JSONARRAY);

  resourceManager.load()
    .then((_) => stage.addChild(new PerformanceDemo()))
    .catchError((e) => print(e));
}
part of demo;

class PerformanceDemo extends DisplayObjectContainer {

  PerformanceDemo() {

    // let's start with 500 flags
    _addFlags(500);

    // add html-button event listeners
    html.querySelector('#minus100').onClick.listen((e) => _removeFlags(100));
    html.querySelector('#plus100').onClick.listen((e) => _addFlags(100));

    // add event listener for EnterFrame (fps meter)
    this.onEnterFrame.listen(_onEnterFrame);
  }

  //---------------------------------------------------------------------------------

  num _fpsAverage = null;

  _onEnterFrame(EnterFrameEvent e) {

    if (_fpsAverage == null) {
      _fpsAverage = 1.00 / e.passedTime;
    } else {
      _fpsAverage = 0.05 / e.passedTime + 0.95 * _fpsAverage;
    }

    html.querySelector('#fpsMeter').innerHtml = 'fps: ${_fpsAverage.round()}';
  }

  //---------------------------------------------------------------------------------

  _addFlags(int amount) {

    var random = new Random();
    var textureAtlas = resourceManager.getTextureAtlas('flags');
    var flagNames = textureAtlas.frameNames;

    while(--amount >= 0) {
      var flagName = flagNames[random.nextInt(flagNames.length)];
      var flagBitmapData = textureAtlas.getBitmapData(flagName);

      var flyingFlag = new FlyingFlag(flagBitmapData, random.nextInt(200) - 100, random.nextInt(200) - 100);
      flyingFlag.x = 30 + random.nextInt(940 - 60);
      flyingFlag.y = 30 + random.nextInt(500 - 60);
      addChild(flyingFlag);

      stage.juggler.add(flyingFlag);
    }

    html.querySelector('#flagCounter').innerHtml = 'Flags: ${numChildren}';
  }

  //---------------------------------------------------------------------------------

  _removeFlags(int amount) {

    while(--amount >= 0 && numChildren > 0) {
      var displayObject = getChildAt(0);
      displayObject.removeFromParent();
      stage.juggler.remove(displayObject);
    }

    html.querySelector('#flagCounter').innerHtml = 'Flags: ${numChildren}';
  }
}
part of demo;

class FlyingFlag extends Bitmap implements Animatable {

    num vx, vy;

    FlyingFlag(BitmapData bitmapData, this.vx, this.vy):super(bitmapData) {
      this.pivotX = bitmapData.width / 2;
      this.pivotY = bitmapData.height / 2;
    }

    bool advanceTime(num time) {
      var tx = x + vx * time;
      var ty = y + vy * time;
      if (tx > 910 || tx < 30) vx = -vx; else x = tx;
      if (ty > 470 || ty < 30) vy = -vy; else y = ty;
      return true;
    }
}