From f501824de21eb70b1683f90e141025be6e246162 Mon Sep 17 00:00:00 2001 From: Charles Averill Date: Wed, 11 Oct 2023 23:06:27 -0500 Subject: [PATCH] MTL support --- .gitignore | 1 - README.md | 2 +- bin/argparse.ml | 2 +- lib/logging/logging.ml | 1 + lib/mesh.ml | 65 ++++-- lib/objloader.ml | 144 +++++++++--- lib/renderer.ml | 18 +- media/logo.png | Bin 6158 -> 9237 bytes objs/teapot.obj | 1 - objs/zenith.mtl | 72 ++++++ objs/zenith.obj | 516 ++++++++++++++++++++++++++--------------- 11 files changed, 572 insertions(+), 250 deletions(-) create mode 100644 objs/zenith.mtl diff --git a/.gitignore b/.gitignore index 3e57027..a353719 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,4 @@ *.cmxa _build .vscode/* -*.mtl .ocamlformat diff --git a/README.md b/README.md index 47ffc4f..77ecec2 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ OBJS="objs/uv_sphere.obj objs/torus.obj objs/star_destroyer.obj objs/pyramid.obj ### Blender -If you're using Blender to create 3D models for ZENITH, ensure that, in the export window under `Geometry`, the options "Write Normals," "Include UVs," and "Write Materials" are deactivated. These options generate vernacular in the output `.obj` file that my loader does not support. +If you want to color your Blender models, the only shader compatible with the `Kd` (diffuse color) field is Principled BSDF. ### Supported .OBJ Vernacular diff --git a/bin/argparse.ml b/bin/argparse.ml index 8bb59a7..4861c38 100644 --- a/bin/argparse.ml +++ b/bin/argparse.ml @@ -9,7 +9,7 @@ let copies l n = let parse_arguments () = let obj_files = ref [] in - let objs = ref [ cube ] in + let objs : mesh list ref = ref [ cube ] in let num_each = ref 1 in let speclist = diff --git a/lib/logging/logging.ml b/lib/logging/logging.ml index 71d985a..ce55273 100644 --- a/lib/logging/logging.ml +++ b/lib/logging/logging.ml @@ -27,6 +27,7 @@ let rc_Ok = (0, "OK") and rc_Error = (1, "ERROR") and rc_OOB = (2, "OUT OF BOUNDS ERROR") and rc_MatchError = (3, "MATCH ERROR") +and rc_MaterialError = (4, "MATERIAL ERROR") (** ANSI encoding for bold text *) let ansi_bold = "\x1b[1m" diff --git a/lib/mesh.ml b/lib/mesh.ml index 6608a2c..d1f03c4 100644 --- a/lib/mesh.ml +++ b/lib/mesh.ml @@ -1,24 +1,34 @@ +open Graphics open Math.Vector -type mesh = vec list * (int * int) list +(* Vertices, edges, edge colors *) +type mesh = vec list * ((int * int) * color option) list -let print_mesh mesh = +let print_mesh (mesh : mesh) = let vertices, edges = mesh in Printf.printf "Vertices:\n"; List.iteri (fun i v -> Printf.printf "%d: %s\n" i (string_of_vec v)) vertices; Printf.printf "\nEdges:\n"; - List.iter (fun (a, b) -> Printf.printf "(%d, %d)\n" a b) edges + List.iter + (fun ((a, b), c) -> + Printf.printf "(%d, %d) Color: %s\n" a b + (match c with None -> "None" | Some x -> string_of_int x)) + edges -let map_verts mesh f = (List.map f (fst mesh), snd mesh) +let map_verts (mesh : mesh) (f : vec -> vec) : mesh = + let verts, edges = mesh in + (List.map f verts, edges) -let triangle = - ([ v3 0.5 0. 0.; v3 1. 0. 0.; v3 1. 1. 0. ], [ (0, 1); (1, 2); (2, 0) ]) +let edge a b = ((a, b), None) -let square = +let triangle : mesh = + ([ v3 0.5 0. 0.; v3 1. 0. 0.; v3 1. 1. 0. ], [ edge 0 1; edge 1 2; edge 2 0 ]) + +let square : mesh = ( [ v3 0. 0. 0.; v3 0. 1. 0.; v3 1. 0. 0.; v3 1. 1. 0. ], - [ (0, 1); (0, 2); (3, 1); (3, 2) ] ) + [ edge 0 1; edge 0 2; edge 3 1; edge 3 2 ] ) -let cube = +let cube : mesh = ( [ v3 0. 0. 0.; v3 0. 0. 1.; @@ -30,23 +40,32 @@ let cube = v3 1. 1. 1.; ], [ - (0, 1); - (0, 2); - (0, 4); - (1, 3); - (1, 5); - (2, 3); - (2, 6); - (3, 7); - (4, 5); - (4, 6); - (5, 7); - (6, 7); + edge 0 1; + edge 0 2; + edge 0 4; + edge 1 3; + edge 1 5; + edge 2 3; + edge 2 6; + edge 3 7; + edge 4 5; + edge 4 6; + edge 5 7; + edge 6 7; ] ) -let pyramid = +let pyramid : mesh = ( [ v3 0. 0. 0.; v3 1. 0. 0.; v3 1. 0. 1.; v3 0. 0. 1.; v3 0.5 1. 0.5 ], - [ (0, 1); (1, 2); (2, 3); (3, 0); (0, 4); (1, 4); (2, 4); (3, 4) ] ) + [ + edge 0 1; + edge 1 2; + edge 2 3; + edge 3 0; + edge 0 4; + edge 1 4; + edge 2 4; + edge 3 4; + ] ) let filter_duplicates meshes = let rec aux acc seen = function diff --git a/lib/objloader.ml b/lib/objloader.ml index f3a5957..d66e6e3 100644 --- a/lib/objloader.ml +++ b/lib/objloader.ml @@ -1,7 +1,15 @@ +open Graphics open Mesh open Math.Vector +open Logging -type vernacular = Vertex of vec | Edge of (int * int) +type vernacular = + | Vertex of vec + | Edge of ((int * int) * color option) + | MaterialFilename of string + | UseMaterial of string + +type material = { name : string; color : color } let pairs_of_consecutive_elements lst = let rec aux first = function @@ -13,52 +21,120 @@ let pairs_of_consecutive_elements lst = in match lst with [] | [ _ ] -> [] | h :: _ :: _ -> aux h lst -let parse_obj_line line : vernacular list option = +let parse_obj_line line current_mtl : vernacular list option = match String.split_on_char ' ' line with - | [] -> None - | [ "#" ] -> None (* Comment line *) | "v" :: xs -> let v = List.map float_of_string xs in Some [ Vertex (v3 (List.nth v 0) (List.nth v 1) (List.nth v 2)) ] | "l" :: xs -> - let edge = List.map (fun s -> int_of_string s - 1) xs in - Some [ Edge (List.nth edge 0, List.nth edge 1) ] + let parsed_edge = List.map (fun s -> int_of_string s - 1) xs in + Some + [ + Edge + ( (List.nth parsed_edge 0, List.nth parsed_edge 1), + Some current_mtl.color ); + ] | "f" :: xs -> - let vertices = List.map (fun s -> int_of_string s - 1) xs in + let vertices = + List.map + (fun s -> + int_of_string + (if String.contains s '/' then String.sub s 0 (String.index s '/') + else s) + - 1) + xs + in let edges = pairs_of_consecutive_elements vertices in - Some (List.map (fun x -> Edge x) edges) + Some (List.map (fun x -> Edge (x, Some current_mtl.color)) edges) + | [ "mtllib"; name ] -> Some [ MaterialFilename name ] + | [ "usemtl"; name ] -> Some [ UseMaterial name ] | _ -> None -let rec parse_obj_lines lines vertices edges = +let scan_file filename = + let lines = ref [] in + try + let chan = open_in filename in + try + while true do + lines := input_line chan :: !lines + done; + !lines + with End_of_file -> + close_in chan; + List.rev !lines + with + | Sys_error s when String.ends_with ~suffix:"No such file or directory" s -> + [] + +let parse_mtls obj_fn mtl_fn : material list = + let lines = scan_file (Filename.concat (Filename.dirname obj_fn) mtl_fn) in + let found_materials : material list ref = ref [] in + let _ = + List.fold_left + (fun (name, color) line -> + if name != None && color != None then + match (name, color) with + | Some n, Some c -> + found_materials := { name = n; color = c } :: !found_materials; + (None, None) + | _ -> failwith "This never happens" + else + match String.split_on_char ' ' line with + | "newmtl" :: n -> (Some (String.concat " " n), color) + | [ "Kd"; r; g; b ] -> + let kd_to_comp kd = int_of_float (float_of_string kd *. 255.) in + (name, Some (rgb (kd_to_comp r) (kd_to_comp g) (kd_to_comp b))) + | _ -> (name, color)) + (None, None) lines + in + if List.length !found_materials = 0 then + fatal rc_MaterialError + ("Material file " ^ mtl_fn + ^ " did not contain both a material name and diffuse color") + else !found_materials + +let get_material l name obj_fn = + match + List.fold_left + (fun s i -> + if s != None then s else if i.name = name then Some i else None) + None l + with + | Some m -> m + | _ -> + fatal rc_MaterialError + ("Object file " ^ obj_fn ^ " tried to use material \"" ^ name + ^ "\" that has not been declared yet") + +let rec parse_obj_lines obj_fn lines (materials : material list) current_mtl + vertices edges = match lines with - | [] -> (vertices, edges) + | [] -> (List.rev vertices, edges) | line :: rest -> ( - match parse_obj_line line with - | Some [ Vertex v ] -> parse_obj_lines rest (v :: vertices) edges - | Some [ Edge e ] -> parse_obj_lines rest vertices (e :: edges) + match parse_obj_line line current_mtl with + | Some [ Vertex v ] -> + parse_obj_lines obj_fn rest materials current_mtl (v :: vertices) + edges + | Some [ Edge e ] -> + parse_obj_lines obj_fn rest materials current_mtl vertices (e :: edges) | Some (Edge e :: t) -> - parse_obj_lines rest vertices + parse_obj_lines obj_fn rest materials current_mtl vertices (List.map - (fun x -> match x with Edge _e -> _e | _ -> (0, 0)) + (fun x -> match x with Edge _e -> _e | _ -> edge 0 0) (Edge e :: t) @ edges) - | _ -> parse_obj_lines rest vertices edges) - -let parse_obj_file filename = - let lines = ref [] in - let chan = open_in filename in - try - while true do - lines := input_line chan :: !lines - done; - !lines - with End_of_file -> - close_in chan; - List.rev !lines + | Some [ MaterialFilename mtl_fn ] -> + parse_obj_lines obj_fn rest + (parse_mtls obj_fn mtl_fn @ materials) + current_mtl vertices edges + | Some [ UseMaterial mtl_name ] -> + parse_obj_lines obj_fn rest materials + (get_material materials mtl_name obj_fn) + vertices edges + | _ -> parse_obj_lines obj_fn rest materials current_mtl vertices edges) -let load_obj filename : mesh = - let lines = parse_obj_file filename in - let vertices, edges = parse_obj_lines lines [] [] in - let out = (List.rev vertices, List.rev edges) in - (* print_mesh out; *) - out +let load_obj obj_fn : mesh = + let obj_lines = scan_file obj_fn in + parse_obj_lines obj_fn obj_lines [] + { name = "Default"; color = Config.edge_color } + [] [] diff --git a/lib/renderer.ml b/lib/renderer.ml index 1303a84..9b5f450 100644 --- a/lib/renderer.ml +++ b/lib/renderer.ml @@ -182,7 +182,7 @@ let projection_matrix fov aspect_ratio z_near z_far = dim = (4, 4); } -let project_mesh mesh euler_rot translation = +let project_mesh (m : mesh) euler_rot translation : mesh = let mvp = matmul (matmul @@ -195,7 +195,7 @@ let project_mesh mesh euler_rot translation = ( (Config.z_far -. Config.z_near) /. 2., (Config.z_far +. Config.z_near) /. 2. ) in - map_verts mesh (fun v -> + map_verts m (fun v -> v |> fun x -> (* Projection *) vecmatmul x mvp |> fun x -> @@ -209,14 +209,16 @@ let project_mesh mesh euler_rot translation = w = x.w; }) -let draw_mesh mesh euler_rot translation = +let draw_mesh m euler_rot translation = let c = foreground in set_color Config.edge_color; - let verts, edges = project_mesh mesh euler_rot translation in + let verts, edges = project_mesh m euler_rot translation in let _ = List.fold_left - (fun visited_verts edge -> - let v1, v2 = (List.nth verts (fst edge), List.nth verts (snd edge)) in + (fun (index, visited_verts) e -> + let (e1, e2), ecolor = e in + let v1, v2 = (List.nth verts e1, List.nth verts e2) in + let _ = match ecolor with Some c -> set_color c | _ -> () in draw_line v1 v2; if Config.draw_verts then ( set_color Config.vert_color; @@ -227,7 +229,7 @@ let draw_mesh mesh euler_rot translation = fill_circle (int_of_float v2.x) (int_of_float v2.y) Config.vert_radius; set_color Config.edge_color); - v1 :: v2 :: visited_verts) - [] edges + (index + 1, v1 :: v2 :: visited_verts)) + (0, []) edges in set_color c diff --git a/media/logo.png b/media/logo.png index 7c4bcb8ac939dd644f8617b6790de97bf53d5d4b..95b4f1577b6e7e53d2e919a836b9ecc08bc58a1d 100644 GIT binary patch literal 9237 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 JP^{-j`yV)(h^7Dl diff --git a/objs/teapot.obj b/objs/teapot.obj index 9b194f3..3914788 100644 --- a/objs/teapot.obj +++ b/objs/teapot.obj @@ -1,6 +1,5 @@ # Blender v3.0.0 OBJ File: '' # www.blender.org -mtllib teapot.mtl o teapot v 1.368074 2.435437 -0.227403 v 1.381968 2.400000 -0.229712 diff --git a/objs/zenith.mtl b/objs/zenith.mtl new file mode 100644 index 0000000..f79cc13 --- /dev/null +++ b/objs/zenith.mtl @@ -0,0 +1,72 @@ +# Blender MTL File: 'untitled.blend' +# Material Count: 7 + +newmtl Blue +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.000000 0.000000 1.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Green +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.000000 1.000000 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Indigo +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.131147 0.000000 0.416085 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Orange +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 1.000000 0.376262 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Red +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 1.000000 0.000000 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Violet +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.212231 0.000000 1.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 + +newmtl Yellow +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 1.000000 1.000000 0.000000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/objs/zenith.obj b/objs/zenith.obj index 4752d2e..ff47bce 100644 --- a/objs/zenith.obj +++ b/objs/zenith.obj @@ -1,5 +1,6 @@ -# Blender v3.0.1 OBJ File: '' +# Blender v3.0.1 OBJ File: 'untitled.blend' # www.blender.org +mtllib zenith.mtl o Text v 6.430280 -1.504543 -0.625003 v 6.430280 1.402433 -0.625002 @@ -137,184 +138,337 @@ v -7.980018 -0.786105 0.624998 v -7.980018 -0.902384 0.624998 v -6.219220 -0.902384 0.624998 v -6.219220 -1.504543 0.624998 +vt 0.363636 0.000000 +vt 0.454545 0.000000 +vt 0.545455 0.000000 +vt 0.272727 0.000000 +vt 0.636364 0.000000 +vt 0.181818 0.000000 +vt 0.090909 0.000000 +vt 0.727273 0.000000 +vt 0.000000 0.000000 +vt 0.818182 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.363636 0.000000 +vt 0.545455 0.000000 +vt 0.454545 0.000000 +vt 0.272727 0.000000 +vt 0.636364 0.000000 +vt 0.181818 0.000000 +vt 0.090909 0.000000 +vt 0.727273 0.000000 +vt 0.000000 0.000000 +vt 0.818182 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.090909 0.000000 +vt 0.363636 0.000000 +vt 0.181818 0.000000 +vt 0.272727 0.000000 +vt 0.454545 0.000000 +vt 0.727273 0.000000 +vt 0.545455 0.000000 +vt 0.636364 0.000000 +vt 0.818182 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.363636 0.000000 +vt 0.090909 0.000000 +vt 0.181818 0.000000 +vt 0.272727 0.000000 +vt 0.454545 0.000000 +vt 0.727273 0.000000 +vt 0.545455 0.000000 +vt 0.636364 0.000000 +vt 0.818182 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.090909 0.000000 +vt 0.909091 0.000000 +vt 0.181818 0.000000 +vt 0.818182 0.000000 +vt 0.272727 0.000000 +vt 0.363636 0.000000 +vt 0.454545 0.000000 +vt 0.545455 0.000000 +vt 0.636364 0.000000 +vt 1.000000 0.000000 +vt 0.727273 0.000000 +vt 0.000000 0.000000 +vt 0.909091 0.000000 +vt 0.090909 0.000000 +vt 0.181818 0.000000 +vt 0.818182 0.000000 +vt 0.272727 0.000000 +vt 0.363636 0.000000 +vt 0.545455 0.000000 +vt 0.454545 0.000000 +vt 0.636364 0.000000 +vt 1.000000 0.000000 +vt 0.727273 0.000000 +vt 0.363636 0.000000 +vt 0.454545 0.000000 +vt 0.545455 0.000000 +vt 0.636364 0.000000 +vt 0.272727 0.000000 +vt 0.181818 0.000000 +vt 0.727273 0.000000 +vt 0.818182 0.000000 +vt 0.000000 0.000000 +vt 0.090909 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.363636 0.000000 +vt 0.545455 0.000000 +vt 0.454545 0.000000 +vt 0.636364 0.000000 +vt 0.272727 0.000000 +vt 0.181818 0.000000 +vt 0.727273 0.000000 +vt 0.818182 0.000000 +vt 0.000000 0.000000 +vt 0.090909 0.000000 +vt 0.909091 0.000000 +vt 1.000000 0.000000 +vt 0.285714 0.000000 +vt 0.428571 0.000000 +vt 0.571429 0.000000 +vt 0.714286 0.000000 +vt 0.142857 0.000000 +vt 0.000000 0.000000 +vt 0.857143 0.000000 +vt 1.000000 0.000000 +vt 0.285714 0.000000 +vt 0.571429 0.000000 +vt 0.428571 0.000000 +vt 0.714286 0.000000 +vt 0.142857 0.000000 +vt 0.000000 0.000000 +vt 0.857143 0.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.090909 0.000000 +vt 0.181818 0.000000 +vt 0.272727 0.000000 +vt 0.909091 0.000000 +vt 0.363636 0.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.181818 0.000000 +vt 0.090909 0.000000 +vt 0.272727 0.000000 +vt 0.909091 0.000000 +vt 0.363636 0.000000 +vt 1.000000 0.000000 +vt 0.454545 0.000000 +vt 0.545455 0.000000 +vt 0.636364 0.000000 +vt 0.818182 0.000000 +vt 0.727273 0.000000 +vt 0.545455 0.000000 +vt 0.454545 0.000000 +vt 0.636364 0.000000 +vt 0.818182 0.000000 +vt 0.727273 0.000000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 -0.0000 1.0000 +vn 0.0000 -1.0000 0.0000 +vn 1.0000 0.0000 0.0000 +vn -1.0000 0.0000 0.0000 +vn -0.6192 0.7852 0.0000 +vn 0.6192 -0.7852 -0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.8889 0.4582 0.0000 +vn -0.8889 -0.4582 0.0000 +usemtl Red s off -f 1 2 3 -f 1 3 4 -f 5 6 7 -f 5 7 8 -f 1 4 11 -f 11 4 5 -f 11 5 10 -f 10 5 8 -f 1 11 12 -f 9 10 8 -f 15 16 17 -f 15 17 18 -f 14 15 18 -f 13 14 19 -f 19 14 18 -f 13 19 20 -f 25 26 27 -f 25 27 28 -f 24 25 28 -f 23 24 29 -f 29 24 28 -f 23 29 30 -f 21 22 23 -f 21 23 30 -f 21 30 31 -f 21 31 32 -f 33 34 43 -f 43 34 35 -f 43 35 42 -f 42 35 36 -f 37 38 39 -f 37 39 40 -f 33 43 44 -f 41 42 36 -f 41 36 37 -f 41 37 40 -f 45 46 49 -f 49 46 47 -f 49 47 48 -f 45 49 50 -f 45 50 53 -f 53 50 51 -f 53 51 52 -f 45 53 54 -f 45 54 55 -f 45 55 56 -f 61 62 63 -f 61 63 60 -f 60 63 64 -f 59 60 64 -f 58 59 64 -f 58 64 65 -f 57 58 65 -f 57 65 66 -f 57 66 67 -f 57 67 68 -f 69 71 70 -f 69 72 71 -f 73 75 74 -f 73 76 75 -f 69 79 72 -f 79 73 72 -f 79 78 73 -f 78 76 73 -f 69 80 79 -f 77 76 78 -f 83 85 84 -f 83 86 85 -f 82 86 83 -f 81 87 82 -f 87 86 82 -f 81 88 87 -f 93 95 94 -f 93 96 95 -f 92 96 93 -f 91 97 92 -f 97 96 92 -f 91 98 97 -f 89 91 90 -f 89 98 91 -f 89 99 98 -f 89 100 99 -f 101 111 102 -f 111 103 102 -f 111 110 103 -f 110 104 103 -f 105 107 106 -f 105 108 107 -f 101 112 111 -f 109 104 110 -f 109 105 104 -f 109 108 105 -f 113 117 114 -f 117 115 114 -f 117 116 115 -f 113 118 117 -f 113 121 118 -f 121 119 118 -f 121 120 119 -f 113 122 121 -f 113 123 122 -f 113 124 123 -f 129 131 130 -f 129 128 131 -f 128 132 131 -f 127 132 128 -f 126 132 127 -f 126 133 132 -f 125 133 126 -f 125 134 133 -f 125 135 134 -f 125 136 135 -f 61 60 128 129 -f 37 36 104 105 -f 41 40 108 109 -f 23 22 90 91 -f 17 16 84 85 -f 46 45 113 114 -f 64 63 131 132 -f 18 17 85 86 -f 60 59 127 128 -f 31 30 98 99 -f 15 14 82 83 -f 2 1 69 70 -f 21 32 100 89 -f 59 58 126 127 -f 47 46 114 115 -f 32 31 99 100 -f 14 13 81 82 -f 3 2 70 71 -f 49 48 116 117 -f 34 33 101 102 -f 48 47 115 116 -f 4 3 71 72 -f 65 64 132 133 -f 19 18 86 87 -f 6 5 73 74 -f 58 57 125 126 -f 50 49 117 118 -f 13 20 88 81 -f 35 34 102 103 -f 20 19 87 88 -f 7 6 74 75 -f 43 42 110 111 -f 26 25 93 94 -f 66 65 133 134 -f 8 7 75 76 -f 51 50 118 119 -f 27 26 94 95 -f 67 66 134 135 -f 53 52 120 121 -f 36 35 103 104 -f 57 68 136 125 -f 52 51 119 120 -f 38 37 105 106 -f 28 27 95 96 -f 68 67 135 136 -f 25 24 92 93 -f 5 4 72 73 -f 54 53 121 122 -f 39 38 106 107 -f 11 10 78 79 -f 24 23 91 92 -f 55 54 122 123 -f 40 39 107 108 -f 45 56 124 113 -f 33 44 112 101 -f 1 12 80 69 -f 56 55 123 124 -f 44 43 111 112 -f 29 28 96 97 -f 12 11 79 80 -f 62 61 129 130 -f 42 41 109 110 -f 10 9 77 78 -f 30 29 97 98 -f 9 8 76 77 -f 63 62 130 131 -f 22 21 89 90 -f 16 15 83 84 +f 61/1/1 62/2/1 63/3/1 +f 61/1/1 63/3/1 60/4/1 +f 60/4/1 63/3/1 64/5/1 +f 59/6/1 60/4/1 64/5/1 +f 58/7/1 59/6/1 64/5/1 +f 58/7/1 64/5/1 65/8/1 +f 57/9/1 58/7/1 65/8/1 +f 57/9/1 65/8/1 66/10/1 +f 57/9/1 66/10/1 67/11/1 +f 57/9/1 67/11/1 68/12/1 +f 129/13/2 131/14/2 130/15/2 +f 129/13/2 128/16/2 131/14/2 +f 128/16/2 132/17/2 131/14/2 +f 127/18/2 132/17/2 128/16/2 +f 126/19/2 132/17/2 127/18/2 +f 126/19/2 133/20/2 132/17/2 +f 125/21/2 133/20/2 126/19/2 +f 125/21/2 134/22/2 133/20/2 +f 125/21/2 135/23/2 134/22/2 +f 125/21/2 136/24/2 135/23/2 +f 61/1/3 60/4/3 128/16/3 129/13/3 +f 64/5/4 63/3/4 131/14/4 132/17/4 +f 60/4/5 59/6/5 127/18/5 128/16/5 +f 59/6/6 58/7/6 126/19/6 127/18/6 +f 65/8/7 64/5/7 132/17/7 133/20/7 +f 58/7/5 57/9/5 125/21/5 126/19/5 +f 66/10/4 65/8/4 133/20/4 134/22/4 +f 67/11/8 66/10/8 134/22/8 135/23/8 +f 57/9/3 68/12/3 136/24/3 125/21/3 +f 68/12/4 67/11/4 135/23/4 136/24/4 +f 62/2/5 61/1/5 129/13/5 130/15/5 +f 63/3/8 62/2/8 130/15/8 131/14/8 +usemtl Orange +f 45/25/1 46/26/1 49/27/1 +f 49/27/1 46/26/1 47/28/1 +f 49/27/1 47/28/1 48/29/1 +f 45/25/1 49/27/1 50/30/1 +f 45/25/1 50/30/1 53/31/1 +f 53/31/1 50/30/1 51/32/1 +f 53/31/1 51/32/1 52/33/1 +f 45/25/1 53/31/1 54/34/1 +f 45/25/1 54/34/1 55/35/1 +f 45/25/1 55/35/1 56/36/1 +f 113/37/2 117/38/2 114/39/2 +f 117/38/2 115/40/2 114/39/2 +f 117/38/2 116/41/2 115/40/2 +f 113/37/2 118/42/2 117/38/2 +f 113/37/2 121/43/2 118/42/2 +f 121/43/2 119/44/2 118/42/2 +f 121/43/2 120/45/2 119/44/2 +f 113/37/2 122/46/2 121/43/2 +f 113/37/2 123/47/2 122/46/2 +f 113/37/2 124/48/2 123/47/2 +f 46/26/5 45/25/5 113/37/5 114/39/5 +f 47/28/8 46/26/8 114/39/8 115/40/8 +f 49/27/3 48/29/3 116/41/3 117/38/3 +f 48/29/4 47/28/4 115/40/4 116/41/4 +f 50/30/4 49/27/4 117/38/4 118/42/4 +f 51/32/8 50/30/8 118/42/8 119/44/8 +f 53/31/3 52/33/3 120/45/3 121/43/3 +f 52/33/4 51/32/4 119/44/4 120/45/4 +f 54/34/4 53/31/4 121/43/4 122/46/4 +f 55/35/8 54/34/8 122/46/8 123/47/8 +f 45/25/3 56/36/3 124/48/3 113/37/3 +f 56/36/4 55/35/4 123/47/4 124/48/4 +usemtl Yellow +f 33/49/1 34/50/1 43/51/1 +f 43/51/1 34/50/1 35/52/1 +f 43/51/1 35/52/1 42/53/1 +f 42/53/1 35/52/1 36/54/1 +f 37/55/1 38/56/1 39/57/1 +f 37/55/1 39/57/1 40/58/1 +f 33/49/1 43/51/1 44/59/1 +f 41/60/1 42/53/1 36/54/1 +f 41/60/1 36/54/1 37/55/1 +f 41/60/1 37/55/1 40/58/1 +f 101/61/2 111/62/2 102/63/2 +f 111/62/2 103/64/2 102/63/2 +f 111/62/2 110/65/2 103/64/2 +f 110/65/2 104/66/2 103/64/2 +f 105/67/2 107/68/2 106/69/2 +f 105/67/2 108/70/2 107/68/2 +f 101/61/2 112/71/2 111/62/2 +f 109/72/2 104/66/2 110/65/2 +f 109/72/2 105/67/2 104/66/2 +f 109/72/2 108/70/2 105/67/2 +f 37/55/8 36/54/8 104/66/8 105/67/8 +f 41/60/3 40/58/3 108/70/3 109/72/3 +f 34/50/5 33/49/5 101/61/5 102/63/5 +f 35/52/8 34/50/8 102/63/8 103/64/8 +f 43/51/3 42/53/3 110/65/3 111/62/3 +f 36/54/9 35/52/9 103/64/9 104/66/9 +f 38/56/5 37/55/5 105/67/5 106/69/5 +f 39/57/8 38/56/8 106/69/8 107/68/8 +f 40/58/4 39/57/4 107/68/4 108/70/4 +f 33/49/3 44/59/3 112/71/3 101/61/3 +f 44/59/4 43/51/4 111/62/4 112/71/4 +f 42/53/10 41/60/10 109/72/10 110/65/10 +usemtl Green +f 25/73/1 26/74/1 27/75/1 +f 25/73/1 27/75/1 28/76/1 +f 24/77/1 25/73/1 28/76/1 +f 23/78/1 24/77/1 29/79/1 +f 29/79/2 24/77/2 28/76/2 +f 23/78/1 29/79/1 30/80/1 +f 21/81/1 22/82/1 23/78/1 +f 21/81/1 23/78/1 30/80/1 +f 21/81/1 30/80/1 31/83/1 +f 21/81/1 31/83/1 32/84/1 +f 93/85/2 95/86/2 94/87/2 +f 93/85/2 96/88/2 95/86/2 +f 92/89/2 96/88/2 93/85/2 +f 91/90/2 97/91/2 92/89/2 +f 97/91/2 96/88/2 92/89/2 +f 91/90/2 98/92/2 97/91/2 +f 89/93/2 91/90/2 90/94/2 +f 89/93/2 98/92/2 91/90/2 +f 89/93/2 99/95/2 98/92/2 +f 89/93/2 100/96/2 99/95/2 +f 23/78/8 22/82/8 90/94/8 91/90/8 +f 31/83/8 30/80/8 98/92/8 99/95/8 +f 21/81/3 32/84/3 100/96/3 89/93/3 +f 32/84/4 31/83/4 99/95/4 100/96/4 +f 26/74/5 25/73/5 93/85/5 94/87/5 +f 27/75/8 26/74/8 94/87/8 95/86/8 +f 28/76/4 27/75/4 95/86/4 96/88/4 +f 25/73/3 24/77/3 92/89/3 93/85/3 +f 24/77/5 23/78/5 91/90/5 92/89/5 +f 29/79/3 28/76/3 96/88/3 97/91/3 +f 30/80/4 29/79/4 97/91/4 98/92/4 +f 22/82/5 21/81/5 89/93/5 90/94/5 +usemtl Blue +f 15/97/1 16/98/1 17/99/1 +f 15/97/1 17/99/1 18/100/1 +f 14/101/2 15/97/2 18/100/2 +f 13/102/1 14/101/1 19/103/1 +f 19/103/2 14/101/2 18/100/2 +f 13/102/1 19/103/1 20/104/1 +f 83/105/2 85/106/2 84/107/2 +f 83/105/2 86/108/2 85/106/2 +f 82/109/2 86/108/2 83/105/2 +f 81/110/2 87/111/2 82/109/2 +f 87/111/1 86/108/1 82/109/1 +f 81/110/2 88/112/2 87/111/2 +f 17/99/8 16/98/8 84/107/8 85/106/8 +f 18/100/4 17/99/4 85/106/4 86/108/4 +f 15/97/3 14/101/3 82/109/3 83/105/3 +f 14/101/5 13/102/5 81/110/5 82/109/5 +f 19/103/3 18/100/3 86/108/3 87/111/3 +f 13/102/3 20/104/3 88/112/3 81/110/3 +f 20/104/4 19/103/4 87/111/4 88/112/4 +f 16/98/5 15/97/5 83/105/5 84/107/5 +usemtl Indigo +f 1/113/1 2/114/1 3/115/1 +f 1/113/1 3/115/1 4/116/1 +f 1/113/1 4/116/1 11/117/1 +f 11/117/1 4/116/1 5/118/1 +f 1/113/1 11/117/1 12/119/1 +f 69/120/2 71/121/2 70/122/2 +f 69/120/2 72/123/2 71/121/2 +f 69/120/2 79/124/2 72/123/2 +f 79/124/2 73/125/2 72/123/2 +f 69/120/2 80/126/2 79/124/2 +f 2/114/5 1/113/5 69/120/5 70/122/5 +f 3/115/8 2/114/8 70/122/8 71/121/8 +f 4/116/4 3/115/4 71/121/4 72/123/4 +f 5/118/8 4/116/8 72/123/8 73/125/8 +f 1/113/3 12/119/3 80/126/3 69/120/3 +f 12/119/4 11/117/4 79/124/4 80/126/4 +usemtl Violet +f 5/118/1 6/127/1 7/128/1 +f 5/118/1 7/128/1 8/129/1 +f 11/117/1 5/118/1 10/130/1 +f 10/130/1 5/118/1 8/129/1 +f 9/131/1 10/130/1 8/129/1 +f 73/125/2 75/132/2 74/133/2 +f 73/125/2 76/134/2 75/132/2 +f 79/124/2 78/135/2 73/125/2 +f 78/135/2 76/134/2 73/125/2 +f 77/136/2 76/134/2 78/135/2 +f 6/127/5 5/118/5 73/125/5 74/133/5 +f 7/128/8 6/127/8 74/133/8 75/132/8 +f 8/129/4 7/128/4 75/132/4 76/134/4 +f 11/117/3 10/130/3 78/135/3 79/124/3 +f 10/130/5 9/131/5 77/136/5 78/135/5 +f 9/131/3 8/129/3 76/134/3 77/136/3