From 3a70a4566b04382ee536193d97dd6389a935fb28 Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Wed, 27 Jul 2022 12:42:40 +0200 Subject: [PATCH] Replaced old rendering with nanoVG based GUI rendering. --- .../aos2_client/render/GameRenderer.java | 64 +----------- .../aos2_client/render/gui/GUITexture.java | 31 +++--- .../aos2_client/render/gui/GuiRenderer.java | 95 ++++++++++++++++-- client/src/main/resources/gui/bullet.png | Bin 1907 -> 0 bytes client/src/main/resources/gui/clip.png | Bin 2808 -> 0 bytes client/src/main/resources/gui/crosshair.png | Bin 218 -> 0 bytes .../src/main/resources/gui/health-green.png | Bin 90 -> 0 bytes client/src/main/resources/gui/health-red.png | Bin 90 -> 0 bytes .../java/nl/andrewl/aos_core/FileUtils.java | 9 ++ 9 files changed, 112 insertions(+), 87 deletions(-) delete mode 100644 client/src/main/resources/gui/bullet.png delete mode 100644 client/src/main/resources/gui/clip.png delete mode 100644 client/src/main/resources/gui/crosshair.png delete mode 100644 client/src/main/resources/gui/health-green.png delete mode 100644 client/src/main/resources/gui/health-red.png diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java index 987113b..373db8d 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/GameRenderer.java @@ -6,12 +6,9 @@ import nl.andrewl.aos2_client.config.ClientConfig; import nl.andrewl.aos2_client.model.ClientPlayer; import nl.andrewl.aos2_client.render.chunk.ChunkRenderer; import nl.andrewl.aos2_client.render.gui.GuiRenderer; -import nl.andrewl.aos2_client.render.gui.GUITexture; import nl.andrewl.aos2_client.render.model.Model; import nl.andrewl.aos_core.model.Team; import nl.andrewl.aos_core.model.item.BlockItemStack; -import nl.andrewl.aos_core.model.item.Gun; -import nl.andrewl.aos_core.model.item.GunItemStack; import nl.andrewl.aos_core.model.item.ItemTypes; import org.joml.Matrix3f; import org.joml.Matrix4f; @@ -53,13 +50,6 @@ public class GameRenderer { private Model shotgunModel; private Model flagModel; - // Standard GUI textures. - private GUITexture crosshairTexture; - private GUITexture clipTexture; - private GUITexture bulletTexture; - private GUITexture healthBarRedTexture; - private GUITexture healthBarGreenTexture; - private long windowHandle; private int screenWidth = 800; private int screenHeight = 600; @@ -134,16 +124,6 @@ public class GameRenderer { } catch (IOException e) { throw new RuntimeException(e); } - crosshairTexture = new GUITexture("gui/crosshair.png"); - clipTexture = new GUITexture("gui/clip.png"); - bulletTexture = new GUITexture("gui/bullet.png"); - healthBarRedTexture = new GUITexture("gui/health-red.png"); - healthBarGreenTexture = new GUITexture("gui/health-green.png"); - guiRenderer.addTexture("crosshair", crosshairTexture); - guiRenderer.addTexture("clip", clipTexture); - guiRenderer.addTexture("bullet", bulletTexture); - guiRenderer.addTexture("health-red", healthBarRedTexture); - guiRenderer.addTexture("health-green", healthBarGreenTexture); log.debug("Initialized GUI renderer."); this.modelRenderer = new ModelRenderer(); @@ -183,10 +163,6 @@ public class GameRenderer { if (modelRenderer != null) modelRenderer.setPerspective(data); } - public Matrix4f getPerspectiveTransform() { - return perspectiveTransform; - } - public boolean windowShouldClose() { return glfwWindowShouldClose(windowHandle); } @@ -290,45 +266,7 @@ public class GameRenderer { // GUI rendering guiRenderer.start(); - guiRenderer.draw(crosshairTexture, crosshairTexture.getIdealScaleX(32, screenWidth), crosshairTexture.getIdealScaleY(32, screenHeight), 0, 0); - // If we're holding a gun, draw clip and bullet graphics. - if (client.getMyPlayer().getInventory().getSelectedItemStack().getType() instanceof Gun) { - GunItemStack stack = (GunItemStack) client.getMyPlayer().getInventory().getSelectedItemStack(); - for (int i = 0; i < stack.getClipCount(); i++) { - guiRenderer.draw( - clipTexture, - clipTexture.getIdealScaleX(64, screenWidth), - clipTexture.getIdealScaleY(clipTexture.getIdealHeight(64), screenHeight), - 0.90f, - -0.90f + (i * 0.15f) - ); - } - for (int i = 0; i < stack.getBulletCount(); i++) { - guiRenderer.draw( - bulletTexture, - bulletTexture.getIdealScaleX(16, screenWidth), - bulletTexture.getIdealScaleY(bulletTexture.getIdealHeight(16), screenHeight), - 0.80f - (i * 0.05f), - -0.90f - ); - } - } - // Render the player's health. - guiRenderer.draw( - healthBarRedTexture, - healthBarRedTexture.getIdealScaleX(64, screenWidth), - healthBarRedTexture.getIdealScaleY(16, screenHeight), - -0.90f, - -0.90f - ); - guiRenderer.draw( - healthBarGreenTexture, - healthBarGreenTexture.getIdealScaleX(64 * client.getMyPlayer().getHealth(), screenWidth), - healthBarGreenTexture.getIdealScaleY(16, screenHeight), - -0.90f, - -0.90f - ); - guiRenderer.drawNvg(screenWidth, screenHeight); + guiRenderer.drawNvg(screenWidth, screenHeight, myPlayer); guiRenderer.end(); glfwSwapBuffers(windowHandle); diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java index 56a1ba0..91cf40b 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GUITexture.java @@ -1,5 +1,6 @@ package nl.andrewl.aos2_client.render.gui; +import nl.andrewl.aos_core.FileUtils; import nl.andrewl.aos_core.ImageUtils; import org.joml.Vector2f; @@ -23,23 +24,21 @@ public class GUITexture { */ private final int height; - public GUITexture(String location) { - try (var in = GUITexture.class.getClassLoader().getResourceAsStream(location)) { - if (in == null) throw new IOException("Couldn't load texture image from " + location); - BufferedImage img = ImageIO.read(in); - width = img.getWidth(); - height = img.getHeight(); + public GUITexture(String location) throws IOException { + this(FileUtils.readClasspathImage(location)); + } - textureId = glGenTextures(); - glBindTexture(GL_TEXTURE_2D, textureId); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - var buf = ImageUtils.decodePng(img); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); - } catch (IOException e) { - throw new RuntimeException("Failed to load GUI texture.", e); - } + public GUITexture(BufferedImage img) { + width = img.getWidth(); + height = img.getHeight(); + + textureId = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, textureId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + var buf = ImageUtils.decodePng(img); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); } public int getWidth() { diff --git a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GuiRenderer.java b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GuiRenderer.java index 4c2cd13..da60c88 100644 --- a/client/src/main/java/nl/andrewl/aos2_client/render/gui/GuiRenderer.java +++ b/client/src/main/java/nl/andrewl/aos2_client/render/gui/GuiRenderer.java @@ -1,8 +1,12 @@ package nl.andrewl.aos2_client.render.gui; +import nl.andrewl.aos2_client.model.ClientPlayer; import nl.andrewl.aos2_client.render.ShaderProgram; -import nl.andrewl.aos2_client.util.ResourceUtils; import nl.andrewl.aos_core.FileUtils; +import nl.andrewl.aos_core.model.item.BlockItem; +import nl.andrewl.aos_core.model.item.BlockItemStack; +import nl.andrewl.aos_core.model.item.Gun; +import nl.andrewl.aos_core.model.item.GunItemStack; import org.joml.Matrix4f; import org.lwjgl.BufferUtils; import org.lwjgl.nanovg.NVGColor; @@ -35,6 +39,7 @@ public class GuiRenderer { private static final NVGPaint paintB = NVGPaint.create(); private static final NVGPaint paintC = NVGPaint.create(); + // Simple 2d texture quad information. private final int vaoId; private final int vboId; private final int vertexCount; @@ -85,7 +90,11 @@ public class GuiRenderer { } public void loadTexture(String name, String resource) { - textures.put(name, new GUITexture(resource)); + try { + textures.put(name, new GUITexture(resource)); + } catch (IOException e) { + throw new RuntimeException(e); + } } public void addTexture(String name, GUITexture texture) { @@ -102,10 +111,6 @@ public class GuiRenderer { glUniform1i(textureSamplerUniform, 0); } - public void draw(String name, float scaleX, float scaleY, float x, float y) { - draw(textures.get(name), scaleX, scaleY, x, y); - } - public void draw(GUITexture texture, float scaleX, float scaleY, float x, float y) { glActiveTexture(0); transformMatrix.identity() @@ -117,13 +122,19 @@ public class GuiRenderer { glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount); } - public void drawNvg(float width, float height) { + public void drawNvg(float width, float height, ClientPlayer player) { nvgBeginFrame(vgId, width, height, width / height); nvgSave(vgId); nvgFontSize(vgId, 60f); nvgFontFaceId(vgId, jetbrainsMonoFont); nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); - nvgText(vgId, 50, 50, "Hello world!"); + nvgFillColor(vgId, GuiUtils.rgba(1, 0, 0, 1, colorA)); + nvgText(vgId, 5, 5, "Hello world!"); + + drawCrosshair(width, height); + drawHealthBar(width, height, player); + drawHeldItemStackInfo(width, height, player); + nvgRestore(vgId); nvgEndFrame(vgId); } @@ -145,5 +156,73 @@ public class GuiRenderer { shaderProgram.free(); } + private void drawCrosshair(float w, float h) { + float cx = w / 2f; + float cy = h / 2f; + nvgStrokeColor(vgId, GuiUtils.rgba(1, 1, 1, 0.25f, colorA)); + nvgBeginPath(vgId); + nvgMoveTo(vgId, cx - 10, cy); + nvgLineTo(vgId, cx + 10, cy); + nvgMoveTo(vgId, cx, cy - 10); + nvgLineTo(vgId, cx, cy + 10); + nvgStroke(vgId); + } + + private void drawHealthBar(float w, float h, ClientPlayer player) { + nvgFillColor(vgId, GuiUtils.rgba(1, 0, 0, 1, colorA)); + nvgBeginPath(vgId); + nvgRect(vgId, 20, h - 60, 100, 20); + nvgFill(vgId); + nvgFillColor(vgId, GuiUtils.rgba(0, 1, 0, 1, colorA)); + nvgBeginPath(vgId); + nvgRect(vgId, 20, h - 60, 100 * player.getHealth(), 20); + nvgFill(vgId); + + nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 1, colorA)); + nvgFontSize(vgId, 12f); + nvgFontFaceId(vgId, jetbrainsMonoFont); + nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); + nvgText(vgId, 20, h - 30, String.format("%.2f / 1.00 HP", player.getHealth())); + } + + private void drawHeldItemStackInfo(float w, float h, ClientPlayer player) { + var stack = player.getInventory().getSelectedItemStack(); + if (stack instanceof GunItemStack g) { + drawGunInfo(w, h, g); + } else if (stack instanceof BlockItemStack b) { + drawBlockInfo(w, h, b); + } + } + + private void drawGunInfo(float w, float h, GunItemStack stack) { + Gun gun = (Gun) stack.getType(); + float y = h - 50; + for (int i = 0; i < gun.getMaxClipCount(); i++) { + float alpha = i < stack.getClipCount() ? 0.75f : 0.25f; + nvgFillColor(vgId, GuiUtils.rgba(0.2f, 0.2f, 0.1f, alpha, colorA)); + nvgBeginPath(vgId); + nvgRect(vgId, w - 60, y, 40, 30); + nvgFill(vgId); + y -= 35; + } + float x = w - 80; + for (int i = 0; i < gun.getMaxBulletCount(); i++) { + float alpha = i < stack.getBulletCount() ? 0.75f : 0.1f; + nvgFillColor(vgId, GuiUtils.rgba(0.7f, 0.3f, 0, alpha, colorA)); + nvgBeginPath(vgId); + nvgRect(vgId, x, h - 60, 10, 40); + nvgFill(vgId); + x -= 15; + } + } + + private void drawBlockInfo(float w, float h, BlockItemStack stack) { + BlockItem block = (BlockItem) stack.getType(); + nvgFillColor(vgId, GuiUtils.rgba(1, 1, 1, 0.75f, colorA)); + nvgFontSize(vgId, 12f); + nvgFontFaceId(vgId, jetbrainsMonoFont); + nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); + nvgText(vgId, w - 140, h - 30, String.format("%d / %d Blocks", stack.getAmount(), block.getMaxAmount())); + } } diff --git a/client/src/main/resources/gui/bullet.png b/client/src/main/resources/gui/bullet.png deleted file mode 100644 index 6abbce453535d838f0566715568f47219c7036c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1907 zcmds2iC5D37XSW0z+6&CO2Z9v(oUq|LtM(*;c`TJ50^)Pw> z07D-d<){`(S{3UewYGfsiT7I2;duE3>S`rjH%g%Ow=sZ+Pp_I;31ys z9;b$k#dUs zT8?}D|1w%K2d=qd)f30Znp$Uo&`|KM4Yu`p)-wb&*bVe(>iWg{Rk7LYYq`ceI{{11`(7d7CkYr`*pWF z(tB%^Z^x~%mPOx?cy7w1E}UNL~X{*`J(`S1I63z$3hjh0*RSKG0cd&2z6{xy$@cQN1eaz`^_#!@9xq~(81rBt^yx2uI2 zf4djEeP3$Srwb{C$if)@eLVukw-e9?iyWX?xa+oUXNIKIKSDQgBT(Z>h_!6md)OM(ck@ys|mLAH?DqS%o6a2 z*hK^nykc9zQf1?ujF*AzETCHtlGhC=vwLqZtUKJ|4~IfCyauZlxAR~(K0;dhnS82_ z7v?4892RxJCp7RUw)A?}j+FjiB!Nb>ScC{~ajo?R3Ru-k#2nHy9Cl^?k7`biv4L!+ z`jOtzP{_XMWd4S>VCP~@0oONL98liMqC^zKr(ZDoLy&a4{jqZ=L#*B@M8kT5#)d7X z+AgPu=uGCG1G%j*-}ybtYlUhzUd7$!$$t(J^0}NDW_$`auUY;O$6MYs6tT6`UJbJ~ zvmcZx78-PTXnb})&`FDyUhFm)l*&7dZ?@G5P4V@M6lOSG;|ymPws-m3ZV{yZTO_B- z2W1Hz>eF2xRA4jZr4p;^h_#2b6huh4uR8SEtE|O=E6jU%$gxjvur%>U8cgOK8D|H>yU%4m zjp~fN)B3gD1kz3IwX#y%maVL8TtToWObx(8Inhpin>}GA5~lXlgYAB=V={Fm>~n7w z5s={gFbXL7S#DPm(?03ndLs7Hq#o%AkUiOK!pl!bJaO{d#|i1ZxOw=3_^IZ39!ijw znwyii@!q>q+46cng3-!^)pz^A{127Rh|rAm*n3-Wyjsc`9qeFEd8z5oz|XAV8qcIO z))P2SIYaJm`f^d>S8%1n&k(wS9?K7q2B8c3zws6{(Z0$qKHtU+6AT52g^`iLo8e|B zKD1nq#BRsNhnEFv$FkS111&&=TLnZXPf`hMGCi!!VfarQ2`TD4Z+ut$kw(ww*1?2+ zvkU%iftyGY+BVm zCF>GS!>2e^!f5)m|7XMLLE%Bt&J{;hMy3b*dgcWEX6Cq?UJ8aX`uKS*)H$o_npO3Q z`iy0w^90_fVS89GYBBfq{3&nx`$e*pwUNIC!j diff --git a/client/src/main/resources/gui/clip.png b/client/src/main/resources/gui/clip.png deleted file mode 100644 index 6b3a8a1b7a69aa7f0fb200c617cdbefa1df026e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2808 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 KrE#N?C+6P+$659O diff --git a/client/src/main/resources/gui/crosshair.png b/client/src/main/resources/gui/crosshair.png deleted file mode 100644 index e554cd8dc0547e499220d6f3a42f1eaef9c19497..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq z_>O=u<5X=vX`rBFiEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0xFo-U3d z5v^~p8FC$P;BdJpaj9aqOk)4O?XxaznUp2T)cDjteW6W`37_#KxAn%wR>gkeA3}lp zfS}=Z?bWd0(DL=Fkq!6F85Hig*(re~Ht;@R{1_ov@$tS@6G*_*)z4*}Q$iB}eV{?G diff --git a/client/src/main/resources/gui/health-green.png b/client/src/main/resources/gui/health-green.png deleted file mode 100644 index 155a74862676391487af52b436f9e3a0e6a5a3a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^OhC-Y!3HG1DAjiXDVAa<&kznEsNqQI0P+PrT^vI= kW+tcnIR9aOV`C#D0}mS$!z?k0r$9*tPgg&ebxsLQ0Qb!l8~^|S diff --git a/client/src/main/resources/gui/health-red.png b/client/src/main/resources/gui/health-red.png deleted file mode 100644 index 0c1d6074b64af4d04b667a457949ab7867a90f6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^OhC-Y!3HG1DAjiXDVAa<&kznEsNqQI0P+PrT^vI= kW+vCHU-@%>V`C#D1K%trr-NTYBY=_&p00i_>zopr018(XTL1t6 diff --git a/core/src/main/java/nl/andrewl/aos_core/FileUtils.java b/core/src/main/java/nl/andrewl/aos_core/FileUtils.java index 0530b34..9b010cd 100644 --- a/core/src/main/java/nl/andrewl/aos_core/FileUtils.java +++ b/core/src/main/java/nl/andrewl/aos_core/FileUtils.java @@ -1,5 +1,7 @@ package nl.andrewl.aos_core; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; @@ -21,6 +23,13 @@ public final class FileUtils { } } + public static BufferedImage readClasspathImage(String resource) throws IOException { + try (var in = FileUtils.class.getClassLoader().getResourceAsStream(resource)) { + if (in == null) throw new IOException("Couldn't load texture image from " + resource); + return ImageIO.read(in); + } + } + /** * Reads a classpath resource into a directly-allocated byte buffer that * must be deallocated manually.