001    package org.bukkit.map;
002    
003    import java.util.HashMap;
004    
005    /**
006     * Represents a bitmap font drawable to a map.
007     */
008    public class MapFont {
009    
010        private final HashMap<Character, CharacterSprite> chars = new HashMap<Character, CharacterSprite>();
011        private int height = 0;
012        protected boolean malleable = true;
013    
014        /**
015         * Set the sprite for a given character.
016         *
017         * @param ch The character to set the sprite for.
018         * @param sprite The CharacterSprite to set.
019         * @throws IllegalStateException if this font is static.
020         */
021        public void setChar(char ch, CharacterSprite sprite) {
022            if (!malleable) {
023                throw new IllegalStateException("this font is not malleable");
024            }
025    
026            chars.put(ch, sprite);
027            if (sprite.getHeight() > height) {
028                height = sprite.getHeight();
029            }
030        }
031    
032        /**
033         * Get the sprite for a given character.
034         *
035         * @param ch The character to get the sprite for.
036         * @return The CharacterSprite associated with the character, or null if
037         *     there is none.
038         */
039        public CharacterSprite getChar(char ch) {
040            return chars.get(ch);
041        }
042    
043        /**
044         * Get the width of the given text as it would be rendered using this
045         * font.
046         *
047         * @param text The text.
048         * @return The width in pixels.
049         */
050        public int getWidth(String text) {
051            if (!isValid(text)) {
052                throw new IllegalArgumentException("text contains invalid characters");
053            }
054    
055            if (text.length() == 0){
056                return 0;
057            }
058    
059            int result = 0;
060            for (int i = 0; i < text.length(); ++i) {
061                result += chars.get(text.charAt(i)).getWidth();
062            }
063            result += text.length() - 1; // Account for 1px spacing between characters
064    
065            return result;
066        }
067    
068        /**
069         * Get the height of this font.
070         *
071         * @return The height of the font.
072         */
073        public int getHeight() {
074            return height;
075        }
076    
077        /**
078         * Check whether the given text is valid.
079         *
080         * @param text The text.
081         * @return True if the string contains only defined characters, false
082         *     otherwise.
083         */
084        public boolean isValid(String text) {
085            for (int i = 0; i < text.length(); ++i) {
086                char ch = text.charAt(i);
087                if (ch == '\u00A7' || ch == '\n') continue;
088                if (chars.get(ch) == null) return false;
089            }
090            return true;
091        }
092    
093        /**
094         * Represents the graphics for a single character in a MapFont.
095         */
096        public static class CharacterSprite {
097    
098            private final int width;
099            private final int height;
100            private final boolean[] data;
101    
102            public CharacterSprite(int width, int height, boolean[] data) {
103                this.width = width;
104                this.height = height;
105                this.data = data;
106    
107                if (data.length != width * height) {
108                    throw new IllegalArgumentException("size of data does not match dimensions");
109                }
110            }
111    
112            /**
113             * Get the value of a pixel of the character.
114             *
115             * @param row The row, in the range [0,8).
116             * @param col The column, in the range [0,8).
117             * @return True if the pixel is solid, false if transparent.
118             */
119            public boolean get(int row, int col) {
120                if (row < 0 || col < 0 || row >= height || col >= width) return false;
121                return data[row * width + col];
122            }
123    
124            /**
125             * Get the width of the character sprite.
126             *
127             * @return The width of the character.
128             */
129            public int getWidth() {
130                return width;
131            }
132    
133            /**
134             * Get the height of the character sprite.
135             *
136             * @return The height of the character.
137             */
138            public int getHeight() {
139                return height;
140            }
141    
142        }
143    
144    }