1
votes

I am working on a project in OpenGL with lwjgl. I was having a hard time loading an icon for the window, as it wanted a GLFWImage buffer. After a long time of scouring the internet, this is what I have:

try {
            BufferedImage originalImage =
                    ImageIO.read(new File("favicon.png"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write( originalImage, "png", baos );
            baos.flush();
            byte[] imageInByte = baos.toByteArray();
            ByteBuffer buF = ByteBuffer.wrap(imageInByte);
            GLFWImage.Buffer b = new GLFWImage.Buffer(buF);
            glfwSetWindowIcon(window, b);
        } catch (IOException io){
            System.out.println("Could not load window icon!");
            System.out.println(io.toString());
        }

The java runtime crashes with an output like this:

# A fatal error has been detected by the Java Runtime Environment:
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.

I haven't been able to find a method to do this that doesn't give this kind of error. The official glfw documentation says to use a method that doesn't seem to exist in LWJGL. If you have any experience with this, it would even be helpful to just point me in the right direction.

Thanks in advance.

1
I'm having this same problem; however, I have found something interesting:if one adds buF.flip() immediately before the b = new Buffer line, it will prevent the crash, but fail to change the icon. Also, mine only works with Buffer instead of GLFWImage.Buffer, but that's probably IDE dependent. - Ash Pera

1 Answers

0
votes

This solution is unwieldy; however, it works for me! :) It's based on code in the lwjgl events demo, but to use that I had to implement the demo IOUtil. The code for setting the icon is this:

ByteBuffer icon16;
ByteBuffer icon32;
try {
    icon16 = IOUtil.ioResourceToByteBuffer("src/hexsweeper/hex16.png", 2048);
    icon32 = IOUtil.ioResourceToByteBuffer("src/hexsweeper/hex32.png", 4096);
} catch (Exception e) {
    throw new RuntimeException(e);
}

    
IntBuffer w = memAllocInt(1);
IntBuffer h = memAllocInt(1);
IntBuffer comp = memAllocInt(1);
    
try ( GLFWImage.Buffer icons = GLFWImage.malloc(2) ) {
    ByteBuffer pixels16 = stbi_load_from_memory(icon16, w, h, comp, 4);
    icons
        .position(0)
        .width(w.get(0))
        .height(h.get(0))
        .pixels(pixels16);

    ByteBuffer pixels32 = stbi_load_from_memory(icon32, w, h, comp, 4);
    icons
        .position(1)
        .width(w.get(0))
        .height(h.get(0))
        .pixels(pixels32);

    icons.position(0);
    glfwSetWindowIcon(window, icons);

    stbi_image_free(pixels32);
    stbi_image_free(pixels16);
}

The imports are as follows:

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import org.lwjgl.glfw.GLFWImage;

import static org.lwjgl.stb.STBImage.*;
import static org.lwjgl.system.MemoryUtil.*;

And in another file (named IOUtil) I put the following code:

import org.lwjgl.BufferUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static org.lwjgl.BufferUtils.*;

public final class IOUtil {

private IOUtil() {
}

private static ByteBuffer resizeBuffer(ByteBuffer buffer, int newCapacity) {
    ByteBuffer newBuffer = BufferUtils.createByteBuffer(newCapacity);
    buffer.flip();
    newBuffer.put(buffer);
    return newBuffer;
}

/**
 * Reads the specified resource and returns the raw data as a ByteBuffer.
 *
 * @param resource   the resource to read
 * @param bufferSize the initial buffer size
 *
 * @return the resource data
 *
 * @throws IOException if an IO error occurs
 */
public static ByteBuffer ioResourceToByteBuffer(String resource, int bufferSize) throws IOException {
    ByteBuffer buffer;

    Path path = Paths.get(resource);
    if ( Files.isReadable(path) ) {
        try (SeekableByteChannel fc = Files.newByteChannel(path)) {
            buffer = BufferUtils.createByteBuffer((int)fc.size() + 1);
            while ( fc.read(buffer) != -1 ) ;
        }
    } else {
        try (
            InputStream source = IOUtil.class.getClassLoader().getResourceAsStream(resource);
            ReadableByteChannel rbc = Channels.newChannel(source)
        ) {
            buffer = createByteBuffer(bufferSize);

            while ( true ) {
                int bytes = rbc.read(buffer);
                if ( bytes == -1 )
                    break;
                if ( buffer.remaining() == 0 )
                    buffer = resizeBuffer(buffer, buffer.capacity() * 2);
            }
        }
    }

    buffer.flip();
    return buffer;
}

}

Replace the "src/hexsweeper/hex16.png" with however you get to your files, the window with your window, and you should be set. This worked for me, hope it works for everyone else!

Note: I didn't write the bulk of this code. It was made by the wonderfully helpfull lwjgl contributors apostolos, Spasi, and kappaOne.