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.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);

View File

@ -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() {

View File

@ -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()));
}
}

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;
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.