summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--chickadee/render/asset.scm493
-rw-r--r--chickadee/render/model.scm911
-rw-r--r--chickadee/render/pbr.scm130
-rw-r--r--chickadee/render/phong.scm160
-rw-r--r--chickadee/render/scene.scm252
-rw-r--r--data/shaders/pbr/pbr-frag.glsl10
-rw-r--r--data/shaders/pbr/pbr-vert.glsl11
-rw-r--r--examples/model.scm73
-rw-r--r--examples/models/suzanne.obj2580
10 files changed, 3857 insertions, 768 deletions
diff --git a/Makefile.am b/Makefile.am
index 7754081..171a4ce 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,9 +68,10 @@ SOURCES = \
chickadee/render/sprite.scm \
chickadee/render/font.scm \
chickadee/render/tiled.scm \
- chickadee/render/scene.scm \
- chickadee/render/asset.scm \
chickadee/render/particles.scm \
+ chickadee/render/phong.scm \
+ chickadee/render/pbr.scm \
+ chickadee/render/model.scm \
chickadee/render.scm \
chickadee/scripting/agenda.scm \
chickadee/scripting/script.scm \
diff --git a/chickadee/render/asset.scm b/chickadee/render/asset.scm
deleted file mode 100644
index 44e7afc..0000000
--- a/chickadee/render/asset.scm
+++ /dev/null
@@ -1,493 +0,0 @@
-;;; Chickadee Game Toolkit
-;;; Copyright © 2017 David Thompson <davet@gnu.org>
-;;;
-;;; Chickadee is free software: you can redistribute it and/or modify
-;;; it under the terms of the GNU General Public License as published
-;;; by the Free Software Foundation, either version 3 of the License,
-;;; or (at your option) any later version.
-;;;
-;;; Chickadee is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;;; General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with this program. If not, see
-;;; <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; Implementation of the glTF 2.0 specification
-;;
-;;; Code:
-
-(define-module (chickadee render asset)
- #:use-module (chickadee json)
- #:use-module (chickadee math matrix)
- #:use-module (chickadee math vector)
- #:use-module (chickadee render buffer)
- #:use-module (chickadee render color)
- #:use-module (chickadee render scene)
- #:use-module (chickadee render shader)
- #:use-module (chickadee render texture)
- #:use-module (ice-9 format)
- #:use-module (ice-9 match)
- #:use-module (rnrs base)
- #:use-module (rnrs bytevectors)
- #:use-module (rnrs io ports)
- #:use-module (srfi srfi-9)
- #:use-module (srfi srfi-9 gnu)
- #:use-module ((srfi srfi-43) #:select (vector-every))
- #:export (load-asset
- asset?
- asset-copyright
- asset-generator
- asset-scenes
- asset-default-scene
- draw-asset))
-
-(define-record-type <asset>
- (make-asset copyright generator scenes default-scene)
- asset?
- (copyright asset-copyright)
- (generator asset-generator)
- (scenes asset-scenes)
- (default-scene asset-default-scene))
-
-(define (display-asset asset port)
- (format port "#<asset generator: ~s scene: ~s>"
- (asset-generator asset)
- (scene-name (asset-default-scene asset))))
-
-(set-record-type-printer! <asset> display-asset)
-
-(define (read-gltf port file)
- (define (object-ref obj key)
- (let ((value (assoc-ref obj key)))
- (unless (pair? value)
- (error "expected object for key" key value))
- value))
- (define (object-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (or (not value) (pair? value))
- (error "expected object for optional key" key value))
- value))
- (define (array-ref obj key)
- (let ((value (assoc-ref obj key)))
- (unless (vector? value)
- (error "expected array for key" key value))
- value))
- (define (array-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (or (not value) (vector? value))
- (error "expected array for optional key" key value))
- value))
- (define (string-ref obj key)
- (let ((value (assoc-ref obj key)))
- (unless (string? value)
- (error "expected string for key" key value))
- value))
- (define (string-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (or (not value) (string? value))
- (error "expected string for optional key" key value))
- value))
- (define (number-ref obj key)
- (let ((value (assoc-ref obj key)))
- (unless (number? value)
- (error "expected number for key" key value))
- value))
- (define (number-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (or (not value) (number? value))
- (error "expected number for key" key value))
- value))
- (define (boolean-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (boolean? value)
- (error "expected boolean for key" key value))
- value))
- (define (number-array-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (unless (or (not value)
- (and (vector? value) (vector-every number? value)))
- (error "expected numeric array for key" key value))
- value))
- (define (matrix-ref/optional obj key)
- (let ((value (assoc-ref obj key)))
- (cond
- ((not value) #f)
- ((and (vector? value)
- (= (vector-length value) 16)
- (vector-every number? value))
- ;; glTF matrices are in column-major order.
- (make-matrix4 (vector-ref value 0)
- (vector-ref value 4)
- (vector-ref value 8)
- (vector-ref value 12)
- (vector-ref value 1)
- (vector-ref value 5)
- (vector-ref value 9)
- (vector-ref value 13)
- (vector-ref value 2)
- (vector-ref value 6)
- (vector-ref value 10)
- (vector-ref value 14)
- (vector-ref value 3)
- (vector-ref value 7)
- (vector-ref value 11)
- (vector-ref value 15)))
- (else
- (error "expected 4x4 matrix for key" key value)))))
- (define (assert-color v)
- (if (and (= (vector-length v) 4)
- (vector-every (lambda (x) (and (>= x 0.0) (<= x 1.0))) v))
- (make-color (vector-ref v 0)
- (vector-ref v 1)
- (vector-ref v 2)
- (vector-ref v 3))
- (error "not a color vector" v)))
- (define scope-file
- (let ((gltf-root (dirname
- (if (absolute-file-name? file)
- file
- (string-append (getcwd) "/" file)))))
- (lambda (file)
- (if (absolute-file-name? file)
- file
- (string-append gltf-root "/" file)))))
- (define (parse-buffer obj)
- ;; TODO: support base64 encoded buffer data as uri
- ;; TODO: support glb-stored buffers:
- ;; https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-stored-buffer
- (let* ((uri (string-ref/optional obj "uri"))
- (length (number-ref obj "byteLength"))
- (name (or (string-ref/optional obj "name") "anonymous"))
- (extensions (object-ref/optional obj "extensions"))
- (extras (assoc-ref obj "extras"))
- (data (if uri
- (call-with-input-file (scope-file uri)
- (lambda (port)
- (get-bytevector-n port length)))
- (make-bytevector length))))
- data))
- (define (parse-buffer-view obj buffers)
- (let ((name (string-ref/optional obj "name"))
- (data (vector-ref buffers (number-ref obj "buffer")))
- (offset (or (number-ref/optional obj "byteOffset") 0))
- (length (number-ref obj "byteLength"))
- (stride (number-ref/optional obj "byteStride"))
- (target (match (or (number-ref/optional obj "target") 34962)
- (34962 'vertex)
- (34963 'index)))
- (extensions (object-ref/optional obj "extensions"))
- (extras (assoc-ref obj "extras")))
- (make-buffer data
- #:name name
- #:offset offset
- #:length length
- #:stride stride
- #:target target)))
- (define (parse-accessor obj buffer-views)
- (define (type-length type)
- (match type
- ('scalar 1)
- ('vec2 2)
- ('vec3 3)
- ('vec4 4)
- ('mat2 4)
- ('mat3 9)
- ('mat4 16)))
- (let ((name (or (string-ref/optional obj "name") "anonymous"))
- (view (match (number-ref/optional obj "bufferView")
- (#f #f)
- (n (vector-ref buffer-views n))))
- (offset (or (number-ref/optional obj "byteOffset") 0))
- (component-type (match (number-ref obj "componentType")
- (5120 'byte)
- (5121 'unsigned-byte)
- (5122 'short)
- (5123 'unsigned-short)
- (5125 'unsigned-int)
- (5126 'float)))
- (normalized? (boolean-ref/optional obj "normalized"))
- (length (number-ref obj "count"))
- (type (match (string-ref obj "type")
- ("SCALAR" 'scalar)
- ("VEC2" 'vec2)
- ("VEC3" 'vec3)
- ("VEC4" 'vec4)
- ("MAT2" 'mat2)
- ("MAT3" 'mat3)
- ("MAT4" 'mat4)))
- (max (number-array-ref/optional obj "max"))
- (min (number-array-ref/optional obj "min"))
- (sparse (object-ref/optional obj "sparse"))
- (extensions (object-ref/optional obj "extensions"))
- (extras (assoc-ref obj "extras")))
- (unless (>= length 1)
- (error "count must be greater than 0" length))
- (when (and (vector? max)
- (not (= (vector-length max) (type-length type))))
- (error "not enough elements for max" max type))
- (when (and (vector? min)
- (not (= (vector-length min) (type-length type))))
- (error "not enough elements for min" min type))
- (make-buffer-view #:name name
- #:buffer view
- #:offset offset
- #:component-type component-type
- #:normalized? normalized?
- #:length length
- #:type type
- #:max max
- #:min min
- #:sparse sparse)))
- (define (texture-filter n)
- (match n
- (9728 'nearest)
- ((or #f 9729) 'linear)
- ;; TODO: Support mip-mapping
- ;; (9984 'nearest-mipmap-nearest)
- ;; (9985 'linear-mipmap-nearest)
- ;; (9986 'nearest-mipmap-linear)
- ;; (9987 'linear-mipmap-linear)
- (_ 'linear)))
- (define (texture-wrap n)
- (match n
- (10496 'clamp)
- ((or #f 10497) 'repeat)
- (33069 'clamp-to-border)
- (33071 'clamp-to-edge)))
- (define (parse-texture obj images samplers)
- (let ((image (vector-ref images (number-ref obj "source")))
- (sampler
- (vector-ref samplers (or (number-ref/optional obj "sampler") 0))))
- (load-image (scope-file (string-ref image "uri"))
- #:min-filter (texture-filter
- (number-ref/optional sampler "minFilter"))
- #:mag-filter (texture-filter
- (number-ref/optional sampler "magFilter"))
- #:wrap-s (texture-wrap (number-ref/optional sampler "wrapS"))
- #:wrap-t (texture-wrap (number-ref/optional sampler "wrapT")))))
- (define (parse-material obj textures)
- (let* ((name (or (string-ref/optional obj "name") "anonymous"))
- (pbrmr (or (object-ref/optional obj "pbrMetallicRoughness") '()))
- (base-color-factor
- (let ((v (or (number-array-ref/optional pbrmr "baseColorFactor")
- #(1.0 1.0 1.0 1.0))))
- (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
- (base-color-texture
- (match (object-ref/optional pbrmr "baseColorTexture")
- (#f null-texture)
- (obj
- (vector-ref textures (number-ref obj "index")))))
- (metallic-factor
- (or (number-ref/optional pbrmr "metallicFactor")
- 1.0))
- (roughness-factor
- (or (number-ref/optional pbrmr "roughnessFactor")
- 1.0))
- (metallic-roughness-texture
- (match (object-ref/optional pbrmr "metallicRoughnessTexture")
- (#f null-texture)
- (obj
- (vector-ref textures (number-ref obj "index")))))
- (normal-factor
- (let ((v (or (array-ref/optional obj "normalFactor")
- #(1.0 1.0 1.0))))
- (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
- (normal-texture
- (match (object-ref/optional obj "normalTexture")
- (#f null-texture)
- (obj (vector-ref textures (number-ref obj "index")))))
- (occlusion-factor
- (let ((v (or (array-ref/optional obj "occlusionFactor")
- #(1.0 1.0 1.0))))
- (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
- (occlusion-texture
- (match (object-ref/optional obj "occlusionTexture")
- (#f null-texture)
- (obj (vector-ref textures (number-ref obj "index")))))
- (emissive-factor
- (let ((v (or (array-ref/optional obj "emissiveFactor")
- #(1.0 1.0 1.0))))
- (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
- (emissive-texture
- (match (object-ref/optional obj "emissiveTexture")
- (#f null-texture)
- (obj (vector-ref textures (number-ref obj "index")))))
- (alpha-mode (match (or (string-ref/optional obj "alphaMode")
- "BLEND")
- ("OPAQUE" 'opaque)
- ("MASK" 'mask)
- ("BLEND" 'blend)))
- (alpha-cutoff (or (number-ref/optional obj "alphaCutoff") 0.5))
- (double-sided? (boolean-ref/optional obj "doubleSided"))
- (extensions (object-ref/optional obj "extensions"))
- (extras (assoc-ref obj "extras")))
- (make-material #:name name
- #:base-color-factor base-color-factor
- #:base-color-texture base-color-texture
- #:metallic-factor metallic-factor
- #:roughness-factor roughness-factor
- #:metallic-roughness-texture metallic-roughness-texture
- #:normal-factor normal-factor
- #:normal-texture normal-texture
- #:occlusion-factor occlusion-factor
- #:occlusion-texture occlusion-texture
- #:emissive-factor emissive-factor
- #:emissive-texture emissive-texture
- #:alpha-mode alpha-mode
- #:alpha-cutoff alpha-cutoff
- #:double-sided? double-sided?)))
- (define (attribute-name->index name)
- (match name
- ("POSITION"
- (attribute-location
- (hash-ref (shader-attributes (pbr-shader)) "position")))
- ("NORMAL" 1)
- ("TANGENT" 2)
- ("TEXCOORD_0"
- (attribute-location
- (hash-ref (shader-attributes (pbr-shader)) "texcoord_0")))
- ("TEXCOORD_1" 4)
- ("COLOR_0" 5)
- ("JOINTS_0" 6)
- ("WEIGHTS_0" 7)))
- (define (parse-primitive obj materials accessors)
- (let ((attributes (map (match-lambda
- ((name . n)
- (cons (attribute-name->index name)
- (vector-ref accessors n))))
- (object-ref obj "attributes")))
- (indices (match (number-ref/optional obj "indices")
- (#f #f)
- (n (vector-ref accessors n))))
- ;; TODO: Set a default material when none is given.
- (material (match (number-ref/optional obj "material")
- (#f #f)
- (n (vector-ref materials n))))
- (mode (match (or (number-ref/optional obj "mode") 4)
- (0 'points)
- (1 'lines)
- (2 'line-loop)
- (3 'line-strip)
- (4 'triangles)
- (5 'triangle-strip)
- (6 'triangle-fan)))
- ;; TODO: Support morph targets.
- (targets #f))
- (make-primitive #:vertex-array
- (make-vertex-array #:indices indices
- #:attributes attributes
- #:mode mode)
- #:material material
- #:targets targets)))
- (define (parse-mesh obj materials accessors)
- (let ((name (or (string-ref/optional obj "name") "anonymous"))
- (primitives
- (map (lambda (obj)
- (parse-primitive obj materials accessors))
- (vector->list (array-ref obj "primitives"))))
- (weights (number-array-ref/optional obj "weights")))
- (make-mesh #:name name
- #:primitives primitives
- #:weights weights)))
- (define (parse-node obj parse-child meshes)
- ;; TODO: Parse all fields of nodes.
- (let ((name (or (string-ref/optional obj "name") "anonymous"))
- ;; TODO: Parse camera.
- (camera #f)
- ;; TODO: Parse skin.
- (skin #f)
- (matrix (or (matrix-ref/optional obj "matrix")
- (make-identity-matrix4)))
- (mesh (match (number-ref/optional obj "mesh")
- (#f #f)
- (n (vector-ref meshes n))))
- ;; TODO: Parse rotation, scale, translation
- (rotation #f)
- (scale #f)
- (translation #f)
- ;; TODO: Parse weights.
- (weights #f)
- (children (map parse-child
- (vector->list
- (or (array-ref/optional obj "children")
- #())))))
- (make-scene-node #:name name
- #:children children
- #:camera camera
- #:skin skin
- #:matrix matrix
- #:mesh mesh
- #:rotation rotation
- #:scale scale
- #:translation translation
- #:weights weights)))
- (define (parse-nodes array meshes)
- (define nodes (make-vector (vector-length array) #f))
- (define (parse-node* i)
- (let ((node (vector-ref nodes i)))
- (or node
- (let ((node (parse-node (vector-ref array i)
- parse-node*
- meshes)))
- (vector-set! nodes i node)
- node))))
- (let loop ((i 0))
- (when (< i (vector-length array))
- (parse-node* i)
- (loop (+ i 1))))
- nodes)
- (define (parse-scene obj nodes)
- (let ((name (or (string-ref/optional obj "name") "anonymous"))
- (children
- (map (lambda (i) (vector-ref nodes i))
- (vector->list
- (or (number-array-ref/optional obj "nodes")
- #())))))
- (make-scene #:name name #:nodes children)))
- (let* ((tree (read-json port))
- (asset (object-ref tree "asset"))
- (version (string-ref asset "version"))
- (copyright (string-ref/optional asset "copyright"))
- (generator (string-ref/optional asset "generator"))
- (minimum-version (string-ref/optional asset "minVersion"))
- (extensions (object-ref/optional asset "extensions"))
- ;; TODO: Figure out how to parse extras in a user-defined way
- (extras (assoc-ref asset "extras"))
- (buffers (vector-map parse-buffer
- (or (assoc-ref tree "buffers") #())))
- (buffer-views (vector-map (lambda (obj)
- (parse-buffer-view obj buffers))
- (or (assoc-ref tree "bufferViews") #())))
- (accessors (vector-map (lambda (obj)
- (parse-accessor obj buffer-views))
- (or (assoc-ref tree "accessors") #())))
- (images (or (assoc-ref tree "images") #()))
- (samplers (or (assoc-ref tree "samplers") #(())))
- (textures (vector-map (lambda (obj)
- (parse-texture obj images samplers))
- (or (assoc-ref tree "textures") #())))
- (materials (vector-map (lambda (obj)
- (parse-material obj textures))
- (or (assoc-ref tree "materials") #())))
- (meshes (vector-map (lambda (obj)
- (parse-mesh obj materials accessors))
- (or (assoc-ref tree "meshes") #())))
- (nodes (parse-nodes (or (assoc-ref tree "nodes") #()) meshes))
- (scenes (map (lambda (obj)
- (parse-scene obj nodes))
- (vector->list
- (or (assoc-ref tree "scenes") #()))))
- (default-scene (list-ref scenes
- (or (number-ref/optional tree "scene")
- 0))))
- (unless (string=? version "2.0")
- (error "unsupported glTF version" version))
- (make-asset copyright generator scenes default-scene)))
-
-(define (load-asset file)
- (call-with-input-file file (lambda (port) (read-gltf port file))))
diff --git a/chickadee/render/model.scm b/chickadee/render/model.scm
new file mode 100644
index 0000000..1a9356d
--- /dev/null
+++ b/chickadee/render/model.scm
@@ -0,0 +1,911 @@
+;;; Chickadee Game Toolkit
+;;; Copyright © 2019 David Thompson <davet@gnu.org>
+;;;
+;;; Chickadee is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; Chickadee is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; 3D Model loading and rendering.
+;;
+;;; Code:
+
+(define-module (chickadee render model)
+ #:use-module (chickadee array-list)
+ #:use-module (chickadee json)
+ #:use-module (chickadee math matrix)
+ #:use-module (chickadee math vector)
+ #:use-module (chickadee render)
+ #:use-module (chickadee render buffer)
+ #:use-module (chickadee render color)
+ #:use-module (chickadee render pbr)
+ #:use-module (chickadee render phong)
+ #:use-module (chickadee render shader)
+ #:use-module (chickadee render texture)
+ #:use-module (ice-9 format)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 rdelim)
+ #:use-module (rnrs bytevectors)
+ #:use-module (rnrs io ports)
+ #:use-module (srfi srfi-9)
+ #:use-module ((srfi srfi-43) #:select (vector-every))
+ #:export (model?
+ draw-model
+ load-obj
+ load-gltf))
+
+
+;;;
+;;; Rendering State
+;;;
+
+(define-record-type <render-state>
+ (%make-render-state shader renderer world-matrix view-matrix)
+ render-state?
+ (shader render-state-shader)
+ (renderer render-state-renderer)
+ (world-matrix render-state-world-matrix)
+ (view-matrix render-state-view-matrix))
+
+(define* (make-render-state #:key shader renderer)
+ (%make-render-state shader renderer
+ (make-identity-matrix4)
+ (make-identity-matrix4)))
+
+(define (render-state-reset! state)
+ (matrix4-identity! (render-state-world-matrix state))
+ (matrix4-identity! (render-state-view-matrix state)))
+
+(define (render-state-world-matrix-mult! state matrix)
+ (let ((world (render-state-world-matrix state)))
+ (matrix4-mult! world world matrix)))
+
+(define (render-state-view-matrix-mult! state matrix)
+ (let ((view (render-state-view-matrix state)))
+ (matrix4-mult! view view matrix)))
+
+
+;;;
+;;; Primitives
+;;;
+
+;; A piece of a mesh. Represents a single draw call.
+(define-record-type <primitive>
+ (make-primitive name vertex-array material)
+ primitive?
+ (name primitive-name)
+ (vertex-array primitive-vertex-array)
+ (material primitive-material))
+
+(define (draw-primitive/phong primitive state)
+ (gpu-apply/phong (render-state-shader state)
+ (primitive-vertex-array primitive)
+ (primitive-material primitive)
+ (render-state-world-matrix state)
+ (render-state-view-matrix state)))
+
+(define (draw-primitive/pbr primitive state)
+ (gpu-apply/pbr (render-state-shader state)
+ (primitive-vertex-array primitive)
+ (primitive-material primitive)
+ (render-state-world-matrix state)
+ (render-state-view-matrix state)))
+
+
+;;;
+;;; Meshes
+;;;
+
+;; A complete 3D model composed of many primitives.
+(define-record-type <mesh>
+ (make-mesh name primitives)
+ mesh?
+ (name mesh-name)
+ (primitives mesh-primitives))
+
+(define (draw-mesh mesh state)
+ (let ((render (render-state-renderer state)))
+ (for-each (lambda (primitive) (render primitive state))
+ (mesh-primitives mesh))))
+
+
+;;;
+;;; Scene Node
+;;;
+
+;; A tree of meshes with their own transformation matrices.
+(define-record-type <scene-node>
+ (%make-scene-node name mesh matrix children)
+ node?
+ (name scene-node-name)
+ (mesh scene-node-mesh)
+ (matrix scene-node-matrix)
+ (children scene-node-children))
+
+(define* (make-scene-node #:key
+ (name "anonymous")
+ mesh
+ (matrix (make-identity-matrix4))
+ (children '()))
+ (%make-scene-node name mesh matrix children))
+
+(define (draw-scene-node node state)
+ ;; TODO: Apply push/pop model matrix stuff.
+ (for-each (lambda (child)
+ (draw-scene-node child state))
+ (scene-node-children node))
+ (let ((mesh (scene-node-mesh node)))
+ (when mesh
+ (draw-mesh mesh state))))
+
+
+;;;
+;;; Model
+;;;
+
+;; A collection of scenes and the associated information about *how*
+;; to actually render the darn thing.
+(define-record-type <model>
+ (%make-model name scenes default-scene render-state)
+ model?
+ (name model-name)
+ (scenes model-scenes)
+ (default-scene model-default-scene)
+ (render-state model-render-state))
+
+(define* (make-model #:key name scenes (default-scene (car scenes)) render-state)
+ (%make-model name scenes default-scene render-state))
+
+(define (draw-model model model-matrix view-matrix)
+ ;; TODO: Support drawing non-default scenes.
+ (let ((state (model-render-state model)))
+ (render-state-reset! state)
+ (render-state-view-matrix-mult! state view-matrix)
+ (render-state-world-matrix-mult! state model-matrix)
+ (draw-scene-node (model-default-scene model) state)))
+
+
+;;;
+;;; OBJ Format
+;;;
+
+(define (load-obj file-name)
+ (define (scope-file other-file)
+ (string-append (dirname file-name) "/" other-file))
+ (call-with-input-file file-name
+ (lambda (port)
+ (let ((vertices (make-array-list))
+ (texcoords (make-array-list))
+ (normals (make-array-list))
+ (faces (make-array-list))
+ (face-map (make-hash-table))
+ (face-indices-map (make-hash-table))
+ (material-map (make-hash-table)))
+ (define (load-mtl mtl-file-name)
+ (call-with-input-file mtl-file-name
+ (lambda (port)
+ (let loop ((name #f)
+ (ambient #f)
+ (diffuse #f)
+ (specular #f)
+ (shininess #f))
+ (define (maybe-add-material)
+ (when name
+ (hash-set! material-map
+ name
+ (make-phong-material
+ #:name name
+ #:ambient ambient
+ #:diffuse diffuse
+ #:specular specular
+ #:shininess shininess))))
+ (match (read-line port)
+ ((? eof-object?)
+ (maybe-add-material))
+ (line
+ (match (delete "" (string-split line char-set:whitespace))
+ ((or () ("#" . _)) ; ignore comments and blank lines
+ (loop name ambient diffuse specular shininess))
+ (("Ka" r g b)
+ (let ((new-ambient (vec3 (string->number r)
+ (string->number g)
+ (string->number b))))
+ (loop name new-ambient diffuse specular shininess)))
+ (("Kd" r g b)
+ (let ((new-diffuse (vec3 (string->number r)
+ (string->number g)
+ (string->number b))))
+ (loop name ambient new-diffuse specular shininess)))
+ (("Ks" r g b)
+ (let ((new-specular (vec3 (string->number r)
+ (string->number g)
+ (string->number b))))
+ (loop name ambient diffuse new-specular shininess)))
+ (("Ns" n)
+ (let ((new-exp (* (string->number n) 1.0))) ; force it to be a float
+ (loop name ambient diffuse specular new-exp)))
+ (("newmtl" new-name)
+ ;; Begin new material
+ (maybe-add-material)
+ (loop new-name
+ (vec3 0.0 0.0 0.0)
+ (vec3 0.0 0.0 0.0)
+ (vec3 0.0 0.0 0.0)
+ 1.0))
+ (data
+ (format (current-error-port)
+ "warning: ~a:~d: unsupported MTL data: ~s~%"
+ mtl-file-name
+ (port-line port)
+ data)
+ (loop name ambient diffuse specular shininess)))))))))
+ (define (parse-error message args)
+ (apply error (format #f "OBJ parser error @ ~a:~d: ~a"
+ file-name
+ (port-line port)
+ message)
+ args))
+ (define (parse-vertex args)
+ (array-list-push! vertices
+ (match args
+ ((x y z)
+ (vec3 (string->number x)
+ (string->number y)
+ (string->number z)))
+ ;; TODO: handle w properly
+ ((x y z w)
+ (vec3 (string->number x)
+ (string->number y)
+ (string->number z)))
+ (_
+ (parse-error "wrong number of vertex arguments" args)))))
+ (define (parse-texcoord args)
+ ;; TODO: Handle w properly.
+ (array-list-push! texcoords
+ (match args
+ ((u)
+ (vec2 (string->number u) 0.0))
+ ((u v)
+ (vec2 (string->number u) (string->number v)))
+ ((u v w)
+ (vec2 (string->number u)
+ (string->number v)))
+ (_
+ (parse-error "wrong number of texcoord arguments" args)))))
+ (define (parse-normal args)
+ (array-list-push! normals
+ (match args
+ ((i j k)
+ (vec3 (string->number i)
+ (string->number j)
+ (string->number k)))
+ (_
+ (parse-error "wrong number of normal arguments" args)))))
+ (define (parse-face-index arg)
+ (- (string->number arg) 1))
+ (define (parse-face-element arg)
+ (match (string-split arg #\/)
+ ((v)
+ (list (parse-face-index v) #f #f))
+ ((v t)
+ (list (parse-face-index v)
+ (parse-face-index t)
+ #f))
+ ((v "" n)
+ (list (parse-face-index v)
+ #f
+ (parse-face-index n)))
+ ((v t n)
+ (list (parse-face-index v)
+ (parse-face-index t)
+ (parse-face-index n)))
+ (_
+ (parse-error "invalid face syntax" (list arg)))))
+ (define (indices-for-material material)
+ (or (hash-ref face-indices-map material)
+ (let ((new-indices (make-array-list)))
+ (hash-set! face-indices-map material new-indices)
+ new-indices)))
+ (define (parse-face args material)
+ (match args
+ ((and (_ _ _ . _) args)
+ (for-each (lambda (e)
+ ;; Faces may very well be redundant, so we
+ ;; deduplicate in order to make the VBOs we
+ ;; build later as small as possible.
+ (let ((cached-index (hash-ref face-map e))
+ (face-indices (indices-for-material material)))
+ (if cached-index
+ (array-list-push! face-indices cached-index)
+ (let ((i (array-list-size faces)))
+ (array-list-push! faces (parse-face-element e))
+ (array-list-push! face-indices i)
+ (hash-set! face-map e i)))))
+ args))
+ (_
+ (parse-error "wrong number of face arguments" args))))
+ ;; Register default material
+ (hash-set! material-map "default" default-phong-material)
+ ;; Parse file.
+ (let loop ((material "default"))
+ (match (read-line port)
+ ((? eof-object?)
+ #f)
+ (line
+ (match (delete "" (string-split line char-set:whitespace))
+ ((or () ("#" . _)) ; ignore comments and blank lines
+ (loop material))
+ (("f" . args)
+ (parse-face args material)
+ (loop material))
+ (("g" . _) ; ignore
+ (loop material))
+ (("mtllib" mtl-file-name)
+ (load-mtl (scope-file mtl-file-name))
+ (loop material))
+ (("s" . _) ; ignore
+ (loop material))
+ (("usemtl" new-material)
+ (loop new-material))
+ (("v" . args)
+ (parse-vertex args)
+ (loop material))
+ (("vn" . args)
+ (parse-normal args)
+ (loop material))
+ (("vt" . args)
+ (parse-texcoord args)
+ (loop material))
+ (data
+ (format (current-error-port)
+ "warning: ~a:~d: unsupported OBJ data: ~s~%"
+ file-name
+ (port-line port)
+ data)
+ (loop material))))))
+ ;; Build a vertex array for all the faces of a single
+ ;; material.
+ ;;
+ ;; XXX: We assume there is normal and texture data. Models
+ ;; that don't have one or both will still use up as much
+ ;; memory as if they did. Maybe that's just fine? Dunno.
+ (define (make-primitive-for-material material)
+ (let* ((face-indices (indices-for-material material))
+ (vertex-count (array-list-size faces))
+ (index-count (array-list-size face-indices))
+ (stride 8)
+ (mesh-data (make-f32vector (* vertex-count stride)))
+ (mesh-indices (make-u32vector index-count))
+ (null-texcoord (vec2 0.0 0.0))
+ (null-normal (vec3 0.0 0.0 0.0)))
+ ;; The mesh vertex data is packed like so:
+ ;; - 3 floats for vertex
+ ;; - 2 floats for texture coordinate
+ ;; - 3 floats for normal
+ ;; - repeat for each face
+ (let loop ((i 0))
+ (when (< i vertex-count)
+ (let ((offset (* i stride)))
+ (match (array-list-ref faces i)
+ ((vert-index tex-index norm-index)
+ ;; Vertex
+ (let ((v (array-list-ref vertices vert-index)))
+ (f32vector-set! mesh-data offset (vec3-x v))
+ (f32vector-set! mesh-data (+ offset 1) (vec3-y v))
+ (f32vector-set! mesh-data (+ offset 2) (vec3-z v)))
+ ;; Texture coordinate
+ (let ((t (if tex-index
+ (array-list-ref texcoords tex-index)
+ null-texcoord)))
+ (f32vector-set! mesh-data (+ offset 3) (vec2-x t))
+ (f32vector-set! mesh-data (+ offset 4) (vec2-y t)))
+ ;; Normal
+ (let ((n (if norm-index
+ (array-list-ref normals norm-index)
+ null-normal)))
+ (f32vector-set! mesh-data (+ offset 5) (vec3-x n))
+ (f32vector-set! mesh-data (+ offset 6) (vec3-y n))
+ (f32vector-set! mesh-data (+ offset 7) (vec3-z n))))))
+ (loop (+ i 1))))
+ ;; Pack indices.
+ (let loop ((i 0))
+ (when (< i index-count)
+ (u32vector-set! mesh-indices i (array-list-ref face-indices i))
+ (loop (+ i 1))))
+ ;; Construct vertex array.
+ ;; TODO: Add names to buffers and views.
+ (let* ((index-buffer (make-buffer mesh-indices #:target 'index))
+ (index-view (make-buffer-view #:type 'scalar
+ #:component-type 'unsigned-int
+ #:buffer index-buffer))
+ (data-buffer (make-buffer mesh-data #:stride (* stride 4)))
+ (vertex-view (make-buffer-view #:type 'vec3
+ #:component-type 'float
+ #:buffer data-buffer))
+ (texcoord-view (make-buffer-view #:type 'vec2
+ #:component-type 'float
+ #:buffer data-buffer
+ #:offset 12))
+ (normal-view (make-buffer-view #:type 'vec3
+ #:component-type 'float
+ #:buffer data-buffer
+ #:offset 20)))
+ (make-primitive material
+ (make-vertex-array
+ #:indices index-view
+ #:attributes `((0 . ,vertex-view)
+ (1 . ,texcoord-view)
+ (2 . ,normal-view)))
+ (or (hash-ref material-map material)
+ (hash-ref material-map "default"))))))
+ ;; Construct a mesh by composing primitives. One primitive
+ ;; per material.
+ (let* ((model-name (basename file-name))
+ (mesh (make-mesh model-name
+ (hash-fold (lambda (material indices memo)
+ ;; It's possible that a material has
+ ;; no data associated with it, so we
+ ;; drop those.
+ (if (array-list-empty? indices)
+ memo
+ (cons (make-primitive-for-material material)
+ memo)))
+ '()
+ face-indices-map)))
+ (scene (make-scene-node #:name model-name
+ #:mesh mesh)))
+ (make-model #:name model-name
+ #:scenes (list scene)
+ #:render-state
+ (make-render-state #:shader (load-phong-shader)
+ #:renderer draw-primitive/phong)))))))
+
+
+;;;
+;;; glTF 2.0
+;;;
+
+(define (load-gltf file-name)
+ (define (object-ref obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (pair? value)
+ (error "expected object for key" key value))
+ value))
+ (define (object-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (or (not value) (pair? value))
+ (error "expected object for optional key" key value))
+ value))
+ (define (array-ref obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (vector? value)
+ (error "expected array for key" key value))
+ value))
+ (define (array-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (or (not value) (vector? value))
+ (error "expected array for optional key" key value))
+ value))
+ (define (string-ref obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (string? value)
+ (error "expected string for key" key value))
+ value))
+ (define (string-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (or (not value) (string? value))
+ (error "expected string for optional key" key value))
+ value))
+ (define (number-ref obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (number? value)
+ (error "expected number for key" key value))
+ value))
+ (define (number-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (or (not value) (number? value))
+ (error "expected number for key" key value))
+ value))
+ (define (boolean-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (boolean? value)
+ (error "expected boolean for key" key value))
+ value))
+ (define (number-array-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (unless (or (not value)
+ (and (vector? value) (vector-every number? value)))
+ (error "expected numeric array for key" key value))
+ value))
+ (define (matrix-ref/optional obj key)
+ (let ((value (assoc-ref obj key)))
+ (cond
+ ((not value) #f)
+ ((and (vector? value)
+ (= (vector-length value) 16)
+ (vector-every number? value))
+ ;; glTF matrices are in column-major order.
+ (make-matrix4 (vector-ref value 0)
+ (vector-ref value 4)
+ (vector-ref value 8)
+ (vector-ref value 12)
+ (vector-ref value 1)
+ (vector-ref value 5)
+ (vector-ref value 9)
+ (vector-ref value 13)
+ (vector-ref value 2)
+ (vector-ref value 6)
+ (vector-ref value 10)
+ (vector-ref value 14)
+ (vector-ref value 3)
+ (vector-ref value 7)
+ (vector-ref value 11)
+ (vector-ref value 15)))
+ (else
+ (error "expected 4x4 matrix for key" key value)))))
+ (define (assert-color v)
+ (if (and (= (vector-length v) 4)
+ (vector-every (lambda (x) (and (>= x 0.0) (<= x 1.0))) v))
+ (make-color (vector-ref v 0)
+ (vector-ref v 1)
+ (vector-ref v 2)
+ (vector-ref v 3))
+ (error "not a color vector" v)))
+ (define scope-file
+ (let ((gltf-root (dirname
+ (if (absolute-file-name? file-name)
+ file-name
+ (string-append (getcwd) "/" file-name)))))
+ (lambda (other-file)
+ (if (absolute-file-name? other-file)
+ other-file
+ (string-append gltf-root "/" other-file)))))
+ (define (parse-buffer obj)
+ ;; TODO: support base64 encoded buffer data as uri
+ ;; TODO: support glb-stored buffers:
+ ;; https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-stored-buffer
+ (let* ((uri (string-ref/optional obj "uri"))
+ (length (number-ref obj "byteLength"))
+ (name (or (string-ref/optional obj "name") "anonymous"))
+ (extensions (object-ref/optional obj "extensions"))
+ (extras (assoc-ref obj "extras"))
+ (data (if uri
+ (call-with-input-file (scope-file uri)
+ (lambda (port)
+ (get-bytevector-n port length)))
+ (make-bytevector length))))
+ data))
+ (define (parse-buffer-view obj buffers)
+ (let ((name (string-ref/optional obj "name"))
+ (data (vector-ref buffers (number-ref obj "buffer")))
+ (offset (or (number-ref/optional obj "byteOffset") 0))
+ (length (number-ref obj "byteLength"))
+ (stride (number-ref/optional obj "byteStride"))
+ (target (match (or (number-ref/optional obj "target") 34962)
+ (34962 'vertex)
+ (34963 'index)))
+ (extensions (object-ref/optional obj "extensions"))
+ (extras (assoc-ref obj "extras")))
+ (make-buffer data
+ #:name name
+ #:offset offset
+ #:length length
+ #:stride stride
+ #:target target)))
+ (define (parse-accessor obj buffer-views)
+ (define (type-length type)
+ (match type
+ ('scalar 1)
+ ('vec2 2)
+ ('vec3 3)
+ ('vec4 4)
+ ('mat2 4)
+ ('mat3 9)
+ ('mat4 16)))
+ (let ((name (or (string-ref/optional obj "name") "anonymous"))
+ (view (match (number-ref/optional obj "bufferView")
+ (#f #f)
+ (n (vector-ref buffer-views n))))
+ (offset (or (number-ref/optional obj "byteOffset") 0))
+ (component-type (match (number-ref obj "componentType")
+ (5120 'byte)
+ (5121 'unsigned-byte)
+ (5122 'short)
+ (5123 'unsigned-short)
+ (5125 'unsigned-int)
+ (5126 'float)))
+ (normalized? (boolean-ref/optional obj "normalized"))
+ (length (number-ref obj "count"))
+ (type (match (string-ref obj "type")
+ ("SCALAR" 'scalar)
+ ("VEC2" 'vec2)
+ ("VEC3" 'vec3)
+ ("VEC4" 'vec4)
+ ("MAT2" 'mat2)
+ ("MAT3" 'mat3)
+ ("MAT4" 'mat4)))
+ (max (number-array-ref/optional obj "max"))
+ (min (number-array-ref/optional obj "min"))
+ (sparse (object-ref/optional obj "sparse"))
+ (extensions (object-ref/optional obj "extensions"))
+ (extras (assoc-ref obj "extras")))
+ (unless (>= length 1)
+ (error "count must be greater than 0" length))
+ (when (and (vector? max)
+ (not (= (vector-length max) (type-length type))))
+ (error "not enough elements for max" max type))
+ (when (and (vector? min)
+ (not (= (vector-length min) (type-length type))))
+ (error "not enough elements for min" min type))
+ (make-buffer-view #:name name
+ #:buffer view
+ #:offset offset
+ #:component-type component-type
+ #:normalized? normalized?
+ #:length length
+ #:type type
+ #:max max
+ #:min min
+ #:sparse sparse)))
+ (define (texture-filter n)
+ (match n
+ (9728 'nearest)
+ ((or #f 9729) 'linear)
+ ;; TODO: Support mip-mapping
+ ;; (9984 'nearest-mipmap-nearest)
+ ;; (9985 'linear-mipmap-nearest)
+ ;; (9986 'nearest-mipmap-linear)
+ ;; (9987 'linear-mipmap-linear)
+ (_ 'linear)))
+ (define (texture-wrap n)
+ (match n
+ (10496 'clamp)
+ ((or #f 10497) 'repeat)
+ (33069 'clamp-to-border)
+ (33071 'clamp-to-edge)))
+ (define (parse-texture obj images samplers)
+ (let ((image (vector-ref images (number-ref obj "source")))
+ (sampler
+ (vector-ref samplers (or (number-ref/optional obj "sampler") 0))))
+ (load-image (scope-file (string-ref image "uri"))
+ #:min-filter (texture-filter
+ (number-ref/optional sampler "minFilter"))
+ #:mag-filter (texture-filter
+ (number-ref/optional sampler "magFilter"))
+ #:wrap-s (texture-wrap (number-ref/optional sampler "wrapS"))
+ #:wrap-t (texture-wrap (number-ref/optional sampler "wrapT")))))
+ (define (parse-material obj textures)
+ (let* ((name (or (string-ref/optional obj "name") "anonymous"))
+ (pbrmr (or (object-ref/optional obj "pbrMetallicRoughness") '()))
+ (base-color-factor
+ (let ((v (or (number-array-ref/optional pbrmr "baseColorFactor")
+ #(1.0 1.0 1.0 1.0))))
+ (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
+ (base-color-texture
+ (match (object-ref/optional pbrmr "baseColorTexture")
+ (#f null-texture)
+ (obj
+ (vector-ref textures (number-ref obj "index")))))
+ (metallic-factor
+ (or (number-ref/optional pbrmr "metallicFactor")
+ 1.0))
+ (roughness-factor
+ (or (number-ref/optional pbrmr "roughnessFactor")
+ 1.0))
+ (metallic-roughness-texture
+ (match (object-ref/optional pbrmr "metallicRoughnessTexture")
+ (#f null-texture)
+ (obj
+ (vector-ref textures (number-ref obj "index")))))
+ (normal-factor
+ (let ((v (or (array-ref/optional obj "normalFactor")
+ #(1.0 1.0 1.0))))
+ (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
+ (normal-texture
+ (match (object-ref/optional obj "normalTexture")
+ (#f null-texture)
+ (obj (vector-ref textures (number-ref obj "index")))))
+ (occlusion-factor
+ (let ((v (or (array-ref/optional obj "occlusionFactor")
+ #(1.0 1.0 1.0))))
+ (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
+ (occlusion-texture
+ (match (object-ref/optional obj "occlusionTexture")
+ (#f null-texture)
+ (obj (vector-ref textures (number-ref obj "index")))))
+ (emissive-factor
+ (let ((v (or (array-ref/optional obj "emissiveFactor")
+ #(1.0 1.0 1.0))))
+ (vec3 (vector-ref v 0) (vector-ref v 1) (vector-ref v 2))))
+ (emissive-texture
+ (match (object-ref/optional obj "emissiveTexture")
+ (#f null-texture)
+ (obj (vector-ref textures (number-ref obj "index")))))
+ (alpha-mode (match (or (string-ref/optional obj "alphaMode")
+ "BLEND")
+ ("OPAQUE" 'opaque)
+ ("MASK" 'mask)
+ ("BLEND" 'blend)))
+ (alpha-cutoff (or (number-ref/optional obj "alphaCutoff") 0.5))
+ (double-sided? (boolean-ref/optional obj "doubleSided"))
+ (extensions (object-ref/optional obj "extensions"))
+ (extras (assoc-ref obj "extras")))
+ (make-pbr-material #:name name
+ #:base-color-factor base-color-factor
+ #:base-color-texture base-color-texture
+ #:metallic-factor metallic-factor
+ #:roughness-factor roughness-factor
+ #:metallic-roughness-texture metallic-roughness-texture
+ #:normal-factor normal-factor
+ #:normal-texture normal-texture
+ #:occlusion-factor occlusion-factor
+ #:occlusion-texture occlusion-texture
+ #:emissive-factor emissive-factor
+ #:emissive-texture emissive-texture
+ #:alpha-mode alpha-mode
+ #:alpha-cutoff alpha-cutoff
+ #:double-sided? double-sided?)))
+ (define (attribute-name->index name)
+ (let ((shader (load-pbr-shader)))
+ (match name
+ ("POSITION"
+ (attribute-location
+ (hash-ref (shader-attributes shader) "position")))
+ ("NORMAL" 1)
+ ("TANGENT" 2)
+ ("TEXCOORD_0"
+ (attribute-location
+ (hash-ref (shader-attributes shader) "texcoord0")))
+ ("TEXCOORD_1" 4)
+ ("COLOR_0" 5)
+ ("JOINTS_0" 6)
+ ("WEIGHTS_0" 7))))
+ (define (parse-primitive obj materials accessors)
+ (let ((attributes (map (match-lambda
+ ((name . n)
+ (cons (attribute-name->index name)
+ (vector-ref accessors n))))
+ (object-ref obj "attributes")))
+ (indices (match (number-ref/optional obj "indices")
+ (#f #f)
+ (n (vector-ref accessors n))))
+ ;; TODO: Set a default material when none is given.
+ (material (match (number-ref/optional obj "material")
+ (#f #f)
+ (n (vector-ref materials n))))
+ (mode (match (or (number-ref/optional obj "mode") 4)
+ (0 'points)
+ (1 'lines)
+ (2 'line-loop)
+ (3 'line-strip)
+ (4 'triangles)
+ (5 'triangle-strip)
+ (6 'triangle-fan)))
+ ;; TODO: Support morph targets.
+ (targets #f))
+ (make-primitive "primitive"
+ (make-vertex-array #:indices indices
+ #:attributes attributes
+ #:mode mode)
+ material)))
+ (define (parse-mesh obj materials accessors)
+ (let ((name (or (string-ref/optional obj "name") "anonymous"))
+ (primitives
+ (map (lambda (obj)
+ (parse-primitive obj materials accessors))
+ (vector->list (array-ref obj "primitives"))))
+ (weights (number-array-ref/optional obj "weights")))
+ ;; TODO: Support weights.
+ (make-mesh name primitives)))
+ (define (parse-node obj parse-child meshes)
+ ;; TODO: Parse all fields of nodes.
+ (let ((name (or (string-ref/optional obj "name") "anonymous"))
+ ;; TODO: Parse camera.
+ (camera #f)
+ ;; TODO: Parse skin.
+ (skin #f)
+ (matrix (or (matrix-ref/optional obj "matrix")
+ (make-identity-matrix4)))
+ (mesh (match (number-ref/optional obj "mesh")
+ (#f #f)
+ (n (vector-ref meshes n))))
+ ;; TODO: Parse rotation, scale, translation
+ (rotation #f)
+ (scale #f)
+ (translation #f)
+ ;; TODO: Parse weights.
+ (weights #f)
+ (children (map parse-child
+ (vector->list
+ (or (array-ref/optional obj "children")
+ #())))))
+ (make-scene-node #:name name
+ #:children children
+ #:matrix matrix
+ #:mesh mesh)))
+ (define (parse-nodes array meshes)
+ (define nodes (make-vector (vector-length array) #f))
+ (define (parse-node* i)
+ (let ((node (vector-ref nodes i)))
+ (or node
+ (let ((node (parse-node (vector-ref array i)
+ parse-node*
+ meshes)))
+ (vector-set! nodes i node)
+ node))))
+ (let loop ((i 0))
+ (when (< i (vector-length array))
+ (parse-node* i)
+ (loop (+ i 1))))
+ nodes)
+ (define (parse-scene obj nodes)
+ (let ((name (or (string-ref/optional obj "name") "anonymous"))
+ (children
+ (map (lambda (i) (vector-ref nodes i))
+ (vector->list
+ (or (number-array-ref/optional obj "nodes")
+ #())))))
+ (make-scene-node #:name name #:children children)))
+ (define (vector-map proc v)
+ (let ((new-v (make-vector (vector-length v))))
+ (let loop ((i 0))
+ (when (< i (vector-length v))
+ (vector-set! new-v i (proc (vector-ref v i)))
+ (loop (+ i 1))))
+ new-v))
+ (call-with-input-file file-name
+ (lambda (port)
+ (let* ((tree (read-json port))
+ (asset (object-ref tree "asset"))
+ (version (string-ref asset "version"))
+ (copyright (string-ref/optional asset "copyright"))
+ (generator (string-ref/optional asset "generator"))
+ (minimum-version (string-ref/optional asset "minVersion"))
+ (extensions (object-ref/optional asset "extensions"))
+ ;; TODO: Figure out how to parse extras in a user-defined way
+ (extras (assoc-ref asset "extras"))
+ (buffers (vector-map parse-buffer
+ (or (assoc-ref tree "buffers") #())))
+ (buffer-views (vector-map (lambda (obj)
+ (parse-buffer-view obj buffers))
+ (or (assoc-ref tree "bufferViews") #())))
+ (accessors (vector-map (lambda (obj)
+ (parse-accessor obj buffer-views))
+ (or (assoc-ref tree "accessors") #())))
+ (images (or (assoc-ref tree "images") #()))
+ (samplers (or (assoc-ref tree "samplers") #(())))
+ (textures (vector-map (lambda (obj)
+ (parse-texture obj images samplers))
+ (or (assoc-ref tree "textures") #())))
+ (materials (vector-map (lambda (obj)
+ (parse-material obj textures))
+ (or (assoc-ref tree "materials") #())))
+ (meshes (vector-map (lambda (obj)
+ (parse-mesh obj materials accessors))
+ (or (assoc-ref tree "meshes") #())))
+ (nodes (parse-nodes (or (assoc-ref tree "nodes") #()) meshes))
+ (scenes (map (lambda (obj)
+ (parse-scene obj nodes))
+ (vector->list
+ (or (assoc-ref tree "scenes") #()))))
+ (default-scene (list-ref scenes
+ (or (number-ref/optional tree "scene")
+ 0))))
+ (unless (string=? version "2.0")
+ (error "unsupported glTF version" version))
+ (make-model #:name (basename file-name)
+ #:scenes (list default-scene)
+ #:render-state
+ (make-render-state #:shader (load-pbr-shader)
+ #:renderer draw-primitive/pbr))))))
diff --git a/chickadee/render/pbr.scm b/chickadee/render/pbr.scm
new file mode 100644
index 0000000..2738b77
--- /dev/null
+++ b/chickadee/render/pbr.scm
@@ -0,0 +1,130 @@
+;;; Chickadee Game Toolkit
+;;; Copyright © 2019 David Thompson <davet@gnu.org>
+;;;
+;;; Chickadee is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; Chickadee is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Physically based lighting model.
+;;
+;;; Code:
+
+(define-module (chickadee render pbr)
+ #:use-module (chickadee math vector)
+ #:use-module (chickadee render)
+ #:use-module (chickadee render color)
+ #:use-module (chickadee render shader)
+ #:use-module (chickadee render texture)
+ #:use-module (srfi srfi-9)
+ #:export (make-pbr-material
+ pbr-material?
+ pbr-material-name
+ pbr-material-base-color-factor
+ pbr-material-base-color-texture
+ pbr-material-metallic-factor
+ pbr-material-roughness-factor
+ pbr-material-metallic-roughness-texture
+ pbr-material-normal-factor
+ pbr-material-normal-texture
+ pbr-material-occlusion-facgor
+ pbr-material-occlusion-texture
+ pbr-material-emissive-factor
+ pbr-material-emissive-texture
+ pbr-material-alpha-mode
+ pbr-material-alpha-cutoff
+ pbr-material-double-sided?
+ default-pbr-material
+ load-pbr-shader
+ gpu-apply/pbr))
+
+(define-shader-type <pbr-material>
+ make-pbr-material
+ pbr-material?
+ (local-field name pbr-material-name)
+ (float-vec3 base-color-factor pbr-material-base-color-factor)
+ (local-field base-color-texture pbr-material-base-color-texture)
+ (float metallic-factor pbr-material-metallic-factor)
+ (float roughness-factor pbr-material-roughness-factor)
+ (local-field metallic-roughness-texture pbr-material-metallic-roughness-texture)
+ (float-vec3 normal-factor pbr-material-normal-factor)
+ (local-field normal-texture pbr-material-normal-texture)
+ (float-vec3 occlusion-factor pbr-material-occlusion-factor)
+ (local-field occlusion-texture pbr-material-occlusion-texture)
+ (float-vec3 emissive-factor pbr-material-emissive-factor)
+ (local-field emissive-texture pbr-material-emissive-texture)
+ (local-field alpha-mode pbr-material-alpha-mode)
+ (float alpha-cutoff pbr-material-alpha-cutoff)
+ (bool double-sided? pbr-material-double-sided?))
+
+(define default-pbr-material
+ (make-pbr-material #:name "default"
+ #:base-color-factor #v(1.0 1.0 1.0)
+ #:base-color-texture null-texture
+ #:metallic-factor 1.0
+ #:roughness-factor 1.0
+ #:metallic-roughness-texture null-texture
+ #:normal-factor #v(1.0 1.0 1.0)
+ #:normal-texture null-texture
+ #:occlusion-factor #v(1.0 1.0 1.0)
+ #:occlusion-texture null-texture
+ #:emissive-factor #v(1.0 1.0 1.0)
+ #:emissive-texture null-texture
+ #:alpha-mode 'opaque
+ #:alpha-cutoff 0.5
+ #:double-sided? #f))
+
+;; TODO: Actually implement PBR. For now it's just the minimal amount
+;; of code needed to render the base texture of a mesh.
+(define pbr-shader
+ (delay
+ (strings->shader
+ "
+#version 130
+
+in vec3 position;
+in vec2 texcoord0;
+out vec2 fragTex;
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+void main(void) {
+ fragTex = texcoord0;
+ gl_Position = projection * view * model * vec4(position.xyz, 1.0);
+}
+"
+ "
+#version 130
+
+in vec2 fragTex;
+uniform vec3 baseColorFactor;
+uniform sampler2D baseColorTexture;
+
+void main (void) {
+ gl_FragColor = texture2D(baseColorTexture, fragTex) *
+ vec4(baseColorFactor, 1.0);
+}
+")))
+
+(define (load-pbr-shader)
+ (force pbr-shader))
+
+(define (gpu-apply/pbr shader vertex-array material model-matrix view-matrix)
+ (with-texture 0 (pbr-material-base-color-texture material)
+ (gpu-apply shader vertex-array
+ #:model model-matrix
+ #:view view-matrix
+ #:projection (current-projection)
+ #:base-color-factor (pbr-material-base-color-factor material))))
diff --git a/chickadee/render/phong.scm b/chickadee/render/phong.scm
new file mode 100644
index 0000000..07c0eeb
--- /dev/null
+++ b/chickadee/render/phong.scm
@@ -0,0 +1,160 @@
+;;; Chickadee Game Toolkit
+;;; Copyright © 2019 David Thompson <davet@gnu.org>
+;;;
+;;; Chickadee is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published
+;;; by the Free Software Foundation, either version 3 of the License,
+;;; or (at your option) any later version.
+;;;
+;;; Chickadee is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with this program. If not, see
+;;; <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Simple forward rendered Phong lighting model.
+;;
+;;; Code:
+
+(define-module (chickadee render phong)
+ #:use-module (chickadee math vector)
+ #:use-module (chickadee render)
+ #:use-module (chickadee render color)
+ #:use-module (chickadee render shader)
+ #:use-module (srfi srfi-9)
+ #:export (make-phong-material
+ phong-material?
+ phong-material-name
+ phong-material-ambient
+ phong-material-diffuse
+ phong-material-specular
+ phong-material-specular-exponent
+ default-phong-material
+ load-phong-shader
+ gpu-apply/phong))
+
+
+;;;
+;;; Phong Material
+;;;
+
+(define-shader-type <phong-material>
+ make-phong-material
+ phong-material?
+ (local-field name phong-material-name)
+ (float-vec3 ambient phong-material-ambient)
+ (float-vec3 diffuse phong-material-diffuse)
+ (float-vec3 specular phong-material-specular)
+ (float shininess phong-material-shininess))
+
+(define default-phong-material
+ (make-phong-material #:name "default"
+ #:ambient (vec3 0.5 0.5 0.5)
+ #:diffuse (vec3 0.5 0.5 0.5)
+ #:specular (vec3 0.5 0.5 0.5)
+ #:shininess 32.0))
+
+
+;;;
+;;; Lights
+;;;
+
+(define-shader-type <directional-light>
+ make-directional-light
+ directional-light?
+ (float-vec4 color directional-light-color)
+ (float-vec3 direction directional-light-direction)
+ (float-vec3 ambient directional-light-ambient)
+ (float-vec3 diffuse directional-light-diffuse)
+ (float-vec3 specular directional-light-specular)
+ (float shininess directional-light-shininess))
+
+(define default-directional-light
+ (make-directional-light #:color white
+ #:direction (vec3 -1.0 0.0 -1.0)
+ #:ambient (vec3 0.5 0.5 0.5)
+ #:diffuse (vec3 0.5 0.5 0.5)
+ #:specular (vec3 0.5 0.5 0.5)
+ #:shininess 32.0))
+
+
+;;;
+;;; Phong Shader
+;;;
+
+(define phong-shader
+ (delay
+ (strings->shader
+ "
+#version 130
+
+in vec3 position;
+in vec2 texcoord;
+in vec3 normal;
+
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+out vec3 fragNorm;
+out vec2 fragTex;
+
+void main() {
+ gl_Position = projection * view * model * vec4(position, 1.0);
+ // TODO: Calculate normal matrix on CPU
+ fragNorm = normalize(model * vec4(normal, 1.0)).xyz;
+ fragTex = texcoord;
+}
+"
+ "
+#version 130
+
+struct Material {
+ vec3 ambient;
+ vec3 diffuse;
+ vec3 specular;
+ float shininess;
+};
+
+struct DirectionalLight {
+ vec4 color;
+ vec3 direction;
+ vec3 ambient;
+ vec3 diffuse;
+ vec3 specular;
+};
+
+in vec3 fragNorm;
+in vec2 fragTex;
+
+uniform Material material;
+uniform DirectionalLight directionalLight;
+
+void main() {
+ vec3 lightColor = directionalLight.color.xyz;
+ vec3 ambientColor = material.ambient * lightColor;
+ vec3 lightDir = normalize(-directionalLight.direction);
+ float diffuseFactor = max(dot(lightDir, fragNorm), 0.0);
+ vec3 diffuseColor = diffuseFactor * material.diffuse * lightColor;
+ vec3 reflectDir = reflect(-lightDir, fragNorm);
+ float specularFactor = pow(max(dot(lightDir, reflectDir), 0.0), material.shininess);
+ vec3 specularColor = specularFactor * material.specular * lightColor;
+ gl_FragColor = vec4(ambientColor + diffuseColor + specularColor, 1.0);
+}
+")))
+
+(define (load-phong-shader)
+ (force phong-shader))
+
+(define (gpu-apply/phong shader vertex-array material model-matrix view-matrix)
+ (gpu-apply shader vertex-array
+ #:model model-matrix
+ #:view view-matrix
+ #:projection (current-projection)
+ #:material material
+ #:directional-light default-directional-light))
diff --git a/chickadee/render/scene.scm b/chickadee/render/scene.scm
deleted file mode 100644
index 818957e..0000000
--- a/chickadee/render/scene.scm
+++ /dev/null
@@ -1,252 +0,0 @@
-;;; Chickadee Game Toolkit
-;;; Copyright © 2017 David Thompson <davet@gnu.org>
-;;;
-;;; Chickadee is free software: you can redistribute it and/or modify
-;;; it under the terms of the GNU General Public License as published
-;;; by the Free Software Foundation, either version 3 of the License,
-;;; or (at your option) any later version.
-;;;
-;;; Chickadee is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;;; General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with this program. If not, see
-;;; <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; 3D scene graph with physically based rendering.
-;;
-;;; Code:
-
-(define-module (chickadee render scene)
- #:use-module (chickadee config)
- #:use-module (chickadee math matrix)
- #:use-module (chickadee math quaternion)
- #:use-module (chickadee math vector)
- #:use-module (chickadee render)
- #:use-module (chickadee render color)
- #:use-module (chickadee render buffer)
- #:use-module (chickadee render texture)
- #:use-module (chickadee render shader)
- #:use-module (srfi srfi-9)
- #:use-module (srfi srfi-9 gnu)
- #:export (make-material
- default-material
- material?
- material-name
- material-base-color-factor
- material-base-color-texture
- material-metallic-factor
- material-roughness-factor
- material-metallic-roughness-texture
- material-normal-factor
- material-normal-texture
- material-occlusion-facgor
- material-occlusion-texture
- material-emissive-factor
- material-emissive-texture
- material-alpha-mode
- material-alpha-cutoff
- material-double-sided?
- pbr-shader
- make-primitive
- primitive?
- primitive-vertex-array
- primitive-material
- primitive-targets
- make-mesh
- mesh?
- mesh-name
- mesh-primitives
- mesh-weights
- make-scene-node
- scene-node?
- scene-node-name
- scene-node-children
- scene-node-camera
- scene-node-skin
- scene-node-matrix
- scene-node-mesh
- scene-node-rotation
- scene-node-scale
- scene-node-translation
- scene-node-weights
- make-scene
- scene?
- scene-name
- scene-nodes
- draw-scene))
-
-(define-record-type <material>
- (%make-material name base-color-factor base-color-texture
- metallic-factor roughness-factor metallic-roughness-texture
- normal-factor normal-texture
- occlusion-factor occlusion-texture
- emissive-texture emissive-factor
- alpha-mode alpha-cutoff
- double-sided?)
- material?
- (name material-name)
- (base-color-factor material-base-color-factor)
- (base-color-texture material-base-color-texture)
- (metallic-factor material-metallic-factor)
- (roughness-factor material-roughness-factor)
- (metallic-roughness-texture material-metallic-roughness-texture)
- (normal-factor material-normal-factor)
- (normal-texture material-normal-texture)
- (occlusion-factor material-occlusion-factor)
- (occlusion-texture material-occlusion-texture)
- (emissive-factor material-emissive-factor)
- (emissive-texture material-emissive-texture)
- (alpha-mode material-alpha-mode)
- (alpha-cutoff material-alpha-cutoff)
- (double-sided? material-double-sided?))
-
-(define* (make-material #:key
- (name "anonymous")
- (base-color-factor #v(1.0 1.0 1.0))
- (base-color-texture null-texture)
- (metallic-factor 1.0)
- (roughness-factor 1.0)
- (metallic-roughness-texture null-texture)
- (normal-factor #v(1.0 1.0 1.0))
- (normal-texture null-texture)
- (occlusion-factor #v(1.0 1.0 1.0))
- (occlusion-texture null-texture)
- (emissive-factor #v(1.0 1.0 1.0))
- (emissive-texture null-texture)
- (alpha-mode 'opaque)
- (alpha-cutoff 0.5)
- double-sided?)
- (%make-material name base-color-factor base-color-texture
- metallic-factor roughness-factor metallic-roughness-texture
- normal-factor normal-texture
- occlusion-factor occlusion-texture
- emissive-texture emissive-factor
- alpha-mode alpha-cutoff double-sided?))
-
-(define default-material (make-material))
-
-(define pbr-shader
- (let ((shader
- (delay
- (load-shader (scope-datadir "shaders/pbr/pbr-vert.glsl")
- (scope-datadir "shaders/pbr/pbr-frag.glsl")))))
- (lambda ()
- (force shader))))
-
-(define-record-type <primitive>
- (%make-primitive vertex-array material targets matrix)
- primitive?
- (vertex-array primitive-vertex-array)
- (material primitive-material)
- (targets primitive-targets)
- (matrix primitive-matrix))
-
-(define (display-primitive primitive port)
- (format port "#<primitive material: ~s targets: ~s>"
- (primitive-material primitive)
- (primitive-targets primitive)))
-
-(set-record-type-printer! <primitive> display-primitive)
-
-(define* (make-primitive #:key
- vertex-array
- (material default-material)
- targets)
- (%make-primitive vertex-array material targets (make-identity-matrix4)))
-
-(define-record-type <mesh>
- (%make-mesh name primitives weights)
- mesh?
- (name mesh-name)
- (primitives mesh-primitives)
- (weights mesh-weights))
-
-(define (display-mesh mesh port)
- (format port "#<mesh name: ~s>" (mesh-name mesh)))
-
-(set-record-type-printer! <mesh> display-mesh)
-
-(define* (make-mesh #:key
- (name "anonymous")
- primitives
- weights)
- (%make-mesh name primitives weights))
-
-(define-record-type <scene-node>
- (%make-scene-node name children camera skin matrix world-matrix
- mesh rotation scale translation weights)
- node?
- (name scene-node-name)
- (children scene-node-children)
- (camera scene-node-camera)
- (skin scene-node-skin)
- (matrix scene-node-matrix)
- (world-matrix scene-node-world-matrix)
- (mesh scene-node-mesh)
- (rotation scene-node-rotation)
- (scale scene-node-scale)
- (translation scene-node-translation)
- (weights scene-node-weights))
-
-(define (display-scene-node scene port)
- (format port "#<scene-node name: ~s>" (scene-node-name scene)))
-
-(set-record-type-printer! <scene-node> display-scene-node)
-
-(define* (make-scene-node #:key
- (name "anonymous")
- (children #())
- camera
- skin
- (matrix (make-identity-matrix4))
- mesh
- (rotation (quaternion 0.0 0.0 0.0 1.0))
- (scale (vec3 1.0 1.0 1.0))
- (translation (vec3 0.0 0.0 0.0))
- weights)
- (%make-scene-node name children camera skin matrix (make-identity-matrix4)
- mesh rotation scale translation weights))
-
-(define-record-type <scene>
- (%make-scene name nodes)
- scene?
- (name scene-name)
- (nodes scene-nodes))
-
-(define* (make-scene #:key (name "anonymous") (nodes '()))
- (%make-scene name nodes))
-
-(define (draw-primitive primitive matrix)
- ;; TODO: Actually use physically based rendering.
- (let ((mvp (primitive-matrix primitive))
- (material (primitive-material primitive)))
- (matrix4-mult! mvp matrix (current-projection))
- (with-texture 0 (material-base-color-texture material)
- (gpu-apply (pbr-shader)
- (primitive-vertex-array primitive)
- #:mvp mvp
- #:base_color_factor (material-base-color-factor material)))))
-
-(define (draw-mesh mesh matrix)
- (for-each (lambda (primitive)
- (draw-primitive primitive matrix))
- (mesh-primitives mesh)))
-
-(define (draw-scene-node node matrix)
- (let ((world-matrix (scene-node-world-matrix node)))
- (matrix4-mult! world-matrix matrix (scene-node-matrix node))
- (when (scene-node-mesh node)
- (draw-mesh (scene-node-mesh node) world-matrix))
- (for-each (lambda (node)
- (draw-scene-node node world-matrix))
- (scene-node-children node))))
-
-(define (draw-scene scene)
- (for-each (lambda (scene)
- (draw-scene-node scene (scene-node-world-matrix scene)))
- (scene-nodes scene)))
diff --git a/data/shaders/pbr/pbr-frag.glsl b/data/shaders/pbr/pbr-frag.glsl
deleted file mode 100644
index 1552880..0000000
--- a/data/shaders/pbr/pbr-frag.glsl
+++ /dev/null
@@ -1,10 +0,0 @@
-#version 130
-
-in vec2 frag_tex;
-uniform vec3 base_color_factor;
-uniform sampler2D base_color_texture;
-
-void main (void) {
- gl_FragColor = texture2D(base_color_texture, frag_tex) *
- vec4(base_color_factor, 1.0);
-}
diff --git a/data/shaders/pbr/pbr-vert.glsl b/data/shaders/pbr/pbr-vert.glsl
deleted file mode 100644
index b6fefef..0000000
--- a/data/shaders/pbr/pbr-vert.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-#version 130
-
-in vec3 position;
-in vec2 texcoord_0;
-out vec2 frag_tex;
-uniform mat4 mvp;
-
-void main(void) {
- frag_tex = texcoord_0;
- gl_Position = mvp * vec4(position.xyz, 1.0);
-}
diff --git a/examples/model.scm b/examples/model.scm
new file mode 100644
index 0000000..cc73918
--- /dev/null
+++ b/examples/model.scm
@@ -0,0 +1,73 @@
+(use-modules (chickadee)
+ (chickadee math)
+ (chickadee math matrix)
+ (chickadee math vector)
+ (chickadee render)
+ (chickadee render model)
+ (chickadee render font)
+ (ice-9 format))
+
+(define projection (perspective-projection (/ pi 3) (/ 4.0 3.0) 0.1 500.0))
+(define rotation (make-identity-matrix4))
+(define translation (make-identity-matrix4))
+(define view-matrix (make-identity-matrix4))
+(define model-matrix (make-identity-matrix4))
+(define position (vec3 0.0 0.0 0.0))
+(define velocity (vec3 0.0 0.0 0.0))
+(define model #f)
+(define text-position #v(4.0 464.0))
+(define text "")
+(define y-rotation 0.0)
+
+(define (reset-position)
+ (set-vec3! position 0.0 0.0 -4.0))
+
+(define (load)
+ (set! model (load-obj "models/suzanne.obj"))
+ (reset-position))
+
+(define (draw alpha)
+ (with-projection projection
+ (with-depth-test #t
+ (draw-model model model-matrix view-matrix)))
+ (draw-text text text-position))
+
+(define (update dt)
+ ;; Update camera position
+ (set-vec3! velocity
+ (+ (if (key-pressed? 'd) -1.0 0.0)
+ (if (key-pressed? 'a) 1.0 0.0))
+ 0.0
+ (+ (if (key-pressed? 's) -1.0 0.0)
+ (if (key-pressed? 'w) 1.0 0.0)))
+ (vec3-normalize! velocity)
+ (vec3-mult! velocity 0.1)
+ (vec3-add! position velocity)
+ (set! text (format #f "(~6,2f, ~6,2f, ~6,2f)"
+ (vec3-x position)
+ (vec3-y position)
+ (vec3-z position)))
+
+ ;; Compute new view matrix
+ (matrix4-rotate-y! rotation theta)
+ (matrix4-translate! translation position)
+ (matrix4-identity! view-matrix)
+ (matrix4-mult! view-matrix view-matrix rotation)
+ (matrix4-mult! view-matrix view-matrix translation)
+
+ ;; Rotate the model about the y-axis
+ (set! y-rotation (+ y-rotation 0.03))
+ (matrix4-rotate-y! model-matrix y-rotation))
+
+(define (key-press key scancode modifiers repeat?)
+ (cond
+ ((eq? key 'q)
+ (abort-game))
+ ((eq? key 'r)
+ (reset-position))))
+
+(run-game #:window-title "3D!"
+ #:load load
+ #:draw draw
+ #:update update
+ #:key-press key-press)
diff --git a/examples/models/suzanne.obj b/examples/models/suzanne.obj
new file mode 100644
index 0000000..7d657dc
--- /dev/null
+++ b/examples/models/suzanne.obj
@@ -0,0 +1,2580 @@
+# Blender3D v249 OBJ File: suzanne.blend
+# www.blender3d.org
+v 0.437500 0.164063 0.765625
+v -0.437500 0.164063 0.765625
+v 0.500000 0.093750 0.687500
+v -0.500000 0.093750 0.687500
+v 0.546875 0.054688 0.578125
+v -0.546875 0.054688 0.578125
+v 0.351563 -0.023438 0.617188
+v -0.351563 -0.023438 0.617188
+v 0.351563 0.031250 0.718750
+v -0.351563 0.031250 0.718750
+v 0.351563 0.132813 0.781250
+v -0.351563 0.132813 0.781250
+v 0.273438 0.164063 0.796875
+v -0.273438 0.164063 0.796875
+v 0.203125 0.093750 0.742188
+v -0.203125 0.093750 0.742188
+v 0.156250 0.054688 0.648438
+v -0.156250 0.054688 0.648438
+v 0.078125 0.242188 0.656250
+v -0.078125 0.242188 0.656250
+v 0.140625 0.242188 0.742188
+v -0.140625 0.242188 0.742188
+v 0.242188 0.242188 0.796875
+v -0.242188 0.242188 0.796875
+v 0.273438 0.328125 0.796875
+v -0.273438 0.328125 0.796875
+v 0.203125 0.390625 0.742188
+v -0.203125 0.390625 0.742188
+v 0.156250 0.437500 0.648438
+v -0.156250 0.437500 0.648438
+v 0.351563 0.515625 0.617188
+v -0.351563 0.515625 0.617188
+v 0.351563 0.453125 0.718750
+v -0.351563 0.453125 0.718750
+v 0.351563 0.359375 0.781250
+v -0.351563 0.359375 0.781250
+v 0.437500 0.328125 0.765625
+v -0.437500 0.328125 0.765625
+v 0.500000 0.390625 0.687500
+v -0.500000 0.390625 0.687500
+v 0.546875 0.437500 0.578125
+v -0.546875 0.437500 0.578125
+v 0.625000 0.242188 0.562500
+v -0.625000 0.242188 0.562500
+v 0.562500 0.242188 0.671875
+v -0.562500 0.242188 0.671875
+v 0.468750 0.242188 0.757813
+v -0.468750 0.242188 0.757813
+v 0.476563 0.242188 0.773438
+v -0.476563 0.242188 0.773438
+v 0.445313 0.335938 0.781250
+v -0.445313 0.335938 0.781250
+v 0.351563 0.375000 0.804688
+v -0.351563 0.375000 0.804688
+v 0.265625 0.335938 0.820313
+v -0.265625 0.335938 0.820313
+v 0.226563 0.242188 0.820313
+v -0.226563 0.242188 0.820313
+v 0.265625 0.156250 0.820313
+v -0.265625 0.156250 0.820313
+v 0.351563 0.242188 0.828125
+v -0.351563 0.242188 0.828125
+v 0.351563 0.117188 0.804688
+v -0.351563 0.117188 0.804688
+v 0.445313 0.156250 0.781250
+v -0.445313 0.156250 0.781250
+v 0.000000 0.429688 0.742188
+v 0.000000 0.351563 0.820313
+v 0.000000 -0.679688 0.734375
+v 0.000000 -0.320313 0.781250
+v 0.000000 -0.187500 0.796875
+v 0.000000 -0.773438 0.718750
+v 0.000000 0.406250 0.601563
+v 0.000000 0.570313 0.570313
+v 0.000000 0.898438 -0.546875
+v 0.000000 0.562500 -0.851563
+v 0.000000 0.070313 -0.828125
+v 0.000000 -0.382813 -0.351563
+v 0.203125 -0.187500 0.562500
+v -0.203125 -0.187500 0.562500
+v 0.312500 -0.437500 0.570313
+v -0.312500 -0.437500 0.570313
+v 0.351563 -0.695313 0.570313
+v -0.351563 -0.695313 0.570313
+v 0.367188 -0.890625 0.531250
+v -0.367188 -0.890625 0.531250
+v 0.328125 -0.945313 0.523438
+v -0.328125 -0.945313 0.523438
+v 0.179688 -0.968750 0.554688
+v -0.179688 -0.968750 0.554688
+v 0.000000 -0.984375 0.578125
+v 0.437500 -0.140625 0.531250
+v -0.437500 -0.140625 0.531250
+v 0.632813 -0.039063 0.539063
+v -0.632813 -0.039063 0.539063
+v 0.828125 0.148438 0.445313
+v -0.828125 0.148438 0.445313
+v 0.859375 0.429688 0.593750
+v -0.859375 0.429688 0.593750
+v 0.710938 0.484375 0.625000
+v -0.710938 0.484375 0.625000
+v 0.492188 0.601563 0.687500
+v -0.492188 0.601563 0.687500
+v 0.320313 0.757813 0.734375
+v -0.320313 0.757813 0.734375
+v 0.156250 0.718750 0.757813
+v -0.156250 0.718750 0.757813
+v 0.062500 0.492188 0.750000
+v -0.062500 0.492188 0.750000
+v 0.164063 0.414063 0.773438
+v -0.164063 0.414063 0.773438
+v 0.125000 0.304688 0.765625
+v -0.125000 0.304688 0.765625
+v 0.203125 0.093750 0.742188
+v -0.203125 0.093750 0.742188
+v 0.375000 0.015625 0.703125
+v -0.375000 0.015625 0.703125
+v 0.492188 0.062500 0.671875
+v -0.492188 0.062500 0.671875
+v 0.625000 0.187500 0.648438
+v -0.625000 0.187500 0.648438
+v 0.640625 0.296875 0.648438
+v -0.640625 0.296875 0.648438
+v 0.601563 0.375000 0.664063
+v -0.601563 0.375000 0.664063
+v 0.429688 0.437500 0.718750
+v -0.429688 0.437500 0.718750
+v 0.250000 0.468750 0.757813
+v -0.250000 0.468750 0.757813
+v 0.000000 -0.765625 0.734375
+v 0.109375 -0.718750 0.734375
+v -0.109375 -0.718750 0.734375
+v 0.117188 -0.835938 0.710938
+v -0.117188 -0.835938 0.710938
+v 0.062500 -0.882813 0.695313
+v -0.062500 -0.882813 0.695313
+v 0.000000 -0.890625 0.687500
+v 0.000000 -0.195313 0.750000
+v 0.000000 -0.140625 0.742188
+v 0.101563 -0.148438 0.742188
+v -0.101563 -0.148438 0.742188
+v 0.125000 -0.226563 0.750000
+v -0.125000 -0.226563 0.750000
+v 0.085938 -0.289063 0.742188
+v -0.085938 -0.289063 0.742188
+v 0.398438 -0.046875 0.671875
+v -0.398438 -0.046875 0.671875
+v 0.617188 0.054688 0.625000
+v -0.617188 0.054688 0.625000
+v 0.726563 0.203125 0.601563
+v -0.726563 0.203125 0.601563
+v 0.742188 0.375000 0.656250
+v -0.742188 0.375000 0.656250
+v 0.687500 0.414063 0.726563
+v -0.687500 0.414063 0.726563
+v 0.437500 0.546875 0.796875
+v -0.437500 0.546875 0.796875
+v 0.312500 0.640625 0.835938
+v -0.312500 0.640625 0.835938
+v 0.203125 0.617188 0.851563
+v -0.203125 0.617188 0.851563
+v 0.101563 0.429688 0.843750
+v -0.101563 0.429688 0.843750
+v 0.125000 -0.101563 0.812500
+v -0.125000 -0.101563 0.812500
+v 0.210938 -0.445313 0.710938
+v -0.210938 -0.445313 0.710938
+v 0.250000 -0.703125 0.687500
+v -0.250000 -0.703125 0.687500
+v 0.265625 -0.820313 0.664063
+v -0.265625 -0.820313 0.664063
+v 0.234375 -0.914063 0.632813
+v -0.234375 -0.914063 0.632813
+v 0.164063 -0.929688 0.632813
+v -0.164063 -0.929688 0.632813
+v 0.000000 -0.945313 0.640625
+v 0.000000 0.046875 0.726563
+v 0.000000 0.210938 0.765625
+v 0.328125 0.476563 0.742188
+v -0.328125 0.476563 0.742188
+v 0.164063 0.140625 0.750000
+v -0.164063 0.140625 0.750000
+v 0.132813 0.210938 0.757813
+v -0.132813 0.210938 0.757813
+v 0.117188 -0.687500 0.734375
+v -0.117188 -0.687500 0.734375
+v 0.078125 -0.445313 0.750000
+v -0.078125 -0.445313 0.750000
+v 0.000000 -0.445313 0.750000
+v 0.000000 -0.328125 0.742188
+v 0.093750 -0.273438 0.781250
+v -0.093750 -0.273438 0.781250
+v 0.132813 -0.226563 0.796875
+v -0.132813 -0.226563 0.796875
+v 0.109375 -0.132813 0.781250
+v -0.109375 -0.132813 0.781250
+v 0.039063 -0.125000 0.781250
+v -0.039063 -0.125000 0.781250
+v 0.000000 -0.203125 0.828125
+v 0.046875 -0.148438 0.812500
+v -0.046875 -0.148438 0.812500
+v 0.093750 -0.156250 0.812500
+v -0.093750 -0.156250 0.812500
+v 0.109375 -0.226563 0.828125
+v -0.109375 -0.226563 0.828125
+v 0.078125 -0.250000 0.804688
+v -0.078125 -0.250000 0.804688
+v 0.000000 -0.289063 0.804688
+v 0.257813 -0.312500 0.554688
+v -0.257813 -0.312500 0.554688
+v 0.164063 -0.242188 0.710938
+v -0.164063 -0.242188 0.710938
+v 0.179688 -0.312500 0.710938
+v -0.179688 -0.312500 0.710938
+v 0.234375 -0.250000 0.554688
+v -0.234375 -0.250000 0.554688
+v 0.000000 -0.875000 0.687500
+v 0.046875 -0.867188 0.687500
+v -0.046875 -0.867188 0.687500
+v 0.093750 -0.820313 0.710938
+v -0.093750 -0.820313 0.710938
+v 0.093750 -0.742188 0.726563
+v -0.093750 -0.742188 0.726563
+v 0.000000 -0.781250 0.656250
+v 0.093750 -0.750000 0.664063
+v -0.093750 -0.750000 0.664063
+v 0.093750 -0.812500 0.640625
+v -0.093750 -0.812500 0.640625
+v 0.046875 -0.851563 0.632813
+v -0.046875 -0.851563 0.632813
+v 0.000000 -0.859375 0.632813
+v 0.171875 0.218750 0.781250
+v -0.171875 0.218750 0.781250
+v 0.187500 0.156250 0.773438
+v -0.187500 0.156250 0.773438
+v 0.335938 0.429688 0.757813
+v -0.335938 0.429688 0.757813
+v 0.273438 0.421875 0.773438
+v -0.273438 0.421875 0.773438
+v 0.421875 0.398438 0.773438
+v -0.421875 0.398438 0.773438
+v 0.562500 0.351563 0.695313
+v -0.562500 0.351563 0.695313
+v 0.585938 0.289063 0.687500
+v -0.585938 0.289063 0.687500
+v 0.578125 0.195313 0.679688
+v -0.578125 0.195313 0.679688
+v 0.476563 0.101563 0.718750
+v -0.476563 0.101563 0.718750
+v 0.375000 0.062500 0.742188
+v -0.375000 0.062500 0.742188
+v 0.226563 0.109375 0.781250
+v -0.226563 0.109375 0.781250
+v 0.179688 0.296875 0.781250
+v -0.179688 0.296875 0.781250
+v 0.210938 0.375000 0.781250
+v -0.210938 0.375000 0.781250
+v 0.234375 0.359375 0.757813
+v -0.234375 0.359375 0.757813
+v 0.195313 0.296875 0.757813
+v -0.195313 0.296875 0.757813
+v 0.242188 0.125000 0.757813
+v -0.242188 0.125000 0.757813
+v 0.375000 0.085938 0.726563
+v -0.375000 0.085938 0.726563
+v 0.460938 0.117188 0.703125
+v -0.460938 0.117188 0.703125
+v 0.546875 0.210938 0.671875
+v -0.546875 0.210938 0.671875
+v 0.554688 0.281250 0.671875
+v -0.554688 0.281250 0.671875
+v 0.531250 0.335938 0.679688
+v -0.531250 0.335938 0.679688
+v 0.414063 0.390625 0.750000
+v -0.414063 0.390625 0.750000
+v 0.281250 0.398438 0.765625
+v -0.281250 0.398438 0.765625
+v 0.335938 0.406250 0.750000
+v -0.335938 0.406250 0.750000
+v 0.203125 0.171875 0.750000
+v -0.203125 0.171875 0.750000
+v 0.195313 0.226563 0.750000
+v -0.195313 0.226563 0.750000
+v 0.109375 0.460938 0.609375
+v -0.109375 0.460938 0.609375
+v 0.195313 0.664063 0.617188
+v -0.195313 0.664063 0.617188
+v 0.335938 0.687500 0.593750
+v -0.335938 0.687500 0.593750
+v 0.484375 0.554688 0.554688
+v -0.484375 0.554688 0.554688
+v 0.679688 0.453125 0.492188
+v -0.679688 0.453125 0.492188
+v 0.796875 0.406250 0.460938
+v -0.796875 0.406250 0.460938
+v 0.773438 0.164063 0.375000
+v -0.773438 0.164063 0.375000
+v 0.601563 0.000000 0.414063
+v -0.601563 0.000000 0.414063
+v 0.437500 -0.093750 0.468750
+v -0.437500 -0.093750 0.468750
+v 0.000000 0.898438 0.289063
+v 0.000000 0.984375 -0.078125
+v 0.000000 -0.195313 -0.671875
+v 0.000000 -0.460938 0.187500
+v 0.000000 -0.976563 0.460938
+v 0.000000 -0.804688 0.343750
+v 0.000000 -0.570313 0.320313
+v 0.000000 -0.484375 0.281250
+v 0.851563 0.234375 0.054688
+v -0.851563 0.234375 0.054688
+v 0.859375 0.320313 -0.046875
+v -0.859375 0.320313 -0.046875
+v 0.773438 0.265625 -0.437500
+v -0.773438 0.265625 -0.437500
+v 0.460938 0.437500 -0.703125
+v -0.460938 0.437500 -0.703125
+v 0.734375 -0.046875 0.070313
+v -0.734375 -0.046875 0.070313
+v 0.593750 -0.125000 -0.164063
+v -0.593750 -0.125000 -0.164063
+v 0.640625 -0.007813 -0.429688
+v -0.640625 -0.007813 -0.429688
+v 0.335938 0.054688 -0.664063
+v -0.335938 0.054688 -0.664063
+v 0.234375 -0.351563 0.406250
+v -0.234375 -0.351563 0.406250
+v 0.179688 -0.414063 0.257813
+v -0.179688 -0.414063 0.257813
+v 0.289063 -0.710938 0.382813
+v -0.289063 -0.710938 0.382813
+v 0.250000 -0.500000 0.390625
+v -0.250000 -0.500000 0.390625
+v 0.328125 -0.914063 0.398438
+v -0.328125 -0.914063 0.398438
+v 0.140625 -0.757813 0.367188
+v -0.140625 -0.757813 0.367188
+v 0.125000 -0.539063 0.359375
+v -0.125000 -0.539063 0.359375
+v 0.164063 -0.945313 0.437500
+v -0.164063 -0.945313 0.437500
+v 0.218750 -0.281250 0.429688
+v -0.218750 -0.281250 0.429688
+v 0.210938 -0.226563 0.468750
+v -0.210938 -0.226563 0.468750
+v 0.203125 -0.171875 0.500000
+v -0.203125 -0.171875 0.500000
+v 0.210938 -0.390625 0.164063
+v -0.210938 -0.390625 0.164063
+v 0.296875 -0.312500 -0.265625
+v -0.296875 -0.312500 -0.265625
+v 0.343750 -0.148438 -0.539063
+v -0.343750 -0.148438 -0.539063
+v 0.453125 0.867188 -0.382813
+v -0.453125 0.867188 -0.382813
+v 0.453125 0.929688 -0.070313
+v -0.453125 0.929688 -0.070313
+v 0.453125 0.851563 0.234375
+v -0.453125 0.851563 0.234375
+v 0.460938 0.523438 0.429688
+v -0.460938 0.523438 0.429688
+v 0.726563 0.406250 0.335938
+v -0.726563 0.406250 0.335938
+v 0.632813 0.453125 0.281250
+v -0.632813 0.453125 0.281250
+v 0.640625 0.703125 0.054688
+v -0.640625 0.703125 0.054688
+v 0.796875 0.562500 0.125000
+v -0.796875 0.562500 0.125000
+v 0.796875 0.617188 -0.117188
+v -0.796875 0.617188 -0.117188
+v 0.640625 0.750000 -0.195313
+v -0.640625 0.750000 -0.195313
+v 0.640625 0.679688 -0.445313
+v -0.640625 0.679688 -0.445313
+v 0.796875 0.539063 -0.359375
+v -0.796875 0.539063 -0.359375
+v 0.617188 0.328125 -0.585938
+v -0.617188 0.328125 -0.585938
+v 0.484375 0.023438 -0.546875
+v -0.484375 0.023438 -0.546875
+v 0.820313 0.328125 -0.203125
+v -0.820313 0.328125 -0.203125
+v 0.406250 -0.171875 0.148438
+v -0.406250 -0.171875 0.148438
+v 0.429688 -0.195313 -0.210938
+v -0.429688 -0.195313 -0.210938
+v 0.890625 0.406250 -0.234375
+v -0.890625 0.406250 -0.234375
+v 0.773438 -0.140625 -0.125000
+v -0.773438 -0.140625 -0.125000
+v 1.039063 -0.101563 -0.328125
+v -1.039063 -0.101563 -0.328125
+v 1.281250 0.054688 -0.429688
+v -1.281250 0.054688 -0.429688
+v 1.351563 0.320313 -0.421875
+v -1.351563 0.320313 -0.421875
+v 1.234375 0.507813 -0.421875
+v -1.234375 0.507813 -0.421875
+v 1.023438 0.476563 -0.312500
+v -1.023438 0.476563 -0.312500
+v 1.015625 0.414063 -0.289063
+v -1.015625 0.414063 -0.289063
+v 1.187500 0.437500 -0.390625
+v -1.187500 0.437500 -0.390625
+v 1.265625 0.289063 -0.406250
+v -1.265625 0.289063 -0.406250
+v 1.210938 0.078125 -0.406250
+v -1.210938 0.078125 -0.406250
+v 1.031250 -0.039063 -0.304688
+v -1.031250 -0.039063 -0.304688
+v 0.828125 -0.070313 -0.132813
+v -0.828125 -0.070313 -0.132813
+v 0.921875 0.359375 -0.218750
+v -0.921875 0.359375 -0.218750
+v 0.945313 0.304688 -0.289063
+v -0.945313 0.304688 -0.289063
+v 0.882813 -0.023438 -0.210938
+v -0.882813 -0.023438 -0.210938
+v 1.039063 0.000000 -0.367188
+v -1.039063 0.000000 -0.367188
+v 1.187500 0.093750 -0.445313
+v -1.187500 0.093750 -0.445313
+v 1.234375 0.250000 -0.445313
+v -1.234375 0.250000 -0.445313
+v 1.171875 0.359375 -0.437500
+v -1.171875 0.359375 -0.437500
+v 1.023438 0.343750 -0.359375
+v -1.023438 0.343750 -0.359375
+v 0.843750 0.289063 -0.210938
+v -0.843750 0.289063 -0.210938
+v 0.835938 0.171875 -0.273438
+v -0.835938 0.171875 -0.273438
+v 0.757813 0.093750 -0.273438
+v -0.757813 0.093750 -0.273438
+v 0.820313 0.085938 -0.273438
+v -0.820313 0.085938 -0.273438
+v 0.843750 0.015625 -0.273438
+v -0.843750 0.015625 -0.273438
+v 0.812500 -0.015625 -0.273438
+v -0.812500 -0.015625 -0.273438
+v 0.726563 0.000000 -0.070313
+v -0.726563 0.000000 -0.070313
+v 0.718750 -0.023438 -0.171875
+v -0.718750 -0.023438 -0.171875
+v 0.718750 0.039063 -0.187500
+v -0.718750 0.039063 -0.187500
+v 0.796875 0.203125 -0.210938
+v -0.796875 0.203125 -0.210938
+v 0.890625 0.242188 -0.265625
+v -0.890625 0.242188 -0.265625
+v 0.890625 0.234375 -0.320313
+v -0.890625 0.234375 -0.320313
+v 0.812500 -0.015625 -0.320313
+v -0.812500 -0.015625 -0.320313
+v 0.851563 0.015625 -0.320313
+v -0.851563 0.015625 -0.320313
+v 0.828125 0.078125 -0.320313
+v -0.828125 0.078125 -0.320313
+v 0.765625 0.093750 -0.320313
+v -0.765625 0.093750 -0.320313
+v 0.843750 0.171875 -0.320313
+v -0.843750 0.171875 -0.320313
+v 1.039063 0.328125 -0.414063
+v -1.039063 0.328125 -0.414063
+v 1.187500 0.343750 -0.484375
+v -1.187500 0.343750 -0.484375
+v 1.257813 0.242188 -0.492188
+v -1.257813 0.242188 -0.492188
+v 1.210938 0.085938 -0.484375
+v -1.210938 0.085938 -0.484375
+v 1.046875 0.000000 -0.421875
+v -1.046875 0.000000 -0.421875
+v 0.882813 -0.015625 -0.265625
+v -0.882813 -0.015625 -0.265625
+v 0.953125 0.289063 -0.343750
+v -0.953125 0.289063 -0.343750
+v 0.890625 0.109375 -0.328125
+v -0.890625 0.109375 -0.328125
+v 0.937500 0.062500 -0.335938
+v -0.937500 0.062500 -0.335938
+v 1.000000 0.125000 -0.367188
+v -1.000000 0.125000 -0.367188
+v 0.960938 0.171875 -0.351563
+v -0.960938 0.171875 -0.351563
+v 1.015625 0.234375 -0.375000
+v -1.015625 0.234375 -0.375000
+v 1.054688 0.187500 -0.382813
+v -1.054688 0.187500 -0.382813
+v 1.109375 0.210938 -0.390625
+v -1.109375 0.210938 -0.390625
+v 1.085938 0.273438 -0.390625
+v -1.085938 0.273438 -0.390625
+v 1.023438 0.437500 -0.484375
+v -1.023438 0.437500 -0.484375
+v 1.250000 0.468750 -0.546875
+v -1.250000 0.468750 -0.546875
+v 1.367188 0.296875 -0.500000
+v -1.367188 0.296875 -0.500000
+v 1.312500 0.054688 -0.531250
+v -1.312500 0.054688 -0.531250
+v 1.039063 -0.085938 -0.492188
+v -1.039063 -0.085938 -0.492188
+v 0.789063 -0.125000 -0.328125
+v -0.789063 -0.125000 -0.328125
+v 0.859375 0.382813 -0.382813
+v -0.859375 0.382813 -0.382813
+v -1.023438 0.476563 -0.312500
+v -1.234375 0.507813 -0.421875
+v -0.890625 0.406250 -0.234375
+v -0.820313 0.328125 -0.203125
+vt 0.315596 0.792535
+vt 0.331462 0.787091
+vt 0.331944 0.799704
+vt 0.049262 0.798007
+vt 0.050304 0.785428
+vt 0.065913 0.791570
+vt 0.321453 0.778649
+vt 0.060677 0.777438
+vt 0.310368 0.778802
+vt 0.071744 0.778083
+vt 0.302416 0.786560
+vt 0.079345 0.786186
+vt 0.301514 0.798474
+vt 0.079717 0.798128
+vt 0.308740 0.806873
+vt 0.072125 0.806199
+vt 0.321648 0.808687
+vt 0.059149 0.807438
+vt 0.048462 0.201858
+vt 0.040084 0.207259
+vt 0.043232 0.202821
+vt 0.043249 0.220655
+vt 0.040093 0.216224
+vt 0.048480 0.221607
+vt 0.563710 0.649220
+vt 0.540594 0.657349
+vt 0.547067 0.627433
+vt 0.974643 0.218739
+vt 0.968169 0.188824
+vt 0.991286 0.196952
+vt 0.166564 0.702856
+vt 0.160061 0.635503
+vt 0.218800 0.643864
+vt 0.646379 0.202310
+vt 0.587641 0.210669
+vt 0.594146 0.143318
+vt 0.231653 0.710981
+vt 0.181122 0.727399
+vt 0.174315 0.716236
+vt 0.601897 0.129938
+vt 0.608704 0.118775
+vt 0.659234 0.135195
+vt 0.266169 0.503056
+vt 0.270502 0.531304
+vt 0.237927 0.525958
+vt 0.665505 0.320215
+vt 0.698081 0.314870
+vt 0.693747 0.343118
+vt 0.392095 0.783569
+vt 0.421339 0.774990
+vt 0.422693 0.793271
+vt 0.628129 0.465996
+vt 0.613733 0.456434
+vt 0.634389 0.436387
+vt 0.501778 0.870396
+vt 0.507486 0.857499
+vt 0.528577 0.865850
+vt 0.643384 0.583025
+vt 0.644052 0.562152
+vt 0.656465 0.561923
+vt 0.766386 0.787223
+vt 0.745292 0.810963
+vt 0.708792 0.802136
+vt 0.769147 0.634951
+vt 0.732033 0.641034
+vt 0.711181 0.618495
+vt 0.849461 0.545148
+vt 0.823375 0.497849
+vt 0.897469 0.500666
+vt 0.902318 0.546395
+vt 0.572425 0.679855
+vt 0.643837 0.668801
+vt 0.623443 0.718088
+vt 0.572425 0.724426
+vt 0.726607 0.540494
+vt 0.753364 0.518460
+vt 0.715449 0.680462
+vt 0.749227 0.698466
+vt 0.695922 0.534580
+vt 0.693526 0.510498
+vt 0.772837 0.655221
+vt 0.784620 0.679820
+vt 0.718163 0.580185
+vt 0.809389 0.599417
+vt 0.761761 0.743313
+vt 0.667750 0.767676
+vt 0.693110 0.564191
+vt 0.797155 0.722534
+vt 0.682009 0.616616
+vt 0.795802 0.787304
+vt 0.719538 0.655221
+vt 0.756895 0.826983
+vt 0.782765 0.655221
+vt 0.695179 0.821970
+vt 0.843059 0.610497
+vt 0.635588 0.780626
+vt 0.634422 0.561399
+vt 0.628274 0.581967
+vt 0.511020 0.847430
+vt 0.533908 0.850607
+vt 0.633815 0.551490
+vt 0.613046 0.571327
+vt 0.530368 0.831407
+vt 0.501394 0.842435
+vt 0.626589 0.538875
+vt 0.604527 0.544684
+vt 0.508929 0.810914
+vt 0.492547 0.829318
+vt 0.618247 0.522587
+vt 0.602583 0.501781
+vt 0.480939 0.813120
+vt 0.469234 0.787943
+vt 0.616652 0.502716
+vt 0.613925 0.497595
+vt 0.459358 0.796431
+vt 0.462840 0.801566
+vt 0.644899 0.511966
+vt 0.630336 0.517087
+vt 0.628893 0.504351
+vt 0.635735 0.498392
+vt 0.458270 0.813966
+vt 0.469630 0.821874
+vt 0.457144 0.833207
+vt 0.449054 0.817297
+vt 0.637359 0.534149
+vt 0.654293 0.524569
+vt 0.464258 0.849211
+vt 0.482600 0.837505
+vt 0.644187 0.548520
+vt 0.659377 0.540935
+vt 0.478087 0.863369
+vt 0.493557 0.851414
+vt 0.597230 0.539263
+vt 0.595257 0.495349
+vt 0.466971 0.777596
+vt 0.507407 0.801398
+vt 0.605628 0.572478
+vt 0.534801 0.825096
+vt 0.627145 0.592333
+vt 0.544318 0.853620
+vt 0.651887 0.586528
+vt 0.528822 0.875551
+vt 0.665532 0.557472
+vt 0.492878 0.878439
+vt 0.669345 0.535984
+vt 0.467321 0.871200
+vt 0.612569 0.491986
+vt 0.454710 0.792385
+vt 0.619277 0.495381
+vt 0.454636 0.800448
+vt 0.628580 0.496763
+vt 0.451294 0.809743
+vt 0.636682 0.490206
+vt 0.440853 0.813605
+vt 0.652342 0.504728
+vt 0.446182 0.836397
+vt 0.664409 0.519225
+vt 0.453285 0.856119
+vt 0.666191 0.492411
+vt 0.717596 0.474672
+vt 0.382398 0.879324
+vt 0.427166 0.842398
+vt 0.681733 0.511408
+vt 0.427493 0.877628
+vt 0.435523 0.867805
+vt 0.685777 0.532869
+vt 0.453231 0.887054
+vt 0.588528 0.478377
+vt 0.454313 0.762782
+vt 0.446975 0.900429
+vt 0.713425 0.237886
+vt 0.709019 0.215724
+vt 0.755152 0.224403
+vt 0.762923 0.242445
+vt 0.327574 0.621771
+vt 0.281440 0.630451
+vt 0.285847 0.608289
+vt 0.335345 0.603729
+vt 0.576794 0.465515
+vt 0.583867 0.423087
+vt 0.405805 0.730353
+vt 0.448347 0.745304
+vt 0.686035 0.253032
+vt 0.258456 0.593142
+vt 0.683851 0.556229
+vt 0.482266 0.899349
+vt 0.670531 0.597684
+vt 0.532990 0.898426
+vt 0.630909 0.604157
+vt 0.553941 0.861896
+vt 0.596864 0.576275
+vt 0.542184 0.818594
+vt 0.585561 0.529242
+vt 0.503791 0.785451
+vt 0.572425 0.529736
+vt 0.510638 0.773572
+vt 0.587548 0.588270
+vt 0.557294 0.815416
+vt 0.629961 0.623919
+vt 0.572425 0.868524
+vt 0.548104 0.914571
+vt 0.488130 0.914571
+vt 0.658830 0.266292
+vt 0.631691 0.281488
+vt 0.204112 0.564686
+vt 0.231252 0.579881
+vt 0.706402 0.288928
+vt 0.278823 0.557246
+vt 0.743528 0.317934
+vt 0.752264 0.346660
+vt 0.324686 0.499513
+vt 0.315950 0.528240
+vt 0.743309 0.289810
+vt 0.315731 0.556363
+vt 0.700326 0.147967
+vt 0.272746 0.698208
+vt 0.795874 0.266472
+vt 0.775660 0.289442
+vt 0.757507 0.263314
+vt 0.348083 0.556732
+vt 0.329929 0.582860
+vt 0.368297 0.579702
+vt 0.804056 0.232825
+vt 0.376478 0.613349
+vt 0.810124 0.179100
+vt 0.382547 0.667075
+vt 0.753847 0.157090
+vt 0.811201 0.146834
+vt 0.383624 0.699341
+vt 0.326269 0.689085
+vt 0.879685 0.183943
+vt 0.888071 0.157228
+vt 0.460496 0.688946
+vt 0.452109 0.662231
+vt 0.925222 0.140531
+vt 0.947451 0.149372
+vt 0.519876 0.696801
+vt 0.497647 0.705643
+vt 0.876420 0.258223
+vt 0.946138 0.286262
+vt 0.518561 0.559910
+vt 0.448843 0.587951
+vt 0.829953 0.196170
+vt 0.837053 0.152275
+vt 0.409477 0.693900
+vt 0.402377 0.650004
+vt 0.829888 0.255993
+vt 0.402311 0.590181
+vt 0.852096 0.297194
+vt 0.813695 0.289418
+vt 0.424519 0.548979
+vt 0.386117 0.556756
+vt 0.820842 0.328587
+vt 0.789451 0.311961
+vt 0.393264 0.517587
+vt 0.361873 0.534212
+vt 0.840465 0.403536
+vt 0.762603 0.423087
+vt 0.412887 0.442637
+vt 0.335024 0.423087
+vt 0.909248 0.345901
+vt 0.481670 0.500271
+vt 0.676670 0.402805
+vt 0.249092 0.443369
+vt 0.573469 0.193539
+vt 0.579214 0.151927
+vt 0.151632 0.694246
+vt 0.145888 0.652633
+vt 0.546919 0.227092
+vt 0.536510 0.214419
+vt 0.119340 0.619080
+vt 0.108931 0.631753
+vt 0.588792 0.317539
+vt 0.161214 0.528634
+vt 0.630429 0.371564
+vt 0.202851 0.474609
+vt 0.657494 0.118541
+vt 0.164237 0.319427
+vt 0.169464 0.304721
+vt 0.210459 0.345510
+vt 0.169574 0.118572
+vt 0.164356 0.103821
+vt 0.210731 0.077759
+vt 0.229913 0.727634
+vt 0.589956 0.115821
+vt 0.153468 0.300432
+vt 0.153526 0.122857
+vt 0.162374 0.730353
+vt 0.578472 0.119429
+vt 0.553653 0.120209
+vt 0.126070 0.725964
+vt 0.150890 0.726744
+vt 0.546510 0.159800
+vt 0.509384 0.119033
+vt 0.081800 0.727137
+vt 0.118929 0.686371
+vt 0.534072 0.185482
+vt 0.106492 0.660689
+vt 0.462352 0.161885
+vt 0.478174 0.145123
+vt 0.493641 0.175543
+vt 0.505521 0.150780
+vt 0.077939 0.695390
+vt 0.050592 0.701044
+vt 0.066060 0.670626
+vt 0.034770 0.684282
+vt 0.476706 0.124129
+vt 0.049122 0.722039
+vt 0.465324 0.131169
+vt 0.037741 0.714998
+vt 0.446348 0.149671
+vt 0.018765 0.696495
+vt 0.445483 0.184898
+vt 0.427581 0.175095
+vt 0.000000 0.671069
+vt 0.017903 0.661268
+vt 0.480167 0.198327
+vt 0.052588 0.647841
+vt 0.521714 0.207472
+vt 0.094135 0.638699
+vt 0.701979 0.120236
+vt 0.274400 0.725940
+vt 0.757541 0.138176
+vt 0.329963 0.708000
+vt 0.817327 0.117813
+vt 0.389751 0.728363
+vt 0.844767 0.126748
+vt 0.417191 0.719428
+vt 0.893893 0.126476
+vt 0.466319 0.719698
+vt 0.936543 0.115821
+vt 0.508970 0.730353
+vt 0.965717 0.128368
+vt 0.538144 0.717805
+vt 0.989276 0.166159
+vt 0.561701 0.680013
+vt 1.000000 0.175243
+vt 0.572425 0.670929
+vt 0.289028 0.269037
+vt 0.283878 0.263049
+vt 0.299187 0.258321
+vt 0.300964 0.267357
+vt 0.299421 0.165436
+vt 0.284101 0.160633
+vt 0.289287 0.154655
+vt 0.301244 0.156393
+vt 0.317793 0.260767
+vt 0.316733 0.267304
+vt 0.318078 0.163079
+vt 0.317052 0.156521
+vt 0.335398 0.269583
+vt 0.330421 0.276220
+vt 0.335777 0.154335
+vt 0.330824 0.147649
+vt 0.278552 0.277080
+vt 0.273734 0.272912
+vt 0.273975 0.150706
+vt 0.278818 0.146548
+vt 0.271078 0.306358
+vt 0.264864 0.305818
+vt 0.265194 0.117691
+vt 0.271427 0.117166
+vt 0.278613 0.324240
+vt 0.274006 0.327477
+vt 0.274436 0.095993
+vt 0.279049 0.099253
+vt 0.298062 0.342565
+vt 0.294660 0.349561
+vt 0.295240 0.073895
+vt 0.298634 0.080932
+vt 0.312476 0.342961
+vt 0.315033 0.350198
+vt 0.315702 0.073322
+vt 0.313108 0.080584
+vt 0.323281 0.337709
+vt 0.328696 0.344302
+vt 0.329405 0.079293
+vt 0.323940 0.085897
+vt 0.335361 0.313857
+vt 0.339396 0.315576
+vt 0.340031 0.108187
+vt 0.335968 0.109893
+vt 0.339920 0.298303
+vt 0.345292 0.298556
+vt 0.345869 0.125306
+vt 0.340471 0.125531
+vt 0.339277 0.286081
+vt 0.344398 0.284332
+vt 0.344895 0.139582
+vt 0.339764 0.137799
+vt 0.345671 0.260159
+vt 0.355483 0.280619
+vt 0.356003 0.143373
+vt 0.346021 0.163854
+vt 0.356162 0.297750
+vt 0.356783 0.126174
+vt 0.349494 0.319809
+vt 0.350195 0.103982
+vt 0.333524 0.354692
+vt 0.334295 0.068869
+vt 0.317323 0.364551
+vt 0.318050 0.058911
+vt 0.293154 0.361782
+vt 0.293765 0.061619
+vt 0.263750 0.335417
+vt 0.264168 0.087998
+vt 0.251373 0.309082
+vt 0.251676 0.114380
+vt 0.264926 0.265507
+vt 0.265122 0.158092
+vt 0.278030 0.255522
+vt 0.278212 0.168150
+vt 0.320744 0.246538
+vt 0.320956 0.177355
+vt 0.296570 0.247318
+vt 0.296748 0.176443
+vt 0.038845 0.211743
+vt 0.047440 0.211734
+vt 0.055230 0.211728
+vt 0.057303 0.228458
+vt 0.057278 0.194991
+vt 0.041287 0.229096
+vt 0.041253 0.194380
+vt 0.032564 0.220061
+vt 0.032546 0.203437
+vt 0.030743 0.211752
+vt 0.029931 0.223131
+vt 0.028053 0.211756
+vt 0.029906 0.200372
+vt 0.038587 0.233067
+vt 0.038544 0.190412
+vt 0.061533 0.231825
+vt 0.061505 0.191616
+vt 0.057382 0.211726
+vt 0.168191 0.258703
+vt 0.213958 0.246887
+vt 0.214040 0.176591
+vt 0.168236 0.164676
+vt 0.148297 0.258447
+vt 0.138777 0.299079
+vt 0.138791 0.124216
+vt 0.148319 0.164919
+vt 0.115455 0.259296
+vt 0.109657 0.296761
+vt 0.109611 0.126556
+vt 0.115440 0.164070
+vt 0.119233 0.228698
+vt 0.156540 0.233552
+vt 0.156556 0.189842
+vt 0.119230 0.194690
+vt 0.173998 0.244074
+vt 0.174035 0.179329
+vt 0.195860 0.238258
+vt 0.195909 0.185188
+vt 0.203534 0.211734
+vt 0.252997 0.211802
+vt 0.171285 0.225095
+vt 0.164455 0.211704
+vt 0.180017 0.211713
+vt 0.177113 0.227468
+vt 0.171300 0.198319
+vt 0.177134 0.195952
+vt 0.185539 0.227013
+vt 0.187516 0.221322
+vt 0.187531 0.202116
+vt 0.185563 0.196419
+vt 0.176585 0.232500
+vt 0.165993 0.229894
+vt 0.176611 0.190916
+vt 0.166011 0.193512
+vt 0.189406 0.230672
+vt 0.189438 0.192766
+vt 0.193574 0.221791
+vt 0.193592 0.201656
+vt 0.186479 0.211718
+vt 0.156919 0.211701
+vt 0.148476 0.211699
+vt 0.427853 0.115821
+vt 0.427581 0.104121
+vt 0.441185 0.104121
+vt 0.427581 0.011703
+vt 0.427581 0.000000
+vt 0.441181 0.011386
+vt 0.067509 0.234045
+vt 0.071465 0.211716
+vt 0.067479 0.189385
+vt 0.119764 0.211696
+vt 0.060932 0.261035
+vt 0.038121 0.261699
+vt 0.038025 0.161756
+vt 0.060860 0.162382
+vt 0.019864 0.255578
+vt 0.019760 0.167921
+vt 0.016617 0.242679
+vt 0.016537 0.180842
+vt 0.014466 0.211775
+vt 0.297831 0.211892
+vt 0.340508 0.212027
+vt 0.356498 0.241635
+vt 0.356742 0.182510
+vt 0.236517 0.317748
+vt 0.236802 0.105655
+vt 0.264789 0.363401
+vt 0.265286 0.059917
+vt 0.296951 0.385966
+vt 0.297650 0.037339
+vt 0.337996 0.385300
+vt 0.338890 0.038126
+vt 0.349401 0.368365
+vt 0.350300 0.055183
+vt 0.377282 0.319664
+vt 0.378129 0.104260
+vt 0.394788 0.292204
+vt 0.395576 0.131978
+vt 0.391029 0.270263
+vt 0.391643 0.154015
+vt 0.368661 0.212151
+vt 0.379482 0.228055
+vt 0.379686 0.196331
+vt 0.420379 0.261837
+vt 0.421104 0.162716
+vt 0.426533 0.298960
+vt 0.427581 0.125377
+vt 0.396664 0.342212
+vt 0.397734 0.081667
+vt 0.365156 0.387054
+vt 0.366203 0.036443
+vt 0.346744 0.416452
+vt 0.347768 0.006839
+vt 0.278009 0.423087
+vt 0.278714 0.000000
+vt 0.241964 0.376122
+vt 0.242399 0.047096
+vt 0.055563 0.291878
+vt 0.055443 0.131506
+vt 0.014495 0.288026
+vt 0.014318 0.135436
+vt 0.003828 0.279132
+vt 0.003650 0.144368
+vt 0.000113 0.248111
+vt 0.000000 0.175447
+vt 0.000000 0.211799
+vt 0.046962 0.798865
+vt 0.047306 0.784561
+vt 0.334495 0.786358
+vt 0.334204 0.800664
+vt 0.058429 0.773633
+vt 0.323868 0.774947
+vt 0.072992 0.774071
+vt 0.309301 0.774739
+vt 0.084403 0.784016
+vt 0.297459 0.784168
+vt 0.083417 0.800146
+vt 0.297728 0.800325
+vt 0.073091 0.810538
+vt 0.307582 0.811166
+vt 0.057505 0.810093
+vt 0.323173 0.811412
+vt 0.024988 0.807478
+vt 0.047717 0.829014
+vt 0.332112 0.830749
+vt 0.355774 0.810244
+vt 0.000000 0.817350
+vt 0.033121 0.852785
+vt 0.345638 0.855146
+vt 0.380299 0.821215
+vt 0.083391 0.855019
+vt 0.078555 0.829097
+vt 0.301299 0.829463
+vt 0.295318 0.855146
+vt 0.100718 0.807888
+vt 0.280100 0.807291
+vt 0.123146 0.821929
+vt 0.257070 0.820323
+vt 0.127501 0.768220
+vt 0.103229 0.776171
+vt 0.279000 0.775494
+vt 0.255105 0.766472
+vt 0.079351 0.756089
+vt 0.303746 0.756492
+vt 0.089008 0.730353
+vt 0.295241 0.730353
+vt 0.049398 0.755271
+vt 0.035422 0.733227
+vt 0.333706 0.757005
+vt 0.348646 0.735604
+vt 0.026877 0.776230
+vt 0.355274 0.778943
+vt 0.000000 0.770061
+vt 0.382398 0.773973
+vn 0.189764 -0.003571 0.981811
+vn 0.646809 -0.758202 0.082095
+vn 0.999573 -0.014496 -0.024445
+vn -0.999573 -0.014496 -0.024445
+vn -0.646809 -0.758202 0.082095
+vn -0.189764 -0.003571 0.981811
+vn -0.085788 -0.982971 0.162389
+vn 0.085788 -0.982971 0.162389
+vn -0.744835 -0.623768 0.236824
+vn 0.744835 -0.623768 0.236824
+vn -0.870968 -0.014710 0.491104
+vn 0.870968 -0.014710 0.491104
+vn -0.758354 0.606128 0.239692
+vn 0.758354 0.606128 0.239692
+vn -0.085788 0.982513 0.165105
+vn 0.085788 0.982513 0.165105
+vn 0.655141 0.750633 0.085574
+vn -0.655141 0.750633 0.085574
+vn -0.349284 -0.719932 0.599719
+vn -0.173681 0.215735 0.960845
+vn -0.809839 0.388287 0.439741
+vn 0.809839 0.388287 0.439741
+vn 0.173681 0.215735 0.960845
+vn 0.349284 -0.719932 0.599719
+vn 0.000000 0.794183 0.607654
+vn -0.508652 0.858119 -0.069887
+vn 0.000000 0.487075 0.873348
+vn 0.508652 0.858119 -0.069887
+vn 0.981414 -0.186682 0.043947
+vn 0.569811 -0.821711 0.007813
+vn 0.563463 -0.814570 0.137669
+vn -0.563463 -0.814570 0.137669
+vn -0.569811 -0.821711 0.007813
+vn -0.981414 -0.186682 0.043947
+vn 0.475845 -0.876247 0.075381
+vn 0.850520 -0.525529 -0.020692
+vn 0.876949 -0.163823 0.451766
+vn -0.876949 -0.163823 0.451766
+vn -0.850520 -0.525529 -0.020692
+vn -0.475845 -0.876247 0.075381
+vn 0.448286 -0.367870 -0.814661
+vn 0.530534 -0.539445 -0.653829
+vn 0.513077 -0.674673 -0.530595
+vn -0.513077 -0.674673 -0.530595
+vn -0.530534 -0.539445 -0.653829
+vn -0.448286 -0.367870 -0.814661
+vn 0.888180 -0.439955 -0.132389
+vn 0.588519 0.226966 0.775933
+vn 0.911527 -0.115268 0.394665
+vn -0.911527 -0.115268 0.394665
+vn -0.588519 0.226966 0.775933
+vn -0.888180 -0.439955 -0.132389
+vn 0.468886 -0.304727 0.829005
+vn 0.251564 0.260781 0.932005
+vn -0.003082 -0.330882 0.943632
+vn 0.003082 -0.330882 0.943632
+vn -0.251564 0.260781 0.932005
+vn -0.468886 -0.304727 0.829005
+vn 0.473067 0.578997 -0.664022
+vn 0.992462 0.028626 -0.118900
+vn 0.459975 -0.380261 -0.802362
+vn -0.459975 -0.380261 -0.802362
+vn -0.992462 0.028626 -0.118900
+vn -0.473067 0.578997 -0.664022
+vn -0.059908 -0.804712 -0.590594
+vn -0.346141 -0.637287 -0.688498
+vn -0.330546 -0.943236 0.031281
+vn -0.073672 -0.594989 0.800317
+vn 0.330546 -0.943236 0.031281
+vn 0.346141 -0.637287 -0.688498
+vn 0.059908 -0.804712 -0.590594
+vn 0.073672 -0.594989 0.800317
+vn 0.593738 0.595264 -0.541368
+vn -0.626057 -0.002686 -0.779748
+vn 0.626057 -0.002686 -0.779748
+vn -0.593738 0.595264 -0.541368
+vn 0.127689 0.703757 0.698843
+vn -0.713828 0.382183 0.586810
+vn 0.713828 0.382183 0.586810
+vn -0.127689 0.703757 0.698843
+vn 0.378063 0.560045 -0.737144
+vn 0.036805 -0.708457 -0.704764
+vn -0.378063 0.560045 -0.737144
+vn -0.036805 -0.708457 -0.704764
+vn -0.031556 0.838710 0.543626
+vn 0.031556 0.838710 0.543626
+vn -0.361156 0.848689 0.386303
+vn 0.361156 0.848689 0.386303
+vn -0.716392 0.204474 0.667043
+vn 0.716392 0.204474 0.667043
+vn -0.662038 -0.413770 0.624866
+vn 0.662038 -0.413770 0.624866
+vn -0.530229 -0.655751 0.537370
+vn 0.530229 -0.655751 0.537370
+vn -0.437483 0.001221 0.899197
+vn 0.550981 -0.138096 0.822993
+vn 0.437483 0.001221 0.899197
+vn -0.550981 -0.138096 0.822993
+vn -0.315958 -0.102298 0.943205
+vn 0.608539 0.296121 0.736167
+vn -0.608539 0.296121 0.736167
+vn 0.315958 -0.102298 0.943205
+vn -0.445479 -0.088778 0.890866
+vn -0.257698 0.600024 0.757317
+vn 0.257698 0.600024 0.757317
+vn 0.445479 -0.088778 0.890866
+vn -0.327799 0.169927 0.929319
+vn 0.041780 0.927213 0.372112
+vn 0.327799 0.169927 0.929319
+vn -0.041780 0.927213 0.372112
+vn -0.277932 0.260201 0.924680
+vn -0.750725 0.111545 0.651112
+vn 0.750725 0.111545 0.651112
+vn 0.277932 0.260201 0.924680
+vn -0.437910 -0.293985 0.849574
+vn -0.183782 0.036836 0.982269
+vn -0.554216 0.387219 0.736808
+vn -0.814325 0.253426 0.522111
+vn 0.554216 0.387219 0.736808
+vn 0.183782 0.036836 0.982269
+vn 0.437910 -0.293985 0.849574
+vn 0.814325 0.253426 0.522111
+vn -0.326670 -0.001617 0.945128
+vn -0.704337 -0.526872 0.475692
+vn 0.704337 -0.526872 0.475692
+vn 0.326670 -0.001617 0.945128
+vn -0.308786 0.134617 0.941527
+vn -0.629170 -0.371441 0.682730
+vn 0.629170 -0.371441 0.682730
+vn 0.308786 0.134617 0.941527
+vn 0.146184 0.948637 0.280465
+vn -0.137516 0.905820 0.400708
+vn 0.137516 0.905820 0.400708
+vn -0.146184 0.948637 0.280465
+vn 0.723746 0.690023 -0.005219
+vn -0.723746 0.690023 -0.005219
+vn 0.994690 -0.078005 0.067019
+vn -0.994690 -0.078005 0.067019
+vn 0.200934 -0.758141 0.620350
+vn -0.200934 -0.758141 0.620350
+vn -0.541246 -0.672658 0.504501
+vn 0.541246 -0.672658 0.504501
+vn -0.690054 -0.553209 0.466628
+vn 0.690054 -0.553209 0.466628
+vn -0.464003 0.686666 0.559557
+vn 0.464003 0.686666 0.559557
+vn -0.827448 -0.135899 0.544786
+vn 0.827448 -0.135899 0.544786
+vn -0.466231 0.808863 0.358196
+vn 0.466231 0.808863 0.358196
+vn -0.743980 -0.022919 0.667776
+vn 0.743980 -0.022919 0.667776
+vn -0.711295 -0.638325 0.294137
+vn 0.711295 -0.638325 0.294137
+vn -0.709769 -0.501999 0.494125
+vn 0.709769 -0.501999 0.494125
+vn -0.818903 -0.425520 0.385113
+vn -0.992523 -0.071444 -0.098758
+vn 0.992523 -0.071444 -0.098758
+vn 0.818903 -0.425520 0.385113
+vn -0.439192 -0.273568 0.855708
+vn 0.439192 -0.273568 0.855708
+vn -0.414686 -0.059877 0.907956
+vn 0.414686 -0.059877 0.907956
+vn -0.341563 0.452132 0.823939
+vn 0.341563 0.452132 0.823939
+vn -0.724509 -0.684927 0.076632
+vn -0.987548 -0.123020 0.097995
+vn 0.987548 -0.123020 0.097995
+vn 0.724509 -0.684927 0.076632
+vn -0.572741 -0.088443 0.814936
+vn 0.572741 -0.088443 0.814936
+vn -0.291818 -0.152104 0.944273
+vn 0.291818 -0.152104 0.944273
+vn 0.239662 -0.128605 0.962279
+vn -0.239662 -0.128605 0.962279
+vn 0.187017 0.370678 0.909696
+vn -0.187017 0.370678 0.909696
+vn -0.455794 0.423170 0.783044
+vn 0.455794 0.423170 0.783044
+vn -0.543504 -0.813379 -0.207343
+vn -0.560045 -0.814417 -0.151738
+vn 0.560045 -0.814417 -0.151738
+vn 0.543504 -0.813379 -0.207343
+vn -0.615375 -0.087649 -0.783319
+vn -0.447310 0.229530 -0.864406
+vn 0.447310 0.229530 -0.864406
+vn 0.615375 -0.087649 -0.783319
+vn -0.547166 -0.832179 -0.089785
+vn 0.547166 -0.832179 -0.089785
+vn -0.873135 0.486984 -0.020264
+vn -0.865352 0.331217 -0.376049
+vn 0.865352 0.331217 -0.376049
+vn 0.873135 0.486984 -0.020264
+vn -0.748741 0.518387 0.413038
+vn 0.748741 0.518387 0.413038
+vn -0.766167 0.634816 0.099612
+vn 0.766167 0.634816 0.099612
+vn -0.953185 -0.248299 -0.172430
+vn -0.665639 0.602496 -0.440321
+vn 0.665639 0.602496 -0.440321
+vn 0.953185 -0.248299 -0.172430
+vn -0.322642 0.847713 0.421033
+vn -0.188574 0.788934 -0.584765
+vn 0.188574 0.788934 -0.584765
+vn 0.322642 0.847713 0.421033
+vn -0.239784 0.745262 -0.622120
+vn 0.494247 0.520585 -0.696158
+vn -0.494247 0.520585 -0.696158
+vn 0.239784 0.745262 -0.622120
+vn -0.480697 0.731223 0.483932
+vn 0.000000 0.758690 0.651418
+vn 0.480697 0.731223 0.483932
+vn -0.489242 0.762963 0.422498
+vn -0.363109 0.908567 -0.206458
+vn 0.363109 0.908567 -0.206458
+vn 0.489242 0.762963 0.422498
+vn -0.645039 0.694540 0.318613
+vn 0.645039 0.694540 0.318613
+vn -0.492843 0.869015 0.043062
+vn -0.679434 0.728965 -0.083468
+vn 0.492843 0.869015 0.043062
+vn 0.679434 0.728965 -0.083468
+vn -0.391736 0.826014 -0.405225
+vn -0.644398 0.527207 -0.553880
+vn 0.391736 0.826014 -0.405225
+vn 0.644398 0.527207 -0.553880
+vn 0.000000 0.800714 -0.599017
+vn 0.000000 0.330729 -0.943693
+vn 0.000000 0.999664 0.025636
+vn 0.000000 -0.271462 -0.962432
+vn -0.685293 -0.583148 -0.436232
+vn -0.907224 0.252602 -0.336253
+vn 0.907224 0.252602 -0.336253
+vn 0.685293 -0.583148 -0.436232
+vn 0.000000 -0.984344 -0.176214
+vn 0.000000 -0.736351 -0.676565
+vn 0.000000 -0.948759 -0.315928
+vn 0.000000 -0.648244 -0.761406
+vn -0.317362 -0.946959 -0.049959
+vn -0.838282 -0.408155 0.361461
+vn 0.838282 -0.408155 0.361461
+vn 0.317362 -0.946959 -0.049959
+vn -0.939360 0.325999 0.106113
+vn 0.939360 0.325999 0.106113
+vn -0.930631 0.340159 0.134770
+vn -0.960143 0.231361 0.156774
+vn 0.960143 0.231361 0.156774
+vn 0.930631 0.340159 0.134770
+vn -0.812555 -0.001068 -0.582842
+vn -0.979583 0.093387 0.177862
+vn 0.979583 0.093387 0.177862
+vn 0.812555 -0.001068 -0.582842
+vn -0.272530 -0.301157 -0.913785
+vn 0.272530 -0.301157 -0.913785
+vn -0.090915 -0.776330 -0.623707
+vn -0.506851 -0.488144 -0.710471
+vn -0.142521 -0.147282 -0.978759
+vn -0.637257 0.093326 -0.764946
+vn 0.637257 0.093326 -0.764946
+vn 0.506851 -0.488144 -0.710471
+vn 0.142521 -0.147282 -0.978759
+vn 0.090915 -0.776330 -0.623707
+vn -0.937284 -0.254250 0.238350
+vn 0.937284 -0.254250 0.238350
+vn -0.430525 -0.895260 0.114597
+vn 0.430525 -0.895260 0.114597
+vn -0.158391 -0.974822 0.156774
+vn 0.158391 -0.974822 0.156774
+vn 0.000000 -0.915860 -0.401440
+vn 0.000000 -0.946440 0.322855
+vn 0.000000 -0.336802 -0.941557
+vn 0.000000 -0.175726 -0.984436
+vn -0.599231 -0.773980 0.204566
+vn 0.599231 -0.773980 0.204566
+vn -0.890988 -0.423261 -0.164037
+vn 0.890988 -0.423261 -0.164037
+vn -0.851985 0.219275 0.475387
+vn 0.851985 0.219275 0.475387
+vn -0.509171 0.852229 0.119999
+vn 0.509171 0.852229 0.119999
+vn -0.610431 0.759148 0.225867
+vn 0.610431 0.759148 0.225867
+vn -0.182470 0.981780 0.052492
+vn 0.182470 0.981780 0.052492
+vn 0.520371 0.770348 0.368389
+vn -0.520371 0.770348 0.368389
+vn 0.852718 0.504257 0.136204
+vn -0.852718 0.504257 0.136204
+vn 0.000000 0.970214 0.242164
+vn -0.709647 0.261818 0.654042
+vn 0.067293 -0.064272 0.995636
+vn -0.246590 -0.034089 0.968505
+vn -0.809717 -0.010224 0.586688
+vn 0.246590 -0.034089 0.968505
+vn -0.067293 -0.064272 0.995636
+vn 0.709647 0.261818 0.654042
+vn 0.809717 -0.010224 0.586688
+vn -0.465835 -0.080325 0.881191
+vn -0.737114 -0.244179 0.630085
+vn 0.465835 -0.080325 0.881191
+vn 0.737114 -0.244179 0.630085
+vn -0.211951 -0.085971 0.973479
+vn -0.367504 -0.376476 0.850398
+vn 0.211951 -0.085971 0.973479
+vn 0.367504 -0.376476 0.850398
+vn -0.430280 0.556597 0.710624
+vn -0.020081 -0.072939 0.997131
+vn 0.020081 -0.072939 0.997131
+vn 0.430280 0.556597 0.710624
+vn -0.090976 0.597339 0.796777
+vn -0.187933 -0.091617 0.977874
+vn 0.187933 -0.091617 0.977874
+vn 0.090976 0.597339 0.796777
+vn 0.165929 0.609363 0.775292
+vn -0.203314 0.092532 0.974700
+vn 0.203314 0.092532 0.974700
+vn -0.165929 0.609363 0.775292
+vn 0.269295 0.241676 0.932218
+vn -0.314219 -0.132420 0.940062
+vn 0.314219 -0.132420 0.940062
+vn -0.269295 0.241676 0.932218
+vn 0.420057 -0.118992 0.899625
+vn -0.119755 -0.070925 0.990234
+vn 0.119755 -0.070925 0.990234
+vn -0.420057 -0.118992 0.899625
+vn 0.226142 -0.606586 0.762139
+vn -0.320841 0.040712 0.946226
+vn 0.320841 0.040712 0.946226
+vn -0.226142 -0.606586 0.762139
+vn 0.232612 -0.746055 0.623890
+vn -0.074557 -0.391644 0.917081
+vn 0.074557 -0.391644 0.917081
+vn -0.232612 -0.746055 0.623890
+vn -0.121250 -0.313883 0.941679
+vn -0.146702 -0.035707 0.988525
+vn 0.146702 -0.035707 0.988525
+vn 0.121250 -0.313883 0.941679
+vn -0.216834 -0.273721 0.937010
+vn -0.187445 0.001160 0.982269
+vn 0.187445 0.001160 0.982269
+vn 0.216834 -0.273721 0.937010
+vn -0.303018 -0.201941 0.931333
+vn -0.253090 -0.161809 0.953795
+vn 0.253090 -0.161809 0.953795
+vn 0.303018 -0.201941 0.931333
+vn -0.140110 -0.091189 0.985900
+vn 0.140110 -0.091189 0.985900
+vn -0.237983 0.050172 0.969939
+vn 0.237983 0.050172 0.969939
+vn -0.312662 -0.237922 0.919553
+vn 0.312662 -0.237922 0.919553
+vn -0.373791 -0.105197 0.921506
+vn 0.373791 -0.105197 0.921506
+vn -0.470595 -0.164647 0.866817
+vn 0.470595 -0.164647 0.866817
+vn -0.439222 -0.376141 0.815821
+vn 0.439222 -0.376141 0.815821
+vn -0.219611 -0.540635 0.812037
+vn 0.219611 -0.540635 0.812037
+vn 0.166967 -0.374828 0.911893
+vn -0.166967 -0.374828 0.911893
+vn 0.201849 -0.277596 0.939238
+vn -0.201849 -0.277596 0.939238
+vn 0.001160 -0.165563 0.986175
+vn -0.001160 -0.165563 0.986175
+vn 0.292917 -0.174108 0.940123
+vn -0.292917 -0.174108 0.940123
+vn 0.000000 0.732200 0.681051
+vn 0.000000 -0.603626 0.797266
+vn 0.000000 -0.971740 0.235908
+vn 0.131779 -0.608295 0.782678
+vn -0.131779 -0.608295 0.782678
+vn 0.759117 0.068392 0.647298
+vn -0.759117 0.068392 0.647298
+vn 0.405957 0.643605 0.648793
+vn -0.405957 0.643605 0.648793
+vn 0.000000 0.598346 0.801202
+vn 0.073855 -0.330546 0.940855
+vn 0.000000 -0.124516 0.992187
+vn -0.073855 -0.330546 0.940855
+vn -0.085116 -0.339244 0.936827
+vn 0.085116 -0.339244 0.936827
+vn -0.141881 -0.148350 0.978698
+vn 0.141881 -0.148350 0.978698
+vn 0.000000 -0.482803 0.875698
+vn -0.692984 -0.001343 0.720908
+vn -0.095523 -0.326090 0.940489
+vn 0.095523 -0.326090 0.940489
+vn 0.692984 -0.001343 0.720908
+vn -0.646687 0.162603 0.745201
+vn 0.646687 0.162603 0.745201
+vn -0.593463 0.121860 0.795556
+vn 0.593463 0.121860 0.795556
+vn -0.124363 0.009674 0.992187
+vn -0.509995 -0.457717 0.728233
+vn 0.509995 -0.457717 0.728233
+vn 0.124363 0.009674 0.992187
+vn -0.972137 -0.167882 0.163549
+vn 0.972137 -0.167882 0.163549
+vn -0.715995 0.572161 0.399945
+vn 0.715995 0.572161 0.399945
+vn 0.000000 0.430525 0.902554
+vn 0.000000 0.010865 0.999939
+vn -0.221839 -0.606037 0.763848
+vn 0.000000 -0.492935 0.870022
+vn 0.000000 0.010315 0.999939
+vn -0.294320 -0.184484 0.937712
+vn 0.221839 -0.606037 0.763848
+vn 0.294320 -0.184484 0.937712
+vn -0.396924 0.534989 0.745781
+vn 0.247780 0.568224 0.784661
+vn -0.247780 0.568224 0.784661
+vn 0.396924 0.534989 0.745781
+vn -0.868221 -0.261330 0.421735
+vn -0.555986 -0.690695 0.462355
+vn 0.868221 -0.261330 0.421735
+vn 0.555986 -0.690695 0.462355
+vn -0.753075 0.649892 0.102298
+vn 0.753075 0.649892 0.102298
+vn 0.194189 0.935697 0.294473
+vn -0.194189 0.935697 0.294473
+vn 0.000000 0.788965 0.614399
+vn 0.000000 -0.888638 0.458571
+vn 0.000000 -0.336772 0.941557
+vn 0.000000 -0.251991 0.967711
+vn -0.188360 -0.040132 0.981262
+vn 0.000000 -0.032899 0.999451
+vn 0.188360 -0.040132 0.981262
+vn 0.000000 0.000000 1.000000
+vn -0.572039 -0.018708 0.820002
+vn -0.536332 -0.212409 0.816828
+vn 0.536332 -0.212409 0.816828
+vn 0.572039 -0.018708 0.820002
+vn -0.357707 -0.638325 0.681570
+vn 0.357707 -0.638325 0.681570
+vn -0.154302 -0.754112 0.638325
+vn 0.154302 -0.754112 0.638325
+vn 0.000000 -0.743461 0.668752
+vn 0.000000 -0.189123 0.981933
+vn 0.000000 -0.114475 0.993408
+vn 0.001404 -0.055635 0.998444
+vn -0.001404 -0.055635 0.998444
+vn -0.336283 -0.512833 0.789850
+vn 0.336283 -0.512833 0.789850
+vn -0.454543 -0.337077 0.824458
+vn 0.454543 -0.337077 0.824458
+vn -0.543474 -0.308603 0.780602
+vn 0.543474 -0.308603 0.780602
+vn -0.387158 -0.187811 0.902646
+vn 0.387158 -0.187811 0.902646
+vn -0.430647 -0.144902 0.890805
+vn 0.430647 -0.144902 0.890805
+vn -0.234016 -0.120548 0.964721
+vn 0.234016 -0.120548 0.964721
+vn -0.263833 0.168798 0.949675
+vn 0.263833 0.168798 0.949675
+vn 0.196722 0.141881 0.970122
+vn -0.196722 0.141881 0.970122
+vn -0.906766 -0.008332 0.421522
+vn -0.744133 -0.640919 0.188269
+vn 0.744133 -0.640919 0.188269
+vn 0.906766 -0.008332 0.421522
+vn -0.044191 -0.974395 0.220313
+vn 0.044191 -0.974395 0.220313
+vn 0.639943 -0.761498 0.102786
+vn -0.639943 -0.761498 0.102786
+vn 0.955504 -0.011444 0.294717
+vn -0.955504 -0.011444 0.294717
+vn 0.649678 0.754387 0.093570
+vn -0.649678 0.754387 0.093570
+vn -0.037049 0.978881 0.200903
+vn 0.037049 0.978881 0.200903
+vn -0.752342 0.635395 0.173742
+vn 0.752342 0.635395 0.173742
+vn -0.811792 -0.002777 0.583880
+vn -0.596942 0.486770 0.637684
+vn 0.596942 0.486770 0.637684
+vn 0.811792 -0.002777 0.583880
+vn -0.868221 -0.005829 0.496109
+vn -0.719504 0.473006 0.508469
+vn 0.719504 0.473006 0.508469
+vn 0.868221 -0.005829 0.496109
+vn -0.204260 0.828761 0.520951
+vn -0.095767 0.717277 0.690146
+vn 0.095767 0.717277 0.690146
+vn 0.204260 0.828761 0.520951
+vn 0.451704 0.459883 0.764458
+vn -0.451704 0.459883 0.764458
+vn 0.450362 0.693899 0.561815
+vn -0.450362 0.693899 0.561815
+vn 0.805536 0.109409 0.582324
+vn 0.691488 -0.074099 0.718558
+vn -0.691488 -0.074099 0.718558
+vn -0.805536 0.109409 0.582324
+vn 0.386212 -0.474685 0.790857
+vn -0.386212 -0.474685 0.790857
+vn 0.557756 -0.629109 0.541368
+vn -0.557756 -0.629109 0.541368
+vn -0.091159 -0.723716 0.684011
+vn -0.199744 -0.858058 0.473067
+vn 0.091159 -0.723716 0.684011
+vn 0.199744 -0.858058 0.473067
+vn -0.597949 -0.496475 0.629231
+vn 0.597949 -0.496475 0.629231
+vn -0.723197 -0.488907 0.487747
+vn 0.723197 -0.488907 0.487747
+usemtl Material_ray.png
+s 1
+f 61/1/1 65/2/2 49/3/3
+f 50/4/4 66/5/5 62/6/6
+f 63/7/7 65/2/2 61/1/1
+f 62/6/6 66/5/5 64/8/8
+f 61/1/1 59/9/9 63/7/7
+f 64/8/8 60/10/10 62/6/6
+f 61/1/1 57/11/11 59/9/9
+f 60/10/10 58/12/12 62/6/6
+f 61/1/1 55/13/13 57/11/11
+f 58/12/12 56/14/14 62/6/6
+f 61/1/1 53/15/15 55/13/13
+f 56/14/14 54/16/16 62/6/6
+f 61/1/1 51/17/17 53/15/15
+f 54/16/16 52/18/18 62/6/6
+f 61/1/1 49/3/3 51/17/17
+f 52/18/18 50/4/4 62/6/6
+f 225/19/19 229/20/20 227/21/21
+f 228/22/22 230/23/23 226/24/24
+f 73/25/25 284/26/26 74/27/27
+f 74/28/27 285/29/28 73/30/25
+f 342/31/29 348/32/30 384/33/31
+f 385/34/32 349/35/33 343/36/34
+f 300/37/35 346/38/36 344/39/37
+f 345/40/38 347/41/39 301/42/40
+f 324/43/41 380/44/42 352/45/43
+f 353/46/44 381/47/45 325/48/46
+f 442/49/47 444/50/48 446/51/49
+f 447/52/50 445/53/51 443/54/52
+f 464/55/53 492/56/54 466/57/55
+f 467/58/56 493/59/57 465/60/58
+f 496/61/59 498/62/60 500/63/61
+f 501/64/62 499/65/63 497/66/64
+f 505/67/65 323/68/66 321/69/67
+f 505/67/65 321/69/67 391/70/68
+f 320/71/69 322/72/70 504/73/71
+f 320/71/69 504/73/71 390/74/72
+f 505/67/65 507/75/73 315/76/74
+f 505/67/65 315/76/74 323/68/66
+f 314/77/75 506/78/76 504/73/71
+f 314/77/75 504/73/71 322/72/70
+f 389/79/77 383/80/78 507/75/73
+f 383/80/78 315/76/74 507/75/73
+f 314/77/75 382/81/79 506/78/76
+f 382/81/79 388/82/80 506/78/76
+f 501/64/62 497/66/64 495/83/81
+f 501/64/62 495/83/81 503/84/82
+f 494/85/83 496/61/59 500/63/61
+f 494/85/83 500/63/61 502/86/84
+f 505/67/65 503/84/82 507/75/73
+f 503/84/82 495/83/81 507/75/73
+f 494/85/83 502/86/84 506/78/76
+f 502/86/84 504/73/71 506/78/76
+f 495/83/81 401/87/85 507/75/73
+f 401/87/85 389/79/77 507/75/73
+f 388/82/80 400/88/86 506/78/76
+f 400/88/86 494/85/83 506/78/76
+f 497/66/64 399/89/87 495/83/81
+f 399/89/87 401/87/85 495/83/81
+f 400/88/86 398/90/88 494/85/83
+f 398/90/88 496/61/59 494/85/83
+f 499/65/63 397/91/89 497/66/64
+f 397/91/89 399/89/87 497/66/64
+f 398/90/88 396/92/90 496/61/59
+f 396/92/90 498/62/60 496/61/59
+f 501/64/62 395/93/91 499/65/63
+f 395/93/91 397/91/89 499/65/63
+f 396/92/90 394/94/92 498/62/60
+f 394/94/92 500/63/61 498/62/60
+f 503/84/82 393/95/93 395/93/91
+f 503/84/82 395/93/91 501/64/62
+f 394/94/92 392/96/94 502/86/84
+f 394/94/92 502/86/84 500/63/61
+f 505/67/65 391/70/68 393/95/93
+f 505/67/65 393/95/93 503/84/82
+f 392/96/94 390/74/72 504/73/71
+f 392/96/94 504/73/71 502/86/84
+f 491/97/95 493/59/57 467/58/56
+f 491/97/95 467/58/56 469/98/96
+f 466/57/55 492/56/54 490/99/97
+f 466/57/55 490/99/97 468/100/98
+f 489/101/99 491/97/95 471/102/100
+f 491/97/95 469/98/96 471/102/100
+f 468/100/98 490/99/97 470/103/101
+f 490/99/97 488/104/102 470/103/101
+f 483/105/103 489/101/99 473/106/104
+f 489/101/99 471/102/100 473/106/104
+f 470/103/101 488/104/102 472/107/105
+f 488/104/102 482/108/106 472/107/105
+f 481/109/107 483/105/103 473/106/104
+f 481/109/107 473/106/104 475/110/108
+f 472/107/105 482/108/106 480/111/109
+f 472/107/105 480/111/109 474/112/110
+f 481/109/107 475/110/108 457/113/111
+f 475/110/108 455/114/112 457/113/111
+f 454/115/113 474/112/110 456/116/114
+f 474/112/110 480/111/109 456/116/114
+f 463/117/115 479/118/116 459/119/117
+f 463/117/115 459/119/117 461/120/118
+f 458/121/119 478/122/120 462/123/121
+f 458/121/119 462/123/121 460/124/122
+f 479/118/116 463/117/115 485/125/123
+f 463/117/115 453/126/124 485/125/123
+f 452/127/125 462/123/121 484/128/126
+f 462/123/121 478/122/120 484/128/126
+f 487/129/127 485/125/123 477/130/128
+f 485/125/123 453/126/124 477/130/128
+f 452/127/125 484/128/126 476/131/129
+f 484/128/126 486/132/130 476/131/129
+f 487/129/127 477/130/128 465/60/58
+f 487/129/127 465/60/58 493/59/57
+f 464/55/53 476/131/129 486/132/130
+f 464/55/53 486/132/130 492/56/54
+f 491/97/95 489/101/99 493/59/57
+f 489/101/99 487/129/127 493/59/57
+f 486/132/130 488/104/102 492/56/54
+f 488/104/102 490/99/97 492/56/54
+f 489/101/99 483/105/103 485/125/123
+f 489/101/99 485/125/123 487/129/127
+f 484/128/126 482/108/106 488/104/102
+f 484/128/126 488/104/102 486/132/130
+f 483/105/103 481/109/107 485/125/123
+f 481/109/107 479/118/116 485/125/123
+f 478/122/120 480/111/109 484/128/126
+f 480/111/109 482/108/106 484/128/126
+f 481/109/107 457/113/111 479/118/116
+f 457/113/111 459/119/117 479/118/116
+f 458/121/119 456/116/114 478/122/120
+f 456/116/114 480/111/109 478/122/120
+f 473/106/104 421/133/131 475/110/108
+f 421/133/131 419/134/132 475/110/108
+f 418/135/133 420/136/134 474/112/110
+f 420/136/134 472/107/105 474/112/110
+f 471/102/100 423/137/135 473/106/104
+f 423/137/135 421/133/131 473/106/104
+f 420/136/134 422/138/136 472/107/105
+f 422/138/136 470/103/101 472/107/105
+f 469/98/96 425/139/137 471/102/100
+f 425/139/137 423/137/135 471/102/100
+f 422/138/136 424/140/138 470/103/101
+f 424/140/138 468/100/98 470/103/101
+f 467/58/56 427/141/139 425/139/137
+f 467/58/56 425/139/137 469/98/96
+f 424/140/138 426/142/140 466/57/55
+f 424/140/138 466/57/55 468/100/98
+f 465/60/58 429/143/141 427/141/139
+f 465/60/58 427/141/139 467/58/56
+f 426/142/140 428/144/142 464/55/53
+f 426/142/140 464/55/53 466/57/55
+f 477/130/128 417/145/143 429/143/141
+f 477/130/128 429/143/141 465/60/58
+f 428/144/142 416/146/144 476/131/129
+f 428/144/142 476/131/129 464/55/53
+f 475/110/108 419/134/132 441/147/145
+f 475/110/108 441/147/145 455/114/112
+f 440/148/146 418/135/133 474/112/110
+f 440/148/146 474/112/110 454/115/113
+f 455/114/112 441/147/145 439/149/147
+f 455/114/112 439/149/147 457/113/111
+f 438/150/148 440/148/146 454/115/113
+f 438/150/148 454/115/113 456/116/114
+f 457/113/111 439/149/147 459/119/117
+f 439/149/147 437/151/149 459/119/117
+f 436/152/150 438/150/148 458/121/119
+f 438/150/148 456/116/114 458/121/119
+f 459/119/117 437/151/149 461/120/118
+f 437/151/149 435/153/151 461/120/118
+f 434/154/152 436/152/150 460/124/122
+f 436/152/150 458/121/119 460/124/122
+f 461/120/118 435/153/151 433/155/153
+f 461/120/118 433/155/153 463/117/115
+f 432/156/154 434/154/152 460/124/122
+f 432/156/154 460/124/122 462/123/121
+f 463/117/115 433/155/153 453/126/124
+f 433/155/153 451/157/155 453/126/124
+f 450/158/156 432/156/154 452/127/125
+f 432/156/154 462/123/121 452/127/125
+f 453/126/124 451/157/155 417/145/143
+f 453/126/124 417/145/143 477/130/128
+f 416/146/144 450/158/156 452/127/125
+f 416/146/144 452/127/125 476/131/129
+f 447/52/50 443/54/52 449/159/157
+f 443/54/52 313/160/158 449/159/157
+f 312/161/159 442/49/47 448/162/160
+f 442/49/47 446/51/49 448/162/160
+f 431/163/161 449/159/157 383/80/78
+f 449/159/157 313/160/158 383/80/78
+f 312/161/159 448/162/160 382/164/79
+f 448/162/160 430/165/162 382/164/79
+f 451/157/155 431/163/161 417/145/143
+f 431/163/161 415/166/163 417/145/143
+f 414/167/164 430/165/162 416/146/144
+f 430/165/162 450/158/156 416/146/144
+f 433/155/153 449/159/157 451/157/155
+f 449/159/157 431/163/161 451/157/155
+f 430/165/162 448/162/160 450/158/156
+f 448/162/160 432/156/154 450/158/156
+f 447/52/50 449/159/157 435/153/151
+f 449/159/157 433/155/153 435/153/151
+f 432/156/154 448/162/160 434/154/152
+f 448/162/160 446/51/49 434/154/152
+f 439/149/147 447/52/50 435/153/151
+f 439/149/147 435/153/151 437/151/149
+f 434/154/152 446/51/49 438/150/148
+f 434/154/152 438/150/148 436/152/150
+f 445/53/51 447/52/50 441/147/145
+f 447/52/50 439/149/147 441/147/145
+f 438/150/148 446/51/49 440/148/146
+f 446/51/49 444/50/48 440/148/146
+f 441/147/145 419/134/132 413/168/165
+f 441/147/145 413/168/165 445/53/51
+f 412/169/166 418/135/133 440/148/146
+f 412/169/166 440/148/146 444/50/48
+f 415/166/163 431/163/161 383/80/78
+f 415/166/163 383/80/78 389/79/77
+f 382/164/79 430/165/162 414/167/164
+f 382/164/79 414/167/164 388/170/80
+f 443/171/52 319/172/167 311/173/168
+f 443/171/52 311/173/168 313/174/158
+f 310/175/169 318/176/170 442/177/47
+f 310/175/169 442/177/47 312/178/159
+f 413/168/165 391/179/68 445/53/51
+f 391/179/68 321/180/67 445/53/51
+f 320/181/69 390/182/72 444/50/48
+f 390/182/72 412/169/166 444/50/48
+f 445/53/51 321/180/67 443/54/52
+f 321/183/67 319/172/167 443/171/52
+f 318/176/170 320/184/69 442/177/47
+f 320/181/69 444/50/48 442/49/47
+f 417/145/143 415/166/163 403/185/171
+f 417/145/143 403/185/171 429/143/141
+f 402/186/172 414/167/164 416/146/144
+f 402/186/172 416/146/144 428/144/142
+f 427/141/139 429/143/141 405/187/173
+f 429/143/141 403/185/171 405/187/173
+f 402/186/172 428/144/142 404/188/174
+f 428/144/142 426/142/140 404/188/174
+f 425/139/137 427/141/139 407/189/175
+f 427/141/139 405/187/173 407/189/175
+f 404/188/174 426/142/140 406/190/176
+f 426/142/140 424/140/138 406/190/176
+f 423/137/135 425/139/137 409/191/177
+f 425/139/137 407/189/175 409/191/177
+f 406/190/176 424/140/138 408/192/178
+f 424/140/138 422/138/136 408/192/178
+f 421/133/131 423/137/135 409/191/177
+f 421/133/131 409/191/177 411/193/179
+f 408/192/178 422/138/136 420/136/134
+f 408/192/178 420/136/134 410/194/180
+f 419/134/132 421/133/131 411/193/179
+f 419/134/132 411/193/179 413/168/165
+f 410/194/180 420/136/134 418/135/133
+f 410/194/180 418/135/133 412/169/166
+f 413/168/165 411/193/179 393/195/93
+f 413/168/165 393/195/93 391/179/68
+f 392/196/94 410/194/180 412/169/166
+f 392/196/94 412/169/166 390/182/72
+f 411/193/179 409/191/177 393/195/93
+f 409/191/177 395/197/91 393/195/93
+f 394/198/92 408/192/178 392/196/94
+f 408/192/178 410/194/180 392/196/94
+f 409/191/177 407/189/175 395/197/91
+f 407/189/175 397/199/89 395/197/91
+f 396/200/90 406/190/176 394/198/92
+f 406/190/176 408/192/178 394/198/92
+f 407/189/175 405/187/173 397/199/89
+f 405/187/173 399/89/87 397/199/89
+f 398/201/88 404/188/174 396/200/90
+f 404/188/174 406/190/176 396/200/90
+f 405/187/173 403/185/171 401/87/85
+f 405/187/173 401/87/85 399/89/87
+f 400/202/86 402/186/172 404/188/174
+f 400/202/86 404/188/174 398/201/88
+f 415/166/163 389/79/77 403/185/171
+f 389/79/77 401/87/85 403/185/171
+f 400/202/86 388/170/80 402/186/172
+f 388/170/80 414/167/164 402/186/172
+f 381/47/45 353/46/44 387/203/181
+f 353/46/44 351/204/182 387/203/181
+f 350/205/183 352/45/43 386/206/184
+f 352/45/43 380/44/42 386/206/184
+f 381/47/45 387/203/181 323/207/66
+f 387/203/181 321/183/67 323/207/66
+f 320/184/69 386/206/184 322/208/70
+f 386/206/184 380/44/42 322/208/70
+f 381/47/45 379/209/185 325/48/46
+f 379/209/185 317/210/186 325/48/46
+f 316/211/187 378/212/188 324/43/41
+f 378/212/188 380/44/42 324/43/41
+f 381/47/45 323/207/66 379/209/185
+f 323/207/66 315/213/74 379/209/185
+f 314/214/75 322/208/70 378/212/188
+f 322/208/70 380/44/42 378/212/188
+f 343/36/34 345/40/38 301/42/40
+f 343/36/34 301/42/40 385/34/32
+f 300/37/35 344/39/37 342/31/29
+f 300/37/35 342/31/29 384/33/31
+f 385/34/32 301/42/40 299/215/189
+f 385/34/32 299/215/189 319/172/167
+f 298/216/190 300/37/35 384/33/31
+f 298/216/190 384/33/31 318/176/170
+f 387/203/181 385/34/32 321/183/67
+f 385/34/32 319/172/167 321/183/67
+f 318/176/170 384/33/31 320/184/69
+f 384/33/31 386/206/184 320/184/69
+f 387/203/181 351/204/182 385/34/32
+f 351/204/182 349/35/33 385/34/32
+f 348/32/30 350/205/183 384/33/31
+f 350/205/183 386/206/184 384/33/31
+f 371/217/191 377/218/192 383/219/78
+f 377/218/192 315/213/74 383/219/78
+f 314/214/75 376/220/193 382/221/79
+f 376/220/193 370/222/194 382/221/79
+f 371/217/191 383/219/78 313/174/158
+f 371/217/191 313/174/158 369/223/195
+f 312/178/159 382/221/79 370/222/194
+f 312/178/159 370/222/194 368/224/196
+f 369/223/195 313/174/158 311/173/168
+f 369/223/195 311/173/168 363/225/197
+f 310/175/169 312/178/159 368/224/196
+f 310/175/169 368/224/196 362/226/198
+f 311/173/168 297/227/199 363/225/197
+f 297/227/199 295/228/200 363/225/197
+f 294/229/201 296/230/202 362/226/198
+f 296/230/202 310/175/169 362/226/198
+f 361/231/203 291/232/204 285/29/28
+f 361/231/203 285/29/28 74/28/27
+f 284/26/26 290/233/205 360/234/206
+f 284/26/26 360/234/206 74/27/27
+f 289/235/207 287/236/208 291/232/204
+f 287/236/208 285/29/28 291/232/204
+f 284/26/26 286/237/209 290/233/205
+f 286/237/209 288/238/210 290/233/205
+f 359/239/211 361/231/203 302/240/212
+f 361/231/203 74/28/27 302/240/212
+f 74/27/27 360/234/206 302/241/212
+f 360/234/206 358/242/213 302/241/212
+f 365/243/214 293/244/215 361/231/203
+f 293/244/215 291/232/204 361/231/203
+f 290/233/205 292/245/216 360/234/206
+f 292/245/216 364/246/217 360/234/206
+f 365/243/214 361/231/203 359/239/211
+f 365/243/214 359/239/211 367/247/218
+f 358/242/213 360/234/206 364/246/217
+f 358/242/213 364/246/217 366/248/219
+f 367/247/218 359/239/211 357/249/220
+f 367/247/218 357/249/220 373/250/221
+f 356/251/222 358/242/213 366/248/219
+f 356/251/222 366/248/219 372/252/223
+f 373/250/221 357/249/220 355/253/224
+f 373/250/221 355/253/224 375/254/225
+f 354/255/226 356/251/222 372/252/223
+f 354/255/226 372/252/223 374/256/227
+f 375/254/225 355/253/224 317/210/186
+f 375/254/225 317/210/186 379/209/185
+f 316/211/187 354/255/226 374/256/227
+f 316/211/187 374/256/227 378/212/188
+f 375/254/225 379/209/185 377/218/192
+f 379/209/185 315/213/74 377/218/192
+f 314/214/75 378/212/188 376/220/193
+f 378/212/188 374/256/227 376/220/193
+f 377/218/192 371/217/191 373/250/221
+f 377/218/192 373/250/221 375/254/225
+f 372/252/223 370/222/194 376/220/193
+f 372/252/223 376/220/193 374/256/227
+f 371/217/191 369/223/195 367/247/218
+f 371/217/191 367/247/218 373/250/221
+f 366/248/219 368/224/196 370/222/194
+f 366/248/219 370/222/194 372/252/223
+f 369/223/195 363/225/197 365/243/214
+f 369/223/195 365/243/214 367/247/218
+f 364/246/217 362/226/198 368/224/196
+f 364/246/217 368/224/196 366/248/219
+f 363/225/197 295/228/200 293/244/215
+f 363/225/197 293/244/215 365/243/214
+f 292/245/216 294/229/201 362/226/198
+f 292/245/216 362/226/198 364/246/217
+f 317/210/186 355/253/224 75/257/228
+f 317/210/186 75/257/228 76/258/229
+f 75/259/228 354/255/226 316/211/187
+f 75/259/228 316/211/187 76/260/229
+f 355/253/224 357/249/220 303/261/230
+f 355/253/224 303/261/230 75/257/228
+f 303/262/230 356/251/222 354/255/226
+f 303/262/230 354/255/226 75/259/228
+f 357/249/220 359/239/211 303/261/230
+f 359/239/211 302/240/212 303/261/230
+f 302/241/212 358/242/213 303/262/230
+f 358/242/213 356/251/222 303/262/230
+f 325/48/46 317/210/186 77/263/231
+f 317/210/186 76/258/229 77/263/231
+f 76/260/229 316/211/187 77/264/231
+f 316/211/187 324/43/41 77/264/231
+f 319/172/167 299/215/189 297/227/199
+f 319/172/167 297/227/199 311/173/168
+f 296/230/202 298/216/190 318/176/170
+f 296/230/202 318/176/170 310/175/169
+f 349/35/33 329/265/232 343/36/34
+f 329/265/232 327/266/233 343/36/34
+f 326/267/234 328/268/235 342/31/29
+f 328/268/235 348/32/30 342/31/29
+f 329/265/232 349/35/33 305/269/236
+f 329/265/232 305/269/236 309/270/237
+f 305/271/236 348/32/30 328/268/235
+f 305/271/236 328/268/235 309/272/237
+f 349/35/33 351/204/182 78/273/238
+f 349/35/33 78/273/238 305/269/236
+f 78/274/238 350/205/183 348/32/30
+f 78/274/238 348/32/30 305/271/236
+f 351/204/182 353/46/44 78/273/238
+f 353/46/44 304/275/239 78/273/238
+f 304/276/239 352/45/43 78/274/238
+f 352/45/43 350/205/183 78/274/238
+f 353/46/44 325/48/46 304/275/239
+f 325/48/46 77/263/231 304/275/239
+f 77/264/231 324/43/41 304/276/239
+f 324/43/41 352/45/43 304/276/239
+f 301/42/40 347/41/39 93/277/240
+f 347/278/39 80/279/241 93/280/240
+f 79/281/242 346/282/36 92/283/243
+f 346/38/36 300/37/35 92/284/243
+f 345/40/38 216/285/244 347/41/39
+f 216/286/244 80/279/241 347/278/39
+f 79/281/242 215/287/245 346/282/36
+f 215/288/245 344/39/37 346/38/36
+f 343/36/34 327/266/233 210/289/246
+f 327/266/233 82/290/247 210/289/246
+f 81/291/248 326/267/234 209/292/249
+f 326/267/234 342/31/29 209/292/249
+f 345/40/38 343/36/34 216/285/244
+f 343/36/34 210/289/246 216/285/244
+f 209/292/249 342/31/29 215/288/245
+f 342/31/29 344/39/37 215/288/245
+f 333/293/250 84/294/251 82/290/247
+f 333/293/250 82/290/247 327/266/233
+f 81/291/248 83/295/252 332/296/253
+f 81/291/248 332/296/253 326/267/234
+f 339/297/254 333/293/250 329/265/232
+f 333/293/250 327/266/233 329/265/232
+f 326/267/234 332/296/253 328/268/235
+f 332/296/253 338/298/255 328/268/235
+f 341/299/256 335/300/257 337/301/258
+f 335/300/257 331/302/259 337/301/258
+f 330/303/260 334/304/261 336/305/262
+f 334/304/261 340/306/263 336/305/262
+f 339/297/254 337/301/258 331/302/259
+f 339/297/254 331/302/259 333/293/250
+f 330/303/260 336/305/262 338/298/255
+f 330/303/260 338/298/255 332/296/253
+f 331/302/259 86/307/264 84/294/251
+f 331/302/259 84/294/251 333/293/250
+f 83/295/252 85/308/265 330/303/260
+f 83/295/252 330/303/260 332/296/253
+f 335/300/257 88/309/266 86/307/264
+f 335/300/257 86/307/264 331/302/259
+f 85/308/265 87/310/267 334/304/261
+f 85/308/265 334/304/261 330/303/260
+f 341/299/256 90/311/268 88/309/266
+f 341/299/256 88/309/266 335/300/257
+f 87/310/267 89/312/269 340/306/263
+f 87/310/267 340/306/263 334/304/261
+f 306/313/270 91/314/271 90/311/268
+f 306/313/270 90/311/268 341/299/256
+f 89/312/269 91/315/271 306/316/270
+f 89/312/269 306/316/270 340/306/263
+f 337/301/258 307/317/272 341/299/256
+f 307/317/272 306/313/270 341/299/256
+f 306/316/270 307/318/272 340/306/263
+f 307/318/272 336/305/262 340/306/263
+f 339/297/254 308/319/273 337/301/258
+f 308/319/273 307/317/272 337/301/258
+f 307/318/272 308/320/273 336/305/262
+f 308/320/273 338/298/255 336/305/262
+f 329/265/232 309/270/237 339/297/254
+f 309/270/237 308/319/273 339/297/254
+f 308/320/273 309/272/237 338/298/255
+f 309/272/237 328/268/235 338/298/255
+f 301/42/40 93/277/240 95/321/274
+f 301/42/40 95/321/274 299/215/189
+f 94/322/275 92/284/243 300/37/35
+f 94/322/275 300/37/35 298/216/190
+f 299/215/189 95/321/274 97/323/276
+f 299/215/189 97/323/276 297/227/199
+f 96/324/277 94/322/275 298/216/190
+f 96/324/277 298/216/190 296/230/202
+f 297/227/199 97/323/276 295/228/200
+f 97/323/276 99/325/278 295/228/200
+f 98/326/279 96/324/277 294/229/201
+f 96/324/277 296/230/202 294/229/201
+f 295/228/200 99/325/278 101/327/280
+f 295/228/200 101/327/280 293/244/215
+f 100/328/281 98/326/279 294/229/201
+f 100/328/281 294/229/201 292/245/216
+f 293/244/215 101/327/280 291/232/204
+f 101/327/280 103/329/282 291/232/204
+f 102/330/283 100/328/281 290/233/205
+f 100/328/281 292/245/216 290/233/205
+f 291/232/204 103/329/282 289/235/207
+f 103/329/282 105/331/284 289/235/207
+f 104/332/285 102/330/283 288/238/210
+f 102/330/283 290/233/205 288/238/210
+f 289/235/207 105/331/284 287/236/208
+f 105/331/284 107/333/286 287/236/208
+f 106/334/287 104/332/285 286/237/209
+f 104/332/285 288/238/210 286/237/209
+f 287/236/208 107/333/286 109/335/288
+f 287/236/208 109/335/288 285/29/28
+f 108/336/289 106/334/287 286/237/209
+f 108/336/289 286/237/209 284/26/26
+f 285/29/28 109/335/288 67/337/290
+f 285/29/28 67/337/290 73/30/25
+f 67/338/290 108/336/289 284/26/26
+f 67/338/290 284/26/26 73/25/25
+f 281/339/291 235/340/292 233/341/293
+f 281/339/291 233/341/293 283/342/294
+f 232/343/295 234/344/296 280/345/297
+f 232/343/295 280/345/297 282/346/298
+f 283/342/294 233/341/293 255/347/299
+f 283/342/294 255/347/299 261/348/300
+f 254/349/301 232/343/295 282/346/298
+f 254/349/301 282/346/298 260/350/302
+f 261/348/300 255/347/299 257/351/303
+f 261/348/300 257/351/303 259/352/304
+f 256/353/305 254/349/301 260/350/302
+f 256/353/305 260/350/302 258/354/306
+f 263/355/307 253/356/308 235/340/292
+f 263/355/307 235/340/292 281/339/291
+f 234/344/296 252/357/309 262/358/310
+f 234/344/296 262/358/310 280/345/297
+f 265/359/311 251/360/312 263/355/307
+f 251/360/312 253/356/308 263/355/307
+f 252/357/309 250/361/313 262/358/310
+f 250/361/313 264/362/314 262/358/310
+f 267/363/315 249/364/316 265/359/311
+f 249/364/316 251/360/312 265/359/311
+f 250/361/313 248/365/317 264/362/314
+f 248/365/317 266/366/318 264/362/314
+f 269/367/319 247/368/320 249/364/316
+f 269/367/319 249/364/316 267/363/315
+f 248/365/317 246/369/321 268/370/322
+f 248/365/317 268/370/322 266/366/318
+f 271/371/323 245/372/324 269/367/319
+f 245/372/324 247/368/320 269/367/319
+f 246/369/321 244/373/325 268/370/322
+f 244/373/325 270/374/326 268/370/322
+f 273/375/327 243/376/328 245/372/324
+f 273/375/327 245/372/324 271/371/323
+f 244/373/325 242/377/329 272/378/330
+f 244/373/325 272/378/330 270/374/326
+f 275/379/331 241/380/332 273/375/327
+f 241/380/332 243/376/328 273/375/327
+f 242/377/329 240/381/333 272/378/330
+f 240/381/333 274/382/334 272/378/330
+f 279/383/335 237/384/336 275/379/331
+f 237/384/336 241/380/332 275/379/331
+f 240/381/333 236/385/337 274/382/334
+f 236/385/337 278/386/338 274/382/334
+f 277/387/339 239/388/340 237/384/336
+f 277/387/339 237/384/336 279/383/335
+f 236/385/337 238/389/341 276/390/342
+f 236/385/337 276/390/342 278/386/338
+f 259/352/304 257/351/303 239/388/340
+f 259/352/304 239/388/340 277/387/339
+f 238/389/341 256/353/305 258/354/306
+f 238/389/341 258/354/306 276/390/342
+f 257/351/303 111/391/343 129/392/344
+f 257/351/303 129/392/344 239/388/340
+f 128/393/345 110/394/346 256/353/305
+f 128/393/345 256/353/305 238/389/341
+f 239/388/340 129/392/344 180/395/347
+f 239/388/340 180/395/347 237/384/336
+f 179/396/348 128/393/345 238/389/341
+f 179/396/348 238/389/341 236/385/337
+f 237/384/336 180/395/347 127/397/349
+f 237/384/336 127/397/349 241/380/332
+f 126/398/350 179/396/348 236/385/337
+f 126/398/350 236/385/337 240/381/333
+f 241/380/332 127/397/349 243/376/328
+f 127/397/349 125/399/351 243/376/328
+f 124/400/352 126/398/350 242/377/329
+f 126/398/350 240/381/333 242/377/329
+f 243/376/328 125/399/351 245/372/324
+f 125/399/351 123/401/353 245/372/324
+f 122/402/354 124/400/352 244/373/325
+f 124/400/352 242/377/329 244/373/325
+f 245/372/324 123/401/353 121/403/355
+f 245/372/324 121/403/355 247/368/320
+f 120/404/356 122/402/354 244/373/325
+f 120/404/356 244/373/325 246/369/321
+f 247/368/320 121/403/355 119/405/357
+f 247/368/320 119/405/357 249/364/316
+f 118/406/358 120/404/356 246/369/321
+f 118/406/358 246/369/321 248/365/317
+f 249/364/316 119/405/357 117/407/359
+f 249/364/316 117/407/359 251/360/312
+f 116/408/360 118/406/358 248/365/317
+f 116/408/360 248/365/317 250/361/313
+f 251/360/312 117/407/359 115/409/361
+f 251/360/312 115/409/361 253/356/308
+f 114/410/362 116/408/360 250/361/313
+f 114/410/362 250/361/313 252/357/309
+f 253/356/308 115/409/361 235/340/292
+f 115/409/361 182/411/363 235/340/292
+f 181/412/364 114/410/362 234/344/296
+f 114/410/362 252/357/309 234/344/296
+f 255/347/299 113/413/365 257/351/303
+f 113/413/365 111/391/343 257/351/303
+f 110/394/346 112/414/366 256/353/305
+f 112/414/366 254/349/301 256/353/305
+f 233/341/293 184/415/367 113/413/365
+f 233/341/293 113/413/365 255/347/299
+f 112/414/366 183/416/368 232/343/295
+f 112/414/366 232/343/295 254/349/301
+f 235/340/292 182/411/363 184/415/367
+f 235/340/292 184/415/367 233/341/293
+f 183/416/368 181/412/364 234/344/296
+f 183/416/368 234/344/296 232/343/295
+f 230/23/23 231/417/369 224/418/370
+f 230/23/23 224/418/370 226/24/24
+f 224/418/370 231/417/369 229/20/20
+f 224/418/370 229/20/20 225/19/19
+f 224/418/370 72/419/371 226/24/24
+f 72/419/371 223/420/372 226/24/24
+f 222/421/373 72/419/371 225/19/19
+f 72/419/371 224/418/370 225/19/19
+f 226/24/24 223/420/372 221/422/374
+f 226/24/24 221/422/374 228/22/22
+f 220/423/375 222/421/373 225/19/19
+f 220/423/375 225/19/19 227/21/21
+f 228/22/22 221/422/374 219/424/376
+f 228/22/22 219/424/376 230/23/23
+f 218/425/377 220/423/375 227/21/21
+f 218/425/377 227/21/21 229/20/20
+f 230/23/23 219/424/376 231/417/369
+f 219/424/376 217/426/378 231/417/369
+f 217/426/378 218/425/377 231/417/369
+f 218/425/377 229/20/20 231/417/369
+f 219/424/376 136/427/379 137/428/380
+f 219/424/376 137/428/380 217/426/378
+f 137/428/380 135/429/381 218/425/377
+f 137/428/380 218/425/377 217/426/378
+f 221/422/374 134/430/382 136/427/379
+f 221/422/374 136/427/379 219/424/376
+f 135/429/381 133/431/383 220/423/375
+f 135/429/381 220/423/375 218/425/377
+f 223/420/372 132/432/384 134/430/382
+f 223/420/372 134/430/382 221/422/374
+f 133/431/383 131/433/385 222/421/373
+f 133/431/383 222/421/373 220/423/375
+f 72/419/371 130/434/386 223/420/372
+f 130/434/386 132/432/384 223/420/372
+f 131/433/385 130/434/386 222/421/373
+f 130/434/386 72/419/371 222/421/373
+f 212/435/387 165/436/388 80/279/241
+f 212/435/387 80/279/241 216/286/244
+f 79/281/242 164/437/389 211/438/390
+f 79/281/242 211/438/390 215/287/245
+f 212/435/387 216/286/244 214/439/391
+f 216/286/244 210/440/246 214/439/391
+f 209/441/249 215/287/245 213/442/392
+f 215/287/245 211/438/390 213/442/392
+f 214/439/391 210/440/246 167/443/393
+f 210/440/246 82/444/247 167/443/393
+f 81/445/248 209/441/249 166/446/394
+f 209/441/249 213/442/392 166/446/394
+f 167/443/393 188/447/395 214/439/391
+f 188/447/395 145/448/396 214/439/391
+f 144/449/397 187/450/398 213/442/392
+f 187/450/398 166/446/394 213/442/392
+f 214/439/391 145/448/396 212/435/387
+f 145/448/396 143/451/399 212/435/387
+f 142/452/400 144/449/397 211/438/390
+f 144/449/397 213/442/392 211/438/390
+f 212/435/387 143/451/399 141/453/401
+f 212/435/387 141/453/401 165/436/388
+f 140/454/402 142/452/400 211/438/390
+f 140/454/402 211/438/390 164/437/389
+f 165/436/388 141/453/401 139/455/403
+f 165/436/388 139/455/403 177/456/404
+f 139/455/403 140/454/402 164/437/389
+f 139/455/403 164/437/389 177/456/404
+f 207/457/405 208/458/406 199/459/407
+f 207/457/405 199/459/407 205/460/408
+f 199/459/407 208/458/406 206/461/409
+f 199/459/407 206/461/409 204/462/410
+f 203/463/411 205/460/408 201/464/412
+f 205/460/408 199/459/407 201/464/412
+f 199/459/407 204/462/410 200/465/413
+f 204/462/410 202/466/414 200/465/413
+f 207/457/405 205/460/408 194/467/415
+f 207/457/405 194/467/415 192/468/416
+f 193/469/417 204/462/410 206/461/409
+f 193/469/417 206/461/409 191/470/418
+f 205/460/408 203/463/411 194/467/415
+f 203/463/411 196/471/419 194/467/415
+f 195/472/420 202/466/414 193/469/417
+f 202/466/414 204/462/410 193/469/417
+f 203/463/411 201/464/412 198/473/421
+f 203/463/411 198/473/421 196/471/419
+f 197/474/422 200/465/413 202/466/414
+f 197/474/422 202/466/414 195/472/420
+f 201/464/412 199/459/407 71/475/423
+f 201/464/412 71/475/423 198/473/421
+f 71/475/423 199/459/407 200/465/413
+f 71/475/423 200/465/413 197/474/422
+f 207/457/405 192/468/416 208/458/406
+f 192/468/416 70/476/424 208/458/406
+f 70/476/424 191/470/418 208/458/406
+f 191/470/418 206/461/409 208/458/406
+f 192/468/416 145/448/396 70/476/424
+f 145/448/396 190/477/425 70/476/424
+f 190/477/425 144/449/397 70/476/424
+f 144/449/397 191/470/418 70/476/424
+f 198/473/421 71/475/423 139/455/403
+f 71/478/423 138/479/426 139/480/403
+f 138/481/426 71/482/423 139/483/403
+f 71/475/423 197/474/422 139/455/403
+f 196/471/419 198/473/421 141/453/401
+f 198/473/421 139/455/403 141/453/401
+f 139/455/403 197/474/422 140/454/402
+f 197/474/422 195/472/420 140/454/402
+f 194/467/415 196/471/419 143/451/399
+f 196/471/419 141/453/401 143/451/399
+f 140/454/402 195/472/420 142/452/400
+f 195/472/420 193/469/417 142/452/400
+f 192/468/416 194/467/415 143/451/399
+f 192/468/416 143/451/399 145/448/396
+f 142/452/400 193/469/417 191/470/418
+f 142/452/400 191/470/418 144/449/397
+f 186/484/427 132/432/384 69/485/428
+f 132/432/384 130/434/386 69/485/428
+f 130/434/386 131/433/385 69/485/428
+f 131/433/385 185/486/429 69/485/428
+f 189/487/430 188/447/395 69/485/428
+f 188/447/395 186/484/427 69/485/428
+f 185/486/429 187/450/398 69/485/428
+f 187/450/398 189/487/430 69/485/428
+f 189/487/430 190/477/425 188/447/395
+f 190/477/425 145/448/396 188/447/395
+f 144/449/397 190/477/425 187/450/398
+f 190/477/425 189/487/430 187/450/398
+f 169/488/431 171/489/432 132/432/384
+f 169/488/431 132/432/384 186/484/427
+f 131/433/385 170/490/433 168/491/434
+f 131/433/385 168/491/434 185/486/429
+f 186/484/427 188/447/395 167/443/393
+f 186/484/427 167/443/393 169/488/431
+f 166/446/394 187/450/398 185/486/429
+f 166/446/394 185/486/429 168/491/434
+f 173/492/435 134/430/382 171/489/432
+f 134/430/382 132/432/384 171/489/432
+f 131/433/385 133/431/383 170/490/433
+f 133/431/383 172/493/436 170/490/433
+f 175/494/437 136/427/379 134/430/382
+f 175/494/437 134/430/382 173/492/435
+f 133/431/383 135/429/381 174/495/438
+f 133/431/383 174/495/438 172/493/436
+f 176/496/439 137/428/380 136/427/379
+f 176/496/439 136/427/379 175/494/437
+f 135/429/381 137/428/380 176/496/439
+f 135/429/381 176/496/439 174/495/438
+f 184/415/367 182/411/363 178/497/440
+f 182/411/363 177/456/404 178/497/440
+f 177/456/404 181/412/364 178/497/440
+f 181/412/364 183/416/368 178/497/440
+f 178/497/440 68/498/441 113/413/365
+f 178/497/440 113/413/365 184/415/367
+f 112/414/366 68/498/441 178/497/440
+f 112/414/366 178/497/440 183/416/368
+f 68/498/441 163/499/442 113/413/365
+f 163/499/442 111/391/343 113/413/365
+f 110/394/346 162/500/443 112/414/366
+f 162/500/443 68/498/441 112/414/366
+f 177/456/404 182/411/363 115/409/361
+f 177/456/404 115/409/361 165/436/388
+f 114/410/362 181/412/364 177/456/404
+f 114/410/362 177/456/404 164/437/389
+f 147/501/444 165/436/388 115/409/361
+f 147/501/444 115/409/361 117/407/359
+f 114/410/362 164/437/389 146/502/445
+f 114/410/362 146/502/445 116/408/360
+f 149/503/446 147/501/444 119/405/357
+f 147/501/444 117/407/359 119/405/357
+f 116/408/360 146/502/445 118/406/358
+f 146/502/445 148/504/447 118/406/358
+f 151/505/448 149/503/446 121/403/355
+f 149/503/446 119/405/357 121/403/355
+f 118/406/358 148/504/447 120/404/356
+f 148/504/447 150/506/449 120/404/356
+f 153/507/450 151/505/448 123/401/353
+f 151/505/448 121/403/355 123/401/353
+f 120/404/356 150/506/449 122/402/354
+f 150/506/449 152/508/451 122/402/354
+f 155/509/452 153/507/450 125/399/351
+f 153/507/450 123/401/353 125/399/351
+f 122/402/354 152/508/451 124/400/352
+f 152/508/451 154/510/453 124/400/352
+f 157/511/454 155/509/452 127/397/349
+f 155/509/452 125/399/351 127/397/349
+f 124/400/352 154/510/453 126/398/350
+f 154/510/453 156/512/455 126/398/350
+f 159/513/456 157/511/454 180/395/347
+f 157/511/454 127/397/349 180/395/347
+f 126/398/350 156/512/455 179/396/348
+f 156/512/455 158/514/457 179/396/348
+f 159/513/456 180/395/347 129/392/344
+f 159/513/456 129/392/344 161/515/458
+f 128/393/345 179/396/348 158/514/457
+f 128/393/345 158/514/457 160/516/459
+f 161/515/458 129/392/344 163/499/442
+f 129/392/344 111/391/343 163/499/442
+f 110/394/346 128/393/345 162/500/443
+f 128/393/345 160/516/459 162/500/443
+f 68/498/441 67/517/290 163/499/442
+f 67/517/290 109/518/288 163/499/442
+f 108/519/289 67/517/290 162/500/443
+f 67/517/290 68/498/441 162/500/443
+f 163/499/442 109/518/288 161/515/458
+f 109/518/288 107/520/286 161/515/458
+f 106/521/287 108/519/289 160/516/459
+f 108/519/289 162/500/443 160/516/459
+f 161/515/458 107/520/286 159/513/456
+f 107/520/286 105/522/284 159/513/456
+f 104/523/285 106/521/287 158/514/457
+f 106/521/287 160/516/459 158/514/457
+f 159/513/456 105/522/284 103/524/282
+f 159/513/456 103/524/282 157/511/454
+f 102/525/283 104/523/285 158/514/457
+f 102/525/283 158/514/457 156/512/455
+f 157/511/454 103/524/282 155/509/452
+f 103/524/282 101/526/280 155/509/452
+f 100/527/281 102/525/283 154/510/453
+f 102/525/283 156/512/455 154/510/453
+f 155/509/452 101/526/280 153/507/450
+f 101/526/280 99/528/278 153/507/450
+f 98/529/279 100/527/281 152/508/451
+f 100/527/281 154/510/453 152/508/451
+f 153/507/450 99/528/278 151/505/448
+f 99/528/278 97/530/276 151/505/448
+f 96/531/277 98/529/279 150/506/449
+f 98/529/279 152/508/451 150/506/449
+f 151/505/448 97/530/276 95/532/274
+f 151/505/448 95/532/274 149/503/446
+f 94/533/275 96/531/277 150/506/449
+f 94/533/275 150/506/449 148/504/447
+f 149/503/446 95/532/274 147/501/444
+f 95/532/274 93/280/240 147/501/444
+f 92/283/243 94/533/275 146/502/445
+f 94/533/275 148/504/447 146/502/445
+f 147/501/444 93/280/240 80/279/241
+f 147/501/444 80/279/241 165/436/388
+f 79/281/242 92/283/243 146/502/445
+f 79/281/242 146/502/445 164/437/389
+f 169/488/431 167/443/393 82/444/247
+f 169/488/431 82/444/247 84/534/251
+f 81/445/248 166/446/394 168/491/434
+f 81/445/248 168/491/434 83/535/252
+f 171/489/432 169/488/431 84/534/251
+f 171/489/432 84/534/251 86/536/264
+f 83/535/252 168/491/434 170/490/433
+f 83/535/252 170/490/433 85/537/265
+f 173/492/435 171/489/432 86/536/264
+f 173/492/435 86/536/264 88/538/266
+f 85/537/265 170/490/433 172/493/436
+f 85/537/265 172/493/436 87/539/267
+f 175/494/437 173/492/435 90/540/268
+f 173/492/435 88/538/266 90/540/268
+f 87/539/267 172/493/436 89/541/269
+f 172/493/436 174/495/438 89/541/269
+f 176/496/439 175/494/437 91/542/271
+f 175/494/437 90/540/268 91/542/271
+f 89/541/269 174/495/438 91/542/271
+f 174/495/438 176/496/439 91/542/271
+f 50/4/4 48/543/460 2/544/461
+f 50/4/4 2/544/461 66/5/5
+f 1/545/462 47/546/463 49/3/3
+f 1/545/462 49/3/3 65/2/2
+f 66/5/5 2/544/461 12/547/464
+f 66/5/5 12/547/464 64/8/8
+f 11/548/465 1/545/462 65/2/2
+f 11/548/465 65/2/2 63/7/7
+f 64/8/8 12/547/464 14/549/466
+f 64/8/8 14/549/466 60/10/10
+f 13/550/467 11/548/465 63/7/7
+f 13/550/467 63/7/7 59/9/9
+f 60/10/10 14/549/466 24/551/468
+f 60/10/10 24/551/468 58/12/12
+f 23/552/469 13/550/467 59/9/9
+f 23/552/469 59/9/9 57/11/11
+f 58/12/12 24/551/468 56/14/14
+f 24/551/468 26/553/470 56/14/14
+f 25/554/471 23/552/469 55/13/13
+f 23/552/469 57/11/11 55/13/13
+f 56/14/14 26/553/470 54/16/16
+f 26/553/470 36/555/472 54/16/16
+f 35/556/473 25/554/471 53/15/15
+f 25/554/471 55/13/13 53/15/15
+f 54/16/16 36/555/472 52/18/18
+f 36/555/472 38/557/474 52/18/18
+f 37/558/475 35/556/473 51/17/17
+f 35/556/473 53/15/15 51/17/17
+f 52/18/18 38/557/474 50/4/4
+f 38/557/474 48/543/460 50/4/4
+f 47/546/463 37/558/475 49/3/3
+f 37/558/475 51/17/17 49/3/3
+f 46/559/476 48/543/460 40/560/477
+f 48/543/460 38/557/474 40/560/477
+f 37/558/475 47/546/463 39/561/478
+f 47/546/463 45/562/479 39/561/478
+f 44/563/480 46/559/476 42/564/481
+f 46/559/476 40/560/477 42/564/481
+f 39/561/478 45/562/479 41/565/482
+f 45/562/479 43/566/483 41/565/482
+f 42/564/481 40/560/477 32/567/484
+f 40/560/477 34/568/485 32/567/484
+f 33/569/486 39/561/478 31/570/487
+f 39/561/478 41/565/482 31/570/487
+f 40/560/477 38/557/474 34/568/485
+f 38/557/474 36/555/472 34/568/485
+f 35/556/473 37/558/475 33/569/486
+f 37/558/475 39/561/478 33/569/486
+f 34/568/485 36/555/472 28/571/488
+f 36/555/472 26/553/470 28/571/488
+f 25/554/471 35/556/473 27/572/489
+f 35/556/473 33/569/486 27/572/489
+f 32/567/484 34/568/485 30/573/490
+f 34/568/485 28/571/488 30/573/490
+f 27/572/489 33/569/486 29/574/491
+f 33/569/486 31/570/487 29/574/491
+f 30/573/490 28/571/488 20/575/492
+f 28/571/488 22/576/493 20/575/492
+f 21/577/494 27/572/489 19/578/495
+f 27/572/489 29/574/491 19/578/495
+f 28/571/488 26/553/470 24/551/468
+f 28/571/488 24/551/468 22/576/493
+f 23/552/469 25/554/471 27/572/489
+f 23/552/469 27/572/489 21/577/494
+f 22/576/493 24/551/468 16/579/496
+f 24/551/468 14/549/466 16/579/496
+f 13/550/467 23/552/469 15/580/497
+f 23/552/469 21/577/494 15/580/497
+f 20/575/492 22/576/493 18/581/498
+f 22/576/493 16/579/496 18/581/498
+f 15/580/497 21/577/494 17/582/499
+f 21/577/494 19/578/495 17/582/499
+f 18/581/498 16/579/496 10/583/500
+f 18/581/498 10/583/500 8/584/501
+f 9/585/502 15/580/497 17/582/499
+f 9/585/502 17/582/499 7/586/503
+f 16/579/496 14/549/466 12/547/464
+f 16/579/496 12/547/464 10/583/500
+f 11/548/465 13/550/467 15/580/497
+f 11/548/465 15/580/497 9/585/502
+f 10/583/500 12/547/464 2/544/461
+f 10/583/500 2/544/461 4/587/504
+f 1/545/462 11/548/465 9/585/502
+f 1/545/462 9/585/502 3/588/505
+f 8/584/501 10/583/500 4/587/504
+f 8/584/501 4/587/504 6/589/506
+f 3/588/505 9/585/502 7/586/503
+f 3/588/505 7/586/503 5/590/507
+f 6/589/506 4/587/504 46/559/476
+f 6/589/506 46/559/476 44/563/480
+f 45/562/479 3/588/505 5/590/507
+f 45/562/479 5/590/507 43/566/483
+f 4/587/504 2/544/461 48/543/460
+f 4/587/504 48/543/460 46/559/476
+f 47/546/463 1/545/462 3/588/505
+f 47/546/463 3/588/505 45/562/479