From ea9fd215009abb2d3ef90b0143af88c183b115a7 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 3 Nov 2024 10:46:22 +0800 Subject: [PATCH] Update Lwjgl3ify (#233) * sync lwjgl3ify * sync lwjgl3ify * fix missing symbol * update * fix config name --- .../net/minecraft/client/Minecraft.java.patch | 91 +-- .../common/ForgeEarlyConfig.java | 47 ++ .../fml/client/FMLClientHandler.java | 3 + src/main/java/org/lwjgl/Sys.java | 2 +- src/main/java/org/lwjgl/input/Controller.java | 72 +++ .../java/org/lwjgl/input/Controllers.java | 101 ++++ src/main/java/org/lwjgl/input/Keyboard.java | 50 +- src/main/java/org/lwjgl/openal/AL.java | 12 + src/main/java/org/lwjgl/opengl/Display.java | 202 ++++++- .../java/org/lwjgl/test/opengl/Gears.java | 335 ----------- .../lwjgl/test/spaceinvaders/AlienEntity.java | 141 ----- .../org/lwjgl/test/spaceinvaders/Entity.java | 162 ----- .../org/lwjgl/test/spaceinvaders/Game.java | 559 ------------------ .../lwjgl/test/spaceinvaders/ShipEntity.java | 81 --- .../lwjgl/test/spaceinvaders/ShotEntity.java | 103 ---- .../test/spaceinvaders/SoundManager.java | 173 ------ .../org/lwjgl/test/spaceinvaders/Sprite.java | 110 ---- .../org/lwjgl/test/spaceinvaders/Texture.java | 167 ------ .../test/spaceinvaders/TextureLoader.java | 277 --------- src/main/java/org/lwjgl/util/Rectangle.java | 7 + 20 files changed, 529 insertions(+), 2166 deletions(-) create mode 100644 src/main/java/org/lwjgl/input/Controller.java create mode 100644 src/main/java/org/lwjgl/input/Controllers.java delete mode 100644 src/main/java/org/lwjgl/test/opengl/Gears.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/AlienEntity.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/Entity.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/Game.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/ShipEntity.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/ShotEntity.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/SoundManager.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/Sprite.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/Texture.java delete mode 100644 src/main/java/org/lwjgl/test/spaceinvaders/TextureLoader.java diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 74788749e..2da0f8e2f 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -880,7 +880,18 @@ { this.field_71460_t.field_78516_c.func_187460_a(enumhand); return; -@@ -1662,6 +1632,11 @@ +@@ -1614,6 +1584,10 @@ + + public void func_71352_k() + { ++ if (net.minecraftforge.common.ForgeEarlyConfig.WINDOW_BORDERLESS_REPLACES_FULLSCREEN) { ++ Display.toggleBorderless(); ++ return; ++ } + try + { + this.field_71431_Q = !this.field_71431_Q; +@@ -1662,6 +1636,11 @@ } Display.setFullscreen(this.field_71431_Q); @@ -892,7 +903,7 @@ Display.setVSyncEnabled(this.field_71474_y.field_74352_v); this.func_175601_h(); } -@@ -1708,6 +1683,8 @@ +@@ -1708,6 +1687,8 @@ --this.field_71467_ac; } @@ -901,7 +912,7 @@ this.field_71424_I.func_76320_a("gui"); if (!this.field_71445_n) -@@ -1736,7 +1713,7 @@ +@@ -1736,7 +1717,7 @@ { if (this.field_71439_g.func_110143_aJ() <= 0.0F && !(this.field_71462_r instanceof GuiGameOver)) { @@ -910,7 +921,7 @@ } else if (this.field_71439_g.func_70608_bn() && this.field_71441_e != null) { -@@ -1745,7 +1722,7 @@ +@@ -1745,7 +1726,7 @@ } else if (this.field_71462_r != null && this.field_71462_r instanceof GuiSleepMP && !this.field_71439_g.func_70608_bn()) { @@ -919,7 +930,7 @@ } if (this.field_71462_r != null) -@@ -1892,12 +1869,7 @@ +@@ -1892,12 +1873,7 @@ if (!this.field_71445_n && this.field_71441_e != null) { @@ -933,7 +944,7 @@ } this.field_71424_I.func_76318_c("particles"); -@@ -1914,6 +1886,7 @@ +@@ -1914,6 +1890,7 @@ } this.field_71424_I.func_76319_b(); @@ -941,7 +952,7 @@ this.field_71423_H = func_71386_F(); } -@@ -2019,6 +1992,7 @@ +@@ -2019,6 +1996,7 @@ } } } @@ -949,7 +960,7 @@ } this.func_184117_aA(); -@@ -2095,16 +2069,16 @@ +@@ -2095,16 +2073,16 @@ { this.func_190521_a("debug.help.message"); GuiNewChat guinewchat = this.field_71456_v.func_146158_b(); @@ -976,7 +987,7 @@ return true; } else if (p_184122_1_ == 20) -@@ -2136,7 +2110,7 @@ +@@ -2136,7 +2114,7 @@ } else if (this.field_71474_y.field_74320_O == 1) { @@ -985,7 +996,7 @@ } } -@@ -2223,16 +2197,27 @@ +@@ -2223,16 +2201,27 @@ this.field_71442_b.func_78766_c(this.field_71439_g); } @@ -1023,7 +1034,7 @@ } } else -@@ -2265,6 +2250,8 @@ +@@ -2265,6 +2254,8 @@ { while (Mouse.next()) { @@ -1032,7 +1043,7 @@ int i = Mouse.getEventButton(); KeyBinding.func_74510_a(i - 100, Mouse.getEventButtonState()); -@@ -2320,24 +2307,19 @@ +@@ -2320,24 +2311,19 @@ this.field_71462_r.func_146274_d(); } } @@ -1061,7 +1072,7 @@ System.gc(); ISaveHandler isavehandler = this.field_71469_aa.func_75804_a(p_71371_1_, false); WorldInfo worldinfo = isavehandler.func_75757_d(); -@@ -2358,15 +2340,11 @@ +@@ -2358,15 +2344,11 @@ YggdrasilAuthenticationService yggdrasilauthenticationservice = new YggdrasilAuthenticationService(this.field_110453_aa, UUID.randomUUID().toString()); MinecraftSessionService minecraftsessionservice = yggdrasilauthenticationservice.createMinecraftSessionService(); GameProfileRepository gameprofilerepository = yggdrasilauthenticationservice.createProfileRepository(); @@ -1079,7 +1090,7 @@ this.field_71437_Z.func_71256_s(); this.field_71455_al = true; } -@@ -2383,6 +2361,12 @@ +@@ -2383,6 +2365,12 @@ while (!this.field_71437_Z.func_71200_ad()) { @@ -1092,7 +1103,7 @@ String s = this.field_71437_Z.func_71195_b_(); if (s != null) -@@ -2398,17 +2382,24 @@ +@@ -2398,17 +2386,24 @@ { Thread.sleep(200L); } @@ -1121,7 +1132,7 @@ this.field_71453_ak = networkmanager; } -@@ -2419,6 +2410,8 @@ +@@ -2419,6 +2414,8 @@ public void func_71353_a(@Nullable WorldClient p_71353_1_, String p_71353_2_) { @@ -1130,7 +1141,7 @@ if (p_71353_1_ == null) { NetHandlerPlayClient nethandlerplayclient = this.func_147114_u(); -@@ -2431,6 +2424,18 @@ +@@ -2431,6 +2428,18 @@ if (this.field_71437_Z != null && this.field_71437_Z.func_175578_N()) { this.field_71437_Z.func_71263_m(); @@ -1149,7 +1160,7 @@ } this.field_71437_Z = null; -@@ -2452,8 +2457,9 @@ +@@ -2452,8 +2461,9 @@ { this.field_110448_aq.func_148529_f(); this.field_71456_v.func_181029_i(); @@ -1160,7 +1171,7 @@ } this.field_147127_av.func_147690_c(); -@@ -2470,6 +2476,7 @@ +@@ -2470,6 +2480,7 @@ } TileEntityRendererDispatcher.field_147556_a.func_147543_a(p_71353_1_); @@ -1168,7 +1179,7 @@ if (p_71353_1_ != null) { -@@ -2478,9 +2485,7 @@ +@@ -2478,9 +2489,7 @@ AuthenticationService authenticationservice = new YggdrasilAuthenticationService(this.field_110453_aa, UUID.randomUUID().toString()); MinecraftSessionService minecraftsessionservice = authenticationservice.createMinecraftSessionService(); GameProfileRepository gameprofilerepository = authenticationservice.createProfileRepository(); @@ -1179,7 +1190,7 @@ TileEntitySkull.func_184293_a(playerprofilecache); TileEntitySkull.func_184294_a(minecraftsessionservice); PlayerProfileCache.func_187320_a(false); -@@ -2524,13 +2529,9 @@ +@@ -2524,13 +2533,9 @@ this.field_175622_Z = null; EntityPlayerSP entityplayersp = this.field_71439_g; @@ -1195,7 +1206,7 @@ this.field_71439_g.field_71093_bK = p_71354_1_; this.field_175622_Z = this.field_71439_g; this.field_71439_g.func_70065_x(); -@@ -2544,7 +2545,7 @@ +@@ -2544,7 +2549,7 @@ if (this.field_71462_r instanceof GuiGameOver) { @@ -1204,7 +1215,7 @@ } } -@@ -2578,159 +2579,8 @@ +@@ -2578,159 +2583,8 @@ { if (this.field_71476_x != null && this.field_71476_x.field_72313_a != RayTraceResult.Type.MISS) { @@ -1366,7 +1377,7 @@ } } -@@ -2778,7 +2628,14 @@ +@@ -2778,7 +2632,14 @@ { public String call() { @@ -1382,7 +1393,7 @@ } }); p_71396_1_.func_85056_g().func_189529_a("GL Caps", new ICrashReportDetail() -@@ -2795,10 +2652,7 @@ +@@ -2795,10 +2656,7 @@ return Minecraft.this.field_71474_y.field_178881_t ? "Yes" : "No"; } }); @@ -1394,7 +1405,7 @@ { public String call() throws Exception { -@@ -2810,13 +2664,10 @@ +@@ -2810,13 +2668,10 @@ } else { @@ -1410,7 +1421,7 @@ p_71396_1_.func_85056_g().func_189529_a("Type", new ICrashReportDetail() { public String call() throws Exception -@@ -2883,11 +2734,11 @@ +@@ -2883,11 +2738,11 @@ return field_71432_P; } @@ -1423,7 +1434,7 @@ public void run() { Minecraft.this.func_110436_a(); -@@ -2895,21 +2746,20 @@ +@@ -2895,21 +2750,20 @@ }); } @@ -1451,7 +1462,7 @@ int i = 0; for (ResourcePackRepository.Entry resourcepackrepository$entry : this.field_110448_aq.func_110613_c()) -@@ -2939,7 +2789,6 @@ +@@ -2939,7 +2793,6 @@ } } @@ -1459,7 +1470,7 @@ public void func_70001_b(Snooper p_70001_1_) { p_70001_1_.func_152767_b("opengl_version", GlStateManager.func_187416_u(7938)); -@@ -2947,110 +2796,110 @@ +@@ -2947,110 +2800,110 @@ p_70001_1_.func_152767_b("client_brand", ClientBrandRetriever.getClientModName()); p_70001_1_.func_152767_b("launched_version", this.field_110447_Z); ContextCapabilities contextcapabilities = GLContext.getCapabilities(); @@ -1674,7 +1685,7 @@ GameProfile gameprofile = this.field_71449_j.func_148256_e(); if (gameprofile != null && gameprofile.getId() != null) -@@ -3061,21 +2910,10 @@ +@@ -3061,21 +2914,10 @@ public static int func_71369_N() { @@ -1698,7 +1709,7 @@ public boolean func_70002_Q() { return this.field_71474_y.field_74355_t; -@@ -3205,6 +3043,9 @@ +@@ -3205,6 +3047,9 @@ } else if (this.field_71439_g != null) { @@ -1708,7 +1719,7 @@ if (this.field_71439_g.field_70170_p.field_73011_w instanceof WorldProviderHell) { return MusicTicker.MusicType.NETHER; -@@ -3215,9 +3056,7 @@ +@@ -3215,9 +3060,7 @@ } else { @@ -1719,7 +1730,7 @@ } } else -@@ -3236,19 +3075,15 @@ +@@ -3236,19 +3079,15 @@ { if (Keyboard.getEventKeyState()) { @@ -1743,7 +1754,7 @@ { this.field_71474_y.func_74306_a(GameSettings.Options.NARRATOR, 1); -@@ -3258,6 +3093,7 @@ +@@ -3258,6 +3097,7 @@ } } } @@ -1751,7 +1762,7 @@ } } } -@@ -3292,16 +3128,16 @@ +@@ -3292,16 +3132,16 @@ { try { @@ -1771,7 +1782,7 @@ synchronized (this.field_152351_aB) { -@@ -3311,14 +3147,12 @@ +@@ -3311,14 +3151,12 @@ } } @@ -1787,7 +1798,7 @@ public boolean func_152345_ab() { return Thread.currentThread() == this.field_152352_aC; -@@ -3346,7 +3180,7 @@ +@@ -3346,7 +3184,7 @@ public ISearchTree func_193987_a(SearchTreeManager.Key p_193987_1_) { @@ -1796,7 +1807,7 @@ } public static int func_175610_ah() -@@ -3389,6 +3223,12 @@ +@@ -3389,6 +3227,12 @@ return this.field_184127_aH; } @@ -1809,7 +1820,7 @@ public boolean func_189648_am() { return this.field_71439_g != null && this.field_71439_g.func_175140_cp() || this.field_71474_y.field_178879_v; -@@ -3402,5 +3242,10 @@ +@@ -3402,5 +3246,10 @@ public Tutorial func_193032_ao() { return this.field_193035_aW; diff --git a/src/main/java/net/minecraftforge/common/ForgeEarlyConfig.java b/src/main/java/net/minecraftforge/common/ForgeEarlyConfig.java index 07090c481..aa059012b 100644 --- a/src/main/java/net/minecraftforge/common/ForgeEarlyConfig.java +++ b/src/main/java/net/minecraftforge/common/ForgeEarlyConfig.java @@ -4,22 +4,69 @@ @Config(modid = ForgeVersion.MOD_ID, name = ForgeVersion.MOD_ID + "_early") public class ForgeEarlyConfig { + public static boolean RAW_INPUT = true; + + //TODO : make CATEGORY? + //TODO : make the config display name lowcase? + public static boolean WINDOW_START_MAXIMIZED = false; public static boolean WINDOW_START_FOCUSED = true; public static boolean WINDOW_START_ICONIFIED = false; + + public static boolean WINDOW_CENTERED = true; + + @Config.Comment("Should the window have decorations (titlebar, border, close button)") public static boolean WINDOW_DECORATED = true; + + @Config.Comment("Should exclusive fullscreen mode replaced with borderless fullscreen mode") + public static boolean WINDOW_BORDERLESS_REPLACES_FULLSCREEN = false; + + @Config.Comment("Windows-only - should borderless window have height increased by 1 to solve flickering on un-focusing") + public static boolean WINDOW_BORDERLESS_WINDOWS_COMPATIBILITY = true; + + @Config.Comment("Enable KHR_debug in the OpenGL context for advanced debugging capabilities") public static boolean OPENGL_DEBUG_CONTEXT = false; + + @Config.Comment("Make the framebuffer use the sRGB color space") public static boolean OPENGL_SRGB_CONTEXT = false; + + @Config.Comment("Make the framebuffer double-buffered (will cause visual artifacts if disabled)") public static boolean OPENGL_DOUBLEBUFFER = true; + + @Config.Comment("Enable GL_KHR_no_error to use faster driver code, but which can cause memory corruption in case of OpenGL errors") public static boolean OPENGL_CONTEXT_NO_ERROR = false; + @Config.Comment("Only use this if you have custom glfw natives") public static boolean FORCE_WAYLAND = false; + public static boolean DECORATED = true; + public static boolean INPUT_INVERT_WHEEL = false; + public static double INPUT_SCROLL_SPEED = 1.0; + + @Config.Comment("Allow text character input when Ctrl+Left Alt are pressed (disables special escape code handling for this combination of keys)") + public static boolean INPUT_CTRL_ALT_TEXT = false; + + @Config.Comment("Allows AltGr use in Ctrl+key special key combinations (disables text character input handling when AltGr is pressed)") + public static boolean INPUT_ALTGR_ESCAPE_CODES = false; + + @Config.Comment("Linux-only - change the X11 class name, which is used by your window manager to identify the running application") public static String X11_CLASS_NAME = "minecraft"; + + @Config.Comment("OSX-only - identifier used to save and restore the window position and size") public static String COCOA_FRAME_NAME = "minecraft"; + public static String CONFIG_ANY_TIME_VERSION = "3.0"; + public static String[] LOADING_PLUGIN_BLACKLIST = new String[] { "com.cleanroommc.configanytime.ConfigAnytimePlugin", "zone.rong.mixinbooter.MixinBooterPlugin"}; + + public static CategoryOpenAlContext OPENAL_CONTEXT = new CategoryOpenAlContext(); + public static class CategoryOpenAlContext{ + @Config.Comment("Enable HRTF sound support") + public boolean ENABLE_HRTF = false; + } + + } diff --git a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java index ea0bc120f..f948621de 100644 --- a/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java +++ b/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java @@ -119,6 +119,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.FormattedMessage; import org.lwjgl.LWJGLUtil; +import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; @@ -266,6 +267,8 @@ public void beginMinecraftLoading(Minecraft minecraft, List resou } } + Keyboard.populateKeyLookupTables(); + @SuppressWarnings("unchecked") Map> sharedModList = (Map>) Launch.blackboard.get("modList"); if (sharedModList == null) diff --git a/src/main/java/org/lwjgl/Sys.java b/src/main/java/org/lwjgl/Sys.java index 0a5aa4f91..0adb5741a 100644 --- a/src/main/java/org/lwjgl/Sys.java +++ b/src/main/java/org/lwjgl/Sys.java @@ -91,7 +91,7 @@ public static boolean is64Bit() { return Platform.getArchitecture().toString().endsWith("64"); } - public String getClipboard() { + public static String getClipboard() { return GLFW.glfwGetClipboardString(Display.getWindow()); } } diff --git a/src/main/java/org/lwjgl/input/Controller.java b/src/main/java/org/lwjgl/input/Controller.java new file mode 100644 index 000000000..e1a22711e --- /dev/null +++ b/src/main/java/org/lwjgl/input/Controller.java @@ -0,0 +1,72 @@ +package org.lwjglx.input; + +public interface Controller { + + public abstract int getAxisCount(); + + public abstract java.lang.String getAxisName(int arg0); + + public abstract float getAxisValue(int arg0); + + public abstract int getButtonCount(); + + public abstract java.lang.String getButtonName(int arg0); + + public abstract float getDeadZone(int arg0); + + public abstract int getIndex(); + + public abstract java.lang.String getName(); + + public abstract float getPovX(); + + public abstract float getPovY(); + + public abstract float getRXAxisDeadZone(); + + public abstract float getRXAxisValue(); + + public abstract float getRYAxisDeadZone(); + + public abstract float getRYAxisValue(); + + public abstract float getRZAxisDeadZone(); + + public abstract float getRZAxisValue(); + + public abstract int getRumblerCount(); + + public abstract java.lang.String getRumblerName(int arg0); + + public abstract float getXAxisDeadZone(); + + public abstract float getXAxisValue(); + + public abstract float getYAxisDeadZone(); + + public abstract float getYAxisValue(); + + public abstract float getZAxisDeadZone(); + + public abstract float getZAxisValue(); + + public abstract boolean isButtonPressed(int arg0); + + public abstract void poll(); + + public abstract void setDeadZone(int arg0, float arg1); + + public abstract void setRXAxisDeadZone(float arg0); + + public abstract void setRYAxisDeadZone(float arg0); + + public abstract void setRZAxisDeadZone(float arg0); + + public abstract void setRumblerStrength(int arg0, float arg1); + + public abstract void setXAxisDeadZone(float arg0); + + public abstract void setYAxisDeadZone(float arg0); + + public abstract void setZAxisDeadZone(float arg0); +} \ No newline at end of file diff --git a/src/main/java/org/lwjgl/input/Controllers.java b/src/main/java/org/lwjgl/input/Controllers.java new file mode 100644 index 000000000..c8f7ee456 --- /dev/null +++ b/src/main/java/org/lwjgl/input/Controllers.java @@ -0,0 +1,101 @@ +package org.lwjglx.input; + +// TODO: This is a dummy implementation +public class Controllers { + + public static void clearEvents() { + // no-op + } + + public static void create() { + // no-op + } + + public static void destroy() { + // no-op + } + + public static Controller getController(int arg0) { + // no-op + return null; + } + + public static int getControllerCount() { + // no-op + return 0; + } + + public static boolean getEventButtonState() { + // no-op + return false; + } + + public static int getEventControlIndex() { + // no-op + return 0; + } + + public static long getEventNanoseconds() { + // no-op + return 1; + } + + public static Controller getEventSource() { + // no-op + return null; + } + + public static float getEventXAxisValue() { + // no-op + return 0.0f; + } + + public static float getEventYAxisValue() { + // no-op + return 0.0f; + } + + public static boolean isCreated() { + // no-op + return true; + } + + public static boolean isEventAxis() { + // no-op + return false; + } + + public static boolean isEventButton() { + // no-op + return false; + } + + public static boolean isEventPovX() { + // no-op + return false; + } + + public static boolean isEventPovY() { + // no-op + return false; + } + + public static boolean isEventXAxis() { + // no-op + return false; + } + + public static boolean isEventYAxis() { + // no-op + return false; + } + + public static boolean next() { + // no-op + return false; + } + + public static void poll() { + // no-op + } +} \ No newline at end of file diff --git a/src/main/java/org/lwjgl/input/Keyboard.java b/src/main/java/org/lwjgl/input/Keyboard.java index 6a5443bdf..6a66b9d1b 100644 --- a/src/main/java/org/lwjgl/input/Keyboard.java +++ b/src/main/java/org/lwjgl/input/Keyboard.java @@ -2,10 +2,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.StringUtils; import org.lwjgl3.glfw.GLFW; @@ -159,6 +159,9 @@ public class Keyboard { public static final int KEY_SLEEP = 0xDF; public static final int keyCount; + + private static final Map reverseKeyMap = new ConcurrentHashMap<>(); + private static final Queue queue = new ArrayBlockingQueue<>(128); @@ -166,8 +169,7 @@ public class Keyboard { public static final int KEYBOARD_SIZE = Short.MAX_VALUE; - private static final String[] keyName = new String[Short.MAX_VALUE]; - private static final Map keyMap = new HashMap<>(Short.MAX_VALUE); + private static final String[] unlocalizedKeyNameMiniLut = new String[Short.MAX_VALUE]; static { // Use reflection to find out key names @@ -183,21 +185,28 @@ public class Keyboard { /* Don't use deprecated names */ int key = field.getInt(null); String name = field.getName().substring(4); - keyName[key] = name; + unlocalizedKeyNameMiniLut[key] = name; + reverseKeyMap.put(name, key); keyCounter++; } } } catch (Exception e) {} keyCount = keyCounter; - for (int i = 0; i < keyName.length; i++) { - if (keyName[i] == null) { - keyName[i] = "Key " + i; + for (int i = 0; i < unlocalizedKeyNameMiniLut.length; i++) { + if (unlocalizedKeyNameMiniLut[i] == null) { + unlocalizedKeyNameMiniLut[i] = "Key " + i; } - keyMap.put(keyName[i], i); } queue.add(new KeyEvent(0, '\0', KeyState.RELEASE, Sys.getNanoTime())); } + /** Populates the key name->index lookup table with the current keyboard layout based names. */ + public static void populateKeyLookupTables() { + for (int key = 0; key <= 255; key++) { + getKeyName(key); + } + } + public static void addGlfwKeyEvent(long window, int key, int scancode, int action, int mods, char c) { final KeyState state; switch (action) { @@ -288,15 +297,30 @@ public static long getEventNanoseconds() { } public static String getKeyName(int key) { - if (key >= 0 && key < keyName.length) { - return keyName[key]; + if (key == KEY_NONE) { + return "NONE"; + } + // GLFW caches this internally, and knows when keyboard layouts switch. + final String glfwName = StringUtils.toRootUpperCase(GLFW.glfwGetKeyName(KeyCodes.toGlfwKey(key), 0)); + final String name; + if (glfwName == null) { + if (key >= 0 && key < unlocalizedKeyNameMiniLut.length) { + name = unlocalizedKeyNameMiniLut[key]; + } else { + name = "Key " + key; + } } else { - return "Key " + key; + name = glfwName; } + reverseKeyMap.put(name, key); + return name; } - public static int getKeyIndex(java.lang.String keyName) { - Integer ret = keyMap.get(keyName); + public static int getKeyIndex(String keyName) { + if (keyName.equals("NONE")) { + return KEY_NONE; + } + Integer ret = reverseKeyMap.get(keyName); if (ret == null) { if (keyName.matches("Key -?[0-9]+]")) { return Integer.parseInt(StringUtils.removeStart(keyName, "Key ")); diff --git a/src/main/java/org/lwjgl/openal/AL.java b/src/main/java/org/lwjgl/openal/AL.java index 6152b7c2b..4388ed222 100644 --- a/src/main/java/org/lwjgl/openal/AL.java +++ b/src/main/java/org/lwjgl/openal/AL.java @@ -1,5 +1,7 @@ package org.lwjgl.openal; +import net.minecraftforge.common.ForgeEarlyConfig; + import java.nio.IntBuffer; import org.lwjgl3.openal.ALC10; @@ -40,6 +42,16 @@ public static void create(String deviceArguments, int contextFrequency, int cont attribs.put(org.lwjgl3.openal.ALC10.ALC_SYNC); attribs.put(contextSynchronized ? org.lwjgl3.openal.ALC10.ALC_TRUE : org.lwjgl3.openal.ALC10.ALC_FALSE); + + ///////////////////////////////////////////// + // HRTF + if (!ForgeEarlyConfig.OPENAL_CONTEXT.ENABLE_HRTF) { + attribs.put(org.lwjgl3.openal.SOFTHRTF.ALC_HRTF_SOFT); + attribs.put(org.lwjgl3.openal.ALC10.ALC_FALSE); + attribs.put(org.lwjgl3.openal.SOFTHRTF.ALC_HRTF_ID_SOFT); + attribs.put(0); + } + ///////////////////////////////////////////// attribs.put(org.lwjgl3.openal.EXTEfx.ALC_MAX_AUXILIARY_SENDS); attribs.put(4); diff --git a/src/main/java/org/lwjgl/opengl/Display.java b/src/main/java/org/lwjgl/opengl/Display.java index 519b60622..ad04dbd9d 100644 --- a/src/main/java/org/lwjgl/opengl/Display.java +++ b/src/main/java/org/lwjgl/opengl/Display.java @@ -1,7 +1,10 @@ package org.lwjgl.opengl; +import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeEarlyConfig; import org.lwjgl.input.*; +import org.lwjgl.util.Rectangle; +import org.lwjgl3.PointerBuffer; import org.lwjgl3.glfw.GLFW; import org.lwjgl3.glfw.*; import org.lwjgl3.opengl.GL; @@ -9,8 +12,14 @@ import org.lwjgl.BufferUtils; import org.lwjgl.Sys; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Optional; import static org.lwjgl3.glfw.GLFW.*; import static org.lwjgl3.system.MemoryUtil.NULL; @@ -25,6 +34,7 @@ public class Display { private static boolean displayDirty = false; private static boolean displayResizable = false; private static boolean startFullscreen = false; + private static boolean borderlessInsteadOfFullscreen = true; private static DisplayMode mode = new DisplayMode(854, 480); private static DisplayMode desktopDisplayMode; @@ -46,6 +56,8 @@ public class Display { private static ByteBuffer[] savedIcons; private static boolean cancelNextChar = false; private static KeyEvent ingredientKeyEvent; + private static boolean lastAltIsRightAlt = false; + private static HashMap glfwKeycodeNames = new HashMap<>(); static { Sys.initialize(); // init using dummy sys method @@ -59,6 +71,20 @@ public class Display { int monitorRefreshRate = vidmode.refreshRate(); desktopDisplayMode = new DisplayMode(monitorWidth, monitorHeight, monitorBitPerPixel, monitorRefreshRate); + + try { + Class glfwClass = GLFW.class; + for (Field f : glfwClass.getFields()) { + if (f.getName() + .startsWith("GLFW_KEY_") && f.getType() == int.class + && Modifier.isStatic(f.getModifiers())) { + int value = f.getInt(null); + glfwKeycodeNames.put(value, f.getName()); + } + } + } catch (ReflectiveOperationException e) { + // ignore + } } /** @@ -124,6 +150,10 @@ public static void create() { glfwWindowHintString(GLFW_X11_CLASS_NAME, ForgeEarlyConfig.X11_CLASS_NAME); glfwWindowHintString(GLFW_COCOA_FRAME_NAME, ForgeEarlyConfig.COCOA_FRAME_NAME); + if (ForgeEarlyConfig.WINDOW_CENTERED) { + glfwWindowHint(GLFW_POSITION_X, (desktopDisplayMode.getWidth() - mode.getWidth()) / 2); + glfwWindowHint(GLFW_POSITION_Y, (desktopDisplayMode.getHeight() - mode.getHeight()) / 2); + } Window.handle = glfwCreateWindow(mode.getWidth(), mode.getHeight(), windowTitle, NULL, NULL); if (Window.handle == 0L) { @@ -139,9 +169,45 @@ public static void create() { @Override public void invoke(long window, int key, int scancode, int action, int mods) { cancelNextChar = false; + if (action == GLFW_PRESS) { + if (key == GLFW_KEY_LEFT_ALT) { + lastAltIsRightAlt = false; + } else if (key == GLFW_KEY_RIGHT_ALT) { + lastAltIsRightAlt = true; + } + } if (key > GLFW_KEY_SPACE && key <= GLFW_KEY_GRAVE_ACCENT) { // Handle keys have a char. Exclude space to // avoid extra input when switching IME - if ((GLFW_MOD_CONTROL & mods) != 0) { // Handle ctrl + x/c/v. + + /* + * AltGr and LAlt require special consideration. + * On Windows, AltGr and Ctrl+Alt send the same `mods` value of ALT|CTRL in this event. + * This means that to distinguish potential text input from special key combos we have to look at + * the last pressed Alt key side. + * Ctrl combos have to send a (key & 0x1f) ASCII Escape code to work correctly with a lot of older + * mods, but this obviously breaks text input. + * Therefore, we assume text input with AltGr, and control combination input with Left Alt, but both + * can be switched in the config if the player desires. + */ + final boolean isAlt = (GLFW_MOD_ALT & mods) != 0; + final boolean isAltGr = lastAltIsRightAlt; + final boolean ctrlGraphicalMode; + if (isAlt) { + if (isAltGr) { + ctrlGraphicalMode = !ForgeEarlyConfig.INPUT_ALTGR_ESCAPE_CODES; + } else { + // is left alt + ctrlGraphicalMode = ForgeEarlyConfig.INPUT_CTRL_ALT_TEXT; + } + if (ctrlGraphicalMode) { + Keyboard.addGlfwKeyEvent(window, key, scancode, action, mods, (char) (key & 0x1f)); + } + } else { + ctrlGraphicalMode = false; + } + + + if ((GLFW_MOD_CONTROL & mods) != 0 && !ctrlGraphicalMode) { // Handle ctrl + x/c/v. Keyboard.addGlfwKeyEvent(window, key, scancode, action, mods, (char) (key & 0x1f)); cancelNextChar = true; // Cancel char event from ctrl key since its already handled here } else if (action > 0) { // Delay press and repeat key event to actual char input. There is ALWAYS a @@ -521,6 +587,51 @@ public static void setDisplayModeAndFullscreen(DisplayMode mode) { private static int savedX[] = new int[1], savedY[] = new int[1]; private static int savedW[] = new int[1], savedH[] = new int[1]; + public static PositionedGLFWVidMode getTargetFullscreenMonitor() { + int x = savedX[0] + (savedW[0] / 2); + int y = savedY[0] + (savedH[0] / 2); + PointerBuffer monitors = glfwGetMonitors(); + assert monitors != null; + ArrayList monitorInfos = new ArrayList<>(monitors.limit()); + for (int i = 0; i < monitors.limit(); i++) { + long monitor = monitors.get(i); + PositionedGLFWVidMode monitorInfo = getPositionedMonitorInfo(monitor); + monitorInfos.add(monitorInfo); + if (monitorInfo.bounds.contains(x, y)) { + return monitorInfo; + } + } + // If the center of the screen doesn't contains in any monitors, try to look by intersect area + Rectangle windowBounds = new Rectangle(savedX[0], savedY[0], savedW[0], savedH[0]); + Optional targetMonitor = monitorInfos.stream() + .filter( + o -> !o.bounds.intersection(windowBounds, null) + .isEmpty()) + .max( + Comparator.comparingInt( + o -> o.bounds.intersection(windowBounds, null) + .getArea())); + return targetMonitor.orElse(getPositionedMonitorInfo(glfwGetPrimaryMonitor())); + } + + private static PositionedGLFWVidMode getPositionedMonitorInfo(long monitorId) { + IntBuffer posX = BufferUtils.createIntBuffer(1); + IntBuffer posY = BufferUtils.createIntBuffer(1); + glfwGetMonitorPos(monitorId, posX, posY); + int x = posX.get(0); + int y = posY.get(0); + GLFWVidMode vidmode = glfwGetVideoMode(monitorId); + assert vidmode != null; + return new PositionedGLFWVidMode( + x, + y, + new Rectangle(x, y, vidmode.width(), vidmode.height()), + monitorId, + vidmode); + } + + public record PositionedGLFWVidMode(int x, int y, Rectangle bounds, long monitorId, GLFWVidMode vidMode) {} + public static void setFullscreen(boolean fullscreen) { final long window = getWindow(); if (window == 0) { @@ -531,16 +642,91 @@ public static void setFullscreen(boolean fullscreen) { if (currentState == fullscreen) { return; } + + glfwSetWindowSizeLimits(window, 0, 0, GLFW_DONT_CARE, GLFW_DONT_CARE); if (fullscreen) { glfwGetWindowPos(window, savedX, savedY); glfwGetWindowSize(window, savedW, savedH); - long monitorId = glfwGetPrimaryMonitor(); - final GLFWVidMode vidMode = glfwGetVideoMode(monitorId); - glfwSetWindowMonitor(window, monitorId, 0, 0, vidMode.width(), vidMode.height(), vidMode.refreshRate()); + PositionedGLFWVidMode monitorInfo = getTargetFullscreenMonitor(); + GLFWVidMode vidMode = monitorInfo.vidMode; + glfwSetWindowMonitor( + window, + monitorInfo.monitorId, + 0, + 0, + vidMode.width(), + vidMode.height(), + vidMode.refreshRate()); + Minecraft.getMinecraft() + .resize(vidMode.width(), vidMode.height()); + } else { + glfwSetWindowSize(window, savedW[0], savedH[0]); + glfwSetWindowMonitor(window, NULL, savedX[0], savedY[0], savedW[0], savedH[0], 0); + } + } + + public static void toggleBorderless() { + setBorderless(!isBorderless()); + } + public static void setBorderless(boolean toBorderless) { + final long window = getWindow(); + if (window == NULL) { + return; + } + if (toBorderless) { + glfwGetWindowPos(window, savedX, savedY); + glfwGetWindowSize(window, savedW, savedH); + PositionedGLFWVidMode monitorInfo = getTargetFullscreenMonitor(); + GLFWVidMode vidMode = monitorInfo.vidMode; + int height = vidMode.height(); + // Fix bothered from + // https://github.com/Kir-Antipov/cubes-without-borders/blob/b38306bf17d3f0936475a3a28c4ee2be4e881a62/src/main/java/dev/kir/cubeswithoutborders/mixin/WindowMixin.java#L130 + // There's a bug that causes a fullscreen window to flicker when it loses focus. + // As far as I know, this is relevant for Windows and X11 desktops. + // Fuck X11 - it's a perpetually broken piece of legacy. + // However, we do need to implement a fix for Windows desktops, as they + // are not going anywhere in the foreseeable future (sadly enough). + // This "fix" involves not bringing a window into a "proper" fullscreen mode, + // but rather stretching it 1 pixel beyond the screen's supported resolution. + if (ForgeEarlyConfig.WINDOW_BORDERLESS_WINDOWS_COMPATIBILITY && System.getProperty("os.name") + .toLowerCase() + .contains("win")) { + height = height + 1; + } + glfwSetWindowSizeLimits(window, 0, 0, vidMode.width(), height); + glfwSetWindowSize(window, vidMode.width(), height); + glfwSetWindowMonitor( + window, + NULL, + monitorInfo.x, + monitorInfo.y, + vidMode.width(), + height, + vidMode.refreshRate()); } else { + glfwSetWindowSizeLimits(window, 0, 0, GLFW_DONT_CARE, GLFW_DONT_CARE); + glfwSetWindowSize(window, savedW[0], savedH[0]); glfwSetWindowMonitor(window, NULL, savedX[0], savedY[0], savedW[0], savedH[0], 0); } } + public static boolean isBorderless() { + long window = Display.getWindow(); + long windowMonitor = glfwGetWindowMonitor(Display.getWindow()); + if (Display.getWindow() != 0 && windowMonitor == NULL) { + IntBuffer windowX = BufferUtils.createIntBuffer(1); + IntBuffer windowY = BufferUtils.createIntBuffer(1); + IntBuffer windowWidth = BufferUtils.createIntBuffer(1); + IntBuffer windowHeight = BufferUtils.createIntBuffer(1); + glfwGetWindowPos(window, windowX, windowY); + glfwGetWindowSize(window, windowWidth, windowHeight); + Display.PositionedGLFWVidMode monitorInfo = Display.getTargetFullscreenMonitor(); + GLFWVidMode vidMode = monitorInfo.vidMode(); + return windowX.get(0) == monitorInfo.x() && windowY.get(0) == monitorInfo.y() + && windowWidth.get(0) == vidMode.width() + && (windowHeight.get(0) >= vidMode.height()); + } + return false; + } public static boolean isFullscreen() { if (getWindow() != 0) { @@ -558,6 +744,14 @@ public static java.awt.Canvas getParent() { return null; } + public static void setSwapInterval(int value) { + glfwSwapInterval(value); + } + + public static void setDisplayConfiguration(float gamma, float brightness, float contrast) { + // ignore + } + public static void releaseContext() { glfwMakeContextCurrent(0); } diff --git a/src/main/java/org/lwjgl/test/opengl/Gears.java b/src/main/java/org/lwjgl/test/opengl/Gears.java deleted file mode 100644 index 824fe0aa3..000000000 --- a/src/main/java/org/lwjgl/test/opengl/Gears.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * 3-D gear wheels. Originally by Brian Paul - */ -package org.lwjgl.test.opengl; - -import static org.lwjgl3.opengl.ARBTransposeMatrix.*; -import static org.lwjgl3.opengl.GL11.*; - -import java.nio.FloatBuffer; - -import org.lwjgl3.Version; -import org.lwjgl.BufferUtils; -import org.lwjgl.LWJGLException; -import org.lwjgl.LWJGLUtil; -import org.lwjgl.opengl.Display; -import org.lwjgl.opengl.DisplayMode; -import org.lwjgl.opengl.GLContext; - -/** - *

- * This is the OpenGL "standard" Gears demo, originally by Brian Paul - *

- * - * @author Brian Matzon - * @version $Revision: 3418 $ $Id: Gears.java 3418 2010-09-28 21:11:35Z spasi $ - */ -public class Gears { - - private float view_rotx = 20.0f; - - private float view_roty = 30.0f; - - private float view_rotz; - - private int gear1; - - private int gear2; - - private int gear3; - - private float angle; - - public static void main(String[] args) { - new Gears().execute(); - System.exit(0); - } - - /** - * - */ - private void execute() { - try { - init(); - } catch (LWJGLException le) { - le.printStackTrace(); - System.out.println("Failed to initialize Gears."); - return; - } - - loop(); - - destroy(); - } - - /** - * - */ - private void destroy() { - Display.destroy(); - } - - /** - * - */ - private void loop() { - long startTime = System.currentTimeMillis() + 5000; - long fps = 0; - - while (!Display.isCloseRequested()) { - angle += 2.0f; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glPushMatrix(); - glRotatef(view_rotx, 1.0f, 0.0f, 0.0f); - glRotatef(view_roty, 0.0f, 1.0f, 0.0f); - glRotatef(view_rotz, 0.0f, 0.0f, 1.0f); - - glPushMatrix(); - glTranslatef(-3.0f, -2.0f, 0.0f); - glRotatef(angle, 0.0f, 0.0f, 1.0f); - glCallList(gear1); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(3.1f, -2.0f, 0.0f); - glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f); - glCallList(gear2); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(-3.1f, 4.2f, 0.0f); - glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f); - glCallList(gear3); - glPopMatrix(); - - glPopMatrix(); - - Display.update(); - if (startTime > System.currentTimeMillis()) { - fps++; - } else { - long timeUsed = 5000 + (startTime - System.currentTimeMillis()); - startTime = System.currentTimeMillis() + 5000; - System.out.println(fps + " frames in " + timeUsed / 1000f + " seconds = " + (fps / (timeUsed / 1000f))); - fps = 0; - } - } - } - - /** - * - */ - private void init() throws LWJGLException { - // create Window of size 300x300 - Display.setLocation( - (Display.getDisplayMode().getWidth() - 300) / 2, - (Display.getDisplayMode().getHeight() - 300) / 2); - Display.setDisplayMode(new DisplayMode(300, 300)); - Display.setTitle("Gears"); - Display.create(); - - // setup ogl - FloatBuffer pos = BufferUtils.createFloatBuffer(4).put(new float[] { 5.0f, 5.0f, 10.0f, 0.0f }); - FloatBuffer red = BufferUtils.createFloatBuffer(4).put(new float[] { 0.8f, 0.1f, 0.0f, 1.0f }); - FloatBuffer green = BufferUtils.createFloatBuffer(4).put(new float[] { 0.0f, 0.8f, 0.2f, 1.0f }); - FloatBuffer blue = BufferUtils.createFloatBuffer(4).put(new float[] { 0.2f, 0.2f, 1.0f, 1.0f }); - - pos.flip(); - red.flip(); - green.flip(); - blue.flip(); - - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - - /* make the gears */ - gear1 = glGenLists(1); - glNewList(gear1, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); - gear(1.0f, 4.0f, 1.0f, 20, 0.7f); - glEndList(); - - gear2 = glGenLists(1); - glNewList(gear2, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); - gear(0.5f, 2.0f, 2.0f, 10, 0.7f); - glEndList(); - - gear3 = glGenLists(1); - glNewList(gear3, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); - gear(1.3f, 2.0f, 0.5f, 10, 0.7f); - glEndList(); - - glEnable(GL_NORMALIZE); - - glMatrixMode(GL_PROJECTION); - - System.err.println("LWJGL: " + Version.getVersion() + " / " + LWJGLUtil.getPlatformName()); - System.err.println("GL_VENDOR: " + glGetString(GL_VENDOR)); - System.err.println("GL_RENDERER: " + glGetString(GL_RENDERER)); - System.err.println("GL_VERSION: " + glGetString(GL_VERSION)); - System.err.println(); - System.err.println( - "glLoadTransposeMatrixfARB() supported: " + GLContext.getCapabilities().GL_ARB_transpose_matrix); - if (!GLContext.getCapabilities().GL_ARB_transpose_matrix) { - // --- not using extensions - glLoadIdentity(); - } else { - // --- using extensions - final FloatBuffer identityTranspose = BufferUtils.createFloatBuffer(16) - .put(new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }); - identityTranspose.flip(); - glLoadTransposeMatrixfARB(identityTranspose); - } - - float h = (float) 300 / (float) 300; - glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f, 0.0f, -40.0f); - } - - /** - * Draw a gear wheel. You'll probably want to call this function when building a display list since we do a lot of - * trig here. - * - * @param inner_radius radius of hole at center - * @param outer_radius radius at center of teeth - * @param width width of gear - * @param teeth number of teeth - * @param tooth_depth depth of tooth - */ - private void gear(float inner_radius, float outer_radius, float width, int teeth, float tooth_depth) { - int i; - float r0, r1, r2; - float angle, da; - float u, v, len; - - r0 = inner_radius; - r1 = outer_radius - tooth_depth / 2.0f; - r2 = outer_radius + tooth_depth / 2.0f; - - da = 2.0f * (float) Math.PI / teeth / 4.0f; - - glShadeModel(GL_FLAT); - - glNormal3f(0.0f, 0.0f, 1.0f); - - /* draw front face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f); - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f); - if (i < teeth) { - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f); - glVertex3f( - r1 * (float) Math.cos(angle + 3.0f * da), - r1 * (float) Math.sin(angle + 3.0f * da), - width * 0.5f); - } - } - glEnd(); - - /* draw front sides of teeth */ - glBegin(GL_QUADS); - for (i = 0; i < teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f); - glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), width * 0.5f); - glVertex3f( - r2 * (float) Math.cos(angle + 2.0f * da), - r2 * (float) Math.sin(angle + 2.0f * da), - width * 0.5f); - glVertex3f( - r1 * (float) Math.cos(angle + 3.0f * da), - r1 * (float) Math.sin(angle + 3.0f * da), - width * 0.5f); - } - glEnd(); - - /* draw back face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f); - glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f); - } - glEnd(); - - /* draw back sides of teeth */ - glBegin(GL_QUADS); - for (i = 0; i < teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f); - glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), -width * 0.5f); - glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), -width * 0.5f); - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f); - } - glEnd(); - - /* draw outward faces of teeth */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i < teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), width * 0.5f); - glVertex3f(r1 * (float) Math.cos(angle), r1 * (float) Math.sin(angle), -width * 0.5f); - u = r2 * (float) Math.cos(angle + da) - r1 * (float) Math.cos(angle); - v = r2 * (float) Math.sin(angle + da) - r1 * (float) Math.sin(angle); - len = (float) Math.sqrt(u * u + v * v); - u /= len; - v /= len; - glNormal3f(v, -u, 0.0f); - glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), width * 0.5f); - glVertex3f(r2 * (float) Math.cos(angle + da), r2 * (float) Math.sin(angle + da), -width * 0.5f); - glNormal3f((float) Math.cos(angle), (float) Math.sin(angle), 0.0f); - glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), width * 0.5f); - glVertex3f(r2 * (float) Math.cos(angle + 2 * da), r2 * (float) Math.sin(angle + 2 * da), -width * 0.5f); - u = r1 * (float) Math.cos(angle + 3 * da) - r2 * (float) Math.cos(angle + 2 * da); - v = r1 * (float) Math.sin(angle + 3 * da) - r2 * (float) Math.sin(angle + 2 * da); - glNormal3f(v, -u, 0.0f); - glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), width * 0.5f); - glVertex3f(r1 * (float) Math.cos(angle + 3 * da), r1 * (float) Math.sin(angle + 3 * da), -width * 0.5f); - glNormal3f((float) Math.cos(angle), (float) Math.sin(angle), 0.0f); - } - glVertex3f(r1 * (float) Math.cos(0), r1 * (float) Math.sin(0), width * 0.5f); - glVertex3f(r1 * (float) Math.cos(0), r1 * (float) Math.sin(0), -width * 0.5f); - glEnd(); - - glShadeModel(GL_SMOOTH); - - /* draw inside radius cylinder */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0f * (float) Math.PI / teeth; - glNormal3f(-(float) Math.cos(angle), -(float) Math.sin(angle), 0.0f); - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), -width * 0.5f); - glVertex3f(r0 * (float) Math.cos(angle), r0 * (float) Math.sin(angle), width * 0.5f); - } - glEnd(); - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/AlienEntity.java b/src/main/java/org/lwjgl/test/spaceinvaders/AlienEntity.java deleted file mode 100644 index 250f655c3..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/AlienEntity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -/** - * An entity which represents one of our space invader aliens. - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class AlienEntity extends Entity { - - /** Movement made downwards when a border is hit */ - private static final int DOWNWARD_MOVEMENT = 10; - - /** Border at which player dies */ - private static final int BOTTOM_BORDER = 570; - - /** Right border at which to shift direction */ - private static final int RIGHT_BORDER = 750; - - /** Left border at which to shift direction */ - private static final int LEFT_BORDER = 10; - - /** The speed at which the alient moves horizontally */ - private float moveSpeed = 75; - - /** The game in which the entity exists */ - private Game game; - - /** The animation frames */ - private Sprite[] frames = new Sprite[4]; - - /** The time since the last frame change took place */ - private long lastFrameChange; - - /** The frame duration in milliseconds, i.e. how long any given frame of animation lasts */ - private long frameDuration = 250; - - /** The current frame of animation being displayed */ - private int frameNumber; - - /** - * Create a new alien entity - * - * @param game The game in which this entity is being created - * @param x The intial x location of this alien - * @param y The intial y location of this alient - */ - public AlienEntity(Game game, int x, int y) { - super(game.getSprite("alien.gif"), x, y); - - // setup the animatin frames - frames[0] = sprite; - frames[1] = game.getSprite("alien2.gif"); - frames[2] = sprite; - frames[3] = game.getSprite("alien3.gif"); - - this.game = game; - dx = -moveSpeed; - } - - /** - * Request that this alien moved based on time elapsed - * - * @param delta The time that has elapsed since last move - */ - public void move(long delta) { - // since the move tells us how much time has passed - // by we can use it to drive the animation, however - // its the not the prettiest solution - lastFrameChange += delta; - - // if we need to change the frame, update the frame number - // and flip over the sprite in use - if (lastFrameChange > frameDuration) { - // reset our frame change time counter - lastFrameChange = 0; - - // update the frame - frameNumber++; - if (frameNumber >= frames.length) { - frameNumber = 0; - } - - sprite = frames[frameNumber]; - } - - // if we have reached the left hand side of the screen and - // are moving left then request a logic update - if ((dx < 0) && (x < LEFT_BORDER)) { - game.updateLogic(); - } - // and vice vesa, if we have reached the right hand side of - // the screen and are moving right, request a logic update - if ((dx > 0) && (x > RIGHT_BORDER)) { - game.updateLogic(); - } - - // proceed with normal move - super.move(delta); - } - - /** - * Update the game logic related to aliens - */ - public void doLogic() { - // swap over horizontal movement and move down the - // screen a bit - dx = -dx; - y += DOWNWARD_MOVEMENT; - - // if we've reached the bottom of the screen then the player - // dies - if (y > BOTTOM_BORDER) { - game.notifyDeath(); - } - } - - /** - * Notification that this alien has collided with another entity - * - * @param other The other entity - */ - public void collidedWith(Entity other) { - // collisions with aliens are handled elsewhere - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/Entity.java b/src/main/java/org/lwjgl/test/spaceinvaders/Entity.java deleted file mode 100644 index 29175e42e..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/Entity.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import java.awt.Rectangle; - -/** - * An entity represents any element that appears in the game. The entity is responsible for resolving collisions and - * movement based on a set of properties defined either by subclass or externally. - * - * Note that doubles are used for positions. This may seem strange given that pixels locations are integers. However, - * using double means that an entity can move a partial pixel. It doesn't of course mean that they will be display half - * way through a pixel but allows us not lose accuracy as we move. - * - * @author Kevin Glass - */ -public abstract class Entity { - - /** The current x location of this entity */ - protected float x; - - /** The current y location of this entity */ - protected float y; - - /** The sprite that represents this entity */ - protected Sprite sprite; - - /** The current speed of this entity horizontally (pixels/sec) */ - protected float dx; - - /** The current speed of this entity vertically (pixels/sec) */ - protected float dy; - - /** The rectangle used for this entity during collisions resolution */ - private Rectangle me = new Rectangle(); - - /** The rectangle used for other entities during collision resolution */ - private Rectangle him = new Rectangle(); - - /** - * Construct a entity based on a sprite image and a location. - * - * @param sprite The reference to the image to be displayed for this entity - * @param x The initial x location of this entity - * @param y The initial y location of this entity - */ - protected Entity(Sprite sprite, int x, int y) { - this.sprite = sprite; - this.x = x; - this.y = y; - } - - /** - * Request that this entity move itself based on a certain ammount of time passing. - * - * @param delta The ammount of time that has passed in milliseconds - */ - public void move(long delta) { - // update the location of the entity based on move speeds - x += (delta * dx) / 1000; - y += (delta * dy) / 1000; - } - - /** - * Set the horizontal speed of this entity - * - * @param dx The horizontal speed of this entity (pixels/sec) - */ - public void setHorizontalMovement(float dx) { - this.dx = dx; - } - - /** - * Set the vertical speed of this entity - * - * @param dy The vertical speed of this entity (pixels/sec) - */ - public void setVerticalMovement(float dy) { - this.dy = dy; - } - - /** - * Get the horizontal speed of this entity - * - * @return The horizontal speed of this entity (pixels/sec) - */ - public float getHorizontalMovement() { - return dx; - } - - /** - * Get the vertical speed of this entity - * - * @return The vertical speed of this entity (pixels/sec) - */ - public float getVerticalMovement() { - return dy; - } - - /** - * Draw this entity to the graphics context provided - */ - public void draw() { - sprite.draw((int) x, (int) y); - } - - /** - * Do the logic associated with this entity. This method will be called periodically based on game events - */ - public void doLogic() {} - - /** - * Get the x location of this entity - * - * @return The x location of this entity - */ - public int getX() { - return (int) x; - } - - /** - * Get the y location of this entity - * - * @return The y location of this entity - */ - public int getY() { - return (int) y; - } - - /** - * Check if this entity collised with another. - * - * @param other The other entity to check collision against - * @return True if the entities collide with each other - */ - public boolean collidesWith(Entity other) { - me.setBounds((int) x, (int) y, sprite.getWidth(), sprite.getHeight()); - him.setBounds((int) other.x, (int) other.y, other.sprite.getWidth(), other.sprite.getHeight()); - - return me.intersects(him); - } - - /** - * Notification that this entity collided with another. - * - * @param other The entity with which this entity collided. - */ - public abstract void collidedWith(Entity other); -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/Game.java b/src/main/java/org/lwjgl/test/spaceinvaders/Game.java deleted file mode 100644 index 586945a89..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/Game.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import static org.lwjgl3.opengl.GL11.*; - -import java.util.ArrayList; - -import org.lwjgl.Sys; -import org.lwjgl.input.Keyboard; -import org.lwjgl.input.Mouse; -import org.lwjgl.opengl.Display; -import org.lwjgl.opengl.DisplayMode; - -/** - * The main hook of our game. This class with both act as a manager for the display and central mediator for the game - * logic. - * - * Display management will consist of a loop that cycles round all entities in the game asking them to move and then - * drawing them in the appropriate place. With the help of an inner class it will also allow the player to control the - * main ship. - * - * As a mediator it will be informed when entities within our game detect events (e.g. alient killed, played died) and - * will take appropriate game actions. - * - *

- * NOTE:
- * This game is a LWJGLized implementation of the Space Invaders game by Kevin Glass. The original implementation is - * renderer agnostic and supports other OpenGL implementations as well as Java2D. This version has been made specific - * for LWJGL, and has added input control as well as sound (which the original doesn't, at the time of writing). You can - * find the original article here:
- * http://www.cokeandcode.com - *

- * - * @author Kevin Glass - * @author Brian Matzon - */ -public class Game { - - /** The normal title of the window */ - private String WINDOW_TITLE = "Space Invaders 104 (for LWJGL)"; - - /** The width of the game display area */ - private int width = 800; - - /** The height of the game display area */ - private int height = 600; - - /** The loader responsible for converting images into OpenGL textures */ - private TextureLoader textureLoader; - - /** The list of all the entities that exist in our game */ - private ArrayList entities = new ArrayList<>(); - - /** The list of entities that need to be removed from the game this loop */ - private ArrayList removeList = new ArrayList<>(); - - /** The entity representing the player */ - private ShipEntity ship; - - /** List of shots */ - private ShotEntity[] shots; - - /** The message to display which waiting for a key press */ - private Sprite message; - - /** The sprite containing the "Press Any Key" message */ - private Sprite pressAnyKey; - - /** The sprite containing the "You win!" message */ - private Sprite youWin; - - /** The sprite containing the "You lose!" message */ - private Sprite gotYou; - - /** Last shot index */ - private int shotIndex; - - /** The speed at which the player's ship should move (pixels/sec) */ - private float moveSpeed = 300; - - /** The time at which last fired a shot */ - private long lastFire; - - /** The interval between our players shot (ms) */ - private long firingInterval = 500; - - /** The number of aliens left on the screen */ - private int alienCount; - - /** True if we're holding up game play until a key has been pressed */ - private boolean waitingForKeyPress = true; - - /** True if game logic needs to be applied this loop, normally as a result of a game event */ - private boolean logicRequiredThisLoop; - - /** The time at which the last rendering looped started from the point of view of the game logic */ - private long lastLoopTime = getTime(); - - /** True if the fire key has been released */ - private boolean fireHasBeenReleased; - - /** The time since the last record of fps */ - private long lastFpsTime; - - /** The recorded fps */ - private int fps; - - private static long timerTicksPerSecond = Sys.getTimerResolution(); - - /** True if the game is currently "running", i.e. the game loop is looping */ - public static boolean gameRunning = true; - - /** SoundManager to make sound with */ - private SoundManager soundManager; - - /** Whether we're running in fullscreen mode */ - private boolean fullscreen; - - /** ID of shot effect */ - private int SOUND_SHOT; - - /** ID of hit effect */ - private int SOUND_HIT; - - /** ID of start sound */ - private int SOUND_START; - - /** ID of win sound */ - private int SOUND_WIN; - - /** ID of loose sound */ - private int SOUND_LOOSE; - - /** Mouse movement on x axis */ - private int mouseX; - - /** Is this an application or applet */ - private static boolean isApplication; - - /** - * Construct our game and set it running. - * - * @param fullscreen - * - */ - public Game(boolean fullscreen) { - this.fullscreen = fullscreen; - initialize(); - } - - /** - * Get the high resolution time in milliseconds - * - * @return The high resolution time in milliseconds - */ - public static long getTime() { - // we get the "timer ticks" from the high resolution timer - // multiply by 1000 so our end result is in milliseconds - // then divide by the number of ticks in a second giving - // us a nice clear time in milliseconds - return (Sys.getTime() * 1000) / timerTicksPerSecond; - } - - /** - * Sleep for a fixed number of milliseconds. - * - * @param duration The amount of time in milliseconds to sleep for - */ - public static void sleep(long duration) { - try { - Thread.sleep((duration * timerTicksPerSecond) / 1000); - } catch (InterruptedException inte) {} - } - - /** - * Intialise the common elements for the game - */ - public void initialize() { - // initialize the window beforehand - setDisplayMode(); - Display.setTitle(WINDOW_TITLE); - Display.setFullscreen(fullscreen); - Display.create(); - - // grab the mouse, dont want that hideous cursor when we're playing! - if (isApplication) { - Mouse.setGrabbed(true); - } - - // enable textures since we're going to use these for our sprites - glEnable(GL_TEXTURE_2D); - - // disable the OpenGL depth test since we're rendering 2D graphics - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glOrtho(0, width, height, 0, -1, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glViewport(0, 0, Display.getFramebufferWidth(), Display.getFramebufferHeight()); - - textureLoader = new TextureLoader(); - - // create our sound manager, and initialize it with 7 channels - // 1 channel for sounds, 6 for effects - this should be enough - // since we have a most 4 shots on screen at any one time, which leaves - // us with 2 channels for explosions. - soundManager = new SoundManager(); - soundManager.initialize(8); - - // load our sound data - SOUND_SHOT = soundManager.addSound("shot.wav"); - SOUND_HIT = soundManager.addSound("hit.wav"); - SOUND_START = soundManager.addSound("start.wav"); - SOUND_WIN = soundManager.addSound("win.wav"); - SOUND_LOOSE = soundManager.addSound("loose.wav"); - - // get our sprites - gotYou = getSprite("gotyou.gif"); - pressAnyKey = getSprite("pressanykey.gif"); - youWin = getSprite("youwin.gif"); - - message = pressAnyKey; - - // setup 5 shots - shots = new ShotEntity[5]; - for (int i = 0; i < shots.length; i++) { - shots[i] = new ShotEntity(this, "shot.gif", 0, 0); - } - - // setup the initial game state - startGame(); - } - - /** - * Sets the display mode for fullscreen mode - */ - private boolean setDisplayMode() { - try { - // get modes - DisplayMode[] dm = org.lwjgl.util.Display.getAvailableDisplayModes(width, height, -1, -1, -1, -1, 60, 60); - - org.lwjgl.util.Display.setDisplayMode( - dm, - new String[] { "width=" + width, "height=" + height, "freq=" + 60, - "bpp=" + org.lwjgl.opengl.Display.getDisplayMode().getBitsPerPixel() }); - return true; - } catch (Exception e) { - e.printStackTrace(); - System.out.println("Unable to enter fullscreen, continuing in windowed mode"); - } - - return false; - } - - /** - * Start a fresh game, this should clear out any old data and create a new set. - */ - private void startGame() { - // clear out any existing entities and intialise a new set - entities.clear(); - initEntities(); - } - - /** - * Initialise the starting state of the entities (ship and aliens). Each entitiy will be added to the overall list - * of entities in the game. - */ - private void initEntities() { - // create the player ship and place it roughly in the center of the screen - ship = new ShipEntity(this, "ship.gif", 370, 550); - entities.add(ship); - - // create a block of aliens (5 rows, by 12 aliens, spaced evenly) - alienCount = 0; - for (int row = 0; row < 5; row++) { - for (int x = 0; x < 12; x++) { - Entity alien = new AlienEntity(this, 100 + (x * 50), (50) + row * 30); - entities.add(alien); - alienCount++; - } - } - } - - /** - * Notification from a game entity that the logic of the game should be run at the next opportunity (normally as a - * result of some game event) - */ - public void updateLogic() { - logicRequiredThisLoop = true; - } - - /** - * Remove an entity from the game. The entity removed will no longer move or be drawn. - * - * @param entity The entity that should be removed - */ - public void removeEntity(Entity entity) { - removeList.add(entity); - } - - /** - * Notification that the player has died. - */ - public void notifyDeath() { - if (!waitingForKeyPress) { - soundManager.playSound(SOUND_LOOSE); - } - message = gotYou; - waitingForKeyPress = true; - } - - /** - * Notification that the player has won since all the aliens are dead. - */ - public void notifyWin() { - message = youWin; - waitingForKeyPress = true; - soundManager.playSound(SOUND_WIN); - } - - /** - * Notification that an alien has been killed - */ - public void notifyAlienKilled() { - // reduce the alient count, if there are none left, the player has won! - alienCount--; - - if (alienCount == 0) { - notifyWin(); - } - - // if there are still some aliens left then they all need to get faster, so - // speed up all the existing aliens - for (Entity entity : entities) { - if (entity instanceof AlienEntity) { - // speed up by 2% - entity.setHorizontalMovement(entity.getHorizontalMovement() * 1.02f); - } - } - - soundManager.playEffect(SOUND_HIT); - } - - /** - * Attempt to fire a shot from the player. Its called "try" since we must first check that the player can fire at - * this point, i.e. has he/she waited long enough between shots - */ - public void tryToFire() { - // check that we have waiting long enough to fire - if (System.currentTimeMillis() - lastFire < firingInterval) { - return; - } - - // if we waited long enough, create the shot entity, and record the time. - lastFire = System.currentTimeMillis(); - ShotEntity shot = shots[shotIndex++ % shots.length]; - shot.reinitialize(ship.getX() + 10, ship.getY() - 30); - entities.add(shot); - - soundManager.playEffect(SOUND_SHOT); - } - - /** - * Run the main game loop. This method keeps rendering the scene and requesting that the callback update its screen. - */ - private void gameLoop() { - while (Game.gameRunning) { - // clear screen - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // let subsystem paint - frameRendering(); - - // update window contents - Display.update(); - } - - // clean up - soundManager.destroy(); - Display.destroy(); - } - - /** - * Notification that a frame is being rendered. Responsible for running game logic and rendering the scene. - */ - public void frameRendering() { - // SystemTimer.sleep(lastLoopTime+10-SystemTimer.getTime()); - Display.sync(60); - - // work out how long its been since the last update, this - // will be used to calculate how far the entities should - // move this loop - long delta = getTime() - lastLoopTime; - lastLoopTime = getTime(); - lastFpsTime += delta; - fps++; - - // update our FPS counter if a second has passed - if (lastFpsTime >= 1000) { - Display.setTitle(WINDOW_TITLE + " (FPS: " + fps + ")"); - lastFpsTime = 0; - fps = 0; - } - - // cycle round asking each entity to move itself - if (!waitingForKeyPress && !soundManager.isPlayingSound()) { - for (Entity entity : entities) { - entity.move(delta); - } - } - - // cycle round drawing all the entities we have in the game - for (Entity entity : entities) { - entity.draw(); - } - - // brute force collisions, compare every entity against - // every other entity. If any of them collide notify - // both entities that the collision has occured - for (int p = 0; p < entities.size(); p++) { - for (int s = p + 1; s < entities.size(); s++) { - Entity me = entities.get(p); - Entity him = entities.get(s); - - if (me.collidesWith(him)) { - me.collidedWith(him); - him.collidedWith(me); - } - } - } - - // remove any entity that has been marked for clear up - entities.removeAll(removeList); - removeList.clear(); - - // if a game event has indicated that game logic should - // be resolved, cycle round every entity requesting that - // their personal logic should be considered. - if (logicRequiredThisLoop) { - for (Entity entity : entities) { - entity.doLogic(); - } - - logicRequiredThisLoop = false; - } - - // if we're waiting for an "any key" press then draw the - // current message - if (waitingForKeyPress) { - message.draw(325, 250); - } - - // resolve the movemfent of the ship. First assume the ship - // isn't moving. If either cursor key is pressed then - // update the movement appropraitely - ship.setHorizontalMovement(0); - - // get mouse movement on x axis. We need to get it now, since - // we can only call getDX ONCE! - secondary calls will yield 0, since - // there haven't been any movement since last call. - mouseX = Mouse.getDX(); - - // we delegate input checking to submethod since we want to check - // for keyboard, mouse & controller - boolean leftPressed = hasInput(Keyboard.KEY_LEFT); - boolean rightPressed = hasInput(Keyboard.KEY_RIGHT); - boolean firePressed = hasInput(Keyboard.KEY_SPACE); - - if (!waitingForKeyPress && !soundManager.isPlayingSound()) { - if ((leftPressed) && (!rightPressed)) { - ship.setHorizontalMovement(-moveSpeed); - } else if ((rightPressed) && (!leftPressed)) { - ship.setHorizontalMovement(moveSpeed); - } - - // if we're pressing fire, attempt to fire - if (firePressed) { - tryToFire(); - } - } else { - if (!firePressed) { - fireHasBeenReleased = true; - } - if ((firePressed) && (fireHasBeenReleased) && !soundManager.isPlayingSound()) { - waitingForKeyPress = false; - fireHasBeenReleased = false; - startGame(); - soundManager.playSound(SOUND_START); - } - } - - // if escape has been pressed, stop the game - if ((Display.isCloseRequested() || Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) && isApplication) { - Game.gameRunning = false; - } - } - - /** - * @param direction - * @return - */ - private boolean hasInput(int direction) { - return switch (direction) { - case Keyboard.KEY_LEFT -> Keyboard.isKeyDown(Keyboard.KEY_LEFT) || mouseX < 0; - case Keyboard.KEY_RIGHT -> Keyboard.isKeyDown(Keyboard.KEY_RIGHT) || mouseX > 0; - case Keyboard.KEY_SPACE -> Keyboard.isKeyDown(Keyboard.KEY_SPACE) || Mouse.isButtonDown(0); - default -> false; - }; - } - - /** - * The entry point into the game. We'll simply create an instance of class which will start the display and game - * loop. - * - * @param argv The arguments that are passed into our game - */ - public static void main(String argv[]) { - isApplication = true; - System.out.println("Use -fullscreen for fullscreen mode"); - new Game((argv.length > 0 && "-fullscreen".equalsIgnoreCase(argv[0]))).execute(); - System.exit(0); - } - - /** - * - */ - public void execute() { - gameLoop(); - } - - /** - * Create or get a sprite which displays the image that is pointed to in the classpath by "ref" - * - * @param ref A reference to the image to load - * @return A sprite that can be drawn onto the current graphics context. - */ - public Sprite getSprite(String ref) { - return new Sprite(textureLoader, ref); - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/ShipEntity.java b/src/main/java/org/lwjgl/test/spaceinvaders/ShipEntity.java deleted file mode 100644 index d668e3598..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/ShipEntity.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -/** - * The entity that represents the players ship - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class ShipEntity extends Entity { - - /** Right border at which to disallow further movement */ - private static final int RIGHT_BORDER = 750; - - /** Left border at which to disallow further movement */ - private static final int LEFT_BORDER = 10; - - /** The game in which the ship exists */ - private Game game; - - /** - * Create a new entity to represent the players ship - * - * @param game The game in which the ship is being created - * @param ref The reference to the sprite to show for the ship - * @param x The initial x location of the player's ship - * @param y The initial y location of the player's ship - */ - public ShipEntity(Game game, String ref, int x, int y) { - super(game.getSprite(ref), x, y); - - this.game = game; - } - - /** - * Request that the ship move itself based on an elapsed ammount of time - * - * @param delta The time that has elapsed since last move (ms) - */ - public void move(long delta) { - // if we're moving left and have reached the left hand side - // of the screen, don't move - if ((dx < 0) && (x < LEFT_BORDER)) { - return; - } - // if we're moving right and have reached the right hand side - // of the screen, don't move - if ((dx > 0) && (x > RIGHT_BORDER)) { - return; - } - - super.move(delta); - } - - /** - * Notification that the player's ship has collided with something - * - * @param other The entity with which the ship has collided - */ - public void collidedWith(Entity other) { - // if its an alien, notify the game that the player - // is dead - if (other instanceof AlienEntity) { - game.notifyDeath(); - } - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/ShotEntity.java b/src/main/java/org/lwjgl/test/spaceinvaders/ShotEntity.java deleted file mode 100644 index 56b43c824..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/ShotEntity.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -/** - * An entity representing a shot fired by the player's ship - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class ShotEntity extends Entity { - - /** Top border at which shots are outside */ - private static final int TOP_BORDER = -100; - - /** The vertical speed at which the players shot moves */ - private float moveSpeed = -300; - - /** The game in which this entity exists */ - private Game game; - - /** True if this shot has been "used", i.e. its hit something */ - private boolean used; - - /** - * Create a new shot from the player - * - * @param game The game in which the shot has been created - * @param sprite The sprite representing this shot - * @param x The initial x location of the shot - * @param y The initial y location of the shot - */ - public ShotEntity(Game game, String sprite, int x, int y) { - super(game.getSprite(sprite), x, y); - - this.game = game; - dy = moveSpeed; - } - - /** - * Reinitializes this entity, for reuse - * - * @param x new x coordinate - * @param y new y coordinate - */ - public void reinitialize(int x, int y) { - this.x = x; - this.y = y; - used = false; - } - - /** - * Request that this shot moved based on time elapsed - * - * @param delta The time that has elapsed since last move - */ - public void move(long delta) { - // proceed with normal move - super.move(delta); - - // if we shot off the screen, remove ourselfs - if (y < TOP_BORDER) { - game.removeEntity(this); - } - } - - /** - * Notification that this shot has collided with another entity - * - * @param other The other entity with which we've collided - */ - public void collidedWith(Entity other) { - // prevents double kills, if we've already hit something, - // don't collide - if (used) { - return; - } - - // if we've hit an alien, kill it! - if (other instanceof AlienEntity) { - // remove the affected entities - game.removeEntity(this); - game.removeEntity(other); - - // notify the game that the alien has been killed - game.notifyAlienKilled(); - used = true; - } - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/SoundManager.java b/src/main/java/org/lwjgl/test/spaceinvaders/SoundManager.java deleted file mode 100644 index 7718291d5..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/SoundManager.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import java.nio.IntBuffer; - -import org.lwjgl.BufferUtils; -import org.lwjgl.LWJGLException; -import org.lwjgl.openal.AL; -import org.lwjgl.openal.AL10; -import org.lwjgl.util.WaveData; - -/** - *

- * Simple sound manager for OpenAL using n sources accessed in a round robin schedule. Source n is reserved for a single - * buffer and checking for whether it's playing. - *

- * - * @author Brian Matzon - * @version $Revision$ $Id$ - */ -public class SoundManager { - - /** We support at most 256 buffers */ - private int[] buffers = new int[256]; - - /** Number of sources is limited tby user (and hardware) */ - private int[] sources; - - /** Our internal scratch buffer */ - private IntBuffer scratchBuffer = BufferUtils.createIntBuffer(256); - - /** Whether we're running in no sound mode */ - private boolean soundOutput; - - /** Current index in our buffers */ - private int bufferIndex; - - /** Current index in our source list */ - private int sourceIndex; - - /** - * Creates a new SoundManager - */ - public SoundManager() {} - - /** - * Plays a sound effect - * - * @param buffer Buffer index to play gotten from addSound - */ - public void playEffect(int buffer) { - if (soundOutput) { - // make sure we never choose last channel, since it is used for special sounds - int channel = sources[(sourceIndex++ % (sources.length - 1))]; - - // link buffer and source, and play it - AL10.alSourcei(channel, AL10.AL_BUFFER, buffers[buffer]); - AL10.alSourcePlay(channel); - } - } - - /** - * Plays a sound on last source - * - * @param buffer Buffer index to play gotten from addSound - */ - public void playSound(int buffer) { - if (soundOutput) { - AL10.alSourcei(sources[sources.length - 1], AL10.AL_BUFFER, buffers[buffer]); - AL10.alSourcePlay(sources[sources.length - 1]); - } - } - - /** - * Whether a sound is playing on last source - * - * @return true if a source is playing right now on source n - */ - public boolean isPlayingSound() { - return AL10.alGetSourcei(sources[sources.length - 1], AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING; - } - - /** - * Initializes the SoundManager - * - * @param channels Number of channels to create - */ - public void initialize(int channels) { - try { - AL.create(); - - // allocate sources - scratchBuffer.limit(channels); - AL10.alGenSources(scratchBuffer); - scratchBuffer.rewind(); - scratchBuffer.get(sources = new int[channels]); - - // could we allocate all channels? - if (AL10.alGetError() != AL10.AL_NO_ERROR) { - throw new LWJGLException("Unable to allocate " + channels + " sources"); - } - - // we have sound - soundOutput = true; - } catch (LWJGLException le) { - le.printStackTrace(); - System.out.println("Sound disabled"); - } - } - - /** - * Adds a sound to the Sound Managers pool - * - * @param path Path to file to load - * @return index into SoundManagers buffer list - */ - public int addSound(String path) { - // Generate 1 buffer entry - scratchBuffer.rewind().position(0).limit(1); - AL10.alGenBuffers(scratchBuffer); - buffers[bufferIndex] = scratchBuffer.get(0); - - // load wave data from buffer - WaveData wavefile = WaveData.create("spaceinvaders/" + path); - - // copy to buffers - AL10.alBufferData(buffers[bufferIndex], wavefile.format, wavefile.data, wavefile.samplerate); - - // unload file again - wavefile.dispose(); - - // return index for this sound - return bufferIndex++; - } - - /** - * Destroy this SoundManager - */ - public void destroy() { - if (soundOutput) { - - // stop playing sounds - scratchBuffer.position(0).limit(sources.length); - scratchBuffer.put(sources).flip(); - AL10.alSourceStop(scratchBuffer); - - // destroy sources - AL10.alDeleteSources(scratchBuffer); - - // destroy buffers - scratchBuffer.position(0).limit(bufferIndex); - scratchBuffer.put(buffers, 0, bufferIndex).flip(); - AL10.alDeleteBuffers(scratchBuffer); - - // destory OpenAL - AL.destroy(); - } - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/Sprite.java b/src/main/java/org/lwjgl/test/spaceinvaders/Sprite.java deleted file mode 100644 index 66c724eda..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/Sprite.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import static org.lwjgl3.opengl.GL11.*; - -import java.io.IOException; - -/** - * Implementation of sprite that uses an OpenGL quad and a texture to render a given image to the screen. - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class Sprite { - - /** The texture that stores the image for this sprite */ - private Texture texture; - - /** The width in pixels of this sprite */ - private int width; - - /** The height in pixels of this sprite */ - private int height; - - /** - * Create a new sprite from a specified image. - * - * @param loader the texture loader to use - * @param ref A reference to the image on which this sprite should be based - */ - public Sprite(TextureLoader loader, String ref) { - try { - texture = loader.getTexture("spaceinvaders/" + ref); - width = texture.getImageWidth(); - height = texture.getImageHeight(); - } catch (IOException ioe) { - ioe.printStackTrace(); - System.exit(-1); - } - } - - /** - * Get the width of this sprite in pixels - * - * @return The width of this sprite in pixels - */ - public int getWidth() { - return texture.getImageWidth(); - } - - /** - * Get the height of this sprite in pixels - * - * @return The height of this sprite in pixels - */ - public int getHeight() { - return texture.getImageHeight(); - } - - /** - * Draw the sprite at the specified location - * - * @param x The x location at which to draw this sprite - * @param y The y location at which to draw this sprite - */ - public void draw(int x, int y) { - // store the current model matrix - glPushMatrix(); - - // bind to the appropriate texture for this sprite - texture.bind(); - - // translate to the right location and prepare to draw - glTranslatef(x, y, 0); - - // draw a quad textured to match the sprite - glBegin(GL_QUADS); - { - glTexCoord2f(0, 0); - glVertex2f(0, 0); - - glTexCoord2f(0, texture.getHeight()); - glVertex2f(0, height); - - glTexCoord2f(texture.getWidth(), texture.getHeight()); - glVertex2f(width, height); - - glTexCoord2f(texture.getWidth(), 0); - glVertex2f(width, 0); - } - glEnd(); - - // restore the model view matrix to prevent contamination - glPopMatrix(); - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/Texture.java b/src/main/java/org/lwjgl/test/spaceinvaders/Texture.java deleted file mode 100644 index 944cf997d..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/Texture.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import static org.lwjgl3.opengl.GL11.*; - -/** - * A texture to be bound within OpenGL. This object is responsible for keeping track of a given OpenGL texture and for - * calculating the texturing mapping coordinates of the full image. - * - * Since textures need to be powers of 2 the actual texture may be considerably bigged that the source image and hence - * the texture mapping coordinates need to be adjusted to matchup drawing the sprite against the texture. - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class Texture { - - /** The GL target type */ - private int target; - - /** The GL texture ID */ - private int textureID; - - /** The height of the image */ - private int height; - - /** The width of the image */ - private int width; - - /** The width of the texture */ - private int texWidth; - - /** The height of the texture */ - private int texHeight; - - /** The ratio of the width of the image to the texture */ - private float widthRatio; - - /** The ratio of the height of the image to the texture */ - private float heightRatio; - - /** - * Create a new texture - * - * @param target The GL target - * @param textureID The GL texture ID - */ - public Texture(int target, int textureID) { - this.target = target; - this.textureID = textureID; - } - - /** - * Bind the specified GL context to a texture - */ - public void bind() { - glBindTexture(target, textureID); - } - - /** - * Set the height of the image - * - * @param height The height of the image - */ - public void setHeight(int height) { - this.height = height; - setHeight(); - } - - /** - * Set the width of the image - * - * @param width The width of the image - */ - public void setWidth(int width) { - this.width = width; - setWidth(); - } - - /** - * Get the height of the original image - * - * @return The height of the original image - */ - public int getImageHeight() { - return height; - } - - /** - * Get the width of the original image - * - * @return The width of the original image - */ - public int getImageWidth() { - return width; - } - - /** - * Get the height of the physical texture - * - * @return The height of physical texture - */ - public float getHeight() { - return heightRatio; - } - - /** - * Get the width of the physical texture - * - * @return The width of physical texture - */ - public float getWidth() { - return widthRatio; - } - - /** - * Set the height of this texture - * - * @param texHeight The height of the texture - */ - public void setTextureHeight(int texHeight) { - this.texHeight = texHeight; - setHeight(); - } - - /** - * Set the width of this texture - * - * @param texWidth The width of the texture - */ - public void setTextureWidth(int texWidth) { - this.texWidth = texWidth; - setWidth(); - } - - /** - * Set the height of the texture. This will update the ratio also. - */ - private void setHeight() { - if (texHeight != 0) { - heightRatio = ((float) height) / texHeight; - } - } - - /** - * Set the width of the texture. This will update the ratio also. - */ - private void setWidth() { - if (texWidth != 0) { - widthRatio = ((float) width) / texWidth; - } - } -} diff --git a/src/main/java/org/lwjgl/test/spaceinvaders/TextureLoader.java b/src/main/java/org/lwjgl/test/spaceinvaders/TextureLoader.java deleted file mode 100644 index b7de91648..000000000 --- a/src/main/java/org/lwjgl/test/spaceinvaders/TextureLoader.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (c) 2002-2008 LWJGL Project All rights reserved. Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following conditions are met: * Redistributions of source code - * must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in - * binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. * Neither the name of 'LWJGL' nor the names of - * its contributors may be used to endorse or promote products derived from this software without specific prior written - * permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package org.lwjgl.test.spaceinvaders; - -import static org.lwjgl3.opengl.GL11.*; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.color.ColorSpace; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.ComponentColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferByte; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; -import java.io.IOException; -import java.net.URL; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.util.HashMap; -import java.util.Hashtable; - -import javax.swing.ImageIcon; - -import org.lwjgl.BufferUtils; - -/** - * A utility class to load textures for OpenGL. This source is based on a texture that can be found in the Java Gaming - * (www.javagaming.org) Wiki. It has been simplified slightly for explicit 2D graphics use. - * - * OpenGL uses a particular image format. Since the images that are loaded from disk may not match this format this - * loader introduces a intermediate image which the source image is copied into. In turn, this image is used as source - * for the OpenGL texture. - * - * @author Kevin Glass - * @author Brian Matzon - */ -public class TextureLoader { - - /** The table of textures that have been loaded in this loader */ - private HashMap table = new HashMap<>(); - - /** The colour model including alpha for the GL image */ - private ColorModel glAlphaColorModel; - - /** The colour model for the GL image */ - private ColorModel glColorModel; - - /** Scratch buffer for texture ID's */ - private IntBuffer textureIDBuffer = BufferUtils.createIntBuffer(1); - - /** - * Create a new texture loader based on the game panel - */ - public TextureLoader() { - glAlphaColorModel = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - new int[] { 8, 8, 8, 8 }, - true, - false, - ComponentColorModel.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - - glColorModel = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), - new int[] { 8, 8, 8, 0 }, - false, - false, - ComponentColorModel.OPAQUE, - DataBuffer.TYPE_BYTE); - } - - /** - * Create a new texture ID - * - * @return A new texture ID - */ - private int createTextureID() { - glGenTextures(textureIDBuffer); - return textureIDBuffer.get(0); - } - - /** - * Load a texture - * - * @param resourceName The location of the resource to load - * @return The loaded texture - * @throws IOException Indicates a failure to access the resource - */ - public Texture getTexture(String resourceName) throws IOException { - Texture tex = table.get(resourceName); - - if (tex != null) { - return tex; - } - - tex = getTexture( - resourceName, - GL_TEXTURE_2D, // target - GL_RGBA, // dst pixel format - GL_LINEAR, // min filter (unused) - GL_LINEAR); - - table.put(resourceName, tex); - - return tex; - } - - /** - * Load a texture into OpenGL from a image reference on disk. - * - * @param resourceName The location of the resource to load - * @param target The GL target to load the texture against - * @param dstPixelFormat The pixel format of the screen - * @param minFilter The minimising filter - * @param magFilter The magnification filter - * @return The loaded texture - * @throws IOException Indicates a failure to access the resource - */ - public Texture getTexture(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) - throws IOException { - int srcPixelFormat; - - // create the texture ID for this texture - int textureID = createTextureID(); - Texture texture = new Texture(target, textureID); - - // bind this texture - glBindTexture(target, textureID); - - BufferedImage bufferedImage = loadImage(resourceName); - texture.setWidth(bufferedImage.getWidth()); - texture.setHeight(bufferedImage.getHeight()); - - if (bufferedImage.getColorModel().hasAlpha()) { - srcPixelFormat = GL_RGBA; - } else { - srcPixelFormat = GL_RGB; - } - - // convert that image into a byte buffer of texture data - ByteBuffer textureBuffer = convertImageData(bufferedImage, texture); - - if (target == GL_TEXTURE_2D) { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter); - } - - // produce a texture from the byte buffer - glTexImage2D( - target, - 0, - dstPixelFormat, - get2Fold(bufferedImage.getWidth()), - get2Fold(bufferedImage.getHeight()), - 0, - srcPixelFormat, - GL_UNSIGNED_BYTE, - textureBuffer); - - return texture; - } - - /** - * Get the closest greater power of 2 to the fold number - * - * @param fold The target number - * @return The power of 2 - */ - private static int get2Fold(int fold) { - int ret = 2; - while (ret < fold) { - ret *= 2; - } - return ret; - } - - /** - * Convert the buffered image to a texture - * - * @param bufferedImage The image to convert to a texture - * @param texture The texture to store the data into - * @return A buffer containing the data - */ - private ByteBuffer convertImageData(BufferedImage bufferedImage, Texture texture) { - ByteBuffer imageBuffer; - WritableRaster raster; - BufferedImage texImage; - - int texWidth = 2; - int texHeight = 2; - - // find the closest power of 2 for the width and height - // of the produced texture - while (texWidth < bufferedImage.getWidth()) { - texWidth *= 2; - } - while (texHeight < bufferedImage.getHeight()) { - texHeight *= 2; - } - - texture.setTextureHeight(texHeight); - texture.setTextureWidth(texWidth); - - // create a raster that can be used by OpenGL as a source - // for a texture - if (bufferedImage.getColorModel().hasAlpha()) { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 4, null); - texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable<>()); - } else { - raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 3, null); - texImage = new BufferedImage(glColorModel, raster, false, new Hashtable<>()); - } - - // copy the source image into the produced image - Graphics g = texImage.getGraphics(); - g.setColor(new Color(0f, 0f, 0f, 0f)); - g.fillRect(0, 0, texWidth, texHeight); - g.drawImage(bufferedImage, 0, 0, null); - - // build a byte buffer from the temporary image - // that be used by OpenGL to produce a texture. - byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData(); - - imageBuffer = ByteBuffer.allocateDirect(data.length); - imageBuffer.order(ByteOrder.nativeOrder()); - imageBuffer.put(data, 0, data.length); - imageBuffer.flip(); - - return imageBuffer; - } - - /** - * Load a given resource as a buffered image - * - * @param ref The location of the resource to load - * @return The loaded buffered image - * @throws IOException Indicates a failure to find a resource - */ - private BufferedImage loadImage(String ref) throws IOException { - URL url = TextureLoader.class.getClassLoader().getResource(ref); - - if (url == null) { - throw new IOException("Cannot find: " + ref); - } - - // due to an issue with ImageIO and mixed signed code - // we are now using good oldfashioned ImageIcon to load - // images and the paint it on top of a new BufferedImage - Image img = new ImageIcon(url).getImage(); - BufferedImage bufferedImage = new BufferedImage( - img.getWidth(null), - img.getHeight(null), - BufferedImage.TYPE_INT_RGB); - Graphics g = bufferedImage.getGraphics(); - g.drawImage(img, 0, 0, null); - g.dispose(); - - return bufferedImage; - } -} diff --git a/src/main/java/org/lwjgl/util/Rectangle.java b/src/main/java/org/lwjgl/util/Rectangle.java index 8b350152c..fd1d24f30 100644 --- a/src/main/java/org/lwjgl/util/Rectangle.java +++ b/src/main/java/org/lwjgl/util/Rectangle.java @@ -108,6 +108,13 @@ public void setBounds(ReadableRectangle r) { height = r.getHeight(); } + /* + * Returns the area of this rectangle + */ + public int getArea() { + return width * height; + } + /* * (Overrides) * @see com.shavenpuppy.jglib.ReadableRectangle#getBounds(com.shavenpuppy.jglib.Rectangle)