1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.tests; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.graphics.Color; 21 import com.badlogic.gdx.graphics.GL20; 22 import com.badlogic.gdx.graphics.OrthographicCamera; 23 import com.badlogic.gdx.graphics.Texture; 24 import com.badlogic.gdx.graphics.Texture.TextureFilter; 25 import com.badlogic.gdx.graphics.g2d.BitmapFont; 26 import com.badlogic.gdx.graphics.g2d.GlyphLayout; 27 import com.badlogic.gdx.graphics.g2d.SpriteBatch; 28 import com.badlogic.gdx.graphics.g2d.TextureRegion; 29 import com.badlogic.gdx.graphics.glutils.ShaderProgram; 30 import com.badlogic.gdx.math.MathUtils; 31 import com.badlogic.gdx.tests.utils.GdxTest; 32 import com.badlogic.gdx.utils.Align; 33 34 public class BitmapFontDistanceFieldTest extends GdxTest { 35 36 private static final String TEXT = "Ta"; 37 private static final Color COLOR = Color.BLACK; 38 private static final float[] SCALES = {0.25f, 0.5f, 1, 2, 4}; 39 40 private static class DistanceFieldShader extends ShaderProgram { 41 public DistanceFieldShader () { 42 super(Gdx.files.internal("data/shaders/distancefield.vert"), Gdx.files.internal("data/shaders/distancefield.frag")); 43 if (!isCompiled()) { 44 throw new RuntimeException("Shader compilation failed:\n" + getLog()); 45 } 46 } 47 48 /** @param smoothing a value between 0 and 1 */ 49 public void setSmoothing (float smoothing) { 50 float delta = 0.5f * MathUtils.clamp(smoothing, 0, 1); 51 setUniformf("u_lower", 0.5f - delta); 52 setUniformf("u_upper", 0.5f + delta); 53 } 54 } 55 56 private OrthographicCamera camera; 57 private SpriteBatch spriteBatch; 58 59 private Texture regularTexture; 60 private Texture distanceFieldTexture; 61 private BitmapFont descriptionFont; 62 private BitmapFont regularFont; 63 private BitmapFont distanceFieldFont; 64 private DistanceFieldShader distanceFieldShader; 65 private GlyphLayout layout = new GlyphLayout(); 66 67 @Override 68 public void create () { 69 camera = new OrthographicCamera(); 70 spriteBatch = new SpriteBatch(); 71 72 descriptionFont = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"), true); 73 descriptionFont.setColor(Color.RED); 74 75 regularTexture = new Texture(Gdx.files.internal("data/verdana39.png"), true); 76 regularFont = new BitmapFont(Gdx.files.internal("data/verdana39.fnt"), new TextureRegion(regularTexture), true); 77 regularFont.setColor(COLOR); 78 79 distanceFieldTexture = new Texture(Gdx.files.internal("data/verdana39distancefield.png"), true); 80 distanceFieldFont = new BitmapFont(Gdx.files.internal("data/verdana39distancefield.fnt"), new TextureRegion( 81 distanceFieldTexture), true); 82 distanceFieldFont.setColor(COLOR); 83 84 distanceFieldShader = new DistanceFieldShader(); 85 ShaderProgram.pedantic = false; // Useful when debugging this test 86 } 87 88 @Override 89 public void render () { 90 Gdx.gl.glClearColor(1, 1, 1, 1); 91 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 92 93 spriteBatch.begin(); 94 95 int x = 10; 96 x += drawFont(regularFont, "Regular font\nNearest filter", false, false, 0, x); 97 x += drawFont(regularFont, "Regular font\nLinear filter", true, false, 0, x); 98 x += drawFont(regularFont, "Regular font\nCustom shader", true, true, 1.0f, x); 99 x += drawFont(distanceFieldFont, "Distance field\nCustom shader", true, true, 1 / 8f, x); 100 x += drawFont(distanceFieldFont, "Distance field\nShowing distance field", false, false, 0, x); 101 102 spriteBatch.end(); 103 } 104 105 private int drawFont (BitmapFont font, String description, boolean linearFiltering, boolean useShader, float smoothing, int x) { 106 int y = 10; 107 float maxWidth = 0; 108 109 spriteBatch.setShader(null); 110 descriptionFont.draw(spriteBatch, description, x, y); 111 spriteBatch.flush(); 112 y += 10 + 2 * descriptionFont.getLineHeight(); 113 114 // set filters for each page 115 TextureFilter minFilter = linearFiltering ? TextureFilter.MipMapLinearNearest : TextureFilter.Nearest; 116 TextureFilter magFilter = linearFiltering ? TextureFilter.Linear : TextureFilter.Nearest; 117 for (int i = 0; i < font.getRegions().size; i++) { 118 font.getRegion(i).getTexture().setFilter(minFilter, magFilter); 119 } 120 121 if (useShader) { 122 spriteBatch.setShader(distanceFieldShader); 123 } else { 124 spriteBatch.setShader(null); 125 } 126 127 for (float scale : SCALES) { 128 font.getData().setScale(scale); 129 layout.setText(font, TEXT); 130 maxWidth = Math.max(maxWidth, layout.width); 131 if (useShader) { 132 distanceFieldShader.setSmoothing(smoothing / scale); 133 } 134 font.draw(spriteBatch, layout, x, y); 135 y += font.getLineHeight(); 136 spriteBatch.flush(); 137 } 138 return (int)Math.ceil(maxWidth); 139 } 140 141 private float getBaselineShift (float shift) { 142 return shift; 143 } 144 145 @Override 146 public void resize (int width, int height) { 147 super.resize(width, height); 148 camera.setToOrtho(true, width, height); 149 spriteBatch.setTransformMatrix(camera.view); 150 spriteBatch.setProjectionMatrix(camera.projection); 151 } 152 153 @Override 154 public void dispose () { 155 spriteBatch.dispose(); 156 regularTexture.dispose(); 157 distanceFieldTexture.dispose(); 158 descriptionFont.dispose(); 159 regularFont.dispose(); 160 distanceFieldFont.dispose(); 161 distanceFieldShader.dispose(); 162 } 163 } 164