package org.flixel.system.gdx.text; import org.flixel.FlxG; import org.flixel.FlxU; import com.badlogic.gdx.assets.loaders.BitmapFontLoader.BitmapFontParameter; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.g2d.BitmapFontCache; import com.badlogic.gdx.graphics.g2d.GlyphLayout; import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.utils.Align; import flash.display.BlendMode; import flash.text.TextField; import flash.text.TextFormat; public class GdxTextField extends TextField { /** * The default vertex shader that will be used. */ private final String VERTEX = "org/flixel/data/shaders/vertex.glsl"; /** * The default fragment shader that will be used for distance field. */ public final String DISTANCE_FIELD_FRAGMENT = "org/flixel/data/shaders/distance_field.glsl"; /** * The current <code>TextFormat</code> */ private TextFormat _currentFormat; /** * The text of this <code>TextField</code>. */ private String _text; /** * Parameters that are used for generating the <code>BitmapFont</code>. */ private BitmapFontParameter _bitmapFontParameter; /** * Internal reference to a libgdx <code>BitmapFontCache</code> object. */ private BitmapFontCache _fontCache; /** * The shader program that is used for distance field. */ private ShaderProgram _distanceFieldShader; /** * Internal tracker whether the distance field is enabled. */ private boolean _distanceFieldEnabled; /** * The padding that is set for generating the bitmap font. */ private int _padding; /** * The smoothness of the font. */ private float _smoothness; /** * Internal, for tracking if the scale has changed and the cache needs to be updated. */ private float _lastScaleX; /** * Internal, for tracking if the scale has changed and the cache needs to be updated. */ private float _lastScaleY; public GdxTextField() { _text = ""; _currentFormat = new TextFormat(""); defaultTextFormat = new TextFormat(""); _bitmapFontParameter = new BitmapFontParameter(); _bitmapFontParameter.flip = true; _lastScaleX = scaleX = 1; _lastScaleY = scaleY = 1; } @Override public void setText(String text) { _text = text; setTextFormat(defaultTextFormat); calcFrame(); } @Override public String getText() { return _text; } @Override public void setTextFormat(TextFormat format) { String font = format.font != null && format.font.length() > 0 ? format.font : _currentFormat.font; String align = format.align != null ? format.align : "left"; float size = format.size; int color = format.color; if(!font.equals(_currentFormat.font) || size != _currentFormat.size) { try { _fontCache = new BitmapFontCache(FlxG.loadFont(font, FlxU.round(size), _bitmapFontParameter)); } catch(Exception e) { FlxG.log(e.getMessage()); _fontCache = new BitmapFontCache(FlxG.loadFont("org/flixel/data/font/nokiafc.fnt", 22, _bitmapFontParameter)); } } if(!align.equals(_currentFormat.align)) { _currentFormat.align = align; calcFrame(); } _currentFormat = new TextFormat(font, size, color, false, false, false, "", "", align); } public void calcFrame() { if(_fontCache != null) { GlyphLayout layout = _fontCache.setText(_text, 2, 3, width, flashAlignToGdx(_currentFormat.align), true); height = layout.height + 4; } } public void render() { // scaling if(_lastScaleX != scaleX || _lastScaleY != scaleY) { _fontCache.getFont().getData().setScale(scaleX, scaleY); _lastScaleX = scaleX; _lastScaleY = scaleY; calcFrame(); } // position _fontCache.setPosition(x, y); // rotation if(rotation != 0) { Matrix4 transform = FlxG.batch.getTransformMatrix(); rotateMatrix(transform, rotation); FlxG.batch.setTransformMatrix(transform); } // blending if(blendMode != null) { int[] blendFunc = BlendMode.getOpenGLBlendMode(blendMode); FlxG.batch.setBlendFunction(blendFunc[0], blendFunc[1]); } // distance field if(_distanceFieldEnabled) drawDistanceField(); // color int color = _currentFormat.color; _fontCache.setColors(((color >> 16) & 0xFF) * 0.00392f, ((color >> 8) & 0xFF) * 0.00392f, (color & 0xFF) * 0.00392f, alpha); _fontCache.draw(FlxG.batch); // turn off distance field if(_distanceFieldEnabled) FlxG.batch.setShader(null); // undo rotation if(rotation != 0) { Matrix4 transform = FlxG.batch.getTransformMatrix(); rotateMatrix(transform, -rotation); FlxG.batch.setTransformMatrix(transform); } } private void rotateMatrix(Matrix4 matrix, float rotation) { Matrix4 rotationMatrix = FlxG.batch.getTransformMatrix(); rotationMatrix.translate(x + (width / 2), y + (height / 2), 0); rotationMatrix.rotate(0, 0, 1, rotation); rotationMatrix.translate(-(x + (width / 2)), -(y + (height / 2)), 0); } /** * Sets whether the font should render as distance field. * * @param Enabled Whether the font should render as distance field or not. * @param Padding The padding that is set to generate the bitmap font. * @param Smoothness The smoothness between 0 and 1. * @param Name The name of the shader. * @param Fragment A custom fragment that will be used for creating the shader. * @return The shader program that will be used */ public ShaderProgram setDistanceField(boolean Enabled, int Padding, float Smoothness, String Name, String Fragment) { _distanceFieldEnabled = Enabled; if(!Enabled) return null; _padding = -Padding; _smoothness = Smoothness; _bitmapFontParameter.genMipMaps = true; _bitmapFontParameter.minFilter = TextureFilter.MipMapLinearNearest; _bitmapFontParameter.magFilter = TextureFilter.Linear; return _distanceFieldShader = FlxG.loadShader(Name, VERTEX, Fragment); } /** * Sets whether the font should render as distance field. * * @param Enabled Whether the font should render as distance field or not. * @param Padding The padding that is set to generate the bitmap font. * @param Smoothness The smoothness between 0 and 1. * @param Name The name of the shader. * @return The shader program that will be used */ public ShaderProgram setDistanceField(boolean Enabled, int Padding, float Smoothness, String Name) { return setDistanceField(Enabled, Padding, Smoothness, Name, DISTANCE_FIELD_FRAGMENT); } /** * Sets whether the font should render as distance field. * * @param Enabled Whether the font should render as distance field or not. * @param Padding The padding that is set to generate the bitmap font. * @param Smoothness The smoothness between 0 and 1. * @return The shader program that will be used */ public ShaderProgram setDistanceField(boolean Enabled, int Padding, float Smoothness) { return setDistanceField(Enabled, Padding, Smoothness, _currentFormat.font, DISTANCE_FIELD_FRAGMENT); } /** * Sets the distance field shader in the batch. */ private void drawDistanceField() { FlxG.batch.flush(); _distanceFieldShader.begin(); float delta = 0.5f * MathUtils.clamp(_smoothness / scaleX, 0, 1); _distanceFieldShader.setUniformf("u_lower", 0.5f - delta); _distanceFieldShader.setUniformf("u_upper", 0.5f + delta); _distanceFieldShader.end(); FlxG.batch.setShader(_distanceFieldShader); _fontCache.setPosition(x, y + (scaleX * _padding)); } private int flashAlignToGdx(String align) { if("right".equals(align)) return Align.right; else if("center".equals(align)) return Align.center; else return Align.left; } }