Skip to content

Commit 5c2bf1c

Browse files
author
Mathias Gredal
committed
Implement a backend for BGFX
1 parent bad0588 commit 5c2bf1c

File tree

4 files changed

+975
-0
lines changed

4 files changed

+975
-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: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
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+
bgfx_reset(width, height, BGFX_RESET_NONE, BGFX_TEXTURE_FORMAT_COUNT);
134+
runFrame();
135+
}
136+
});
137+
}
138+
139+
/**
140+
* Method to initialize Dear ImGui context. Could be overridden to do custom Dear ImGui setup before application start.
141+
*
142+
* @param config configuration object with basic window information
143+
*/
144+
protected void initImGui(final Configuration config) {
145+
ImGui.createContext();
146+
}
147+
148+
/**
149+
* Method called every frame, before calling {@link #process()} method.
150+
*/
151+
protected void preProcess() {
152+
}
153+
154+
/**
155+
* Method called every frame, after calling {@link #process()} method.
156+
*/
157+
protected void postProcess() {
158+
}
159+
160+
/**
161+
* Main application loop.
162+
*/
163+
protected void run() {
164+
while (!GLFW.glfwWindowShouldClose(handle)) {
165+
runFrame();
166+
}
167+
}
168+
169+
/**
170+
* Method used to run the next frame.
171+
*/
172+
protected void runFrame() {
173+
startFrame();
174+
preProcess();
175+
process();
176+
postProcess();
177+
endFrame();
178+
}
179+
180+
/**
181+
* Method to be overridden by user to provide main application logic.
182+
*/
183+
public abstract void process();
184+
185+
/**
186+
* Method used to clear the OpenGL buffer.
187+
*/
188+
private void clearBuffer() {
189+
int color = Math.round(colorBg.getRed() * 255);
190+
color = (color << 8) + Math.round(colorBg.getGreen() * 255);
191+
color = (color << 8) + Math.round(colorBg.getBlue() * 255);
192+
color = (color << 8) + Math.round(colorBg.getAlpha() * 255);
193+
bgfx_set_view_clear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, color, 1.0f, 0);
194+
IntBuffer w = BufferUtils.createIntBuffer(1);
195+
IntBuffer h = BufferUtils.createIntBuffer(1);
196+
glfwGetWindowSize(getHandle(), w, h);
197+
int width = w.get(0);
198+
int height = h.get(0);
199+
bgfx_set_view_rect(0, 0, 0, width, height);
200+
}
201+
202+
/**
203+
* Method called at the beginning of the main cycle.
204+
* It clears OpenGL buffer and starts an ImGui frame.
205+
*/
206+
protected void startFrame() {
207+
clearBuffer();
208+
imGuiGlfw.newFrame();
209+
ImGui.newFrame();
210+
}
211+
212+
/**
213+
* Method called in the end of the main cycle.
214+
* It renders ImGui and swaps GLFW buffers to show an updated frame.
215+
*/
216+
protected void endFrame() {
217+
ImGui.render();
218+
imGuiBGFX.renderDrawData(ImGui.getDrawData());
219+
220+
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
221+
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
222+
ImGui.updatePlatformWindows();
223+
ImGui.renderPlatformWindowsDefault();
224+
GLFW.glfwMakeContextCurrent(backupWindowPtr);
225+
}
226+
227+
renderBuffer();
228+
}
229+
230+
/**
231+
* Method to render the OpenGL buffer and poll window events.
232+
*/
233+
private void renderBuffer() {
234+
bgfx_frame(false);
235+
GLFW.glfwPollEvents();
236+
}
237+
238+
/**
239+
* Method to destroy Dear ImGui context.
240+
*/
241+
protected void disposeImGui() {
242+
ImGui.destroyContext();
243+
}
244+
245+
/**
246+
* Method to destroy GLFW window.
247+
*/
248+
protected void disposeWindow() {
249+
bgfx_shutdown();
250+
Callbacks.glfwFreeCallbacks(handle);
251+
GLFW.glfwDestroyWindow(handle);
252+
GLFW.glfwTerminate();
253+
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
254+
}
255+
256+
/**
257+
* @return pointer to the native GLFW window
258+
*/
259+
public final long getHandle() {
260+
return handle;
261+
}
262+
263+
/**
264+
* @return {@link Color} instance, which represents background color for the window
265+
*/
266+
public final Color getColorBg() {
267+
return colorBg;
268+
}
269+
270+
public ImGuiImplBGFX getImGuiBGFX() {
271+
return imGuiBGFX;
272+
}
273+
}

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)