From 794e3573f6d96775b76cfeb1c833d343a52d2055 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 6 May 2011 01:35:21 +0200 Subject: A lot of view performance optimizations git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@162 72836036-5685-4462-b002-a69064685172 --- src/jrummikub/resource/dark_felt.png | Bin 0 -> 358876 bytes src/jrummikub/view/impl/AbstractStonePanel.java | 2 +- src/jrummikub/view/impl/HandPanel.java | 189 +++++++++++----------- src/jrummikub/view/impl/StoneCollectionPanel.java | 76 ++++++--- src/jrummikub/view/impl/StonePainter.java | 79 +++++++-- src/jrummikub/view/impl/TablePanel.java | 29 ++-- 6 files changed, 224 insertions(+), 151 deletions(-) create mode 100644 src/jrummikub/resource/dark_felt.png (limited to 'src/jrummikub') diff --git a/src/jrummikub/resource/dark_felt.png b/src/jrummikub/resource/dark_felt.png new file mode 100644 index 0000000..c711fbc Binary files /dev/null and b/src/jrummikub/resource/dark_felt.png differ diff --git a/src/jrummikub/view/impl/AbstractStonePanel.java b/src/jrummikub/view/impl/AbstractStonePanel.java index 0c64305..7210d1c 100644 --- a/src/jrummikub/view/impl/AbstractStonePanel.java +++ b/src/jrummikub/view/impl/AbstractStonePanel.java @@ -52,7 +52,7 @@ abstract class AbstractStonePanel extends JPanel implements IStonePanel, * the grid scale */ public AbstractStonePanel(float scale) { - super(true); // Set double buffered + super(false); // Unset double buffered stonePainter = new StonePainter(scale); diff --git a/src/jrummikub/view/impl/HandPanel.java b/src/jrummikub/view/impl/HandPanel.java index b68a1d5..ab4caec 100644 --- a/src/jrummikub/view/impl/HandPanel.java +++ b/src/jrummikub/view/impl/HandPanel.java @@ -25,97 +25,100 @@ import jrummikub.view.IHandPanel; */ @SuppressWarnings("serial") class HandPanel extends AbstractStonePanel implements IHandPanel { - private final static int HAND_HEIGHT = 2; - private final static int HAND_WIDTH = 14; - - private final static BufferedImage BACKGROUND; - static { - ImageIcon image = new ImageIcon( - HandPanel.class.getResource("/jrummikub/resource/wood.png")); - BACKGROUND = new BufferedImage(image.getIconWidth(), image.getIconHeight(), - BufferedImage.TYPE_INT_RGB); - - image.paintIcon(null, BACKGROUND.createGraphics(), 0, 0); - } - private BufferedImage scaledBackground = BACKGROUND; - - private Collection selectedStones = Collections.emptyList(); - - /** - * Creates a new Board instance - */ - HandPanel() { - setBorder(new MatteBorder(0, 1, 0, 1, Color.DARK_GRAY)); - - addComponentListener(new ComponentAdapter() { - - @Override - public void componentResized(ComponentEvent e) { - Insets insets = getInsets(); - int size = (getHeight() - insets.top - insets.bottom) / HAND_HEIGHT; - - getStonePainter().setScale(size * StonePainter.HEIGHT_SCALE); - - setSize(new Dimension(HAND_WIDTH * getStonePainter().getStoneWidth() - + insets.left + insets.right, getHeight())); - } - }); - } - - private BufferedImage getScaledBackground(int size) { - BufferedImage scaled = new BufferedImage(size, size, - BufferedImage.TYPE_INT_RGB); - Graphics2D g = scaled.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BICUBIC); - - g.drawImage(BACKGROUND, 0, 0, size, size, null); - - return scaled; - } - - @Override - protected void paintComponent(Graphics g1) { - Insets insets = getInsets(); - int x = insets.left, y = insets.top, width = getWidth() - insets.left - - insets.right, height = getHeight() - insets.top - insets.bottom; - Graphics2D g = (Graphics2D) g1.create(x, y, width, height); - int size = height / HAND_HEIGHT; - - if (scaledBackground.getHeight() != size) - scaledBackground = getScaledBackground(size); - - for (int i = 0; i < HAND_HEIGHT; ++i) { - for (int xpos = -size * i / 3; xpos < width; xpos += size) { - g.drawImage(scaledBackground, xpos, size * i, null); - } - } - - getStonePainter().setScale(size * StonePainter.HEIGHT_SCALE); - - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - for (Pair entry : getStones()) { - getStonePainter().paintStone(g, entry.getFirst(), entry.getSecond(), - selectedStones.contains(entry.getFirst())); - } - } - - @Override - public void setStones(Iterable> stones) { - super.setStones(stones); - repaint(); - } - - /** - * Sets the stones that are to be painted selected - * - * @param stones - * the selected stones - */ - void setSelectedStones(Collection stones) { - selectedStones = stones; - repaint(); - } + private final static int HAND_HEIGHT = 2; + private final static int HAND_WIDTH = 14; + + private final static BufferedImage BACKGROUND; + static { + ImageIcon image = new ImageIcon( + HandPanel.class.getResource("/jrummikub/resource/wood.png")); + BACKGROUND = new BufferedImage(image.getIconWidth(), image.getIconHeight(), + BufferedImage.TYPE_INT_RGB); + + image.paintIcon(null, BACKGROUND.createGraphics(), 0, 0); + } + private BufferedImage scaledBackground = BACKGROUND; + + private boolean repaintAll = true; + + private Collection selectedStones = Collections.emptyList(); + + /** + * Creates a new Board instance + */ + HandPanel() { + setBorder(new MatteBorder(0, 1, 0, 1, Color.DARK_GRAY)); + + addComponentListener(new ComponentAdapter() { + + @Override + public void componentResized(ComponentEvent e) { + Insets insets = getInsets(); + int size = (getHeight() - insets.top - insets.bottom) / HAND_HEIGHT; + + getStonePainter().setScale(size * StonePainter.HEIGHT_SCALE); + + setSize(new Dimension(HAND_WIDTH * getStonePainter().getStoneWidth() + + insets.left + insets.right, getHeight())); + + repaintAll = true; + } + }); + } + + private BufferedImage getScaledBackground(int size) { + BufferedImage scaled = new BufferedImage(size, size, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = scaled.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + + g.drawImage(BACKGROUND, 0, 0, size, size, null); + + return scaled; + } + + @Override + protected void paintComponent(Graphics g1) { + Insets insets = getInsets(); + int x = insets.left, y = insets.top, width = getWidth() - insets.left + - insets.right, height = getHeight() - insets.top - insets.bottom; + Graphics2D g = (Graphics2D) g1.create(x, y, width, height); + + int size = height / HAND_HEIGHT; + + if (repaintAll) { + if (scaledBackground.getHeight() != size) + scaledBackground = getScaledBackground(size); + + for (int i = 0; i < HAND_HEIGHT; ++i) { + for (int xpos = -size * i / 3; xpos < width; xpos += size) { + g.drawImage(scaledBackground, xpos, size * i, null); + } + } + } + + for (Pair entry : getStones()) { + getStonePainter().paintStone(g, entry.getFirst(), entry.getSecond(), + selectedStones.contains(entry.getFirst())); + } + } + + @Override + public void setStones(Iterable> stones) { + super.setStones(stones); + repaintAll = true; + repaint(); + } + + /** + * Sets the stones that are to be painted selected + * + * @param stones + * the selected stones + */ + void setSelectedStones(Collection stones) { + selectedStones = stones; + repaint(); + } } diff --git a/src/jrummikub/view/impl/StoneCollectionPanel.java b/src/jrummikub/view/impl/StoneCollectionPanel.java index 253160c..493b299 100644 --- a/src/jrummikub/view/impl/StoneCollectionPanel.java +++ b/src/jrummikub/view/impl/StoneCollectionPanel.java @@ -1,14 +1,16 @@ package jrummikub.view.impl; -import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import javax.swing.ImageIcon; import javax.swing.border.EmptyBorder; import jrummikub.model.Position; @@ -22,7 +24,12 @@ import jrummikub.view.IStoneCollectionPanel; @SuppressWarnings("serial") class StoneCollectionPanel extends AbstractStonePanel implements IStoneCollectionPanel { - private final static int INSET = 7; + private final static ImageIcon BACKGROUND = new ImageIcon( + HandPanel.class.getResource("/jrummikub/resource/dark_felt.png")); + /** + * The width of the border of the collection panel + */ + public final static int INSET = 7; private Collection selectedStones = Collections.emptyList(); @@ -31,13 +38,27 @@ class StoneCollectionPanel extends AbstractStonePanel implements */ StoneCollectionPanel() { setOpaque(false); - setVisible(false); setBorder(new EmptyBorder(INSET, INSET, INSET, INSET)); + + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + rescale(); + } + }); } private void rescale() { - setSize(getStonePainter().getStoneWidth() * selectedStones.size() + 2 - * INSET, getStonePainter().getStoneHeight() + 2 * INSET); + Insets insets = getInsets(); + int height = getHeight() - insets.top - insets.bottom; + + getStonePainter().setScale(height * StonePainter.HEIGHT_SCALE); + repaint(); + + /* + * setSize(getStonePainter().getStoneWidth() * selectedStones.size() + 2 + * INSET, getStonePainter().getStoneHeight() + 2 * INSET); + */ } /** @@ -46,12 +67,12 @@ class StoneCollectionPanel extends AbstractStonePanel implements * @param height * the height in pixels */ - void setStoneHeight(int height) { - getStonePainter().setScale(height * StonePainter.HEIGHT_SCALE); - - rescale(); - repaint(); - } + /* + * void setStoneHeight(int height) { getStonePainter().setScale(height * + * StonePainter.HEIGHT_SCALE); + * + * rescale(); repaint(); //} + */ /** * Sets the stones to be shown in the collection @@ -71,27 +92,34 @@ class StoneCollectionPanel extends AbstractStonePanel implements } setStones(stones); + repaint(); + } - if (selectedStones.isEmpty()) { - setVisible(false); - } else { - rescale(); - setVisible(true); + @Override + protected Pair getTranslation() { + int width = getStonePainter().getStoneWidth() * selectedStones.size() + 2 + * INSET; + int x = (getWidth() - width) / 2; - repaint(); - } + return new Pair(x + INSET, INSET); } @Override public void paintComponent(Graphics g1) { - Insets insets = getInsets(); - int x = insets.left, y = insets.top, width = getWidth() - insets.left - - insets.right, height = getHeight() - insets.top - insets.bottom; - Graphics2D g = (Graphics2D) g1.create(x, y, width, height); + int width = getStonePainter().getStoneWidth() * selectedStones.size() + 2 + * INSET, height = getHeight(); + int x = (getWidth() - width) / 2; + Graphics2D g = (Graphics2D) g1.create(x, 0, width, height); if (!selectedStones.isEmpty()) { - g1.setColor(new Color(0, 0, 0, 0.25f)); - g1.fillRoundRect(0, 0, getWidth(), getHeight(), INSET, INSET); + for (int xpos = 0; xpos < getWidth(); xpos += BACKGROUND.getIconWidth()) { + for (int ypos = 0; ypos < getHeight(); ypos += BACKGROUND + .getIconHeight()) { + BACKGROUND.paintIcon(this, g, xpos, ypos); + } + } + + g.translate(INSET, INSET); float xpos = 0; diff --git a/src/jrummikub/view/impl/StonePainter.java b/src/jrummikub/view/impl/StonePainter.java index 0700966..68ab72c 100644 --- a/src/jrummikub/view/impl/StonePainter.java +++ b/src/jrummikub/view/impl/StonePainter.java @@ -6,9 +6,13 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Rectangle; +import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; import jrummikub.model.Position; import jrummikub.model.Stone; @@ -31,6 +35,9 @@ class StonePainter { private static final float BRIGHTER_SCALE = 1.15f; + private Map> defaultStones; + private Map> selectedStones; + /** * The width of one pixel in the scale of 1.0 */ @@ -77,6 +84,7 @@ class StonePainter { */ public void setScale(float scale) { this.scale = scale; + prepaint(); } /** @@ -114,12 +122,59 @@ class StonePainter { return (int) (DEFAULT_WIDTH * scale / ASPECT_RATIO); } + private BufferedImage prepaintStone(Color fg, Color bg, int value) { + Rectangle r = new Rectangle(0, 0, getStoneWidth(), getStoneHeight()); + BufferedImage img = new BufferedImage(r.width, r.height, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = img.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + paintStoneBackground(g, r, bg); + + if (value == 0) { + paintJoker(g, r, fg); + } else { + paintStoneValue(g, r, fg, value); + } + + paintCircle(g, r, bg); + + return img; + } + + private Map prepaintColor(Color fg, Color bg) { + Map images = new HashMap(); + + for (int i = 0; i <= 13; ++i) { + images.put(i, prepaintStone(fg, bg, i)); + } + + return images; + } + + private void prepaint() { + defaultStones = new HashMap>(); + selectedStones = new HashMap>(); + + Color defaultBackground = BACKGROUND_COLOR; + Color selectedBackground = SELECTED_COLOR; + + for (StoneColor color : StoneColor.values()) { + Color defaultFg = getColor(color); + Color selectedFg = defaultFg.darker(); + + defaultStones.put(color, prepaintColor(defaultFg, defaultBackground)); + selectedStones.put(color, prepaintColor(selectedFg, selectedBackground)); + } + } + /** * @param scale * the scaling factor for the grid coordinates */ StonePainter(float scale) { - this.scale = scale; + setScale(scale); } private void paintStoneBackground(Graphics2D g, Rectangle r, Color background) { @@ -250,25 +305,19 @@ class StonePainter { * if selected is true the stone will be painted darker */ public void paintStone(Graphics2D g, Stone stone, Position p, boolean selected) { - Color background = selected ? SELECTED_COLOR : BACKGROUND_COLOR; + // Color background = selected ? SELECTED_COLOR : BACKGROUND_COLOR; int width = getStoneWidth(); int height = getStoneHeight(); - - Rectangle rect = new Rectangle((int) (p.getX() * width), - (int) (p.getY() * height), width, height); - - paintStoneBackground(g, rect, background); - - Color color = getColor(stone.getColor()); - if (selected) - color = color.darker(); + int x = (int) (p.getX() * width), y = (int) (p.getY() * height); if (stone.isJoker()) { - paintJoker(g, rect, color); + g.drawImage( + (selected ? selectedStones : defaultStones).get(stone.getColor()) + .get(0), x, y, null); } else { - paintStoneValue(g, rect, color, stone.getValue()); + g.drawImage( + (selected ? selectedStones : defaultStones).get(stone.getColor()) + .get(stone.getValue()), x, y, null); } - - paintCircle(g, rect, background); } } diff --git a/src/jrummikub/view/impl/TablePanel.java b/src/jrummikub/view/impl/TablePanel.java index 080d476..2c7d899 100644 --- a/src/jrummikub/view/impl/TablePanel.java +++ b/src/jrummikub/view/impl/TablePanel.java @@ -4,10 +4,8 @@ import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; -import java.awt.RenderingHints; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.ArrayList; @@ -31,7 +29,7 @@ import jrummikub.view.ITablePanel; */ @SuppressWarnings("serial") class TablePanel extends AbstractStonePanel implements ITablePanel { - private final static ImageIcon background = new ImageIcon( + private final static ImageIcon BACKGROUND = new ImageIcon( HandPanel.class.getResource("/jrummikub/resource/felt.png")); private final static float MIN_VISIBLE_WIDTH = 15; @@ -141,15 +139,12 @@ class TablePanel extends AbstractStonePanel implements ITablePanel { stoneCollection = new StoneCollectionPanel(); add(stoneCollection); - ComponentListener rescaleListener = new ComponentAdapter() { + addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { rescale(); } - }; - - addComponentListener(rescaleListener); - stoneCollection.addComponentListener(rescaleListener); + }); } private Rectangle2D calculateTableExtent() { @@ -187,9 +182,6 @@ class TablePanel extends AbstractStonePanel implements ITablePanel { topPlayerLabel.setBounds(x, y, width, height); rightPlayerLabel.setBounds(x, y, width, height); - stoneCollection.setLocation(x + width / 2 - stoneCollection.getWidth() / 2, - y + height - stoneCollection.getHeight() - COLLECTION_GAP); - Rectangle2D extent = calculateTableExtent(); float widthScale = width / (float) extent.getWidth() @@ -199,7 +191,11 @@ class TablePanel extends AbstractStonePanel implements ITablePanel { getStonePainter().setScale(Math.min(widthScale, heightScale)); - stoneCollection.setStoneHeight((int) (height * COLLECTION_RATIO)); + int collectionHeight = (int) (height * COLLECTION_RATIO) + 2 + * StoneCollectionPanel.INSET; + stoneCollection + .setBounds(x, y + height - collectionHeight - COLLECTION_GAP, width, + collectionHeight); repaint(); } @@ -267,9 +263,9 @@ class TablePanel extends AbstractStonePanel implements ITablePanel { protected void paintComponent(Graphics g1) { Graphics2D g = (Graphics2D) g1; - for (int x = 0; x < getWidth(); x += background.getIconWidth()) { - for (int y = 0; y < getHeight(); y += background.getIconHeight()) { - background.paintIcon(this, g, x, y); + for (int x = 0; x < getWidth(); x += BACKGROUND.getIconWidth()) { + for (int y = 0; y < getHeight(); y += BACKGROUND.getIconHeight()) { + BACKGROUND.paintIcon(this, g, x, y); } } @@ -278,9 +274,6 @@ class TablePanel extends AbstractStonePanel implements ITablePanel { Pair translation = getTranslation(); g.translate(translation.getFirst(), translation.getSecond()); - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - for (Pair entry : stoneSets) { paintStoneSet(g, entry.getFirst(), entry.getSecond()); } -- cgit v1.2.3