the road to starling 2

31
Consistent Game Development across all Platforms e Road to Starling 2.0 or: How to turn a framework inside out (while staying sane) Daniel Sperl

Upload: daniel-sperl

Post on 13-Apr-2017

1.440 views

Category:

Software


2 download

TRANSCRIPT

Page 1: The Road to Starling 2

Consistent Game Developmentacross all Platforms

The Road to Starling 2.0

or:

How to turn a framework inside out(while staying sane)

Daniel Sperl

Page 2: The Road to Starling 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

Page 3: The Road to Starling 2

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)

Page 4: The Road to Starling 2

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

Page 5: The Road to Starling 2

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

Page 6: The Road to Starling 2

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:

Page 7: The Road to Starling 2

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:

Page 8: The Road to Starling 2

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);

Page 9: The Road to Starling 2

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:

Page 10: The Road to Starling 2

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:

Page 11: The Road to Starling 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

Page 12: The Road to Starling 2

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:

Page 13: The Road to Starling 2

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);

Page 14: The Road to Starling 2

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:

Page 15: The Road to Starling 2

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

Page 16: The Road to Starling 2

// 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:

Page 17: The Road to Starling 2

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:

Page 18: The Road to Starling 2

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:

Page 19: The Road to Starling 2

// 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;

Page 20: The Road to Starling 2

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:

Page 21: The Road to Starling 2

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)

Page 22: The Road to Starling 2

Render Cache

Page 23: The Road to Starling 2

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:

Page 24: The Road to Starling 2

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:

Page 25: The Road to Starling 2

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:

Page 26: The Road to Starling 2

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:

Page 27: The Road to Starling 2

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:

Page 28: The Road to Starling 2

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:

Page 29: The Road to Starling 2

• e.g. “February 2016”

• and keep it!

• Special hint: exploit Leap Years!

Promise a release datePro Tip:

Page 30: The Road to Starling 2

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;

Page 31: The Road to Starling 2

That's it, folks!

Thanks for watching!

Mail: [email protected] Twitter: @PrimaryFeather