[Example] Migrate example to the new module
This commit is contained in:
1 parent
46f74381aa
commit
cf9e74b1d0
17 files changed
+489
-822
No files matched your search
+14
-1
@@ -1,12 +1,25 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'application'
|
id 'application'
|
||||||
id 'checkstyle'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
mainClass = 'Main'
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':imgui-app')
|
implementation project(':imgui-app')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task start(type: JavaExec, dependsOn: build) {
|
||||||
|
main = 'Main'
|
||||||
|
classpath = sourceSets.test.runtimeClasspath
|
||||||
|
jvmArgs = ["-Dimgui.library.path=${System.getProperty('libPath', '../bin')}"]
|
||||||
|
|
||||||
|
if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) {
|
||||||
|
jvmArgs += ['-XstartOnFirstThread', '-Djava.awt.headless=true']
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import imgui.extension.nodeditor.NodeEditor;
|
||||||
|
import imgui.extension.nodeditor.NodeEditorConfig;
|
||||||
|
import imgui.extension.nodeditor.NodeEditorContext;
|
||||||
|
import imgui.extension.nodeditor.flag.NodeEditorPinKind;
|
||||||
|
import imgui.flag.ImGuiCond;
|
||||||
|
import imgui.internal.ImGui;
|
||||||
|
import imgui.type.ImBoolean;
|
||||||
|
import imgui.type.ImLong;
|
||||||
|
|
||||||
|
import java.awt.Desktop;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public class ExampleImGuiNodeEditor {
|
||||||
|
private static final NodeEditorContext CONTEXT;
|
||||||
|
private static final String URL = "https://github.com/thedmd/imgui-node-editor/tree/687a72f940";
|
||||||
|
|
||||||
|
static {
|
||||||
|
NodeEditorConfig config = new NodeEditorConfig();
|
||||||
|
config.setSettingsFile(null);
|
||||||
|
CONTEXT = new NodeEditorContext(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void show(final ImBoolean showImNodeEditorWindow, final Graph graph) {
|
||||||
|
ImGui.setNextWindowSize(500, 400, ImGuiCond.Once);
|
||||||
|
ImGui.setNextWindowPos(ImGui.getMainViewport().getPosX() + 100, ImGui.getMainViewport().getPosY() + 200, ImGuiCond.Once);
|
||||||
|
if (ImGui.begin("imgui-node-editor Demo", showImNodeEditorWindow)) {
|
||||||
|
ImGui.text("This a demo graph editor for imgui-node-editor");
|
||||||
|
|
||||||
|
ImGui.alignTextToFramePadding();
|
||||||
|
ImGui.text("Repo:");
|
||||||
|
ImGui.sameLine();
|
||||||
|
if (ImGui.button(URL)) {
|
||||||
|
try {
|
||||||
|
Desktop.getDesktop().browse(new URI(URL));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.button("Navigate to content")) {
|
||||||
|
NodeEditor.navigateToContent(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEditor.setCurrentEditor(CONTEXT);
|
||||||
|
NodeEditor.begin("Node Editor");
|
||||||
|
|
||||||
|
for (Graph.GraphNode node : graph.nodes.values()) {
|
||||||
|
NodeEditor.beginNode(node.nodeId);
|
||||||
|
|
||||||
|
ImGui.text(node.getName());
|
||||||
|
|
||||||
|
NodeEditor.beginPin(node.getInputPinId(), NodeEditorPinKind.Input);
|
||||||
|
ImGui.text("-> In");
|
||||||
|
NodeEditor.endPin();
|
||||||
|
|
||||||
|
ImGui.sameLine();
|
||||||
|
|
||||||
|
NodeEditor.beginPin(node.getOutputPinId(), NodeEditorPinKind.Output);
|
||||||
|
ImGui.text("Out ->");
|
||||||
|
NodeEditor.endPin();
|
||||||
|
|
||||||
|
NodeEditor.endNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NodeEditor.beginCreate()) {
|
||||||
|
final ImLong a = new ImLong();
|
||||||
|
final ImLong b = new ImLong();
|
||||||
|
if (NodeEditor.queryNewLink(a, b)) {
|
||||||
|
final Graph.GraphNode source = graph.findByOutput(a.get());
|
||||||
|
final Graph.GraphNode target = graph.findByInput(b.get());
|
||||||
|
if (source != null && target != null && source.outputNodeId != target.nodeId && NodeEditor.acceptNewItem()) {
|
||||||
|
source.outputNodeId = target.nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeEditor.endCreate();
|
||||||
|
|
||||||
|
int uniqueLinkId = 1;
|
||||||
|
for (Graph.GraphNode node : graph.nodes.values()) {
|
||||||
|
if (graph.nodes.containsKey(node.outputNodeId)) {
|
||||||
|
NodeEditor.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEditor.suspend();
|
||||||
|
|
||||||
|
final long nodeWithContextMenu = NodeEditor.getNodeWithContextMenu();
|
||||||
|
if (nodeWithContextMenu != -1) {
|
||||||
|
ImGui.openPopup("node_context");
|
||||||
|
ImGui.getStateStorage().setInt(ImGui.getID("delete_node_id"), (int) nodeWithContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.isPopupOpen("node_context")) {
|
||||||
|
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete_node_id"));
|
||||||
|
if (ImGui.beginPopup("node_context")) {
|
||||||
|
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
|
||||||
|
graph.nodes.remove(targetNode);
|
||||||
|
ImGui.closeCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui.endPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NodeEditor.showBackgroundContextMenu()) {
|
||||||
|
ImGui.openPopup("node_editor_context");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.beginPopup("node_editor_context")) {
|
||||||
|
if (ImGui.button("Create New Node")) {
|
||||||
|
final Graph.GraphNode node = graph.createGraphNode();
|
||||||
|
final float canvasX = NodeEditor.toCanvasX(ImGui.getMousePosX());
|
||||||
|
final float canvasY = NodeEditor.toCanvasY(ImGui.getMousePosY());
|
||||||
|
NodeEditor.setNodePosition(node.nodeId, canvasX, canvasY);
|
||||||
|
ImGui.closeCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui.endPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEditor.resume();
|
||||||
|
NodeEditor.end();
|
||||||
|
}
|
||||||
|
ImGui.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import imgui.extension.imnodes.ImNodes;
|
||||||
|
import imgui.extension.imnodes.ImNodesContext;
|
||||||
|
import imgui.extension.imnodes.flag.ImNodesPinShape;
|
||||||
|
import imgui.flag.ImGuiCond;
|
||||||
|
import imgui.flag.ImGuiMouseButton;
|
||||||
|
import imgui.internal.ImGui;
|
||||||
|
import imgui.type.ImBoolean;
|
||||||
|
import imgui.type.ImInt;
|
||||||
|
|
||||||
|
import java.awt.Desktop;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public class ExampleImNodes {
|
||||||
|
private static final ImNodesContext CONTEXT = new ImNodesContext();
|
||||||
|
private static final String URL = "https://github.com/Nelarius/imnodes/tree/5959729410";
|
||||||
|
|
||||||
|
private static final ImInt LINK_A = new ImInt();
|
||||||
|
private static final ImInt LINK_B = new ImInt();
|
||||||
|
|
||||||
|
public static void show(final ImBoolean showImNodesWindow, final Graph graph) {
|
||||||
|
ImGui.setNextWindowSize(500, 400, ImGuiCond.Once);
|
||||||
|
ImGui.setNextWindowPos(ImGui.getMainViewport().getPosX() + 100, ImGui.getMainViewport().getPosY() + 100, ImGuiCond.Once);
|
||||||
|
if (ImGui.begin("ImNodes Demo", showImNodesWindow)) {
|
||||||
|
ImGui.text("This a demo graph editor for ImNodes");
|
||||||
|
|
||||||
|
ImGui.alignTextToFramePadding();
|
||||||
|
ImGui.text("Repo:");
|
||||||
|
ImGui.sameLine();
|
||||||
|
if (ImGui.button(URL)) {
|
||||||
|
try {
|
||||||
|
Desktop.getDesktop().browse(new URI(URL));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImNodes.editorContextSet(CONTEXT);
|
||||||
|
ImNodes.beginNodeEditor();
|
||||||
|
|
||||||
|
for (Graph.GraphNode node : graph.nodes.values()) {
|
||||||
|
ImNodes.beginNode(node.nodeId);
|
||||||
|
|
||||||
|
ImNodes.beginNodeTitleBar();
|
||||||
|
ImGui.text(node.getName());
|
||||||
|
ImNodes.endNodeTitleBar();
|
||||||
|
|
||||||
|
ImNodes.beginInputAttribute(node.getInputPinId(), ImNodesPinShape.CircleFilled);
|
||||||
|
ImGui.text("In");
|
||||||
|
ImNodes.endInputAttribute();
|
||||||
|
|
||||||
|
ImGui.sameLine();
|
||||||
|
|
||||||
|
ImNodes.beginOutputAttribute(node.getOutputPinId());
|
||||||
|
ImGui.text("Out");
|
||||||
|
ImNodes.endOutputAttribute();
|
||||||
|
|
||||||
|
ImNodes.endNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
int uniqueLinkId = 1;
|
||||||
|
for (Graph.GraphNode node : graph.nodes.values()) {
|
||||||
|
if (graph.nodes.containsKey(node.outputNodeId)) {
|
||||||
|
ImNodes.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean isEditorHovered = ImNodes.isEditorHovered();
|
||||||
|
|
||||||
|
ImNodes.endNodeEditor();
|
||||||
|
|
||||||
|
if (ImNodes.isLinkCreated(LINK_A, LINK_B)) {
|
||||||
|
final Graph.GraphNode source = graph.findByOutput(LINK_A.get());
|
||||||
|
final Graph.GraphNode target = graph.findByInput(LINK_B.get());
|
||||||
|
if (source != null && target != null && source.outputNodeId != target.nodeId) {
|
||||||
|
source.outputNodeId = target.nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.isMouseClicked(ImGuiMouseButton.Right)) {
|
||||||
|
final int hoveredNode = ImNodes.getHoveredNode();
|
||||||
|
if (hoveredNode != -1) {
|
||||||
|
ImGui.openPopup("node_context");
|
||||||
|
ImGui.getStateStorage().setInt(ImGui.getID("delete_node_id"), hoveredNode);
|
||||||
|
} else if (isEditorHovered) {
|
||||||
|
ImGui.openPopup("node_editor_context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.isPopupOpen("node_context")) {
|
||||||
|
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete_node_id"));
|
||||||
|
if (ImGui.beginPopup("node_context")) {
|
||||||
|
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
|
||||||
|
graph.nodes.remove(targetNode);
|
||||||
|
ImGui.closeCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui.endPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.beginPopup("node_editor_context")) {
|
||||||
|
if (ImGui.button("Create New Node")) {
|
||||||
|
final Graph.GraphNode node = graph.createGraphNode();
|
||||||
|
ImNodes.setNodeScreenSpacePos(node.nodeId, ImGui.getMousePosX(), ImGui.getMousePosY());
|
||||||
|
ImGui.closeCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui.endPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import imgui.ImGui;
|
||||||
|
import imgui.app.Application;
|
||||||
|
import imgui.type.ImBoolean;
|
||||||
|
|
||||||
|
public class Extra {
|
||||||
|
private static final ImBoolean SHOW_DEMO_WINDOW = new ImBoolean(false);
|
||||||
|
private static final ImBoolean SHOW_IMNODES_DEMO_WINDOW = new ImBoolean(false);
|
||||||
|
private static final ImBoolean SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW = new ImBoolean(false);
|
||||||
|
|
||||||
|
private static final Graph GRAPH = new Graph();
|
||||||
|
|
||||||
|
public static void show(final Application app) {
|
||||||
|
ImGui.colorEdit3("Background Color", app.getColorBg().getData());
|
||||||
|
ImGui.checkbox("Show Demo Window", SHOW_DEMO_WINDOW);
|
||||||
|
ImGui.checkbox("Show ImNodes Demo Window", SHOW_IMNODES_DEMO_WINDOW);
|
||||||
|
ImGui.checkbox("Show imgui-node-editor Demo Window", SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW);
|
||||||
|
|
||||||
|
if (SHOW_DEMO_WINDOW.get()) {
|
||||||
|
ImGui.showDemoWindow(SHOW_DEMO_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHOW_IMNODES_DEMO_WINDOW.get()) {
|
||||||
|
ExampleImNodes.show(SHOW_IMNODES_DEMO_WINDOW, GRAPH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW.get()) {
|
||||||
|
ExampleImGuiNodeEditor.show(SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW, GRAPH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class Graph {
|
||||||
|
public int nextNodeId = 1;
|
||||||
|
public int nextPinId = 100;
|
||||||
|
|
||||||
|
public final Map<Integer, GraphNode> nodes = new HashMap<>();
|
||||||
|
|
||||||
|
public Graph() {
|
||||||
|
final GraphNode first = createGraphNode();
|
||||||
|
final GraphNode second = createGraphNode();
|
||||||
|
first.outputNodeId = second.nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode createGraphNode() {
|
||||||
|
final GraphNode node = new GraphNode(nextNodeId++, nextPinId++, nextPinId++);
|
||||||
|
this.nodes.put(node.nodeId, node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode findByInput(final long inputPinId) {
|
||||||
|
for (GraphNode node : nodes.values()) {
|
||||||
|
if (node.getInputPinId() == inputPinId) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode findByOutput(final long outputPinId) {
|
||||||
|
for (GraphNode node : nodes.values()) {
|
||||||
|
if (node.getOutputPinId() == outputPinId) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class GraphNode {
|
||||||
|
public final int nodeId;
|
||||||
|
public final int inputPinId;
|
||||||
|
public final int outputPinId;
|
||||||
|
|
||||||
|
public int outputNodeId = -1;
|
||||||
|
|
||||||
|
public GraphNode(final int nodeId, final int inputPinId, final int outputPintId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
this.inputPinId = inputPinId;
|
||||||
|
this.outputPinId = outputPintId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInputPinId() {
|
||||||
|
return inputPinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOutputPinId() {
|
||||||
|
return outputPinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return "Node " + (char) (64 + nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,16 @@ import imgui.ImGui;
|
|||||||
import imgui.ImGuiIO;
|
import imgui.ImGuiIO;
|
||||||
import imgui.app.Application;
|
import imgui.app.Application;
|
||||||
import imgui.app.Configuration;
|
import imgui.app.Configuration;
|
||||||
|
import imgui.extension.imnodes.ImNodes;
|
||||||
import imgui.flag.ImGuiConfigFlags;
|
import imgui.flag.ImGuiConfigFlags;
|
||||||
|
import imgui.flag.ImGuiInputTextFlags;
|
||||||
|
import imgui.type.ImString;
|
||||||
|
|
||||||
|
public class Main extends Application {
|
||||||
|
private final ImString str = new ImString(5);
|
||||||
|
private final float[] flt = new float[1];
|
||||||
|
private int count = 0;
|
||||||
|
|
||||||
public final class Main extends Application {
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(final Configuration config) {
|
protected void configure(final Configuration config) {
|
||||||
config.setTitle("Example Application");
|
config.setTitle("Example Application");
|
||||||
@@ -20,11 +27,29 @@ public final class Main extends Application {
|
|||||||
io.addConfigFlags(ImGuiConfigFlags.DockingEnable); // Enable Docking
|
io.addConfigFlags(ImGuiConfigFlags.DockingEnable); // Enable Docking
|
||||||
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable); // Enable Multi-Viewport / Platform Windows
|
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable); // Enable Multi-Viewport / Platform Windows
|
||||||
io.setConfigViewportsNoTaskBarIcon(true);
|
io.setConfigViewportsNoTaskBarIcon(true);
|
||||||
|
|
||||||
|
ImNodes.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void disposeImGui() {
|
||||||
|
ImNodes.shutdown();
|
||||||
|
super.disposeImGui();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process() {
|
public void process() {
|
||||||
ImGui.text("Hello, World");
|
ImGui.text("Hello, World!");
|
||||||
|
if (ImGui.button("Save")) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
ImGui.sameLine();
|
||||||
|
ImGui.text(String.valueOf(count));
|
||||||
|
ImGui.inputText("string", str, ImGuiInputTextFlags.CallbackResize);
|
||||||
|
ImGui.sliderFloat("float", flt, 0, 1);
|
||||||
|
ImGui.separator();
|
||||||
|
ImGui.text("Extra");
|
||||||
|
Extra.show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) {
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ package imgui.app;
|
|||||||
* <li>{@link #configure(Configuration)} It's called before window creation, so only basic application setups are expected.</li>
|
* <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 #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 #initImGui(Configuration)} Method initializes Dear ImGui context. Could be used to do Dear ImGui setup as well.</li>
|
||||||
|
* <li>{@link #preRun()} Method called once, before application loop.</li>
|
||||||
|
* <li>{@link #preProcess()} Method called every frame, before {@link #process()}.</li>
|
||||||
* <li>{@link #process()} Method is meant to be overridden with user application logic.</li>
|
* <li>{@link #process()} Method is meant to be overridden with user application logic.</li>
|
||||||
|
* <li>{@link #postProcess()} Method called every frame, after {@link #process()}.</li>
|
||||||
|
* <li>{@link #postRun()} Method called once, after application loop.</li>
|
||||||
* <li>{@link #disposeImGui()} Destroys Dear ImGui context.</li>
|
* <li>{@link #disposeImGui()} Destroys Dear ImGui context.</li>
|
||||||
* <li>{@link #disposeWindow()} Destroys application window.</li>
|
* <li>{@link #disposeWindow()} Destroys application window.</li>
|
||||||
* </ol>
|
* </ol>
|
||||||
@@ -27,17 +31,11 @@ package imgui.app;
|
|||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* import imgui.ImGui;
|
* import imgui.ImGui;
|
||||||
* import imgui.app.Application;
|
* import imgui.app.Application;
|
||||||
* import imgui.app.Configuration;
|
|
||||||
*
|
*
|
||||||
* public class Main extends Application {
|
* public class Main extends Application {
|
||||||
* @Override
|
* @Override
|
||||||
* protected void configure(final Configuration config) {
|
|
||||||
* config.setTitle("Example Application");
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* public void process() {
|
* public void process() {
|
||||||
* ImGui.text("Hello, World");
|
* ImGui.text("Hello, World!");
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* public static void main(final String[] args) {
|
* public static void main(final String[] args) {
|
||||||
@@ -55,13 +53,25 @@ package imgui.app;
|
|||||||
*/
|
*/
|
||||||
public abstract class Application extends Window {
|
public abstract class Application extends Window {
|
||||||
/**
|
/**
|
||||||
* Method is called before window creation. Could be used to provide basic window information, like title name etc.
|
* Method called before window creation. Could be used to provide basic window information, like title name etc.
|
||||||
*
|
*
|
||||||
* @param config configuration object with basic window information
|
* @param config configuration object with basic window information
|
||||||
*/
|
*/
|
||||||
protected void configure(final Configuration config) {
|
protected void configure(final Configuration config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called once, before application run loop.
|
||||||
|
*/
|
||||||
|
protected void preRun() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called once, after application run loop.
|
||||||
|
*/
|
||||||
|
protected void postRun() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point of any ImGui application. Use it to start the application loop.
|
* Entry point of any ImGui application. Use it to start the application loop.
|
||||||
*
|
*
|
||||||
@@ -69,7 +79,9 @@ public abstract class Application extends Window {
|
|||||||
*/
|
*/
|
||||||
public static void launch(final Application app) {
|
public static void launch(final Application app) {
|
||||||
initialize(app);
|
initialize(app);
|
||||||
|
app.preRun();
|
||||||
app.run();
|
app.run();
|
||||||
|
app.postRun();
|
||||||
app.dispose();
|
app.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package imgui.app;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object for color data.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Color implements Cloneable {
|
||||||
|
private final float[] data = new float[4];
|
||||||
|
|
||||||
|
public Color(final float[] color) {
|
||||||
|
set(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color(final float red, final float green, final float blue, final float alpha) {
|
||||||
|
data[0] = red;
|
||||||
|
data[1] = green;
|
||||||
|
data[2] = blue;
|
||||||
|
data[3] = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void set(final float red, final float green, final float blue, final float alpha) {
|
||||||
|
data[0] = red;
|
||||||
|
data[1] = green;
|
||||||
|
data[2] = blue;
|
||||||
|
data[3] = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void set(final float[] color) {
|
||||||
|
System.arraycopy(color, 0, data, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getRed() {
|
||||||
|
return data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getGreen() {
|
||||||
|
return data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getBlue() {
|
||||||
|
return data[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getAlpha() {
|
||||||
|
return data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to clone Color instance.
|
||||||
|
*
|
||||||
|
* @return cloned Color instance
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||||
|
public Color clone() {
|
||||||
|
return new Color(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import lombok.Data;
|
|||||||
* Data class to provide basic information about the window. Like, the title name etc.
|
* Data class to provide basic information about the window. Like, the title name etc.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public final class Configuration {
|
public class Configuration {
|
||||||
/**
|
/**
|
||||||
* Application title.
|
* Application title.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.lwjgl.opengl.GL32;
|
|||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -29,13 +28,14 @@ public abstract class Window {
|
|||||||
private String glslVersion = null;
|
private String glslVersion = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to native GLFW window.
|
* Pointer to the native GLFW window.
|
||||||
*/
|
*/
|
||||||
protected long handle;
|
protected long handle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Background color of the window.
|
* Background color of the window.
|
||||||
*/
|
*/
|
||||||
protected Color colorBg = Color.GRAY;
|
protected final Color colorBg = new Color(.5f, .5f, .5f, 1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to initialize application.
|
* Method to initialize application.
|
||||||
@@ -126,13 +126,27 @@ public abstract class Window {
|
|||||||
ImGui.createContext();
|
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.
|
* Main application loop.
|
||||||
*/
|
*/
|
||||||
protected final void run() {
|
protected final void run() {
|
||||||
while (!GLFW.glfwWindowShouldClose(handle)) {
|
while (!GLFW.glfwWindowShouldClose(handle)) {
|
||||||
startFrame();
|
startFrame();
|
||||||
|
preProcess();
|
||||||
process();
|
process();
|
||||||
|
postProcess();
|
||||||
endFrame();
|
endFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,10 +157,7 @@ public abstract class Window {
|
|||||||
public abstract void process();
|
public abstract void process();
|
||||||
|
|
||||||
private void startFrame() {
|
private void startFrame() {
|
||||||
if (colorBg != null) {
|
GL32.glClearColor(colorBg.getRed(), colorBg.getGreen(), colorBg.getBlue(), colorBg.getAlpha());
|
||||||
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);
|
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
|
||||||
imGuiGlfw.newFrame();
|
imGuiGlfw.newFrame();
|
||||||
ImGui.newFrame();
|
ImGui.newFrame();
|
||||||
@@ -183,4 +194,18 @@ public abstract class Window {
|
|||||||
GLFW.glfwTerminate();
|
GLFW.glfwTerminate();
|
||||||
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,10 +45,10 @@ public class ImGui {
|
|||||||
|
|
||||||
final String extractedLibAbsPath = tryLoadFromClasspath(fullLibName);
|
final String extractedLibAbsPath = tryLoadFromClasspath(fullLibName);
|
||||||
|
|
||||||
if (extractedLibAbsPath != null) {
|
if (libPath != null) {
|
||||||
System.load(extractedLibAbsPath);
|
|
||||||
} else if (libPath != null) {
|
|
||||||
System.load(Paths.get(libPath).resolve(fullLibName).toFile().getAbsolutePath());
|
System.load(Paths.get(libPath).resolve(fullLibName).toFile().getAbsolutePath());
|
||||||
|
} else if (extractedLibAbsPath != null) {
|
||||||
|
System.load(extractedLibAbsPath);
|
||||||
} else {
|
} else {
|
||||||
System.loadLibrary(libName);
|
System.loadLibrary(libName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,512 +0,0 @@
|
|||||||
import imgui.ImGuiViewport;
|
|
||||||
import imgui.flag.ImGuiColorEditFlags;
|
|
||||||
import imgui.flag.ImGuiCond;
|
|
||||||
import imgui.flag.ImGuiDir;
|
|
||||||
import imgui.flag.ImGuiInputTextFlags;
|
|
||||||
import imgui.flag.ImGuiStyleVar;
|
|
||||||
import imgui.flag.ImGuiWindowFlags;
|
|
||||||
import imgui.extension.imnodes.ImNodes;
|
|
||||||
import imgui.extension.imnodes.ImNodesContext;
|
|
||||||
import imgui.extension.imnodes.flag.ImNodesPinShape;
|
|
||||||
import imgui.extension.nodeditor.NodeEditor;
|
|
||||||
import imgui.internal.ImGui;
|
|
||||||
import imgui.internal.flag.ImGuiDockNodeFlags;
|
|
||||||
import imgui.extension.nodeditor.NodeEditorConfig;
|
|
||||||
import imgui.extension.nodeditor.NodeEditorContext;
|
|
||||||
import imgui.extension.nodeditor.flag.NodeEditorPinKind;
|
|
||||||
import imgui.type.ImBoolean;
|
|
||||||
import imgui.ImColor;
|
|
||||||
import imgui.type.ImInt;
|
|
||||||
import imgui.type.ImLong;
|
|
||||||
import imgui.type.ImString;
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_CLAMP_TO_EDGE;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_LINEAR;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_RGBA;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_RGBA8;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TEXTURE_2D;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TEXTURE_MAG_FILTER;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TEXTURE_MIN_FILTER;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TEXTURE_WRAP_S;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TEXTURE_WRAP_T;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_UNSIGNED_BYTE;
|
|
||||||
import static org.lwjgl.opengl.GL32.glBindTexture;
|
|
||||||
import static org.lwjgl.opengl.GL32.glGenTextures;
|
|
||||||
import static org.lwjgl.opengl.GL32.glTexImage2D;
|
|
||||||
import static org.lwjgl.opengl.GL32.glTexParameteri;
|
|
||||||
|
|
||||||
@SuppressWarnings({"MagicNumber", "VisibilityModifier"})
|
|
||||||
final class ExampleUi {
|
|
||||||
private static final String IMGUI_DEMO_LINK = "https://raw.githubusercontent.com/ocornut/imgui/05bc204/imgui_demo.cpp";
|
|
||||||
|
|
||||||
private static final int COLOR_DODGERBLUE = ImColor.rgbToColor("#1E90FF");
|
|
||||||
private static final int COLOR_CORAL = ImColor.rgbToColor("#FF7F50");
|
|
||||||
private static final int COLOR_LIMEGREEN = ImColor.rgbToColor("#32CD32");
|
|
||||||
|
|
||||||
// Test data for payload
|
|
||||||
private String dropTargetText = "Drop Here";
|
|
||||||
|
|
||||||
// Resizable input example
|
|
||||||
private final ImString resizableStr = new ImString(5);
|
|
||||||
|
|
||||||
// Toggles
|
|
||||||
private final ImBoolean showBottomDockedWindow = new ImBoolean(true);
|
|
||||||
private final ImBoolean showDemoWindow = new ImBoolean();
|
|
||||||
private final ImBoolean showImNodesWindow = new ImBoolean(false);
|
|
||||||
private final ImBoolean showImNodeEditorWindow = new ImBoolean(false);
|
|
||||||
|
|
||||||
// Attach image example
|
|
||||||
private int dukeTexture = 0;
|
|
||||||
|
|
||||||
private boolean isBottomDockedWindowInit = false;
|
|
||||||
|
|
||||||
// To modify background color dynamically
|
|
||||||
final float[] backgroundColor = new float[]{0.5f, 0, 0};
|
|
||||||
|
|
||||||
// Context for imnodes example
|
|
||||||
private ImNodesContext imNodesContext;
|
|
||||||
|
|
||||||
// Context for imgui-node-editor example
|
|
||||||
private NodeEditorContext nodeEditorContext;
|
|
||||||
|
|
||||||
// Graph used both for imnodes and imgui-node-editor demo
|
|
||||||
private final Graph graph = new Graph();
|
|
||||||
|
|
||||||
void render() throws Exception {
|
|
||||||
if (imNodesContext == null) {
|
|
||||||
imNodesContext = new ImNodesContext();
|
|
||||||
}
|
|
||||||
if (nodeEditorContext == null) {
|
|
||||||
final NodeEditorConfig config = new NodeEditorConfig();
|
|
||||||
config.setSettingsFile(null);
|
|
||||||
nodeEditorContext = new NodeEditorContext(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int dockspaceId = ImGui.getID("MyDockSpace");
|
|
||||||
showDockSpace(dockspaceId);
|
|
||||||
setupBottomDockedWindow(dockspaceId);
|
|
||||||
showBottomDockedWindow();
|
|
||||||
|
|
||||||
final ImGuiViewport mainViewport = ImGui.getMainViewport();
|
|
||||||
ImGui.setNextWindowSize(600, 300, ImGuiCond.Once);
|
|
||||||
ImGui.setNextWindowPos(mainViewport.getWorkPosX() + 10, mainViewport.getWorkPosY() + 10, ImGuiCond.Once);
|
|
||||||
|
|
||||||
ImGui.begin("Custom window"); // Start Custom window
|
|
||||||
showWindowImage();
|
|
||||||
showToggles();
|
|
||||||
|
|
||||||
ImGui.separator();
|
|
||||||
|
|
||||||
showDragNDrop();
|
|
||||||
showBackgroundPicker();
|
|
||||||
|
|
||||||
ImGui.separator();
|
|
||||||
|
|
||||||
showResizableInput();
|
|
||||||
|
|
||||||
ImGui.separator();
|
|
||||||
ImGui.newLine();
|
|
||||||
|
|
||||||
showDemoLink();
|
|
||||||
|
|
||||||
ImGui.end(); // End Custom window
|
|
||||||
|
|
||||||
if (showDemoWindow.get()) {
|
|
||||||
ImGui.showDemoWindow(showDemoWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showImNodesWindow.get()) {
|
|
||||||
showImNodesWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showImNodeEditorWindow.get()) {
|
|
||||||
showImNodeEditorWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDockSpace(final int dockspaceId) {
|
|
||||||
final ImGuiViewport mainViewport = ImGui.getMainViewport();
|
|
||||||
final int windowFlags = ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize
|
|
||||||
| ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoNavFocus | ImGuiWindowFlags.NoBackground;
|
|
||||||
|
|
||||||
ImGui.setNextWindowPos(mainViewport.getWorkPosX(), mainViewport.getWorkPosY());
|
|
||||||
ImGui.setNextWindowSize(mainViewport.getWorkSizeX(), mainViewport.getWorkSizeY());
|
|
||||||
ImGui.setNextWindowViewport(mainViewport.getID());
|
|
||||||
ImGui.pushStyleVar(ImGuiStyleVar.WindowRounding, 0);
|
|
||||||
ImGui.pushStyleVar(ImGuiStyleVar.WindowBorderSize, 0);
|
|
||||||
|
|
||||||
ImGui.pushStyleVar(ImGuiStyleVar.WindowPadding, 0, 0);
|
|
||||||
ImGui.begin("Dockspace Demo", windowFlags);
|
|
||||||
ImGui.popStyleVar(3);
|
|
||||||
|
|
||||||
ImGui.dockSpace(dockspaceId, 0, 0, ImGuiDockNodeFlags.PassthruCentralNode);
|
|
||||||
ImGui.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupBottomDockedWindow(final int dockspaceId) {
|
|
||||||
if (!isBottomDockedWindowInit) {
|
|
||||||
ImGui.dockBuilderRemoveNode(dockspaceId);
|
|
||||||
ImGui.dockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags.DockSpace);
|
|
||||||
|
|
||||||
final int dockIdBottom = ImGui.dockBuilderSplitNode(dockspaceId, ImGuiDir.Down, .25f, null, null);
|
|
||||||
|
|
||||||
ImGui.dockBuilderDockWindow("Bottom Docked Window", dockIdBottom);
|
|
||||||
ImGui.dockBuilderSetNodeSize(dockIdBottom, 150f, 150f);
|
|
||||||
ImGui.dockBuilderFinish(dockspaceId);
|
|
||||||
|
|
||||||
isBottomDockedWindowInit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showBottomDockedWindow() {
|
|
||||||
if (showBottomDockedWindow.get()) {
|
|
||||||
ImGui.begin("Bottom Docked Window", showBottomDockedWindow, ImGuiWindowFlags.AlwaysAutoResize);
|
|
||||||
ImGui.text("An example of how to create docked windows.");
|
|
||||||
ImGui.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showWindowImage() throws IOException {
|
|
||||||
if (dukeTexture == 0) {
|
|
||||||
dukeTexture = loadTexture(ImageIO.read(new File("src/test/resources/Duke_waving.png")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw an image in the bottom-right corner of the window
|
|
||||||
final float xPoint = ImGui.getWindowPosX() + ImGui.getWindowSizeX() - 100;
|
|
||||||
final float yPoint = ImGui.getWindowPosY() + ImGui.getWindowSizeY();
|
|
||||||
ImGui.getWindowDrawList().addImage(dukeTexture, xPoint, yPoint - 180, xPoint + 100, yPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showToggles() {
|
|
||||||
ImGui.checkbox("Show Demo Window", showDemoWindow);
|
|
||||||
ImGui.checkbox("Show Bottom Docked Window", showBottomDockedWindow);
|
|
||||||
ImGui.checkbox("Show demo for imnodes", showImNodesWindow);
|
|
||||||
ImGui.checkbox("Show demo for imgui-node-editor", showImNodeEditorWindow);
|
|
||||||
if (ImGui.button("Reset Bottom Dock Window")) {
|
|
||||||
isBottomDockedWindowInit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDragNDrop() {
|
|
||||||
ImGui.button("Drag me");
|
|
||||||
if (ImGui.beginDragDropSource()) {
|
|
||||||
ImGui.setDragDropPayloadObject("payload_type", "Test Payload");
|
|
||||||
ImGui.text("Drag started");
|
|
||||||
ImGui.endDragDropSource();
|
|
||||||
}
|
|
||||||
ImGui.sameLine();
|
|
||||||
ImGui.text(dropTargetText);
|
|
||||||
if (ImGui.beginDragDropTarget()) {
|
|
||||||
final Object payload = ImGui.acceptDragDropPayloadObject("payload_type");
|
|
||||||
if (payload != null) {
|
|
||||||
dropTargetText = (String) payload;
|
|
||||||
}
|
|
||||||
ImGui.endDragDropTarget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showBackgroundPicker() {
|
|
||||||
ImGui.alignTextToFramePadding();
|
|
||||||
ImGui.text("Background color:");
|
|
||||||
ImGui.sameLine();
|
|
||||||
ImGui.colorEdit3("##click_counter_col", backgroundColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.NoDragDrop);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showResizableInput() {
|
|
||||||
ImGui.text("You can use text inputs with auto-resizable strings!");
|
|
||||||
ImGui.inputText("Resizable input", resizableStr, ImGuiInputTextFlags.CallbackResize);
|
|
||||||
ImGui.text("text len:");
|
|
||||||
ImGui.sameLine();
|
|
||||||
ImGui.textColored(COLOR_DODGERBLUE, Integer.toString(resizableStr.getLength()));
|
|
||||||
ImGui.sameLine();
|
|
||||||
ImGui.text("| buffer size:");
|
|
||||||
ImGui.sameLine();
|
|
||||||
ImGui.textColored(COLOR_CORAL, Integer.toString(resizableStr.getBufferSize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDemoLink() {
|
|
||||||
ImGui.text("Consider to look the original ImGui demo: ");
|
|
||||||
ImGui.setNextItemWidth(500);
|
|
||||||
ImGui.textColored(COLOR_LIMEGREEN, IMGUI_DEMO_LINK);
|
|
||||||
ImGui.sameLine();
|
|
||||||
if (ImGui.button("Copy")) {
|
|
||||||
ImGui.setClipboardText(IMGUI_DEMO_LINK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showImNodesWindow() {
|
|
||||||
ImGui.setNextWindowSize(400F, 400F, ImGuiCond.Appearing);
|
|
||||||
ImGui.begin("Demo imnodes", showImNodesWindow);
|
|
||||||
|
|
||||||
ImGui.text("This a demo graph editor for ImNodes");
|
|
||||||
|
|
||||||
ImNodes.editorContextSet(imNodesContext);
|
|
||||||
ImNodes.beginNodeEditor();
|
|
||||||
|
|
||||||
for (Graph.GraphNode node : graph.nodes.values()) {
|
|
||||||
ImNodes.beginNode(node.nodeId);
|
|
||||||
|
|
||||||
ImNodes.beginNodeTitleBar();
|
|
||||||
ImGui.text(node.getName());
|
|
||||||
ImNodes.endNodeTitleBar();
|
|
||||||
|
|
||||||
|
|
||||||
ImNodes.beginInputAttribute(node.getInputPinId(), ImNodesPinShape.CircleFilled);
|
|
||||||
ImGui.text("In");
|
|
||||||
ImNodes.endInputAttribute();
|
|
||||||
|
|
||||||
ImGui.sameLine();
|
|
||||||
|
|
||||||
ImNodes.beginOutputAttribute(node.getOutputPinId());
|
|
||||||
ImGui.text("Out");
|
|
||||||
ImNodes.endOutputAttribute();
|
|
||||||
|
|
||||||
ImNodes.endNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
int uniqueLinkId = 1;
|
|
||||||
for (Graph.GraphNode node : graph.nodes.values()) {
|
|
||||||
if (graph.nodes.containsKey(node.outputNodeId)) {
|
|
||||||
ImNodes.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean isEditorHovered = ImNodes.isEditorHovered();
|
|
||||||
|
|
||||||
ImNodes.endNodeEditor();
|
|
||||||
final ImInt a = new ImInt();
|
|
||||||
final ImInt b = new ImInt();
|
|
||||||
if (ImNodes.isLinkCreated(a, b)) {
|
|
||||||
final Graph.GraphNode source = graph.findByOutput(a.get());
|
|
||||||
final Graph.GraphNode target = graph.findByInput(b.get());
|
|
||||||
if (source != null && target != null && source.outputNodeId != target.nodeId) {
|
|
||||||
source.outputNodeId = target.nodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.isMouseClicked(1)) {
|
|
||||||
final int hoveredNode = ImNodes.getHoveredNode();
|
|
||||||
if (hoveredNode != -1) {
|
|
||||||
ImGui.openPopup("node-context");
|
|
||||||
ImGui.getStateStorage().setInt(ImGui.getID("delete-node-id"), hoveredNode);
|
|
||||||
} else if (isEditorHovered) {
|
|
||||||
ImGui.openPopup("node-editor-context");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.isPopupOpen("node-context")) {
|
|
||||||
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete-node-id"));
|
|
||||||
if (ImGui.beginPopup("node-context")) {
|
|
||||||
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
|
|
||||||
graph.nodes.remove(targetNode);
|
|
||||||
ImGui.closeCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui.endPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.beginPopup("node-editor-context")) {
|
|
||||||
if (ImGui.button("Create new node")) {
|
|
||||||
final Graph.GraphNode node = graph.createGraphNode();
|
|
||||||
ImNodes.setNodeScreenSpacePos(node.nodeId, ImGui.getMousePosX(), ImGui.getMousePosY());
|
|
||||||
ImGui.closeCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui.endPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showImNodeEditorWindow() {
|
|
||||||
ImGui.setNextWindowSize(400F, 400F, ImGuiCond.Appearing);
|
|
||||||
ImGui.begin("Demo imgui-node-editor", showImNodeEditorWindow);
|
|
||||||
|
|
||||||
ImGui.text("This a demo graph editor for imgui-node-editor");
|
|
||||||
|
|
||||||
if (ImGui.button("Navigate to content")) {
|
|
||||||
NodeEditor.navigateToContent(1F);
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeEditor.setCurrentEditor(nodeEditorContext);
|
|
||||||
NodeEditor.begin("Node Editor");
|
|
||||||
|
|
||||||
for (Graph.GraphNode node : graph.nodes.values()) {
|
|
||||||
NodeEditor.beginNode(node.nodeId);
|
|
||||||
|
|
||||||
ImGui.text(node.getName());
|
|
||||||
|
|
||||||
NodeEditor.beginPin(node.getInputPinId(), NodeEditorPinKind.Input);
|
|
||||||
ImGui.text("-> In");
|
|
||||||
NodeEditor.endPin();
|
|
||||||
|
|
||||||
ImGui.sameLine();
|
|
||||||
|
|
||||||
NodeEditor.beginPin(node.getOutputPinId(), NodeEditorPinKind.Output);
|
|
||||||
ImGui.text("Out ->");
|
|
||||||
NodeEditor.endPin();
|
|
||||||
|
|
||||||
NodeEditor.endNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NodeEditor.beginCreate()) {
|
|
||||||
final ImLong a = new ImLong();
|
|
||||||
final ImLong b = new ImLong();
|
|
||||||
if (NodeEditor.queryNewLink(a, b)) {
|
|
||||||
final Graph.GraphNode source = graph.findByOutput(a.get());
|
|
||||||
final Graph.GraphNode target = graph.findByInput(b.get());
|
|
||||||
if (source != null && target != null && source.outputNodeId != target.nodeId && NodeEditor.acceptNewItem()) {
|
|
||||||
source.outputNodeId = target.nodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NodeEditor.endCreate();
|
|
||||||
|
|
||||||
int uniqueLinkId = 1;
|
|
||||||
for (Graph.GraphNode node : graph.nodes.values()) {
|
|
||||||
if (graph.nodes.containsKey(node.outputNodeId)) {
|
|
||||||
NodeEditor.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeEditor.suspend();
|
|
||||||
final long nodeWithContextMenu = NodeEditor.getNodeWithContextMenu();
|
|
||||||
if (nodeWithContextMenu != -1) {
|
|
||||||
ImGui.openPopup("node-context");
|
|
||||||
ImGui.getStateStorage().setInt(ImGui.getID("delete-node-id"), (int) nodeWithContextMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.isPopupOpen("node-context")) {
|
|
||||||
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete-node-id"));
|
|
||||||
if (ImGui.beginPopup("node-context")) {
|
|
||||||
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
|
|
||||||
graph.nodes.remove(targetNode);
|
|
||||||
ImGui.closeCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui.endPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NodeEditor.showBackgroundContextMenu()) {
|
|
||||||
ImGui.openPopup("node-editor-context");
|
|
||||||
}
|
|
||||||
if (ImGui.beginPopup("node-editor-context")) {
|
|
||||||
if (ImGui.button("Create new node")) {
|
|
||||||
final Graph.GraphNode node = graph.createGraphNode();
|
|
||||||
final float canvasX = NodeEditor.toCanvasX(ImGui.getMousePosX());
|
|
||||||
final float canvasY = NodeEditor.toCanvasY(ImGui.getMousePosY());
|
|
||||||
NodeEditor.setNodePosition(node.nodeId, canvasX, canvasY);
|
|
||||||
ImGui.closeCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui.endPopup();
|
|
||||||
}
|
|
||||||
NodeEditor.resume();
|
|
||||||
|
|
||||||
NodeEditor.end();
|
|
||||||
ImGui.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int loadTexture(final BufferedImage image) {
|
|
||||||
final int[] pixels = new int[image.getWidth() * image.getHeight()];
|
|
||||||
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
|
|
||||||
|
|
||||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); // 4 for RGBA, 3 for RGB
|
|
||||||
for (int y = 0; y < image.getHeight(); y++) {
|
|
||||||
for (int x = 0; x < image.getWidth(); x++) {
|
|
||||||
final int pixel = pixels[y * image.getWidth() + x];
|
|
||||||
buffer.put((byte) ((pixel >> 16) & 0xFF));
|
|
||||||
buffer.put((byte) ((pixel >> 8) & 0xFF));
|
|
||||||
buffer.put((byte) (pixel & 0xFF));
|
|
||||||
buffer.put((byte) ((pixel >> 24) & 0xFF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.flip();
|
|
||||||
|
|
||||||
final int textureID = glGenTextures();
|
|
||||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
||||||
|
|
||||||
return textureID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Simple graph struct for both of node editors demos
|
|
||||||
private static final class Graph {
|
|
||||||
|
|
||||||
private int nextNodeId = 1;
|
|
||||||
private int nextPinId = 100;
|
|
||||||
|
|
||||||
final Map<Integer, GraphNode> nodes = new HashMap<>();
|
|
||||||
|
|
||||||
private Graph() {
|
|
||||||
final GraphNode first = createGraphNode();
|
|
||||||
final GraphNode second = createGraphNode();
|
|
||||||
first.outputNodeId = second.nodeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GraphNode createGraphNode() {
|
|
||||||
final GraphNode node = new GraphNode(nextNodeId++, nextPinId++, nextPinId++);
|
|
||||||
this.nodes.put(node.nodeId, node);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GraphNode findByInput(final long inputPinId) {
|
|
||||||
for (GraphNode node : nodes.values()) {
|
|
||||||
if (node.getInputPinId() == inputPinId) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GraphNode findByOutput(final long outputPinId) {
|
|
||||||
for (GraphNode node : nodes.values()) {
|
|
||||||
if (node.getOutputPinId() == outputPinId) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class GraphNode {
|
|
||||||
private final int nodeId;
|
|
||||||
private final int inputPinId;
|
|
||||||
private final int outputPinId;
|
|
||||||
|
|
||||||
public int outputNodeId = -1;
|
|
||||||
|
|
||||||
private GraphNode(final int nodeId, final int inputPinId, final int outputPintId) {
|
|
||||||
this.nodeId = nodeId;
|
|
||||||
this.inputPinId = inputPinId;
|
|
||||||
this.outputPinId = outputPintId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInputPinId() {
|
|
||||||
return inputPinId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOutputPinId() {
|
|
||||||
return outputPinId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "Node " + (char) (64 + nodeId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
import static org.lwjgl.glfw.Callbacks.glfwFreeCallbacks;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
|
|
||||||
import static org.lwjgl.glfw.GLFW.GLFW_VISIBLE;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwDefaultWindowHints;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwDestroyWindow;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwGetCurrentContext;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwGetWindowSize;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwInit;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwPollEvents;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwShowWindow;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwTerminate;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwWindowHint;
|
|
||||||
import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_COLOR_BUFFER_BIT;
|
|
||||||
import static org.lwjgl.opengl.GL32.GL_TRUE;
|
|
||||||
import static org.lwjgl.opengl.GL32.glClear;
|
|
||||||
import static org.lwjgl.opengl.GL32.glClearColor;
|
|
||||||
import static org.lwjgl.system.MemoryStack.stackPush;
|
|
||||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
|
||||||
|
|
||||||
import imgui.ImFontAtlas;
|
|
||||||
import imgui.ImFontConfig;
|
|
||||||
import imgui.ImGui;
|
|
||||||
import imgui.ImGuiIO;
|
|
||||||
import imgui.ImGuiStyle;
|
|
||||||
import imgui.flag.ImGuiCol;
|
|
||||||
import imgui.flag.ImGuiConfigFlags;
|
|
||||||
import imgui.gl3.ImGuiImplGl3;
|
|
||||||
import imgui.glfw.ImGuiImplGlfw;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.UncheckedIOException;
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import imgui.extension.imnodes.ImNodes;
|
|
||||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
|
||||||
import org.lwjgl.glfw.GLFWVidMode;
|
|
||||||
import org.lwjgl.opengl.GL;
|
|
||||||
import org.lwjgl.system.MemoryStack;
|
|
||||||
|
|
||||||
@SuppressWarnings("MagicNumber")
|
|
||||||
public final class ImGuiGlfwExample {
|
|
||||||
private long windowPtr; // pointer to the current GLFW window
|
|
||||||
|
|
||||||
// LWJGJ3 window backend
|
|
||||||
private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
|
|
||||||
|
|
||||||
// LWJGL3 renderer (SHOULD be initialized)
|
|
||||||
private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
|
|
||||||
private String glslVersion = null; // We can initialize our renderer with different versions of the GLSL
|
|
||||||
|
|
||||||
// User UI to render
|
|
||||||
private final ExampleUi exampleUi = new ExampleUi();
|
|
||||||
|
|
||||||
public void run() throws Exception {
|
|
||||||
setupGlfw();
|
|
||||||
setupImGui();
|
|
||||||
|
|
||||||
// Method initializes GLFW backend.
|
|
||||||
// This method SHOULD be called after you've setup GLFW.
|
|
||||||
// ImGui context should be created as well.
|
|
||||||
imGuiGlfw.init(windowPtr, true);
|
|
||||||
// Method initializes LWJGL3 renderer.
|
|
||||||
// This method SHOULD be called after you've initialized your ImGui configuration (fonts and so on).
|
|
||||||
// ImGui context should be created as well.
|
|
||||||
imGuiGl3.init(glslVersion);
|
|
||||||
|
|
||||||
loop();
|
|
||||||
|
|
||||||
// You should clean up after yourself in reverse order.
|
|
||||||
imGuiGl3.dispose();
|
|
||||||
imGuiGlfw.dispose();
|
|
||||||
|
|
||||||
ImNodes.shutdown();
|
|
||||||
ImGui.destroyContext();
|
|
||||||
|
|
||||||
disposeWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize GLFW + create an OpenGL context.
|
|
||||||
// All code is mostly a copy-paste from the official LWJGL3 "Get Started": https://www.lwjgl.org/guide
|
|
||||||
private void setupGlfw() {
|
|
||||||
// Setup an error callback. The default implementation
|
|
||||||
// will print the error message in System.err.
|
|
||||||
GLFWErrorCallback.createPrint(System.err).set();
|
|
||||||
|
|
||||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
|
||||||
if (!glfwInit()) {
|
|
||||||
throw new IllegalStateException("Unable to initialize GLFW");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure GLFW
|
|
||||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
|
||||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
|
|
||||||
|
|
||||||
decideGlGlslVersions();
|
|
||||||
|
|
||||||
windowPtr = glfwCreateWindow(1280, 768, "Dear ImGui+LWJGL Example", NULL, NULL);
|
|
||||||
|
|
||||||
if (windowPtr == NULL) {
|
|
||||||
throw new RuntimeException("Failed to create the GLFW window");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the thread stack and push a new frame
|
|
||||||
try (MemoryStack stack = stackPush()) {
|
|
||||||
final IntBuffer pWidth = stack.mallocInt(1); // int*
|
|
||||||
final IntBuffer pHeight = stack.mallocInt(1); // int*
|
|
||||||
|
|
||||||
// Get the window size passed to glfwCreateWindow
|
|
||||||
glfwGetWindowSize(windowPtr, pWidth, pHeight);
|
|
||||||
|
|
||||||
// Get the resolution of the primary monitor
|
|
||||||
final GLFWVidMode vidmode = Objects.requireNonNull(glfwGetVideoMode(glfwGetPrimaryMonitor()));
|
|
||||||
|
|
||||||
// Center the window
|
|
||||||
glfwSetWindowPos(windowPtr, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
|
|
||||||
} // the stack frame is popped automatically
|
|
||||||
|
|
||||||
glfwMakeContextCurrent(windowPtr); // Make the OpenGL context current
|
|
||||||
glfwSwapInterval(GLFW_TRUE); // Enable v-sync
|
|
||||||
glfwShowWindow(windowPtr); // Make the window visible
|
|
||||||
|
|
||||||
// IMPORTANT!!
|
|
||||||
// This line is critical for LWJGL's interoperation with GLFW's
|
|
||||||
// OpenGL context, or any context that is managed externally.
|
|
||||||
// LWJGL detects the context that is current in the current thread,
|
|
||||||
// creates the GLCapabilities instance and makes the OpenGL
|
|
||||||
// bindings available for use.
|
|
||||||
GL.createCapabilities();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void decideGlGlslVersions() {
|
|
||||||
final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac");
|
|
||||||
if (isMac) {
|
|
||||||
glslVersion = "#version 150";
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
|
||||||
} else {
|
|
||||||
glslVersion = "#version 130";
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize Dear ImGui.
|
|
||||||
private void setupImGui() {
|
|
||||||
// IMPORTANT!!
|
|
||||||
// This line is critical for Dear ImGui to work.
|
|
||||||
ImGui.createContext();
|
|
||||||
ImNodes.initialize();
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Initialize ImGuiIO 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);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
|
||||||
// Fonts configuration
|
|
||||||
// Read: https://raw.githubusercontent.com/ocornut/imgui/master/docs/FONTS.txt
|
|
||||||
|
|
||||||
final ImFontAtlas fontAtlas = io.getFonts();
|
|
||||||
final ImFontConfig fontConfig = new ImFontConfig(); // Natively allocated object, should be explicitly destroyed
|
|
||||||
|
|
||||||
// Glyphs could be added per-font as well as per config used globally like here
|
|
||||||
fontConfig.setGlyphRanges(fontAtlas.getGlyphRangesCyrillic());
|
|
||||||
|
|
||||||
// Add a default font, which is 'ProggyClean.ttf, 13px'
|
|
||||||
fontAtlas.addFontDefault();
|
|
||||||
|
|
||||||
// Fonts merge example
|
|
||||||
fontConfig.setMergeMode(true); // When enabled, all fonts added with this config would be merged with the previously added font
|
|
||||||
fontConfig.setPixelSnapH(true);
|
|
||||||
|
|
||||||
fontAtlas.addFontFromMemoryTTF(loadFromResources("basis33.ttf"), 16, fontConfig);
|
|
||||||
|
|
||||||
fontConfig.setMergeMode(false);
|
|
||||||
fontConfig.setPixelSnapH(false);
|
|
||||||
|
|
||||||
// Fonts from file/memory example
|
|
||||||
// We can add new fonts from the file system
|
|
||||||
fontAtlas.addFontFromFileTTF("src/test/resources/Righteous-Regular.ttf", 14, fontConfig);
|
|
||||||
fontAtlas.addFontFromFileTTF("src/test/resources/Righteous-Regular.ttf", 16, fontConfig);
|
|
||||||
|
|
||||||
// Or directly from the memory
|
|
||||||
fontConfig.setName("Roboto-Regular.ttf, 14px"); // This name will be displayed in Style Editor
|
|
||||||
fontAtlas.addFontFromMemoryTTF(loadFromResources("Roboto-Regular.ttf"), 14, fontConfig);
|
|
||||||
fontConfig.setName("Roboto-Regular.ttf, 16px"); // We can apply a new config value every time we add a new font
|
|
||||||
fontAtlas.addFontFromMemoryTTF(loadFromResources("Roboto-Regular.ttf"), 16, fontConfig);
|
|
||||||
|
|
||||||
fontConfig.destroy(); // After all fonts were added we don't need this config more
|
|
||||||
|
|
||||||
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
|
||||||
if (io.hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
|
|
||||||
final ImGuiStyle style = ImGui.getStyle();
|
|
||||||
style.setWindowRounding(0.0f);
|
|
||||||
style.setColor(ImGuiCol.WindowBg, ImGui.getColorU32(ImGuiCol.WindowBg, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main application loop
|
|
||||||
private void loop() throws Exception {
|
|
||||||
// Run the rendering loop until the user has attempted to close the window
|
|
||||||
while (!glfwWindowShouldClose(windowPtr)) {
|
|
||||||
startFrame();
|
|
||||||
|
|
||||||
// Any Dear ImGui code SHOULD go between ImGui.newFrame()/ImGui.render() methods
|
|
||||||
imGuiGlfw.newFrame();
|
|
||||||
ImGui.newFrame();
|
|
||||||
|
|
||||||
exampleUi.render();
|
|
||||||
ImGui.render();
|
|
||||||
|
|
||||||
endFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startFrame() {
|
|
||||||
// Set the clear color and clear the window
|
|
||||||
glClearColor(exampleUi.backgroundColor[0], exampleUi.backgroundColor[1], exampleUi.backgroundColor[2], 0.0f);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void endFrame() {
|
|
||||||
// After Dear ImGui prepared a draw data, we use it in the LWJGL3 renderer.
|
|
||||||
// At that moment ImGui will be rendered to the current OpenGL context.
|
|
||||||
imGuiGl3.renderDrawData(ImGui.getDrawData());
|
|
||||||
|
|
||||||
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
|
|
||||||
final long backupWindowPtr = glfwGetCurrentContext();
|
|
||||||
ImGui.updatePlatformWindows();
|
|
||||||
ImGui.renderPlatformWindowsDefault();
|
|
||||||
glfwMakeContextCurrent(backupWindowPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwSwapBuffers(windowPtr);
|
|
||||||
glfwPollEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disposeWindow() {
|
|
||||||
glfwFreeCallbacks(windowPtr);
|
|
||||||
glfwDestroyWindow(windowPtr);
|
|
||||||
glfwTerminate();
|
|
||||||
Objects.requireNonNull(glfwSetErrorCallback(null)).free();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] loadFromResources(final String fileName) {
|
|
||||||
try (InputStream is = Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream(fileName));
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
|
|
||||||
|
|
||||||
final byte[] data = new byte[16384];
|
|
||||||
|
|
||||||
int nRead;
|
|
||||||
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
|
||||||
buffer.write(data, 0, nRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new UncheckedIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(final String[] args) throws Exception {
|
|
||||||
new ImGuiGlfwExample().run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user