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 }