LWJGL Forum

Programming => Lightweight Java Gaming Library => Topic started by: WeBeJammin on November 27, 2019, 18:56:56

Title: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: WeBeJammin on November 27, 2019, 18:56:56
I was hoping somebody could give me a clue what I am doing wrong when creating character bitmaps from the STBTruetype library. The generated bitmap seems to be a bitmap representing the character requested, however it is in a 4x4 grid with a slight offset in the negative x asix for each row. I thought I would get back a bitmap representing a single instance of the character. Here is the output for the character 'A':

(https://imgur.com/ivygLBw.png)

Hopefully this code sample isn't too bad:

Font.java
public class Font {
private STBTTFontinfo info;
private float pixelScale;

public Font(final String ttfPath) throws IOException {
final ByteBuffer ttfBuffer = ResourceLoader.toByteBuffer(ttfPath);
info = STBTTFontinfo.create();
stbtt_InitFont(info, ttfBuffer, 0);
pixelScale = stbtt_ScaleForPixelHeight(info, 512);
}

public Character getChar(final char c) {
final int[] w = new int[]{0}, h = new int[]{0}, xoff = new int[]{0}, yoff = new int[]{0};
final ByteBuffer bitmapData = stbtt_GetCodepointBitmap(info, 0, pixelScale, c, w, h, xoff, yoff);
return new Character(bitmapData, w[0], h[0], xoff[0], yoff[0]); // dumb pojo to hold bitmap and dimensions
}
}


FontText.java
public class FontTest {
private Window window = RunnerUtils.setupWindow();
private Font font;

public static void main(String[] args) throws Exception {
new FontTest().run();
}

private void run() throws Exception {
OpenGlState.init(window);
font = new Font("font/roboto/Roboto-Black.ttf");

Character aChar = font.getChar('A');
int textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, aChar.getWidth(), aChar.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, aChar.getBitmapData());

OpenglUtils.saveTextureToJpg(textureId, new File("out.png")); // Saves to file, but rendering the bitmap to a quad is the same image

window.destroy();
}
}
Title: Re: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: overlisted on November 27, 2019, 19:06:15
Doesn't it repeat because of GL_REPEAT?
Title: Re: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: WeBeJammin on November 27, 2019, 19:08:03
I was thinking the same thing, but using GL_CLAMP_TO_BORDER produced the same result.
Title: Re: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: overlisted on November 27, 2019, 21:59:35
I tried to use your class (don't care about font texture on a block)...
(https://sun9-66.userapi.com/c854016/v854016200/18bc22/7KFpFglOsKQ.jpg)

It gets more and more noisy every time I run the game. Once it breaks and OpenGL can't process a texture. :o


My Font.java

public class Font {
  public STBTTFontinfo info;
  public float fontSize = 512;

  public Font(String resource) {
    this.info = STBTTFontinfo.create();
    stbtt_InitFont(info, Utils.loadResource(resource), 0);
  }

  public Texture getTextureFor(char character) {
    try(MemoryStack stack = MemoryStack.stackPush()) {
      final IntBuffer width = stack.mallocInt(1);
      final IntBuffer height = stack.mallocInt(1);

      final ByteBuffer bitmap = stbtt_GetCodepointBitmap(
        this.info,
        0,
        stbtt_ScaleForPixelHeight(this.info, this.fontSize),
        character,
        width,
        height,
        null,
        null
      );

      System.out.println(
        "char: " + width.get(0) + " " + height.get(0) + " " + character + " " + stbtt_ScaleForPixelHeight(this.info, this.fontSize)
      );

      final Texture texture = new Texture(
        bitmap,
        width.get(0),
        height.get(0)
      );

      stbtt_FreeBitmap(bitmap);

      return texture;
    } catch(Throwable e) {
      e.printStackTrace();

      return null;
    }
  }
}


My texture constructor

  public Texture(ByteBuffer bitmap, int width, int height) {
    this.width = width;
    this.height = height;
    this.id = glGenTextures();

    glBindTexture(GL_TEXTURE_2D, this.id);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
//    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
    glGenerateMipmap(GL_TEXTURE_2D);
  }
Title: Re: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: WeBeJammin on November 27, 2019, 22:32:30
Thanks for looking into it a bit. Weird that the texture is so noisy...
Title: Re: stbtt_GetCodepointBitmap generating a 4x4 bitmap of the character
Post by: overlisted on November 28, 2019, 16:57:38
Hmm... The official stb_truetype.h says that the texture format should be GL_ALPHA8
(https://sun9-61.userapi.com/c854016/v854016843/184328/KlxHXF10H64.jpg)


Yaaay! I could make this work! I think we were seeing 4 * 4 letters because of RGBA8-ALPHA8 conflict. The noise also has gone.
Texture constructor

  public Texture(ByteBuffer bitmap, int width, int height) {
    this.width = width;
    this.height = height;
    this.id = glGenTextures();

    glBindTexture(GL_TEXTURE_2D, this.id);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    // uncomment code below to make gl not antialias minecraft-like fonts
//    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
//    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // 8 bpp = 1 byte per pixel

    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap);
    glGenerateMipmap(GL_TEXTURE_2D);
  }


Font class hasn't been changed so you can use it from my previous comment.

Result
(https://sun9-36.userapi.com/c854016/v854016843/1843aa/r7vjPFjR1m8.jpg)


To change the character color you can use a fragment shader.