[API] Add imgui-app and example modules
This commit is contained in:
1 parent
0ed291cb0f
commit
46f74381aa
8 files changed
+408
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
plugins {
|
||||||
|
id 'application'
|
||||||
|
id 'checkstyle'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':imgui-app')
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import imgui.ImGui;
|
||||||
|
import imgui.ImGuiIO;
|
||||||
|
import imgui.app.Application;
|
||||||
|
import imgui.app.Configuration;
|
||||||
|
import imgui.flag.ImGuiConfigFlags;
|
||||||
|
|
||||||
|
public final class Main extends Application {
|
||||||
|
@Override
|
||||||
|
protected void configure(final Configuration config) {
|
||||||
|
config.setTitle("Example Application");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initImGui(final Configuration config) {
|
||||||
|
super.initImGui(config);
|
||||||
|
|
||||||
|
final ImGuiIO io = ImGui.getIO();
|
||||||
|
io.setIniFilename(null); // We don't want to save .ini file
|
||||||
|
io.addConfigFlags(ImGuiConfigFlags.NavEnableKeyboard); // Enable Keyboard Controls
|
||||||
|
io.addConfigFlags(ImGuiConfigFlags.DockingEnable); // Enable Docking
|
||||||
|
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable); // Enable Multi-Viewport / Platform Windows
|
||||||
|
io.setConfigViewportsNoTaskBarIcon(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process() {
|
||||||
|
ImGui.text("Hello, World");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
launch(new Main());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
id 'io.freefair.lombok' version '5.3.0'
|
||||||
|
id 'checkstyle'
|
||||||
|
id 'com.jfrog.bintray' version '1.8.4'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api platform('org.lwjgl:lwjgl-bom:3.2.3')
|
||||||
|
|
||||||
|
api 'org.lwjgl:lwjgl'
|
||||||
|
api 'org.lwjgl:lwjgl-glfw'
|
||||||
|
api 'org.lwjgl:lwjgl-opengl'
|
||||||
|
|
||||||
|
['natives-linux', 'natives-windows', 'natives-macos'].each {
|
||||||
|
runtime "org.lwjgl:lwjgl::$it"
|
||||||
|
runtime "org.lwjgl:lwjgl-glfw::$it"
|
||||||
|
runtime "org.lwjgl:lwjgl-opengl::$it"
|
||||||
|
}
|
||||||
|
|
||||||
|
api project(':imgui-binding')
|
||||||
|
api project(':imgui-lwjgl3')
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from('../bin') {
|
||||||
|
include 'imgui-java64.dll'
|
||||||
|
include 'libimgui-java64.so'
|
||||||
|
include 'libimgui-java64.dylib'
|
||||||
|
into 'io/imgui/java/native-bin/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||||
|
archiveClassifier.set('sources')
|
||||||
|
from sourceSets.main.allSource
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
MyPublication(MavenPublication) {
|
||||||
|
from components.java
|
||||||
|
groupId 'io.imgui.java'
|
||||||
|
artifactId 'imgui-java-app'
|
||||||
|
artifact sourcesJar
|
||||||
|
version property('version')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bintray {
|
||||||
|
user = System.getenv('BINTRAY_USER')
|
||||||
|
key = System.getenv('BINTRAY_API_KEY')
|
||||||
|
publications = ['MyPublication']
|
||||||
|
pkg {
|
||||||
|
repo = 'io.imgui.java'
|
||||||
|
name = 'imgui-java-app'
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# This file is generated by the 'io.freefair.lombok' Gradle plugin
|
||||||
|
config.stopBubbling = true
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package imgui.app;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application class from which ImGui applications extend.
|
||||||
|
* Serves as an abstraction layer to hide all low-level details about window creation and rendering routine.
|
||||||
|
*
|
||||||
|
* <p><h3>Life-cycle</h3>
|
||||||
|
* The entry point for ImGui applications is the Application class and {@link #launch(Application)} method.
|
||||||
|
* It initializes application instance and starts the main application loop.
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li>{@link #configure(Configuration)} It's called before window creation, so only basic application setups are expected.</li>
|
||||||
|
* <li>{@link #initWindow(Configuration)} Method creates application window.</li>
|
||||||
|
* <li>{@link #initImGui(Configuration)} Method initializes Dear ImGui context. Could be used to do Dear ImGui setup as well.</li>
|
||||||
|
* <li>{@link #process()} Method is meant to be overridden with user application logic.</li>
|
||||||
|
* <li>{@link #disposeImGui()} Destroys Dear ImGui context.</li>
|
||||||
|
* <li>{@link #disposeWindow()} Destroys application window.</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>As it could be seen, ImGui application differs from the classic one in the way of its life-cycle flow.
|
||||||
|
* Instead of creating widgets and adding listeners to them we have an application loop where everything is handled right away.
|
||||||
|
* Read more about Immediate GUI mode to understand that paradigm better.
|
||||||
|
*
|
||||||
|
* <p><h3>Example</h3>
|
||||||
|
* The simplest application example could be done in the next way:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* import imgui.ImGui;
|
||||||
|
* import imgui.app.Application;
|
||||||
|
* import imgui.app.Configuration;
|
||||||
|
*
|
||||||
|
* public class Main extends Application {
|
||||||
|
* @Override
|
||||||
|
* protected void configure(final Configuration config) {
|
||||||
|
* config.setTitle("Example Application");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @Override
|
||||||
|
* public void process() {
|
||||||
|
* ImGui.text("Hello, World");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public static void main(final String[] args) {
|
||||||
|
* launch(new Main());
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>As its said, {@link #process()} method is meant to be overridden. All your application logic should go there.
|
||||||
|
*
|
||||||
|
* <p><h3>Threading</h3>
|
||||||
|
* Unlike other Java applications, ImGui is about "one thread for everything". You still can use multi-threading, but be careful.
|
||||||
|
* For example, large list of computations could be separated between application ticks. {@link #process()} method is called constantly.
|
||||||
|
* Use that wisely and remember that all GUI should be in the main thread.
|
||||||
|
*/
|
||||||
|
public abstract class Application extends Window {
|
||||||
|
/**
|
||||||
|
* Method is called before window creation. Could be used to provide basic window information, like title name etc.
|
||||||
|
*
|
||||||
|
* @param config configuration object with basic window information
|
||||||
|
*/
|
||||||
|
protected void configure(final Configuration config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point of any ImGui application. Use it to start the application loop.
|
||||||
|
*
|
||||||
|
* @param app application instance to run
|
||||||
|
*/
|
||||||
|
public static void launch(final Application app) {
|
||||||
|
initialize(app);
|
||||||
|
app.run();
|
||||||
|
app.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initialize(final Application app) {
|
||||||
|
final Configuration config = new Configuration();
|
||||||
|
app.configure(config);
|
||||||
|
app.init(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package imgui.app;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class to provide basic information about the window. Like, the title name etc.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public final class Configuration {
|
||||||
|
/**
|
||||||
|
* Application title.
|
||||||
|
*/
|
||||||
|
private String title = "ImGui Java Application";
|
||||||
|
/**
|
||||||
|
* Application window width.
|
||||||
|
*/
|
||||||
|
private int width = 1280;
|
||||||
|
/**
|
||||||
|
* Application window height.
|
||||||
|
*/
|
||||||
|
private int height = 768;
|
||||||
|
/**
|
||||||
|
* When true, application will be maximized by default.
|
||||||
|
*/
|
||||||
|
private boolean fullScreen = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
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.opengl.GL;
|
||||||
|
import org.lwjgl.opengl.GL32;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
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.
|
||||||
|
* Take a note, that in this case you need to call all application loop methods ({@link #init(Configuration)}, {@link #run()}, {@link #dispose()}) manually.
|
||||||
|
*/
|
||||||
|
public abstract class Window {
|
||||||
|
private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
|
||||||
|
private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
|
||||||
|
|
||||||
|
private String glslVersion = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to native GLFW window.
|
||||||
|
*/
|
||||||
|
protected long handle;
|
||||||
|
/**
|
||||||
|
* Background color of the window.
|
||||||
|
*/
|
||||||
|
protected Color colorBg = Color.GRAY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to initialize application.
|
||||||
|
*
|
||||||
|
* @param config configuration object with basic window information
|
||||||
|
*/
|
||||||
|
protected final 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 final 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);
|
||||||
|
GLFW.glfwSwapInterval(GLFW.GLFW_TRUE);
|
||||||
|
GLFW.glfwShowWindow(handle);
|
||||||
|
|
||||||
|
if (config.isFullScreen()) {
|
||||||
|
GLFW.glfwMaximizeWindow(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.createCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main application loop.
|
||||||
|
*/
|
||||||
|
protected final void run() {
|
||||||
|
while (!GLFW.glfwWindowShouldClose(handle)) {
|
||||||
|
startFrame();
|
||||||
|
process();
|
||||||
|
endFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to be overridden by user to provide main application logic.
|
||||||
|
*/
|
||||||
|
public abstract void process();
|
||||||
|
|
||||||
|
private void startFrame() {
|
||||||
|
if (colorBg != null) {
|
||||||
|
GL32.glClearColor(colorBg.getRed() / 255f, colorBg.getGreen() / 255f, colorBg.getBlue() / 255f, colorBg.getAlpha() / 255f);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
|
imGuiGlfw.newFrame();
|
||||||
|
ImGui.newFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,6 @@ rootProject.name = 'imgui-java'
|
|||||||
include 'imgui-binding'
|
include 'imgui-binding'
|
||||||
include 'imgui-lwjgl3'
|
include 'imgui-lwjgl3'
|
||||||
include 'imgui-binding-natives'
|
include 'imgui-binding-natives'
|
||||||
|
include 'imgui-app'
|
||||||
|
include 'example'
|
||||||
|
|
||||||
Reference in new issue
Block a user