Java tutorial
/* * Copyright LWJGL. All rights reserved. * License terms: https://www.lwjgl.org/license */ package org.lwjgl.demo.glfw; import org.lwjgl.*; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.*; import org.lwjgl.opengl.*; import org.lwjgl.system.*; import org.lwjgl.system.windows.*; import java.io.*; import java.nio.*; import java.util.*; import static java.lang.Math.*; import static org.lwjgl.demo.util.IOUtil.*; import static org.lwjgl.glfw.Callbacks.*; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.*; import static org.lwjgl.stb.STBImage.*; import static org.lwjgl.system.APIUtil.*; import static org.lwjgl.system.MemoryStack.*; import static org.lwjgl.system.MemoryUtil.*; import static org.lwjgl.system.windows.User32.*; /** GLFW events demo. */ public final class Events { private static final Map<Integer, String> KEY_CODES = apiClassTokens( (field, value) -> field.getName().startsWith("GLFW_KEY_"), null, GLFW.class); private Events() { } public static void main(String[] args) { GLFWErrorCallback errorCB = GLFWErrorCallback.createPrint(System.err); glfwSetErrorCallback(errorCB); System.err.println("---- [ Error callback test ] ----"); glfwDefaultWindowHints(); System.err.println("---- [ Error callback done ] ----"); System.err.flush(); if (!glfwInit()) { throw new IllegalStateException("Failed to initialize GLFW."); } System.out.println("GLFW initialized"); try { demo(); } finally { glfwTerminate(); Objects.requireNonNull(glfwSetErrorCallback(null)).free(); } } private static int gcd(int a, int b) { return b != 0 ? gcd(b, a % b) : a; } private static String ratio(int w, int h) { int gcd = gcd(w, h); int ratioX = w / gcd; int ratioY = h / gcd; if (ratioX == 8) { ratioX <<= 1; ratioY <<= 1; } return ratioX + ":" + ratioY; } private static void demo() { if (Platform.get() == Platform.WINDOWS) { if (User32.Functions.SetThreadDpiAwarenessContext != NULL) { SetThreadDpiAwarenessContext(IsValidDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ? DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); } } int WIDTH = 640; int HEIGHT = 480; try (MemoryStack s = stackPush()) { IntBuffer pi = s.mallocInt(1); IntBuffer pj = s.mallocInt(1); FloatBuffer px = s.mallocFloat(1); FloatBuffer py = s.mallocFloat(1); long primaryMonitor = glfwGetPrimaryMonitor(); PointerBuffer monitors = Objects.requireNonNull(glfwGetMonitors()); for (int i = 0; i < monitors.remaining(); i++) { long monitor = monitors.get(i); System.out.format("%nMonitor %d:%n----------%n", i); System.out.format("\tName: %s%s%n", glfwGetMonitorName(monitor), primaryMonitor == monitor ? " (primary)" : ""); glfwGetMonitorPhysicalSize(monitor, pi, pj); int widthMM = pi.get(0); int heightMM = pj.get(0); glfwGetMonitorPos(monitor, pi, pj); int xpos = pi.get(0); int ypos = pj.get(0); glfwGetMonitorContentScale(monitor, px, py); float xscale = px.get(0); float yscale = py.get(0); if (primaryMonitor == monitor && Platform.get() != Platform.MACOSX) { WIDTH = round(WIDTH * xscale); HEIGHT = round(HEIGHT * yscale); } double MM_TO_INCH = 0.0393701; GLFWVidMode mode = Objects.requireNonNull(glfwGetVideoMode(monitor)); System.out.format("\tCurrent mode : %d x %d @ %d Hz (%s, R%dG%dB%d)%n", mode.width(), mode.height(), mode.refreshRate(), ratio(mode.width(), mode.height()), mode.redBits(), mode.greenBits(), mode.blueBits()); System.out.format("\tContent scale : %f x %f%n", xscale, yscale); if (xscale != 1.0f || yscale != 1.0f) { System.out.format("\tContent size : %d x %d%n", round(mode.width() / xscale), round(mode.height() / yscale)); } System.out.format("\tPhysical size : %dmm x %dmm (%d\", %d ppi)%n", widthMM, heightMM, round(Math.sqrt(widthMM * widthMM + heightMM * heightMM) * MM_TO_INCH), // inches round(mode.width() / (widthMM * MM_TO_INCH)) // dpi ); System.out.format("\tVirtual position: %d, %d%n", xpos, ypos); } } glfwDefaultWindowHints(); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); long window = glfwCreateWindow(WIDTH, HEIGHT, "GLFW Event Demo", NULL, NULL); if (window == NULL) { throw new IllegalStateException("Failed to create GLFW window."); } System.out.format("%nWindow opened:%n--------------%n"); try (MemoryStack s = stackPush()) { IntBuffer pi = s.mallocInt(1); IntBuffer pj = s.mallocInt(1); IntBuffer pk = s.mallocInt(1); IntBuffer pl = s.mallocInt(1); FloatBuffer px = s.mallocFloat(1); FloatBuffer py = s.mallocFloat(1); glfwGetWindowSize(window, pi, pj); System.out.format("\tSize: %d x %d%n", pi.get(0), pj.get(0)); glfwGetWindowFrameSize(window, pi, pj, pk, pl); System.out.format("\tFrame size: %d, %d, %d, %d%n", pi.get(0), pj.get(0), pk.get(0), pl.get(0)); glfwGetWindowContentScale(window, px, py); System.out.format("\tContent scale: %f x %f%n", px.get(0), py.get(0)); glfwGetFramebufferSize(window, pi, pj); System.out.format("\tFramebuffer size: %d x %d%n", pi.get(0), pj.get(0)); glfwGetWindowPos(window, pi, pj); System.out.format("\tPosition: %d, %d%n%n", pi.get(0), pj.get(0)); } IntBuffer w = memAllocInt(1); IntBuffer h = memAllocInt(1); IntBuffer comp = memAllocInt(1); long cursor; // Cursor { ByteBuffer png; try { png = ioResourceToByteBuffer("demo/cursor.png", 1024); } catch (IOException e) { throw new RuntimeException(e); } ByteBuffer pixels = Objects.requireNonNull(stbi_load_from_memory(png, w, h, comp, 0)); try (GLFWImage img = GLFWImage.malloc().set(w.get(0), h.get(0), pixels)) { cursor = glfwCreateCursor(img, 0, 8); glfwSetCursor(window, cursor); } finally { stbi_image_free(pixels); } } // Icons { ByteBuffer icon16; ByteBuffer icon32; try { icon16 = ioResourceToByteBuffer("lwjgl16.png", 2048); icon32 = ioResourceToByteBuffer("lwjgl32.png", 4096); } catch (Exception e) { throw new RuntimeException(e); } try (GLFWImage.Buffer icons = GLFWImage.malloc(2)) { ByteBuffer pixels16 = Objects.requireNonNull(stbi_load_from_memory(icon16, w, h, comp, 4)); icons.position(0).width(w.get(0)).height(h.get(0)).pixels(pixels16); ByteBuffer pixels32 = Objects.requireNonNull(stbi_load_from_memory(icon32, w, h, comp, 4)); icons.position(1).width(w.get(0)).height(h.get(0)).pixels(pixels32); icons.position(0); glfwSetWindowIcon(window, icons); stbi_image_free(pixels32); stbi_image_free(pixels16); } } memFree(comp); memFree(h); memFree(w); glfwSetMonitorCallback((monitor, event) -> printEvent("Monitor", "%s", monitor, event == GLFW_CONNECTED ? "connected" : "disconnected")); glfwSetJoystickCallback((joy, event) -> printEvent("Joystick", "%s %s", joy, glfwGetJoystickName(joy), event == GLFW_CONNECTED ? "connected" : "disconnected")); glfwSetWindowPosCallback(window, (windowHnd, xpos, ypos) -> printEvent("moved to %d, %d", windowHnd, xpos, ypos)); glfwSetWindowSizeCallback(window, (windowHnd, width, height) -> printEvent("resized to %d x %d", windowHnd, width, height)); glfwSetWindowCloseCallback(window, windowHnd -> printEvent("closed", windowHnd)); glfwSetWindowRefreshCallback(window, windowHnd -> printEvent("refreshed", windowHnd)); glfwSetWindowFocusCallback(window, (windowHnd, focused) -> printEvent(focused ? "gained focus" : "lost focus", windowHnd)); glfwSetWindowIconifyCallback(window, (windowHnd, iconified) -> printEvent(iconified ? "iconified" : "restored", windowHnd)); glfwSetWindowMaximizeCallback(window, (windowHnd, maximized) -> printEvent(maximized ? "maximized" : "restored", windowHnd)); glfwSetWindowContentScaleCallback(window, (windowHnd, xscale, yscale) -> printEvent("content scale changed to %d x %d", windowHnd, xscale, yscale)); glfwSetFramebufferSizeCallback(window, (windowHnd, width, height) -> printEvent("framebuffer resized to %d x %d", windowHnd, width, height)); glfwSetKeyCallback(window, (windowHnd, key, scancode, action, mods) -> { String state; switch (action) { case GLFW_RELEASE: state = "released"; break; case GLFW_PRESS: state = "pressed"; break; case GLFW_REPEAT: state = "repeated"; break; default: throw new IllegalArgumentException(String.format("Unsupported key action: 0x%X", action)); } printEvent("key %s[%s - %d] was %s", windowHnd, getModState(mods), KEY_CODES.get(key), scancode, state); if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) { glfwSetWindowShouldClose(windowHnd, true); } }); glfwSetCharCallback(window, (windowHnd, codepoint) -> printEvent("char %s", windowHnd, Character.toString((char) codepoint))); glfwSetCharModsCallback(window, (windowHnd, codepoint, mods) -> printEvent("char mods %s%s", windowHnd, getModState(mods), Character.toString((char) codepoint))); glfwSetMouseButtonCallback(window, (windowHnd, button, action, mods) -> { String state; switch (action) { case GLFW_RELEASE: state = "released"; break; case GLFW_PRESS: state = "pressed"; break; default: throw new IllegalArgumentException(String.format("Unsupported mouse button action: 0x%X", action)); } printEvent("mouse button %s[0x%X] was %s", windowHnd, getModState(mods), button, state); }); glfwSetCursorPosCallback(window, (windowHnd, xpos, ypos) -> printEvent("cursor moved to %f, %f", windowHnd, xpos, ypos)); glfwSetCursorEnterCallback(window, (windowHnd, entered) -> printEvent("cursor %s", windowHnd, entered ? "entered" : "left")); glfwSetScrollCallback(window, (windowHnd, xoffset, yoffset) -> printEvent("scroll by %f, %f", windowHnd, xoffset, yoffset)); glfwSetDropCallback(window, (windowHnd, count, names) -> { printEvent("drop %d file%s", windowHnd, count, count == 1 ? "" : "s"); for (int i = 0; i < count; i++) { System.out.format("\t%d: %s%n", i + 1, GLFWDropCallback.getName(names, i)); } }); glfwMakeContextCurrent(window); GL.createCapabilities(); glfwShowWindow(window); glfwSwapInterval(1); glClearColor(1.0f, 1.0f, 1.0f, 0.0f); while (!glfwWindowShouldClose(window)) { glfwWaitEvents(); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); } glfwFreeCallbacks(window); Objects.requireNonNull(glfwSetJoystickCallback(null)).free(); Objects.requireNonNull(glfwSetMonitorCallback(null)).free(); glfwDestroyCursor(cursor); glfwDestroyWindow(window); } private static String getModState(int mods) { if (mods == 0) { return ""; } StringBuilder modState = new StringBuilder(16); if ((mods & GLFW_MOD_SHIFT) != 0) { modState.append("SHIFT+"); } if ((mods & GLFW_MOD_CONTROL) != 0) { modState.append("CONTROL+"); } if ((mods & GLFW_MOD_ALT) != 0) { modState.append("ALT+"); } if ((mods & GLFW_MOD_SUPER) != 0) { modState.append("SUPER+"); } return modState.toString(); } private static void printEvent(String format, long window, Object... args) { printEvent("Window", format, window, args); } private static void printEvent(String type, String format, long object, Object... args) { Object[] formatArgs = new Object[3 + args.length]; formatArgs[0] = glfwGetTime(); formatArgs[1] = type; formatArgs[2] = object; System.arraycopy(args, 0, formatArgs, 3, args.length); System.out.format("%.3f: %s [0x%X] " + format + "%n", formatArgs); } }