UNPKG

unreal.js

Version:

A pak reader for games like VALORANT & Fortnite written in Node.JS

412 lines (411 loc) 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FBox = void 0; const FVector_1 = require("./FVector"); const FArchive_1 = require("../../../reader/FArchive"); /** * Implements an axis-aligned box * Boxes describe an axis-aligned extent in three dimensions. They are used for many different things in the * Engine and in games, such as bounding volumes, collision detection and visibility calculation * @implements {IStructType} */ class FBox { /** DO NOT USE THIS CONSTRUCTOR, THIS IS FOR THE LIBRARY */ constructor(x, y) { if (!x) { this.min = new FVector_1.FVector(0, 0, 0); this.max = new FVector_1.FVector(0, 0, 0); this.isValid = false; } else if (x instanceof FArchive_1.FArchive) { this.min = new FVector_1.FVector(x); this.max = new FVector_1.FVector(x); this.isValid = x.readFlag(); } else if (Array.isArray(x)) { this.min = new FVector_1.FVector(0, 0, 0); this.min = new FVector_1.FVector(0, 0, 0); this.isValid = false; x.forEach((it) => this["+="](it)); } else { this.min = x; this.max = y; this.isValid = true; } } /** * Serializes this * @param {FArchiveWriter} Ar UE4 Writer to use * @returns {void} * @public */ serialize(Ar) { this.min.serialize(Ar); this.max.serialize(Ar); Ar.writeFlag(this.isValid); } /** * Compares two boxes for equality * @returns {boolean} Whether the boxes are equal, false otherwise * @public */ equals(other) { if (this === other) return true; if (!(other instanceof FBox)) return false; other; return this.min.equals(other.min) && this.max.equals(other.max); } /** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */ "+="(other) { if (other instanceof FBox) { if (this.isValid) { const min = (x, y) => Math.min(x, y); // min this.min.x = min(this.min.x, other.min.x); this.min.y = min(this.min.y, other.min.y); this.min.z = min(this.min.z, other.min.z); // max this.max.x = min(this.max.x, other.max.x); this.max.y = min(this.max.y, other.max.y); this.max.z = min(this.max.z, other.max.z); } else { this.min.set(other.min); this.max.set(other.max); this.isValid = true; } } else { if (this.isValid) { const min = (x, y) => Math.min(x, y); // min this.min.x = min(this.min.x, other.x); this.min.y = min(this.min.y, other.y); this.min.z = min(this.min.z, other.z); // max this.max.x = min(this.max.x, other.x); this.max.y = min(this.max.y, other.y); this.max.z = min(this.max.z, other.z); } else { this.min.set(other); this.max.set(other); this.isValid = true; } } } /** DO NOT USE THIS METHOD, THIS IS FOR THE LIBRARY */ "+"(other) { if (other instanceof FBox) { const box = new FBox(this); box["+="](other); return box; } const box = new FBox(this); box["+="](other); return box; } /** * Gets the min or max of this bounding volume * @param {number} index the index into points of the bounding volume * @returns {FVector} a point of the bounding volume * @public */ get(index) { if (index === 0) return this.min; if (index === 1) return this.max; throw new Error(`Index out of bounds! Received: ${index} (min: 0, max: 1)`); } /** * Calculates the distance of a point to this box * @param {FVector} point The point * @returns {number} The distance * @public */ computeSquaredDistanceToPoint(point) { return FVector_1.FVector.computeSquaredDistanceFromBoxToPoint(this.min, this.max, point); } /** * Increases the box size * @param {FVector} v The size to increase the volume by * @returns {FBox} A new bounding box * @public */ expandBy0(v) { return new FBox(this.min["-"](v), this.max["+"](v)); } /** * Increases the box size * @param {number} w The size to increase the volume by * @returns {FBox} A new bounding box * @public */ expandBy1(w) { const v = new FVector_1.FVector(w, w, w); return new FBox(this.min["-"](v), this.max["+"](v)); } /** * Increases the box size * @param {FVector} neg The size to increase the volume by in the negative direction (positive values move the bounds outwards) * @param {FVector} pos The size to increase the volume by in the positive direction (positive values move the bounds outwards) * @returns {FBox} A new bounding box * @public */ expandBy2(neg, pos) { return new FBox(this.min["-"](neg), this.max["+"](pos)); } /** * Shifts the bounding box position * @param {FVector} offset The vector to shift the box by * @returns {FBox} A new bounding box * @public */ shiftBy(offset) { return new FBox(this.min["+"](offset), this.max["+"](offset)); } /** * Moves the center of bounding box to new destination * @param {FVector} destination The destination point to move center of box to * @returns {FBox} A new bounding box * @public */ moveTo(destination) { const offset = destination["-"](this.getCenter()); return new FBox(this.min["+"](offset), this.max["+"](offset)); } /** * Gets the center point of this box * @returns {FVector} The center point * @public * @see {getCenterAndExtents} * @see {getExtent} * @see {getSize} * @see {getVolume} */ getCenter() { return this.min["+"](this.max)["*"](0.5); } /** * Gets the center and extents of this box. * @param {FVector} center(out) Will contain the box center point. * @param {FVector} extents(out) Will contain the extent around the center. * @returns {void} * @public * @see {getCenter} * @see {getExtent} * @see {getSize} * @see {getVolume} */ getCenterAndExtents(center, extents) { extents.set(this.getExtent()); center.set(this.min["+"](extents)); } /** * Calculates the closest point on or inside the box to a given point in space * @param {FVector} point The point in space * @returns {FVector} The closest point on or inside the box * @public */ getClosestPointTo(point) { // start by considering the point inside the box const closestPoint = point; // now clamp to inside box if it's outside | x if (point.x < this.min.x) { closestPoint.x = this.min.x; } else if (point.x > this.max.x) { closestPoint.x = this.max.x; } // now clamp to inside box if it's outside | y if (point.y < this.min.y) { closestPoint.y = this.min.y; } else if (point.y > this.max.y) { closestPoint.y = this.max.y; } // Now clamp to inside box if it's outside | z if (point.z < this.min.z) { closestPoint.z = this.min.z; } else if (point.z > this.max.z) { closestPoint.z = this.max.z; } return closestPoint; } /** * Gets the extents of this box * @returns {FVector} The box extents * @public * @see {getCenter} * @see {getCenterAndExtents} * @see {getSize} * @see {getVolume} */ getExtent() { return this.max["-"](this.max)["*"](0.5); } /** * Gets the size of this box * @returns {FVector} The box size * @public * @see {getCenter} * @see {getCenterAndExtents} * @see {getExtent} * @see {getVolume} */ getSize() { return this.max["-"](this.min); } /** * Gets the volume of this box * @returns {number} The box volume * @public * @see {getCenter} * @see {getCenterAndExtents} * @see {getExtent} * @see {getSize} */ getVolume() { return (this.max.x - this.min.x) * (this.max.y - this.min.y) * (this.max.z - this.min.z); } /** * Checks whether the given bounding box intersects this bounding box * @param {FBox} other The bounding box to intersect with * @returns {boolean} Whether the boxes intersect, false otherwise * @public */ intersect(other) { if ((this.min.x > other.max.x) || (other.min.x > this.max.x)) return false; if ((this.min.y > other.max.y) || (other.min.y > this.max.y)) return false; return !((this.min.z > other.max.z) || (other.min.z > this.max.z)); } /** * Checks whether the given bounding box intersects this bounding box in the XY plane * @param {FBox} other The bounding box to test intersection * @returns {boolean} Whether the boxes intersect in the XY Plane, false otherwise * @public */ intersectXY(other) { if ((this.min.x > other.max.x) || (other.min.x > this.max.x)) return false; return !((this.min.y > other.max.y) || (other.min.y > this.max.y)); } /** * Returns the overlap FBox of two box * @param {FBox} other The bounding box to test overlap * @returns {FBox} the overlap box. It can be 0 if they don't overlap * @public */ overlap(other) { if (!this.intersect(other)) { const v = new FVector_1.FVector(0, 0, 0); return new FBox(v, v); } // otherwise they overlap // so find overlapping box const minVector = new FVector_1.FVector(); const maxVector = new FVector_1.FVector(); minVector.x = Math.max(this.min.x, other.min.x); maxVector.x = Math.min(this.max.x, other.max.x); minVector.y = Math.max(this.min.y, other.min.y); maxVector.y = Math.min(this.max.y, other.max.y); minVector.z = Math.max(this.min.z, other.min.z); maxVector.z = Math.min(this.max.z, other.max.z); return new FBox(minVector, maxVector); } // TODO inverseTransformBy(m: FTransform): FBox /** * Checks whether a given box is fully encapsulated by this box * @param {FBox} other The box to test for encapsulation within the bounding volume * @returns {FBox} Whether box is inside this volume * @public */ isInside0(other) { return this.isInside1(other.min) && this.isInside1(other.max); } /** * Checks whether the given location is inside this box * @param {FVector} _in The location to test for inside the bounding volume * @returns {boolean} Whether location is inside this volume * @public * @see {isInsideXY1} */ isInside1(_in) { return (_in.x > this.min.x) && (_in.x < this.max.x) && (_in.y > this.min.y) && (_in.y < this.max.y) && (_in.z > this.min.z) && (_in.z < this.max.z); } /** * Checks whether the given location is inside or on this box * @param {FVector} _in The location to test for inside the bounding volume * @returns {boolean} Whether location is inside this volume * @public * @see {isInsideXY1} */ isInsideOrOn(_in) { return (_in.x >= this.min.x) && (_in.x <= this.max.x) && (_in.y >= this.min.y) && (_in.y <= this.max.y) && (_in.z >= this.min.z) && (_in.z <= this.max.z); } /** * Checks whether the given box is fully encapsulated by this box in the XY plane * @param {FBox} other The box to test for encapsulation within the bounding box * @returns {boolean} Whether is inside this box in the XY plane * @public */ isInsideXY0(other) { return this.isInsideXY1(other.min) && this.isInsideXY1(other.max); } /** * - Checks whether the given location is inside this box in the XY plane * @param {FVector} _in The location to test for inside the bounding box * @returns {boolean} Whether location is inside this box in the XY plane * @public * @see {isInside1} */ isInsideXY1(_in) { return (_in.x > this.min.x) && (_in.x < this.max.x) && (_in.y > this.min.y) && (_in.y < this.max.y); } // TODO transformBy(m: FMatrix): FBox // TODO transformBy(m: FTransform): FBox // TODO transformProjectBy(projM: FMatrix): FBox /** * Turns this into string * @returns {string} Result * @public */ toString() { return `IsValid=${this.isValid}, Min=(${this.min.toString()}), Max=(${this.max.toString()})`; } /** * Turns this into json * @returns {any} Json * @public */ toJson() { return { bIsValid: this.isValid, max: this.max.toJson(), min: this.min.toJson() }; } /** * Utility function to build an AABB from Origin and Extent * @param {FVector} origin The location of the bounding box * @param {FVector} extent Half size of the bounding box * @returns {FBox} A new axis-aligned bounding box * @public */ static buildAABB(origin, extent) { return new FBox(origin["-"](extent), origin["+"](extent)); } } exports.FBox = FBox;