// taken from Texample, // http://fractiousg.blogspot.com/201/4/rendering-text-in-opengl-on-android.html // Zeno Rogue's modifications (for HyperRogue 4.2): // * to provide a Typeface as an argument, instead of Assets // * drawAlign to provide alignment in HyperRogue-compatible fashion // For HyperRogue 5.3: // * Unicode characters // This is a OpenGL ES 1.0 dynamic font rendering system. It loads actual font // files, generates a font map (texture) from them, and allows rendering of // text strings. // // NOTE: the rendering portions of this class uses a sprite batcher in order // provide decent speed rendering. Also, rendering assumes a BOTTOM-LEFT // origin, and the (x,y) positions are relative to that, as well as the // bottom-left of the string to render. package com.android.texample; import javax.microedition.khronos.opengles.GL10; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Typeface; import android.opengl.GLUtils; public class GLText { // StringBuffer allchars; void buildAllchars() { allchars = new StringBuffer(); for(char c=32; c<=126; c++) allchars.append(c); allchars.append("°´ÁÄÇÉÍÎÖÚÜßáâäçèéìíîóöøùúüýąćČčĎďĘęĚěğİıŁłńňŘřŚśŞşŠšťůŹźŻżŽžϕЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё"); } int numChars() { return allchars.length() + 1; } int charIndex(char c) { int l = allchars.length(); for(int i=0; i charWidthMax ) // IF Width Larger Than Max Width charWidthMax = charWidths[cnt]; // Save New Max Width cnt++; // Advance Array Counter } s[0] = CHAR_NONE; // Set Unknown Character paint.getTextWidths( s, 0, 1, w ); // Get Character Bounds charWidths[cnt] = w[0]; // Get Width if ( charWidths[cnt] > charWidthMax ) // IF Width Larger Than Max Width charWidthMax = charWidths[cnt]; // Save New Max Width cnt++; // Advance Array Counter // set character height to font height charHeight = fontHeight; // Set Character Height // find the maximum size, validate, and setup cell sizes cellWidth = (int)charWidthMax + ( 2 * fontPadX ); // Set Cell Width cellHeight = (int)charHeight + ( 2 * fontPadY ); // Set Cell Height int maxSize = cellWidth > cellHeight ? cellWidth : cellHeight; // Save Max Size (Width/Height) if ( maxSize < FONT_SIZE_MIN || maxSize > FONT_SIZE_MAX ) // IF Maximum Size Outside Valid Bounds return false; // Return Error // set texture size based on max font size (width or height) // NOTE: these values are fixed, based on the defined characters. when // changing start/end characters (CHAR_START/CHAR_END) this will need adjustment too! if ( maxSize <= 24 ) // IF Max Size is 18 or Less textureSize = 256; // Set 256 Texture Size else if ( maxSize <= 40 ) // ELSE IF Max Size is 40 or Less textureSize = 512; // Set 512 Texture Size else if ( maxSize <= 80 ) // ELSE IF Max Size is 80 or Less textureSize = 1024; // Set 1024 Texture Size else // ELSE IF Max Size is Larger Than 80 (and Less than FONT_SIZE_MAX) textureSize = 2048; // Set 2048 Texture Size // create an empty bitmap (alpha only) Bitmap bitmap = Bitmap.createBitmap( textureSize, textureSize, Bitmap.Config.ALPHA_8 ); // Create Bitmap Canvas canvas = new Canvas( bitmap ); // Create Canvas for Rendering to Bitmap bitmap.eraseColor( 0x00000000 ); // Set Transparent Background (ARGB) // calculate rows/columns // NOTE: while not required for anything, these may be useful to have :) colCnt = textureSize / cellWidth; // Calculate Number of Columns rowCnt = (int)Math.ceil( (float)numChars() / (float)colCnt ); // Calculate Number of Rows // render each of the characters to the canvas (ie. build the font map) float x = fontPadX; // Set Start Position (X) float y = ( cellHeight - 1 ) - fontDescent - fontPadY; // Set Start Position (Y) for (int i=0; i textureSize ) { // IF End of Line Reached x = fontPadX; // Set X for New Row y += cellHeight; // Move Down a Row } } s[0] = CHAR_NONE; // Set Character to Use for NONE canvas.drawText( s, 0, 1, x, y, paint ); // Draw Character // generate a new texture int[] textureIds = new int[1]; // Array to Get Texture Id gl.glGenTextures( 1, textureIds, 0 ); // Generate New Texture textureId = textureIds[0]; // Save Texture Id // setup filters for texture gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind Texture gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST ); // Set Minification Filter gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR ); // Set Magnification Filter gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE ); // Set U Wrapping gl.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE ); // Set V Wrapping // load the generated bitmap onto the texture GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap, 0 ); // Load Bitmap to Texture gl.glBindTexture( GL10.GL_TEXTURE_2D, 0 ); // Unbind Texture // release the bitmap bitmap.recycle(); // Release the Bitmap // setup the array of character texture regions x = 0; // Initialize X y = 0; // Initialize Y for ( int c = 0; c < numChars(); c++ ) { // FOR Each Character (On Texture) charRgn[c] = new TextureRegion( textureSize, textureSize, x, y, cellWidth-1, cellHeight-1 ); // Create Region for Character x += cellWidth; // Move to Next Char (Cell) if ( x + cellWidth > textureSize ) { x = 0; // Reset X Position to Start y += cellHeight; // Move to Next Row (Cell) } } // create full texture region textureRgn = new TextureRegion( textureSize, textureSize, 0, 0, textureSize, textureSize ); // Create Full Texture Region // return success return true; // Return Success } //--Begin/End Text Drawing--// // D: call these methods before/after (respectively all draw() calls using a text instance // NOTE: color is set on a per-batch basis, and fonts should be 8-bit alpha only!!! // A: red, green, blue - RGB values for font (default = 1.0) // alpha - optional alpha value for font (default = 1.0) // R: [none] public void begin() { begin( 1.0f, 1.0f, 1.0f, 1.0f ); // Begin with White Opaque } public void begin(float alpha) { begin( 1.0f, 1.0f, 1.0f, alpha ); // Begin with White (Explicit Alpha) } public void begin(float red, float green, float blue, float alpha) { gl.glColor4f( red, green, blue, alpha ); // Set Color+Alpha gl.glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind the Texture batch.beginBatch(); // Begin Batch } public void end() { batch.endBatch(); // End Batch gl.glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); // Restore Default Color/Alpha } //--Draw Text--// // D: draw text at the specified x,y position // A: text - the string to draw // x, y - the x,y position to draw text at (bottom left of text; including descent) // R: [none] public void draw(String text, float x, float y) { float chrHeight = cellHeight * scaleY; // Calculate Scaled Character Height float chrWidth = cellWidth * scaleX; // Calculate Scaled Character Width int len = text.length(); // Get String Length x += ( chrWidth / 2.0f ) - ( fontPadX * scaleX ); // Adjust Start X y += ( chrHeight / 2.0f ) - ( fontPadY * scaleY ); // Adjust Start Y for ( int i = 0; i < len; i++ ) { // FOR Each Character in String int c = charIndex(text.charAt( i )); // Calculate Character Index (Offset by First Char in Font) batch.drawSprite( x, y, chrWidth, chrHeight, charRgn[c] ); // Draw the Character x += ( charWidths[c] + spaceX ) * scaleX; // Advance X Position by Scaled Character Width } } //--Draw Text Centered--// // D: draw text CENTERED at the specified x,y position // A: text - the string to draw // x, y - the x,y position to draw text at (bottom left of text) // R: the total width of the text that was drawn public float drawC(String text, float x, float y) { float len = getLength( text ); // Get Text Length draw( text, x - ( len / 2.0f ), y - ( getCharHeight() / 2.0f ) ); // Draw Text Centered return len; // Return Length } public float drawCX(String text, float x, float y) { float len = getLength( text ); // Get Text Length draw( text, x - ( len / 2.0f ), y ); // Draw Text Centered (X-Axis Only) return len; // Return Length } public void drawCY(String text, float x, float y) { draw( text, x, y - ( getCharHeight() / 2.0f ) ); // Draw Text Centered (Y-Axis Only) } public void drawAlign(String text, float x, float y, int align) { float len = getLength( text ); // Get Text Length draw( text, x - len * (align / 16.0f), y - ( getCharHeight() / 2.0f ) ); // Draw Text Centered (Y-Axis Only) } //--Set Scale--// // D: set the scaling to use for the font // A: scale - uniform scale for both x and y axis scaling // sx, sy - separate x and y axis scaling factors // R: [none] public void setScale(float scale) { scaleX = scaleY = scale; // Set Uniform Scale } public void setScale(float sx, float sy) { scaleX = sx; // Set X Scale scaleY = sy; // Set Y Scale } //--Get Scale--// // D: get the current scaling used for the font // A: [none] // R: the x/y scale currently used for scale public float getScaleX() { return scaleX; // Return X Scale } public float getScaleY() { return scaleY; // Return Y Scale } //--Set Space--// // D: set the spacing (unscaled; ie. pixel size) to use for the font // A: space - space for x axis spacing // R: [none] public void setSpace(float space) { spaceX = space; // Set Space } //--Get Space--// // D: get the current spacing used for the font // A: [none] // R: the x/y space currently used for scale public float getSpace() { return spaceX; // Return X Space } //--Get Length of a String--// // D: return the length of the specified string if rendered using current settings // A: text - the string to get length for // R: the length of the specified string (pixels) public float getLength(String text) { float len = 0.0f; // Working Length int strLen = text.length(); // Get String Length (Characters) for ( int i = 0; i < strLen; i++ ) { // For Each Character in String (Except Last int c = charIndex(text.charAt( i )); // Calculate Character Index (Offset by First Char in Font) len += ( charWidths[c] * scaleX ); // Add Scaled Character Width to Total Length } len += ( strLen > 1 ? ( ( strLen - 1 ) * spaceX ) * scaleX : 0 ); // Add Space Length return len; // Return Total Length } //--Get Width/Height of Character--// // D: return the scaled width/height of a character, or max character width // NOTE: since all characters are the same height, no character index is required! // NOTE: excludes spacing!! // A: chr - the character to get width for // R: the requested character size (scaled) public float getCharWidth(char chr) { return ( charWidths[charIndex(chr)] * scaleX ); // Return Scaled Character Width } public float getCharWidthMax() { return ( charWidthMax * scaleX ); // Return Scaled Max Character Width } public float getCharHeight() { return ( charHeight * scaleY ); // Return Scaled Character Height } //--Get Font Metrics--// // D: return the specified (scaled) font metric // A: [none] // R: the requested font metric (scaled) public float getAscent() { return ( fontAscent * scaleY ); // Return Font Ascent } public float getDescent() { return ( fontDescent * scaleY ); // Return Font Descent } public float getHeight() { return ( fontHeight * scaleY ); // Return Font Height (Actual) } //--Draw Font Texture--// // D: draw the entire font texture (NOTE: for testing purposes only) // A: width, height - the width and height of the area to draw to. this is used // to draw the texture to the top-left corner. public void drawTexture(int width, int height) { batch.beginBatch( textureId ); // Begin Batch (Bind Texture) batch.drawSprite( textureSize / 2, height - ( textureSize / 2 ), textureSize, textureSize, textureRgn ); // Draw batch.endBatch(); // End Batch } }