/* * Utilities.java * * Created on August 22, 2007, 6:04 PM */ package editor.mapmode; import editor.Main; import eug.parser.EUGFileIO; import eug.parser.ParserSettings; import eug.shared.GenericList; import eug.shared.GenericObject; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Rectangle; import java.awt.TexturePaint; import java.awt.image.BufferedImage; import java.util.HashMap; /** * A place for static methods commonly used by mapmodes. * @author Michael Myers * @since 0.5pre3 */ final class Utilities { /** Creates a new instance of Utilities */ private Utilities() { } // static final String[] noCountryStrings = { // "", "---", "XXX", "none" // }; static boolean isNotACountry(final String tag) { // Tested and found that .equals is much faster than .matches, even if // it's done several times and .matches is done once. if (tag.length() == 0 || tag.equals("---") || tag.equalsIgnoreCase("XXX") || tag.equalsIgnoreCase("none")) return true; return false; // for (String match : noCountryStrings) { // if (tag.equalsIgnoreCase(match)) // return true; // } // return false; } // Country, religion, and goods colors /** Color used if the province history cannot be found. */ static final Color COLOR_NO_HIST = Color.RED; /** Color used if the country definition cannot be found. */ static final Color COLOR_NO_CTRY_DEF = Color.BLACK; /** Color used if the religion definition cannot be found. */ static final Color COLOR_NO_RELIGION_DEF = Color.BLACK; /** Color used if a land province does not have a defined religion. */ static final Color COLOR_NO_RELIGION = Color.RED; /** Color used if the goods definition cannot be found. */ static final Color COLOR_NO_GOOD_DEF = Color.BLACK; /** Color used if a land province does not have a defined trade good. */ static final Color COLOR_NO_GOODS = Color.RED; /** Settings used when loading all data files in this class. */ private static final ParserSettings settings = ParserSettings.getNoCommentSettings().setPrintTimingInfo(false); private static final GenericObject countries = EUGFileIO.load( Main.filenameResolver.resolveFilename("common/countries.txt"), settings ); private static final java.util.Map<String, Color> ctryColorCache = new HashMap<String, Color>(); private static final GenericObject religions = EUGFileIO.load( Main.filenameResolver.resolveFilename("common/religion.txt"), settings ); private static final java.util.Map<String, Color> relColorCache = new HashMap<String, Color>(); private static final GenericObject goods = EUGFileIO.load( Main.filenameResolver.resolveFilename("common/tradegoods.txt"), settings ); private static final java.util.Map<String, Color> goodsColorCache = new HashMap<String, Color>(); static Color getCtryColor(String country) { // Special case: XXX means no one if (isNotACountry(country)) country = "NAT"; else country = toUpperCase(country); Color ret = ctryColorCache.get(country); if (ret == null) { String filename = countries.getString(country); if (!filename.startsWith("common")) filename = "common/" + filename.toLowerCase(); filename = Main.filenameResolver.resolveFilename(filename); final GenericObject countryDef = EUGFileIO.load(filename, settings); if (countryDef == null) { System.err.println("No country definition file found for " + country + "."); System.err.println("Expected to find it in " + filename); return COLOR_NO_CTRY_DEF; } final GenericList color = countryDef.getList("color"); if (color == null) { System.err.println("color for " + country + " is null"); return COLOR_NO_CTRY_DEF; } final int red = Math.min(Integer.parseInt(color.get(0)), 255); final int green = Math.min(Integer.parseInt(color.get(1)), 255); final int blue = Math.min(Integer.parseInt(color.get(2)), 255); ret = new Color(red, green, blue); ctryColorCache.put(country, ret); } return ret; } static Color getReligionColor(String religion) { religion = religion.toLowerCase(); Color ret = relColorCache.get(religion); if (ret == null) { for (GenericObject group : religions.children) { for (GenericObject rel : group.children) { if (rel.name.equalsIgnoreCase(religion)) { // found it GenericList color = rel.getList("color"); if (color == null) { System.err.println("color for " + religion + " is null"); return COLOR_NO_RELIGION_DEF; } ret = new Color( Float.parseFloat(color.get(0)), Float.parseFloat(color.get(1)), Float.parseFloat(color.get(2)) ); relColorCache.put(religion, ret); return ret; } } } return COLOR_NO_RELIGION_DEF; } return ret; } static Color getGoodsColor(String good) { good = good.toLowerCase(); Color ret = goodsColorCache.get(good); if (ret == null) { for (GenericObject def : goods.children) { if (def.name.equalsIgnoreCase(good)) { // found it GenericList color = def.getList("color"); if (color == null) { System.err.println("color for " + good + " is null"); return COLOR_NO_GOOD_DEF; } ret = new Color( Float.parseFloat(color.get(0)), Float.parseFloat(color.get(1)), Float.parseFloat(color.get(2)) ); goodsColorCache.put(good, ret); return ret; } } return COLOR_NO_GOOD_DEF; } return ret; } // Our own little toUpperCase method, because every tag is converted to // upper case before processing. This method, unlike String.toUpperCase(), // assumes that only ASCII characters are used, so a faster algorithm can be // used. private static final int diff = 'A' - 'a'; private static String toUpperCase(final String st) { final char[] cArr = st.toCharArray(); boolean change = false; for (int i = 0; i < cArr.length; i++) { int c = (int) cArr[i]; if (c >= 'a' && c <= 'z') { cArr[i] = (char) (c+diff); change = true; } } // only create a new string when necessary return change ? String.valueOf(cArr) : st; } // Texture handling (striped paints) private static final java.util.Map<ColorPair, Paint> imgCache = new HashMap<ColorPair, Paint>(); private static final Rectangle imageRect = new Rectangle(0,0,8,8); /* * The TexturePaints use 8x8 rectangles like the following (where x is the * background color and o is the foreground color): * * ooxxxxoo * oxxxxooo * xxxxoooo * xxxoooox * xxooooxx * xooooxxx * ooooxxxx * oooxxxxo * * Tiling this produces diagonally striped paint. */ static Paint createPaint(final Color c1, final Color c2) { final ColorPair cp = new ColorPair(c1, c2); Paint ret = imgCache.get(cp); if (ret == null) { final BufferedImage img = new BufferedImage(8, 8, BufferedImage.TYPE_INT_ARGB); final Graphics2D g = img.createGraphics(); g.setBackground(c2); g.clearRect(0, 0, 8, 8); g.setColor(c1); g.drawLine(0,0,1,0); g.drawLine(6,0,7,0); g.drawLine(0,1,0,1); g.drawLine(5,1,7,1); g.drawLine(4, 2, 7, 2); g.drawLine(3, 3, 6, 3); g.drawLine(2, 4, 5, 4); g.drawLine(1, 5, 4, 5); g.drawLine(0, 6, 3, 6); g.drawLine(0, 7, 2, 7); g.drawLine(7, 7, 7, 7); g.dispose(); ret = new TexturePaint(img, imageRect); imgCache.put(cp, ret); } return ret; } private static final class ColorPair { private final Color c1; private final Color c2; public ColorPair(Color c1, Color c2) { this.c1 = c1; this.c2 = c2; } @Override public boolean equals(Object other) { if (!(other instanceof ColorPair)) return false; final ColorPair cp = (ColorPair) other; return c1.equals(cp.c1) && c2.equals(cp.c2); } @Override public int hashCode() { int hash = 7; hash = 29 * hash + (this.c1 != null ? this.c1.hashCode() : 0); hash = 29 * hash + (this.c2 != null ? this.c2.hashCode() : 0); return hash; } } }