124 lines
3.4 KiB
OCaml
124 lines
3.4 KiB
OCaml
|
[@@@warning "-32-69"]
|
||
|
|
||
|
module Sexp = Sexplib.Sexp
|
||
|
module Json = Yojson.Basic
|
||
|
|
||
|
type atlas = {
|
||
|
size : int;
|
||
|
width : int;
|
||
|
height : int;
|
||
|
y_origin : [`bottom | `top];
|
||
|
}
|
||
|
|
||
|
(* type metrics = { *)
|
||
|
(* line_height : float; *)
|
||
|
(* ascender : float; *)
|
||
|
(* descender : float; *)
|
||
|
(* underline_y : float; *)
|
||
|
(* } *)
|
||
|
|
||
|
type bounds = {
|
||
|
left : float;
|
||
|
bottom : float;
|
||
|
right : float;
|
||
|
top : float;
|
||
|
}
|
||
|
|
||
|
type glyph = {
|
||
|
unicode : int;
|
||
|
advance : float;
|
||
|
plane_bounds : bounds option;
|
||
|
atlas_bounds : bounds option;
|
||
|
}
|
||
|
|
||
|
type msdf = {
|
||
|
atlas : atlas;
|
||
|
glyphs : glyph list;
|
||
|
}
|
||
|
|
||
|
let invalid_json f x =
|
||
|
invalid_arg (f ^ ": unexpected json: " ^ Json.to_string x)
|
||
|
|
||
|
let int_of_json = function `Int i -> i |
|
||
|
x -> invalid_json "int_of_json" x
|
||
|
let float_of_json = function `Int i -> float_of_int i | `Float f -> f |
|
||
|
x -> invalid_json "float_of_json" x
|
||
|
let string_of_json = function `String s -> s |
|
||
|
x -> invalid_json "string_of_json" x
|
||
|
let list_of_json = function `List l -> l |
|
||
|
x -> invalid_json "list_of_json" x
|
||
|
let json_assoc_opt k = function
|
||
|
| `Assoc kv -> List.assoc_opt k kv
|
||
|
| x -> invalid_json "json_assoc" x
|
||
|
let json_assoc k js = match json_assoc_opt k js with
|
||
|
| Some v -> v
|
||
|
| None -> invalid_arg ("no key " ^ k)
|
||
|
|
||
|
let atlas_of_json = function
|
||
|
| `Assoc kv ->
|
||
|
let size = int_of_json (List.assoc "size" kv) in
|
||
|
let width = int_of_json (List.assoc "width" kv) in
|
||
|
let height = int_of_json (List.assoc "height" kv) in
|
||
|
let y_origin = match List.assoc "yOrigin" kv with
|
||
|
| `String "bottom" -> `bottom
|
||
|
| `String "top" -> `top
|
||
|
| x -> invalid_json "yOrigin" x
|
||
|
in
|
||
|
{ size; width; height; y_origin }
|
||
|
| x -> invalid_json "atlas_of_json" x
|
||
|
|
||
|
let bounds_of_json js =
|
||
|
let left = float_of_json (json_assoc "left" js) in
|
||
|
let right = float_of_json (json_assoc "right" js) in
|
||
|
let top = float_of_json (json_assoc "top" js) in
|
||
|
let bottom = float_of_json (json_assoc "bottom" js) in
|
||
|
{ left; right; top; bottom }
|
||
|
|
||
|
let glyph_of_json js =
|
||
|
let unicode = int_of_json (json_assoc "unicode" js) in
|
||
|
let advance = float_of_json (json_assoc "advance" js) in
|
||
|
let plane_bounds = Option.map bounds_of_json (json_assoc_opt "planeBounds" js) in
|
||
|
let atlas_bounds = Option.map bounds_of_json (json_assoc_opt "atlasBounds" js) in
|
||
|
{ unicode; advance; plane_bounds; atlas_bounds }
|
||
|
|
||
|
let msdf_of_json js =
|
||
|
let atlas = atlas_of_json (json_assoc "atlas" js) in
|
||
|
let glyphs = List.map glyph_of_json (list_of_json (json_assoc "glyphs" js)) in
|
||
|
{ atlas; glyphs }
|
||
|
|
||
|
let sexp_of_bounds b =
|
||
|
Sexp.List [
|
||
|
Atom (Printf.sprintf "%.4f" b.left);
|
||
|
Atom (Printf.sprintf "%.4f" b.top);
|
||
|
Atom (Printf.sprintf "%.4f" b.right);
|
||
|
Atom (Printf.sprintf "%.4f" b.bottom);
|
||
|
]
|
||
|
|
||
|
let sexp_of_glyph g =
|
||
|
let chr = Char.chr g.unicode in
|
||
|
Sexp.List (
|
||
|
Atom "glyph" ::
|
||
|
Atom (String.make 1 chr) ::
|
||
|
List [Atom "advance"; Atom (Printf.sprintf "%.4f" g.advance)] ::
|
||
|
(
|
||
|
(g.plane_bounds |> Option.map sexp_of_bounds |> Option.to_list) @
|
||
|
(g.atlas_bounds |> Option.map sexp_of_bounds |> Option.to_list)
|
||
|
)
|
||
|
)
|
||
|
|
||
|
let sexp_of_msdf msdf =
|
||
|
Sexp.List (
|
||
|
Atom "msdf" ::
|
||
|
List.map sexp_of_glyph
|
||
|
(List.sort (fun a b -> compare a.unicode b.unicode)
|
||
|
msdf.glyphs)
|
||
|
)
|
||
|
|
||
|
let () =
|
||
|
let inp = Json.from_channel stdin in
|
||
|
let msdf = msdf_of_json inp in
|
||
|
if msdf.atlas.y_origin <> `top then
|
||
|
failwith "origin must be top";
|
||
|
Format.printf "%a\n"
|
||
|
Sexp.pp_hum (sexp_of_msdf msdf)
|