1.2 update w/ GZDoom 4.9 features:
- Changeable player skins. - Ammo LEDs are now 1:1 with UT by using canvas textures. - Integrate some add-ons, including reskins. - Various fixes (some backported from Demolitionist). - Migrated from libeye to Gutamatics.
This commit is contained in:
parent
81ffca403d
commit
602a89cc68
1761 changed files with 4461 additions and 1597 deletions
275
zscript/dt_Gutamatics/Quaternion.zsc
Normal file
275
zscript/dt_Gutamatics/Quaternion.zsc
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
class dt_GM_Quaternion {
|
||||
double w, x, y, z;
|
||||
|
||||
/// Initialises the Quaternion.
|
||||
dt_GM_Quaternion init(double w, double x, double y, double z) {
|
||||
self.w = w;
|
||||
self.x = x;
|
||||
self.y = y;
|
||||
self.z = z;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Initialises the Quaternion in a static context.
|
||||
static dt_GM_Quaternion create(double w, double x, double y, double z) {
|
||||
return new("dt_GM_Quaternion").init(w, x, y, z);
|
||||
}
|
||||
|
||||
/// Sets up the quaternion using axis and angle.
|
||||
void setAxisAngle(Vector3 axis, double angle) {
|
||||
double lengthSquared = axis dot axis;
|
||||
// avoid a division by 0 and just return the identity
|
||||
if (dt_GM_GlobalMaths.closeEnough(lengthSquared, 0)) {
|
||||
init(1, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
angle *= 0.5;
|
||||
|
||||
double sinTheta = sin(angle);
|
||||
double cosTheta = cos(angle);
|
||||
double factor = sinTheta / sqrt(lengthSquared);
|
||||
|
||||
w = cosTheta;
|
||||
x = factor * axis.x;
|
||||
y = factor * axis.y;
|
||||
z = factor * axis.z;
|
||||
}
|
||||
|
||||
/// Initialises the Quaternion using axis and angle.
|
||||
dt_GM_Quaternion initFromAxisAngle(Vector3 axis, double angle) {
|
||||
setAxisAngle(axis, angle);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Initialises the Quaternion using axis and angle in a static context.
|
||||
static dt_GM_Quaternion createFromAxisAngle(Vector3 axis, double angle) {
|
||||
return new("dt_GM_Quaternion").initFromAxisAngle(axis, angle);
|
||||
}
|
||||
|
||||
/// Sets up the quaternion using euler angles.
|
||||
void setAngles(double yaw, double pitch, double roll) {
|
||||
dt_GM_Quaternion zRotation = new("dt_GM_Quaternion").initFromAxisAngle((0, 0, 1), yaw);
|
||||
dt_GM_Quaternion yRotation = new("dt_GM_Quaternion").initFromAxisAngle((0, 1, 0), pitch);
|
||||
dt_GM_Quaternion xRotation = new("dt_GM_Quaternion").initFromAxisAngle((1, 0, 0), roll);
|
||||
dt_GM_Quaternion finalRotation = zRotation.multiplyQuat(yRotation);
|
||||
finalRotation = finalRotation.multiplyQuat(xRotation);
|
||||
copy(finalRotation);
|
||||
}
|
||||
|
||||
/// Initialises the quaternion using euler angles.
|
||||
dt_GM_Quaternion initFromAngles(double yaw, double pitch, double roll) {
|
||||
setAngles(yaw, pitch, roll);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Initialises the quaternion using euler angles in a static context.
|
||||
static dt_GM_Quaternion createFromAngles(double yaw, double pitch, double roll) {
|
||||
return new("dt_GM_Quaternion").initFromAngles(yaw, pitch, roll);
|
||||
}
|
||||
|
||||
/// Returns the euler angles from the Quaternion.
|
||||
double, double, double toAngles() {
|
||||
double singularityTest = z * x - w * y;
|
||||
double yawY = 2 * (w * z + x * y);
|
||||
double yawX = (1 - 2 * (y * y + z * z));
|
||||
|
||||
double singularityThreshold = 0.4999995;
|
||||
|
||||
double yaw = 0;
|
||||
double pitch = 0;
|
||||
double roll = 0;
|
||||
|
||||
if (singularityTest < -singularityThreshold) {
|
||||
pitch = 90;
|
||||
yaw = atan2(yawY, yawX);
|
||||
roll = dt_GM_GlobalMaths.normalize180(yaw + (2 * atan2(x, w)));
|
||||
}
|
||||
else if (singularityTest > singularityThreshold) {
|
||||
pitch = -90;
|
||||
yaw = atan2(yawY, yawX);
|
||||
roll = dt_GM_GlobalMaths.normalize180(yaw + (2 * atan2(x, w)));
|
||||
}
|
||||
else {
|
||||
pitch = -asin(2 * singularityTest);
|
||||
yaw = atan2(yawY, yawX);
|
||||
roll = atan2(2 * (w * x + y * z), (1 - 2 * (x * x + y * y)));
|
||||
}
|
||||
|
||||
return yaw, pitch, roll;
|
||||
}
|
||||
|
||||
/// Returns the conjugate of the Quaternion.
|
||||
dt_GM_Quaternion conjugate() const {
|
||||
return new("dt_GM_Quaternion").init(w, -x, -y, -z);
|
||||
}
|
||||
|
||||
/// Returns the normalised form of the Quaternion.
|
||||
dt_GM_Quaternion unit() const {
|
||||
double lengthSquared = w * w + x * x + y * y + z * z;
|
||||
if (dt_GM_GlobalMaths.closeEnough(lengthSquared, 0)) {
|
||||
return zero();
|
||||
}
|
||||
double factor = 1 / sqrt(lengthSquared);
|
||||
return new("dt_GM_Quaternion").init(w * factor, x * factor, y * factor, z * factor);
|
||||
}
|
||||
|
||||
/// Returns the inverse of the Quaternion (equal to conjugate if normalised).
|
||||
dt_GM_Quaternion inverse() {
|
||||
double norm = w * w + x * x + y * y + z * z;
|
||||
// if this is a zero quaternion, just return self
|
||||
if (dt_GM_GlobalMaths.closeEnough(norm, 0)) {
|
||||
return self;
|
||||
}
|
||||
double inverseNorm = 1/norm;
|
||||
return new("dt_GM_Quaternion").init(w * inverseNorm, x * -inverseNorm, y * -inverseNorm, z * -inverseNorm);
|
||||
}
|
||||
|
||||
/// Adds two Quaternions, returning the result.
|
||||
dt_GM_Quaternion add(dt_GM_Quaternion other) const {
|
||||
return new("dt_GM_Quaternion").init(w + other.w, x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
|
||||
/// Subtracts two Quaternions, returning the result.
|
||||
dt_GM_Quaternion subtract(dt_GM_Quaternion other) const {
|
||||
return new("dt_GM_Quaternion").init(w - other.w, x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
|
||||
/// Multiplies the Quaternion by a scalar, returning the result.
|
||||
dt_GM_Quaternion multiplyScalar(double scalar) const {
|
||||
return new("dt_GM_Quaternion").init(w * scalar, x * scalar, y * scalar, z * scalar);
|
||||
}
|
||||
|
||||
/// Multiplies two Quaternions, returning the result.
|
||||
dt_GM_Quaternion multiplyQuat(dt_GM_Quaternion other) const {
|
||||
return new("dt_GM_Quaternion").init(w * other.w - x * other.x - y * other.y - z * other.z,
|
||||
w * other.x + x * other.w + y * other.z - z * other.y,
|
||||
w * other.y + y * other.w + z * other.x - x * other.z,
|
||||
w * other.z + z * other.w + x * other.y - y * other.x );
|
||||
}
|
||||
|
||||
/// Negates the Quaternion.
|
||||
dt_GM_Quaternion negate() const {
|
||||
return new("dt_GM_Quaternion").init(-w, -x, -y, -z);
|
||||
}
|
||||
|
||||
/// Sets the values to 0 if they're close enough to 0.
|
||||
void clean() {
|
||||
if (dt_GM_GlobalMaths.closeEnough(w, 0)) w = 0;
|
||||
if (dt_GM_GlobalMaths.closeEnough(x, 0)) x = 0;
|
||||
if (dt_GM_GlobalMaths.closeEnough(y, 0)) y = 0;
|
||||
if (dt_GM_GlobalMaths.closeEnough(z, 0)) z = 0;
|
||||
}
|
||||
|
||||
/// Returns the length of the Quaternion squared.
|
||||
double lengthSquared() const {
|
||||
return (w * w + x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/// Returns the length of the Quaternion.
|
||||
double length() const {
|
||||
return sqrt(w * w + x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
/// Returns whether the two Quaternions are equal.
|
||||
bool equals(dt_GM_Quaternion other) const {
|
||||
return dt_GM_GlobalMaths.closeEnough(w, other.w) && dt_GM_GlobalMaths.closeEnough(x, other.x) &&
|
||||
dt_GM_GlobalMaths.closeEnough(y, other.y) && dt_GM_GlobalMaths.closeEnough(z, other.z) ;
|
||||
}
|
||||
|
||||
/// Returns if the Quaternion is a 0 Quaternion.
|
||||
bool isZero() const {
|
||||
return dt_GM_GlobalMaths.closeEnough(w * w + x * x + y * y + z * z, 0);
|
||||
}
|
||||
|
||||
/// Returns if the Quaternion is a unit Quaternion.
|
||||
bool isUnit() const {
|
||||
return dt_GM_GlobalMaths.closeEnough(w * w + x * x + y * y + z * z, 1);
|
||||
}
|
||||
|
||||
/// Returns if the Quaternion is an identity Quaternion.
|
||||
bool isIdentity() const {
|
||||
return dt_GM_GlobalMaths.closeEnough(w, 1) && dt_GM_GlobalMaths.closeEnough(x, 0) &&
|
||||
dt_GM_GlobalMaths.closeEnough(y, 0) && dt_GM_GlobalMaths.closeEnough(z, 0) ;
|
||||
}
|
||||
|
||||
/// Returns the dot product of two Quaternions.
|
||||
double dotProduct(dt_GM_Quaternion other) const {
|
||||
return (w * other.w + x * other.x + y * other.y + z * other.z);
|
||||
}
|
||||
|
||||
/// Copies another Quaternion into this one.
|
||||
void copy(dt_GM_Quaternion other) {
|
||||
w = other.w;
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
z = other.z;
|
||||
}
|
||||
|
||||
/// Rotates a Vector3 using this Quaternion.
|
||||
Vector3 rotateVector3(Vector3 vec) const {
|
||||
dt_GM_Quaternion q = unit();
|
||||
|
||||
Vector3 u = (q.x, q.y, q.z);
|
||||
double s = q.w;
|
||||
|
||||
return 2 * (u dot vec) * u + (s * s - (u dot u)) * vec + 2 * s * u cross vec;
|
||||
}
|
||||
|
||||
/// Linearly interpolates between two Quaternions, clamping the parameters.
|
||||
static dt_GM_Quaternion lerp(dt_GM_Quaternion from, dt_GM_Quaternion to, double time) {
|
||||
time = clamp(time, 0, 1);
|
||||
return lerpUnclamped(from, to, time);
|
||||
}
|
||||
|
||||
/// Linearly interpolates between two Quaternions.
|
||||
static dt_GM_Quaternion lerpUnclamped(dt_GM_Quaternion from, dt_GM_Quaternion to, double time) {
|
||||
dt_GM_Quaternion ret = new("dt_GM_Quaternion");
|
||||
double reverseTime = 1 - time;
|
||||
ret.x = reverseTime * from.x + time * to.x;
|
||||
ret.y = reverseTime * from.y + time * to.y;
|
||||
ret.z = reverseTime * from.z + time * to.z;
|
||||
ret.w = reverseTime * from.w + time * to.w;
|
||||
ret = ret.unit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Spherically interpolates between two Quaternions, clamping the parameters.
|
||||
static dt_GM_Quaternion slerp(dt_GM_Quaternion from, dt_GM_Quaternion to, double time) {
|
||||
time = clamp(time, 0, 1);
|
||||
return slerpUnclamped(from, to, time);
|
||||
}
|
||||
|
||||
/// Spherically interpolates between two Quaternions.
|
||||
static dt_GM_Quaternion slerpUnclamped(dt_GM_Quaternion from, dt_GM_Quaternion to, double time) {
|
||||
dt_GM_Quaternion q3;
|
||||
double fromToDot = from.dotProduct(to);
|
||||
|
||||
if (fromToDot < 0) {
|
||||
fromToDot = -fromToDot;
|
||||
q3 = to.negate();
|
||||
}
|
||||
else {
|
||||
q3 = to;
|
||||
}
|
||||
|
||||
if (fromToDot < 0.95) {
|
||||
double angle = acos(fromToDot);
|
||||
return ((from.multiplyScalar(sin(angle * (1 - time)))).add(q3.multiplyScalar(sin(angle * time)))).multiplyScalar(1 / sin(angle));
|
||||
}
|
||||
else {
|
||||
return lerp(from, q3, time);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the 0 Quaternion.
|
||||
static dt_GM_Quaternion zero() {
|
||||
return new("dt_GM_Quaternion").init(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// Returns the identity Quaternion.
|
||||
static dt_GM_Quaternion identity() {
|
||||
return new("dt_GM_Quaternion").init(1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue