Skip to content

Instantly share code, notes, and snippets.

@Maligan
Last active July 9, 2016 18:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Maligan/179d9211aede3c013f83e42f8d3d2718 to your computer and use it in GitHub Desktop.
Save Maligan/179d9211aede3c013f83e42f8d3d2718 to your computer and use it in GitHub Desktop.
Signed Distance Field - Extension for Starling 2.x
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