diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/animation/Animation.java b/api/src/main/java/com/bartlomiejpluta/base/api/animation/Animation.java index 4bbf1a5e..d4859564 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/animation/Animation.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/animation/Animation.java @@ -1,5 +1,6 @@ package com.bartlomiejpluta.base.api.animation; +import com.bartlomiejpluta.base.api.color.Colorful; import com.bartlomiejpluta.base.api.map.layer.base.Layer; import com.bartlomiejpluta.base.api.move.Movable; import com.bartlomiejpluta.base.internal.program.Updatable; @@ -8,7 +9,7 @@ import com.bartlomiejpluta.base.util.path.Path; import java.util.concurrent.CompletableFuture; -public interface Animation extends Movable, Animated, Renderable, Updatable { +public interface Animation extends Movable, Animated, Colorful, Renderable, Updatable { Integer getRepeat(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/character/Character.java b/api/src/main/java/com/bartlomiejpluta/base/api/character/Character.java index dd82628c..5f599756 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/character/Character.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/character/Character.java @@ -1,6 +1,7 @@ package com.bartlomiejpluta.base.api.character; import com.bartlomiejpluta.base.api.animation.Animated; +import com.bartlomiejpluta.base.api.color.Colorful; import com.bartlomiejpluta.base.api.entity.Entity; import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Movable; @@ -26,10 +27,10 @@ import java.util.concurrent.CompletableFuture; * damaged box). * *
This interface combines movement capabilities ({@link Movable}), animation features - * ({@link Animated}), and entity properties ({@link Entity}) to create a complete + * ({@link Animated}), coloring capabilities ({@link Colorful}), and entity properties ({@link Entity}) to create a complete * character system for 2D games. */ -public interface Character extends Movable, Animated, Entity { +public interface Character extends Movable, Animated, Colorful, Entity { /** * Initiates movement in the specified direction. diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/color/Colorful.java b/api/src/main/java/com/bartlomiejpluta/base/api/color/Colorful.java new file mode 100644 index 00000000..117283dc --- /dev/null +++ b/api/src/main/java/com/bartlomiejpluta/base/api/color/Colorful.java @@ -0,0 +1,123 @@ +package com.bartlomiejpluta.base.api.color; + +import org.joml.Vector3fc; +import org.joml.Vector4fc; + +/** + * Interface for objects that can be colored and have their color properties modified. + * This interface provides a comprehensive API for managing RGBA color values using + * various input formats including JOML vectors, individual float components, and + * packed integer values. + * + *
Color components are expected to be in the range [0.0, 1.0] for float values, + * where 0.0 represents no intensity and 1.0 represents full intensity.
+ */ +public interface Colorful { + + /** + * Returns the current color of this object. + * + * @return a Vector4fc containing the RGBA color components, where: + * x = red, y = green, z = blue, w = alpha. + * All components are in the range [0.0, 1.0]. + */ + Vector4fc getColor(); + + /** + * Sets the color of this object using a 4D vector. + * + * @param color a Vector4fc containing the RGBA color components, where: + * x = red, y = green, z = blue, w = alpha. + * All components should be in the range [0.0, 1.0]. + * @throws NullPointerException if color is null + */ + void setColor(Vector4fc color); + + /** + * Sets the RGB color components of this object using a 3D vector. + * The alpha component will remain unchanged or be set to a default value. + * + * @param color a Vector3fc containing the RGB color components, where: + * x = red, y = green, z = blue. + * All components should be in the range [0.0, 1.0]. + * @throws NullPointerException if color is null + */ + void setColor(Vector3fc color); + + /** + * Sets the RGBA color components of this object using individual float values. + * + * @param red the red component in the range [0.0, 1.0] + * @param green the green component in the range [0.0, 1.0] + * @param blue the blue component in the range [0.0, 1.0] + * @param alpha the alpha component in the range [0.0, 1.0] + */ + void setColor(float red, float green, float blue, float alpha); + + /** + * Sets the RGB color components of this object using individual float values. + * The alpha component will remain unchanged or be set to a default value. + * + * @param red the red component in the range [0.0, 1.0] + * @param green the green component in the range [0.0, 1.0] + * @param blue the blue component in the range [0.0, 1.0] + */ + void setColor(float red, float green, float blue); + + /** + * Sets the color of this object using a packed RGBA integer value. + * The integer is expected to be in RGBA format where each component + * occupies 8 bits in the range [0, 255] and is automatically converted + * to the [0.0, 1.0] range by dividing by 255. + * + *The bit layout is as follows:
+ *For example, {@code 0xFF0000FF} represents full red with full alpha, + * while green and blue are zero.
+ * + * @param rgba the packed RGBA color value + */ + default void setColor(int rgba) { + setColor( + ((rgba >>> 24) & 0xFF) / 255f, + ((rgba >>> 16) & 0xFF) / 255f, + ((rgba >>> 8) & 0xFF) / 255f, + (rgba & 0xFF) / 255f + ); + } + + /** + * Sets only the red color component of this object. + * + * @param red the red component in the range [0.0, 1.0] + */ + void setRed(float red); + + /** + * Sets only the green color component of this object. + * + * @param green the green component in the range [0.0, 1.0] + */ + void setGreen(float green); + + /** + * Sets only the blue color component of this object. + * + * @param blue the blue component in the range [0.0, 1.0] + */ + void setBlue(float blue); + + /** + * Sets only the alpha (transparency) component of this object. + * + * @param alpha the alpha component in the range [0.0, 1.0], where + * 0.0 is fully transparent and 1.0 is fully opaque + */ + void setAlpha(float alpha); +} diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java b/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java index 094b56ce..21f6c5f0 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/icon/Icon.java @@ -1,8 +1,9 @@ package com.bartlomiejpluta.base.api.icon; +import com.bartlomiejpluta.base.api.color.Colorful; import com.bartlomiejpluta.base.api.entity.Entity; -public interface Icon extends Entity { +public interface Icon extends Colorful, Entity { void changeIcon(int row, int column); void changeIcon(String iconSetUid, int row, int column); diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/animation/AnimationDelegate.java b/api/src/main/java/com/bartlomiejpluta/base/lib/animation/AnimationDelegate.java index b351a4e3..a3a5d135 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/animation/AnimationDelegate.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/animation/AnimationDelegate.java @@ -11,9 +11,7 @@ import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.internal.object.Placeable; import com.bartlomiejpluta.base.internal.render.ShaderManager; import com.bartlomiejpluta.base.util.path.Path; -import org.joml.Matrix4fc; -import org.joml.Vector2fc; -import org.joml.Vector2ic; +import org.joml.*; import java.util.concurrent.CompletableFuture; @@ -294,6 +292,51 @@ public abstract class AnimationDelegate implements Animation { return animation.getLayer(); } + @Override + public Vector4fc getColor() { + return animation.getColor(); + } + + @Override + public void setColor(Vector4fc color) { + animation.setColor(color); + } + + @Override + public void setColor(Vector3fc color) { + animation.setColor(color); + } + + @Override + public void setColor(float red, float green, float blue, float alpha) { + animation.setColor(red, green, blue, alpha); + } + + @Override + public void setColor(float red, float green, float blue) { + animation.setColor(red, green, blue); + } + + @Override + public void setRed(float red) { + animation.setRed(red); + } + + @Override + public void setGreen(float green) { + animation.setGreen(green); + } + + @Override + public void setBlue(float blue) { + animation.setBlue(blue); + } + + @Override + public void setAlpha(float alpha) { + animation.setAlpha(alpha); + } + @Override public void render(Screen screen, Camera camera, ShaderManager shaderManager) { animation.render(screen, camera, shaderManager); diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/character/CharacterDelegate.java b/api/src/main/java/com/bartlomiejpluta/base/lib/character/CharacterDelegate.java index 5479ce34..838b2eca 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/character/CharacterDelegate.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/character/CharacterDelegate.java @@ -12,9 +12,7 @@ import com.bartlomiejpluta.base.api.move.Movement; import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.internal.object.Placeable; import com.bartlomiejpluta.base.internal.render.ShaderManager; -import org.joml.Matrix4fc; -import org.joml.Vector2fc; -import org.joml.Vector2ic; +import org.joml.*; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -328,6 +326,51 @@ public abstract class CharacterDelegate implements Character { character.abortMove(); } + @Override + public Vector4fc getColor() { + return character.getColor(); + } + + @Override + public void setColor(Vector4fc color) { + character.setColor(color); + } + + @Override + public void setColor(Vector3fc color) { + character.setColor(color); + } + + @Override + public void setColor(float red, float green, float blue, float alpha) { + character.setColor(red, green, blue, alpha); + } + + @Override + public void setColor(float red, float green, float blue) { + character.setColor(red, green, blue); + } + + @Override + public void setRed(float red) { + character.setRed(red); + } + + @Override + public void setGreen(float green) { + character.setGreen(green); + } + + @Override + public void setBlue(float blue) { + character.setBlue(blue); + } + + @Override + public void setAlpha(float alpha) { + character.setAlpha(alpha); + } + @Override public void update(float dt) { character.update(dt); diff --git a/api/src/main/java/com/bartlomiejpluta/base/lib/icon/IconDelegate.java b/api/src/main/java/com/bartlomiejpluta/base/lib/icon/IconDelegate.java index 0f2f073d..57f17f6d 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/lib/icon/IconDelegate.java +++ b/api/src/main/java/com/bartlomiejpluta/base/lib/icon/IconDelegate.java @@ -11,9 +11,7 @@ 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.*; import java.util.function.Consumer; @@ -249,6 +247,51 @@ public abstract class IconDelegate implements Icon { icon.handleEvent(event); } + @Override + public Vector4fc getColor() { + return icon.getColor(); + } + + @Override + public void setColor(Vector4fc color) { + icon.setColor(color); + } + + @Override + public void setColor(Vector3fc color) { + icon.setColor(color); + } + + @Override + public void setColor(float red, float green, float blue, float alpha) { + icon.setColor(red, green, blue, alpha); + } + + @Override + public void setColor(float red, float green, float blue) { + icon.setColor(red, green, blue); + } + + @Override + public void setRed(float red) { + icon.setRed(red); + } + + @Override + public void setGreen(float green) { + icon.setGreen(green); + } + + @Override + public void setBlue(float blue) { + icon.setBlue(blue); + } + + @Override + public void setAlpha(float alpha) { + icon.setAlpha(alpha); + } + @Override public void update(float dt) { icon.update(dt); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/material/Material.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/material/Material.java index a3ce75c2..a222627b 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/material/Material.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/material/Material.java @@ -1,5 +1,8 @@ package com.bartlomiejpluta.base.engine.core.gl.object.material; +import com.bartlomiejpluta.base.engine.core.gl.object.color.Color; +import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; +import com.bartlomiejpluta.base.engine.core.gl.object.texture.TexturedMaterial; import com.bartlomiejpluta.base.internal.render.Renderable; import org.joml.Vector3fc; import org.joml.Vector4fc; @@ -28,4 +31,18 @@ public interface Material extends Renderable { int getRows(); float[][] getTextureCoordinatesForAllFrames(); + + /** + * Creates a material with single, uniform color. + */ + static Material unicolor(float red, float green, float blue, float alpha) { + return new Color(red, green, blue, alpha); + } + + /** + * Creates a textured material + */ + static TexturedMaterial textured(Texture texture) { + return new TexturedMaterial(texture); + } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/Texture.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/Texture.java index aa5870dc..38cbe8b3 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/Texture.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/Texture.java @@ -2,11 +2,10 @@ package com.bartlomiejpluta.base.engine.core.gl.object.texture; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.screen.Screen; -import com.bartlomiejpluta.base.engine.core.gl.object.color.Color; -import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; import com.bartlomiejpluta.base.engine.error.AppException; import com.bartlomiejpluta.base.internal.gc.Disposable; +import com.bartlomiejpluta.base.internal.render.Renderable; import com.bartlomiejpluta.base.internal.render.ShaderManager; import lombok.Getter; import org.joml.Vector2f; @@ -21,7 +20,7 @@ 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 extends Color implements Material, Disposable { +public class Texture implements Renderable, Disposable { private static final int DESIRED_CHANNELS = 4; private final int textureId; @@ -42,10 +41,10 @@ public class Texture extends Color implements Material, Disposable { private final int columns; @Getter - private final Vector2fc spriteFragment; + private final Vector2fc frameFragment; @Getter - private final Vector2fc spriteSize; + private final Vector2fc frameSize; Texture(String textureFilename, ByteBuffer buffer, int rows, int columns) { try (var stack = MemoryStack.stackPush()) { @@ -74,12 +73,11 @@ public class Texture extends Color implements Material, Disposable { this.rows = rows; this.columns = columns; - this.spriteFragment = new Vector2f(1 / (float) columns, 1 / (float) rows); - this.spriteSize = new Vector2f(width, height).mul(spriteFragment); + this.frameFragment = new Vector2f(1 / (float) columns, 1 / (float) rows); + this.frameSize = new Vector2f(width, height).mul(frameFragment); } } - @Override public float[][] getTextureCoordinatesForAllFrames() { var array = new float[rows * columns][]; @@ -95,7 +93,7 @@ public class Texture extends Color implements Material, Disposable { } public float[] getTextureCoordinates(int x, int y) { - return getTextureCoordinates(x * (int) spriteSize.x(), y * (int) spriteSize.y(), (int) spriteSize.x(), (int) spriteSize.y()); + return getTextureCoordinates(x * (int) frameSize.x(), y * (int) frameSize.y(), (int) frameSize.x(), (int) frameSize.y()); } public float[] getTextureCoordinates(int textureX, int textureY, int tileWidth, int tileHeight) { @@ -118,7 +116,6 @@ public class Texture extends Color implements Material, Disposable { @Override public void render(Screen screen, Camera camera, ShaderManager shaderManager) { shaderManager.setUniform(UniformName.UNI_HAS_OBJECT_TEXTURE, true); - shaderManager.setUniform(UniformName.UNI_OBJECT_COLOR, color); shaderManager.setUniform(UniformName.UNI_TEXTURE_SAMPLER, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureId); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/TexturedMaterial.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/TexturedMaterial.java new file mode 100644 index 00000000..5fe61045 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/gl/object/texture/TexturedMaterial.java @@ -0,0 +1,73 @@ +package com.bartlomiejpluta.base.engine.core.gl.object.texture; + +import com.bartlomiejpluta.base.api.camera.Camera; +import com.bartlomiejpluta.base.api.screen.Screen; +import com.bartlomiejpluta.base.engine.core.gl.object.color.Color; +import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; +import com.bartlomiejpluta.base.engine.core.gl.shader.constant.UniformName; +import com.bartlomiejpluta.base.internal.render.ShaderManager; +import lombok.Getter; +import lombok.NonNull; +import org.joml.Vector2fc; + +@Getter +public class TexturedMaterial extends Color implements Material { + private final Texture texture; + + public TexturedMaterial(@NonNull Texture texture) { + this.texture = texture; + } + + @Override + public float[][] getTextureCoordinatesForAllFrames() { + return texture.getTextureCoordinatesForAllFrames(); + } + + @Override + public int getColumns() { + return texture.getColumns(); + } + + @Override + public int getRows() { + return texture.getRows(); + } + + public String getFileName() { + return texture.getFileName(); + } + + public int getHeight() { + return texture.getHeight(); + } + + public int getWidth() { + return texture.getWidth(); + } + + public Vector2fc getFrameFragment() { + return texture.getFrameFragment(); + } + + public Vector2fc getFrameSize() { + return texture.getFrameSize(); + } + + public float[] getTextureCoordinates(int id) { + return texture.getTextureCoordinates(id); + } + + public float[] getTextureCoordinates(int x, int y) { + return texture.getTextureCoordinates(x, y); + } + + public float[] getTextureCoordinates(int textureX, int textureY, int tileWidth, int tileHeight) { + return texture.getTextureCoordinates(textureX, textureY, tileWidth, tileHeight); + } + + @Override + public void render(Screen screen, Camera camera, ShaderManager shaderManager) { + shaderManager.setUniform(UniformName.UNI_OBJECT_COLOR, color); + texture.render(screen, camera, shaderManager); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/animation/model/DefaultAnimation.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/animation/model/DefaultAnimation.java index 2b27089d..fe152144 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/world/animation/model/DefaultAnimation.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/world/animation/model/DefaultAnimation.java @@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.move.AnimationMovement; import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.move.Movement; +import com.bartlomiejpluta.base.engine.core.gl.object.material.Material; import com.bartlomiejpluta.base.engine.core.gl.object.mesh.QuadMesh; import com.bartlomiejpluta.base.engine.core.gl.object.texture.Texture; import com.bartlomiejpluta.base.engine.world.movement.MovableSprite; @@ -19,6 +20,7 @@ import org.joml.Vector2fc; import java.util.concurrent.CompletableFuture; +import static com.bartlomiejpluta.base.engine.core.gl.object.material.Material.textured; import static com.bartlomiejpluta.base.util.path.PathProgress.DONE; import static com.bartlomiejpluta.base.util.path.PathProgress.SEGMENT_FAILED; @@ -52,11 +54,11 @@ public class DefaultAnimation extends MovableSprite implements Animation { private final CompletableFuture