Skip to content

Commit 17a8a3b

Browse files
author
Mathias Gredal
committed
Implement a backend for BGFX
1 parent bad0588 commit 17a8a3b

File tree

4 files changed

+967
-0
lines changed

4 files changed

+967
-0
lines changed

imgui-app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ dependencies {
1818
api 'org.lwjgl:lwjgl'
1919
api 'org.lwjgl:lwjgl-glfw'
2020
api 'org.lwjgl:lwjgl-opengl'
21+
api 'org.lwjgl:lwjgl-bgfx'
2122

2223
['natives-linux', 'natives-windows', 'natives-macos'].each {
2324
api "org.lwjgl:lwjgl::$it"
2425
api "org.lwjgl:lwjgl-glfw::$it"
2526
api "org.lwjgl:lwjgl-opengl::$it"
27+
api "org.lwjgl:lwjgl-bgfx::$it"
2628
}
2729

2830
api project(':imgui-binding')
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
package imgui.app;
2+
3+
import imgui.ImGui;
4+
import imgui.bgfx.ImGuiImplBGFX;
5+
import imgui.flag.ImGuiConfigFlags;
6+
import imgui.glfw.ImGuiImplGlfw;
7+
import org.lwjgl.BufferUtils;
8+
import org.lwjgl.bgfx.BGFXInit;
9+
import org.lwjgl.glfw.GLFW;
10+
import org.lwjgl.glfw.*;
11+
import org.lwjgl.system.MemoryStack;
12+
import org.lwjgl.system.MemoryUtil;
13+
import org.lwjgl.system.Platform;
14+
15+
import java.nio.IntBuffer;
16+
import java.util.Objects;
17+
18+
import static org.lwjgl.bgfx.BGFX.*;
19+
import static org.lwjgl.glfw.GLFW.*;
20+
import static org.lwjgl.system.Configuration.GLFW_LIBRARY_NAME;
21+
import static org.lwjgl.system.MemoryStack.stackPush;
22+
23+
public abstract class BGFXWindow {
24+
private final ImGuiImplBGFX imGuiBGFX = new ImGuiImplBGFX();
25+
private final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
26+
27+
/**
28+
* Pointer to the native GLFW window.
29+
*/
30+
protected long handle;
31+
32+
/**
33+
* Background color of the window.
34+
*/
35+
protected final Color colorBg = new Color(.5f, .5f, .5f, 1);
36+
37+
/**
38+
* Method to initialize application.
39+
*
40+
* @param config configuration object with basic window information
41+
*/
42+
protected void init(final Configuration config) {
43+
initWindow(config);
44+
initImGui(config);
45+
imGuiGlfw.init(handle, true);
46+
imGuiBGFX.init();
47+
}
48+
49+
/**
50+
* Method to dispose all used application resources and destroy its window.
51+
*/
52+
protected void dispose() {
53+
imGuiBGFX.dispose();
54+
imGuiGlfw.dispose();
55+
disposeImGui();
56+
disposeWindow();
57+
}
58+
59+
/**
60+
* Method to create and initialize GLFW window.
61+
*
62+
* @param config configuration object with basic window information
63+
*/
64+
protected void initWindow(final Configuration config) {
65+
if (Platform.get() == Platform.MACOSX) {
66+
GLFW_LIBRARY_NAME.set("glfw_async");
67+
}
68+
69+
GLFWErrorCallback.createPrint(System.err).set();
70+
71+
if (!GLFW.glfwInit()) {
72+
throw new IllegalStateException("Unable to initialize GLFW");
73+
}
74+
75+
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
76+
77+
handle = glfwCreateWindow(config.getWidth(), config.getHeight(), config.getTitle(), MemoryUtil.NULL, MemoryUtil.NULL);
78+
79+
if (handle == MemoryUtil.NULL) {
80+
throw new RuntimeException("Failed to create the GLFW window");
81+
}
82+
83+
try (MemoryStack stack = stackPush()) {
84+
final IntBuffer pWidth = stack.mallocInt(1); // int*
85+
final IntBuffer pHeight = stack.mallocInt(1); // int*
86+
87+
GLFW.glfwGetWindowSize(handle, pWidth, pHeight);
88+
final GLFWVidMode vidmode = Objects.requireNonNull(GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor()));
89+
GLFW.glfwSetWindowPos(handle, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
90+
}
91+
92+
try (MemoryStack stack = stackPush()) {
93+
BGFXInit init = BGFXInit.malloc(stack);
94+
95+
bgfx_init_ctor(init);
96+
init.resolution(it -> it
97+
.width(config.getWidth())
98+
.height(config.getHeight())
99+
.reset(BGFX_RESET_VSYNC));
100+
switch (Platform.get()) {
101+
case LINUX:
102+
init.platformData()
103+
.ndt(GLFWNativeX11.glfwGetX11Display())
104+
.nwh(GLFWNativeX11.glfwGetX11Window(handle));
105+
break;
106+
case MACOSX:
107+
init.platformData()
108+
.nwh(GLFWNativeCocoa.glfwGetCocoaWindow(handle));
109+
break;
110+
case WINDOWS:
111+
init.platformData()
112+
.nwh(GLFWNativeWin32.glfwGetWin32Window(handle));
113+
break;
114+
}
115+
116+
if (!bgfx_init(init)) {
117+
throw new RuntimeException("Error initializing bgfx renderer");
118+
}
119+
}
120+
121+
if (config.isFullScreen()) {
122+
GLFW.glfwMaximizeWindow(handle);
123+
} else {
124+
GLFW.glfwShowWindow(handle);
125+
}
126+
127+
clearBuffer();
128+
renderBuffer();
129+
130+
GLFW.glfwSetWindowSizeCallback(handle, new GLFWWindowSizeCallback() {
131+
@Override
132+
public void invoke(final long window, final int width, final int height) {
133+
runFrame();
134+
}
135+
});
136+
}
137+
138+
/**
139+
* Method to initialize Dear ImGui context. Could be overridden to do custom Dear ImGui setup before application start.
140+
*
141+
* @param config configuration object with basic window information
142+
*/
143+
protected void initImGui(final Configuration config) {
144+
ImGui.createContext();
145+
}
146+
147+
/**
148+
* Method called every frame, before calling {@link #process()} method.
149+
*/
150+
protected void preProcess() {
151+
}
152+
153+
/**
154+
* Method called every frame, after calling {@link #process()} method.
155+
*/
156+
protected void postProcess() {
157+
}
158+
159+
/**
160+
* Main application loop.
161+
*/
162+
protected void run() {
163+
while (!GLFW.glfwWindowShouldClose(handle)) {
164+
runFrame();
165+
}
166+
}
167+
168+
/**
169+
* Method used to run the next frame.
170+
*/
171+
protected void runFrame() {
172+
startFrame();
173+
preProcess();
174+
process();
175+
postProcess();
176+
endFrame();
177+
}
178+
179+
/**
180+
* Method to be overridden by user to provide main application logic.
181+
*/
182+
public abstract void process();
183+
184+
/**
185+
* Method used to clear the OpenGL buffer.
186+
*/
187+
private void clearBuffer() {
188+
int color = Math.round(colorBg.getRed() * 255);
189+
color = (color << 8) + Math.round(colorBg.getGreen() * 255);
190+
color = (color << 8) + Math.round(colorBg.getBlue() * 255);
191+
color = (color << 8) + Math.round(colorBg.getAlpha() * 255);
192+
bgfx_set_view_clear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, color, 1.0f, 0);
193+
IntBuffer w = BufferUtils.createIntBuffer(1);
194+
IntBuffer h = BufferUtils.createIntBuffer(1);
195+
glfwGetWindowSize(getHandle(), w, h);
196+
int width = w.get(0);
197+
int height = h.get(0);
198+
bgfx_set_view_rect(0, 0, 0, width, height);
199+
}
200+
201+
/**
202+
* Method called at the beginning of the main cycle.
203+
* It clears OpenGL buffer and starts an ImGui frame.
204+
*/
205+
protected void startFrame() {
206+
clearBuffer();
207+
imGuiGlfw.newFrame();
208+
ImGui.newFrame();
209+
}
210+
211+
/**
212+
* Method called in the end of the main cycle.
213+
* It renders ImGui and swaps GLFW buffers to show an updated frame.
214+
*/
215+
protected void endFrame() {
216+
ImGui.render();
217+
imGuiBGFX.renderDrawData(ImGui.getDrawData());
218+
219+
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
220+
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
221+
ImGui.updatePlatformWindows();
222+
ImGui.renderPlatformWindowsDefault();
223+
GLFW.glfwMakeContextCurrent(backupWindowPtr);
224+
}
225+
226+
renderBuffer();
227+
}
228+
229+
/**
230+
* Method to render the OpenGL buffer and poll window events.
231+
*/
232+
private void renderBuffer() {
233+
bgfx_frame(false);
234+
GLFW.glfwPollEvents();
235+
}
236+
237+
/**
238+
* Method to destroy Dear ImGui context.
239+
*/
240+
protected void disposeImGui() {
241+
ImGui.destroyContext();
242+
}
243+
244+
/**
245+
* Method to destroy GLFW window.
246+
*/
247+
protected void disposeWindow() {
248+
bgfx_shutdown();
249+
Callbacks.glfwFreeCallbacks(handle);
250+
GLFW.glfwDestroyWindow(handle);
251+
GLFW.glfwTerminate();
252+
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
253+
}
254+
255+
/**
256+
* @return pointer to the native GLFW window
257+
*/
258+
public final long getHandle() {
259+
return handle;
260+
}
261+
262+
/**
263+
* @return {@link Color} instance, which represents background color for the window
264+
*/
265+
public final Color getColorBg() {
266+
return colorBg;
267+
}
268+
}

imgui-lwjgl3/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
implementation 'org.lwjgl:lwjgl'
1818
implementation 'org.lwjgl:lwjgl-glfw'
1919
implementation 'org.lwjgl:lwjgl-opengl'
20+
implementation 'org.lwjgl:lwjgl-bgfx'
2021

2122
implementation project(':imgui-binding')
2223
}

0 commit comments

Comments
 (0)