diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 051746d8..08cca1f5 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -23,6 +23,7 @@ exports tech.fastj.graphics.game; exports tech.fastj.graphics.ui; exports tech.fastj.graphics.ui.elements; + exports tech.fastj.graphics.util; exports tech.fastj.systems.input; exports tech.fastj.systems.input.keyboard; diff --git a/src/main/java/tech/fastj/graphics/game/Polygon2D.java b/src/main/java/tech/fastj/graphics/game/Polygon2D.java index a1b31b82..0738ac88 100644 --- a/src/main/java/tech/fastj/graphics/game/Polygon2D.java +++ b/src/main/java/tech/fastj/graphics/game/Polygon2D.java @@ -9,6 +9,7 @@ import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Paint; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; @@ -34,6 +35,7 @@ public class Polygon2D extends GameObject { private Pointf[] points; private Color color; + private Paint paint; private boolean paintFilled; private float rotation; @@ -140,6 +142,26 @@ public Color getColor() { return color; } + /** + * Gets the paint for this polygon. + * + * @return The {@code Color} set for this polygon. + */ + public Paint getPaint() { + return paint; + } + + /** + * Sets the pain for this polygon. + * + * @param newPaint The {@code Paint} to be used for the polygon. + * @return This instance of the {@code Polygon2D}, for method chaining. + */ + public Polygon2D setPaint(Paint newPaint) { + paint = newPaint; + return this; + } + /** * Sets the color for the polygon. * @@ -271,13 +293,19 @@ public void scale(Pointf scaleMod, Pointf centerpoint) { public void render(Graphics2D g) { if (!shouldRender()) return; - g.setColor(color); +// g.setColor(color); + + Paint oldPaint = g.getPaint(); + + g.setPaint(paint); if (paintFilled) { g.fill(renderPath); } else { g.draw(renderPath); } + + g.setPaint(oldPaint); } @Override diff --git a/src/main/java/tech/fastj/graphics/util/GradientBuilder.java b/src/main/java/tech/fastj/graphics/util/GradientBuilder.java new file mode 100644 index 00000000..3f45bd0e --- /dev/null +++ b/src/main/java/tech/fastj/graphics/util/GradientBuilder.java @@ -0,0 +1,34 @@ +package tech.fastj.graphics.util; + +import tech.fastj.engine.CrashMessages; + +import java.awt.MultipleGradientPaint; + +/** The top-level interface for all gradient builders in the package {@link tech.fastj.graphics.util}. */ +public interface GradientBuilder { + + /** Error message defining that a gradient creation error occurred. */ + String GradientCreationError = CrashMessages.theGameCrashed("a gradient creation error."); + + /** + * Builds a {@code MultipleGradientPaint} object based on the data provided by other methods in the builder. + * + * @return The resulting {@code MultipleGradientPaint} object. + */ + MultipleGradientPaint build(); + + /** + * Generates an array of linear intervals from {@code 0.0f} to {@code 1.0} inclusive, based on the size provided. + * + * @param size The size of the generated array. + * @return The generated array. + */ + default float[] generateIntervals(int size) { + float[] intervals = new float[size]; + + for (int i = 0; i < intervals.length; i++) { + intervals[i] = (1f / (intervals.length - 1)) * (float) (i); + } + return intervals; + } +} diff --git a/src/main/java/tech/fastj/graphics/util/Gradients.java b/src/main/java/tech/fastj/graphics/util/Gradients.java new file mode 100644 index 00000000..18ddc2ae --- /dev/null +++ b/src/main/java/tech/fastj/graphics/util/Gradients.java @@ -0,0 +1,30 @@ +package tech.fastj.graphics.util; + +import java.awt.GradientPaint; +import java.awt.LinearGradientPaint; +import java.awt.RadialGradientPaint; + +/** Class to streamline working with the {@link GradientPaint} class (and its implementations) within FastJ. */ +public class Gradients { + + /** The amount of colors allowed in a single {@link LinearGradientBuilder} or {@link RadialGradientBuilder}. */ + public static final int ColorLimit = 8; + + /** + * Gets a builder instance for creating a {@link LinearGradientPaint}. + * + * @return A {@link LinearGradientPaint} builder. + */ + public static LinearGradientBuilder linearGradient() { + return LinearGradientBuilder.builder(); + } + + /** + * Gets a builder instance for creating a {@link RadialGradientPaint}. + * + * @return A {@link RadialGradientPaint} builder. + */ + public static RadialGradientBuilder radialGradient() { + return RadialGradientBuilder.builder(); + } +} diff --git a/src/main/java/tech/fastj/graphics/util/LinearGradientBuilder.java b/src/main/java/tech/fastj/graphics/util/LinearGradientBuilder.java new file mode 100644 index 00000000..defdda47 --- /dev/null +++ b/src/main/java/tech/fastj/graphics/util/LinearGradientBuilder.java @@ -0,0 +1,116 @@ +package tech.fastj.graphics.util; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Boundary; +import tech.fastj.graphics.Drawable; + +import java.awt.Color; +import java.awt.LinearGradientPaint; + +/** A builder class for creating {@link LinearGradientPaint} objects. */ +public class LinearGradientBuilder implements GradientBuilder { + + private Pointf from; + private Pointf to; + + private final Color[] colors; + private int count; + + /** Initializes a {@code LinearGradientBuilder}'s internals. */ + LinearGradientBuilder() { + colors = new Color[Gradients.ColorLimit]; + } + + /** + * Sets the starting and ending points for the builder, based on the provided {@link Drawable} and {@link Boundary} + * values. + * + * @param drawable The basis for what the {@code start} and {@code end} end positions evaluate to. + * @param start The starting boundary to create the gradient from. + * @param end The ending boundary to create the gradient from. + * @return The {@code LinearGradientBuilder}, for method chaining. + */ + public LinearGradientBuilder position(Drawable drawable, Boundary start, Boundary end) { + if (start.equals(end)) { + FastJEngine.error( + GradientBuilder.GradientCreationError, + new IllegalStateException( + "The starting and ending positions for a gradient must not be the same." + + System.lineSeparator() + + "Both positions evaluated to: " + start.name() + ) + ); + } + + this.from = drawable.getBound(start); + this.to = drawable.getBound(end); + + return this; + } + + /** + * Sets the starting and ending points for the builder, based on the provided {@link Pointf} values. + * + * @param start The {@code Pointf} defining the starting point of the gradient. + * @param end The {@code Pointf} defining the ending point of the gradient. + * @return The {@code LinearGradientBuilder}, for method chaining. + */ + public LinearGradientBuilder position(Pointf start, Pointf end) { + if (start.equals(end)) { + FastJEngine.error( + GradientBuilder.GradientCreationError, + new IllegalStateException( + "The starting and ending positions for a gradient must not be the same." + + System.lineSeparator() + + "Both positions evaluated to: " + start + ) + ); + } + + this.from = start; + this.to = end; + + return this; + } + + /** + * Adds a {@link Color} to the builder to be used in the resulting gradient. + *

+ * The amount of colors used in a {@link LinearGradientBuilder} not exceed {@link Gradients#ColorLimit}. + * + * @param color The {@code Color} being added. + * @return The {@code LinearGradientBuilder}, for method chaining. + */ + public LinearGradientBuilder withColor(Color color) { + if (count == Gradients.ColorLimit) { + FastJEngine.error(GradientBuilder.GradientCreationError, + new IllegalStateException("Gradients cannot contain more than " + Gradients.ColorLimit + " colors.") + ); + } + + colors[count] = color; + count++; + return this; + } + + /** + * Creates a new {@link LinearGradientPaint} object, using the data provided by other method calls. + * + * @return The resulting {@code LinearGradientPaint}. + */ + @Override + public LinearGradientPaint build() { + float[] fractions = generateIntervals(colors.length); + return new LinearGradientPaint(from.x, from.y, to.x, to.y, fractions, colors); + } + + /** + * Gets a new instance of a {@link LinearGradientBuilder}. + * + * @return The {@code LinearGradientBuilder} instance. + */ + static LinearGradientBuilder builder() { + return new LinearGradientBuilder(); + } +} diff --git a/src/main/java/tech/fastj/graphics/util/RadialGradientBuilder.java b/src/main/java/tech/fastj/graphics/util/RadialGradientBuilder.java new file mode 100644 index 00000000..eaa8d126 --- /dev/null +++ b/src/main/java/tech/fastj/graphics/util/RadialGradientBuilder.java @@ -0,0 +1,99 @@ +package tech.fastj.graphics.util; + +import tech.fastj.engine.FastJEngine; +import tech.fastj.math.Pointf; +import tech.fastj.graphics.Boundary; +import tech.fastj.graphics.Drawable; + +import java.awt.Color; +import java.awt.RadialGradientPaint; + +/** A builder class for creating {@link RadialGradientPaint} objects. */ +public class RadialGradientBuilder implements GradientBuilder { + + private Pointf center; + private float radius; + + private final Color[] colors; + private int count; + + /** Initializes a {@code RadialGradientBuilder}'s internals. */ + RadialGradientBuilder() { + colors = new Color[Gradients.ColorLimit]; + } + + /** + * Sets the centerpoint and radius for the builder, based on the provided {@link Drawable}. + * + * @param drawable The drawable to get the center and radius from. + * @return The {@code RadialGradientBuilder}, for method chaining. + */ + public RadialGradientBuilder position(Drawable drawable) { + this.center = drawable.getCenter(); + + Pointf drawableSize = Pointf.subtract(this.center, drawable.getBound(Boundary.TopLeft)); + this.radius = (float) Math.hypot(drawableSize.x, drawableSize.y); + + return this; + } + + /** + * Sets the centerpoint and radius for the builder, based on the provided {@link Pointf} and float values. + * + * @param center The {@code Pointf} defining the centerpoint for the gradient. + * @param radius The {@code float} defining the radius for the gradient. + * @return The {@code LinearGradientBuilder}, for method chaining. + */ + public RadialGradientBuilder position(Pointf center, float radius) { + if (radius <= 0f) { + FastJEngine.error( + GradientBuilder.GradientCreationError, + new IllegalStateException("The radius for a gradient must be larger than 0.") + ); + } + this.center = center; + this.radius = radius; + + return this; + } + + /** + * Adds a {@link Color} to the builder to be used in the resulting gradient. + *

+ * The amount of colors used in a {@link RadialGradientBuilder} not exceed {@link Gradients#ColorLimit}. + * + * @param color The {@code Color} being added. + * @return The {@code LinearGradientBuilder}, for method chaining. + */ + public RadialGradientBuilder withColor(Color color) { + if (count == Gradients.ColorLimit) { + FastJEngine.error(GradientBuilder.GradientCreationError, + new IllegalStateException("Gradients cannot contain more than " + Gradients.ColorLimit + " colors.") + ); + } + + colors[count] = color; + count++; + return this; + } + + /** + * Creates a new {@link RadialGradientPaint} object, using the data provided by other method calls. + * + * @return The resulting {@code RadialGradientPaint}. + */ + @Override + public RadialGradientPaint build() { + float[] fractions = generateIntervals(colors.length); + return new RadialGradientPaint(center.x, center.y, radius, fractions, colors); + } + + /** + * Gets a new instance of a {@link RadialGradientBuilder}. + * + * @return The {@code RadialGradientBuilder} instance. + */ + static RadialGradientBuilder builder() { + return new RadialGradientBuilder(); + } +}