public
Created

Software graphics library with blending, textures, and simple primitives.

  • Download Gist
Blend.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
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 );
 
}
CircleDraw.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
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 );
}
 
}
Color.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
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
);
}
 
}
Colors.java
Java
1 2 3 4 5 6 7 8 9 10
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 );
}
Gfx.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
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 );
}
 
}
LineDraw.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
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;
}
}
 
}
RectDraw.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
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;
}
}
 
}
Test.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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();
}
}
Texture.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
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;
}
 
}
TextureLoader.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
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 );
}
}
Tile.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
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);
}
}
TileDraw.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
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;
}
}
}
TimeTracker.java
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
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();
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.