Replaced old rendering with nanoVG based GUI rendering.
This commit is contained in:
parent
0b5bfca706
commit
3a70a4566b
|
@ -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);
|
||||||
|
|
|
@ -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,23 +24,21 @@ 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);
|
|
||||||
width = img.getWidth();
|
|
||||||
height = img.getHeight();
|
|
||||||
|
|
||||||
textureId = glGenTextures();
|
public GUITexture(BufferedImage img) {
|
||||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
width = img.getWidth();
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
height = img.getHeight();
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
textureId = glGenTextures();
|
||||||
var buf = ImageUtils.decodePng(img);
|
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
} catch (IOException e) {
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
throw new RuntimeException("Failed to load GUI texture.", e);
|
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() {
|
public int getWidth() {
|
||||||
|
|
|
@ -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) {
|
||||||
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) {
|
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 |
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue