diff --git a/pom.xml b/pom.xml index 499eef3..bc10f7b 100644 --- a/pom.xml +++ b/pom.xml @@ -178,6 +178,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + \ No newline at end of file diff --git a/src/main/java/lemon/engine/event/Computable.java b/src/main/java/lemon/engine/async/Computable.java similarity index 98% rename from src/main/java/lemon/engine/event/Computable.java rename to src/main/java/lemon/engine/async/Computable.java index f0a8149..b1ef314 100644 --- a/src/main/java/lemon/engine/event/Computable.java +++ b/src/main/java/lemon/engine/async/Computable.java @@ -1,5 +1,6 @@ -package lemon.engine.event; +package lemon.engine.async; +import lemon.engine.event.OneTimeEventWith; import lemon.engine.toolbox.Lazy; import java.util.ArrayList; diff --git a/src/main/java/lemon/engine/draw/UnindexedDrawable.java b/src/main/java/lemon/engine/draw/UnindexedDrawable.java index 61afb46..9e22c81 100644 --- a/src/main/java/lemon/engine/draw/UnindexedDrawable.java +++ b/src/main/java/lemon/engine/draw/UnindexedDrawable.java @@ -27,7 +27,7 @@ public UnindexedDrawable(FloatData[][] vertices, int drawMode) { for (int i = 0; i < vertices.length; i++) { int dimensions = vertices[i][0].numDimensions(); GL20.glVertexAttribPointer(i, dimensions, GL11.GL_FLOAT, false, - stride * BYTES_PER_FLOAT, offset * BYTES_PER_FLOAT); + stride * Float.BYTES, offset * BYTES_PER_FLOAT); offset += dimensions; } }); diff --git a/src/main/java/lemon/engine/math/Triangle.java b/src/main/java/lemon/engine/math/Triangle.java index da8a1e3..d2a1d5a 100644 --- a/src/main/java/lemon/engine/math/Triangle.java +++ b/src/main/java/lemon/engine/math/Triangle.java @@ -5,6 +5,12 @@ public static Triangle of(Vector3D a, Vector3D b, Vector3D c) { return new ConstantTriangle(a, b, c); } + public static Triangle of(float ax, float ay, float az, + float bx, float by, float bz, + float cx, float cy, float cz) { + return of(Vector3D.of(ax, ay, az), Vector3D.of(bx, by, bz), Vector3D.of(cx, cy, cz)); + } + public record ConstantTriangle(Vector3D a, Vector3D b, Vector3D c, Vector3D normal, float area) implements Triangle { public ConstantTriangle(Vector3D a, Vector3D b, Vector3D c, DerivedTriangleData data) { diff --git a/src/main/java/lemon/evolution/Game.java b/src/main/java/lemon/evolution/Game.java index 5c49d1a..0aa219c 100644 --- a/src/main/java/lemon/evolution/Game.java +++ b/src/main/java/lemon/evolution/Game.java @@ -6,6 +6,8 @@ import lemon.engine.draw.CommonDrawables; import lemon.engine.draw.IndexedDrawable; import lemon.engine.draw.TextModel; +import lemon.evolution.fastspheres.FastSphere; +import lemon.evolution.fastspheres.FastSpheres; import lemon.futility.FObservable; import lemon.engine.font.CommonFonts; import lemon.engine.frameBuffer.FrameBuffer; @@ -100,6 +102,7 @@ public class Game implements Screen { private TaskQueue postLoadTasks = TaskQueue.ofConcurrent(); + private FastSpheres fastSpheres; private ParticleSystem particleSystem; private UIScreen uiScreen; @@ -375,12 +378,17 @@ public float getProgress() { }); }); + fastSpheres = disposables.add(new FastSpheres(1000000)); + var texture = disposables.add(new Texture(new TextureData(Toolbox.readImage("/res/particles/fire_01.png").orElseThrow(), true))); particleSystem = disposables.add(new ParticleSystem(100000, texture)); disposables.add(world.onExplosion((position, radius) -> particleSystem.addExplosionParticles(position, radius))); disposables.add(window.input().keyEvent().add(event -> { if (event.action() == GLFW.GLFW_RELEASE) { + if (event.key() == GLFW.GLFW_KEY_G) { + fastSpheres.spheres.add(new FastSphere(Vector3D.ofCopy(gameLoop.currentPlayer().position()), Color.GREEN)); + } if (event.key() == GLFW.GLFW_KEY_C) { world.entities().removeIf(x -> x instanceof PuzzleBall || x instanceof ExplodeOnHitProjectile || x instanceof StaticEntity); } @@ -557,6 +565,8 @@ public void render() { particleTime = System.nanoTime() - particleTime; benchmarker.getLineGraph("particleTime").add(particleTime); + fastSpheres.render(gameLoop.currentPlayer().position()); + GL11.glEnable(GL11.GL_DEPTH_TEST); for (var player : gameLoop.players()) { if (!player.alive().getValue()) { diff --git a/src/main/java/lemon/evolution/cmd/EvolutionOptions.java b/src/main/java/lemon/evolution/cmd/EvolutionOptions.java index 125a4bd..fa7c384 100644 --- a/src/main/java/lemon/evolution/cmd/EvolutionOptions.java +++ b/src/main/java/lemon/evolution/cmd/EvolutionOptions.java @@ -1,6 +1,6 @@ package lemon.evolution.cmd; public class EvolutionOptions { - public static final boolean ENABLE_MUSIC = true; + public static final boolean ENABLE_MUSIC = false; public static final boolean ENABLE_ESCAPE = true; } diff --git a/src/main/java/lemon/evolution/destructible/beta/TerrainChunk.java b/src/main/java/lemon/evolution/destructible/beta/TerrainChunk.java index f9be8c6..aaae450 100644 --- a/src/main/java/lemon/evolution/destructible/beta/TerrainChunk.java +++ b/src/main/java/lemon/evolution/destructible/beta/TerrainChunk.java @@ -3,7 +3,7 @@ import com.google.common.collect.ImmutableList; import lemon.engine.draw.DrawableData; import lemon.engine.draw.DynamicIndexedDrawable; -import lemon.engine.event.Computable; +import lemon.engine.async.Computable; import lemon.engine.math.FloatData; import lemon.engine.math.Matrix; import lemon.engine.math.MutableVector3D; diff --git a/src/main/java/lemon/evolution/fastspheres/FastSphere.java b/src/main/java/lemon/evolution/fastspheres/FastSphere.java new file mode 100644 index 0000000..f4d113f --- /dev/null +++ b/src/main/java/lemon/evolution/fastspheres/FastSphere.java @@ -0,0 +1,10 @@ +package lemon.evolution.fastspheres; + +import lemon.engine.math.*; +import lemon.engine.toolbox.Color; + +public record FastSphere(Vector3D position, float size, Color color) { + public FastSphere(Vector3D position, Color color) { + this(position, 1f, color); + } +} diff --git a/src/main/java/lemon/evolution/fastspheres/FastSpheres.java b/src/main/java/lemon/evolution/fastspheres/FastSpheres.java new file mode 100644 index 0000000..1f3bf62 --- /dev/null +++ b/src/main/java/lemon/evolution/fastspheres/FastSpheres.java @@ -0,0 +1,110 @@ +package lemon.evolution.fastspheres; + +import lemon.engine.math.Matrix; +import lemon.engine.math.Vector3D; +import lemon.engine.model.SphereModelBuilder; +import lemon.engine.render.MatrixType; +import lemon.engine.render.VertexArray; +import lemon.engine.render.VertexBuffer; +import lemon.engine.toolbox.Color; +import lemon.engine.toolbox.Disposable; +import lemon.evolution.util.CommonPrograms3D; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL31; +import org.lwjgl.opengl.GL33; + +import java.nio.FloatBuffer; +import java.util.*; + +public class FastSpheres implements Disposable { + private static final Vector3D[] VERTICES = SphereModelBuilder.of(1f, 5).build((indices, vertices) -> { + return Arrays.stream(indices).mapToObj(i -> vertices[i]).toArray(Vector3D[]::new); + }); + private static final float[] VERTICES_FLOATS; + static { + VERTICES_FLOATS = new float[VERTICES.length * 3]; + for (int i = 0; i < VERTICES.length; i++) { + VERTICES_FLOATS[i * 3] = VERTICES[i].x(); + VERTICES_FLOATS[i * 3 + 1] = VERTICES[i].y(); + VERTICES_FLOATS[i * 3 + 2] = VERTICES[i].z(); + } + } + private static final int FLOATS_PER_PARTICLE = 8; + private final VertexArray vertexArray; + private VertexBuffer vertexBuffer; + private final int maxSpheres; + public final List spheres = new ArrayList<>(); + + public FastSpheres(int maxSpheres) { + spheres.add(new FastSphere(Vector3D.ZERO, Color.BLUE)); // TODO + this.maxSpheres = maxSpheres; + vertexArray = new VertexArray(); + vertexArray.bind(vao -> { + new VertexBuffer().bind(GL15.GL_ARRAY_BUFFER, (target, vbo) -> { // Quad Vertices + GL15.glBufferData(target, VERTICES_FLOATS, GL15.GL_STATIC_DRAW); + GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 3 * 4, 0); + }); + vertexBuffer = new VertexBuffer(); + vertexBuffer.bind(GL15.GL_ARRAY_BUFFER, (target, vbo) -> { // Particle Center [x, y, z] + Size [w] + Color [r, g, b, a] + GL15.glBufferData(target, getInitialFloatBuffer(), GL15.GL_STREAM_DRAW); + GL20.glVertexAttribPointer(1, 4, GL11.GL_FLOAT, false, 8 * 4, 0); + GL20.glVertexAttribPointer(2, 4, GL11.GL_FLOAT, false, 8 * 4, 4 * 4); + }); + GL33.glVertexAttribDivisor(0, 0); + GL33.glVertexAttribDivisor(1, 1); + GL33.glVertexAttribDivisor(2, 1); + GL20.glEnableVertexAttribArray(0); + GL20.glEnableVertexAttribArray(1); + GL20.glEnableVertexAttribArray(2); + }); + } + + public FloatBuffer getInitialFloatBuffer() { + var numFloats = FLOATS_PER_PARTICLE * maxSpheres; + var buffer = BufferUtils.createFloatBuffer(numFloats); + for (int i = 0; i < numFloats; i++) { + buffer.put(0f); + } + buffer.flip(); + return buffer; + } + + public FloatBuffer getFloatBuffer() { + var buffer = BufferUtils.createFloatBuffer(FLOATS_PER_PARTICLE * spheres.size()); + for (var sphere : spheres) { + sphere.position().putInBuffer(buffer); + buffer.put(sphere.size()); // size + sphere.color().putInBuffer(buffer); + } + buffer.flip(); + return buffer; + } + + public void render(Vector3D viewPosition) { + // Update VBO + vertexBuffer.bind(GL15.GL_ARRAY_BUFFER, (target, vbo) -> { + GL15.glBufferSubData(target, 0, getFloatBuffer()); + }); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glEnable(GL11.GL_DEPTH_TEST); + CommonPrograms3D.FAST_SPHERES.use(program -> { + program.loadMatrix(MatrixType.MODEL_MATRIX, Matrix.IDENTITY_4); + program.loadVector("viewPos", viewPosition); + vertexArray.bind(vao -> { + GL31.glDrawArraysInstanced(GL11.GL_TRIANGLES, 0, VERTICES.length, spheres.size()); + }); + }); + GL11.glDisable(GL11.GL_DEPTH_TEST); + GL11.glDisable(GL11.GL_BLEND); + } + + @Override + public void dispose() { + vertexBuffer.dispose(); + vertexArray.dispose(); + } +} diff --git a/src/main/java/lemon/evolution/physics/beta/CollisionContext.java b/src/main/java/lemon/evolution/physics/beta/CollisionContext.java index 07936b7..baf4443 100644 --- a/src/main/java/lemon/evolution/physics/beta/CollisionContext.java +++ b/src/main/java/lemon/evolution/physics/beta/CollisionContext.java @@ -12,8 +12,9 @@ public interface CollisionContext { public void checkCollision(Vector3D position, Vector3D velocity, Consumer checker); + // TODO: Mutates force to something arbitrary when it's not supposed to public default void collideWithWorld(MutableVector3D position, MutableVector3D velocity, MutableVector3D force, - Vector3D scalar, float dt, BiConsumer onCollide, Supplier responder) { + Vector3D scalar, float dt, BiConsumer onCollide, CollisionResponse response) { var scalarSquared = scalar.multiply(scalar); var transformed = new MutableTriangle(); position.divide(scalar); @@ -28,7 +29,7 @@ public default void collideWithWorld(MutableVector3D position, MutableVector3D v return collision; }, position, velocity, force, dt, collision -> { onCollide.accept(collision.intersection().multiply(scalar), collision.negSlidePlaneNormal().multiply(scalar)); - return responder.get(); + return response; }); position.multiply(scalar); velocity.multiply(scalar); diff --git a/src/main/java/lemon/evolution/util/CommonPrograms3D.java b/src/main/java/lemon/evolution/util/CommonPrograms3D.java index 1135d9d..eadcb1f 100644 --- a/src/main/java/lemon/evolution/util/CommonPrograms3D.java +++ b/src/main/java/lemon/evolution/util/CommonPrograms3D.java @@ -85,7 +85,16 @@ public enum CommonPrograms3D implements ShaderProgramHolder { program.loadSampler("textureSampler", TextureBank.REUSE); }, new Shader(GL20.GL_VERTEX_SHADER, Toolbox.getFile("/shaders/textVertexShader").orElseThrow()), - new Shader(GL20.GL_FRAGMENT_SHADER, Toolbox.getFile("/shaders/textFragmentShader").orElseThrow())); + new Shader(GL20.GL_FRAGMENT_SHADER, Toolbox.getFile("/shaders/textFragmentShader").orElseThrow())), + FAST_SPHERES(names("position", "particleCenter", "particleColor"), program -> { + program.loadMatrix(MatrixType.MODEL_MATRIX, Matrix.IDENTITY_4); + program.loadMatrix(MatrixType.VIEW_MATRIX, Matrix.IDENTITY_4); + program.loadMatrix(MatrixType.PROJECTION_MATRIX, Matrix.IDENTITY_4); + program.loadVector("sunlightDirection", Vector3D.of(0f, 1f, 0f)); + program.loadVector("viewPos", Vector3D.ZERO); + }, + new Shader(GL20.GL_VERTEX_SHADER, Toolbox.getFile("/shaders/sphereVertexShader").orElseThrow()), + new Shader(GL20.GL_FRAGMENT_SHADER, Toolbox.getFile("/shaders/sphereFragmentShader").orElseThrow())); private ShaderProgram shaderProgram; private final String[] names; private final Consumer setDefaultUniformVariables; diff --git a/src/main/java/lemon/evolution/world/World.java b/src/main/java/lemon/evolution/world/World.java index 674f0d7..e9aeb4f 100644 --- a/src/main/java/lemon/evolution/world/World.java +++ b/src/main/java/lemon/evolution/world/World.java @@ -76,7 +76,7 @@ public void update(float dt) { entity.scalar(), dt, entity.onCollide()::callListeners, - entity::getCollisionResponse + entity.getCollisionResponse() ); entity.mutableForce().set(entity.getEnvironmentalForce()); }); diff --git a/src/main/resources/shaders/sphereFragmentShader b/src/main/resources/shaders/sphereFragmentShader new file mode 100644 index 0000000..26d9063 --- /dev/null +++ b/src/main/resources/shaders/sphereFragmentShader @@ -0,0 +1,26 @@ +#version 400 core + +in vec4 passColor; +in vec3 passNormal; +in vec3 fragPos; + +out vec4 outColor; + +uniform vec3 sunlightDirection; +uniform vec3 viewPos; + +void main(void) { + //outColor = passColor; + + vec3 lightColor = vec3(1, 1, 1); + float ambientStrength = 0.1; + vec3 ambient = ambientStrength * lightColor; + float diffuseStrength = max(dot(passNormal, sunlightDirection), 0); + vec3 diffuse = diffuseStrength * lightColor; + float specularStrength = 5; + vec3 viewDirection = normalize(viewPos - fragPos); + vec3 reflectDirection = reflect(-sunlightDirection, passNormal); + vec3 specular = specularStrength * pow(max(dot(viewDirection, reflectDirection), 0), 32) * lightColor; + vec3 result = (ambient + diffuse + specular) * passColor.rgb; + outColor = vec4(result, passColor.a); +} diff --git a/src/main/resources/shaders/sphereVertexShader b/src/main/resources/shaders/sphereVertexShader new file mode 100644 index 0000000..c8d1ae1 --- /dev/null +++ b/src/main/resources/shaders/sphereVertexShader @@ -0,0 +1,29 @@ +#version 400 core + +in vec3 position; +in vec4 particleCenter; +in vec4 particleColor; + +out vec4 passColor; +out vec3 passNormal; +out vec3 fragPos; + +uniform mat4 modelMatrix; +uniform mat4 viewMatrix; +uniform mat4 projectionMatrix; + +void main(void) { + //mat4 inverted = inverse(viewMatrix); + //vec3 cameraPositiveX = inverted[0].xyz; + //vec3 cameraPositiveY = inverted[1].xyz; + + //vec3 vertexPosition = particleCenter.a * (cameraPositiveX * position.x + cameraPositiveY * position.y); + vec3 vertexPosition = particleCenter.a * position.xyz; + + vec4 worldPosition = modelMatrix * vec4(vertexPosition + particleCenter.xyz, 1.0); + + gl_Position = projectionMatrix * viewMatrix * worldPosition; + passColor = particleColor; + passNormal = position; + fragPos = worldPosition.xyz; +}