Skip to content

Instantly share code, notes, and snippets.

@joshtynjala
Last active April 23, 2025 17:13
Show Gist options
  • Save joshtynjala/275aeeb5014e5e7a2d2573182e98c29d to your computer and use it in GitHub Desktop.
Save joshtynjala/275aeeb5014e5e7a2d2573182e98c29d to your computer and use it in GitHub Desktop.
A MeshStyle for Starling 2 that allows to add an offset to each color channel of a mesh, as described in the Starling Manual for OpenFL.
// =================================================================================================
//
// Starling Framework
// Copyright Gamua GmbH. 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 openfl.display3D.Context3D;
import starling.display.Mesh;
import starling.rendering.FilterEffect;
import starling.rendering.MeshEffect;
import starling.rendering.Program;
import starling.rendering.VertexDataFormat;
import starling.styles.MeshStyle;
class ColorOffsetStyle extends MeshStyle
{
public static final VERTEX_FORMAT:VertexDataFormat =
MeshStyle.VERTEX_FORMAT.extend("offset:float4");
private var _offsets:Array<Float>;
public function new(redOffset:Float=0.0, greenOffset:Float=0.0,
blueOffset:Float=0.0, alphaOffset:Float=0.0)
{
super();
_offsets = [];
_offsets.resize(4);
setTo(redOffset, greenOffset, blueOffset, alphaOffset);
}
public function setTo(redOffset:Float=0.0, greenOffset:Float=0.0,
blueOffset:Float=0.0, alphaOffset:Float=0.0):Void
{
_offsets[0] = redOffset;
_offsets[1] = greenOffset;
_offsets[2] = blueOffset;
_offsets[3] = alphaOffset;
updateVertices();
}
override public function copyFrom(meshStyle:MeshStyle):Void
{
var colorOffsetStyle:ColorOffsetStyle = Std.downcast(meshStyle, ColorOffsetStyle);
if (colorOffsetStyle != null)
{
for (i in 0...4)
_offsets[i] = colorOffsetStyle._offsets[i];
}
super.copyFrom(meshStyle);
}
override public function createEffect():MeshEffect
{
return new ColorOffsetEffect();
}
override private function onTargetAssigned(target:Mesh):Void
{
updateVertices();
}
override private function get_vertexFormat():VertexDataFormat
{
return VERTEX_FORMAT;
}
private function updateVertices():Void
{
if (target != null)
{
var numVertices:Int = vertexData.numVertices;
for (i in 0...numVertices)
vertexData.setPoint4D(i, "offset",
_offsets[0], _offsets[1], _offsets[2], _offsets[3]);
setRequiresRedraw();
}
}
public var redOffset(get, set):Float;
private function get_redOffset():Float { return _offsets[0]; }
private function set_redOffset(value:Float):Float
{
_offsets[0] = value;
updateVertices();
return value;
}
public var greenOffset(get, set):Float;
private function get_greenOffset():Float { return _offsets[1]; }
private function set_greenOffset(value:Float):Float
{
_offsets[1] = value;
updateVertices();
return value;
}
public var blueOffset(get, set):Float;
private function get_blueOffset():Float { return _offsets[2]; }
private function set_blueOffset(value:Float):Float
{
_offsets[2] = value;
updateVertices();
return value;
}
public var alphaOffset(get, set):Float;
private function get_alphaOffset():Float { return _offsets[3]; }
private function set_alphaOffset(value:Float):Float
{
_offsets[3] = value;
updateVertices();
return value;
}
}
private class ColorOffsetEffect extends MeshEffect
{
public static final VERTEX_FORMAT:VertexDataFormat = ColorOffsetStyle.VERTEX_FORMAT;
public function new()
{
super();
}
override private function createProgram():Program
{
var vertexShader:String;
var fragmentShader:String;
var addOffset:String = [
"mov ft1, v2", // copy complete offset to ft1
"mul ft1.xyz, v2.xyz, ft0.www", // multiply offset.rgb with alpha (pma!)
"add oc, ft0, ft1" // add offset, copy to output
].join("\n");
if (texture != null)
{
vertexShader = [
"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 offset to fp
].join("\n");
fragmentShader = [
FilterEffect.tex("ft0", "v0", 0, texture) +
"mul ft0, ft0, v1", // multiply color with texel color
addOffset
].join("\n");
}
else
{
vertexShader = [
"m44 op, va0, vc0", // 4x4 matrix transform to output clipspace
"mul v0, va2, vc4", // multiply alpha (vc4) with color (va2)
"mov v2, va3 " // pass offset to fp
].join("\n");
fragmentShader = [
"mov ft0, v0", addOffset
].join("\n");
}
return Program.fromSource(vertexShader, fragmentShader);
}
override private function get_vertexFormat():VertexDataFormat
{
return VERTEX_FORMAT;
}
override private function beforeDraw(context:Context3D):Void
{
super.beforeDraw(context);
vertexFormat.setVertexBufferAt(3, vertexBuffer, "offset");
}
override private function afterDraw(context:Context3D):Void
{
context.setVertexBufferAt(3, null);
super.afterDraw(context);
}
}
@joshtynjala
Copy link
Author

joshtynjala commented Apr 23, 2025

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