Skip to content

Commit 5ea2712

Browse files
AAstroPhysiCSSpaiR
andauthored
[API] ImGuizmo (#54)
* [API] ImGuizmo * [Example] Fix ImGuizmo demo Co-authored-by: SpaiR <[email protected]>
1 parent db6e03f commit 5ea2712

File tree

9 files changed

+770
-1
lines changed

9 files changed

+770
-1
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "include/imnodes"]
88
path = include/imnodes
99
url = https://github.com/Nelarius/imnodes
10+
[submodule "include/imguizmo"]
11+
path = include/imguizmo
12+
url = https://github.com/CedricGuillemet/ImGuizmo.git

buildSrc/src/main/groovy/imgui/generate/GenerateLibs.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class GenerateLibs extends DefaultTask {
4848

4949
// Copy ImGui h/cpp files
5050
project.copy { CopySpec spec ->
51-
['include/imgui', 'include/imnodes', 'include/imgui-node-editor'].each {
51+
['include/imgui', 'include/imnodes', 'include/imgui-node-editor', 'include/imguizmo'].each {
5252
spec.from(project.rootProject.file(it)) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') }
5353
}
5454
spec.from(project.rootProject.file('imgui-binding/src/main/native'))
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
import imgui.ImGui;
2+
import imgui.extension.imguizmo.ImGuizmo;
3+
import imgui.extension.imguizmo.flag.Mode;
4+
import imgui.extension.imguizmo.flag.Operation;
5+
import imgui.flag.ImGuiCond;
6+
import imgui.flag.ImGuiInputTextFlags;
7+
import imgui.flag.ImGuiWindowFlags;
8+
import imgui.type.ImBoolean;
9+
import imgui.type.ImFloat;
10+
11+
import java.awt.Desktop;
12+
import java.net.URI;
13+
import java.util.Arrays;
14+
15+
import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT;
16+
import static org.lwjgl.glfw.GLFW.GLFW_KEY_R;
17+
import static org.lwjgl.glfw.GLFW.GLFW_KEY_S;
18+
import static org.lwjgl.glfw.GLFW.GLFW_KEY_T;
19+
20+
public class ExampleImGuizmo {
21+
private static final String URL = "https://github.com/CedricGuillemet/ImGuizmo/tree/f7bbbe";
22+
23+
private static final int CAM_DISTANCE = 8;
24+
private static final float CAM_Y_ANGLE = 165.f / 180.f * (float) Math.PI;
25+
private static final float CAM_X_ANGLE = 32.f / 180.f * (float) Math.PI;
26+
private static final float FLT_EPSILON = 1.19209290E-07f;
27+
28+
private static final float[][] OBJECT_MATRICES = {
29+
{
30+
1.f, 0.f, 0.f, 0.f,
31+
0.f, 1.f, 0.f, 0.f,
32+
0.f, 0.f, 1.f, 0.f,
33+
0.f, 0.f, 0.f, 1.f
34+
},
35+
{
36+
1.f, 0.f, 0.f, 0.f,
37+
0.f, 1.f, 0.f, 0.f,
38+
0.f, 0.f, 1.f, 0.f,
39+
2.f, 0.f, 0.f, 1.f
40+
},
41+
{
42+
1.f, 0.f, 0.f, 0.f,
43+
0.f, 1.f, 0.f, 0.f,
44+
0.f, 0.f, 1.f, 0.f,
45+
2.f, 0.f, 2.f, 1.f
46+
},
47+
{
48+
1.f, 0.f, 0.f, 0.f,
49+
0.f, 1.f, 0.f, 0.f,
50+
0.f, 0.f, 1.f, 0.f,
51+
0.f, 0.f, 2.f, 1.f
52+
}
53+
};
54+
55+
private static final float[] IDENTITY_MATRIX = {
56+
1.f, 0.f, 0.f, 0.f,
57+
0.f, 1.f, 0.f, 0.f,
58+
0.f, 0.f, 1.f, 0.f,
59+
0.f, 0.f, 0.f, 1.f
60+
};
61+
62+
private static final float[] VIEW_MANIPULATE_SIZE = new float[]{128f, 128f};
63+
64+
private static final float[] EMPTY = new float[]{0};
65+
66+
private static final float[] INPUT_CAMERA_VIEW = {
67+
1.f, 0.f, 0.f, 0.f,
68+
0.f, 1.f, 0.f, 0.f,
69+
0.f, 0.f, 1.f, 0.f,
70+
0.f, 0.f, 0.f, 1.f
71+
};
72+
73+
private static final float[] INPUT_BOUNDS = new float[]{-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f};
74+
private static final float[] INPUT_BOUNDS_SNAP = new float[]{1f, 1f, 1f};
75+
76+
private static final float[] INPUT_SNAP_VALUE = new float[]{1f, 1f, 1f};
77+
private static final float[] INPUT_MATRIX_TRANSLATION = new float[3];
78+
private static final float[] INPUT_MATRIX_SCALE = new float[3];
79+
private static final float[] INPUT_MATRIX_ROTATION = new float[3];
80+
81+
private static final ImFloat INPUT_FLOAT = new ImFloat();
82+
83+
private static final ImBoolean BOUNDING_SIZE = new ImBoolean(false);
84+
private static final ImBoolean USE_SNAP = new ImBoolean(false);
85+
86+
private static int currentMode = Mode.LOCAL;
87+
private static int currentGizmoOperation;
88+
89+
private static boolean boundSizingSnap = false;
90+
private static boolean firstFrame = true;
91+
92+
public static void show(final ImBoolean showImGuizmoWindow) {
93+
ImGuizmo.beginFrame();
94+
95+
if (ImGui.begin("ImGuizmo Demo", showImGuizmoWindow)) {
96+
ImGui.text("This a demo for ImGuizmo");
97+
98+
ImGui.alignTextToFramePadding();
99+
ImGui.text("Repo:");
100+
ImGui.sameLine();
101+
if (ImGui.button(URL)) {
102+
try {
103+
Desktop.getDesktop().browse(new URI(URL));
104+
} catch (Exception e) {
105+
e.printStackTrace();
106+
}
107+
}
108+
ImGui.separator();
109+
110+
if (firstFrame) {
111+
float[] eye = new float[]{
112+
(float) (Math.cos(CAM_Y_ANGLE) * Math.cos(CAM_X_ANGLE) * CAM_DISTANCE),
113+
(float) (Math.sin(CAM_X_ANGLE) * CAM_DISTANCE),
114+
(float) (Math.sin(CAM_Y_ANGLE) * Math.cos(CAM_X_ANGLE) * CAM_DISTANCE)
115+
};
116+
float[] at = new float[]{0.f, 0.f, 0.f};
117+
float[] up = new float[]{0.f, 1.f, 0.f};
118+
lookAt(eye, at, up, INPUT_CAMERA_VIEW);
119+
firstFrame = false;
120+
}
121+
122+
ImGui.text("Keybindings:");
123+
ImGui.text("T - Translate");
124+
ImGui.text("R - Rotate");
125+
ImGui.text("S - Scale");
126+
ImGui.separator();
127+
128+
if (ImGuizmo.isUsing()) {
129+
ImGui.text("Using gizmo");
130+
if (ImGuizmo.isOver()) {
131+
ImGui.text("Over a gizmo");
132+
}
133+
if (ImGuizmo.isOver(Operation.TRANSLATE)) {
134+
ImGui.text("Over translate gizmo");
135+
} else if (ImGuizmo.isOver(Operation.ROTATE)) {
136+
ImGui.text("Over rotate gizmo");
137+
} else if (ImGuizmo.isOver(Operation.SCALE)) {
138+
ImGui.text("Over scale gizmo");
139+
}
140+
} else {
141+
ImGui.text("Not using gizmo");
142+
}
143+
144+
editTransform(showImGuizmoWindow);
145+
ImGui.end();
146+
}
147+
}
148+
149+
private static void editTransform(final ImBoolean showImGuizmoWindow) {
150+
if (ImGui.isKeyPressed(GLFW_KEY_T)) {
151+
currentGizmoOperation = Operation.TRANSLATE;
152+
} else if (ImGui.isKeyPressed(GLFW_KEY_R)) {
153+
currentGizmoOperation = Operation.ROTATE;
154+
} else if (ImGui.isKeyPressed(GLFW_KEY_S)) {
155+
currentGizmoOperation = Operation.SCALE;
156+
} else if (ImGui.isKeyPressed(GLFW_KEY_LEFT_SHIFT)) {
157+
USE_SNAP.set(!USE_SNAP.get());
158+
}
159+
160+
if (ImGuizmo.isUsing()) {
161+
ImGuizmo.decomposeMatrixToComponents(OBJECT_MATRICES[0], INPUT_MATRIX_TRANSLATION, INPUT_MATRIX_ROTATION, INPUT_MATRIX_SCALE);
162+
}
163+
164+
ImGui.inputFloat3("Tr", INPUT_MATRIX_TRANSLATION, "%.3f", ImGuiInputTextFlags.ReadOnly);
165+
ImGui.inputFloat3("Rt", INPUT_MATRIX_ROTATION, "%.3f", ImGuiInputTextFlags.ReadOnly);
166+
ImGui.inputFloat3("Sc", INPUT_MATRIX_SCALE, "%.3f", ImGuiInputTextFlags.ReadOnly);
167+
168+
if (ImGuizmo.isUsing()) {
169+
ImGuizmo.recomposeMatrixFromComponents(OBJECT_MATRICES[0], INPUT_MATRIX_TRANSLATION, INPUT_MATRIX_ROTATION, INPUT_MATRIX_SCALE);
170+
}
171+
172+
if (currentGizmoOperation != Operation.SCALE) {
173+
if (ImGui.radioButton("Local", currentMode == Mode.LOCAL)) {
174+
currentMode = Mode.LOCAL;
175+
}
176+
ImGui.sameLine();
177+
if (ImGui.radioButton("World", currentMode == Mode.WORLD)) {
178+
currentMode = Mode.WORLD;
179+
}
180+
}
181+
182+
ImGui.checkbox("Snap Checkbox", USE_SNAP);
183+
184+
INPUT_FLOAT.set(INPUT_SNAP_VALUE[0]);
185+
switch (currentGizmoOperation) {
186+
case Operation.TRANSLATE:
187+
ImGui.inputFloat3("Snap Value", INPUT_SNAP_VALUE);
188+
break;
189+
case Operation.ROTATE:
190+
ImGui.inputFloat("Angle Value", INPUT_FLOAT);
191+
float rotateValue = INPUT_FLOAT.get();
192+
Arrays.fill(INPUT_SNAP_VALUE, rotateValue); //avoiding allocation
193+
break;
194+
case Operation.SCALE:
195+
ImGui.inputFloat("Scale Value", INPUT_FLOAT);
196+
float scaleValue = INPUT_FLOAT.get();
197+
Arrays.fill(INPUT_SNAP_VALUE, scaleValue);
198+
break;
199+
}
200+
201+
ImGui.checkbox("Show Bound Sizing", BOUNDING_SIZE);
202+
203+
if (BOUNDING_SIZE.get()) {
204+
if (ImGui.checkbox("BoundSizingSnap", boundSizingSnap)) {
205+
boundSizingSnap = !boundSizingSnap;
206+
}
207+
ImGui.sameLine();
208+
ImGui.inputFloat3("Snap", INPUT_BOUNDS_SNAP);
209+
}
210+
211+
ImGui.setNextWindowPos(ImGui.getMainViewport().getPosX() + 100, ImGui.getMainViewport().getPosY() + 100, ImGuiCond.Once);
212+
ImGui.setNextWindowSize(800, 400, ImGuiCond.Once);
213+
ImGui.begin("Gizmo", showImGuizmoWindow);
214+
ImGui.beginChild("prevent_window_from_moving_by_drag", 0, 0, false, ImGuiWindowFlags.NoMove);
215+
216+
float aspect = ImGui.getWindowWidth() / ImGui.getWindowHeight();
217+
float[] cameraProjection = perspective(27, aspect, 0.1f, 100f);
218+
219+
ImGuizmo.setOrthographic(false);
220+
ImGuizmo.setEnabled(true);
221+
ImGuizmo.setDrawList();
222+
223+
float windowWidth = ImGui.getWindowWidth();
224+
float windowHeight = ImGui.getWindowHeight();
225+
ImGuizmo.setRect(ImGui.getWindowPosX(), ImGui.getWindowPosY(), windowWidth, windowHeight);
226+
227+
ImGuizmo.drawGrid(INPUT_CAMERA_VIEW, cameraProjection, IDENTITY_MATRIX, 100);
228+
ImGuizmo.setId(0);
229+
ImGuizmo.drawCubes(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0]);
230+
231+
if (USE_SNAP.get() && BOUNDING_SIZE.get() && boundSizingSnap) {
232+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode, INPUT_SNAP_VALUE, INPUT_BOUNDS, INPUT_BOUNDS_SNAP);
233+
} else if (USE_SNAP.get() && BOUNDING_SIZE.get()) {
234+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode, INPUT_SNAP_VALUE, INPUT_BOUNDS);
235+
} else if (BOUNDING_SIZE.get() && boundSizingSnap) {
236+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode, EMPTY, INPUT_BOUNDS, INPUT_BOUNDS_SNAP);
237+
} else if (BOUNDING_SIZE.get()) {
238+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode, EMPTY, INPUT_BOUNDS);
239+
} else if (USE_SNAP.get()) {
240+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode, INPUT_SNAP_VALUE);
241+
} else {
242+
ImGuizmo.manipulate(INPUT_CAMERA_VIEW, cameraProjection, OBJECT_MATRICES[0], currentGizmoOperation, currentMode);
243+
}
244+
245+
float viewManipulateRight = ImGui.getWindowPosX() + windowWidth;
246+
float viewManipulateTop = ImGui.getWindowPosY();
247+
ImGuizmo.viewManipulate(INPUT_CAMERA_VIEW, CAM_DISTANCE, new float[]{viewManipulateRight - 128, viewManipulateTop}, VIEW_MANIPULATE_SIZE, 0x10101010);
248+
249+
ImGui.endChild();
250+
ImGui.end();
251+
}
252+
253+
private static float[] perspective(float fovY, float aspect, float near, float far) {
254+
float ymax, xmax;
255+
ymax = (float) (near * Math.tan(fovY * Math.PI / 180.0f));
256+
xmax = ymax * aspect;
257+
return frustum(-xmax, xmax, -ymax, ymax, near, far);
258+
}
259+
260+
private static float[] frustum(float left, float right, float bottom, float top, float near, float far) {
261+
float[] r = new float[16];
262+
float temp = 2.0f * near;
263+
float temp2 = right - left;
264+
float temp3 = top - bottom;
265+
float temp4 = far - near;
266+
r[0] = temp / temp2;
267+
r[1] = 0.0f;
268+
r[2] = 0.0f;
269+
r[3] = 0.0f;
270+
r[4] = 0.0f;
271+
r[5] = temp / temp3;
272+
r[6] = 0.0f;
273+
r[7] = 0.0f;
274+
r[8] = (right + left) / temp2;
275+
r[9] = (top + bottom) / temp3;
276+
r[10] = (-far - near) / temp4;
277+
r[11] = -1.0f;
278+
r[12] = 0.0f;
279+
r[13] = 0.0f;
280+
r[14] = (-temp * far) / temp4;
281+
r[15] = 0.0f;
282+
return r;
283+
}
284+
285+
private static float[] cross(float[] a, float[] b) {
286+
float[] r = new float[3];
287+
r[0] = a[1] * b[2] - a[2] * b[1];
288+
r[1] = a[2] * b[0] - a[0] * b[2];
289+
r[2] = a[0] * b[1] - a[1] * b[0];
290+
return r;
291+
}
292+
293+
private static float dot(float[] a, float[] b) {
294+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
295+
}
296+
297+
private static float[] normalize(float[] a) {
298+
float[] r = new float[3];
299+
float il = (float) (1.f / (Math.sqrt(dot(a, a)) + FLT_EPSILON));
300+
r[0] = a[0] * il;
301+
r[1] = a[1] * il;
302+
r[2] = a[2] * il;
303+
return r;
304+
}
305+
306+
private static void lookAt(float[] eye, float[] at, float[] up, float[] m16) {
307+
float[] x;
308+
float[] y;
309+
float[] z;
310+
float[] tmp = new float[3];
311+
312+
tmp[0] = eye[0] - at[0];
313+
tmp[1] = eye[1] - at[1];
314+
tmp[2] = eye[2] - at[2];
315+
z = normalize(tmp);
316+
y = normalize(up);
317+
318+
tmp = cross(y, z);
319+
x = normalize(tmp);
320+
321+
tmp = cross(z, x);
322+
y = normalize(tmp);
323+
324+
m16[0] = x[0];
325+
m16[1] = y[0];
326+
m16[2] = z[0];
327+
m16[3] = 0.0f;
328+
m16[4] = x[1];
329+
m16[5] = y[1];
330+
m16[6] = z[1];
331+
m16[7] = 0.0f;
332+
m16[8] = x[2];
333+
m16[9] = y[2];
334+
m16[10] = z[2];
335+
m16[11] = 0.0f;
336+
m16[12] = -dot(x, eye);
337+
m16[13] = -dot(y, eye);
338+
m16[14] = -dot(z, eye);
339+
m16[15] = 1.0f;
340+
}
341+
}

example/src/main/java/Extra.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class Extra {
77
private static final ImBoolean SHOW_IMNODES_DEMO_WINDOW = new ImBoolean(false);
88
private static final ImBoolean SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW = new ImBoolean(false);
99
private static final ImBoolean SHOW_DRAG_N_DROP_WINDOW = new ImBoolean(false);
10+
private static final ImBoolean SHOW_IMGUIZMO_DEMO = new ImBoolean(false);
1011

1112
private static final Graph GRAPH = new Graph();
1213

@@ -16,6 +17,7 @@ public static void show(final Application app) {
1617
ImGui.checkbox("Show ImNodes Demo Window", SHOW_IMNODES_DEMO_WINDOW);
1718
ImGui.checkbox("Show imgui-node-editor Demo Window", SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW);
1819
ImGui.checkbox("Show Drag'N'Drop Demo Window", SHOW_DRAG_N_DROP_WINDOW);
20+
ImGui.checkbox("Show ImGuizmo Demo Window", SHOW_IMGUIZMO_DEMO);
1921

2022
if (SHOW_DEMO_WINDOW.get()) {
2123
ImGui.showDemoWindow(SHOW_DEMO_WINDOW);
@@ -29,6 +31,10 @@ public static void show(final Application app) {
2931
ExampleImGuiNodeEditor.show(SHOW_IMGUI_NODE_EDITOR_DEMO_WINDOW, GRAPH);
3032
}
3133

34+
if (SHOW_IMGUIZMO_DEMO.get()) {
35+
ExampleImGuizmo.show(SHOW_IMGUIZMO_DEMO);
36+
}
37+
3238
if (SHOW_DRAG_N_DROP_WINDOW.get()) {
3339
ExampleDragAndDrop.show(SHOW_DRAG_N_DROP_WINDOW);
3440
}

0 commit comments

Comments
 (0)