Skip to content

Commit

Permalink
(#10, #109) Add curve support to Drawables
Browse files Browse the repository at this point in the history
New Additions:
- Created Pair class to handle returning 2 values at once, for generating point meshes with curves.
  • Loading branch information
lucasstarsz committed May 9, 2022
1 parent 3ded671 commit db10125
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@
exports tech.fastj.systems.audio.state;
exports tech.fastj.systems.behaviors;
exports tech.fastj.systems.control;
exports tech.fastj.systems.collections;
exports tech.fastj.systems.tags;
}
108 changes: 90 additions & 18 deletions src/main/java/tech/fastj/graphics/game/Polygon2D.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tech.fastj.graphics.game;

import tech.fastj.math.Point;
import tech.fastj.math.Pointf;

import tech.fastj.graphics.Drawable;
Expand All @@ -14,6 +15,7 @@
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.Arrays;
import java.util.Objects;

Expand All @@ -34,7 +36,12 @@ public class Polygon2D extends GameObject {
/** {@link Color} representing the default outline color value as the color black. */
public static final Color DefaultOutlineColor = Color.black;

public static final int QuadCurve = 1;
public static final int BezierCurve = 2;
public static final int MovePath = 3;

private Pointf[] originalPoints;
private Point[] alternateIndexes;

private RenderStyle renderStyle;
private Paint fillPaint;
Expand All @@ -44,15 +51,18 @@ public class Polygon2D extends GameObject {
/**
* {@code Polygon2D} constructor that takes in an array of points.
* <p>
* This constructor defaults the fill paint to {@link #DefaultFill}, the outline stroke to {@link
* #DefaultOutlineStroke}, the outline color to {@link #DefaultOutlineColor}, the render style to {@link
* #DefaultRenderStyle}, and the {@code shouldRender} boolean to {@link Drawable#DefaultShouldRender}.
* If needed, an array of alternate point indexes can be supplied to model curves and other {@link Path2D} options.
* <p>
* This constructor defaults the fill paint to {@link #DefaultFill}, the outline stroke to
* {@link #DefaultOutlineStroke}, the outline color to {@link #DefaultOutlineColor}, the render style to
* {@link #DefaultRenderStyle}, and the {@code shouldRender} boolean to {@link Drawable#DefaultShouldRender}.
*
* @param points {@code Pointf} array that defines the points for the polygon.
*/
protected Polygon2D(Pointf[] points) {
protected Polygon2D(Pointf[] points, Point[] altIndexes) {
originalPoints = points;
setCollisionPath(DrawUtil.createPath(originalPoints));
alternateIndexes = altIndexes;
setCollisionPath(DrawUtil.createPath(originalPoints, alternateIndexes));

setFill(DefaultFill);
setOutlineStroke(DefaultOutlineStroke);
Expand All @@ -68,38 +78,49 @@ protected Polygon2D(Pointf[] points) {
* @return A {@code Polygon2DBuilder} instance for creating a {@code Polygon2D}.
*/
public static Polygon2DBuilder create(Pointf[] points) {
return new Polygon2DBuilder(points, DefaultRenderStyle, Drawable.DefaultShouldRender);
return new Polygon2DBuilder(points, null, DefaultRenderStyle, Drawable.DefaultShouldRender);
}

/**
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points} and {@code
* shouldRender} fields.
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points} field.
* <p>
*
* @param points {@code Pointf} array that defines the points for the {@code Polygon2D}.
* @return A {@code Polygon2DBuilder} instance for creating a {@code Polygon2D}.
*/
public static Polygon2DBuilder create(Pointf[] points, Point[] altIndexes) {
return new Polygon2DBuilder(points, altIndexes, DefaultRenderStyle, Drawable.DefaultShouldRender);
}

/**
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points} and
* {@code shouldRender} fields.
* <p>
*
* @param points {@code Pointf} array that defines the points for the {@code Polygon2D}.
* @param shouldRender {@code boolean} that defines whether the {@code Polygon2D} would be rendered to the screen.
* @return A {@code Polygon2DBuilder} instance for creating a {@code Polygon2D}.
*/
public static Polygon2DBuilder create(Pointf[] points, boolean shouldRender) {
return new Polygon2DBuilder(points, DefaultRenderStyle, shouldRender);
return new Polygon2DBuilder(points, null, DefaultRenderStyle, shouldRender);
}

/**
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points} and {@code
* renderStyle} fields.
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points} and
* {@code renderStyle} fields.
* <p>
*
* @param points {@code Pointf} array that defines the points for the {@code Polygon2D}.
* @param renderStyle {@code RenderStyle} that defines the render style for the {@code Polygon2D}.
* @return A {@code Polygon2DBuilder} instance for creating a {@code Polygon2D}.
*/
public static Polygon2DBuilder create(Pointf[] points, RenderStyle renderStyle) {
return new Polygon2DBuilder(points, renderStyle, Drawable.DefaultShouldRender);
return new Polygon2DBuilder(points, null, renderStyle, Drawable.DefaultShouldRender);
}

/**
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points}, {@code
* renderStyle}, and {@code shouldRender} fields.
* Gets a {@link Polygon2DBuilder} instance while setting the eventual {@link Polygon2D}'s {@code points},
* {@code renderStyle}, and {@code shouldRender} fields.
* <p>
*
* @param points {@code Pointf} array that defines the points for the {@code Polygon2D}.
Expand All @@ -108,7 +129,7 @@ public static Polygon2DBuilder create(Pointf[] points, RenderStyle renderStyle)
* @return A {@code Polygon2DBuilder} instance for creating a {@code Polygon2D}.
*/
public static Polygon2DBuilder create(Pointf[] points, RenderStyle renderStyle, boolean shouldRender) {
return new Polygon2DBuilder(points, renderStyle, shouldRender);
return new Polygon2DBuilder(points, null, renderStyle, shouldRender);
}

/**
Expand All @@ -118,7 +139,17 @@ public static Polygon2DBuilder create(Pointf[] points, RenderStyle renderStyle,
* @return The resulting {@code Polygon2D}.
*/
public static Polygon2D fromPoints(Pointf[] points) {
return new Polygon2DBuilder(points, DefaultRenderStyle, Drawable.DefaultShouldRender).build();
return new Polygon2DBuilder(points, null, DefaultRenderStyle, Drawable.DefaultShouldRender).build();
}

/**
* Creates a {@code Polygon2D} from the specified points.
*
* @param points {@code Pointf} array that defines the points for the {@code Polygon2D}.
* @return The resulting {@code Polygon2D}.
*/
public static Polygon2D fromPoints(Pointf[] points, Point[] altIndexes) {
return new Polygon2DBuilder(points, altIndexes, DefaultRenderStyle, Drawable.DefaultShouldRender).build();
}

/**
Expand All @@ -130,6 +161,16 @@ public Pointf[] getOriginalPoints() {
return originalPoints;
}

/**
* Gets the polygon's alternate indexes, which are associated with the
* {@link #getOriginalPoints() original point set.}
*
* @return The original set of points for this polygon, as a {@code Pointf[]}.
*/
public Point[] getAlternateIndexes() {
return alternateIndexes;
}

/**
* Gets the polygon's fill paint.
*
Expand Down Expand Up @@ -245,7 +286,40 @@ public Pointf[] getPoints() {
*/
public void modifyPoints(Pointf[] points, boolean resetTranslation, boolean resetRotation, boolean resetScale) {
originalPoints = points;
alternateIndexes = null;

resetTransform(resetTranslation, resetRotation, resetScale);
setCollisionPath(DrawUtil.createPath(originalPoints));
}

/**
* Replaces the current point array with the parameter point array and alternate indexes.
* <p>
* This does not reset the rotation, scale, or location of the original, unless specified with the third, fourth,
* and fifth parameters.
*
* @param points {@code Pointf} array that will replace the current points of the polygon.
* @param altIndexes {@code Point} array that will replace the current alternate indexes of the polygon.
* @param resetTranslation Boolean to determine if the translation should be reset.
* @param resetRotation Boolean to determine if the rotation should be reset.
* @param resetScale Boolean to determine if the scale should be reset.
*/
public void modifyPoints(Pointf[] points, Point[] altIndexes, boolean resetTranslation, boolean resetRotation, boolean resetScale) {
originalPoints = points;
alternateIndexes = altIndexes;

resetTransform(resetTranslation, resetRotation, resetScale);
setCollisionPath(DrawUtil.createPath(originalPoints, altIndexes));
}

/**
* Resets the {@code Polygon2D}'s transform.
*
* @param resetTranslation Boolean to determine if the translation should be reset.
* @param resetRotation Boolean to determine if the rotation should be reset.
* @param resetScale Boolean to determine if the scale should be reset.
*/
private void resetTransform(boolean resetTranslation, boolean resetRotation, boolean resetScale) {
if (resetTranslation && resetRotation && resetScale) {
transform.reset();
} else {
Expand All @@ -259,8 +333,6 @@ public void modifyPoints(Pointf[] points, boolean resetTranslation, boolean rese
transform.resetScale();
}
}

setCollisionPath(DrawUtil.createPath(originalPoints));
}

@Override
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/tech/fastj/graphics/game/Polygon2DBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tech.fastj.graphics.game;

import tech.fastj.math.Point;
import tech.fastj.math.Pointf;
import tech.fastj.math.Transform2D;

Expand All @@ -12,6 +13,7 @@
public class Polygon2DBuilder {

private final Pointf[] points;
private final Point[] altIndexes;
private final boolean shouldRender;
private final RenderStyle renderStyle;

Expand All @@ -31,8 +33,9 @@ public class Polygon2DBuilder {
* @param renderStyle The {@code RenderStyle} to use for the resulting {@code Polygon2D}.
* @param shouldRender The "should render" {@code boolean} to use for the resulting {@code Polygon2D}.
*/
Polygon2DBuilder(Pointf[] points, RenderStyle renderStyle, boolean shouldRender) {
Polygon2DBuilder(Pointf[] points, Point[] altIndexes, RenderStyle renderStyle, boolean shouldRender) {
this.points = Objects.requireNonNull(points, "The array of points must not be null.");
this.altIndexes = altIndexes;
this.renderStyle = Objects.requireNonNull(renderStyle, "The render style must not be null.");
this.shouldRender = shouldRender;
}
Expand Down Expand Up @@ -85,7 +88,7 @@ public Polygon2DBuilder withTransform(Pointf translation, float rotation, Pointf
* @return The resulting {@code Polygon2D}.
*/
public Polygon2D build() {
return (Polygon2D) new Polygon2D(points)
return (Polygon2D) new Polygon2D(points, altIndexes)
.setOutlineStroke(outlineStroke)
.setOutlineColor(outlineColor)
.setRenderStyle(renderStyle)
Expand Down
88 changes: 88 additions & 0 deletions src/main/java/tech/fastj/graphics/util/DrawUtil.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package tech.fastj.graphics.util;

import tech.fastj.math.Maths;
import tech.fastj.math.Point;
import tech.fastj.math.Pointf;

import tech.fastj.graphics.Drawable;
import tech.fastj.graphics.game.Polygon2D;

import tech.fastj.systems.collections.Pair;

import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
Expand Down Expand Up @@ -135,6 +138,52 @@ public static Path2D.Float createPath(Pointf[] pts) {
return p;
}

/**
* Creates a {@code Path2D.Float} based on the specified {@code Pointf} array.
*
* @param pts The {@code Pointf} array to create the {@code Path2D.Float} from.
* @return The resulting {@code Path2D.Float}.
*/
public static Path2D.Float createPath(Pointf[] pts, Point[] altIndexes) {
if (altIndexes == null) {
return createPath(pts);
}

Path2D.Float p = new Path2D.Float();

p.moveTo(pts[0].x, pts[0].y);
for (int i = 1, ai = 0; i < pts.length; i++) {
if (altIndexes[ai].x == i) {
switch (altIndexes[ai++].y) {
case Polygon2D.MovePath: {
p.moveTo(pts[i].x, pts[i].y);
break;
}
case Polygon2D.QuadCurve: {
p.quadTo(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y);
i += 1;
break;
}
case Polygon2D.BezierCurve: {
p.curveTo(pts[i].x, pts[i].y, pts[i + 1].x, pts[i + 1].y, pts[i + 2].x, pts[i + 2].y);
i += 2;
break;
}
default: {
throw new UnsupportedOperationException(
"No known path option for " + altIndexes[ai - 1].y + " on index " + i + " of the path."
);
}
}
} else {
p.lineTo(pts[i].x, pts[i].y);
}
}
p.closePath();

return p;
}

/**
* Checks for equality in length and point values between two {@link Path2D} objects.
* <p>
Expand Down Expand Up @@ -254,6 +303,45 @@ private static boolean mGradientEquals(MultipleGradientPaint mGradientPaint1, Mu
&& Arrays.equals(mGradientPaint1.getFractions(), mGradientPaint2.getFractions());
}

public static Pair<Pointf[], Point[]> createCircle(float x, float y, float radius) {
return createCircle(new Pointf(x, y), radius);
}

public static Pair<Pointf[], Point[]> createCircle(float xy, float radius) {
return createCircle(new Pointf(xy), radius);
}

public static Pair<Pointf[], Point[]> createCircle(Pointf center, float radius) {
float curveOffset = (float) ((4f / 3f) * (Math.sqrt(2) - 1) * radius);
return Pair.of(
new Pointf[]{
Pointf.subtract(center, radius, 0f),

Pointf.subtract(center, radius, curveOffset),
Pointf.subtract(center, curveOffset, radius),
Pointf.subtract(center, 0f, radius),

Pointf.subtract(center, -curveOffset, radius),
Pointf.add(center, radius, -curveOffset),
Pointf.add(center, radius, 0f),

Pointf.add(center, radius, curveOffset),
Pointf.add(center, curveOffset, radius),
Pointf.add(center, 0f, radius),

Pointf.add(center, -curveOffset, radius),
Pointf.subtract(center, radius, -curveOffset),
Pointf.subtract(center, radius, 0f)
},
new Point[]{
new Point(1, Polygon2D.BezierCurve),
new Point(4, Polygon2D.BezierCurve),
new Point(7, Polygon2D.BezierCurve),
new Point(10, Polygon2D.BezierCurve)
}
);
}

/**
* Creates a {@code Pointf} array of 4 points, based on the specified x, y, width, and height floats.
* <p>
Expand Down
Loading

0 comments on commit db10125

Please sign in to comment.