Skip to content

Instantly share code, notes, and snippets.

@ClickerMonkey
Created November 18, 2013 19:58
Show Gist options
  • Save ClickerMonkey/7534326 to your computer and use it in GitHub Desktop.
Save ClickerMonkey/7534326 to your computer and use it in GitHub Desktop.
Software graphics library with blending, textures, and simple primitives.
public abstract class Blend
{
public static final Blend Alpha = new Blend()
{
public int blend( int o, int n )
{
return Color.mixRGB( o, n, Color.alpha( n ), Color.alpha( o ) );
}
};
public static final Blend Additive = new Blend()
{
public int blend( int o, int n )
{
return Color.add( o, Color.scaleRGB( n, Color.alpha( n ), 0 ) );
}
};
public static final Blend Invert = new Blend()
{
public int blend( int o, int n )
{
return Color.subRGB( Color.scaleRGB( n, Color.alpha( n ), Color.COMPONENT_MAX ), o, Color.alpha( o ) );
}
};
public static final Blend Replace = new Blend()
{
public int blend( int o, int n )
{
return n;
}
};
public static final Blend Ignore = new Blend()
{
public int blend( int o, int n )
{
return o;
}
};
public abstract int blend( int o, int n );
}
public class CircleDraw
{
public Gfx g;
public CircleDraw( Gfx g )
{
this.g = g;
}
public void fillSmooth( int cx, int cy, int radius, int color )
{
// Adjust for anti-aliasing of pixels around borders
cx++;
cy++;
radius -= 2;
final int radius2 = radius << 1;
final int radius4 = radius << 2;
int error = -radius - 1;
int x = radius;
int y = 1;
scanline( cy, cx - x, cx + x + 1, color );
int alpha = (((error + radius2) << 8) / radius4) ^ 255;
int alphad = Color.mulAlpha( color, alpha );
g.apply( cx - x - 1, cy, alphad );
g.apply( cx + x, cy, alphad );
g.apply( cx, cy - x - 1, alphad );
g.apply( cx, cy + x + 1, alphad );
while (x > y)
{
alpha = (((error + radius2) << 8) / radius4) ^ 255;
alphad = Color.mulAlpha( color, alpha );
g.apply( cx - x - 1, cy - y, alphad );
g.apply( cx + x, cy - y, alphad );
g.apply( cx - x - 1, cy + y, alphad );
g.apply( cx + x, cy + y, alphad );
g.apply( cx - y, cy - x - 1, alphad );
g.apply( cx - y, cy + x + 1, alphad );
if (y != 1)
{
g.apply( cx + y - 1, cy - x - 1, alphad );
g.apply( cx + y - 1, cy + x + 1, alphad );
}
scanline( cy - y, cx - x, cx + x + 1, color );
scanline( cy + y, cx - x, cx + x + 1, color );
error += y + ++y;
if (error >= 0)
{
scanline( cy - x, cx - y + 1, cx + y, color );
scanline( cy + x, cx - y + 1, cx + y, color );
error -= x + --x;
}
}
alpha = (((error + radius2) << 8) / radius4) ^ 255;
alphad = Color.mulAlpha( color, alpha );
g.apply( cx - x - 1, cy - y, alphad );
g.apply( cx + x, cy - y, alphad );
g.apply( cx - x - 1, cy + y, alphad );
g.apply( cx + x, cy + y, alphad );
if (x == y)
{
g.apply( cx - x, cy - y - 1, alphad );
g.apply( cx + x - 1, cy - y - 1, alphad );
g.apply( cx - x, cy + y + 1, alphad );
g.apply( cx + x - 1, cy + y + 1, alphad );
scanline( cy - y, cx - x, cx + x + 1, color );
scanline( cy + y, cx - x, cx + x + 1, color );
}
}
public void fillFast( int cx, int cy, int radius, int color )
{
int error = -radius + 1;
int x = radius;
int y = 1;
scanline( cy, cx - x, cx + x, color );
while (x > y)
{
scanline( cy - y, cx - x, cx + x, color );
scanline( cy + y, cx - x, cx + x, color );
error += y + ++y;
if (error >= 0)
{
scanline( cy - x, cx - y, cx + y, color );
scanline( cy + x, cx - y, cx + y, color );
error -= x + --x;
}
}
if (x == y)
{
scanline( cy - y, cx - x, cx + x, color );
scanline( cy + y, cx - x, cx + x, color );
}
}
private void scanline( int y, int x0, int x1, int color )
{
final int bw = g.width();
final int bh = g.height();
if (y < 0 || y >= bh || (x0 < 0 && x1 < 0) || (x0 > bw && x1 > bw))
{
return;
}
x0 = (x0 < 0 ? 0 : (x0 > bw ? bw : x0));
x1 = (x1 < 0 ? 0 : (x1 > bw ? bw : x1));
int offset = g.getOffset( x0, y );
while (x0 < --x1)
{
g.apply( offset++, color );
}
}
public void outlineFast( int cx, int cy, int radius, int color )
{
int error = -radius;
int x = radius;
int y = 0;
while (x > y)
{
apply8( cx, cy, x, y, color );
error += y++ + y;
if (error >= 0)
{
error -= x + --x;
}
}
apply4( cx, cy, x, y, color );
}
private void apply8( int cx, int cy, int x, int y, int color )
{
apply4( cx, cy, x, y, color );
apply4( cx, cy, y, x, color );
}
private void apply4( int cx, int cy, int x, int y, int color )
{
g.applyCheck( cx + x, cy + y, color );
g.applyCheck( cx - x, cy + y, color );
g.applyCheck( cx + x, cy - y, color );
g.applyCheck( cx - x, cy - y, color );
}
public void outlineSmooth( int cx, int cy, int r, int color )
{
// TODO not suck
int R2 = r * r;
int y = 0;
int x = r;
int B = x * x;
int xTop = x + 1;
int T = xTop * xTop;
while (y < x)
{
int E = R2 - y * y;
int L = E - B;
int U = T - E;
if (L < 0)
{
xTop = x;
x--;
T = B;
U = -L;
B = x * x;
L = E - B;
}
octants( cx, cy, x, xTop, y, color, 255 * U / (U + L) );
y++;
}
}
public void octants( int cx, int cy, int x0, int x1, int y, int color, int u )
{
int ucolor = Color.mulAlpha( color, u );
int vcolor = Color.mulAlpha( color, Color.COMPONENT_MAX - u );
g.applyCheck( cx + x0, cy + y, ucolor );
g.applyCheck( cx + x1, cy + y, vcolor );
g.applyCheck( cx + x0, cy - y, ucolor );
g.applyCheck( cx + x1, cy - y, vcolor );
g.applyCheck( cx - x0, cy + y, ucolor );
g.applyCheck( cx - x1, cy + y, vcolor );
g.applyCheck( cx - x0, cy - y, ucolor );
g.applyCheck( cx - x1, cy - y, vcolor );
g.applyCheck( cx + y, cy + x0, ucolor );
g.applyCheck( cx + y, cy + x1, vcolor );
g.applyCheck( cx - y, cy + x0, ucolor );
g.applyCheck( cx - y, cy + x1, vcolor );
g.applyCheck( cx + y, cy - x0, ucolor );
g.applyCheck( cx + y, cy - x1, vcolor );
g.applyCheck( cx - y, cy - x0, ucolor );
g.applyCheck( cx - y, cy - x1, vcolor );
}
}
public class Color
{
public static final int A_SHIFT = 24;
public static final int A_MASK = 0xFF000000;
public static final int R_SHIFT = 16;
public static final int R_MASK = 0x00FF0000;
public static final int G_SHIFT = 8;
public static final int G_MASK = 0x0000FF00;
public static final int B_SHIFT = 0;
public static final int B_MASK = 0x000000FF;
public static final int COMPONENT_MASK = 0xFF;
public static final int COMPONENT_MIN = 0;
public static final int COMPONENT_MAX = 255;
public static final int COMPONENT_POWER = 8;
public static int clamp( int c )
{
return ( c < COMPONENT_MIN ? COMPONENT_MIN : ( c > COMPONENT_MAX ? COMPONENT_MAX : c ) );
}
public static int create( int r, int g, int b )
{
return create( r, g, b, COMPONENT_MAX );
}
public static int create( int r, int g, int b, int a )
{
return ( a << A_SHIFT ) | ( r << R_SHIFT ) | ( g << G_SHIFT ) | ( b << B_SHIFT );
}
public static int mulComponents(int c0, int c1)
{
return (c0 * c1 + COMPONENT_MAX) >> COMPONENT_POWER;
}
public static int mixComponents(int c0, int c1, int delta)
{
return mulComponents( c0, COMPONENT_MAX ^ delta ) + mulComponents( c1, delta );
}
public static int mulAlpha(int c, int alpha)
{
return (c & ~A_MASK) | (mulComponents( alpha(c), alpha ) << A_SHIFT);
}
public static int mulRed(int c, int red)
{
return (c & ~R_MASK) | (mulComponents( red(c), red ) << R_SHIFT);
}
public static int mulGreen(int c, int green)
{
return (c & ~G_MASK) | (mulComponents( green(c), green ) << G_SHIFT);
}
public static int mulBlue(int c, int blue)
{
return (c & ~B_MASK) | (mulComponents( blue(c), blue ) << B_SHIFT);
}
public static int withAlpha(int c, int alpha)
{
return (c & ~A_MASK) | (alpha << A_SHIFT);
}
public static int withRed(int c, int red)
{
return (c & ~R_MASK) | (red << R_SHIFT);
}
public static int withGreen(int c, int green)
{
return (c & ~G_MASK) | (green << G_SHIFT);
}
public static int withBlue(int c, int blue)
{
return (c & ~B_MASK) | (blue << B_SHIFT);
}
public static int createAndClamp( int r, int g, int b )
{
return create( clamp( r ), clamp( g ), clamp( b ) );
}
public static int createAndClamp( int r, int g, int b, int a )
{
return create( clamp( r ), clamp( g ), clamp( b ), clamp( a ) );
}
public static int alpha( int color )
{
return ( color >> A_SHIFT ) & COMPONENT_MASK;
}
public static int red( int color )
{
return ( color >> R_SHIFT ) & COMPONENT_MASK;
}
public static int green( int color )
{
return ( color >> G_SHIFT ) & COMPONENT_MASK;
}
public static int blue( int color )
{
return ( color >> B_SHIFT ) & COMPONENT_MASK;
}
public static int add( int c0, int c1 )
{
return createAndClamp(
red( c0 ) + red( c1 ),
green( c0 ) + green( c1 ),
blue( c0 ) + blue( c1 ),
alpha( c0 ) + alpha( c1 )
);
}
public static int addRGB( int c0, int c1, int alpha )
{
return createAndClamp(
red( c0 ) + red( c1 ),
green( c0 ) + green( c1 ),
blue( c0 ) + blue( c1 ),
alpha
);
}
public static int sub( int c0, int c1 )
{
return createAndClamp(
red( c0 ) - red( c1 ),
green( c0 ) - green( c1 ),
blue( c0 ) - blue( c1 ),
alpha( c0 ) - alpha( c1 )
);
}
public static int subRGB( int c0, int c1, int alpha )
{
return createAndClamp(
red( c0 ) - red( c1 ),
green( c0 ) - green( c1 ),
blue( c0 ) - blue( c1 ),
alpha
);
}
public static int mul( int c0, int c1 )
{
return create(
mulComponents(red( c0 ), red( c1 )),
mulComponents(green( c0 ), green( c1 )),
mulComponents(blue( c0 ), blue( c1 )),
mulComponents(alpha( c0 ), alpha( c1 ))
);
}
public static int mulRGB( int c0, int c1, int alpha )
{
return create(
mulComponents(red( c0 ), red( c1 )),
mulComponents(green( c0 ), green( c1 )),
mulComponents(blue( c0 ), blue( c1 )),
alpha
);
}
public static int lighten( int c, int delta )
{
return create(
mixComponents( red( c ), COMPONENT_MAX, delta ),
mixComponents( green( c ), COMPONENT_MAX, delta ),
mixComponents( blue( c ), COMPONENT_MAX, delta ),
mixComponents( alpha( c ), COMPONENT_MAX, delta )
);
}
public static int lightenRGB( int c, int delta, int alpha )
{
return create(
mixComponents( red( c ), COMPONENT_MAX, delta ),
mixComponents( green( c ), COMPONENT_MAX, delta ),
mixComponents( blue( c ), COMPONENT_MAX, delta ),
alpha
);
}
public static int darken( int c, int delta )
{
return create(
mixComponents( red( c ), COMPONENT_MIN, delta ),
mixComponents( green( c ), COMPONENT_MIN, delta ),
mixComponents( blue( c ), COMPONENT_MIN, delta ),
mixComponents( alpha( c ), COMPONENT_MIN, delta )
);
}
public static int darkenRGB( int c, int delta, int alpha )
{
return create(
mixComponents( red( c ), COMPONENT_MIN, delta ),
mixComponents( green( c ), COMPONENT_MIN, delta ),
mixComponents( blue( c ), COMPONENT_MIN, delta ),
alpha
);
}
public static int mix(int c0, int c1, int delta)
{
return create(
mixComponents( red(c0), red(c1), delta ),
mixComponents( green(c0), green(c1), delta ),
mixComponents( blue(c0), blue(c1), delta ),
mixComponents( alpha(c0), alpha(c1), delta )
);
}
public static int mixRGB(int c0, int c1, int delta, int alpha)
{
return create(
mixComponents( red(c0), red(c1), delta ),
mixComponents( green(c0), green(c1), delta ),
mixComponents( blue(c0), blue(c1), delta ),
alpha
);
}
public static int scale(int c, int delta)
{
return create(
mixComponents( COMPONENT_MIN, red(c), delta ),
mixComponents( COMPONENT_MIN, green(c), delta ),
mixComponents( COMPONENT_MIN, blue(c), delta ),
mixComponents( COMPONENT_MIN, alpha(c), delta )
);
}
public static int scaleRGB(int c, int delta, int alpha)
{
return create(
mixComponents( COMPONENT_MIN, red(c), delta ),
mixComponents( COMPONENT_MIN, green(c), delta ),
mixComponents( COMPONENT_MIN, blue(c), delta ),
alpha
);
}
}
public class Colors
{
public static final int White = Color.create( 255, 255, 255 );
public static final int Black = Color.create( 0, 0, 0 );
public static final int Red = Color.create( 255, 0, 0 );
public static final int Blue = Color.create( 0, 0, 255 );
public static final int Green = Color.create( 0, 255, 0 );
public static final int Magenta = Color.create( 255, 0, 255 );
public static final int Gray = Color.create( 128, 128, 128 );
}
public final class Gfx
{
public Image renderBuffer;
public MemoryImageSource renderBufferSource;
public Texture texture;
public Blend blend = Blend.Alpha;
public Gfx( int w, int h )
{
resize( w, h );
}
public void resize( int w, int h )
{
texture = new Texture( w, h );
renderBufferSource = new MemoryImageSource( w, h, texture.pixels, 0, w );
renderBufferSource.setAnimated( true );
renderBuffer = Toolkit.getDefaultToolkit().createImage( renderBufferSource );
}
public void clear( int color )
{
texture.clear( color );
}
public void apply( int x, int y, int color )
{
final int[] pixels = texture.pixels;
final int offset = texture.getOffset( x, y );
pixels[offset] = blend.blend( pixels[offset], color );
}
public void applyCheck( int x, int y, int color )
{
if (x < 0 || x >= texture.width || y < 0 || y >= texture.height)
{
return;
}
apply( x, y, color );
}
public void apply( int offset, int color )
{
final int[] pixels = texture.pixels;
pixels[offset] = blend.blend( pixels[offset], color );
}
public int get( int x, int y )
{
return texture.get( x, y );
}
public int width()
{
return texture.width;
}
public int height()
{
return texture.height;
}
public int getOffset(int x, int y)
{
return texture.getOffset( x, y );
}
public void flush( Graphics gr )
{
renderBufferSource.newPixels();
gr.drawImage( renderBuffer, 0, 0, null );
}
}
public class LineDraw
{
public Gfx g;
public LineDraw( Gfx g )
{
this.g = g;
}
public void smooth( int x0, int y0, int x1, int y1, int color )
{
int temp = 0;
if (y0 > y1)
{
temp = y1; y1 = y0; y0 = temp;
temp = x1; x1 = x0; x0 = temp;
}
int dx = x1 - x0;
int dy = y1 - y0;
if (dx == 0)
{
vertical( x0, y0, y1, color );
}
else if (dy == 0)
{
horizontal( y0, x0, x1, color );
}
else
{
g.applyCheck( x0, y0, color );
g.applyCheck( x1, y1, color );
int sx = Integer.signum( dx );
dx = StrictMath.abs( dx );
dy = StrictMath.abs( dy );
if (dy > dx)
{
char errorAdj = (char)((dx << 16) / dy);
char errorAccTemp = 0;
char errorAcc = 0;
int weighting = 0;
while (--dy > 0)
{
errorAccTemp = errorAcc;
errorAcc += errorAdj;
if (errorAcc <= errorAccTemp)
{
x0 += sx;
}
y0++;
weighting = (errorAcc >> 8);
g.applyCheck( x0, y0, Color.mulAlpha( color, weighting ^ 0xFF ) );
g.applyCheck( x0 + sx, y0, Color.mulAlpha( color, weighting ) );
}
}
else
{
char errorAdj = (char)((dy << 16) / dx);
char errorAccTemp = 0;
char errorAcc = 0;
int weighting = 0;
while (--dx > 0)
{
errorAccTemp = errorAcc;
errorAcc += errorAdj;
if (errorAcc <= errorAccTemp)
{
y0++;
}
x0 += sx;
weighting = (errorAcc >> 8);
g.applyCheck( x0, y0, Color.mulAlpha( color, weighting ^ 0xFF ) );
g.applyCheck( x0, y0 + 1, Color.mulAlpha( color, weighting ) );
}
}
}
}
public void fast( int x0, int y0, int x1, int y1, int color )
{
// TODO clipping
int dx = x1 - x0;
int dy = y1 - y0;
int adx = StrictMath.abs( dx );
int ady = StrictMath.abs( dy );
int sx = Integer.signum( dx );
int sy = Integer.signum( dy );
int err = adx - ady;
int e2 = 0;
for (;;)
{
g.apply( x0, y0, color );
if (x0 == x1 && y0 == y1)
{
break;
}
e2 = 2 * err;
if (e2 > -ady)
{
err -= ady;
x0 += sx;
}
if (e2 < adx)
{
err += adx;
y0 += sy;
}
}
}
public void horizontal( int y, int x0, int x1, int color )
{
final int bw = g.width();
final int bh = g.height();
if (y < 0 || y >= bh || (x0 < 0 && x1 < 0) || (x0 > bw && x1 > bw))
{
return;
}
x0 = (x0 < 0 ? 0 : (x0 > bw ? bw : x0));
x1 = (x1 < 0 ? 0 : (x1 > bw ? bw : x1));
int d = x1 - x0;
int ad = StrictMath.abs( d );
int s = Integer.signum( d );
int offset = g.getOffset( x0, y );
while (--ad > 0)
{
g.apply( offset, color );
offset += s;
}
}
public void vertical( int x, int y0, int y1, int color )
{
final int bw = g.width();
final int bh = g.height();
if (x < 0 || x >= bw || (y0 < 0 && y1 < 0) || (y0 > bh && y1 > bh))
{
return;
}
y0 = (y0 < 0 ? 0 : (y0 > bh ? bh : y0));
y1 = (y1 < 0 ? 0 : (y1 > bh ? bh : y1));
int d = y1 - y0;
int ad = StrictMath.abs( d );
int s = Integer.signum( d ) * g.width();
int offset = g.getOffset( x, y0 );
while (--ad > 0)
{
g.apply( offset, color );
offset += s;
}
}
}
public class RectDraw
{
public Gfx g;
public RectDraw( Gfx g )
{
this.g = g;
}
public void fill( int x, int y, int w, int h, int color )
{
final int backWidth = g.width();
final int backHeight = g.height();
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x + w > backWidth) w = backWidth - x;
if (y + h > backHeight) h = backHeight - y;
final int stride = backWidth - w;
int offset = g.getOffset( x, y );
for (int yy = 0; yy < h; yy++)
{
for (int xx = 0; xx < w; xx++)
{
g.apply( offset++, color );
}
offset += stride;
}
}
public void outline( int x, int y, int w, int h, int color )
{
// TODO clipping
final int stride = g.width();
int toffset = g.getOffset( x, y );
int boffset = g.getOffset( x, y + h - 1 );
for (int i = 0; i < w; i++ )
{
g.apply( toffset++, color );
g.apply( boffset++, color );
}
int loffset = g.getOffset( x, y + 1 );
int roffset = g.getOffset( x + w - 1, y + 1 );
for (int i = 2; i < h; i++ )
{
g.apply( loffset, color );
g.apply( roffset, color );
loffset += stride;
roffset += stride;
}
}
}
public class Test
{
public static void main(String[] args) throws Exception
{
final Gfx gfx = new Gfx( 480, 320 );
final LineDraw line = new LineDraw( gfx );
final RectDraw rect = new RectDraw( gfx );
final TileDraw tile = new TileDraw( gfx );
final CircleDraw circle = new CircleDraw( gfx );
final Texture texture = TextureLoader.fromUrl( "http://cdn1.iconfinder.com/data/icons/musthave/256/Cancel.png" );
final TimeTracker tracker = new TimeTracker( "Gfx FPS: %.1f", 500, TimeUnit.MILLISECONDS );
final JPanel panel = new JPanel();
panel.setPreferredSize( new Dimension( gfx.width(), gfx.height() ) );
final JFrame window = new JFrame();
window.setResizable( false );
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setVisible( true );
window.add( panel );
window.pack();
final Thread thread = new Thread() {
public void run() {
Graphics gr = null;
tracker.reset();
for(;;)
{
if (gr == null)
{
gr = panel.getGraphics();
}
if (gr != null )
{
gfx.clear( Colors.Black );
gfx.blend = Blend.Alpha;
tile.draw( texture.tile(), 20, 20/*, Color.lighten( Colors.Red, 128 )*/ ); // halfway between red and white
gfx.blend = Blend.Additive;
rect.fill( 50, 50, 100, 100, Color.withAlpha( Colors.Blue, 128 ) );
rect.fill( 125, 100, 100, 100, Color.withAlpha( Colors.Green, 128 ) );
rect.fill( 100, 50, 100, 100, Color.withAlpha( Colors.Red, 128 ) );
gfx.blend = Blend.Alpha;
line.fast( 5, 5, 50, 100, Colors.White );
line.smooth( 10, 5, 55, 100, Colors.White );
rect.outline( 75, 75, 100, 100, Color.withAlpha( Colors.White, 128 ) );
gfx.blend = Blend.Alpha;
circle.fillSmooth( 400, 100, 50, Color.withAlpha( Colors.White, 128 ) );
gfx.flush( gr );
}
if (tracker.update())
{
window.setTitle( tracker.rateString );
}
}
}
};
thread.start();
}
}
public class Texture
{
public int[] pixels;
public int width;
public int height;
public Texture( int w, int h )
{
resize( w, h );
}
public Texture (int w, int h, int[] pixels)
{
this.width = w;
this.height = h;
this.pixels = pixels;
}
public void resize( int w, int h )
{
width = w;
height = h;
pixels = new int[w * h];
}
public void clear( int color )
{
for (int i = 0; i < pixels.length; i++)
{
pixels[i] = color;
}
}
public int get( int x, int y )
{
return pixels[getOffset( x, y )];
}
public void set( int x, int y, int color )
{
pixels[getOffset( x, y )] = color;
}
public Tile tile( int x, int y, int w, int h )
{
return new Tile( this, x, y, w, h );
}
public Tile tile()
{
return new Tile( this );
}
public int getOffset( int x, int y )
{
return y * width + x;
}
}
public class TextureLoader
{
public static Texture fromStream( InputStream in, boolean close ) throws IOException
{
try
{
BufferedImage image = ImageIO.read( in );
Texture texture = new Texture( image.getWidth(), image.getHeight() );
int[] pixels = texture.pixels;
int offset = 0;
for (int y = 0; y < texture.height; y++)
{
for (int x = 0; x < texture.width; x++)
{
pixels[offset++] = image.getRGB( x, y );
}
}
return texture;
}
finally
{
if (close)
{
in.close();
}
}
}
public static Texture fromUrl( String url ) throws MalformedURLException, IOException
{
return fromStream( new URL( url ).openStream(), true );
}
public static Texture fromClasspath(String name) throws IOException
{
return fromStream( TextureLoader.class.getResourceAsStream( name ), true );
}
}
public class Tile
{
public Texture texture;
public int l, t, r, b;
public Tile()
{
}
public Tile( Texture texture )
{
set( texture, 0, 0, texture.width, texture.height );
}
public Tile( Texture texture, int x, int y, int w, int h )
{
set( texture, x, y, x + w, y + h );
}
public void set( Texture texture, int l, int t, int r, int b )
{
this.texture = texture;
this.l = l;
this.t = t;
this.r = r;
this.b = b;
}
public int width()
{
return (r - l);
}
public int height()
{
return (b - t);
}
}
public class TileDraw
{
public Gfx g;
public TileDraw(Gfx g)
{
this.g = g;
}
public void draw(Tile tile, int x, int y)
{
int bw = g.width();
int bh = g.height();
int tl = tile.l;
int tt = tile.t;
int tr = tile.r;
int rl = x;
int rt = y;
int rr = x + tile.width();
int rb = y + tile.height();
if (rl < 0)
{
tl -= rl;
rl = 0;
}
if (rt < 0)
{
tt -= rt;
rt = 0;
}
if (rr > bw)
{
tr -= rr - bw;
rr = bw;
}
if (rb > bh)
{
rb = bh;
}
final Texture tex = tile.texture;
final int[] src = tex.pixels;
final int tstride = tile.width() - (tr - tl);
final int rstride = bw - (rr - rl);
int toffset = tex.getOffset( tl, tt );
int roffset = g.getOffset( rl, rt );
for (y = rt; y < rb; y++)
{
for (x = rl; x < rr; x++)
{
g.apply( roffset++, src[toffset++] );
}
toffset += tstride;
roffset += rstride;
}
}
public void draw(Tile tile, int x, int y, int color)
{
int bw = g.width();
int bh = g.height();
int tl = tile.l;
int tt = tile.t;
int tr = tile.r;
int rl = x;
int rt = y;
int rr = x + tile.width();
int rb = y + tile.height();
if (rl < 0)
{
tl -= rl;
rl = 0;
}
if (rt < 0)
{
tt -= rt;
rt = 0;
}
if (rr > bw)
{
tr -= rr - bw;
rr = bw;
}
if (rb > bh)
{
rb = bh;
}
final Texture tex = tile.texture;
final int[] src = tex.pixels;
final int tstride = tile.width() - (tr - tl);
final int rstride = bw - (rr - rl);
int toffset = tex.getOffset( tl, tt );
int roffset = g.getOffset( rl, rt );
for (y = rt; y < rb; y++)
{
for (x = rl; x < rr; x++)
{
g.apply( roffset++, Color.mul( color, src[toffset++] ) );
}
toffset += tstride;
roffset += rstride;
}
}
}
public class TimeTracker
{
public long lastTime;
public long time;
public long interval;
public long frames;
public double rate;
public String rateFormat;
public String rateString;
public char[] rateText;
public TimeTracker( String rateStringFormat, long refreshInterval, TimeUnit unit )
{
rateFormat = rateStringFormat;
setRefreshInterval( refreshInterval, unit );
}
public void setRefreshInterval( long refreshInterval, TimeUnit unit )
{
interval = unit.toNanos( refreshInterval );
}
public void reset()
{
lastTime = System.nanoTime();
time = 0;
frames = 0;
rate = 0;
updateRateString();
}
public boolean update()
{
boolean updated = false;
long currentTime = System.nanoTime();
long elapsed = (currentTime - lastTime);
time += elapsed;
frames++;
if ( time >= interval )
{
rate = (frames / (time * 0.000000001));
updateRateString();
time -= interval;
frames = 0;
updated = true;
}
lastTime = currentTime;
return updated;
}
private void updateRateString()
{
rateString = String.format( rateFormat, rate);
rateText = rateString.toCharArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment