Last active
July 9, 2016 18:56
-
-
Save Maligan/179d9211aede3c013f83e42f8d3d2718 to your computer and use it in GitHub Desktop.
Signed Distance Field - Extension for Starling 2.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package starling.extensions | |
{ | |
import starling.display.DisplayObject; | |
import starling.rendering.MeshEffect; | |
import starling.rendering.RenderState; | |
import starling.styles.MeshStyle; | |
/** @author Alexandr Frolov (maligan@rambler.ru) */ | |
public class SignedDistanceFieldStyle extends MeshStyle | |
{ | |
private var _spread:Number; | |
public function SignedDistanceFieldStyle(spread:Number = 4.0) | |
{ | |
_spread = spread; | |
} | |
public override function createEffect():MeshEffect | |
{ | |
return new SignedDistanceFieldEffect(); | |
} | |
override public function canBatchWith(meshStyle:MeshStyle):Boolean | |
{ | |
return false; // Because effects may have different deltas | |
} | |
public override function updateEffect(effect:MeshEffect, state:RenderState):void | |
{ | |
super.updateEffect(effect, state); | |
SignedDistanceFieldEffect(effect).delta = 1 / (_spread * getAbsoluteTargetScale()); | |
} | |
public function getAbsoluteTargetScale():Number | |
{ | |
var scale:Number = 1; | |
var cursor:DisplayObject = target; | |
while (cursor) | |
{ | |
scale *= cursor.scale; | |
cursor = cursor.parent; | |
} | |
return scale; | |
} | |
public override function copyFrom(meshStyle:MeshStyle):void | |
{ | |
super.copyFrom(meshStyle); | |
} | |
public function get spread():Number { return _spread; } | |
public function set spread(value:Number):void | |
{ | |
_spread = value; | |
setRequiresRedraw(); | |
} | |
} | |
} | |
import flash.display3D.Context3D; | |
import flash.display3D.Context3DProgramType; | |
import starling.rendering.MeshEffect; | |
import starling.rendering.Program; | |
class SignedDistanceFieldEffect extends MeshEffect | |
{ | |
private var _delta:Number; | |
override protected function createProgram():Program | |
{ | |
if (texture) | |
{ | |
var vertexShader:String, fragmentShader:String; | |
vertexShader = | |
"m44 op, va0, vc0 \n" + // 4x4 matrix transform to output clip-space | |
"mov v0, va1 \n" + // pass texture coordinates to fragment program | |
"mul v1, va2, vc4 \n"; // multiply alpha (vc4) with color (va2), pass to fp | |
fragmentShader = | |
tex("ft0", "v0", 0, texture) + | |
// fc0.x (edge0) = 0.5 - delta | |
// fc0.y (edge1) = 0.5 + delta | |
// fc0.z (edge1 - edge0) = 2*delta | |
// fc0.w = 3 | |
// smooth step: | |
// scale, bias and saturate x to 0..1 range | |
"sub ft2.x, ft0.w, fc0.x \n" + // (x - edge0) | |
"div ft2.x, ft2.x, fc0.z \n" + // (x - edge0) / (edge1 - edge0) | |
"sat ft2.x, ft2.x \n" + // clamp result into 0..1 | |
// evaluate polynomial: x*x*(3 - 2*x) | |
"add ft2.y, ft2.x, ft2.x \n" + // 2x | |
"sub ft2.y, fc0.w, ft2.y \n" + // 3 - 2x | |
"mul ft2.x, ft2.x, ft2.x \n" + // x*x | |
"mul ft2.x, ft2.y, ft2.x \n" + // x*x*(3 - 2*x) | |
// output: | |
"mul oc, v1, ft2.x \n"; // place smooth alpha (ft2.x) into color (v1) | |
return Program.fromSource(vertexShader, fragmentShader); | |
} | |
return super.createProgram(); | |
} | |
override protected function beforeDraw(context:Context3D):void | |
{ | |
super.beforeDraw(context); | |
context.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, new <Number>[0.5-_delta, 0.5+_delta, 2*_delta, 3]); | |
} | |
override protected function afterDraw(context:Context3D):void | |
{ | |
super.afterDraw(context); | |
} | |
public function get delta():Number { return _delta; } | |
public function set delta(value:Number):void { _delta = value; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment