|
| 1 | +/* |
| 2 | + * Copyright LWJGL. All rights reserved. |
| 3 | + * License terms: http://lwjgl.org/license.php |
| 4 | + */ |
| 5 | +package org.lwjgl.demo.intro; |
| 6 | + |
| 7 | +import static org.lwjgl.glfw.GLFW.*; |
| 8 | +import static org.lwjgl.opengl.GL.*; |
| 9 | +import static org.lwjgl.system.MemoryUtil.*; |
| 10 | + |
| 11 | +import org.lwjgl.glfw.GLFWMouseButtonCallbackI; |
| 12 | + |
| 13 | +/** |
| 14 | + * In this part we will see how callbacks work. Callbacks mean any method which we can register in a native library so |
| 15 | + * that the native library can call use back and invoke our callback method whenever it wants to. |
| 16 | + * <p> |
| 17 | + * One example of where callbacks occur frequently is GLFW. GLFW provides some number of different callbacks for various |
| 18 | + * events that happen on a window, such as resizing, maximizing, minimizing and mouse or keyboard events. |
| 19 | + * <p> |
| 20 | + * Now, before we go into using callback with LWJGL 3 and GLFW, we should first get a clear picture of what a callback |
| 21 | + * looks in the native library, which LWJGL 3 tries to provide a Java counterpart for. |
| 22 | + * <p> |
| 23 | + * In a native library like GLFW a callback is nothing more than a function pointer. This means that it is a physical |
| 24 | + * virtual memory address pointing to an executable piece of code, a function. The function pointer also has a type to |
| 25 | + * make it callable in C. This function type consists of the parameter types and the return type, just like a method |
| 26 | + * signature in Java including the return type. So, both caller and callee agree on a defined set of parameters and a |
| 27 | + * return type to expect when the callback function is called. |
| 28 | + * <p> |
| 29 | + * When LWJGL 3 maps this concept of a function pointer into Java, it provides the user (that means you) with a Java |
| 30 | + * interface type that contains a single method. This method has the same (or similar) signature and return type as the |
| 31 | + * native callback function. If you want to see an example, look at {@link GLFWMouseButtonCallbackI}. It is an interface |
| 32 | + * with a single non-default method which must be implemented and will be called whenever the native library calls the |
| 33 | + * callback. |
| 34 | + * <p> |
| 35 | + * The fact that it is an interface with a single method makes it applicable to be the target of a Java 8 Lambda method |
| 36 | + * or a Java 8 method reference. That means, with callbacks we need not provide an actual implementation of the callback |
| 37 | + * interface by either anonymously or explicitly creating a class implementing that interface, but we can use Java 8 |
| 38 | + * Lambda methods and Java 8 method references with a compatible signature. |
| 39 | + * <p> |
| 40 | + * If you are not yet familiar with Java 8 Lambda methods or Java 8 method references, please look them up on the Oracle |
| 41 | + * documentation. We will make use of them in the example code below. |
| 42 | + * |
| 43 | + * @author Kai Burjack |
| 44 | + */ |
| 45 | +public class Intro5 { |
| 46 | + |
| 47 | + /** |
| 48 | + * Callback method used with Java 8 method references. See the main() method below. |
| 49 | + */ |
| 50 | + private static void mouseCallback(long win, int button, int action, int mods) { |
| 51 | + /* Print a message when the user pressed down a mouse button */ |
| 52 | + if (action == GLFW_PRESS) { |
| 53 | + System.out.println("Pressed!"); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * In this demo we will register a callback with GLFW. We will use a mouse callback which notifies us whenever a |
| 59 | + * mouse button was pressed or released. |
| 60 | + */ |
| 61 | + public static void main(String[] args) { |
| 62 | + glfwInit(); |
| 63 | + long window = createWindow(); |
| 64 | + |
| 65 | + /* |
| 66 | + * The following is one way of registering a callback. In this case with GLFW for receiving mouse button events |
| 67 | + * happening for the window. |
| 68 | + * |
| 69 | + * We use an instance of an anonymous class which implements the callback interface GLFWMouseButtonCallbackI. |
| 70 | + * Instead of using the GLFWMouseButtonCallbackI interface, we could also just use the GLFWMouseButtonCallback |
| 71 | + * class (without the 'I' suffix). It would work the same, since that class implements the interface. But there |
| 72 | + * is a reason why that class exists in the first place, which will be covered later. |
| 73 | + */ |
| 74 | + glfwSetMouseButtonCallback(window, new GLFWMouseButtonCallbackI() { |
| 75 | + /** |
| 76 | + * This is the single method of the callback interface which we must provide an implementation for. |
| 77 | + * <p> |
| 78 | + * This method will get called by the native library (GLFW) whenever some event happens with a mouse button. |
| 79 | + * For a more detailed explanation of the GLFW callback itself, see |
| 80 | + * <a href="http://www.glfw.org/docs/latest/group__input.html#gaef49b72d84d615bca0a6ed65485e035d">the GLFW |
| 81 | + * documentation</a>. |
| 82 | + * <p> |
| 83 | + * For now, we just do nothing in this method. We just assume that it was registered successfully. |
| 84 | + */ |
| 85 | + public void invoke(long window, int button, int action, int mods) { |
| 86 | + /* We don't do anything here. */ |
| 87 | + } |
| 88 | + }); |
| 89 | + |
| 90 | + /* |
| 91 | + * The next possible way is to use Java 8 Lambda methods to avoid having to type the actual Java interface type |
| 92 | + * name. You either know the method signature or use an IDE with autocomplete/autosuggest support, such as |
| 93 | + * IntelliJ IDEA. |
| 94 | + */ |
| 95 | + glfwSetMouseButtonCallback(window, (long win, int button, int action, int mods) -> { |
| 96 | + /* We also don't do anything here. */ |
| 97 | + }); |
| 98 | + |
| 99 | + /* |
| 100 | + * The last possible way to register a callback should look more familiar to C/C++ programmers. We use a Java 8 |
| 101 | + * method reference. See the method mouseCallback() above for what happens when we receive a mouse event. |
| 102 | + */ |
| 103 | + glfwSetMouseButtonCallback(window, Intro5::mouseCallback); |
| 104 | + |
| 105 | + /* |
| 106 | + * Now, when we start the application and click inside the window using any mouse button, we should see a |
| 107 | + * message printed. |
| 108 | + */ |
| 109 | + |
| 110 | + /* |
| 111 | + * We don't render anything. Just an empty window. The focus of this introduction is just callbacks. |
| 112 | + */ |
| 113 | + while (!glfwWindowShouldClose(window)) { |
| 114 | + glfwPollEvents(); |
| 115 | + } |
| 116 | + glfwTerminate(); |
| 117 | + System.out.println("Fin."); |
| 118 | + } |
| 119 | + |
| 120 | + private static long createWindow() { |
| 121 | + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); |
| 122 | + long window = glfwCreateWindow(800, 600, "Intro5", NULL, NULL); |
| 123 | + glfwMakeContextCurrent(window); |
| 124 | + createCapabilities(); |
| 125 | + return window; |
| 126 | + } |
| 127 | + |
| 128 | +} |
0 commit comments