Skip to content

Instantly share code, notes, and snippets.

@PrimaryFeather
Last active November 6, 2023 10:40
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save PrimaryFeather/d13b8d14d329a364c7cb to your computer and use it in GitHub Desktop.
Save PrimaryFeather/d13b8d14d329a364c7cb to your computer and use it in GitHub Desktop.
A MeshStyle for Starling 2 that discards texels with an alpha value below a certain threshold. This makes it perfect for arbitrarily shaped stencil masks.
// =================================================================================================
//
// Starling Framework
// Copyright 2011-2016 Gamua. All Rights Reserved.
//
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================
package starling.extensions
{
import starling.display.Mesh;
import starling.rendering.MeshEffect;
import starling.rendering.VertexDataFormat;
import starling.styles.MeshStyle;
public class TextureMaskStyle extends MeshStyle
{
public static const VERTEX_FORMAT:VertexDataFormat =
MeshStyle.VERTEX_FORMAT.extend("threshold:float1");
private var _threshold:Number;
public function TextureMaskStyle(threshold:Number=0.5)
{
_threshold = threshold;
}
override public function copyFrom(meshStyle:MeshStyle):void
{
var otherStyle:TextureMaskStyle = meshStyle as TextureMaskStyle;
if (otherStyle) _threshold = otherStyle._threshold;
super.copyFrom(meshStyle);
}
override public function createEffect():MeshEffect
{
return new TextureMaskEffect();
}
override public function get vertexFormat():VertexDataFormat
{
return VERTEX_FORMAT;
}
override protected function onTargetAssigned(target:Mesh):void
{
updateVertices();
}
private function updateVertices():void
{
var numVertices:int = vertexData.numVertices;
for (var i:int=0; i<numVertices; ++i)
vertexData.setFloat(i, "threshold", _threshold);
setRequiresRedraw();
}
// properties
public function get threshold():Number { return _threshold; }
public function set threshold(value:Number):void
{
if (_threshold != value && target)
{
_threshold = value;
updateVertices();
}
}
}
}
import flash.display3D.Context3D;
import starling.extensions.TextureMaskStyle;
import starling.rendering.MeshEffect;
import starling.rendering.Program;
import starling.rendering.VertexDataFormat;
class TextureMaskEffect extends MeshEffect
{
public static const VERTEX_FORMAT:VertexDataFormat = TextureMaskStyle.VERTEX_FORMAT;
public function TextureMaskEffect()
{ }
override protected function createProgram():Program
{
if (texture)
{
var vertexShader:String = [
"m44 op, va0, vc0", // 4x4 matrix transform to output clip-space
"mov v0, va1 ", // pass texture coordinates to fragment program
"mul v1, va2, vc4", // multiply alpha (vc4) with color (va2), pass to fp
"mov v2, va3 " // pass threshold to fp
].join("\n");
var fragmentShader:String = [
tex("ft0", "v0", 0, texture),
"sub ft1, ft0, v2.xxxx", // subtract threshold
"kil ft1.w ", // abort if alpha < 0
"mul oc, ft0, v1 " // else multiply with color & copy to output buffer
].join("\n");
return Program.fromSource(vertexShader, fragmentShader);
}
else return super.createProgram();
}
override protected function beforeDraw(context:Context3D):void
{
super.beforeDraw(context);
if (texture) vertexFormat.setVertexBufferAt(3, vertexBuffer, "threshold");
}
override protected function afterDraw(context:Context3D):void
{
if (texture) context.setVertexBufferAt(3, null);
super.afterDraw(context);
}
override public function get vertexFormat():VertexDataFormat
{
return VERTEX_FORMAT;
}
}
@soccerob
Copy link

var style:TextureMaskStyle = new TextureMaskStyle(0.8);

the above line will cause the following error just by creating a new instance of a TextureMaskStyle (testing starling 2.0 alpha)

[Fault] exception, information=ArgumentError: Invalid attribute format: bytes4. Use one of the following: 'float1'-'float4'

@PrimaryFeather
Copy link
Author

Sorry for that! With the very latest Starling head revision, it should work again.

@andrewmillion
Copy link

Hi! I need hide a part of image (ball) by maskTexture:Texture with some threshold. How i can use it?
Not work for me, when i do:

var ball:Image = new Image(ballTexture);
var textureMaskStyle:TextureMaskStyle = new TextureMaskStyle(0.5);
textureMaskStyle.texture = maskTexture;
ball.style = textureMaskStyle;

@PrimaryFeather
Copy link
Author

You need to use the mask a little different than that. I updated your sample:

var ball:Image = new Image(ballTexture);
var textureMaskStyle:TextureMaskStyle = new TextureMaskStyle(0.5);
var mask:Image = new Image(maskTexture);
mask.style = textureMaskStyle;
ball.mask = mask;

In a nutshell, you are using the mask property that's part of all display object. But since masks normally only work for the actual polygon area (i.e. they ignore the texture contents), you use the TextureMaskStyle for the mask.

Does that help?

@andrewmillion
Copy link

Yes, it helped! Thank you!

@fmrunware
Copy link

Hi there,

First, excuse my very poor english.

Is there a way to use your starling extension with a Sprite as a mask instead of an Image ?

I'm trying to threshold a sprite containing particles with blur effect and affect this result as a mask on an image.

I'm using Starling 2.0 and Nape.

Thanks for your advices.

Regards

@Vabavia
Copy link

Vabavia commented Jun 20, 2016

Hi! Can you explain how to use this extension with Starling Builder if possible?

@yuhengh
Copy link

yuhengh commented Oct 3, 2016

@Vabavia You can now use TextureMaskStyle in Starling Builder 2.2. Make sure to use the EmbeddedComponents.swf from the latest demo workspace, which contains the TextureMaskStyle.

@Adrian-S
Copy link

Adrian-S commented Mar 8, 2023

Is there a version of this what will straight up copy the alpha channel without applying a threshold?

I'm trying to get smooth rounded corners over some images, without using starling.antiAliasing. Basically copy the already anti-aliased corners from an Image with a PNG texture and .scale9grid.

@PrimaryFeather
Copy link
Author

@Adrian-S Not with this class, because it uses the GPUs stencil buffer / stencil test to achieve transparency; and that doesn't support anything else than "on" / "off".

However, there is another Starling extension that should be able to do what you're looking for: PixelMask. That should do the trick!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment