Files
radiantwave-legacy/vendor/github.com/veandco/go-sdl2/sdl/rect.go
T

781 lines
15 KiB
Go

package sdl
// #include "sdl_wrapper.h"
import "C"
import (
"math"
"unsafe"
)
// Point defines a two dimensional point.
// (https://wiki.libsdl.org/SDL_Point)
type Point struct {
X int32 // the x coordinate of the point
Y int32 // the y coordinate of the point
}
// Rect contains the definition of a rectangle, with the origin at the upper left.
// (https://wiki.libsdl.org/SDL_Rect)
type Rect struct {
X int32 // the x location of the rectangle's upper left corner
Y int32 // the y location of the rectangle's upper left corner
W int32 // the width of the rectangle
H int32 // the height of the rectangle
}
// FPoint defines a two dimensional point.
// TODO: (https://wiki.libsdl.org/SDL_FPoint)
type FPoint struct {
X float32 // the x coordinate of the point
Y float32 // the y coordinate of the point
}
// FRect contains the definition of a rectangle, with the origin at the upper left.
// TODO: (https://wiki.libsdl.org/SDL_FRect)
type FRect struct {
X float32 // the x location of the rectangle's upper left corner
Y float32 // the y location of the rectangle's upper left corner
W float32 // the width of the rectangle
H float32 // the height of the rectangle
}
func (p *Point) cptr() *C.SDL_Point {
return (*C.SDL_Point)(unsafe.Pointer(p))
}
func (a *Rect) cptr() *C.SDL_Rect {
return (*C.SDL_Rect)(unsafe.Pointer(a))
}
func (p *FPoint) cptr() *C.SDL_FPoint {
return (*C.SDL_FPoint)(unsafe.Pointer(p))
}
func (a *FRect) cptr() *C.SDL_FRect {
return (*C.SDL_FRect)(unsafe.Pointer(a))
}
// InRect reports whether the point resides inside a rectangle.
// (https://wiki.libsdl.org/SDL_PointInRect)
func (p *Point) InRect(r *Rect) bool {
if (p.X >= r.X) && (p.X < (r.X + r.W)) &&
(p.Y >= r.Y) && (p.Y < (r.Y + r.H)) {
return true
}
return false
}
// InRect reports whether the point resides inside a rectangle.
// (https://wiki.libsdl.org/SDL_PointInRect)
func (p *FPoint) InRect(r *FRect) bool {
if (p.X >= r.X) && (p.X < (r.X + r.W)) &&
(p.Y >= r.Y) && (p.Y < (r.Y + r.H)) {
return true
}
return false
}
// Empty reports whether a rectangle has no area.
// (https://wiki.libsdl.org/SDL_RectEmpty)
func (a *Rect) Empty() bool {
return a == nil || a.W <= 0 || a.H <= 0
}
// Equals reports whether two rectangles are equal.
// (https://wiki.libsdl.org/SDL_RectEquals)
func (a *Rect) Equals(b *Rect) bool {
if (a != nil) && (b != nil) &&
(a.X == b.X) && (a.Y == b.Y) &&
(a.W == b.W) && (a.H == b.H) {
return true
}
return false
}
// HasIntersection reports whether two rectangles intersect.
// (https://wiki.libsdl.org/SDL_HasIntersection)
func (a *Rect) HasIntersection(b *Rect) bool {
if a == nil || b == nil {
return false
}
// Special case for empty rects
if a.Empty() || b.Empty() {
return false
}
if a.X >= b.X+b.W || a.X+a.W <= b.X || a.Y >= b.Y+b.H || a.Y+a.H <= b.Y {
return false
}
return true
}
// Intersect calculates the intersection of two rectangles.
// (https://wiki.libsdl.org/SDL_IntersectRect)
func (a *Rect) Intersect(b *Rect) (Rect, bool) {
var result Rect
if a == nil || b == nil {
return result, false
}
// Special case for empty rects
if a.Empty() || b.Empty() {
result.W = 0
result.H = 0
return result, false
}
aMin := a.X
aMax := aMin + a.W
bMin := b.X
bMax := bMin + b.W
if bMin > aMin {
aMin = bMin
}
result.X = aMin
if bMax < aMax {
aMax = bMax
}
result.W = aMax - aMin
aMin = a.Y
aMax = aMin + a.H
bMin = b.Y
bMax = bMin + b.H
if bMin > aMin {
aMin = bMin
}
result.Y = aMin
if bMax < aMax {
aMax = bMax
}
result.H = aMax - aMin
return result, !result.Empty()
}
// Union calculates the union of two rectangles.
// (https://wiki.libsdl.org/SDL_UnionRect)
func (a *Rect) Union(b *Rect) Rect {
var result Rect
if a == nil || b == nil {
return result
}
// Special case for empty rects
if a.Empty() {
return *b
} else if b.Empty() {
return *a
} else if a.Empty() && b.Empty() {
return result
}
aMin := a.X
aMax := aMin + a.W
bMin := b.X
bMax := bMin + b.W
if bMin < aMin {
aMin = bMin
}
result.X = aMin
if bMax > aMax {
aMax = bMax
}
result.W = aMax - aMin
aMin = a.Y
aMax = aMin + a.H
bMin = b.Y
bMax = bMin + b.H
if bMin < aMin {
aMin = bMin
}
result.Y = aMin
if bMax > aMax {
aMax = bMax
}
result.H = aMax - aMin
return result
}
// Empty reports whether a rectangle has no area.
// (https://wiki.libsdl.org/SDL_RectEmpty)
func (a *FRect) Empty() bool {
return a == nil || a.W <= 0 || a.H <= 0
}
// Equals reports whether two rectangles are equal.
// (https://wiki.libsdl.org/SDL_RectEquals)
func (a *FRect) Equals(b *FRect) bool {
if (a != nil) && (b != nil) &&
(a.X == b.X) && (a.Y == b.Y) &&
(a.W == b.W) && (a.H == b.H) {
return true
}
return false
}
// EqualsEpsilon returns true if the two rectangles are equal, within some given epsilon.
// (https://wiki.libsdl.org/SDL_FRectEqualsEpsilon)
func (a *FRect) EqualsEpsilon(b *FRect, epsilon float32) bool {
if (a != nil) && (b != nil) && (a == b ||
(float32(math.Abs(float64(a.X-b.X))) <= epsilon) &&
(float32(math.Abs(float64(a.Y-b.Y))) <= epsilon) &&
(float32(math.Abs(float64(a.W-b.W))) <= epsilon) &&
(float32(math.Abs(float64(a.H-b.H))) <= epsilon)) {
return true
}
return false
}
// HasIntersection reports whether two rectangles intersect.
// (https://wiki.libsdl.org/SDL_HasIntersection)
func (a *FRect) HasIntersection(b *FRect) bool {
if a == nil || b == nil {
return false
}
// Special case for empty rects
if a.Empty() || b.Empty() {
return false
}
if a.X >= b.X+b.W || a.X+a.W <= b.X || a.Y >= b.Y+b.H || a.Y+a.H <= b.Y {
return false
}
return true
}
// Intersect calculates the intersection of two rectangles.
// (https://wiki.libsdl.org/SDL_IntersectRect)
func (a *FRect) Intersect(b *FRect) (FRect, bool) {
var result FRect
if a == nil || b == nil {
return result, false
}
// Special case for empty rects
if a.Empty() || b.Empty() {
result.W = 0
result.H = 0
return result, false
}
aMin := a.X
aMax := aMin + a.W
bMin := b.X
bMax := bMin + b.W
if bMin > aMin {
aMin = bMin
}
result.X = aMin
if bMax < aMax {
aMax = bMax
}
result.W = aMax - aMin
aMin = a.Y
aMax = aMin + a.H
bMin = b.Y
bMax = bMin + b.H
if bMin > aMin {
aMin = bMin
}
result.Y = aMin
if bMax < aMax {
aMax = bMax
}
result.H = aMax - aMin
return result, !result.Empty()
}
// Union calculates the union of two rectangles.
// (https://wiki.libsdl.org/SDL_UnionRect)
func (a *FRect) Union(b *FRect) FRect {
var result FRect
if a == nil || b == nil {
return result
}
// Special case for empty rects
if a.Empty() {
return *b
} else if b.Empty() {
return *a
} else if a.Empty() && b.Empty() {
return result
}
aMin := a.X
aMax := aMin + a.W
bMin := b.X
bMax := bMin + b.W
if bMin < aMin {
aMin = bMin
}
result.X = aMin
if bMax > aMax {
aMax = bMax
}
result.W = aMax - aMin
aMin = a.Y
aMax = aMin + a.H
bMin = b.Y
bMax = bMin + b.H
if bMin < aMin {
aMin = bMin
}
result.Y = aMin
if bMax > aMax {
aMax = bMax
}
result.H = aMax - aMin
return result
}
// EnclosePoints calculates a minimal rectangle that encloses a set of points.
// (https://wiki.libsdl.org/SDL_EnclosePoints)
func EnclosePoints(points []Point, clip *Rect) (Rect, bool) {
var result Rect
if len(points) == 0 {
return result, false
}
var minX, minY, maxX, maxY int32
if clip != nil {
added := false
clipMinX := clip.X
clipMinY := clip.Y
clipMaxX := clip.X + clip.W - 1
clipMaxY := clip.Y + clip.H - 1
// If the clip has no size, we're done
if clip.Empty() {
return result, false
}
for _, val := range points {
// Check if the point is inside the clip rect
if val.X < clipMinX || val.X > clipMaxX || val.Y < clipMinY || val.Y > clipMaxY {
continue
}
if !added {
// If it's the first point
minX = val.X
maxX = val.X
minY = val.Y
maxY = val.Y
added = true
}
// Find mins and maxes
if val.X < minX {
minX = val.X
} else if val.X > maxX {
maxX = val.X
}
if val.Y < minY {
minY = val.Y
} else if val.Y > maxY {
maxY = val.Y
}
}
} else {
for i, val := range points {
if i == 0 {
// Populate the first point
minX = val.X
maxX = val.X
minY = val.Y
maxY = val.Y
continue
}
// Find mins and maxes
if val.X < minX {
minX = val.X
} else if val.X > maxX {
maxX = val.X
}
if val.Y < minY {
minY = val.Y
} else if val.Y > maxY {
maxY = val.Y
}
}
}
result.X = minX
result.Y = minY
result.W = (maxX - minX) + 1
result.H = (maxY - minY) + 1
return result, true
}
// EncloseFPoints calculates a minimal rectangle that encloses a set of points with float precision.
// (https://wiki.libsdl.org/SDL_EncloseFPoints)
func EncloseFPoints(points []FPoint, clip *FRect) (result FRect, enclosed bool) {
if len(points) == 0 {
return result, false
}
var minX, minY, maxX, maxY float32
if clip != nil {
added := false
clipMinX := clip.X
clipMinY := clip.Y
clipMaxX := clip.X + clip.W - 1
clipMaxY := clip.Y + clip.H - 1
// If the clip has no size, we're done
if clip.Empty() {
return result, false
}
for _, val := range points {
// Check if the point is inside the clip rect
if val.X < clipMinX || val.X > clipMaxX || val.Y < clipMinY || val.Y > clipMaxY {
continue
}
if !added {
// If it's the first point
minX = val.X
maxX = val.X
minY = val.Y
maxY = val.Y
added = true
}
// Find mins and maxes
if val.X < minX {
minX = val.X
} else if val.X > maxX {
maxX = val.X
}
if val.Y < minY {
minY = val.Y
} else if val.Y > maxY {
maxY = val.Y
}
}
} else {
for i, val := range points {
if i == 0 {
// Populate the first point
minX = val.X
maxX = val.X
minY = val.Y
maxY = val.Y
continue
}
// Find mins and maxes
if val.X < minX {
minX = val.X
} else if val.X > maxX {
maxX = val.X
}
if val.Y < minY {
minY = val.Y
} else if val.Y > maxY {
maxY = val.Y
}
}
}
result.X = minX
result.Y = minY
result.W = (maxX - minX) + 1
result.H = (maxY - minY) + 1
return result, true
}
const (
codeBottom = 1
codeTop = 2
codeLeft = 4
codeRight = 8
)
func computeOutCode(rect *Rect, x, y int32) int {
code := 0
if y < rect.Y {
code |= codeTop
} else if y >= rect.Y+rect.H {
code |= codeBottom
}
if x < rect.X {
code |= codeLeft
} else if x >= rect.X+rect.W {
code |= codeRight
}
return code
}
func computeFOutCode(rect *FRect, x, y float32) int {
code := 0
if y < rect.Y {
code |= codeTop
} else if y >= rect.Y+rect.H {
code |= codeBottom
}
if x < rect.X {
code |= codeLeft
} else if x >= rect.X+rect.W {
code |= codeRight
}
return code
}
// IntersectLine calculates the intersection of a rectangle and a line segment.
// (https://wiki.libsdl.org/SDL_IntersectRectAndLine)
func (a *Rect) IntersectLine(X1, Y1, X2, Y2 *int32) bool {
if a.Empty() {
return false
}
x1 := *X1
y1 := *Y1
x2 := *X2
y2 := *Y2
rectX1 := a.X
rectY1 := a.Y
rectX2 := a.X + a.W - 1
rectY2 := a.Y + a.H - 1
// Check if the line is entirely inside the rect
if x1 >= rectX1 && x1 <= rectX2 && x2 >= rectX1 && x2 <= rectX2 &&
y1 >= rectY1 && y1 <= rectY2 && y2 >= rectY1 && y2 <= rectY2 {
return true
}
// Check if the line is entirely outside the rect
if (x1 < rectX1 && x2 < rectX1) || (x1 > rectX2 && x2 > rectX2) ||
(y1 < rectY1 && y2 < rectY1) || (y1 > rectY2 && y2 > rectY2) {
return false
}
// Check if the line is horizontal
if y1 == y2 {
if x1 < rectX1 {
*X1 = rectX1
} else if x1 > rectX2 {
*X1 = rectX2
}
if x2 < rectX1 {
*X2 = rectX1
} else if x2 > rectX2 {
*X2 = rectX2
}
return true
}
// Check if the line is vertical
if x1 == x2 {
if y1 < rectY1 {
*Y1 = rectY1
} else if y1 > rectY2 {
*Y1 = rectY2
}
if y2 < rectY1 {
*Y2 = rectY1
} else if y2 > rectY2 {
*Y2 = rectY2
}
return true
}
// Use Cohen-Sutherland algorithm when all shortcuts fail
outCode1 := computeOutCode(a, x1, y1)
outCode2 := computeOutCode(a, x2, y2)
for outCode1 != 0 || outCode2 != 0 {
if outCode1&outCode2 != 0 {
return false
}
if outCode1 != 0 {
var x, y int32
if outCode1&codeTop != 0 {
y = rectY1
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode1&codeBottom != 0 {
y = rectY2
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode1&codeLeft != 0 {
x = rectX1
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
} else if outCode1&codeRight != 0 {
x = rectX2
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
}
x1 = x
y1 = y
outCode1 = computeOutCode(a, x, y)
} else {
var x, y int32
if outCode2&codeTop != 0 {
y = rectY1
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode2&codeBottom != 0 {
y = rectY2
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode2&codeLeft != 0 {
x = rectX1
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
} else if outCode2&codeRight != 0 {
x = rectX2
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
}
x2 = x
y2 = y
outCode2 = computeOutCode(a, x, y)
}
}
*X1 = x1
*Y1 = y1
*X2 = x2
*Y2 = y2
return true
}
// IntersectLine calculates the intersection of a rectangle and a line segment.
// (https://wiki.libsdl.org/SDL_IntersectFRectAndLine)
func (a *FRect) IntersectLine(X1, Y1, X2, Y2 *float32) bool {
if a.Empty() {
return false
}
x1 := *X1
y1 := *Y1
x2 := *X2
y2 := *Y2
rectX1 := a.X
rectY1 := a.Y
rectX2 := a.X + a.W - 1
rectY2 := a.Y + a.H - 1
// Check if the line is entirely inside the rect
if x1 >= rectX1 && x1 <= rectX2 && x2 >= rectX1 && x2 <= rectX2 &&
y1 >= rectY1 && y1 <= rectY2 && y2 >= rectY1 && y2 <= rectY2 {
return true
}
// Check if the line is entirely outside the rect
if (x1 < rectX1 && x2 < rectX1) || (x1 > rectX2 && x2 > rectX2) ||
(y1 < rectY1 && y2 < rectY1) || (y1 > rectY2 && y2 > rectY2) {
return false
}
// Check if the line is horizontal
if y1 == y2 {
if x1 < rectX1 {
*X1 = rectX1
} else if x1 > rectX2 {
*X1 = rectX2
}
if x2 < rectX1 {
*X2 = rectX1
} else if x2 > rectX2 {
*X2 = rectX2
}
return true
}
// Check if the line is vertical
if x1 == x2 {
if y1 < rectY1 {
*Y1 = rectY1
} else if y1 > rectY2 {
*Y1 = rectY2
}
if y2 < rectY1 {
*Y2 = rectY1
} else if y2 > rectY2 {
*Y2 = rectY2
}
return true
}
// Use Cohen-Sutherland algorithm when all shortcuts fail
outCode1 := computeFOutCode(a, x1, y1)
outCode2 := computeFOutCode(a, x2, y2)
for outCode1 != 0 || outCode2 != 0 {
if outCode1&outCode2 != 0 {
return false
}
if outCode1 != 0 {
var x, y float32
if outCode1&codeTop != 0 {
y = rectY1
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode1&codeBottom != 0 {
y = rectY2
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode1&codeLeft != 0 {
x = rectX1
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
} else if outCode1&codeRight != 0 {
x = rectX2
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
}
x1 = x
y1 = y
outCode1 = computeFOutCode(a, x, y)
} else {
var x, y float32
if outCode2&codeTop != 0 {
y = rectY1
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode2&codeBottom != 0 {
y = rectY2
x = x1 + ((x2-x1)*(y-y1))/(y2-y1)
} else if outCode2&codeLeft != 0 {
x = rectX1
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
} else if outCode2&codeRight != 0 {
x = rectX2
y = y1 + ((y2-y1)*(x-x1))/(x2-x1)
}
x2 = x
y2 = y
outCode2 = computeFOutCode(a, x, y)
}
}
*X1 = x1
*Y1 = y1
*X2 = x2
*Y2 = y2
return true
}