mirror of
https://github.com/Rushilwiz/APCS.git
synced 2025-04-05 13:00:20 -04:00
205 lines
7.6 KiB
Java
205 lines
7.6 KiB
Java
// Class: ScaledImageDisplay
|
|
//
|
|
// Author: Alyce Brady
|
|
//
|
|
// This class is based on the College Board's FishImageDisplay class,
|
|
// as allowed by the GNU General Public License. FishImageDisplay is a
|
|
// black-box GUI class within the AP(r) CS Marine Biology Simulation
|
|
// case study (see
|
|
// http://www.collegeboard.com/student/testing/ap/compsci_a/case.html).
|
|
//
|
|
// License Information:
|
|
// This class is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation.
|
|
//
|
|
// This class is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
package edu.kzoo.grid.display;
|
|
|
|
import edu.kzoo.grid.GridObject;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Component;
|
|
import java.awt.MediaTracker;
|
|
import java.awt.Image;
|
|
import java.awt.image.FilteredImageSource;
|
|
import java.awt.image.RGBImageFilter;
|
|
import java.awt.Graphics2D;
|
|
import javax.swing.ImageIcon;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.util.HashMap;
|
|
|
|
/**
|
|
* Grid Display Package:<br>
|
|
*
|
|
* A <code>ScaledImageDisplay</code> uses an image read from a file to
|
|
* represent an object in a location in a grid. Images can be rotated
|
|
* or tinted using appropriate decorators. <code>ScaledImageDisplay</code>
|
|
* provides a <code>tint</code> method that can be used by a
|
|
* tint decorator.
|
|
*
|
|
* @author Alyce Brady (based on FishImageDisplay by Julie Zelenski)
|
|
* @version 13 December 2003
|
|
**/
|
|
public class ScaledImageDisplay extends ScaledDisplay
|
|
{
|
|
private ImageIcon icon;
|
|
private DefaultDisplay defaultDisp = new DefaultDisplay();
|
|
private HashMap tintedVersions = new HashMap();
|
|
|
|
/** Internal constructor that does not initialize the icon
|
|
* instance variable; subclasses must be sure to set the icon
|
|
* using the <code>setIcon</code> method (e.g., at the beginning
|
|
* of a redefined draw method).
|
|
**/
|
|
protected ScaledImageDisplay()
|
|
{
|
|
}
|
|
|
|
/** Constructs an object that knows how to display a
|
|
* GridObject object as an image. Looks for the
|
|
* named file first in the jar file, then in the
|
|
* current directory. If the named file is not found
|
|
* or the file is malformed, the display will fall
|
|
* back to the DefaultDisplay class.
|
|
* @param imageFilename name of file containing image
|
|
**/
|
|
public ScaledImageDisplay(String imageFilename)
|
|
{
|
|
java.net.URL urlInJarFile = getClass().getResource(imageFilename);
|
|
if (urlInJarFile != null)
|
|
icon = new ImageIcon(urlInJarFile);
|
|
else
|
|
{
|
|
String path = System.getProperty("user.dir") +
|
|
java.io.File.separator + imageFilename;
|
|
icon = new ImageIcon(path);
|
|
}
|
|
}
|
|
|
|
/** Returns <code>true</code> if the image loaded OK; <code>false</code>
|
|
* otherwise.
|
|
**/
|
|
public boolean imageLoadedOK()
|
|
{
|
|
return (icon.getImageLoadStatus() == MediaTracker.COMPLETE) ;
|
|
}
|
|
|
|
/** Defines the image to use for display purposes. **/
|
|
protected void setIcon(ImageIcon icon)
|
|
{
|
|
this.icon = icon;
|
|
}
|
|
|
|
/** Draws a unit-length object using an image.
|
|
* This implementation draws the object by scaling
|
|
* the image provided to the constructor. It calls
|
|
* the <code>adjust</code> method to make further
|
|
* adjustments (for example, rotating and tinting
|
|
* the image) as appropriate.
|
|
* @param obj object we want to draw
|
|
* @param comp the component we're drawing on
|
|
* @param g2 drawing surface
|
|
**/
|
|
public void draw(GridObject obj, Component comp, Graphics2D g2)
|
|
{
|
|
if ( ! imageLoadedOK() )
|
|
{
|
|
// Image failed to load, so fall back to default display.
|
|
defaultDisp.draw(obj, comp, g2);
|
|
return;
|
|
}
|
|
|
|
// Scale to shrink or enlarge the image to fit the size 1x1 cell.
|
|
g2.scale(1.0/icon.getIconWidth(), 1.0/icon.getIconHeight());
|
|
|
|
icon.paintIcon(comp, g2, -icon.getIconWidth()/2, -icon.getIconHeight()/2);
|
|
}
|
|
|
|
|
|
/** Adjusts the graphics system to use an object's color to tint an image.
|
|
* (Precondition: <code>obj</code> has a <code>color</code> method.)
|
|
* @param obj object we want to draw
|
|
* @param comp the component we're drawing on
|
|
* @param g2 drawing surface
|
|
**/
|
|
public void tint(GridObject obj, Component comp, Graphics2D g2)
|
|
{
|
|
// Use the object's color as an image filter.
|
|
Class objClass = obj.getClass();
|
|
try
|
|
{
|
|
Method colorMethod = objClass.getMethod("color", new Class[0]);
|
|
Color col = (Color)colorMethod.invoke(obj, new Object[0]);
|
|
Image tinted = (Image)tintedVersions.get(col);
|
|
if (tinted == null) // not cached, need new filter for color
|
|
{
|
|
Image originalImage = icon.getImage();
|
|
FilteredImageSource src =
|
|
new FilteredImageSource(originalImage.getSource(),
|
|
new TintFilter(col));
|
|
tinted = comp.createImage(src);
|
|
// Cache tinted image in map by color, we're likely to need it again.
|
|
tintedVersions.put(col, tinted);
|
|
}
|
|
|
|
icon.setImage(tinted);
|
|
}
|
|
catch (NoSuchMethodException e)
|
|
{ throw new IllegalArgumentException("Cannot tint object of " + objClass +
|
|
" class; cannot invoke color method."); }
|
|
catch (InvocationTargetException e)
|
|
{ throw new IllegalArgumentException("Cannot tint object of " + objClass +
|
|
" class; exception in color method."); }
|
|
catch (IllegalAccessException e)
|
|
{ throw new IllegalArgumentException("Cannot tint object of " + objClass +
|
|
" class; cannot access color method."); }
|
|
}
|
|
|
|
|
|
/** An image filter class that tints colors based on the tint provided
|
|
* to the constructor.
|
|
**/
|
|
private static class TintFilter extends RGBImageFilter
|
|
{
|
|
private int tintR, tintG, tintB;
|
|
|
|
/** Constructs an image filter for tinting colors in an image. **/
|
|
public TintFilter(Color color)
|
|
{
|
|
canFilterIndexColorModel = true;
|
|
int rgb = color.getRGB();
|
|
tintR = (rgb >> 16) & 0xff;
|
|
tintG = (rgb >> 8) & 0xff;
|
|
tintB = rgb & 0xff;
|
|
}
|
|
|
|
public int filterRGB(int x, int y, int argb)
|
|
{
|
|
// Separate pixel into its RGB coomponents.
|
|
int alpha = (argb >> 24) & 0xff;
|
|
int red = (argb >> 16) & 0xff;
|
|
int green = (argb >> 8) & 0xff;
|
|
int blue = argb & 0xff;
|
|
|
|
// Use NTSC/PAL algorithm to convert RGB to grayscale.
|
|
int lum = (int) (0.2989 * red + 0.5866 * green + 0.1144 * blue);
|
|
|
|
// Interpolate along spectrum black->white with tint at midpoint
|
|
double scale = Math.abs((lum - 128)/128.0); // absolute distance from midpt
|
|
int edge = lum < 128 ? 0 : 255; // going towards white or black?
|
|
red = tintR + (int)((edge - tintR) * scale); // scale from midpt to edge
|
|
green = tintG + (int)((edge - tintG) * scale);
|
|
blue = tintB + (int)((edge - tintB) * scale);
|
|
return (alpha << 24) | (red << 16) | (green << 8) | blue;
|
|
}
|
|
|
|
}
|
|
|
|
}
|