Files
imgui-java/imgui-app/src/main/java/imgui/app/Window.java
T
Marco Lima 34e282e091 [API] Fixed window rendering on resize and white background on start up. (#62)
* Fixed window rendering on resize and white background on start up.

* Code formatting and clean up.

* Fixed attribute modifier.
2021-06-24 11:51:43 +03:00

253 lines
7.3 KiB
Java

package imgui.app;
import imgui.ImGui;
import imgui.flag.ImGuiConfigFlags;
import imgui.gl3.ImGuiImplGl3;
import imgui.glfw.ImGuiImplGlfw;
import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import java.nio.IntBuffer;
import java.util.Objects;
/**
* Low-level abstraction, which creates application window and starts the main loop.
* It's recommended to use {@link Application}, but this class could be extended directly as well.
* When extended, life-cycle methods should be called manually.
*/
public abstract class Window {
private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
private String glslVersion = null;
/**
* Pointer to the native GLFW window.
*/
protected long handle;
/**
* Background color of the window.
*/
protected final Color colorBg = new Color(.5f, .5f, .5f, 1);
/**
* Method to initialize application.
*
* @param config configuration object with basic window information
*/
protected void init(final Configuration config) {
initWindow(config);
initImGui(config);
imGuiGlfw.init(handle, true);
imGuiGl3.init(glslVersion);
}
/**
* Method to dispose all used application resources and destroy its window.
*/
protected void dispose() {
imGuiGl3.dispose();
imGuiGlfw.dispose();
disposeImGui();
disposeWindow();
}
/**
* Method to create and initialize GLFW window.
*
* @param config configuration object with basic window information
*/
protected void initWindow(final Configuration config) {
GLFWErrorCallback.createPrint(System.err).set();
if (!GLFW.glfwInit()) {
throw new IllegalStateException("Unable to initialize GLFW");
}
decideGlGlslVersions();
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
handle = GLFW.glfwCreateWindow(config.getWidth(), config.getHeight(), config.getTitle(), MemoryUtil.NULL, MemoryUtil.NULL);
if (handle == MemoryUtil.NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
try (MemoryStack stack = MemoryStack.stackPush()) {
final IntBuffer pWidth = stack.mallocInt(1); // int*
final IntBuffer pHeight = stack.mallocInt(1); // int*
GLFW.glfwGetWindowSize(handle, pWidth, pHeight);
final GLFWVidMode vidmode = Objects.requireNonNull(GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor()));
GLFW.glfwSetWindowPos(handle, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
}
GLFW.glfwMakeContextCurrent(handle);
GL.createCapabilities();
GLFW.glfwSwapInterval(GLFW.GLFW_TRUE);
if (config.isFullScreen()) {
GLFW.glfwMaximizeWindow(handle);
} else {
GLFW.glfwShowWindow(handle);
}
clearBuffer();
renderBuffer();
GLFW.glfwSetWindowSizeCallback(handle, new GLFWWindowSizeCallback() {
@Override
public void invoke(final long window, final int width, final int height) {
runFrame();
}
});
}
private void decideGlGlslVersions() {
final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
if (isMac) {
glslVersion = "#version 150";
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE); // Required on Mac
} else {
glslVersion = "#version 130";
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
}
}
/**
* Method to initialize Dear ImGui context. Could be overridden to do custom Dear ImGui setup before application start.
*
* @param config configuration object with basic window information
*/
protected void initImGui(final Configuration config) {
ImGui.createContext();
}
/**
* Method called every frame, before calling {@link #process()} method.
*/
protected void preProcess() {
}
/**
* Method called every frame, after calling {@link #process()} method.
*/
protected void postProcess() {
}
/**
* Main application loop.
*/
protected void run() {
while (!GLFW.glfwWindowShouldClose(handle)) {
runFrame();
}
}
/**
* Method used to run the next frame.
*/
protected void runFrame() {
startFrame();
preProcess();
process();
postProcess();
endFrame();
}
/**
* Method to be overridden by user to provide main application logic.
*/
public abstract void process();
/**
* Method used to clear the OpenGL buffer.
*/
private void clearBuffer() {
GL32.glClearColor(colorBg.getRed(), colorBg.getGreen(), colorBg.getBlue(), colorBg.getAlpha());
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
/**
* Method called at the beginning of the main cycle.
* It clears OpenGL buffer and starts an ImGui frame.
*/
protected void startFrame() {
clearBuffer();
imGuiGlfw.newFrame();
ImGui.newFrame();
}
/**
* Method called in the end of the main cycle.
* It renders ImGui and swaps GLFW buffers to show an updated frame.
*/
protected void endFrame() {
ImGui.render();
imGuiGl3.renderDrawData(ImGui.getDrawData());
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
ImGui.updatePlatformWindows();
ImGui.renderPlatformWindowsDefault();
GLFW.glfwMakeContextCurrent(backupWindowPtr);
}
renderBuffer();
}
/**
* Method to render the OpenGL buffer and poll window events.
*/
private void renderBuffer() {
GLFW.glfwSwapBuffers(handle);
GLFW.glfwPollEvents();
}
/**
* Method to destroy Dear ImGui context.
*/
protected void disposeImGui() {
ImGui.destroyContext();
}
/**
* Method to destroy GLFW window.
*/
protected void disposeWindow() {
Callbacks.glfwFreeCallbacks(handle);
GLFW.glfwDestroyWindow(handle);
GLFW.glfwTerminate();
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
}
/**
* @return pointer to the native GLFW window
*/
public final long getHandle() {
return handle;
}
/**
* @return {@link Color} instance, which represents background color for the window
*/
public final Color getColorBg() {
return colorBg;
}
}