LWJGL / lwjgl3

LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.
https://www.lwjgl.org
BSD 3-Clause "New" or "Revised" License
4.75k stars 635 forks source link

STBTruetype.stbtt_MakeCodepointBitmap doesn't have a way to add a byte offset #859

Closed theosib closed 1 year ago

theosib commented 1 year ago

Description

I'm trying to follow this example for rendering text: https://github.com/justinmeiners/stb-truetype-example/blob/master/main.c

I found LWJGL equivalents for everything except one thing. There's this line of code:

        stbtt_MakeCodepointBitmap(&info, bitmap + byteOffset, c_x2 - c_x1, c_y2 - c_y1, b_w, scale, scale, word[i]);

Here, the bitmap has an offset added to it to control the X coordinate of where the glyph is rendered. Unfortunately, there is no variant of STBTruetype.stbtt_MakeCodepointBitmap that includes that option. Fortunately, the developers of LWJGL are smart and have made all the internal native method calls public, so I was able to add my own inside my own font rendering class:

    public static void stbtt_MakeCodepointBitmap(STBTTFontinfo info, ByteBuffer output, int byteOffset, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) {
        STBTruetype.nstbtt_MakeCodepointBitmap(info.address(), MemoryUtil.memAddress(output) + byteOffset, out_w, out_h, out_stride, scale_x, scale_y, codepoint);
    }

I would like to suggest that this method be added to the official STBTrueType class.

Thanks.

httpdigest commented 1 year ago

LWJGL respects the .position() of the ByteBuffer you put into that. So, just advance that ByteBuffer's (or a slice of that) position by the offset.

theosib commented 1 year ago

Oh, I didn't think of that. That does sound like a good alternative.

theosib commented 1 year ago

That said, I think this is a bit awkward:

                imageBuf.position(byteOffset + lpad);
                STBTruetype.stbtt_MakeCodepointBitmap(info, imageBuf,c_x2.get(0) - c_x1.get(0), c_y2.get(0) - c_y1.get(0), bw, scale, scale, c);
                imageBuf.position(0);
httpdigest commented 1 year ago

That's why I said "or a slice of that". Suppose, you have an API that you want to call:

public static void something(ByteBuffer bbWithPotentialOffset);

And suppose you have an original ByteBuffer that you allocated somehow and want to use with that method at an offset, then:

ByteBuffer original = ...
something(original.slice().position(offset));

Please first read the JavaDoc of [ByteBuffer.slice](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/nio/ByteBuffer.html#slice()).

httpdigest commented 1 year ago

Let's just discuss the rationale of my alternative suggestion:

The thing is: There are probably a thousand C API functions that take pointers for which LWJGL then provides Java methods that take ByteBuffers (or other derivatives of Buffer, depending on the type of pointer), because a ByteBuffer is the nearest possible standard and safe abstraction for a memory region (before Project Panama, that is). And you can argue with all those functions that, in C, you could have used pointer arithmetic at the call-site to come up with an argument to that function's pointer paramter. But that does not mean that LWJGL then should also provides this "pointer arithmetic" or "pointer but with an integer offset" as a direct mechanism for all C functions with a pointer parameter. And there would also be no real reasoning behind providing that as a special case for one function but not for all other.

theosib commented 1 year ago

What you say makes sense. Since I'm filling the buffer, it was convenient enough for me to just set the position before making the JNI call. I'll keep in mind the slice thing for future reference in case I don't want to disturb the current position of a buffer. Thanks for the help!