Upload
daniel-sperl
View
1.442
Download
2
Embed Size (px)
Citation preview
Consistent Game Developmentacross all Platforms
The Road to Starling 2.0
or:
How to turn a framework inside out(while staying sane)
Daniel Sperl
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
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)
Meticulous Planning
Custom Batching
Clean Up APIs
Dynamic Lighting
Flexible Meshes
Release: Q1 2016Simplify!
Easier to extend
State Stack
Scale9-TexturesFilterChain
Procrasti
nate!
Release!
Rough
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
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:
Start small
• Instead, work bottom-up:small components first, big components later
• Underlying building blocksbecome ready for your rough plan
• Work in baby steps: Each commit must leave Starling running!
Pro Tip:
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);
VertexData
// format string defines per-vertex contentsvertexData = new VertexData("position:float2, color:bytes4");vertexData.setPoint(0, "position", 320, 480);vertexData.setColor(0, "color", 0xff00ff);
// default format contains position, texCoords and colorvertexData = new VertexData();vertexData.setPoint(0, "position", 320, 480);vertexData.setPoint(0, "texCoords", 1.0, 0.5);vertexData.setColor(0, "color", 0xff00ff);
Building Block #1:
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:
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 contextdrawSomething(); // insert Stage3D rendering code here
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:
Effect// create effectvar effect:MeshEffect = new MeshEffect();
Building Block #3:
// configure effecteffect.mvpMatrix3D = painter.state.mvpMatrix3D;effect.texture = getHeroTexture();effect.color = 0xf0f0f0;
// upload vertex dataeffect.uploadIndexData(indexData);effect.uploadVertexData(vertexData);
// draw!effect.render(0, numTriangles);
Effect
Effect position:float2
FilterEffect position:float2, texCoords:float2
MeshEffect position:float2, texCoords:float2, color:bytes4
LightEffect position:float2, texCoords:float2, color:bytes4, normalTexCoords:float2
Building Block #3:
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
// create geometryvar 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 Meshvar mesh:Mesh = new Mesh(vertexData, indexData);addChild(mesh);
Mesh & MeshBatchBuilding Block #4:
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:
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:
// example: ColorOffsetStyle (tutorial)var image:Image = new Image(texture);var style:ColorOffsetStyle = new ColorOffsetStyle();style.redOffset = 0.5;image.style = style;
MeshStylesBuilding 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;
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:
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)
Render Cache
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:
Fix things you always hated
• Changed prefix of all member variablesmVariable → _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:
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:
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:
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 fewlines of code (see: MatrixUtil.snapToPixels)
Pro Tip:
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:
• e.g. “February 2016”
• and keep it!
• Special hint: exploit Leap Years!
Promise a release datePro Tip:
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;