up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled

This commit is contained in:
2026-07-09 08:33:57 +08:00
commit 26ed99fda6
845 changed files with 75419 additions and 0 deletions
+284
View File
@@ -0,0 +1,284 @@
package cube
import (
"github.com/go-gl/mathgl/mgl64"
)
// BBox represents an Axis Aligned Bounding Box in a 3D space. It is defined as
// two Vec3s, of which one is the minimum and one is the maximum.
type BBox struct {
min, max mgl64.Vec3
}
// Box creates a new axis aligned bounding box with the minimum and maximum
// coordinates provided. The returned box has minimum and maximum coordinates
// swapped if necessary so that it is well-formed.
func Box(x0, y0, z0, x1, y1, z1 float64) BBox {
if x0 > x1 {
x0, x1 = x1, x0
}
if y0 > y1 {
y0, y1 = y1, y0
}
if z0 > z1 {
z0, z1 = z1, z0
}
return BBox{min: mgl64.Vec3{x0, y0, z0}, max: mgl64.Vec3{x1, y1, z1}}
}
// Grow grows the bounding box in all directions by x and returns the new
// bounding box.
func (box BBox) Grow(x float64) BBox {
add := mgl64.Vec3{x, x, x}
return BBox{min: box.min.Sub(add), max: box.max.Add(add)}
}
// GrowVec3 grows the BBox on all axes as represented by the Vec3 passed. The
// vec values are subtracted from the minimum values of the BBox and added to
// the maximum values of the BBox.
func (box BBox) GrowVec3(vec mgl64.Vec3) BBox {
return BBox{min: box.min.Sub(vec), max: box.max.Add(vec)}
}
// Min returns the minimum coordinate of the bounding box.
func (box BBox) Min() mgl64.Vec3 {
return box.min
}
// Max returns the maximum coordinate of the bounding box.
func (box BBox) Max() mgl64.Vec3 {
return box.max
}
// Width returns the width of the BBox.
func (box BBox) Width() float64 {
return box.max[0] - box.min[0]
}
// Length returns the length of the BBox.
func (box BBox) Length() float64 {
return box.max[2] - box.min[2]
}
// Height returns the height of the BBox.
func (box BBox) Height() float64 {
return box.max[1] - box.min[1]
}
// Extend expands the BBox on all axes as represented by the Vec3 passed.
// Negative coordinates result in an expansion towards the negative axis, and
// vice versa for positive coordinates.
func (box BBox) Extend(vec mgl64.Vec3) BBox {
if vec[0] < 0 {
box.min[0] += vec[0]
} else if vec[0] > 0 {
box.max[0] += vec[0]
}
if vec[1] < 0 {
box.min[1] += vec[1]
} else if vec[1] > 0 {
box.max[1] += vec[1]
}
if vec[2] < 0 {
box.min[2] += vec[2]
} else if vec[2] > 0 {
box.max[2] += vec[2]
}
return box
}
// ExtendTowards extends the bounding box by x in a given direction.
func (box BBox) ExtendTowards(f Face, x float64) BBox {
switch f {
case FaceDown:
box.min[1] -= x
case FaceUp:
box.max[1] += x
case FaceNorth:
box.min[2] -= x
case FaceSouth:
box.max[2] += x
case FaceWest:
box.min[0] -= x
case FaceEast:
box.max[0] += x
}
return box
}
// Stretch stretches the bounding box by x in a given axis.
func (box BBox) Stretch(a Axis, x float64) BBox {
switch a {
case Y:
box.min[1] -= x
box.max[1] += x
case Z:
box.min[2] -= x
box.max[2] += x
case X:
box.min[0] -= x
box.max[0] += x
}
return box
}
// Translate moves the entire BBox with the Vec3 given. The (minimum and
// maximum) x, y and z coordinates are moved by those in the Vec3 passed.
func (box BBox) Translate(vec mgl64.Vec3) BBox {
return BBox{min: box.min.Add(vec), max: box.max.Add(vec)}
}
// TranslateTowards moves the entire BBox by x in the direction of a Face f.
func (box BBox) TranslateTowards(f Face, x float64) BBox {
switch f {
case FaceDown:
return box.Translate(mgl64.Vec3{0, -x, 0})
case FaceUp:
return box.Translate(mgl64.Vec3{0, x, 0})
case FaceNorth:
return box.Translate(mgl64.Vec3{0, 0, -x})
case FaceSouth:
return box.Translate(mgl64.Vec3{0, 0, x})
case FaceWest:
return box.Translate(mgl64.Vec3{-x, 0, 0})
case FaceEast:
return box.Translate(mgl64.Vec3{x, 0, 0})
}
return box
}
// IntersectsWith checks if the BBox intersects with another BBox.
func (box BBox) IntersectsWith(other BBox) bool {
return box.intersectsWith(other, 1e-5)
}
// intersectsWith checks if the BBox intersects with another BBox using a
// specific epsilon.
func (box BBox) intersectsWith(other BBox, epsilon float64) bool {
if other.max[0]-box.min[0] > epsilon && box.max[0]-other.min[0] > epsilon {
if other.max[1]-box.min[1] > epsilon && box.max[1]-other.min[1] > epsilon {
return other.max[2]-box.min[2] > epsilon && box.max[2]-other.min[2] > epsilon
}
}
return false
}
// AnyIntersections checks if any of boxes intersect with search.
func AnyIntersections(boxes []BBox, search BBox) bool {
for _, box := range boxes {
if box.intersectsWith(search, 0) {
return true
}
}
return false
}
// Vec3Within checks if a BBox has vec within it.
func (box BBox) Vec3Within(vec mgl64.Vec3) bool {
if vec[0] <= box.min[0] || vec[0] >= box.max[0] {
return false
}
if vec[2] <= box.min[2] || vec[2] >= box.max[2] {
return false
}
return vec[1] > box.min[1] && vec[1] < box.max[1]
}
// Vec3WithinYZ checks if a BBox has vec within its Y and Z bounds.
func (box BBox) Vec3WithinYZ(vec mgl64.Vec3) bool {
if vec[2] < box.min[2] || vec[2] > box.max[2] {
return false
}
return vec[1] >= box.min[1] && vec[1] <= box.max[1]
}
// Vec3WithinXZ checks if a BBox has vec within its X and Z bounds.
func (box BBox) Vec3WithinXZ(vec mgl64.Vec3) bool {
if vec[0] < box.min[0] || vec[0] > box.max[0] {
return false
}
return vec[2] >= box.min[2] && vec[2] <= box.max[2]
}
// Vec3WithinXY checks if a BBox has vec within its X and Y bounds.
func (box BBox) Vec3WithinXY(vec mgl64.Vec3) bool {
if vec[0] < box.min[0] || vec[0] > box.max[0] {
return false
}
return vec[1] >= box.min[1] && vec[1] <= box.max[1]
}
// XOffset calculates the offset on the X axis between two bounding boxes,
// returning a delta always smaller than or equal to deltaX if deltaX is bigger
// than 0, or always bigger than or equal to deltaX if it is smaller than 0.
func (box BBox) XOffset(nearby BBox, deltaX float64) float64 {
if box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] || box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
// Not in the same Y/Z plane.
return deltaX
}
if deltaX > 0 && box.max[0] <= nearby.min[0] {
deltaX = min(deltaX, nearby.min[0]-box.max[0])
} else if deltaX < 0 && box.min[0] >= nearby.max[0] {
deltaX = max(deltaX, nearby.max[0]-box.min[0])
}
return deltaX
}
// YOffset calculates the offset on the Y axis between two bounding boxes,
// returning a delta always smaller than or equal to deltaY if deltaY is bigger
// than 0, or always bigger than or equal to deltaY if it is smaller than 0.
func (box BBox) YOffset(nearby BBox, deltaY float64) float64 {
if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] || box.max[2] <= nearby.min[2] || box.min[2] >= nearby.max[2] {
// Not the same X/Z plane.
return deltaY
}
if deltaY > 0 && box.max[1] <= nearby.min[1] {
deltaY = min(deltaY, nearby.min[1]-box.max[1])
}
if deltaY < 0 && box.min[1] >= nearby.max[1] {
deltaY = max(deltaY, nearby.max[1]-box.min[1])
}
return deltaY
}
// ZOffset calculates the offset on the Z axis between two bounding boxes,
// returning a delta always smaller than or equal to deltaZ if deltaZ is bigger
// than 0, or always bigger than or equal to deltaZ if it is smaller than 0.
func (box BBox) ZOffset(nearby BBox, deltaZ float64) float64 {
if box.max[0] <= nearby.min[0] || box.min[0] >= nearby.max[0] || box.max[1] <= nearby.min[1] || box.min[1] >= nearby.max[1] {
// Not the same X/Y plane.
return deltaZ
}
if deltaZ > 0 && box.max[2] <= nearby.min[2] {
deltaZ = min(deltaZ, nearby.min[2]-box.max[2])
}
if deltaZ < 0 && box.min[2] >= nearby.max[2] {
deltaZ = max(deltaZ, nearby.max[2]-box.min[2])
}
return deltaZ
}
// Corners returns the positions of all corners of a BBox.
func (box BBox) Corners() []mgl64.Vec3 {
bbmin, bbmax := box.min, box.max
return []mgl64.Vec3{
box.min,
box.max,
{bbmin[0], bbmin[1], bbmax[2]},
{bbmin[0], bbmax[1], bbmin[2]},
{bbmin[0], bbmax[1], bbmax[2]},
{bbmax[0], bbmax[1], bbmin[2]},
{bbmax[0], bbmin[1], bbmax[2]},
{bbmax[0], bbmin[1], bbmin[2]},
}
}
// Mul performs a scalar multiplication of the min and max points of a BBox.
func (box BBox) Mul(val float64) BBox {
return BBox{min: box.min.Mul(val), max: box.max.Mul(val)}
}
// Volume calculates the volume of a BBox.
func (box BBox) Volume() float64 {
return box.Height() * box.Length() * box.Width()
}