rainwarrior.mt100.client.PstFont.java Source code

Java tutorial

Introduction

Here is the source code for rainwarrior.mt100.client.PstFont.java

Source

/*
    
Copyright  2012, 2013 RainWarrior
    
This file is part of MT100.
    
MT100 is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
MT100 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with MT100. If not, see <http://www.gnu.org/licenses/>.
    
*/

package rainwarrior.mt100.client;

import java.io.InputStream;
import java.io.DataInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.zip.GZIPInputStream;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import rainwarrior.mt100.*;

public class PstFont {
    public IntBuffer texture;

    int charsize;
    public int width;
    public int height;
    public int length;
    public int lShift;
    int textureWidth;
    int textureHeight;
    public String fontFile = null;
    boolean debug = false;

    public PstFont() {
        charsize = 1;
        width = 1;
        height = 1;
        length = 1;
        lShift = 0;
        textureWidth = 1;
        textureHeight = 1;
        ByteBuffer textureBuffer = BufferUtils.createByteBuffer(1);
        texture = BufferUtils.createIntBuffer(1);
        GL11.glGenTextures(texture);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.get(0));
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0x0, GL11.GL_ALPHA, textureWidth, textureHeight, 0x0, GL11.GL_ALPHA,
                GL11.GL_UNSIGNED_BYTE, textureBuffer);
    }

    public PstFont(String fontFile) {
        this.fontFile = fontFile;
        boolean hasUni;
        boolean psf1;
        try {
            InputStream str = this.getClass().getResourceAsStream(fontFile);
            if (str != null) {
                GZIPInputStream stream = new GZIPInputStream(str);
                DataInputStream file = new DataInputStream(stream);
                byte[] b = new byte[4];
                for (int i = 0; i < 4; i++)
                    b[i] = file.readByte();
                int hoffset;
                if (b[0] == (byte) 0x36 && b[1] == (byte) 04) // psf1 magic
                {
                    psf1 = true;
                    width = 8;
                    height = charsize = b[3];
                    length = ((b[2] & 0x01) != 0) ? 512 : 256;
                    lShift = 4;
                    hasUni = ((b[2] & 0x02) != 0);
                    hoffset = 0;
                } else if (b[0] == (byte) 0x72 && b[1] == (byte) 0xB5 && b[2] == (byte) 0x4A && b[3] == (byte) 0x86) // psf2 magic
                {
                    psf1 = false;
                    ByteBuffer header = ByteBuffer.allocate(28);
                    file.readFully(header.array(), 0, 28);
                    header.order(ByteOrder.LITTLE_ENDIAN);
                    int version = header.getInt();
                    hoffset = header.getInt() - 32;
                    if (debug)
                        MT100.logger.info("hoffset: " + hoffset);
                    int flags = header.getInt();
                    hasUni = ((flags & 0x01) != 0);
                    length = header.getInt();
                    if (length != 256 && length != 512) {
                        throw new RuntimeException("PSF2 file of unsupported length:" + length);
                    }
                    lShift = 4;
                    charsize = header.getInt();
                    height = header.getInt();
                    width = header.getInt();
                } else {
                    if (debug)
                        MT100.logger.severe("File " + fontFile + " is not a PSf file: " + b[0] + " " + b[1] + " "
                                + b[2] + " " + b[3]);
                    throw new java.io.IOException();
                }
                if (debug)
                    MT100.logger.info("width: " + width);
                if (debug)
                    MT100.logger.info("height: " + height);
                if (debug)
                    MT100.logger.info("charsize: " + charsize);
                if (debug)
                    MT100.logger.info("length: " + length);
                ByteBuffer chars = ByteBuffer.allocate(length * charsize);
                chars.order(ByteOrder.LITTLE_ENDIAN);
                file.skipBytes(hoffset);
                file.readFully(chars.array(), 0, length * charsize);

                int roundWidth = charsize / height; // bytes
                textureWidth = 1;
                while (textureWidth < (1 << lShift) * width) {
                    textureWidth <<= 1;
                }
                textureHeight = 1;
                while (textureHeight < (length >> lShift) * height) {
                    textureHeight <<= 1;
                }

                ByteBuffer textureBuffer = BufferUtils.createByteBuffer(textureWidth * textureHeight);

                byte bt;
                for (int i = 0; i < (1 << lShift); i++) {
                    //               if(debug) MT100.logger.info("i: " + i + ", ^i: "+ ((i >> 4) + (i & 0xF) * (length >> 4)));
                    for (int j = 0; j < (length >> lShift); j++) {
                        //                  if(debug) MT100.logger.info("j: " + j + " " + (j * roundWidth) + " " + (i * charsize + j * roundWidth) + " " + ((i >> 4) * width + (i & 0xF) * 16 * width * height + j * 16 * width));
                        for (int k = 0; k < height; k++) {
                            //                     if(debug) MT100.logger.info("k: " + k);
                            for (int l = 0; l < width; l++) {
                                bt = (byte) (((chars
                                        .get((i * (length >> lShift) + j) * charsize + k * roundWidth + (l >> 3))
                                        & (1 << (7 - (l & 7)))) != 0) ? 0xFF : 0x00);
                                textureBuffer.put(i * width + (j * height + k) * textureWidth + l, bt);
                            }
                        }
                    }
                }

                texture = BufferUtils.createIntBuffer(1);
                GL11.glGenTextures(texture);
                GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.get(0));
                GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0x0, GL11.GL_ALPHA, textureWidth, textureHeight, 0x0,
                        GL11.GL_ALPHA, GL11.GL_UNSIGNED_BYTE, textureBuffer);

                int ss = (psf1 ? 0xFFFE : 0xFE);
                int term = (psf1 ? 0xFFFF : 0xFF);
                if (hasUni) {
                    int c = 0;
                    int sep;
                    int i = 0;
                    boolean leading = true;
                    do {
                        c = 0;
                        sep = file.readByte();
                        if (sep < 0)
                            sep += 0x100;
                        if (psf1) {
                            int sep2 = file.readByte();
                            if (sep2 < 0)
                                sep2 += 0x100;
                            sep |= (sep2 << 8);
                        }
                        if (sep < 0)
                            sep += (psf1 ? 0x10000 : 0x100);
                        if (sep == ss) {
                            leading = false;
                        } else if (sep == term) {
                            leading = true;
                            i++;
                            c = 0;
                        } else // real char
                        {
                            if (!psf1) // parse utf8; TODO: maybe more compact?
                            {
                                int shift;
                                if (sep >= 0xFE) {
                                    throw new RuntimeException("Illegal UTF8 start byte");
                                }
                                if (sep >= 0xFC) {
                                    shift = 5;
                                    c |= ((sep & 0x01) << 30);
                                } else if (sep >= 0xF8) {
                                    shift = 4;
                                    c |= ((sep & 0x03) << 24);
                                } else if (sep >= 0xF0) {
                                    shift = 3;
                                    c |= ((sep & 0x07) << 18);
                                } else if (sep >= 0xE0) {
                                    shift = 2;
                                    c |= ((sep & 0x0F) << 12);
                                } else if (sep >= 0xC0) {
                                    shift = 1;
                                    c |= ((sep & 0x1F) << 6);
                                } else if (sep >= 0x80) {
                                    throw new RuntimeException("Illegal UTF8 start byte: " + sep);
                                } else {
                                    shift = 0;
                                    c = sep;
                                }
                                if (debug)
                                    MT100.logger.info("c: " + c + ", sep: " + sep + ", shift: " + shift);
                                while (shift-- > 0) {
                                    sep = file.readByte();
                                    if (sep < 0)
                                        sep += 0x100;
                                    if (sep >= 0xC0 || sep < 0x80) {
                                        throw new RuntimeException("Illegal UTF8 intermediate byte" + sep);
                                    }
                                    c |= (sep & 0x3F) << (shift * 6);
                                }
                            } else {
                                c = sep;
                            }
                            if (leading) {
                                PstFontRegistry.fontMap.put(c, this);
                                PstFontRegistry.indexMap.put(c, i);
                                if (debug)
                                    MT100.logger.info("c: " + c + ", sep: " + sep + ", i: " + i);
                            }
                        }
                    } while (i < length);
                } else {
                    for (int i = 0; i < length; i++) {
                        PstFontRegistry.fontMap.put(i, this);
                        PstFontRegistry.indexMap.put(i, i);
                    }
                }
                //            System.out.println(file);
            } else {
                MT100.logger.warning("No font file!");
            }
        } catch (java.io.IOException e) {
            throw new RuntimeException(e);
        }
        debug = false;
    }

    public void bindFontTexture() {
        GL11.glLoadIdentity();
        GL11.glScalef(1F / textureWidth, 1F / textureHeight, 1F);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.get(0));
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
    }
}