From a7c2d13bcca784350d851b665b8a19697e113b34 Mon Sep 17 00:00:00 2001 From: San Jacobs Date: Thu, 17 Aug 2023 01:48:00 +0200 Subject: Screw everything, we do oui now --- lib/oui/rect.odin | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 lib/oui/rect.odin (limited to 'lib/oui/rect.odin') 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 +} -- cgit v1.2.1