From d5ac5461e2c749e4051c2d2d0d8e436b567564c2 Mon Sep 17 00:00:00 2001 From: ouczbs Date: Fri, 22 Dec 2023 22:04:27 +0800 Subject: [PATCH] objloader --- .gitignore | 3 + asset/model/cube.obj | 84 + asset/model/sphere.obj | 4811 ++++++++++++++++++ cmd/main.go | 17 + engine/actor/Component/mesh.go | 1 + engine/actor/Component/root.go | 1 + engine/actor/Component/type.go | 4 + engine/actor/actor.go | 17 + engine/core/zlog/type.go | 16 + engine/core/zlog/zlog.go | 98 + engine/render/vulkan/instance/ext_linux.go | 15 + engine/render/vulkan/instance/ext_windows.go | 16 + engine/render/vulkan/instance/instance.go | 62 + engine/rule/actor.go | 21 + engine/rule/render.go | 11 + engine/rule/time.go | 21 + engine/rule/type.go | 16 + engine/type.go | 7 + engine/world.go | 26 + engine/world_new.go | 39 + go.mod | 18 + go.sum | 55 + library/zos/error.go | 8 + library/zos/line.go | 77 + library/zos/reader.go | 127 + plugin/math/byte4/byte4.go | 10 + plugin/math/ivec2/ivec2.go | 32 + plugin/math/mat4/mat4.go | 317 ++ plugin/math/mat4/operations.go | 11 + plugin/math/mat4/project.go | 67 + plugin/math/mat4/project_test.go | 56 + plugin/math/mat4/translation.go | 20 + plugin/math/math32.go | 177 + plugin/math/noise.go | 28 + plugin/math/quat/quat.go | 553 ++ plugin/math/quat/quat_suite_test.go | 29 + plugin/math/random/random.go | 28 + plugin/math/shape/frustum.go | 107 + plugin/math/shape/sphere.go | 15 + plugin/math/vec2/array.go | 21 + plugin/math/vec2/operations.go | 37 + plugin/math/vec2/vec2.go | 134 + plugin/math/vec3/array.go | 21 + plugin/math/vec3/operations.go | 85 + plugin/math/vec3/vec3.go | 205 + plugin/math/vec4/array.go | 21 + plugin/math/vec4/operations.go | 56 + plugin/math/vec4/vec4.go | 144 + plugin/objloader/parser.go | 111 + test/vulkan_instance_test.go | 10 + 50 files changed, 7866 insertions(+) create mode 100644 .gitignore create mode 100644 asset/model/cube.obj create mode 100644 asset/model/sphere.obj create mode 100644 cmd/main.go create mode 100644 engine/actor/Component/mesh.go create mode 100644 engine/actor/Component/root.go create mode 100644 engine/actor/Component/type.go create mode 100644 engine/actor/actor.go create mode 100644 engine/core/zlog/type.go create mode 100644 engine/core/zlog/zlog.go create mode 100644 engine/render/vulkan/instance/ext_linux.go create mode 100644 engine/render/vulkan/instance/ext_windows.go create mode 100644 engine/render/vulkan/instance/instance.go create mode 100644 engine/rule/actor.go create mode 100644 engine/rule/render.go create mode 100644 engine/rule/time.go create mode 100644 engine/rule/type.go create mode 100644 engine/type.go create mode 100644 engine/world.go create mode 100644 engine/world_new.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 library/zos/error.go create mode 100644 library/zos/line.go create mode 100644 library/zos/reader.go create mode 100644 plugin/math/byte4/byte4.go create mode 100644 plugin/math/ivec2/ivec2.go create mode 100644 plugin/math/mat4/mat4.go create mode 100644 plugin/math/mat4/operations.go create mode 100644 plugin/math/mat4/project.go create mode 100644 plugin/math/mat4/project_test.go create mode 100644 plugin/math/mat4/translation.go create mode 100644 plugin/math/math32.go create mode 100644 plugin/math/noise.go create mode 100644 plugin/math/quat/quat.go create mode 100644 plugin/math/quat/quat_suite_test.go create mode 100644 plugin/math/random/random.go create mode 100644 plugin/math/shape/frustum.go create mode 100644 plugin/math/shape/sphere.go create mode 100644 plugin/math/vec2/array.go create mode 100644 plugin/math/vec2/operations.go create mode 100644 plugin/math/vec2/vec2.go create mode 100644 plugin/math/vec3/array.go create mode 100644 plugin/math/vec3/operations.go create mode 100644 plugin/math/vec3/vec3.go create mode 100644 plugin/math/vec4/array.go create mode 100644 plugin/math/vec4/operations.go create mode 100644 plugin/math/vec4/vec4.go create mode 100644 plugin/objloader/parser.go create mode 100644 test/vulkan_instance_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b65fdd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.log +.idea/* +*/.ipynb_checkpoints/* \ No newline at end of file diff --git a/asset/model/cube.obj b/asset/model/cube.obj new file mode 100644 index 0000000..a14d49f --- /dev/null +++ b/asset/model/cube.obj @@ -0,0 +1,84 @@ +v -0.500000 0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 0.500000 -0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 -0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 0.500000 -0.500000 +v -0.500000 0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v 0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 -0.500000 +v -0.500000 -0.500000 0.500000 +v -0.500000 -0.500000 -0.500000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +f 1/1/1 2/2/2 4/4/4 +f 4/4/4 2/2/2 3/3/3 +f 5/5/5 8/8/8 6/6/6 +f 8/8/8 7/7/7 6/6/6 +f 9/9/9 11/11/11 10/10/10 +f 10/10/10 11/11/11 12/12/12 +f 13/13/13 15/15/15 14/14/14 +f 14/14/14 15/15/15 16/16/16 +f 17/17/17 18/18/18 19/19/19 +f 18/18/18 20/20/20 19/19/19 +f 21/21/21 23/23/23 22/22/22 +f 22/22/22 23/23/23 24/24/24 diff --git a/asset/model/sphere.obj b/asset/model/sphere.obj new file mode 100644 index 0000000..6246af8 --- /dev/null +++ b/asset/model/sphere.obj @@ -0,0 +1,4811 @@ +# Blender OBJ File: /home/william/Documents/Blender/sphere.obj + +# www.blender.org + +mtllib sphere.mtl + +o Sphere_Sphere + +v 0.0 0.5 -2.54558420181 + +v 1.84198486805 -0.838264584541 -1.13842344284 + +v -0.703561306 -1.66537570953 -1.13842344284 + +v -2.27683401108 0.5 -1.13842344284 + +v -0.703561306 2.66537570953 -1.13842344284 + +v 1.84198486805 1.83826458454 -1.13842344284 + +v 0.703561306 -1.66537570953 1.13842344284 + +v -1.84198486805 -0.838264584541 1.13842344284 + +v -1.84198486805 1.83826458454 1.13842344284 + +v 0.703561306 2.66537570953 1.13842344284 + +v 2.27683401108 0.5 1.13842344284 + +v 0.0 0.5 2.54558420181 + +v 1.08269488811 -0.286614596844 -2.16541218758 + +v -0.413544327021 -0.772780179977 -2.16541218758 + +v 0.669154822826 -1.55940723419 -1.33830952644 + +v 1.08269488811 1.28661465645 -2.16541218758 + +v 2.16539573669 0.5 -1.33830487728 + +v -1.33828949928 0.5 -2.16540551186 + +v -1.7518440485 -0.772784352303 -1.33830583096 + +v -0.413544327021 1.77278017998 -2.16541218758 + +v -1.7518440485 1.7727843523 -1.33830583096 + +v 0.669154822826 2.55940723419 -1.33830952644 + +v 2.42099809647 1.28661775589 0.0 + +v 2.42099809647 -0.28661775589 0.0 + +v 1.49625790119 -1.5594201088 0.0 + +v 0.0 -2.04558420181 0.0 + +v -1.49625790119 -1.5594201088 0.0 + +v -2.42099809647 -0.28661775589 0.0 + +v -2.42099809647 1.28661775589 0.0 + +v -1.49625790119 2.5594201088 0.0 + +v 0.0 3.04558420181 0.0 + +v 1.49625790119 2.5594201088 0.0 + +v 1.7518440485 -0.772784352303 1.33830583096 + +v -0.669154822826 -1.55940723419 1.33830952644 + +v -2.16539573669 0.5 1.33830487728 + +v -0.669154822826 2.55940723419 1.33830952644 + +v 1.7518440485 1.7727843523 1.33830583096 + +v 1.33828949928 0.5 2.16540551186 + +v 0.413544327021 -0.772780179977 2.16541218758 + +v -1.08269488811 -0.286614596844 2.16541218758 + +v -1.08269488811 1.28661465645 2.16541218758 + +v 0.413544327021 1.77278017998 2.16541218758 + +v 1.27628755569 2.28711080551 1.28737151623 + +v 2.09404230118 1.1615729332 1.28736424446 + +v 0.580656588078 2.28710746765 1.71728980541 + +v 0.214953452349 1.16156983376 2.44869756699 + +v 1.87908375263 0.5 1.71727788448 + +v 0.695621073246 0.5 2.44869589806 + +v 1.13841235638 1.83828282356 1.84201407433 + +v 0.920993208885 1.16913986206 2.27684497833 + +v 1.62457787991 1.16914176941 1.84200847149 + +v -1.30525624752 2.26606321335 1.28737187386 + +v 0.0178840458393 2.69598531723 1.28737258911 + +v -1.52020871639 1.60448336601 1.71728873253 + +v -0.562766730785 0.908869147301 2.44869756699 + +v -0.921001434326 1.99624156952 1.84201455116 + +v -0.351792931557 1.58268678188 2.27684664726 + +v -0.134382337332 2.25183391571 1.84201490879 + +v -2.08298039436 -0.19561111927 1.287368536 + +v -2.08298039436 1.19561111927 1.287368536 + +v -1.52020871639 -0.604483366013 1.71728873253 + +v -0.562766730785 0.0911308526993 2.44869756699 + +v -1.70762121677 0.0864524841309 1.84201192856 + +v -1.13841044903 0.5 2.2768445015 + +v -1.70762121677 0.913547515869 1.84201192856 + +v 0.0178840458393 -1.69598531723 1.28737258911 + +v -1.30525624752 -1.26606333256 1.28737187386 + +v 0.580656588078 -1.28710758686 1.71728980541 + +v 0.214953452349 -0.16156989336 2.44869756699 + +v -0.134382337332 -1.25183391571 1.84201490879 + +v -0.351792931557 -0.582686781883 2.27684664726 + +v -0.921001434326 -0.996241569519 1.84201455116 + +v 1.27628755569 -1.2871106863 1.28737151623 + +v 2.09404230118 -0.161572933197 1.28736424446 + +v 1.62457787991 -0.169141769409 1.84200847149 + +v 0.920993208885 -0.169139921665 2.27684497833 + +v 1.13841235638 -0.838282823563 1.84201407433 + +v 1.73517549038 2.26607275009 -0.591737806797 + +v 1.14343810081 2.69599509239 0.591738045216 + +v 2.21584224701 1.60448586941 -0.591737508774 + +v 2.44185876846 0.908871412277 0.591734528542 + +v 2.05942463875 1.9962515831 0.0 + +v 2.19379520416 1.58269298077 0.703589677811 + +v 1.70762968063 2.2518453598 0.703589677811 + +v -1.14343810081 2.69599509239 -0.591738045216 + +v -1.73517549038 2.26607275009 0.591737806797 + +v -0.365701913834 2.9486951828 -0.591737627983 + +v 0.365701913834 2.9486951828 0.591737627983 + +v -0.7866294384 2.92099428177 0.0 + +v -0.351796030998 2.92099094391 0.703592061996 + +v -1.13842558861 2.66539716721 0.703591346741 + +v -2.44185876846 0.0911285579205 -0.591734528542 + +v -2.21584224701 -0.604485869408 0.591737508774 + +v -2.44185876846 0.908871412277 -0.591734528542 + +v -2.21584224701 1.60448586941 0.591737508774 + +v -2.54558420181 0.5 0.0 + +v -2.41121101379 0.913549661636 0.70358890295 + +v -2.41121101379 0.086450368166 0.70358890295 + +v -0.365701913834 -1.9486951828 -0.591737627983 + +v 0.365701913834 -1.9486951828 0.591737627983 + +v -1.14343810081 -1.69599509239 -0.591738045216 + +v -1.73517549038 -1.26607263088 0.591737806797 + +v -0.7866294384 -1.92099428177 0.0 + +v -1.13842558861 -1.66539716721 0.703591346741 + +v -0.351796030998 -1.92099094391 0.703592061996 + +v 2.21584224701 -0.604485869408 -0.591737508774 + +v 2.44185876846 0.0911285579205 0.591734528542 + +v 1.14343810081 -1.69599509239 0.591738045216 + +v 1.73517549038 -1.26607263088 -0.591737806797 + +v 2.05942463875 -0.996251583099 0.0 + +v 1.70762968063 -1.25184524059 0.703589677811 + +v 2.19379520416 -0.582692980766 0.703589677811 + +v -0.0178840458393 2.69598531723 -1.28737258911 + +v 1.30525624752 2.26606321335 -1.28737187386 + +v 0.351796030998 2.92099094391 -0.703592061996 + +v 0.7866294384 2.92099428177 0.0 + +v 1.13842558861 2.66539716721 -0.703591346741 + +v -2.09404230118 1.1615729332 -1.28736424446 + +v -1.27628755569 2.28711080551 -1.28737151623 + +v -2.19379520416 1.58269298077 -0.703589677811 + +v -2.05942463875 1.9962515831 0.0 + +v -1.70762968063 2.2518453598 -0.703589677811 + +v -1.27628755569 -1.2871106863 -1.28737151623 + +v -2.09404230118 -0.161572933197 -1.28736424446 + +v -1.70762968063 -1.25184524059 -0.703589677811 + +v -2.05942463875 -0.996251583099 0.0 + +v -2.19379520416 -0.582692980766 -0.703589677811 + +v -0.0178840458393 -1.69598531723 -1.28737258911 + +v 1.30525624752 -1.26606333256 -1.28737187386 + +v 1.13842558861 -1.66539716721 -0.703591346741 + +v 0.7866294384 -1.92099428177 0.0 + +v 0.351796030998 -1.92099094391 -0.703592061996 + +v 2.08298039436 1.19561111927 -1.287368536 + +v 2.08298039436 -0.19561111927 -1.287368536 + +v 2.41121101379 0.913549661636 -0.70358890295 + +v 2.54558420181 0.5 0.0 + +v 2.41121101379 0.086450368166 -0.70358890295 + +v -0.580656588078 2.28710746765 -1.71728980541 + +v -0.214953452349 1.16156983376 -2.44869756699 + +v 1.52020871639 1.60448336601 -1.71728873253 + +v 0.562766730785 0.908869147301 -2.44869756699 + +v 0.351792931557 1.58268678188 -2.27684664726 + +v 0.921001434326 1.99624156952 -1.84201455116 + +v 0.134382337332 2.25183391571 -1.84201490879 + +v -1.87908375263 0.5 -1.71727788448 + +v -0.695621073246 0.5 -2.44869589806 + +v -0.920993208885 1.16913986206 -2.27684497833 + +v -1.13841235638 1.83828282356 -1.84201407433 + +v -1.62457787991 1.16914176941 -1.84200847149 + +v -0.580656588078 -1.28710758686 -1.71728980541 + +v -0.214953452349 -0.16156989336 -2.44869756699 + +v -0.920993208885 -0.169139921665 -2.27684497833 + +v -1.62457787991 -0.169141769409 -1.84200847149 + +v -1.13841235638 -0.838282823563 -1.84201407433 + +v 0.562766730785 0.0911308526993 -2.44869756699 + +v 1.52020871639 -0.604483366013 -1.71728873253 + +v 1.13841044903 0.5 -2.2768445015 + +v 1.70762121677 0.913547515869 -1.84201192856 + +v 1.70762121677 0.0864524841309 -1.84201192856 + +v 0.351792931557 -0.582686781883 -2.27684664726 + +v 0.134382337332 -1.25183391571 -1.84201490879 + +v 0.921001434326 -0.996241569519 -1.84201455116 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vt 0.0 0.0 0.0 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.45647957921 0.0 0.889733850956 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn 0.739546358585 0.0 0.673105597496 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn -0.45647957921 0.0 0.889733850956 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn 0.739546358585 0.0 0.673105597496 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn -0.271281123161 0.0 -0.962500154972 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.271281123161 0.0 -0.962500154972 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn 0.723606467247 -0.525720953941 -0.447226017714 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn -0.276378363371 -0.850650846958 -0.447222679853 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn 0.0 0.0 -1.0 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn 0.723606467247 -0.525720953941 -0.447226017714 + +vn 0.598305284977 -0.434689968824 -0.673108756542 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.723606467247 0.525720953941 -0.447226017714 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.0 0.0 -1.0 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn 0.219460606575 -0.159460678697 -0.962501585484 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.276378363371 -0.850650846958 -0.447222679853 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.228529512882 -0.703350901604 -0.673106133938 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.894433319569 0.0 -0.447201430798 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.271281123161 0.0 -0.962500154972 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn 0.0 0.0 -1.0 + +vn -0.0838349089026 -0.258005231619 -0.962499320507 + +vn -0.271281123161 0.0 -0.962500154972 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn -0.894433319569 0.0 -0.447201430798 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn -0.739546358585 0.0 -0.673105597496 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn -0.276378363371 0.850650846958 -0.447222679853 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.271281123161 0.0 -0.962500154972 + +vn 0.0 0.0 -1.0 + +vn -0.271281123161 0.0 -0.962500154972 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn -0.276378363371 0.850650846958 -0.447222679853 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn -0.228529512882 0.703350901604 -0.673106133938 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.723606467247 0.525720953941 -0.447226017714 + +vn 0.598305284977 0.434689968824 -0.673108756542 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn 0.0 0.0 -1.0 + +vn -0.0838349089026 0.258005231619 -0.962499320507 + +vn 0.219460606575 0.159460678697 -0.962501585484 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.723606467247 -0.525720953941 -0.447226017714 + +vn 0.817796707153 -0.275223553181 -0.505431056023 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.894433319569 0.0 0.447201430798 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.723606467247 0.525720953941 -0.447226017714 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.817796707153 0.275223553181 -0.505431056023 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn 0.0 -1.0 0.0 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn -0.276378363371 -0.850650846958 -0.447222679853 + +vn -0.00903354585171 -0.8628256917 -0.505420804024 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn 0.0 -1.0 0.0 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.276378363371 -0.850650846958 0.447222679853 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.723606467247 -0.525720953941 -0.447226017714 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.514485359192 -0.69271504879 -0.505421340466 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn -0.894433319569 0.0 -0.447201430798 + +vn -0.823386907578 -0.258012235165 -0.505434215069 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.723606467247 -0.525720953941 0.447226017714 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.276378363371 -0.850650846958 -0.447222679853 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.499821513891 -0.703357517719 -0.505437135696 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn -0.276378363371 0.850650846958 -0.447222679853 + +vn -0.499821513891 0.703357517719 -0.505437135696 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.723606467247 0.525720953941 0.447226017714 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.894433319569 0.0 -0.447201430798 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.823386907578 0.258012235165 -0.505434215069 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn 0.723606467247 0.525720953941 -0.447226017714 + +vn 0.514485359192 0.69271504879 -0.505421340466 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.0 1.0 0.0 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.276378363371 0.850650846958 0.447222679853 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn 0.0 1.0 0.0 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn -0.276378363371 0.850650846958 -0.447222679853 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn -0.00903354585171 0.8628256917 -0.505420804024 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn 0.894433319569 0.0 0.447201430798 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn 0.959042072296 -0.159463942051 0.234114408493 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn 0.276378363371 -0.850650846958 0.447222679853 + +vn 0.448016673326 -0.862828791142 0.234110057354 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.723606467247 -0.525720953941 -0.447226017714 + +vn 0.869619071484 -0.434687465429 -0.234114125371 + +vn 0.682156324387 -0.69271594286 -0.234109759331 + +vn 0.0 -1.0 0.0 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn 0.276378363371 -0.850650846958 0.447222679853 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn 0.144691079855 -0.961382389069 0.234112069011 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.723606467247 -0.525720953941 0.447226017714 + +vn -0.682156324387 -0.69271594286 0.234109759331 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn 0.0 -1.0 0.0 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn -0.276378363371 -0.850650846958 -0.447222679853 + +vn -0.144691079855 -0.961382389069 -0.234112069011 + +vn -0.448016673326 -0.862828791142 -0.234110057354 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.723606467247 -0.525720953941 0.447226017714 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.869619071484 -0.434687465429 0.234114125371 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.723606467247 0.525720953941 0.447226017714 + +vn -0.869619071484 0.434687465429 0.234114125371 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn -0.894433319569 0.0 -0.447201430798 + +vn -0.959042072296 -0.159463942051 -0.234114408493 + +vn -0.959042072296 0.159463942051 -0.234114408493 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn -0.723606467247 0.525720953941 0.447226017714 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn -0.682156324387 0.69271594286 0.234109759331 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn 0.0 1.0 0.0 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn 0.276378363371 0.850650846958 0.447222679853 + +vn 0.144691079855 0.961382389069 0.234112069011 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn 0.0 1.0 0.0 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.276378363371 0.850650846958 -0.447222679853 + +vn -0.448016673326 0.862828791142 -0.234110057354 + +vn -0.144691079855 0.961382389069 -0.234112069011 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.276378363371 0.850650846958 0.447222679853 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.448016673326 0.862828791142 0.234110057354 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.894433319569 0.0 0.447201430798 + +vn 0.959042072296 0.159463942051 0.234114408493 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn 0.723606467247 0.525720953941 -0.447226017714 + +vn 0.682156324387 0.69271594286 -0.234109759331 + +vn 0.869619071484 0.434687465429 -0.234114125371 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn 0.276378363371 -0.850650846958 0.447222679853 + +vn 0.499821513891 -0.703357517719 0.505437135696 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.0 0.0 1.0 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.739546358585 0.0 0.673105597496 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.894433319569 0.0 0.447201430798 + +vn 0.739546358585 0.0 0.673105597496 + +vn 0.823386907578 -0.258012235165 0.505434215069 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn -0.723606467247 -0.525720953941 0.447226017714 + +vn -0.514485359192 -0.69271504879 0.505421340466 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn 0.0 0.0 1.0 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn 0.0838349089026 -0.258005231619 0.962499320507 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn 0.276378363371 -0.850650846958 0.447222679853 + +vn 0.228529512882 -0.703350901604 0.673106133938 + +vn 0.00903354585171 -0.8628256917 0.505420804024 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn -0.723606467247 0.525720953941 0.447226017714 + +vn -0.817796707153 0.275223553181 0.505431056023 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.45647957921 0.0 0.889733850956 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn -0.45647957921 0.0 0.889733850956 + +vn 0.0 0.0 1.0 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn -0.219460606575 -0.159460678697 0.962501585484 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.723606467247 -0.525720953941 0.447226017714 + +vn -0.598305284977 -0.434689968824 0.673108756542 + +vn -0.817796707153 -0.275223553181 0.505431056023 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn 0.276378363371 0.850650846958 0.447222679853 + +vn 0.00903354585171 0.8628256917 0.505420804024 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn 0.0 0.0 1.0 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn -0.219460606575 0.159460678697 0.962501585484 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn -0.723606467247 0.525720953941 0.447226017714 + +vn -0.598305284977 0.434689968824 0.673108756542 + +vn -0.514485359192 0.69271504879 0.505421340466 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.739546358585 0.0 0.673105597496 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn 0.894433319569 0.0 0.447201430798 + +vn 0.823386907578 0.258012235165 0.505434215069 + +vn 0.739546358585 0.0 0.673105597496 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.0 0.0 1.0 + +vn 0.271281123161 0.0 0.962500154972 + +vn 0.0838349089026 0.258005231619 0.962499320507 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.276378363371 0.850650846958 0.447222679853 + +vn 0.228529512882 0.703350901604 0.673106133938 + +vn 0.499821513891 0.703357517719 0.505437135696 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn 0.369288951159 0.268299132586 0.889742255211 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.450069189072 0.516845583916 0.728222727776 + +vn 0.630648136139 0.268294006586 0.728217899799 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn 0.162452682853 0.499992907047 0.850656330585 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn -0.141060844064 0.434139043093 0.889733195305 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn -0.352471232414 0.587747097015 0.728228986263 + +vn -0.0603060387075 0.682685136795 0.728219866753 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.45647957921 0.0 0.889733850956 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.425314754248 0.309006273746 0.850659966469 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn -0.45647957921 0.0 0.889733850956 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.667911529541 -0.153602868319 0.728217303753 + +vn -0.667911529541 0.153602868319 0.728217303753 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn -0.425314754248 -0.309006273746 0.850659966469 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn -0.141060844064 -0.434139043093 0.889733195305 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn -0.0603060387075 -0.682685136795 0.728219866753 + +vn -0.352471232414 -0.587747097015 0.728228986263 + +vn 0.525720894337 0.0 0.850657105446 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.162452682853 -0.499992907047 0.850656330585 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn 0.369288951159 -0.268299132586 0.889742255211 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.630648136139 -0.268294006586 0.728217899799 + +vn 0.450069189072 -0.516845583916 0.728222727776 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.688187897205 0.500003635883 0.525731682777 + +vn 0.85889595747 0.434132635593 0.271710574627 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.678318798542 0.682683110237 0.271712064743 + +vn 0.808980166912 0.587744355202 0.010376627557 + +vn 0.0 1.0 0.0 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn -0.26286610961 0.809016048908 0.525732219219 + +vn -0.147469341755 0.951012432575 0.271713465452 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.439665496349 0.856075108051 0.271716088057 + +vn -0.309005230665 0.951003730297 0.0103764729574 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.850657105446 0.0 0.525720894337 + +vn -0.950040400028 0.153604477644 0.271714806557 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.950040400028 -0.153604477644 0.271714806557 + +vn -0.999946177006 0.0 0.0103763686493 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn -0.26286610961 -0.809016048908 0.525732219219 + +vn -0.439665496349 -0.856075108051 0.271716088057 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn 0.0 -1.0 0.0 + +vn -0.147469341755 -0.951012432575 0.271713465452 + +vn -0.309005230665 -0.951003730297 0.0103764729574 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn 0.688187897205 -0.500003635883 0.525731682777 + +vn 0.678318798542 -0.682683110237 0.271712064743 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.85889595747 -0.434132635593 0.271710574627 + +vn 0.808980166912 -0.587744355202 0.010376627557 + +vn 0.0 1.0 0.0 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn 0.587767004967 0.809030294418 0.0 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn 0.309005230665 0.951003730297 -0.0103764729574 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn 0.147469341755 0.951012432575 -0.271713465452 + +vn 0.439665496349 0.856075108051 -0.271716088057 + +vn -0.951060771942 0.309003949165 0.0 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.587767004967 0.809030294418 0.0 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn -0.808980166912 0.587744355202 -0.010376627557 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.85889595747 0.434132635593 -0.271710574627 + +vn -0.678318798542 0.682683110237 -0.271712064743 + +vn -0.587767004967 -0.809030294418 0.0 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.951060771942 -0.309003949165 0.0 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn -0.808980166912 -0.587744355202 -0.010376627557 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.678318798542 -0.682683110237 -0.271712064743 + +vn -0.85889595747 -0.434132635593 -0.271710574627 + +vn 0.587767004967 -0.809030294418 0.0 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.0 -1.0 0.0 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn 0.309005230665 -0.951003730297 -0.0103764729574 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn 0.439665496349 -0.856075108051 -0.271716088057 + +vn 0.147469341755 -0.951012432575 -0.271713465452 + +vn 0.951060771942 0.309003949165 0.0 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.951060771942 -0.309003949165 0.0 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.999946177006 0.0 -0.0103763686493 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.950040400028 0.153604477644 -0.271714806557 + +vn 0.950040400028 -0.153604477644 -0.271714806557 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn 0.26286610961 0.809016048908 -0.525732219219 + +vn 0.352471232414 0.587747097015 -0.728228986263 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn 0.0603060387075 0.682685136795 -0.728219866753 + +vn 0.141060844064 0.434139043093 -0.889733195305 + +vn -0.162452682853 0.499992907047 -0.850656330585 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn -0.688187897205 0.500003635883 -0.525731682777 + +vn -0.450069189072 0.516845583916 -0.728222727776 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.630648136139 0.268294006586 -0.728217899799 + +vn -0.369288951159 0.268299132586 -0.889742255211 + +vn -0.525720894337 0.0 -0.850657105446 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.688187897205 -0.500003635883 -0.525731682777 + +vn -0.630648136139 -0.268294006586 -0.728217899799 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn -0.450069189072 -0.516845583916 -0.728222727776 + +vn -0.369288951159 -0.268299132586 -0.889742255211 + +vn 0.425314754248 0.309006273746 -0.850659966469 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.850657105446 0.0 -0.525720894337 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn 0.667911529541 0.153602868319 -0.728217303753 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.45647957921 0.0 -0.889733850956 + +vn 0.667911529541 -0.153602868319 -0.728217303753 + +vn -0.162452682853 -0.499992907047 -0.850656330585 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn 0.26286610961 -0.809016048908 -0.525732219219 + +vn 0.0603060387075 -0.682685136795 -0.728219866753 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.425314754248 -0.309006273746 -0.850659966469 + +vn 0.352471232414 -0.587747097015 -0.728228986263 + +vn 0.141060844064 -0.434139043093 -0.889733195305 + +f 160/1/1 162/2/2 161/3/3 + +f 157/4/4 158/5/5 159/6/6 + +f 152/7/7 154/8/8 153/9/9 + +f 147/10/10 149/11/11 148/12/12 + +f 142/13/13 144/14/14 143/15/15 + +f 135/16/16 136/17/17 137/18/18 + +f 130/19/19 131/20/20 132/21/21 + +f 125/22/22 126/23/23 127/24/24 + +f 120/25/25 121/26/26 122/27/27 + +f 115/28/28 116/29/29 117/30/30 + +f 110/31/31 112/32/32 111/33/33 + +f 103/34/34 105/35/35 104/36/36 + +f 96/37/37 98/38/38 97/39/39 + +f 89/40/40 91/41/41 90/42/42 + +f 82/43/43 84/44/44 83/45/45 + +f 75/46/46 76/47/47 77/48/48 + +f 70/49/49 71/50/50 72/51/51 + +f 63/52/52 64/53/53 65/54/54 + +f 56/55/55 57/56/56 58/57/57 + +f 49/58/58 50/59/59 51/60/60 + +f 45/61/61 49/62/62 43/63/63 + +f 48/64/64 50/65/65 46/66/66 + +f 44/67/67 51/68/68 47/69/69 + +f 54/70/70 56/71/71 52/72/72 + +f 46/73/73 57/74/74 55/75/75 + +f 53/76/76 58/77/77 45/78/78 + +f 61/79/79 63/80/80 59/81/81 + +f 55/82/82 64/83/83 62/84/84 + +f 60/85/85 65/86/86 54/87/87 + +f 68/88/88 70/89/89 66/90/90 + +f 62/91/91 71/92/92 69/93/93 + +f 67/94/94 72/95/95 61/96/96 + +f 47/97/97 75/98/98 74/99/99 + +f 69/100/100 76/101/101 48/102/102 + +f 73/103/103 77/104/104 68/105/105 + +f 80/106/106 78/107/107 82/108/108 + +f 44/109/109 81/110/110 83/111/111 + +f 79/112/112 43/113/113 84/114/114 + +f 87/115/115 85/116/116 89/117/117 + +f 53/118/118 88/119/119 90/120/120 + +f 86/121/121 52/122/122 91/123/123 + +f 94/124/124 92/125/125 96/126/126 + +f 60/127/127 95/128/128 97/129/129 + +f 93/130/130 59/131/131 98/132/132 + +f 101/133/133 99/134/134 103/135/135 + +f 67/136/136 102/137/137 104/138/138 + +f 100/139/139 66/140/140 105/141/141 + +f 109/142/142 106/143/143 110/144/144 + +f 73/145/145 108/146/146 111/147/147 + +f 107/148/148 74/149/149 112/150/150 + +f 87/151/151 115/152/152 113/153/153 + +f 79/154/154 116/155/155 88/156/156 + +f 114/157/157 117/158/158 78/159/159 + +f 94/160/160 120/161/161 118/162/162 + +f 86/163/163 121/164/164 95/165/165 + +f 119/166/166 122/167/167 85/168/168 + +f 101/169/169 125/170/170 123/171/171 + +f 93/172/172 126/173/173 102/174/174 + +f 124/175/175 127/176/176 92/177/177 + +f 109/178/178 130/179/179 129/180/180 + +f 100/181/181 131/182/182 108/183/183 + +f 128/184/184 132/185/185 99/186/186 + +f 80/187/187 135/188/188 133/189/189 + +f 107/190/190 136/191/191 81/192/192 + +f 134/193/193 137/194/194 106/195/195 + +f 141/196/196 139/197/197 142/198/198 + +f 114/199/199 140/200/200 143/201/201 + +f 138/202/202 113/203/203 144/204/204 + +f 139/205/205 146/206/206 147/207/207 + +f 119/208/208 138/209/209 148/210/210 + +f 145/211/211 118/212/212 149/213/213 + +f 146/214/214 151/215/215 152/216/216 + +f 124/217/217 145/218/218 153/219/219 + +f 150/220/220 123/221/221 154/222/222 + +f 141/223/223 157/224/224 155/225/225 + +f 133/226/226 158/227/227 140/228/228 + +f 156/229/229 159/230/230 134/231/231 + +f 151/232/232 155/233/233 160/234/234 + +f 128/235/235 150/236/236 161/237/237 + +f 156/238/238 129/239/239 162/240/240 + +f 13/241/241 156/242/242 162/243/243 + +f 15/244/244 162/245/245 129/246/246 + +f 2/247/247 129/248/248 156/249/249 + +f 15/250/250 128/251/251 161/252/252 + +f 14/253/253 161/254/254 150/255/255 + +f 3/256/256 150/257/257 128/258/258 + +f 14/259/259 151/260/260 160/261/261 + +f 13/262/262 160/263/263 155/264/264 + +f 1/265/265 155/266/266 151/267/267 + +f 13/268/268 159/269/269 156/270/270 + +f 17/271/271 134/272/272 159/273/273 + +f 2/274/274 156/275/275 134/276/276 + +f 17/277/277 158/278/278 133/279/279 + +f 16/280/280 140/281/281 158/282/282 + +f 6/283/283 133/284/284 140/285/285 + +f 16/286/286 157/287/287 141/288/288 + +f 13/289/289 155/290/290 157/291/291 + +f 1/292/292 141/293/293 155/294/294 + +f 14/295/295 150/296/296 154/297/297 + +f 19/298/298 154/299/299 123/300/300 + +f 3/301/301 123/302/302 150/303/303 + +f 19/304/304 124/305/305 153/306/306 + +f 18/307/307 153/308/308 145/309/309 + +f 4/310/310 145/311/311 124/312/312 + +f 18/313/313 146/314/314 152/315/315 + +f 14/316/316 152/317/317 151/318/318 + +f 1/319/319 151/320/320 146/321/321 + +f 18/322/322 145/323/323 149/324/324 + +f 21/325/325 149/326/326 118/327/327 + +f 4/328/328 118/329/329 145/330/330 + +f 21/331/331 119/332/332 148/333/333 + +f 20/334/334 148/335/335 138/336/336 + +f 5/337/337 138/338/338 119/339/339 + +f 20/340/340 139/341/341 147/342/342 + +f 18/343/343 147/344/344 146/345/345 + +f 1/346/346 146/347/347 139/348/348 + +f 20/349/349 138/350/350 144/351/351 + +f 22/352/352 144/353/353 113/354/354 + +f 5/355/355 113/356/356 138/357/357 + +f 22/358/358 114/359/359 143/360/360 + +f 16/361/361 143/362/362 140/363/363 + +f 6/364/364 140/365/365 114/366/366 + +f 16/367/367 141/368/368 142/369/369 + +f 20/370/370 142/371/371 139/372/372 + +f 1/373/373 139/374/374 141/375/375 + +f 17/376/376 137/377/377 134/378/378 + +f 24/379/379 106/380/380 137/381/381 + +f 2/382/382 134/383/383 106/384/384 + +f 24/385/385 136/386/386 107/387/387 + +f 23/388/388 81/389/389 136/390/390 + +f 11/391/391 107/392/392 81/393/393 + +f 23/394/394 135/395/395 80/396/396 + +f 17/397/397 133/398/398 135/399/399 + +f 6/400/400 80/401/401 133/402/402 + +f 15/403/403 132/404/404 128/405/405 + +f 26/406/406 99/407/407 132/408/408 + +f 3/409/409 128/410/410 99/411/411 + +f 26/412/412 131/413/413 100/414/414 + +f 25/415/415 108/416/416 131/417/417 + +f 7/418/418 100/419/419 108/420/420 + +f 25/421/421 130/422/422 109/423/423 + +f 15/424/424 129/425/425 130/426/426 + +f 2/427/427 109/428/428 129/429/429 + +f 19/430/430 127/431/431 124/432/432 + +f 28/433/433 92/434/434 127/435/435 + +f 4/436/436 124/437/437 92/438/438 + +f 28/439/439 126/440/440 93/441/441 + +f 27/442/442 102/443/443 126/444/444 + +f 8/445/445 93/446/446 102/447/447 + +f 27/448/448 125/449/449 101/450/450 + +f 19/451/451 123/452/452 125/453/453 + +f 3/454/454 101/455/455 123/456/456 + +f 21/457/457 122/458/458 119/459/459 + +f 30/460/460 85/461/461 122/462/462 + +f 5/463/463 119/464/464 85/465/465 + +f 30/466/466 121/467/467 86/468/468 + +f 29/469/469 95/470/470 121/471/471 + +f 9/472/472 86/473/473 95/474/474 + +f 29/475/475 120/476/476 94/477/477 + +f 21/478/478 118/479/479 120/480/480 + +f 4/481/481 94/482/482 118/483/483 + +f 22/484/484 117/485/485 114/486/486 + +f 32/487/487 78/488/488 117/489/489 + +f 6/490/490 114/491/491 78/492/492 + +f 32/493/493 116/494/494 79/495/495 + +f 31/496/496 88/497/497 116/498/498 + +f 10/499/499 79/500/500 88/501/501 + +f 31/502/502 115/503/503 87/504/504 + +f 22/505/505 113/506/506 115/507/507 + +f 5/508/508 87/509/509 113/510/510 + +f 24/511/511 107/512/512 112/513/513 + +f 33/514/514 112/515/515 74/516/516 + +f 11/517/517 74/518/518 107/519/519 + +f 33/520/520 73/521/521 111/522/522 + +f 25/523/523 111/524/524 108/525/525 + +f 7/526/526 108/527/527 73/528/528 + +f 25/529/529 109/530/530 110/531/531 + +f 24/532/532 110/533/533 106/534/534 + +f 2/535/535 106/536/536 109/537/537 + +f 26/538/538 100/539/539 105/540/540 + +f 34/541/541 105/542/542 66/543/543 + +f 7/544/544 66/545/545 100/546/546 + +f 34/547/547 67/548/548 104/549/549 + +f 27/550/550 104/551/551 102/552/552 + +f 8/553/553 102/554/554 67/555/555 + +f 27/556/556 101/557/557 103/558/558 + +f 26/559/559 103/560/560 99/561/561 + +f 3/562/562 99/563/563 101/564/564 + +f 28/565/565 93/566/566 98/567/567 + +f 35/568/568 98/569/569 59/570/570 + +f 8/571/571 59/572/572 93/573/573 + +f 35/574/574 60/575/575 97/576/576 + +f 29/577/577 97/578/578 95/579/579 + +f 9/580/580 95/581/581 60/582/582 + +f 29/583/583 94/584/584 96/585/585 + +f 28/586/586 96/587/587 92/588/588 + +f 4/589/589 92/590/590 94/591/591 + +f 30/592/592 86/593/593 91/594/594 + +f 36/595/595 91/596/596 52/597/597 + +f 9/598/598 52/599/599 86/600/600 + +f 36/601/601 53/602/602 90/603/603 + +f 31/604/604 90/605/605 88/606/606 + +f 10/607/607 88/608/608 53/609/609 + +f 31/610/610 87/611/611 89/612/612 + +f 30/613/613 89/614/614 85/615/615 + +f 5/616/616 85/617/617 87/618/618 + +f 32/619/619 79/620/620 84/621/621 + +f 37/622/622 84/623/623 43/624/624 + +f 10/625/625 43/626/626 79/627/627 + +f 37/628/628 44/629/629 83/630/630 + +f 23/631/631 83/632/632 81/633/633 + +f 11/634/634 81/635/635 44/636/636 + +f 23/637/637 80/638/638 82/639/639 + +f 32/640/640 82/641/641 78/642/642 + +f 6/643/643 78/644/644 80/645/645 + +f 33/646/646 77/647/647 73/648/648 + +f 39/649/649 68/650/650 77/651/651 + +f 7/652/652 73/653/653 68/654/654 + +f 39/655/655 76/656/656 69/657/657 + +f 38/658/658 48/659/659 76/660/660 + +f 12/661/661 69/662/662 48/663/663 + +f 38/664/664 75/665/665 47/666/666 + +f 33/667/667 74/668/668 75/669/669 + +f 11/670/670 47/671/671 74/672/672 + +f 34/673/673 72/674/674 67/675/675 + +f 40/676/676 61/677/677 72/678/678 + +f 8/679/679 67/680/680 61/681/681 + +f 40/682/682 71/683/683 62/684/684 + +f 39/685/685 69/686/686 71/687/687 + +f 12/688/688 62/689/689 69/690/690 + +f 39/691/691 70/692/692 68/693/693 + +f 34/694/694 66/695/695 70/696/696 + +f 7/697/697 68/698/698 66/699/699 + +f 35/700/700 65/701/701 60/702/702 + +f 41/703/703 54/704/704 65/705/705 + +f 9/706/706 60/707/707 54/708/708 + +f 41/709/709 64/710/710 55/711/711 + +f 40/712/712 62/713/713 64/714/714 + +f 12/715/715 55/716/716 62/717/717 + +f 40/718/718 63/719/719 61/720/720 + +f 35/721/721 59/722/722 63/723/723 + +f 8/724/724 61/725/725 59/726/726 + +f 36/727/727 58/728/728 53/729/729 + +f 42/730/730 45/731/731 58/732/732 + +f 10/733/733 53/734/734 45/735/735 + +f 42/736/736 57/737/737 46/738/738 + +f 41/739/739 55/740/740 57/741/741 + +f 12/742/742 46/743/743 55/744/744 + +f 41/745/745 56/746/746 54/747/747 + +f 36/748/748 52/749/749 56/750/750 + +f 9/751/751 54/752/752 52/753/753 + +f 37/754/754 51/755/755 44/756/756 + +f 38/757/757 47/758/758 51/759/759 + +f 11/760/760 44/761/761 47/762/762 + +f 38/763/763 50/764/764 48/765/765 + +f 42/766/766 46/767/767 50/768/768 + +f 12/769/769 48/770/770 46/771/771 + +f 42/772/772 49/773/773 45/774/774 + +f 37/775/775 43/776/776 49/777/777 + +f 10/778/778 45/779/779 43/780/780 + +f 42/781/781 50/782/782 49/783/783 + +f 38/784/784 51/785/785 50/786/786 + +f 37/787/787 49/788/788 51/789/789 + +f 41/790/790 57/791/791 56/792/792 + +f 42/793/793 58/794/794 57/795/795 + +f 36/796/796 56/797/797 58/798/798 + +f 40/799/799 64/800/800 63/801/801 + +f 41/802/802 65/803/803 64/804/804 + +f 35/805/805 63/806/806 65/807/807 + +f 39/808/808 71/809/809 70/810/810 + +f 40/811/811 72/812/812 71/813/813 + +f 34/814/814 70/815/815 72/816/816 + +f 38/817/817 76/818/818 75/819/819 + +f 39/820/820 77/821/821 76/822/822 + +f 33/823/823 75/824/824 77/825/825 + +f 23/826/826 82/827/827 83/828/828 + +f 37/829/829 83/830/830 84/831/831 + +f 32/832/832 84/833/833 82/834/834 + +f 31/835/835 89/836/836 90/837/837 + +f 36/838/838 90/839/839 91/840/840 + +f 30/841/841 91/842/842 89/843/843 + +f 29/844/844 96/845/845 97/846/846 + +f 35/847/847 97/848/848 98/849/849 + +f 28/850/850 98/851/851 96/852/852 + +f 27/853/853 103/854/854 104/855/855 + +f 34/856/856 104/857/857 105/858/858 + +f 26/859/859 105/860/860 103/861/861 + +f 25/862/862 110/863/863 111/864/864 + +f 33/865/865 111/866/866 112/867/867 + +f 24/868/868 112/869/869 110/870/870 + +f 31/871/871 116/872/872 115/873/873 + +f 32/874/874 117/875/875 116/876/876 + +f 22/877/877 115/878/878 117/879/879 + +f 29/880/880 121/881/881 120/882/882 + +f 30/883/883 122/884/884 121/885/885 + +f 21/886/886 120/887/887 122/888/888 + +f 27/889/889 126/890/890 125/891/891 + +f 28/892/892 127/893/893 126/894/894 + +f 19/895/895 125/896/896 127/897/897 + +f 25/898/898 131/899/899 130/900/900 + +f 26/901/901 132/902/902 131/903/903 + +f 15/904/904 130/905/905 132/906/906 + +f 23/907/907 136/908/908 135/909/909 + +f 24/910/910 137/911/911 136/912/912 + +f 17/913/913 135/914/914 137/915/915 + +f 16/916/916 142/917/917 143/918/918 + +f 22/919/919 143/920/920 144/921/921 + +f 20/922/922 144/923/923 142/924/924 + +f 20/925/925 147/926/926 148/927/927 + +f 21/928/928 148/929/929 149/930/930 + +f 18/931/931 149/932/932 147/933/933 + +f 18/934/934 152/935/935 153/936/936 + +f 19/937/937 153/938/938 154/939/939 + +f 14/940/940 154/941/941 152/942/942 + +f 16/943/943 158/944/944 157/945/945 + +f 17/946/946 159/947/947 158/948/948 + +f 13/949/949 157/950/950 159/951/951 + +f 14/952/952 160/953/953 161/954/954 + +f 15/955/955 161/956/956 162/957/957 + +f 13/958/958 162/959/959 160/960/960 diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..1e21385 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "zworld/engine" + "zworld/engine/core/zlog" + "zworld/engine/rule" + "zworld/plugin/objloader" +) + +func main() { + w := engine.NewWorld(nil, engine.FTimeRuleOption(&rule.FTimeRule{}), engine.FActorRuleOption(&rule.FActorRule{})) + for i := 1; i < 100; i++ { + w.Tick() + } + err, mesh := objloader.LoadObj("asset/model/sphere.obj") + zlog.Infof("err", err, len(mesh.Positions)) +} diff --git a/engine/actor/Component/mesh.go b/engine/actor/Component/mesh.go new file mode 100644 index 0000000..c192233 --- /dev/null +++ b/engine/actor/Component/mesh.go @@ -0,0 +1 @@ +package Component diff --git a/engine/actor/Component/root.go b/engine/actor/Component/root.go new file mode 100644 index 0000000..c192233 --- /dev/null +++ b/engine/actor/Component/root.go @@ -0,0 +1 @@ +package Component diff --git a/engine/actor/Component/type.go b/engine/actor/Component/type.go new file mode 100644 index 0000000..e7b3bfc --- /dev/null +++ b/engine/actor/Component/type.go @@ -0,0 +1,4 @@ +package Component + +type IComponent interface { +} diff --git a/engine/actor/actor.go b/engine/actor/actor.go new file mode 100644 index 0000000..303d201 --- /dev/null +++ b/engine/actor/actor.go @@ -0,0 +1,17 @@ +package actor + +import ( + "zworld/engine/actor/Component" +) + +type FActorCompWrap struct { + Render Component.IComponent +} +type FActor struct { + CompList []Component.IComponent + CompWrap *FActorCompWrap +} + +func (r *FActor) Tick(delta float32) { + +} diff --git a/engine/core/zlog/type.go b/engine/core/zlog/type.go new file mode 100644 index 0000000..8fba21f --- /dev/null +++ b/engine/core/zlog/type.go @@ -0,0 +1,16 @@ +package zlog + +import ( + "go.uber.org/zap/zapcore" +) + +// Level is type of log levels +type Level = zapcore.Level + +type FLogf = func(template string, args ...interface{}) +type FLog = func(args ...interface{}) + +var ( + Debugf, Infof, Warnf, Errorf, Panicf, Fatalf FLogf + Debug, Error, Panic, Fatal FLog +) diff --git a/engine/core/zlog/zlog.go b/engine/core/zlog/zlog.go new file mode 100644 index 0000000..f121cc4 --- /dev/null +++ b/engine/core/zlog/zlog.go @@ -0,0 +1,98 @@ +package zlog + +import ( + "go.uber.org/zap" + "strings" +) + +var ( + cfg zap.Config + logger *zap.Logger + sugar *zap.SugaredLogger + source string + currentLevel Level +) + +func init() { + currentLevel = zap.DebugLevel + cfg = zap.NewDevelopmentConfig() + cfg.Development = true + rebuildLoggerFromCfg() +} + +// SetSource sets the component name (dispatcher/gate/game) of gwlog module +func SetSource(source_ string) { + source = source_ + rebuildLoggerFromCfg() +} + +func SetParseLevel(slv string) { + lv := ParseLevel(slv) + SetLevel(lv) +} + +// SetLevel sets the zlog level +func SetLevel(lv Level) { + currentLevel = lv + cfg.Level.SetLevel(lv) +} + +// GetLevel get the current zlog level +func GetLevel() Level { + return currentLevel +} + +// SetOutput sets the output writer +func SetOutput(outputs []string) { + cfg.OutputPaths = outputs + rebuildLoggerFromCfg() +} + +// ParseLevel converts string to Levels +func ParseLevel(s string) Level { + if strings.ToLower(s) == "debug" { + return zap.DebugLevel + } else if strings.ToLower(s) == "info" { + return zap.InfoLevel + } else if strings.ToLower(s) == "warn" || strings.ToLower(s) == "warning" { + return zap.WarnLevel + } else if strings.ToLower(s) == "error" { + return zap.ErrorLevel + } else if strings.ToLower(s) == "panic" { + return zap.PanicLevel + } else if strings.ToLower(s) == "fatal" { + return zap.FatalLevel + } + Errorf("ParseLevel: unknown level: %s", s) + return zap.DebugLevel +} + +func rebuildLoggerFromCfg() { + newLogger, err := cfg.Build() + if err != nil { + panic(err) + return + } + if logger != nil { + logger.Sync() + } + logger = newLogger + if source != "" { + logger = logger.With(zap.String("source", source)) + } + sugar = logger.Sugar() + initFLog() +} +func initFLog() { + Debugf = sugar.Debugf + Infof = sugar.Infof + Warnf = sugar.Warnf + Errorf = sugar.Errorf + Panicf = sugar.Panicf + Fatalf = sugar.Fatalf + + Debug = sugar.Debug + Error = sugar.Error + Panic = sugar.Panic + Fatal = sugar.Fatal +} diff --git a/engine/render/vulkan/instance/ext_linux.go b/engine/render/vulkan/instance/ext_linux.go new file mode 100644 index 0000000..e0c8136 --- /dev/null +++ b/engine/render/vulkan/instance/ext_linux.go @@ -0,0 +1,15 @@ +package instance + +import ( + "github.com/vkngwrapper/extensions/v2/ext_debug_utils" + "github.com/vkngwrapper/extensions/v2/khr_get_physical_device_properties2" + "github.com/vkngwrapper/extensions/v2/khr_surface" +) + +var extensions = []string{ + khr_surface.ExtensionName, + khr_get_physical_device_properties2.ExtensionName, + ext_debug_utils.ExtensionName, + + "VK_KHR_xcb_surface", +} diff --git a/engine/render/vulkan/instance/ext_windows.go b/engine/render/vulkan/instance/ext_windows.go new file mode 100644 index 0000000..3ed00f0 --- /dev/null +++ b/engine/render/vulkan/instance/ext_windows.go @@ -0,0 +1,16 @@ +package instance + +import ( + "github.com/vkngwrapper/extensions/v2/ext_debug_utils" + "github.com/vkngwrapper/extensions/v2/khr_get_physical_device_properties2" + "github.com/vkngwrapper/extensions/v2/khr_surface" +) + +var extensions = []string{ + khr_surface.ExtensionName, + ext_debug_utils.ExtensionName, + khr_get_physical_device_properties2.ExtensionName, + + "VK_EXT_debug_report", + "VK_EXT_metal_surface", +} diff --git a/engine/render/vulkan/instance/instance.go b/engine/render/vulkan/instance/instance.go new file mode 100644 index 0000000..0831518 --- /dev/null +++ b/engine/render/vulkan/instance/instance.go @@ -0,0 +1,62 @@ +package instance + +import ( + "github.com/go-gl/glfw/v3.3/glfw" + "github.com/vkngwrapper/core/v2" + "github.com/vkngwrapper/core/v2/common" + "github.com/vkngwrapper/core/v2/core1_0" +) + +var layers = []string{ + "VK_LAYER_KHRONOS_validation", + //"VK_LAYER_LUNARG_api_dump", +} + +type T interface { + EnumeratePhysicalDevices() []core1_0.PhysicalDevice + Destroy() + Ptr() core1_0.Instance +} + +type instance struct { + ptr core1_0.Instance +} + +func New(appName string) T { + loader, err := core.CreateLoaderFromProcAddr(glfw.GetVulkanGetInstanceProcAddress()) + if err != nil { + panic(err) + } + handle, _, err := loader.CreateInstance(nil, core1_0.InstanceCreateInfo{ + APIVersion: common.APIVersion(common.CreateVersion(1, 1, 0)), + ApplicationName: appName, + ApplicationVersion: common.CreateVersion(0, 1, 0), + EngineName: "goworld", + EngineVersion: common.CreateVersion(0, 2, 1), + EnabledLayerNames: layers, + EnabledExtensionNames: extensions, + }) + if err != nil { + panic(err) + } + return &instance{ + ptr: handle, + } +} + +func (i *instance) Ptr() core1_0.Instance { + return i.ptr +} + +func (i *instance) Destroy() { + i.ptr.Destroy(nil) + i.ptr = nil +} + +func (i *instance) EnumeratePhysicalDevices() []core1_0.PhysicalDevice { + r, _, err := i.ptr.EnumeratePhysicalDevices() + if err != nil { + panic(err) + } + return r +} diff --git a/engine/rule/actor.go b/engine/rule/actor.go new file mode 100644 index 0000000..546c3b6 --- /dev/null +++ b/engine/rule/actor.go @@ -0,0 +1,21 @@ +package rule + +type FActor struct { +} + +func (r *FActor) Tick(delta float32) { + +} + +type FActorRule struct { + actorList []*FActor +} + +func (r *FActorRule) Tick(w IWorld, delta float32) { + for _, actor := range r.actorList { + actor.Tick(delta) + } +} +func (r *FActorRule) GetPriority() RulePriority { + return EActorRule +} diff --git a/engine/rule/render.go b/engine/rule/render.go new file mode 100644 index 0000000..7958b0f --- /dev/null +++ b/engine/rule/render.go @@ -0,0 +1,11 @@ +package rule + +type FRenderRule struct { +} + +func (r *FRenderRule) Tick(w IWorld, delta float32) { + +} +func (r *FRenderRule) GetPriority() RulePriority { + return ERenderRule +} diff --git a/engine/rule/time.go b/engine/rule/time.go new file mode 100644 index 0000000..a8e9995 --- /dev/null +++ b/engine/rule/time.go @@ -0,0 +1,21 @@ +package rule + +type FTimeRule struct { + isPause bool + interval float32 +} + +func (r *FTimeRule) GetInterval() float32 { + if r.isPause { + return 0 + } + return r.interval +} +func (r *FTimeRule) Tick(w IWorld, delta float32) { + if r.isPause { + return + } +} +func (r *FTimeRule) GetPriority() RulePriority { + return ETimeRule +} diff --git a/engine/rule/type.go b/engine/rule/type.go new file mode 100644 index 0000000..ea860fc --- /dev/null +++ b/engine/rule/type.go @@ -0,0 +1,16 @@ +package rule + +type IWorld interface { +} +type IRule interface { + Tick(w IWorld, delta float32) + GetPriority() RulePriority +} + +type RulePriority int + +const ( + ETimeRule = iota + ERenderRule + EActorRule +) diff --git a/engine/type.go b/engine/type.go new file mode 100644 index 0000000..f750cfc --- /dev/null +++ b/engine/type.go @@ -0,0 +1,7 @@ +package engine + +import "zworld/engine/rule" + +type ( + IRule = rule.IRule +) diff --git a/engine/world.go b/engine/world.go new file mode 100644 index 0000000..d391c97 --- /dev/null +++ b/engine/world.go @@ -0,0 +1,26 @@ +package engine + +import ( + "zworld/engine/rule" +) + +type FWorldRuleWrap struct { + TimeRule *rule.FTimeRule + ActorRule *rule.FActorRule +} +type FWorld struct { + Name string + RuleList []IRule + RuleWrap *FWorldRuleWrap +} + +func (w *FWorld) Tick() { + delta := w.RuleWrap.TimeRule.GetInterval() + if delta == 0 { + w.RuleWrap.TimeRule.Tick(w, delta) + return + } + for _, rule := range w.RuleList { + rule.Tick(w, delta) + } +} diff --git a/engine/world_new.go b/engine/world_new.go new file mode 100644 index 0000000..50cb3b7 --- /dev/null +++ b/engine/world_new.go @@ -0,0 +1,39 @@ +package engine + +import ( + "sort" + "zworld/engine/rule" +) + +type FWorldOption func(*FWorld) + +func FTimeRuleOption(rule *rule.FTimeRule) FWorldOption { + return func(world *FWorld) { + world.RuleWrap.TimeRule = rule + world.RuleList = append(world.RuleList, rule) + } +} +func FActorRuleOption(rule *rule.FActorRule) FWorldOption { + return func(world *FWorld) { + world.RuleWrap.ActorRule = rule + world.RuleList = append(world.RuleList, rule) + } +} +func NewWorld(wrap *FWorldRuleWrap, ops ...FWorldOption) *FWorld { + w := FWorld{} + if wrap == nil { + wrap = &FWorldRuleWrap{} + } + w.RuleWrap = wrap + for _, op := range ops { + op(&w) + } + sort.Slice(w.RuleList, func(i, j int) bool { + pi, pj := w.RuleList[i].GetPriority(), w.RuleList[j].GetPriority() + if pi != pj { + return pi < pj + } + return i < j + }) + return &w +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..249f33e --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module zworld + +go 1.20 + +require ( + github.com/CannibalVox/cgoparam v1.1.0 // indirect + github.com/go-gl/glfw v0.0.0-20221017161538-93cebf72946b // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/ojrac/opensimplex-go v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/vkngwrapper/core/v2 v2.2.1 // indirect + github.com/vkngwrapper/extensions/v2 v2.2.0 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..eb52f54 --- /dev/null +++ b/go.sum @@ -0,0 +1,55 @@ +github.com/CannibalVox/VKng v0.0.0-20220707035000-0931f864c378 h1:VT+Uklgvu+BMI2MLouYtTd/HL7uqE/ds3n9yeP8bj8I= +github.com/CannibalVox/cgoparam v1.1.0 h1:6UDDhOpT06csFE2vkcanXsIJmebMc9o+6Vzhvi4i0wY= +github.com/CannibalVox/cgoparam v1.1.0/go.mod h1:9LDFLuHVgE+IIBDd1QFN3dPqmGQN9bS6H+NPizMv2fA= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/go-gl/glfw v0.0.0-20221017161538-93cebf72946b h1:2hdUMUOJuLQkhaPAwoyOeSzoaBydYEkXkBEuqDuDBfg= +github.com/go-gl/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:wyvWpaEu9B/VQiV1jsPs7Mha9I7yto/HqIBw197ZAzk= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/ojrac/opensimplex-go v1.0.2 h1:l4vs0D+JCakcu5OV0kJ99oEaWJfggSc9jiLpxaWvSzs= +github.com/ojrac/opensimplex-go v1.0.2/go.mod h1:NwbXFFbXcdGgIFdiA7/REME+7n/lOf1TuEbLiZYOWnM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/vkngwrapper/core/v2 v2.2.1 h1:8xw2tuIXAeyNQj4mnDA7BHO6T6f7ba08UbJZB7UM6xg= +github.com/vkngwrapper/core/v2 v2.2.1/go.mod h1:EWABLJZGHa8nyeO4Bh9eR/V862HAz+Fvk5DitkOvYF4= +github.com/vkngwrapper/extensions/v2 v2.2.0 h1:2ZP+Nom2EbefqgR2EPherJRS836wSWPoXeOLvV7aUuY= +github.com/vkngwrapper/extensions/v2 v2.2.0/go.mod h1:55exjYwTUyQVNS/zhrC/Or/c2CA4Q9Cj/88Tu9EqlJ0= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/library/zos/error.go b/library/zos/error.go new file mode 100644 index 0000000..86400cf --- /dev/null +++ b/library/zos/error.go @@ -0,0 +1,8 @@ +package zos + +import "errors" + +var ( + ErrBufferFull = errors.New("read: buffer full") + ErrBufferEOF = errors.New("read: buffer EOF") +) diff --git a/library/zos/line.go b/library/zos/line.go new file mode 100644 index 0000000..8bd5b91 --- /dev/null +++ b/library/zos/line.go @@ -0,0 +1,77 @@ +package zos + +import "strconv" + +type FByteView struct { + Line []byte + sign byte + err error +} + +func NewByteView(line []byte) *FByteView { + return &FByteView{ + Line: line, + sign: ' ', + err: nil, + } +} +func (v *FByteView) Err() error { + return v.err +} +func (v *FByteView) SetSign(sign byte) { + v.sign = sign +} +func (v *FByteView) GetToken() []byte { + if v.sign == ' ' { + return v.ReadTokenBySpace() + } + return v.ReadTokenByChar(v.sign) +} +func (v *FByteView) GetInt() int32 { + if v.err != nil { + return 0 + } + token := string(v.GetToken()) + num, err := strconv.ParseInt(token, 10, 32) + v.err = err + return int32(num) +} +func (v *FByteView) GetFloat() float32 { + if v.err != nil { + return 0 + } + token := string(v.GetToken()) + num, err := strconv.ParseFloat(token, 32) + v.err = err + return float32(num) +} + +func (v *FByteView) SkipWhitespace() { + r, w := 0, len(v.Line) + for r < w && (v.Line[r] == ' ' || v.Line[r] == '\t') { + r++ + } + if r > 0 { + v.Line = v.Line[r:w] + } +} +func (v *FByteView) ReadTokenBySpace() []byte { + v.SkipWhitespace() + r, w := 0, len(v.Line) + for r < w && (v.Line[r] != ' ' && v.Line[r] != '\t') { + r++ + } + token := v.Line[0:r] + v.Line = v.Line[r:w] + return token +} +func (v *FByteView) ReadTokenByChar(char byte) []byte { + v.SkipWhitespace() + r, w := 0, len(v.Line) + for r < w && (v.Line[r] != char) { + r++ + } + token := v.Line[0:r] + v.Line = v.Line[r:w] + return token +} diff --git a/library/zos/reader.go b/library/zos/reader.go new file mode 100644 index 0000000..3306351 --- /dev/null +++ b/library/zos/reader.go @@ -0,0 +1,127 @@ +package zos + +import ( + "bytes" + "io" + "os" +) + +func min(a int, b int) int { + if a < b { + return a + } + return b +} + +type FReader struct { + io io.Reader + buf []byte + r, w int + err error +} + +func NewReader(io io.Reader) *FReader { + return &FReader{ + io: io, + buf: make([]byte, 4096), + r: 0, + w: 0, + } +} +func (b *FReader) Read(data []byte) (int, error) { + n, rn := len(data), 0 + for rn < n { + d := min(b.w-b.r, n-rn) + if d > 0 { + copy(data[rn:rn+d], b.buf[b.r:b.r+d]) + b.r += d + rn += d + if rn >= n { + break + } + } + err := b.fill() + if err != nil { + return rn, err + } + } + return rn, nil + +} +func (b *FReader) ReadLine() ([]byte, error) { + line, err := b.ReadSlice('\n') + i := len(line) - 1 + if i >= 0 && line[i] == '\r' { + return line[:i], err + } + return line, err +} +func (b *FReader) ReadLineFast() ([]byte, error) { + line, err := b.ReadSliceFast('\n') + i := len(line) - 1 + if i >= 0 && line[i] == '\r' { + return line[:i], err + } + return line, err +} +func (b *FReader) ReadSlice(delim byte) ([]byte, error) { + var lines []byte + for { + line, err := b.ReadSliceFast(delim) + if err == nil || err != ErrBufferFull { + return line, err + } + lines = append(lines, line...) + } + return lines, nil +} +func (b *FReader) ReadSliceFast(delim byte) ([]byte, error) { + for { + // Search buffer. + if i := bytes.IndexByte(b.buf[b.r+0:b.w], delim); i >= 0 { + i += 1 + b.r += i + return b.buf[b.r-i : b.r-1], nil + } + err := b.fill() + if err != nil { + return b.buf[b.r:], err + } + } +} +func (b *FReader) fill() error { + d := b.w - b.r + if d >= len(b.buf) { + b.r = 0 + b.w = 0 + return ErrBufferFull + } + // Slide existing data to beginning. + if b.r > 0 { + copy(b.buf, b.buf[b.r:b.w]) + b.w -= b.r + b.r = 0 + } + // Read new data: try a limited number of times. + n, err := b.io.Read(b.buf[b.w:]) + b.w += n + return err +} +func (b *FReader) Clear() { + b.r = 0 + b.w = 0 +} + +func (b *FReader) Seek(pos, offset int) { + r := b.r + offset + if r >= 0 && r <= b.w { + b.r = r + return + } + f, ok := b.io.(*os.File) + if ok { + f.Seek(int64(pos), 0) + b.r = 0 + b.w = 0 + } +} diff --git a/plugin/math/byte4/byte4.go b/plugin/math/byte4/byte4.go new file mode 100644 index 0000000..cf0c74a --- /dev/null +++ b/plugin/math/byte4/byte4.go @@ -0,0 +1,10 @@ +package byte4 + +// T is a 4-component vector of uint8 (bytes) +type T struct { + X, Y, Z, W byte +} + +func New(x, y, z, w byte) T { + return T{x, y, z, w} +} diff --git a/plugin/math/ivec2/ivec2.go b/plugin/math/ivec2/ivec2.go new file mode 100644 index 0000000..20a3ec7 --- /dev/null +++ b/plugin/math/ivec2/ivec2.go @@ -0,0 +1,32 @@ +package ivec2 + +var Zero = T{} +var One = T{X: 1, Y: 1} +var UnitX = T{X: 1} +var UnitY = T{Y: 1} + +type T struct { + X int + Y int +} + +func New(x, y int) T { + return T{ + X: x, + Y: y, + } +} + +func (v T) Add(v2 T) T { + return T{ + X: v.X + v2.X, + Y: v.Y + v2.Y, + } +} + +func (v T) Sub(v2 T) T { + return T{ + X: v.X - v2.X, + Y: v.Y - v2.Y, + } +} diff --git a/plugin/math/mat4/mat4.go b/plugin/math/mat4/mat4.go new file mode 100644 index 0000000..55e35fa --- /dev/null +++ b/plugin/math/mat4/mat4.go @@ -0,0 +1,317 @@ +// Based on code from github.com/go-gl/mathgl: +// Copyright 2014 The go-gl Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package mat4 + +import ( + "bytes" + "fmt" + "text/tabwriter" + + "golang.org/x/image/math/f32" + + "zworld/plugin/math" + "zworld/plugin/math/vec3" + "zworld/plugin/math/vec4" +) + +// T holds a 4x4 float32 matrix +type T f32.Mat4 + +// Add performs an element-wise addition of two matrices, this is +// equivalent to iterating over every element of m and adding the corresponding value of m2. +func (m *T) Add(m2 *T) T { + return T{ + m[0] + m2[0], m[1] + m2[1], m[2] + m2[2], m[3] + m2[3], + m[4] + m2[4], m[5] + m2[5], m[6] + m2[6], m[7] + m2[7], + m[8] + m2[8], m[9] + m2[9], m[10] + m2[10], m[11] + m2[11], + m[12] + m2[12], m[13] + m2[13], m[14] + m2[14], m[15] + m2[15], + } +} + +// Sub performs an element-wise subtraction of two matrices, this is +// equivalent to iterating over every element of m and subtracting the corresponding value of m2. +func (m *T) Sub(m2 *T) T { + return T{ + m[0] - m2[0], m[1] - m2[1], m[2] - m2[2], m[3] - m2[3], + m[4] - m2[4], m[5] - m2[5], m[6] - m2[6], m[7] - m2[7], + m[8] - m2[8], m[9] - m2[9], m[10] - m2[10], m[11] - m2[11], + m[12] - m2[12], m[13] - m2[13], m[14] - m2[14], m[15] - m2[15], + } +} + +// Scale performs a scalar multiplcation of the matrix. This is equivalent to iterating +// over every element of the matrix and multiply it by c. +func (m T) Scale(c float32) T { + return T{ + m[0] * c, m[1] * c, m[2] * c, m[3] * c, + m[4] * c, m[5] * c, m[6] * c, m[7] * c, + m[8] * c, m[9] * c, m[10] * c, m[11] * c, + m[12] * c, m[13] * c, m[14] * c, m[15] * c, + } +} + +// VMul multiplies a vec4 with the matrix +func (m *T) VMul(v vec4.T) vec4.T { + return vec4.T{ + X: m[0]*v.X + m[4]*v.Y + m[8]*v.Z + m[12]*v.W, + Y: m[1]*v.X + m[5]*v.Y + m[9]*v.Z + m[13]*v.W, + Z: m[2]*v.X + m[6]*v.Y + m[10]*v.Z + m[14]*v.W, + W: m[3]*v.X + m[7]*v.Y + m[11]*v.Z + m[15]*v.W, + } +} + +// TransformPoint transforms a point to world space +func (m *T) TransformPoint(v vec3.T) vec3.T { + p := vec4.Extend(v, 1) + vt := m.VMul(p) + return vt.XYZ().Scaled(1 / vt.W) +} + +// TransformDir transforms a direction vector to world space +func (m *T) TransformDir(v vec3.T) vec3.T { + p := vec4.Extend(v, 0) + vt := m.VMul(p) + return vt.XYZ() +} + +// Mul performs a "matrix product" between this matrix and another of the same dimension +func (a *T) Mul(b *T) T { + return T{ + a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3], + a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3], + a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3], + a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3], + + a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7], + a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7], + a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7], + a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7], + + a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11], + a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11], + a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11], + a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11], + + a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15], + a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15], + a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15], + a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15], + } +} + +// Transpose produces the transpose of this matrix. For any MxN matrix +// the transpose is an NxM matrix with the rows swapped with the columns. For instance +// the transpose of the Mat3x2 is a Mat2x3 like so: +// +// [[a b]] [[a c e]] +// [[c d]] = [[b d f]] +// [[e f]] +func (m *T) Transpose() T { + return T{ + m[0], m[4], m[8], m[12], + m[1], m[5], m[9], m[13], + m[2], m[6], m[10], m[14], + m[3], m[7], m[11], m[15], + } +} + +// Det returns the determinant of a matrix. It is a measure of a square matrix's +// singularity and invertability, among other things. In this library, the +// determinant is hard coded based on pre-computed cofactor expansion, and uses +// no loops. Of course, the addition and multiplication must still be done. +func (m *T) Det() float32 { + return m[0]*m[5]*m[10]*m[15] - m[0]*m[5]*m[11]*m[14] - m[0]*m[6]*m[9]*m[15] + m[0]*m[6]*m[11]*m[13] + + m[0]*m[7]*m[9]*m[14] - m[0]*m[7]*m[10]*m[13] - m[1]*m[4]*m[10]*m[15] + m[1]*m[4]*m[11]*m[14] + + m[1]*m[6]*m[8]*m[15] - m[1]*m[6]*m[11]*m[12] - m[1]*m[7]*m[8]*m[14] + m[1]*m[7]*m[10]*m[12] + + m[2]*m[4]*m[9]*m[15] - m[2]*m[4]*m[11]*m[13] - m[2]*m[5]*m[8]*m[15] + m[2]*m[5]*m[11]*m[12] + + m[2]*m[7]*m[8]*m[13] - m[2]*m[7]*m[9]*m[12] - m[3]*m[4]*m[9]*m[14] + m[3]*m[4]*m[10]*m[13] + + m[3]*m[5]*m[8]*m[14] - m[3]*m[5]*m[10]*m[12] - m[3]*m[6]*m[8]*m[13] + m[3]*m[6]*m[9]*m[12] +} + +// Invert computes the inverse of a square matrix. An inverse is a square matrix such that when multiplied by the +// original, yields the identity. +// +// M_inv * M = M * M_inv = I +// +// In this library, the math is precomputed, and uses no loops, though the multiplications, additions, determinant calculation, and scaling +// are still done. This can still be (relatively) expensive for a 4x4. +// +// This function checks the determinant to see if the matrix is invertible. +// If the determinant is 0.0, this function returns the zero matrix. However, due to floating point errors, it is +// entirely plausible to get a false positive or negative. +// In the future, an alternate function may be written which takes in a pre-computed determinant. +func (m *T) Invert() T { + det := m.Det() + if math.Equal(det, float32(0.0)) { + return T{} + } + + retMat := T{ + -m[7]*m[10]*m[13] + m[6]*m[11]*m[13] + m[7]*m[9]*m[14] - m[5]*m[11]*m[14] - m[6]*m[9]*m[15] + m[5]*m[10]*m[15], + m[3]*m[10]*m[13] - m[2]*m[11]*m[13] - m[3]*m[9]*m[14] + m[1]*m[11]*m[14] + m[2]*m[9]*m[15] - m[1]*m[10]*m[15], + -m[3]*m[6]*m[13] + m[2]*m[7]*m[13] + m[3]*m[5]*m[14] - m[1]*m[7]*m[14] - m[2]*m[5]*m[15] + m[1]*m[6]*m[15], + m[3]*m[6]*m[9] - m[2]*m[7]*m[9] - m[3]*m[5]*m[10] + m[1]*m[7]*m[10] + m[2]*m[5]*m[11] - m[1]*m[6]*m[11], + m[7]*m[10]*m[12] - m[6]*m[11]*m[12] - m[7]*m[8]*m[14] + m[4]*m[11]*m[14] + m[6]*m[8]*m[15] - m[4]*m[10]*m[15], + -m[3]*m[10]*m[12] + m[2]*m[11]*m[12] + m[3]*m[8]*m[14] - m[0]*m[11]*m[14] - m[2]*m[8]*m[15] + m[0]*m[10]*m[15], + m[3]*m[6]*m[12] - m[2]*m[7]*m[12] - m[3]*m[4]*m[14] + m[0]*m[7]*m[14] + m[2]*m[4]*m[15] - m[0]*m[6]*m[15], + -m[3]*m[6]*m[8] + m[2]*m[7]*m[8] + m[3]*m[4]*m[10] - m[0]*m[7]*m[10] - m[2]*m[4]*m[11] + m[0]*m[6]*m[11], + -m[7]*m[9]*m[12] + m[5]*m[11]*m[12] + m[7]*m[8]*m[13] - m[4]*m[11]*m[13] - m[5]*m[8]*m[15] + m[4]*m[9]*m[15], + m[3]*m[9]*m[12] - m[1]*m[11]*m[12] - m[3]*m[8]*m[13] + m[0]*m[11]*m[13] + m[1]*m[8]*m[15] - m[0]*m[9]*m[15], + -m[3]*m[5]*m[12] + m[1]*m[7]*m[12] + m[3]*m[4]*m[13] - m[0]*m[7]*m[13] - m[1]*m[4]*m[15] + m[0]*m[5]*m[15], + m[3]*m[5]*m[8] - m[1]*m[7]*m[8] - m[3]*m[4]*m[9] + m[0]*m[7]*m[9] + m[1]*m[4]*m[11] - m[0]*m[5]*m[11], + m[6]*m[9]*m[12] - m[5]*m[10]*m[12] - m[6]*m[8]*m[13] + m[4]*m[10]*m[13] + m[5]*m[8]*m[14] - m[4]*m[9]*m[14], + -m[2]*m[9]*m[12] + m[1]*m[10]*m[12] + m[2]*m[8]*m[13] - m[0]*m[10]*m[13] - m[1]*m[8]*m[14] + m[0]*m[9]*m[14], + m[2]*m[5]*m[12] - m[1]*m[6]*m[12] - m[2]*m[4]*m[13] + m[0]*m[6]*m[13] + m[1]*m[4]*m[14] - m[0]*m[5]*m[14], + -m[2]*m[5]*m[8] + m[1]*m[6]*m[8] + m[2]*m[4]*m[9] - m[0]*m[6]*m[9] - m[1]*m[4]*m[10] + m[0]*m[5]*m[10], + } + + return retMat.Scale(1 / det) +} + +// ApproxEqual performs an element-wise approximate equality test between two matrices, +// as if FloatEqual had been used. +func (m *T) ApproxEqual(m2 *T) bool { + for i := range m { + if !math.Equal(m[i], m2[i]) { + return false + } + } + return true +} + +// ApproxEqualThreshold performs an element-wise approximate equality test between two matrices +// with a given epsilon threshold, as if FloatEqualThreshold had been used. +func (m *T) ApproxEqualThreshold(m2 *T, threshold float32) bool { + for i := range m { + if !math.EqualThreshold(m[i], m2[i], threshold) { + return false + } + } + return true +} + +// At returns the matrix element at the given row and column. +// This is equivalent to mat[col * numRow + row] where numRow is constant +// (E.G. for a Mat3x2 it's equal to 3) +// +// This method is garbage-in garbage-out. For instance, on a T asking for +// At(5,0) will work just like At(1,1). Or it may panic if it's out of bounds. +func (m *T) At(row, col int) float32 { + return m[col*4+row] +} + +// Set sets the corresponding matrix element at the given row and column. +func (m *T) Set(row, col int, value float32) { + m[col*4+row] = value +} + +// Index returns the index of the given row and column, to be used with direct +// access. E.G. Index(0,0) = 0. +func (m *T) Index(row, col int) int { + return col*4 + row +} + +// Row returns a vector representing the corresponding row (starting at row 0). +// This package makes no distinction between row and column vectors, so it +// will be a normal VecM for a MxN matrix. +func (m *T) Row(row int) vec4.T { + return vec4.T{ + X: m[row+0], + Y: m[row+4], + Z: m[row+8], + W: m[row+12], + } +} + +// Rows decomposes a matrix into its corresponding row vectors. +// This is equivalent to calling mat.Row for each row. +func (m *T) Rows() (row0, row1, row2, row3 vec4.T) { + return m.Row(0), m.Row(1), m.Row(2), m.Row(3) +} + +// Col returns a vector representing the corresponding column (starting at col 0). +// This package makes no distinction between row and column vectors, so it +// will be a normal VecN for a MxN matrix. +func (m *T) Col(col int) vec4.T { + return vec4.T{ + X: m[col*4+0], + Y: m[col*4+1], + Z: m[col*4+2], + W: m[col*4+3], + } +} + +// Cols decomposes a matrix into its corresponding column vectors. +// This is equivalent to calling mat.Col for each column. +func (m *T) Cols() (col0, col1, col2, col3 vec4.T) { + return m.Col(0), m.Col(1), m.Col(2), m.Col(3) +} + +// Trace is a basic operation on a square matrix that simply +// sums up all elements on the main diagonal (meaning all elements such that row==col). +func (m *T) Trace() float32 { + return m[0] + m[5] + m[10] + m[15] +} + +// Abs returns the element-wise absolute value of this matrix +func (m *T) Abs() T { + return T{ + math.Abs(m[0]), math.Abs(m[1]), math.Abs(m[2]), math.Abs(m[3]), + math.Abs(m[4]), math.Abs(m[5]), math.Abs(m[6]), math.Abs(m[7]), + math.Abs(m[8]), math.Abs(m[9]), math.Abs(m[10]), math.Abs(m[11]), + math.Abs(m[12]), math.Abs(m[13]), math.Abs(m[14]), math.Abs(m[15]), + } +} + +// String pretty prints the matrix +func (m T) String() string { + buf := new(bytes.Buffer) + w := tabwriter.NewWriter(buf, 4, 4, 1, ' ', tabwriter.AlignRight) + for i := 0; i < 4; i++ { + r := m.Row(i) + fmt.Fprintf(w, "%f\t", r.X) + fmt.Fprintf(w, "%f\t", r.Y) + fmt.Fprintf(w, "%f\t", r.Z) + fmt.Fprintf(w, "%f\t", r.W) + } + w.Flush() + return buf.String() +} + +// Right extracts the right vector from a transformation matrix +func (m *T) Right() vec3.T { + return vec3.T{ + X: m[4*0+0], + Y: m[4*1+0], + Z: m[4*2+0], + } +} + +// Up extracts the up vector from a transformation matrix +func (m *T) Up() vec3.T { + return vec3.T{ + X: m[4*0+1], + Y: m[4*1+1], + Z: m[4*2+1], + } +} + +// Forward extracts the forward vector from a transformation matrix +func (m *T) Forward() vec3.T { + return vec3.T{ + X: m[4*0+2], + Y: m[4*1+2], + Z: m[4*2+2], + } +} + +// Origin extracts origin point of the coordinate system represented by the matrix +func (m *T) Origin() vec3.T { + return vec3.T{ + X: m[4*3+0], + Y: m[4*3+1], + Z: m[4*3+2], + } +} diff --git a/plugin/math/mat4/operations.go b/plugin/math/mat4/operations.go new file mode 100644 index 0000000..979ecbb --- /dev/null +++ b/plugin/math/mat4/operations.go @@ -0,0 +1,11 @@ +package mat4 + +// Ident returns a new 4x4 identity matrix +func Ident() T { + return T{ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + } +} diff --git a/plugin/math/mat4/project.go b/plugin/math/mat4/project.go new file mode 100644 index 0000000..8629b7c --- /dev/null +++ b/plugin/math/mat4/project.go @@ -0,0 +1,67 @@ +package mat4 + +import ( + "zworld/plugin/math" + "zworld/plugin/math/vec3" +) + +// Orthographic generates a left-handed orthographic projection matrix. +// Outputs depth values in the range [0, 1] +func Orthographic(left, right, bottom, top, near, far float32) T { + rml, tmb, fmn := (right - left), (top - bottom), (far - near) + return T{ + 2 / rml, 0, 0, 0, + 0, 2 / tmb, 0, 0, + 0, 0, 1 / fmn, 0, + (right + left) / rml, + -(top + bottom) / tmb, + -near / fmn, + 1, + } +} + +// OrthographicRZ generates a left-handed orthographic projection matrix. +// Outputs depth values in the range [1, 0] (reverse Z) +func OrthographicRZ(left, right, bottom, top, near, far float32) T { + rml, tmb, fmn := (right - left), (top - bottom), (near - far) + + return T{ + 2 / rml, 0, 0, 0, + 0, 2 / tmb, 0, 0, + 0, 0, 1 / fmn, 0, + -(right + left) / rml, + -(top + bottom) / tmb, + near / fmn, + 1, + } +} + +// Perspective generates a left-handed perspective projection matrix with reversed depth. +// Outputs depth values in the range [0, 1] +func Perspective(fovy, aspect, near, far float32) T { + fovy = math.DegToRad(fovy) + tanHalfFov := math.Tan(fovy) / 2 + + return T{ + 1 / (aspect * tanHalfFov), 0, 0, 0, + 0, -1 / tanHalfFov, 0, 0, + 0, 0, far / (far - near), 1, + 0, 0, -(far * near) / (far - near), 0, + } +} + +func LookAt(eye, center, up vec3.T) T { + f := center.Sub(eye).Normalized() + r := vec3.Cross(up, f).Normalized() + u := vec3.Cross(f, r) + + M := T{ + r.X, u.X, f.X, 0, + r.Y, u.Y, f.Y, 0, + r.Z, u.Z, f.Z, 0, + 0, 0, 0, 1, + } + + et := Translate(eye.Scaled(-1)) + return M.Mul(&et) +} diff --git a/plugin/math/mat4/project_test.go b/plugin/math/mat4/project_test.go new file mode 100644 index 0000000..8457c6c --- /dev/null +++ b/plugin/math/mat4/project_test.go @@ -0,0 +1,56 @@ +package mat4_test + +import ( + "testing" + + . "zworld/plugin/math/mat4" + "zworld/plugin/math/vec3" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestMat4(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "math/mat4") +} + +type TransformTest struct { + Input vec3.T + Output vec3.T +} + +func AssertTransforms(t *testing.T, transform T, cases []TransformTest) { + t.Helper() + for _, c := range cases { + point := transform.TransformPoint(c.Input) + if !point.ApproxEqual(c.Output) { + t.Errorf("expected %v was %v", c.Output, point) + } + } +} + +func TestOrthographicRZ(t *testing.T) { + proj := OrthographicRZ(0, 10, 0, 10, -1, 1) + AssertTransforms(t, proj, []TransformTest{ + {vec3.New(5, 5, 0), vec3.New(0, 0, 0.5)}, + {vec3.New(5, 5, 1), vec3.New(0, 0, 0)}, + {vec3.New(5, 5, -1), vec3.New(0, 0, 1)}, + {vec3.New(0, 0, -1), vec3.New(-1, -1, 1)}, + }) +} + +func TestPerspectiveVK(t *testing.T) { + proj := Perspective(45, 1, 1, 100) + AssertTransforms(t, proj, []TransformTest{ + {vec3.New(0, 0, 1), vec3.New(0, 0, 0)}, + {vec3.New(0, 0, 100), vec3.New(0, 0, 1)}, + }) +} + +var _ = Describe("LookAt (LH)", func() { + It("correctly projects", func() { + proj := LookAt(vec3.Zero, vec3.UnitZ, vec3.UnitY) + Expect(proj.Forward().ApproxEqual(vec3.UnitZ)).To(BeTrue()) + }) +}) diff --git a/plugin/math/mat4/translation.go b/plugin/math/mat4/translation.go new file mode 100644 index 0000000..6c22290 --- /dev/null +++ b/plugin/math/mat4/translation.go @@ -0,0 +1,20 @@ +// Based on code from github.com/go-gl/mathgl: +// Copyright 2014 The go-gl Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package mat4 + +import ( + "zworld/plugin/math/vec3" +) + +// Translate returns a homogeneous (4x4 for 3D-space) Translation matrix that moves a point by Tx units in the x-direction, Ty units in the y-direction, +// and Tz units in the z-direction +func Translate(translation vec3.T) T { + return T{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, translation.X, translation.Y, translation.Z, 1} +} + +// Scale creates a homogeneous 3D scaling matrix +func Scale(scale vec3.T) T { + return T{scale.X, 0, 0, 0, 0, scale.Y, 0, 0, 0, 0, scale.Z, 0, 0, 0, 0, 1} +} diff --git a/plugin/math/math32.go b/plugin/math/math32.go new file mode 100644 index 0000000..e359561 --- /dev/null +++ b/plugin/math/math32.go @@ -0,0 +1,177 @@ +package math + +import ( + "math" + + "golang.org/x/exp/constraints" +) + +// Various useful constants. +var ( + MinNormal = float32(1.1754943508222875e-38) // 1 / 2**(127 - 1) + MinValue = float32(math.SmallestNonzeroFloat32) + MaxValue = float32(math.MaxFloat32) + + InfPos = float32(math.Inf(1)) + InfNeg = float32(math.Inf(-1)) + NaN = float32(math.NaN()) + + E = float32(math.E) + Pi = float32(math.Pi) + PiOver2 = Pi / 2 + PiOver4 = Pi / 4 + Sqrt2 = float32(math.Sqrt2) + + Epsilon = float32(1e-10) +) + +// Abs returns the absolute value of a number +func Abs[T constraints.Float | constraints.Integer](v T) T { + if v < 0 { + return -v + } + return v +} + +// Min returns the smaller of two numbers +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +// Max returns the greater of two numbers +func Max[T constraints.Ordered](a, b T) T { + if a > b { + return a + } + return b +} + +// Clamp a value between a minimum and a maximum value +func Clamp[T constraints.Ordered](v, min, max T) T { + if v > max { + return max + } + if v < min { + return min + } + return v +} + +// Ceil a number to the closest integer +func Ceil(x float32) float32 { + return float32(math.Ceil(float64(x))) +} + +// Floor a number to the closest integer +func Floor(x float32) float32 { + return float32(math.Floor(float64(x))) +} + +// Mod returns the remainder of a floating point division +func Mod(x, y float32) float32 { + return float32(math.Mod(float64(x), float64(y))) +} + +// Sqrt returns the square root of a number +func Sqrt(x float32) float32 { + return float32(math.Sqrt(float64(x))) +} + +// Sin computes the sine of x +func Sin(x float32) float32 { + return float32(math.Sin(float64(x))) +} + +// Cos computes the cosine of x +func Cos(x float32) float32 { + return float32(math.Cos(float64(x))) +} + +// Tan computes the tangent of x +func Tan(x float32) float32 { + return float32(math.Tan(float64(x))) +} + +func Sincos(x float32) (float32, float32) { + sin, cos := math.Sincos(float64(x)) + return float32(sin), float32(cos) +} + +func Acos(x float32) float32 { + return float32(math.Acos(float64(x))) +} + +func Asin(x float32) float32 { + return float32(math.Asin(float64(x))) +} + +func Atan2(y, x float32) float32 { + return float32(math.Atan2(float64(y), float64(x))) +} + +// Sign returns the sign of x (-1 or 1) +func Sign(x float32) float32 { + if x > 0 { + return 1 + } + return -1 +} + +func Copysign(f, sign float32) float32 { + return float32(math.Copysign(float64(f), float64(sign))) +} + +// DegToRad converts degrees to radians +func DegToRad(deg float32) float32 { + return Pi * deg / 180.0 +} + +// RadToDeg converts radians to degrees +func RadToDeg(rad float32) float32 { + return 180.0 * rad / Pi +} + +// Equal checks two floats for (approximate) equality +func Equal(a, b float32) bool { + return EqualThreshold(a, b, Epsilon) +} + +// EqualThreshold is a utility function to compare floats. +// It's Taken from http://floating-point-gui.de/errors/comparison/ +// +// It is slightly altered to not call Abs when not needed. +// +// This differs from FloatEqual in that it lets you pass in your comparison threshold, so that you can adjust the comparison value to your specific needs +func EqualThreshold(a, b, epsilon float32) bool { + if a == b { // Handles the case of inf or shortcuts the loop when no significant error has accumulated + return true + } + + diff := Abs(a - b) + if a*b == 0 || diff < MinNormal { // If a or b are 0 or both are extremely close to it + return diff < epsilon*epsilon + } + + // Else compare difference + return diff/(Abs(a)+Abs(b)) < epsilon +} + +// Lerp performs linear interpolation between a and b +func Lerp(a, b, f float32) float32 { + return a + f*(b-a) +} + +func Round(f float32) float32 { + return float32(math.Round(float64(f))) +} + +func Snap(f, multiple float32) float32 { + return Ceil(f/multiple) * multiple +} + +func Pow(f, x float32) float32 { + return float32(math.Pow(float64(f), float64(x))) +} diff --git a/plugin/math/noise.go b/plugin/math/noise.go new file mode 100644 index 0000000..361174a --- /dev/null +++ b/plugin/math/noise.go @@ -0,0 +1,28 @@ +package math + +import ( + opensimplex "github.com/ojrac/opensimplex-go" +) + +// Noise utility to sample simplex noise +type Noise struct { + opensimplex.Noise + Seed int + Freq float32 +} + +// NewNoise creates a new noise struct from a seed value and a frequency factor. +func NewNoise(seed int, freq float32) *Noise { + return &Noise{ + Noise: opensimplex.New(int64(seed)), + Seed: seed, + Freq: freq, + } +} + +// Sample the noise at a certain position +func (n *Noise) Sample(x, y, z int) float32 { + // jeez + fx, fy, fz := float64(float32(x)*n.Freq), float64(float32(y)*n.Freq), float64(float32(z)*n.Freq) + return float32(n.Eval3(fx, fy, fz)) +} diff --git a/plugin/math/quat/quat.go b/plugin/math/quat/quat.go new file mode 100644 index 0000000..15493fc --- /dev/null +++ b/plugin/math/quat/quat.go @@ -0,0 +1,553 @@ +// Based on code from github.com/go-gl/mathgl: +// Copyright 2014 The go-gl Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package quat + +import ( + "zworld/plugin/math" + "zworld/plugin/math/mat4" + "zworld/plugin/math/vec3" +) + +// RotationOrder is the order in which rotations will be transformed for the +// purposes of AnglesToQuat. +type RotationOrder int + +// The RotationOrder constants represent a series of rotations along the given +// axes for the use of AnglesToQuat. +const ( + XYX RotationOrder = iota + XYZ + XZX + XZY + YXY + YXZ + YZY + YZX + ZYZ + ZYX + ZXZ + ZXY +) + +// T represents a Quaternion, which is an extension of the imaginary numbers; +// there's all sorts of interesting theory behind it. In 3D graphics we mostly +// use it as a cheap way of representing rotation since quaternions are cheaper +// to multiply by, and easier to interpolate than matrices. +// +// A Quaternion has two parts: W, the so-called scalar component, and "V", the +// vector component. The vector component is considered to be the part in 3D +// space, while W (loosely interpreted) is its 4D coordinate. +type T struct { + W float32 + V vec3.T +} + +// Ident returns the quaternion identity: W=1; V=(0,0,0). +// +// As with all identities, multiplying any quaternion by this will yield the same +// quaternion you started with. +func Ident() T { + return T{1., vec3.New(0, 0, 0)} +} + +// Rotate creates an angle from an axis and an angle relative to that axis. +// +// This is cheaper than HomogRotate3D. +func Rotate(angle float32, axis vec3.T) T { + // angle = (float32(math.Pi) * angle) / 180.0 + + c, s := math.Cos(angle/2), math.Sin(angle/2) + + return T{c, axis.Scaled(s)} +} + +// X is a convenient alias for q.V[0] +func (q T) X() float32 { + return q.V.X +} + +// Y is a convenient alias for q.V[1] +func (q T) Y() float32 { + return q.V.Y +} + +// Z is a convenient alias for q.V[2] +func (q T) Z() float32 { + return q.V.X +} + +// Add adds two quaternions. It's no more complicated than +// adding their W and V components. +func (q1 T) Add(q2 T) T { + return T{q1.W + q2.W, q1.V.Add(q2.V)} +} + +// Sub subtracts two quaternions. It's no more complicated than +// subtracting their W and V components. +func (q1 T) Sub(q2 T) T { + return T{q1.W - q2.W, q1.V.Sub(q2.V)} +} + +// Mul multiplies two quaternions. This can be seen as a rotation. Note that +// Multiplication is NOT commutative, meaning q1.Mul(q2) does not necessarily +// equal q2.Mul(q1). +func (q1 T) Mul(q2 T) T { + return T{q1.W*q2.W - vec3.Dot(q1.V, q2.V), vec3.Cross(q1.V, q2.V).Add(q2.V.Scaled(q1.W)).Add(q1.V.Scaled(q2.W))} +} + +// Scale every element of the quaternion by some constant factor. +func (q1 T) Scale(c float32) T { + return T{q1.W * c, vec3.New(q1.V.X*c, q1.V.Y*c, q1.V.Z*c)} +} + +// Conjugate returns the conjugate of a quaternion. Equivalent to +// Quat{q1.W, q1.V.Mul(-1)}. +func (q1 T) Conjugate() T { + return T{q1.W, q1.V.Scaled(-1)} +} + +// Len gives the Length of the quaternion, also known as its Norm. This is the +// same thing as the Len of a Vec4. +func (q1 T) Len() float32 { + return math.Sqrt(q1.W*q1.W + vec3.Dot(q1.V, q1.V)) +} + +// Norm is an alias for Len() since both are very common terms. +func (q1 T) Norm() float32 { + return q1.Len() +} + +// Normalize the quaternion, returning its versor (unit quaternion). +// +// This is the same as normalizing it as a Vec4. +func (q1 T) Normalize() T { + length := q1.Len() + + if math.Equal(1, length) { + return q1 + } + if length == 0 { + return Ident() + } + if length == math.InfPos { + length = math.MaxValue + } + + return T{q1.W * 1 / length, q1.V.Scaled(1 / length)} +} + +// Inverse of a quaternion. The inverse is equivalent +// to the conjugate divided by the square of the length. +// +// This method computes the square norm by directly adding the sum +// of the squares of all terms instead of actually squaring q1.Len(), +// both for performance and precision. +func (q1 T) Inverse() T { + return q1.Conjugate().Scale(1 / q1.Dot(q1)) +} + +// Rotate a vector by the rotation this quaternion represents. +// This will result in a 3D vector. Strictly speaking, this is +// equivalent to q1.v.q* where the "."" is quaternion multiplication and v is interpreted +// as a quaternion with W 0 and V v. In code: +// q1.Mul(Quat{0,v}).Mul(q1.Conjugate()), and +// then retrieving the imaginary (vector) part. +// +// In practice, we hand-compute this in the general case and simplify +// to save a few operations. +func (q1 T) Rotate(v vec3.T) vec3.T { + cross := vec3.Cross(q1.V, v) + // v + 2q_w * (q_v x v) + 2q_v x (q_v x v) + return v.Add(cross.Scaled(2 * q1.W)).Add(vec3.Cross(q1.V.Scaled(2), cross)) +} + +// Mat4 returns the homogeneous 3D rotation matrix corresponding to the +// quaternion. +func (q1 T) Mat4() mat4.T { + w, x, y, z := q1.W, q1.V.X, q1.V.Y, q1.V.Z + return mat4.T{ + 1 - 2*y*y - 2*z*z, 2*x*y + 2*w*z, 2*x*z - 2*w*y, 0, + 2*x*y - 2*w*z, 1 - 2*x*x - 2*z*z, 2*y*z + 2*w*x, 0, + 2*x*z + 2*w*y, 2*y*z - 2*w*x, 1 - 2*x*x - 2*y*y, 0, + 0, 0, 0, 1, + } +} + +// Dot product between two quaternions, equivalent to if this was a Vec4. +func (q1 T) Dot(q2 T) float32 { + return q1.W*q2.W + vec3.Dot(q1.V, q2.V) +} + +// ApproxEqual returns whether the quaternions are approximately equal, as if +// FloatEqual was called on each matching element +func (q1 T) ApproxEqual(q2 T) bool { + return math.Equal(q1.W, q2.W) && q1.V.ApproxEqual(q2.V) +} + +// OrientationEqual returns whether the quaternions represents the same orientation +// +// Different values can represent the same orientation (q == -q) because quaternions avoid singularities +// and discontinuities involved with rotation in 3 dimensions by adding extra dimensions +func (q1 T) OrientationEqual(q2 T) bool { + return q1.OrientationEqualThreshold(q2, math.Epsilon) +} + +// OrientationEqualThreshold returns whether the quaternions represents the same orientation with a given tolerence +func (q1 T) OrientationEqualThreshold(q2 T, epsilon float32) bool { + return math.Abs(q1.Normalize().Dot(q2.Normalize())) > 1-math.Epsilon +} + +// Slerp is *S*pherical *L*inear Int*erp*olation, a method of interpolating +// between two quaternions. This always takes the straightest path on the sphere between +// the two quaternions, and maintains constant velocity. +// +// However, it's expensive and Slerp(q1,q2) is not the same as Slerp(q2,q1) +func Slerp(q1, q2 T, amount float32) T { + q1, q2 = q1.Normalize(), q2.Normalize() + dot := q1.Dot(q2) + + // If the inputs are too close for comfort, linearly interpolate and normalize the result. + if dot > 0.9995 { + return Nlerp(q1, q2, amount) + } + + // This is here for precision errors, I'm perfectly aware that *technically* the dot is bound [-1,1], but since Acos will freak out if it's not (even if it's just a liiiiitle bit over due to normal error) we need to clamp it + dot = math.Clamp(dot, -1, 1) + + theta := math.Acos(dot) * amount + c, s := math.Cos(theta), math.Sin(theta) + rel := q2.Sub(q1.Scale(dot)).Normalize() + + return q1.Scale(c).Add(rel.Scale(s)) +} + +// Lerp is a *L*inear Int*erp*olation between two Quaternions, cheap and simple. +// +// Not excessively useful, but uses can be found. +func Lerp(q1, q2 T, amount float32) T { + return q1.Add(q2.Sub(q1).Scale(amount)) +} + +// Nlerp is a *Normalized* *L*inear Int*erp*olation between two Quaternions. Cheaper than Slerp +// and usually just as good. This is literally Lerp with Normalize() called on it. +// +// Unlike Slerp, constant velocity isn't maintained, but it's much faster and +// Nlerp(q1,q2) and Nlerp(q2,q1) return the same path. You should probably +// use this more often unless you're suffering from choppiness due to the +// non-constant velocity problem. +func Nlerp(q1, q2 T, amount float32) T { + return Lerp(q1, q2, amount).Normalize() +} + +// FromAngles performs a rotation in the specified order. If the order is not +// a valid RotationOrder, this function will panic +// +// The rotation "order" is more of an axis descriptor. For instance XZX would +// tell the function to interpret angle1 as a rotation about the X axis, angle2 about +// the Z axis, and angle3 about the X axis again. +// +// Based off the code for the Matlab function "angle2quat", though this implementation +// only supports 3 single angles as opposed to multiple angles. +func FromAngles(angle1, angle2, angle3 float32, order RotationOrder) T { + var s [3]float32 + var c [3]float32 + + s[0], c[0] = math.Sincos(angle1 / 2) + s[1], c[1] = math.Sincos(angle2 / 2) + s[2], c[2] = math.Sincos(angle3 / 2) + + ret := T{} + switch order { + case ZYX: + ret.W = c[0]*c[1]*c[2] + s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: c[0]*c[1]*s[2] - s[0]*s[1]*c[2], + Y: c[0]*s[1]*c[2] + s[0]*c[1]*s[2], + Z: s[0]*c[1]*c[2] - c[0]*s[1]*s[2], + } + case ZYZ: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*s[2] - s[0]*s[1]*c[2], + Y: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + Z: s[0]*c[1]*c[2] + c[0]*c[1]*s[2], + } + case ZXY: + ret.W = c[0]*c[1]*c[2] - s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*c[2] - s[0]*c[1]*s[2], + Y: c[0]*c[1]*s[2] + s[0]*s[1]*c[2], + Z: c[0]*s[1]*s[2] + s[0]*c[1]*c[2], + } + case ZXZ: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + Y: s[0]*s[1]*c[2] - c[0]*s[1]*s[2], + Z: c[0]*c[1]*s[2] + s[0]*c[1]*c[2], + } + case YXZ: + ret.W = c[0]*c[1]*c[2] + s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*c[2] + s[0]*c[1]*s[2], + Y: s[0]*c[1]*c[2] - c[0]*s[1]*s[2], + Z: c[0]*c[1]*s[2] - s[0]*s[1]*c[2], + } + case YXY: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + Y: s[0]*c[1]*c[2] + c[0]*c[1]*s[2], + Z: c[0]*s[1]*s[2] - s[0]*s[1]*c[2], + } + case YZX: + ret.W = c[0]*c[1]*c[2] - s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: c[0]*c[1]*s[2] + s[0]*s[1]*c[2], + Y: c[0]*s[1]*s[2] + s[0]*c[1]*c[2], + Z: c[0]*s[1]*c[2] - s[0]*c[1]*s[2], + } + case YZY: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: s[0]*s[1]*c[2] - c[0]*s[1]*s[2], + Y: c[0]*c[1]*s[2] + s[0]*c[1]*c[2], + Z: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + } + case XYZ: + ret.W = c[0]*c[1]*c[2] - s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: c[0]*s[1]*s[2] + s[0]*c[1]*c[2], + Y: c[0]*s[1]*c[2] - s[0]*c[1]*s[2], + Z: c[0]*c[1]*s[2] + s[0]*s[1]*c[2], + } + case XYX: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: c[0]*c[1]*s[2] + s[0]*c[1]*c[2], + Y: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + Z: s[0]*s[1]*c[2] - c[0]*s[1]*s[2], + } + case XZY: + ret.W = c[0]*c[1]*c[2] + s[0]*s[1]*s[2] + ret.V = vec3.T{ + X: s[0]*c[1]*c[2] - c[0]*s[1]*s[2], + Y: c[0]*c[1]*s[2] - s[0]*s[1]*c[2], + Z: c[0]*s[1]*c[2] + s[0]*c[1]*s[2], + } + case XZX: + ret.W = c[0]*c[1]*c[2] - s[0]*c[1]*s[2] + ret.V = vec3.T{ + X: c[0]*c[1]*s[2] + s[0]*c[1]*c[2], + Y: c[0]*s[1]*s[2] - s[0]*s[1]*c[2], + Z: c[0]*s[1]*c[2] + s[0]*s[1]*s[2], + } + default: + panic("Unsupported rotation order") + } + return ret +} + +// FromMat4 converts a pure rotation matrix into a quaternion +func FromMat4(m mat4.T) T { + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + + if tr := m[0] + m[5] + m[10]; tr > 0 { + s := 0.5 / math.Sqrt(tr+1.0) + return T{ + 0.25 / s, + vec3.T{ + X: (m[6] - m[9]) * s, + Y: (m[8] - m[2]) * s, + Z: (m[1] - m[4]) * s, + }, + } + } + + if (m[0] > m[5]) && (m[0] > m[10]) { + s := 2.0 * math.Sqrt(1.0+m[0]-m[5]-m[10]) + return T{ + (m[6] - m[9]) / s, + vec3.T{ + X: 0.25 * s, + Y: (m[4] + m[1]) / s, + Z: (m[8] + m[2]) / s, + }, + } + } + + if m[5] > m[10] { + s := 2.0 * math.Sqrt(1.0+m[5]-m[0]-m[10]) + return T{ + (m[8] - m[2]) / s, + vec3.T{ + X: (m[4] + m[1]) / s, + Y: 0.25 * s, + Z: (m[9] + m[6]) / s, + }, + } + + } + + s := 2.0 * math.Sqrt(1.0+m[10]-m[0]-m[5]) + return T{ + (m[1] - m[4]) / s, + vec3.T{ + X: (m[8] + m[2]) / s, + Y: (m[9] + m[6]) / s, + Z: 0.25 * s, + }, + } +} + +// LookAtV creates a rotation from an eye vector to a center vector +// +// It assumes the front of the rotated object at Z- and up at Y+ +func LookAtV(eye, center, up vec3.T) T { + // http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/#I_need_an_equivalent_of_gluLookAt__How_do_I_orient_an_object_towards_a_point__ + // https://bitbucket.org/sinbad/ogre/src/d2ef494c4a2f5d6e2f0f17d3bfb9fd936d5423bb/OgreMain/src/OgreCamera.cpp?at=default#cl-161 + + direction := center.Sub(eye).Normalized() + + // Find the rotation between the front of the object (that we assume towards Z-, + // but this depends on your model) and the desired direction + rotDir := BetweenVectors(vec3.UnitZN, direction) + + // Recompute up so that it's perpendicular to the direction + // You can skip that part if you really want to force up + //right := direction.Cross(up) + //up = right.Cross(direction) + + // Because of the 1rst rotation, the up is probably completely screwed up. + // Find the rotation between the "up" of the rotated object, and the desired up + upCur := rotDir.Rotate(vec3.Zero) + rotUp := BetweenVectors(upCur, up) + + rotTarget := rotUp.Mul(rotDir) // remember, in reverse order. + return rotTarget.Inverse() // camera rotation should be inversed! +} + +// BetweenVectors calculates the rotation between two vectors +func BetweenVectors(start, dest vec3.T) T { + // http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/#I_need_an_equivalent_of_gluLookAt__How_do_I_orient_an_object_towards_a_point__ + // https://github.com/g-truc/glm/blob/0.9.5/glm/gtx/quaternion.inl#L225 + // https://bitbucket.org/sinbad/ogre/src/d2ef494c4a2f5d6e2f0f17d3bfb9fd936d5423bb/OgreMain/include/OgreVector3.h?at=default#cl-654 + + start = start.Normalized() + dest = dest.Normalized() + epsilon := float32(0.001) + + cosTheta := vec3.Dot(start, dest) + if cosTheta < -1.0+epsilon { + // special case when vectors in opposite directions: + // there is no "ideal" rotation axis + // So guess one; any will do as long as it's perpendicular to start + axis := vec3.Cross(vec3.UnitX, start) + if vec3.Dot(axis, axis) < epsilon { + // bad luck, they were parallel, try again! + axis = vec3.Cross(vec3.UnitY, start) + } + + return Rotate(math.Pi, axis.Normalized()) + } + + axis := vec3.Cross(start, dest) + s := float32(math.Sqrt(float32(1.0+cosTheta) * 2.0)) + + return T{ + s * 0.5, + axis.Scaled(1.0 / s), + } +} + +func (q T) ToAngles(order RotationOrder) vec3.T { + // this function was adapted from a Go port of Three.js math, github.com/tengge1/go-three-math + // Copyright 2017-2020 The ShadowEditor Authors. All rights reserved. + // Use of e source code is governed by a MIT-style + // license that can be found in the LICENSE file. + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + te := q.Mat4() + m11, m12, m13 := te[0], te[4], te[8] + m21, m22, m23 := te[1], te[5], te[9] + m31, m32, m33 := te[2], te[6], te[10] + + e := vec3.Zero + switch order { + default: + panic("unsupported rotation order") + case XYZ: + e.Y = math.Asin(math.Clamp(m13, -1, 1)) + + if math.Abs(m13) < 0.9999999 { + e.X = math.Atan2(-m23, m33) + e.Z = math.Atan2(-m12, m11) + } else { + e.X = math.Atan2(m32, m22) + e.Z = 0 + } + case YXZ: + e.X = math.Asin(-math.Clamp(m23, -1, 1)) + + if math.Abs(m23) < 0.9999999 { + e.Y = math.Atan2(m13, m33) + e.Z = math.Atan2(m21, m22) + } else { + e.Y = math.Atan2(-m31, m11) + e.Z = 0 + } + case ZXY: + e.X = math.Asin(math.Clamp(m32, -1, 1)) + + if math.Abs(m32) < 0.9999999 { + e.Y = math.Atan2(-m31, m33) + e.Z = math.Atan2(-m12, m22) + } else { + e.Y = 0 + e.Z = math.Atan2(m21, m11) + } + case ZYX: + e.Y = math.Asin(-math.Clamp(m31, -1, 1)) + + if math.Abs(m31) < 0.9999999 { + e.X = math.Atan2(m32, m33) + e.Z = math.Atan2(m21, m11) + } else { + e.X = 0 + e.Z = math.Atan2(-m12, m22) + } + case YZX: + e.Z = math.Asin(math.Clamp(m21, -1, 1)) + + if math.Abs(m21) < 0.9999999 { + e.X = math.Atan2(-m23, m22) + e.Y = math.Atan2(-m31, m11) + } else { + e.X = 0 + e.Y = math.Atan2(m13, m33) + } + case XZY: + e.Z = math.Asin(-math.Clamp(m12, -1, 1)) + + if math.Abs(m12) < 0.9999999 { + e.X = math.Atan2(m32, m22) + e.Y = math.Atan2(m13, m11) + } else { + e.X = math.Atan2(-m23, m33) + e.Y = 0 + } + } + + return e +} + +func (q T) Euler() vec3.T { + // convert radians to degrees + return q.ToAngles(YXZ).Scaled(180.0 / math.Pi) +} + +func Euler(x, y, z float32) T { + return FromAngles(math.DegToRad(y), math.DegToRad(x), math.DegToRad(z), YXZ) +} diff --git a/plugin/math/quat/quat_suite_test.go b/plugin/math/quat/quat_suite_test.go new file mode 100644 index 0000000..0a7378f --- /dev/null +++ b/plugin/math/quat/quat_suite_test.go @@ -0,0 +1,29 @@ +package quat_test + +import ( + . "github.com/johanhenriksson/goworld/test" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "testing" + + "zworld/plugin/math/quat" + "zworld/plugin/math/vec3" +) + +func TestQuat(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "math/quat") +} + +var _ = Describe("quaternion", func() { + Context("euler angles", func() { + It("converts back and forth", func() { + x, y, z := float32(10), float32(20), float32(30) + q := quat.Euler(x, y, z) + r := q.Euler() + GinkgoWriter.Println(x, y, z, r) + Expect(r).To(ApproxVec3(vec3.New(x, y, z)), "wrong rotation") + }) + }) +}) diff --git a/plugin/math/random/random.go b/plugin/math/random/random.go new file mode 100644 index 0000000..b909b53 --- /dev/null +++ b/plugin/math/random/random.go @@ -0,0 +1,28 @@ +package random + +import ( + "math/rand" + "time" +) + +func init() { + seed := time.Now().Nanosecond() + Seed(seed) +} + +func Seed(seed int) { + rand.Seed(int64(seed)) +} + +func Range(min, max float32) float32 { + return min + rand.Float32()*(max-min) +} + +func Chance(chance float32) bool { + return Range(0, 1) <= chance +} + +func Choice[T any](slice []T) T { + idx := rand.Intn(len(slice)) + return slice[idx] +} diff --git a/plugin/math/shape/frustum.go b/plugin/math/shape/frustum.go new file mode 100644 index 0000000..41d7e24 --- /dev/null +++ b/plugin/math/shape/frustum.go @@ -0,0 +1,107 @@ +package shape + +import ( + "zworld/plugin/math/mat4" + "zworld/plugin/math/vec3" +) + +type Plane struct { + Normal vec3.T + Distance float32 +} + +func (p *Plane) normalize() { + length := p.Normal.LengthSqr() + p.Distance*p.Distance + p.Normal = p.Normal.Scaled(1 / length) + p.Distance /= length +} + +func (p *Plane) DistanceToPoint(point vec3.T) float32 { + return vec3.Dot(p.Normal, point) + p.Distance +} + +type Frustum struct { + Front, Back, Left, Right, Top, Bottom Plane +} + +func (f *Frustum) IntersectsSphere(s *Sphere) bool { + if f.Left.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + if f.Right.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + if f.Top.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + if f.Bottom.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + if f.Front.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + if f.Back.DistanceToPoint(s.Center) <= -s.Radius { + return false + } + return true +} + +func FrustumFromMatrix(vp mat4.T) Frustum { + f := Frustum{ + Left: Plane{ + Normal: vec3.T{ + X: vp[0+3] + vp[0+0], + Y: vp[4+3] + vp[4+0], + Z: vp[8+3] + vp[8+0], + }, + Distance: vp[12+3] + vp[12+0], + }, + Right: Plane{ + Normal: vec3.T{ + X: vp[0+3] - vp[0+0], + Y: vp[4+3] - vp[4+0], + Z: vp[8+3] - vp[8+0], + }, + Distance: vp[12+3] - vp[12+0], + }, + Top: Plane{ + Normal: vec3.T{ + X: vp[0+3] - vp[0+1], + Y: vp[4+3] - vp[4+1], + Z: vp[8+3] - vp[8+1], + }, + Distance: vp[12+3] - vp[12+1], + }, + Bottom: Plane{ + Normal: vec3.T{ + X: vp[0+3] + vp[0+1], + Y: vp[4+3] + vp[4+1], + Z: vp[8+3] + vp[8+1], + }, + Distance: vp[12+3] + vp[12+1], + }, + Back: Plane{ + Normal: vec3.T{ + X: vp[0+3] + vp[0+2], + Y: vp[4+3] + vp[4+2], + Z: vp[8+3] + vp[8+2], + }, + Distance: vp[12+3] + vp[12+2], + }, + Front: Plane{ + Normal: vec3.T{ + X: vp[0+3] - vp[0+2], + Y: vp[4+3] - vp[4+2], + Z: vp[8+3] - vp[8+2], + }, + Distance: vp[12+3] - vp[12+2], + }, + } + f.Front.normalize() + f.Back.normalize() + f.Top.normalize() + f.Bottom.normalize() + f.Left.normalize() + f.Right.normalize() + return f +} diff --git a/plugin/math/shape/sphere.go b/plugin/math/shape/sphere.go new file mode 100644 index 0000000..a29c4e7 --- /dev/null +++ b/plugin/math/shape/sphere.go @@ -0,0 +1,15 @@ +package shape + +import "zworld/plugin/math/vec3" + +type Sphere struct { + Center vec3.T + Radius float32 +} + +func (s *Sphere) IntersectsSphere(other *Sphere) bool { + sepAxis := s.Center.Sub(other.Center) + radiiSum := s.Radius + other.Radius + intersects := sepAxis.LengthSqr() < (radiiSum * radiiSum) + return intersects +} diff --git a/plugin/math/vec2/array.go b/plugin/math/vec2/array.go new file mode 100644 index 0000000..40d84c4 --- /dev/null +++ b/plugin/math/vec2/array.go @@ -0,0 +1,21 @@ +package vec2 + +import "unsafe" + +// Array holds an array of 2-component vectors +type Array []T + +// Elements returns the number of elements in the array +func (a Array) Elements() int { + return len(a) +} + +// Size return the byte size of an element +func (a Array) Size() int { + return 8 +} + +// Pointer returns an unsafe pointer to the first element in the array +func (a Array) Pointer() unsafe.Pointer { + return unsafe.Pointer(&a[0]) +} diff --git a/plugin/math/vec2/operations.go b/plugin/math/vec2/operations.go new file mode 100644 index 0000000..117c69f --- /dev/null +++ b/plugin/math/vec2/operations.go @@ -0,0 +1,37 @@ +package vec2 + +import "zworld/plugin/math" + +// New returns a vec2 from its components +func New(x, y float32) T { + return T{X: x, Y: y} +} + +// NewI returns a vec2 from integer components +func NewI(x, y int) T { + return T{X: float32(x), Y: float32(y)} +} + +// Dot returns the dot product of two vectors. +func Dot(a, b T) float32 { + return a.X*b.X + a.Y*b.Y +} + +// Distance returns the euclidian distance between two points. +func Distance(a, b T) float32 { + return a.Sub(b).Length() +} + +func Min(a, b T) T { + return T{ + X: math.Min(a.X, b.X), + Y: math.Min(a.Y, b.Y), + } +} + +func Max(a, b T) T { + return T{ + X: math.Max(a.X, b.X), + Y: math.Max(a.Y, b.Y), + } +} diff --git a/plugin/math/vec2/vec2.go b/plugin/math/vec2/vec2.go new file mode 100644 index 0000000..dd4dbf7 --- /dev/null +++ b/plugin/math/vec2/vec2.go @@ -0,0 +1,134 @@ +package vec2 + +import ( + "fmt" + + "zworld/plugin/math" +) + +var ( + // Zero is the zero vector + Zero = T{0, 0} + + // One is the one vector + One = T{1, 1} + + // UnitX is the unit vector in the X direction + UnitX = T{1, 0} + + // UnitY is the unit vector in the Y direction + UnitY = T{0, 1} + + InfPos = T{math.InfPos, math.InfPos} + InfNeg = T{math.InfNeg, math.InfNeg} +) + +// T holds a 2-component vector of 32-bit floats +type T struct { + X, Y float32 +} + +// Slice converts the vector into a 2-element slice of float32 +func (v T) Slice() [2]float32 { + return [2]float32{v.X, v.Y} +} + +// Length returns the length of the vector. +// See also LengthSqr and Normalize. +func (v T) Length() float32 { + return math.Sqrt(v.LengthSqr()) +} + +// LengthSqr returns the squared length of the vector. +// See also Length and Normalize. +func (v T) LengthSqr() float32 { + return v.X*v.X + v.Y*v.Y +} + +// Abs sets every component of the vector to its absolute value. +func (v T) Abs() T { + return T{math.Abs(v.X), math.Abs(v.Y)} +} + +// Normalize normalizes the vector to unit length. +func (v *T) Normalize() { + sl := v.LengthSqr() + if sl == 0 || sl == 1 { + return + } + s := 1 / math.Sqrt(sl) + v.X *= s + v.Y *= s +} + +// Normalized returns a unit length normalized copy of the vector. +func (v T) Normalized() T { + v.Normalize() + return v +} + +// Scaled returns a scaled copy of the vector. +func (v T) Scaled(f float32) T { + return T{v.X * f, v.Y * f} +} + +// Scale the vector by a constant (in-place) +func (v *T) Scale(f float32) { + v.X *= f + v.Y *= f +} + +// Swap returns a new vector with components swapped. +func (v T) Swap() T { + return T{v.Y, v.X} +} + +// Invert components in place +func (v *T) Invert() { + v.X = -v.X + v.Y = -v.Y +} + +// Inverted returns a new vector with inverted components +func (v T) Inverted() T { + return T{-v.X, -v.Y} +} + +// Add each element of the vector with the corresponding element of another vector +func (v T) Add(v2 T) T { + return T{v.X + v2.X, v.Y + v2.Y} +} + +// Sub subtracts each element of the vector with the corresponding element of another vector +func (v T) Sub(v2 T) T { + return T{v.X - v2.X, v.Y - v2.Y} +} + +// Mul multiplies each element of the vector with the corresponding element of another vector +func (v T) Mul(v2 T) T { + return T{v.X * v2.X, v.Y * v2.Y} +} + +// Div divides each element of the vector with the corresponding element of another vector +func (v T) Div(v2 T) T { + return T{v.X / v2.X, v.Y / v2.Y} +} + +func (v T) ApproxEqual(v2 T) bool { + epsilon := float32(0.0001) + return Distance(v, v2) < epsilon +} + +func (v T) String() string { + return fmt.Sprintf("%.3f,%.3f", v.X, v.Y) +} + +// Floor each components of the vector +func (v T) Floor() T { + return T{math.Floor(v.X), math.Floor(v.Y)} +} + +// Ceil each component of the vector +func (v T) Ceil() T { + return T{math.Ceil(v.X), math.Ceil(v.Y)} +} diff --git a/plugin/math/vec3/array.go b/plugin/math/vec3/array.go new file mode 100644 index 0000000..c54c3d3 --- /dev/null +++ b/plugin/math/vec3/array.go @@ -0,0 +1,21 @@ +package vec3 + +import "unsafe" + +// Array holds an array of 3-component vectors +type Array []T + +// Elements returns the number of elements in the array +func (a Array) Elements() int { + return len(a) +} + +// Size return the byte size of an element +func (a Array) Size() int { + return 12 +} + +// Pointer returns an unsafe pointer to the first element in the array +func (a Array) Pointer() unsafe.Pointer { + return unsafe.Pointer(&a[0]) +} diff --git a/plugin/math/vec3/operations.go b/plugin/math/vec3/operations.go new file mode 100644 index 0000000..6eee77b --- /dev/null +++ b/plugin/math/vec3/operations.go @@ -0,0 +1,85 @@ +package vec3 + +import ( + "zworld/plugin/math" + "zworld/plugin/math/random" + "zworld/plugin/math/vec2" +) + +// New returns a Vec3 from its components +func New(x, y, z float32) T { + return T{x, y, z} +} + +func New1(v float32) T { + return T{v, v, v} +} + +// NewI returns a Vec3 from integer components +func NewI(x, y, z int) T { + return T{float32(x), float32(y), float32(z)} +} + +func NewI1(v int) T { + return T{float32(v), float32(v), float32(v)} +} + +func FromSlice(v []float32) T { + if len(v) < 3 { + panic("slice must have at least 3 components") + } + return T{v[0], v[1], v[2]} +} + +// Extend a vec2 to a vec3 by adding a Z component +func Extend(v vec2.T, z float32) T { + return T{v.X, v.Y, z} +} + +// Dot returns the dot product of two vectors. +func Dot(a, b T) float32 { + return a.X*b.X + a.Y*b.Y + a.Z*b.Z +} + +// Cross returns the cross product of two vectors. +func Cross(a, b T) T { + return T{ + a.Y*b.Z - a.Z*b.Y, + a.Z*b.X - a.X*b.Z, + a.X*b.Y - a.Y*b.X, + } +} + +// Distance returns the euclidian distance between two points. +func Distance(a, b T) float32 { + return a.Sub(b).Length() +} + +func Mid(a, b T) T { + return a.Add(b).Scaled(0.5) +} + +// Random vector, not normalized. +func Random(min, max T) T { + return T{ + random.Range(min.X, max.X), + random.Range(min.Y, max.Y), + random.Range(min.Z, max.Z), + } +} + +func Min(a, b T) T { + return T{ + X: math.Min(a.X, b.X), + Y: math.Min(a.Y, b.Y), + Z: math.Min(a.Z, b.Z), + } +} + +func Max(a, b T) T { + return T{ + X: math.Max(a.X, b.X), + Y: math.Max(a.Y, b.Y), + Z: math.Max(a.Z, b.Z), + } +} diff --git a/plugin/math/vec3/vec3.go b/plugin/math/vec3/vec3.go new file mode 100644 index 0000000..15de205 --- /dev/null +++ b/plugin/math/vec3/vec3.go @@ -0,0 +1,205 @@ +package vec3 + +import ( + "fmt" + "zworld/plugin/math" + + "zworld/plugin/math/vec2" +) + +var ( + // Zero is the zero vector + Zero = T{0, 0, 0} + + // One is the unit vector + One = T{1, 1, 1} + + // UnitX is the unit vector in the X direction (right) + UnitX = T{1, 0, 0} + Right = T{1, 0, 0} + + // UnitXN is the unit vector in the negative X direction (left) + UnitXN = T{-1, 0, 0} + Left = T{-1, 0, 0} + + // UnitY is the unit vector in the Y direction (up) + UnitY = T{0, 1, 0} + Up = T{0, 1, 0} + + // UnitYN is the unit vector in the negative Y direction (down) + UnitYN = T{0, -1, 0} + Down = T{0, -1, 0} + + // UnitZ is the unit vector in the Z direction (forward) + UnitZ = T{0, 0, 1} + Forward = T{0, 0, 1} + + // UnitZN is the unit vector in the negative Z direction (backward) + UnitZN = T{0, 0, -1} + Backward = T{0, 0, 1} + + InfPos = T{math.InfPos, math.InfPos, math.InfPos} + InfNeg = T{math.InfNeg, math.InfNeg, math.InfNeg} +) + +// T holds a 3-component vector of 32-bit floats +type T struct { + X, Y, Z float32 +} + +// Slice converts the vector into a 3-element slice of float32 +func (v T) Slice() [3]float32 { + return [3]float32{v.X, v.Y, v.Z} +} + +// Length returns the length of the vector. +// See also LengthSqr and Normalize. +func (v T) Length() float32 { + return math.Sqrt(v.LengthSqr()) +} + +// LengthSqr returns the squared length of the vector. +// See also Length and Normalize. +func (v T) LengthSqr() float32 { + return v.X*v.X + v.Y*v.Y + v.Z*v.Z +} + +// Abs returns a copy containing the absolute values of the vector components. +func (v T) Abs() T { + return T{math.Abs(v.X), math.Abs(v.Y), math.Abs(v.Z)} +} + +// Normalize normalizes the vector to unit length. +func (v *T) Normalize() { + sl := v.LengthSqr() + if sl == 0 || sl == 1 { + return + } + s := 1 / math.Sqrt(sl) + v.X *= s + v.Y *= s + v.Z *= s +} + +// Normalized returns a unit length normalized copy of the vector. +func (v T) Normalized() T { + v.Normalize() + return v +} + +// Scale the vector by a constant (in-place) +func (v *T) Scale(f float32) { + v.X *= f + v.Y *= f + v.Z *= f +} + +// Scaled returns a scaled vector +func (v T) Scaled(f float32) T { + return T{v.X * f, v.Y * f, v.Z * f} +} + +// ScaleI returns a vector scaled by an integer factor +func (v T) ScaleI(i int) T { + return v.Scaled(float32(i)) +} + +// Invert the vector components +func (v *T) Invert() { + v.X = -v.X + v.Y = -v.Y + v.Z = -v.Z +} + +// Inverted returns an inverted vector +func (v *T) Inverted() T { + i := *v + i.Invert() + return i +} + +// Floor each components of the vector +func (v T) Floor() T { + return T{math.Floor(v.X), math.Floor(v.Y), math.Floor(v.Z)} +} + +// Ceil each component of the vector +func (v T) Ceil() T { + return T{math.Ceil(v.X), math.Ceil(v.Y), math.Ceil(v.Z)} +} + +// Round each component of the vector +func (v T) Round() T { + return T{math.Round(v.X), math.Round(v.Y), math.Round(v.Z)} +} + +// Add each element of the vector with the corresponding element of another vector +func (v T) Add(v2 T) T { + return T{ + v.X + v2.X, + v.Y + v2.Y, + v.Z + v2.Z, + } +} + +// Sub subtracts each element of the vector with the corresponding element of another vector +func (v T) Sub(v2 T) T { + return T{ + v.X - v2.X, + v.Y - v2.Y, + v.Z - v2.Z, + } +} + +// Mul multiplies each element of the vector with the corresponding element of another vector +func (v T) Mul(v2 T) T { + return T{ + v.X * v2.X, + v.Y * v2.Y, + v.Z * v2.Z, + } +} + +// XY returns a 2-component vector with the X, Y components of this vector +func (v T) XY() vec2.T { + return vec2.T{X: v.X, Y: v.Y} +} + +// XZ returns a 2-component vector with the X, Z components of this vector +func (v T) XZ() vec2.T { + return vec2.T{X: v.X, Y: v.Z} +} + +// YZ returns a 2-component vector with the Y, Z components of this vector +func (v T) YZ() vec2.T { + return vec2.T{X: v.Y, Y: v.Z} +} + +// Div divides each element of the vector with the corresponding element of another vector +func (v T) Div(v2 T) T { + return T{v.X / v2.X, v.Y / v2.Y, v.Z / v2.Z} +} + +// WithX returns a new vector with the X component set to a given value +func (v T) WithX(x float32) T { + return T{x, v.Y, v.Z} +} + +// WithY returns a new vector with the Y component set to a given value +func (v T) WithY(y float32) T { + return T{v.X, y, v.Z} +} + +// WithZ returns a new vector with the Z component set to a given value +func (v T) WithZ(z float32) T { + return T{v.X, v.Y, z} +} + +func (v T) ApproxEqual(v2 T) bool { + epsilon := float32(0.0001) + return Distance(v, v2) < epsilon +} + +func (v T) String() string { + return fmt.Sprintf("%.3f,%.3f,%.3f", v.X, v.Y, v.Z) +} diff --git a/plugin/math/vec4/array.go b/plugin/math/vec4/array.go new file mode 100644 index 0000000..57989cb --- /dev/null +++ b/plugin/math/vec4/array.go @@ -0,0 +1,21 @@ +package vec4 + +import "unsafe" + +// Array holds an array of 4-component vectors +type Array []T + +// Elements returns the number of elements in the array +func (a Array) Elements() int { + return len(a) +} + +// Size return the byte size of an element +func (a Array) Size() int { + return 16 +} + +// Pointer returns an unsafe pointer to the first element in the array +func (a Array) Pointer() unsafe.Pointer { + return unsafe.Pointer(&a[0]) +} diff --git a/plugin/math/vec4/operations.go b/plugin/math/vec4/operations.go new file mode 100644 index 0000000..6c437d0 --- /dev/null +++ b/plugin/math/vec4/operations.go @@ -0,0 +1,56 @@ +package vec4 + +import ( + "zworld/plugin/math" + "zworld/plugin/math/random" + "zworld/plugin/math/vec2" + "zworld/plugin/math/vec3" +) + +// New returns a new vec4 from its components +func New(x, y, z, w float32) T { + return T{x, y, z, w} +} + +// Extend a vec3 to a vec4 by adding a W component +func Extend(v vec3.T, w float32) T { + return T{v.X, v.Y, v.Z, w} +} + +// Extend2 a vec2 to a vec4 by adding the Z and W components +func Extend2(v vec2.T, z, w float32) T { + return T{v.X, v.Y, z, w} +} + +// Dot returns the dot product of two vectors. +func Dot(a, b T) float32 { + return a.X*b.X + a.Y*b.Y + a.Z*b.Z + a.W*b.W +} + +// Random vector, not normalized. +func Random(min, max T) T { + return T{ + random.Range(min.X, max.X), + random.Range(min.Y, max.Y), + random.Range(min.Z, max.Z), + random.Range(min.W, max.W), + } +} + +func Min(a, b T) T { + return T{ + X: math.Min(a.X, b.X), + Y: math.Min(a.Y, b.Y), + Z: math.Min(a.Z, b.Z), + W: math.Min(a.W, b.W), + } +} + +func Max(a, b T) T { + return T{ + X: math.Max(a.X, b.X), + Y: math.Max(a.Y, b.Y), + Z: math.Max(a.Z, b.Z), + W: math.Max(a.W, b.W), + } +} diff --git a/plugin/math/vec4/vec4.go b/plugin/math/vec4/vec4.go new file mode 100644 index 0000000..bb68607 --- /dev/null +++ b/plugin/math/vec4/vec4.go @@ -0,0 +1,144 @@ +package vec4 + +import ( + "fmt" + + "zworld/plugin/math" + "zworld/plugin/math/vec2" + "zworld/plugin/math/vec3" +) + +var ( + // Zero is the zero vector + Zero = T{0, 0, 0, 0} + + // One is the unit vector + One = T{1, 1, 1, 1} + + // UnitX returns a unit vector in the X direction + UnitX = T{1, 0, 0, 0} + + // UnitY returns a unit vector in the Y direction + UnitY = T{0, 1, 0, 0} + + // UnitZ returns a unit vector in the Z direction + UnitZ = T{0, 0, 1, 0} + + // UnitW returns a unit vector in the W direction + UnitW = T{0, 0, 0, 1} + + InfPos = T{math.InfPos, math.InfPos, math.InfPos, math.InfPos} + InfNeg = T{math.InfNeg, math.InfNeg, math.InfNeg, math.InfNeg} +) + +// T holds a 4-component vector of 32-bit floats +type T struct { + X, Y, Z, W float32 +} + +// Slice converts the vector into a 4-element slice of float32 +func (v T) Slice() [4]float32 { + return [4]float32{v.X, v.Y, v.Z, v.W} +} + +// Length returns the length of the vector. +// See also LengthSqr and Normalize. +func (v T) Length() float32 { + return math.Sqrt(v.LengthSqr()) +} + +// LengthSqr returns the squared length of the vector. +// See also Length and Normalize. +func (v T) LengthSqr() float32 { + return v.X*v.X + v.Y*v.Y + v.Z*v.Z + v.W*v.W +} + +// Abs sets every component of the vector to its absolute value. +func (v T) Abs() T { + return T{ + math.Abs(v.X), + math.Abs(v.Y), + math.Abs(v.Z), + math.Abs(v.W), + } +} + +// Normalize normalizes the vector to unit length. +func (v *T) Normalize() { + sl := v.LengthSqr() + if sl == 0 || sl == 1 { + return + } + s := 1 / math.Sqrt(sl) + v.X *= s + v.Y *= s + v.Z *= s + v.W *= s +} + +// Normalized returns a unit length normalized copy of the vector. +func (v T) Normalized() T { + v.Normalize() + return v +} + +// Scaled the vector +func (v T) Scaled(f float32) T { + return T{v.X * f, v.Y * f, v.Z * f, v.W * f} +} + +// Scale the vector by a constant (in-place) +func (v *T) Scale(f float32) { + v.X *= f + v.Y *= f + v.Z *= f + v.W *= f +} + +// Invert the vector components +func (v *T) Invert() { + v.X = -v.X + v.Y = -v.Y + v.Z = -v.Z + v.W = -v.W +} + +// Inverted returns an inverted vector +func (v T) Inverted() T { + v.Invert() + return v +} + +// Add each element of the vector with the corresponding element of another vector +func (v T) Add(v2 T) T { + return T{v.X + v2.X, v.Y + v2.Y, v.Z + v2.Z, v.W + v2.W} +} + +// Sub subtracts each element of the vector with the corresponding element of another vector +func (v T) Sub(v2 T) T { + return T{v.X - v2.X, v.Y - v2.Y, v.Z - v2.Z, v.W - v2.W} +} + +// Mul multiplies each element of the vector with the corresponding element of another vector +func (v T) Mul(v2 T) T { + return T{v.X * v2.X, v.Y * v2.Y, v.Z * v2.Z, v.W * v2.W} +} + +// XY returns a 2-component vector with the X, Y components +func (v T) XY() vec2.T { + return vec2.T{X: v.X, Y: v.Y} +} + +// XYZ returns a 3-component vector with the X, Y, Z components +func (v T) XYZ() vec3.T { + return vec3.T{X: v.X, Y: v.Y, Z: v.Z} +} + +// Div divides each element of the vector with the corresponding element of another vector +func (v T) Div(v2 T) T { + return T{v.X / v2.X, v.Y / v2.Y, v.Z / v2.Z, v.W / v2.W} +} + +func (v T) String() string { + return fmt.Sprintf("%.3f,%.3f,%.3f,%.3f", v.X, v.Y, v.Z, v.W) +} diff --git a/plugin/objloader/parser.go b/plugin/objloader/parser.go new file mode 100644 index 0000000..59342bd --- /dev/null +++ b/plugin/objloader/parser.go @@ -0,0 +1,111 @@ +package objloader + +import ( + "os" + "zworld/library/zos" + "zworld/plugin/math/vec3" +) + +type FByteView = zos.FByteView +type FVertex struct { + pos int32 + nor int32 + tex int32 +} +type FMesh struct { + Positions []vec3.T + Normals []vec3.T + TexCoords []vec3.T + Faces [][]FVertex + Indices []uint16 +} +type FObjLoader struct { + reader *zos.FReader + mesh *FMesh +} + +func (l *FObjLoader) GetTexCoord(bv *FByteView) error { + x := bv.GetFloat() + y := bv.GetFloat() + if err := bv.Err(); err != nil { + return err + } + w := bv.GetFloat() + if bv.Err() != nil { + w = 0 + } + v := vec3.T{X: x, Y: y, Z: w} + l.mesh.TexCoords = append(l.mesh.TexCoords, v) + return nil +} +func (l *FObjLoader) GetPosition(bv *FByteView) error { + x := bv.GetFloat() + y := bv.GetFloat() + z := bv.GetFloat() + if err := bv.Err(); err != nil { + return err + } + v := vec3.T{X: x, Y: y, Z: z} + l.mesh.Positions = append(l.mesh.Positions, v) + return nil +} +func (l *FObjLoader) GetNormal(bv *FByteView) error { + x := bv.GetFloat() + y := bv.GetFloat() + z := bv.GetFloat() + if err := bv.Err(); err != nil { + return err + } + v := vec3.T{X: x, Y: y, Z: z} + l.mesh.Normals = append(l.mesh.Normals, v) + return nil +} +func (l *FObjLoader) GetFace(b *FByteView) error { + var faces []FVertex + for i := 0; i < 3; i++ { + line := b.GetToken() + bv := zos.NewByteView(line) + bv.SetSign('/') + v := FVertex{} + v.pos = bv.GetInt() + if err := bv.Err(); err != nil { + return err + } + v.nor = bv.GetInt() + v.tex = bv.GetInt() + faces = append(faces, v) + } + l.mesh.Faces = append(l.mesh.Faces, faces) + return nil +} +func (l *FObjLoader) Parse() error { + for line, err := l.reader.ReadLine(); err == nil; line, err = l.reader.ReadLine() { + bv := zos.NewByteView(line) + bv.SkipWhitespace() + token := string(bv.ReadTokenBySpace()) + //zlog.Infof("line {}", string(line)) + switch token { + case "v": + err = l.GetPosition(bv) + case "vt": + err = l.GetTexCoord(bv) + case "vn": + err = l.GetNormal(bv) + case "f": + err = l.GetFace(bv) + } + if err != nil { + return err + } + } + return nil +} +func LoadObj(filename string) (err error, mesh *FMesh) { + file, err := os.Open(filename) + if err != nil { + return err, nil + } + l := &FObjLoader{reader: zos.NewReader(file), mesh: &FMesh{}} + err = l.Parse() + return err, l.mesh +} diff --git a/test/vulkan_instance_test.go b/test/vulkan_instance_test.go new file mode 100644 index 0000000..ea23d8a --- /dev/null +++ b/test/vulkan_instance_test.go @@ -0,0 +1,10 @@ +package test + +import ( + "testing" + "zworld/engine/render/vulkan/instance" +) + +func TestInstance(t *testing.T) { + instance.New("hello world") +}