Organized client code a bit more, and added GUI crosshair thing.

This commit is contained in:
Andrew Lalis 2022-07-16 12:39:27 +02:00
parent ab69ccbe5b
commit 91ef650457
23 changed files with 242 additions and 18 deletions

View File

@ -1,13 +1,19 @@
package nl.andrewl.aos2_client.render;
import nl.andrewl.aos2_client.Camera;
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.aos_core.model.World;
import org.joml.Matrix4f;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL46.*;
@ -23,6 +29,7 @@ public class GameRenderer {
private static final float Z_FAR = 500f;
private final ChunkRenderer chunkRenderer;
private final GUIRenderer guiRenderer;
private final Camera camera;
private final World world;
@ -38,6 +45,7 @@ public class GameRenderer {
public GameRenderer(World world) {
this.world = world;
this.chunkRenderer = new ChunkRenderer();
this.guiRenderer = new GUIRenderer();
this.camera = new Camera();
this.perspectiveTransform = new Matrix4f();
@ -52,6 +60,7 @@ public class GameRenderer {
primaryMonitorSettings = glfwGetVideoMode(glfwGetPrimaryMonitor());
if (primaryMonitorSettings == null) throw new IllegalStateException("Could not get information about the primary monitory.");
log.debug("Primary monitor settings: Width: {}, Height: {}", primaryMonitorSettings.width(), primaryMonitorSettings.height());
windowHandle = glfwCreateWindow(screenWidth, screenHeight, "Ace of Shades 2", 0, 0);
if (windowHandle == 0) throw new RuntimeException("Failed to create GLFW window.");
fullscreen = false;
@ -80,6 +89,16 @@ public class GameRenderer {
log.debug("Initialized OpenGL context.");
chunkRenderer.setupShaderProgram();
guiRenderer.setup();
// TODO: More organized way to load textures for GUI.
try {
var crosshairTexture = new GUITexture("gui/crosshair.png");
float size = 32;
crosshairTexture.getScale().set(size / screenWidth, size / screenHeight);
guiRenderer.addTexture(crosshairTexture);
} catch (IOException e) {
throw new RuntimeException(e);
}
updatePerspective();
}
@ -143,12 +162,14 @@ public class GameRenderer {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
chunkRenderer.draw(camera, world);
guiRenderer.draw();
glfwSwapBuffers(windowHandle);
glfwPollEvents();
}
public void freeWindow() {
guiRenderer.free();
chunkRenderer.free();
GL.destroy();
Callbacks.glfwFreeCallbacks(windowHandle);

View File

@ -28,10 +28,18 @@ public class ShaderProgram {
glUseProgram(id);
}
public void stopUsing() {
glUseProgram(0);
}
public int getUniform(String name) {
return glGetUniformLocation(id, name);
}
public void bindAttribute(int attribute, String variableName) {
glBindAttribLocation(id, attribute, variableName);
}
public void free() {
glDeleteProgram(id);
}

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.chunk;
import org.joml.Vector3f;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.chunk;
import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.World;
@ -89,8 +89,15 @@ public class ChunkMesh {
*/
public void draw() {
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);
}
public void free() {

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.chunk;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.chunk;
import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.World;

View File

@ -1,6 +1,7 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.chunk;
import nl.andrewl.aos2_client.Camera;
import nl.andrewl.aos2_client.render.ShaderProgram;
import nl.andrewl.aos_core.model.Chunk;
import nl.andrewl.aos_core.model.World;
import org.joml.Matrix4f;

View File

@ -0,0 +1,86 @@
package nl.andrewl.aos2_client.render.gui;
import nl.andrewl.aos2_client.render.ShaderProgram;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL46.*;
/**
* Manages rendering of 2D GUI components like cross-hairs, inventory stuff, etc.
*/
public class GUIRenderer {
private int vaoId;
private int vboId;
private int vertexCount;
private ShaderProgram shaderProgram;
private int transformUniformLocation;
private final List<GUITexture> guiTextures = new ArrayList<>();
public void addTexture(GUITexture texture) {
guiTextures.add(texture);
}
public void setup() {
vaoId = glGenVertexArrays();
vboId = glGenBuffers();
FloatBuffer buffer = BufferUtils.createFloatBuffer(8);
buffer.put(new float[]{
-1, 1,
-1, -1,
1, 1,
1, -1
});
buffer.flip();
vertexCount = buffer.limit();
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2 * Float.BYTES, 0);
shaderProgram = new ShaderProgram.Builder()
.withShader("shader/gui/vertex.glsl", GL_VERTEX_SHADER)
.withShader("shader/gui/fragment.glsl", GL_FRAGMENT_SHADER)
.build();
transformUniformLocation = shaderProgram.getUniform("transform");
shaderProgram.bindAttribute(0, "position");
}
public void draw() {
shaderProgram.use();
glBindVertexArray(vaoId);
glEnableVertexAttribArray(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
for (var texture : guiTextures) {
glActiveTexture(GL_TEXTURE0);
Matrix4f transform = new Matrix4f()
.translate(texture.getPosition().x, texture.getPosition().y, 0)
.scale(texture.getScale().x, texture.getScale().y, 1);
float[] transformData = new float[16];
transform.get(transformData);
glUniformMatrix4fv(transformUniformLocation, false, transformData);
glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
}
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDisableVertexAttribArray(0);
glBindVertexArray(0);
}
public void free() {
for (var tex : guiTextures) tex.free();
glDeleteBuffers(vboId);
glDeleteVertexArrays(vaoId);
shaderProgram.free();
}
}

View File

@ -0,0 +1,52 @@
package nl.andrewl.aos2_client.render.gui;
import nl.andrewl.aos_core.ImageUtils;
import org.joml.Vector2f;
import org.joml.Vector3f;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import static org.lwjgl.opengl.GL46.*;
public class GUITexture {
private final int textureId;
private final int width;
private final int height;
private final Vector2f position = new Vector2f(0, 0);
private final Vector2f scale = new Vector2f(1, 1);
public GUITexture(String location) throws IOException {
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();
textureId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, textureId);
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 getTextureId() {
return textureId;
}
public Vector2f getPosition() {
return position;
}
public Vector2f getScale() {
return scale;
}
public void free() {
glDeleteTextures(textureId);
}
}

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
/**
* Simple data structure class holding information about a certain glyph in the

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import nl.andrewl.aos2_client.render.ShaderProgram;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import java.io.File;

View File

@ -1,10 +1,7 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import java.nio.FloatBuffer;
import static org.lwjgl.opengl.GL46.*;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import java.io.BufferedReader;
import java.io.File;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render;
package nl.andrewl.aos2_client.render.gui.font;
import org.joml.Vector2f;
import org.lwjgl.BufferUtils;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import java.io.File;
import java.util.ArrayList;

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
/**
* Stores the vertex data for all the quads on which a text will be rendered.

View File

@ -1,4 +1,4 @@
package nl.andrewl.aos2_client.render.font;
package nl.andrewl.aos2_client.render.gui.font;
import java.util.ArrayList;
import java.util.List;

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -0,0 +1,10 @@
#version 460 core
in vec2 texturePosition;
out vec4 fragmentColor;
uniform sampler2D guiTexture;
void main() {
fragmentColor = texture(guiTexture, texturePosition);
}

View File

@ -0,0 +1,14 @@
#version 460 core
in vec2 position;
out vec2 texturePosition;
uniform mat4 transform;
void main() {
gl_Position = transform * vec4(position, 0.0, 1.0);
texturePosition = vec2(
(position.x + 1.0) / 2.0,
1 - (position.y + 1.0) / 2.0
);
}

View File

@ -0,0 +1,28 @@
package nl.andrewl.aos_core;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
public class ImageUtils {
public static ByteBuffer decodePng(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
// Load texture contents into a byte buffer
ByteBuffer buf = ByteBuffer.allocateDirect(4 * width * height );
// decode image
// ARGB format to -> RGBA
for( int h = 0; h < height; h++ )
for( int w = 0; w < width; w++ ) {
int argb = image.getRGB( w, h );
buf.put( (byte) ( 0xFF & ( argb >> 16 ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 8 ) ) );
buf.put( (byte) ( 0xFF & ( argb ) ) );
buf.put( (byte) ( 0xFF & ( argb >> 24 ) ) );
}
buf.flip();
return buf;
}
}