# HG changeset patch # User Matti Hamalainen # Date 1480595605 -7200 # Node ID e8eeac403e5f14d6b963e7c12002b4d7fdeb902d # Parent fb33d3796942106b4b8f768c0e1806639a34bf50 Backed out changeset fb33d3796942 diff -r fb33d3796942 -r e8eeac403e5f Makefile --- a/Makefile Tue Jun 21 12:53:53 2016 +0300 +++ b/Makefile Thu Dec 01 14:33:25 2016 +0200 @@ -3,14 +3,14 @@ RESOURCES=graphics/*.png graphics/*.jpg graphics/font.ttf sounds/*.wav -CLASSES=src/G.class \ - src/Piece.class src/PieceType.class \ - src/Engine.class src/Interpolate.class \ - src/ResourceLoader.class \ - src/Sound.class src/SoundManager.class \ - src/IDMPoint.class src/IDMWidget.class \ - src/IDMButton.class src/IDMContainer.class \ - src/AnimatedPointElement.class +CLASSES=game/G.class \ + game/Piece.class game/PieceType.class \ + game/Engine.class game/Interpolate.class \ + game/ResourceLoader.class \ + game/Sound.class game/SoundManager.class \ + game/IDMPoint.class game/IDMWidget.class \ + game/IDMButton.class game/IDMContainer.class \ + game/AnimatedPointElement.class # Utils JAVAC=javac -g -Xlint:unchecked @@ -23,7 +23,7 @@ all: $(TARGETS) -src/%.class: src/%.java +game/%.class: game/%.java $(JAVAC) $< Ristipolku.class: Ristipolku.java $(CLASSES) @@ -38,7 +38,7 @@ ### Package ### Ristipolku.jar: $(RUN) $(RESOURCES) - jar cvfm $@ manifest.txt $+ src/*.class + jar cvfm $@ manifest.txt $+ game/*.class upload: Ristipolku.jar @@ -50,10 +50,10 @@ ### Cleanup ### clean: - $(RM) $(TARGETS) *.class src/*.class + $(RM) $(TARGETS) *.class game/*.class srcclean: clean - $(RM) *~ src/*~ graphics/*~ + $(RM) *~ game/*~ graphics/*~ # dummy diff -r fb33d3796942 -r e8eeac403e5f game/AnimatedPointElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/AnimatedPointElement.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,75 @@ +/* + * Ristipolku animated game element + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.geom.*; +import java.util.*; +import java.math.*; + + +public class AnimatedPointElement +{ + private float stime, value, steps; + private IDMPoint pos; + private Interpolate lerpV, lerpX, lerpY; + boolean active, first; + String text; + + public AnimatedPointElement(IDMPoint start, String text) + { + Random rnd = new Random(); + steps = 100; + + lerpX = new Interpolate(start.x - rnd.nextInt(100) + 50, start.x, steps); + lerpY = new Interpolate(start.y - rnd.nextInt(100) + 50, start.y, steps); + lerpV = new Interpolate(0.0f, 1.0f, steps); + + pos = new IDMPoint(start); + active = false; + first = true; + this.text = text; + } + + public void animate(float time) + { + if (first) + { + first = false; + active = true; + stime = time; + } + + if (active) + { + float t = (time - stime); + if (t >= steps) + { + t = steps; + active = false; + } + + value = lerpV.getValue(t); + pos.x = lerpX.getValue(t); + pos.y = lerpY.getValue(t); + } + } + + public void paint(Graphics2D g) + { + if (!active) + return; + + Paint psave = g.getPaint(); +// AffineTransform tsave = g.getTransform(); + + g.setFont(G.fonts[2]); + g.setPaint(new Color(value, value, value, value)); + g.drawString(text, pos.x, pos.y); + +// g.setTransform(tsave); + g.setPaint(psave); + } +} diff -r fb33d3796942 -r e8eeac403e5f game/Engine.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/Engine.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,909 @@ +/* + * Ristipolku Game Engine + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.geom.*; +import java.awt.event.*; +import java.awt.image.*; +import java.awt.event.*; +import java.awt.font.*; +import javax.imageio.*; +import javax.swing.*; +import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.io.*; +import game.*; +import javax.sound.sampled.*; + + +class AboutBox extends IDMWidget +{ + BufferedImage aboutImg; + boolean aboutSecret; + + IDMPoint currPos, currOffs; + Paint textPaint; + Font textFont; + FontMetrics textMetrics; + + + public AboutBox() + { + try { + ResourceLoader res = new ResourceLoader("graphics/girl.jpg"); + aboutImg = ImageIO.read(res.getStream()); + } + catch (IOException e) + { + } + + aboutSecret = false; + + setPos(150f, 150f); + setSize(675f, 420f); + } + + public void setTextFont(Font font, FontMetrics metrics) + { + textFont = font; + textMetrics = metrics; + } + + public void setTextPaint(Paint paint) + { + textPaint = paint; + } + + public void setCurrPos(IDMPoint npos) + { + currPos = npos; + currOffs = new IDMPoint(0, 0); + } + + public void setCurrPos(float x, float y) + { + setCurrPos(new IDMPoint(x, y)); + } + + public void drawString(Graphics2D g, String text) + { + Paint savePaint = g.getPaint(); + g.setPaint(textPaint); + g.setFont(textFont); + + int i = 0; + while (i < text.length()) + { + int p = text.indexOf("\n", i); + boolean linefeed; + String str; + if (p >= i) + { + str = text.substring(i, p); + i = p + 1; + linefeed = true; + } + else + { + str = text.substring(i); + i += str.length(); + linefeed = false; + } + + g.drawString(str, currPos.x + currOffs.x, currPos.y + currOffs.y); + + if (linefeed) + { + currOffs.x = 0; + currOffs.y += textMetrics.getHeight(); + } + else + { + currOffs.x += textMetrics.stringWidth(str); + } + } + + g.setPaint(savePaint); + } + + public void paint(Graphics2D g) + { + int x = getScaledX(), y = getScaledY(), + w = getScaledWidth(), h = getScaledHeight(); + + g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.7f)); + g.fill(new RoundRectangle2D.Float(x, y, w, h, 10, 10)); + + setTextFont(G.fonts[3], G.metrics[3]); + setTextPaint(Color.white); + + setCurrPos(x + 20, y + 30); + drawString(g, "RistiPolku (CrossPaths) v"+ G.version +"\n"); + + setTextFont(G.fonts[1], G.metrics[1]); + if (aboutSecret) + { + g.drawImage(aboutImg, x + 20, y + 55, + aboutImg.getWidth(), aboutImg.getHeight(), null); + + setCurrPos(x + 225, y + 75); + drawString(g, + "Dedicated to my\n" + + "favorite woman\n" + + "in the world."); + + setCurrPos(x + 370, y + 175); + drawString(g, "- Matti"); + } + else + { + setTextPaint(Color.yellow); + drawString(g, "(c) Copyright 2011 Tecnic Software productions (TNSP)\n"); + + setTextPaint(Color.white); + drawString(g, "Programming, graphics and design by " + + "Matti 'ccr' Hämäläinen.\n" + + "Audio from archive.org, used non-commercially.\n \n"); + + setTextPaint(Color.red); + drawString(g, "Controls:\n"); + + IDMPoint old = currOffs.copy(); + + setTextPaint(Color.white); + drawString(g, + "Arrow keys / mouse wheel\n"+ + "Enter / mouse click\n"+ + "Space bar\n"); + + currPos.x += 330; + currOffs.y = old.y; + drawString(g, + "- Rotate piece\n" + + "- Place/lock piece\n" + + "- Swap piece\n"); + + currPos.x -= 330; + setTextPaint(Color.green); + drawString(g, + "\nObjective: Create a path long as possible by rotating\n"+ + "and placing pieces. More points will be awarded for\n"+ + "advancing the path by several segments per turn." + ); + } + } + + public boolean keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_L) + { + aboutSecret = true; + } + else + { + clicked(); + aboutSecret = false; + } + return true; + } + + public void clicked() + { + parent.remove(this); + } +} + + +class GameBoard extends IDMWidget +{ + static final int boardSize = 9; + static final int boardMiddle = 4; + Piece[][] board; + float pscale, ptime; + + public boolean flagGameOver, flagBoardIsDirty; + int gameScore; + + Piece currPiece, nextPiece; + int currX, currY, currPoint; + + Sound sndPlaced; + + private final ReentrantReadWriteLock pointLock = new ReentrantReadWriteLock(); + private ArrayList pointElems; + + public GameBoard(IDMPoint pos, float ps) + { + super(pos); + pscale = ps; + +// sndPlaced = G.smgr.getSound("sounds/placed.wav"); + + pointElems = new ArrayList(); + + startNewGame(); + } + + public void startNewGame() + { + board = new Piece[boardSize][boardSize]; + board[boardMiddle][boardMiddle] = new Piece(PieceType.START); + + currX = boardMiddle; + currY = boardMiddle; + currPoint = 0; + + currPiece = null; + nextPiece = new Piece(PieceType.ACTIVE); + + flagGameOver = false; + flagBoardIsDirty = true; + pieceFinishTurn(); + gameScore = 0; + } + + public void paintBackPlate(Graphics2D g) + { + g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.2f)); + g.setStroke(new BasicStroke(5.0f)); + g.draw(new RoundRectangle2D.Float(getScaledX(), getScaledY(), + boardSize * pscale, boardSize * pscale, + pscale / 5, pscale / 5)); + } + + public void paintBoard(Graphics2D g, boolean drawCurrent) + { + for (int y = 0; y < boardSize; y++) + for (int x = 0; x < boardSize; x++) + if (board[x][y] != null) + { + if ((drawCurrent && board[x][y] == currPiece) || + (!drawCurrent && board[x][y] != currPiece)) + { + board[x][y].paint(g, + getScaledX() + (x * pscale), + getScaledY() + (y * pscale), + pscale - pscale / 10); + } + } + } + + public void paint(Graphics2D g) + { + paintBoard(g, true); + + Lock read = pointLock.readLock(); + read.lock(); + try + { + for (AnimatedPointElement elem : pointElems) + { + elem.paint(g); + } + } + finally + { + read.unlock(); + } + + + if (!flagGameOver) + { + if (nextPiece != null) + { + // Draw next piece + AffineTransform save = g.getTransform(); + nextPiece.paint(g, G.screenDim.width * 0.85f - 90.0f/2.0f, G.screenDim.height * 0.43f, 90.0f); + g.setTransform(save); + } + } + else + { + // Game over text + String text = "Game Over!"; + int textWidth = G.metrics[2].stringWidth(text); + g.setFont(G.fonts[2]); + + g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.5f)); + g.drawString(text, (G.screenDim.width - textWidth) / 2 + 5, G.screenDim.height / 2 + 5); + + double f = Math.sin(ptime * 0.1) * 4.0; + g.setPaint(Color.white); + g.drawString(text, (G.screenDim.width - textWidth) / 2 + (float) f, G.screenDim.height / 2 + (float) f); + } + + // Score + String text = ""+ String.format("%05d", gameScore); + int textWidth = G.metrics[2].stringWidth(text); + g.setFont(G.fonts[2]); + g.setPaint(Color.white); + g.drawString(text, (G.screenDim.width * 0.85f) - textWidth / 2, G.screenDim.height * 0.3f); + } + + public boolean contains(float x, float y) + { + return (x >= getScaledX() && + y >= getScaledY() && + x < getScaledX() + boardSize * pscale && + y < getScaledY() + boardSize * pscale); + } + + public boolean isBoardDirty() + { + if (flagBoardIsDirty) + { + flagBoardIsDirty = false; + return true; + } + else + return false; + } + + public void animate(float time) + { + if (nextPiece != null) + { + nextPiece.animate(time); + } + + ptime = time; + for (int y = 0; y < boardSize; y++) + for (int x = 0; x < boardSize; x++) + if (board[x][y] != null) + { + board[x][y].animate(time); + if (board[x][y] != currPiece && board[x][y].active) + flagBoardIsDirty = true; + } + + Lock write = pointLock.writeLock(); + write.lock(); + try + { + ArrayList tmp = new ArrayList(); + + for (AnimatedPointElement elem : pointElems) + { + elem.animate(time); + if (elem.active) + tmp.add(elem); + } + + pointElems = tmp; + + if (time % 32 == 1) + { + Random rnd = new Random(); + pointElems.add(new AnimatedPointElement( + new IDMPoint(10 + rnd.nextInt(400), 10 + rnd.nextInt(100)), ".")); + } + } + finally + { + write.unlock(); + } + } + + public void pieceRotate(Piece.RotateDir dir) + { + if (currPiece != null && !flagGameOver) + { + currPiece.rotate(dir); + } + } + + // Change coordinates based on the "outgoing" + // piece connection point. + private void pieceMoveTo(int point) + { + switch (point) + { + case 0: currY--; break; + case 1: currY--; break; + + case 2: currX++; break; + case 3: currX++; break; + + case 4: currY++; break; + case 5: currY++; break; + + case 6: currX--; break; + case 7: currX--; break; + } + } + + public void pieceCreateNew() + { + currPiece = nextPiece; + currPiece.changed(); + nextPiece = new Piece(PieceType.ACTIVE); + flagBoardIsDirty = true; + } + + public void pieceSwapCurrent() + { + if (!flagGameOver) + { + Piece tmp = currPiece; + currPiece = nextPiece; + nextPiece = tmp; + board[currX][currY] = currPiece; + currPiece.changed(); + nextPiece.changed(); + flagBoardIsDirty = true; + } + } + + // Check one piece, set connections, find the new placement + // based on piece rotations etc. + private boolean pieceCheck(Piece piece) + { + if (piece == null) + { + // Create new piece + pieceCreateNew(); + board[currX][currY] = currPiece; + return true; + } + else + if (piece.getType() == PieceType.START) + { + if (currPiece != null) + { + // Hit center starting piece, game over + flagGameOver = true; + return true; + } + else + { + // Start piece as first piece means game is starting + pieceMoveTo(currPoint); + pieceCreateNew(); + board[currX][currY] = currPiece; + return true; + } + } + + // Mark the current piece as locked + piece.setType(PieceType.LOCKED); + + // Solve connection (with rotations) through the piece + currPoint = piece.getRotatedPoint(piece.getMatchingPoint(currPoint)); + + // Mark connection as active + piece.setConnectionState(currPoint, true); + + // Solve exit point (with rotations) + currPoint = piece.getAntiRotatedPoint(piece.getConnection(currPoint)); + + // Move to next position accordingly + pieceMoveTo(currPoint); + return false; + } + + // Finish one move/turn of the game, resolve path and find placement + // of the next piece, or set "game over" state if required. + public void pieceFinishTurn() + { + boolean finished = false; + int connections = 0; + + if (currPiece != null) + { + G.smgr.play(sndPlaced); + } + + while (!finished) + { + if (currX >= 0 && currX < boardSize && currY >= 0 && currY < boardSize) + { + int oldX = currX, oldY = currY; + connections++; + finished = pieceCheck(board[currX][currY]); + + if (!finished) + { + Lock write = pointLock.writeLock(); + write.lock(); + try + { + pointElems.add(new AnimatedPointElement( + new IDMPoint( + getScaledX() + ((oldX + 0.5f) * pscale), + getScaledY() + ((oldY + 0.5f) * pscale)), + "" + connections)); + } + finally + { + write.unlock(); + } + } + + } + else + { + // Outside of the board, game over + finished = true; + flagGameOver = true; + } + } + + // Compute and add score + gameScore += connections * connections; + + // If game over, clear the game + if (flagGameOver) + { + currPiece = null; + } + + flagBoardIsDirty = true; + } + + public boolean mouseWheelMoved(MouseWheelEvent e) + { + int notches = e.getWheelRotation(); + + if (notches < 0) + pieceRotate(Piece.RotateDir.LEFT); + else + pieceRotate(Piece.RotateDir.RIGHT); + + return true; + } + + public void clicked() + { + if (!flagGameOver) + pieceFinishTurn(); + } + + public boolean keyPressed(KeyEvent e) + { + if (flagGameOver) + return false; + + switch (e.getKeyCode()) + { + case KeyEvent.VK_LEFT: + case KeyEvent.VK_UP: + pieceRotate(Piece.RotateDir.LEFT); + return true; + + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_DOWN: + pieceRotate(Piece.RotateDir.RIGHT); + return true; + + case KeyEvent.VK_ENTER: + pieceFinishTurn(); + return true; + } + return false; + } +} + + +public class Engine extends JPanel + implements Runnable, KeyListener, + MouseListener, MouseWheelListener +{ + long startTime; + float gameUpdates, gameFrames; + + Thread animThread; + boolean animEnable = false; + + GameBoard lauta = null; + InputStream musa; + IDMContainer widgets; + AboutBox aboutBox; + + public void dbg(String msg) + { + System.out.print("Engine: " + msg); + } + + public Engine() + { + // Initialize globals + System.out.print("Engine() constructor\n"); + + // Sound system + G.smgr = new SoundManager(new AudioFormat(22050, 16, 1, true, false), 1); + + // Load resources + try + { + ResourceLoader res = new ResourceLoader("graphics/board.jpg"); + G.lautaBG = ImageIO.read(res.getStream()); + + try { + res = new ResourceLoader("graphics/font.ttf"); + + G.fonts = new Font[G.numFonts]; + G.fonts[0] = Font.createFont(Font.TRUETYPE_FONT, res.getStream()); + G.fonts[1] = G.fonts[0].deriveFont(24f); + G.fonts[2] = G.fonts[0].deriveFont(64f); + G.fonts[3] = G.fonts[0].deriveFont(32f); + } + catch (FontFormatException e) + { + dbg("Could not initialize fonts.\n"); + } + + res = new ResourceLoader("sounds/gamemusic.wav"); + musa = res.getStream(); + } + catch (IOException e) + { + JOptionPane.showMessageDialog(null, + e.getMessage(), + "Initialization error", + JOptionPane.ERROR_MESSAGE); + + dbg(e.getMessage()); + } + + // Create IDM GUI widgets + widgets = new IDMContainer(); + + lauta = new GameBoard(new IDMPoint(95, 130), 63); + widgets.add(lauta); + + widgets.add(new BtnSwapPiece(767f, 450f)); + widgets.add(new BtnAbout (767f, 550f)); + widgets.add(new BtnNewGame (767f, 630f)); + + aboutBox = new AboutBox(); + + // Game + startNewGame(); + + // Initialize event listeners + addKeyListener(this); + addMouseListener(this); + addMouseWheelListener(this); + + // Start playing background music + G.smgr.play(musa); + + // Get initial focus + if (!hasFocus()) + { + dbg("Requesting focus.\n"); + requestFocus(); + } + + gameUpdates = 0; + } + + public void startNewGame() + { + gameFrames = 0; + startTime = new Date().getTime(); + lauta.startNewGame(); + } + + public void paintComponent(Graphics g) + { + Graphics2D g2 = (Graphics2D) g; + boolean scaleChanged = false, + updateBoard = lauta.isBoardDirty(); + + // Rescale if parent component size has changed + Dimension dim = getSize(); + if (G.screenDim == null || !dim.equals(G.screenDim)) + { + float dw = dim.width / 1024.0f, + dh = dim.height / 768.0f; + + // Rescale IDM GUI widgets + widgets.setScale(dw, dh); + G.screenDim = dim; + + // Rescale background image + // Rescale fonts + G.fonts[1] = G.fonts[0].deriveFont(24f * dw); + G.fonts[2] = G.fonts[0].deriveFont(64f * dw); + G.fonts[3] = G.fonts[0].deriveFont(32f * dw); + + dbg("Scale changed.\n"); + scaleChanged = true; + updateBoard = true; + } + + if (updateBoard) + { +// dbg("updateBoard()\n"); + G.lautaBGScaled = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB); + Graphics2D gimg = G.lautaBGScaled.createGraphics(); + gimg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + + gimg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + gimg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + gimg.drawImage(G.lautaBG, 0, 0, dim.width, dim.height, null); + lauta.paintBackPlate(gimg); + lauta.paintBoard(gimg, false); + } + + // Get font metrics against current Graphics2D context + if (G.metrics == null || scaleChanged) + { + G.metrics = new FontMetrics[G.numFonts]; + for (int i = 0; i < G.numFonts; i++) + G.metrics[i] = g2.getFontMetrics(G.fonts[i]); + } + + // Draw background image, pieces, widgets + g2.drawImage(G.lautaBGScaled, 0, 0, null); + + // Use antialiasing when rendering the game elements + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + widgets.paint(g2); + + + // Frames per second counter +/* + g2.setFont(G.fonts[1]); + long currTime = new Date().getTime(); + g2.drawString("fps = "+ ((gameFrames * 1000) / (currTime - startTime)), G.screenDim.width - 120, 20); +*/ + gameFrames++; + } + + public void startThreads() + { + dbg("startThreads()\n"); + if (animThread == null) + { + animThread = new Thread(this); + animEnable = true; + animThread.start(); + } + } + + public void stopThreads() + { + dbg("stopThreads()\n"); + + // Stop animations + if (animThread != null) + { + animThread.interrupt(); + animEnable = false; + animThread = null; + } + + // Shut down sound manager + G.smgr.close(); + } + + public void mouseEntered(MouseEvent e) + { + widgets.mouseEntered(e); + } + public void mouseExited(MouseEvent e) + { + widgets.mouseExited(e); + } + + public void mousePressed(MouseEvent e) + { + if (widgets.containsObject(aboutBox)) + aboutBox.mousePressed(e); + else + widgets.mousePressed(e); + } + + public void mouseReleased(MouseEvent e) + { + if (widgets.containsObject(aboutBox)) + aboutBox.mouseReleased(e); + else + widgets.mouseReleased(e); + } + + public void mouseClicked(MouseEvent e) + { + if (!hasFocus()) + { + dbg("Requesting focus.\n"); + requestFocus(); + } + } + + public void mouseWheelMoved(MouseWheelEvent e) + { + lauta.mouseWheelMoved(e); + } + + public void keyTyped(KeyEvent e) { } + public void keyReleased(KeyEvent e) { } + + public void keyPressed(KeyEvent e) + { + // Handle keyboard input + if (widgets.containsObject(aboutBox)) + aboutBox.keyPressed(e); + else + widgets.keyPressed(e); + } + + public void run() + { + while (animEnable) + { + // Progress game animation clock + gameUpdates++; + + // Animate components + lauta.animate(gameUpdates); + + // Repaint with a frame limiter + if (gameUpdates % 4 == 1) + repaint(); + + // Sleep for a moment + try { + Thread.sleep(10); + } + catch (InterruptedException x) { + } + } + } + + class BtnNewGame extends IDMButton + { + public BtnNewGame(float x, float y) + { + super(x, y, KeyEvent.VK_ESCAPE, G.fonts[1], "New Game"); + } + + public void clicked() + { + startNewGame(); + } + } + + class BtnSwapPiece extends IDMButton + { + public BtnSwapPiece(float x, float y) + { + super(x, y, KeyEvent.VK_SPACE, G.fonts[1], "Swap"); + } + + public void clicked() + { + lauta.pieceSwapCurrent(); + } + } + + class BtnAbout extends IDMButton + { + public BtnAbout(float x, float y) + { + super(x, y, KeyEvent.VK_A, G.fonts[1], "About"); + } + + public void clicked() + { + if (!widgets.containsObject(aboutBox)) + widgets.add(aboutBox); + } + } +} diff -r fb33d3796942 -r e8eeac403e5f game/G.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/G.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,29 @@ +package game; + +import java.awt.*; +import java.awt.geom.*; +import java.awt.event.*; +import java.awt.image.*; +import java.awt.event.*; +import java.awt.font.*; +import javax.imageio.*; +import javax.swing.*; +import java.util.*; +import java.io.*; +import game.*; +import javax.sound.sampled.*; + +public class G +{ + public static final String version = "0.85"; + + public static final int numFonts = 4; + public static Font fonts[]; + public static FontMetrics metrics[]; + + public static SoundManager smgr; + + public static Dimension screenDim; + + public static BufferedImage lautaBG = null, lautaBGScaled = null; +} diff -r fb33d3796942 -r e8eeac403e5f game/IDMButton.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/IDMButton.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,134 @@ +/* + * Ristipolku IDM button widget + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.awt.geom.*; +import javax.imageio.*; +import java.io.*; + + +public class IDMButton extends IDMWidget +{ + enum State { FOCUSED, PRESSED, NORMAL } + State state; + static BufferedImage imgUp, imgPressed; + Font font; + FontMetrics metrics; + String text; + boolean active; + + public IDMButton(IDMPoint pos, int keyCode, Font font, String text) + { + super(pos); + loadImages(); + setSize(imgUp.getWidth(), imgUp.getHeight()); + + this.font = font; + this.keyCode = keyCode; + this.text = text; + + state = State.NORMAL; + active = false; + } + + public IDMButton(float x, float y, int keyCode, Font font, String text) + { + this(new IDMPoint(x, y), keyCode, font, text); + } + + private static void loadImages() + { + if (imgUp != null && imgPressed != null) + return; + + try + { + ResourceLoader res = new ResourceLoader("graphics/button1_up.png"); + imgUp = ImageIO.read(res.getStream()); + + res = new ResourceLoader("graphics/button1_down.png"); + imgPressed = ImageIO.read(res.getStream()); + } + catch (IOException e) + { + System.out.print(e.getMessage()); + } + } + + public void scale() + { + } + + public void paint(Graphics2D g) + { + BufferedImage img; + int xoffs, yoffs; + + if (state == State.PRESSED) + { + img = imgPressed; + xoffs = yoffs = 5; + } + else + { + xoffs = yoffs = 0; + img = imgUp; + } + + if (metrics == null) + metrics = g.getFontMetrics(font); + + int textWidth = metrics.stringWidth(text); + g.drawImage(img, getScaledX() + xoffs, getScaledY() + yoffs, null); + + g.setFont(font); + g.setPaint(Color.black); + g.drawString(text, + getScaledX() + xoffs + (getScaledWidth() - textWidth) / 2, + getScaledY() + yoffs + getScaledHeight() / 2); + } + + + public boolean mousePressed(MouseEvent e) + { + state = State.PRESSED; + active = true; + return true; + } + + public boolean mouseReleased(MouseEvent e) + { + boolean oldActive = active; + super.mouseReleased(e); + state = State.NORMAL; + active = false; + return oldActive; + } + + public boolean mouseEntered(MouseEvent e) + { + if (active) + { + state = State.PRESSED; + return true; + } + else + return false; + } + + public boolean mouseExited(MouseEvent e) + { + if (active) + { + state = State.NORMAL; + return true; + } + else + return false; + } +} diff -r fb33d3796942 -r e8eeac403e5f game/IDMContainer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/IDMContainer.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,190 @@ +/* + * Ristipolku IDM widget container + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; + + + +public class IDMContainer extends IDMWidget +{ + private ArrayList children, queue; + private IDMWidget modal; + private int iterated; + private boolean modified; + + public IDMContainer() + { + children = new ArrayList(); + iterated = 0; + modified = false; + } + + synchronized public void add(IDMWidget widget) + { + widget.setParent(this); + if (iterated > 0) + { + queue.add(0, widget); + modified = true; + } + else + children.add(widget); + } + + synchronized public void remove(IDMWidget widget) + { + widget.setParent(null); + if (iterated > 0) + { + queue.remove(widget); + modified = true; + } + else + children.remove(widget); + } + + synchronized private void beginIteration() + { + modified = false; + if (iterated == 0) + { + queue = new ArrayList(); + for (IDMWidget widget : children) + queue.add(widget); + } + iterated++; + } + + synchronized private void endIteration() + { + if (modified && iterated == 1) + { + children = queue; + queue = null; + } + iterated--; + } + + synchronized public void paint(Graphics2D g) + { + // Paint in reverse order + ListIterator iter = children.listIterator(children.size()); + + while (iter.hasPrevious()) + { + final IDMWidget widget = iter.previous(); + widget.paint(g); + } + } + + synchronized public boolean mousePressed(MouseEvent e) + { + try { + beginIteration(); + for (IDMWidget widget : children) + { + if (widget.contains(e.getPoint())) + { + if (widget.mousePressed(e)) + return true; + } + } + } + finally { endIteration(); } + return false; + } + + synchronized public boolean mouseReleased(MouseEvent e) + { + try { + beginIteration(); + for (IDMWidget widget : children) + { + if (widget.mouseReleased(e)) + return true; + } + } + finally { endIteration(); } + return false; + } + + synchronized public boolean mouseExited(MouseEvent e) + { + try { + beginIteration(); + for (IDMWidget widget : children) + { + if (widget.mouseExited(e)) + return true; + } + } + finally { endIteration(); } + return false; + } + + synchronized public boolean mouseEntered(MouseEvent e) + { + try { + beginIteration(); + for (IDMWidget widget : children) + { + if (widget.contains(e.getPoint())) + { + if (widget.mouseEntered(e)) + return true; + } + } + } + finally { endIteration(); } + return false; + } + + synchronized public boolean keyPressed(KeyEvent e) + { + try { + beginIteration(); + for (IDMWidget widget : children) + { + if (widget.keyPressed(e)) + return true; + } + } + finally { endIteration(); } + return false; + } + + synchronized public void setScale(IDMPoint scale) + { + beginIteration(); + for (IDMWidget widget : children) + { + widget.setScale(scale); + } + endIteration(); + } + + synchronized public boolean hasObject(Class c) + { + for (IDMWidget widget : children) + { + if (widget.getClass() == c) + return true; + } + return false; + } + + synchronized public boolean containsObject(Object o) + { + for (IDMWidget widget : children) + { + if (widget == o) + return true; + } + return false; + } +} diff -r fb33d3796942 -r e8eeac403e5f game/IDMPoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/IDMPoint.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,27 @@ +/* + * Ristipolku IDM point + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +public class IDMPoint +{ + public float x, y; + + public IDMPoint(float x, float y) + { + this.x = x; + this.y = y; + } + + public IDMPoint(IDMPoint pt) + { + this.x = pt.x; + this.y = pt.y; + } + + public IDMPoint copy() + { + return new IDMPoint(x, y); + } +} diff -r fb33d3796942 -r e8eeac403e5f game/IDMWidget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/IDMWidget.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,163 @@ +/* + * Ristipolku IDM base widget + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.event.*; + + +public class IDMWidget +{ + IDMWidget parent; + IDMPoint pos, size, scale; + int keyCode; + + public IDMWidget() + { + keyCode = -1; + this.scale = new IDMPoint(1, 1); + this.pos = new IDMPoint(0, 0); + this.size = new IDMPoint(0, 0); + } + + public IDMWidget(IDMPoint pos) + { + this(); + this.pos = pos; + } + + public IDMWidget(IDMPoint pos, IDMPoint size) + { + this(); + this.pos = pos; + this.size = size; + } + + public void setParent(IDMWidget par) + { + this.parent = par; + } + + public void add(IDMWidget widget) + { + } + + public void remove(IDMWidget widget) + { + } + + public void setPos(IDMPoint pos) + { + this.pos = pos; + } + + public void setPos(float x, float y) + { + this.pos = new IDMPoint(x, y); + } + + public void setSize(IDMPoint size) + { + this.size = size; + } + + public void setSize(float w, float h) + { + this.size = new IDMPoint(w, h); + } + + public void setScale(IDMPoint scale) + { + this.scale = scale; + } + + public void setScale(float x, float y) + { + this.setScale(new IDMPoint(x, y)); + } + + public int getScaledX() + { + return (int) (pos.x * scale.x); + } + + public int getScaledY() + { + return (int) (pos.y * scale.y); + } + + public int getScaledWidth() + { + return (int) (size.x * scale.x); + } + + public int getScaledHeight() + { + return (int) (size.y * scale.y); + } + + public boolean contains(float x, float y) + { + return (x >= getScaledX() && + y >= getScaledY() && + x < getScaledX() + getScaledWidth() && + y < getScaledY() + getScaledHeight()); + } + + public boolean contains(Point where) + { + return contains(where.x, where.y); + } + + public boolean contains(IDMPoint where) + { + return contains(where.x, where.y); + } + + public void paint(Graphics2D g) + { + } + + public boolean mousePressed(MouseEvent e) + { + return false; + } + + public boolean mouseReleased(MouseEvent e) + { + if (contains(e.getPoint())) + { + clicked(); + return true; + } + return false; + } + + public boolean mouseEntered(MouseEvent e) + { + return false; + } + + public boolean mouseExited(MouseEvent e) + { + return false; + } + + // Generic key handler + public boolean keyPressed(KeyEvent e) + { + if (e.getKeyCode() == keyCode) + { + clicked(); + return true; + } + else + return false; + } + + public void clicked() + { + } +} diff -r fb33d3796942 -r e8eeac403e5f game/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/Interpolate.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,26 @@ +/* + * Class for smooth non-linear interpolation between two given values in N steps + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.util.*; + +public class Interpolate +{ + public float start, end, steps; + + public Interpolate(float start, float end, float steps) + { + this.start = start; + this.end = end; + this.steps = steps; + } + + public float getValue(float step) + { + float n = step / steps; + float v = n * n * (3.0f - 2.0f * n); + return (start * v) + (end * (1.0f - v)); + } +} diff -r fb33d3796942 -r e8eeac403e5f game/Piece.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/Piece.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,365 @@ +/* + * Ristipolku + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.awt.*; +import java.awt.geom.*; +import java.util.*; +import java.math.*; + + +public class Piece +{ + public enum RotateDir { LEFT, RIGHT } + + static final int numConnections = 8; + static final float maxTime = 50.0f; + + int currRotation; + int[] connections; + boolean[] states; + PieceType type, prevType; + + boolean rotationChanged, rotationActive, + typeChanged, typeActive, + stateChanged, stateActive, + active; + + float currAngle, rotationTime, rotationSpeed, + typeTime, typeValue, throbTime; + + Interpolate lerpRotation, + lerpScale, + lerpType; + + + public Piece(PieceType ptype) + { + // Initialize + connections = new int[numConnections]; + states = new boolean[numConnections]; + type = ptype; + + rotationChanged = false; + rotationActive = false; + currRotation = 4 * 5000; + currAngle = getAngle(currRotation); + + typeChanged = false; + typeActive = false; + + throbTime = 0; + + lerpType = new Interpolate(1.0f, 0.0f, maxTime); + lerpScale = new Interpolate(0.0f, (float) Math.PI, maxTime); + + // Initialize connections between endpoints of the paths inside the piece + for (int i = 0; i < numConnections; i++) + connections[i] = -1; + + + // Randomize connections in the piece + Random rnd = new Random(); + for (int i = 0; i < numConnections; i++) + { + while (connections[i] < 0) + { + int tmp = rnd.nextInt(numConnections); + if (tmp != i && connections[tmp] < 0) + { + connections[i] = tmp; + connections[tmp] = i; + } + } + } + } + + public Piece() + { + this(PieceType.NONE); + } + + + public void changed() + { + typeChanged = true; + } + + public void setType(PieceType ptype) + { +// typeChanged = (prevType != ptype) && (ptype == PieceType.LOCKED); + prevType = type; + type = ptype; + } + + public void clearStates() + { + for (int i = 0; i < numConnections; i++) + states[i] = false; + stateChanged = true; + } + + public int getRotation() + { + return currRotation % 4; + } + + public int getRotatedPoint(int in) + { + int point = (in - (getRotation() * 2)) % 8; + if (point < 0) point = 8 + point; + return point; + } + + public int getAntiRotatedPoint(int in) + { + int point = (in + (getRotation() * 2)) % 8; + if (point < 0) point = 8 + point; + return point; + } + + public int getMatchingPoint(int point) + { + switch (point) + { + case 0: return 5; + case 1: return 4; + + case 2: return 7; + case 3: return 6; + + case 4: return 1; + case 5: return 0; + + case 6: return 3; + case 7: return 2; + } + return -1; + } + + public void setConnectionState(int point, boolean state) + { + states[point] = state; + states[connections[point]] = state; + stateChanged = true; + } + + public int getConnection(int point) + { + return connections[point]; + } + + private float getAngle(float rotation) + { + return (float) ((rotation * Math.PI) / 2.0f); + } + + public void rotate(RotateDir dir) + { + // Only normal + if (type != PieceType.LOCKED && type != PieceType.ACTIVE) + return; + + currRotation = (currRotation + (dir == RotateDir.RIGHT ? 1 : -1)); + lerpRotation = new Interpolate(getAngle(currRotation), currAngle, maxTime); + rotationChanged = true; + } + + public Point2D getPointCoords(float x, float y, float dim, int index) + { + float ox = 0, oy = 0; + float step = dim / 10; + + switch (index) { + // Normal line starting and ending points + case 0: ox = 3.0f; oy = 0.4f; break; + case 1: ox = 7.0f; oy = 0.4f; break; + + case 2: ox = 9.6f; oy = 3.0f; break; + case 3: ox = 9.6f; oy = 7.0f; break; + + case 4: ox = 7.0f; oy = 9.6f; break; + case 5: ox = 3.0f; oy = 9.6f; break; + + case 6: ox = 0.4f; oy = 7.0f; break; + case 7: ox = 0.4f; oy = 3.0f; break; + + + // Matching control points for each point above (+8) + case 8: ox = 3.0f; oy = 2.5f; break; + case 9: ox = 7.0f; oy = 2.5f; break; + + case 10: ox = 7.5f; oy = 3.0f; break; + case 11: ox = 7.5f; oy = 7.0f; break; + + case 12: ox = 7.0f; oy = 7.5f; break; + case 13: ox = 3.0f; oy = 7.5f; break; + + case 14: ox = 2.5f; oy = 7.0f; break; + case 15: ox = 2.5f; oy = 3.0f; break; + } + + return new Point2D.Float(x + ox * step, y + oy * step); + } + + public PieceType getType() + { + return type; + } + + public void animate(float time) + { + active = false; + + if (rotationChanged) + { + rotationTime = time; + rotationActive = true; + rotationChanged = false; + rotationSpeed = 1.0f; + } + + if (typeChanged && type == PieceType.LOCKED) + { + rotationSpeed = 1.5f; + } + + if (rotationActive) + { + float t = (time - rotationTime) * rotationSpeed; + + if (t < maxTime) + { + currAngle = lerpRotation.getValue(t); + } + else + { + currAngle = lerpRotation.start; + rotationActive = false; + } + + active = true; + } + + if (typeChanged) + { + typeTime = time; + typeActive = true; + typeChanged = false; + } + + if (typeActive) + { + float t = (time - typeTime) * 2.0f; + + if (t < maxTime) + { + typeValue = lerpType.getValue(t); + } + else + { + typeValue = lerpType.start; + typeActive = false; + } + + + active = true; + } + + if (stateChanged) + { + } + + throbTime = (time % 100) / 100.0f; + } + + public void paint(Graphics2D g, float x, float y, float dim) + { + AffineTransform save = g.getTransform(); + Composite csave = g.getComposite(); + + + // Change compositing alpha for the whole piece drawing + // when the piece is being "introduced". + if (typeActive) + { + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, typeValue)); + } + + + // Transform drawing by current angle + g.rotate(currAngle, x + dim / 2.0f, y + dim / 2.0f); + + // Color piece by type + switch (type) { + case LOCKED: g.setPaint(new Color(0.3f, 0.8f, 0.3f, 0.35f)); break; + case ACTIVE: g.setPaint(new Color(0.9f, 0.3f, 0.3f, 0.35f)); break; + case START: g.setPaint(new Color(1.0f, 0.6f, 0.0f, 0.95f)); break; + } + + float corner = dim / 10.0f; + g.fill(new RoundRectangle2D.Float(x, y, dim, dim, corner, corner)); + + // Start pieces (center piece) have a different kind of border + // and no connections drawn inside + if (type == PieceType.START) + { + // Draw piece border + g.setPaint(Color.black); + g.setStroke(new BasicStroke(2.0f)); + g.draw(new RoundRectangle2D.Float(x, y, dim, dim, corner, corner)); + } + else + { + // Active piece has a throbbing "ghost" border + if (type == PieceType.ACTIVE) + { + float offs1 = throbTime * 10.0f, + offs2 = throbTime * 20.0f; + + g.setPaint(new Color(0.0f, 0.0f, 0.0f, (float) (1.0f - throbTime) )); + g.setStroke(new BasicStroke(2.0f + throbTime * 2.0f)); + g.draw(new RoundRectangle2D.Float( + x - offs1, y - offs1, + dim + offs2, dim + offs2, + corner, corner)); + } + + // Draw piece border + g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.6f)); + g.setStroke(new BasicStroke(5.0f)); + g.draw(new RoundRectangle2D.Float(x, y, dim, dim, dim / 10, dim / 10)); + + // Draw the connections + g.setStroke(new BasicStroke(5.5f)); + CubicCurve2D curve = new CubicCurve2D.Float(); + boolean[] drawn = new boolean[numConnections]; + for (int i = 0; i < numConnections; i++) + if (!drawn[i]) + { + Point2D start, cp1, cp2, end; + boolean isActive = states[i] || states[connections[i]]; + + g.setPaint(isActive ? Color.white : Color.black); + + start = getPointCoords(x, y, dim, i); + end = getPointCoords(x, y, dim, connections[i]); + cp1 = getPointCoords(x, y, dim, i + 8); + cp2 = getPointCoords(x, y, dim, connections[i] + 8); + + curve.setCurve(start, cp1, cp2, end); + g.draw(curve); + + // Mark connection drawn, so we don't overdraw + drawn[i] = true; + drawn[connections[i]] = true; + } + + } // !PieceType.START + + g.setTransform(save); + g.setComposite(csave); + } +} diff -r fb33d3796942 -r e8eeac403e5f game/PieceType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/PieceType.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,8 @@ +/* + * Ristipolku + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +public enum PieceType { START, LOCKED, ACTIVE, NONE } + diff -r fb33d3796942 -r e8eeac403e5f game/ResourceLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/ResourceLoader.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,37 @@ +/* + * Ristipolku Resource Loader + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.util.*; +import java.io.*; +import java.net.*; + + +public class ResourceLoader +{ + InputStream stream; + String name; + URL resourceURL; + + public ResourceLoader(String name) + { + this.name = name; + resourceURL = getClass().getClassLoader().getResource(name); + if (resourceURL != null) + stream = getClass().getClassLoader().getResourceAsStream(name); + + System.out.print("ResourceLoader('"+ name +"'): "+ resourceURL +" - "+ stream +"\n"); + } + + public InputStream getStream() + { + return stream; + } + + public URL getURL() + { + return resourceURL; + } +} diff -r fb33d3796942 -r e8eeac403e5f game/Sound.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/Sound.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,17 @@ +package game; + +public class Sound { + + private byte[] samples; + + public Sound(byte[] samples) + { + this.samples = samples; + } + + public byte[] getSamples() + { + return samples; + } + +} diff -r fb33d3796942 -r e8eeac403e5f game/SoundManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game/SoundManager.java Thu Dec 01 14:33:25 2016 +0200 @@ -0,0 +1,459 @@ +/* + * Ristipolku Game Engine + * (C) Copyright 2011 Matti 'ccr' Hämäläinen + */ +package game; + +import java.util.*; +import java.io.*; +import game.*; +import javax.sound.sampled.*; + + +public class SoundManager extends ThreadGroup +{ + private boolean alive; + private LinkedList queue; + private int id; + private static int poolID; + + private AudioFormat playbackFormat; + private ThreadLocal localLine; + private ThreadLocal localBuffer; + private Object pausedLock; + private boolean paused; + + + public SoundManager(AudioFormat format) + { + this(format, getMaxSimultaneousSounds(format)); + } + + + public SoundManager(AudioFormat format, int maxSounds) + { + super("SoundManagerPool-" + (poolID++)); + + int numThreads = Math.min(maxSounds, getMaxSimultaneousSounds(playbackFormat)); + + System.out.print("SMGR.SoundManager() initializing with " + numThreads +" max sounds\n"); + + setDaemon(true); + alive = true; + + playbackFormat = format; + localLine = new ThreadLocal(); + localBuffer = new ThreadLocal(); + pausedLock = new Object(); + + queue = new LinkedList(); + for (int i = 0; i < numThreads; i++) + new PooledThread().start(); + + synchronized (this) + { + notifyAll(); + } + } + + + public static int getMaxSimultaneousSounds(AudioFormat playbackFormat) + { + DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, playbackFormat); + + Mixer.Info[] info = AudioSystem.getMixerInfo(); + System.out.print("SMGR.getMaxSimultaneousSounds() mixer information:\n"); + Mixer.Info select = null; + for (Mixer.Info i : info) + { + System.out.print(" - '"+i.getName()+"'\n"); + if (i.getName().equals("Java Sound Audio Engine")) + select = i; + } + + Mixer mixer = AudioSystem.getMixer(select); + + Mixer.Info i = mixer.getMixerInfo(); + System.out.print(" * selected='"+i.getName()+"'\n"); + + int maxLines = mixer.getMaxLines(lineInfo); + if (maxLines == AudioSystem.NOT_SPECIFIED) + maxLines = 8; + + System.out.print(" * maxLines="+maxLines+"\n"); + + return maxLines; + } + + + protected void cleanUp() + { + System.out.print("SMGR.cleanUp()\n"); + // signal to unpause + setPaused(false); + + System.out.print("SMGR.cleanUp(): closing mixer\n"); + + // close the mixer (stops any running sounds) + Mixer mixer = AudioSystem.getMixer(null); + if (mixer.isOpen()) + mixer.close(); + + System.out.print("SMGR.cleanUp(): leaving\n"); + } + + + public void setPaused(boolean paused) + { + if (this.paused != paused) + { + synchronized (pausedLock) + { + this.paused = paused; + if (!paused) + { + // restart sounds + pausedLock.notifyAll(); + } + } + } + } + + + public boolean isPaused() + { + return paused; + } + + + public Sound getSound(String filename) + { + return getSound(getAudioInputStream(filename)); + } + + + public Sound getSound(InputStream is) + { + return getSound(getAudioInputStream(is)); + } + + + public Sound getSound(AudioInputStream audioStream) + { + if (audioStream == null) + return null; + + // get the number of bytes to read + int length = (int)(audioStream.getFrameLength() * audioStream.getFormat().getFrameSize()); + + // read the entire stream + byte[] samples = new byte[length]; + DataInputStream is = new DataInputStream(audioStream); + try { + is.readFully(samples); + is.close(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + + // return the samples + return new Sound(samples); + } + + + public AudioInputStream getAudioInputStream(String filename) + { + ResourceLoader res = new ResourceLoader(filename); + if (res == null || res.getStream() == null) + { + System.out.print("Could not load audio resource '"+ filename +"'.\n"); + return null; + } + try { + return getAudioInputStream(res.getStream()); + } + catch (Exception ex) + { + System.out.print("Could not get AudioInputStream for '"+ filename +"'\n"); + return null; + } + } + + + public AudioInputStream getAudioInputStream(InputStream is) + { + try { + if (!is.markSupported()) + is = new BufferedInputStream(is); + + // open the source stream + AudioInputStream source = AudioSystem.getAudioInputStream(is); + + // convert to playback format + return AudioSystem.getAudioInputStream(playbackFormat, source); + } + + catch (UnsupportedAudioFileException ex) { + ex.printStackTrace(); + } + catch (IOException ex) { + ex.printStackTrace(); + } + catch (IllegalArgumentException ex) { + ex.printStackTrace(); + } + + return null; + } + + + public InputStream play(Sound sound) + { + InputStream is; + if (sound != null) + { + is = new ByteArrayInputStream(sound.getSamples()); + return play(is); + } + return null; + } + + + public InputStream play(InputStream is) + { + System.out.print("SMGR.play(is="+is+")\n"); + if (is != null) + { + runTask(new SoundPlayer(is)); + } + return is; + } + + + protected void threadStarted() + { + synchronized (this) + { + try { + wait(); + } + catch (InterruptedException ex) { } + } + + + // use a short, 100ms (1/10th sec) buffer for filters that + // change in real-time + int bufferSize = playbackFormat.getFrameSize() * Math.round(playbackFormat.getSampleRate() / 10); + + // create, open, and start the line + SourceDataLine line; + DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, playbackFormat); + + System.out.print("SMGR.threadStarted(): "+lineInfo.toString()+"\n"); + + try { + line = (SourceDataLine) AudioSystem.getLine(lineInfo); + line.open(playbackFormat, bufferSize); + } + catch (LineUnavailableException ex) + { + System.out.print("SMGR.threadStarted() line unavailable!\n"); + // the line is unavailable - signal to end this thread + Thread.currentThread().interrupt(); + return; + } + + // Change volume + Control.Type ct = FloatControl.Type.MASTER_GAIN; + if (line.isControlSupported(ct)) + { + FloatControl c = (FloatControl) line.getControl(ct); + c.setValue(-20f); + } + + line.start(); + + // create the buffer + byte[] buffer = new byte[bufferSize]; + + // set this thread's locals + localLine.set(line); + localBuffer.set(buffer); + } + + + protected void threadStopped() + { + System.out.print("SMGR.threadStopped()\n"); + SourceDataLine line = (SourceDataLine) localLine.get(); + if (line != null) + { + line.drain(); + line.close(); + } + } + + + protected class SoundPlayer implements Runnable + { + private InputStream source; + + public SoundPlayer(InputStream source) + { + this.source = source; + } + + public void run() + { + // get line and buffer from ThreadLocals + SourceDataLine line = (SourceDataLine) localLine.get(); + byte[] buffer = (byte[])localBuffer.get(); + + if (line == null || buffer == null) + return; + + // copy data to the line + try { + boolean playing = true; + while (playing) { + // if paused, wait until unpaused + synchronized (pausedLock) + { + if (paused) { + try { + pausedLock.wait(); + } + catch (InterruptedException ex) { + return; + } + } + } + + // copy data + int bufPos = 0; + while (bufPos < buffer.length && playing) + { + int res = source.read(buffer, bufPos, buffer.length - bufPos); + if (res != -1) + bufPos += res; + else + playing = false; + } + if (playing) + line.write(buffer, 0, bufPos); + } + } + + catch (IOException ex) { + ex.printStackTrace(); + } + + } + } + + public synchronized void runTask(Runnable task) + { + if (!alive) + { + throw new IllegalStateException(); + } + if (task != null) + { + queue.add(task); + notify(); + } + + } + + protected synchronized Runnable getTask() throws InterruptedException + { + while (queue.size() == 0) + { + if (!alive) + return null; + + wait(); + } + return (Runnable) queue.removeFirst(); + } + + + public synchronized void close() + { + System.out.print("SMGR.close()\n"); + + if (alive) + { + System.out.print("SMGR.close(): alive queue clear\n"); + // Clear queue + alive = false; + queue.clear(); + interrupt(); + } + + cleanUp(); + System.out.print("SMGR.close(): leaving\n"); + } + + + public void join() + { + System.out.print("SMGR.join()\n"); + cleanUp(); + + synchronized (this) + { + alive = false; + notifyAll(); + } + + Thread[] threads = new Thread[activeCount()]; + int count = enumerate(threads); + for (int i = 0; i < count; i++) + { + try { + threads[i].join(); + } + catch (InterruptedException ex) + { + } + } + } + + + private class PooledThread extends Thread + { + public PooledThread() + { + super(SoundManager.this, "SoundManagerPool-" + (id++)); + } + + public void run() + { + threadStarted(); + + while (!isInterrupted()) { + Runnable task = null; + try { + task = getTask(); + } + catch (InterruptedException ex) + { + } + + if (task == null) + break; + + try { + task.run(); + } + catch (Throwable t) { + uncaughtException(this, t); + } + } + threadStopped(); + } + } +} diff -r fb33d3796942 -r e8eeac403e5f src/AnimatedPointElement.java --- a/src/AnimatedPointElement.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Ristipolku animated game element - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.geom.*; -import java.util.*; -import java.math.*; - - -public class AnimatedPointElement -{ - private float stime, value, steps; - private IDMPoint pos; - private Interpolate lerpV, lerpX, lerpY; - boolean active, first; - String text; - - public AnimatedPointElement(IDMPoint start, String text) - { - Random rnd = new Random(); - steps = 100; - - lerpX = new Interpolate(start.x - rnd.nextInt(100) + 50, start.x, steps); - lerpY = new Interpolate(start.y - rnd.nextInt(100) + 50, start.y, steps); - lerpV = new Interpolate(0.0f, 1.0f, steps); - - pos = new IDMPoint(start); - active = false; - first = true; - this.text = text; - } - - public void animate(float time) - { - if (first) - { - first = false; - active = true; - stime = time; - } - - if (active) - { - float t = (time - stime); - if (t >= steps) - { - t = steps; - active = false; - } - - value = lerpV.getValue(t); - pos.x = lerpX.getValue(t); - pos.y = lerpY.getValue(t); - } - } - - public void paint(Graphics2D g) - { - if (!active) - return; - - Paint psave = g.getPaint(); -// AffineTransform tsave = g.getTransform(); - - g.setFont(G.fonts[2]); - g.setPaint(new Color(value, value, value, value)); - g.drawString(text, pos.x, pos.y); - -// g.setTransform(tsave); - g.setPaint(psave); - } -} diff -r fb33d3796942 -r e8eeac403e5f src/Engine.java --- a/src/Engine.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,909 +0,0 @@ -/* - * Ristipolku Game Engine - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.geom.*; -import java.awt.event.*; -import java.awt.image.*; -import java.awt.event.*; -import java.awt.font.*; -import javax.imageio.*; -import javax.swing.*; -import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.io.*; -import game.*; -import javax.sound.sampled.*; - - -class AboutBox extends IDMWidget -{ - BufferedImage aboutImg; - boolean aboutSecret; - - IDMPoint currPos, currOffs; - Paint textPaint; - Font textFont; - FontMetrics textMetrics; - - - public AboutBox() - { - try { - ResourceLoader res = new ResourceLoader("graphics/girl.jpg"); - aboutImg = ImageIO.read(res.getStream()); - } - catch (IOException e) - { - } - - aboutSecret = false; - - setPos(150f, 150f); - setSize(675f, 420f); - } - - public void setTextFont(Font font, FontMetrics metrics) - { - textFont = font; - textMetrics = metrics; - } - - public void setTextPaint(Paint paint) - { - textPaint = paint; - } - - public void setCurrPos(IDMPoint npos) - { - currPos = npos; - currOffs = new IDMPoint(0, 0); - } - - public void setCurrPos(float x, float y) - { - setCurrPos(new IDMPoint(x, y)); - } - - public void drawString(Graphics2D g, String text) - { - Paint savePaint = g.getPaint(); - g.setPaint(textPaint); - g.setFont(textFont); - - int i = 0; - while (i < text.length()) - { - int p = text.indexOf("\n", i); - boolean linefeed; - String str; - if (p >= i) - { - str = text.substring(i, p); - i = p + 1; - linefeed = true; - } - else - { - str = text.substring(i); - i += str.length(); - linefeed = false; - } - - g.drawString(str, currPos.x + currOffs.x, currPos.y + currOffs.y); - - if (linefeed) - { - currOffs.x = 0; - currOffs.y += textMetrics.getHeight(); - } - else - { - currOffs.x += textMetrics.stringWidth(str); - } - } - - g.setPaint(savePaint); - } - - public void paint(Graphics2D g) - { - int x = getScaledX(), y = getScaledY(), - w = getScaledWidth(), h = getScaledHeight(); - - g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.7f)); - g.fill(new RoundRectangle2D.Float(x, y, w, h, 10, 10)); - - setTextFont(G.fonts[3], G.metrics[3]); - setTextPaint(Color.white); - - setCurrPos(x + 20, y + 30); - drawString(g, "RistiPolku (CrossPaths) v"+ G.version +"\n"); - - setTextFont(G.fonts[1], G.metrics[1]); - if (aboutSecret) - { - g.drawImage(aboutImg, x + 20, y + 55, - aboutImg.getWidth(), aboutImg.getHeight(), null); - - setCurrPos(x + 225, y + 75); - drawString(g, - "Dedicated to my\n" + - "favorite woman\n" + - "in the world."); - - setCurrPos(x + 370, y + 175); - drawString(g, "- Matti"); - } - else - { - setTextPaint(Color.yellow); - drawString(g, "(c) Copyright 2011 Tecnic Software productions (TNSP)\n"); - - setTextPaint(Color.white); - drawString(g, "Programming, graphics and design by " + - "Matti 'ccr' Hämäläinen.\n" + - "Audio from archive.org, used non-commercially.\n \n"); - - setTextPaint(Color.red); - drawString(g, "Controls:\n"); - - IDMPoint old = currOffs.copy(); - - setTextPaint(Color.white); - drawString(g, - "Arrow keys / mouse wheel\n"+ - "Enter / mouse click\n"+ - "Space bar\n"); - - currPos.x += 330; - currOffs.y = old.y; - drawString(g, - "- Rotate piece\n" + - "- Place/lock piece\n" + - "- Swap piece\n"); - - currPos.x -= 330; - setTextPaint(Color.green); - drawString(g, - "\nObjective: Create a path long as possible by rotating\n"+ - "and placing pieces. More points will be awarded for\n"+ - "advancing the path by several segments per turn." - ); - } - } - - public boolean keyPressed(KeyEvent e) - { - if (e.getKeyCode() == KeyEvent.VK_L) - { - aboutSecret = true; - } - else - { - clicked(); - aboutSecret = false; - } - return true; - } - - public void clicked() - { - parent.remove(this); - } -} - - -class GameBoard extends IDMWidget -{ - static final int boardSize = 9; - static final int boardMiddle = 4; - Piece[][] board; - float pscale, ptime; - - public boolean flagGameOver, flagBoardIsDirty; - int gameScore; - - Piece currPiece, nextPiece; - int currX, currY, currPoint; - - Sound sndPlaced; - - private final ReentrantReadWriteLock pointLock = new ReentrantReadWriteLock(); - private ArrayList pointElems; - - public GameBoard(IDMPoint pos, float ps) - { - super(pos); - pscale = ps; - -// sndPlaced = G.smgr.getSound("sounds/placed.wav"); - - pointElems = new ArrayList(); - - startNewGame(); - } - - public void startNewGame() - { - board = new Piece[boardSize][boardSize]; - board[boardMiddle][boardMiddle] = new Piece(PieceType.START); - - currX = boardMiddle; - currY = boardMiddle; - currPoint = 0; - - currPiece = null; - nextPiece = new Piece(PieceType.ACTIVE); - - flagGameOver = false; - flagBoardIsDirty = true; - pieceFinishTurn(); - gameScore = 0; - } - - public void paintBackPlate(Graphics2D g) - { - g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.2f)); - g.setStroke(new BasicStroke(5.0f)); - g.draw(new RoundRectangle2D.Float(getScaledX(), getScaledY(), - boardSize * pscale, boardSize * pscale, - pscale / 5, pscale / 5)); - } - - public void paintBoard(Graphics2D g, boolean drawCurrent) - { - for (int y = 0; y < boardSize; y++) - for (int x = 0; x < boardSize; x++) - if (board[x][y] != null) - { - if ((drawCurrent && board[x][y] == currPiece) || - (!drawCurrent && board[x][y] != currPiece)) - { - board[x][y].paint(g, - getScaledX() + (x * pscale), - getScaledY() + (y * pscale), - pscale - pscale / 10); - } - } - } - - public void paint(Graphics2D g) - { - paintBoard(g, true); - - Lock read = pointLock.readLock(); - read.lock(); - try - { - for (AnimatedPointElement elem : pointElems) - { - elem.paint(g); - } - } - finally - { - read.unlock(); - } - - - if (!flagGameOver) - { - if (nextPiece != null) - { - // Draw next piece - AffineTransform save = g.getTransform(); - nextPiece.paint(g, G.screenDim.width * 0.85f - 90.0f/2.0f, G.screenDim.height * 0.43f, 90.0f); - g.setTransform(save); - } - } - else - { - // Game over text - String text = "Game Over!"; - int textWidth = G.metrics[2].stringWidth(text); - g.setFont(G.fonts[2]); - - g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.5f)); - g.drawString(text, (G.screenDim.width - textWidth) / 2 + 5, G.screenDim.height / 2 + 5); - - double f = Math.sin(ptime * 0.1) * 4.0; - g.setPaint(Color.white); - g.drawString(text, (G.screenDim.width - textWidth) / 2 + (float) f, G.screenDim.height / 2 + (float) f); - } - - // Score - String text = ""+ String.format("%05d", gameScore); - int textWidth = G.metrics[2].stringWidth(text); - g.setFont(G.fonts[2]); - g.setPaint(Color.white); - g.drawString(text, (G.screenDim.width * 0.85f) - textWidth / 2, G.screenDim.height * 0.3f); - } - - public boolean contains(float x, float y) - { - return (x >= getScaledX() && - y >= getScaledY() && - x < getScaledX() + boardSize * pscale && - y < getScaledY() + boardSize * pscale); - } - - public boolean isBoardDirty() - { - if (flagBoardIsDirty) - { - flagBoardIsDirty = false; - return true; - } - else - return false; - } - - public void animate(float time) - { - if (nextPiece != null) - { - nextPiece.animate(time); - } - - ptime = time; - for (int y = 0; y < boardSize; y++) - for (int x = 0; x < boardSize; x++) - if (board[x][y] != null) - { - board[x][y].animate(time); - if (board[x][y] != currPiece && board[x][y].active) - flagBoardIsDirty = true; - } - - Lock write = pointLock.writeLock(); - write.lock(); - try - { - ArrayList tmp = new ArrayList(); - - for (AnimatedPointElement elem : pointElems) - { - elem.animate(time); - if (elem.active) - tmp.add(elem); - } - - pointElems = tmp; - - if (time % 32 == 1) - { - Random rnd = new Random(); - pointElems.add(new AnimatedPointElement( - new IDMPoint(10 + rnd.nextInt(400), 10 + rnd.nextInt(100)), ".")); - } - } - finally - { - write.unlock(); - } - } - - public void pieceRotate(Piece.RotateDir dir) - { - if (currPiece != null && !flagGameOver) - { - currPiece.rotate(dir); - } - } - - // Change coordinates based on the "outgoing" - // piece connection point. - private void pieceMoveTo(int point) - { - switch (point) - { - case 0: currY--; break; - case 1: currY--; break; - - case 2: currX++; break; - case 3: currX++; break; - - case 4: currY++; break; - case 5: currY++; break; - - case 6: currX--; break; - case 7: currX--; break; - } - } - - public void pieceCreateNew() - { - currPiece = nextPiece; - currPiece.changed(); - nextPiece = new Piece(PieceType.ACTIVE); - flagBoardIsDirty = true; - } - - public void pieceSwapCurrent() - { - if (!flagGameOver) - { - Piece tmp = currPiece; - currPiece = nextPiece; - nextPiece = tmp; - board[currX][currY] = currPiece; - currPiece.changed(); - nextPiece.changed(); - flagBoardIsDirty = true; - } - } - - // Check one piece, set connections, find the new placement - // based on piece rotations etc. - private boolean pieceCheck(Piece piece) - { - if (piece == null) - { - // Create new piece - pieceCreateNew(); - board[currX][currY] = currPiece; - return true; - } - else - if (piece.getType() == PieceType.START) - { - if (currPiece != null) - { - // Hit center starting piece, game over - flagGameOver = true; - return true; - } - else - { - // Start piece as first piece means game is starting - pieceMoveTo(currPoint); - pieceCreateNew(); - board[currX][currY] = currPiece; - return true; - } - } - - // Mark the current piece as locked - piece.setType(PieceType.LOCKED); - - // Solve connection (with rotations) through the piece - currPoint = piece.getRotatedPoint(piece.getMatchingPoint(currPoint)); - - // Mark connection as active - piece.setConnectionState(currPoint, true); - - // Solve exit point (with rotations) - currPoint = piece.getAntiRotatedPoint(piece.getConnection(currPoint)); - - // Move to next position accordingly - pieceMoveTo(currPoint); - return false; - } - - // Finish one move/turn of the game, resolve path and find placement - // of the next piece, or set "game over" state if required. - public void pieceFinishTurn() - { - boolean finished = false; - int connections = 0; - - if (currPiece != null) - { - G.smgr.play(sndPlaced); - } - - while (!finished) - { - if (currX >= 0 && currX < boardSize && currY >= 0 && currY < boardSize) - { - int oldX = currX, oldY = currY; - connections++; - finished = pieceCheck(board[currX][currY]); - - if (!finished) - { - Lock write = pointLock.writeLock(); - write.lock(); - try - { - pointElems.add(new AnimatedPointElement( - new IDMPoint( - getScaledX() + ((oldX + 0.5f) * pscale), - getScaledY() + ((oldY + 0.5f) * pscale)), - "" + connections)); - } - finally - { - write.unlock(); - } - } - - } - else - { - // Outside of the board, game over - finished = true; - flagGameOver = true; - } - } - - // Compute and add score - gameScore += connections * connections; - - // If game over, clear the game - if (flagGameOver) - { - currPiece = null; - } - - flagBoardIsDirty = true; - } - - public boolean mouseWheelMoved(MouseWheelEvent e) - { - int notches = e.getWheelRotation(); - - if (notches < 0) - pieceRotate(Piece.RotateDir.LEFT); - else - pieceRotate(Piece.RotateDir.RIGHT); - - return true; - } - - public void clicked() - { - if (!flagGameOver) - pieceFinishTurn(); - } - - public boolean keyPressed(KeyEvent e) - { - if (flagGameOver) - return false; - - switch (e.getKeyCode()) - { - case KeyEvent.VK_LEFT: - case KeyEvent.VK_UP: - pieceRotate(Piece.RotateDir.LEFT); - return true; - - case KeyEvent.VK_RIGHT: - case KeyEvent.VK_DOWN: - pieceRotate(Piece.RotateDir.RIGHT); - return true; - - case KeyEvent.VK_ENTER: - pieceFinishTurn(); - return true; - } - return false; - } -} - - -public class Engine extends JPanel - implements Runnable, KeyListener, - MouseListener, MouseWheelListener -{ - long startTime; - float gameUpdates, gameFrames; - - Thread animThread; - boolean animEnable = false; - - GameBoard lauta = null; - InputStream musa; - IDMContainer widgets; - AboutBox aboutBox; - - public void dbg(String msg) - { - System.out.print("Engine: " + msg); - } - - public Engine() - { - // Initialize globals - System.out.print("Engine() constructor\n"); - - // Sound system - G.smgr = new SoundManager(new AudioFormat(22050, 16, 1, true, false), 1); - - // Load resources - try - { - ResourceLoader res = new ResourceLoader("graphics/board.jpg"); - G.lautaBG = ImageIO.read(res.getStream()); - - try { - res = new ResourceLoader("graphics/font.ttf"); - - G.fonts = new Font[G.numFonts]; - G.fonts[0] = Font.createFont(Font.TRUETYPE_FONT, res.getStream()); - G.fonts[1] = G.fonts[0].deriveFont(24f); - G.fonts[2] = G.fonts[0].deriveFont(64f); - G.fonts[3] = G.fonts[0].deriveFont(32f); - } - catch (FontFormatException e) - { - dbg("Could not initialize fonts.\n"); - } - - res = new ResourceLoader("sounds/gamemusic.wav"); - musa = res.getStream(); - } - catch (IOException e) - { - JOptionPane.showMessageDialog(null, - e.getMessage(), - "Initialization error", - JOptionPane.ERROR_MESSAGE); - - dbg(e.getMessage()); - } - - // Create IDM GUI widgets - widgets = new IDMContainer(); - - lauta = new GameBoard(new IDMPoint(95, 130), 63); - widgets.add(lauta); - - widgets.add(new BtnSwapPiece(767f, 450f)); - widgets.add(new BtnAbout (767f, 550f)); - widgets.add(new BtnNewGame (767f, 630f)); - - aboutBox = new AboutBox(); - - // Game - startNewGame(); - - // Initialize event listeners - addKeyListener(this); - addMouseListener(this); - addMouseWheelListener(this); - - // Start playing background music - G.smgr.play(musa); - - // Get initial focus - if (!hasFocus()) - { - dbg("Requesting focus.\n"); - requestFocus(); - } - - gameUpdates = 0; - } - - public void startNewGame() - { - gameFrames = 0; - startTime = new Date().getTime(); - lauta.startNewGame(); - } - - public void paintComponent(Graphics g) - { - Graphics2D g2 = (Graphics2D) g; - boolean scaleChanged = false, - updateBoard = lauta.isBoardDirty(); - - // Rescale if parent component size has changed - Dimension dim = getSize(); - if (G.screenDim == null || !dim.equals(G.screenDim)) - { - float dw = dim.width / 1024.0f, - dh = dim.height / 768.0f; - - // Rescale IDM GUI widgets - widgets.setScale(dw, dh); - G.screenDim = dim; - - // Rescale background image - // Rescale fonts - G.fonts[1] = G.fonts[0].deriveFont(24f * dw); - G.fonts[2] = G.fonts[0].deriveFont(64f * dw); - G.fonts[3] = G.fonts[0].deriveFont(32f * dw); - - dbg("Scale changed.\n"); - scaleChanged = true; - updateBoard = true; - } - - if (updateBoard) - { -// dbg("updateBoard()\n"); - G.lautaBGScaled = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_RGB); - Graphics2D gimg = G.lautaBGScaled.createGraphics(); - gimg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BICUBIC); - - gimg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - gimg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - gimg.drawImage(G.lautaBG, 0, 0, dim.width, dim.height, null); - lauta.paintBackPlate(gimg); - lauta.paintBoard(gimg, false); - } - - // Get font metrics against current Graphics2D context - if (G.metrics == null || scaleChanged) - { - G.metrics = new FontMetrics[G.numFonts]; - for (int i = 0; i < G.numFonts; i++) - G.metrics[i] = g2.getFontMetrics(G.fonts[i]); - } - - // Draw background image, pieces, widgets - g2.drawImage(G.lautaBGScaled, 0, 0, null); - - // Use antialiasing when rendering the game elements - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - - widgets.paint(g2); - - - // Frames per second counter -/* - g2.setFont(G.fonts[1]); - long currTime = new Date().getTime(); - g2.drawString("fps = "+ ((gameFrames * 1000) / (currTime - startTime)), G.screenDim.width - 120, 20); -*/ - gameFrames++; - } - - public void startThreads() - { - dbg("startThreads()\n"); - if (animThread == null) - { - animThread = new Thread(this); - animEnable = true; - animThread.start(); - } - } - - public void stopThreads() - { - dbg("stopThreads()\n"); - - // Stop animations - if (animThread != null) - { - animThread.interrupt(); - animEnable = false; - animThread = null; - } - - // Shut down sound manager - G.smgr.close(); - } - - public void mouseEntered(MouseEvent e) - { - widgets.mouseEntered(e); - } - public void mouseExited(MouseEvent e) - { - widgets.mouseExited(e); - } - - public void mousePressed(MouseEvent e) - { - if (widgets.containsObject(aboutBox)) - aboutBox.mousePressed(e); - else - widgets.mousePressed(e); - } - - public void mouseReleased(MouseEvent e) - { - if (widgets.containsObject(aboutBox)) - aboutBox.mouseReleased(e); - else - widgets.mouseReleased(e); - } - - public void mouseClicked(MouseEvent e) - { - if (!hasFocus()) - { - dbg("Requesting focus.\n"); - requestFocus(); - } - } - - public void mouseWheelMoved(MouseWheelEvent e) - { - lauta.mouseWheelMoved(e); - } - - public void keyTyped(KeyEvent e) { } - public void keyReleased(KeyEvent e) { } - - public void keyPressed(KeyEvent e) - { - // Handle keyboard input - if (widgets.containsObject(aboutBox)) - aboutBox.keyPressed(e); - else - widgets.keyPressed(e); - } - - public void run() - { - while (animEnable) - { - // Progress game animation clock - gameUpdates++; - - // Animate components - lauta.animate(gameUpdates); - - // Repaint with a frame limiter - if (gameUpdates % 4 == 1) - repaint(); - - // Sleep for a moment - try { - Thread.sleep(10); - } - catch (InterruptedException x) { - } - } - } - - class BtnNewGame extends IDMButton - { - public BtnNewGame(float x, float y) - { - super(x, y, KeyEvent.VK_ESCAPE, G.fonts[1], "New Game"); - } - - public void clicked() - { - startNewGame(); - } - } - - class BtnSwapPiece extends IDMButton - { - public BtnSwapPiece(float x, float y) - { - super(x, y, KeyEvent.VK_SPACE, G.fonts[1], "Swap"); - } - - public void clicked() - { - lauta.pieceSwapCurrent(); - } - } - - class BtnAbout extends IDMButton - { - public BtnAbout(float x, float y) - { - super(x, y, KeyEvent.VK_A, G.fonts[1], "About"); - } - - public void clicked() - { - if (!widgets.containsObject(aboutBox)) - widgets.add(aboutBox); - } - } -} diff -r fb33d3796942 -r e8eeac403e5f src/G.java --- a/src/G.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -package game; - -import java.awt.*; -import java.awt.geom.*; -import java.awt.event.*; -import java.awt.image.*; -import java.awt.event.*; -import java.awt.font.*; -import javax.imageio.*; -import javax.swing.*; -import java.util.*; -import java.io.*; -import game.*; -import javax.sound.sampled.*; - -public class G -{ - public static final String version = "0.85"; - - public static final int numFonts = 4; - public static Font fonts[]; - public static FontMetrics metrics[]; - - public static SoundManager smgr; - - public static Dimension screenDim; - - public static BufferedImage lautaBG = null, lautaBGScaled = null; -} diff -r fb33d3796942 -r e8eeac403e5f src/IDMButton.java --- a/src/IDMButton.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * Ristipolku IDM button widget - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; -import java.awt.geom.*; -import javax.imageio.*; -import java.io.*; - - -public class IDMButton extends IDMWidget -{ - enum State { FOCUSED, PRESSED, NORMAL } - State state; - static BufferedImage imgUp, imgPressed; - Font font; - FontMetrics metrics; - String text; - boolean active; - - public IDMButton(IDMPoint pos, int keyCode, Font font, String text) - { - super(pos); - loadImages(); - setSize(imgUp.getWidth(), imgUp.getHeight()); - - this.font = font; - this.keyCode = keyCode; - this.text = text; - - state = State.NORMAL; - active = false; - } - - public IDMButton(float x, float y, int keyCode, Font font, String text) - { - this(new IDMPoint(x, y), keyCode, font, text); - } - - private static void loadImages() - { - if (imgUp != null && imgPressed != null) - return; - - try - { - ResourceLoader res = new ResourceLoader("graphics/button1_up.png"); - imgUp = ImageIO.read(res.getStream()); - - res = new ResourceLoader("graphics/button1_down.png"); - imgPressed = ImageIO.read(res.getStream()); - } - catch (IOException e) - { - System.out.print(e.getMessage()); - } - } - - public void scale() - { - } - - public void paint(Graphics2D g) - { - BufferedImage img; - int xoffs, yoffs; - - if (state == State.PRESSED) - { - img = imgPressed; - xoffs = yoffs = 5; - } - else - { - xoffs = yoffs = 0; - img = imgUp; - } - - if (metrics == null) - metrics = g.getFontMetrics(font); - - int textWidth = metrics.stringWidth(text); - g.drawImage(img, getScaledX() + xoffs, getScaledY() + yoffs, null); - - g.setFont(font); - g.setPaint(Color.black); - g.drawString(text, - getScaledX() + xoffs + (getScaledWidth() - textWidth) / 2, - getScaledY() + yoffs + getScaledHeight() / 2); - } - - - public boolean mousePressed(MouseEvent e) - { - state = State.PRESSED; - active = true; - return true; - } - - public boolean mouseReleased(MouseEvent e) - { - boolean oldActive = active; - super.mouseReleased(e); - state = State.NORMAL; - active = false; - return oldActive; - } - - public boolean mouseEntered(MouseEvent e) - { - if (active) - { - state = State.PRESSED; - return true; - } - else - return false; - } - - public boolean mouseExited(MouseEvent e) - { - if (active) - { - state = State.NORMAL; - return true; - } - else - return false; - } -} diff -r fb33d3796942 -r e8eeac403e5f src/IDMContainer.java --- a/src/IDMContainer.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/* - * Ristipolku IDM widget container - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.event.*; -import java.util.*; - - - -public class IDMContainer extends IDMWidget -{ - private ArrayList children, queue; - private IDMWidget modal; - private int iterated; - private boolean modified; - - public IDMContainer() - { - children = new ArrayList(); - iterated = 0; - modified = false; - } - - synchronized public void add(IDMWidget widget) - { - widget.setParent(this); - if (iterated > 0) - { - queue.add(0, widget); - modified = true; - } - else - children.add(widget); - } - - synchronized public void remove(IDMWidget widget) - { - widget.setParent(null); - if (iterated > 0) - { - queue.remove(widget); - modified = true; - } - else - children.remove(widget); - } - - synchronized private void beginIteration() - { - modified = false; - if (iterated == 0) - { - queue = new ArrayList(); - for (IDMWidget widget : children) - queue.add(widget); - } - iterated++; - } - - synchronized private void endIteration() - { - if (modified && iterated == 1) - { - children = queue; - queue = null; - } - iterated--; - } - - synchronized public void paint(Graphics2D g) - { - // Paint in reverse order - ListIterator iter = children.listIterator(children.size()); - - while (iter.hasPrevious()) - { - final IDMWidget widget = iter.previous(); - widget.paint(g); - } - } - - synchronized public boolean mousePressed(MouseEvent e) - { - try { - beginIteration(); - for (IDMWidget widget : children) - { - if (widget.contains(e.getPoint())) - { - if (widget.mousePressed(e)) - return true; - } - } - } - finally { endIteration(); } - return false; - } - - synchronized public boolean mouseReleased(MouseEvent e) - { - try { - beginIteration(); - for (IDMWidget widget : children) - { - if (widget.mouseReleased(e)) - return true; - } - } - finally { endIteration(); } - return false; - } - - synchronized public boolean mouseExited(MouseEvent e) - { - try { - beginIteration(); - for (IDMWidget widget : children) - { - if (widget.mouseExited(e)) - return true; - } - } - finally { endIteration(); } - return false; - } - - synchronized public boolean mouseEntered(MouseEvent e) - { - try { - beginIteration(); - for (IDMWidget widget : children) - { - if (widget.contains(e.getPoint())) - { - if (widget.mouseEntered(e)) - return true; - } - } - } - finally { endIteration(); } - return false; - } - - synchronized public boolean keyPressed(KeyEvent e) - { - try { - beginIteration(); - for (IDMWidget widget : children) - { - if (widget.keyPressed(e)) - return true; - } - } - finally { endIteration(); } - return false; - } - - synchronized public void setScale(IDMPoint scale) - { - beginIteration(); - for (IDMWidget widget : children) - { - widget.setScale(scale); - } - endIteration(); - } - - synchronized public boolean hasObject(Class c) - { - for (IDMWidget widget : children) - { - if (widget.getClass() == c) - return true; - } - return false; - } - - synchronized public boolean containsObject(Object o) - { - for (IDMWidget widget : children) - { - if (widget == o) - return true; - } - return false; - } -} diff -r fb33d3796942 -r e8eeac403e5f src/IDMPoint.java --- a/src/IDMPoint.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Ristipolku IDM point - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -public class IDMPoint -{ - public float x, y; - - public IDMPoint(float x, float y) - { - this.x = x; - this.y = y; - } - - public IDMPoint(IDMPoint pt) - { - this.x = pt.x; - this.y = pt.y; - } - - public IDMPoint copy() - { - return new IDMPoint(x, y); - } -} diff -r fb33d3796942 -r e8eeac403e5f src/IDMWidget.java --- a/src/IDMWidget.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * Ristipolku IDM base widget - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.event.*; - - -public class IDMWidget -{ - IDMWidget parent; - IDMPoint pos, size, scale; - int keyCode; - - public IDMWidget() - { - keyCode = -1; - this.scale = new IDMPoint(1, 1); - this.pos = new IDMPoint(0, 0); - this.size = new IDMPoint(0, 0); - } - - public IDMWidget(IDMPoint pos) - { - this(); - this.pos = pos; - } - - public IDMWidget(IDMPoint pos, IDMPoint size) - { - this(); - this.pos = pos; - this.size = size; - } - - public void setParent(IDMWidget par) - { - this.parent = par; - } - - public void add(IDMWidget widget) - { - } - - public void remove(IDMWidget widget) - { - } - - public void setPos(IDMPoint pos) - { - this.pos = pos; - } - - public void setPos(float x, float y) - { - this.pos = new IDMPoint(x, y); - } - - public void setSize(IDMPoint size) - { - this.size = size; - } - - public void setSize(float w, float h) - { - this.size = new IDMPoint(w, h); - } - - public void setScale(IDMPoint scale) - { - this.scale = scale; - } - - public void setScale(float x, float y) - { - this.setScale(new IDMPoint(x, y)); - } - - public int getScaledX() - { - return (int) (pos.x * scale.x); - } - - public int getScaledY() - { - return (int) (pos.y * scale.y); - } - - public int getScaledWidth() - { - return (int) (size.x * scale.x); - } - - public int getScaledHeight() - { - return (int) (size.y * scale.y); - } - - public boolean contains(float x, float y) - { - return (x >= getScaledX() && - y >= getScaledY() && - x < getScaledX() + getScaledWidth() && - y < getScaledY() + getScaledHeight()); - } - - public boolean contains(Point where) - { - return contains(where.x, where.y); - } - - public boolean contains(IDMPoint where) - { - return contains(where.x, where.y); - } - - public void paint(Graphics2D g) - { - } - - public boolean mousePressed(MouseEvent e) - { - return false; - } - - public boolean mouseReleased(MouseEvent e) - { - if (contains(e.getPoint())) - { - clicked(); - return true; - } - return false; - } - - public boolean mouseEntered(MouseEvent e) - { - return false; - } - - public boolean mouseExited(MouseEvent e) - { - return false; - } - - // Generic key handler - public boolean keyPressed(KeyEvent e) - { - if (e.getKeyCode() == keyCode) - { - clicked(); - return true; - } - else - return false; - } - - public void clicked() - { - } -} diff -r fb33d3796942 -r e8eeac403e5f src/Interpolate.java --- a/src/Interpolate.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Class for smooth non-linear interpolation between two given values in N steps - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.util.*; - -public class Interpolate -{ - public float start, end, steps; - - public Interpolate(float start, float end, float steps) - { - this.start = start; - this.end = end; - this.steps = steps; - } - - public float getValue(float step) - { - float n = step / steps; - float v = n * n * (3.0f - 2.0f * n); - return (start * v) + (end * (1.0f - v)); - } -} diff -r fb33d3796942 -r e8eeac403e5f src/Piece.java --- a/src/Piece.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,365 +0,0 @@ -/* - * Ristipolku - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.awt.*; -import java.awt.geom.*; -import java.util.*; -import java.math.*; - - -public class Piece -{ - public enum RotateDir { LEFT, RIGHT } - - static final int numConnections = 8; - static final float maxTime = 50.0f; - - int currRotation; - int[] connections; - boolean[] states; - PieceType type, prevType; - - boolean rotationChanged, rotationActive, - typeChanged, typeActive, - stateChanged, stateActive, - active; - - float currAngle, rotationTime, rotationSpeed, - typeTime, typeValue, throbTime; - - Interpolate lerpRotation, - lerpScale, - lerpType; - - - public Piece(PieceType ptype) - { - // Initialize - connections = new int[numConnections]; - states = new boolean[numConnections]; - type = ptype; - - rotationChanged = false; - rotationActive = false; - currRotation = 4 * 5000; - currAngle = getAngle(currRotation); - - typeChanged = false; - typeActive = false; - - throbTime = 0; - - lerpType = new Interpolate(1.0f, 0.0f, maxTime); - lerpScale = new Interpolate(0.0f, (float) Math.PI, maxTime); - - // Initialize connections between endpoints of the paths inside the piece - for (int i = 0; i < numConnections; i++) - connections[i] = -1; - - - // Randomize connections in the piece - Random rnd = new Random(); - for (int i = 0; i < numConnections; i++) - { - while (connections[i] < 0) - { - int tmp = rnd.nextInt(numConnections); - if (tmp != i && connections[tmp] < 0) - { - connections[i] = tmp; - connections[tmp] = i; - } - } - } - } - - public Piece() - { - this(PieceType.NONE); - } - - - public void changed() - { - typeChanged = true; - } - - public void setType(PieceType ptype) - { -// typeChanged = (prevType != ptype) && (ptype == PieceType.LOCKED); - prevType = type; - type = ptype; - } - - public void clearStates() - { - for (int i = 0; i < numConnections; i++) - states[i] = false; - stateChanged = true; - } - - public int getRotation() - { - return currRotation % 4; - } - - public int getRotatedPoint(int in) - { - int point = (in - (getRotation() * 2)) % 8; - if (point < 0) point = 8 + point; - return point; - } - - public int getAntiRotatedPoint(int in) - { - int point = (in + (getRotation() * 2)) % 8; - if (point < 0) point = 8 + point; - return point; - } - - public int getMatchingPoint(int point) - { - switch (point) - { - case 0: return 5; - case 1: return 4; - - case 2: return 7; - case 3: return 6; - - case 4: return 1; - case 5: return 0; - - case 6: return 3; - case 7: return 2; - } - return -1; - } - - public void setConnectionState(int point, boolean state) - { - states[point] = state; - states[connections[point]] = state; - stateChanged = true; - } - - public int getConnection(int point) - { - return connections[point]; - } - - private float getAngle(float rotation) - { - return (float) ((rotation * Math.PI) / 2.0f); - } - - public void rotate(RotateDir dir) - { - // Only normal - if (type != PieceType.LOCKED && type != PieceType.ACTIVE) - return; - - currRotation = (currRotation + (dir == RotateDir.RIGHT ? 1 : -1)); - lerpRotation = new Interpolate(getAngle(currRotation), currAngle, maxTime); - rotationChanged = true; - } - - public Point2D getPointCoords(float x, float y, float dim, int index) - { - float ox = 0, oy = 0; - float step = dim / 10; - - switch (index) { - // Normal line starting and ending points - case 0: ox = 3.0f; oy = 0.4f; break; - case 1: ox = 7.0f; oy = 0.4f; break; - - case 2: ox = 9.6f; oy = 3.0f; break; - case 3: ox = 9.6f; oy = 7.0f; break; - - case 4: ox = 7.0f; oy = 9.6f; break; - case 5: ox = 3.0f; oy = 9.6f; break; - - case 6: ox = 0.4f; oy = 7.0f; break; - case 7: ox = 0.4f; oy = 3.0f; break; - - - // Matching control points for each point above (+8) - case 8: ox = 3.0f; oy = 2.5f; break; - case 9: ox = 7.0f; oy = 2.5f; break; - - case 10: ox = 7.5f; oy = 3.0f; break; - case 11: ox = 7.5f; oy = 7.0f; break; - - case 12: ox = 7.0f; oy = 7.5f; break; - case 13: ox = 3.0f; oy = 7.5f; break; - - case 14: ox = 2.5f; oy = 7.0f; break; - case 15: ox = 2.5f; oy = 3.0f; break; - } - - return new Point2D.Float(x + ox * step, y + oy * step); - } - - public PieceType getType() - { - return type; - } - - public void animate(float time) - { - active = false; - - if (rotationChanged) - { - rotationTime = time; - rotationActive = true; - rotationChanged = false; - rotationSpeed = 1.0f; - } - - if (typeChanged && type == PieceType.LOCKED) - { - rotationSpeed = 1.5f; - } - - if (rotationActive) - { - float t = (time - rotationTime) * rotationSpeed; - - if (t < maxTime) - { - currAngle = lerpRotation.getValue(t); - } - else - { - currAngle = lerpRotation.start; - rotationActive = false; - } - - active = true; - } - - if (typeChanged) - { - typeTime = time; - typeActive = true; - typeChanged = false; - } - - if (typeActive) - { - float t = (time - typeTime) * 2.0f; - - if (t < maxTime) - { - typeValue = lerpType.getValue(t); - } - else - { - typeValue = lerpType.start; - typeActive = false; - } - - - active = true; - } - - if (stateChanged) - { - } - - throbTime = (time % 100) / 100.0f; - } - - public void paint(Graphics2D g, float x, float y, float dim) - { - AffineTransform save = g.getTransform(); - Composite csave = g.getComposite(); - - - // Change compositing alpha for the whole piece drawing - // when the piece is being "introduced". - if (typeActive) - { - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, typeValue)); - } - - - // Transform drawing by current angle - g.rotate(currAngle, x + dim / 2.0f, y + dim / 2.0f); - - // Color piece by type - switch (type) { - case LOCKED: g.setPaint(new Color(0.3f, 0.8f, 0.3f, 0.35f)); break; - case ACTIVE: g.setPaint(new Color(0.9f, 0.3f, 0.3f, 0.35f)); break; - case START: g.setPaint(new Color(1.0f, 0.6f, 0.0f, 0.95f)); break; - } - - float corner = dim / 10.0f; - g.fill(new RoundRectangle2D.Float(x, y, dim, dim, corner, corner)); - - // Start pieces (center piece) have a different kind of border - // and no connections drawn inside - if (type == PieceType.START) - { - // Draw piece border - g.setPaint(Color.black); - g.setStroke(new BasicStroke(2.0f)); - g.draw(new RoundRectangle2D.Float(x, y, dim, dim, corner, corner)); - } - else - { - // Active piece has a throbbing "ghost" border - if (type == PieceType.ACTIVE) - { - float offs1 = throbTime * 10.0f, - offs2 = throbTime * 20.0f; - - g.setPaint(new Color(0.0f, 0.0f, 0.0f, (float) (1.0f - throbTime) )); - g.setStroke(new BasicStroke(2.0f + throbTime * 2.0f)); - g.draw(new RoundRectangle2D.Float( - x - offs1, y - offs1, - dim + offs2, dim + offs2, - corner, corner)); - } - - // Draw piece border - g.setPaint(new Color(0.0f, 0.0f, 0.0f, 0.6f)); - g.setStroke(new BasicStroke(5.0f)); - g.draw(new RoundRectangle2D.Float(x, y, dim, dim, dim / 10, dim / 10)); - - // Draw the connections - g.setStroke(new BasicStroke(5.5f)); - CubicCurve2D curve = new CubicCurve2D.Float(); - boolean[] drawn = new boolean[numConnections]; - for (int i = 0; i < numConnections; i++) - if (!drawn[i]) - { - Point2D start, cp1, cp2, end; - boolean isActive = states[i] || states[connections[i]]; - - g.setPaint(isActive ? Color.white : Color.black); - - start = getPointCoords(x, y, dim, i); - end = getPointCoords(x, y, dim, connections[i]); - cp1 = getPointCoords(x, y, dim, i + 8); - cp2 = getPointCoords(x, y, dim, connections[i] + 8); - - curve.setCurve(start, cp1, cp2, end); - g.draw(curve); - - // Mark connection drawn, so we don't overdraw - drawn[i] = true; - drawn[connections[i]] = true; - } - - } // !PieceType.START - - g.setTransform(save); - g.setComposite(csave); - } -} diff -r fb33d3796942 -r e8eeac403e5f src/PieceType.java --- a/src/PieceType.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -/* - * Ristipolku - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -public enum PieceType { START, LOCKED, ACTIVE, NONE } - diff -r fb33d3796942 -r e8eeac403e5f src/ResourceLoader.java --- a/src/ResourceLoader.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Ristipolku Resource Loader - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.util.*; -import java.io.*; -import java.net.*; - - -public class ResourceLoader -{ - InputStream stream; - String name; - URL resourceURL; - - public ResourceLoader(String name) - { - this.name = name; - resourceURL = getClass().getClassLoader().getResource(name); - if (resourceURL != null) - stream = getClass().getClassLoader().getResourceAsStream(name); - - System.out.print("ResourceLoader('"+ name +"'): "+ resourceURL +" - "+ stream +"\n"); - } - - public InputStream getStream() - { - return stream; - } - - public URL getURL() - { - return resourceURL; - } -} diff -r fb33d3796942 -r e8eeac403e5f src/Sound.java --- a/src/Sound.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -package game; - -public class Sound { - - private byte[] samples; - - public Sound(byte[] samples) - { - this.samples = samples; - } - - public byte[] getSamples() - { - return samples; - } - -} diff -r fb33d3796942 -r e8eeac403e5f src/SoundManager.java --- a/src/SoundManager.java Tue Jun 21 12:53:53 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,459 +0,0 @@ -/* - * Ristipolku Game Engine - * (C) Copyright 2011 Matti 'ccr' Hämäläinen - */ -package game; - -import java.util.*; -import java.io.*; -import game.*; -import javax.sound.sampled.*; - - -public class SoundManager extends ThreadGroup -{ - private boolean alive; - private LinkedList queue; - private int id; - private static int poolID; - - private AudioFormat playbackFormat; - private ThreadLocal localLine; - private ThreadLocal localBuffer; - private Object pausedLock; - private boolean paused; - - - public SoundManager(AudioFormat format) - { - this(format, getMaxSimultaneousSounds(format)); - } - - - public SoundManager(AudioFormat format, int maxSounds) - { - super("SoundManagerPool-" + (poolID++)); - - int numThreads = Math.min(maxSounds, getMaxSimultaneousSounds(playbackFormat)); - - System.out.print("SMGR.SoundManager() initializing with " + numThreads +" max sounds\n"); - - setDaemon(true); - alive = true; - - playbackFormat = format; - localLine = new ThreadLocal(); - localBuffer = new ThreadLocal(); - pausedLock = new Object(); - - queue = new LinkedList(); - for (int i = 0; i < numThreads; i++) - new PooledThread().start(); - - synchronized (this) - { - notifyAll(); - } - } - - - public static int getMaxSimultaneousSounds(AudioFormat playbackFormat) - { - DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, playbackFormat); - - Mixer.Info[] info = AudioSystem.getMixerInfo(); - System.out.print("SMGR.getMaxSimultaneousSounds() mixer information:\n"); - Mixer.Info select = null; - for (Mixer.Info i : info) - { - System.out.print(" - '"+i.getName()+"'\n"); - if (i.getName().equals("Java Sound Audio Engine")) - select = i; - } - - Mixer mixer = AudioSystem.getMixer(select); - - Mixer.Info i = mixer.getMixerInfo(); - System.out.print(" * selected='"+i.getName()+"'\n"); - - int maxLines = mixer.getMaxLines(lineInfo); - if (maxLines == AudioSystem.NOT_SPECIFIED) - maxLines = 8; - - System.out.print(" * maxLines="+maxLines+"\n"); - - return maxLines; - } - - - protected void cleanUp() - { - System.out.print("SMGR.cleanUp()\n"); - // signal to unpause - setPaused(false); - - System.out.print("SMGR.cleanUp(): closing mixer\n"); - - // close the mixer (stops any running sounds) - Mixer mixer = AudioSystem.getMixer(null); - if (mixer.isOpen()) - mixer.close(); - - System.out.print("SMGR.cleanUp(): leaving\n"); - } - - - public void setPaused(boolean paused) - { - if (this.paused != paused) - { - synchronized (pausedLock) - { - this.paused = paused; - if (!paused) - { - // restart sounds - pausedLock.notifyAll(); - } - } - } - } - - - public boolean isPaused() - { - return paused; - } - - - public Sound getSound(String filename) - { - return getSound(getAudioInputStream(filename)); - } - - - public Sound getSound(InputStream is) - { - return getSound(getAudioInputStream(is)); - } - - - public Sound getSound(AudioInputStream audioStream) - { - if (audioStream == null) - return null; - - // get the number of bytes to read - int length = (int)(audioStream.getFrameLength() * audioStream.getFormat().getFrameSize()); - - // read the entire stream - byte[] samples = new byte[length]; - DataInputStream is = new DataInputStream(audioStream); - try { - is.readFully(samples); - is.close(); - } - catch (IOException ex) - { - ex.printStackTrace(); - } - - // return the samples - return new Sound(samples); - } - - - public AudioInputStream getAudioInputStream(String filename) - { - ResourceLoader res = new ResourceLoader(filename); - if (res == null || res.getStream() == null) - { - System.out.print("Could not load audio resource '"+ filename +"'.\n"); - return null; - } - try { - return getAudioInputStream(res.getStream()); - } - catch (Exception ex) - { - System.out.print("Could not get AudioInputStream for '"+ filename +"'\n"); - return null; - } - } - - - public AudioInputStream getAudioInputStream(InputStream is) - { - try { - if (!is.markSupported()) - is = new BufferedInputStream(is); - - // open the source stream - AudioInputStream source = AudioSystem.getAudioInputStream(is); - - // convert to playback format - return AudioSystem.getAudioInputStream(playbackFormat, source); - } - - catch (UnsupportedAudioFileException ex) { - ex.printStackTrace(); - } - catch (IOException ex) { - ex.printStackTrace(); - } - catch (IllegalArgumentException ex) { - ex.printStackTrace(); - } - - return null; - } - - - public InputStream play(Sound sound) - { - InputStream is; - if (sound != null) - { - is = new ByteArrayInputStream(sound.getSamples()); - return play(is); - } - return null; - } - - - public InputStream play(InputStream is) - { - System.out.print("SMGR.play(is="+is+")\n"); - if (is != null) - { - runTask(new SoundPlayer(is)); - } - return is; - } - - - protected void threadStarted() - { - synchronized (this) - { - try { - wait(); - } - catch (InterruptedException ex) { } - } - - - // use a short, 100ms (1/10th sec) buffer for filters that - // change in real-time - int bufferSize = playbackFormat.getFrameSize() * Math.round(playbackFormat.getSampleRate() / 10); - - // create, open, and start the line - SourceDataLine line; - DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, playbackFormat); - - System.out.print("SMGR.threadStarted(): "+lineInfo.toString()+"\n"); - - try { - line = (SourceDataLine) AudioSystem.getLine(lineInfo); - line.open(playbackFormat, bufferSize); - } - catch (LineUnavailableException ex) - { - System.out.print("SMGR.threadStarted() line unavailable!\n"); - // the line is unavailable - signal to end this thread - Thread.currentThread().interrupt(); - return; - } - - // Change volume - Control.Type ct = FloatControl.Type.MASTER_GAIN; - if (line.isControlSupported(ct)) - { - FloatControl c = (FloatControl) line.getControl(ct); - c.setValue(-20f); - } - - line.start(); - - // create the buffer - byte[] buffer = new byte[bufferSize]; - - // set this thread's locals - localLine.set(line); - localBuffer.set(buffer); - } - - - protected void threadStopped() - { - System.out.print("SMGR.threadStopped()\n"); - SourceDataLine line = (SourceDataLine) localLine.get(); - if (line != null) - { - line.drain(); - line.close(); - } - } - - - protected class SoundPlayer implements Runnable - { - private InputStream source; - - public SoundPlayer(InputStream source) - { - this.source = source; - } - - public void run() - { - // get line and buffer from ThreadLocals - SourceDataLine line = (SourceDataLine) localLine.get(); - byte[] buffer = (byte[])localBuffer.get(); - - if (line == null || buffer == null) - return; - - // copy data to the line - try { - boolean playing = true; - while (playing) { - // if paused, wait until unpaused - synchronized (pausedLock) - { - if (paused) { - try { - pausedLock.wait(); - } - catch (InterruptedException ex) { - return; - } - } - } - - // copy data - int bufPos = 0; - while (bufPos < buffer.length && playing) - { - int res = source.read(buffer, bufPos, buffer.length - bufPos); - if (res != -1) - bufPos += res; - else - playing = false; - } - if (playing) - line.write(buffer, 0, bufPos); - } - } - - catch (IOException ex) { - ex.printStackTrace(); - } - - } - } - - public synchronized void runTask(Runnable task) - { - if (!alive) - { - throw new IllegalStateException(); - } - if (task != null) - { - queue.add(task); - notify(); - } - - } - - protected synchronized Runnable getTask() throws InterruptedException - { - while (queue.size() == 0) - { - if (!alive) - return null; - - wait(); - } - return (Runnable) queue.removeFirst(); - } - - - public synchronized void close() - { - System.out.print("SMGR.close()\n"); - - if (alive) - { - System.out.print("SMGR.close(): alive queue clear\n"); - // Clear queue - alive = false; - queue.clear(); - interrupt(); - } - - cleanUp(); - System.out.print("SMGR.close(): leaving\n"); - } - - - public void join() - { - System.out.print("SMGR.join()\n"); - cleanUp(); - - synchronized (this) - { - alive = false; - notifyAll(); - } - - Thread[] threads = new Thread[activeCount()]; - int count = enumerate(threads); - for (int i = 0; i < count; i++) - { - try { - threads[i].join(); - } - catch (InterruptedException ex) - { - } - } - } - - - private class PooledThread extends Thread - { - public PooledThread() - { - super(SoundManager.this, "SoundManagerPool-" + (id++)); - } - - public void run() - { - threadStarted(); - - while (!isInterrupted()) { - Runnable task = null; - try { - task = getTask(); - } - catch (InterruptedException ex) - { - } - - if (task == null) - break; - - try { - task.run(); - } - catch (Throwable t) { - uncaughtException(this, t); - } - } - threadStopped(); - } - } -}