LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: TheBoneJarmer on November 26, 2014, 23:51:55

Title: Slick utility with lwjgl 3
Post by: TheBoneJarmer on November 26, 2014, 23:51:55
Hey

I couldn't find any stuff about this, but the slick utility wont work with LWJGL3. I haven't found any info about this. I don't know who the developer is and if he or she is active on this forum. I'm not busy with OpenAL at the moment, but I need to be able to draw fonts. That is a piece of cake with slick's utility but I have no clue what to do without it. So, any info/news/updates?

Thanks in advance!
Title: Re: Slick utility with lwjgl 3
Post by: lightbringer on November 27, 2014, 00:46:17
For now you'd need to roll your own. You could take a look at gdx-freetype, it's quite possible that you can integrate that (without the rest of libgdx).
Title: Re: Slick utility with lwjgl 3
Post by: Cornix on November 27, 2014, 07:06:38
Slick is outdated and not continued. Its very unlikely there will ever be any support for it.
It would be a much better choice to work on your own solution or to look for a different library.
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on November 27, 2014, 15:06:22
I feared so. Besides gdx-freetype (which I will take a look at later), are there any other libraries to use for drawing text? Slick used AWT, although I'm sure there should be other solutions. I read a lot about bitmap fonts but the tutorials I find (which are written in c++) are hard to translate to Java. And I do not even know where to go with TTF.
Title: Re: Slick utility with lwjgl 3
Post by: Cornix on November 27, 2014, 15:26:28
You can simply use a texture atlas or spritesheet with single letters and then draw textured quads for each letter in your text.
What you can do is use AWT to create a BufferedImage, then use the native OS specific font rendering mechanism to render a text to the buffered image and then use the buffered image to create an OpenGL texture. I did this myself once, it isnt too hard to do.
Title: Re: Slick utility with lwjgl 3
Post by: abcdef on November 27, 2014, 15:36:22
Here is a basic framework you need for rendering TTF using awt

1) Create an awt Font


        Font font = Font.createFont(java.awt.Font.TRUETYPE_FONT, "locationToMyFont");


2) Create a graphics object using this font


        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Graphics2D graphics = gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();
        graphics.setFont(font);


3) Extract the font metrics and find out where in a bitmap you want to draw the glyphs


         FontMetrics fontMetrics = graphics.getFontMetrics();


Specifics of doing this is left up to you

4) Create a buffered image of the size you want to draw it


        BufferedImage bufferedImage = graphics.getDeviceConfiguration().createCompatibleImage(textureWidth, textureHeight, Transparency.TRANSLUCENT);

        Graphics2D imageGraphics = (Graphics2D) bufferedImage.getGraphics();
        imageGraphics.setFont(font);
        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);


5) Draw each character you want to use (this is normally all visible characters) at the location you worked out above


        imageGraphics.drawChars('glyphChar', 0, 1,glyphLocationX, glyphLocationY);


6) Convert this BufferedImage to a ByteBuffer

        int[] pixels = new int[bufferedImage.getWidth() * bufferedImage.getHeight()];
        bufferedImage.getRGB(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), pixels, 0, bufferedImage.getWidth());

        ByteBuffer data = ByteBuffer.allocateDirect((bufferedImage.getWidth() * bufferedImage.getHeight() * 4));

        for (int y = 0; y < bufferedImage.getHeight(); y++)
        {
            for (int x = 0; x < bufferedImage.getWidth(); x++)
            {
                int pixel = pixels[y * bufferedImage.getWidth() + x];
                data.put((byte) ((pixel >> 16) & 0xFF));     // Red component
                data.put((byte) ((pixel >> 8) & 0xFF));      // Green component
                data.put((byte) (pixel & 0xFF));               // Blue component
                data.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA               
            }
        }


You now have your texture for opengl which is in the RGBA format, you can now use your glyph coordinates to string together a set of characters to draw in your opengl app.

There is obviously more to it but it should help you out.

Hopefully a freetype bindings of some sort would be added in the future, lots still to do on LWJGL3 though so it might be a while.
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on November 27, 2014, 16:48:12
@Cornix

Funny, I was thinking the same thing while I was walking with my dogs lol. Thanks for the idea though!

@abcdef

Amazing! But can you please explain the purpose of textureWidth, textureHeight, glyphLocationX,glyphLocationY? I do not know what values I have to provide there.
Title: Re: Slick utility with lwjgl 3
Post by: abcdef on November 27, 2014, 18:48:41
The texture width and height are the size of the texture you want to draw all your glyphs on, it is this texture you will pass to opengl

The glyphX and glyphY are the coordinates in that texture that you want to draw the glyph in. Example below

ABCDEabcdeYPyp

If all I wanted to do was to draw the characters above I would create a texture big enough to draw them all, i would then draw A at the far left on the texture and then B. A might have coordinate (0,0), B might have (10,0) and so on.

If I then wanted to use this to draw the word Bed, I would give opengl the overall texture then I would create three quads (created from triangles) with the texture coordinates pointing the locations of B e d in the texture.

Hope that makes sense
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on December 12, 2014, 16:00:57
Hey and sorry for the late reply!

I have been busy for 3 hours now and I still cannot get it to work. This is my font class:
import org.jarmer.*;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.nio.*;
import org.lwjgl.*;
import org.lwjgl.opengl.*;
import org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.*;

public class TrueTypeFont {
private String path;
private Font font;
private ByteBuffer imageData;
private BufferedImage imageBuffer;
private Graphics2D imageGraphics;
private int image = 0;

public TrueTypeFont(String path) throws JarmerException {
this.path = path;

try {
Font font = Font.createFont(java.awt.Font.TRUETYPE_FONT, new File(path));

char[] chars = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
generateTexture(chars);

} catch (FontFormatException ex) {
throw new JarmerException("Font is not a TTF!");
} catch (IOException ex) {
throw new JarmerException(ex);
}
}

//Draws the bitmap generated by the class
public void drawBitmap(float x,float y) {
glBindTexture(GL_TEXTURE_2D, image);
glBegin(GL_QUADS);
glVertex2f(x,y);
glVertex2f(x+512,y);
glVertex2f(x+512,y+512);
glVertex2f(x,y+512);

glTexCoord2f(0,0);
glTexCoord2f(1,0);
glTexCoord2f(1,1);
glTexCoord2f(0,1);
glEnd();
}

public void drawText(char[] text,float x,float y) {

}

private void generateTexture(char[] text) {

//Configure
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    Graphics2D graphics = gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();
        graphics.setFont(font);
       
        //Create the image buffer
FontMetrics fontMetrics = graphics.getFontMetrics();
BufferedImage imageBuffer = graphics.getDeviceConfiguration().createCompatibleImage(512, 512, Transparency.TRANSLUCENT);

//Draw the characters on our image
imageGraphics = (Graphics2D) imageBuffer.getGraphics();
imageGraphics.setFont(font);
imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
imageGraphics.drawChars(text,0,text.length,0,0);

//Generate texture data
int[] pixels = new int[imageBuffer.getWidth() * imageBuffer.getHeight()];
    imageBuffer.getRGB(0, 0, imageBuffer.getWidth(), imageBuffer.getHeight(), pixels, 0, imageBuffer.getWidth());
    imageData = ByteBuffer.allocateDirect((imageBuffer.getWidth() * imageBuffer.getHeight() * 4));

    for (int y = 0; y < imageBuffer.getHeight(); y++)
    {
        for (int x = 0; x < imageBuffer.getWidth(); x++)
        {
            int pixel = pixels[y * imageBuffer.getWidth() + x];
            imageData.put((byte) ((pixel >> 16) & 0xFF));     // Red component
            imageData.put((byte) ((pixel >> 8) & 0xFF));      // Green component
            imageData.put((byte) (pixel & 0xFF));               // Blue component
            imageData.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA               
        }
    }
   
    imageData.flip();
   
    //Generate texture
    image = glGenTextures();
   
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,image);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,512,512,0,GL_RGBA,GL_UNSIGNED_BYTE,imageData);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
}


I'm obviously missing something but I can't figure out what. The texture I try to draw remains entirely blank and nothing is being rendered. Also, which lines are required and which not? I'd like to learn about it by playing around but I don't know which lines are required and which aren't. I haven't used AWT but I'm very familiar with the HTML5 canvas and it's graphics context. I think I understand what you wanted to let me do here. It's like creating a canvas with a context, render the font's glyps 1 by 1 and create an image from it isn't it?
Title: Re: Slick utility with lwjgl 3
Post by: SHC on December 12, 2014, 16:37:55
This is your error:


glBegin(GL_QUADS);
    glVertex2f(x,y);
    glVertex2f(x+512,y);
    glVertex2f(x+512,y+512);
    glVertex2f(x,y+512);
             
    glTexCoord2f(0,0);
    glTexCoord2f(1,0);
    glTexCoord2f(1,1);
    glTexCoord2f(0,1);
glEnd();

You have to add texture-coordinates just after adding the vertices. Add the vertex, then the corresponding texture coordinate. Again, add the vertex and it's texture coordinate and follow the order.
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on December 12, 2014, 17:03:05
Oh god I feel like an idiot, thanks! I've been using VAO's and VBO's lately so I completely got used their vertex orders. Things are still screwed up though (I don't see any glyphs, just some random pixels at the end of the image or something) but at least I do see something. Now I got at least some visual results I can go on with.
Title: Re: Slick utility with lwjgl 3
Post by: Leycarno on January 20, 2015, 21:44:31
Hi BoneJarmer,

I'm just at this Point for my app now - do you have completed your class?

Title: Re: Slick utility with lwjgl 3
Post by: Leycarno on January 20, 2015, 23:51:02
I modify your code just a LITTLE...
Now it works usefull, but there ist still lot more more to do... but I need sleep  ;D


import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.nio.*;
import java.util.HashMap;
import java.util.Map;

import static org.lwjgl.opengl.GL11.*;

public class TrueTypeFont {
    private String path;
    private Font font;
    private ByteBuffer imageData;
    private BufferedImage imageBuffer;
    private Graphics2D imageGraphics;
    private int image = 0;

    private static final Map<Integer, String> CHARS = new HashMap<Integer, String>() {{
        put(1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        put(2, "abcdefghijklmnopqrstuvwxyz");
        put(3, "0123456789");
        put(4, "ÄÃâ€"ÃÅ"äöüß");   // Yep - I am from Germany ^^
        put(5, "$+-*/=%\"'#@&_(),.;:?!\\|<>[]Ã,§`^~");
    }};

    public TrueTypeFont(String path) throws Exception {
        this.path = path;

        try {
            font = Font.createFont(java.awt.Font.TRUETYPE_FONT, new File(path)).deriveFont(32f);

            generateTexture();

        } catch (FontFormatException ex) {
            throw new Exception("Font is not a TTF!");
        } catch (IOException ex) {
            throw new Exception(ex);
        }
    }

    //Draws the bitmap generated by the class
    public void drawBitmap(float x, float y) {
        glBindTexture(GL_TEXTURE_2D, image);
        glBegin(GL_QUADS);

        glTexCoord2f(0, 0);
        glVertex3f(x, y, 0);

        glTexCoord2f(1, 0);
        glVertex3f(x + 512, y, 0);

        glTexCoord2f(1, 1);
        glVertex3f(x + 512, y + 512, 0);

        glTexCoord2f(0, 1);
        glVertex3f(x, y + 512, 0);

        glEnd();
    }

    public void drawText(String text, float x, float y) {
        glBindTexture(GL_TEXTURE_2D, image);
        glBegin(GL_QUADS);
        for (char c : text.toCharArray()) {
            for (int index : CHARS.keySet()) {
                float p = (float) CHARS.get(index).indexOf(c);
                if (p >= 0) {
                    float recY = 1f / 512f * 32f;
                    float recX = 1f / 512f * 16f;
                    float xStart = recX * p;
                    float yStart = recY * (index - 1);

                    glTexCoord2f(xStart, yStart);
                    glVertex3f(x, y, 0);

                    glTexCoord2f(xStart + recX, yStart);
                    glVertex3f(x + 16, y, 0);

                    glTexCoord2f(xStart + recX, yStart + recY);
                    glVertex3f(x + 16, y + 32, 0);

                    glTexCoord2f(xStart, yStart + recY);
                    glVertex3f(x, y + 32, 0);

                    break;
                }
            }
            x += 16;
        }

        glEnd();
    }

    private void generateTexture() {

//Configure
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Graphics2D graphics = gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();
        graphics.setFont(font);

        //Create the image buffer
        FontMetrics fontMetrics = graphics.getFontMetrics();
        BufferedImage imageBuffer = graphics.getDeviceConfiguration().createCompatibleImage(512, 512, Transparency.TRANSLUCENT);

//Draw the characters on our image
        imageGraphics = (Graphics2D) imageBuffer.getGraphics();
        imageGraphics.setFont(font);
        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // draw every CHAR by line...
        imageGraphics.setColor(Color.WHITE);
        CHARS.keySet().stream().forEach(i -> {
            imageGraphics.drawString(CHARS.get(i), 0, fontMetrics.getMaxAscent() * i);
        });


//Generate texture data
        int[] pixels = new int[imageBuffer.getWidth() * imageBuffer.getHeight()];
        imageBuffer.getRGB(0, 0, imageBuffer.getWidth(), imageBuffer.getHeight(), pixels, 0, imageBuffer.getWidth());
        imageData = ByteBuffer.allocateDirect((imageBuffer.getWidth() * imageBuffer.getHeight() * 4));

        for (int y = 0; y < imageBuffer.getHeight(); y++) {
            for (int x = 0; x < imageBuffer.getWidth(); x++) {
                int pixel = pixels[y * imageBuffer.getWidth() + x];
                imageData.put((byte) ((pixel >> 16) & 0xFF));     // Red component
                imageData.put((byte) ((pixel >> 8) & 0xFF));      // Green component
                imageData.put((byte) (pixel & 0xFF));               // Blue component
                imageData.put((byte) ((pixel >> 24) & 0xFF));    // Alpha component. Only for RGBA
            }
        }

        imageData.flip();

        //Generate texture
        image = glGenTextures();

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, image);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
}


IMPORTANT -> you need a MONOSPACE (i use this: http://www.dafont.com/de/monofonto.font)
I will improve this part later...

um.. and you need java 8...

Here my (working) test:

TrueTypeFont font = new TrueTypeFont("font\\monofonto.ttf");
font.drawBitmap(0, 0);
font.drawText("HALLO World ! ;-)", 600, 100);


PS: Sorry for ugly format, but code dont work for me at the moment, so i use the BB-Code php-tag...
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on January 22, 2015, 15:01:53
Oh hey and sorry! Haven't been online for a while but no, I didn't complete my class to be honest. I got stuck after a couple of tries, and duties required me to use my time for other business so I didn't spent much more efforts into it. In fact, I have to thank you for your code. I haven't tried it yet but you did what I could not.
Title: Re: Slick utility with lwjgl 3
Post by: Leycarno on January 22, 2015, 15:21:31
Hi :)

here an all-purpose version for any TTF with any width for the Chars...

First class is just a utility for the AWT-stuff:


import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

public class Ley2dFontUtilAwt {

    private static final float DEFAULT_FONT_SIZE = 32f; // ok THIS is specific... you can give it as param of construct...
    private static final Map< Integer, String> CHARS = new HashMap< Integer, String>() {{
        put(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        put(1, "abcdefghijklmnopqrstuvwxyz");
        put(2, "0123456789");
        put(3, "ÄÃâ€"ÃÅ"äöüß");
        put(4, "$+-*/=%\"'#@&_(),.;:?!\\|<>[]Ã,§`^~");
    }};

    private Font font;
    private FontMetrics fontMetrics;

    public Ley2dFontUtilAwt(String ttfFilename) throws Throwable {
        this.loadFont(ttfFilename);
    }

    public ByteBuffer getFontAsByteBuffer() {

        BufferedImage bufferedImage = this.generateBufferedImage();

        this.drawFontChars(bufferedImage);

        ByteBuffer byteBuffer = this.generateByteBuffer(bufferedImage);

        return byteBuffer;
    }

    public float getFontImageWidth() {
        return (float) CHARS.values().stream()
                .mapToDouble(e -> fontMetrics.getStringBounds(e, null).getWidth())
                .max().getAsDouble();
    }

    public float getFontImageHeight() {
        return (float) CHARS.keySet().size() * (this.getCharHeight());
    }

    /**
     * @return the "start"-PositionX of the Char on the FontImage
     */
    public float getCharX(char c) {
        String originStr = CHARS.values().stream()
                .filter(e -> e.contains("" + c))
                .findFirst()
                .orElse("" + c);
        return (float) fontMetrics.getStringBounds(originStr.substring(0, originStr.indexOf(c)), null).getWidth();
    }

    /**
     * @return the "start"-PositionY of the Char on the FontImage
     */
    public float getCharY(char c) {
        float lineId = (float) CHARS.keySet().stream()
                .filter(i -> CHARS.get(i).contains("" + c))
                .findFirst()
                .orElse(0);
        return this.getCharHeight() * lineId;
    }

    /**
     * @return the width of the specific Character
     */
    public float getCharWidth(char c) {
        return fontMetrics.charWidth(c);
    }

    /**
     * Hint:
     *      getMaxAscent is the max Height above the baseline
     *      getMaxDescent is the max Height under the baseline
     *
     * @returns the max Height of every possible Char
     */
    public float getCharHeight() {
        return (float) (fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent());
    }

    private BufferedImage generateBufferedImage() {
        //Configure
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Graphics2D graphics = gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();
        graphics.setFont(font);
        fontMetrics = graphics.getFontMetrics();
        return graphics
                .getDeviceConfiguration()
                .createCompatibleImage(
                        (int) getFontImageWidth(),
                        (int) getFontImageHeight(),
                        Transparency.TRANSLUCENT);
    }

    private void drawFontChars(BufferedImage imageBuffer) {
        //Draw the characters on our image
        Graphics2D imageGraphics = (Graphics2D) imageBuffer.getGraphics();
        imageGraphics.setFont(font);
        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // draw every CHAR by line...
        imageGraphics.setColor(Color.WHITE);
        CHARS.keySet().stream().forEach(i -> imageGraphics.drawString(CHARS.get(i), 0, fontMetrics.getMaxAscent() + (this.getCharHeight() * i)));
    }

    private ByteBuffer generateByteBuffer(BufferedImage imageBuffer) {
        //Generate texture data
        int[] pixels = new int[imageBuffer.getWidth() * imageBuffer.getHeight()];
        imageBuffer.getRGB(0, 0, imageBuffer.getWidth(), imageBuffer.getHeight(), pixels, 0, imageBuffer.getWidth());
        ByteBuffer imageData = ByteBuffer.allocateDirect((imageBuffer.getWidth() * imageBuffer.getHeight() * 4));

        for (int y = 0; y < imageBuffer.getHeight(); y++) {
            for (int x = 0; x < imageBuffer.getWidth(); x++) {
                int pixel = pixels[y * imageBuffer.getWidth() + x];
                imageData.put((byte) ((pixel >> 16) & 0xFF));   // Red component
                imageData.put((byte) ((pixel >> 8) & 0xFF));    // Green component
                imageData.put((byte) (pixel & 0xFF));           // Blue component
                imageData.put((byte) ((pixel >> 24) & 0xFF));   // Alpha component. Only for RGBA
            }
        }
        imageData.flip();
        return imageData;
    }

    private void loadFont(String ttfFilename) throws Throwable {
        try {
            font = Font.createFont(java.awt.Font.TRUETYPE_FONT, new File(ttfFilename))
                    .deriveFont(DEFAULT_FONT_SIZE);
        } catch (FontFormatException ex) {
            throw new Exception("Font is not a TTF!");
        } catch (IOException ex) {
            throw new Exception(ex);
        }
    }
}


And the second Class with the LWJGL-Stuff using the AwtUtil:


import java.nio.ByteBuffer;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.GL_LINEAR;

class Ley2dFontLWJGL3 {

    private Ley2dFontUtilAwt fontUtil;
    private int fontTextureId;

    Ley2dFontLWJGL3(String ttfFilename) throws Throwable {
        fontUtil = new Ley2dFontUtilAwt(ttfFilename);
        generateTexture(fontUtil.getFontAsByteBuffer());
    }

    private void generateTexture(ByteBuffer bb) {
        this.fontTextureId = glGenTextures();

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, this.fontTextureId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                (int) fontUtil.getFontImageWidth(),
                (int) fontUtil.getFontImageHeight(),
                0, GL_RGBA, GL_UNSIGNED_BYTE, bb);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }

    public void drawFontTexture(int x, int y) {
        glBindTexture(GL_TEXTURE_2D, this.fontTextureId);
        glBegin(GL_QUADS);

        glTexCoord2f(0, 0);
        glVertex3f(x, y, 0);

        glTexCoord2f(1, 0);
        glVertex3f(x + fontUtil.getFontImageWidth(), y, 0);

        glTexCoord2f(1, 1);
        glVertex3f(x + fontUtil.getFontImageWidth(), y + fontUtil.getFontImageHeight(), 0);

        glTexCoord2f(0, 1);
        glVertex3f(x, y + fontUtil.getFontImageHeight(), 0);

        glEnd();
    }

    public void drawText(String text, int xPosition, int yPosition) {
        glBindTexture(GL_TEXTURE_2D, this.fontTextureId);
        glBegin(GL_QUADS);
        int xTmp = xPosition;
        for (char c : text.toCharArray()) {
            float width = fontUtil.getCharWidth(c);
            float height = fontUtil.getCharHeight();
            float w = 1f / fontUtil.getFontImageWidth() * width;
            float h = 1f / fontUtil.getFontImageHeight() * height;
            float x = 1f / fontUtil.getFontImageWidth() * fontUtil.getCharX(c);
            float y = 1f / fontUtil.getFontImageHeight() * fontUtil.getCharY(c);

            glTexCoord2f(x, y);
            glVertex3f(xTmp, yPosition, 0);

            glTexCoord2f(x + w, y);
            glVertex3f(xTmp + width, yPosition, 0);

            glTexCoord2f(x + w, y + h);
            glVertex3f(xTmp + width, yPosition + height, 0);

            glTexCoord2f(x, y + h);
            glVertex3f(xTmp, yPosition + height, 0);

            xTmp += width;
        }
        glEnd();
    }
}


PS: the Problem with the code-Tag is:
<Integer, String>
<Integer, String>
Solution: Space before the Integer!
< Integer, String>
< Integer, String>

Best Regards
Ley
Title: Re: Slick utility with lwjgl 3
Post by: TheBoneJarmer on January 30, 2015, 15:17:33
Hey Ley!

Thanks for posting your code! I tried it just now and it works great! I've made some modifications though. I merged the two classes together and cleaned things up a bit (yea sorry but I've to be honest, your code is a mess :p). I'll leave it behind here for others who are interested.

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.GL_LINEAR;

public class Font {

//Constants
private final Map<Integer,String> CHARS = new HashMap<Integer,String>() {{
        put(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        put(1, "abcdefghijklmnopqrstuvwxyz");
        put(2, "0123456789");
        put(3, "ÄÃâ€"ÃÅ"äöüß");
        put(4, " $+-*/=%\"'#@&_(),.;:?!\\|<>[]Ã,§`^~");
    }};

//Variables
    private java.awt.Font font;
    private FontMetrics fontMetrics;
    private BufferedImage bufferedImage;
    private int fontTextureId;
   
    //Getters
    public float getFontImageWidth() {
        return (float) CHARS.values().stream().mapToDouble(e -> fontMetrics.getStringBounds(e, null).getWidth()).max().getAsDouble();
    }
    public float getFontImageHeight() {
        return (float) CHARS.keySet().size() * (this.getCharHeight());
    }
    public float getCharX(char c) {
        String originStr = CHARS.values().stream().filter(e -> e.contains("" + c)).findFirst().orElse("" + c);
        return (float) fontMetrics.getStringBounds(originStr.substring(0, originStr.indexOf(c)), null).getWidth();
    }
    public float getCharY(char c) {
        float lineId = (float) CHARS.keySet().stream().filter(i -> CHARS.get(i).contains("" + c)).findFirst().orElse(0);
        return this.getCharHeight() * lineId;
    }
    public float getCharWidth(char c) {
        return fontMetrics.charWidth(c);
    }
    public float getCharHeight() {
        return (float) (fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent());
    }
   
    //Constructors
    public Font(String path, float size) throws Exception {
        font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, new File(path)).deriveFont(size);
       
        //Generate buffered image
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        Graphics2D graphics = gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();
        graphics.setFont(font);
       
        fontMetrics = graphics.getFontMetrics();
        bufferedImage = graphics.getDeviceConfiguration().createCompatibleImage((int) getFontImageWidth(),(int) getFontImageHeight(),Transparency.TRANSLUCENT);
       
//Generate texture
fontTextureId = glGenTextures();
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, fontTextureId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,(int) getFontImageWidth(),(int) getFontImageHeight(),0, GL_RGBA, GL_UNSIGNED_BYTE, asByteBuffer());

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
   
    //Functions
    public void drawText(String text, int x, int y) {
        glBindTexture(GL_TEXTURE_2D, this.fontTextureId);
        glBegin(GL_QUADS);
       
        int xTmp = x;
        for (char c : text.toCharArray()) {
            float width = getCharWidth(c);
            float height = getCharHeight();
            float cw = 1f / getFontImageWidth() * width;
            float ch = 1f / getFontImageHeight() * height;
            float cx = 1f / getFontImageWidth() * getCharX(c);
            float cy = 1f / getFontImageHeight() * getCharY(c);

            glTexCoord2f(cx, cy);
            glVertex3f(xTmp, y, 0);

            glTexCoord2f(cx + cw, cy);
            glVertex3f(xTmp + width, y, 0);

            glTexCoord2f(cx + cw, cy + ch);
            glVertex3f(xTmp + width, y + height, 0);

            glTexCoord2f(cx, cy + ch);
            glVertex3f(xTmp, y + height, 0);

            xTmp += width;
        }
       
        glEnd();
    }
   
    //Conversions
    public ByteBuffer asByteBuffer() {

        ByteBuffer byteBuffer;

        //Draw the characters on our image
        Graphics2D imageGraphics = (Graphics2D) bufferedImage.getGraphics();
        imageGraphics.setFont(font);
        imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
        imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        // draw every CHAR by line...
        imageGraphics.setColor(Color.WHITE);
        CHARS.keySet().stream().forEach(i -> imageGraphics.drawString(CHARS.get(i), 0, fontMetrics.getMaxAscent() + (this.getCharHeight() * i)));
       
        //Generate texture data
        int[] pixels = new int[bufferedImage.getWidth() * bufferedImage.getHeight()];
        bufferedImage.getRGB(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), pixels, 0, bufferedImage.getWidth());
        byteBuffer = ByteBuffer.allocateDirect((bufferedImage.getWidth() * bufferedImage.getHeight() * 4));

        for (int y = 0; y < bufferedImage.getHeight(); y++) {
            for (int x = 0; x < bufferedImage.getWidth(); x++) {
                int pixel = pixels[y * bufferedImage.getWidth() + x];
                byteBuffer.put((byte) ((pixel >> 16) & 0xFF));   // Red component
                byteBuffer.put((byte) ((pixel >> 8) & 0xFF));    // Green component
                byteBuffer.put((byte) (pixel & 0xFF));           // Blue component
                byteBuffer.put((byte) ((pixel >> 24) & 0xFF));   // Alpha component. Only for RGBA
            }
        }
       
        byteBuffer.flip();

        return byteBuffer;
    }
}
Title: Re: Slick utility with lwjgl 3
Post by: SHC on January 30, 2015, 17:50:48
I think I have a better implementation. It doesn't support unicode chars, but it does support overhanging glyphs in script fonts. You can find it here.

https://github.com/sriharshachilakapati/SilenceEngine/blob/master/src/main/java/com/shc/silenceengine/graphics/TrueTypeFont.java

Here's a proof of overhanging glyphs:

(http://puu.sh/dBTbK/c4ba04e77b.png)

The main difference is this uses texture pages, so it is easy enough to convert this to a BitmapFont as well if you need it.