diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 9c53bbe3..19740c77 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -25,6 +25,7 @@ import itdelatrisu.opsu.GameMod; import itdelatrisu.opsu.OsuFile; import itdelatrisu.opsu.OsuHitObject; import itdelatrisu.opsu.Utils; +import itdelatrisu.opsu.objects.curves.CatmullCurve; import itdelatrisu.opsu.objects.curves.CircumscribedCircle; import itdelatrisu.opsu.objects.curves.Curve; import itdelatrisu.opsu.objects.curves.LinearBezier; @@ -459,8 +460,10 @@ public class Slider implements HitObject { if (hitObject.getSliderType() == OsuHitObject.SLIDER_PASSTHROUGH && hitObject.getSliderX().length == 2) this.curve = new CircumscribedCircle(hitObject, color); + else if ( hitObject.getSliderType() == OsuHitObject.SLIDER_CATMULL) + this.curve = new CatmullCurve(hitObject, color); else - this.curve = new LinearBezier(hitObject, color); + this.curve = new LinearBezier(hitObject, color, hitObject.getSliderType() == OsuHitObject.SLIDER_LINEAR); } @Override diff --git a/src/itdelatrisu/opsu/objects/curves/Bezier2.java b/src/itdelatrisu/opsu/objects/curves/Bezier2.java index 35552b4a..fa02b542 100644 --- a/src/itdelatrisu/opsu/objects/curves/Bezier2.java +++ b/src/itdelatrisu/opsu/objects/curves/Bezier2.java @@ -23,22 +23,10 @@ package itdelatrisu.opsu.objects.curves; * * @author fluddokt (https://github.com/fluddokt) */ -public class Bezier2 { +public class Bezier2 extends CurveType{ /** The control points of the Bezier curve. */ private Vec2f[] points; - /** Points along the curve of the Bezier curve. */ - private Vec2f[] curve; - - /** Distances between a point of the curve and the last point. */ - private float[] curveDis; - - /** The number of points along the curve. */ - private int ncurve; - - /** The total distances of this Bezier. */ - private float totalDistance; - /** * Constructor. * @param points the control points @@ -52,27 +40,10 @@ public class Bezier2 { for (int i = 0; i < points.length - 1; i++) approxlength += points[i].cpy().sub(points[i + 1]).len(); - // subdivide the curve - this.ncurve = (int) (approxlength / 4); - this.curve = new Vec2f[ncurve]; - for (int i = 0; i < ncurve; i++) - curve[i] = pointAt(i / (float) ncurve); - - // find the distance of each point from the previous point - this.curveDis = new float[ncurve]; - this.totalDistance = 0; - for (int i = 0; i < ncurve; i++) { - curveDis[i] = (i == 0) ? 0 : curve[i].cpy().sub(curve[i - 1]).len(); - totalDistance += curveDis[i]; - } -// System.out.println("New Bezier2 "+points.length+" "+approxlength+" "+totalDistance()); + init(approxlength); } - /** - * Returns the point on the Bezier curve at a value t. - * @param t the t value [0, 1] - * @return the point [x, y] - */ + @Override public Vec2f pointAt(float t) { Vec2f c = new Vec2f(); int n = points.length - 1; @@ -84,25 +55,6 @@ public class Bezier2 { return c; } - /** - * Returns the points along the curve of the Bezier curve. - */ - public Vec2f[] getCurve() { return curve; } - - /** - * Returns the distances between a point of the curve and the last point. - */ - public float[] getCurveDistances() { return curveDis; } - - /** - * Returns the number of points along the curve. - */ - public int points() { return ncurve; } - - /** - * Returns the total distances of this Bezier curve. - */ - public float totalDistance() { return totalDistance; } /** * Calculates the binomial coefficient. diff --git a/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java b/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java new file mode 100644 index 00000000..262906f5 --- /dev/null +++ b/src/itdelatrisu/opsu/objects/curves/CatmullCurve.java @@ -0,0 +1,64 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014, 2015 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu.objects.curves; + +import java.util.LinkedList; + +import itdelatrisu.opsu.OsuHitObject; + +import org.newdawn.slick.Color; + +/** + * Representation of Catmull Curve with equidistant points. + * + * @author fluddokt (https://github.com/fluddokt) + */ +public class CatmullCurve extends EqualDistanceMultiCurve{ + + /** + * Constructor. + * @param hitObject the associated OsuHitObject + * @param color the color of this curve + */ + public CatmullCurve(OsuHitObject hitObject, Color color) { + super(hitObject, color); + LinkedList catmulls = new LinkedList(); + int ncontrolPoints = hitObject.getSliderX().length + 1; + // temporary list of points to separate different curves + LinkedList points = new LinkedList(); + + // repeat the first and last points as controls points + // aabb + // aabc abcc + // aabc abcd bcdd + points.addLast(new Vec2f(getX(0), getY(0))); + for (int i = 0; i < ncontrolPoints; i++) { + points.addLast(new Vec2f(getX(i), getY(i))); + if (points.size() >= 4) { + catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0]))); + points.removeFirst(); + } + } + points.addLast(new Vec2f(getX(ncontrolPoints - 1),getY(ncontrolPoints - 1))); + if (points.size() >= 4) { + catmulls.add(new CentripetalCatmullRom(points.toArray(new Vec2f[0]))); + } + init(catmulls); + } +} diff --git a/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java b/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java new file mode 100644 index 00000000..283dab2b --- /dev/null +++ b/src/itdelatrisu/opsu/objects/curves/CentripetalCatmullRom.java @@ -0,0 +1,86 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014, 2015 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu.objects.curves; + +/** + * Representation of a Centripetal Catmull–Rom spline. + * http://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline + * + * Currently not technically Centripetal Catmull–Rom + * + * @author fluddokt (https://github.com/fluddokt) + */ +public class CentripetalCatmullRom extends CurveType{ + + /** The time values of the Catmull curve. */ + float [] time; + + /** The control points of the Catmull curve. */ + Vec2f[] points; + + /** + * Constructor. + * @param hitObject the associated OsuHitObject + * @param color the color of this curve + */ + protected CentripetalCatmullRom(Vec2f[] points) { + if (points.length != 4) + throw new Error("need exactly 4 points"); + + this.points = points; + time = new float[4]; + time[0] = 0; + float approxLength = 0; + for (int i = 1; i < 4; i++) { + float len = 0; + if (i > 0) + len = points[i].cpy().sub(points[i - 1]).len(); + if (len <= 0) + len += 0.0001f; + approxLength += len; + // time[i] = (float) Math.sqrt(len) + time[i-1];// ^(0.5) + time[i] = i; + } + init(approxLength / 2); + } + + + @Override + public Vec2f pointAt(float t){ + t = t * (time[2] - time[1]) + time[1]; + + Vec2f A1 = points[0].cpy().scale((time[1] - t) / (time[1] - time[0])) + .add(points[1].cpy().scale((t - time[0]) / (time[1] - time[0]))); + Vec2f A2 = points[1].cpy().scale((time[2] - t) / (time[2] - time[1])) + .add(points[2].cpy().scale((t - time[1]) / (time[2] - time[1]))); + Vec2f A3 = points[2].cpy().scale((time[3] - t) / (time[3] - time[2])) + .add(points[3].cpy().scale((t - time[2]) / (time[3] - time[2]))); + + Vec2f B1 = A1.cpy().scale((time[2] - t) / (time[2] - time[0])) + .add(A2.cpy().scale((t - time[0]) / (time[2] - time[0]))); + Vec2f B2 = A2.cpy().scale((time[3] - t) / (time[3] - time[1])) + .add(A3.cpy().scale((t - time[1]) / (time[3] - time[1]))); + + Vec2f C = B1.cpy().scale((time[2] - t) / (time[2] - time[1])) + .add(B2.cpy().scale((t - time[1]) / (time[2] - time[1]))); + + return C; + } + +} diff --git a/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java b/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java index f534db95..0e334634 100644 --- a/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java +++ b/src/itdelatrisu/opsu/objects/curves/CircumscribedCircle.java @@ -19,12 +19,9 @@ package itdelatrisu.opsu.objects.curves; import itdelatrisu.opsu.ErrorHandler; -import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.OsuHitObject; -import itdelatrisu.opsu.Utils; import org.newdawn.slick.Color; -import org.newdawn.slick.Image; /** * Representation of a curve along a Circumscribed Circle of three points. @@ -53,12 +50,6 @@ public class CircumscribedCircle extends Curve { /** The start and end angles for drawing. */ private float drawStartAngle, drawEndAngle; - /** The number of steps in the curve to draw. */ - private float step; - - /** Points along the curve. */ - private Vec2f[] curve; - /** * Constructor. * @param hitObject the associated OsuHitObject @@ -67,8 +58,6 @@ public class CircumscribedCircle extends Curve { public CircumscribedCircle(OsuHitObject hitObject, Color color) { super(hitObject, color); - this.step = hitObject.getPixelLength() / 5f; - // construct the three points this.start = new Vec2f(getX(0), getY(0)); this.mid = new Vec2f(getX(1), getY(1)); @@ -125,6 +114,7 @@ public class CircumscribedCircle extends Curve { this.drawStartAngle = (float) ((startAng + (startAng > endAng ? -HALF_PI : HALF_PI)) * 180 / Math.PI); // calculate points + float step = hitObject.getPixelLength() / CURVE_POINTS_SEPERATION; curve = new Vec2f[(int) step + 1]; for (int i = 0; i < curve.length; i++) { float[] xy = pointAt(i / step); @@ -178,15 +168,6 @@ public class CircumscribedCircle extends Curve { }; } - @Override - public void draw(Color color) { - Image hitCircle = GameImage.HITCIRCLE.getImage(); - Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage(); - for (int i = 0; i < step; i++) - hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Utils.COLOR_WHITE_FADE); - for (int i = 0; i < step; i++) - hitCircle.drawCentered(curve[i].x, curve[i].y, color); - } @Override public float getEndAngle() { return drawEndAngle; } diff --git a/src/itdelatrisu/opsu/objects/curves/Curve.java b/src/itdelatrisu/opsu/objects/curves/Curve.java index ab3d23aa..354c0135 100644 --- a/src/itdelatrisu/opsu/objects/curves/Curve.java +++ b/src/itdelatrisu/opsu/objects/curves/Curve.java @@ -18,9 +18,12 @@ package itdelatrisu.opsu.objects.curves; +import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.OsuHitObject; +import itdelatrisu.opsu.Utils; import org.newdawn.slick.Color; +import org.newdawn.slick.Image; /** * Representation of a curve. @@ -28,6 +31,10 @@ import org.newdawn.slick.Color; * @author fluddokt (https://github.com/fluddokt) */ public abstract class Curve { + + /** Points generated along the curve should be spaced this much apart*/ + protected static float CURVE_POINTS_SEPERATION = 5; + /** The associated OsuHitObject. */ protected OsuHitObject hitObject; @@ -37,6 +44,9 @@ public abstract class Curve { /** The scaled slider x, y coordinate lists. */ protected float[] sliderX, sliderY; + /** Points along the curve. To be set be inherited classes*/ + protected Vec2f[] curve; + /** * Constructor. * @param hitObject the associated OsuHitObject @@ -61,7 +71,17 @@ public abstract class Curve { * Draws the full curve to the graphics context. * @param color the color filter */ - public abstract void draw(Color color); + public void draw(Color color) { + if (curve == null){ + return; + } + Image hitCircle = GameImage.HITCIRCLE.getImage(); + Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage(); + for (int i = 0; i < curve.length; i++) + hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Utils.COLOR_WHITE_FADE); + for (int i = 0; i < curve.length; i++) + hitCircle.drawCentered(curve[i].x, curve[i].y, color); + } /** * Returns the angle of the first control point. diff --git a/src/itdelatrisu/opsu/objects/curves/CurveType.java b/src/itdelatrisu/opsu/objects/curves/CurveType.java new file mode 100644 index 00000000..b1986ac1 --- /dev/null +++ b/src/itdelatrisu/opsu/objects/curves/CurveType.java @@ -0,0 +1,88 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014, 2015 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu.objects.curves; + +/** + * Representation of a curve with the distance between each point calculated. + * + * @author fluddokt (https://github.com/fluddokt) + */ +public abstract class CurveType { + + /** Points along the curve of the Bezier curve. */ + private Vec2f[] curve; + + /** Distances between a point of the curve and the last point. */ + private float[] curveDis; + + /** The number of points along the curve. */ + private int ncurve; + + /** The total distances of this Bezier. */ + private float totalDistance; + + /** + * Returns the point on the curve at a value t. + * @param t the t value [0, 1] + * @return the point [x, y] + */ + public abstract Vec2f pointAt(float t); + + /** + * Initialize the curve points and distance + * Must be called by inherited classes + * + * @param approxlength an approximate length of the curve + */ + public void init(float approxlength) { + // subdivide the curve + this.ncurve = (int) (approxlength / 4) + 1; + this.curve = new Vec2f[ncurve]; + for (int i = 0; i < ncurve; i++) + curve[i] = pointAt(i / (float) (ncurve - 1)); + + // find the distance of each point from the previous point + this.curveDis = new float[ncurve]; + this.totalDistance = 0; + for (int i = 0; i < ncurve; i++) { + curveDis[i] = (i == 0) ? 0 : curve[i].cpy().sub(curve[i - 1]).len(); + totalDistance += curveDis[i]; + } + } + /** + * Returns the points along the curve of the Bezier curve. + */ + public Vec2f[] getCurvePoint() { return curve; } + + /** + * Returns the distances between a point of the curve and the last point. + */ + public float[] getCurveDistances() { return curveDis; } + + /** + * Returns the number of points along the curve. + */ + public int getCurvesCount() { return ncurve; } + + /** + * Returns the total distances of this Bezier curve. + */ + public float totalDistance() { return totalDistance; } + +} diff --git a/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java b/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java new file mode 100644 index 00000000..f1959ffb --- /dev/null +++ b/src/itdelatrisu/opsu/objects/curves/EqualDistanceMultiCurve.java @@ -0,0 +1,143 @@ +/* + * opsu! - an open-source osu! client + * Copyright (C) 2014, 2015 Jeffrey Han + * + * opsu! is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * opsu! is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with opsu!. If not, see . + */ + +package itdelatrisu.opsu.objects.curves; + +import itdelatrisu.opsu.OsuHitObject; + +import java.util.Iterator; +import java.util.LinkedList; + +import org.newdawn.slick.Color; + +/** + * Representation of multiple curve with equidistant points. + * http://pomax.github.io/bezierinfo/#tracing + * + * @author fluddokt (https://github.com/fluddokt) + */ +public abstract class EqualDistanceMultiCurve extends Curve { + /** The angles of the first and last control points for drawing. */ + private float startAngle, endAngle; + + /** The number of points along the curve. */ + private int ncurve; + + /** + * Constructor. + * @param hitObject the associated OsuHitObject + * @param color the color of this curve + */ + public EqualDistanceMultiCurve(OsuHitObject hitObject, Color color) { + super(hitObject, color); + + } + + /** + * Initialize the curve points with equal distance + * Must be called by inherited classes + * + * @param curvesList a list of curves to join + */ + public void init(LinkedList curvesList){ + // now try to creates points the are equidistant to each other + this.ncurve = (int) (hitObject.getPixelLength() / CURVE_POINTS_SEPERATION); + this.curve = new Vec2f[ncurve + 1]; + + float distanceAt = 0; + Iterator iter = curvesList.iterator(); + int curPoint = 0; + CurveType curCurve = iter.next(); + Vec2f lastCurve = curCurve.getCurvePoint()[0]; + float lastDistanceAt = 0; + + // length of Curve should equal pixel length (in 640x480) + float pixelLength = hitObject.getPixelLength() * OsuHitObject.getXMultiplier(); + + // for each distance, try to get in between the two points that are between it + for (int i = 0; i < ncurve + 1; i++) { + int prefDistance = (int) (i * pixelLength / ncurve); + while (distanceAt < prefDistance) { + lastDistanceAt = distanceAt; + lastCurve = curCurve.getCurvePoint()[curPoint]; + distanceAt += curCurve.getCurveDistances()[curPoint++]; + + if (curPoint >= curCurve.getCurvesCount()) { + if (iter.hasNext()) { + curCurve = iter.next(); + curPoint = 0; + } else { + curPoint = curCurve.getCurvesCount() - 1; + if (lastDistanceAt == distanceAt) { + // out of points even though the preferred distance hasn't been reached + break; + } + } + } + } + Vec2f thisCurve = curCurve.getCurvePoint()[curPoint]; + + // interpolate the point between the two closest distances + if (distanceAt - lastDistanceAt > 1) { + float t = (prefDistance - lastDistanceAt) / (distanceAt - lastDistanceAt); + curve[i] = new Vec2f(lerp(lastCurve.x, thisCurve.x, t), lerp(lastCurve.y, thisCurve.y, t)); + } else + curve[i] = thisCurve; + } + +// if (hitObject.getRepeatCount() > 1) { + Vec2f c1 = curve[0]; + int cnt = 1; + Vec2f c2 = curve[cnt++]; + while (cnt <= ncurve && c2.cpy().sub(c1).len() < 1) + c2 = curve[cnt++]; + this.startAngle = (float) (Math.atan2(c2.y - c1.y, c2.x - c1.x) * 180 / Math.PI); + + c1 = curve[ncurve]; + cnt = ncurve - 1; + c2 = curve[cnt--]; + while (cnt >= 0 && c2.cpy().sub(c1).len() < 1) + c2 = curve[cnt--]; + this.endAngle = (float) (Math.atan2(c2.y - c1.y, c2.x - c1.x) * 180 / Math.PI); +// } + } + + @Override + public float[] pointAt(float t) { + float indexF = t * ncurve; + int index = (int) indexF; + if (index >= ncurve) { + Vec2f poi = curve[ncurve]; + return new float[] { poi.x, poi.y }; + } else { + Vec2f poi = curve[index]; + Vec2f poi2 = curve[index + 1]; + float t2 = indexF - index; + return new float[] { + lerp(poi.x, poi2.x, t2), + lerp(poi.y, poi2.y, t2) + }; + } + } + + @Override + public float getEndAngle() { return endAngle; } + + @Override + public float getStartAngle() { return startAngle; } +} diff --git a/src/itdelatrisu/opsu/objects/curves/LinearBezier.java b/src/itdelatrisu/opsu/objects/curves/LinearBezier.java index ca7dede2..5d2e7a5c 100644 --- a/src/itdelatrisu/opsu/objects/curves/LinearBezier.java +++ b/src/itdelatrisu/opsu/objects/curves/LinearBezier.java @@ -18,50 +18,46 @@ package itdelatrisu.opsu.objects.curves; -import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.OsuHitObject; -import itdelatrisu.opsu.Utils; - -import java.util.Iterator; import java.util.LinkedList; import org.newdawn.slick.Color; -import org.newdawn.slick.Image; /** - * Representation of a Bezier curve with equidistant points. + * Representation of Bezier curve with equidistant points. * http://pomax.github.io/bezierinfo/#tracing * * @author fluddokt (https://github.com/fluddokt) */ -public class LinearBezier extends Curve { - /** The angles of the first and last control points for drawing. */ - private float startAngle, endAngle; - - /** List of Bezier curves in the set of points. */ - private LinkedList beziers = new LinkedList(); - - /** Points along the curve at equal distance. */ - private Vec2f[] curve; - - /** The number of points along the curve. */ - private int ncurve; +public class LinearBezier extends EqualDistanceMultiCurve { /** * Constructor. * @param hitObject the associated OsuHitObject * @param color the color of this curve */ - public LinearBezier(OsuHitObject hitObject, Color color) { + public LinearBezier(OsuHitObject hitObject, Color color, boolean line) { super(hitObject, color); - // splits points into different Beziers if has the same points (red points) + LinkedList beziers = new LinkedList(); + + // Beziers: splits points into different Beziers if has the same points (red points) + // a b c - c d - d e f g + // Lines: generate a new curve for each sequential pair + // ab bc cd de ef fg + int controlPoints = hitObject.getSliderX().length + 1; LinkedList points = new LinkedList(); // temporary list of points to separate different Bezier curves Vec2f lastPoi = null; for (int i = 0; i < controlPoints; i++) { Vec2f tpoi = new Vec2f(getX(i), getY(i)); - if (lastPoi != null && tpoi.equals(lastPoi)) { + if (line) { + if(lastPoi != null) { + points.add(tpoi); + beziers.add(new Bezier2(points.toArray(new Vec2f[0]))); + points.clear(); + } + } else if (lastPoi != null && tpoi.equals(lastPoi)) { if (points.size() >= 2) beziers.add(new Bezier2(points.toArray(new Vec2f[0]))); points.clear(); @@ -69,113 +65,14 @@ public class LinearBezier extends Curve { points.add(tpoi); lastPoi = tpoi; } - if (points.size() < 2) { + if (line || points.size() < 2) { // trying to continue Bezier with less than 2 points // probably ending on a red point, just ignore it } else { beziers.add(new Bezier2(points.toArray(new Vec2f[0]))); points.clear(); } - - // find the length of all beziers -// int totalDistance = 0; -// for (Bezier2 bez : beziers) { -// totalDistance += bez.totalDistance(); -// } - - // now try to creates points the are equidistant to each other - this.ncurve = (int) (hitObject.getPixelLength() / 5f); - this.curve = new Vec2f[ncurve + 1]; - - float distanceAt = 0; - Iterator iter = beziers.iterator(); - int curPoint = 0; - Bezier2 curBezier = iter.next(); - Vec2f lastCurve = curBezier.getCurve()[0]; - float lastDistanceAt = 0; - - // length of Bezier should equal pixel length (in 640x480) - float pixelLength = hitObject.getPixelLength() * OsuHitObject.getXMultiplier(); - - // for each distance, try to get in between the two points that are between it - for (int i = 0; i < ncurve + 1; i++) { - int prefDistance = (int) (i * pixelLength / ncurve); - while (distanceAt < prefDistance) { - lastDistanceAt = distanceAt; - lastCurve = curBezier.getCurve()[curPoint]; - distanceAt += curBezier.getCurveDistances()[curPoint++]; - - if (curPoint >= curBezier.points()) { - if (iter.hasNext()) { - curBezier = iter.next(); - curPoint = 0; - } else { - curPoint = curBezier.points() - 1; - if (lastDistanceAt == distanceAt) { - // out of points even though the preferred distance hasn't been reached - break; - } - } - } - } - Vec2f thisCurve = curBezier.getCurve()[curPoint]; - - // interpolate the point between the two closest distances - if (distanceAt - lastDistanceAt > 1) { - float t = (prefDistance - lastDistanceAt) / (distanceAt - lastDistanceAt); - curve[i] = new Vec2f(lerp(lastCurve.x, thisCurve.x, t), lerp(lastCurve.y, thisCurve.y, t)); - } else - curve[i] = thisCurve; - } - -// if (hitObject.getRepeatCount() > 1) { - Vec2f c1 = curve[0]; - int cnt = 1; - Vec2f c2 = curve[cnt++]; - while (cnt <= ncurve && c2.cpy().sub(c1).len() < 1) - c2 = curve[cnt++]; - this.startAngle = (float) (Math.atan2(c2.y - c1.y, c2.x - c1.x) * 180 / Math.PI); - - c1 = curve[ncurve]; - cnt = ncurve - 1; - c2 = curve[cnt--]; - while (cnt >= 0 && c2.cpy().sub(c1).len() < 1) - c2 = curve[cnt--]; - this.endAngle = (float) (Math.atan2(c2.y - c1.y, c2.x - c1.x) * 180 / Math.PI); -// } + + init(beziers); } - - @Override - public float[] pointAt(float t) { - float indexF = t * ncurve; - int index = (int) indexF; - if (index >= ncurve) { - Vec2f poi = curve[ncurve]; - return new float[] { poi.x, poi.y }; - } else { - Vec2f poi = curve[index]; - Vec2f poi2 = curve[index + 1]; - float t2 = indexF - index; - return new float[] { - lerp(poi.x, poi2.x, t2), - lerp(poi.y, poi2.y, t2) - }; - } - } - - @Override - public void draw(Color color) { - Image hitCircle = GameImage.HITCIRCLE.getImage(); - Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage(); - for (int i = curve.length - 2; i >= 0; i--) - hitCircleOverlay.drawCentered(curve[i].x, curve[i].y, Utils.COLOR_WHITE_FADE); - for (int i = curve.length - 2; i >= 0; i--) - hitCircle.drawCentered(curve[i].x, curve[i].y, color); - } - - @Override - public float getEndAngle() { return endAngle; } - - @Override - public float getStartAngle() { return startAngle; } } diff --git a/src/itdelatrisu/opsu/objects/curves/Vec2f.java b/src/itdelatrisu/opsu/objects/curves/Vec2f.java index b49bac2d..b857ad33 100644 --- a/src/itdelatrisu/opsu/objects/curves/Vec2f.java +++ b/src/itdelatrisu/opsu/objects/curves/Vec2f.java @@ -49,6 +49,28 @@ public class Vec2f { return new Vec2f((x + o.x) / 2, (y + o.y) / 2); } + /** + * Scales the vector. + * @param s scaler to scale by + * @return itself (for chaining) + */ + public Vec2f scale(float s) { + x *= s; + y *= s; + return this; + } + + /** + * Adds a vector to this vector. + * @param o the other vector + * @return itself (for chaining) + */ + public Vec2f add(Vec2f o) { + x += o.x; + y += o.y; + return this; + } + /** * Subtracts a vector from this vector. * @param o the other vector @@ -97,4 +119,8 @@ public class Vec2f { * @return true if the two vectors are numerically equal */ public boolean equals(Vec2f o) { return (x == o.x && y == o.y); } + + public String toString(){ + return "Vec2f:"+x+" "+y; + } } diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 6032b5b8..cede90d4 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -1043,6 +1043,16 @@ public class Game extends BasicGameState { // reset game data resetGameData(); + // load the first timingPoint for stacking + timingPointIndex = 0; + beatLengthBase = beatLength = 1; + if (!osu.timingPoints.isEmpty()) { + OsuTimingPoint timingPoint = osu.timingPoints.get(0); + if (!timingPoint.isInherited()) { + setBeatLength(timingPoint, true); + timingPointIndex++; + } + } // initialize object maps for (int i = 0; i < osu.objects.length; i++) { OsuHitObject hitObject = osu.objects[i];