Migrate CRLF file endings to LF
This commit is contained in:
0
engine/build.gradle
Executable file → Normal file
0
engine/build.gradle
Executable file → Normal file
222
engine/src/main/java/com/bartlomiejpluta/base/core/engine/DefaultGameEngine.java
Executable file → Normal file
222
engine/src/main/java/com/bartlomiejpluta/base/core/engine/DefaultGameEngine.java
Executable file → Normal file
@@ -1,111 +1,111 @@
|
||||
package com.bartlomiejpluta.base.core.engine;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.OffHeapGarbageCollector;
|
||||
import com.bartlomiejpluta.base.core.logic.GameLogic;
|
||||
import com.bartlomiejpluta.base.core.thread.ThreadManager;
|
||||
import com.bartlomiejpluta.base.core.time.ChronoMeter;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.ui.WindowManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DefaultGameEngine implements GameEngine {
|
||||
private static final String THREAD_NAME = "Game Main Thread";
|
||||
|
||||
private final WindowManager windowManager;
|
||||
private final ThreadManager threadManager;
|
||||
private final GameLogic logic;
|
||||
private final OffHeapGarbageCollector garbageCollector;
|
||||
|
||||
private final Thread thread;
|
||||
private final Window window;
|
||||
private final ChronoMeter chrono;
|
||||
private final int targetUps;
|
||||
|
||||
private boolean running = false;
|
||||
|
||||
@Autowired
|
||||
public DefaultGameEngine(WindowManager windowManager,
|
||||
ThreadManager threadManager,
|
||||
GameLogic logic,
|
||||
OffHeapGarbageCollector garbageCollector,
|
||||
@Value("${app.window.title}") String title,
|
||||
@Value("${app.window.width}") int width,
|
||||
@Value("${app.window.height}") int height,
|
||||
@Value("${app.core.targetUps}") int targetUps) {
|
||||
this.windowManager = windowManager;
|
||||
this.threadManager = threadManager;
|
||||
this.logic = logic;
|
||||
this.garbageCollector = garbageCollector;
|
||||
|
||||
this.window = windowManager.createWindow(title, width, height);
|
||||
this.thread = threadManager.createThread(THREAD_NAME, this::run);
|
||||
this.chrono = new ChronoMeter();
|
||||
this.targetUps = targetUps;
|
||||
}
|
||||
|
||||
private void run() {
|
||||
try {
|
||||
init();
|
||||
loop();
|
||||
} finally {
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
log.info("Initializing game engine");
|
||||
window.init();
|
||||
chrono.init();
|
||||
logic.init(window);
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
log.info("Starting game loop");
|
||||
running = true;
|
||||
var dt = 0.0f;
|
||||
var accumulator = 0.0f;
|
||||
var step = 1.0f / targetUps;
|
||||
|
||||
while (running && !window.shouldClose()) {
|
||||
dt = chrono.getElapsedTime();
|
||||
accumulator += dt;
|
||||
|
||||
input();
|
||||
|
||||
while (accumulator >= step) {
|
||||
update(dt);
|
||||
accumulator -= step;
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
private void input() {
|
||||
logic.input(window);
|
||||
}
|
||||
|
||||
private void update(float dt) {
|
||||
logic.update(dt);
|
||||
}
|
||||
|
||||
private void render() {
|
||||
window.update();
|
||||
logic.render(window);
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
log.info("Performing off heap garbage collection");
|
||||
garbageCollector.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.engine;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.OffHeapGarbageCollector;
|
||||
import com.bartlomiejpluta.base.core.logic.GameLogic;
|
||||
import com.bartlomiejpluta.base.core.thread.ThreadManager;
|
||||
import com.bartlomiejpluta.base.core.time.ChronoMeter;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.ui.WindowManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DefaultGameEngine implements GameEngine {
|
||||
private static final String THREAD_NAME = "Game Main Thread";
|
||||
|
||||
private final WindowManager windowManager;
|
||||
private final ThreadManager threadManager;
|
||||
private final GameLogic logic;
|
||||
private final OffHeapGarbageCollector garbageCollector;
|
||||
|
||||
private final Thread thread;
|
||||
private final Window window;
|
||||
private final ChronoMeter chrono;
|
||||
private final int targetUps;
|
||||
|
||||
private boolean running = false;
|
||||
|
||||
@Autowired
|
||||
public DefaultGameEngine(WindowManager windowManager,
|
||||
ThreadManager threadManager,
|
||||
GameLogic logic,
|
||||
OffHeapGarbageCollector garbageCollector,
|
||||
@Value("${app.window.title}") String title,
|
||||
@Value("${app.window.width}") int width,
|
||||
@Value("${app.window.height}") int height,
|
||||
@Value("${app.core.targetUps}") int targetUps) {
|
||||
this.windowManager = windowManager;
|
||||
this.threadManager = threadManager;
|
||||
this.logic = logic;
|
||||
this.garbageCollector = garbageCollector;
|
||||
|
||||
this.window = windowManager.createWindow(title, width, height);
|
||||
this.thread = threadManager.createThread(THREAD_NAME, this::run);
|
||||
this.chrono = new ChronoMeter();
|
||||
this.targetUps = targetUps;
|
||||
}
|
||||
|
||||
private void run() {
|
||||
try {
|
||||
init();
|
||||
loop();
|
||||
} finally {
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
log.info("Initializing game engine");
|
||||
window.init();
|
||||
chrono.init();
|
||||
logic.init(window);
|
||||
}
|
||||
|
||||
private void loop() {
|
||||
log.info("Starting game loop");
|
||||
running = true;
|
||||
var dt = 0.0f;
|
||||
var accumulator = 0.0f;
|
||||
var step = 1.0f / targetUps;
|
||||
|
||||
while (running && !window.shouldClose()) {
|
||||
dt = chrono.getElapsedTime();
|
||||
accumulator += dt;
|
||||
|
||||
input();
|
||||
|
||||
while (accumulator >= step) {
|
||||
update(dt);
|
||||
accumulator -= step;
|
||||
}
|
||||
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
private void input() {
|
||||
logic.input(window);
|
||||
}
|
||||
|
||||
private void update(float dt) {
|
||||
logic.update(dt);
|
||||
}
|
||||
|
||||
private void render() {
|
||||
window.update();
|
||||
logic.render(window);
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
log.info("Performing off heap garbage collection");
|
||||
garbageCollector.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/engine/GameEngine.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/engine/GameEngine.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.engine;
|
||||
|
||||
public interface GameEngine {
|
||||
void start();
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.engine;
|
||||
|
||||
public interface GameEngine {
|
||||
void start();
|
||||
}
|
||||
|
||||
44
engine/src/main/java/com/bartlomiejpluta/base/core/error/AppException.java
Executable file → Normal file
44
engine/src/main/java/com/bartlomiejpluta/base/core/error/AppException.java
Executable file → Normal file
@@ -1,22 +1,22 @@
|
||||
package com.bartlomiejpluta.base.core.error;
|
||||
|
||||
public class AppException extends RuntimeException {
|
||||
public AppException() {
|
||||
}
|
||||
|
||||
public AppException(String message, Object... args) {
|
||||
super(String.format(message, args));
|
||||
}
|
||||
|
||||
public AppException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public AppException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public AppException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.error;
|
||||
|
||||
public class AppException extends RuntimeException {
|
||||
public AppException() {
|
||||
}
|
||||
|
||||
public AppException(String message, Object... args) {
|
||||
super(String.format(message, args));
|
||||
}
|
||||
|
||||
public AppException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public AppException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public AppException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Cleanable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Cleanable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface Cleanable {
|
||||
void cleanUp();
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface Cleanable {
|
||||
void cleanUp();
|
||||
}
|
||||
|
||||
44
engine/src/main/java/com/bartlomiejpluta/base/core/gc/DefaultOffHeapGarbageCollector.java
Executable file → Normal file
44
engine/src/main/java/com/bartlomiejpluta/base/core/gc/DefaultOffHeapGarbageCollector.java
Executable file → Normal file
@@ -1,22 +1,22 @@
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultOffHeapGarbageCollector implements OffHeapGarbageCollector {
|
||||
private final List<Cleanable> cleanables;
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
cleanables.stream()
|
||||
.peek(cleanable -> log.info("Performing {} cleaning", cleanable.getClass().getSimpleName()))
|
||||
.forEach(Cleanable::cleanUp);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultOffHeapGarbageCollector implements OffHeapGarbageCollector {
|
||||
private final List<Cleanable> cleanables;
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
cleanables.stream()
|
||||
.peek(cleanable -> log.info("Performing {} cleaning", cleanable.getClass().getSimpleName()))
|
||||
.forEach(Cleanable::cleanUp);
|
||||
}
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Disposable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/Disposable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface Disposable {
|
||||
void dispose();
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface Disposable {
|
||||
void dispose();
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/OffHeapGarbageCollector.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/gc/OffHeapGarbageCollector.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface OffHeapGarbageCollector {
|
||||
void cleanUp();
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gc;
|
||||
|
||||
public interface OffHeapGarbageCollector {
|
||||
void cleanUp();
|
||||
}
|
||||
|
||||
166
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/material/Material.java
Executable file → Normal file
166
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/material/Material.java
Executable file → Normal file
@@ -1,83 +1,83 @@
|
||||
package com.bartlomiejpluta.base.core.gl.object.material;
|
||||
|
||||
import com.bartlomiejpluta.base.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) {
|
||||
this.texture = texture;
|
||||
setColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
this.color.w = alpha;
|
||||
}
|
||||
|
||||
public void setColor(Vector4f color) {
|
||||
this.color.x = color.x;
|
||||
this.color.y = color.y;
|
||||
this.color.z = color.z;
|
||||
this.color.w = color.w;
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float alpha) {
|
||||
color.x = r;
|
||||
color.y = g;
|
||||
color.z = b;
|
||||
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;
|
||||
}
|
||||
|
||||
public void activateTextureIfExists() {
|
||||
if(hasTexture()) {
|
||||
texture.activate();
|
||||
}
|
||||
}
|
||||
|
||||
public static Material colored(float r, float g, float b, float alpha) {
|
||||
return new Material(null, r, g, b, alpha);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture) {
|
||||
return new Material(texture, 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture, float r, float g, float b, float alpha) {
|
||||
return new Material(texture, r, g, b, alpha);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture, float alpha) {
|
||||
return new Material(texture, 1, 1, 1, alpha);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.object.material;
|
||||
|
||||
import com.bartlomiejpluta.base.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) {
|
||||
this.texture = texture;
|
||||
setColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
this.color.w = alpha;
|
||||
}
|
||||
|
||||
public void setColor(Vector4f color) {
|
||||
this.color.x = color.x;
|
||||
this.color.y = color.y;
|
||||
this.color.z = color.z;
|
||||
this.color.w = color.w;
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float alpha) {
|
||||
color.x = r;
|
||||
color.y = g;
|
||||
color.z = b;
|
||||
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;
|
||||
}
|
||||
|
||||
public void activateTextureIfExists() {
|
||||
if(hasTexture()) {
|
||||
texture.activate();
|
||||
}
|
||||
}
|
||||
|
||||
public static Material colored(float r, float g, float b, float alpha) {
|
||||
return new Material(null, r, g, b, alpha);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture) {
|
||||
return new Material(texture, 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture, float r, float g, float b, float alpha) {
|
||||
return new Material(texture, r, g, b, alpha);
|
||||
}
|
||||
|
||||
public static Material textured(Texture texture, float alpha) {
|
||||
return new Material(texture, 1, 1, 1, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
188
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/mesh/Mesh.java
Executable file → Normal file
188
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/mesh/Mesh.java
Executable file → Normal file
@@ -1,94 +1,94 @@
|
||||
package com.bartlomiejpluta.base.core.gl.object.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
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 Mesh implements Renderable, Disposable {
|
||||
private final int vaoId;
|
||||
private final List<Integer> vboIds = new ArrayList<>(2);
|
||||
private final int elementsCount;
|
||||
|
||||
public Mesh(float[] vertices, float[] texCoords, int[] elements) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
elementsCount = elements.length;
|
||||
var verticesBuffer = stack.mallocFloat(vertices.length);
|
||||
var texCoordsBuffer = stack.mallocFloat(texCoords.length);
|
||||
var elementsBuffer = stack.mallocInt(elementsCount);
|
||||
verticesBuffer.put(vertices).flip();
|
||||
texCoordsBuffer.put(texCoords).flip();
|
||||
elementsBuffer.put(elements).flip();
|
||||
|
||||
vaoId = glGenVertexArrays();
|
||||
glBindVertexArray(vaoId);
|
||||
|
||||
int vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
|
||||
|
||||
vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ARRAY_BUFFER, texCoordsBuffer, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
|
||||
|
||||
vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
glBindVertexArray(vaoId);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_INT, 0);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glDisableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
vboIds.forEach(GL15::glDeleteBuffers);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(vaoId);
|
||||
}
|
||||
|
||||
public static Mesh quad(float width, float height, float originX, float originY) {
|
||||
var vertices = new float[] {
|
||||
-originX, -originY,
|
||||
-originX, height - originY,
|
||||
width - originX, height - originY,
|
||||
width - originX, - originY
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.object.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
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 Mesh implements Renderable, Disposable {
|
||||
private final int vaoId;
|
||||
private final List<Integer> vboIds = new ArrayList<>(2);
|
||||
private final int elementsCount;
|
||||
|
||||
public Mesh(float[] vertices, float[] texCoords, int[] elements) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
elementsCount = elements.length;
|
||||
var verticesBuffer = stack.mallocFloat(vertices.length);
|
||||
var texCoordsBuffer = stack.mallocFloat(texCoords.length);
|
||||
var elementsBuffer = stack.mallocInt(elementsCount);
|
||||
verticesBuffer.put(vertices).flip();
|
||||
texCoordsBuffer.put(texCoords).flip();
|
||||
elementsBuffer.put(elements).flip();
|
||||
|
||||
vaoId = glGenVertexArrays();
|
||||
glBindVertexArray(vaoId);
|
||||
|
||||
int vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ARRAY_BUFFER, verticesBuffer, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
|
||||
|
||||
vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ARRAY_BUFFER, texCoordsBuffer, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
|
||||
|
||||
vboId = glGenBuffers();
|
||||
vboIds.add(vboId);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
glBindVertexArray(vaoId);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_INT, 0);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glDisableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
vboIds.forEach(GL15::glDeleteBuffers);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glDeleteVertexArrays(vaoId);
|
||||
}
|
||||
|
||||
public static Mesh quad(float width, float height, float originX, float originY) {
|
||||
var vertices = new float[] {
|
||||
-originX, -originY,
|
||||
-originX, height - originY,
|
||||
width - originX, height - originY,
|
||||
width - originX, - originY
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
78
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/DefaultTextureManager.java
Executable file → Normal file
78
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/DefaultTextureManager.java
Executable file → Normal file
@@ -1,39 +1,39 @@
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultTextureManager implements TextureManager {
|
||||
private final ResourcesManager resourcesManager;
|
||||
private final Map<String, Texture> loadedTextures = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Texture loadTexture(String textureFileName) {
|
||||
var texture = loadedTextures.get(textureFileName);
|
||||
|
||||
if (texture == null) {
|
||||
log.info("Loading [{}] texture to cache", textureFileName);
|
||||
var buffer = resourcesManager.loadResourceAsByteBuffer(textureFileName);
|
||||
texture = new Texture(textureFileName, buffer);
|
||||
loadedTextures.put(textureFileName, texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing textures");
|
||||
loadedTextures.forEach((name, texture) -> texture.dispose());
|
||||
log.info("{} textures has been disposed", loadedTextures.size());
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultTextureManager implements TextureManager {
|
||||
private final ResourcesManager resourcesManager;
|
||||
private final Map<String, Texture> loadedTextures = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Texture loadTexture(String textureFileName) {
|
||||
var texture = loadedTextures.get(textureFileName);
|
||||
|
||||
if (texture == null) {
|
||||
log.info("Loading [{}] texture to cache", textureFileName);
|
||||
var buffer = resourcesManager.loadResourceAsByteBuffer(textureFileName);
|
||||
texture = new Texture(textureFileName, buffer);
|
||||
loadedTextures.put(textureFileName, texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing textures");
|
||||
loadedTextures.forEach((name, texture) -> texture.dispose());
|
||||
log.info("{} textures has been disposed", loadedTextures.size());
|
||||
}
|
||||
}
|
||||
|
||||
132
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/Texture.java
Executable file → Normal file
132
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/Texture.java
Executable file → Normal file
@@ -1,66 +1,66 @@
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import lombok.Getter;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
||||
import static org.lwjgl.opengl.GL13.glActiveTexture;
|
||||
import static org.lwjgl.stb.STBImage.stbi_failure_reason;
|
||||
import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
|
||||
|
||||
public class Texture implements Disposable {
|
||||
private static final int DESIRED_CHANNELS = 4;
|
||||
|
||||
private final int textureId;
|
||||
|
||||
@Getter
|
||||
private final String fileName;
|
||||
|
||||
@Getter
|
||||
private final int width;
|
||||
|
||||
@Getter
|
||||
private final int height;
|
||||
|
||||
Texture(String textureFilename, ByteBuffer buffer) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
var widthBuffer = stack.mallocInt(1);
|
||||
var heightBuffer = stack.mallocInt(1);
|
||||
var channelsBuffer = stack.mallocInt(1);
|
||||
|
||||
buffer = stbi_load_from_memory(buffer, widthBuffer, heightBuffer, channelsBuffer, DESIRED_CHANNELS);
|
||||
if (buffer == null) {
|
||||
throw new AppException("Image file [%s] could not be loaded: %s", textureFilename, stbi_failure_reason());
|
||||
}
|
||||
|
||||
width = widthBuffer.get();
|
||||
height = heightBuffer.get();
|
||||
|
||||
textureId = glGenTextures();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
fileName = textureFilename;
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glDeleteTextures(textureId);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import lombok.Getter;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
||||
import static org.lwjgl.opengl.GL13.glActiveTexture;
|
||||
import static org.lwjgl.stb.STBImage.stbi_failure_reason;
|
||||
import static org.lwjgl.stb.STBImage.stbi_load_from_memory;
|
||||
|
||||
public class Texture implements Disposable {
|
||||
private static final int DESIRED_CHANNELS = 4;
|
||||
|
||||
private final int textureId;
|
||||
|
||||
@Getter
|
||||
private final String fileName;
|
||||
|
||||
@Getter
|
||||
private final int width;
|
||||
|
||||
@Getter
|
||||
private final int height;
|
||||
|
||||
Texture(String textureFilename, ByteBuffer buffer) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
var widthBuffer = stack.mallocInt(1);
|
||||
var heightBuffer = stack.mallocInt(1);
|
||||
var channelsBuffer = stack.mallocInt(1);
|
||||
|
||||
buffer = stbi_load_from_memory(buffer, widthBuffer, heightBuffer, channelsBuffer, DESIRED_CHANNELS);
|
||||
if (buffer == null) {
|
||||
throw new AppException("Image file [%s] could not be loaded: %s", textureFilename, stbi_failure_reason());
|
||||
}
|
||||
|
||||
width = widthBuffer.get();
|
||||
height = heightBuffer.get();
|
||||
|
||||
textureId = glGenTextures();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
fileName = textureFilename;
|
||||
}
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glDeleteTextures(textureId);
|
||||
}
|
||||
}
|
||||
|
||||
14
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/TextureManager.java
Executable file → Normal file
14
engine/src/main/java/com/bartlomiejpluta/base/core/gl/object/texture/TextureManager.java
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
|
||||
public interface TextureManager extends Cleanable {
|
||||
Texture loadTexture(String textureFileName);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.object.texture;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
|
||||
public interface TextureManager extends Cleanable {
|
||||
Texture loadTexture(String textureFileName);
|
||||
}
|
||||
|
||||
124
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/DefaultRenderer.java
Executable file → Normal file
124
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/DefaultRenderer.java
Executable file → Normal file
@@ -1,62 +1,62 @@
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.lwjgl.opengl.GL15.*;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultRenderer implements Renderer {
|
||||
private final ShaderManager shaderManager;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
log.info("Initializing renderer");
|
||||
shaderManager
|
||||
.createShader("default", "/shaders/default.vs", "/shaders/default.fs")
|
||||
.selectShader("default")
|
||||
.createUniform(UniformName.UNI_MODEL_MATRIX)
|
||||
.createUniform(UniformName.UNI_VIEW_MATRIX)
|
||||
.createUniform(UniformName.UNI_PROJECTION_MATRIX)
|
||||
.createUniform(UniformName.UNI_OBJECT_COLOR)
|
||||
.createUniform(UniformName.UNI_HAS_OBJECT_TEXTURE)
|
||||
.createUniform(UniformName.UNI_TEXTURE_SAMPLER)
|
||||
.createUniform(UniformName.UNI_SPRITE_SIZE)
|
||||
.createUniform(UniformName.UNI_SPRITE_POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, Renderable renderable) {
|
||||
clear();
|
||||
updateViewport(window);
|
||||
|
||||
shaderManager.selectShader("default").useSelectedShader();
|
||||
|
||||
renderable.render(window, shaderManager);
|
||||
|
||||
shaderManager.detachCurrentShader();
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
private void updateViewport(Window window) {
|
||||
if (window.isResized()) {
|
||||
glViewport(0, 0, window.getWidth(), window.getHeight());
|
||||
window.setResized(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static org.lwjgl.opengl.GL15.*;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultRenderer implements Renderer {
|
||||
private final ShaderManager shaderManager;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
log.info("Initializing renderer");
|
||||
shaderManager
|
||||
.createShader("default", "/shaders/default.vs", "/shaders/default.fs")
|
||||
.selectShader("default")
|
||||
.createUniform(UniformName.UNI_MODEL_MATRIX)
|
||||
.createUniform(UniformName.UNI_VIEW_MATRIX)
|
||||
.createUniform(UniformName.UNI_PROJECTION_MATRIX)
|
||||
.createUniform(UniformName.UNI_OBJECT_COLOR)
|
||||
.createUniform(UniformName.UNI_HAS_OBJECT_TEXTURE)
|
||||
.createUniform(UniformName.UNI_TEXTURE_SAMPLER)
|
||||
.createUniform(UniformName.UNI_SPRITE_SIZE)
|
||||
.createUniform(UniformName.UNI_SPRITE_POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, Renderable renderable) {
|
||||
clear();
|
||||
updateViewport(window);
|
||||
|
||||
shaderManager.selectShader("default").useSelectedShader();
|
||||
|
||||
renderable.render(window, shaderManager);
|
||||
|
||||
shaderManager.detachCurrentShader();
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
private void updateViewport(Window window) {
|
||||
if (window.isResized()) {
|
||||
glViewport(0, 0, window.getWidth(), window.getHeight());
|
||||
window.setResized(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
|
||||
16
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderable.java
Executable file → Normal file
16
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderable.java
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface Renderable {
|
||||
void render(Window window, ShaderManager shaderManager);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface Renderable {
|
||||
void render(Window window, ShaderManager shaderManager);
|
||||
}
|
||||
|
||||
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderer.java
Executable file → Normal file
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/render/Renderer.java
Executable file → Normal file
@@ -1,9 +1,9 @@
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface Renderer extends Cleanable {
|
||||
void init();
|
||||
void render(Window window, Renderable renderable);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.render;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface Renderer extends Cleanable {
|
||||
void init();
|
||||
void render(Window window, Renderable renderable);
|
||||
}
|
||||
|
||||
24
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/constant/UniformName.java
Executable file → Normal file
24
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/constant/UniformName.java
Executable file → Normal file
@@ -1,12 +1,12 @@
|
||||
package com.bartlomiejpluta.base.core.gl.shader.constant;
|
||||
|
||||
public interface UniformName {
|
||||
String UNI_MODEL_MATRIX = "modelMatrix";
|
||||
String UNI_VIEW_MATRIX = "viewMatrix";
|
||||
String UNI_PROJECTION_MATRIX = "projectionMatrix";
|
||||
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";
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.shader.constant;
|
||||
|
||||
public interface UniformName {
|
||||
String UNI_MODEL_MATRIX = "modelMatrix";
|
||||
String UNI_VIEW_MATRIX = "viewMatrix";
|
||||
String UNI_PROJECTION_MATRIX = "projectionMatrix";
|
||||
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";
|
||||
}
|
||||
|
||||
298
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/DefaultShaderManager.java
Executable file → Normal file
298
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/DefaultShaderManager.java
Executable file → Normal file
@@ -1,149 +1,149 @@
|
||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultShaderManager implements ShaderManager {
|
||||
private final ResourcesManager resourcesManager;
|
||||
private final Map<String, ShaderProgram> shaders = new HashMap<>();
|
||||
private ShaderProgram current;
|
||||
|
||||
@Override
|
||||
public ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename) {
|
||||
log.info("Creating {} shader", programName);
|
||||
var vertexShaderCode = resourcesManager.loadResourceAsString(vertexShaderFilename);
|
||||
var fragmentShaderCode = resourcesManager.loadResourceAsString(fragmentShaderFilename);
|
||||
var program = ShaderProgram.compile(vertexShaderCode, fragmentShaderCode);
|
||||
|
||||
shaders.put(programName, program);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager selectShader(String programName) {
|
||||
current = shaders.get(programName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager useSelectedShader() {
|
||||
current.use();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager detachCurrentShader() {
|
||||
current.detach();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniform(String uniformName) {
|
||||
current.createUniform(uniformName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniform(String uniformName, Uniform uniform) {
|
||||
current.createUniform(uniformName, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniforms(String uniformName, int size) {
|
||||
current.createUniforms(uniformName, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniforms(String uniformName, int size, Uniform uniform) {
|
||||
current.createUniforms(uniformName, size, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, int value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, boolean value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, float value) {
|
||||
current.setUniform(uniformName, value);
|
||||
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);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Vector4f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Matrix3f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Matrix4f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Uniform uniform) {
|
||||
current.setUniform(uniformName, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, int index, Uniform uniform) {
|
||||
current.setUniform(uniformName, index, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniforms(String uniformName, Uniform[] uniforms) {
|
||||
current.setUniforms(uniformName, uniforms);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing shaders");
|
||||
shaders.forEach((name, program) -> program.dispose());
|
||||
log.info("{} shaders has been disposed", shaders.size());
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import com.bartlomiejpluta.base.core.util.res.ResourcesManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultShaderManager implements ShaderManager {
|
||||
private final ResourcesManager resourcesManager;
|
||||
private final Map<String, ShaderProgram> shaders = new HashMap<>();
|
||||
private ShaderProgram current;
|
||||
|
||||
@Override
|
||||
public ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename) {
|
||||
log.info("Creating {} shader", programName);
|
||||
var vertexShaderCode = resourcesManager.loadResourceAsString(vertexShaderFilename);
|
||||
var fragmentShaderCode = resourcesManager.loadResourceAsString(fragmentShaderFilename);
|
||||
var program = ShaderProgram.compile(vertexShaderCode, fragmentShaderCode);
|
||||
|
||||
shaders.put(programName, program);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager selectShader(String programName) {
|
||||
current = shaders.get(programName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager useSelectedShader() {
|
||||
current.use();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager detachCurrentShader() {
|
||||
current.detach();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniform(String uniformName) {
|
||||
current.createUniform(uniformName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniform(String uniformName, Uniform uniform) {
|
||||
current.createUniform(uniformName, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniforms(String uniformName, int size) {
|
||||
current.createUniforms(uniformName, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager createUniforms(String uniformName, int size, Uniform uniform) {
|
||||
current.createUniforms(uniformName, size, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, int value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, boolean value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, float value) {
|
||||
current.setUniform(uniformName, value);
|
||||
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);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Vector4f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Matrix3f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Matrix4f value) {
|
||||
current.setUniform(uniformName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, Uniform uniform) {
|
||||
current.setUniform(uniformName, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniform(String uniformName, int index, Uniform uniform) {
|
||||
current.setUniform(uniformName, index, uniform);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShaderManager setUniforms(String uniformName, Uniform[] uniforms) {
|
||||
current.setUniforms(uniformName, uniforms);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing shaders");
|
||||
shaders.forEach((name, program) -> program.dispose());
|
||||
log.info("{} shaders has been disposed", shaders.size());
|
||||
}
|
||||
}
|
||||
|
||||
88
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/ShaderManager.java
Executable file → Normal file
88
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/manager/ShaderManager.java
Executable file → Normal file
@@ -1,45 +1,45 @@
|
||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import org.joml.*;
|
||||
|
||||
public interface ShaderManager extends Cleanable {
|
||||
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
|
||||
|
||||
ShaderManager selectShader(String programName);
|
||||
|
||||
ShaderManager useSelectedShader();
|
||||
|
||||
ShaderManager detachCurrentShader();
|
||||
|
||||
ShaderManager createUniform(String uniformName);
|
||||
|
||||
ShaderManager createUniform(String uniformName, Uniform uniform);
|
||||
|
||||
ShaderManager createUniforms(String uniformName, int size);
|
||||
|
||||
ShaderManager createUniforms(String uniformName, int size, Uniform uniform);
|
||||
|
||||
ShaderManager setUniform(String uniformName, int value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, boolean value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, float value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector2f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector3f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector4f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Matrix3f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Matrix4f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Uniform uniform);
|
||||
|
||||
ShaderManager setUniform(String uniformName, int index, Uniform uniform);
|
||||
|
||||
ShaderManager setUniforms(String uniformName, Uniform[] uniforms);
|
||||
package com.bartlomiejpluta.base.core.gl.shader.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import org.joml.*;
|
||||
|
||||
public interface ShaderManager extends Cleanable {
|
||||
ShaderManager createShader(String programName, String vertexShaderFilename, String fragmentShaderFilename);
|
||||
|
||||
ShaderManager selectShader(String programName);
|
||||
|
||||
ShaderManager useSelectedShader();
|
||||
|
||||
ShaderManager detachCurrentShader();
|
||||
|
||||
ShaderManager createUniform(String uniformName);
|
||||
|
||||
ShaderManager createUniform(String uniformName, Uniform uniform);
|
||||
|
||||
ShaderManager createUniforms(String uniformName, int size);
|
||||
|
||||
ShaderManager createUniforms(String uniformName, int size, Uniform uniform);
|
||||
|
||||
ShaderManager setUniform(String uniformName, int value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, boolean value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, float value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector2f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector3f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Vector4f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Matrix3f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Matrix4f value);
|
||||
|
||||
ShaderManager setUniform(String uniformName, Uniform uniform);
|
||||
|
||||
ShaderManager setUniform(String uniformName, int index, Uniform uniform);
|
||||
|
||||
ShaderManager setUniforms(String uniformName, Uniform[] uniforms);
|
||||
}
|
||||
350
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/program/ShaderProgram.java
Executable file → Normal file
350
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/program/ShaderProgram.java
Executable file → Normal file
@@ -1,175 +1,175 @@
|
||||
package com.bartlomiejpluta.base.core.gl.shader.program;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.*;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.lwjgl.opengl.GL20.*;
|
||||
|
||||
@Slf4j
|
||||
public class ShaderProgram implements Disposable {
|
||||
private final int programId;
|
||||
private final int vertexShaderId;
|
||||
private final int fragmentShaderId;
|
||||
private final Map<String, Integer> uniforms = new HashMap<>();
|
||||
|
||||
private ShaderProgram(String vertexShaderCode, String fragmentShaderCode) {
|
||||
this.programId = glCreateProgram();
|
||||
|
||||
if(this.programId == 0) {
|
||||
throw new AppException("Could not create shader program");
|
||||
}
|
||||
|
||||
this.vertexShaderId = createShader(vertexShaderCode, GL_VERTEX_SHADER);
|
||||
this.fragmentShaderId = createShader(fragmentShaderCode, GL_FRAGMENT_SHADER);
|
||||
|
||||
linkProgram();
|
||||
}
|
||||
|
||||
private int createShader(String shaderCode, int shaderType) {
|
||||
int shaderId = glCreateShader(shaderType);
|
||||
if(shaderId == 0) {
|
||||
throw new AppException("Could not create shader of type: %s", shaderType);
|
||||
}
|
||||
|
||||
glShaderSource(shaderId, shaderCode);
|
||||
glCompileShader(shaderId);
|
||||
|
||||
if(glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
|
||||
throw new AppException("Could not compile shader code: %s", glGetShaderInfoLog(shaderId, 1024));
|
||||
}
|
||||
|
||||
glAttachShader(programId, shaderId);
|
||||
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
private void linkProgram() {
|
||||
glLinkProgram(programId);
|
||||
if(glGetProgrami(programId, GL_LINK_STATUS) == 0) {
|
||||
throw new AppException("Could not link shader program: %s", glGetProgramInfoLog(programId, 1024));
|
||||
}
|
||||
|
||||
if(vertexShaderId != 0) {
|
||||
glDetachShader(programId, vertexShaderId);
|
||||
}
|
||||
|
||||
if(fragmentShaderId != 0) {
|
||||
glDetachShader(programId, fragmentShaderId);
|
||||
}
|
||||
|
||||
glValidateProgram(programId);
|
||||
if(glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
|
||||
log.warn("Program validation failed: {}", glGetProgramInfoLog(programId, 1024));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUniform(String uniformName) {
|
||||
int location = glGetUniformLocation(programId, uniformName);
|
||||
|
||||
if(location < 0) {
|
||||
throw new AppException("Could not find uniform: %s", uniformName);
|
||||
}
|
||||
|
||||
uniforms.put(uniformName, location);
|
||||
}
|
||||
|
||||
public void createUniform(String uniformName, Uniform uniform) {
|
||||
uniform.createUniform(this, uniformName);
|
||||
}
|
||||
|
||||
public void createUniforms(String uniformName, int size) {
|
||||
for(int i=0; i<size; ++i) {
|
||||
createUniform(format("%s[%d]", uniformName, i));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUniforms(String uniformName, int size, Uniform uniform) {
|
||||
for(int i=0; i<size; ++i) {
|
||||
createUniform(format("%s[%d]", uniformName, i), uniform);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, int value) {
|
||||
glUniform1i(uniforms.get(uniformName), value);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, boolean value) {
|
||||
glUniform1i(uniforms.get(uniformName), value ? 1 : 0);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, float value) {
|
||||
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);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Vector4f value) {
|
||||
glUniform4f(uniforms.get(uniformName), value.x, value.y, value.z, value.w);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Matrix3f value) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
var buffer = stack.mallocFloat(3 * 3);
|
||||
value.get(buffer);
|
||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Matrix4f value) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
var buffer = stack.mallocFloat(4 * 4);
|
||||
value.get(buffer);
|
||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Uniform uniform) {
|
||||
uniform.setUniform(this, uniformName);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, int index, Uniform uniform) {
|
||||
setUniform(format("%s[%d]", uniformName, index), uniform);
|
||||
}
|
||||
|
||||
public void setUniforms(String uniformName, Uniform[] uniforms) {
|
||||
var size = uniforms != null ? uniforms.length : 0;
|
||||
for(int i=0; i<size; ++i) {
|
||||
setUniform(format("%s[%d]", uniformName, i), uniforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void use() {
|
||||
glUseProgram(programId);
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glUseProgram(0);
|
||||
|
||||
if(programId != 0) {
|
||||
glDeleteProgram(programId);
|
||||
}
|
||||
}
|
||||
|
||||
public static ShaderProgram compile(String vertexShaderCode, String fragmentShaderCode) {
|
||||
return new ShaderProgram(vertexShaderCode, fragmentShaderCode);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.shader.program;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import com.bartlomiejpluta.base.core.gc.Disposable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.uniform.Uniform;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.*;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.lwjgl.opengl.GL20.*;
|
||||
|
||||
@Slf4j
|
||||
public class ShaderProgram implements Disposable {
|
||||
private final int programId;
|
||||
private final int vertexShaderId;
|
||||
private final int fragmentShaderId;
|
||||
private final Map<String, Integer> uniforms = new HashMap<>();
|
||||
|
||||
private ShaderProgram(String vertexShaderCode, String fragmentShaderCode) {
|
||||
this.programId = glCreateProgram();
|
||||
|
||||
if(this.programId == 0) {
|
||||
throw new AppException("Could not create shader program");
|
||||
}
|
||||
|
||||
this.vertexShaderId = createShader(vertexShaderCode, GL_VERTEX_SHADER);
|
||||
this.fragmentShaderId = createShader(fragmentShaderCode, GL_FRAGMENT_SHADER);
|
||||
|
||||
linkProgram();
|
||||
}
|
||||
|
||||
private int createShader(String shaderCode, int shaderType) {
|
||||
int shaderId = glCreateShader(shaderType);
|
||||
if(shaderId == 0) {
|
||||
throw new AppException("Could not create shader of type: %s", shaderType);
|
||||
}
|
||||
|
||||
glShaderSource(shaderId, shaderCode);
|
||||
glCompileShader(shaderId);
|
||||
|
||||
if(glGetShaderi(shaderId, GL_COMPILE_STATUS) == 0) {
|
||||
throw new AppException("Could not compile shader code: %s", glGetShaderInfoLog(shaderId, 1024));
|
||||
}
|
||||
|
||||
glAttachShader(programId, shaderId);
|
||||
|
||||
return shaderId;
|
||||
}
|
||||
|
||||
private void linkProgram() {
|
||||
glLinkProgram(programId);
|
||||
if(glGetProgrami(programId, GL_LINK_STATUS) == 0) {
|
||||
throw new AppException("Could not link shader program: %s", glGetProgramInfoLog(programId, 1024));
|
||||
}
|
||||
|
||||
if(vertexShaderId != 0) {
|
||||
glDetachShader(programId, vertexShaderId);
|
||||
}
|
||||
|
||||
if(fragmentShaderId != 0) {
|
||||
glDetachShader(programId, fragmentShaderId);
|
||||
}
|
||||
|
||||
glValidateProgram(programId);
|
||||
if(glGetProgrami(programId, GL_VALIDATE_STATUS) == 0) {
|
||||
log.warn("Program validation failed: {}", glGetProgramInfoLog(programId, 1024));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUniform(String uniformName) {
|
||||
int location = glGetUniformLocation(programId, uniformName);
|
||||
|
||||
if(location < 0) {
|
||||
throw new AppException("Could not find uniform: %s", uniformName);
|
||||
}
|
||||
|
||||
uniforms.put(uniformName, location);
|
||||
}
|
||||
|
||||
public void createUniform(String uniformName, Uniform uniform) {
|
||||
uniform.createUniform(this, uniformName);
|
||||
}
|
||||
|
||||
public void createUniforms(String uniformName, int size) {
|
||||
for(int i=0; i<size; ++i) {
|
||||
createUniform(format("%s[%d]", uniformName, i));
|
||||
}
|
||||
}
|
||||
|
||||
public void createUniforms(String uniformName, int size, Uniform uniform) {
|
||||
for(int i=0; i<size; ++i) {
|
||||
createUniform(format("%s[%d]", uniformName, i), uniform);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, int value) {
|
||||
glUniform1i(uniforms.get(uniformName), value);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, boolean value) {
|
||||
glUniform1i(uniforms.get(uniformName), value ? 1 : 0);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, float value) {
|
||||
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);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Vector4f value) {
|
||||
glUniform4f(uniforms.get(uniformName), value.x, value.y, value.z, value.w);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Matrix3f value) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
var buffer = stack.mallocFloat(3 * 3);
|
||||
value.get(buffer);
|
||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Matrix4f value) {
|
||||
try(var stack = MemoryStack.stackPush()) {
|
||||
var buffer = stack.mallocFloat(4 * 4);
|
||||
value.get(buffer);
|
||||
glUniformMatrix4fv(uniforms.get(uniformName), false, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, Uniform uniform) {
|
||||
uniform.setUniform(this, uniformName);
|
||||
}
|
||||
|
||||
public void setUniform(String uniformName, int index, Uniform uniform) {
|
||||
setUniform(format("%s[%d]", uniformName, index), uniform);
|
||||
}
|
||||
|
||||
public void setUniforms(String uniformName, Uniform[] uniforms) {
|
||||
var size = uniforms != null ? uniforms.length : 0;
|
||||
for(int i=0; i<size; ++i) {
|
||||
setUniform(format("%s[%d]", uniformName, i), uniforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void use() {
|
||||
glUseProgram(programId);
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
glUseProgram(0);
|
||||
|
||||
if(programId != 0) {
|
||||
glDeleteProgram(programId);
|
||||
}
|
||||
}
|
||||
|
||||
public static ShaderProgram compile(String vertexShaderCode, String fragmentShaderCode) {
|
||||
return new ShaderProgram(vertexShaderCode, fragmentShaderCode);
|
||||
}
|
||||
}
|
||||
|
||||
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/uniform/Uniform.java
Executable file → Normal file
18
engine/src/main/java/com/bartlomiejpluta/base/core/gl/shader/uniform/Uniform.java
Executable file → Normal file
@@ -1,9 +1,9 @@
|
||||
package com.bartlomiejpluta.base.core.gl.shader.uniform;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||
|
||||
public interface Uniform {
|
||||
void createUniform(ShaderProgram shaderProgram, String uniformName);
|
||||
|
||||
void setUniform(ShaderProgram shaderProgram, String uniformName);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.gl.shader.uniform;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.program.ShaderProgram;
|
||||
|
||||
public interface Uniform {
|
||||
void createUniform(ShaderProgram shaderProgram, String uniformName);
|
||||
|
||||
void setUniform(ShaderProgram shaderProgram, String uniformName);
|
||||
}
|
||||
|
||||
78
engine/src/main/java/com/bartlomiejpluta/base/core/image/DefaultImageManager.java
Executable file → Normal file
78
engine/src/main/java/com/bartlomiejpluta/base/core/image/DefaultImageManager.java
Executable file → Normal file
@@ -1,39 +1,39 @@
|
||||
package com.bartlomiejpluta.base.core.image;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
||||
import com.bartlomiejpluta.base.core.util.math.MathUtil;
|
||||
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultImageManager implements ImageManager {
|
||||
private final MeshManager meshManager;
|
||||
private final TextureManager textureManager;
|
||||
|
||||
@Override
|
||||
public Image createImage(String imageFileName) {
|
||||
var texture = textureManager.loadTexture(imageFileName);
|
||||
var width = texture.getWidth();
|
||||
var height = texture.getHeight();
|
||||
var gcd = MathUtil.gcdEuclidean(width, height);
|
||||
var initialWidth = width / gcd;
|
||||
var initialHeight = height / gcd;
|
||||
var mesh = meshManager.createQuad(initialWidth, initialHeight, 0, 0);
|
||||
|
||||
var image = new Image(mesh, Material.textured(texture), initialWidth, initialHeight);
|
||||
image.setScale(gcd);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.image;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
||||
import com.bartlomiejpluta.base.core.util.math.MathUtil;
|
||||
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultImageManager implements ImageManager {
|
||||
private final MeshManager meshManager;
|
||||
private final TextureManager textureManager;
|
||||
|
||||
@Override
|
||||
public Image createImage(String imageFileName) {
|
||||
var texture = textureManager.loadTexture(imageFileName);
|
||||
var width = texture.getWidth();
|
||||
var height = texture.getHeight();
|
||||
var gcd = MathUtil.gcdEuclidean(width, height);
|
||||
var initialWidth = width / gcd;
|
||||
var initialHeight = height / gcd;
|
||||
var mesh = meshManager.createQuad(initialWidth, initialHeight, 0, 0);
|
||||
|
||||
var image = new Image(mesh, Material.textured(texture), initialWidth, initialHeight);
|
||||
image.setScale(gcd);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
|
||||
38
engine/src/main/java/com/bartlomiejpluta/base/core/image/Image.java
Executable file → Normal file
38
engine/src/main/java/com/bartlomiejpluta/base/core/image/Image.java
Executable file → Normal file
@@ -1,19 +1,19 @@
|
||||
package com.bartlomiejpluta.base.core.image;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Image extends RenderableObject {
|
||||
private final int initialWidth;
|
||||
private final int initialHeight;
|
||||
|
||||
Image(Mesh mesh, Material texture, int initialWidth, int initialHeight) {
|
||||
super(mesh);
|
||||
this.initialWidth = initialWidth;
|
||||
this.initialHeight = initialHeight;
|
||||
setMaterial(texture);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.image;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Image extends RenderableObject {
|
||||
private final int initialWidth;
|
||||
private final int initialHeight;
|
||||
|
||||
Image(Mesh mesh, Material texture, int initialWidth, int initialHeight) {
|
||||
super(mesh);
|
||||
this.initialWidth = initialWidth;
|
||||
this.initialHeight = initialHeight;
|
||||
setMaterial(texture);
|
||||
}
|
||||
}
|
||||
|
||||
0
engine/src/main/java/com/bartlomiejpluta/base/core/image/ImageManager.java
Executable file → Normal file
0
engine/src/main/java/com/bartlomiejpluta/base/core/image/ImageManager.java
Executable file → Normal file
28
engine/src/main/java/com/bartlomiejpluta/base/core/logic/GameLogic.java
Executable file → Normal file
28
engine/src/main/java/com/bartlomiejpluta/base/core/logic/GameLogic.java
Executable file → Normal file
@@ -1,14 +1,14 @@
|
||||
package com.bartlomiejpluta.base.core.logic;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface GameLogic extends Cleanable {
|
||||
void init(Window window);
|
||||
|
||||
void input(Window window);
|
||||
|
||||
void update(float dt);
|
||||
|
||||
void render(Window window);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.logic;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public interface GameLogic extends Cleanable {
|
||||
void init(Window window);
|
||||
|
||||
void input(Window window);
|
||||
|
||||
void update(float dt);
|
||||
|
||||
void render(Window window);
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/logic/Updatable.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/logic/Updatable.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.logic;
|
||||
|
||||
public interface Updatable {
|
||||
void update(float dt);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.logic;
|
||||
|
||||
public interface Updatable {
|
||||
void update(float dt);
|
||||
}
|
||||
|
||||
14
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/FPSMonitor.java
Executable file → Normal file
14
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/FPSMonitor.java
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
|
||||
public interface FPSMonitor extends Updatable, Cleanable {
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
|
||||
public interface FPSMonitor extends Updatable, Cleanable {
|
||||
}
|
||||
|
||||
126
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/LogFPSMonitor.java
Executable file → Normal file
126
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/fps/LogFPSMonitor.java
Executable file → Normal file
@@ -1,63 +1,63 @@
|
||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparingInt;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LogFPSMonitor implements FPSMonitor {
|
||||
private static final int MOD = 30;
|
||||
private final List<Double> values = new LinkedList<>();
|
||||
private float fpsAccumulator = 0;
|
||||
private int pointer = 0;
|
||||
private double fps = 0;
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
fpsAccumulator += dt;
|
||||
|
||||
if (++pointer % MOD == 0) {
|
||||
fps = pointer / fpsAccumulator;
|
||||
fpsAccumulator = 0;
|
||||
pointer = 0;
|
||||
|
||||
values.add(fps);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Min FPS: {}, max FPS: {}, avg FPS: {}",
|
||||
values.stream().min(Double::compareTo).orElse(-1.0),
|
||||
values.stream().max(Double::compareTo).orElse(-1.0),
|
||||
totalAverage()
|
||||
);
|
||||
|
||||
printHistogram();
|
||||
}
|
||||
|
||||
private double totalAverage() {
|
||||
return values.stream().reduce(0.0, Double::sum) / values.size();
|
||||
}
|
||||
|
||||
private void printHistogram() {
|
||||
values
|
||||
.stream()
|
||||
.mapToInt(Double::intValue)
|
||||
.boxed()
|
||||
.collect(groupingBy(identity(), counting()))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.sorted(comparingInt(Map.Entry::getKey))
|
||||
.forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.profiling.fps;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Comparator.comparingInt;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LogFPSMonitor implements FPSMonitor {
|
||||
private static final int MOD = 30;
|
||||
private final List<Double> values = new LinkedList<>();
|
||||
private float fpsAccumulator = 0;
|
||||
private int pointer = 0;
|
||||
private double fps = 0;
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
fpsAccumulator += dt;
|
||||
|
||||
if (++pointer % MOD == 0) {
|
||||
fps = pointer / fpsAccumulator;
|
||||
fpsAccumulator = 0;
|
||||
pointer = 0;
|
||||
|
||||
values.add(fps);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Min FPS: {}, max FPS: {}, avg FPS: {}",
|
||||
values.stream().min(Double::compareTo).orElse(-1.0),
|
||||
values.stream().max(Double::compareTo).orElse(-1.0),
|
||||
totalAverage()
|
||||
);
|
||||
|
||||
printHistogram();
|
||||
}
|
||||
|
||||
private double totalAverage() {
|
||||
return values.stream().reduce(0.0, Double::sum) / values.size();
|
||||
}
|
||||
|
||||
private void printHistogram() {
|
||||
values
|
||||
.stream()
|
||||
.mapToInt(Double::intValue)
|
||||
.boxed()
|
||||
.collect(groupingBy(identity(), counting()))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.sorted(comparingInt(Map.Entry::getKey))
|
||||
.forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
22
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/annotation/MeasureExecutionTime.java
Executable file → Normal file
22
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/annotation/MeasureExecutionTime.java
Executable file → Normal file
@@ -1,11 +1,11 @@
|
||||
package com.bartlomiejpluta.base.core.profiling.time.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface MeasureExecutionTime {
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.profiling.time.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface MeasureExecutionTime {
|
||||
}
|
||||
|
||||
76
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/aspect/ExecutionTimeAspect.java
Executable file → Normal file
76
engine/src/main/java/com/bartlomiejpluta/base/core/profiling/time/aspect/ExecutionTimeAspect.java
Executable file → Normal file
@@ -1,38 +1,38 @@
|
||||
package com.bartlomiejpluta.base.core.profiling.time.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@ConditionalOnExpression("${app.profiling.aspects:false}")
|
||||
public class ExecutionTimeAspect {
|
||||
|
||||
@Around("@annotation(com.bartlomiejpluta.base.core.stat.metrics.annotation.MeasureExecutionTime)")
|
||||
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
long start = 0;
|
||||
long end = 0;
|
||||
long elapsed;
|
||||
Object result;
|
||||
try {
|
||||
start = System.nanoTime();
|
||||
result = joinPoint.proceed();
|
||||
} finally {
|
||||
end = System.nanoTime();
|
||||
}
|
||||
|
||||
elapsed = end - start;
|
||||
log.debug("[{}.{}] = [{}s] [{}ms] [{}ns]",
|
||||
joinPoint.getTarget().getClass().getSimpleName(),
|
||||
joinPoint.getSignature().getName(),
|
||||
elapsed / 1000000.0, elapsed / 1000.0, elapsed
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.profiling.time.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@ConditionalOnExpression("${app.profiling.aspects:false}")
|
||||
public class ExecutionTimeAspect {
|
||||
|
||||
@Around("@annotation(com.bartlomiejpluta.base.core.stat.metrics.annotation.MeasureExecutionTime)")
|
||||
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
long start = 0;
|
||||
long end = 0;
|
||||
long elapsed;
|
||||
Object result;
|
||||
try {
|
||||
start = System.nanoTime();
|
||||
result = joinPoint.proceed();
|
||||
} finally {
|
||||
end = System.nanoTime();
|
||||
}
|
||||
|
||||
elapsed = end - start;
|
||||
log.debug("[{}.{}] = [{}s] [{}ms] [{}ns]",
|
||||
joinPoint.getTarget().getClass().getSimpleName(),
|
||||
joinPoint.getSignature().getName(),
|
||||
elapsed / 1000000.0, elapsed / 1000.0, elapsed
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
20
engine/src/main/java/com/bartlomiejpluta/base/core/thread/ThreadManager.java
Executable file → Normal file
20
engine/src/main/java/com/bartlomiejpluta/base/core/thread/ThreadManager.java
Executable file → Normal file
@@ -1,10 +1,10 @@
|
||||
package com.bartlomiejpluta.base.core.thread;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ThreadManager {
|
||||
public Thread createThread(String name, Runnable runnable) {
|
||||
return new Thread(runnable, name);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.thread;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ThreadManager {
|
||||
public Thread createThread(String name, Runnable runnable) {
|
||||
return new Thread(runnable, name);
|
||||
}
|
||||
}
|
||||
|
||||
40
engine/src/main/java/com/bartlomiejpluta/base/core/time/ChronoMeter.java
Executable file → Normal file
40
engine/src/main/java/com/bartlomiejpluta/base/core/time/ChronoMeter.java
Executable file → Normal file
@@ -1,20 +1,20 @@
|
||||
package com.bartlomiejpluta.base.core.time;
|
||||
|
||||
public class ChronoMeter {
|
||||
private double latchedTime;
|
||||
|
||||
public void init() {
|
||||
latchedTime = getTime();
|
||||
}
|
||||
|
||||
private double getTime() {
|
||||
return System.nanoTime() / 1_000_000_000.0;
|
||||
}
|
||||
|
||||
public float getElapsedTime() {
|
||||
double time = getTime();
|
||||
float elapsedTime = (float) (time - latchedTime);
|
||||
latchedTime = time;
|
||||
return elapsedTime;
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.time;
|
||||
|
||||
public class ChronoMeter {
|
||||
private double latchedTime;
|
||||
|
||||
public void init() {
|
||||
latchedTime = getTime();
|
||||
}
|
||||
|
||||
private double getTime() {
|
||||
return System.nanoTime() / 1_000_000_000.0;
|
||||
}
|
||||
|
||||
public float getElapsedTime() {
|
||||
double time = getTime();
|
||||
float elapsedTime = (float) (time - latchedTime);
|
||||
latchedTime = time;
|
||||
return elapsedTime;
|
||||
}
|
||||
}
|
||||
|
||||
238
engine/src/main/java/com/bartlomiejpluta/base/core/ui/Window.java
Executable file → Normal file
238
engine/src/main/java/com/bartlomiejpluta/base/core/ui/Window.java
Executable file → Normal file
@@ -1,119 +1,119 @@
|
||||
package com.bartlomiejpluta.base.core.ui;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.opengl.GL;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Window {
|
||||
private final String title;
|
||||
private long windowHandle;
|
||||
|
||||
@Getter
|
||||
private int width;
|
||||
|
||||
@Getter
|
||||
private int height;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean resized;
|
||||
|
||||
public void init() {
|
||||
// Setup an error callback. The default implementation
|
||||
// will print the error message in System.err.
|
||||
GLFWErrorCallback.createPrint(System.err).set();
|
||||
|
||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
||||
if (!glfwInit()) {
|
||||
throw new AppException("Unable to initialize GLFW");
|
||||
}
|
||||
|
||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
// Create the window
|
||||
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
if (windowHandle == NULL) {
|
||||
throw new AppException("Failed to create the GLFW window");
|
||||
}
|
||||
|
||||
// Setup resize callback
|
||||
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
|
||||
Window.this.width = width;
|
||||
Window.this.height = height;
|
||||
Window.this.resized = true;
|
||||
});
|
||||
|
||||
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
||||
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
||||
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
|
||||
}
|
||||
});
|
||||
|
||||
// Get the resolution of the primary monitor
|
||||
GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
|
||||
// Center our window
|
||||
glfwSetWindowPos(windowHandle, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);
|
||||
|
||||
// Make the OpenGL context current
|
||||
glfwMakeContextCurrent(windowHandle);
|
||||
|
||||
// Enable V-Sync
|
||||
// glfwSwapInterval(1);
|
||||
|
||||
// Make the window visible
|
||||
glfwShowWindow(windowHandle);
|
||||
|
||||
GL.createCapabilities();
|
||||
|
||||
// Support for transparencies
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Set the clear color
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
glfwSwapBuffers(windowHandle);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
public boolean isKeyPressed(int keyCode) {
|
||||
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
public void clear(float r, float g, float b, float alpha) {
|
||||
glClearColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public boolean shouldClose() {
|
||||
return glfwWindowShouldClose(windowHandle);
|
||||
}
|
||||
|
||||
public Vector2f getSize() {
|
||||
return new Vector2f(width, height);
|
||||
}
|
||||
|
||||
public static Window create(String title, int width, int height) {
|
||||
return new Window(title, -1, width, height, false);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.ui;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.opengl.GL;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Window {
|
||||
private final String title;
|
||||
private long windowHandle;
|
||||
|
||||
@Getter
|
||||
private int width;
|
||||
|
||||
@Getter
|
||||
private int height;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean resized;
|
||||
|
||||
public void init() {
|
||||
// Setup an error callback. The default implementation
|
||||
// will print the error message in System.err.
|
||||
GLFWErrorCallback.createPrint(System.err).set();
|
||||
|
||||
// Initialize GLFW. Most GLFW functions will not work before doing this.
|
||||
if (!glfwInit()) {
|
||||
throw new AppException("Unable to initialize GLFW");
|
||||
}
|
||||
|
||||
glfwDefaultWindowHints(); // optional, the current window hints are already the default
|
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
|
||||
// Create the window
|
||||
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
if (windowHandle == NULL) {
|
||||
throw new AppException("Failed to create the GLFW window");
|
||||
}
|
||||
|
||||
// Setup resize callback
|
||||
glfwSetFramebufferSizeCallback(windowHandle, (window, width, height) -> {
|
||||
Window.this.width = width;
|
||||
Window.this.height = height;
|
||||
Window.this.resized = true;
|
||||
});
|
||||
|
||||
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
|
||||
glfwSetKeyCallback(windowHandle, (window, key, scancode, action, mods) -> {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
|
||||
glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop
|
||||
}
|
||||
});
|
||||
|
||||
// Get the resolution of the primary monitor
|
||||
GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
|
||||
// Center our window
|
||||
glfwSetWindowPos(windowHandle, (videoMode.width() - width) / 2, (videoMode.height() - height) / 2);
|
||||
|
||||
// Make the OpenGL context current
|
||||
glfwMakeContextCurrent(windowHandle);
|
||||
|
||||
// Enable V-Sync
|
||||
// glfwSwapInterval(1);
|
||||
|
||||
// Make the window visible
|
||||
glfwShowWindow(windowHandle);
|
||||
|
||||
GL.createCapabilities();
|
||||
|
||||
// Support for transparencies
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Set the clear color
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
glfwSwapBuffers(windowHandle);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
public boolean isKeyPressed(int keyCode) {
|
||||
return glfwGetKey(windowHandle, keyCode) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
public void clear(float r, float g, float b, float alpha) {
|
||||
glClearColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public boolean shouldClose() {
|
||||
return glfwWindowShouldClose(windowHandle);
|
||||
}
|
||||
|
||||
public Vector2f getSize() {
|
||||
return new Vector2f(width, height);
|
||||
}
|
||||
|
||||
public static Window create(String title, int width, int height) {
|
||||
return new Window(title, -1, width, height, false);
|
||||
}
|
||||
}
|
||||
|
||||
20
engine/src/main/java/com/bartlomiejpluta/base/core/ui/WindowManager.java
Executable file → Normal file
20
engine/src/main/java/com/bartlomiejpluta/base/core/ui/WindowManager.java
Executable file → Normal file
@@ -1,10 +1,10 @@
|
||||
package com.bartlomiejpluta.base.core.ui;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class WindowManager {
|
||||
public Window createWindow(String title, int width, int height) {
|
||||
return Window.create(title, width, height);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.ui;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class WindowManager {
|
||||
public Window createWindow(String title, int width, int height) {
|
||||
return Window.create(title, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
64
engine/src/main/java/com/bartlomiejpluta/base/core/util/math/MathUtil.java
Executable file → Normal file
64
engine/src/main/java/com/bartlomiejpluta/base/core/util/math/MathUtil.java
Executable file → Normal file
@@ -1,32 +1,32 @@
|
||||
package com.bartlomiejpluta.base.core.util.math;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
public class MathUtil {
|
||||
public static int gcdEuclidean(int a, int b) {
|
||||
int x = a;
|
||||
int y = b;
|
||||
int z;
|
||||
|
||||
while(y != 0) {
|
||||
z = x % y;
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static int clamp(int value, int min, int max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
|
||||
public static float clamp(float value, float min, float max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
|
||||
public static double clamp(double value, double min, double max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.util.math;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
public class MathUtil {
|
||||
public static int gcdEuclidean(int a, int b) {
|
||||
int x = a;
|
||||
int y = b;
|
||||
int z;
|
||||
|
||||
while(y != 0) {
|
||||
z = x % y;
|
||||
x = y;
|
||||
y = z;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
public static int clamp(int value, int min, int max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
|
||||
public static float clamp(float value, float min, float max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
|
||||
public static double clamp(double value, double min, double max) {
|
||||
return min(max, max(value, min));
|
||||
}
|
||||
}
|
||||
|
||||
86
engine/src/main/java/com/bartlomiejpluta/base/core/util/mesh/DefaultMeshManager.java
Executable file → Normal file
86
engine/src/main/java/com/bartlomiejpluta/base/core/util/mesh/DefaultMeshManager.java
Executable file → Normal file
@@ -1,43 +1,43 @@
|
||||
package com.bartlomiejpluta.base.core.util.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.Vector2f;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
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:{},{}] and putting it into the cache", width, height, originX, originY);
|
||||
mesh = Mesh.quad(width, height, originX, originY);
|
||||
quads.put(dim, mesh);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing meshes");
|
||||
quads.forEach((dim, mesh) -> mesh.dispose());
|
||||
log.info("{} meshes has been disposed", quads.size());
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class QuadDimension {
|
||||
private final Vector2f size;
|
||||
private final Vector2f origin;
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.util.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.joml.Vector2f;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
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:{},{}] and putting it into the cache", width, height, originX, originY);
|
||||
mesh = Mesh.quad(width, height, originX, originY);
|
||||
quads.put(dim, mesh);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("Disposing meshes");
|
||||
quads.forEach((dim, mesh) -> mesh.dispose());
|
||||
log.info("{} meshes has been disposed", quads.size());
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class QuadDimension {
|
||||
private final Vector2f size;
|
||||
private final Vector2f origin;
|
||||
}
|
||||
}
|
||||
|
||||
16
engine/src/main/java/com/bartlomiejpluta/base/core/util/mesh/MeshManager.java
Executable file → Normal file
16
engine/src/main/java/com/bartlomiejpluta/base/core/util/mesh/MeshManager.java
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.core.util.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
|
||||
public interface MeshManager extends Cleanable {
|
||||
Mesh createQuad(float width, float height, float originX, float originY);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.util.mesh;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
|
||||
public interface MeshManager extends Cleanable {
|
||||
Mesh createQuad(float width, float height, float originX, float originY);
|
||||
}
|
||||
|
||||
70
engine/src/main/java/com/bartlomiejpluta/base/core/util/res/ResourcesManager.java
Executable file → Normal file
70
engine/src/main/java/com/bartlomiejpluta/base/core/util/res/ResourcesManager.java
Executable file → Normal file
@@ -1,35 +1,35 @@
|
||||
package com.bartlomiejpluta.base.core.util.res;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Scanner;
|
||||
|
||||
@Component
|
||||
public class ResourcesManager {
|
||||
public String loadResourceAsString(String fileName) {
|
||||
try (InputStream in = ResourcesManager.class.getResourceAsStream(fileName);
|
||||
Scanner scanner = new Scanner(in, java.nio.charset.StandardCharsets.UTF_8.name())) {
|
||||
return scanner.useDelimiter("\\A").next();
|
||||
} catch (Exception e) {
|
||||
throw new AppException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer loadResourceAsByteBuffer(String fileName) {
|
||||
try {
|
||||
var bytes = ResourcesManager.class.getResourceAsStream(fileName).readAllBytes();
|
||||
return ByteBuffer
|
||||
.allocateDirect(bytes.length)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
.put(bytes)
|
||||
.flip();
|
||||
} catch (IOException e) {
|
||||
throw new AppException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.util.res;
|
||||
|
||||
import com.bartlomiejpluta.base.core.error.AppException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Scanner;
|
||||
|
||||
@Component
|
||||
public class ResourcesManager {
|
||||
public String loadResourceAsString(String fileName) {
|
||||
try (InputStream in = ResourcesManager.class.getResourceAsStream(fileName);
|
||||
Scanner scanner = new Scanner(in, java.nio.charset.StandardCharsets.UTF_8.name())) {
|
||||
return scanner.useDelimiter("\\A").next();
|
||||
} catch (Exception e) {
|
||||
throw new AppException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer loadResourceAsByteBuffer(String fileName) {
|
||||
try {
|
||||
var bytes = ResourcesManager.class.getResourceAsStream(fileName).readAllBytes();
|
||||
return ByteBuffer
|
||||
.allocateDirect(bytes.length)
|
||||
.order(ByteOrder.nativeOrder())
|
||||
.put(bytes)
|
||||
.flip();
|
||||
} catch (IOException e) {
|
||||
throw new AppException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/AnimationableObject.java
Executable file → Normal file
66
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/AnimationableObject.java
Executable file → Normal file
@@ -1,33 +1,33 @@
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class AnimationableObject extends RenderableObject {
|
||||
protected final Vector2i spriteSheetDimension;
|
||||
|
||||
public AnimationableObject(Mesh mesh, Material material, Vector2i spriteSheetDimension) {
|
||||
super(mesh);
|
||||
this.spriteSheetDimension = spriteSheetDimension;
|
||||
|
||||
material.setSpriteSize(1 / (float) spriteSheetDimension.y, 1 / (float) spriteSheetDimension.x);
|
||||
setMaterial(material);
|
||||
}
|
||||
|
||||
// Returns time in ms between frames
|
||||
public abstract int getAnimationSpeed();
|
||||
|
||||
public abstract boolean shouldAnimate();
|
||||
|
||||
public abstract Vector2f[] getSpriteAnimationFramesPositions();
|
||||
|
||||
protected void setAnimationFrame(Vector2f framePosition) {
|
||||
var spriteSize = getMaterial().getSpriteSize();
|
||||
setSpritePosition(spriteSize.x * framePosition.x, spriteSize.y * framePosition.y);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class AnimationableObject extends RenderableObject {
|
||||
protected final Vector2i spriteSheetDimension;
|
||||
|
||||
public AnimationableObject(Mesh mesh, Material material, Vector2i spriteSheetDimension) {
|
||||
super(mesh);
|
||||
this.spriteSheetDimension = spriteSheetDimension;
|
||||
|
||||
material.setSpriteSize(1 / (float) spriteSheetDimension.y, 1 / (float) spriteSheetDimension.x);
|
||||
setMaterial(material);
|
||||
}
|
||||
|
||||
// Returns time in ms between frames
|
||||
public abstract int getAnimationSpeed();
|
||||
|
||||
public abstract boolean shouldAnimate();
|
||||
|
||||
public abstract Vector2f[] getSpriteAnimationFramesPositions();
|
||||
|
||||
protected void setAnimationFrame(Vector2f framePosition) {
|
||||
var spriteSize = getMaterial().getSpriteSize();
|
||||
setSpritePosition(spriteSize.x * framePosition.x, spriteSize.y * framePosition.y);
|
||||
}
|
||||
}
|
||||
|
||||
10
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/Animator.java
Executable file → Normal file
10
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/Animator.java
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
public interface Animator {
|
||||
void animate(AnimationableObject objects);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
public interface Animator {
|
||||
void animate(AnimationableObject objects);
|
||||
}
|
||||
|
||||
36
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/DefaultAnimator.java
Executable file → Normal file
36
engine/src/main/java/com/bartlomiejpluta/base/core/world/animation/DefaultAnimator.java
Executable file → Normal file
@@ -1,18 +1,18 @@
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DefaultAnimator implements Animator {
|
||||
|
||||
@Override
|
||||
public void animate(AnimationableObject object) {
|
||||
if(object.shouldAnimate()) {
|
||||
var positions = object.getSpriteAnimationFramesPositions();
|
||||
var delay = object.getAnimationSpeed();
|
||||
var currentPosition = (int) (System.currentTimeMillis() % (positions.length * delay)) / delay;
|
||||
var current = positions[currentPosition];
|
||||
object.setAnimationFrame(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.animation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DefaultAnimator implements Animator {
|
||||
|
||||
@Override
|
||||
public void animate(AnimationableObject object) {
|
||||
if(object.shouldAnimate()) {
|
||||
var positions = object.getSpriteAnimationFramesPositions();
|
||||
var delay = object.getAnimationSpeed();
|
||||
var currentPosition = (int) (System.currentTimeMillis() % (positions.length * delay)) / delay;
|
||||
var current = positions[currentPosition];
|
||||
object.setAnimationFrame(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
engine/src/main/java/com/bartlomiejpluta/base/core/world/camera/Camera.java
Executable file → Normal file
44
engine/src/main/java/com/bartlomiejpluta/base/core/world/camera/Camera.java
Executable file → Normal file
@@ -1,22 +1,22 @@
|
||||
package com.bartlomiejpluta.base.core.world.camera;
|
||||
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.object.PositionableObject;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public class Camera extends PositionableObject {
|
||||
private final Matrix4f projectionMatrix = new Matrix4f();
|
||||
private final Matrix4f viewMatrix = new Matrix4f();
|
||||
|
||||
public Matrix4f getProjectionMatrix(Window window) {
|
||||
return projectionMatrix
|
||||
.identity()
|
||||
.setOrtho2D(0, window.getWidth(), window.getHeight(), 0);
|
||||
}
|
||||
|
||||
public Matrix4f getViewMatrix() {
|
||||
return viewMatrix
|
||||
.identity()
|
||||
.translate(-position.x, -position.y, 0);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.camera;
|
||||
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.object.PositionableObject;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public class Camera extends PositionableObject {
|
||||
private final Matrix4f projectionMatrix = new Matrix4f();
|
||||
private final Matrix4f viewMatrix = new Matrix4f();
|
||||
|
||||
public Matrix4f getProjectionMatrix(Window window) {
|
||||
return projectionMatrix
|
||||
.identity()
|
||||
.setOrtho2D(0, window.getWidth(), window.getHeight(), 0);
|
||||
}
|
||||
|
||||
public Matrix4f getViewMatrix() {
|
||||
return viewMatrix
|
||||
.identity()
|
||||
.translate(-position.x, -position.y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
272
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/GameMap.java
Executable file → Normal file
272
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/GameMap.java
Executable file → Normal file
@@ -1,136 +1,136 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.image.Image;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.animation.Animator;
|
||||
import com.bartlomiejpluta.base.core.world.camera.Camera;
|
||||
import com.bartlomiejpluta.base.core.world.movement.MovableObject;
|
||||
import com.bartlomiejpluta.base.core.world.movement.Movement;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.Tile;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class GameMap implements Renderable, Updatable {
|
||||
private final Animator animator;
|
||||
|
||||
private final Camera camera;
|
||||
private final TileSet tileSet;
|
||||
private final List<Layer> layers = new ArrayList<>();
|
||||
|
||||
private final float scale;
|
||||
|
||||
@Getter
|
||||
private final int rows;
|
||||
|
||||
@Getter
|
||||
private final int columns;
|
||||
|
||||
@Getter
|
||||
private final Vector2f stepSize;
|
||||
|
||||
public GameMap(Animator animator, Camera camera, TileSet tileSet, int rows, int columns, float scale) {
|
||||
this.animator = animator;
|
||||
this.camera = camera;
|
||||
this.tileSet = tileSet;
|
||||
this.scale = scale;
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.stepSize = new Vector2f(this.scale * this.tileSet.getTileWidth(), this.scale * this.tileSet.getTileHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
shaderManager.setUniform(UniformName.UNI_PROJECTION_MATRIX, camera.getProjectionMatrix(window));
|
||||
shaderManager.setUniform(UniformName.UNI_VIEW_MATRIX, camera.getViewMatrix());
|
||||
|
||||
for (var layer : layers) {
|
||||
layer.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
for (var layer : layers) {
|
||||
layer.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2f getSize() {
|
||||
return new Vector2f(columns * stepSize.x, rows * stepSize.y);
|
||||
}
|
||||
|
||||
public GameMap createObjectLayer() {
|
||||
var passageMap = new PassageAbility[rows][columns];
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
Arrays.fill(passageMap[i], 0, columns, PassageAbility.ALLOW);
|
||||
}
|
||||
|
||||
layers.add(new ObjectLayer(animator, new ArrayList<>(), passageMap));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap createTileLayer() {
|
||||
layers.add(new TileLayer(new Tile[rows][columns], stepSize, scale));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap createImageLayer(Image image, ImageLayer.Mode imageDisplayMode) {
|
||||
layers.add(new ImageLayer(this, image, imageDisplayMode));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap addObject(int layerIndex, MovableObject object) {
|
||||
((ObjectLayer) layers.get(layerIndex)).addObject(object);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap removeObject(int layerIndex, MovableObject object) {
|
||||
((ObjectLayer) layers.get(layerIndex)).removeObject(object);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setPassageAbility(int layerIndex, int row, int column, PassageAbility passageAbility) {
|
||||
((ObjectLayer) layers.get(layerIndex)).setPassageAbility(row, column, passageAbility);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setTile(int layerIndex, int row, int column, Tile tile) {
|
||||
((TileLayer) layers.get(layerIndex)).setTile(row, column, tile);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setImage(int layerIndex, Image image) {
|
||||
((ImageLayer) layers.get(layerIndex)).setImage(image);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isMovementPossible(int layerIndex, Movement movement) {
|
||||
var target = movement.getTargetCoordinate();
|
||||
|
||||
// Is trying to go beyond the map
|
||||
if(target.x < 0 || target.y < 0 || target.x >= columns || target.y >= rows) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var source = movement.getSourceCoordinate();
|
||||
var direction = movement.getDirection();
|
||||
|
||||
return ((ObjectLayer) layers.get(layerIndex)).isMovementPossible(source, target, direction);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.image.Image;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.animation.Animator;
|
||||
import com.bartlomiejpluta.base.core.world.camera.Camera;
|
||||
import com.bartlomiejpluta.base.core.world.movement.MovableObject;
|
||||
import com.bartlomiejpluta.base.core.world.movement.Movement;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.Tile;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class GameMap implements Renderable, Updatable {
|
||||
private final Animator animator;
|
||||
|
||||
private final Camera camera;
|
||||
private final TileSet tileSet;
|
||||
private final List<Layer> layers = new ArrayList<>();
|
||||
|
||||
private final float scale;
|
||||
|
||||
@Getter
|
||||
private final int rows;
|
||||
|
||||
@Getter
|
||||
private final int columns;
|
||||
|
||||
@Getter
|
||||
private final Vector2f stepSize;
|
||||
|
||||
public GameMap(Animator animator, Camera camera, TileSet tileSet, int rows, int columns, float scale) {
|
||||
this.animator = animator;
|
||||
this.camera = camera;
|
||||
this.tileSet = tileSet;
|
||||
this.scale = scale;
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
this.stepSize = new Vector2f(this.scale * this.tileSet.getTileWidth(), this.scale * this.tileSet.getTileHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
shaderManager.setUniform(UniformName.UNI_PROJECTION_MATRIX, camera.getProjectionMatrix(window));
|
||||
shaderManager.setUniform(UniformName.UNI_VIEW_MATRIX, camera.getViewMatrix());
|
||||
|
||||
for (var layer : layers) {
|
||||
layer.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
for (var layer : layers) {
|
||||
layer.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2f getSize() {
|
||||
return new Vector2f(columns * stepSize.x, rows * stepSize.y);
|
||||
}
|
||||
|
||||
public GameMap createObjectLayer() {
|
||||
var passageMap = new PassageAbility[rows][columns];
|
||||
for (int i = 0; i < rows; ++i) {
|
||||
Arrays.fill(passageMap[i], 0, columns, PassageAbility.ALLOW);
|
||||
}
|
||||
|
||||
layers.add(new ObjectLayer(animator, new ArrayList<>(), passageMap));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap createTileLayer() {
|
||||
layers.add(new TileLayer(new Tile[rows][columns], stepSize, scale));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap createImageLayer(Image image, ImageLayer.Mode imageDisplayMode) {
|
||||
layers.add(new ImageLayer(this, image, imageDisplayMode));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap addObject(int layerIndex, MovableObject object) {
|
||||
((ObjectLayer) layers.get(layerIndex)).addObject(object);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap removeObject(int layerIndex, MovableObject object) {
|
||||
((ObjectLayer) layers.get(layerIndex)).removeObject(object);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setPassageAbility(int layerIndex, int row, int column, PassageAbility passageAbility) {
|
||||
((ObjectLayer) layers.get(layerIndex)).setPassageAbility(row, column, passageAbility);
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setTile(int layerIndex, int row, int column, Tile tile) {
|
||||
((TileLayer) layers.get(layerIndex)).setTile(row, column, tile);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public GameMap setImage(int layerIndex, Image image) {
|
||||
((ImageLayer) layers.get(layerIndex)).setImage(image);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isMovementPossible(int layerIndex, Movement movement) {
|
||||
var target = movement.getTargetCoordinate();
|
||||
|
||||
// Is trying to go beyond the map
|
||||
if(target.x < 0 || target.y < 0 || target.x >= columns || target.y >= rows) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var source = movement.getSourceCoordinate();
|
||||
var direction = movement.getDirection();
|
||||
|
||||
return ((ObjectLayer) layers.get(layerIndex)).isMovementPossible(source, target, direction);
|
||||
}
|
||||
}
|
||||
|
||||
116
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/ImageLayer.java
Executable file → Normal file
116
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/ImageLayer.java
Executable file → Normal file
@@ -1,58 +1,58 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.image.Image;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public class ImageLayer implements Layer {
|
||||
|
||||
public enum Mode {
|
||||
NORMAL,
|
||||
FIT_SCREEN,
|
||||
FIT_MAP;
|
||||
}
|
||||
|
||||
private final float mapWidth;
|
||||
private final float mapHeight;
|
||||
|
||||
private Image image;
|
||||
private float imageInitialWidth;
|
||||
private float imageInitialHeight;
|
||||
private final Mode mode;
|
||||
|
||||
public ImageLayer(GameMap map, Image image, Mode mode) {
|
||||
var stepSize = map.getStepSize();
|
||||
this.mapWidth = map.getColumns() * stepSize.x;
|
||||
this.mapHeight = map.getRows() * stepSize.y;
|
||||
this.mode = mode;
|
||||
setImage(image);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.image = image;
|
||||
this.imageInitialWidth = image.getInitialWidth();
|
||||
this.imageInitialHeight = image.getInitialHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, image.getModelMatrix());
|
||||
|
||||
switch (mode) {
|
||||
case FIT_SCREEN -> image.setScale(window.getWidth() / imageInitialWidth, window.getHeight() / imageInitialHeight);
|
||||
case FIT_MAP -> image.setScale(mapWidth / imageInitialWidth, mapHeight / imageInitialHeight);
|
||||
}
|
||||
|
||||
image.render(window, shaderManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.image.Image;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
|
||||
public class ImageLayer implements Layer {
|
||||
|
||||
public enum Mode {
|
||||
NORMAL,
|
||||
FIT_SCREEN,
|
||||
FIT_MAP;
|
||||
}
|
||||
|
||||
private final float mapWidth;
|
||||
private final float mapHeight;
|
||||
|
||||
private Image image;
|
||||
private float imageInitialWidth;
|
||||
private float imageInitialHeight;
|
||||
private final Mode mode;
|
||||
|
||||
public ImageLayer(GameMap map, Image image, Mode mode) {
|
||||
var stepSize = map.getStepSize();
|
||||
this.mapWidth = map.getColumns() * stepSize.x;
|
||||
this.mapHeight = map.getRows() * stepSize.y;
|
||||
this.mode = mode;
|
||||
setImage(image);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.image = image;
|
||||
this.imageInitialWidth = image.getInitialWidth();
|
||||
this.imageInitialHeight = image.getInitialHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, image.getModelMatrix());
|
||||
|
||||
switch (mode) {
|
||||
case FIT_SCREEN -> image.setScale(window.getWidth() / imageInitialWidth, window.getHeight() / imageInitialHeight);
|
||||
case FIT_MAP -> image.setScale(mapWidth / imageInitialWidth, mapHeight / imageInitialHeight);
|
||||
}
|
||||
|
||||
image.render(window, shaderManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
16
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/Layer.java
Executable file → Normal file
16
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/Layer.java
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
|
||||
public interface Layer extends Renderable, Updatable {
|
||||
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
|
||||
public interface Layer extends Renderable, Updatable {
|
||||
|
||||
}
|
||||
|
||||
146
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/ObjectLayer.java
Executable file → Normal file
146
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/ObjectLayer.java
Executable file → Normal file
@@ -1,73 +1,73 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.animation.Animator;
|
||||
import com.bartlomiejpluta.base.core.world.movement.Direction;
|
||||
import com.bartlomiejpluta.base.core.world.movement.MovableObject;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ObjectLayer implements Layer {
|
||||
private final Animator animator;
|
||||
private final List<MovableObject> objects;
|
||||
|
||||
private final PassageAbility[][] passageMap;
|
||||
|
||||
public ObjectLayer(Animator animator, List<MovableObject> objects, PassageAbility[][] passageMap) {
|
||||
this.animator = animator;
|
||||
this.objects = objects;
|
||||
this.passageMap = passageMap;
|
||||
}
|
||||
|
||||
public void addObject(MovableObject object) {
|
||||
objects.add(object);
|
||||
}
|
||||
|
||||
public void removeObject(MovableObject object) {
|
||||
objects.remove(object);
|
||||
}
|
||||
|
||||
public void setPassageAbility(int row, int column, PassageAbility passageAbility) {
|
||||
passageMap[row][column] = passageAbility;
|
||||
}
|
||||
|
||||
public boolean isMovementPossible(Vector2i source, Vector2i target, Direction direction) {
|
||||
var isTargetReachable = switch (passageMap[target.y][target.x]) {
|
||||
case UP_ONLY -> direction != Direction.DOWN;
|
||||
case DOWN_ONLY -> direction != Direction.UP;
|
||||
case LEFT_ONLY -> direction != Direction.RIGHT;
|
||||
case RIGHT_ONLY -> direction != Direction.LEFT;
|
||||
case BLOCK -> false;
|
||||
case ALLOW -> true;
|
||||
};
|
||||
|
||||
var canMoveFromCurrentTile = switch (passageMap[source.y][source.x]) {
|
||||
case UP_ONLY -> direction == Direction.UP;
|
||||
case DOWN_ONLY -> direction == Direction.DOWN;
|
||||
case LEFT_ONLY -> direction == Direction.LEFT;
|
||||
case RIGHT_ONLY -> direction == Direction.RIGHT;
|
||||
default -> true;
|
||||
};
|
||||
|
||||
return isTargetReachable && canMoveFromCurrentTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
for (var object : objects) {
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, object.getModelMatrix());
|
||||
animator.animate(object);
|
||||
object.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
for (var object : objects) {
|
||||
object.update(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.animation.Animator;
|
||||
import com.bartlomiejpluta.base.core.world.movement.Direction;
|
||||
import com.bartlomiejpluta.base.core.world.movement.MovableObject;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ObjectLayer implements Layer {
|
||||
private final Animator animator;
|
||||
private final List<MovableObject> objects;
|
||||
|
||||
private final PassageAbility[][] passageMap;
|
||||
|
||||
public ObjectLayer(Animator animator, List<MovableObject> objects, PassageAbility[][] passageMap) {
|
||||
this.animator = animator;
|
||||
this.objects = objects;
|
||||
this.passageMap = passageMap;
|
||||
}
|
||||
|
||||
public void addObject(MovableObject object) {
|
||||
objects.add(object);
|
||||
}
|
||||
|
||||
public void removeObject(MovableObject object) {
|
||||
objects.remove(object);
|
||||
}
|
||||
|
||||
public void setPassageAbility(int row, int column, PassageAbility passageAbility) {
|
||||
passageMap[row][column] = passageAbility;
|
||||
}
|
||||
|
||||
public boolean isMovementPossible(Vector2i source, Vector2i target, Direction direction) {
|
||||
var isTargetReachable = switch (passageMap[target.y][target.x]) {
|
||||
case UP_ONLY -> direction != Direction.DOWN;
|
||||
case DOWN_ONLY -> direction != Direction.UP;
|
||||
case LEFT_ONLY -> direction != Direction.RIGHT;
|
||||
case RIGHT_ONLY -> direction != Direction.LEFT;
|
||||
case BLOCK -> false;
|
||||
case ALLOW -> true;
|
||||
};
|
||||
|
||||
var canMoveFromCurrentTile = switch (passageMap[source.y][source.x]) {
|
||||
case UP_ONLY -> direction == Direction.UP;
|
||||
case DOWN_ONLY -> direction == Direction.DOWN;
|
||||
case LEFT_ONLY -> direction == Direction.LEFT;
|
||||
case RIGHT_ONLY -> direction == Direction.RIGHT;
|
||||
default -> true;
|
||||
};
|
||||
|
||||
return isTargetReachable && canMoveFromCurrentTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
for (var object : objects) {
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, object.getModelMatrix());
|
||||
animator.animate(object);
|
||||
object.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
for (var object : objects) {
|
||||
object.update(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/PassageAbility.java
Executable file → Normal file
20
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/PassageAbility.java
Executable file → Normal file
@@ -1,10 +1,10 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
public enum PassageAbility {
|
||||
BLOCK,
|
||||
ALLOW,
|
||||
UP_ONLY,
|
||||
DOWN_ONLY,
|
||||
LEFT_ONLY,
|
||||
RIGHT_ONLY
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
public enum PassageAbility {
|
||||
BLOCK,
|
||||
ALLOW,
|
||||
UP_ONLY,
|
||||
DOWN_ONLY,
|
||||
LEFT_ONLY,
|
||||
RIGHT_ONLY
|
||||
}
|
||||
|
||||
92
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/TileLayer.java
Executable file → Normal file
92
engine/src/main/java/com/bartlomiejpluta/base/core/world/map/TileLayer.java
Executable file → Normal file
@@ -1,46 +1,46 @@
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.Tile;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
public class TileLayer implements Layer {
|
||||
private final Tile[][] layer;
|
||||
private final Vector2f stepSize;
|
||||
private final float scale;
|
||||
|
||||
public TileLayer(Tile[][] layer, Vector2f stepSize, float scale) {
|
||||
this.layer = layer;
|
||||
this.stepSize = stepSize;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public void setTile(int row, int column, Tile tile) {
|
||||
layer[row][column] = tile;
|
||||
recalculateTileGeometry(tile, row, column);
|
||||
}
|
||||
|
||||
private void recalculateTileGeometry(Tile tile, int row, int column) {
|
||||
tile.setScale(scale);
|
||||
tile.setPosition(column * stepSize.x, row * stepSize.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
for (var row : layer) {
|
||||
for (var tile : row) {
|
||||
if (tile != null) {
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, tile.getModelMatrix());
|
||||
tile.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.map;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.Tile;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
public class TileLayer implements Layer {
|
||||
private final Tile[][] layer;
|
||||
private final Vector2f stepSize;
|
||||
private final float scale;
|
||||
|
||||
public TileLayer(Tile[][] layer, Vector2f stepSize, float scale) {
|
||||
this.layer = layer;
|
||||
this.stepSize = stepSize;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public void setTile(int row, int column, Tile tile) {
|
||||
layer[row][column] = tile;
|
||||
recalculateTileGeometry(tile, row, column);
|
||||
}
|
||||
|
||||
private void recalculateTileGeometry(Tile tile, int row, int column) {
|
||||
tile.setScale(scale);
|
||||
tile.setPosition(column * stepSize.x, row * stepSize.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
for (var row : layer) {
|
||||
for (var tile : row) {
|
||||
if (tile != null) {
|
||||
shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, tile.getModelMatrix());
|
||||
tile.render(window, shaderManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
48
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/Direction.java
Executable file → Normal file
48
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/Direction.java
Executable file → Normal file
@@ -1,24 +1,24 @@
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum Direction {
|
||||
UP(new Vector2i(0, -1)),
|
||||
DOWN(new Vector2i(0, 1)),
|
||||
LEFT(new Vector2i(-1, 0)),
|
||||
RIGHT(new Vector2i(1, 0));
|
||||
|
||||
private final Vector2i vector;
|
||||
|
||||
public Vector2i asIntVector() {
|
||||
return new Vector2i(vector);
|
||||
}
|
||||
|
||||
public Vector2f asFloatVector() {
|
||||
return new Vector2f(vector);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum Direction {
|
||||
UP(new Vector2i(0, -1)),
|
||||
DOWN(new Vector2i(0, 1)),
|
||||
LEFT(new Vector2i(-1, 0)),
|
||||
RIGHT(new Vector2i(1, 0));
|
||||
|
||||
private final Vector2i vector;
|
||||
|
||||
public Vector2i asIntVector() {
|
||||
return new Vector2i(vector);
|
||||
}
|
||||
|
||||
public Vector2f asFloatVector() {
|
||||
return new Vector2f(vector);
|
||||
}
|
||||
}
|
||||
|
||||
162
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/MovableObject.java
Executable file → Normal file
162
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/MovableObject.java
Executable file → Normal file
@@ -1,81 +1,81 @@
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
import com.bartlomiejpluta.base.core.world.animation.AnimationableObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class MovableObject extends AnimationableObject implements Updatable {
|
||||
private final Vector2f coordinateStepSize;
|
||||
|
||||
private int moveTime = 0;
|
||||
private Vector2f movementVector;
|
||||
|
||||
@Getter
|
||||
private final Vector2i coordinates = new Vector2i(0, 0);
|
||||
|
||||
protected int framesToCrossOneTile = 1;
|
||||
|
||||
public boolean isMoving() {
|
||||
return movementVector != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
if(movementVector != null) {
|
||||
if(moveTime > 0) {
|
||||
--moveTime;
|
||||
movePosition(movementVector);
|
||||
} else {
|
||||
adjustCoordinates();
|
||||
setDefaultAnimationFrame();
|
||||
movementVector = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setDefaultAnimationFrame();
|
||||
|
||||
private void adjustCoordinates() {
|
||||
var position = new Vector2f(getPosition());
|
||||
setCoordinates(new Vector2i((int) (position.x / coordinateStepSize.x), (int) (position.y / coordinateStepSize.y)));
|
||||
}
|
||||
|
||||
public Movement prepareMovement(Direction direction) {
|
||||
return new Movement(this, direction);
|
||||
}
|
||||
|
||||
protected boolean move(Direction direction) {
|
||||
if (this.movementVector != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var speed = new Vector2f(coordinateStepSize).div(framesToCrossOneTile);
|
||||
movementVector = direction.asFloatVector().mul(speed);
|
||||
moveTime = framesToCrossOneTile;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public MovableObject setCoordinates(int x, int y) {
|
||||
coordinates.x = x;
|
||||
coordinates.y = y;
|
||||
setPosition((x + 0.5f) * coordinateStepSize.x, (y + 0.5f) * coordinateStepSize.y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MovableObject setCoordinates(Vector2i coordinates) {
|
||||
return setCoordinates(coordinates.x, coordinates.y);
|
||||
}
|
||||
|
||||
public MovableObject(Mesh mesh, Material material, Vector2f coordinateStepSize, Vector2i spriteSheetDimensions) {
|
||||
super(mesh, material, spriteSheetDimensions);
|
||||
this.coordinateStepSize = coordinateStepSize;
|
||||
setCoordinates(0, 0);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.logic.Updatable;
|
||||
import com.bartlomiejpluta.base.core.world.animation.AnimationableObject;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class MovableObject extends AnimationableObject implements Updatable {
|
||||
private final Vector2f coordinateStepSize;
|
||||
|
||||
private int moveTime = 0;
|
||||
private Vector2f movementVector;
|
||||
|
||||
@Getter
|
||||
private final Vector2i coordinates = new Vector2i(0, 0);
|
||||
|
||||
protected int framesToCrossOneTile = 1;
|
||||
|
||||
public boolean isMoving() {
|
||||
return movementVector != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(float dt) {
|
||||
if(movementVector != null) {
|
||||
if(moveTime > 0) {
|
||||
--moveTime;
|
||||
movePosition(movementVector);
|
||||
} else {
|
||||
adjustCoordinates();
|
||||
setDefaultAnimationFrame();
|
||||
movementVector = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void setDefaultAnimationFrame();
|
||||
|
||||
private void adjustCoordinates() {
|
||||
var position = new Vector2f(getPosition());
|
||||
setCoordinates(new Vector2i((int) (position.x / coordinateStepSize.x), (int) (position.y / coordinateStepSize.y)));
|
||||
}
|
||||
|
||||
public Movement prepareMovement(Direction direction) {
|
||||
return new Movement(this, direction);
|
||||
}
|
||||
|
||||
protected boolean move(Direction direction) {
|
||||
if (this.movementVector != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var speed = new Vector2f(coordinateStepSize).div(framesToCrossOneTile);
|
||||
movementVector = direction.asFloatVector().mul(speed);
|
||||
moveTime = framesToCrossOneTile;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public MovableObject setCoordinates(int x, int y) {
|
||||
coordinates.x = x;
|
||||
coordinates.y = y;
|
||||
setPosition((x + 0.5f) * coordinateStepSize.x, (y + 0.5f) * coordinateStepSize.y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MovableObject setCoordinates(Vector2i coordinates) {
|
||||
return setCoordinates(coordinates.x, coordinates.y);
|
||||
}
|
||||
|
||||
public MovableObject(Mesh mesh, Material material, Vector2f coordinateStepSize, Vector2i spriteSheetDimensions) {
|
||||
super(mesh, material, spriteSheetDimensions);
|
||||
this.coordinateStepSize = coordinateStepSize;
|
||||
setCoordinates(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
98
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/Movement.java
Executable file → Normal file
98
engine/src/main/java/com/bartlomiejpluta/base/core/world/movement/Movement.java
Executable file → Normal file
@@ -1,49 +1,49 @@
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class Movement {
|
||||
private final MovableObject object;
|
||||
private final Direction direction;
|
||||
private boolean performed = false;
|
||||
|
||||
public boolean perform() {
|
||||
performed = object.move(direction);
|
||||
return performed;
|
||||
}
|
||||
|
||||
public Vector2i getSourceCoordinate() {
|
||||
return new Vector2i(object.getCoordinates());
|
||||
}
|
||||
|
||||
public Vector2i getTargetCoordinate() {
|
||||
return direction.asIntVector().add(object.getCoordinates());
|
||||
}
|
||||
|
||||
public Movement getAnother() {
|
||||
return object.prepareMovement(direction);
|
||||
}
|
||||
}
|
||||
//@Data
|
||||
//public class Movement {
|
||||
// private final MovableObject object;
|
||||
// private final Direction direction;
|
||||
// private final Vector2i source;
|
||||
// private final Vector2i target;
|
||||
//
|
||||
// Movement(MovableObject object, Direction direction) {
|
||||
// this.object = object;
|
||||
// this.direction = direction;
|
||||
// this.source = new Vector2i(object.getCoordinates());
|
||||
// this.target = direction.asIntVector().add(source);
|
||||
// }
|
||||
//
|
||||
// public boolean perform() {
|
||||
// return object.move(direction);
|
||||
// }
|
||||
//}
|
||||
package com.bartlomiejpluta.base.core.world.movement;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||
public class Movement {
|
||||
private final MovableObject object;
|
||||
private final Direction direction;
|
||||
private boolean performed = false;
|
||||
|
||||
public boolean perform() {
|
||||
performed = object.move(direction);
|
||||
return performed;
|
||||
}
|
||||
|
||||
public Vector2i getSourceCoordinate() {
|
||||
return new Vector2i(object.getCoordinates());
|
||||
}
|
||||
|
||||
public Vector2i getTargetCoordinate() {
|
||||
return direction.asIntVector().add(object.getCoordinates());
|
||||
}
|
||||
|
||||
public Movement getAnother() {
|
||||
return object.prepareMovement(direction);
|
||||
}
|
||||
}
|
||||
//@Data
|
||||
//public class Movement {
|
||||
// private final MovableObject object;
|
||||
// private final Direction direction;
|
||||
// private final Vector2i source;
|
||||
// private final Vector2i target;
|
||||
//
|
||||
// Movement(MovableObject object, Direction direction) {
|
||||
// this.object = object;
|
||||
// this.direction = direction;
|
||||
// this.source = new Vector2i(object.getCoordinates());
|
||||
// this.target = direction.asIntVector().add(source);
|
||||
// }
|
||||
//
|
||||
// public boolean perform() {
|
||||
// return object.move(direction);
|
||||
// }
|
||||
//}
|
||||
|
||||
156
engine/src/main/java/com/bartlomiejpluta/base/core/world/object/PositionableObject.java
Executable file → Normal file
156
engine/src/main/java/com/bartlomiejpluta/base/core/world/object/PositionableObject.java
Executable file → Normal file
@@ -1,78 +1,78 @@
|
||||
package com.bartlomiejpluta.base.core.world.object;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
import static java.lang.Math.toRadians;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract class PositionableObject {
|
||||
private final Matrix4f modelMatrix = new Matrix4f();
|
||||
|
||||
@Getter
|
||||
protected final Vector2f position = new Vector2f(0, 0);
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float rotation;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float scaleX = 1.0f;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float scaleY = 1.0f;
|
||||
|
||||
public PositionableObject setPosition(float x, float y) {
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setPosition(Vector2f position) {
|
||||
this.position.x = position.x;
|
||||
this.position.y = position.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject movePosition(float x, float y) {
|
||||
position.x += x;
|
||||
position.y += y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject movePosition(Vector2f position) {
|
||||
this.position.x += position.x;
|
||||
this.position.y += position.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject moveRotation(float rotation) {
|
||||
this.rotation += rotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setScale(float scale) {
|
||||
this.scaleX = scale;
|
||||
this.scaleY = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setScale(float scaleX, float scaleY) {
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Matrix4f getModelMatrix() {
|
||||
return modelMatrix
|
||||
.identity()
|
||||
.translate(position.x, position.y, 0)
|
||||
.rotateZ((float) toRadians(-rotation))
|
||||
.scaleXY(scaleX, scaleY);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.object;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
|
||||
import static java.lang.Math.toRadians;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract class PositionableObject {
|
||||
private final Matrix4f modelMatrix = new Matrix4f();
|
||||
|
||||
@Getter
|
||||
protected final Vector2f position = new Vector2f(0, 0);
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float rotation;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float scaleX = 1.0f;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected float scaleY = 1.0f;
|
||||
|
||||
public PositionableObject setPosition(float x, float y) {
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setPosition(Vector2f position) {
|
||||
this.position.x = position.x;
|
||||
this.position.y = position.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject movePosition(float x, float y) {
|
||||
position.x += x;
|
||||
position.y += y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject movePosition(Vector2f position) {
|
||||
this.position.x += position.x;
|
||||
this.position.y += position.y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject moveRotation(float rotation) {
|
||||
this.rotation += rotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setScale(float scale) {
|
||||
this.scaleX = scale;
|
||||
this.scaleY = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PositionableObject setScale(float scaleX, float scaleY) {
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Matrix4f getModelMatrix() {
|
||||
return modelMatrix
|
||||
.identity()
|
||||
.translate(position.x, position.y, 0)
|
||||
.rotateZ((float) toRadians(-rotation))
|
||||
.scaleXY(scaleX, scaleY);
|
||||
}
|
||||
}
|
||||
|
||||
130
engine/src/main/java/com/bartlomiejpluta/base/core/world/object/RenderableObject.java
Executable file → Normal file
130
engine/src/main/java/com/bartlomiejpluta/base/core/world/object/RenderableObject.java
Executable file → Normal file
@@ -1,65 +1,65 @@
|
||||
package com.bartlomiejpluta.base.core.world.object;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class RenderableObject extends PositionableObject implements Renderable {
|
||||
private final Mesh mesh;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Material material;
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
material.activateTextureIfExists();
|
||||
|
||||
shaderManager.setUniform(UniformName.UNI_OBJECT_COLOR, material.getColor());
|
||||
shaderManager.setUniform(UniformName.UNI_HAS_OBJECT_TEXTURE, material.hasTexture());
|
||||
shaderManager.setUniform(UniformName.UNI_TEXTURE_SAMPLER, 0);
|
||||
shaderManager.setUniform(UniformName.UNI_SPRITE_SIZE, material.getSpriteSize());
|
||||
shaderManager.setUniform(UniformName.UNI_SPRITE_POSITION, material.getSpritePosition());
|
||||
|
||||
mesh.render(window, shaderManager);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
material.setAlpha(alpha);
|
||||
}
|
||||
|
||||
public void setColor(Vector4f color) {
|
||||
material.setColor(color);
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float alpha) {
|
||||
material.setColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public void setSpriteSize(Vector2f spriteSize) {
|
||||
material.setSpriteSize(spriteSize);
|
||||
}
|
||||
|
||||
public void setSpriteSize(float w, float h) {
|
||||
material.setSpriteSize(w, h);
|
||||
}
|
||||
|
||||
public void setSpritePosition(Vector2f spritePosition) {
|
||||
material.setSpritePosition(spritePosition);
|
||||
}
|
||||
|
||||
public void setSpritePosition(float x, float y) {
|
||||
material.setSpritePosition(x, y);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.object;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.gl.render.Renderable;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.constant.UniformName;
|
||||
import com.bartlomiejpluta.base.core.gl.shader.manager.ShaderManager;
|
||||
import com.bartlomiejpluta.base.core.ui.Window;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class RenderableObject extends PositionableObject implements Renderable {
|
||||
private final Mesh mesh;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private Material material;
|
||||
|
||||
@Override
|
||||
public void render(Window window, ShaderManager shaderManager) {
|
||||
material.activateTextureIfExists();
|
||||
|
||||
shaderManager.setUniform(UniformName.UNI_OBJECT_COLOR, material.getColor());
|
||||
shaderManager.setUniform(UniformName.UNI_HAS_OBJECT_TEXTURE, material.hasTexture());
|
||||
shaderManager.setUniform(UniformName.UNI_TEXTURE_SAMPLER, 0);
|
||||
shaderManager.setUniform(UniformName.UNI_SPRITE_SIZE, material.getSpriteSize());
|
||||
shaderManager.setUniform(UniformName.UNI_SPRITE_POSITION, material.getSpritePosition());
|
||||
|
||||
mesh.render(window, shaderManager);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
material.setAlpha(alpha);
|
||||
}
|
||||
|
||||
public void setColor(Vector4f color) {
|
||||
material.setColor(color);
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float alpha) {
|
||||
material.setColor(r, g, b, alpha);
|
||||
}
|
||||
|
||||
public void setSpriteSize(Vector2f spriteSize) {
|
||||
material.setSpriteSize(spriteSize);
|
||||
}
|
||||
|
||||
public void setSpriteSize(float w, float h) {
|
||||
material.setSpriteSize(w, h);
|
||||
}
|
||||
|
||||
public void setSpritePosition(Vector2f spritePosition) {
|
||||
material.setSpritePosition(spritePosition);
|
||||
}
|
||||
|
||||
public void setSpritePosition(float x, float y) {
|
||||
material.setSpritePosition(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
84
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/manager/DefaultTileSetManager.java
Executable file → Normal file
84
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/manager/DefaultTileSetManager.java
Executable file → Normal file
@@ -1,42 +1,42 @@
|
||||
package com.bartlomiejpluta.base.core.world.tileset.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
||||
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultTileSetManager implements TileSetManager {
|
||||
private final TextureManager textureManager;
|
||||
private final MeshManager meshManager;
|
||||
private final Map<String, TileSet> tileSets = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public TileSet createTileSet(String tileSetFileName, int rows, int columns) {
|
||||
var tileset = tileSets.get(tileSetFileName);
|
||||
|
||||
if(tileset == null) {
|
||||
log.info("Loading [{}] tileset to cache", tileSetFileName);
|
||||
var texture = textureManager.loadTexture(tileSetFileName);
|
||||
var tileWidth = texture.getWidth() / columns;
|
||||
var tileHeight = texture.getHeight() / rows;
|
||||
var mesh = meshManager.createQuad(tileWidth, tileHeight, 0, 0);
|
||||
tileset = new TileSet(mesh, texture, rows, columns, tileWidth, tileHeight);
|
||||
}
|
||||
|
||||
return tileset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.tileset.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.TextureManager;
|
||||
import com.bartlomiejpluta.base.core.util.mesh.MeshManager;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||
public class DefaultTileSetManager implements TileSetManager {
|
||||
private final TextureManager textureManager;
|
||||
private final MeshManager meshManager;
|
||||
private final Map<String, TileSet> tileSets = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public TileSet createTileSet(String tileSetFileName, int rows, int columns) {
|
||||
var tileset = tileSets.get(tileSetFileName);
|
||||
|
||||
if(tileset == null) {
|
||||
log.info("Loading [{}] tileset to cache", tileSetFileName);
|
||||
var texture = textureManager.loadTexture(tileSetFileName);
|
||||
var tileWidth = texture.getWidth() / columns;
|
||||
var tileHeight = texture.getHeight() / rows;
|
||||
var mesh = meshManager.createQuad(tileWidth, tileHeight, 0, 0);
|
||||
tileset = new TileSet(mesh, texture, rows, columns, tileWidth, tileHeight);
|
||||
}
|
||||
|
||||
return tileset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUp() {
|
||||
log.info("There is nothing to clean up here");
|
||||
}
|
||||
}
|
||||
|
||||
16
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/manager/TileSetManager.java
Executable file → Normal file
16
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/manager/TileSetManager.java
Executable file → Normal file
@@ -1,8 +1,8 @@
|
||||
package com.bartlomiejpluta.base.core.world.tileset.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
|
||||
public interface TileSetManager extends Cleanable {
|
||||
TileSet createTileSet(String tileSetFileName, int rows, int columns);
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.tileset.manager;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gc.Cleanable;
|
||||
import com.bartlomiejpluta.base.core.world.tileset.model.TileSet;
|
||||
|
||||
public interface TileSetManager extends Cleanable {
|
||||
TileSet createTileSet(String tileSetFileName, int rows, int columns);
|
||||
}
|
||||
|
||||
38
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/model/Tile.java
Executable file → Normal file
38
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/model/Tile.java
Executable file → Normal file
@@ -1,19 +1,19 @@
|
||||
package com.bartlomiejpluta.base.core.world.tileset.model;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Tile extends RenderableObject {
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
Tile(Mesh mesh, Material material, int width, int height) {
|
||||
super(mesh);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
setMaterial(material);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.tileset.model;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.world.object.RenderableObject;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Tile extends RenderableObject {
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
Tile(Mesh mesh, Material material, int width, int height) {
|
||||
super(mesh);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
setMaterial(material);
|
||||
}
|
||||
}
|
||||
|
||||
78
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/model/TileSet.java
Executable file → Normal file
78
engine/src/main/java/com/bartlomiejpluta/base/core/world/tileset/model/TileSet.java
Executable file → Normal file
@@ -1,39 +1,39 @@
|
||||
package com.bartlomiejpluta.base.core.world.tileset.model;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.Texture;
|
||||
import lombok.Getter;
|
||||
|
||||
public class TileSet {
|
||||
private final Texture texture;
|
||||
private final int rows;
|
||||
private final int columns;
|
||||
private final float columnStep;
|
||||
private final float rowStep;
|
||||
private final Mesh mesh;
|
||||
|
||||
@Getter
|
||||
private final int tileWidth;
|
||||
|
||||
@Getter
|
||||
private final int tileHeight;
|
||||
|
||||
public TileSet(Mesh mesh, Texture texture, int rows, int columns, int tileWidth, int tileHeight) {
|
||||
this.texture = texture;
|
||||
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;
|
||||
}
|
||||
|
||||
public Tile getTile(int row, int column) {
|
||||
var material = Material.textured(texture);
|
||||
material.setSpriteSize(columnStep, rowStep);
|
||||
material.setSpritePosition(column * columnStep, row * rowStep);
|
||||
return new Tile(mesh, material, tileWidth, tileHeight);
|
||||
}
|
||||
}
|
||||
package com.bartlomiejpluta.base.core.world.tileset.model;
|
||||
|
||||
import com.bartlomiejpluta.base.core.gl.object.material.Material;
|
||||
import com.bartlomiejpluta.base.core.gl.object.mesh.Mesh;
|
||||
import com.bartlomiejpluta.base.core.gl.object.texture.Texture;
|
||||
import lombok.Getter;
|
||||
|
||||
public class TileSet {
|
||||
private final Texture texture;
|
||||
private final int rows;
|
||||
private final int columns;
|
||||
private final float columnStep;
|
||||
private final float rowStep;
|
||||
private final Mesh mesh;
|
||||
|
||||
@Getter
|
||||
private final int tileWidth;
|
||||
|
||||
@Getter
|
||||
private final int tileHeight;
|
||||
|
||||
public TileSet(Mesh mesh, Texture texture, int rows, int columns, int tileWidth, int tileHeight) {
|
||||
this.texture = texture;
|
||||
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;
|
||||
}
|
||||
|
||||
public Tile getTile(int row, int column) {
|
||||
var material = Material.textured(texture);
|
||||
material.setSpriteSize(columnStep, rowStep);
|
||||
material.setSpritePosition(column * columnStep, row * rowStep);
|
||||
return new Tile(mesh, material, tileWidth, tileHeight);
|
||||
}
|
||||
}
|
||||
|
||||
44
engine/src/main/resources/shaders/default.fs
Executable file → Normal file
44
engine/src/main/resources/shaders/default.fs
Executable file → Normal file
@@ -1,23 +1,23 @@
|
||||
#version 330
|
||||
|
||||
uniform vec4 objectColor;
|
||||
uniform int hasTexture;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec2 spriteSize;
|
||||
uniform vec2 spritePosition;
|
||||
|
||||
in vec2 fragmentTexCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
if(hasTexture == 1)
|
||||
{
|
||||
fragColor = objectColor * texture(sampler, fragmentTexCoord * spriteSize + spritePosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
fragColor = objectColor;
|
||||
}
|
||||
#version 330
|
||||
|
||||
uniform vec4 objectColor;
|
||||
uniform int hasTexture;
|
||||
uniform sampler2D sampler;
|
||||
uniform vec2 spriteSize;
|
||||
uniform vec2 spritePosition;
|
||||
|
||||
in vec2 fragmentTexCoord;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
if(hasTexture == 1)
|
||||
{
|
||||
fragColor = objectColor * texture(sampler, fragmentTexCoord * spriteSize + spritePosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
fragColor = objectColor;
|
||||
}
|
||||
}
|
||||
30
engine/src/main/resources/shaders/default.vs
Executable file → Normal file
30
engine/src/main/resources/shaders/default.vs
Executable file → Normal file
@@ -1,16 +1,16 @@
|
||||
#version 330
|
||||
|
||||
uniform mat4 modelMatrix;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
layout(location=0) in vec2 position;
|
||||
layout(location=1) in vec2 texCoord;
|
||||
|
||||
out vec2 fragmentTexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 0.0, 1.0);
|
||||
fragmentTexCoord = texCoord;
|
||||
#version 330
|
||||
|
||||
uniform mat4 modelMatrix;
|
||||
uniform mat4 viewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
layout(location=0) in vec2 position;
|
||||
layout(location=1) in vec2 texCoord;
|
||||
|
||||
out vec2 fragmentTexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 0.0, 1.0);
|
||||
fragmentTexCoord = texCoord;
|
||||
}
|
||||
Reference in New Issue
Block a user