/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.tests;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.tests.utils.GdxTest;
import com.badlogic.gdx.utils.Align;
public class BitmapFontDistanceFieldTest extends GdxTest {
private static final String TEXT = "Ta";
private static final Color COLOR = Color.BLACK;
private static final float[] SCALES = {0.25f, 0.5f, 1, 2, 4};
private static class DistanceFieldShader extends ShaderProgram {
public DistanceFieldShader () {
super(Gdx.files.internal("data/shaders/distancefield.vert"), Gdx.files.internal("data/shaders/distancefield.frag"));
if (!isCompiled()) {
throw new RuntimeException("Shader compilation failed:\n" + getLog());
}
}
/** @param smoothing a value between 0 and 1 */
public void setSmoothing (float smoothing) {
float delta = 0.5f * MathUtils.clamp(smoothing, 0, 1);
setUniformf("u_lower", 0.5f - delta);
setUniformf("u_upper", 0.5f + delta);
}
}
private OrthographicCamera camera;
private SpriteBatch spriteBatch;
private Texture regularTexture;
private Texture distanceFieldTexture;
private BitmapFont descriptionFont;
private BitmapFont regularFont;
private BitmapFont distanceFieldFont;
private DistanceFieldShader distanceFieldShader;
private GlyphLayout layout = new GlyphLayout();
@Override
public void create () {
camera = new OrthographicCamera();
spriteBatch = new SpriteBatch();
descriptionFont = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"), true);
descriptionFont.setColor(Color.RED);
regularTexture = new Texture(Gdx.files.internal("data/verdana39.png"), true);
regularFont = new BitmapFont(Gdx.files.internal("data/verdana39.fnt"), new TextureRegion(regularTexture), true);
regularFont.setColor(COLOR);
distanceFieldTexture = new Texture(Gdx.files.internal("data/verdana39distancefield.png"), true);
distanceFieldFont = new BitmapFont(Gdx.files.internal("data/verdana39distancefield.fnt"), new TextureRegion(
distanceFieldTexture), true);
distanceFieldFont.setColor(COLOR);
distanceFieldShader = new DistanceFieldShader();
ShaderProgram.pedantic = false; // Useful when debugging this test
}
@Override
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
int x = 10;
x += drawFont(regularFont, "Regular font\nNearest filter", false, false, 0, x);
x += drawFont(regularFont, "Regular font\nLinear filter", true, false, 0, x);
x += drawFont(regularFont, "Regular font\nCustom shader", true, true, 1.0f, x);
x += drawFont(distanceFieldFont, "Distance field\nCustom shader", true, true, 1 / 8f, x);
x += drawFont(distanceFieldFont, "Distance field\nShowing distance field", false, false, 0, x);
spriteBatch.end();
}
private int drawFont (BitmapFont font, String description, boolean linearFiltering, boolean useShader, float smoothing, int x) {
int y = 10;
float maxWidth = 0;
spriteBatch.setShader(null);
descriptionFont.draw(spriteBatch, description, x, y);
spriteBatch.flush();
y += 10 + 2 * descriptionFont.getLineHeight();
// set filters for each page
TextureFilter minFilter = linearFiltering ? TextureFilter.MipMapLinearNearest : TextureFilter.Nearest;
TextureFilter magFilter = linearFiltering ? TextureFilter.Linear : TextureFilter.Nearest;
for (int i = 0; i < font.getRegions().size; i++) {
font.getRegion(i).getTexture().setFilter(minFilter, magFilter);
}
if (useShader) {
spriteBatch.setShader(distanceFieldShader);
} else {
spriteBatch.setShader(null);
}
for (float scale : SCALES) {
font.getData().setScale(scale);
layout.setText(font, TEXT);
maxWidth = Math.max(maxWidth, layout.width);
if (useShader) {
distanceFieldShader.setSmoothing(smoothing / scale);
}
font.draw(spriteBatch, layout, x, y);
y += font.getLineHeight();
spriteBatch.flush();
}
return (int)Math.ceil(maxWidth);
}
private float getBaselineShift (float shift) {
return shift;
}
@Override
public void resize (int width, int height) {
super.resize(width, height);
camera.setToOrtho(true, width, height);
spriteBatch.setTransformMatrix(camera.view);
spriteBatch.setProjectionMatrix(camera.projection);
}
@Override
public void dispose () {
spriteBatch.dispose();
regularTexture.dispose();
distanceFieldTexture.dispose();
descriptionFont.dispose();
regularFont.dispose();
distanceFieldFont.dispose();
distanceFieldShader.dispose();
}
}