/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine 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. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.game; import totalcross.ui.gfx.*; import totalcross.ui.image.*; import totalcross.ui.font.*; import totalcross.util.*; /** * A game specific, fast text renderer (no memory allocs during runtime). <br> * Important! The text displayed must not reach the screen limits!<br> * <br> * It renders the text and the digits in image buffers and the display * functions of this class just copies the image buffers back to the * graphic context.<br> * <br> * The text buffer is copied first, then the configured amount of digits * of the optional integer are copied next to the text with leading zeros.<br> * <br> * This class can be used to display game information such as scores, levels, etc. * <br> * <p> * You can find a complete game API sample named 'Scape' in the TotalCross examples folder.<br> * Here is some sample code: * * <pre> * import totalcross.game.*; * import totalcross.util.props.*; * ... * * <i>public class Ping extends <U>GameEngine</U></i> { * * // 2 text renderers to quickly display level and score values * * private TextRenderer levelRenderer; * private TextRenderer scoreRenderer; * * //--------------------------------------------------------- * // overload the API's game init event. * // this function is called when the game is launched. * //--------------------------------------------------------- * * <i>public void onGameInit()</i> { * * // create two text renderers, one for the 'level' and one for the 'score' * // we use the current font, the text should be black on the game background * * // level display has 2 digits: max value is 99 * * levelRenderer=createTextRenderer(getFont(),Color.BLACK,"level:",2); * * // score display has 5 digits: max value is 99999 * * scoreRenderer=createTextRenderer(getFont(),Color.BLACK,"score:",5); * } * * //--------------------------------------------------------- * // overload TotalCross' onPaint function. * //--------------------------------------------------------- * * <i>public void onPaint(Graphics gfx)</i> { * * ... * if (gameIsRunning) { // game engine's running state * * ... * // display the game level & score, both enable transparency * * levelRenderer.display(15,2,level,true); * scoreRenderer.display(80,2,score,true); * ... * } * ... * } * @author Frank Diebolt * @author Guilherme Campos Hazan * @version 1.1 */ public class TextRenderer { /* * share all digit renderings by font. */ private static Hashtable byFont=new Hashtable(13); private static String strDigits[]={"0","1","2","3","4","5","6","7","8","9"}; private Image []digits; private Image textImg; private int w0; private int maxDigits; private Graphics gfx; /** * height in pixels of the drawing (= font metrics height). */ protected int fmH; /** * width in pixels of the text. */ protected int textWidth; /** * enable left zero padding. */ protected boolean zeroPadding; // fdie@420_27 /** * Creates a text renderer with the given parameters. * * @param font * to use * @param foreColor * text foreground color * @param backColor * text background color * @param text * to be displayed before the digits (or null if none) * @param maxDigits * the number of digits to display. E.g.: 4 means the max value shown will be 9999. * @param zeroPadding * pad with leading zeros. * @throws ImageException */ protected TextRenderer(Font font, int foreColor, int backColor, String text, int maxDigits, boolean zeroPadding) throws ImageException // fdie@420_27 { this(font, foreColor, backColor, text, maxDigits); this.zeroPadding = zeroPadding; } /** * Creates a text renderer with the given parameters. * * @param font * to use * @param foreColor * text foreground color * @param backColor * text background color * @param text * to be displayed before the digits (or null if none) * @param maxDigits * the number of digits to display. E.g.: 4 means the max value shown will be 9999. * @throws ImageException */ protected TextRenderer(Font font, int foreColor, int backColor, String text, int maxDigits) throws ImageException { this.maxDigits = maxDigits; gfx = GameEngineMainWindow.getEngineGraphics(); gfx.setFont(font); gfx.backColor = backColor; gfx.foreColor = foreColor; FontMetrics fm = font.fm; this.textWidth = text != null ? fm.stringWidth(text) : 0; this.w0 = fm.charWidth('0'); this.fmH = fm.height; // lookup the digits in the shared space or build a new digits rendering Object o = byFont.get(font); if (o == null) { // store the new digits renderings o = buildDigits(font, backColor, foreColor); byFont.put(font, o); } digits = (Image[]) o; if (text != null) textImg = render(text, textWidth, font, backColor, foreColor); // guich@340_10 } /** * Display a text rendering. * This function just draws the text to the * GameEngineMainWindow at the specified x,y position. * @param x position. * @param y position. * @param transparent should the background be preserved. */ public void display(int x, int y, boolean transparent) { if (textImg!=null) gfx.drawImage(textImg,x,y,false); } /** * Display a text rendering. * This function just copies back the image buffer of the text to the * GameEngineMainWindow at the specified x,y position and displays the * integer value next to the text by using pre-rendered digit image buffers. * @param x position. * @param y position. * @param value positive integer value to draw next to the text. */ public void display(int x,int y,int value) { if (maxDigits < 1) return; if (textImg != null) gfx.drawImage(textImg,x,y,false); if (value < 0) value = 0; int numDigits = 0; if (zeroPadding) // fdie@420_27 { numDigits = maxDigits; } else { // compute how many digits intValue has so we can left justify the text int tempValue = value; do { numDigits++; tempValue /= 10; } while (tempValue != 0); } x += textWidth + numDigits * w0; // scan from least to most significant digit while (numDigits-- > 0) { x -= w0; int d = value % 10; gfx.drawImage(digits[d],x,y,false); value /= 10; if (value == 0 && !zeroPadding) break; } } private Image[] buildDigits(Font font, int backColor, int foreColor) throws ImageException { Image array[] = new Image[10]; for (int i = 0 ; i < 10 ; i++) array[i] = render(strDigits[i], w0, font, backColor, foreColor); return array; } private Image render(String text, int w, Font font, int backColor, int foreColor) throws ImageException { Image image = new Image(w, fmH); Graphics gfx = image.getGraphics(); if (backColor != -1) gfx.backColor = backColor; gfx.fillRect(0, 0, totalcross.sys.Settings.screenWidth, totalcross.sys.Settings.screenHeight); gfx.foreColor = foreColor != -1 ? foreColor : Color.WHITE; gfx.setFont(font); gfx.drawText(text, 0, 0); return image; } /** Returns the maximum width of the text plus the number of digits */ public int getWidth() { return textWidth + (maxDigits*w0); } /** Returns the height of the current font */ public int getHeight() { return fmH; } }