Replaced old rendering with nanoVG based GUI rendering.

This commit is contained in:
Andrew Lalis 2022-07-27 12:42:40 +02:00
parent 0b5bfca706
commit 3a70a4566b
9 changed files with 112 additions and 87 deletions

View File

@ -6,12 +6,9 @@ import nl.andrewl.aos2_client.config.ClientConfig;
import nl.andrewl.aos2_client.model.ClientPlayer; import nl.andrewl.aos2_client.model.ClientPlayer;
import nl.andrewl.aos2_client.render.chunk.ChunkRenderer; import nl.andrewl.aos2_client.render.chunk.ChunkRenderer;
import nl.andrewl.aos2_client.render.gui.GuiRenderer; 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.aos2_client.render.model.Model;
import nl.andrewl.aos_core.model.Team; import nl.andrewl.aos_core.model.Team;
import nl.andrewl.aos_core.model.item.BlockItemStack; 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 nl.andrewl.aos_core.model.item.ItemTypes;
import org.joml.Matrix3f; import org.joml.Matrix3f;
import org.joml.Matrix4f; import org.joml.Matrix4f;
@ -53,13 +50,6 @@ public class GameRenderer {
private Model shotgunModel; private Model shotgunModel;
private Model flagModel; 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 long windowHandle;
private int screenWidth = 800; private int screenWidth = 800;
private int screenHeight = 600; private int screenHeight = 600;
@ -134,16 +124,6 @@ public class GameRenderer {
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(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."); log.debug("Initialized GUI renderer.");
this.modelRenderer = new ModelRenderer(); this.modelRenderer = new ModelRenderer();
@ -183,10 +163,6 @@ public class GameRenderer {
if (modelRenderer != null) modelRenderer.setPerspective(data); if (modelRenderer != null) modelRenderer.setPerspective(data);
} }
public Matrix4f getPerspectiveTransform() {
return perspectiveTransform;
}
public boolean windowShouldClose() { public boolean windowShouldClose() {
return glfwWindowShouldClose(windowHandle); return glfwWindowShouldClose(windowHandle);
} }
@ -290,45 +266,7 @@ public class GameRenderer {
// GUI rendering // GUI rendering
guiRenderer.start(); guiRenderer.start();
guiRenderer.draw(crosshairTexture, crosshairTexture.getIdealScaleX(32, screenWidth), crosshairTexture.getIdealScaleY(32, screenHeight), 0, 0); guiRenderer.drawNvg(screenWidth, screenHeight, myPlayer);
// 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.end(); guiRenderer.end();
glfwSwapBuffers(windowHandle); glfwSwapBuffers(windowHandle);

View File

@ -1,5 +1,6 @@
package nl.andrewl.aos2_client.render.gui; package nl.andrewl.aos2_client.render.gui;
import nl.andrewl.aos_core.FileUtils;
import nl.andrewl.aos_core.ImageUtils; import nl.andrewl.aos_core.ImageUtils;
import org.joml.Vector2f; import org.joml.Vector2f;
@ -23,10 +24,11 @@ public class GUITexture {
*/ */
private final int height; private final int height;
public GUITexture(String location) { public GUITexture(String location) throws IOException {
try (var in = GUITexture.class.getClassLoader().getResourceAsStream(location)) { this(FileUtils.readClasspathImage(location));
if (in == null) throw new IOException("Couldn't load texture image from " + location); }
BufferedImage img = ImageIO.read(in);
public GUITexture(BufferedImage img) {
width = img.getWidth(); width = img.getWidth();
height = img.getHeight(); height = img.getHeight();
@ -37,9 +39,6 @@ public class GUITexture {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
var buf = ImageUtils.decodePng(img); var buf = ImageUtils.decodePng(img);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); 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 int getWidth() { public int getWidth() {

View File

@ -1,8 +1,12 @@
package nl.andrewl.aos2_client.render.gui; 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.render.ShaderProgram;
import nl.andrewl.aos2_client.util.ResourceUtils;
import nl.andrewl.aos_core.FileUtils; 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.joml.Matrix4f;
import org.lwjgl.BufferUtils; import org.lwjgl.BufferUtils;
import org.lwjgl.nanovg.NVGColor; import org.lwjgl.nanovg.NVGColor;
@ -35,6 +39,7 @@ public class GuiRenderer {
private static final NVGPaint paintB = NVGPaint.create(); private static final NVGPaint paintB = NVGPaint.create();
private static final NVGPaint paintC = NVGPaint.create(); private static final NVGPaint paintC = NVGPaint.create();
// Simple 2d texture quad information.
private final int vaoId; private final int vaoId;
private final int vboId; private final int vboId;
private final int vertexCount; private final int vertexCount;
@ -85,7 +90,11 @@ public class GuiRenderer {
} }
public void loadTexture(String name, String resource) { public void loadTexture(String name, String resource) {
try {
textures.put(name, new GUITexture(resource)); textures.put(name, new GUITexture(resource));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
public void addTexture(String name, GUITexture texture) { public void addTexture(String name, GUITexture texture) {
@ -102,10 +111,6 @@ public class GuiRenderer {
glUniform1i(textureSamplerUniform, 0); 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) { public void draw(GUITexture texture, float scaleX, float scaleY, float x, float y) {
glActiveTexture(0); glActiveTexture(0);
transformMatrix.identity() transformMatrix.identity()
@ -117,13 +122,19 @@ public class GuiRenderer {
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount); 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); nvgBeginFrame(vgId, width, height, width / height);
nvgSave(vgId); nvgSave(vgId);
nvgFontSize(vgId, 60f); nvgFontSize(vgId, 60f);
nvgFontFaceId(vgId, jetbrainsMonoFont); nvgFontFaceId(vgId, jetbrainsMonoFont);
nvgTextAlign(vgId, NVG_ALIGN_LEFT | NVG_ALIGN_TOP); 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); nvgRestore(vgId);
nvgEndFrame(vgId); nvgEndFrame(vgId);
} }
@ -145,5 +156,73 @@ public class GuiRenderer {
shaderProgram.free(); 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()));
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

View File

@ -1,5 +1,7 @@
package nl.andrewl.aos_core; package nl.andrewl.aos_core;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; 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 * Reads a classpath resource into a directly-allocated byte buffer that
* must be deallocated manually. * must be deallocated manually.