From e1ea66ccb39f8eaafecd624ac1f88046ab50d05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Tue, 7 Nov 2023 16:51:44 +0100 Subject: [PATCH] Create working lighting system --- .../base/api/context/Context.java | 3 + .../bartlomiejpluta/base/api/light/Light.java | 56 +++++ .../base/api/map/layer/base/Layer.java | 11 + .../base/api/map/model/GameMap.java | 12 + .../base/internal/render/ShaderManager.java | 10 + .../base/lib/light/LightDelegate.java | 233 ++++++++++++++++++ .../engine/context/model/DefaultContext.java | 7 + .../core/gl/render/DefaultRenderer.java | 33 ++- .../core/gl/shader/constant/CounterName.java | 5 + .../gl/shader/constant/RenderConstants.java | 5 + .../core/gl/shader/constant/UniformName.java | 4 + .../shader/manager/DefaultShaderManager.java | 41 +++ .../base/engine/world/light/DefaultLight.java | 61 +++++ .../world/map/layer/base/BaseLayer.java | 38 +++ .../world/map/model/DefaultGameMap.java | 19 ++ .../base/engine/world/object/Sprite.java | 1 + engine/src/main/resources/shaders/default.fs | 28 ++- engine/src/main/resources/shaders/default.vs | 3 + 18 files changed, 555 insertions(+), 15 deletions(-) create mode 100644 api/src/main/java/com/bartlomiejpluta/base/api/light/Light.java create mode 100644 api/src/main/java/com/bartlomiejpluta/base/lib/light/LightDelegate.java create mode 100644 engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/shader/constant/CounterName.java create mode 100644 engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/shader/constant/RenderConstants.java create mode 100644 engine/src/main/java/com/bartlomiejpluta/base/engine/world/light/DefaultLight.java diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java b/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java index 7512524f..df88b3f0 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/context/Context.java @@ -11,6 +11,7 @@ import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.input.Input; +import com.bartlomiejpluta.base.api.light.Light; import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.runner.GameRunner; import com.bartlomiejpluta.base.api.screen.Screen; @@ -47,6 +48,8 @@ public interface Context extends Updatable, Renderable, Disposable { Entity createAbstractEntity(); + Light createLight(); + Icon createIcon(String iconSetUid, int row, int column); Image getImage(String imageUid); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/light/Light.java b/api/src/main/java/com/bartlomiejpluta/base/api/light/Light.java new file mode 100644 index 00000000..a4d45d1a --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/light/Light.java @@ -0,0 +1,56 @@ +package com.bartlomiejpluta.base.api.light; + +import com.bartlomiejpluta.base.api.location.Locationable; +import com.bartlomiejpluta.base.internal.logic.Updatable; +import com.bartlomiejpluta.base.internal.render.Renderable; +import org.joml.Vector3fc; + +public interface Light extends Locationable, Updatable, Renderable { + boolean isLuminescent(); + + void setLuminescent(boolean luminescent); + + default void enableLuminescent() { + setLuminescent(true); + } + + default void disableLuminescent() { + setLuminescent(false); + } + + default void toggleLuminescent() { + setLuminescent(!isLuminescent()); + } + + Vector3fc getIntensity(); + + default void setIntensity(Vector3fc intensity) { + setIntensity(intensity.x(), intensity.y(), intensity.z()); + } + + void setIntensity(float red, float green, float blue); + + float getConstantAttenuation(); + + float getLinearAttenuation(); + + float getQuadraticAttenuation(); + + void setConstantAttenuation(float attenuation); + + void setLinearAttenuation(float attenuation); + + void setQuadraticAttenuation(float attenuation); + + default void setAttenuation(float constant, float linear, float quadratic) { + setConstantAttenuation(constant); + setLinearAttenuation(linear); + setQuadraticAttenuation(quadratic); + } + + default void setAttenuation(Vector3fc attenuation) { + setConstantAttenuation(attenuation.x()); + setLinearAttenuation(attenuation.y()); + setQuadraticAttenuation(attenuation.z()); + } +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/base/Layer.java b/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/base/Layer.java index bb9fac91..d33547e8 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/base/Layer.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/map/layer/base/Layer.java @@ -2,12 +2,23 @@ package com.bartlomiejpluta.base.api.map.layer.base; import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.event.Reactive; +import com.bartlomiejpluta.base.api.light.Light; import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.internal.logic.Updatable; import com.bartlomiejpluta.base.internal.render.Renderable; +import java.util.List; + public interface Layer extends Renderable, Updatable, Reactive { GameMap getMap(); void pushAnimation(Animation animation); + + void addLight(Light light); + + void removeLight(Light light); + + void clearLights(); + + List getLights(); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/map/model/GameMap.java b/api/src/main/java/com/bartlomiejpluta/base/api/map/model/GameMap.java index 6357ee5c..19dddeb6 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/map/model/GameMap.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/map/model/GameMap.java @@ -1,11 +1,13 @@ package com.bartlomiejpluta.base.api.map.model; import com.bartlomiejpluta.base.api.event.Reactive; +import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.map.layer.color.ColorLayer; import com.bartlomiejpluta.base.api.map.layer.image.ImageLayer; import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.layer.tile.TileLayer; import org.joml.Vector2fc; +import org.joml.Vector3fc; public interface GameMap extends Reactive { float getWidth(); @@ -20,6 +22,8 @@ public interface GameMap extends Reactive { Vector2fc getStepSize(); + Layer getLayer(int layerIndex); + TileLayer getTileLayer(int layerIndex); ImageLayer getImageLayer(int layerIndex); @@ -27,4 +31,12 @@ public interface GameMap extends Reactive { ColorLayer getColorLayer(int layerIndex); ObjectLayer getObjectLayer(int layerIndex); + + Vector3fc getAmbientColor(); + + default void setAmbientColor(Vector3fc color) { + setAmbientColor(color.x(), color.y(), color.z()); + } + + void setAmbientColor(float red, float green, float blue); } diff --git a/api/src/main/java/com/bartlomiejpluta/base/internal/render/ShaderManager.java b/api/src/main/java/com/bartlomiejpluta/base/internal/render/ShaderManager.java index 1a7cdaac..ad00dede 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/internal/render/ShaderManager.java +++ b/api/src/main/java/com/bartlomiejpluta/base/internal/render/ShaderManager.java @@ -41,4 +41,14 @@ public interface ShaderManager extends Cleanable { ShaderManager setUniform(String uniformName, int index, Uniform uniform); ShaderManager setUniforms(String uniformName, Uniform[] uniforms); + + ShaderManager createCounter(String counterName); + + int nextNumber(String counterName); + + int topNumber(String counterName); + + ShaderManager setUniformCounter(String uniformName, String counterName); + + ShaderManager resetCounters(); } \ No newline at end of file diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/light/LightDelegate.java b/api/src/main/java/com/bartlomiejpluta/base/lib/light/LightDelegate.java new file mode 100644 index 00000000..90006aa7 --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/light/LightDelegate.java @@ -0,0 +1,233 @@ +package com.bartlomiejpluta.base.lib.light; + +import com.bartlomiejpluta.base.api.camera.Camera; +import com.bartlomiejpluta.base.api.light.Light; +import com.bartlomiejpluta.base.api.location.Locationable; +import com.bartlomiejpluta.base.api.move.Direction; +import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.internal.object.Placeable; +import com.bartlomiejpluta.base.internal.render.ShaderManager; +import lombok.NonNull; +import org.joml.Matrix4fc; +import org.joml.Vector2fc; +import org.joml.Vector2ic; +import org.joml.Vector3fc; + +public class LightDelegate implements Light { + protected final Light light; + + protected LightDelegate(@NonNull Light light) { + this.light = light; + } + + @Override + public void setStepSize(float x, float y) { + light.setStepSize(x, y); + } + + @Override + public Vector2ic getCoordinates() { + return light.getCoordinates(); + } + + @Override + public void setCoordinates(Vector2ic coordinates) { + light.setCoordinates(coordinates); + } + + @Override + public void setCoordinates(int x, int y) { + light.setCoordinates(x, y); + } + + @Override + public Vector2fc getPositionOffset() { + return light.getPositionOffset(); + } + + @Override + public void setPositionOffset(Vector2fc offset) { + light.setPositionOffset(offset); + } + + @Override + public void setPositionOffset(float offsetX, float offsetY) { + light.setPositionOffset(offsetX, offsetY); + } + + @Override + public int chebyshevDistance(Locationable other) { + return light.chebyshevDistance(other); + } + + @Override + public int manhattanDistance(Locationable other) { + return light.manhattanDistance(other); + } + + @Override + public double euclideanDistance(Locationable other) { + return light.euclideanDistance(other); + } + + @Override + public Direction getDirectionTowards(Locationable target) { + return light.getDirectionTowards(target); + } + + @Override + public Vector2fc getPosition() { + return light.getPosition(); + } + + @Override + public void setPosition(Vector2fc position) { + light.setPosition(position); + } + + @Override + public void setPosition(float x, float y) { + light.setPosition(x, y); + } + + @Override + public void movePosition(float x, float y) { + light.movePosition(x, y); + } + + @Override + public void movePosition(Vector2fc position) { + light.movePosition(position); + } + + @Override + public float getRotation() { + return light.getRotation(); + } + + @Override + public void setRotation(float rotation) { + light.setRotation(rotation); + } + + @Override + public void moveRotation(float rotation) { + light.moveRotation(rotation); + } + + @Override + public float getScaleX() { + return light.getScaleX(); + } + + @Override + public void setScaleX(float scale) { + light.setScaleX(scale); + } + + @Override + public float getScaleY() { + return light.getScaleY(); + } + + @Override + public void setScaleY(float scale) { + light.setScaleY(scale); + } + + @Override + public void setScale(float scale) { + light.setScale(scale); + } + + @Override + public void setScale(float scaleX, float scaleY) { + light.setScale(scaleX, scaleY); + } + + @Override + public float euclideanDistance(Placeable other) { + return light.euclideanDistance(other); + } + + @Override + public double euclideanDistance(Vector2ic coordinates) { + return light.euclideanDistance(coordinates); + } + + @Override + public int chebyshevDistance(Vector2ic coordinates) { + return light.chebyshevDistance(coordinates); + } + + @Override + public int manhattanDistance(Vector2ic coordinates) { + return light.manhattanDistance(coordinates); + } + + @Override + public Matrix4fc getModelMatrix() { + return light.getModelMatrix(); + } + + @Override + public boolean isLuminescent() { + return light.isLuminescent(); + } + + @Override + public void setLuminescent(boolean luminescent) { + light.setLuminescent(luminescent); + } + + + @Override + public Vector3fc getIntensity() { + return light.getIntensity(); + } + + @Override + public void setIntensity(float red, float green, float blue) { + light.setIntensity(red, green, blue); + } + + @Override + public float getConstantAttenuation() { + return light.getConstantAttenuation(); + } + + @Override + public float getLinearAttenuation() { + return light.getLinearAttenuation(); + } + + @Override + public float getQuadraticAttenuation() { + return light.getQuadraticAttenuation(); + } + + @Override + public void setConstantAttenuation(float attenuation) { + light.setConstantAttenuation(attenuation); + } + + @Override + public void setLinearAttenuation(float attenuation) { + light.setLinearAttenuation(attenuation); + } + + @Override + public void setQuadraticAttenuation(float attenuation) { + light.setQuadraticAttenuation(attenuation); + } + + @Override + public void update(float dt) { + light.update(dt); + } + + @Override + public void render(Screen screen, Camera camera, ShaderManager shaderManager) { + light.render(screen, camera, shaderManager); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java index f202ccf8..440c4bd3 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/context/model/DefaultContext.java @@ -13,6 +13,7 @@ import com.bartlomiejpluta.base.api.gui.GUI; import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.image.Image; import com.bartlomiejpluta.base.api.input.Input; +import com.bartlomiejpluta.base.api.light.Light; import com.bartlomiejpluta.base.api.map.handler.MapHandler; import com.bartlomiejpluta.base.api.runner.GameRunner; import com.bartlomiejpluta.base.api.screen.Screen; @@ -29,6 +30,7 @@ import com.bartlomiejpluta.base.engine.world.entity.AbstractEntity; import com.bartlomiejpluta.base.engine.world.icon.manager.IconManager; import com.bartlomiejpluta.base.engine.world.icon.manager.IconSetManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; +import com.bartlomiejpluta.base.engine.world.light.DefaultLight; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap; import com.bartlomiejpluta.base.internal.render.ShaderManager; @@ -171,6 +173,11 @@ public class DefaultContext implements Context { return new AbstractEntity(); } + @Override + public Light createLight() { + return new DefaultLight(); + } + @Override public Icon createIcon(@NonNull String iconSetUid, int row, int column) { return iconManager.createIcon(iconSetUid, row, column); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/render/DefaultRenderer.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/render/DefaultRenderer.java index f1f891b5..4a8ef674 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/render/DefaultRenderer.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/render/DefaultRenderer.java @@ -2,6 +2,8 @@ package com.bartlomiejpluta.base.engine.core.gl.render; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.CounterName; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.RenderConstants; import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.ShaderManager; @@ -22,15 +24,27 @@ public class DefaultRenderer implements Renderer { public void init() { log.info("Initializing renderer"); shaderManager - .createShader("default", "/shaders/default.vs", "/shaders/default.fs") - .selectShader("default") - .createUniform(UniformName.UNI_VIEW_MODEL_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); + .createShader("default", "/shaders/default.vs", "/shaders/default.fs") + .selectShader("default") + .createUniform(UniformName.UNI_VIEW_MODEL_MATRIX) + .createUniform(UniformName.UNI_MODEL_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) + .createUniform(UniformName.UNI_AMBIENT) + .createUniform(UniformName.UNI_ACTIVE_LIGHTS) + .createCounter(CounterName.LIGHT); + + for(int i=0; i shaders = new HashMap<>(); + private final Map counters = new HashMap<>(); private ShaderProgram current; @Override @@ -142,6 +147,42 @@ public class DefaultShaderManager implements ShaderManager { return this; } + @Override + public ShaderManager createCounter(String counterName) { + if (counters.containsKey(counterName)) { + throw new AppException(format("The [%s] counter already exists", counterName)); + } + + log.info("Creating {} uniform counter", counterName); + counters.put(counterName, new AtomicInteger(0)); + return this; + } + + @Override + public int nextNumber(String counterName) { + return counters.get(counterName).getAndIncrement(); + } + + @Override + public int topNumber(String counterName) { + return counters.get(counterName).get(); + } + + @Override + public ShaderManager setUniformCounter(String uniformName, String counterName) { + setUniform(uniformName, counters.get(counterName).get()); + return this; + } + + @Override + public ShaderManager resetCounters() { + for(var counter : counters.values()) { + counter.set(0); + } + + return this; + } + @Override public void cleanUp() { log.info("Disposing shaders"); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/light/DefaultLight.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/light/DefaultLight.java new file mode 100644 index 00000000..faaba2dd --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/light/DefaultLight.java @@ -0,0 +1,61 @@ +package com.bartlomiejpluta.base.engine.world.light; + +import com.bartlomiejpluta.base.api.camera.Camera; +import com.bartlomiejpluta.base.api.light.Light; +import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.CounterName; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; +import com.bartlomiejpluta.base.engine.world.location.LocationableModel; +import com.bartlomiejpluta.base.internal.render.ShaderManager; +import lombok.Getter; +import lombok.Setter; +import org.joml.Vector2f; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +public class DefaultLight extends LocationableModel implements Light { + private final Vector3f intensity = new Vector3f(1f, 1f, 1f); + + @Getter + @Setter + private boolean luminescent; + + @Getter + @Setter + private float constantAttenuation = 1f; + + @Getter + @Setter + private float linearAttenuation = 0f; + + @Getter + @Setter + private float quadraticAttenuation = 1f; + + @Override + public Vector3fc getIntensity() { + return intensity; + } + + @Override + public void setIntensity(float red, float green, float blue) { + this.intensity.x = red; + this.intensity.y = green; + this.intensity.z = blue; + } + + @Override + public void update(float dt) { + // noop + } + + @Override + public void render(Screen screen, Camera camera, ShaderManager shaderManager) { + var lightNumber = shaderManager.nextNumber(CounterName.LIGHT); + shaderManager.setUniform(UniformName.UNI_LIGHTS + "[" + lightNumber + "].position", position); + shaderManager.setUniform(UniformName.UNI_LIGHTS + "[" + lightNumber + "].intensity", intensity); + shaderManager.setUniform(UniformName.UNI_LIGHTS + "[" + lightNumber + "].constantAttenuation", constantAttenuation); + shaderManager.setUniform(UniformName.UNI_LIGHTS + "[" + lightNumber + "].linearAttenuation", linearAttenuation); + shaderManager.setUniform(UniformName.UNI_LIGHTS + "[" + lightNumber + "].quadraticAttenuation", quadraticAttenuation); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/base/BaseLayer.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/base/BaseLayer.java index 52f402f3..e1041715 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/base/BaseLayer.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/layer/base/BaseLayer.java @@ -3,11 +3,15 @@ package com.bartlomiejpluta.base.engine.world.map.layer.base; import com.bartlomiejpluta.base.api.animation.Animation; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.event.Event; +import com.bartlomiejpluta.base.api.light.Light; import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.CounterName; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.internal.logic.Updatable; import com.bartlomiejpluta.base.internal.render.ShaderManager; +import lombok.Getter; import lombok.NonNull; import org.joml.Vector2fc; @@ -23,6 +27,9 @@ public abstract class BaseLayer implements Layer, Updatable { protected final ArrayList animations = new ArrayList<>(); + @Getter + protected final ArrayList lights = new ArrayList<>(); + public BaseLayer(@NonNull GameMap map) { this.map = map; this.stepSize = map.getStepSize(); @@ -40,6 +47,26 @@ public abstract class BaseLayer implements Layer, Updatable { return map; } + @Override + public void addLight(Light light) { + lights.add(light); + light.setStepSize(stepSize.x(), stepSize.y()); + } + + @Override + public void removeLight(Light light) { + // Disclaimer + // This is a workaround for concurrent modification exception + // which is thrown when entity is tried to be removed + // in the body of for-each-entity loop + lights.remove(lights.indexOf(light)); + } + + @Override + public void clearLights() { + lights.clear(); + } + @Override public void update(float dt) { @@ -58,6 +85,11 @@ public abstract class BaseLayer implements Layer, Updatable { animation.onFinish(this); } } + + // Disclaimer as above for lights + for (int i = 0; i < lights.size(); ++i) { + lights.get(i).update(dt); + } } @Override @@ -65,6 +97,12 @@ public abstract class BaseLayer implements Layer, Updatable { for (var animation : animations) { animation.render(screen, camera, shaderManager); } + + for (var light : lights) { + light.render(screen, camera, shaderManager); + } + + shaderManager.setUniformCounter(UniformName.UNI_ACTIVE_LIGHTS, CounterName.LIGHT); } @Override diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/model/DefaultGameMap.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/model/DefaultGameMap.java index 25261173..1916678d 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/model/DefaultGameMap.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/map/model/DefaultGameMap.java @@ -12,6 +12,7 @@ import com.bartlomiejpluta.base.api.map.layer.object.PassageAbility; import com.bartlomiejpluta.base.api.map.layer.tile.TileLayer; import com.bartlomiejpluta.base.api.map.model.GameMap; import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.engine.util.mesh.MeshManager; import com.bartlomiejpluta.base.engine.world.autotile.model.AutoTileSet; import com.bartlomiejpluta.base.engine.world.map.layer.autotile.DefaultAutoTileLayer; @@ -27,6 +28,7 @@ import lombok.Getter; import lombok.NonNull; import org.joml.Vector2f; import org.joml.Vector2fc; +import org.joml.Vector3f; import java.util.ArrayList; import java.util.Arrays; @@ -58,6 +60,9 @@ public class DefaultGameMap implements Renderable, Updatable, GameMap { @Getter private final String handler; + @Getter + private final Vector3f ambientColor = new Vector3f(1, 1, 1); + public DefaultGameMap(int tileWidth, int tileHeight, int rows, int columns, String handler) { this.rows = rows; this.columns = columns; @@ -77,11 +82,18 @@ public class DefaultGameMap implements Renderable, Updatable, GameMap { @Override public void render(Screen screen, Camera camera, ShaderManager shaderManager) { + shaderManager.setUniform(UniformName.UNI_AMBIENT, ambientColor); + for (var layer : layers) { layer.render(screen, camera, shaderManager); } } + @Override + public Layer getLayer(int layerIndex) { + return layers.get(layerIndex); + } + @Override public TileLayer getTileLayer(int layerIndex) { return (TileLayer) layers.get(layerIndex); @@ -113,6 +125,13 @@ public class DefaultGameMap implements Renderable, Updatable, GameMap { } } + @Override + public void setAmbientColor(float red, float green, float blue) { + this.ambientColor.x = red; + this.ambientColor.y = green; + this.ambientColor.z = blue; + } + public TileLayer createTileLayer(@NonNull TileSet tileSet) { var layer = new DefaultTileLayer(this, tileSet, rows, columns); layers.add(layer); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/object/Sprite.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/object/Sprite.java index 58d35d3f..27d037e2 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/object/Sprite.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/object/Sprite.java @@ -38,6 +38,7 @@ public abstract class Sprite extends LocationableModel implements Renderable { } shaderManager.setUniform(UniformName.UNI_VIEW_MODEL_MATRIX, camera.computeViewModelMatrix(getModelMatrix())); + shaderManager.setUniform(UniformName.UNI_MODEL_MATRIX, getModelMatrix()); material.render(screen, camera, shaderManager); mesh.render(screen, camera, shaderManager); } diff --git a/engine/src/main/resources/shaders/default.fs b/engine/src/main/resources/shaders/default.fs index 0f807b33..e81250b4 100644 --- a/engine/src/main/resources/shaders/default.fs +++ b/engine/src/main/resources/shaders/default.fs @@ -1,23 +1,39 @@ #version 330 +struct Light +{ + vec2 position; + vec3 intensity; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; +}; + uniform vec4 objectColor; uniform int hasTexture; uniform sampler2D sampler; uniform vec2 spriteSize; uniform vec2 spritePosition; +uniform vec3 ambient; +uniform Light lights[100]; +uniform int activeLights; +in vec2 objectPosition; in vec2 fragmentTexCoord; out vec4 fragColor; void main() { - if(hasTexture == 1) + vec4 color = hasTexture == 1 ? objectColor * texture(sampler, fragmentTexCoord * spriteSize + spritePosition) : objectColor; + vec4 total = vec4(color.rgb * ambient, color.a); + + for(int i=0; i