Initial Repository Push

This commit is contained in:
2022-04-30 09:41:17 -04:00
parent d4eef9097a
commit bbfdde57a3
835 changed files with 168392 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.math;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicFloat {
private final AtomicInteger fl;
public AtomicFloat() {
fl = new AtomicInteger(Float.floatToIntBits(0f));
}
public AtomicFloat(float value) {
fl = new AtomicInteger(Float.floatToIntBits(value));
}
public float addAndGet(float delta) {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) + delta))) {
oldValue = fl.get();
}
return fl.get();
}
public boolean compareAndSet(float oldVal, float newVal) {
return fl.compareAndSet(Float.floatToIntBits(oldVal), Float.floatToIntBits(newVal));
}
public float decrementAndGet() {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) - 1f))) {
oldValue = fl.get();
}
return fl.get();
}
public float get() {
return Float.intBitsToFloat(fl.get());
}
public float getAndAdd(float delta) {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) + delta))) {
oldValue = fl.get();
}
return oldValue;
}
public float getAndIncrement() {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) + 1f))) {
oldValue = fl.get();
}
return oldValue;
}
public float getAndDecrement(float delta) {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) - 1f))) {
oldValue = fl.get();
}
return oldValue;
}
public float getAndSet(float value) {
return Float.intBitsToFloat(fl.getAndSet(Float.floatToIntBits(value)));
}
public float incrementAndGet() {
int oldValue = fl.get();
while (!fl.compareAndSet(oldValue, Float.floatToIntBits(Float.intBitsToFloat(oldValue) + 1f))) {
oldValue = fl.get();
}
return fl.get();
}
public void lazySet(float value) {
fl.lazySet(Float.floatToIntBits(value));
}
public void set(float value) {
fl.set(Float.floatToIntBits(value));
}
@Override
public String toString() {
return fl.toString();
}
public boolean weakCompareAndSet(float oldVal, float newVal) {
return fl.weakCompareAndSet(Float.floatToIntBits(oldVal), Float.floatToIntBits(newVal));
}
}
+583
View File
@@ -0,0 +1,583 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.math;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.ZoneManager;
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
import engine.objects.*;
import engine.server.MBServerStatics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.LinkedBlockingQueue;
/**
* This class contains all methods of storing bounds
* information within MagicBane and performing collision
* detection against them.
* <p>
* These objects are essentially an AABB, given rotations
* in MagicBane for placed objects come in a quantum of 90.
*/
public class Bounds {
private static final LinkedBlockingQueue<Bounds> boundsPool = new LinkedBlockingQueue<>();
public static HashMap<Integer,MeshBounds> meshBoundsCache = new HashMap<>();
private Vector2f origin = new Vector2f();
private Vector2f halfExtents = new Vector2f();
private float rotation;
private float rotationDegrees = 0;
private Quaternion quaternion;
private boolean flipExtents;
private ArrayList<Regions> regions = new ArrayList<>();
private ArrayList<Colliders> colliders = new ArrayList<>();
// Default constructor
public Bounds() {
origin.zero();
halfExtents.zero();
rotation = 0.0f;
flipExtents = false;
}
public static Bounds borrow() {
Bounds outBounds;
outBounds = boundsPool.poll();
if (outBounds == null)
outBounds = new Bounds();
return outBounds;
}
public void release() {
Bounds.zero(this);
boundsPool.add(this);
}
public void setBounds(Vector2f origin, Vector2f extents, float rotation) {
this.origin.set(origin);
this.halfExtents.set(extents);
this.rotation = rotation;
this.flipExtents = Bounds.calculateFlipExtents(this);
}
public void setBounds(PlacementInfo sourceInfo) {
Blueprint sourceBlueprint;
sourceBlueprint = Blueprint.getBlueprint(sourceInfo.getBlueprintUUID());
this.origin.set(sourceInfo.getLoc().x, sourceInfo.getLoc().z);
this.halfExtents.set(sourceBlueprint.getExtents());
this.quaternion = new Quaternion(sourceInfo.getRot().x, sourceInfo.getRot().y,sourceInfo.getRot().z,sourceInfo.getW());
this.rotation = sourceInfo.getRot().y;
this.flipExtents = Bounds.calculateFlipExtents(this);
}
public void setBounds(Bounds sourceBounds) {
origin.set(sourceBounds.origin);
halfExtents.set(sourceBounds.halfExtents);
this.rotation = sourceBounds.rotation;
this.flipExtents = sourceBounds.flipExtents;
}
public void setBounds(AbstractCharacter sourcePlayer) {
this.origin.set(sourcePlayer.getLoc().x, sourcePlayer.getLoc().z);
this.halfExtents.set(.5f, .5f);
this.rotation = 0;
this.flipExtents = false;
}
public void setBounds(Vector3fImmutable sourceLocation) {
this.origin.set(sourceLocation.x, sourceLocation.z);
this.halfExtents.set(.5f, .5f);
this.rotation = 0;
this.flipExtents = false;
}
public void setBounds(Vector3fImmutable sourceLocation, float halfExtent) {
this.origin.set(sourceLocation.x, sourceLocation.z);
this.halfExtents.set(halfExtent, halfExtent);
this.rotation = 0;
this.flipExtents = false;
}
public void setBounds(Building building) {
Blueprint blueprint;
MeshBounds meshBounds;
int halfExtentX;
int halfExtentY;
// Need a blueprint for proper bounds
blueprint = building.getBlueprint();
this.quaternion = new Quaternion(building.getRot().x, building.getRot().y,building.getRot().z,building.getw());
// Calculate Bounds for non-blueprint objects
if (blueprint == null) {
// If a mesh is a non-blueprint structure then we calculate
// it's bounding box based upon defaults from original source
// lookup.
meshBounds = meshBoundsCache.get(building.getMeshUUID());
this.origin.set(building.getLoc().x, building.getLoc().z);
// Magicbane uses half halfExtents
if (meshBounds == null){
halfExtentX = 1;
halfExtentY = 1;
}else{
float halfExtent = Math.max((meshBounds.maxX - meshBounds.minX)/2, (meshBounds.maxZ - meshBounds.minZ) /2);
halfExtentX = Math.round(halfExtent);
halfExtentY = Math.round(halfExtent);
}
// The rotation is reset after the new aabb is calculated.
this.rotation = building.getRot().y;
// Caclculate and set the new half halfExtents for the rotated bounding box
// and reset the rotation to 0 for this bounds.
this.halfExtents.set(halfExtentX, (halfExtentY));
this.rotation = 0;
this.setRegions(building);
this.setColliders(building);
return;
}
this.origin.set(building.getLoc().x, building.getLoc().z);
this.rotation = building.getRot().y;
this.halfExtents.set(blueprint.getExtents());
this.flipExtents = Bounds.calculateFlipExtents(this);
this.setRegions(building);
this.setColliders(building);
}
// Identity Bounds at location
public static void zero(Bounds bounds) {
bounds.origin.zero();
bounds.halfExtents.zero();
bounds.rotation = 0.0f;
bounds.flipExtents = false;
}
public static boolean collide(Vector3fImmutable location, Bounds targetBounds) {
if (targetBounds == null)
return false;
boolean collisionState = false;
Bounds identityBounds = Bounds.borrow();
identityBounds.setBounds(location);
collisionState = collide(targetBounds, identityBounds, 0.0f);
identityBounds.release();
return collisionState;
}
public static boolean collide(Vector3fImmutable location, Building targetBuilding) {
boolean collisionState = false;
Bounds targetBounds = targetBuilding.getBounds();
if (targetBounds == null)
return false;
Bounds identityBounds = Bounds.borrow();
identityBounds.setBounds(location);
collisionState = collide(targetBounds, identityBounds, 0.1f);
identityBounds.release();
return collisionState;
}
public static boolean collide(Bounds sourceBounds, Bounds targetBounds, float threshold) {
float deltaX;
float deltaY;
float extentX;
float extentY;
float sourceExtentX;
float sourceExtentY;
float targetExtentX;
float targetExtentY;
deltaX = Math.abs(sourceBounds.origin.x - targetBounds.origin.x);
deltaY = Math.abs(sourceBounds.origin.y - targetBounds.origin.y);
if (sourceBounds.flipExtents) {
sourceExtentX = sourceBounds.halfExtents.y;
sourceExtentY = sourceBounds.halfExtents.x;
}
else {
sourceExtentX = sourceBounds.halfExtents.x;
sourceExtentY = sourceBounds.halfExtents.y;
}
if (targetBounds.flipExtents) {
targetExtentX = targetBounds.halfExtents.y;
targetExtentY = targetBounds.halfExtents.x;
}
else {
targetExtentX = targetBounds.halfExtents.x;
targetExtentY = targetBounds.halfExtents.y;
}
extentX = sourceExtentX + targetExtentX;
extentY = sourceExtentY + targetExtentY;
// Return false on overlapping edge cases
if ((Math.abs(deltaX + threshold) < extentX))
if ((Math.abs(deltaY + threshold) < extentY))
return true;
return false;
}
// Method detects overlap of two given Bounds objects.
// Just your generic AABB collision algorythm.
public static boolean collide(PlacementInfo sourceInfo, Building targetBuilding) {
Bounds sourceBounds;
Bounds targetBounds;
boolean collisionState = false;
// Early exit sanity check. Can't quite collide against nothing
if ((sourceInfo == null) || (targetBuilding == null))
return false;
sourceBounds = Bounds.borrow();
sourceBounds.setBounds(sourceInfo);
// WARNING: DO NOT EVER RELEASE THESE WORLDOBJECT BOUNDS
// THEY ARE NOT IMMUTABLE
targetBounds = targetBuilding.getBounds();
// If target building has no bounds, we certainly cannot collide.
// Note: We remove and release bounds objects to the pool when
// buildings are destroyed.
if (targetBounds == null)
return false;
collisionState = collide(sourceBounds, targetBounds,.1f);
// Release bounds and return collision state
sourceBounds.release();
return collisionState;
}
public static boolean collide(Bounds bounds, Vector3fImmutable start, Vector3fImmutable end) {
boolean collide = false;
for (Colliders collider: bounds.colliders) {
collide = linesTouching(collider.startX, collider.startY, collider.endX,collider.endY, start.x, start.z, end.x,end.z);
if (collide)
break;
}
return collide;
}
//used for wall collision with players.
public static Vector3fImmutable PlayerBuildingCollisionPoint(PlayerCharacter player, Vector3fImmutable start, Vector3fImmutable end) {
Vector3fImmutable collidePoint = null;
//player can fly over walls when at max altitude. skip collision checks.
if (player.getAltitude() >= 60)
return null;
float distance = player.getLoc().distance2D(end);
// Players should not be able to move more than 2000 units at a time, stop them dead in their tracks if they do. (hacks)
if (distance > 2000)
return player.getLoc();
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(player, distance + 1000, MBServerStatics.MASK_BUILDING);
float collideDistance = 0;
float lastDistance = -1;
for (AbstractWorldObject awo : awoList) {
Building building = (Building)awo;
//player is inside building region, skip collision check. we only do collision from the outside.
if (player.getRegion() != null && player.getRegion().parentBuildingID == building.getObjectUUID())
continue;
if (building.getBounds().colliders == null)
continue;
for (Colliders collider: building.getBounds().colliders) {
//links are what link together buildings, allow players to run through them only if they are in a building already.
if (collider.isLink() && player.getRegion() != null)
continue;
if (collider.getDoorID() != 0 && building.isDoorOpen(collider.getDoorID()))
continue;
Vector3fImmutable tempCollidePoint = lineIntersection(collider.startX, collider.startY, collider.endX,collider.endY, start.x, start.z, end.x,end.z);
//didnt collide, skip distance checks.
if (tempCollidePoint == null)
continue;
//first collision detection, inititialize all variables.
if (lastDistance == -1) {
collideDistance = start.distance2D(tempCollidePoint);
lastDistance = collideDistance;
collidePoint = tempCollidePoint;
}else
//get closest collide point.
collideDistance = start.distance2D(tempCollidePoint);
if (collideDistance < lastDistance) {
lastDistance = collideDistance;
collidePoint = tempCollidePoint;
}
}
}
//
if (collidePoint != null) {
if(collideDistance >= 2)
collidePoint = player.getFaceDir().scaleAdd(-2f, new Vector3fImmutable((float) collidePoint.getX(), end.y, (float) collidePoint.getZ()));
else
collidePoint = player.getLoc();
}
return collidePoint;
}
public static boolean linesTouching(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
float denominator = ((x2 - x1) * (y4 - y3)) - ((y2 - y1) * (x4 - x3));
float numerator1 = ((y1 - y3) * (x4 - x3)) - ((x1 - x3) * (y4 - y3));
float numerator2 = ((y1 - y3) * (x2 - x1)) - ((x1 - x3) * (y2 - y1));
// Detect coincident lines (has a problem, read below)
if (denominator == 0) return numerator1 == 0 && numerator2 == 0;
float r = numerator1 / denominator;
float s = numerator2 / denominator;
return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
}
public static Vector3fImmutable lineIntersection(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
// calculate the distance to intersection point
float uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
float uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
// if uA and uB are between 0-1, lines are colliding
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
return new Vector3fImmutable(x1 + (uA * (x2-x1)),0, y1 + (uA * (y2-y1)));
}
return null;
}
private static boolean calculateFlipExtents(Bounds bounds) {
int degrees;
double radian =0;
if (bounds.quaternion != null){
radian = bounds.quaternion.angleY;
}
degrees = (int) Math.toDegrees(radian);
bounds.rotationDegrees = degrees;
if (degrees < 0)
degrees += 360;
return (degrees >= 85 && degrees <= 95) ||
(degrees >= 265 && degrees <= 275);
}
public void modify(float x, float y, float extents) {
this.origin.x = x;
this.origin.y = y;
this.halfExtents.x = extents;
this.halfExtents.y = extents;
}
/**
* @return the origin
*/
public Vector2f getOrigin() {
return origin;
}
/**
* @return the halfExtents
*/
public Vector2f getHalfExtents() {
return halfExtents;
}
/**
* @return the rotation
*/
public float getRotation() {
return rotation;
}
/**
* @param rotation the rotation to set
*/
public void setRotation(float rotation) {
this.rotation = rotation;
}
public void setRegions(Building building ){
//Collidables are for player movement collision
ArrayList<BuildingRegions> tempList = BuildingRegions._staticRegions.get(building.getMeshUUID());
ArrayList<Regions> tempRegions = new ArrayList<>();
if (tempList != null){
for (BuildingRegions buildingRegion:tempList){
ArrayList<Vector3f> regionPoints = new ArrayList<>();
Vector3f centerPoint = ZoneManager.convertLocalToWorld(building, buildingRegion.center, this);
for (Vector3f point: buildingRegion.getRegionPoints()){
Vector3f rotatedPoint = ZoneManager.convertLocalToWorld(building, point,this);
regionPoints.add(rotatedPoint);
}
tempRegions.add(new Regions(regionPoints, buildingRegion.getLevel(),buildingRegion.getRoom(),buildingRegion.isOutside(),buildingRegion.isExitRegion(), buildingRegion.isStairs(), centerPoint,building.getObjectUUID()));
}
}
this.regions = tempRegions;
}
public void setColliders(Building building ){
//Collidables are for player movement collision
ArrayList<StaticColliders> tempList = StaticColliders._staticColliders.get(building.getMeshUUID());
ArrayList<Colliders> tempColliders = new ArrayList<>();
if (tempList != null){
for (StaticColliders staticCollider :tempList){
ArrayList<Vector3f> regionPoints = new ArrayList<>();
Vector3f colliderStart = new Vector3f(staticCollider.getStartX(), 0, staticCollider.getStartY());
Vector3f colliderEnd = new Vector3f(staticCollider.getEndX(), 0, staticCollider.getEndY());
Vector3f worldStart = ZoneManager.convertLocalToWorld(building, colliderStart, this);
Vector3f worldEnd = ZoneManager.convertLocalToWorld(building, colliderEnd, this);
tempColliders.add(new Colliders(worldStart.x, worldStart.z, worldEnd.x, worldEnd.z, staticCollider.getDoorID(), staticCollider.isLink()));
}
}
this.colliders = tempColliders;
}
public ArrayList<Regions> getRegions() {
return regions;
}
public void setRegions(ArrayList<Regions> regions) {
this.regions = regions;
}
public static Vector3f getRotatedPoint(Vector3f point, float centerX, float centerZ, float angle){
//TRANSLATE TO ORIGIN
float x1 = point.getX() - centerX;
float y1 = point.getZ() - centerZ;
//APPLY ROTATION
float temp_x1 = (float) (x1 * Math.cos(angle) - y1 * Math.sin(angle));
float temp_z1 = (float) (x1 * Math.sin(angle) + y1 * Math.cos(angle));
temp_x1 += centerX;
temp_z1 += centerZ;
return new Vector3f(temp_x1,point.y,temp_z1);
}
public float getRotationDegrees() {
return rotationDegrees;
}
public boolean isFlipExtents() {
return flipExtents;
}
public Quaternion getQuaternion() {
return quaternion;
}
}
+668
View File
@@ -0,0 +1,668 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.math;
import java.util.Calendar;
import java.util.concurrent.ThreadLocalRandom;
/**
* <code>FastMath</code> provides 'fast' math approximations and float
* equivalents of Math functions. These are all used as static values and
* functions.
*
* @author Various
*/
final public class FastMath {
private FastMath() {
}
/** A "close to zero" double epsilon value for use */
public static final double DBL_EPSILON = 2.220446049250313E-16d;
/** A "close to zero" float epsilon value for use */
public static final float FLT_EPSILON = 1.1920928955078125E-7f;
/** A "close to zero" float epsilon value for use */
public static final float ZERO_TOLERANCE = 0.0001f;
public static final float ONE_THIRD = 1f / 3f;
/** The value PI as a float. (180 degrees) */
public static final float PI = (float) Math.PI;
/** The value 2PI as a float. (360 degrees) */
public static final float TWO_PI = 2.0f * PI;
/** The value PI/2 as a float. (90 degrees) */
public static final float HALF_PI = 0.5f * PI;
/** The value PI/4 as a float. (45 degrees) */
public static final float QUARTER_PI = 0.25f * PI;
/** The value 1/PI as a float. */
public static final float INV_PI = 1.0f / PI;
/** The value 1/(2PI) as a float. */
public static final float INV_TWO_PI = 1.0f / TWO_PI;
/** A value to multiply a degree value by, to convert it to radians. */
public static final float DEG_TO_RAD = PI / 180.0f;
/** A value to multiply a radian value by, to convert it to degrees. */
public static final float RAD_TO_DEG = 180.0f / PI;
/**
* Returns true if the number is a power of 2 (2,4,8,16...)
*
* A good implementation found on the Java boards. note: a number is a power
* of two if and only if it is the smallest number with that number of
* significant bits. Therefore, if you subtract 1, you know that the new
* number will have fewer bits, so ANDing the original number with anything
* less than it will give 0.
*
* @param number
* The number to test.
* @return True if it is a power of two.
*/
public static boolean isPowerOfTwo(int number) {
return (number > 0) && (number & (number - 1)) == 0;
}
public static int nearestPowerOfTwo(int number) {
return (int) Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
}
public static boolean between(float i, float minValueInclusive, float maxValueInclusive) {
return (i >= minValueInclusive && i <= maxValueInclusive);
}
/**
* Linear interpolation from startValue to endValue by the given percent.
* Basically: ((1 - percent) * startValue) + (percent * endValue)
*
* @param percent
* Percent value to use.
* @param startValue
* Begining value. 0% of f
* @param endValue
* ending value. 100% of f
* @return The interpolated value between startValue and endValue.
*/
public static float LERP(float percent, float startValue, float endValue) {
if (startValue == endValue)
return startValue;
return ((1 - percent) * startValue) + (percent * endValue);
}
/**
* Returns the arc cosine of an angle given in radians.<br>
* Special cases:
* <ul>
* <li>If fValue is smaller than -1, then the result is PI.
* <li>If the argument is greater than 1, then the result is 0.
* </ul>
*
* @param fValue
* The angle, in radians.
* @return fValue's acos
* @see java.lang.Math#acos(double)
*/
public static float acos(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f)
return (float) Math.acos(fValue);
return 0.0f;
}
return PI;
}
/**
* Returns the arc sine of an angle given in radians.<br>
* Special cases:
* <ul>
* <li>If fValue is smaller than -1, then the result is -HALF_PI.
* <li>If the argument is greater than 1, then the result is HALF_PI.
* </ul>
*
* @param fValue
* The angle, in radians.
* @return fValue's asin
* @see java.lang.Math#asin(double)
*/
public static float asin(float fValue) {
if (-1.0f < fValue) {
if (fValue < 1.0f)
return (float) Math.asin(fValue);
return HALF_PI;
}
return -HALF_PI;
}
/**
* Returns the arc tangent of an angle given in radians.<br>
*
* @param fValue
* The angle, in radians.
* @return fValue's asin
* @see java.lang.Math#atan(double)
*/
public static float atan(float fValue) {
return (float) Math.atan(fValue);
}
/**
* A direct call to Math.atan2.
*
* @param fY
* @param fX
* @return Math.atan2(fY,fX)
* @see java.lang.Math#atan2(double, double)
*/
public static float atan2(float fY, float fX) {
return (float) Math.atan2(fY, fX);
}
/**
* Rounds a fValue up. A call to Math.ceil
*
* @param fValue
* The value.
* @return The fValue rounded up
* @see java.lang.Math#ceil(double)
*/
public static float ceil(float fValue) {
return (float) Math.ceil(fValue);
}
/**
* Fast Trig functions for x86. This forces the trig functiosn to stay
* within the safe area on the x86 processor (-45 degrees to +45 degrees)
* The results may be very slightly off from what the Math and StrictMath
* trig functions give due to rounding in the angle reduction but it will be
* very very close.
*
*/
public static float reduceSinAngle(float radians) {
radians %= TWO_PI; // put us in -2PI to +2PI space
if (Math.abs(radians) > PI) { // put us in -PI to +PI space
radians -= (TWO_PI);
}
if (Math.abs(radians) > HALF_PI) {// put us in -PI/2 to +PI/2 space
radians = PI - radians;
}
return radians;
}
/**
* Returns sine of a value.
*
* @param fValue
* The value to sine, in radians.
* @return The sine of fValue.
* @see java.lang.Math#sin(double)
*/
public static float sin(float fValue) {
fValue = reduceSinAngle(fValue); // limits angle to between -PI/2 and
// +PI/2
if (Math.abs(fValue) <= Math.PI / 4) {
return (float) Math.sin(fValue);
}
return (float) Math.cos(Math.PI / 2 - fValue);
}
/**
* Returns cos of a value.
*
* @param fValue
* The value to cosine, in radians.
* @return The cosine of fValue.
* @see java.lang.Math#cos(double)
*/
public static float cos(float fValue) {
return sin(fValue + HALF_PI);
}
/**
* Returns E^fValue
*
* @param fValue
* Value to raise to a power.
* @return The value E^fValue
* @see java.lang.Math#exp(double)
*/
public static float exp(float fValue) {
return (float) Math.exp(fValue);
}
/**
* Returns Absolute value of a float.
*
* @param fValue
* The value to abs.
* @return The abs of the value.
* @see java.lang.Math#abs(float)
*/
public static float abs(float fValue) {
if (fValue < 0)
return -fValue;
return fValue;
}
/**
* Returns a number rounded down.
*
* @param fValue
* The value to round
* @return The given number rounded down
* @see java.lang.Math#floor(double)
*/
public static float floor(float fValue) {
return (float) Math.floor(fValue);
}
/**
* Returns 1/sqrt(fValue)
*
* @param fValue
* The value to process.
* @return 1/sqrt(fValue)
* @see java.lang.Math#sqrt(double)
*/
public static float invSqrt(float fValue) {
return (float) (1.0f / Math.sqrt(fValue));
}
/**
* Returns the log base E of a value.
*
* @param fValue
* The value to Logger.getInstance().
* @return The log of fValue base E
* @see java.lang.Math#log(double)
*/
public static float log(float fValue) {
return (float) Math.log(fValue);
}
/**
* Returns the logarithm of value with given base, calculated as
* log(value)/log(base), so that pow(base, return)==value (contributed by
* vear)
*
* @param value
* The value to Logger.getInstance().
* @param base
* Base of logarithm.
* @return The logarithm of value with given base
*/
public static float log(float value, float base) {
return (float) (Math.log(value) / Math.log(base));
}
/**
* Returns a number raised to an exponent power. fBase^fExponent
*
* @param fBase
* The base value (IE 2)
* @param fExponent
* The exponent value (IE 3)
* @return base raised to exponent (IE 8)
* @see java.lang.Math#pow(double, double)
*/
public static float pow(float fBase, float fExponent) {
return (float) Math.pow(fBase, fExponent);
}
/**
* Returns the value squared. fValue ^ 2
*
* @param fValue
* The vaule to square.
* @return The square of the given value.
*/
public static float sqr(float fValue) {
return fValue * fValue;
}
public static double sqr(double fValue) {
return fValue * fValue;
}
/**
* Returns the square root of a given value.
*
* @param fValue
* The value to sqrt.
* @return The square root of the given value.
* @see java.lang.Math#sqrt(double)
*/
public static float sqrt(float fValue) {
return (float) Math.sqrt(fValue);
}
/**
* Returns the tangent of a value. If USE_FAST_TRIG is enabled, an
* approximate value is returned. Otherwise, a direct value is used.
*
* @param fValue
* The value to tangent, in radians.
* @return The tangent of fValue.
* @see java.lang.Math#tan(double)
*/
public static float tan(float fValue) {
return (float) Math.tan(fValue);
}
/**
* Returns 1 if the number is positive, -1 if the number is negative, and 0
* otherwise
*
* @param iValue
* The integer to examine.
* @return The integer's sign.
*/
public static int sign(int iValue) {
if (iValue > 0)
return 1;
if (iValue < 0)
return -1;
return 0;
}
/**
* Returns 1 if the number is positive, -1 if the number is negative, and 0
* otherwise
*
* @param fValue
* The float to examine.
* @return The float's sign.
*/
public static float sign(float fValue) {
return Math.signum(fValue);
}
/**
* Given 3 points in a 2d plane, this function computes if the points going
* from A-B-C are moving counter clock wise.
*
* @param p0
* Point 0.
* @param p1
* Point 1.
* @param p2
* Point 2.
* @return 1 If they are CCW, -1 if they are not CCW, 0 if p2 is between p0
* and p1.
*/
public static int counterClockwise(Vector2f p0, Vector2f p1, Vector2f p2) {
float dx1, dx2, dy1, dy2;
dx1 = p1.x - p0.x;
dy1 = p1.y - p0.y;
dx2 = p2.x - p0.x;
dy2 = p2.y - p0.y;
if (dx1 * dy2 > dy1 * dx2)
return 1;
if (dx1 * dy2 < dy1 * dx2)
return -1;
if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0))
return -1;
if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2))
return 1;
return 0;
}
/**
* Test if a point is inside a triangle. 1 if the point is on the ccw side,
* -1 if the point is on the cw side, and 0 if it is on neither.
*
* @param t0
* First point of the triangle.
* @param t1
* Second point of the triangle.
* @param t2
* Third point of the triangle.
* @param p
* The point to test.
* @return Value 1 or -1 if inside triangle, 0 otherwise.
*/
public static int pointInsideTriangle(Vector2f t0, Vector2f t1,
Vector2f t2, Vector2f p) {
int val1 = counterClockwise(t0, t1, p);
if (val1 == 0)
return 1;
int val2 = counterClockwise(t1, t2, p);
if (val2 == 0)
return 1;
if (val2 != val1)
return 0;
int val3 = counterClockwise(t2, t0, p);
if (val3 == 0)
return 1;
if (val3 != val1)
return 0;
return val3;
}
/**
* Returns the determinant of a 4x4 matrix.
*/
public static float determinant(double m00, double m01, double m02,
double m03, double m10, double m11, double m12, double m13,
double m20, double m21, double m22, double m23, double m30,
double m31, double m32, double m33) {
double det01 = m20 * m31 - m21 * m30;
double det02 = m20 * m32 - m22 * m30;
double det03 = m20 * m33 - m23 * m30;
double det12 = m21 * m32 - m22 * m31;
double det13 = m21 * m33 - m23 * m31;
double det23 = m22 * m33 - m23 * m32;
return (float) (m00 * (m11 * det23 - m12 * det13 + m13 * det12) - m01
* (m10 * det23 - m12 * det03 + m13 * det02) + m02
* (m10 * det13 - m11 * det03 + m13 * det01) - m03
* (m10 * det12 - m11 * det02 + m12 * det01));
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive
* Y as up) and stores the results in the store var.
*/
public static Vector3f sphericalToCartesian(Vector3f sphereCoords,
Vector3f store) {
store.y = sphereCoords.x * FastMath.sin(sphereCoords.z);
float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
store.x = a * FastMath.cos(sphereCoords.y);
store.z = a * FastMath.sin(sphereCoords.y);
return store;
}
/**
* Converts a point from Cartesian coordinates (using positive Y as up) to
* Spherical and stores the results in the store var. (Radius, Azimuth,
* Polar)
*/
public static Vector3f cartesianToSpherical(Vector3f cartCoords,
Vector3f store) {
if (cartCoords.x == 0)
cartCoords.x = FastMath.FLT_EPSILON;
store.x = FastMath
.sqrt((cartCoords.x * cartCoords.x)
+ (cartCoords.y * cartCoords.y)
+ (cartCoords.z * cartCoords.z));
store.y = FastMath.atan(cartCoords.z / cartCoords.x);
if (cartCoords.x < 0)
store.y += FastMath.PI;
store.z = FastMath.asin(cartCoords.y / store.x);
return store;
}
/**
* Converts a point from Spherical coordinates to Cartesian (using positive
* Z as up) and stores the results in the store var.
*/
public static Vector3f sphericalToCartesianZ(Vector3f sphereCoords,
Vector3f store) {
store.z = sphereCoords.x * FastMath.sin(sphereCoords.z);
float a = sphereCoords.x * FastMath.cos(sphereCoords.z);
store.x = a * FastMath.cos(sphereCoords.y);
store.y = a * FastMath.sin(sphereCoords.y);
return store;
}
/**
* Converts a point from Cartesian coordinates (using positive Z as up) to
* Spherical and stores the results in the store var. (Radius, Azimuth,
* Polar)
*/
public static Vector3f cartesianZToSpherical(Vector3f cartCoords,
Vector3f store) {
if (cartCoords.x == 0)
cartCoords.x = FastMath.FLT_EPSILON;
store.x = FastMath
.sqrt((cartCoords.x * cartCoords.x)
+ (cartCoords.y * cartCoords.y)
+ (cartCoords.z * cartCoords.z));
store.z = FastMath.atan(cartCoords.z / cartCoords.x);
if (cartCoords.x < 0)
store.z += FastMath.PI;
store.y = FastMath.asin(cartCoords.y / store.x);
return store;
}
/**
* Takes an value and expresses it in terms of min to max.
*
* @param val
* - the angle to normalize (in radians)
* @return the normalized angle (also in radians)
*/
public static float normalize(float val, float min, float max) {
if (Float.isInfinite(val) || Float.isNaN(val))
return 0f;
float range = max - min;
while (val > max)
val -= range;
while (val < min)
val += range;
return val;
}
/**
* @param x
* the value whose sign is to be adjusted.
* @param y
* the value whose sign is to be used.
* @return x with its sign changed to match the sign of y.
*/
public static float copysign(float x, float y) {
if (y >= 0 && x <= -0)
return -x;
else if (y < 0 && x >= 0)
return -x;
else
return x;
}
/**
* Take a float input and clamp it between min and max.
*
* @param input
* @param min
* @param max
* @return clamped input
*/
public static float clamp(float input, float min, float max) {
return (input < min) ? min : (input > max) ? max : input;
}
/**
* Return a random 2D vector
* this needs checked
*/
public static Vector3fImmutable randomVector2D() {
float x = ((ThreadLocalRandom.current().nextFloat() * 2) - 1);
float z = ((ThreadLocalRandom.current().nextFloat() * 2) - 1);
Vector3fImmutable ret = new Vector3fImmutable(x, 0, z);
return ret.normalize();
}
/**
* Turns a String into an Integer hash that the client will recognize.
*
* @param s
* The String to hash
* @return the Integer hash
*/
public static int hash(String s) {
int out = 0, pad = 0;
for(char c : s.toCharArray()) {
if(c == ' ' || c == '\\') {
pad += 5;
continue;
}
if(c > 0x40 && c < 0x60)
out ^= _rotl((byte) 0x60, pad);
out ^= _rotl((byte) (c & 0xDF), pad);
pad += 5;
}
return out;
}
/**
* Utility function for making hashes
*/
private static int _rotl(int value, int shift) {
if ((shift &= 31) == 0)
return value;
return (value << shift) | (value >> (32 - shift));
}
/**
* Gets number of seconds until next hours
*/
public static int secondsUntilNextHour() {
Calendar cal = Calendar.getInstance();
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
return 3600 - (minute * 60) - second;
}
public static float area(float x1, float y1, float x2, float y2, float x3, float y3){
return (float) Math.abs((x1*(y2-y3) + x2*(y3-y1)+ x3*(y1-y2))/2.0); //Change to *.5?
}
public static float GetDegrees(float yRot){
double radian = Math.asin(yRot);
float degrees = (float) Math.toDegrees(radian);
degrees *=2;
return degrees;
}
public static float degreesToW(float degrees){
return (float) Math.abs(Math.cos(Math.toRadians(degrees)/2));
}
public static float degreesToYRotation(float degrees){
return (float)Math.sin(Math.toRadians(degrees)/2);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+662
View File
@@ -0,0 +1,662 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.math;
/**
* <code>Vector2f</code> defines a Vector for a two float value vector.
*
*/
public class Vector2f {
/**
* the x value of the vector.
*/
public float x;
/**
* the y value of the vector.
*/
public float y;
/**
* Creates a Vector2f with the given initial x and y values.
*
* @param x
* The x value of this Vector2f.
* @param y
* The y value of this Vector2f.
*/
public Vector2f(float x, float y) {
this.x = x;
this.y = y;
}
/**
* Creates a Vector2f with x and y set to 0. Equivalent to Vector2f(0,0).
*/
public Vector2f() {
x = y = 0;
}
/**
* Creates a new Vector2f that contains the passed vector's information
*
* @param vector2f
* The vector to copy
*/
public Vector2f(Vector2f vector2f) {
this.x = vector2f.x;
this.y = vector2f.y;
}
/**
* set the x and y values of the vector
*
* @param x
* the x value of the vector.
* @param y
* the y value of the vector.
* @return this vector
*/
public Vector2f set(float x, float y) {
this.x = x;
this.y = y;
return this;
}
/**
* set the x and y values of the vector from another vector
*
* @param vec
* the vector to copy from
* @return this vector
*/
public Vector2f set(Vector2f vec) {
this.x = vec.x;
this.y = vec.y;
return this;
}
/**
* <code>add</code> adds a provided vector to this vector creating a
* resultant vector which is returned. If the provided vector is null, null
* is returned.
*
* @param vec
* the vector to add to this.
* @return the resultant vector.
*/
public Vector2f add(Vector2f vec) {
if (null == vec) {
return null;
}
return new Vector2f(x + vec.x, y + vec.y);
}
/**
* <code>addLocal</code> adds a provided vector to this vector internally,
* and returns a handle to this vector for easy chaining of calls. If the
* provided vector is null, null is returned.
*
* @param vec
* the vector to add to this vector.
* @return this
*/
public Vector2f addLocal(Vector2f vec) {
if (null == vec) {
return null;
}
x += vec.x;
y += vec.y;
return this;
}
/**
* <code>addLocal</code> adds the provided values to this vector internally,
* and returns a handle to this vector for easy chaining of calls.
*
* @param addX
* value to add to x
* @param addY
* value to add to y
* @return this
*/
public Vector2f addLocal(float addX, float addY) {
x += addX;
y += addY;
return this;
}
/**
* <code>add</code> adds this vector by <code>vec</code> and stores the
* result in <code>result</code>.
*
* @param vec
* The vector to add.
* @param result
* The vector to store the result in.
* @return The result vector, after adding.
*/
public Vector2f add(Vector2f vec, Vector2f result) {
if (null == vec) {
return null;
}
if (result == null)
result = new Vector2f();
result.x = x + vec.x;
result.y = y + vec.y;
return result;
}
/**
* <code>dot</code> calculates the dot product of this vector with a
* provided vector. If the provided vector is null, 0 is returned.
*
* @param vec
* the vector to dot with this vector.
* @return the resultant dot product of this vector and a given vector.
*/
public float dot(Vector2f vec) {
if (null == vec) {
return 0;
}
return x * vec.x + y * vec.y;
}
/**
* <code>cross</code> calculates the cross product of this vector with a
* parameter vector v.
*
* @param v
* the vector to take the cross product of with this.
* @return the cross product vector.
*/
public Vector3f cross(Vector2f v) {
return new Vector3f(0, 0, determinant(v));
}
public float determinant(Vector2f v) {
return (x * v.y) - (y * v.x);
}
/**
* Sets this vector to the interpolation by changeAmnt from this to the
* finalVec this=(1-changeAmnt)*this + changeAmnt * finalVec
*
* @param finalVec
* The final vector to interpolate towards
* @param changeAmnt
* An amount between 0.0 - 1.0 representing a percentage change
* from this towards finalVec
*/
public void interpolate(Vector2f finalVec, float changeAmnt) {
this.x = (1 - changeAmnt) * this.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * this.y + changeAmnt * finalVec.y;
}
/**
* Sets this vector to the interpolation by changeAmnt from beginVec to
* finalVec this=(1-changeAmnt)*beginVec + changeAmnt * finalVec
*
* @param beginVec
* The begining vector (delta=0)
* @param finalVec
* The final vector to interpolate towards (delta=1)
* @param changeAmnt
* An amount between 0.0 - 1.0 representing a precentage change
* from beginVec towards finalVec
*/
public void interpolate(Vector2f beginVec, Vector2f finalVec,
float changeAmnt) {
this.x = (1 - changeAmnt) * beginVec.x + changeAmnt * finalVec.x;
this.y = (1 - changeAmnt) * beginVec.y + changeAmnt * finalVec.y;
}
/**
* Check a vector... if it is null or its floats are NaN or infinite, return
* false. Else return true.
*
* @param vector
* the vector to check
* @return true or false as stated above.
*/
public static boolean isValidVector(Vector2f vector) {
if (vector == null)
return false;
if (Float.isNaN(vector.x) || Float.isNaN(vector.y))
return false;
return !Float.isInfinite(vector.x) && !Float.isInfinite(vector.y);
}
public static boolean isZeroVector(Vector2f vector) {
return (vector.x == 0) &&
(vector.y == 0);
}
/**
* <code>length</code> calculates the magnitude of this vector.
*
* @return the length or magnitude of the vector.
*/
public float length() {
return FastMath.sqrt(lengthSquared());
}
/**
* <code>lengthSquared</code> calculates the squared value of the magnitude
* of the vector.
*
* @return the magnitude squared of the vector.
*/
public float lengthSquared() {
return x * x + y * y;
}
/**
* <code>distanceSquared</code> calculates the distance squared between this
* vector and vector v.
*
* @param v
* the second vector to determine the distance squared.
* @return the distance squared between the two vectors.
*/
public float distanceSquared(Vector2f v) {
double dx = x - v.x;
double dy = y - v.y;
return (float) (dx * dx + dy * dy);
}
/**
* <code>distanceSquared</code> calculates the distance squared between this
* vector and vector v.
*
* @return the distance squared between the two vectors.
*/
public float distanceSquared(float otherX, float otherY) {
double dx = x - otherX;
double dy = y - otherY;
return (float) (dx * dx + dy * dy);
}
/**
* <code>distance</code> calculates the distance between this vector and
* vector v.
*
* @param v
* the second vector to determine the distance.
* @return the distance between the two vectors.
*/
public float distance(Vector2f v) {
return FastMath.sqrt(distanceSquared(v));
}
/**
* <code>mult</code> multiplies this vector by a scalar. The resultant
* vector is returned.
*
* @param scalar
* the value to multiply this vector by.
* @return the new vector.
*/
public Vector2f mult(float scalar) {
return new Vector2f(x * scalar, y * scalar);
}
/**
* <code>multLocal</code> multiplies this vector by a scalar internally, and
* returns a handle to this vector for easy chaining of calls.
*
* @param scalar
* the value to multiply this vector by.
* @return this
*/
public Vector2f multLocal(float scalar) {
x *= scalar;
y *= scalar;
return this;
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* @return this
*/
public Vector2f multLocal(Vector2f vec) {
if (null == vec) {
return null;
}
x *= vec.x;
y *= vec.y;
return this;
}
/**
* Multiplies this Vector2f's x and y by the scalar and stores the result in
* product. The result is returned for chaining. Similar to
* product=this*scalar;
*
* @param scalar
* The scalar to multiply by.
* @param product
* The vector2f to store the result in.
* @return product, after multiplication.
*/
public Vector2f mult(float scalar, Vector2f product) {
if (null == product) {
product = new Vector2f();
}
product.x = x * scalar;
product.y = y * scalar;
return product;
}
/**
* <code>divide</code> divides the values of this vector by a scalar and
* returns the result. The values of this vector remain untouched.
*
* @param scalar
* the value to divide this vectors attributes by.
* @return the result <code>Vector</code>.
*/
public Vector2f divide(float scalar) {
return new Vector2f(x / scalar, y / scalar);
}
/**
* <code>divideLocal</code> divides this vector by a scalar internally, and
* returns a handle to this vector for easy chaining of calls. Dividing by
* zero will result in an exception.
*
* @param scalar
* the value to divides this vector by.
* @return this
*/
public Vector2f divideLocal(float scalar) {
x /= scalar;
y /= scalar;
return this;
}
/**
* <code>negate</code> returns the negative of this vector. All values are
* negated and set to a new vector.
*
* @return the negated vector.
*/
public Vector2f negate() {
return new Vector2f(-x, -y);
}
/**
* <code>negateLocal</code> negates the internal values of this vector.
*
* @return this.
*/
public Vector2f negateLocal() {
x = -x;
y = -y;
return this;
}
/**
* <code>subtract</code> subtracts the values of a given vector from those
* of this vector creating a new vector object. If the provided vector is
* null, an exception is thrown.
*
* @param vec
* the vector to subtract from this vector.
* @return the result vector.
*/
public Vector2f subtract(Vector2f vec) {
return subtract(vec, null);
}
/**
* <code>subtract</code> subtracts the values of a given vector from those
* of this vector storing the result in the given vector object. If the
* provided vector is null, an exception is thrown.
*
* @param vec
* the vector to subtract from this vector.
* @param store
* the vector to store the result in. It is safe for this to be
* the same as vec. If null, a new vector is created.
* @return the result vector.
*/
public Vector2f subtract(Vector2f vec, Vector2f store) {
if (store == null)
store = new Vector2f();
store.x = x - vec.x;
store.y = y - vec.y;
return store;
}
/**
* <code>subtract</code> subtracts the given x,y values from those of this
* vector creating a new vector object.
*
* @param valX
* value to subtract from x
* @param valY
* value to subtract from y
* @return this
*/
public Vector2f subtract(float valX, float valY) {
return new Vector2f(x - valX, y - valY);
}
/**
* <code>subtractLocal</code> subtracts a provided vector to this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to subtract
* @return this
*/
public Vector2f subtractLocal(Vector2f vec) {
if (null == vec) {
return null;
}
x -= vec.x;
y -= vec.y;
return this;
}
/**
* <code>subtractLocal</code> subtracts the provided values from this vector
* internally, and returns a handle to this vector for easy chaining of
* calls.
*
* @param valX
* value to subtract from x
* @param valY
* value to subtract from y
* @return this
*/
public Vector2f subtractLocal(float valX, float valY) {
x -= valX;
y -= valY;
return this;
}
/**
* <code>normalize</code> returns the unit vector of this vector.
*
* @return unit vector of this vector.
*/
public Vector2f normalize() {
float length = length();
if (length != 0) {
return divide(length);
}
return divide(1);
}
/**
* <code>normalizeLocal</code> makes this vector into a unit vector of
* itself.
*
* @return this.
*/
public Vector2f normalizeLocal() {
float length = length();
if (length != 0) {
return divideLocal(length);
}
return divideLocal(1);
}
/**
* <code>smallestAngleBetween</code> returns (in radians) the minimum angle
* between two vectors. It is assumed that both this vector and the given
* vector are unit vectors (iow, normalized).
*
* @param otherVector
* a unit vector to find the angle against
* @return the angle in radians.
*/
public float smallestAngleBetween(Vector2f otherVector) {
float dotProduct = dot(otherVector);
return FastMath.acos(dotProduct);
}
/**
* <code>angleBetween</code> returns (in radians) the angle required to
* rotate a ray represented by this vector to lie colinear to a ray
* described by the given vector. It is assumed that both this vector and
* the given vector are unit vectors (iow, normalized).
*
* @param otherVector
* the "destination" unit vector
* @return the angle in radians.
*/
public float angleBetween(Vector2f otherVector) {
return FastMath.atan2(otherVector.y, otherVector.x)
- FastMath.atan2(y, x);
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
/**
* <code>getAngle</code> returns (in radians) the angle represented by this
* Vector2f as expressed by a conversion from rectangular coordinates (
* <code>x</code>,&nbsp;<code>y</code>) to polar coordinates
* (r,&nbsp;<i>theta</i>).
*
* @return the angle in radians. [-pi, pi)
*/
public float getAngle() {
return -FastMath.atan2(y, x);
}
/**
* <code>zero</code> resets this vector's data to zero internally.
*/
public void zero() {
x = y = 0;
}
@Override
public Vector2f clone() {
try {
return (Vector2f) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // can not happen
}
}
/**
* Saves this Vector2f into the given float[] object.
*
* @param floats
* The float[] to take this Vector2f. If null, a new float[2] is
* created.
* @return The array, with X, Y float values in that order
*/
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[2];
}
floats[0] = x;
floats[1] = y;
return floats;
}
/**
* are these two vectors the same? they are is they both have the same x and
* y values.
*
* @param o
* the object to compare for equality
* @return true if they are equal
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof Vector2f)) {
return false;
}
if (this == o) {
return true;
}
Vector2f comp = (Vector2f) o;
if (Float.compare(x, comp.x) != 0)
return false;
return Float.compare(y, comp.y) == 0;
}
public void rotateAroundOrigin(float angle, boolean cw) {
if (cw)
angle = -angle;
float newX = FastMath.cos(angle) * x - FastMath.sin(angle) * y;
float newY = FastMath.sin(angle) * x + FastMath.cos(angle) * y;
x = newX;
y = newY;
}
public synchronized float getLat() {
return x;
}
public synchronized float getLong() {
return y;
}
public synchronized void setLat(float lat) {
this.x = lat;
}
public synchronized void setLong(float lon) {
this.y = lon;
}
}
File diff suppressed because it is too large Load Diff
+595
View File
@@ -0,0 +1,595 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.math;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.concurrent.ThreadLocalRandom;
import static engine.math.FastMath.sqr;
public class Vector3fImmutable {
public final float x, y, z;
public Vector3fImmutable() {
x = y = z = 0.0f;
}
public Vector3fImmutable(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3fImmutable(Vector3f original) {
this.x = original.x;
this.y = original.y;
this.z = original.z;
}
public Vector3fImmutable(Vector3fImmutable original) {
this.x = original.x;
this.y = original.y;
this.z = original.z;
}
public boolean isInsideCircle(Vector3fImmutable circleCenter, float radius) {
return (circleCenter.distanceSquared2D(this) < sqr(radius));
}
public Vector3fImmutable add(Vector3f vec) {
if (null == vec)
return null;
return new Vector3fImmutable(x + vec.x, y + vec.y, z + vec.z);
}
public Vector3fImmutable add(Vector3fImmutable vec) {
if (null == vec)
return null;
return new Vector3fImmutable(x + vec.x, y + vec.y, z + vec.z);
}
public Vector3fImmutable add(float x, float y, float z) {
return new Vector3fImmutable(this.x + x, this.y + y, this.z + z);
}
public Vector3fImmutable scaleAdd(float scalar, Vector3fImmutable add) {
return new Vector3fImmutable(x * scalar + add.x, y * scalar + add.y , z
* scalar + add.z);
}
public static Vector3fImmutable scaleAdd(float scalar, Vector3fImmutable mult,
Vector3fImmutable add) {
return new Vector3fImmutable(mult.x * scalar + add.x, mult.y * scalar
+ add.y, mult.z * scalar + add.z);
}
public float dot(Vector3fImmutable vec) {
if (null == vec) {
return 0.0f;
}
return x * vec.x + y * vec.y + z * vec.z;
}
public float dot2D(Vector3fImmutable vec) {
if (null == vec) {
return 0.0f;
}
return x * vec.x + z * vec.z;
}
public Vector3fImmutable cross(Vector3fImmutable v) {
return cross(v.x, v.y, v.z);
}
public Vector3fImmutable cross(float x, float y, float z) {
return new Vector3fImmutable(this.y * z - this.z * y, this.z * x
- this.x * z, this.x * y - this.y * x);
}
public float length() {
return FastMath.sqrt(lengthSquared());
}
public float lengthSquared() {
return x * x + y * y + z * z;
}
public float distanceSquared(Vector3fImmutable v) {
double dx = x - v.x;
double dy = y - v.y;
double dz = z - v.z;
return (float) (dx * dx + dy * dy + dz * dz);
}
public float magnitude() {
return FastMath.sqrt(sqrMagnitude());
}
public float sqrMagnitude() {
return x * x + y * y + z * z;
}
public Vector3fImmutable moveTowards (Vector3fImmutable target, float maxDistanceDelta)
{
Vector3fImmutable outVector;
Vector3fImmutable direction = target.subtract2D(this);
float magnitude = direction.magnitude();
if (magnitude <= maxDistanceDelta || magnitude == 0f)
{
return target;
}
outVector = direction.divide(magnitude).mult(maxDistanceDelta);
outVector = this.add(outVector);
return outVector;
}
public float distanceSquared2D(Vector3fImmutable v) {
double dx = x - v.x;
double dz = z - v.z;
return (float) (dx * dx + dz * dz);
}
public float distance(Vector3fImmutable v) {
return FastMath.sqrt(distanceSquared(v));
}
public float distance2D(Vector3fImmutable v) {
return FastMath.sqrt(distanceSquared2D(v));
}
public Vector3fImmutable mult(float scalar) {
return new Vector3fImmutable(x * scalar, y * scalar, z * scalar);
}
public Vector3fImmutable mult(Vector3fImmutable vec) {
if (null == vec) {
return null;
}
return new Vector3fImmutable(x * vec.x, y * vec.y, z * vec.z);
}
public Vector3fImmutable divide(float scalar) {
scalar = 1f / scalar;
return new Vector3fImmutable(x * scalar, y * scalar, z * scalar);
}
public Vector3fImmutable divide(Vector3fImmutable scalar) {
return new Vector3fImmutable(x / scalar.x, y / scalar.y, z / scalar.z);
}
public Vector3fImmutable negate() {
return new Vector3fImmutable(-x, -y, -z);
}
public Vector3fImmutable subtract(Vector3fImmutable vec) {
return new Vector3fImmutable(x - vec.x, y - vec.y, z - vec.z);
}
public Vector3fImmutable subtract2D(Vector3fImmutable vec) {
return new Vector3fImmutable(x - vec.x, 0, z - vec.z);
}
public Vector3fImmutable subtract(float x, float y, float z) {
return new Vector3fImmutable(this.x - x, this.y - y, this.z - z);
}
public Vector3fImmutable normalize() {
float length = length();
if (length != 0) {
return divide(length);
}
return divide(1);
}
public float angleBetween(Vector3fImmutable otherVector) {
float dotProduct = dot(otherVector);
return FastMath.acos(dotProduct);
}
public float angleBetween2D(Vector3fImmutable otherVector) {
float dotProduct = dot(otherVector);
return FastMath.acos(dotProduct);
}
public Vector3fImmutable interpolate(Vector3f finalVec, float changeAmnt) {
return new Vector3fImmutable((1 - changeAmnt) * this.x + changeAmnt
* finalVec.x, (1 - changeAmnt) * this.y + changeAmnt
* finalVec.y, (1 - changeAmnt) * this.z + changeAmnt
* finalVec.z);
}
public Vector3fImmutable interpolate(Vector3fImmutable finalVec, float changeAmnt) {
return new Vector3fImmutable((1 - changeAmnt) * this.x + changeAmnt
* finalVec.x, (1 - changeAmnt) * this.y + changeAmnt
* finalVec.y, (1 - changeAmnt) * this.z + changeAmnt
* finalVec.z);
}
public static boolean isValidVector(Vector3fImmutable vector) {
if (vector == null)
return false;
if (Float.isNaN(vector.x) || Float.isNaN(vector.y)
|| Float.isNaN(vector.z))
return false;
return !Float.isInfinite(vector.x) && !Float.isInfinite(vector.y)
&& !Float.isInfinite(vector.z);
}
@Override
public Vector3fImmutable clone() throws CloneNotSupportedException {
return (Vector3fImmutable) super.clone();
}
public float[] toArray(float[] floats) {
if (floats == null) {
floats = new float[3];
}
floats[0] = x;
floats[1] = y;
floats[2] = z;
return floats;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Vector3fImmutable)) {
return false;
}
if (this == o) {
return true;
}
Vector3fImmutable comp = (Vector3fImmutable) o;
if (Float.compare(x, comp.x) != 0)
return false;
if (Float.compare(y, comp.y) != 0)
return false;
return Float.compare(z, comp.z) == 0;
}
@Override
public int hashCode() {
int hash = 37;
hash += 37 * hash + Float.floatToIntBits(x);
hash += 37 * hash + Float.floatToIntBits(y);
hash += 37 * hash + Float.floatToIntBits(z);
return hash;
}
public static Vector3fImmutable readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
return new Vector3fImmutable(in.readFloat(), in.readFloat(), in
.readFloat());
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeFloat(x);
out.writeFloat(y);
out.writeFloat(z);
}
public Vector3fImmutable getOffset(float rotation, float xOffset, float yOffset, float zOffset, boolean invertZ) {
float sin = FastMath.sin(rotation);
float cos = FastMath.cos(rotation);
Vector3f faceDir = new Vector3f(sin, 0f, cos);
Vector3f crossDir = new Vector3f(cos, 0f, sin);
faceDir.multLocal(zOffset);
crossDir.multLocal(xOffset);
if (invertZ) {
faceDir.z = -faceDir.z;
crossDir.z = -crossDir.z;
}
Vector3f loc = new Vector3f(this);
loc.addLocal(faceDir);
loc.addLocal(crossDir);
loc.y += yOffset;
return new Vector3fImmutable(loc);
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public float get(int index) {
switch (index) {
case 0:
return x;
case 1:
return y;
case 2:
return z;
}
throw new IllegalArgumentException("index must be either 0, 1 or 2");
}
public Vector2f getLatLong() {
return new Vector2f(this.x, this.z);
}
public synchronized float getLat() {
return x;
}
public synchronized float getLong() {
return z;
}
public synchronized float getAlt() {
return y;
}
public Vector3fImmutable setX(float x) {
return new Vector3fImmutable(x, y, z);
}
public Vector3fImmutable setY(float y) {
return new Vector3fImmutable(x, y, z);
}
public Vector3fImmutable setZ(float z) {
return new Vector3fImmutable(x, y, z);
}
public float getRotation() {
return 3.14f + FastMath.atan2(-x, -z);
}
public boolean inRange2D(Vector3fImmutable otherVec, float range){
float distance = this.distanceSquared2D(otherVec);
return !(distance > range * range);
}
public static String toString(Vector3fImmutable vector) {
return vector.toString();
}
@Override
public String toString() {
String outString;
outString = "(" + this.x + '/' + this.y + '/' + this.z;
return outString;
}
public String toString2D() {
String outString;
outString = "( " + (int)this.x + " , " + (int)(this.z *-1) +" )";
return outString;
}
public static Vector3fImmutable ClosestPointOnLine(Vector3fImmutable lineStart, Vector3fImmutable lineEnd, Vector3fImmutable sourcePoint) {
Vector3fImmutable closestPoint;
Vector3fImmutable lineStartToTarget;
Vector3fImmutable lineDirection;
float lineLength;
float dotProduct;
lineStartToTarget = sourcePoint.subtract(lineStart);
lineDirection = lineEnd.subtract(lineStart).normalize();
lineLength = lineStart.distance2D(lineEnd);
dotProduct = lineDirection.dot(lineStartToTarget);
if (dotProduct <= 0)
return lineStart;
if (dotProduct >= lineLength)
return lineEnd;
// Project the point by advancing it along the line from
// the starting point.
closestPoint = lineDirection.mult(dotProduct);
closestPoint = lineStart.add(closestPoint);
return closestPoint;
}
public Vector3fImmutable ClosestPointOnLine(Vector3fImmutable lineStart, Vector3fImmutable lineEnd) {
Vector3fImmutable closestPoint;
Vector3fImmutable lineStartToTarget;
Vector3fImmutable lineDirection;
float lineLength;
float dotProduct;
lineStartToTarget = this.subtract(lineStart);
lineDirection = lineEnd.subtract(lineStart).normalize();
lineLength = lineStart.distance2D(lineEnd);
dotProduct = lineDirection.dot(lineStartToTarget);
if (dotProduct <= 0)
return lineStart;
if (dotProduct >= lineLength)
return lineEnd;
// Project the point by advancing it along the line from
// the starting point.
closestPoint = lineDirection.mult(dotProduct);
closestPoint = lineStart.add(closestPoint);
return closestPoint;
}
public static Vector3fImmutable rotateAroundPoint(Vector3fImmutable origin, Vector3fImmutable point, int angle) {
float angleRadians;
int modifiedAngle;
// Convert angle to radians
modifiedAngle = angle;
if (angle < 0)
modifiedAngle = 360 + modifiedAngle;
angleRadians = (float) Math.toRadians(modifiedAngle);
return rotateAroundPoint(origin, point, angleRadians);
}
public static Vector3fImmutable rotateAroundPoint(Vector3fImmutable origin, Vector3fImmutable point, float radians) {
Vector3fImmutable outVector;
Vector3f directionVector;
Quaternion angleRotation;
// Build direction vector relative to origin
directionVector = new Vector3f(point.subtract(origin));
// Build quaternion rotation
angleRotation = new Quaternion().fromAngleAxis(radians, new Vector3f(0,1,0));
// Apply rotation to direction vector
directionVector = angleRotation.mult(directionVector);
// Translate from origin back to new rotated point
outVector = origin.add(directionVector);
return outVector;
}
public static Vector3fImmutable rotateAroundPoint(Vector3fImmutable origin, Vector3fImmutable point,Quaternion angleRotation) {
Vector3fImmutable outVector;
Vector3f directionVector;
// Build direction vector relative to origin
directionVector = new Vector3f(point.subtract(origin));
// Build quaternion rotation
// Apply rotation to direction vector
directionVector = angleRotation.mult(directionVector);
// Translate from origin back to new rotated point
outVector = origin.add(directionVector);
return outVector;
}
public static Vector3fImmutable rotateAroundPoint(Vector3fImmutable origin, Vector3fImmutable point, float w, Vector3f axis) {
Vector3fImmutable outVector;
Vector3f directionVector;
Quaternion angleRotation;
// Build direction vector relative to origin
directionVector = new Vector3f(point.subtract(origin));
// Build quaternion rotation
angleRotation = new Quaternion().fromAngleAxis(w, axis);
// Apply rotation to direction vector
directionVector = angleRotation.mult(directionVector);
// Translate from origin back to new rotated point
outVector = origin.add(directionVector);
return outVector;
}
public static Vector3fImmutable getRandomPointInCircle(Vector3fImmutable origin, float radius) {
// Member variables
float targetAngle;
float targetRadius;
Vector3fImmutable targetPosition;
targetAngle = (float) (ThreadLocalRandom.current().nextFloat() * Math.PI * 2);
targetRadius = (float) (Math.sqrt(ThreadLocalRandom.current().nextFloat()) * radius);
targetPosition = new Vector3fImmutable((float) (origin.x + targetRadius * Math.cos(targetAngle)), origin.y, (float) (origin.z + targetRadius * Math.sin(targetAngle)));
return targetPosition;
}
public static Vector3fImmutable getLocBetween(Vector3fImmutable start, Vector3fImmutable end) {
// Member variables
Vector3fImmutable faceDirection = end.subtract(start).normalize();
float distance = end.distance(start) * .5f;
return faceDirection.scaleAdd(distance, start);
}
public static Vector3fImmutable getRandomPointOnCircle(Vector3fImmutable origin, float radius) {
// Member variables
int randomAngle;
Vector3fImmutable targetPosition;
randomAngle = ThreadLocalRandom.current().nextInt(360);
targetPosition = new Vector3fImmutable((float) (origin.x + radius * Math.cos(randomAngle)), origin.y, (float) (origin.z + radius * Math.sin(randomAngle)));
return targetPosition;
}
public static final Vector3fImmutable ZERO = new Vector3fImmutable(0,0,0);
public static Vector3fImmutable transform(Vector3fImmutable origin,Vector3fImmutable point, float angle){
//TRANSLATE TO ORIGIN
float x1 = point.x - origin.x;
float y1 = point.z - origin.z;
//APPLY ROTATION
float temp_x1 = (float) (x1 * Math.cos(angle) - y1 * Math.sin(angle));
float temp_z1 = (float) (x1 * Math.sin(angle) + y1 * Math.cos(angle));
temp_x1 += origin.x;
temp_z1 += origin.z;
return new Vector3fImmutable(temp_x1,point.y,temp_z1);
}
public float Lerp(Vector3fImmutable dest, float lerpFactor)
{
return dest.subtract(this).mult(lerpFactor).add(this).y;
}
}