Migrate to BatchedQuads mesh

This commit is contained in:
2025-07-18 14:41:59 +02:00
parent f131f9ef7f
commit 1d1730f97b
29 changed files with 432 additions and 584 deletions

View File

@@ -1,288 +0,0 @@
package com.bartlomiejpluta.base.engine.core.gl.object.mesh;
import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.internal.gc.Disposable;
import com.bartlomiejpluta.base.internal.render.Renderable;
import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.Getter;
import org.lwjgl.opengl.GL15;
import org.lwjgl.system.MemoryStack;
import java.util.ArrayList;
import java.util.List;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
public class BatchedQuads implements Renderable, Disposable {
// Texture: Quad:
// (0,1) ---- (1,1) 1 ----------- 2
// | | | |
// | | => | TEXTURE |
// | | | |
// (0,0) ---- (1,0) 0 ----------- 3
private static final float[] DEFAULT_TEXTURE_COORDINATES = new float[] {
0, 0, // 0 - bottom left
0, 1, // 1 - top left
1, 1, // 2 - top right
1, 0 // 3 - bottom right
};
private static final int POSITION_VECTOR_LAYOUT_INDEX = 0;
private static final int POSITION_VECTOR_LENGTH = 2;
private static final int TEXTURE_COORDINATES_VECTOR_LAYOUT_INDEX = 1;
private static final int TEXTURE_COORDINATES_VECTOR_LENGTH = 2;
private static final int VERTICES_PER_QUAD = 4;
private static final int INDICES_PER_QUAD = 6;
private final int maxQuads;
private final int vaoId;
private final List<Integer> vboIds = new ArrayList<>(3);
private final int maxVertices;
private final int maxIndices;
private final float[] vertexBuffer;
private final float[] texCoordBuffer;
private final int[] indexBuffer;
@Getter
private int currentQuadCount = 0;
public BatchedQuads(int maxQuads) {
this.maxQuads = maxQuads;
this.maxVertices = maxQuads * VERTICES_PER_QUAD * 2;
this.maxIndices = maxQuads * INDICES_PER_QUAD;
this.vertexBuffer = new float[maxVertices];
this.texCoordBuffer = new float[maxVertices];
this.indexBuffer = new int[maxIndices];
try (var stack = MemoryStack.stackPush()) {
vaoId = glGenVertexArrays();
glBindVertexArray(vaoId);
// Vertex buffer
var vertexVboId = glGenBuffers();
vboIds.add(vertexVboId);
glBindBuffer(GL_ARRAY_BUFFER, vertexVboId);
glBufferData(GL_ARRAY_BUFFER, maxVertices * Float.BYTES, GL_DYNAMIC_DRAW);
glVertexAttribPointer(POSITION_VECTOR_LAYOUT_INDEX, POSITION_VECTOR_LENGTH, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
// Texture coordinates buffer
var texCoordVboId = glGenBuffers();
vboIds.add(texCoordVboId);
glBindBuffer(GL_ARRAY_BUFFER, texCoordVboId);
glBufferData(GL_ARRAY_BUFFER, maxVertices * Float.BYTES, GL_DYNAMIC_DRAW);
glVertexAttribPointer(TEXTURE_COORDINATES_VECTOR_LAYOUT_INDEX, TEXTURE_COORDINATES_VECTOR_LENGTH, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1);
// Index buffer
var indexVboId = glGenBuffers();
vboIds.add(indexVboId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, maxIndices * Integer.BYTES, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
public int addQuad(Quad quad, float x, float y) {
return addQuad(quad, x, y, DEFAULT_TEXTURE_COORDINATES);
}
public int addQuad(Quad quad, float x, float y, float[] textureCoordinates) {
if (currentQuadCount >= maxQuads) {
throw new RuntimeException("Batch is full!");
}
int quadId = currentQuadCount;
// Vertices
var localVertices = quad.getVertices();
int vertexStartIndex = currentQuadCount * VERTICES_PER_QUAD * 2;
for (int i = 0; i < VERTICES_PER_QUAD; i++) {
float localX = localVertices[i * 2];
float localY = localVertices[i * 2 + 1];
vertexBuffer[vertexStartIndex + i * 2] = x + localX;
vertexBuffer[vertexStartIndex + i * 2 + 1] = y + localY;
}
// Texture
var texCoordStartIndex = currentQuadCount * VERTICES_PER_QUAD * 2;
System.arraycopy(textureCoordinates, 0, texCoordBuffer, texCoordStartIndex, textureCoordinates.length);
// Indices
var indexStartIndex = currentQuadCount * INDICES_PER_QUAD;
var vertexOffset = currentQuadCount * VERTICES_PER_QUAD;
int[] quadIndices = {
// First triangle: indices 0-1-2
// 1 ----------- 2
// |XXXXXXXXXXX |
// |XXXXXXXX |
// |XXXXX |
// |XX |
// 0 ----------- 3
vertexOffset + 0, vertexOffset + 1, vertexOffset + 2,
// Second triangle: indices 2-3-0
// 1 ----------- 2
// | X|
// | XXXX|
// | XXXXXXX|
// | XXXXXXXXXX|
// 0 ----------- 3
vertexOffset + 2, vertexOffset + 3, vertexOffset + 0
};
System.arraycopy(quadIndices, 0, indexBuffer, indexStartIndex, quadIndices.length);
currentQuadCount++;
return quadId;
}
public void setQuadTextureCoordinates(int quadId, float[] textureCoordinates) {
if (quadId < 0 || quadId >= currentQuadCount) {
throw new IllegalArgumentException("Invalid quad ID: " + quadId);
}
var texCoordsIndex = quadId * VERTICES_PER_QUAD * 2;
System.arraycopy(textureCoordinates, 0, texCoordBuffer, texCoordsIndex, textureCoordinates.length);
}
public void clear() {
currentQuadCount = 0;
}
public void removeQuad(int quadId) {
if (quadId < 0 || quadId >= currentQuadCount) {
throw new IllegalArgumentException("Invalid quad ID: " + quadId);
}
int lastQuadId = currentQuadCount - 1;
if (quadId != lastQuadId) {
swapQuads(quadId, lastQuadId);
}
currentQuadCount--;
}
private void swapQuads(int quad1, int quad2) {
// Swap vertices
swapQuadData(vertexBuffer, quad1, quad2, VERTICES_PER_QUAD * 2);
// Swap texture coordinates
swapQuadData(texCoordBuffer, quad1, quad2, VERTICES_PER_QUAD * 2);
// Swap indices
swapQuadIndices(quad1, quad2);
}
private void swapQuadData(float[] buffer, int quad1, int quad2, int dataSize) {
var start1 = quad1 * dataSize;
var start2 = quad2 * dataSize;
for (int i = 0; i < dataSize; i++) {
var temp = buffer[start1 + i];
buffer[start1 + i] = buffer[start2 + i];
buffer[start2 + i] = temp;
}
}
private void swapQuadIndices(int quad1, int quad2) {
var start1 = quad1 * INDICES_PER_QUAD;
var start2 = quad2 * INDICES_PER_QUAD;
var vertexOffset1 = quad1 * VERTICES_PER_QUAD;
int[] newIndices1 = {
vertexOffset1 + 0, vertexOffset1 + 1, vertexOffset1 + 2,
vertexOffset1 + 2, vertexOffset1 + 3, vertexOffset1 + 0
};
var vertexOffset2 = quad2 * VERTICES_PER_QUAD;
int[] newIndices2 = {
vertexOffset2 + 0, vertexOffset2 + 1, vertexOffset2 + 2,
vertexOffset2 + 2, vertexOffset2 + 3, vertexOffset2 + 0
};
System.arraycopy(newIndices1, 0, indexBuffer, start1, INDICES_PER_QUAD);
System.arraycopy(newIndices2, 0, indexBuffer, start2, INDICES_PER_QUAD);
}
@Override
public void render(Screen screen, Camera camera, ShaderManager shaderManager) {
if (currentQuadCount == 0) {
return;
}
glBindVertexArray(vaoId);
try (var stack = MemoryStack.stackPush()) {
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vboIds.get(0));
var vertexFloatBuffer = stack.mallocFloat(currentQuadCount * VERTICES_PER_QUAD * 2);
for (int i = 0; i < currentQuadCount * VERTICES_PER_QUAD * 2; i++) {
vertexFloatBuffer.put(vertexBuffer[i]);
}
vertexFloatBuffer.flip();
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexFloatBuffer);
// Texture coordinate buffer
glBindBuffer(GL_ARRAY_BUFFER, vboIds.get(1));
var texCoordFloatBuffer = stack.mallocFloat(currentQuadCount * VERTICES_PER_QUAD * 2);
for (int i = 0; i < currentQuadCount * VERTICES_PER_QUAD * 2; i++) {
texCoordFloatBuffer.put(texCoordBuffer[i]);
}
texCoordFloatBuffer.flip();
glBufferSubData(GL_ARRAY_BUFFER, 0, texCoordFloatBuffer);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
var indexIntBuffer = stack.mallocInt(currentQuadCount * INDICES_PER_QUAD);
for (int i = 0; i < currentQuadCount * INDICES_PER_QUAD; i++) {
indexIntBuffer.put(indexBuffer[i]);
}
indexIntBuffer.flip();
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexIntBuffer);
}
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, currentQuadCount * INDICES_PER_QUAD, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindVertexArray(0);
}
@Override
public void dispose() {
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
vboIds.forEach(GL15::glDeleteBuffers);
glBindVertexArray(0);
glDeleteVertexArrays(vaoId);
}
public boolean isFull() {
return currentQuadCount >= maxQuads;
}
public boolean isEmpty() {
return currentQuadCount == 0;
}
}

View File

@@ -6,110 +6,257 @@ import com.bartlomiejpluta.base.internal.gc.Disposable;
import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.Renderable;
import com.bartlomiejpluta.base.internal.render.ShaderManager; import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.Getter; import lombok.Getter;
import org.joml.Vector2f;
import org.joml.Vector2fc;
import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static java.lang.Math.abs;
import static org.lwjgl.opengl.GL15.*; import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*; import static org.lwjgl.opengl.GL30.*;
public class Mesh implements Renderable, Disposable { public class Mesh implements Renderable, Disposable {
// default.vs: layout(location=0) in vec2 position; // Texture: Quad:
// ^ ^ // (0,1) ---- (1,1) 1 ----------- 2
// | | | |
// | | => | TEXTURE |
// | | | |
// (0,0) ---- (1,0) 0 ----------- 3
private static final float[] DEFAULT_TEXTURE_COORDINATES = new float[] {
0, 0, // 0 - bottom left
0, 1, // 1 - top left
1, 1, // 2 - top right
1, 0 // 3 - bottom right
};
private static final int POSITION_VECTOR_LAYOUT_INDEX = 0; private static final int POSITION_VECTOR_LAYOUT_INDEX = 0;
private static final int POSITION_VECTOR_LENGTH = 2; private static final int POSITION_VECTOR_LENGTH = 2;
private static final int TEXTURE_COORDINATES_VECTOR_LAYOUT_INDEX = 1;
private static final int TEXTURE_COORDINATES_VECTOR_LENGTH = 2;
// default.vs: layout(location=1) in vec2 texCoord; private static final int VERTICES_PER_QUAD = 4;
// ^ ^ private static final int INDICES_PER_QUAD = 6;
private static final int TEX_COORDS_VECTOR_LAYOUT_INDEX = 1;
private static final int TEX_COORDS_VECTOR_LENGTH = 2;
private final int maxQuads;
private final int vaoId; private final int vaoId;
private final List<Integer> vboIds = new ArrayList<>(2); private final List<Integer> vboIds = new ArrayList<>(3);
private final int elementsCount; private final int maxVertices;
private final int maxIndices;
private final float[] vertexBuffer;
private final float[] texCoordBuffer;
private final int[] indexBuffer;
@Getter @Getter
private final Vector2fc farthestVertex; private int currentQuadCount = 0;
@Getter public Mesh(int maxQuads) {
private final Vector2fc primarySize; this.maxQuads = maxQuads;
this.maxVertices = maxQuads * VERTICES_PER_QUAD * 2;
this.maxIndices = maxQuads * INDICES_PER_QUAD;
public Mesh(float[] vertices, float[] texCoords, int[] elements) { this.vertexBuffer = new float[maxVertices];
this.elementsCount = elements.length; this.texCoordBuffer = new float[maxVertices];
this.indexBuffer = new int[maxIndices];
var vboId = 0;
try (var stack = MemoryStack.stackPush()) { try (var stack = MemoryStack.stackPush()) {
vaoId = glGenVertexArrays(); vaoId = glGenVertexArrays();
glBindVertexArray(vaoId); glBindVertexArray(vaoId);
// Vertices VBO // Vertex buffer
vboId = glGenBuffers(); var vertexVboId = glGenBuffers();
vboIds.add(vboId); vboIds.add(vertexVboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId); glBindBuffer(GL_ARRAY_BUFFER, vertexVboId);
glBufferData(GL_ARRAY_BUFFER, stack.mallocFloat(vertices.length).put(vertices).flip(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, maxVertices * Float.BYTES, GL_DYNAMIC_DRAW);
glVertexAttribPointer(POSITION_VECTOR_LAYOUT_INDEX, POSITION_VECTOR_LENGTH, GL_FLOAT, false, 0, 0); glVertexAttribPointer(POSITION_VECTOR_LAYOUT_INDEX, POSITION_VECTOR_LENGTH, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
// Texture Coordinates VBO // Texture coordinates buffer
vboId = glGenBuffers(); var texCoordVboId = glGenBuffers();
vboIds.add(vboId); vboIds.add(texCoordVboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId); glBindBuffer(GL_ARRAY_BUFFER, texCoordVboId);
glBufferData(GL_ARRAY_BUFFER, stack.mallocFloat(texCoords.length).put(texCoords).flip(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, maxVertices * Float.BYTES, GL_DYNAMIC_DRAW);
glVertexAttribPointer(TEX_COORDS_VECTOR_LAYOUT_INDEX, TEX_COORDS_VECTOR_LENGTH, GL_FLOAT, false, 0, 0); glVertexAttribPointer(TEXTURE_COORDINATES_VECTOR_LAYOUT_INDEX, TEXTURE_COORDINATES_VECTOR_LENGTH, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1);
// Elements VBO // Index buffer
vboId = glGenBuffers(); var indexVboId = glGenBuffers();
vboIds.add(vboId); vboIds.add(indexVboId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, stack.mallocInt(elementsCount).put(elements).flip(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, maxIndices * Integer.BYTES, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0); glBindVertexArray(0);
} }
var minX = Float.MAX_VALUE;
var minY = Float.MAX_VALUE;
var maxX = 0f;
var maxY = 0f;
for (int i = 0; i < vertices.length / 2; ++i) {
var x = vertices[2 * i];
var y = vertices[2 * i + 1];
if (x < minX) {
minX = x;
} }
if (x > maxX) { public int addQuad(QuadTemplate template, float x, float y) {
maxX = x; return addQuad(template, x, y, DEFAULT_TEXTURE_COORDINATES);
} }
if (y < minY) { public int addQuad(QuadTemplate template, float x, float y, float[] textureCoordinates) {
minY = y; if (currentQuadCount >= maxQuads) {
throw new RuntimeException("Batch is full!");
} }
if (y > maxY) { int quadId = currentQuadCount;
maxY = y;
// Vertices
var localVertices = template.getVertices();
int vertexStartIndex = currentQuadCount * VERTICES_PER_QUAD * 2;
for (int i = 0; i < VERTICES_PER_QUAD; i++) {
float localX = localVertices[i * 2];
float localY = localVertices[i * 2 + 1];
vertexBuffer[vertexStartIndex + i * 2] = x + localX;
vertexBuffer[vertexStartIndex + i * 2 + 1] = y + localY;
}
// Texture
var texCoordStartIndex = currentQuadCount * VERTICES_PER_QUAD * 2;
System.arraycopy(textureCoordinates, 0, texCoordBuffer, texCoordStartIndex, textureCoordinates.length);
// Indices
var indexStartIndex = currentQuadCount * INDICES_PER_QUAD;
var vertexOffset = currentQuadCount * VERTICES_PER_QUAD;
int[] quadIndices = {
// First triangle: indices 0-1-2
// 1 ----------- 2
// |XXXXXXXXXXX |
// |XXXXXXXX |
// |XXXXX |
// |XX |
// 0 ----------- 3
vertexOffset + 0, vertexOffset + 1, vertexOffset + 2,
// Second triangle: indices 2-3-0
// 1 ----------- 2
// | X|
// | XXXX|
// | XXXXXXX|
// | XXXXXXXXXX|
// 0 ----------- 3
vertexOffset + 2, vertexOffset + 3, vertexOffset + 0
};
System.arraycopy(quadIndices, 0, indexBuffer, indexStartIndex, quadIndices.length);
currentQuadCount++;
return quadId;
}
public void setQuadTextureCoordinates(int quadId, float[] textureCoordinates) {
if (quadId < 0 || quadId >= currentQuadCount) {
throw new IllegalArgumentException("Invalid quad ID: " + quadId);
}
var texCoordsIndex = quadId * VERTICES_PER_QUAD * 2;
System.arraycopy(textureCoordinates, 0, texCoordBuffer, texCoordsIndex, textureCoordinates.length);
}
public void clear() {
currentQuadCount = 0;
}
public void removeQuad(int quadId) {
if (quadId < 0 || quadId >= currentQuadCount) {
throw new IllegalArgumentException("Invalid quad ID: " + quadId);
}
int lastQuadId = currentQuadCount - 1;
if (quadId != lastQuadId) {
swapQuads(quadId, lastQuadId);
}
currentQuadCount--;
}
private void swapQuads(int quad1, int quad2) {
// Swap vertices
swapQuadData(vertexBuffer, quad1, quad2, VERTICES_PER_QUAD * 2);
// Swap texture coordinates
swapQuadData(texCoordBuffer, quad1, quad2, VERTICES_PER_QUAD * 2);
// Swap indices
swapQuadIndices(quad1, quad2);
}
private void swapQuadData(float[] buffer, int quad1, int quad2, int dataSize) {
var start1 = quad1 * dataSize;
var start2 = quad2 * dataSize;
for (int i = 0; i < dataSize; i++) {
var temp = buffer[start1 + i];
buffer[start1 + i] = buffer[start2 + i];
buffer[start2 + i] = temp;
} }
} }
farthestVertex = new Vector2f(abs(maxX) > abs(minX) ? maxX : minX, abs(maxY) > abs(minY) ? maxY : minY); private void swapQuadIndices(int quad1, int quad2) {
primarySize = new Vector2f(maxX - minX, maxY - minY); var start1 = quad1 * INDICES_PER_QUAD;
var start2 = quad2 * INDICES_PER_QUAD;
var vertexOffset1 = quad1 * VERTICES_PER_QUAD;
int[] newIndices1 = {
vertexOffset1 + 0, vertexOffset1 + 1, vertexOffset1 + 2,
vertexOffset1 + 2, vertexOffset1 + 3, vertexOffset1 + 0
};
var vertexOffset2 = quad2 * VERTICES_PER_QUAD;
int[] newIndices2 = {
vertexOffset2 + 0, vertexOffset2 + 1, vertexOffset2 + 2,
vertexOffset2 + 2, vertexOffset2 + 3, vertexOffset2 + 0
};
System.arraycopy(newIndices1, 0, indexBuffer, start1, INDICES_PER_QUAD);
System.arraycopy(newIndices2, 0, indexBuffer, start2, INDICES_PER_QUAD);
} }
@Override @Override
public void render(Screen screen, Camera camera, ShaderManager shaderManager) { public void render(Screen screen, Camera camera, ShaderManager shaderManager) {
if (currentQuadCount == 0) {
return;
}
glBindVertexArray(vaoId); glBindVertexArray(vaoId);
try (var stack = MemoryStack.stackPush()) {
// Vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vboIds.get(0));
var vertexFloatBuffer = stack.mallocFloat(currentQuadCount * VERTICES_PER_QUAD * 2);
for (int i = 0; i < currentQuadCount * VERTICES_PER_QUAD * 2; i++) {
vertexFloatBuffer.put(vertexBuffer[i]);
}
vertexFloatBuffer.flip();
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexFloatBuffer);
// Texture coordinate buffer
glBindBuffer(GL_ARRAY_BUFFER, vboIds.get(1));
var texCoordFloatBuffer = stack.mallocFloat(currentQuadCount * VERTICES_PER_QUAD * 2);
for (int i = 0; i < currentQuadCount * VERTICES_PER_QUAD * 2; i++) {
texCoordFloatBuffer.put(texCoordBuffer[i]);
}
texCoordFloatBuffer.flip();
glBufferSubData(GL_ARRAY_BUFFER, 0, texCoordFloatBuffer);
// Index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
var indexIntBuffer = stack.mallocInt(currentQuadCount * INDICES_PER_QUAD);
for (int i = 0; i < currentQuadCount * INDICES_PER_QUAD; i++) {
indexIntBuffer.put(indexBuffer[i]);
}
indexIntBuffer.flip();
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexIntBuffer);
}
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_INT, 0); glDrawElements(GL_TRIANGLES, currentQuadCount * INDICES_PER_QUAD, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
@@ -131,55 +278,15 @@ public class Mesh implements Renderable, Disposable {
glDeleteVertexArrays(vaoId); glDeleteVertexArrays(vaoId);
} }
public static Mesh quad(float width, float height, float originX, float originY) { public boolean isFull() {
// 1 ----------- 2 return currentQuadCount >= maxQuads;
// | | }
// | |
// | |
// | |
// | |
// 0 ----------- 3
var vertices = new float[]{
-originX, -originY, // 0 - bottom left
-originX, height - originY, // 1 - top left
width - originX, height - originY, // 2 - top right
width - originX, -originY // 3 - bottom right
};
// Texture: Quad: public boolean isEmpty() {
// (0,1) ---- (1,1) 1 ----------- 2 return currentQuadCount == 0;
// | | | | }
// | | => | TEKSTURA |
// | | | |
// (0,0) ---- (1,0) 0 ----------- 3
var texCoords = new float[]{
0, 0, // 0 - bottom left
0, 1, // 1 - top left
1, 1, // 2 - top right
1, 0 // 3 - bottom right
};
public static QuadMesh quad(float width, float height, float originX, float originY) {
var elements = new int[]{ return new QuadMesh(width, height, originX, originY);
// First triangle: indices 0-1-2
// 1 ----------- 2
// |XXXXXXXXXXX |
// |XXXXXXXX |
// |XXXXX |
// |XX |
// 0 ----------- 3
0, 1, 2,
// Second triangle: indices 2-3-0
// 1 ----------- 2
// | X|
// | XXXX|
// | XXXXXXX|
// | XXXXXXXXXX|
// 0 ----------- 3
2, 3, 0
};
return new Mesh(vertices, texCoords, elements);
} }
} }

View File

@@ -0,0 +1,26 @@
package com.bartlomiejpluta.base.engine.core.gl.object.mesh;
import lombok.NonNull;
public class QuadMesh extends Mesh {
private final int quadId;
QuadMesh(float width, float height, float originX, float originY) {
this(new QuadTemplate(width, height, originX, originY));
}
QuadMesh(@NonNull QuadTemplate template) {
super(1);
this.quadId = addQuad(template, 0, 0);
}
@Override
public void removeQuad(int quadId) {
throw new UnsupportedOperationException();
}
public void setTextureCoordinates(float[] textureCoordinates) {
super.setQuadTextureCoordinates(quadId, textureCoordinates);
}
}

View File

@@ -3,14 +3,14 @@ package com.bartlomiejpluta.base.engine.core.gl.object.mesh;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
public class Quad { public class QuadTemplate {
private final float width; private final float width;
private final float height; private final float height;
private final float originX; private final float originX;
private final float originY; private final float originY;
private final float[] vertices; private final float[] vertices;
public Quad(float width, float height, float originX, float originY) { public QuadTemplate(float width, float height, float originX, float originY) {
this.width = width; this.width = width;
this.height = height; this.height = height;
this.originX = originX; this.originX = originX;
@@ -30,33 +30,4 @@ public class Quad {
width - originX, -originY // 3 - bottom right width - originX, -originY // 3 - bottom right
}; };
} }
static float[] textureCoordinates = new float[]{
0, 0, // 0 - bottom left
0, 1, // 1 - top left
1, 1, // 2 - top right
1, 0 // 3 - bottom right
};
static int[] elements = new int[]{
// First triangle: indices 0-1-2
// 1 ----------- 2
// |XXXXXXXXXXX |
// |XXXXXXXX |
// |XXXXX |
// |XX |
// 0 ----------- 3
0, 1, 2,
// Second triangle: indices 2-3-0
// 1 ----------- 2
// | X|
// | XXXX|
// | XXXXXXX|
// | XXXXXXXXXX|
// 0 ----------- 3
2, 3, 0
};
} }

View File

@@ -74,6 +74,16 @@ public class Texture implements Disposable {
} }
} }
public float[][] getTextureCoordinatesForAllFrames() {
var array = new float[rows*columns][];
for (var i=0; i<array.length; ++i) {
array[i] = getTextureCoordinates(i);
}
return array;
}
public float[] getTextureCoordinates(int id) { public float[] getTextureCoordinates(int id) {
return getTextureCoordinates(id % columns, id / columns); return getTextureCoordinates(id % columns, id / columns);
} }

View File

@@ -1,43 +1,15 @@
package com.bartlomiejpluta.base.engine.util.mesh; package com.bartlomiejpluta.base.engine.util.mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.joml.Vector2f;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.HashMap; // TODO
import java.util.Map;
@Slf4j @Slf4j
@Component @Component
public class DefaultMeshManager implements MeshManager { public class DefaultMeshManager implements MeshManager {
private final Map<QuadDimension, Mesh> quads = new HashMap<>();
@Override
public Mesh createQuad(float width, float height, float originX, float originY) {
var dim = new QuadDimension(new Vector2f(width, height), new Vector2f(originX, originY));
var mesh = quads.get(dim);
if(mesh == null) {
log.info("Creating [w:{}, h:{} | O:{}, {}] mesh and putting it into the cache", width, height, originX, originY);
mesh = Mesh.quad(width, height, originX, originY);
quads.put(dim, mesh);
}
return mesh;
}
@Override @Override
public void cleanUp() { public void cleanUp() {
log.info("Disposing meshes"); log.info("Nothing to do for now (todo...)");
quads.forEach((dim, mesh) -> mesh.dispose());
log.info("{} meshes have been disposed", quads.size());
} }
@Data
private static class QuadDimension {
private final Vector2f size;
private final Vector2f origin;
}
} }

View File

@@ -1,8 +1,6 @@
package com.bartlomiejpluta.base.engine.util.mesh; package com.bartlomiejpluta.base.engine.util.mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.internal.gc.Cleanable; import com.bartlomiejpluta.base.internal.gc.Cleanable;
public interface MeshManager extends Cleanable { public interface MeshManager extends Cleanable {
Mesh createQuad(float width, float height, float originX, float originY);
} }

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.animation.manager;
import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.animation.Animation;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
@@ -28,11 +27,10 @@ public class DefaultAnimationManager implements AnimationManager {
private final Map<String, AnimationAsset> assets = new HashMap<>(); private final Map<String, AnimationAsset> assets = new HashMap<>();
private final Map<String, Vector2fc[]> frames = new HashMap<>(); private final Map<String, Vector2fc[]> frames = new HashMap<>();
private final ProjectConfiguration configuration; private final ProjectConfiguration configuration;
private Mesh mesh;
@Override @Override
public void init() { public void init() {
mesh = meshManager.createQuad(1, 1, 0.5f, 0.5f); // TODO mesh = meshManager.createQuad(1, 1, 0.5f, 0.5f);
} }
@Override @Override
@@ -62,7 +60,7 @@ public class DefaultAnimationManager implements AnimationManager {
var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns()); var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns());
var material = Material.textured(texture); var material = Material.textured(texture);
return new DefaultAnimation(mesh, material, animationFrames); return new DefaultAnimation(material, animationFrames);
} }
private Vector2fc[] createFrames(int rows, int columns) { private Vector2fc[] createFrames(int rows, int columns) {

View File

@@ -3,7 +3,6 @@ package com.bartlomiejpluta.base.engine.world.animation.model;
import com.bartlomiejpluta.base.api.animation.Animated; import com.bartlomiejpluta.base.api.animation.Animated;
import com.bartlomiejpluta.base.engine.core.engine.DefaultGameEngine; import com.bartlomiejpluta.base.engine.core.engine.DefaultGameEngine;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
import com.bartlomiejpluta.base.util.math.MathUtil; import com.bartlomiejpluta.base.util.math.MathUtil;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -17,14 +16,18 @@ public abstract class AnimatedSprite extends Sprite implements Animated {
private int intervalInMilliseconds = 100; private int intervalInMilliseconds = 100;
protected int currentAnimationFrame; protected int currentAnimationFrame;
public AnimatedSprite(Mesh mesh, Material material) { public AnimatedSprite(Material material) {
super(mesh, material); super(material);
} }
protected abstract boolean shouldAnimate(); protected abstract boolean shouldAnimate();
protected abstract Vector2fc[] getSpriteAnimationFramesPositions(); protected abstract Vector2fc[] getSpriteAnimationFramesPositions();
protected int[] getAvailableFrames() {
return null;
}
@Override @Override
public void setAnimationSpeed(float speed) { public void setAnimationSpeed(float speed) {
intervalInMilliseconds = (int) (1 / MathUtil.clamp(speed / DefaultGameEngine.TARGET_UPS, Float.MIN_VALUE, 1.0)); intervalInMilliseconds = (int) (1 / MathUtil.clamp(speed / DefaultGameEngine.TARGET_UPS, Float.MIN_VALUE, 1.0));
@@ -37,20 +40,24 @@ public abstract class AnimatedSprite extends Sprite implements Animated {
@Override @Override
public void setAnimationFrame(int frame) { public void setAnimationFrame(int frame) {
var positions = getSpriteAnimationFramesPositions(); var availableFrames = getAvailableFrames();
currentAnimationFrame = frame % positions.length;
var current = positions[currentAnimationFrame]; if (availableFrames == null) {
material.setSpritePosition(current); setFrame(frame % getTextureCoordinates().length);
return;
}
setFrame(availableFrames[frame % availableFrames.length]);
} }
@Override @Override
public void update(float dt) { public void update(float dt) {
if (shouldAnimate()) { if (shouldAnimate()) {
time += dt * 1000; time += dt * 1000;
var positions = getSpriteAnimationFramesPositions(); setAnimationFrame(time / intervalInMilliseconds * intervalInMilliseconds);
currentAnimationFrame = ((time % (positions.length * intervalInMilliseconds)) / intervalInMilliseconds); // var maxFrames = getTextureCoordinates().length;
var current = positions[currentAnimationFrame]; // currentAnimationFrame = ((time % (maxFrames * intervalInMilliseconds)) / intervalInMilliseconds);
material.setSpritePosition(current); // setSprite(currentAnimationFrame);
} else { } else {
time = 0; time = 0;
} }

View File

@@ -7,7 +7,6 @@ import com.bartlomiejpluta.base.api.move.AnimationMovement;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.movement.MovableSprite; import com.bartlomiejpluta.base.engine.world.movement.MovableSprite;
import com.bartlomiejpluta.base.util.path.Path; import com.bartlomiejpluta.base.util.path.Path;
import com.bartlomiejpluta.base.util.path.PathExecutor; import com.bartlomiejpluta.base.util.path.PathExecutor;
@@ -51,8 +50,8 @@ public class DefaultAnimation extends MovableSprite implements Animation {
@Getter @Getter
private final CompletableFuture<Animation> future = new CompletableFuture<>(); private final CompletableFuture<Animation> future = new CompletableFuture<>();
public DefaultAnimation(Mesh mesh, Material material, @NonNull Vector2fc[] frames) { public DefaultAnimation(Material material, @NonNull Vector2fc[] frames) {
super(mesh, material); super(material);
this.frames = frames; this.frames = frames;
this.lastFrameIndex = frames.length - 1; this.lastFrameIndex = frames.length - 1;

View File

@@ -1,6 +1,5 @@
package com.bartlomiejpluta.base.engine.world.autotile.manager; package com.bartlomiejpluta.base.engine.world.autotile.manager;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
@@ -24,11 +23,10 @@ public class DefaultAutoTileSetManager implements AutoTileManager {
private final Map<String, AutoTileSet> autoTiles = new HashMap<>(); private final Map<String, AutoTileSet> autoTiles = new HashMap<>();
private final Map<String, AutoTileSetAsset> assets = new HashMap<>(); private final Map<String, AutoTileSetAsset> assets = new HashMap<>();
private final ProjectConfiguration configuration; private final ProjectConfiguration configuration;
private Mesh mesh;
@Override @Override
public void init() { public void init() {
this.mesh = meshManager.createQuad(1, 1, 0, 0); // TODO: this.mesh = meshManager.createQuad(1, 1, 0, 0);
} }
@Override @Override
@@ -55,7 +53,7 @@ public class DefaultAutoTileSetManager implements AutoTileManager {
var source = configuration.projectFile("autotiles", asset.getSource()); var source = configuration.projectFile("autotiles", asset.getSource());
var texture = textureManager.loadTexture(source, asset.getRows() * asset.getLayout().getRows() * 2, asset.getColumns() * asset.getLayout().getColumns() * 2); var texture = textureManager.loadTexture(source, asset.getRows() * asset.getLayout().getRows() * 2, asset.getColumns() * asset.getLayout().getColumns() * 2);
autoTile = new AutoTileSet(texture, mesh, asset.getRows(), asset.getColumns(), asset.getLayout()); autoTile = new AutoTileSet(texture, asset.getRows(), asset.getColumns(), asset.getLayout());
log.info("Loading auto tile set from assets to cache under the key: [{}]", uid); log.info("Loading auto tile set from assets to cache under the key: [{}]", uid);
autoTiles.put(uid, autoTile); autoTiles.put(uid, autoTile);
} }

View File

@@ -1,7 +1,6 @@
package com.bartlomiejpluta.base.engine.world.autotile.model; package com.bartlomiejpluta.base.engine.world.autotile.model;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@@ -14,16 +13,16 @@ public class AutoSubTile extends Sprite {
private final Vector2fc tileSpriteSize; private final Vector2fc tileSpriteSize;
private final Vector2f tileScale = new Vector2f(1, 1); private final Vector2f tileScale = new Vector2f(1, 1);
public AutoSubTile(Mesh mesh, AutoTileSet autoTileSet) { public AutoSubTile(AutoTileSet autoTileSet) {
super(mesh, Material.textured(autoTileSet.getTexture())); super(Material.textured(autoTileSet.getTexture()));
tileSpriteSize = material.getTexture().getSpriteSize(); tileSpriteSize = getMaterial().getTexture().getSpriteSize();
super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y); super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y);
} }
public void recalculate(@NonNull Vector2ic spritePosition) { public void recalculate(@NonNull Vector2ic spritePosition) {
material.setSpritePosition(spritePosition.y(), spritePosition.x()); setFrame(spritePosition.x(), spritePosition.y());
} }
@Override @Override

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.autotile.model;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.Renderable;
import com.bartlomiejpluta.base.internal.render.ShaderManager; import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.Getter; import lombok.Getter;
@@ -18,11 +17,11 @@ public class AutoTile implements Renderable {
@Getter @Getter
private int setId; private int setId;
public AutoTile(@NonNull Mesh mesh, @NonNull AutoTileSet autoTileSet, int setId) { public AutoTile(@NonNull AutoTileSet autoTileSet, int setId) {
this.topLeftSubTile = new AutoSubTile(mesh, autoTileSet); this.topLeftSubTile = new AutoSubTile(autoTileSet);
this.topRightSubTile = new AutoSubTile(mesh, autoTileSet); this.topRightSubTile = new AutoSubTile(autoTileSet);
this.bottomLeftSubTile = new AutoSubTile(mesh, autoTileSet); this.bottomLeftSubTile = new AutoSubTile(autoTileSet);
this.bottomRightSubTile = new AutoSubTile(mesh, autoTileSet); this.bottomRightSubTile = new AutoSubTile(autoTileSet);
this.autoTileSet = autoTileSet; this.autoTileSet = autoTileSet;
this.setId = setId; this.setId = setId;
} }

View File

@@ -1,6 +1,5 @@
package com.bartlomiejpluta.base.engine.world.autotile.model; package com.bartlomiejpluta.base.engine.world.autotile.model;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@@ -45,7 +44,6 @@ public class AutoTileSet {
@Getter @Getter
private final Texture texture; private final Texture texture;
private final Mesh mesh;
@Getter @Getter
private final Vector2fc tileSize; private final Vector2fc tileSize;
@@ -58,9 +56,8 @@ public class AutoTileSet {
@Getter @Getter
private final int setsCount; private final int setsCount;
public AutoTileSet(@NonNull Texture texture, @NonNull Mesh mesh, int rows, int columns, @NonNull AutoTileLayout layout) { public AutoTileSet(@NonNull Texture texture, int rows, int columns, @NonNull AutoTileLayout layout) {
this.texture = texture; this.texture = texture;
this.mesh = mesh;
this.rows = rows; this.rows = rows;
this.columns = columns; this.columns = columns;
this.tileSize = texture.getSpriteSize(); this.tileSize = texture.getSpriteSize();
@@ -202,6 +199,6 @@ public class AutoTileSet {
} }
public AutoTile createTile(int setId) { public AutoTile createTile(int setId) {
return new AutoTile(mesh, this, setId); return new AutoTile(this, setId);
} }
} }

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.character.manager;
import com.bartlomiejpluta.base.api.character.Character; import com.bartlomiejpluta.base.api.character.Character;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.util.mesh.MeshManager; import com.bartlomiejpluta.base.engine.util.mesh.MeshManager;
import com.bartlomiejpluta.base.engine.world.character.config.CharacterSpriteConfiguration; import com.bartlomiejpluta.base.engine.world.character.config.CharacterSpriteConfiguration;
import com.bartlomiejpluta.base.engine.world.character.model.DefaultCharacter; import com.bartlomiejpluta.base.engine.world.character.model.DefaultCharacter;
@@ -27,8 +26,6 @@ public class DefaultCharacterManager implements CharacterManager {
private final Map<Direction, Integer> spriteDirectionRows; private final Map<Direction, Integer> spriteDirectionRows;
private final Map<Direction, Vector2fc> spriteDefaultRows; private final Map<Direction, Vector2fc> spriteDefaultRows;
private Mesh mesh;
@Autowired @Autowired
public DefaultCharacterManager(MeshManager meshManager, CharacterSetManager characterSetManager, CharacterSpriteConfiguration configuration) { public DefaultCharacterManager(MeshManager meshManager, CharacterSetManager characterSetManager, CharacterSpriteConfiguration configuration) {
this.meshManager = meshManager; this.meshManager = meshManager;
@@ -45,12 +42,12 @@ public class DefaultCharacterManager implements CharacterManager {
@Override @Override
public void init() { public void init() {
mesh = meshManager.createQuad(1, 1, 0.5f, 1); // TODO mesh = meshManager.createQuad(1, 1, 0.5f, 1);
} }
@Override @Override
public Character createCharacter(String characterSetUid) { public Character createCharacter(String characterSetUid) {
return new DefaultCharacter(mesh, characterSetManager, defaultSpriteColumn, spriteDirectionRows, spriteDefaultRows, characterSetUid); return new DefaultCharacter(characterSetManager, defaultSpriteColumn, spriteDirectionRows, spriteDefaultRows, characterSetUid);
} }
@Override @Override

View File

@@ -8,7 +8,6 @@ import com.bartlomiejpluta.base.api.move.CharacterMovement;
import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Direction;
import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.world.character.manager.CharacterSetManager; import com.bartlomiejpluta.base.engine.world.character.manager.CharacterSetManager;
import com.bartlomiejpluta.base.engine.world.movement.MovableSprite; import com.bartlomiejpluta.base.engine.world.movement.MovableSprite;
@@ -29,6 +28,15 @@ import static java.util.Objects.requireNonNull;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class DefaultCharacter extends MovableSprite implements Character { public class DefaultCharacter extends MovableSprite implements Character {
private static final Map<Direction, int[]> CHARSET_FRAMES = Map.of(
Direction.DOWN, new int[]{0, 1, 2, 3},
Direction.LEFT, new int[]{4, 5, 6, 7},
Direction.RIGHT, new int[]{8, 9, 10, 11},
Direction.UP, new int[]{12, 13, 14, 15}
);
private static final int DEFAULT_CHARSET_FRAME_COLUMN = 0;
private final int defaultSpriteColumn; private final int defaultSpriteColumn;
private final CharacterSetManager characterSetManager; private final CharacterSetManager characterSetManager;
private final Map<Direction, Integer> spriteDirectionRows; private final Map<Direction, Integer> spriteDirectionRows;
@@ -56,19 +64,21 @@ public class DefaultCharacter extends MovableSprite implements Character {
private final Queue<CharacterInstantAnimation> instantAnimations = new LinkedList<>(); private final Queue<CharacterInstantAnimation> instantAnimations = new LinkedList<>();
public DefaultCharacter(Mesh mesh, CharacterSetManager characterSetManager, int defaultSpriteColumn, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows, String characterSetUid) { public DefaultCharacter(CharacterSetManager characterSetManager, int defaultSpriteColumn, Map<Direction, Integer> spriteDirectionRows, Map<Direction, Vector2fc> spriteDefaultRows, String characterSetUid) {
super(mesh, createMaterial(characterSetManager, characterSetUid)); super(createMaterial(characterSetManager, characterSetUid));
this.defaultSpriteColumn = defaultSpriteColumn; this.defaultSpriteColumn = defaultSpriteColumn;
this.characterSetManager = characterSetManager; this.characterSetManager = characterSetManager;
this.spriteDirectionRows = spriteDirectionRows; this.spriteDirectionRows = spriteDirectionRows;
this.faceDirection = Direction.DOWN; this.faceDirection = Direction.DOWN;
this.spriteDefaultRows = spriteDefaultRows; this.spriteDefaultRows = spriteDefaultRows;
var texture = material.getTexture(); var texture = getMaterial().getTexture();
if (texture != null) { if (texture != null) {
this.characterSetSize = texture.getSpriteSize(); this.characterSetSize = texture.getSpriteSize();
super.setScale(characterSetSize.x() * characterScale.x, characterSetSize.y() * characterScale.y); super.setScale(characterSetSize.x() * characterScale.x, characterSetSize.y() * characterScale.y);
} }
setDefaultAnimationFrame();
} }
private static Material createMaterial(CharacterSetManager characterSetManager, String characterSetUid) { private static Material createMaterial(CharacterSetManager characterSetManager, String characterSetUid) {
@@ -102,13 +112,13 @@ public class DefaultCharacter extends MovableSprite implements Character {
@Override @Override
protected boolean shouldAnimate() { protected boolean shouldAnimate() {
return animationEnabled && material.getTexture() != null && (isMoving() || !instantAnimations.isEmpty()); return animationEnabled && getMaterial().getTexture() != null && (isMoving() || !instantAnimations.isEmpty());
} }
@Override @Override
protected Vector2fc[] getSpriteAnimationFramesPositions() { protected Vector2fc[] getSpriteAnimationFramesPositions() {
var row = spriteDirectionRows.get(faceDirection); var row = spriteDirectionRows.get(faceDirection);
var frames = material.getTexture().getColumns(); var frames = getMaterial().getTexture().getColumns();
var array = new Vector2f[frames]; var array = new Vector2f[frames];
for (int column = 0; column < frames; ++column) { for (int column = 0; column < frames; ++column) {
@@ -118,15 +128,21 @@ public class DefaultCharacter extends MovableSprite implements Character {
return array; return array;
} }
@Override
protected int[] getAvailableFrames() {
return CHARSET_FRAMES.get(faceDirection);
}
@Override @Override
protected void setDefaultAnimationFrame() { protected void setDefaultAnimationFrame() {
material.setSpritePosition(spriteDefaultRows.get(faceDirection)); // getMaterial().setSpritePosition(spriteDefaultRows.get(faceDirection));
setAnimationFrame(CHARSET_FRAMES.get(faceDirection)[DEFAULT_CHARSET_FRAME_COLUMN]);
} }
@Override @Override
public void changeCharacterSet(String characterSetUid) { public void changeCharacterSet(String characterSetUid) {
this.material = createMaterial(characterSetManager, characterSetUid); setMaterial(createMaterial(characterSetManager, characterSetUid));
var texture = this.material.getTexture(); var texture = this.getMaterial().getTexture();
if (texture != null) { if (texture != null) {
this.characterSetSize = texture.getSpriteSize(); this.characterSetSize = texture.getSpriteSize();

View File

@@ -1,7 +1,6 @@
package com.bartlomiejpluta.base.engine.world.icon.manager; package com.bartlomiejpluta.base.engine.world.icon.manager;
import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.icon.Icon;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.util.mesh.MeshManager; import com.bartlomiejpluta.base.engine.util.mesh.MeshManager;
import com.bartlomiejpluta.base.engine.world.icon.model.DefaultIcon; import com.bartlomiejpluta.base.engine.world.icon.model.DefaultIcon;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -15,16 +14,15 @@ import org.springframework.stereotype.Component;
public class DefaultIconManager implements IconManager { public class DefaultIconManager implements IconManager {
private final MeshManager meshManager; private final MeshManager meshManager;
private final IconSetManager iconSetManager; private final IconSetManager iconSetManager;
private Mesh mesh;
@Override @Override
public void init() { public void init() {
this.mesh = meshManager.createQuad(1, 1, 0.5f, 1); // TODO: this.mesh = meshManager.createQuad(1, 1, 0.5f, 1);
} }
@Override @Override
public Icon createIcon(String iconSetUid, int row, int column) { public Icon createIcon(String iconSetUid, int row, int column) {
return new DefaultIcon(mesh, iconSetManager, iconSetUid, row, column); return new DefaultIcon(iconSetManager, iconSetUid, row, column);
} }
@Override @Override

View File

@@ -4,7 +4,6 @@ import com.bartlomiejpluta.base.api.event.Event;
import com.bartlomiejpluta.base.api.event.EventType; import com.bartlomiejpluta.base.api.event.EventType;
import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.icon.Icon;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager; import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
@@ -42,12 +41,12 @@ public class DefaultIcon extends Sprite implements Icon {
@Getter @Getter
private int zIndex; private int zIndex;
public DefaultIcon(Mesh mesh, IconSetManager iconSetManager, String iconSetUid, int row, int column) { public DefaultIcon(IconSetManager iconSetManager, String iconSetUid, int row, int column) {
super(mesh, iconSetManager.loadObject(iconSetUid)); super(iconSetManager.loadObject(iconSetUid));
this.iconSetManager = iconSetManager; this.iconSetManager = iconSetManager;
material.setSpritePosition(column, row); getMaterial().setSpritePosition(column, row);
var texture = material.getTexture(); var texture = getMaterial().getTexture();
if (texture != null) { if (texture != null) {
this.iconSetSize = texture.getSpriteSize(); this.iconSetSize = texture.getSpriteSize();
super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y); super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y);
@@ -70,21 +69,21 @@ public class DefaultIcon extends Sprite implements Icon {
@Override @Override
public void changeIcon(int row, int column) { public void changeIcon(int row, int column) {
material.setSpritePosition(column, row); getMaterial().setSpritePosition(column, row);
this.iconSetRow = row; this.iconSetRow = row;
this.iconSetColumn = column; this.iconSetColumn = column;
} }
@Override @Override
public void changeIcon(String iconSetUid, int row, int column) { public void changeIcon(String iconSetUid, int row, int column) {
this.material = iconSetManager.loadObject(iconSetUid); setMaterial(iconSetManager.loadObject(iconSetUid));
material.setSpritePosition(column, row); getMaterial().setSpritePosition(column, row);
this.iconSetUid = iconSetUid; this.iconSetUid = iconSetUid;
this.iconSetRow = row; this.iconSetRow = row;
this.iconSetColumn = column; this.iconSetColumn = column;
var texture = material.getTexture(); var texture = getMaterial().getTexture();
if (texture != null) { if (texture != null) {
this.iconSetSize = texture.getSpriteSize(); this.iconSetSize = texture.getSpriteSize();
super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y); super.setScale(iconSetSize.x() * iconScale.x, iconSetSize.y() * iconScale.y);

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.image.manager;
import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.image.Image;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
@@ -30,11 +29,10 @@ public class DefaultImageManager implements ImageManager {
private final Map<String, ImageAsset> assets = new HashMap<>(); private final Map<String, ImageAsset> assets = new HashMap<>();
private final Map<String, ByteBuffer> imageBuffers = new HashMap<>(); private final Map<String, ByteBuffer> imageBuffers = new HashMap<>();
private final ProjectConfiguration configuration; private final ProjectConfiguration configuration;
private Mesh mesh;
@Override @Override
public void init() { public void init() {
mesh = meshManager.createQuad(1, 1, 0, 0); // TODO mesh = meshManager.createQuad(1, 1, 0, 0);
} }
@Override @Override
@@ -66,7 +64,7 @@ public class DefaultImageManager implements ImageManager {
var material = Material.textured(texture); var material = Material.textured(texture);
log.info("Creating new image on asset with UID: [{}]", uid); log.info("Creating new image on asset with UID: [{}]", uid);
return new DefaultImage(mesh, material, initialWidth, initialHeight, gcd); return new DefaultImage(material, initialWidth, initialHeight, gcd);
} }
@Override @Override

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.image.model;
import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.image.Image;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@@ -17,8 +16,8 @@ public class DefaultImage extends Sprite implements Image {
private final int width; private final int width;
private final int height; private final int height;
public DefaultImage(@NonNull Mesh mesh, @NonNull Material texture, int primaryWidth, int primaryHeight, int factor) { public DefaultImage(@NonNull Material texture, int primaryWidth, int primaryHeight, int factor) {
super(mesh, texture); super(texture);
this.primaryWidth = primaryWidth; this.primaryWidth = primaryWidth;
this.primaryHeight = primaryHeight; this.primaryHeight = primaryHeight;
this.factor = factor; this.factor = factor;
@@ -31,12 +30,12 @@ public class DefaultImage extends Sprite implements Image {
@Override @Override
public void setOpacity(float opacity) { public void setOpacity(float opacity) {
material.setAlpha(opacity); getMaterial().setAlpha(opacity);
} }
@Override @Override
public float getOpacity() { public float getOpacity() {
return material.getColor().w(); return getMaterial().getColor().w();
} }
@Override @Override

View File

@@ -9,7 +9,6 @@ import com.bartlomiejpluta.base.engine.world.location.LocationableModel;
import com.bartlomiejpluta.base.internal.render.ShaderManager; import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.joml.Vector2f;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector3fc; import org.joml.Vector3fc;

View File

@@ -144,7 +144,8 @@ public class DefaultColorLayer extends BaseLayer implements ColorLayer {
private static class Color extends Sprite { private static class Color extends Sprite {
public Color(@NonNull MeshManager meshManager, float red, float green, float blue, float alpha) { public Color(@NonNull MeshManager meshManager, float red, float green, float blue, float alpha) {
super(meshManager.createQuad(1, 1, 0, 0), Material.colored(red, green, blue, alpha)); // TODO (Custom Mesh): super(meshManager.createQuad(1, 1, 0, 0), Material.colored(red, green, blue, alpha));
super(Material.colored(red, green, blue, alpha));
} }
} }
} }

View File

@@ -2,8 +2,8 @@ package com.bartlomiejpluta.base.engine.world.map.layer.tile;
import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.BatchedQuads; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Quad; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.QuadTemplate;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture;
import com.bartlomiejpluta.base.engine.core.gl.shader.constant.Shader; import com.bartlomiejpluta.base.engine.core.gl.shader.constant.Shader;
import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName;
@@ -16,9 +16,9 @@ import com.bartlomiejpluta.base.internal.render.ShaderManager;
public class TileChunk extends Model implements Placeable, Renderable, Disposable, BoundingBox { public class TileChunk extends Model implements Placeable, Renderable, Disposable, BoundingBox {
private final Texture tileSet; private final Texture tileSet;
private final BatchedQuads mesh; private final Mesh mesh;
private final int chunkSize; private final int chunkSize;
private final Quad quad; private final QuadTemplate template;
private final float originX; private final float originX;
private final float originY; private final float originY;
@@ -29,14 +29,14 @@ public class TileChunk extends Model implements Placeable, Renderable, Disposabl
public TileChunk(Texture tileSet, int chunkSize, float originX, float originY) { public TileChunk(Texture tileSet, int chunkSize, float originX, float originY) {
this.tileSet = tileSet; this.tileSet = tileSet;
this.chunkSize = chunkSize; this.chunkSize = chunkSize;
this.mesh = new BatchedQuads(chunkSize * chunkSize); this.mesh = new Mesh(chunkSize * chunkSize);
this.quad = new Quad(tileSet.getSpriteSize().x(), tileSet.getSpriteSize().y(), originX, originY); this.template = new QuadTemplate(tileSet.getSpriteSize().x(), tileSet.getSpriteSize().y(), originX, originY);
this.originX = originX; this.originX = originX;
this.originY = originY; this.originY = originY;
} }
public int addTile(int x, int y, int tileId) { public int addTile(int x, int y, int tileId) {
return mesh.addQuad(quad, x, y, tileSet.getTextureCoordinates(tileId)); return mesh.addQuad(template, x, y, tileSet.getTextureCoordinates(tileId));
} }
public void removeTile(int quadId) { public void removeTile(int quadId) {

View File

@@ -2,7 +2,6 @@ package com.bartlomiejpluta.base.engine.world.map.manager;
import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.context.Context;
import com.bartlomiejpluta.base.api.map.handler.MapHandler; import com.bartlomiejpluta.base.api.map.handler.MapHandler;
import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader; import com.bartlomiejpluta.base.engine.util.reflection.ClassLoader;

View File

@@ -4,7 +4,6 @@ import com.bartlomiejpluta.base.api.move.Movable;
import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.move.Movement;
import com.bartlomiejpluta.base.engine.core.engine.DefaultGameEngine; import com.bartlomiejpluta.base.engine.core.engine.DefaultGameEngine;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.world.animation.model.AnimatedSprite; import com.bartlomiejpluta.base.engine.world.animation.model.AnimatedSprite;
import com.bartlomiejpluta.base.internal.program.Updatable; import com.bartlomiejpluta.base.internal.program.Updatable;
import com.bartlomiejpluta.base.util.math.MathUtil; import com.bartlomiejpluta.base.util.math.MathUtil;
@@ -12,9 +11,6 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.joml.Vector2f; import org.joml.Vector2f;
import static java.lang.Math.abs;
import static java.lang.Math.max;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public abstract class MovableSprite extends AnimatedSprite implements Movable, Updatable { public abstract class MovableSprite extends AnimatedSprite implements Movable, Updatable {
private int moveTime = 0; private int moveTime = 0;
@@ -24,8 +20,8 @@ public abstract class MovableSprite extends AnimatedSprite implements Movable, U
@Getter @Getter
private Movement movement; private Movement movement;
public MovableSprite(Mesh mesh, Material material) { public MovableSprite(Material material) {
super(mesh, material); super(material);
} }
@Override @Override

View File

@@ -4,43 +4,103 @@ import com.bartlomiejpluta.base.api.camera.Camera;
import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.api.screen.Screen;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.QuadMesh;
import com.bartlomiejpluta.base.engine.core.gl.shader.constant.Shader;
import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName;
import com.bartlomiejpluta.base.engine.world.location.LocationableModel; import com.bartlomiejpluta.base.engine.world.location.LocationableModel;
import com.bartlomiejpluta.base.internal.render.BoundingBox;
import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.Renderable;
import com.bartlomiejpluta.base.internal.render.ShaderManager; import com.bartlomiejpluta.base.internal.render.ShaderManager;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.Setter;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public abstract class Sprite extends LocationableModel implements Renderable { public abstract class Sprite extends LocationableModel implements Renderable, BoundingBox {
private final float farthestVertexDistance;
protected final Mesh mesh;
@NonNull @NonNull
@Setter
@Getter @Getter
protected Material material; private Material material;
public Sprite(Mesh mesh, Material material) { private final QuadMesh quad;
this.mesh = mesh; private final float width = 1f;
private final float height = 1f;
private final float originX = .5f;
private final float originY = 1f;
@Getter
private float[][] textureCoordinates;
public Sprite(Material material) {
this.material = material; this.material = material;
this.quad = Mesh.quad(width, height, originX, originY);
this.farthestVertexDistance = this.mesh.getFarthestVertex().lengthSquared(); updateTextureCoordinates();
}
private void updateTextureCoordinates() {
var texture = material.getTexture();
if (texture == null) {
return;
}
textureCoordinates = texture.getTextureCoordinatesForAllFrames();
}
public void setMaterial(@NonNull Material material) {
this.material = material;
updateTextureCoordinates();
}
public void setFrame(int row, int column) {
setFrame(row * material.getTexture().getColumns() + column);
}
public void setFrame(int id) {
quad.setTextureCoordinates(textureCoordinates[id]);
}
@Override
public float getMinX() {
float scaledOriginX = originX * scaleX;
return getPosition().x() - scaledOriginX;
}
@Override
public float getMaxX() {
float scaledOriginX = originX * scaleX;
float scaledChunkWidth = width * scaleX;
return getPosition().x() + scaledChunkWidth - scaledOriginX;
}
@Override
public float getMinY() {
float scaledOriginY = originY * scaleY;
return getPosition().y() - scaledOriginY;
}
@Override
public float getMaxY() {
float scaledOriginY = originY * scaleY;
float scaledChunkHeight = height * scaleY;
return getPosition().y() + scaledChunkHeight - scaledOriginY;
} }
@Override @Override
public void render(Screen screen, Camera camera, ShaderManager shaderManager) { public void render(Screen screen, Camera camera, ShaderManager shaderManager) {
if (!camera.insideFrustum(position.x, position.y, farthestVertexDistance * (scaleX > scaleY ? scaleX : scaleY))) { if (!camera.containsBox(this)) {
return; return;
} }
material.getTexture().activate();
shaderManager.activateShader(Shader.BATCH.name);
shaderManager.setUniform(UniformName.UNI_PROJECTION_MATRIX, camera.getProjectionMatrix()); shaderManager.setUniform(UniformName.UNI_PROJECTION_MATRIX, camera.getProjectionMatrix());
shaderManager.setUniform(UniformName.UNI_VIEW_MODEL_MATRIX, camera.computeViewModelMatrix(getModelMatrix())); shaderManager.setUniform(UniformName.UNI_VIEW_MODEL_MATRIX, camera.computeViewModelMatrix(getModelMatrix()));
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, getModelMatrix()); shaderManager.setUniform(UniformName.UNI_TEXTURE_SAMPLER, 0);
material.render(screen, camera, shaderManager);
mesh.render(screen, camera, shaderManager); quad.render(screen, camera, shaderManager);
shaderManager.deactivateShader();
} }
} }

View File

@@ -1,6 +1,5 @@
package com.bartlomiejpluta.base.engine.world.tileset.manager; package com.bartlomiejpluta.base.engine.world.tileset.manager;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager;
import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.engine.error.AppException;
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
@@ -24,11 +23,10 @@ public class DefaultTileSetManager implements TileSetManager {
private final Map<String, TileSet> tileSets = new HashMap<>(); private final Map<String, TileSet> tileSets = new HashMap<>();
private final Map<String, TileSetAsset> assets = new HashMap<>(); private final Map<String, TileSetAsset> assets = new HashMap<>();
private final ProjectConfiguration configuration; private final ProjectConfiguration configuration;
private Mesh mesh;
@Override @Override
public void init() { public void init() {
this.mesh = meshManager.createQuad(1, 1, 0, 0); // TODO this.mesh = meshManager.createQuad(1, 1, 0, 0);
} }
@Override @Override
@@ -55,7 +53,7 @@ public class DefaultTileSetManager implements TileSetManager {
var source = configuration.projectFile("tilesets", asset.getSource()); var source = configuration.projectFile("tilesets", asset.getSource());
var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns()); var texture = textureManager.loadTexture(source, asset.getRows(), asset.getColumns());
tileset = new TileSet(texture, mesh); tileset = new TileSet(texture);
log.info("Loading tile set from assets to cache under the key: [{}]", uid); log.info("Loading tile set from assets to cache under the key: [{}]", uid);
tileSets.put(uid, tileset); tileSets.put(uid, tileset);
} }

View File

@@ -1,7 +1,6 @@
package com.bartlomiejpluta.base.engine.world.tileset.model; package com.bartlomiejpluta.base.engine.world.tileset.model;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture;
import com.bartlomiejpluta.base.engine.world.object.Sprite; import com.bartlomiejpluta.base.engine.world.object.Sprite;
import lombok.Getter; import lombok.Getter;
@@ -17,28 +16,28 @@ public class Tile extends Sprite {
private final Vector2fc tileSpriteSize; private final Vector2fc tileSpriteSize;
public Tile setLocation(int row, int column) { public Tile setLocation(int row, int column) {
var stepSize = material.getTexture().getSpriteSize(); var stepSize = getMaterial().getTexture().getSpriteSize();
setPosition(column * stepSize.x(), row * stepSize.y()); setPosition(column * stepSize.x(), row * stepSize.y());
return this; return this;
} }
public Tile(Mesh mesh, Texture tileSet, int id) { public Tile(Texture tileSet, int id) {
super(mesh, Material.textured(tileSet)); super(Material.textured(tileSet));
this.id = id; this.id = id;
this.tileSetRow = id / tileSet.getColumns(); this.tileSetRow = id / tileSet.getColumns();
this.tileSetColumn = id % tileSet.getColumns(); this.tileSetColumn = id % tileSet.getColumns();
material.setSpritePosition(tileSetColumn, tileSetRow); getMaterial().setSpritePosition(tileSetColumn, tileSetRow);
tileSpriteSize = tileSet.getSpriteSize(); tileSpriteSize = tileSet.getSpriteSize();
super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y); super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y);
} }
public Tile(Mesh mesh, Texture tileSet, int row, int column) { public Tile(Texture tileSet, int row, int column) {
super(mesh, Material.textured(tileSet)); super(Material.textured(tileSet));
this.tileSetRow = row; this.tileSetRow = row;
this.tileSetColumn = column; this.tileSetColumn = column;
this.id = row * tileSet.getColumns() + column; this.id = row * tileSet.getColumns() + column;
material.setSpritePosition(tileSetColumn, tileSetRow); getMaterial().setSpritePosition(tileSetColumn, tileSetRow);
tileSpriteSize = tileSet.getSpriteSize(); tileSpriteSize = tileSet.getSpriteSize();
super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y); super.setScale(tileSpriteSize.x() * tileScale.x, tileSpriteSize.y() * tileScale.y);

View File

@@ -1,29 +1,25 @@
package com.bartlomiejpluta.base.engine.world.tileset.model; package com.bartlomiejpluta.base.engine.world.tileset.model;
import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.material.Material;
import com.bartlomiejpluta.base.engine.core.gl.object.mesh.Mesh;
import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Getter @Getter
public class TileSet { public class TileSet {
private final Texture tileSet; private final Texture tileSet;
private final Mesh mesh;
private final Material material; private final Material material;
public TileSet(@NonNull Texture tileSet, @NonNull Mesh mesh) { public TileSet(@NonNull Texture tileSet) {
this.tileSet = tileSet; this.tileSet = tileSet;
this.mesh = mesh;
this.material = Material.textured(tileSet); this.material = Material.textured(tileSet);
} }
public Tile tileById(int id) { public Tile tileById(int id) {
return new Tile(mesh, tileSet, id); return new Tile(tileSet, id);
} }
public Tile tileAt(int row, int column) { public Tile tileAt(int row, int column) {
return new Tile(mesh, tileSet, row, column); return new Tile(tileSet, row, column);
} }
} }