cn.liutils.util.render.LambdaFont.java Source code

Java tutorial

Introduction

Here is the source code for cn.liutils.util.render.LambdaFont.java

Source

/**
 * Copyright (c) Lambda Innovation, 2013-2015
 * ??Lambda Innovation
 * http://www.li-dev.cn/
 *
 * This project is open-source, and it is distributed under 
 * the terms of GNU General Public License. You can modify
 * and distribute freely as long as you follow the license.
 * ??GNU???
 * ????
 * http://www.gnu.org/licenses/gpl.html
 */
package cn.liutils.util.render;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.vecmath.Vector2d;

import net.minecraft.util.ResourceLocation;

import org.lwjgl.opengl.GL11;

import cn.liutils.core.LIUtils;
import cn.liutils.util.HudUtils;
import cn.liutils.util.RenderUtils;
import cn.liutils.util.misc.Pair;

/**
 * Java+LIUtils implementation of LambdaFont.
 * @author WeathFolD
 */
@Deprecated
public class LambdaFont {

    public enum Align {
        LEFT, CENTER, RIGHT
    };

    final ResourceLocation[] png;
    final Map<Character, CharExtent> table = new HashMap();
    int perLine, fontSize, spacing, texWidth, texHeight, maxlines;

    double ratio;

    public LambdaFont(String file, ResourceLocation[] pngs) {
        png = pngs;
        Properties prop = new Properties();
        init(LambdaFont.class.getResourceAsStream(file));
    }

    private int udiv(int a, int b) {
        int ret = a / b;
        return ret * b == a ? ret : ret + 1;
    }

    private void init(InputStream stm) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(stm, "utf-8"));
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        Map<String, String> props = new HashMap();

        String str;
        LIUtils.log.info("LambdaFont is loading a charset.");
        try {
            while ((str = reader.readLine()) != null) {
                int ind;
                if ((ind = str.indexOf('=')) != -1) {
                    String key = str.substring(0, ind),
                            value = ind == str.length() - 1 ? "" : str.substring(ind + 1, str.length());

                    //Start proc
                    if (key.length() == 0)
                        continue;
                    if (key.length() != 1 && key.charAt(0) == '_') {
                        props.put(key, value);
                    } else {
                        if (key.length() == 1) {
                            String[] toparse = value.split(",");
                            //System.out.print(key.charAt(0));
                            table.put(key.charAt(0), new CharExtent(Integer.valueOf(toparse[0]),
                                    Integer.valueOf(toparse[1]), Double.valueOf(toparse[2])));
                        }
                    }
                } else {
                    LIUtils.log.error("LambdaFont meets a wrong line: " + str);
                }
            }
        } catch (Exception e) {
            LIUtils.log.error("Exception occured during font loading");
            e.printStackTrace();
        }
        LIUtils.log.info("Charset Loading ended.");

        perLine = Integer.valueOf(props.get("_per_line"));
        fontSize = Integer.valueOf(props.get("_size"));
        spacing = Integer.valueOf(props.get("_spacing"));
        int csSize = Integer.valueOf(props.get("_charset_size"));
        maxlines = Integer.valueOf(props.get("_maxlines"));

        texWidth = fontSize * perLine;
        texHeight = (spacing + fontSize) * maxlines;
        ratio = (double) (spacing + fontSize) / fontSize;
    }

    public void draw(String str, double x, double y, double size) {
        draw(str, x, y, size, Align.LEFT);
    }

    public void draw(String str, double x, double y, double size, Align align) {
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        //GL11.glDepthMask(false);
        double psx = HudUtils.SCALE_X, psy = HudUtils.SCALE_Y;
        GL11.glPushMatrix();
        {
            GL11.glTranslated(x, y, 0);
            GL11.glScaled(size, size, 1);
            String[] ss = str.split("\n");
            for (int i = 0; i < ss.length; ++i) {
                GL11.glPushMatrix();
                {
                    double dy = i * (fontSize + spacing) / fontSize;
                    GL11.glTranslated(0, dy, 0);
                    drawSingleLine(ss[i], align);
                }
                GL11.glPopMatrix();
            }
        }
        GL11.glPopMatrix();
        //GL11.glDepthMask(true);
        HudUtils.SCALE_X = psx;
        HudUtils.SCALE_Y = psy;
    }

    public void drawAdjusted(String str, double x, double y, double size, double cst) {
        drawAdjusted(str, x, y, size, Align.LEFT, cst);
    }

    public void drawAdjusted(String str, double x, double y, double size, Align align, double cst) {
        size = adjustFontSize(this, str, size, cst);
        draw(str, x, y, size, align);
    }

    /**
     * Basic Assumption: No line breaks.
     */
    public void drawTrimmed(String str, double x, double y, double size, Align align, double cst, String postfix) {
        double cur = 0.0;
        for (int i = 0; i < str.length(); ++i) {
            CharExtent ext = getExtent(str.charAt(i));
            cur += ext.getStep() * size;
            if (cur > cst) {
                str = str.substring(0, i).concat(postfix);
                break;
            }
        }
        draw(str, x, y, size, align);
    }

    /**
     * It must be guaranteed that the string contains no line-break characters
     * @returns area of drawing
     */
    public Vector2d drawLinebreak(String str, double x, double y, double size, double cst) {
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        double psx = HudUtils.SCALE_X, psy = HudUtils.SCALE_Y;
        GL11.glPushMatrix();
        GL11.glTranslated(x, y, 0);
        GL11.glScaled(size, size, 1);

        List<Pair<String, Boolean>> arr = dlbPreProc(str, size, cst);

        double spcstp = getExtent(' ').getStep();

        double y0 = 0;
        double curLen = 0;
        double maxLen = 0;
        for (int i = 0; i < arr.size(); ++i) {
            Pair<String, Boolean> pair = arr.get(i);
            double len = widthSingleLine(pair.first);
            if (size * len < cst && size * (curLen + len) > cst) {
                --i;
                maxLen = Math.max(curLen, maxLen);
                curLen = 0;
                y0 += 1.0;
                continue;
            }

            GL11.glPushMatrix();
            {
                GL11.glTranslated(curLen, y0, 0);
                drawSingleLine(pair.first, Align.LEFT);
            }
            GL11.glPopMatrix();
            curLen += len + (pair.second ? spcstp : 0);

            if (size * len > cst) {
                maxLen = Math.max(curLen, maxLen);
                curLen = 0;
                y0 += 1.0;
            }
        }
        maxLen = Math.max(curLen, maxLen);
        GL11.glPopMatrix();
        HudUtils.SCALE_X = psx;
        HudUtils.SCALE_Y = psy;

        return new Vector2d(maxLen * size, y0 * size + size + spacing * size / fontSize);
    }

    public Vector2d simDrawLinebreak(String str, double x, double y, double size, double cst) {
        List<Pair<String, Boolean>> arr = dlbPreProc(str, size, cst);

        double spcstp = getExtent(' ').getStep();

        double y0 = 0;
        double curLen = 0;
        double maxLen = 0;
        for (int i = 0; i < arr.size(); ++i) {
            Pair<String, Boolean> pair = arr.get(i);
            double len = widthSingleLine(pair.first);
            if (size * len < cst && size * (curLen + len) > cst) {
                --i;
                maxLen = Math.max(curLen, maxLen);
                curLen = 0;
                y0 += 1.0;
                continue;
            }
            curLen += len + (pair.second ? spcstp : 0);

            if (size * len > cst) {
                maxLen = Math.max(curLen, maxLen);
                curLen = 0;
                y0 += 1.0;
            }
        }
        maxLen = Math.max(curLen, maxLen);
        return new Vector2d(maxLen * size, y0 * size + size + spacing * size / fontSize);
    }

    /**
     * Chop up over-length words.
     */
    private List<Pair<String, Boolean>> dlbPreProc(String str, double size, double cst) {
        String[] raw = str.split(" ");
        List<Pair<String, Boolean>> res = new ArrayList();
        for (int i = 0; i < raw.length; ++i) {
            String to = raw[i];
            double len = widthSingleLine(to);
            if (len * size < cst) {
                res.add(new Pair(to, true));
            } else {
                double cur = 0.0;
                int li = 0;
                //System.out.println("st: " + to);
                //System.out.println("---");
                for (int j = 1; j < to.length(); ++j) {
                    double l = getExtent(to.charAt(j)).getStep() * size;
                    //System.out.println(cur);
                    if (cur + l > cst) {
                        cur = 0.0;
                        res.add(new Pair(to.substring(li, j), false));
                        li = j;
                        continue;
                    }
                    cur += l;
                }
                //System.out.println("---");
                if (li != to.length() - 1) {
                    res.add(new Pair(to.substring(li, to.length()), true));
                } else {
                    res.get(res.size() - 1).second = true;
                }
            }
        }

        return res;
    }

    public double getWidth(String str, double size) {
        double ret = 0.0;
        String[] strs = str.split("\n");
        for (String s : strs) {
            ret = Math.max(ret, widthSingleLine(s));
        }
        return ret * size;
    }

    public static double adjustFontSize(LambdaFont font, String str, double expSize, double lenCst) {
        double len = font.getWidth(str, expSize);
        return len > lenCst ? (expSize * (lenCst / len)) : expSize;
    }

    private double widthSingleLine(String str) {
        double ret = 0.0;
        for (int i = 0; i < str.length(); ++i) {
            ret += getExtent(str.charAt(i)).getStep();
        }
        return ret;
    }

    private void drawSingleLine(String line, Align align) {
        double x0 = 0, y0 = 0;
        switch (align) {
        case CENTER:
            x0 = -widthSingleLine(line) / 2;
            break;
        case LEFT:
            x0 = 0;
            break;
        case RIGHT:
            x0 = -widthSingleLine(line);
            break;
        default:
            break;
        }
        for (int i = 0; i < line.length(); ++i) {
            CharExtent ext = getExtent(line.charAt(i));
            double HT_RATIO = 0.95;
            int ind = ext.id;
            double u = fontSize * (ind % perLine), v = (fontSize + spacing) * (ind / perLine);
            RenderUtils.loadTexture(png[ext.pid]);
            HudUtils.drawRect(x0, y0, u, v, 1, ratio * HT_RATIO, fontSize, (fontSize + spacing) * HT_RATIO);
            x0 += ext.getStep();
        }
    }

    private CharExtent getExtent(char ch) {
        //here we assert that '?' already have a mapping.
        CharExtent ret = table.get(ch);
        return ret == null ? table.get('?') : ret;
    }

    private class CharExtent {
        public final int id, pid;
        private final double step;

        public CharExtent(int _pid, int _id, double _step) {
            pid = _pid;
            id = _id;
            step = _step;
        }

        public double getStep() {
            return step / fontSize;
        }
    }

}