ice1000 / jimgui

:sparkling_heart: Pure Java binding for dear-imgui
Apache License 2.0
186 stars 13 forks source link

GLFW support for Windows #12

Closed wrymn closed 6 years ago

wrymn commented 6 years ago

I would like to request feature, where image would be rendered using only textureId, that was already created and rendered into by OpenGL.

Many existing imgui frameworks accept only textureId to draw images.

Thank you

ice1000 commented 6 years ago

Do you mean GLuint?

ice1000 commented 6 years ago

For testing purpose please try invoking this constructor

        /**
         * package-private by design
         *
         * @param nativeObjectPtr native ImTextureID*
         *                        have different implementation on difference platforms
         * @param width           image width
         * @param height          image height
         */
        private JImTextureID(long nativeObjectPtr, int width, int height) {
                this.width = width;
                this.height = height;
                this.nativeObjectPtr = nativeObjectPtr;
        }

You can use reflection. If it works I'll add a public API for this.

wrymn commented 6 years ago

@ice1000 I have managed to create JImTextureID from its constructor, but when trying to draw it via gui.image(), it does crash. I am not sure why, maybe because that texture ID is used already by our framework?

I have tried to copy our texture into new generated texture, but result was the same, crash

int newTextureId = GL11.glGenTextures();
GL43.glCopyImageSubData(GL_TEXTURE_2D, GLMain.backBufferTextureId, 0, 0, 0, 0, GL_TEXTURE_2D, newTextureId, 0, 0, 0, 0, 2048, 1024, 0);
ice1000 commented 6 years ago

Windows? Oh dear, currently on windows you'll have to provide a LPDIRECT3DTEXTURE9.

Please wait I'll give you a glfw impl on Windows soon.

wrymn commented 6 years ago

It seems directx and opengl cannot share texture pointers (which is what I expected), so its back to trying it on opengl version of imgui (which we kinda failed to generate via cmake)

wrymn commented 6 years ago

Hi @ice1000, what is the progress on this issue? Will we be able to use textureId from OpenGL on windows to display image?

This is the last critical blocker :(

ice1000 commented 6 years ago

Fighting against windows glfw developing environment and https://youtrack.jetbrains.com/issue/KT-24946. Will be available very soon.

ice1000 commented 6 years ago

It's done! Waiting for the mac guy to give me the dylib.

ice1000 commented 6 years ago

It's raising

WGL: The driver does not appear to support OpenGL

While testing. I don't know much about this, maybe it's just because the tester computer is not working properly?

wrymn commented 6 years ago

Every PC or mobile device has to support OpenGL, its how they draw on screen. Its bridge between application and GPU. So this is either old GPU driver or have to upgrade OpenGL version

What I have found out so far:

ice1000 commented 6 years ago

It says that WGL_ARB_create_context_profile is not defined when I retry running it with a lower version of jre (a workaround told by my friend)..

wrymn commented 6 years ago

Try upgrading OpenGL: http://glew.sourceforge.net/ Also please make sure graphics driver is up to date.

Here is similar issue: https://stackoverflow.com/questions/11383651/opengl-3-3-glx-arb-create-context-profile-is-unavailable-on-linux-with-bumblebee

ice1000 commented 6 years ago

Oh fuck. I give up, simply use the dll I'll upload about 1min later and use System.load(absolute path to the dll) instead of JniLoader.load(), and check if it works on your computer.

ice1000 commented 6 years ago

Maybe it's just the problem of the testing computer.

ice1000 commented 6 years ago

The dll is compatible with v0.4-3

wrymn commented 6 years ago

Thank you, so the DLL will use OpenGL and accept textureId?

HoshinoTented commented 6 years ago

Expected to be.

HoshinoTented commented 6 years ago

jimgui-glfw.zip

😃

ice1000 commented 6 years ago

:arrow_up: My friend, owner of the Windows testing machine :smile:

HoshinoTented commented 6 years ago

The project files, works with mingw jimgui-glfw.zip

ice1000 commented 6 years ago

Thanks to @mikecovlee

ice1000 commented 6 years ago

@wrymn Is that working for you? I'm gonna sleep since it's 3:19 a.m.

wrymn commented 6 years ago

Working on it...will run it in few minutes

wrymn commented 6 years ago

@ice1000 both jimgui and our framework use GLFW, which is then initialized twice.

Not sure how to solve this.

This error is thrown when I create JImGui before or after our framework inits GLFW.

ImGui Error 65544: Win32: Failed to register window class

Would it be possible to provide existing instance of GLFW? Or stop it from initializing second time.

ice1000 commented 6 years ago

Seems work (at least the creation of the window).

And the initialization of imgui and glfw is already separated in the newest version, which should work. The only reason I'm not publishing v0.5 is that the mac guy is sleeping.

I'll create a v0.4-4 without mac native library but with the newest progress, then delete v0.4-3.

ice1000 commented 6 years ago

A new artifact is available: org.ice1000.jimgui:extension:v0.4-4, which brings you JniLoaderEx.loadGlfw(), which will use glfw on Windows.

ice1000 commented 6 years ago

Done creating v0.4-4, plz try it out

wrymn commented 6 years ago

Will it fix the issue that GLFW is loaded twice? Not sure how GLFW initialization is working, but can it check if it is already initialized in system, or can I reuse it in order to prevent crash from duplicate initialization.

ice1000 commented 6 years ago

@wrymn Yes, with org.ice1000.jimgui.JImGui#fromExistingPointer(long, (optional) org.ice1000.jimgui.JImFontAtlas)

ice1000 commented 6 years ago

Use this factory function, I'll only initialize imgui but not glfw.

wrymn commented 6 years ago

In docs it says

a C++ pointer to {@code GLFWwindow} on Linux/OSX,
{@code NativeObject} (see dx9_impl.cpp) on Windows

Does it mean window context ID (created via glfwCreateWindow())? Or some glfw ID from its initialization?

ice1000 commented 6 years ago

Does it mean window context ID (created via glfwCreateWindow())?

Yes! Yes! Yes!

wrymn commented 6 years ago

I have used GLFW.glfwGetCurrentContext(), pointer ID seemed to be valid (675601680), but sadly I have been met with following error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.ice1000.jimgui.JImVec4.allocateNativeObjects(FFFF)J
    at org.ice1000.jimgui.JImVec4.allocateNativeObjects(Native Method)
    at org.ice1000.jimgui.JImVec4.<init>(JImVec4.java:34)
    at org.ice1000.jimgui.JImGui.<init>(JImGui.java:52)
    at org.ice1000.jimgui.JImGui.fromExistingPointer(JImGui.java:75)

Just for clarification, now I only need to call JImGui.fromExistingPointer() before I can start to render right? Or is System.load() call still necessary?

EDIT: When loading provided .dll first, this error is received instead:

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.ice1000.jimgui.JImGui.setupImbueSpecificObjects(JJ)V
    at org.ice1000.jimgui.JImGui.setupImbueSpecificObjects(Native Method)
    at org.ice1000.jimgui.JImGui.fromExistingPointer(JImGui.java:76)

This is GLFW version our framework printed out: 3.3.0 Win32 WGL EGL VisualC DLL

ice1000 commented 6 years ago

Ok, let me explain the whole correct process:

ice1000 commented 6 years ago

Complete example:

import org.ice1000.jimgui.JImGui;
import org.ice1000.jimgui.JImTextureID;
import org.ice1000.jimgui.util.JniLoaderEx;

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws NoSuchMethodException {
        JniLoaderEx.loadGlfw();
        try (JImGui gui = JImGui.fromExistingPointer(window pointer)) {
            Constructor<JImTextureID> constructor = JImTextureID.class.getConstructor(long.class, int.class, int.class);
            JImTextureID textureID = constructor.newInstance(texture id, width, height);
            while (!gui.windowShouldClose()) {
                gui.initNewFrame();
                gui.image(textureID);
                gui.render();
            }
        }
    }
}
ice1000 commented 6 years ago

Sorry for the non-public constructor, there will be a public factory function in v0.5

wrymn commented 6 years ago
private JImGui gui;

@Override
public void tick() {

    // Our framework initializes and creates new GLFW window before this method runs
    if(gui == null){
        long pointer = GLFW.glfwGetCurrentContext();
        // This outputs valid pointer like 675180544
        Log.message("window poineter: " + pointer);
        JniLoaderEx.loadGlfw();
        // Crash here
        gui = JImGui.fromExistingPointer(pointer);
    }
}

This is code I use. Both jimgui extension and core version are v.4-4

ice1000 commented 6 years ago

Ahhh... I know! The C++ codes in the dll is not up-to-date (stays on the old version).

Let me update it, and will give you a finally working one

wrymn commented 6 years ago

If this will all work I will buy you a car... If you had any idea what consequences this will have if it will work :D

wrymn commented 6 years ago

@ice1000 any news regarding your last message?

ice1000 commented 6 years ago

The Mac guy has uploaded the dylib. Last step: build the newest version. (Many files are affected)

ice1000 commented 6 years ago

@wrymn Done! v0.4-5 -- if it works, this version will become v0.5

wrymn commented 6 years ago

I have changed dependency for core and extension for v0.4-5, but sadly as soon as I call initNewFrame(), it does crash

Here is full crash log: https://pastebin.com/6LRVWSJH

Code I use:

    private JImGui gui;

    @Override
    public void tick() {
        if(gui == null){
            long pointer = GLFW.glfwGetCurrentContext();
            Log.message("window pointer: " + pointer);
            JniLoaderEx.loadGlfw();
            gui = JImGui.fromExistingPointer(pointer);
            // Start to render on second frame
            return;
        }

        //Crash here
        gui.initNewFrame();
        gui.text("Test");
        gui.render();
    }
wrymn commented 6 years ago

I have tried running imgui on separate thread. The imgui loads and does not crash. I can render our game as well as imgui window with text etc.

However, when I create new texture from pointer ID and try to render it, it crashes on gui.render() method.

Again, crash log: https://pastebin.com/hwRAsRpD

ice1000 commented 6 years ago

I think I've figured out why is that happening..

ice1000 commented 6 years ago

Tried fixing this in v0.4-6... Added gl3wInit in fromExistingPointer..

wrymn commented 6 years ago

The imgui no longer crashes when in main thread with our framework on initNewFrame()

But sadly, it still does crash when trying to render texture from pointer, same crash as before (https://pastebin.com/hwRAsRpD)

    private void startImgui() {
        JniLoader.load();
        JImGui gui = new JImGui();
        JImTextureID textureID = JImTextureID.fromExistingID(GLMain.backBufferTextureId, 2048, 1024);
        while (!gui.windowShouldClose()) {
            gui.initNewFrame();
            gui.image(textureID, 500, 500);
            gui.render();
        }
    }

Does it still use GLFW when not forcing it with JniLoaderEx.startGlfw()? Because it seems I cannot using when not giving it existing pointer

ice1000 commented 6 years ago

Could you plz give me a minimum crashing project? It's too hard to do this "remote debug" and the JVM dump message does not actually help..

ice1000 commented 6 years ago

Does it still use GLFW when not forcing it with JniLoaderEx.startGlfw()?

No. Currently you can only use the glfw backend on Windows with JniLoaderEx.loadGlfw()

ice1000 commented 6 years ago

What about this?

    private void startImgui() {
        JniLoaderEx.loadGlfw();
        JImGui gui = new JImGui();
        JImTextureID textureID = JImTextureID.fromExistingID(GLMain.backBufferTextureId, 2048, 1024);
        while (!gui.windowShouldClose()) {
            gui.initNewFrame();
            gui.image(textureID);
            gui.render();
        }
    }