Last active
October 14, 2023 23:55
-
-
Save nanjizal/f2db86737fb089744cb3aa100197b18b to your computer and use it in GitHub Desktop.
testing Bytes Colour
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
// https://try.haxe.org/#f7d671F9 | |
import haxe.io.Bytes; | |
import haxe.io.UInt32Array; | |
function main() { | |
trace("Haxe is great!"); | |
var width = 10; | |
var height = 10; | |
var a1 = new ByteImage( width, height ); | |
a1.set( 1, 0x1234567A ); | |
trace( a1.get( 1 ) ); | |
var a2 = new UInt32Wrap( Std.int( width * height ) ); | |
a2.set( 1, 0x1234567A ); | |
trace( a2.get( 1 ) ); | |
var v1: ByteImage = cast testWrap( cast a1 ); | |
trace( v1.get(1).stringHash() ); | |
trace( a1.image.toHex() ); | |
var v2: UInt32Wrap = cast testWrap( cast a2 ); | |
trace( v2.get(1).stringHash() ); | |
} | |
function testWrap<T:ImageWrapper>(a:T){ | |
return (a:T); | |
} | |
typedef ImageWrapper = { | |
public function set( key: Int, val: Pixel32 ): Pixel32; | |
public function get( key: Int ): Pixel32; | |
} | |
abstract UInt32Wrap( UInt32Array ){ | |
public inline | |
function new( v: Int ){ | |
this = new UInt32Array( v ); | |
} | |
public inline | |
function set( key: Int, v: Pixel32 ): Pixel32 { | |
return ( this.set( key, new Pixel32( v ) ): Pixel32 ); | |
} | |
public inline | |
function get( key: Int ): Pixel32 { | |
return ( this.get( key ) : Pixel32 ); | |
} | |
} | |
@:allow(Test) | |
@:structInit | |
class ByteImage_ { | |
public var width: Int; | |
public var height: Int; | |
public var image: Bytes; | |
public function new( width: Int, height: Int, image: Bytes ){ | |
this.width = width; | |
this.height = height; | |
this.image = image; | |
} | |
} | |
@:forward | |
@:transient | |
abstract ByteImage( ByteImage_ ) from ByteImage_ to ByteImage_ { | |
public inline | |
function new( w: Int, h: Int ){ | |
this = { width: w, height: h, image: Bytes.alloc( w * h * 4 + h ) }; | |
zero(); | |
} | |
public inline | |
function zero(){ | |
var w = 0, row = 0; | |
for( y in 0...this.height ) { | |
for( x in 0...this.width ) { | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
row += 4; | |
} | |
} | |
} | |
inline | |
function rowWidth(): Int { | |
return this.width * 4; | |
} | |
inline | |
function get_y( key: Int ): Int { | |
return Math.floor( key/this.height ); | |
} | |
inline | |
function wholeRows( y: Int ){ | |
return y * rowWidth(); | |
} | |
inline | |
function colPos( y: Int, key: Int ){ | |
return key - ( y * this.height ); | |
} | |
inline | |
function get_xOff( y: Int, key: Int ){ | |
return 4*colPos( y, key ); | |
} | |
public inline | |
function pos( key: Int ){ | |
final y = get_y( key ); | |
return wholeRows( y ) + get_xOff( y, key ); | |
} | |
public inline | |
function location( px: Float, py: Float ): Int { | |
// key | |
return Std.int( py * this.width + px ); | |
} | |
@:arrayAccess | |
public inline | |
function get( key: Int ): Pixel32 { | |
final p = pos( key ); | |
return new Pixel32( this.image.getInt32(p) ); | |
} | |
@:arrayAccess | |
public inline | |
function set( key: Int, col: Pixel32 ): Pixel32 { | |
final p = pos( key ); | |
this.image.setInt32( p, col ); | |
return col; | |
} | |
} | |
@:forward | |
@:transient | |
abstract PixelChannel( Int ) to Int from Int { | |
inline | |
public function new( v: Int ) | |
this = v; | |
@:from | |
public inline static function toHexInt( c: Float ): PixelChannel | |
return ( cast Math.round( c * 255 ) : PixelChannel ); | |
@:to | |
public inline function colIntToFloat(): Float | |
return ( this == 0 )? 0.: this/255; | |
@:to | |
public inline function stringHash(): String | |
return '#' + StringTools.hex( this, 2 ); | |
inline | |
public static function boundChannel( f: Float ): Int { | |
var i = Std.int( f ); | |
if( i > 0xFF ) i = 0xFF; | |
if( i < 0 ) i = 0; | |
return new PixelChannel( i ); | |
} | |
} | |
@:forward | |
@:transient | |
abstract Pixel32( Int ) to Int from Int { | |
inline | |
public function new( v: Int ) | |
this = v; | |
/** | |
returns the 0x00 -> 0xFF number component | |
in ARGB, 0 -> B, 1 -> G, 2 - R, 3 -> A | |
**/ | |
inline | |
public function hexChannel( i: Int ): PixelChannel { | |
return switch( i ){ | |
case 0: | |
( cast this >> 24 & 0xFF: PixelChannel ); | |
case 1: | |
( cast this >> 16 & 0xFF: PixelChannel ); | |
case 2: | |
( cast this >> 8 & 0xFF : PixelChannel ); | |
case 3: | |
( cast this & 0xFF: PixelChannel ); | |
case _: | |
( 0x00: PixelChannel ); | |
} | |
} | |
public var c0( get, set ): PixelChannel; | |
inline | |
function get_c0(): PixelChannel | |
return ( cast this >> 24 & 0xFF: PixelChannel ); | |
inline | |
function set_c0( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( v, c1, c2, c3 ); | |
return v; | |
} | |
public var c1( get, set ): PixelChannel; | |
inline | |
function get_c1(): PixelChannel | |
return ( cast this >> 16 & 0xFF: PixelChannel ); | |
inline | |
function set_c1( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, v, c2, c3 ); | |
return v; | |
} | |
public var c2( get, set ): PixelChannel; | |
inline | |
function get_c2(): PixelChannel | |
return ( cast this >> 8 & 0xFF : PixelChannel ); | |
inline | |
function set_c2( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, c1, v, c3 ); | |
return v; | |
} | |
public var c3( get, set ): PixelChannel; | |
inline | |
function get_c3(): PixelChannel | |
return ( cast this & 0xFF: PixelChannel ); | |
inline | |
function set_c3( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, c1, c2, v ); | |
return v; | |
} | |
inline | |
public function flip13(): Pixel32 | |
return ( cast c0 << 24 | c3 << 16 | c2 << 8 | c1 : Pixel32 ); | |
/* | |
inline | |
public function transferColor(): Pixel32 | |
return ( isLittleEndian )? flip13(): ( cast this: Pixel32 ); | |
*/ | |
inline | |
public function stringHash(): String | |
return '#' + StringTools.hex( this, 8 ); | |
inline | |
public function isTransparent(): Bool | |
return ( cast c0: Int ) < 0xFE; | |
/* | |
inline | |
public static function fromPixel28Alpha( col: Pixel28, alpha: Int ): Pixel32 | |
return ( cast ( alpha << 24 | col ) : Pixel32 ); | |
*/ | |
inline | |
public static function fromChannels( ch0: Int, ch1: Int, ch2: Int, ch3: Int ): Pixel32 | |
return ( cast ch0 << 24 | ch1 << 16 | ch2 << 8 | ch3 : Pixel32 ); | |
inline | |
public static function from_argb( a: Float, r: Float, g: Float, b: Float ): Pixel32 | |
return ( cast | |
( PixelChannel.toHexInt( a ) << 24 ) | |
| ( PixelChannel.toHexInt( r ) << 16 ) | |
| ( PixelChannel.toHexInt( g ) << 8 ) | |
| PixelChannel.toHexInt( b ): Pixel32 ); | |
inline | |
public function maskPixel( m: Pixel32 ): Pixel32 { | |
return if( m*1 == 0 ){ | |
return new Pixel32( this ); | |
} else { | |
var m0: Float = m.c0; | |
var m1: Float = m.c1; | |
var m2: Float = m.c2; | |
var m3: Float = m.c3; | |
// may need some extra logic for round error especially at 1, 0? | |
var ch0 = Std.int( (1.-m0)*abstract.c0 ); | |
var ch1 = Std.int( (1.-m1)*abstract.c1 ); | |
var ch2 = Std.int( (1.-m2)*abstract.c2 ); | |
var ch3 = Std.int( (1.-m3)*abstract.c3 ); | |
Pixel32.from_argb( ch0, ch1, ch2, ch3 ); | |
} | |
} | |
public inline | |
function channelBlend( ch0: PixelChannel | |
, ch1: PixelChannel | |
, ch2: PixelChannel | |
, ch3: PixelChannel ){ | |
var a1: Float = c0; // abstract conversion | |
var r1: Float = c1; | |
var g1: Float = c2; | |
var b1: Float = c3; | |
var a2: Float = ch0; | |
var r2: Float = ch1; | |
var g2: Float = ch2; | |
var b2: Float = ch3; | |
var a3 = a1 * ( 1 - a2 ); | |
var r = colBlendFunc( r1, r2, a3, a2 ); | |
var g = colBlendFunc( g1, g2, a3, a2 ); | |
var b = colBlendFunc( b1, b2, a3, a2 ); | |
var a = alphaBlendFunc( a3, a2 ); | |
return fromChannels( a, r, g, b ); | |
} | |
// does not flip colors | |
@:op(A + B) public inline | |
function alphaBlend( rhs: Pixel32 ): Pixel32 { | |
var a1: Float = c0; // abstract conversion | |
var r1: Float = c1; | |
var g1: Float = c2; | |
var b1: Float = c3; | |
var a2: Float = rhs.c0; | |
var r2: Float = rhs.c1; | |
var g2: Float = rhs.c2; | |
var b2: Float = rhs.c3; | |
var a3 = a1 * ( 1 - a2 ); | |
var r = colBlendFunc( r1, r2, a3, a2 ); | |
var g = colBlendFunc( g1, g2, a3, a2 ); | |
var b = colBlendFunc( b1, b2, a3, a2 ); | |
var a = alphaBlendFunc( a3, a2 ); | |
return fromChannels( a, r, g, b ); | |
} | |
inline | |
static function colBlendFunc( x1: Float, x2: Float, a3: Float, a2: Float ): Int | |
return Std.int( 255 * ( x1 * a3 + x2 * a2 ) ); | |
inline | |
static function alphaBlendFunc( a3: Float, a2: Float ): Int | |
return Std.int( 255 * ( a3 + a2 ) ); | |
} |
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
import haxe.io.Bytes; | |
import haxe.io.UInt32Array; | |
import haxe.ds.Either; | |
function main() { | |
trace("Haxe is great!"); | |
var width = 10; | |
var height = 10; | |
var a1 = new ByteImage( width, height ); | |
a1.set( 3, 0x1234567A ); | |
trace( a1.get( 3 ) ); | |
var a2 = new UInt32Wrap( Std.int( width * height ) ); | |
a2.set( 2, 0x1234567A ); | |
trace( a2.get( 2 ) ); | |
var v1: ByteImage = cast testWrap( cast a1 ); | |
trace( v1.get(2).stringHash() ); | |
trace( a1.image.toHex() ); | |
var a3: OneOf<ByteImage,UInt32Wrap> = a2; | |
//var v2: Either<ByteImage,UInt32Wrap> = a3; | |
//trace( v2 ); | |
//trace( v2.get(1).stringHash() ); | |
switch(a3) { | |
case Left(l): trace( l.get(2).stringHash() ); | |
case Right(r): trace( r.get(2).stringHash() ); | |
case _: trace('oops'); | |
} | |
var a4: OneOf<ByteImage,UInt32Wrap> = a1; | |
switch(a4){ | |
case Left(l): trace( l.get(2).stringHash() ); | |
case Right(r): trace( r.get(2).stringHash() ); | |
case _: trace('oops'); | |
} | |
} | |
abstract OneOf<A, B>(Either<A, B>) from Either<A, B> to Either<A, B> { | |
@:from inline static function fromA<A, B>(a:A):OneOf<A, B> { | |
return Left(a); | |
} | |
@:from inline static function fromB<A, B>(b:B):OneOf<A, B> { | |
return Right(b); | |
} | |
@:to inline function toA():Null<A> return switch(this) { | |
case Left(a): a; | |
default: null; | |
} | |
@:to inline function toB():Null<B> return switch(this) { | |
case Right(b): b; | |
default: null; | |
} | |
} | |
function testWrap<T:ImageWrapper>(a:T){ | |
return (a:T); | |
} | |
typedef ImageWrapper = { | |
public function set( key: Int, val: Pixel32 ): Pixel32; | |
public function get( key: Int ): Pixel32; | |
} | |
@:keep | |
abstract UInt32Wrap( UInt32Array ){ | |
public inline | |
function new( v: Int ){ | |
this = new UInt32Array( v ); | |
} | |
public inline | |
function set( key: Int, v: Pixel32 ): Pixel32 { | |
return ( this.set( key, new Pixel32( v ) ): Pixel32 ); | |
} | |
public inline | |
function get( key: Int ): Pixel32 { | |
return ( this.get( key ) : Pixel32 ); | |
} | |
} | |
@:allow(Test) | |
@:structInit | |
class ByteImage_ { | |
public var width: Int; | |
public var height: Int; | |
public var image: Bytes; | |
public function new( width: Int, height: Int, image: Bytes ){ | |
this.width = width; | |
this.height = height; | |
this.image = image; | |
} | |
} | |
@:forward | |
@:transient | |
abstract ByteImage( ByteImage_ ) from ByteImage_ to ByteImage_ { | |
public inline | |
function new( w: Int, h: Int ){ | |
this = { width: w, height: h, image: Bytes.alloc( w * h * 4 + h ) }; | |
zero(); | |
} | |
public inline | |
function zero(){ | |
var w = 0, row = 0; | |
for( y in 0...this.height ) { | |
for( x in 0...this.width ) { | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
this.image.set(w++,0); | |
row += 4; | |
} | |
} | |
} | |
inline | |
function rowWidth(): Int { | |
return this.width * 4; | |
} | |
inline | |
function get_y( key: Int ): Int { | |
return Math.floor( key/this.height ); | |
} | |
inline | |
function wholeRows( y: Int ){ | |
return y * rowWidth(); | |
} | |
inline | |
function colPos( y: Int, key: Int ){ | |
return key - ( y * this.height ); | |
} | |
inline | |
function get_xOff( y: Int, key: Int ){ | |
return 4*colPos( y, key ); | |
} | |
public inline | |
function pos( key: Int ){ | |
final y = get_y( key ); | |
//return 4*( y * this.width - y * this.height + 1 ); | |
return wholeRows( y ) + get_xOff( y, key ); | |
} | |
public inline | |
function location( px: Float, py: Float ): Int { | |
// key | |
return Std.int( py * this.width + px ); | |
} | |
@:arrayAccess | |
public inline | |
function get( key: Int ): Pixel32 { | |
final p = pos( key ); | |
return new Pixel32( this.image.getInt32(p) ); | |
} | |
@:arrayAccess | |
public inline | |
function set( key: Int, col: Pixel32 ): Pixel32 { | |
final p = pos( key ); | |
this.image.setInt32( p, col ); | |
return col; | |
} | |
} | |
@:forward | |
@:transient | |
abstract PixelChannel( Int ) to Int from Int { | |
inline | |
public function new( v: Int ) | |
this = v; | |
@:from | |
public inline static function toHexInt( c: Float ): PixelChannel | |
return ( cast Math.round( c * 255 ) : PixelChannel ); | |
@:to | |
public inline function colIntToFloat(): Float | |
return ( this == 0 )? 0.: this/255; | |
@:to | |
public inline function stringHash(): String | |
return '#' + StringTools.hex( this, 2 ); | |
inline | |
public static function boundChannel( f: Float ): Int { | |
var i = Std.int( f ); | |
if( i > 0xFF ) i = 0xFF; | |
if( i < 0 ) i = 0; | |
return new PixelChannel( i ); | |
} | |
} | |
@:forward | |
@:transient | |
abstract Pixel32( Int ) to Int from Int { | |
inline | |
public function new( v: Int ) | |
this = v; | |
/** | |
returns the 0x00 -> 0xFF number component | |
in ARGB, 0 -> B, 1 -> G, 2 - R, 3 -> A | |
**/ | |
inline | |
public function hexChannel( i: Int ): PixelChannel { | |
return switch( i ){ | |
case 0: | |
( cast this >> 24 & 0xFF: PixelChannel ); | |
case 1: | |
( cast this >> 16 & 0xFF: PixelChannel ); | |
case 2: | |
( cast this >> 8 & 0xFF : PixelChannel ); | |
case 3: | |
( cast this & 0xFF: PixelChannel ); | |
case _: | |
( 0x00: PixelChannel ); | |
} | |
} | |
public var c0( get, set ): PixelChannel; | |
inline | |
function get_c0(): PixelChannel | |
return ( cast this >> 24 & 0xFF: PixelChannel ); | |
inline | |
function set_c0( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( v, c1, c2, c3 ); | |
return v; | |
} | |
public var c1( get, set ): PixelChannel; | |
inline | |
function get_c1(): PixelChannel | |
return ( cast this >> 16 & 0xFF: PixelChannel ); | |
inline | |
function set_c1( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, v, c2, c3 ); | |
return v; | |
} | |
public var c2( get, set ): PixelChannel; | |
inline | |
function get_c2(): PixelChannel | |
return ( cast this >> 8 & 0xFF : PixelChannel ); | |
inline | |
function set_c2( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, c1, v, c3 ); | |
return v; | |
} | |
public var c3( get, set ): PixelChannel; | |
inline | |
function get_c3(): PixelChannel | |
return ( cast this & 0xFF: PixelChannel ); | |
inline | |
function set_c3( v: PixelChannel ): PixelChannel { | |
this = Pixel32.fromChannels( c0, c1, c2, v ); | |
return v; | |
} | |
inline | |
public function flip13(): Pixel32 | |
return ( cast c0 << 24 | c3 << 16 | c2 << 8 | c1 : Pixel32 ); | |
/* | |
inline | |
public function transferColor(): Pixel32 | |
return ( isLittleEndian )? flip13(): ( cast this: Pixel32 ); | |
*/ | |
inline | |
public function stringHash(): String | |
return '#' + StringTools.hex( this, 8 ); | |
inline | |
public function isTransparent(): Bool | |
return ( cast c0: Int ) < 0xFE; | |
/* | |
inline | |
public static function fromPixel28Alpha( col: Pixel28, alpha: Int ): Pixel32 | |
return ( cast ( alpha << 24 | col ) : Pixel32 ); | |
*/ | |
inline | |
public static function fromChannels( ch0: Int, ch1: Int, ch2: Int, ch3: Int ): Pixel32 | |
return ( cast ch0 << 24 | ch1 << 16 | ch2 << 8 | ch3 : Pixel32 ); | |
inline | |
public static function from_argb( a: Float, r: Float, g: Float, b: Float ): Pixel32 | |
return ( cast | |
( PixelChannel.toHexInt( a ) << 24 ) | |
| ( PixelChannel.toHexInt( r ) << 16 ) | |
| ( PixelChannel.toHexInt( g ) << 8 ) | |
| PixelChannel.toHexInt( b ): Pixel32 ); | |
inline | |
public function maskPixel( m: Pixel32 ): Pixel32 { | |
return if( m*1 == 0 ){ | |
return new Pixel32( this ); | |
} else { | |
var m0: Float = m.c0; | |
var m1: Float = m.c1; | |
var m2: Float = m.c2; | |
var m3: Float = m.c3; | |
// may need some extra logic for round error especially at 1, 0? | |
var ch0 = Std.int( (1.-m0)*abstract.c0 ); | |
var ch1 = Std.int( (1.-m1)*abstract.c1 ); | |
var ch2 = Std.int( (1.-m2)*abstract.c2 ); | |
var ch3 = Std.int( (1.-m3)*abstract.c3 ); | |
Pixel32.from_argb( ch0, ch1, ch2, ch3 ); | |
} | |
} | |
public inline | |
function channelBlend( ch0: PixelChannel | |
, ch1: PixelChannel | |
, ch2: PixelChannel | |
, ch3: PixelChannel ){ | |
var a1: Float = c0; // abstract conversion | |
var r1: Float = c1; | |
var g1: Float = c2; | |
var b1: Float = c3; | |
var a2: Float = ch0; | |
var r2: Float = ch1; | |
var g2: Float = ch2; | |
var b2: Float = ch3; | |
var a3 = a1 * ( 1 - a2 ); | |
var r = colBlendFunc( r1, r2, a3, a2 ); | |
var g = colBlendFunc( g1, g2, a3, a2 ); | |
var b = colBlendFunc( b1, b2, a3, a2 ); | |
var a = alphaBlendFunc( a3, a2 ); | |
return fromChannels( a, r, g, b ); | |
} | |
// does not flip colors | |
@:op(A + B) public inline | |
function alphaBlend( rhs: Pixel32 ): Pixel32 { | |
var a1: Float = c0; // abstract conversion | |
var r1: Float = c1; | |
var g1: Float = c2; | |
var b1: Float = c3; | |
var a2: Float = rhs.c0; | |
var r2: Float = rhs.c1; | |
var g2: Float = rhs.c2; | |
var b2: Float = rhs.c3; | |
var a3 = a1 * ( 1 - a2 ); | |
var r = colBlendFunc( r1, r2, a3, a2 ); | |
var g = colBlendFunc( g1, g2, a3, a2 ); | |
var b = colBlendFunc( b1, b2, a3, a2 ); | |
var a = alphaBlendFunc( a3, a2 ); | |
return fromChannels( a, r, g, b ); | |
} | |
inline | |
static function colBlendFunc( x1: Float, x2: Float, a3: Float, a2: Float ): Int | |
return Std.int( 255 * ( x1 * a3 + x2 * a2 ) ); | |
inline | |
static function alphaBlendFunc( a3: Float, a2: Float ): Int | |
return Std.int( 255 * ( a3 + a2 ) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment