package rabbitescape.ui.swing; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferStrategy; import java.util.List; import rabbitescape.engine.Thing; import rabbitescape.engine.World; import rabbitescape.engine.World.CompletionState; import rabbitescape.engine.util.Util; import rabbitescape.render.AnimationCache; import rabbitescape.render.AnimationLoader; import rabbitescape.render.BitmapCache; import rabbitescape.render.GraphPaperBackground; import rabbitescape.render.PolygonBuilder; import rabbitescape.render.Renderer; import rabbitescape.render.SoundPlayer; import rabbitescape.render.Sprite; import rabbitescape.render.SpriteAnimator; import rabbitescape.render.Overlay; import rabbitescape.render.Vertex; import rabbitescape.render.androidlike.Path; import rabbitescape.render.androidlike.Sound; import rabbitescape.render.gameloop.Graphics; import rabbitescape.render.gameloop.WaterAnimation; public class SwingGraphics implements Graphics { private static class DrawFrame extends BufferedDraw { private static final SwingPaint white = new SwingPaint( Color.WHITE ); private static final SwingPaint graphPaperMajor = new SwingPaint( new Color( 205, 212, 220 ) ); private static final SwingPaint graphPaperMinor = new SwingPaint( new Color( 235, 243, 255 ) ); private static final SwingPaint waterColor = new SwingPaint( new Color( 10, 100, 220, 100 ) ); private final java.awt.Canvas canvas; private final Renderer<SwingBitmap, SwingPaint> renderer; private final SoundPlayer soundPlayer; private final SpriteAnimator animator; private final int frameNum; private final World world; private final WaterAnimation waterAnimation; static { waterColor.setStyle( SwingPaint.Style.FILL ); } public DrawFrame( BufferStrategy strategy, java.awt.Canvas canvas, Renderer<SwingBitmap, SwingPaint> renderer, SoundPlayer soundPlayer, SpriteAnimator animator, int frameNum, World world, WaterAnimation waterAnimation ) { super( strategy ); this.canvas = canvas; this.renderer = renderer; this.soundPlayer = soundPlayer; this.animator = animator; this.frameNum = frameNum; this.world = world; this.waterAnimation = waterAnimation; } @Override void draw( Graphics2D g ) { SwingCanvas swingCanvas = new SwingCanvas( g, canvas.getWidth(), canvas.getHeight() ); GraphPaperBackground.drawBackground( world, renderer, swingCanvas, white, graphPaperMajor, graphPaperMinor ); drawPolygons( waterAnimation, swingCanvas ); List<Sprite> sprites = animator.getSprites( frameNum ); renderer.render( swingCanvas, sprites, white ); if ( world.paused ) { tacticalOverlay( swingCanvas, world ); } if ( null != soundPlayer ) { soundPlayer.play( sprites ); } } private void tacticalOverlay( SwingCanvas swingCanvas, World world ) { SwingPaint dull = new SwingPaint( new Color( 70, 70, 70, 200 ) ); swingCanvas.drawColor( dull ); Overlay overlay = new Overlay( world ); SwingPaint textPaint = new SwingPaint( new Color( 100, 255, 100, 255 ) ); int h = swingCanvas.stringHeight(); for ( Thing t : overlay.items ) { String notation = overlay.at( t.x, t.y ); String[] lines = Util.split( notation, "\n" ); for ( int i = 0; i < lines.length ; i++ ) { int x = renderer.offsetX + t.x * renderer.tileSize; int y = renderer.offsetY + t.y * renderer.tileSize + i * h; x += ( renderer.tileSize - swingCanvas.stringWidth( lines[i] ) ) / 2; // centre y += ( renderer.tileSize - h * lines.length ) / 2 ; swingCanvas.drawText( lines[i], x, y, textPaint); } } } public void drawPolygons( WaterAnimation wa, SwingCanvas swingCanvas ) { float f = renderer.tileSize / 32f; for ( PolygonBuilder pb : wa.calculatePolygons() ) { Path p = pb.path( f, new Vertex( renderer.offsetX, renderer.offsetY ) ); swingCanvas.drawPath( p, waterColor ); } } } public final World world; private final GameUi jframe; private final BufferStrategy strategy; private final SpriteAnimator animator; private final FrameDumper frameDumper; private final WaterAnimation waterAnimation; public final Renderer<SwingBitmap, SwingPaint> renderer; private final SoundPlayer soundPlayer; private int prevScrollX; private int prevScrollY; private CompletionState lastWorldState; private int lastFrame; private volatile boolean drawing; public SwingGraphics( World world, GameUi jframe, BitmapCache<SwingBitmap> bitmapCache, Sound sound, FrameDumper frameDumper, WaterAnimation waterAnimation ) { this.world = world; this.jframe = jframe; this.strategy = jframe.canvas.getBufferStrategy(); this.animator = new SpriteAnimator( world, new AnimationCache( new AnimationLoader() ) ); this.renderer = new Renderer<SwingBitmap, SwingPaint>( 0, 0, -1, bitmapCache ); this.soundPlayer = new SoundPlayer( sound ); this.prevScrollX = -1; this.prevScrollY = -1; this.lastWorldState = null; this.frameDumper = frameDumper; this.waterAnimation = waterAnimation; this.lastFrame = -1; this.drawing = false; } @Override public void draw( int frame ) { setRendererOffset( renderer ); DrawFrame df = new DrawFrame( strategy, jframe.canvas, renderer, soundPlayer, animator, frame, world, waterAnimation ); df.run(); frameDumper.dump( jframe.canvas, df ); lastFrame = frame; } public void redraw() { // We may be invoked from multiple threads - give up if we're already // drawing. if ( drawing ) { return; } drawing = true; // Can't redraw before drawing if ( -1 == lastFrame ) { return; } setRendererOffset( renderer ); DrawFrame df = new DrawFrame( strategy, jframe.canvas, renderer, null, // Do not repeat sounds animator, lastFrame, world, waterAnimation ); df.run(); drawing = false; } public void setTileSize( int timeSize ) { renderer.tileSize = timeSize; } private void setRendererOffset( Renderer<SwingBitmap, SwingPaint> renderer ) { renderer.setOffset( calcOffset( jframe.scrollX, jframe.canvas.getWidth(), jframe.worldSizeInPixels.width ), calcOffset( jframe.scrollY, jframe.canvas.getHeight(), jframe.worldSizeInPixels.height ) ); } private int calcOffset( int scroll, int canvasSize, int worldSize ) { if ( worldSize < canvasSize ) { return ( ( canvasSize - worldSize ) / 2 ); } else { return -scroll; } } @Override public void rememberScrollPos() { prevScrollX = jframe.scrollX; prevScrollY = jframe.scrollY; } @Override public void drawIfScrolled( int frame ) { if ( prevScrollX != jframe.scrollX || prevScrollY != jframe.scrollY || lastWorldState != world.completionState() ) { lastWorldState = world.completionState(); draw( frame ); prevScrollX = jframe.scrollX; prevScrollY = jframe.scrollY; } } public void playSound( String soundEffect ) { soundPlayer.sound.playSound( soundEffect ); } public void setMuted( boolean muted ) { soundPlayer.sound.mute( muted ); } @Override public void dispose() { } }