Refactor tile system

This commit is contained in:
2021-01-31 00:26:52 +01:00
parent c76f3df70d
commit 81b7a7571b
18 changed files with 126 additions and 108 deletions

View File

@@ -2,11 +2,14 @@ package com.bartlomiejpluta.samplegame.core.gl.object.material;
import com.bartlomiejpluta.samplegame.core.gl.object.texture.Texture;
import lombok.Getter;
import org.joml.Vector2f;
import org.joml.Vector4f;
@Getter
public class Material {
private final Vector4f color = new Vector4f();
private final Vector2f spriteSize = new Vector2f(1, 1);
private final Vector2f spritePosition = new Vector2f(0, 0);
private final Texture texture;
private Material(Texture texture, float r, float g, float b, float alpha) {
@@ -21,6 +24,26 @@ public class Material {
color.w = alpha;
}
public void setSpriteSize(Vector2f spriteSize) {
this.spriteSize.x = spriteSize.x;
this.spriteSize.y = spriteSize.y;
}
public void setSpriteSize(float w, float h) {
this.spriteSize.x = w;
this.spriteSize.y = h;
}
public void setSpritePosition(Vector2f spritePosition) {
this.spritePosition.x = spritePosition.x;
this.spritePosition.y = spritePosition.y;
}
public void setSpritePosition(float x, float y) {
this.spritePosition.x = x;
this.spritePosition.y = y;
}
public boolean hasTexture() {
return texture != null;
}

View File

@@ -22,10 +22,6 @@ public class Mesh implements Renderable {
private final List<Integer> vboIds = new ArrayList<>(2);
private final int elementsCount;
@Getter
@Setter
private Material material;
public Mesh(float[] vertices, float[] texCoords, int[] elements) {
try(var stack = MemoryStack.stackPush()) {
elementsCount = elements.length;
@@ -83,4 +79,22 @@ public class Mesh implements Renderable {
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
public static Mesh quad(float width, float height) {
var halfWidth = width/2;
var halfHeight = height/2;
var vertices = new float[] {
-halfWidth, -halfHeight,
-halfWidth, halfHeight,
halfWidth, halfHeight,
halfWidth, -halfHeight
};
var texCoords = new float[] { 0, 0, 0, 1, 1, 1, 1, 0 };
var elements = new int[] { 0, 1, 2, 2, 3, 0 };
return new Mesh(vertices, texCoords, elements);
}
}

View File

@@ -27,7 +27,9 @@ public class DefaultRenderer implements Renderer {
.createUniform(UniformName.UNI_PROJECTION_MATRIX)
.createUniform(UniformName.UNI_OBJECT_COLOR)
.createUniform(UniformName.UNI_HAS_OBJECT_TEXTURE)
.createUniform(UniformName.UNI_TEXTURE_SAMPLER);
.createUniform(UniformName.UNI_TEXTURE_SAMPLER)
.createUniform(UniformName.UNI_SPRITE_SIZE)
.createUniform(UniformName.UNI_SPRITE_POSITION);
}
@Override

View File

@@ -7,4 +7,6 @@ public interface UniformName {
String UNI_OBJECT_COLOR = "objectColor";
String UNI_HAS_OBJECT_TEXTURE = "hasTexture";
String UNI_TEXTURE_SAMPLER = "sampler";
String UNI_SPRITE_SIZE = "spriteSize";
String UNI_SPRITE_POSITION = "spritePosition";
}

View File

@@ -5,10 +5,7 @@ import com.bartlomiejpluta.samplegame.core.gl.shader.program.ShaderProgram;
import com.bartlomiejpluta.samplegame.core.gl.shader.uniform.Uniform;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.joml.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -95,6 +92,12 @@ public class DefaultShaderManager implements ShaderManager {
return this;
}
@Override
public ShaderManager setUniform(String uniformName, Vector2f value) {
current.setUniform(uniformName, value);
return this;
}
@Override
public ShaderManager setUniform(String uniformName, Vector3f value) {
current.setUniform(uniformName, value);

View File

@@ -1,10 +1,7 @@
package com.bartlomiejpluta.samplegame.core.gl.shader.manager;
import com.bartlomiejpluta.samplegame.core.gl.shader.uniform.Uniform;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.joml.*;
public interface ShaderManager {
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
@@ -29,6 +26,8 @@ public interface ShaderManager {
ShaderManager setUniform(String uniformName, float value);
ShaderManager setUniform(String uniformName, Vector2f value);
ShaderManager setUniform(String uniformName, Vector3f value);
ShaderManager setUniform(String uniformName, Vector4f value);

View File

@@ -3,10 +3,7 @@ package com.bartlomiejpluta.samplegame.core.gl.shader.program;
import com.bartlomiejpluta.samplegame.core.error.AppException;
import com.bartlomiejpluta.samplegame.core.gl.shader.uniform.Uniform;
import lombok.extern.slf4j.Slf4j;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.joml.*;
import org.lwjgl.system.MemoryStack;
import java.util.HashMap;
@@ -111,6 +108,10 @@ public class ShaderProgram {
glUniform1f(uniforms.get(uniformName), value);
}
public void setUniform(String uniformName, Vector2f value) {
glUniform2f(uniforms.get(uniformName), value.x, value.y);
}
public void setUniform(String uniformName, Vector3f value) {
glUniform3f(uniforms.get(uniformName), value.x, value.y, value.z);
}

View File

@@ -5,19 +5,17 @@ import com.bartlomiejpluta.samplegame.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.samplegame.core.gl.render.Renderable;
import com.bartlomiejpluta.samplegame.core.gl.shader.manager.ShaderManager;
import com.bartlomiejpluta.samplegame.core.ui.Window;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
@RequiredArgsConstructor
public abstract class RenderableObject extends Object implements Renderable {
private final Mesh mesh;
public void setMaterial(Material material) {
mesh.setMaterial(material);
}
public Material getMaterial() {
return mesh.getMaterial();
}
@Getter
@Setter
private Material material;
@Override
public void render(Window window, ShaderManager shaderManager) {

View File

@@ -29,7 +29,6 @@ public class Scene implements Renderable {
renderArray(map.getLayer(2), window, shaderManager);
renderArray(map.getLayer(3), window, shaderManager);
}
private <T extends RenderableObject> void renderArray(T[] objects, Window window, ShaderManager shaderManager) {
@@ -45,6 +44,8 @@ public class Scene implements Renderable {
shaderManager.setUniform(UniformName.UNI_OBJECT_COLOR, object.getMaterial().getColor());
shaderManager.setUniform(UniformName.UNI_HAS_OBJECT_TEXTURE, object.getMaterial().hasTexture());
shaderManager.setUniform(UniformName.UNI_TEXTURE_SAMPLER, 0);
shaderManager.setUniform(UniformName.UNI_SPRITE_SIZE, object.getMaterial().getSpriteSize());
shaderManager.setUniform(UniformName.UNI_SPRITE_POSITION, object.getMaterial().getSpritePosition());
object.render(window, shaderManager);
}

View File

@@ -16,7 +16,6 @@ import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultGameLogic implements GameLogic {
private static final float SCALE = 3.0f;
private final Renderer renderer;
private final TileSetManager tileSetManager;

View File

@@ -1,55 +0,0 @@
package com.bartlomiejpluta.samplegame.game.sprite;
import com.bartlomiejpluta.samplegame.core.gl.object.material.Material;
import com.bartlomiejpluta.samplegame.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.samplegame.core.gl.object.texture.Texture;
import com.bartlomiejpluta.samplegame.core.world.object.RenderableObject;
import lombok.Getter;
@Getter
public class BaseSprite extends RenderableObject {
private static final int[] ELEMENTS = new int[]{
0, 1, 2,
2, 3, 0
};
private final int row;
private final int col;
private final int tileWidth;
private final int tileHeight;
public BaseSprite(Texture texture, int row, int col, int tileWidth, int tileHeight) {
super(buildTileMesh(texture, row, col, tileWidth, tileHeight));
this.row = row;
this.col = col;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
setMaterial(Material.textured(texture));
}
private static Mesh buildTileMesh(Texture texture, int row, int col, int tileWidth, int tileHeight) {
var vertices = getVertices(tileWidth, tileHeight);
var texCoords = getTextureCoordinates(row, col, tileWidth, tileHeight, texture.getWidth(), texture.getHeight());
return new Mesh(vertices, texCoords, ELEMENTS);
}
private static float[] getVertices(int tileWidth, int tileHeight) {
var halfWidth = tileWidth / 2;
var halfHeight = tileHeight / 2;
return new float[]{
-halfWidth, -halfHeight,
-halfWidth, halfHeight,
halfWidth, halfHeight,
halfWidth, -halfHeight
};
}
private static float[] getTextureCoordinates(int col, int row, int tileWidth, int tileHeight, int textureWidth, int textureHeight) {
return new float[]{
(col * tileWidth) / (float) textureWidth, (row * tileHeight) / (float) textureHeight,
(col * tileWidth) / (float) textureWidth, ((row + 1) * tileHeight) / (float) textureHeight,
((col + 1) * tileWidth) / (float) textureWidth, ((row + 1) * tileHeight) / (float) textureHeight,
((col + 1) * tileWidth) / (float) textureWidth, (row * tileHeight) / (float) textureHeight
};
}
}

View File

@@ -32,7 +32,7 @@ public class GameMap {
private void recalculateTileGeometry(Tile tile, int i, int j) {
tile.setScale(scale);
var size = tile.getSize();
var size = tile.getWidth();
var offset = size * scale;
tile.setPosition(i * offset, j * offset);
}

View File

@@ -2,17 +2,28 @@ package com.bartlomiejpluta.samplegame.game.world.tileset.manager;
import com.bartlomiejpluta.samplegame.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.samplegame.game.world.tileset.model.TileSet;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DefaultTileSetManager implements TileSetManager {
private final TextureManager textureManager;
private final int tileWidth;
private final int tileHeight;
@Autowired
public DefaultTileSetManager(
TextureManager textureManager,
@Value("${app.map.tile.width}") int tileWidth,
@Value("${app.map.tile.width}") int tileHeight) {
this.textureManager = textureManager;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
}
@Override
public TileSet createTileSet(String tileSetFileName) {
return new TileSet(textureManager.loadTexture(tileSetFileName));
public TileSet createTileSet(String tileSetFileName, int rows, int columns) {
return new TileSet(textureManager.loadTexture(tileSetFileName), rows, columns, tileWidth, tileHeight);
}
}

View File

@@ -3,5 +3,5 @@ package com.bartlomiejpluta.samplegame.game.world.tileset.manager;
import com.bartlomiejpluta.samplegame.game.world.tileset.model.TileSet;
public interface TileSetManager {
TileSet createTileSet(String tileSetFileName);
TileSet createTileSet(String tileSetFileName, int rows, int columns);
}

View File

@@ -1,16 +1,19 @@
package com.bartlomiejpluta.samplegame.game.world.tileset.model;
import com.bartlomiejpluta.samplegame.core.gl.object.texture.Texture;
import com.bartlomiejpluta.samplegame.game.sprite.BaseSprite;
import com.bartlomiejpluta.samplegame.core.gl.object.material.Material;
import com.bartlomiejpluta.samplegame.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.samplegame.core.world.object.RenderableObject;
import lombok.Getter;
@Getter
public class Tile extends BaseSprite {
private final int size;
public class Tile extends RenderableObject {
private final int width;
private final int height;
public Tile(Texture texture, int row, int col, int size) {
super(texture, row, col, size, size);
this.size = size;
Tile(Mesh mesh, Material material, int width, int height) {
super(mesh);
this.width = width;
this.height = height;
setMaterial(material);
}
}

View File

@@ -1,25 +1,35 @@
package com.bartlomiejpluta.samplegame.game.world.tileset.model;
import com.bartlomiejpluta.samplegame.core.gl.object.material.Material;
import com.bartlomiejpluta.samplegame.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.samplegame.core.gl.object.texture.Texture;
import com.bartlomiejpluta.samplegame.core.world.object.RenderableObject;
public class TileSet {
private static final int TILE_SIZE = 16;
private final Texture texture;
private final int rows;
private final int cols;
private final int columns;
private final float columnStep;
private final float rowStep;
private final int tileWidth;
private final int tileHeight;
private final Mesh mesh;
public TileSet(Texture texture) {
public TileSet(Texture texture, int rows, int columns, int tileWidth, int tileHeight) {
this.texture = texture;
this.rows = texture.getHeight() / TILE_SIZE;
this.cols = texture.getWidth() / TILE_SIZE;
this.rows = rows;
this.columns = columns;
this.columnStep = 1/(float) columns;
this.rowStep = 1/(float) rows;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.mesh = Mesh.quad(tileWidth, tileHeight);
}
public Tile getTile(int m, int n) {
return new Tile(texture, m, n, TILE_SIZE);
}
public Tile getTile(int i) {
return new Tile(texture, i % cols, i / rows, TILE_SIZE);
var material = Material.textured(texture);
material.setSpriteSize(columnStep, rowStep);
material.setSpritePosition(n * columnStep, m * rowStep);
return new Tile(mesh, material, tileWidth, tileHeight);
}
}

View File

@@ -6,3 +6,8 @@ app:
core:
targetUps: 50 # Updates per second
map:
tile:
width: 50
height: 50

View File

@@ -3,6 +3,8 @@
uniform vec4 objectColor;
uniform int hasTexture;
uniform sampler2D sampler;
uniform vec2 spriteSize;
uniform vec2 spritePosition;
in vec2 fragmentTexCoord;
@@ -12,7 +14,7 @@ void main()
{
if(hasTexture == 1)
{
fragColor = objectColor * texture(sampler, fragmentTexCoord);
fragColor = objectColor * texture(sampler, fragmentTexCoord * spriteSize + spritePosition);
}
else
{