Catch the Wave: SAP Event-Driven and Data Streaming for the Intelligence Ente...
Consistent Game Development across all Platforms with Starling 2.0
1. Consistent Game Development
across all Platforms
The Road to
Starling 2.0
or:
How to turn a framework inside out
(while staying sane)
Daniel Sperl
2. Starling 1.x
• (quite) backwards-compatible since 2012
• Rock solid, but lots of small quirks
• Difficult to add new features
without major API changes
• Underlying render architecture at its limit
3. Starling 2.0
• A major rework is required!
• Rethink complete architecture
• Clean up inconsistencies
• But: keep all basic concepts intact
(it’s still Starling, after all)
4. Meticulous Planning
Custom Batching
Clean Up APIs
Dynamic Lighting
Flexible Meshes
Release: Q1 2016
Simplify!
Easier to extend
State Stack
Scale9-Textures
FilterChain
Pro
cra
sti
nate!
Re
lea
se!
Rough
5. Kick-off
• Started development on July 24th, 2015
• All work done on a new branch (private)!
• That way, I could still fix bugs in Starling 1.7
6. Start small
• It’s tempting to start with the big components.
• That way, you’ll end up with
too many changes at once
• One class leads to the next!
• Can you even compile?!
• Hard to pinpoint problems
Pro Tip:
7. Start small
• Instead, work bottom-up:
small components first,
big components later
• Underlying building blocks
become ready for your
rough plan
• Work in baby steps: Each
commit must leave Starling
running!
Pro Tip:
8. VertexData
• Stores information about each vertex:
position, texture coordinates, color
• Old class was very rigid
• Wanted: arbitrary per-vertex data
• Important: fast (!) and easy to use
Building Block #1:
vertexData = new VertexData();
vertexData.setPosition(0, 50, 20);
vertexData.setTexCoords(0, 1.0, 0.5);
vertexData.setColor(0, 0xff00ff);
9. VertexData
// format string defines per-vertex contents
vertexData = new VertexData("position:float2, color:bytes4");
vertexData.setPoint(0, "position", 320, 480);
vertexData.setColor(0, "color", 0xff00ff);
// default format contains position, texCoords and color
vertexData = new VertexData();
vertexData.setPoint(0, "position", 320, 480);
vertexData.setPoint(0, "texCoords", 1.0, 0.5);
vertexData.setColor(0, "color", 0xff00ff);
Building Block #1:
10. Painter
• RenderSupport → Painter
• Wraps many Context3D methods
• Passed to all “render” methods
• Universally accessible (Starling.painter)
• Keeps a stack of state changes
Building Block #2:
11. Painter
override public function render(painter:Painter):void
{
}
Building Block #2:
painter.pushState(); // save a current state on the stack
painter.popState(); // restore previous state
}
painter.state.renderTarget = renderTexture;
painter.state.alpha = 0.5;
painter.state.transformModelviewMatrix(matrix);
painter.prepareToDraw(); // apply all settings at context
drawSomething(); // insert Stage3D rendering code here
12. Effect
• Each Stage3D draw call requires a lot of set-up:
• shaders and buffers
• program constants
• context loss restoration
• The “Effect” class encapsulates all of this
• Plus, it supports inheritance!
Building Block #3:
13. Effect
// create effect
var effect:MeshEffect = new MeshEffect();
Building Block #3:
// configure effect
effect.mvpMatrix3D = painter.state.mvpMatrix3D;
effect.texture = getHeroTexture();
effect.color = 0xf0f0f0;
// upload vertex data
effect.uploadIndexData(indexData);
effect.uploadVertexData(vertexData);
// draw!
effect.render(0, numTriangles);
15. Mesh & MeshBatch
• Basic “tangible” object in Starling 1: Quad
• Arguably the most important 2D object …
• … but shouldn’t be the only one.
• New: Mesh allows arbitrary shapes
• New: MeshBatch to batch meshes together
Building Block #4:
Mesh
Quad
Image
MeshBatch
16. // create geometry
var vertexData:VertexData = new VertexData();
vertexData.setPoint(0, "position", 0, 0);
vertexData.setPoint(1, "position", 10, 0);
vertexData.setPoint(2, "position", 0, 10);
var indexData:IndexData = new IndexData();
indexData.addTriangle(0, 1, 2);
// create Mesh
var mesh:Mesh = new Mesh(vertexData, indexData);
addChild(mesh);
Mesh & MeshBatch
Building Block #4:
17. Run into Dead Ends
• Original idea: IMeshBatch interface
• Custom Rendering: write “batchers”
implementing this interface
• Turned out to be too rigid:
uses inheritance → can’t apply to existing classes
• Turned out to be too slow:
performance issue with AOT (fixed with AIR 21)
• You’ll find more dead ends when browsing
through the GitHub history ;-)
Pro Tip:
18. MeshStyles
• The more flexible solution after the
IMeshBatch dead-end
• Can be attached to any mesh
(composition instead of inheritance)
• Allows customization of both
rendering and batching
Building Block #5:
19. // example: ColorOffsetStyle (tutorial)
var image:Image = new Image(texture);
var style:ColorOffsetStyle = new ColorOffsetStyle();
style.redOffset = 0.5;
image.style = style;
MeshStyles
Building Block #5:
// example: LightStyle (extension)
var normalMap:Texture = Texture.fromBitmap(…);
var image:Image = new Image(texture);
var style:LightStyle = new LightStyle(normalMap);
style.light = new Light();
image.style = style;
20. Follow ideas along the road
• “Sprite.flatten()” needed to be re-implemented
• When starting to work on that, I realized that an
automatic render-cache would be feasible
• I gave it a try, and it worked out great!
Pro Tip:
21. Render Cache
• Starling keeps track of changes in the display tree
• Unmodified meshes can be drawn from cache
• Fewer matrix operations, method calls, loops
• Only ByteArray.copy → upload → draw
• Great for menus, business apps, etc.
(anything with often static content)
23. Hide complexities
• no more “clipRect”
→ instead, optimized masking with Quads
• TextField
→ supporting different font types through
ITextCompositor
• Texture class
→ many internal classes inheriting “Texture”
Pro Tip:
24. Fix things
you always hated
• Changed prefix of all member variables
mVariable → _variable
• … with the help of a small Ruby script:
http://tinyurl.com/convert-members
• Done very late in development
→ easy “cherry-picking” between branches
Pro Tip:
25. Fix things
you always hated
• Now enforcing “premultipliedAlpha”
• via Fragment Shader
• Simplified a lot of areas
• Fixed inconsistencies when switching
between ATF and PNG textures
Pro Tip:
26. Fix things
even if you’re hated for it ;)
• old TextField class had format settings
directly on instance
• Hard to re-use format or pass around
• new: TextFormat class, just like in Flash
• … but sucks less!
• Everybody upgrading to Starling 2 will have to
change a LOT of code because of this.
Pro Tip:
27. Admit when
you’ve been stupid
• PixelSnapping
prevents blurriness when object is not pixel-aligned
• I never came up with a good solution!
• Now that it finally happened, and it’s just a few
lines of code (see: MatrixUtil.snapToPixels)
Pro Tip:
28. Write extensive
commit messages
• When refactoring code, you often run into things
you know were important, but not: why?!
• Via “git blame”, you find the responsible commit
• Clutters up the code less than inline comments
Pro Tip:
29. • e.g. “February 2016”
• and keep it!
• Special hint:
exploit Leap Years!
Promise a release date
Pro Tip:
30. One more thing …
• New (experimental) extension:
Cross-Texture-Batching
• Batches up to 4 textures in one draw call
• Available here:
http://wiki.starling-framework.org/extensions/cross-texture-batching
// usage:
Mesh.defaultStyle = MultiTextureStyle;