LWJGL / STB:IntelliJ 中 运行 与控制台 运行 不一致

LWJGL / STB: Inconsistency when running in IntelliJ vs. running over Console

我在 IntelliJ 中使用 LWJGL 和 STB TrueType 时遇到问题。

当我现在尝试创建位图并将所有内容放入 Main(下面的“代码 1”)时,一切正常。
一旦我尝试将其拆分 创建一个 OpenGL 上下文 (如果我将其拆分而不创建 OpenGL 上下文它也可以正常工作), 加载的字体以某种方式损坏,并且程序崩溃并显示 ACCESS_VIOLATION 或 运行s 而没有生成位图。您可以在下面看到损坏的代码,如“代码 2”。

错误行为仅在 运行 java 运行 参数时发生,IntelliJ 使用 - 通过 Intellij 运行 或通过控制台。
它不会发生在构建到 JAR 中并 运行ning 时不会发生。

有问题的论点如下。如果控制台中缺少这个,它 运行s.

-javaagent:<INTELLIJ_HOME>\lib\idea_rt.jar=52850:<INTELLIJ_HOME>\bin

我已阅读 here idea_rt.jar 文件 "is needed to provide graceful shutdown/exit/stacktrace features",因此我不想在 IntelliJ 中禁用它。


注意: 在损坏的代码中(下面的 'Code 2'),您会注意到 'unnecessary' 行
ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf"); 模拟加载多种字体。如果我只加载一种字体,一切正常。
您还会注意到代码 2 中的 OpenGL 上下文创建,这似乎也是问题的原因(如上所述)


代码 1(有效)

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBTTFontinfo;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;

import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointBitmap;
import static org.lwjgl.stb.STBTruetype.stbtt_InitFont;


public class STBTTExampleOnlyMain {
    private static ByteBuffer loadByteBufferFromResource(String resource) throws IOException {
        try(InputStream stream = STBTTExampleOnlyMain .class.getResourceAsStream(resource)) {
            byte[] bytes = stream.readAllBytes();

            ByteBuffer buffer = BufferUtils.createByteBuffer(bytes.length);
            buffer.put(bytes);
            buffer.flip();

            return buffer;
        }
    }

    public static void main(String[] args) throws IOException {
        ByteBuffer data = loadByteBufferFromResource("/fonts/arial.ttf");
        ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf");

        STBTTFontinfo font = STBTTFontinfo.create();
        stbtt_InitFont(font, data);

        IntBuffer bufWidth = BufferUtils.createIntBuffer(1);
        IntBuffer bufHeight = BufferUtils.createIntBuffer(1);
        ByteBuffer bitmap = stbtt_GetCodepointBitmap(font, 0, 1, 'a', bufWidth, bufHeight, null, null);

        System.out.println(bitmap);
    }
}


代码 2(损坏)

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL;
import org.lwjgl.stb.STBTTFontinfo;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;

import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
import static org.lwjgl.glfw.GLFW.glfwInit;
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
import static org.lwjgl.stb.STBTruetype.stbtt_GetCodepointBitmap;
import static org.lwjgl.stb.STBTruetype.stbtt_InitFont;


public class STBTTExample {
    private static final Map<Integer, STBTTFontinfo> fontMap = new HashMap<>();

    private static ByteBuffer loadByteBufferFromResource(String resource) throws IOException {
        try(InputStream stream = STBTTExample.class.getResourceAsStream(resource)) {
            byte[] bytes = stream.readAllBytes();

            ByteBuffer buffer = BufferUtils.createByteBuffer(bytes.length);
            buffer.put(bytes);
            buffer.flip();

            return buffer;
        }
    }

    private static void initFont() throws IOException {
        ByteBuffer data = loadByteBufferFromResource("/fonts/arial.ttf");
        ByteBuffer data2 = loadByteBufferFromResource("/fonts/arial.ttf");

        STBTTFontinfo font = STBTTFontinfo.create();
        stbtt_InitFont(font, data);

        fontMap.put(0, font);
    }

    public static void main(String[] args) throws IOException {
        initFont();

        glfwInit();
        glfwDefaultWindowHints();
        long windowHandle = glfwCreateWindow(800, 600, "Test", 0, 0);
        glfwMakeContextCurrent(windowHandle);
        GL.createCapabilities();

        IntBuffer bufWidth = BufferUtils.createIntBuffer(1);
        IntBuffer bufHeight = BufferUtils.createIntBuffer(1);
        ByteBuffer bitmap = stbtt_GetCodepointBitmap(fontMap.get(0), 0, 1, 'a', bufWidth, bufHeight, null, null);

        System.out.println(bitmap);
    }
}


如何解决在使用文本渲染时无法 运行 程序脱离 IntelliJ 的问题?

我是否可能误解了 STBTT 库并且实际上不能以这种方式使用字体?

如果您能帮助我们理解错误并解决这个问题,我们将不胜感激。

我在LWJGL论坛问过,问题解决了

The STBTTFontinfo object contains metadata only. The actual font data is NOT copied from the ByteBuffer you pass to stbtt_InitFont. Only its memory address is copied and the font data is accessed via that pointer when necessary. The segfault you're seeing happens because you don't store a reference to the ByteBuffer anywhere, it is GCed/deallocated by the time you try to use the font. An easy fix would be to change your Font class to also store the ByteBuffer.

你可以看看post here.