draw_tree.ml 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. open Base
  2. open Math
  3. type dir = [`H | `V]
  4. type fig = Rect of Dim.t * Color.t
  5. type path = int list Lazy.t ref
  6. type tree = (arm, leaf) Generic_tree.t
  7. and arm = [`H of path | `V of path | `Uninit]
  8. and leaf = path * Event.Id.t * fig
  9. and t = tree
  10. let create_path () =
  11. ref (lazy (failwith "Path.to_list: path is uninitialized!"))
  12. let uninit : t =
  13. Arm(`Uninit, [])
  14. let arm dir ts : t =
  15. Arm((match dir with
  16. | `H -> `H(create_path ())
  17. | `V -> `V(create_path ())), ts)
  18. let figure fg : t =
  19. Leaf((create_path (), Event.Id.gen (), fg))
  20. let is_init : t -> bool = function
  21. | Arm(`Uninit, _) -> false
  22. | _ -> true
  23. let rec event_ids : t -> _ = function
  24. | Arm(_, ts) ->
  25. Sequence.(bind (of_list ts)) ~f:event_ids
  26. | Leaf((_, ev_id, _)) ->
  27. Sequence.singleton ev_id
  28. module Zipper = Generic_tree.Zipper
  29. type zipper = (arm, leaf) Zipper.t
  30. let fig_to_string = function
  31. | Rect(dim, color) ->
  32. Printf.sprintf "Rect(%s,%s)"
  33. (Dim.to_string dim)
  34. (Color.to_string color)
  35. let fig_equal fg1 fg2 = match fg1, fg2 with
  36. | Rect(d1, c1), Rect(d2, c2) ->
  37. Dim.equal d1 d2 && Color.equal c1 c2
  38. include Generic_tree.Make_show_eq
  39. (struct
  40. type t = arm
  41. let to_string = function
  42. | `H _ -> "H"
  43. | `V _ -> "V"
  44. | `Uninit -> "Uninit"
  45. let equal a b = match a, b with
  46. | `H _, `H _ -> true
  47. | `V _, `V _ -> true
  48. | `Uninit, `Uninit -> true
  49. | _, _ -> false
  50. end)
  51. (struct
  52. type t = leaf
  53. let to_string (_, _, fg) = fig_to_string fg
  54. let equal (_, _, fg1) (_, _, fg2) = fig_equal fg1 fg2
  55. end)
  56. (*** paths ***)
  57. module Path = struct
  58. type t = path
  59. let root () = ref (Lazy.from_val [])
  60. let of_list l = ref (Lazy.from_val l)
  61. let of_list_rev l = ref (lazy (List.rev l))
  62. let to_list p = Lazy.force !p
  63. let set_rev p l = p := lazy (List.rev l)
  64. let to_string p =
  65. Printf.sprintf "path[%s]" @@
  66. String.concat ~sep:";" @@
  67. List.map (to_list p) ~f:Int.to_string
  68. let equal a b =
  69. Polymorphic_compare.(to_list a = to_list b)
  70. end
  71. let path : t -> path = function
  72. | Leaf((path, _, _)) -> path
  73. | Arm((`H(path) | `V(path)), _) -> path
  74. | Arm(`Uninit, _) -> raise (Invalid_argument("Draw_tree.path called on uninit"))
  75. let rec refresh_paths ?(rev_prefix=[]) (t : t) =
  76. let () = Path.set_rev (path t) rev_prefix in
  77. match t with
  78. | Leaf _ -> ()
  79. | Arm(_, ts) ->
  80. List.iteri ts
  81. ~f:(fun i t ->
  82. refresh_paths ~rev_prefix:(i::rev_prefix) t)
  83. (*** updating ***)
  84. module Update = struct
  85. type t = Set of fig | Mount of tree | Unmount
  86. let to_string = function
  87. | Set(fig) -> Printf.sprintf "Set(%s)" (fig_to_string fig)
  88. | Mount(t) -> Printf.sprintf "Mount(%s)" (to_string t)
  89. | Unmount -> "Unmount"
  90. let equal a b = match a, b with
  91. | Set(fg1), Set(fg2) -> fig_equal fg1 fg2
  92. | Mount(t1), Mount(t2) -> equal t1 t2
  93. | Unmount, Unmount -> true
  94. | _, _ -> false
  95. let fail_message = function
  96. | Mount _ -> "cannot mount already-initialized tree"
  97. | Set _ -> "cannot update non-figure tree"
  98. | Unmount -> "cannot umount already-uninitialized tree"
  99. let apply_exn ~path (upd : t) : zipper -> zipper =
  100. Zipper.modify ~f:(fun tree ->
  101. match upd, tree with
  102. | Set(new_fig), Leaf((path, id, _)) ->
  103. Leaf((path, id, new_fig))
  104. | Mount(tree), Arm(`Uninit, _) ->
  105. let () = refresh_paths ~rev_prefix:(List.rev path) tree in
  106. tree
  107. | Unmount, _ when is_init tree ->
  108. uninit
  109. | _, _ ->
  110. failwith (fail_message upd))
  111. end
  112. type updates = (Path.t * Update.t) Sequence.t
  113. let apply_updates_exn upds t : t =
  114. Zipper.to_tree @@ snd @@
  115. Sequence.fold upds ~init:([], Zipper.of_tree t)
  116. ~f:(fun (p, zip) (p', upd) ->
  117. let p' = Path.to_list p' in
  118. (p', (zip
  119. |> Zipper.nav_exn ~prev:p ~targ:p'
  120. |> Update.apply_exn ~path:p' upd)))
  121. (*** generic geometry calculation ***)
  122. module type GEOMETRY_MONOID = sig
  123. type t
  124. val concat : t Sequence.t -> t
  125. val rect : AABB.t -> Color.t -> Event.Id.t -> t
  126. end
  127. let geometry
  128. (type a)
  129. (module A : GEOMETRY_MONOID with type t = a)
  130. (tree : t) : a =
  131. let rec compute : t -> (int * int * (AABB.t -> a)) = function
  132. | Leaf(_, ev_id, Rect({w;h} as dim, fill)) ->
  133. let go bounds = A.rect (AABB.center bounds dim) fill ev_id in
  134. (w, h, go)
  135. | Arm(`Uninit, _) ->
  136. (0, 0, fun _ -> A.concat Sequence.empty)
  137. | Arm((`H _ | `V _) as ty, ts) ->
  138. let axis1 x y = match ty with `H _ -> x | `V _ -> y in
  139. let axis2 x y = match ty with `H _ -> y | `V _ -> x in
  140. let pair a1 a2 = match ty with `H _ -> (a1, a2) | `V _ -> (a2, a1) in
  141. let (sizes_funcs, max_size, total_size) =
  142. List.fold_right ts ~init:([], 0, 0)
  143. ~f:(fun t (s_f, max_sz, tot_sz) ->
  144. let (w, h, func) = compute t in
  145. ((axis1 w h, func)::s_f,
  146. max (axis2 w h) max_sz,
  147. axis1 w h + tot_sz))
  148. in
  149. let go {bx;by;bh;bw} =
  150. let init = (axis1 bw bh - total_size) / 2 in
  151. Sequence.folding_map (Sequence.of_list sizes_funcs) ~init
  152. ~f:(fun off (size, func) ->
  153. (off + size,
  154. func { bx = bx + axis1 off 0
  155. ; by = by + axis2 off 0
  156. ; bw = axis1 size bw
  157. ; bh = axis2 size bh }))
  158. |> A.concat
  159. in
  160. let (w, h) = pair total_size max_size in
  161. (w, h, go)
  162. in
  163. let (bw, bh, func) = compute tree in
  164. func {bx=0;by=0;bw;bh}
  165. (*** rendering ***)
  166. module Draw = struct
  167. type t = Rect of AABB.t * Color.t
  168. let equal x y = match x, y with
  169. | Rect(b1, c1), Rect(b2, c2) ->
  170. AABB.equal b1 b2 && Color.equal c1 c2
  171. let to_string = function
  172. | Rect(b, c) -> Printf.sprintf "Rect(%s, %s)"
  173. (AABB.to_string b)
  174. (Color.to_string c)
  175. end
  176. module Draw_monoid = struct
  177. type nonrec t = Draw.t Sequence.t
  178. let concat = Sequence.concat
  179. let rect aabb color _ = Sequence.singleton (Draw.Rect(aabb, color))
  180. end
  181. let render tree : Draw.t Sequence.t =
  182. geometry (module Draw_monoid) tree
  183. (*** collision ***)
  184. module Collide_monoid = struct
  185. type t = Pos.t -> Event.Id.t option
  186. let concat ts pos = Sequence.find_map ts ~f:(fun f -> f pos)
  187. let rect bounds _ id pos = Option.some_if (AABB.contains bounds pos) id
  188. end
  189. let capture_point ~pos tree : Event.Id.t option =
  190. geometry (module Collide_monoid) tree pos