aboutsummaryrefslogtreecommitdiff
path: root/lib/oui/rect.odin
diff options
context:
space:
mode:
Diffstat (limited to 'lib/oui/rect.odin')
-rw-r--r--lib/oui/rect.odin245
1 files changed, 245 insertions, 0 deletions
diff --git a/lib/oui/rect.odin b/lib/oui/rect.odin
new file mode 100644
index 0000000..23f2e6d
--- /dev/null
+++ b/lib/oui/rect.odin
@@ -0,0 +1,245 @@
+package oui
+
+import "core:math"
+
+Rect :: struct {
+ l, r, t, b: int,
+}
+
+RECT_INF :: Rect {
+ max(int),
+ -max(int),
+ max(int),
+ -max(int),
+}
+
+// build a rectangle from multiple
+rect_inf_push :: proc(rect: ^Rect, other: Rect) {
+ rect.t = min(rect.t, other.t)
+ rect.l = min(rect.l, other.l)
+ rect.b = max(rect.b, other.b)
+ rect.r = max(rect.r, other.r)
+}
+
+rect_one :: #force_inline proc(a: int) -> Rect {
+ return { a, a, a, a }
+}
+
+rect_one_inv :: #force_inline proc(a: int) -> Rect {
+ return { a, -a, a, -a }
+}
+
+rect_negate :: #force_inline proc(a: Rect) -> Rect {
+ return {
+ -a.l,
+ -a.r,
+ -a.t,
+ -a.b,
+ }
+}
+
+rect_valid :: #force_inline proc(a: Rect) -> bool {
+ return a.r > a.l && a.b > a.t
+}
+
+rect_invalid :: #force_inline proc(rect: Rect) -> bool {
+ return !rect_valid(rect)
+}
+
+rect_width_invalid :: #force_inline proc(rect: Rect) -> bool {
+ return rect.r < rect.l
+}
+
+rect_height_invalid :: #force_inline proc(rect: Rect) -> bool {
+ return rect.b < rect.t
+}
+
+rect_wh :: #force_inline proc(x, y, w, h: int) -> Rect {
+ return { x, x + w, y, y + h }
+}
+
+rect_center :: #force_inline proc(a: Rect) -> (x, y: f32) {
+ return f32(a.l) + f32(a.r - a.l) / 2, f32(a.t) + f32(a.b - a.t) / 2
+}
+
+// width
+rect_width :: #force_inline proc(a: Rect) -> int {
+ return (a.r - a.l)
+}
+rect_widthf :: #force_inline proc(a: Rect) -> f32 {
+ return f32(a.r - a.l)
+}
+rect_width_halfed :: #force_inline proc(a: Rect) -> int {
+ return (a.r - a.l) / 2
+}
+rect_widthf_halfed :: #force_inline proc(a: Rect) -> f32 {
+ return f32(a.r - a.l) / 2
+}
+
+// height
+rect_height :: #force_inline proc(a: Rect) -> int {
+ return (a.b - a.t)
+}
+rect_heightf :: #force_inline proc(a: Rect) -> f32 {
+ return f32(a.b - a.t)
+}
+rect_height_halfed :: #force_inline proc(a: Rect) -> int {
+ return (a.b - a.t) / 2
+}
+rect_heightf_halfed :: #force_inline proc(a: Rect) -> f32 {
+ return f32(a.b - a.t) / 2
+}
+
+// width / height by option
+rect_opt_v :: #force_inline proc(a: Rect, vertical: bool) -> int {
+ return vertical ? rect_height(a) : rect_width(a)
+}
+rect_opt_h :: #force_inline proc(a: Rect, horizontal: bool) -> int {
+ return horizontal ? rect_width(a) : rect_height(a)
+}
+rect_opt_vf :: #force_inline proc(a: Rect, vertical: bool) -> f32 {
+ return vertical ? rect_heightf(a) : rect_widthf(a)
+}
+rect_opt_hf :: #force_inline proc(a: Rect, horizontal: bool) -> f32 {
+ return horizontal ? rect_widthf(a) : rect_heightf(a)
+}
+
+rect_xxyy :: #force_inline proc(x, y: int) -> Rect {
+ return { x, x, y, y }
+}
+
+rect_intersection :: proc(a, b: Rect) -> Rect {
+ a := a
+ if a.l < b.l do a.l = b.l
+ if a.t < b.t do a.t = b.t
+ if a.r > b.r do a.r = b.r
+ if a.b > b.b do a.b = b.b
+ return a
+}
+
+// smallest rectangle
+rect_bounding :: proc(a, b: Rect) -> Rect {
+ a := a
+ if a.l > b.l do a.l = b.l
+ if a.t > b.t do a.t = b.t
+ if a.r < b.r do a.r = b.r
+ if a.b < b.b do a.b = b.b
+ return a
+}
+
+rect_contains :: proc(a: Rect, x, y: int) -> bool {
+ return a.l <= x && a.r > x && a.t <= y && a.b > y
+}
+
+rect_offset :: proc(rect: ^Rect, x, y: int) {
+ rect.l += x
+ rect.r += x
+ rect.t += y
+ rect.b += y
+}
+
+rect_sized :: #force_inline proc(rect: ^Rect, pos: [2]int, size: [2]int) {
+ rect.l = pos.x
+ rect.r = pos.x + size.x
+ rect.t = pos.y
+ rect.b = pos.y + size.y
+}
+
+// rect cutting with HARD CUT, will result in invalid rectangles when out of size
+
+rect_cut_left :: proc(rect: ^Rect, a: int) -> (res: Rect) {
+ res = rect^
+ res.r = rect.l + a
+ rect.l = res.r
+ return
+}
+
+rect_cut_right :: proc(rect: ^Rect, a: int) -> (res: Rect) {
+ res = rect^
+ res.l = rect.r - a
+ rect.r = res.l
+ return
+}
+
+rect_cut_top :: proc(rect: ^Rect, a: int) -> (res: Rect) {
+ res = rect^
+ res.b = rect.t + a
+ rect.t = res.b
+ return
+}
+
+rect_cut_bottom :: proc(rect: ^Rect, a: int) -> (res: Rect) {
+ res = rect^
+ res.t = rect.b - a
+ rect.b = res.t
+ return
+}
+
+// add another rect as padding
+rect_padding :: proc(a, b: Rect) -> Rect {
+ a := a
+ a.l += b.l
+ a.t += b.t
+ a.r -= b.r
+ a.b -= b.b
+ return a
+}
+
+// add another rect as padding
+rect_margin :: proc(a: Rect, value: int) -> Rect {
+ a := a
+ a.l += value
+ a.t += value
+ a.r -= value
+ a.b -= value
+ return a
+}
+
+rect_add :: proc(a, b: Rect) -> Rect {
+ a := a
+ a.l += b.l
+ a.t += b.t
+ a.r += b.r
+ a.b += b.b
+ return a
+}
+
+rect_translate :: proc(a, b: Rect) -> Rect {
+ a := a
+ a.l += b.l
+ a.t += b.t
+ a.r += b.l
+ a.b += b.t
+ return a
+}
+
+rect_overlap :: proc(a, b: Rect) -> bool {
+ return b.r >= a.l && b.l <= a.r && b.b >= a.t && b.t <= a.b
+}
+
+rect_inside :: proc(a, b: Rect) -> bool {
+ return b.r >= a.l && b.l <= a.r && b.t >= a.t && b.b <= a.b
+}
+
+// cuts out rect b from a and returns the left regions
+rect_cut_out_rect :: proc(a, b: Rect) -> (res: [4]Rect) {
+ // top
+ res[0] = a
+ res[0].b = b.t
+
+ // bottom
+ res[1] = a
+ res[1].t = b.b
+
+ // middle
+ last := rect_intersection(res[0], res[1])
+
+ // left
+ res[2] = last
+ res[2].r = b.l
+
+ // right
+ res[3] = last
+ res[3].l = b.r
+ return
+}