소스 검색

Merge branch 'master' of github.com:narodnik/sapvi

plato 5 년 전
부모
커밋
53411337db
50개의 변경된 파일3756개의 추가작업 그리고 256개의 파일을 삭제
  1. 10 1
      Cargo.toml
  2. 0 0
      res/font/PressStart2P-Regular.ttf
  3. 0 0
      res/img/absolutely-proprietary.png
  4. 0 0
      res/img/absolutely-proprietary2.png
  5. BIN
      res/model/earth.blend
  6. BIN
      res/model/earth.jpg
  7. 13 0
      res/model/earth.mtl
  8. 2071 0
      res/model/earth.obj
  9. 8 0
      res/shader/light.frag
  10. BIN
      res/shader/light.frag.spv
  11. 27 0
      res/shader/light.vert
  12. BIN
      res/shader/light.vert.spv
  13. 47 0
      res/shader/phong.frag
  14. BIN
      res/shader/phong.frag.spv
  15. 47 0
      res/shader/shader.frag
  16. BIN
      res/shader/shader.frag.spv
  17. 37 0
      res/shader/shader.vert
  18. BIN
      res/shader/shader.vert.spv
  19. 11 0
      res/shader/ui_shader.frag
  20. 0 0
      res/shader/ui_shader.frag.spv
  21. 11 0
      res/shader/ui_shader.vert
  22. 0 0
      res/shader/ui_shader.vert.spv
  23. 94 0
      src/bin/compile-shaders.rs
  24. 589 181
      src/bin/dfg.rs
  25. 191 0
      src/gfx/camera.rs
  26. 3 0
      src/gfx/mod.rs
  27. 317 0
      src/gfx/model.rs
  28. 135 0
      src/gfx/texture.rs
  29. 0 1
      src/gui/mod.rs
  30. 0 1
      src/gui/texture.rs
  31. 1 0
      src/lib.rs
  32. 9 7
      src/net/acceptor.rs
  33. 12 13
      src/net/channel.rs
  34. 1 1
      src/net/connector.rs
  35. 8 4
      src/net/hosts.rs
  36. 6 7
      src/net/message_subscriber.rs
  37. 1 1
      src/net/messages.rs
  38. 1 1
      src/net/mod.rs
  39. 2 2
      src/net/p2p.rs
  40. 15 1
      src/net/protocols/protocol_address.rs
  41. 8 2
      src/net/protocols/protocol_jobs_manager.rs
  42. 18 7
      src/net/protocols/protocol_ping.rs
  43. 11 3
      src/net/protocols/protocol_seed.rs
  44. 9 4
      src/net/protocols/protocol_version.rs
  45. 6 2
      src/net/sessions/inbound_session.rs
  46. 14 9
      src/net/sessions/outbound_session.rs
  47. 5 1
      src/net/sessions/seed_session.rs
  48. 7 1
      src/net/sessions/session.rs
  49. 0 1
      src/net/settings.rs
  50. 11 5
      src/old/mimc.rs

+ 10 - 1
Cargo.toml

@@ -64,12 +64,17 @@ async-native-tls = "0.3.3"
 anyhow = "1.0"
 bytemuck = { version = "1.4", features = [ "derive" ] }
 image = "0.23"
-winit = "0.22"
+winit = "0.23"
 shaderc = "0.7"
 cgmath = "0.17"
 env_logger = "0.7"
 wgpu = "0.7"
 wgpu_glyph = "0.11"
+tobj = "2.0.4"
+
+# used by compile-shaders
+fs_extra = "1.2"
+glob = "0.3"
 
 [[bin]]
 name = "lisp"
@@ -91,3 +96,7 @@ path = "src/old/mimc.rs"
 name = "dfg"
 path = "src/bin/dfg.rs"
 
+[[bin]]
+name = "compile-shaders"
+path = "src/bin/compile-shaders.rs"
+

+ 0 - 0
res/fonts/PressStart2P-Regular.ttf → res/font/PressStart2P-Regular.ttf


+ 0 - 0
src/bin/assets/absolutely-proprietary.png → res/img/absolutely-proprietary.png


+ 0 - 0
src/bin/assets/absolutely-proprietary2.png → res/img/absolutely-proprietary2.png


BIN
res/model/earth.blend


BIN
res/model/earth.jpg


+ 13 - 0
res/model/earth.mtl

@@ -0,0 +1,13 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl Material.001
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+map_Kd earth.jpg

+ 2071 - 0
res/model/earth.obj

@@ -0,0 +1,2071 @@
+# Blender v2.92.0 OBJ File: ''
+# www.blender.org
+mtllib earth.mtl
+o Sphere
+v 0.000000 0.980785 -0.195090
+v 0.000000 0.923880 -0.382683
+v 0.000000 0.831470 -0.555570
+v 0.000000 0.707107 -0.707107
+v 0.000000 0.555570 -0.831470
+v 0.000000 0.382683 -0.923880
+v 0.000000 0.195090 -0.980785
+v 0.000000 0.000000 -1.000000
+v 0.000000 -0.195090 -0.980785
+v 0.000000 -0.831470 -0.555570
+v 0.038060 0.980785 -0.191342
+v 0.074658 0.923880 -0.375330
+v 0.108386 0.831470 -0.544895
+v 0.137950 0.707107 -0.693520
+v 0.162212 0.555570 -0.815493
+v 0.180240 0.382683 -0.906127
+v 0.191342 0.195090 -0.961940
+v 0.195090 0.000000 -0.980785
+v 0.191342 -0.195090 -0.961940
+v 0.180240 -0.382683 -0.906127
+v 0.162212 -0.555570 -0.815493
+v 0.137950 -0.707107 -0.693520
+v 0.108386 -0.831470 -0.544895
+v 0.074658 -0.923880 -0.375330
+v 0.038060 -0.980785 -0.191341
+v 0.074658 0.980785 -0.180240
+v 0.146447 0.923880 -0.353553
+v 0.212608 0.831470 -0.513280
+v 0.270598 0.707107 -0.653281
+v 0.318190 0.555570 -0.768178
+v 0.353553 0.382683 -0.853553
+v 0.375330 0.195090 -0.906127
+v 0.382684 0.000000 -0.923879
+v 0.375330 -0.195090 -0.906127
+v 0.353554 -0.382683 -0.853553
+v 0.318190 -0.555570 -0.768178
+v 0.270598 -0.707107 -0.653281
+v 0.212608 -0.831470 -0.513280
+v 0.146447 -0.923880 -0.353553
+v 0.074658 -0.980785 -0.180240
+v 0.108387 0.980785 -0.162212
+v 0.212608 0.923880 -0.318190
+v 0.308658 0.831470 -0.461940
+v 0.392848 0.707107 -0.587938
+v 0.461940 0.555570 -0.691342
+v 0.513280 0.382683 -0.768178
+v 0.544895 0.195090 -0.815493
+v 0.555570 0.000000 -0.831469
+v 0.544895 -0.195090 -0.815493
+v 0.513280 -0.382683 -0.768178
+v 0.461940 -0.555570 -0.691342
+v 0.392848 -0.707107 -0.587938
+v 0.308658 -0.831470 -0.461940
+v 0.212608 -0.923880 -0.318189
+v 0.108386 -0.980785 -0.162211
+v 0.137950 0.980785 -0.137950
+v 0.270598 0.923880 -0.270598
+v 0.392848 0.831470 -0.392847
+v 0.500000 0.707107 -0.500000
+v 0.587938 0.555570 -0.587938
+v 0.653282 0.382683 -0.653281
+v 0.693520 0.195090 -0.693520
+v 0.707107 0.000000 -0.707107
+v 0.693520 -0.195090 -0.693520
+v 0.653282 -0.382683 -0.653281
+v 0.587938 -0.555570 -0.587938
+v 0.500000 -0.707107 -0.500000
+v 0.392848 -0.831470 -0.392847
+v 0.270598 -0.923880 -0.270598
+v 0.137950 -0.980785 -0.137949
+v 0.162212 0.980785 -0.108386
+v 0.318190 0.923880 -0.212607
+v 0.461940 0.831470 -0.308658
+v 0.587938 0.707107 -0.392847
+v 0.691342 0.555570 -0.461940
+v 0.768178 0.382683 -0.513280
+v 0.815493 0.195090 -0.544895
+v 0.831470 0.000000 -0.555570
+v 0.815493 -0.195090 -0.544895
+v 0.768178 -0.382683 -0.513280
+v 0.691342 -0.555570 -0.461940
+v 0.587938 -0.707107 -0.392847
+v 0.461940 -0.831470 -0.308658
+v 0.318190 -0.923880 -0.212607
+v 0.162212 -0.980785 -0.108386
+v 0.180240 0.980785 -0.074658
+v 0.353554 0.923880 -0.146446
+v 0.513280 0.831470 -0.212607
+v 0.653282 0.707107 -0.270598
+v 0.768178 0.555570 -0.318189
+v 0.853554 0.382683 -0.353553
+v 0.906128 0.195090 -0.375330
+v 0.923880 0.000000 -0.382683
+v 0.906128 -0.195090 -0.375330
+v 0.853554 -0.382683 -0.353553
+v 0.768178 -0.555570 -0.318189
+v 0.653282 -0.707107 -0.270598
+v 0.513280 -0.831470 -0.212607
+v 0.353554 -0.923880 -0.146446
+v 0.180240 -0.980785 -0.074658
+v 0.191342 0.980785 -0.038060
+v 0.375331 0.923880 -0.074658
+v 0.544895 0.831470 -0.108386
+v 0.693520 0.707107 -0.137949
+v 0.815493 0.555570 -0.162211
+v 0.906128 0.382683 -0.180240
+v 0.961940 0.195090 -0.191341
+v 0.980785 0.000000 -0.195090
+v 0.961940 -0.195090 -0.191341
+v 0.906128 -0.382683 -0.180240
+v 0.815493 -0.555570 -0.162211
+v 0.693520 -0.707107 -0.137949
+v 0.544895 -0.831470 -0.108386
+v 0.375330 -0.923880 -0.074658
+v 0.191342 -0.980785 -0.038060
+v 0.195091 0.980785 0.000000
+v 0.382684 0.923880 0.000000
+v 0.555570 0.831470 0.000000
+v 0.707107 0.707107 0.000000
+v 0.831470 0.555570 0.000000
+v 0.923880 0.382683 0.000000
+v 0.980785 0.195090 0.000000
+v 1.000000 0.000000 0.000000
+v 0.980785 -0.195090 0.000000
+v 0.923880 -0.382683 0.000000
+v 0.831470 -0.555570 0.000000
+v 0.707107 -0.707107 0.000000
+v 0.555570 -0.831470 0.000000
+v 0.382684 -0.923880 0.000000
+v 0.195090 -0.980785 0.000000
+v 0.191342 0.980785 0.038061
+v 0.375331 0.923880 0.074658
+v 0.544895 0.831470 0.108387
+v 0.693520 0.707107 0.137950
+v 0.815493 0.555570 0.162212
+v 0.906128 0.382683 0.180240
+v 0.961940 0.195090 0.191342
+v 0.980785 0.000000 0.195091
+v 0.961940 -0.195090 0.191342
+v 0.906128 -0.382683 0.180240
+v 0.815493 -0.555570 0.162212
+v 0.693520 -0.707107 0.137950
+v 0.544895 -0.831470 0.108387
+v 0.375330 -0.923880 0.074658
+v 0.191342 -0.980785 0.038061
+v 0.180240 0.980785 0.074658
+v 0.353554 0.923880 0.146447
+v 0.513280 0.831470 0.212608
+v 0.653282 0.707107 0.270598
+v 0.768178 0.555570 0.318190
+v 0.853554 0.382683 0.353554
+v 0.906127 0.195090 0.375331
+v 0.923880 0.000000 0.382684
+v 0.906127 -0.195090 0.375331
+v 0.853554 -0.382683 0.353554
+v 0.768178 -0.555570 0.318190
+v 0.653282 -0.707107 0.270598
+v 0.513280 -0.831470 0.212608
+v 0.353553 -0.923880 0.146447
+v 0.180240 -0.980785 0.074658
+v 0.162212 0.980785 0.108387
+v 0.318190 0.923880 0.212608
+v 0.461940 0.831470 0.308659
+v 0.587938 0.707107 0.392848
+v 0.691342 0.555570 0.461940
+v 0.768178 0.382683 0.513280
+v 0.815493 0.195090 0.544895
+v 0.831470 0.000000 0.555571
+v 0.815493 -0.195090 0.544895
+v 0.768178 -0.382683 0.513280
+v 0.691342 -0.555570 0.461940
+v 0.587938 -0.707107 0.392848
+v 0.461940 -0.831470 0.308659
+v 0.318190 -0.923880 0.212608
+v 0.162212 -0.980785 0.108387
+v 0.137950 0.980785 0.137950
+v 0.270598 0.923880 0.270599
+v 0.392848 0.831470 0.392848
+v 0.500000 0.707107 0.500000
+v 0.587938 0.555570 0.587938
+v 0.653282 0.382683 0.653282
+v 0.693520 0.195090 0.693520
+v 0.707107 0.000000 0.707107
+v 0.693520 -0.195090 0.693520
+v 0.653282 -0.382683 0.653282
+v 0.587938 -0.555570 0.587938
+v 0.500000 -0.707107 0.500000
+v 0.392848 -0.831470 0.392848
+v 0.270598 -0.923880 0.270598
+v 0.137950 -0.980785 0.137950
+v 0.108386 0.980785 0.162212
+v 0.212608 0.923880 0.318190
+v 0.308658 0.831470 0.461940
+v 0.392848 0.707107 0.587938
+v 0.461940 0.555570 0.691342
+v 0.513280 0.382683 0.768178
+v 0.544895 0.195090 0.815493
+v 0.555570 0.000000 0.831470
+v 0.544895 -0.195090 0.815493
+v 0.513280 -0.382683 0.768178
+v 0.461940 -0.555570 0.691342
+v 0.392848 -0.707107 0.587938
+v 0.308658 -0.831470 0.461940
+v 0.212608 -0.923880 0.318190
+v 0.108386 -0.980785 0.162212
+v 0.000000 -1.000000 0.000000
+v 0.074658 0.980785 0.180240
+v 0.146447 0.923880 0.353554
+v 0.212608 0.831470 0.513280
+v 0.270598 0.707107 0.653282
+v 0.318190 0.555570 0.768178
+v 0.353553 0.382683 0.853554
+v 0.375330 0.195090 0.906128
+v 0.382683 0.000000 0.923880
+v 0.375330 -0.195090 0.906128
+v 0.353553 -0.382683 0.853554
+v 0.318190 -0.555570 0.768178
+v 0.270598 -0.707107 0.653282
+v 0.212608 -0.831470 0.513280
+v 0.146447 -0.923880 0.353554
+v 0.074658 -0.980785 0.180240
+v 0.038060 0.980785 0.191342
+v 0.074658 0.923880 0.375331
+v 0.108386 0.831470 0.544896
+v 0.137950 0.707107 0.693520
+v 0.162212 0.555570 0.815493
+v 0.180240 0.382683 0.906128
+v 0.191342 0.195090 0.961940
+v 0.195090 0.000000 0.980786
+v 0.191342 -0.195090 0.961940
+v 0.180240 -0.382683 0.906128
+v 0.162212 -0.555570 0.815493
+v 0.137950 -0.707107 0.693520
+v 0.108386 -0.831470 0.544895
+v 0.074658 -0.923880 0.375331
+v 0.038060 -0.980785 0.191342
+v -0.000000 0.980785 0.195091
+v 0.000000 0.923880 0.382684
+v 0.000000 0.831470 0.555571
+v -0.000000 0.707107 0.707107
+v -0.000000 0.555570 0.831470
+v 0.000000 0.382683 0.923880
+v -0.000000 0.195090 0.980785
+v -0.000000 0.000000 1.000000
+v -0.000000 -0.195090 0.980785
+v 0.000000 -0.382683 0.923880
+v -0.000000 -0.555570 0.831470
+v -0.000000 -0.707107 0.707107
+v -0.000000 -0.831470 0.555570
+v 0.000000 -0.923880 0.382684
+v 0.000000 -0.980785 0.195091
+v -0.038060 0.980785 0.191342
+v -0.074658 0.923880 0.375331
+v -0.108386 0.831470 0.544896
+v -0.137950 0.707107 0.693520
+v -0.162212 0.555570 0.815493
+v -0.180240 0.382683 0.906128
+v -0.191342 0.195090 0.961940
+v -0.195090 0.000000 0.980786
+v -0.191342 -0.195090 0.961940
+v -0.180240 -0.382683 0.906128
+v -0.162212 -0.555570 0.815493
+v -0.137950 -0.707107 0.693520
+v -0.108386 -0.831470 0.544895
+v -0.074658 -0.923880 0.375331
+v -0.038060 -0.980785 0.191342
+v -0.074658 0.980785 0.180240
+v -0.146447 0.923880 0.353554
+v -0.212608 0.831470 0.513280
+v -0.270598 0.707107 0.653282
+v -0.318190 0.555570 0.768178
+v -0.353553 0.382683 0.853554
+v -0.375330 0.195090 0.906127
+v -0.382684 0.000000 0.923880
+v -0.375330 -0.195090 0.906127
+v -0.353553 -0.382683 0.853554
+v -0.318190 -0.555570 0.768178
+v -0.270598 -0.707107 0.653282
+v -0.212608 -0.831470 0.513280
+v -0.146447 -0.923880 0.353554
+v -0.074658 -0.980785 0.180240
+v -0.108386 0.980785 0.162212
+v -0.212608 0.923880 0.318190
+v -0.308658 0.831470 0.461940
+v -0.392847 0.707107 0.587938
+v -0.461940 0.555570 0.691342
+v -0.513280 0.382683 0.768178
+v -0.544895 0.195090 0.815493
+v -0.555570 0.000000 0.831470
+v -0.544895 -0.195090 0.815493
+v -0.513280 -0.382683 0.768178
+v -0.461940 -0.555570 0.691342
+v -0.392847 -0.707107 0.587938
+v -0.308658 -0.831470 0.461940
+v -0.212607 -0.923880 0.318190
+v -0.108386 -0.980785 0.162212
+v -0.000000 1.000000 0.000001
+v -0.137950 0.980785 0.137950
+v -0.270598 0.923880 0.270598
+v -0.392848 0.831470 0.392848
+v -0.500000 0.707107 0.500000
+v -0.587938 0.555570 0.587938
+v -0.653281 0.382683 0.653282
+v -0.693520 0.195090 0.693520
+v -0.707107 0.000000 0.707107
+v -0.693520 -0.195090 0.693520
+v -0.653281 -0.382683 0.653282
+v -0.587938 -0.555570 0.587938
+v -0.500000 -0.707107 0.500000
+v -0.392847 -0.831470 0.392848
+v -0.270598 -0.923880 0.270598
+v -0.137950 -0.980785 0.137950
+v -0.162212 0.980785 0.108387
+v -0.318190 0.923880 0.212608
+v -0.461940 0.831470 0.308659
+v -0.587938 0.707107 0.392848
+v -0.691342 0.555570 0.461940
+v -0.768178 0.382683 0.513280
+v -0.815493 0.195090 0.544895
+v -0.831470 0.000000 0.555570
+v -0.815493 -0.195090 0.544895
+v -0.768178 -0.382683 0.513280
+v -0.691342 -0.555570 0.461940
+v -0.587938 -0.707107 0.392848
+v -0.461940 -0.831470 0.308658
+v -0.318190 -0.923880 0.212608
+v -0.162212 -0.980785 0.108387
+v -0.180240 0.980785 0.074658
+v -0.353553 0.923880 0.146447
+v -0.513280 0.831470 0.212608
+v -0.653281 0.707107 0.270598
+v -0.768177 0.555570 0.318190
+v -0.853553 0.382683 0.353554
+v -0.906127 0.195090 0.375330
+v -0.923880 0.000000 0.382684
+v -0.906127 -0.195090 0.375330
+v -0.853553 -0.382683 0.353554
+v -0.768177 -0.555570 0.318190
+v -0.653281 -0.707107 0.270598
+v -0.513280 -0.831470 0.212608
+v -0.353553 -0.923880 0.146447
+v -0.180240 -0.980785 0.074658
+v -0.191342 0.980785 0.038061
+v -0.375330 0.923880 0.074658
+v -0.544895 0.831470 0.108387
+v -0.693520 0.707107 0.137950
+v -0.815493 0.555570 0.162212
+v -0.906127 0.382683 0.180240
+v -0.961939 0.195090 0.191342
+v -0.980785 0.000000 0.195090
+v -0.961939 -0.195090 0.191342
+v -0.906127 -0.382683 0.180240
+v -0.815493 -0.555570 0.162212
+v -0.693520 -0.707107 0.137950
+v -0.544895 -0.831470 0.108387
+v -0.375330 -0.923880 0.074658
+v -0.191342 -0.980785 0.038061
+v -0.195090 0.980785 0.000000
+v -0.382683 0.923880 0.000000
+v -0.555570 0.831470 0.000000
+v -0.707107 0.707107 0.000000
+v -0.831469 0.555570 0.000000
+v -0.923879 0.382683 0.000000
+v -0.980785 0.195090 0.000000
+v -1.000000 0.000000 0.000000
+v -0.980785 -0.195090 0.000000
+v -0.923879 -0.382683 0.000000
+v -0.831469 -0.555570 0.000000
+v -0.707107 -0.707107 0.000000
+v -0.555570 -0.831470 0.000000
+v -0.382683 -0.923880 0.000000
+v -0.195090 -0.980785 0.000000
+v -0.191342 0.980785 -0.038060
+v -0.375330 0.923880 -0.074658
+v -0.544895 0.831470 -0.108386
+v -0.693520 0.707107 -0.137949
+v -0.815493 0.555570 -0.162211
+v -0.906127 0.382683 -0.180240
+v -0.961939 0.195090 -0.191342
+v -0.980785 0.000000 -0.195090
+v -0.961939 -0.195090 -0.191342
+v -0.906127 -0.382683 -0.180240
+v -0.815493 -0.555570 -0.162211
+v -0.693520 -0.707107 -0.137949
+v -0.544895 -0.831470 -0.108386
+v -0.375330 -0.923880 -0.074658
+v -0.191342 -0.980785 -0.038060
+v -0.180240 0.980785 -0.074658
+v -0.353553 0.923880 -0.146446
+v -0.513280 0.831470 -0.212607
+v -0.653281 0.707107 -0.270598
+v -0.768177 0.555570 -0.318189
+v -0.853553 0.382683 -0.353553
+v -0.906127 0.195090 -0.375330
+v -0.923879 0.000000 -0.382683
+v -0.906127 -0.195090 -0.375330
+v -0.853553 -0.382683 -0.353553
+v -0.768177 -0.555570 -0.318189
+v -0.653281 -0.707107 -0.270598
+v -0.513280 -0.831470 -0.212607
+v -0.353553 -0.923880 -0.146446
+v -0.180240 -0.980785 -0.074657
+v -0.162212 0.980785 -0.108386
+v -0.318190 0.923880 -0.212607
+v -0.461940 0.831470 -0.308658
+v -0.587938 0.707107 -0.392847
+v -0.691341 0.555570 -0.461939
+v -0.768178 0.382683 -0.513280
+v -0.815493 0.195090 -0.544895
+v -0.831469 0.000000 -0.555570
+v -0.815493 -0.195090 -0.544895
+v -0.768178 -0.382683 -0.513280
+v -0.691341 -0.555570 -0.461939
+v -0.587938 -0.707107 -0.392847
+v -0.461940 -0.831470 -0.308658
+v -0.318189 -0.923880 -0.212607
+v -0.162212 -0.980785 -0.108386
+v -0.137950 0.980785 -0.137949
+v -0.270598 0.923880 -0.270598
+v -0.392847 0.831470 -0.392847
+v -0.500000 0.707107 -0.500000
+v -0.587937 0.555570 -0.587937
+v -0.653281 0.382683 -0.653281
+v -0.693519 0.195090 -0.693519
+v -0.707106 0.000000 -0.707106
+v -0.693519 -0.195090 -0.693519
+v -0.653281 -0.382683 -0.653281
+v -0.587937 -0.555570 -0.587937
+v -0.500000 -0.707107 -0.500000
+v -0.392847 -0.831470 -0.392847
+v -0.270598 -0.923880 -0.270598
+v -0.137950 -0.980785 -0.137949
+v -0.108386 0.980785 -0.162211
+v -0.212607 0.923880 -0.318189
+v -0.308658 0.831470 -0.461939
+v -0.392847 0.707107 -0.587937
+v -0.461939 0.555570 -0.691341
+v -0.513280 0.382683 -0.768177
+v -0.544895 0.195090 -0.815492
+v -0.555570 0.000000 -0.831469
+v -0.544895 -0.195090 -0.815492
+v -0.513280 -0.382683 -0.768177
+v -0.461939 -0.555570 -0.691341
+v -0.392847 -0.707107 -0.587937
+v -0.308658 -0.831470 -0.461939
+v -0.212607 -0.923880 -0.318189
+v -0.108386 -0.980785 -0.162211
+v -0.074658 0.980785 -0.180240
+v -0.146447 0.923880 -0.353553
+v -0.212607 0.831470 -0.513280
+v -0.270598 0.707107 -0.653281
+v -0.318189 0.555570 -0.768177
+v -0.353553 0.382683 -0.853553
+v -0.375330 0.195090 -0.906127
+v -0.382683 0.000000 -0.923879
+v -0.375330 -0.195090 -0.906127
+v -0.353553 -0.382683 -0.853553
+v -0.318189 -0.555570 -0.768177
+v -0.270598 -0.707107 -0.653281
+v -0.212607 -0.831470 -0.513279
+v -0.146446 -0.923880 -0.353553
+v -0.074658 -0.980785 -0.180240
+v -0.038060 0.980785 -0.191342
+v -0.074658 0.923880 -0.375330
+v -0.108386 0.831470 -0.544895
+v -0.137950 0.707107 -0.693520
+v -0.162211 0.555570 -0.815492
+v -0.180240 0.382683 -0.906127
+v -0.191341 0.195090 -0.961939
+v -0.195090 0.000000 -0.980785
+v -0.191341 -0.195090 -0.961939
+v -0.180240 -0.382683 -0.906127
+v -0.162211 -0.555570 -0.815492
+v -0.137950 -0.707107 -0.693520
+v -0.108386 -0.831470 -0.544895
+v -0.074658 -0.923880 -0.375330
+v -0.038060 -0.980785 -0.191341
+v 0.000000 -0.382683 -0.923879
+v 0.000000 -0.555570 -0.831469
+v 0.000000 -0.707107 -0.707106
+v 0.000000 -0.923880 -0.382683
+v 0.000000 -0.980785 -0.195090
+vt 0.750000 0.187500
+vt 0.750000 0.250000
+vt 0.718750 0.250000
+vt 0.718750 0.187500
+vt 0.750000 0.625000
+vt 0.750000 0.687500
+vt 0.718750 0.687500
+vt 0.718750 0.625000
+vt 0.750000 0.125000
+vt 0.718750 0.125000
+vt 0.750000 0.562500
+vt 0.718750 0.562500
+vt 0.750000 0.062500
+vt 0.718750 0.062500
+vt 0.750000 0.500000
+vt 0.718750 0.500000
+vt 0.750000 0.937500
+vt 0.734375 1.000000
+vt 0.718750 0.937500
+vt 0.734375 0.000000
+vt 0.750000 0.437500
+vt 0.718750 0.437500
+vt 0.750000 0.875000
+vt 0.718750 0.875000
+vt 0.750000 0.375000
+vt 0.718750 0.375000
+vt 0.750000 0.812500
+vt 0.718750 0.812500
+vt 0.750000 0.312500
+vt 0.718750 0.312500
+vt 0.750000 0.750000
+vt 0.718750 0.750000
+vt 0.687500 0.312500
+vt 0.687500 0.250000
+vt 0.687500 0.750000
+vt 0.687500 0.687500
+vt 0.687500 0.187500
+vt 0.687500 0.625000
+vt 0.687500 0.125000
+vt 0.687500 0.562500
+vt 0.687500 0.062500
+vt 0.687500 0.500000
+vt 0.703125 1.000000
+vt 0.687500 0.937500
+vt 0.703125 0.000000
+vt 0.687500 0.437500
+vt 0.687500 0.875000
+vt 0.687500 0.375000
+vt 0.687500 0.812500
+vt 0.671875 1.000000
+vt 0.656250 0.937500
+vt 0.671875 0.000000
+vt 0.656250 0.062500
+vt 0.656250 0.500000
+vt 0.656250 0.437500
+vt 0.656250 0.875000
+vt 0.656250 0.375000
+vt 0.656250 0.812500
+vt 0.656250 0.312500
+vt 0.656250 0.750000
+vt 0.656250 0.250000
+vt 0.656250 0.687500
+vt 0.656250 0.187500
+vt 0.656250 0.625000
+vt 0.656250 0.125000
+vt 0.656250 0.562500
+vt 0.625000 0.750000
+vt 0.625000 0.687500
+vt 0.625000 0.250000
+vt 0.625000 0.187500
+vt 0.625000 0.625000
+vt 0.625000 0.125000
+vt 0.625000 0.562500
+vt 0.625000 0.062500
+vt 0.625000 0.500000
+vt 0.640625 1.000000
+vt 0.625000 0.937500
+vt 0.640625 0.000000
+vt 0.625000 0.437500
+vt 0.625000 0.875000
+vt 0.625000 0.375000
+vt 0.625000 0.812500
+vt 0.625000 0.312500
+vt 0.593750 0.500000
+vt 0.593750 0.437500
+vt 0.593750 0.937500
+vt 0.593750 0.875000
+vt 0.593750 0.375000
+vt 0.593750 0.812500
+vt 0.593750 0.312500
+vt 0.593750 0.750000
+vt 0.593750 0.250000
+vt 0.593750 0.687500
+vt 0.593750 0.187500
+vt 0.593750 0.625000
+vt 0.593750 0.125000
+vt 0.593750 0.562500
+vt 0.593750 0.062500
+vt 0.609375 1.000000
+vt 0.609375 0.000000
+vt 0.562500 0.250000
+vt 0.562500 0.187500
+vt 0.562500 0.687500
+vt 0.562500 0.625000
+vt 0.562500 0.125000
+vt 0.562500 0.562500
+vt 0.562500 0.062500
+vt 0.562500 0.500000
+vt 0.578125 1.000000
+vt 0.562500 0.937500
+vt 0.578125 0.000000
+vt 0.562500 0.437500
+vt 0.562500 0.875000
+vt 0.562500 0.375000
+vt 0.562500 0.812500
+vt 0.562500 0.312500
+vt 0.562500 0.750000
+vt 0.531250 0.937500
+vt 0.531250 0.875000
+vt 0.531250 0.437500
+vt 0.531250 0.375000
+vt 0.531250 0.812500
+vt 0.531250 0.312500
+vt 0.531250 0.750000
+vt 0.531250 0.250000
+vt 0.531250 0.687500
+vt 0.531250 0.187500
+vt 0.531250 0.625000
+vt 0.531250 0.125000
+vt 0.531250 0.562500
+vt 0.531250 0.062500
+vt 0.531250 0.500000
+vt 0.546875 1.000000
+vt 0.546875 0.000000
+vt 0.500000 0.687500
+vt 0.500000 0.625000
+vt 0.500000 0.187500
+vt 0.500000 0.125000
+vt 0.500000 0.562500
+vt 0.500000 0.062500
+vt 0.500000 0.500000
+vt 0.515625 1.000000
+vt 0.500000 0.937500
+vt 0.515625 0.000000
+vt 0.500000 0.437500
+vt 0.500000 0.875000
+vt 0.500000 0.375000
+vt 0.500000 0.812500
+vt 0.500000 0.312500
+vt 0.500000 0.750000
+vt 0.500000 0.250000
+vt 0.468750 0.437500
+vt 0.468750 0.375000
+vt 0.468750 0.875000
+vt 0.468750 0.812500
+vt 0.468750 0.312500
+vt 0.468750 0.750000
+vt 0.468750 0.250000
+vt 0.468750 0.687500
+vt 0.468750 0.187500
+vt 0.468750 0.625000
+vt 0.468750 0.125000
+vt 0.468750 0.562500
+vt 0.468750 0.062500
+vt 0.468750 0.500000
+vt 0.484374 1.000000
+vt 0.468750 0.937500
+vt 0.484375 0.000000
+vt 0.437500 0.187500
+vt 0.437500 0.125000
+vt 0.437500 0.625000
+vt 0.437500 0.562500
+vt 0.437500 0.062500
+vt 0.437500 0.500000
+vt 0.453124 1.000000
+vt 0.437500 0.937500
+vt 0.453125 0.000000
+vt 0.437500 0.437500
+vt 0.437500 0.875000
+vt 0.437500 0.375000
+vt 0.437500 0.812500
+vt 0.437500 0.312500
+vt 0.437500 0.750000
+vt 0.437500 0.250000
+vt 0.437500 0.687500
+vt 0.406250 0.375000
+vt 0.406250 0.312500
+vt 0.406250 0.812500
+vt 0.406250 0.750000
+vt 0.406250 0.250000
+vt 0.406250 0.687500
+vt 0.406250 0.187500
+vt 0.406250 0.625000
+vt 0.406250 0.125000
+vt 0.406250 0.562500
+vt 0.406250 0.062500
+vt 0.406250 0.500000
+vt 0.421874 1.000000
+vt 0.406250 0.937500
+vt 0.421875 0.000000
+vt 0.406250 0.437500
+vt 0.406250 0.875000
+vt 0.375000 0.125000
+vt 0.375000 0.062500
+vt 0.375000 0.562500
+vt 0.375000 0.500000
+vt 0.390625 1.000000
+vt 0.375000 0.937500
+vt 0.390625 0.000000
+vt 0.375000 0.437500
+vt 0.375000 0.875000
+vt 0.375000 0.375000
+vt 0.375000 0.812500
+vt 0.375000 0.312500
+vt 0.375000 0.750000
+vt 0.375000 0.250000
+vt 0.375000 0.687500
+vt 0.375000 0.187500
+vt 0.375000 0.625000
+vt 0.343750 0.812500
+vt 0.343750 0.750000
+vt 0.343750 0.312500
+vt 0.343750 0.250000
+vt 0.343750 0.687500
+vt 0.343750 0.187500
+vt 0.343750 0.625000
+vt 0.343750 0.125000
+vt 0.343750 0.562500
+vt 0.343750 0.062500
+vt 0.343750 0.500000
+vt 0.359375 1.000000
+vt 0.343750 0.937500
+vt 0.359375 0.000000
+vt 0.343750 0.437500
+vt 0.343750 0.875000
+vt 0.343750 0.375000
+vt 0.312500 0.562500
+vt 0.312500 0.500000
+vt 0.328125 1.000000
+vt 0.312500 0.937500
+vt 0.328125 0.000000
+vt 0.312500 0.062500
+vt 0.312500 0.437500
+vt 0.312500 0.875000
+vt 0.312500 0.375000
+vt 0.312500 0.812500
+vt 0.312500 0.312500
+vt 0.312500 0.750000
+vt 0.312500 0.250000
+vt 0.312500 0.687500
+vt 0.312500 0.187500
+vt 0.312500 0.625000
+vt 0.312500 0.125000
+vt 0.281250 0.312500
+vt 0.281250 0.250000
+vt 0.281250 0.750000
+vt 0.281250 0.687500
+vt 0.281250 0.187500
+vt 0.281250 0.625000
+vt 0.281250 0.125000
+vt 0.281250 0.562500
+vt 0.281250 0.062500
+vt 0.281250 0.500000
+vt 0.296875 1.000000
+vt 0.281250 0.937500
+vt 0.296875 0.000000
+vt 0.281250 0.437500
+vt 0.281250 0.875000
+vt 0.281250 0.375000
+vt 0.281250 0.812500
+vt 0.265625 1.000000
+vt 0.250000 0.937500
+vt 0.265625 0.000000
+vt 0.250000 0.062500
+vt 0.250000 0.500000
+vt 0.250000 0.437500
+vt 0.250000 0.875000
+vt 0.250000 0.375000
+vt 0.250000 0.812500
+vt 0.250000 0.312500
+vt 0.250000 0.750000
+vt 0.250000 0.250000
+vt 0.250000 0.687500
+vt 0.250000 0.187500
+vt 0.250000 0.625000
+vt 0.250000 0.125000
+vt 0.250000 0.562500
+vt 0.218750 0.750000
+vt 0.218750 0.687500
+vt 0.218750 0.250000
+vt 0.218750 0.187500
+vt 0.218750 0.625000
+vt 0.218750 0.125000
+vt 0.218750 0.562500
+vt 0.218750 0.062500
+vt 0.218750 0.500000
+vt 0.234375 1.000000
+vt 0.218750 0.937500
+vt 0.234375 0.000000
+vt 0.218750 0.437500
+vt 0.218750 0.875000
+vt 0.218750 0.375000
+vt 0.218750 0.812500
+vt 0.218750 0.312500
+vt 0.187500 0.500000
+vt 0.187500 0.437500
+vt 0.187500 0.937500
+vt 0.187500 0.875000
+vt 0.187500 0.375000
+vt 0.187500 0.812500
+vt 0.187500 0.312500
+vt 0.187500 0.750000
+vt 0.187500 0.250000
+vt 0.187500 0.687500
+vt 0.187500 0.187500
+vt 0.187500 0.625000
+vt 0.187500 0.125000
+vt 0.187500 0.562500
+vt 0.187500 0.062500
+vt 0.203125 1.000000
+vt 0.203125 0.000000
+vt 0.156250 0.250000
+vt 0.156250 0.187500
+vt 0.156250 0.687500
+vt 0.156250 0.625000
+vt 0.156250 0.125000
+vt 0.156250 0.562500
+vt 0.156250 0.062500
+vt 0.156250 0.500000
+vt 0.171875 1.000000
+vt 0.156250 0.937500
+vt 0.171875 0.000000
+vt 0.156250 0.437500
+vt 0.156250 0.875000
+vt 0.156250 0.375000
+vt 0.156250 0.812500
+vt 0.156250 0.312500
+vt 0.156250 0.750000
+vt 0.125000 0.437500
+vt 0.125000 0.375000
+vt 0.125000 0.875000
+vt 0.125000 0.812500
+vt 0.125000 0.312500
+vt 0.125000 0.750000
+vt 0.125000 0.250000
+vt 0.125000 0.687500
+vt 0.125000 0.187500
+vt 0.125000 0.625000
+vt 0.125000 0.125000
+vt 0.125000 0.562500
+vt 0.125000 0.062500
+vt 0.125000 0.500000
+vt 0.140625 1.000000
+vt 0.125000 0.937500
+vt 0.140625 0.000000
+vt 0.093750 0.187500
+vt 0.093750 0.125000
+vt 0.093750 0.625000
+vt 0.093750 0.562500
+vt 0.093750 0.062500
+vt 0.093750 0.500000
+vt 0.109375 1.000000
+vt 0.093750 0.937500
+vt 0.109375 0.000000
+vt 0.093750 0.437500
+vt 0.093750 0.875000
+vt 0.093750 0.375000
+vt 0.093750 0.812500
+vt 0.093750 0.312500
+vt 0.093750 0.750000
+vt 0.093750 0.250000
+vt 0.093750 0.687500
+vt 0.062500 0.875000
+vt 0.062500 0.812500
+vt 0.062500 0.375000
+vt 0.062500 0.312500
+vt 0.062500 0.750000
+vt 0.062500 0.250000
+vt 0.062500 0.687500
+vt 0.062500 0.187500
+vt 0.062500 0.625000
+vt 0.062500 0.125000
+vt 0.062500 0.562500
+vt 0.062500 0.062500
+vt 0.062500 0.500000
+vt 0.078125 1.000000
+vt 0.062500 0.937500
+vt 0.078125 0.000000
+vt 0.062500 0.437500
+vt 0.031250 0.625000
+vt 0.031250 0.562500
+vt 0.031250 0.125000
+vt 0.031250 0.062500
+vt 0.031250 0.500000
+vt 0.046875 1.000000
+vt 0.031250 0.937500
+vt 0.046875 0.000000
+vt 0.031250 0.437500
+vt 0.031250 0.875000
+vt 0.031250 0.375000
+vt 0.031250 0.812500
+vt 0.031250 0.312500
+vt 0.031250 0.750000
+vt 0.031250 0.250000
+vt 0.031250 0.687500
+vt 0.031250 0.187500
+vt 0.000000 0.375000
+vt 0.000000 0.312500
+vt 0.000000 0.812500
+vt 0.000000 0.750000
+vt 0.000000 0.250000
+vt 0.000000 0.687500
+vt 0.000000 0.187500
+vt 0.000000 0.625000
+vt 0.000000 0.125000
+vt 0.000000 0.562500
+vt 0.000000 0.062500
+vt 0.000000 0.500000
+vt 0.015625 1.000000
+vt 0.000000 0.937500
+vt 0.015625 0.000000
+vt 0.000000 0.437500
+vt 0.000000 0.875000
+vt 1.000000 0.062500
+vt 1.000000 0.125000
+vt 0.968750 0.125000
+vt 0.968750 0.062500
+vt 1.000000 0.500000
+vt 1.000000 0.562500
+vt 0.968750 0.562500
+vt 0.968750 0.500000
+vt 1.000000 0.937500
+vt 0.984375 1.000000
+vt 0.968750 0.937500
+vt 0.984375 0.000000
+vt 1.000000 0.437500
+vt 0.968750 0.437500
+vt 1.000000 0.875000
+vt 0.968750 0.875000
+vt 1.000000 0.375000
+vt 0.968750 0.375000
+vt 1.000000 0.812500
+vt 0.968750 0.812500
+vt 1.000000 0.312500
+vt 0.968750 0.312500
+vt 1.000000 0.750000
+vt 0.968750 0.750000
+vt 1.000000 0.250000
+vt 0.968750 0.250000
+vt 1.000000 0.687500
+vt 0.968750 0.687500
+vt 1.000000 0.187500
+vt 0.968750 0.187500
+vt 1.000000 0.625000
+vt 0.968750 0.625000
+vt 0.937500 0.812500
+vt 0.937500 0.750000
+vt 0.937500 0.312500
+vt 0.937500 0.250000
+vt 0.937500 0.687500
+vt 0.937500 0.187500
+vt 0.937500 0.625000
+vt 0.937500 0.125000
+vt 0.937500 0.562500
+vt 0.937500 0.062500
+vt 0.937500 0.500000
+vt 0.953125 1.000000
+vt 0.937500 0.937500
+vt 0.953125 0.000000
+vt 0.937500 0.437500
+vt 0.937500 0.875000
+vt 0.937500 0.375000
+vt 0.906250 0.562500
+vt 0.906250 0.500000
+vt 0.921875 1.000000
+vt 0.906250 0.937500
+vt 0.921875 0.000000
+vt 0.906250 0.062500
+vt 0.906250 0.437500
+vt 0.906250 0.875000
+vt 0.906250 0.375000
+vt 0.906250 0.812500
+vt 0.906250 0.312500
+vt 0.906250 0.750000
+vt 0.906250 0.250000
+vt 0.906250 0.687500
+vt 0.906250 0.187500
+vt 0.906250 0.625000
+vt 0.906250 0.125000
+vt 0.875000 0.312500
+vt 0.875000 0.250000
+vt 0.875000 0.750000
+vt 0.875000 0.687500
+vt 0.875000 0.187500
+vt 0.875000 0.625000
+vt 0.875000 0.125000
+vt 0.875000 0.562500
+vt 0.875000 0.062500
+vt 0.875000 0.500000
+vt 0.890625 1.000000
+vt 0.875000 0.937500
+vt 0.890625 0.000000
+vt 0.875000 0.437500
+vt 0.875000 0.875000
+vt 0.875000 0.375000
+vt 0.875000 0.812500
+vt 0.859375 0.000000
+vt 0.843750 0.062500
+vt 0.843750 0.500000
+vt 0.843750 0.437500
+vt 0.843750 0.937500
+vt 0.843750 0.875000
+vt 0.843750 0.375000
+vt 0.843750 0.812500
+vt 0.843750 0.312500
+vt 0.843750 0.750000
+vt 0.843750 0.250000
+vt 0.843750 0.687500
+vt 0.843750 0.187500
+vt 0.843750 0.625000
+vt 0.843750 0.125000
+vt 0.843750 0.562500
+vt 0.859375 1.000000
+vt 0.812500 0.250000
+vt 0.812500 0.187500
+vt 0.812500 0.687500
+vt 0.812500 0.625000
+vt 0.812500 0.125000
+vt 0.812500 0.562500
+vt 0.812500 0.062500
+vt 0.812500 0.500000
+vt 0.828125 1.000000
+vt 0.812500 0.937500
+vt 0.828125 0.000000
+vt 0.812500 0.437500
+vt 0.812500 0.875000
+vt 0.812500 0.375000
+vt 0.812500 0.812500
+vt 0.812500 0.312500
+vt 0.812500 0.750000
+vt 0.781250 0.937500
+vt 0.781250 0.875000
+vt 0.781250 0.437500
+vt 0.781250 0.375000
+vt 0.781250 0.812500
+vt 0.781250 0.312500
+vt 0.781250 0.750000
+vt 0.781250 0.250000
+vt 0.781250 0.687500
+vt 0.781250 0.187500
+vt 0.781250 0.625000
+vt 0.781250 0.125000
+vt 0.781250 0.562500
+vt 0.781250 0.062500
+vt 0.781250 0.500000
+vt 0.796875 1.000000
+vt 0.796875 0.000000
+vt 0.765625 1.000000
+vt 0.765625 0.000000
+vn 0.0624 -0.7715 -0.6332
+vn 0.0865 0.4696 -0.8786
+vn 0.0464 -0.8810 -0.4709
+vn 0.0938 0.2890 -0.9527
+vn 0.0286 -0.9565 -0.2902
+vn 0.0975 0.0975 -0.9904
+vn 0.0097 0.9951 -0.0980
+vn 0.0097 -0.9951 -0.0980
+vn 0.0976 -0.0975 -0.9904
+vn 0.0286 0.9565 -0.2902
+vn 0.0938 -0.2890 -0.9527
+vn 0.0464 0.8810 -0.4709
+vn 0.0865 -0.4696 -0.8786
+vn 0.0624 0.7715 -0.6332
+vn 0.0759 -0.6326 -0.7708
+vn 0.0759 0.6326 -0.7708
+vn 0.2248 -0.6326 -0.7412
+vn 0.2248 0.6326 -0.7412
+vn 0.1847 -0.7715 -0.6088
+vn 0.2563 0.4696 -0.8448
+vn 0.1374 -0.8810 -0.4528
+vn 0.2779 0.2890 -0.9161
+vn 0.0846 -0.9565 -0.2790
+vn 0.2889 0.0975 -0.9524
+vn 0.0286 0.9951 -0.0942
+vn 0.0286 -0.9951 -0.0942
+vn 0.2889 -0.0975 -0.9524
+vn 0.0846 0.9565 -0.2790
+vn 0.2779 -0.2890 -0.9161
+vn 0.1374 0.8810 -0.4528
+vn 0.2563 -0.4696 -0.8448
+vn 0.1847 0.7715 -0.6088
+vn 0.0464 0.9951 -0.0869
+vn 0.0464 -0.9951 -0.0869
+vn 0.4691 -0.0975 -0.8777
+vn 0.1374 0.9565 -0.2571
+vn 0.4513 -0.2890 -0.8443
+vn 0.2230 0.8810 -0.4173
+vn 0.4162 -0.4696 -0.7786
+vn 0.2999 0.7715 -0.5611
+vn 0.3651 -0.6326 -0.6831
+vn 0.3651 0.6326 -0.6831
+vn 0.2999 -0.7715 -0.5611
+vn 0.4162 0.4696 -0.7786
+vn 0.2230 -0.8810 -0.4173
+vn 0.4513 0.2890 -0.8443
+vn 0.1374 -0.9565 -0.2571
+vn 0.4691 0.0975 -0.8777
+vn 0.4913 0.6326 -0.5987
+vn 0.4036 -0.7715 -0.4918
+vn 0.5601 0.4696 -0.6825
+vn 0.3002 -0.8810 -0.3658
+vn 0.6073 0.2890 -0.7400
+vn 0.1850 -0.9565 -0.2254
+vn 0.6314 0.0976 -0.7693
+vn 0.0625 0.9951 -0.0761
+vn 0.0625 -0.9951 -0.0761
+vn 0.6314 -0.0976 -0.7693
+vn 0.1850 0.9565 -0.2254
+vn 0.6073 -0.2890 -0.7400
+vn 0.3002 0.8810 -0.3658
+vn 0.5601 -0.4696 -0.6825
+vn 0.4036 0.7715 -0.4918
+vn 0.4913 -0.6326 -0.5987
+vn 0.7693 -0.0975 -0.6314
+vn 0.2254 0.9565 -0.1850
+vn 0.7400 -0.2890 -0.6073
+vn 0.3658 0.8810 -0.3002
+vn 0.6825 -0.4696 -0.5601
+vn 0.4918 0.7715 -0.4036
+vn 0.5987 -0.6326 -0.4913
+vn 0.5987 0.6326 -0.4913
+vn 0.4918 -0.7715 -0.4036
+vn 0.6825 0.4696 -0.5601
+vn 0.3658 -0.8810 -0.3002
+vn 0.7400 0.2890 -0.6073
+vn 0.2254 -0.9565 -0.1850
+vn 0.7693 0.0975 -0.6314
+vn 0.0761 0.9951 -0.0625
+vn 0.0761 -0.9951 -0.0625
+vn 0.5611 -0.7715 -0.2999
+vn 0.7786 0.4696 -0.4162
+vn 0.4173 -0.8810 -0.2231
+vn 0.8443 0.2890 -0.4513
+vn 0.2571 -0.9565 -0.1374
+vn 0.8777 0.0976 -0.4691
+vn 0.0869 0.9951 -0.0464
+vn 0.0869 -0.9951 -0.0464
+vn 0.8777 -0.0976 -0.4691
+vn 0.2571 0.9565 -0.1374
+vn 0.8443 -0.2890 -0.4513
+vn 0.4173 0.8810 -0.2231
+vn 0.7786 -0.4696 -0.4162
+vn 0.5611 0.7715 -0.2999
+vn 0.6831 -0.6326 -0.3651
+vn 0.6831 0.6326 -0.3651
+vn 0.2790 0.9565 -0.0846
+vn 0.9161 -0.2890 -0.2779
+vn 0.4528 0.8810 -0.1374
+vn 0.8448 -0.4696 -0.2563
+vn 0.6088 0.7715 -0.1847
+vn 0.7412 -0.6326 -0.2248
+vn 0.7412 0.6326 -0.2248
+vn 0.6088 -0.7715 -0.1847
+vn 0.8448 0.4696 -0.2563
+vn 0.4528 -0.8810 -0.1374
+vn 0.9161 0.2890 -0.2779
+vn 0.2790 -0.9565 -0.0846
+vn 0.9524 0.0976 -0.2889
+vn 0.0942 0.9951 -0.0286
+vn 0.0942 -0.9951 -0.0286
+vn 0.9524 -0.0976 -0.2889
+vn 0.8786 0.4696 -0.0865
+vn 0.4709 -0.8810 -0.0464
+vn 0.9527 0.2890 -0.0938
+vn 0.2902 -0.9565 -0.0286
+vn 0.9904 0.0976 -0.0975
+vn 0.0980 0.9951 -0.0097
+vn 0.0980 -0.9951 -0.0097
+vn 0.9904 -0.0976 -0.0975
+vn 0.2902 0.9565 -0.0286
+vn 0.9527 -0.2890 -0.0938
+vn 0.4709 0.8810 -0.0464
+vn 0.8786 -0.4696 -0.0865
+vn 0.6332 0.7715 -0.0624
+vn 0.7708 -0.6326 -0.0759
+vn 0.7708 0.6326 -0.0759
+vn 0.6332 -0.7715 -0.0624
+vn 0.9527 -0.2890 0.0938
+vn 0.4709 0.8810 0.0464
+vn 0.8786 -0.4696 0.0865
+vn 0.6332 0.7715 0.0624
+vn 0.7708 -0.6326 0.0759
+vn 0.7708 0.6326 0.0759
+vn 0.6332 -0.7715 0.0624
+vn 0.8786 0.4696 0.0865
+vn 0.4709 -0.8810 0.0464
+vn 0.9527 0.2890 0.0938
+vn 0.2902 -0.9565 0.0286
+vn 0.9904 0.0976 0.0975
+vn 0.0980 0.9951 0.0097
+vn 0.0980 -0.9951 0.0097
+vn 0.9904 -0.0976 0.0975
+vn 0.2902 0.9565 0.0286
+vn 0.4528 -0.8810 0.1374
+vn 0.9161 0.2890 0.2779
+vn 0.2790 -0.9565 0.0846
+vn 0.9524 0.0976 0.2889
+vn 0.0942 0.9951 0.0286
+vn 0.0942 -0.9951 0.0286
+vn 0.9524 -0.0976 0.2889
+vn 0.2790 0.9565 0.0846
+vn 0.9161 -0.2890 0.2779
+vn 0.4528 0.8810 0.1374
+vn 0.8448 -0.4696 0.2563
+vn 0.6088 0.7715 0.1847
+vn 0.7412 -0.6326 0.2248
+vn 0.7412 0.6326 0.2248
+vn 0.6088 -0.7715 0.1847
+vn 0.8448 0.4696 0.2563
+vn 0.7786 -0.4696 0.4162
+vn 0.5611 0.7715 0.2999
+vn 0.6831 -0.6326 0.3651
+vn 0.6831 0.6326 0.3651
+vn 0.5611 -0.7715 0.2999
+vn 0.7786 0.4696 0.4162
+vn 0.4173 -0.8810 0.2231
+vn 0.8443 0.2890 0.4513
+vn 0.2571 -0.9565 0.1374
+vn 0.8777 0.0976 0.4691
+vn 0.0869 0.9951 0.0464
+vn 0.0869 -0.9951 0.0464
+vn 0.8777 -0.0976 0.4691
+vn 0.2571 0.9565 0.1374
+vn 0.8443 -0.2890 0.4513
+vn 0.4173 0.8810 0.2231
+vn 0.2254 -0.9565 0.1850
+vn 0.7693 0.0976 0.6314
+vn 0.0761 0.9951 0.0625
+vn 0.0761 -0.9951 0.0625
+vn 0.7693 -0.0976 0.6314
+vn 0.2254 0.9565 0.1850
+vn 0.7400 -0.2890 0.6073
+vn 0.3658 0.8810 0.3002
+vn 0.6825 -0.4696 0.5601
+vn 0.4918 0.7715 0.4036
+vn 0.5987 -0.6326 0.4913
+vn 0.5987 0.6326 0.4913
+vn 0.4918 -0.7715 0.4036
+vn 0.6825 0.4696 0.5601
+vn 0.3658 -0.8810 0.3002
+vn 0.7400 0.2890 0.6073
+vn 0.4036 0.7715 0.4918
+vn 0.4913 -0.6326 0.5987
+vn 0.4913 0.6326 0.5987
+vn 0.4036 -0.7715 0.4918
+vn 0.5601 0.4696 0.6825
+vn 0.3002 -0.8810 0.3658
+vn 0.6073 0.2890 0.7400
+vn 0.1850 -0.9565 0.2254
+vn 0.6314 0.0976 0.7693
+vn 0.0625 0.9951 0.0761
+vn 0.0625 -0.9951 0.0761
+vn 0.6314 -0.0976 0.7693
+vn 0.1850 0.9565 0.2254
+vn 0.6073 -0.2890 0.7400
+vn 0.3002 0.8810 0.3658
+vn 0.5601 -0.4696 0.6825
+vn 0.4691 0.0976 0.8777
+vn 0.0464 0.9951 0.0869
+vn 0.0464 -0.9951 0.0869
+vn 0.4691 -0.0976 0.8777
+vn 0.1374 0.9565 0.2571
+vn 0.4513 -0.2890 0.8443
+vn 0.2230 0.8810 0.4173
+vn 0.4162 -0.4696 0.7786
+vn 0.2999 0.7715 0.5611
+vn 0.3651 -0.6326 0.6831
+vn 0.3651 0.6326 0.6831
+vn 0.2999 -0.7715 0.5611
+vn 0.4162 0.4696 0.7786
+vn 0.2230 -0.8810 0.4173
+vn 0.4513 0.2890 0.8443
+vn 0.1374 -0.9565 0.2571
+vn 0.2248 -0.6326 0.7412
+vn 0.2248 0.6326 0.7412
+vn 0.1847 -0.7715 0.6088
+vn 0.2563 0.4696 0.8448
+vn 0.1374 -0.8810 0.4528
+vn 0.2779 0.2890 0.9161
+vn 0.0846 -0.9565 0.2790
+vn 0.2889 0.0976 0.9524
+vn 0.0286 0.9951 0.0942
+vn 0.0286 -0.9951 0.0942
+vn 0.2889 -0.0976 0.9524
+vn 0.0846 0.9565 0.2790
+vn 0.2779 -0.2890 0.9161
+vn 0.1374 0.8810 0.4528
+vn 0.2563 -0.4696 0.8448
+vn 0.1847 0.7715 0.6088
+vn 0.0097 0.9951 0.0980
+vn 0.0097 -0.9951 0.0980
+vn 0.0975 -0.0976 0.9904
+vn 0.0286 0.9565 0.2902
+vn 0.0938 -0.2890 0.9527
+vn 0.0464 0.8810 0.4709
+vn 0.0865 -0.4696 0.8786
+vn 0.0624 0.7715 0.6332
+vn 0.0759 -0.6326 0.7708
+vn 0.0759 0.6326 0.7708
+vn 0.0624 -0.7715 0.6332
+vn 0.0865 0.4696 0.8786
+vn 0.0464 -0.8810 0.4709
+vn 0.0938 0.2890 0.9527
+vn 0.0286 -0.9565 0.2902
+vn 0.0975 0.0976 0.9904
+vn -0.0759 0.6326 0.7708
+vn -0.0624 -0.7715 0.6332
+vn -0.0865 0.4696 0.8786
+vn -0.0464 -0.8810 0.4709
+vn -0.0938 0.2890 0.9527
+vn -0.0286 -0.9565 0.2902
+vn -0.0976 0.0976 0.9904
+vn -0.0097 0.9951 0.0980
+vn -0.0097 -0.9951 0.0980
+vn -0.0976 -0.0976 0.9904
+vn -0.0286 0.9565 0.2902
+vn -0.0938 -0.2890 0.9527
+vn -0.0464 0.8810 0.4709
+vn -0.0865 -0.4696 0.8786
+vn -0.0624 0.7715 0.6332
+vn -0.0759 -0.6326 0.7708
+vn -0.2889 -0.0976 0.9524
+vn -0.0846 0.9565 0.2790
+vn -0.2779 -0.2890 0.9161
+vn -0.1374 0.8810 0.4528
+vn -0.2563 -0.4696 0.8448
+vn -0.1847 0.7715 0.6088
+vn -0.2248 -0.6326 0.7412
+vn -0.2248 0.6326 0.7412
+vn -0.1847 -0.7715 0.6088
+vn -0.2563 0.4696 0.8448
+vn -0.1374 -0.8810 0.4528
+vn -0.2779 0.2890 0.9161
+vn -0.0846 -0.9565 0.2790
+vn -0.2889 0.0976 0.9524
+vn -0.0286 0.9951 0.0942
+vn -0.0286 -0.9951 0.0942
+vn -0.2999 -0.7715 0.5611
+vn -0.4162 0.4696 0.7786
+vn -0.2230 -0.8810 0.4173
+vn -0.4513 0.2890 0.8443
+vn -0.1374 -0.9565 0.2571
+vn -0.4691 0.0976 0.8777
+vn -0.0464 0.9951 0.0869
+vn -0.0464 -0.9951 0.0869
+vn -0.4691 -0.0976 0.8777
+vn -0.1374 0.9565 0.2571
+vn -0.4513 -0.2890 0.8443
+vn -0.2230 0.8810 0.4173
+vn -0.4162 -0.4696 0.7786
+vn -0.2999 0.7715 0.5611
+vn -0.3651 -0.6326 0.6831
+vn -0.3651 0.6326 0.6831
+vn -0.6073 -0.2890 0.7400
+vn -0.3002 0.8810 0.3658
+vn -0.5601 -0.4696 0.6825
+vn -0.4036 0.7715 0.4918
+vn -0.4913 -0.6326 0.5987
+vn -0.4913 0.6326 0.5987
+vn -0.4036 -0.7715 0.4918
+vn -0.5601 0.4696 0.6825
+vn -0.3002 -0.8810 0.3658
+vn -0.6073 0.2890 0.7400
+vn -0.1850 -0.9565 0.2254
+vn -0.6314 0.0976 0.7693
+vn -0.0625 0.9951 0.0761
+vn -0.0625 -0.9951 0.0761
+vn -0.6314 -0.0976 0.7693
+vn -0.1850 0.9565 0.2254
+vn -0.3658 -0.8810 0.3002
+vn -0.7400 0.2890 0.6073
+vn -0.2254 -0.9565 0.1850
+vn -0.7693 0.0976 0.6314
+vn -0.0761 0.9951 0.0625
+vn -0.0761 -0.9951 0.0625
+vn -0.7693 -0.0976 0.6314
+vn -0.2254 0.9565 0.1850
+vn -0.7400 -0.2890 0.6073
+vn -0.3658 0.8810 0.3002
+vn -0.6825 -0.4696 0.5601
+vn -0.4918 0.7715 0.4036
+vn -0.5987 -0.6326 0.4913
+vn -0.5987 0.6326 0.4913
+vn -0.4918 -0.7715 0.4036
+vn -0.6825 0.4696 0.5601
+vn -0.4173 0.8810 0.2231
+vn -0.7786 -0.4696 0.4162
+vn -0.5611 0.7715 0.2999
+vn -0.6831 -0.6326 0.3651
+vn -0.6831 0.6326 0.3651
+vn -0.5611 -0.7715 0.2999
+vn -0.7786 0.4696 0.4162
+vn -0.4173 -0.8810 0.2231
+vn -0.8443 0.2890 0.4513
+vn -0.2571 -0.9565 0.1374
+vn -0.8777 0.0976 0.4691
+vn -0.0869 0.9951 0.0464
+vn -0.0869 -0.9951 0.0464
+vn -0.8777 -0.0976 0.4691
+vn -0.2571 0.9565 0.1374
+vn -0.8443 -0.2890 0.4513
+vn -0.9161 0.2890 0.2779
+vn -0.2790 -0.9565 0.0846
+vn -0.9524 0.0976 0.2889
+vn -0.0942 0.9951 0.0286
+vn -0.0942 -0.9951 0.0286
+vn -0.9524 -0.0976 0.2889
+vn -0.2790 0.9565 0.0846
+vn -0.9161 -0.2890 0.2779
+vn -0.4528 0.8810 0.1374
+vn -0.8448 -0.4696 0.2563
+vn -0.6088 0.7715 0.1847
+vn -0.7412 -0.6326 0.2248
+vn -0.7412 0.6326 0.2248
+vn -0.6088 -0.7715 0.1847
+vn -0.8448 0.4696 0.2563
+vn -0.4528 -0.8810 0.1374
+vn -0.8786 -0.4696 0.0865
+vn -0.6332 0.7715 0.0624
+vn -0.7708 -0.6326 0.0759
+vn -0.7708 0.6326 0.0759
+vn -0.6332 -0.7715 0.0624
+vn -0.8786 0.4696 0.0865
+vn -0.4709 -0.8810 0.0464
+vn -0.9527 0.2890 0.0938
+vn -0.2902 -0.9565 0.0286
+vn -0.9904 0.0976 0.0975
+vn -0.0980 0.9951 0.0097
+vn -0.0980 -0.9951 0.0097
+vn -0.9904 -0.0976 0.0975
+vn -0.2902 0.9565 0.0286
+vn -0.9527 -0.2890 0.0938
+vn -0.4709 0.8810 0.0464
+vn -0.2902 -0.9565 -0.0286
+vn -0.9904 0.0976 -0.0976
+vn -0.0980 0.9951 -0.0097
+vn -0.0980 -0.9951 -0.0097
+vn -0.9904 -0.0976 -0.0976
+vn -0.2902 0.9565 -0.0286
+vn -0.9527 -0.2890 -0.0938
+vn -0.4709 0.8810 -0.0464
+vn -0.8786 -0.4696 -0.0865
+vn -0.6332 0.7715 -0.0624
+vn -0.7708 -0.6326 -0.0759
+vn -0.7708 0.6326 -0.0759
+vn -0.6332 -0.7715 -0.0624
+vn -0.8786 0.4696 -0.0865
+vn -0.4709 -0.8810 -0.0464
+vn -0.9527 0.2890 -0.0938
+vn -0.6088 0.7715 -0.1847
+vn -0.7412 -0.6326 -0.2248
+vn -0.7412 0.6326 -0.2248
+vn -0.6088 -0.7715 -0.1847
+vn -0.8448 0.4696 -0.2563
+vn -0.4528 -0.8810 -0.1374
+vn -0.9161 0.2890 -0.2779
+vn -0.2790 -0.9565 -0.0846
+vn -0.9524 0.0976 -0.2889
+vn -0.0942 0.9951 -0.0286
+vn -0.0942 -0.9951 -0.0286
+vn -0.9524 -0.0976 -0.2889
+vn -0.2790 0.9565 -0.0846
+vn -0.9161 -0.2890 -0.2779
+vn -0.4528 0.8810 -0.1374
+vn -0.8448 -0.4696 -0.2563
+vn -0.8777 0.0976 -0.4691
+vn -0.0869 0.9951 -0.0464
+vn -0.0869 -0.9951 -0.0464
+vn -0.8777 -0.0976 -0.4691
+vn -0.2571 0.9565 -0.1374
+vn -0.8443 -0.2890 -0.4513
+vn -0.4173 0.8810 -0.2231
+vn -0.7786 -0.4696 -0.4162
+vn -0.5611 0.7715 -0.2999
+vn -0.6831 -0.6326 -0.3651
+vn -0.6831 0.6326 -0.3651
+vn -0.5611 -0.7715 -0.2999
+vn -0.7786 0.4696 -0.4162
+vn -0.4173 -0.8810 -0.2231
+vn -0.8443 0.2890 -0.4513
+vn -0.2571 -0.9565 -0.1374
+vn -0.5987 -0.6326 -0.4913
+vn -0.5987 0.6326 -0.4913
+vn -0.4918 -0.7715 -0.4036
+vn -0.6825 0.4696 -0.5601
+vn -0.3658 -0.8810 -0.3002
+vn -0.7400 0.2890 -0.6073
+vn -0.2254 -0.9565 -0.1850
+vn -0.7693 0.0976 -0.6314
+vn -0.0761 0.9951 -0.0625
+vn -0.0761 -0.9951 -0.0625
+vn -0.7693 -0.0976 -0.6314
+vn -0.2254 0.9565 -0.1850
+vn -0.7400 -0.2890 -0.6073
+vn -0.3658 0.8810 -0.3002
+vn -0.6825 -0.4696 -0.5601
+vn -0.4918 0.7715 -0.4036
+vn -0.0625 -0.9951 -0.0761
+vn -0.6314 -0.0976 -0.7693
+vn -0.1850 0.9565 -0.2254
+vn -0.6073 -0.2890 -0.7400
+vn -0.3002 0.8810 -0.3658
+vn -0.5601 -0.4696 -0.6825
+vn -0.4036 0.7715 -0.4918
+vn -0.4913 -0.6326 -0.5987
+vn -0.4913 0.6326 -0.5987
+vn -0.4036 -0.7715 -0.4918
+vn -0.5601 0.4696 -0.6825
+vn -0.3002 -0.8810 -0.3658
+vn -0.6073 0.2890 -0.7400
+vn -0.1850 -0.9565 -0.2254
+vn -0.6314 0.0976 -0.7693
+vn -0.0625 0.9951 -0.0761
+vn -0.2999 -0.7715 -0.5611
+vn -0.4162 0.4696 -0.7786
+vn -0.2230 -0.8810 -0.4173
+vn -0.4513 0.2890 -0.8443
+vn -0.1374 -0.9565 -0.2571
+vn -0.4691 0.0976 -0.8777
+vn -0.0464 0.9951 -0.0869
+vn -0.0464 -0.9951 -0.0869
+vn -0.4691 -0.0976 -0.8777
+vn -0.1374 0.9565 -0.2571
+vn -0.4513 -0.2890 -0.8443
+vn -0.2230 0.8810 -0.4173
+vn -0.4162 -0.4696 -0.7786
+vn -0.2999 0.7715 -0.5611
+vn -0.3651 -0.6326 -0.6831
+vn -0.3651 0.6326 -0.6831
+vn -0.0846 0.9565 -0.2790
+vn -0.2779 -0.2890 -0.9161
+vn -0.1374 0.8810 -0.4528
+vn -0.2563 -0.4696 -0.8448
+vn -0.1847 0.7715 -0.6088
+vn -0.2248 -0.6326 -0.7412
+vn -0.2248 0.6326 -0.7412
+vn -0.1847 -0.7715 -0.6088
+vn -0.2563 0.4696 -0.8448
+vn -0.1374 -0.8810 -0.4528
+vn -0.2779 0.2890 -0.9161
+vn -0.0846 -0.9565 -0.2790
+vn -0.2889 0.0976 -0.9524
+vn -0.0286 0.9951 -0.0942
+vn -0.0286 -0.9951 -0.0942
+vn -0.2889 -0.0976 -0.9524
+vn -0.0865 0.4696 -0.8786
+vn -0.0464 -0.8810 -0.4709
+vn -0.0938 0.2890 -0.9527
+vn -0.0286 -0.9565 -0.2902
+vn -0.0976 0.0976 -0.9904
+vn -0.0097 0.9951 -0.0980
+vn -0.0097 -0.9951 -0.0980
+vn -0.0976 -0.0976 -0.9904
+vn -0.0286 0.9565 -0.2902
+vn -0.0938 -0.2890 -0.9527
+vn -0.0464 0.8810 -0.4709
+vn -0.0865 -0.4696 -0.8786
+vn -0.0624 0.7715 -0.6332
+vn -0.0759 -0.6326 -0.7708
+vn -0.0759 0.6326 -0.7708
+vn -0.0624 -0.7715 -0.6332
+usemtl Material.001
+s off
+f 10/1/1 480/2/1 22/3/1 23/4/1
+f 6/5/2 5/6/2 15/7/2 16/8/2
+f 481/9/3 10/1/3 23/4/3 24/10/3
+f 7/11/4 6/5/4 16/8/4 17/12/4
+f 482/13/5 481/9/5 24/10/5 25/14/5
+f 8/15/6 7/11/6 17/12/6 18/16/6
+f 1/17/7 297/18/7 11/19/7
+f 206/20/8 482/13/8 25/14/8
+f 9/21/9 8/15/9 18/16/9 19/22/9
+f 2/23/10 1/17/10 11/19/10 12/24/10
+f 478/25/11 9/21/11 19/22/11 20/26/11
+f 3/27/12 2/23/12 12/24/12 13/28/12
+f 479/29/13 478/25/13 20/26/13 21/30/13
+f 4/31/14 3/27/14 13/28/14 14/32/14
+f 480/2/15 479/29/15 21/30/15 22/3/15
+f 5/6/16 4/31/16 14/32/16 15/7/16
+f 22/3/17 21/30/17 36/33/17 37/34/17
+f 15/7/18 14/32/18 29/35/18 30/36/18
+f 23/4/19 22/3/19 37/34/19 38/37/19
+f 16/8/20 15/7/20 30/36/20 31/38/20
+f 24/10/21 23/4/21 38/37/21 39/39/21
+f 17/12/22 16/8/22 31/38/22 32/40/22
+f 25/14/23 24/10/23 39/39/23 40/41/23
+f 18/16/24 17/12/24 32/40/24 33/42/24
+f 11/19/25 297/43/25 26/44/25
+f 206/45/26 25/14/26 40/41/26
+f 19/22/27 18/16/27 33/42/27 34/46/27
+f 12/24/28 11/19/28 26/44/28 27/47/28
+f 20/26/29 19/22/29 34/46/29 35/48/29
+f 13/28/30 12/24/30 27/47/30 28/49/30
+f 21/30/31 20/26/31 35/48/31 36/33/31
+f 14/32/32 13/28/32 28/49/32 29/35/32
+f 26/44/33 297/50/33 41/51/33
+f 206/52/34 40/41/34 55/53/34
+f 34/46/35 33/42/35 48/54/35 49/55/35
+f 27/47/36 26/44/36 41/51/36 42/56/36
+f 35/48/37 34/46/37 49/55/37 50/57/37
+f 28/49/38 27/47/38 42/56/38 43/58/38
+f 36/33/39 35/48/39 50/57/39 51/59/39
+f 29/35/40 28/49/40 43/58/40 44/60/40
+f 37/34/41 36/33/41 51/59/41 52/61/41
+f 30/36/42 29/35/42 44/60/42 45/62/42
+f 38/37/43 37/34/43 52/61/43 53/63/43
+f 31/38/44 30/36/44 45/62/44 46/64/44
+f 39/39/45 38/37/45 53/63/45 54/65/45
+f 32/40/46 31/38/46 46/64/46 47/66/46
+f 40/41/47 39/39/47 54/65/47 55/53/47
+f 33/42/48 32/40/48 47/66/48 48/54/48
+f 45/62/49 44/60/49 59/67/49 60/68/49
+f 53/63/50 52/61/50 67/69/50 68/70/50
+f 46/64/51 45/62/51 60/68/51 61/71/51
+f 54/65/52 53/63/52 68/70/52 69/72/52
+f 47/66/53 46/64/53 61/71/53 62/73/53
+f 55/53/54 54/65/54 69/72/54 70/74/54
+f 48/54/55 47/66/55 62/73/55 63/75/55
+f 41/51/56 297/76/56 56/77/56
+f 206/78/57 55/53/57 70/74/57
+f 49/55/58 48/54/58 63/75/58 64/79/58
+f 42/56/59 41/51/59 56/77/59 57/80/59
+f 50/57/60 49/55/60 64/79/60 65/81/60
+f 43/58/61 42/56/61 57/80/61 58/82/61
+f 51/59/62 50/57/62 65/81/62 66/83/62
+f 44/60/63 43/58/63 58/82/63 59/67/63
+f 52/61/64 51/59/64 66/83/64 67/69/64
+f 64/79/65 63/75/65 78/84/65 79/85/65
+f 57/80/66 56/77/66 71/86/66 72/87/66
+f 65/81/67 64/79/67 79/85/67 80/88/67
+f 58/82/68 57/80/68 72/87/68 73/89/68
+f 66/83/69 65/81/69 80/88/69 81/90/69
+f 59/67/70 58/82/70 73/89/70 74/91/70
+f 67/69/71 66/83/71 81/90/71 82/92/71
+f 60/68/72 59/67/72 74/91/72 75/93/72
+f 68/70/73 67/69/73 82/92/73 83/94/73
+f 61/71/74 60/68/74 75/93/74 76/95/74
+f 69/72/75 68/70/75 83/94/75 84/96/75
+f 62/73/76 61/71/76 76/95/76 77/97/76
+f 70/74/77 69/72/77 84/96/77 85/98/77
+f 63/75/78 62/73/78 77/97/78 78/84/78
+f 56/77/79 297/99/79 71/86/79
+f 206/100/80 70/74/80 85/98/80
+f 83/94/81 82/92/81 97/101/81 98/102/81
+f 76/95/82 75/93/82 90/103/82 91/104/82
+f 84/96/83 83/94/83 98/102/83 99/105/83
+f 77/97/84 76/95/84 91/104/84 92/106/84
+f 85/98/85 84/96/85 99/105/85 100/107/85
+f 78/84/86 77/97/86 92/106/86 93/108/86
+f 71/86/87 297/109/87 86/110/87
+f 206/111/88 85/98/88 100/107/88
+f 79/85/89 78/84/89 93/108/89 94/112/89
+f 72/87/90 71/86/90 86/110/90 87/113/90
+f 80/88/91 79/85/91 94/112/91 95/114/91
+f 73/89/92 72/87/92 87/113/92 88/115/92
+f 81/90/93 80/88/93 95/114/93 96/116/93
+f 74/91/94 73/89/94 88/115/94 89/117/94
+f 82/92/95 81/90/95 96/116/95 97/101/95
+f 75/93/96 74/91/96 89/117/96 90/103/96
+f 87/113/97 86/110/97 101/118/97 102/119/97
+f 95/114/98 94/112/98 109/120/98 110/121/98
+f 88/115/99 87/113/99 102/119/99 103/122/99
+f 96/116/100 95/114/100 110/121/100 111/123/100
+f 89/117/101 88/115/101 103/122/101 104/124/101
+f 97/101/102 96/116/102 111/123/102 112/125/102
+f 90/103/103 89/117/103 104/124/103 105/126/103
+f 98/102/104 97/101/104 112/125/104 113/127/104
+f 91/104/105 90/103/105 105/126/105 106/128/105
+f 99/105/106 98/102/106 113/127/106 114/129/106
+f 92/106/107 91/104/107 106/128/107 107/130/107
+f 100/107/108 99/105/108 114/129/108 115/131/108
+f 93/108/109 92/106/109 107/130/109 108/132/109
+f 86/110/110 297/133/110 101/118/110
+f 206/134/111 100/107/111 115/131/111
+f 94/112/112 93/108/112 108/132/112 109/120/112
+f 106/128/113 105/126/113 120/135/113 121/136/113
+f 114/129/114 113/127/114 128/137/114 129/138/114
+f 107/130/115 106/128/115 121/136/115 122/139/115
+f 115/131/116 114/129/116 129/138/116 130/140/116
+f 108/132/117 107/130/117 122/139/117 123/141/117
+f 101/118/118 297/142/118 116/143/118
+f 206/144/119 115/131/119 130/140/119
+f 109/120/120 108/132/120 123/141/120 124/145/120
+f 102/119/121 101/118/121 116/143/121 117/146/121
+f 110/121/122 109/120/122 124/145/122 125/147/122
+f 103/122/123 102/119/123 117/146/123 118/148/123
+f 111/123/124 110/121/124 125/147/124 126/149/124
+f 104/124/125 103/122/125 118/148/125 119/150/125
+f 112/125/126 111/123/126 126/149/126 127/151/126
+f 105/126/127 104/124/127 119/150/127 120/135/127
+f 113/127/128 112/125/128 127/151/128 128/137/128
+f 125/147/129 124/145/129 139/152/129 140/153/129
+f 118/148/130 117/146/130 132/154/130 133/155/130
+f 126/149/131 125/147/131 140/153/131 141/156/131
+f 119/150/132 118/148/132 133/155/132 134/157/132
+f 127/151/133 126/149/133 141/156/133 142/158/133
+f 120/135/134 119/150/134 134/157/134 135/159/134
+f 128/137/135 127/151/135 142/158/135 143/160/135
+f 121/136/136 120/135/136 135/159/136 136/161/136
+f 129/138/137 128/137/137 143/160/137 144/162/137
+f 122/139/138 121/136/138 136/161/138 137/163/138
+f 130/140/139 129/138/139 144/162/139 145/164/139
+f 123/141/140 122/139/140 137/163/140 138/165/140
+f 116/143/141 297/166/141 131/167/141
+f 206/168/142 130/140/142 145/164/142
+f 124/145/143 123/141/143 138/165/143 139/152/143
+f 117/146/144 116/143/144 131/167/144 132/154/144
+f 144/162/145 143/160/145 158/169/145 159/170/145
+f 137/163/146 136/161/146 151/171/146 152/172/146
+f 145/164/147 144/162/147 159/170/147 160/173/147
+f 138/165/148 137/163/148 152/172/148 153/174/148
+f 131/167/149 297/175/149 146/176/149
+f 206/177/150 145/164/150 160/173/150
+f 139/152/151 138/165/151 153/174/151 154/178/151
+f 132/154/152 131/167/152 146/176/152 147/179/152
+f 140/153/153 139/152/153 154/178/153 155/180/153
+f 133/155/154 132/154/154 147/179/154 148/181/154
+f 141/156/155 140/153/155 155/180/155 156/182/155
+f 134/157/156 133/155/156 148/181/156 149/183/156
+f 142/158/157 141/156/157 156/182/157 157/184/157
+f 135/159/158 134/157/158 149/183/158 150/185/158
+f 143/160/159 142/158/159 157/184/159 158/169/159
+f 136/161/160 135/159/160 150/185/160 151/171/160
+f 156/182/161 155/180/161 170/186/161 171/187/161
+f 149/183/162 148/181/162 163/188/162 164/189/162
+f 157/184/163 156/182/163 171/187/163 172/190/163
+f 150/185/164 149/183/164 164/189/164 165/191/164
+f 158/169/165 157/184/165 172/190/165 173/192/165
+f 151/171/166 150/185/166 165/191/166 166/193/166
+f 159/170/167 158/169/167 173/192/167 174/194/167
+f 152/172/168 151/171/168 166/193/168 167/195/168
+f 160/173/169 159/170/169 174/194/169 175/196/169
+f 153/174/170 152/172/170 167/195/170 168/197/170
+f 146/176/171 297/198/171 161/199/171
+f 206/200/172 160/173/172 175/196/172
+f 154/178/173 153/174/173 168/197/173 169/201/173
+f 147/179/174 146/176/174 161/199/174 162/202/174
+f 155/180/175 154/178/175 169/201/175 170/186/175
+f 148/181/176 147/179/176 162/202/176 163/188/176
+f 175/196/177 174/194/177 189/203/177 190/204/177
+f 168/197/178 167/195/178 182/205/178 183/206/178
+f 161/199/179 297/207/179 176/208/179
+f 206/209/180 175/196/180 190/204/180
+f 169/201/181 168/197/181 183/206/181 184/210/181
+f 162/202/182 161/199/182 176/208/182 177/211/182
+f 170/186/183 169/201/183 184/210/183 185/212/183
+f 163/188/184 162/202/184 177/211/184 178/213/184
+f 171/187/185 170/186/185 185/212/185 186/214/185
+f 164/189/186 163/188/186 178/213/186 179/215/186
+f 172/190/187 171/187/187 186/214/187 187/216/187
+f 165/191/188 164/189/188 179/215/188 180/217/188
+f 173/192/189 172/190/189 187/216/189 188/218/189
+f 166/193/190 165/191/190 180/217/190 181/219/190
+f 174/194/191 173/192/191 188/218/191 189/203/191
+f 167/195/192 166/193/192 181/219/192 182/205/192
+f 179/215/193 178/213/193 193/220/193 194/221/193
+f 187/216/194 186/214/194 201/222/194 202/223/194
+f 180/217/195 179/215/195 194/221/195 195/224/195
+f 188/218/196 187/216/196 202/223/196 203/225/196
+f 181/219/197 180/217/197 195/224/197 196/226/197
+f 189/203/198 188/218/198 203/225/198 204/227/198
+f 182/205/199 181/219/199 196/226/199 197/228/199
+f 190/204/200 189/203/200 204/227/200 205/229/200
+f 183/206/201 182/205/201 197/228/201 198/230/201
+f 176/208/202 297/231/202 191/232/202
+f 206/233/203 190/204/203 205/229/203
+f 184/210/204 183/206/204 198/230/204 199/234/204
+f 177/211/205 176/208/205 191/232/205 192/235/205
+f 185/212/206 184/210/206 199/234/206 200/236/206
+f 178/213/207 177/211/207 192/235/207 193/220/207
+f 186/214/208 185/212/208 200/236/208 201/222/208
+f 198/230/209 197/228/209 213/237/209 214/238/209
+f 191/232/210 297/239/210 207/240/210
+f 206/241/211 205/229/211 221/242/211
+f 199/234/212 198/230/212 214/238/212 215/243/212
+f 192/235/213 191/232/213 207/240/213 208/244/213
+f 200/236/214 199/234/214 215/243/214 216/245/214
+f 193/220/215 192/235/215 208/244/215 209/246/215
+f 201/222/216 200/236/216 216/245/216 217/247/216
+f 194/221/217 193/220/217 209/246/217 210/248/217
+f 202/223/218 201/222/218 217/247/218 218/249/218
+f 195/224/219 194/221/219 210/248/219 211/250/219
+f 203/225/220 202/223/220 218/249/220 219/251/220
+f 196/226/221 195/224/221 211/250/221 212/252/221
+f 204/227/222 203/225/222 219/251/222 220/253/222
+f 197/228/223 196/226/223 212/252/223 213/237/223
+f 205/229/224 204/227/224 220/253/224 221/242/224
+f 218/249/225 217/247/225 232/254/225 233/255/225
+f 211/250/226 210/248/226 225/256/226 226/257/226
+f 219/251/227 218/249/227 233/255/227 234/258/227
+f 212/252/228 211/250/228 226/257/228 227/259/228
+f 220/253/229 219/251/229 234/258/229 235/260/229
+f 213/237/230 212/252/230 227/259/230 228/261/230
+f 221/242/231 220/253/231 235/260/231 236/262/231
+f 214/238/232 213/237/232 228/261/232 229/263/232
+f 207/240/233 297/264/233 222/265/233
+f 206/266/234 221/242/234 236/262/234
+f 215/243/235 214/238/235 229/263/235 230/267/235
+f 208/244/236 207/240/236 222/265/236 223/268/236
+f 216/245/237 215/243/237 230/267/237 231/269/237
+f 209/246/238 208/244/238 223/268/238 224/270/238
+f 217/247/239 216/245/239 231/269/239 232/254/239
+f 210/248/240 209/246/240 224/270/240 225/256/240
+f 222/265/241 297/271/241 237/272/241
+f 206/273/242 236/262/242 251/274/242
+f 230/267/243 229/263/243 244/275/243 245/276/243
+f 223/268/244 222/265/244 237/272/244 238/277/244
+f 231/269/245 230/267/245 245/276/245 246/278/245
+f 224/270/246 223/268/246 238/277/246 239/279/246
+f 232/254/247 231/269/247 246/278/247 247/280/247
+f 225/256/248 224/270/248 239/279/248 240/281/248
+f 233/255/249 232/254/249 247/280/249 248/282/249
+f 226/257/250 225/256/250 240/281/250 241/283/250
+f 234/258/251 233/255/251 248/282/251 249/284/251
+f 227/259/252 226/257/252 241/283/252 242/285/252
+f 235/260/253 234/258/253 249/284/253 250/286/253
+f 228/261/254 227/259/254 242/285/254 243/287/254
+f 236/262/255 235/260/255 250/286/255 251/274/255
+f 229/263/256 228/261/256 243/287/256 244/275/256
+f 241/283/257 240/281/257 255/288/257 256/289/257
+f 249/284/258 248/282/258 263/290/258 264/291/258
+f 242/285/259 241/283/259 256/289/259 257/292/259
+f 250/286/260 249/284/260 264/291/260 265/293/260
+f 243/287/261 242/285/261 257/292/261 258/294/261
+f 251/274/262 250/286/262 265/293/262 266/295/262
+f 244/275/263 243/287/263 258/294/263 259/296/263
+f 237/272/264 297/297/264 252/298/264
+f 206/299/265 251/274/265 266/295/265
+f 245/276/266 244/275/266 259/296/266 260/300/266
+f 238/277/267 237/272/267 252/298/267 253/301/267
+f 246/278/268 245/276/268 260/300/268 261/302/268
+f 239/279/269 238/277/269 253/301/269 254/303/269
+f 247/280/270 246/278/270 261/302/270 262/304/270
+f 240/281/271 239/279/271 254/303/271 255/288/271
+f 248/282/272 247/280/272 262/304/272 263/290/272
+f 260/300/273 259/296/273 274/305/273 275/306/273
+f 253/301/274 252/298/274 267/307/274 268/308/274
+f 261/302/275 260/300/275 275/306/275 276/309/275
+f 254/303/276 253/301/276 268/308/276 269/310/276
+f 262/304/277 261/302/277 276/309/277 277/311/277
+f 255/288/278 254/303/278 269/310/278 270/312/278
+f 263/290/279 262/304/279 277/311/279 278/313/279
+f 256/289/280 255/288/280 270/312/280 271/314/280
+f 264/291/281 263/290/281 278/313/281 279/315/281
+f 257/292/282 256/289/282 271/314/282 272/316/282
+f 265/293/283 264/291/283 279/315/283 280/317/283
+f 258/294/284 257/292/284 272/316/284 273/318/284
+f 266/295/285 265/293/285 280/317/285 281/319/285
+f 259/296/286 258/294/286 273/318/286 274/305/286
+f 252/298/287 297/320/287 267/307/287
+f 206/321/288 266/295/288 281/319/288
+f 279/315/289 278/313/289 293/322/289 294/323/289
+f 272/316/290 271/314/290 286/324/290 287/325/290
+f 280/317/291 279/315/291 294/323/291 295/326/291
+f 273/318/292 272/316/292 287/325/292 288/327/292
+f 281/319/293 280/317/293 295/326/293 296/328/293
+f 274/305/294 273/318/294 288/327/294 289/329/294
+f 267/307/295 297/330/295 282/331/295
+f 206/332/296 281/319/296 296/328/296
+f 275/306/297 274/305/297 289/329/297 290/333/297
+f 268/308/298 267/307/298 282/331/298 283/334/298
+f 276/309/299 275/306/299 290/333/299 291/335/299
+f 269/310/300 268/308/300 283/334/300 284/336/300
+f 277/311/301 276/309/301 291/335/301 292/337/301
+f 270/312/302 269/310/302 284/336/302 285/338/302
+f 278/313/303 277/311/303 292/337/303 293/322/303
+f 271/314/304 270/312/304 285/338/304 286/324/304
+f 291/335/305 290/333/305 306/339/305 307/340/305
+f 284/336/306 283/334/306 299/341/306 300/342/306
+f 292/337/307 291/335/307 307/340/307 308/343/307
+f 285/338/308 284/336/308 300/342/308 301/344/308
+f 293/322/309 292/337/309 308/343/309 309/345/309
+f 286/324/310 285/338/310 301/344/310 302/346/310
+f 294/323/311 293/322/311 309/345/311 310/347/311
+f 287/325/312 286/324/312 302/346/312 303/348/312
+f 295/326/313 294/323/313 310/347/313 311/349/313
+f 288/327/314 287/325/314 303/348/314 304/350/314
+f 296/328/315 295/326/315 311/349/315 312/351/315
+f 289/329/316 288/327/316 304/350/316 305/352/316
+f 282/331/317 297/353/317 298/354/317
+f 206/355/318 296/328/318 312/351/318
+f 290/333/319 289/329/319 305/352/319 306/339/319
+f 283/334/320 282/331/320 298/354/320 299/341/320
+f 311/349/321 310/347/321 325/356/321 326/357/321
+f 304/350/322 303/348/322 318/358/322 319/359/322
+f 312/351/323 311/349/323 326/357/323 327/360/323
+f 305/352/324 304/350/324 319/359/324 320/361/324
+f 298/354/325 297/362/325 313/363/325
+f 206/364/326 312/351/326 327/360/326
+f 306/339/327 305/352/327 320/361/327 321/365/327
+f 299/341/328 298/354/328 313/363/328 314/366/328
+f 307/340/329 306/339/329 321/365/329 322/367/329
+f 300/342/330 299/341/330 314/366/330 315/368/330
+f 308/343/331 307/340/331 322/367/331 323/369/331
+f 301/344/332 300/342/332 315/368/332 316/370/332
+f 309/345/333 308/343/333 323/369/333 324/371/333
+f 302/346/334 301/344/334 316/370/334 317/372/334
+f 310/347/335 309/345/335 324/371/335 325/356/335
+f 303/348/336 302/346/336 317/372/336 318/358/336
+f 315/368/337 314/366/337 329/373/337 330/374/337
+f 323/369/338 322/367/338 337/375/338 338/376/338
+f 316/370/339 315/368/339 330/374/339 331/377/339
+f 324/371/340 323/369/340 338/376/340 339/378/340
+f 317/372/341 316/370/341 331/377/341 332/379/341
+f 325/356/342 324/371/342 339/378/342 340/380/342
+f 318/358/343 317/372/343 332/379/343 333/381/343
+f 326/357/344 325/356/344 340/380/344 341/382/344
+f 319/359/345 318/358/345 333/381/345 334/383/345
+f 327/360/346 326/357/346 341/382/346 342/384/346
+f 320/361/347 319/359/347 334/383/347 335/385/347
+f 313/363/348 297/386/348 328/387/348
+f 206/388/349 327/360/349 342/384/349
+f 321/365/350 320/361/350 335/385/350 336/389/350
+f 314/366/351 313/363/351 328/387/351 329/373/351
+f 322/367/352 321/365/352 336/389/352 337/375/352
+f 334/383/353 333/381/353 348/390/353 349/391/353
+f 342/384/354 341/382/354 356/392/354 357/393/354
+f 335/385/355 334/383/355 349/391/355 350/394/355
+f 328/387/356 297/395/356 343/396/356
+f 206/397/357 342/384/357 357/393/357
+f 336/389/358 335/385/358 350/394/358 351/398/358
+f 329/373/359 328/387/359 343/396/359 344/399/359
+f 337/375/360 336/389/360 351/398/360 352/400/360
+f 330/374/361 329/373/361 344/399/361 345/401/361
+f 338/376/362 337/375/362 352/400/362 353/402/362
+f 331/377/363 330/374/363 345/401/363 346/403/363
+f 339/378/364 338/376/364 353/402/364 354/404/364
+f 332/379/365 331/377/365 346/403/365 347/405/365
+f 340/380/366 339/378/366 354/404/366 355/406/366
+f 333/381/367 332/379/367 347/405/367 348/390/367
+f 341/382/368 340/380/368 355/406/368 356/392/368
+f 353/402/369 352/400/369 367/407/369 368/408/369
+f 346/403/370 345/401/370 360/409/370 361/410/370
+f 354/404/371 353/402/371 368/408/371 369/411/371
+f 347/405/372 346/403/372 361/410/372 362/412/372
+f 355/406/373 354/404/373 369/411/373 370/413/373
+f 348/390/374 347/405/374 362/412/374 363/414/374
+f 356/392/375 355/406/375 370/413/375 371/415/375
+f 349/391/376 348/390/376 363/414/376 364/416/376
+f 357/393/377 356/392/377 371/415/377 372/417/377
+f 350/394/378 349/391/378 364/416/378 365/418/378
+f 343/396/379 297/419/379 358/420/379
+f 206/421/380 357/393/380 372/417/380
+f 351/398/381 350/394/381 365/418/381 366/422/381
+f 344/399/382 343/396/382 358/420/382 359/423/382
+f 352/400/383 351/398/383 366/422/383 367/407/383
+f 345/401/384 344/399/384 359/423/384 360/409/384
+f 372/424/385 371/425/385 386/426/385 387/427/385
+f 365/428/386 364/429/386 379/430/386 380/431/386
+f 358/432/387 297/433/387 373/434/387
+f 206/435/388 372/424/388 387/427/388
+f 366/436/389 365/428/389 380/431/389 381/437/389
+f 359/438/390 358/432/390 373/434/390 374/439/390
+f 367/440/391 366/436/391 381/437/391 382/441/391
+f 360/442/392 359/438/392 374/439/392 375/443/392
+f 368/444/393 367/440/393 382/441/393 383/445/393
+f 361/446/394 360/442/394 375/443/394 376/447/394
+f 369/448/395 368/444/395 383/445/395 384/449/395
+f 362/450/396 361/446/396 376/447/396 377/451/396
+f 370/452/397 369/448/397 384/449/397 385/453/397
+f 363/454/398 362/450/398 377/451/398 378/455/398
+f 371/425/399 370/452/399 385/453/399 386/426/399
+f 364/429/400 363/454/400 378/455/400 379/430/400
+f 376/447/401 375/443/401 390/456/401 391/457/401
+f 384/449/402 383/445/402 398/458/402 399/459/402
+f 377/451/403 376/447/403 391/457/403 392/460/403
+f 385/453/404 384/449/404 399/459/404 400/461/404
+f 378/455/405 377/451/405 392/460/405 393/462/405
+f 386/426/406 385/453/406 400/461/406 401/463/406
+f 379/430/407 378/455/407 393/462/407 394/464/407
+f 387/427/408 386/426/408 401/463/408 402/465/408
+f 380/431/409 379/430/409 394/464/409 395/466/409
+f 373/434/410 297/467/410 388/468/410
+f 206/469/411 387/427/411 402/465/411
+f 381/437/412 380/431/412 395/466/412 396/470/412
+f 374/439/413 373/434/413 388/468/413 389/471/413
+f 382/441/414 381/437/414 396/470/414 397/472/414
+f 375/443/415 374/439/415 389/471/415 390/456/415
+f 383/445/416 382/441/416 397/472/416 398/458/416
+f 395/466/417 394/464/417 409/473/417 410/474/417
+f 388/468/418 297/475/418 403/476/418
+f 206/477/419 402/465/419 417/478/419
+f 396/470/420 395/466/420 410/474/420 411/479/420
+f 389/471/421 388/468/421 403/476/421 404/480/421
+f 397/472/422 396/470/422 411/479/422 412/481/422
+f 390/456/423 389/471/423 404/480/423 405/482/423
+f 398/458/424 397/472/424 412/481/424 413/483/424
+f 391/457/425 390/456/425 405/482/425 406/484/425
+f 399/459/426 398/458/426 413/483/426 414/485/426
+f 392/460/427 391/457/427 406/484/427 407/486/427
+f 400/461/428 399/459/428 414/485/428 415/487/428
+f 393/462/429 392/460/429 407/486/429 408/488/429
+f 401/463/430 400/461/430 415/487/430 416/489/430
+f 394/464/431 393/462/431 408/488/431 409/473/431
+f 402/465/432 401/463/432 416/489/432 417/478/432
+f 414/485/433 413/483/433 428/490/433 429/491/433
+f 407/486/434 406/484/434 421/492/434 422/493/434
+f 415/487/435 414/485/435 429/491/435 430/494/435
+f 408/488/436 407/486/436 422/493/436 423/495/436
+f 416/489/437 415/487/437 430/494/437 431/496/437
+f 409/473/438 408/488/438 423/495/438 424/497/438
+f 417/478/439 416/489/439 431/496/439 432/498/439
+f 410/474/440 409/473/440 424/497/440 425/499/440
+f 403/476/441 297/500/441 418/501/441
+f 206/502/442 417/478/442 432/498/442
+f 411/479/443 410/474/443 425/499/443 426/503/443
+f 404/480/444 403/476/444 418/501/444 419/504/444
+f 412/481/445 411/479/445 426/503/445 427/505/445
+f 405/482/446 404/480/446 419/504/446 420/506/446
+f 413/483/447 412/481/447 427/505/447 428/490/447
+f 406/484/448 405/482/448 420/506/448 421/492/448
+f 206/507/449 432/498/449 447/508/449
+f 426/503/450 425/499/450 440/509/450 441/510/450
+f 419/504/451 418/501/451 433/511/451 434/512/451
+f 427/505/452 426/503/452 441/510/452 442/513/452
+f 420/506/453 419/504/453 434/512/453 435/514/453
+f 428/490/454 427/505/454 442/513/454 443/515/454
+f 421/492/455 420/506/455 435/514/455 436/516/455
+f 429/491/456 428/490/456 443/515/456 444/517/456
+f 422/493/457 421/492/457 436/516/457 437/518/457
+f 430/494/458 429/491/458 444/517/458 445/519/458
+f 423/495/459 422/493/459 437/518/459 438/520/459
+f 431/496/460 430/494/460 445/519/460 446/521/460
+f 424/497/461 423/495/461 438/520/461 439/522/461
+f 432/498/462 431/496/462 446/521/462 447/508/462
+f 425/499/463 424/497/463 439/522/463 440/509/463
+f 418/501/464 297/523/464 433/511/464
+f 445/519/465 444/517/465 459/524/465 460/525/465
+f 438/520/466 437/518/466 452/526/466 453/527/466
+f 446/521/467 445/519/467 460/525/467 461/528/467
+f 439/522/468 438/520/468 453/527/468 454/529/468
+f 447/508/469 446/521/469 461/528/469 462/530/469
+f 440/509/470 439/522/470 454/529/470 455/531/470
+f 433/511/471 297/532/471 448/533/471
+f 206/534/472 447/508/472 462/530/472
+f 441/510/473 440/509/473 455/531/473 456/535/473
+f 434/512/474 433/511/474 448/533/474 449/536/474
+f 442/513/475 441/510/475 456/535/475 457/537/475
+f 435/514/476 434/512/476 449/536/476 450/538/476
+f 443/515/477 442/513/477 457/537/477 458/539/477
+f 436/516/478 435/514/478 450/538/478 451/540/478
+f 444/517/479 443/515/479 458/539/479 459/524/479
+f 437/518/480 436/516/480 451/540/480 452/526/480
+f 449/536/481 448/533/481 463/541/481 464/542/481
+f 457/537/482 456/535/482 471/543/482 472/544/482
+f 450/538/483 449/536/483 464/542/483 465/545/483
+f 458/539/484 457/537/484 472/544/484 473/546/484
+f 451/540/485 450/538/485 465/545/485 466/547/485
+f 459/524/486 458/539/486 473/546/486 474/548/486
+f 452/526/487 451/540/487 466/547/487 467/549/487
+f 460/525/488 459/524/488 474/548/488 475/550/488
+f 453/527/489 452/526/489 467/549/489 468/551/489
+f 461/528/490 460/525/490 475/550/490 476/552/490
+f 454/529/491 453/527/491 468/551/491 469/553/491
+f 462/530/492 461/528/492 476/552/492 477/554/492
+f 455/531/493 454/529/493 469/553/493 470/555/493
+f 448/533/494 297/556/494 463/541/494
+f 206/557/495 462/530/495 477/554/495
+f 456/535/496 455/531/496 470/555/496 471/543/496
+f 468/551/497 467/549/497 5/6/497 6/5/497
+f 476/552/498 475/550/498 10/1/498 481/9/498
+f 469/553/499 468/551/499 6/5/499 7/11/499
+f 477/554/500 476/552/500 481/9/500 482/13/500
+f 470/555/501 469/553/501 7/11/501 8/15/501
+f 463/541/502 297/558/502 1/17/502
+f 206/559/503 477/554/503 482/13/503
+f 471/543/504 470/555/504 8/15/504 9/21/504
+f 464/542/505 463/541/505 1/17/505 2/23/505
+f 472/544/506 471/543/506 9/21/506 478/25/506
+f 465/545/507 464/542/507 2/23/507 3/27/507
+f 473/546/508 472/544/508 478/25/508 479/29/508
+f 466/547/509 465/545/509 3/27/509 4/31/509
+f 474/548/510 473/546/510 479/29/510 480/2/510
+f 467/549/511 466/547/511 4/31/511 5/6/511
+f 475/550/512 474/548/512 480/2/512 10/1/512

+ 8 - 0
res/shader/light.frag

@@ -0,0 +1,8 @@
+#version 450
+
+layout(location=0) in vec3 v_color;
+layout(location=0) out vec4 f_color;
+
+void main() {
+    f_color = vec4(v_color, 1.0);
+}

BIN
res/shader/light.frag.spv


+ 27 - 0
res/shader/light.vert

@@ -0,0 +1,27 @@
+#version 450
+
+layout(location=0) in vec3 a_position;
+
+layout(location=0) out vec3 v_color;
+
+layout(set=0, binding=0)
+uniform Uniforms {
+    vec3 u_view_position; // unused
+    mat4 u_view_proj;
+};
+
+layout(set=1, binding=0)
+uniform Light {
+    vec3 u_position;
+    vec3 u_color;
+};
+
+// Let's keep our light smaller than our other objects
+float scale = 0.25;
+
+void main() {
+    vec3 v_position = a_position * scale + u_position;
+    gl_Position = u_view_proj * vec4(v_position, 1);
+
+    v_color = u_color;
+}

BIN
res/shader/light.vert.spv


+ 47 - 0
res/shader/phong.frag

@@ -0,0 +1,47 @@
+#version 450
+
+layout(location=0) in vec2 v_tex_coords;
+layout(location=1) in vec3 v_normal;
+layout(location=2) in vec3 v_position;
+
+layout(location=0) out vec4 f_color;
+
+layout(set = 0, binding = 0) uniform texture2D t_diffuse;
+layout(set = 0, binding = 1) uniform sampler s_diffuse;
+
+layout(set=1, binding=0) 
+uniform Uniforms {
+    vec3 u_view_position;
+    mat4 u_view_proj; // unused
+};
+
+layout(set = 2, binding = 0) uniform Light {
+    vec3 light_position;
+    vec3 light_color;
+};
+
+void main() {
+    vec4 object_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
+
+    // We don't need (or want) much ambient light, so 0.1 is fine
+    float ambient_strength = 0.1;
+    vec3 ambient_color = light_color * ambient_strength;
+
+    vec3 normal = normalize(v_normal);
+    vec3 light_dir = normalize(light_position - v_position);
+    
+    float diffuse_strength = max(dot(normal, light_dir), 0.0);
+    vec3 diffuse_color = light_color * diffuse_strength;
+
+    vec3 view_dir = normalize(u_view_position - v_position);
+    vec3 reflect_dir = reflect(-light_dir, normal);
+
+    float specular_strength = pow(max(dot(view_dir, reflect_dir), 0.0), 32);
+    vec3 specular_color = specular_strength * light_color;
+
+    vec3 result = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
+
+    // Since lights don't typically (afaik) cast transparency, so we use
+    // the alpha here at the end.
+    f_color = vec4(result, object_color.a);
+}

BIN
res/shader/phong.frag.spv


+ 47 - 0
res/shader/shader.frag

@@ -0,0 +1,47 @@
+#version 450
+
+layout(location=0) in vec2 v_tex_coords;
+layout(location=1) in vec3 v_normal;
+layout(location=2) in vec3 v_position;
+
+layout(location=0) out vec4 f_color;
+
+layout(set = 0, binding = 0) uniform texture2D t_diffuse;
+layout(set = 0, binding = 1) uniform sampler s_diffuse;
+
+layout(set=1, binding=0) 
+uniform Uniforms {
+    vec3 u_view_position;
+    mat4 u_view_proj; // unused
+};
+
+layout(set=2, binding=0) uniform Light {
+    vec3 light_position;
+    vec3 light_color;
+};
+
+void main() {
+    vec4 object_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
+
+    // We don't need (or want) much ambient light, so 0.1 is fine
+    float ambient_strength = 0.1;
+    vec3 ambient_color = light_color * ambient_strength;
+
+    vec3 normal = normalize(v_normal);
+    vec3 light_dir = normalize(light_position - v_position);
+    
+    float diffuse_strength = max(dot(normal, light_dir), 0.0);
+    vec3 diffuse_color = light_color * diffuse_strength;
+
+    vec3 view_dir = normalize(u_view_position - v_position);
+    vec3 half_dir = normalize(view_dir + light_dir);
+
+    float specular_strength = pow(max(dot(normal, half_dir), 0.0), 32);
+    vec3 specular_color = specular_strength * light_color;
+
+    vec3 result = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
+
+    // Since lights don't typically (afaik) cast transparency, so we use
+    // the alpha here at the end.
+    f_color = vec4(result, object_color.a);
+}

BIN
res/shader/shader.frag.spv


+ 37 - 0
res/shader/shader.vert

@@ -0,0 +1,37 @@
+#version 450
+
+layout(location=0) in vec3 a_position;
+layout(location=1) in vec2 a_tex_coords;
+layout(location=2) in vec3 a_normal;
+
+layout(location=0) out vec2 v_tex_coords;
+layout(location=1) out vec3 v_normal;
+layout(location=2) out vec3 v_position;
+
+layout(set=1, binding=0) 
+uniform Uniforms {
+    vec3 u_view_position; // unused
+    mat4 u_view_proj;
+};
+
+layout(location=5) in vec4 model_matrix_0;
+layout(location=6) in vec4 model_matrix_1;
+layout(location=7) in vec4 model_matrix_2;
+layout(location=8) in vec4 model_matrix_3;
+
+void main() {
+    mat4 model_matrix = mat4(
+        model_matrix_0,
+        model_matrix_1,
+        model_matrix_2,
+        model_matrix_3
+    );
+    v_tex_coords = a_tex_coords;
+    mat3 normal_matrix = mat3(transpose(inverse(model_matrix)));
+    v_normal = normal_matrix * a_normal;
+
+    vec4 model_space = model_matrix * vec4(a_position, 1.0);
+    v_position = model_space.xyz;
+
+    gl_Position = u_view_proj * model_space;
+}

BIN
res/shader/shader.vert.spv


+ 11 - 0
res/shader/ui_shader.frag

@@ -0,0 +1,11 @@
+#version 450
+
+layout(location=0) in vec2 v_tex_coords;
+layout(location=0) out vec4 f_color;
+
+layout(set = 0, binding = 0) uniform texture2D t_diffuse;
+layout(set = 0, binding = 1) uniform sampler s_diffuse;
+
+void main() {
+    f_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
+}

+ 0 - 0
src/bin/assets/shader.frag.spv → res/shader/ui_shader.frag.spv


+ 11 - 0
res/shader/ui_shader.vert

@@ -0,0 +1,11 @@
+#version 450
+
+layout(location=0) in vec3 a_position;
+layout(location=1) in vec2 a_tex_coords;
+
+layout(location=0) out vec2 v_tex_coords;
+
+void main() {
+    v_tex_coords = a_tex_coords;
+    gl_Position = vec4(a_position, 1.0);
+}

+ 0 - 0
src/bin/assets/shader.vert.spv → res/shader/ui_shader.vert.spv


+ 94 - 0
src/bin/compile-shaders.rs

@@ -0,0 +1,94 @@
+use anyhow::*;
+use fs_extra::copy_items;
+use fs_extra::dir::CopyOptions;
+use glob::glob;
+use std::env;
+use std::fs::{read_to_string, write};
+use std::path::PathBuf;
+
+struct ShaderData {
+    src: String,
+    src_path: PathBuf,
+    spv_path: PathBuf,
+    kind: shaderc::ShaderKind,
+}
+
+impl ShaderData {
+    pub fn load(src_path: PathBuf) -> Result<Self> {
+        let extension = src_path
+            .extension()
+            .context("File has no extension")?
+            .to_str()
+            .context("Extension cannot be converted to &str")?;
+        let kind = match extension {
+            "vert" => shaderc::ShaderKind::Vertex,
+            "frag" => shaderc::ShaderKind::Fragment,
+            "comp" => shaderc::ShaderKind::Compute,
+            _ => bail!("Unsupported shader: {}", src_path.display()),
+        };
+
+        let src = read_to_string(src_path.clone())?;
+        let spv_path = src_path.with_extension(format!("{}.spv", extension));
+
+        Ok(Self {
+            src,
+            src_path,
+            spv_path,
+            kind,
+        })
+    }
+}
+
+fn main() -> Result<()> {
+    // Collect all shaders recursively within /src/
+    let mut shader_paths = [
+        glob("./res/shader/**/*.vert")?,
+        glob("./res/shader/**/*.frag")?,
+        glob("./res/shader/**/*.comp")?,
+    ];
+
+    // This could be parallelized
+    let shaders = shader_paths
+        .iter_mut()
+        .flatten()
+        .map(|glob_result| ShaderData::load(glob_result?))
+        .collect::<Vec<Result<_>>>()
+        .into_iter()
+        .collect::<Result<Vec<_>>>()?;
+
+    let mut compiler = shaderc::Compiler::new().context("Unable to create shader compiler")?;
+
+    // This can't be parallelized. The [shaderc::Compiler] is not
+    // thread safe. Also, it creates a lot of resources. You could
+    // spawn multiple processes to handle this, but it would probably
+    // be better just to only compile shaders that have been changed
+    // recently.
+    for shader in shaders {
+        // This tells cargo to rerun this script if something in /src/ changes.
+        println!(
+            "cargo:rerun-if-changed={}",
+            shader.src_path.as_os_str().to_str().unwrap()
+        );
+
+        let compiled = compiler.compile_into_spirv(
+            &shader.src,
+            shader.kind,
+            &shader.src_path.to_str().unwrap(),
+            "main",
+            None,
+        )?;
+        write(shader.spv_path, compiled.as_binary_u8())?;
+    }
+
+    // This tells cargo to rerun this script if something in /res/ changes.
+    println!("cargo:rerun-if-changed=res/*");
+
+    //let out_dir = env::var("OUT_DIR")?;
+    //let mut copy_options = CopyOptions::new();
+    //copy_options.overwrite = true;
+    //let mut paths_to_copy = Vec::new();
+    //paths_to_copy.push("res/");
+    //copy_items(&paths_to_copy, out_dir, &copy_options)?;
+
+    Ok(())
+}

+ 589 - 181
src/bin/dfg.rs

@@ -1,99 +1,124 @@
-use std::iter;
 use rand::Rng;
+use std::iter;
+
+use cgmath::prelude::*;
 use wgpu::util::DeviceExt;
 use winit::{
     event::*,
     event_loop::{ControlFlow, EventLoop},
-    window::{Window, WindowBuilder},
+    window::Window,
 };
 
-use sapvi::gui::texture;
+use sapvi::gfx::{camera, model, texture};
+
+use model::{DrawLight, DrawModel, Vertex};
+
+use std::time::Instant;
+#[macro_use]
+extern crate lazy_static;
+
+lazy_static! {
+    static ref START: Instant = Instant::now();
+}
+
+fn get_time() -> f32 {
+    START.elapsed().as_secs_f32()
+}
+
+const FONT_BYTES: &[u8] = include_bytes!("../../res/font/PressStart2P-Regular.ttf");
 
-const FONT_BYTES: &[u8] = include_bytes!("../../res/fonts/PressStart2P-Regular.ttf");
+const NUM_INSTANCES_PER_ROW: u32 = 10;
 
 #[repr(C)]
-#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
-struct Vertex {
-    position: [f32; 3],
-    tex_coords: [f32; 2],
+#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct Uniforms {
+    view_position: [f32; 4],
+    view_proj: [[f32; 4]; 4],
+}
+
+impl Uniforms {
+    fn new() -> Self {
+        Self {
+            view_position: [0.0; 4],
+            view_proj: cgmath::Matrix4::identity().into(),
+        }
+    }
+
+    fn update_view_proj(&mut self, camera: &camera::Camera, projection: &camera::Projection) {
+        self.view_position = camera.position.to_homogeneous().into();
+        self.view_proj = (projection.calc_matrix() * camera.calc_matrix()).into()
+    }
+}
+
+struct Instance {
+    position: cgmath::Vector3<f32>,
+    rotation: cgmath::Quaternion<f32>,
+}
+
+impl Instance {
+    fn to_raw(&self) -> InstanceRaw {
+        InstanceRaw {
+            model: (cgmath::Matrix4::from_translation(self.position)
+                * cgmath::Matrix4::from(self.rotation))
+            .into(),
+        }
+    }
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct InstanceRaw {
+    #[allow(dead_code)]
+    model: [[f32; 4]; 4],
 }
 
-impl Vertex {
+impl model::Vertex for InstanceRaw {
     fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
         use std::mem;
         wgpu::VertexBufferLayout {
-            array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
-            step_mode: wgpu::InputStepMode::Vertex,
+            array_stride: mem::size_of::<InstanceRaw>() as wgpu::BufferAddress,
+            // We need to switch from using a step mode of Vertex to Instance
+            // This means that our shaders will only change to use the next
+            // instance when the shader starts processing a new instance
+            step_mode: wgpu::InputStepMode::Instance,
             attributes: &[
                 wgpu::VertexAttribute {
                     offset: 0,
-                    shader_location: 0,
-                    format: wgpu::VertexFormat::Float3,
+                    // While our vertex shader only uses locations 0, and 1 now, in later tutorials we'll
+                    // be using 2, 3, and 4, for Vertex. We'll start at slot 5 not conflict with them later
+                    shader_location: 5,
+                    format: wgpu::VertexFormat::Float4,
+                },
+                // A mat4 takes up 4 vertex slots as it is technically 4 vec4s. We need to define a slot
+                // for each vec4. We don't have to do this in code though.
+                wgpu::VertexAttribute {
+                    offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
+                    shader_location: 6,
+                    format: wgpu::VertexFormat::Float4,
                 },
                 wgpu::VertexAttribute {
-                    offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
-                    shader_location: 1,
-                    format: wgpu::VertexFormat::Float2,
+                    offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress,
+                    shader_location: 7,
+                    format: wgpu::VertexFormat::Float4,
+                },
+                wgpu::VertexAttribute {
+                    offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress,
+                    shader_location: 8,
+                    format: wgpu::VertexFormat::Float4,
                 },
             ],
         }
     }
 }
 
-//  (-1, 1)                  (1, 1)
-//     +-----------------------+
-//     |                       |
-//     |                       |
-//     |                       |
-//     |                       |
-//     |                       |
-//     |                       |
-//     |                       |
-//     +-----------------------+
-//  (-1, -1)                 (1, -1)
-const VERTICES: &[Vertex] = &[
-    Vertex {
-        position: [-1.0, 1.0, 0.0],
-        tex_coords: [0.0, 0.0],
-    },
-    Vertex {
-        position: [-1.0, -1.0, 0.0],
-        tex_coords: [0.0, 1.0],
-    },
-    Vertex {
-        position: [1.0, -1.0, 0.0],
-        tex_coords: [1.0, 1.0],
-    },
-    Vertex {
-        position: [1.0, 1.0, 0.0],
-        tex_coords: [1.0, 0.0],
-    },
-    /*
-    Vertex {
-        position: [-0.0868241, 0.49240386, 0.0],
-        tex_coords: [0.4131759, 0.00759614],
-    }, // A
-    Vertex {
-        position: [-0.49513406, 0.06958647, 0.0],
-        tex_coords: [0.0048659444, 0.43041354],
-    }, // B
-    Vertex {
-        position: [-0.21918549, -0.44939706, 0.0],
-        tex_coords: [0.28081453, 0.949397057],
-    }, // C
-    Vertex {
-        position: [0.35966998, -0.3473291, 0.0],
-        tex_coords: [0.85967, 0.84732911],
-    }, // D
-    Vertex {
-        position: [0.44147372, 0.2347359, 0.0],
-        tex_coords: [0.9414737, 0.2652641],
-    }, // E
-    */
-];
-
-//const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
-const INDICES: &[u16] = &[0, 1, 2, 0, 2, 3];
+#[repr(C)]
+#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
+struct Light {
+    position: [f32; 3],
+    // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here
+    _padding: u32,
+    color: [f32; 3],
+}
 
 pub const UNBOUNDED_F32: f32 = std::f32::INFINITY;
 
@@ -124,18 +149,77 @@ impl Default for Text {
     }
 }
 
+const VERTEX_Z: f32 = 0.0;
+//  (-1, 1)                  (1, 1)
+//     +-----------------------+
+//     |                       |
+//     |                       |
+//     |                       |
+//     |                       |
+//     |                       |
+//     |                       |
+//     |                       |
+//     +-----------------------+
+//  (-1, -1)                 (1, -1)
+const VERTICES: &[model::ModelVertex] = &[
+    // top left
+    model::ModelVertex {
+        position: [-1.0, 1.0, VERTEX_Z],
+        tex_coords: [0.0, 0.0],
+        normal: [0.0, 0.0, -1.0],
+    },
+    // bottom left
+    model::ModelVertex {
+        position: [-1.0, 0.5, VERTEX_Z],
+        tex_coords: [0.0, 1.0],
+        normal: [0.0, 0.0, -1.0],
+    },
+    // bottom right
+    model::ModelVertex {
+        position: [-0.5, 0.5, VERTEX_Z],
+        tex_coords: [1.0, 1.0],
+        normal: [0.0, 0.0, -1.0],
+    },
+    // top right
+    model::ModelVertex {
+        position: [-0.5, 1.0, VERTEX_Z],
+        tex_coords: [1.0, 0.0],
+        normal: [0.0, 0.0, -1.0],
+    },
+];
+
+//const INDICES: &[u16] = &[0, 1, 4, 1, 2, 4, 2, 3, 4];
+const INDICES: &[u16] = &[0, 1, 2, 0, 2, 3];
+
 struct State {
     surface: wgpu::Surface,
     device: wgpu::Device,
     queue: wgpu::Queue,
     sc_desc: wgpu::SwapChainDescriptor,
     swap_chain: wgpu::SwapChain,
-    size: winit::dpi::PhysicalSize<u32>,
     render_pipeline: wgpu::RenderPipeline,
+    obj_model: model::Model,
+
+    camera: camera::Camera,                      // UPDATED!
+    projection: camera::Projection,              // NEW!
+    camera_controller: camera::CameraController, // UPDATED!
+
+    uniforms: Uniforms,
+    uniform_buffer: wgpu::Buffer,
+    uniform_bind_group: wgpu::BindGroup,
+    instances: Vec<Instance>,
+    #[allow(dead_code)]
+    instance_buffer: wgpu::Buffer,
+    depth_texture: texture::Texture,
+    size: winit::dpi::PhysicalSize<u32>,
+    light: Light,
+    light_buffer: wgpu::Buffer,
+    light_bind_group: wgpu::BindGroup,
+    light_render_pipeline: wgpu::RenderPipeline,
+
+    ui_render_pipeline: wgpu::RenderPipeline,
     vertex_buffer: wgpu::Buffer,
     index_buffer: wgpu::Buffer,
-    glyph_brush: wgpu_glyph::GlyphBrush<()>,
-    staging_belt: wgpu::util::StagingBelt,
     num_indices: u32,
     #[allow(dead_code)]
     diffuse_texture: texture::Texture,
@@ -143,7 +227,67 @@ struct State {
     #[allow(dead_code)]
     cartoon_texture: texture::Texture,
     cartoon_bind_group: wgpu::BindGroup,
+
+    glyph_brush: wgpu_glyph::GlyphBrush<()>,
+    staging_belt: wgpu::util::StagingBelt,
+
     is_space_pressed: bool,
+    mouse_pressed: bool,
+}
+
+fn create_render_pipeline(
+    device: &wgpu::Device,
+    layout: &wgpu::PipelineLayout,
+    color_format: wgpu::TextureFormat,
+    depth_format: Option<wgpu::TextureFormat>,
+    vertex_layouts: &[wgpu::VertexBufferLayout],
+    vs_src: wgpu::ShaderModuleDescriptor,
+    fs_src: wgpu::ShaderModuleDescriptor,
+) -> wgpu::RenderPipeline {
+    let vs_module = device.create_shader_module(&vs_src);
+    let fs_module = device.create_shader_module(&fs_src);
+
+    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+        label: Some("Render Pipeline"),
+        layout: Some(&layout),
+        vertex: wgpu::VertexState {
+            module: &vs_module,
+            entry_point: "main",
+            buffers: vertex_layouts,
+        },
+        fragment: Some(wgpu::FragmentState {
+            module: &fs_module,
+            entry_point: "main",
+            targets: &[wgpu::ColorTargetState {
+                format: color_format,
+                alpha_blend: wgpu::BlendState::REPLACE,
+                color_blend: wgpu::BlendState::REPLACE,
+                write_mask: wgpu::ColorWrite::ALL,
+            }],
+        }),
+        primitive: wgpu::PrimitiveState {
+            topology: wgpu::PrimitiveTopology::TriangleList,
+            strip_index_format: None,
+            front_face: wgpu::FrontFace::Ccw,
+            cull_mode: wgpu::CullMode::Back,
+            // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
+            polygon_mode: wgpu::PolygonMode::Fill,
+        },
+        depth_stencil: depth_format.map(|format| wgpu::DepthStencilState {
+            format,
+            depth_write_enabled: true,
+            depth_compare: wgpu::CompareFunction::Less,
+            stencil: wgpu::StencilState::default(),
+            bias: wgpu::DepthBiasState::default(),
+            // Setting this to true requires Features::DEPTH_CLAMPING
+            clamp_depth: false,
+        }),
+        multisample: wgpu::MultisampleState {
+            count: 1,
+            mask: !0,
+            alpha_to_coverage_enabled: false,
+        },
+    })
 }
 
 impl State {
@@ -180,6 +324,7 @@ impl State {
             height: size.height,
             present_mode: wgpu::PresentMode::Fifo,
         };
+
         let swap_chain = device.create_swap_chain(&surface, &sc_desc);
 
         let texture_bind_group_layout =
@@ -208,9 +353,190 @@ impl State {
                 label: Some("texture_bind_group_layout"),
             });
 
-        let diffuse_bytes = include_bytes!("assets/absolutely-proprietary.png");
+        let camera = camera::Camera::new((0.0, 5.0, 10.0), cgmath::Deg(-90.0), cgmath::Deg(-20.0));
+        let projection =
+            camera::Projection::new(sc_desc.width, sc_desc.height, cgmath::Deg(45.0), 0.1, 100.0);
+        let camera_controller = camera::CameraController::new(4.0, 0.4);
+
+        let mut uniforms = Uniforms::new();
+        uniforms.update_view_proj(&camera, &projection);
+
+        let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+            label: Some("Uniform Buffer"),
+            contents: bytemuck::cast_slice(&[uniforms]),
+            usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
+        });
+
+        const SPACE_BETWEEN: f32 = 3.0;
+        let instances = (0..NUM_INSTANCES_PER_ROW)
+            .flat_map(|z| {
+                (0..NUM_INSTANCES_PER_ROW).map(move |x| {
+                    let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
+                    let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
+
+                    let y = 0.0;
+
+                    let position = cgmath::Vector3 { x, y, z };
+
+                    let rotation = cgmath::Quaternion::from_axis_angle(
+                        cgmath::Vector3::unit_z(),
+                        cgmath::Deg(180.0 + 0.0),
+                    );
+
+                    Instance { position, rotation }
+                })
+            })
+            .collect::<Vec<_>>();
+
+        let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
+        let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+            label: Some("Instance Buffer"),
+            contents: bytemuck::cast_slice(&instance_data),
+            usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST,
+        });
+
+        let uniform_bind_group_layout =
+            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+                entries: &[wgpu::BindGroupLayoutEntry {
+                    binding: 0,
+                    visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
+                    ty: wgpu::BindingType::Buffer {
+                        ty: wgpu::BufferBindingType::Uniform,
+                        has_dynamic_offset: false,
+                        min_binding_size: None,
+                    },
+                    count: None,
+                }],
+                label: Some("uniform_bind_group_layout"),
+            });
+
+        let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+            layout: &uniform_bind_group_layout,
+            entries: &[wgpu::BindGroupEntry {
+                binding: 0,
+                resource: uniform_buffer.as_entire_binding(),
+            }],
+            label: Some("uniform_bind_group"),
+        });
+
+        let res_dir = std::path::Path::new("res/model/");
+        let obj_model = model::Model::load(
+            &device,
+            &queue,
+            &texture_bind_group_layout,
+            res_dir.join("earth.obj"),
+        )
+        .unwrap();
+
+        let light = Light {
+            position: [4.0, 4.0, 2.0],
+            _padding: 0,
+            color: [1.0, 1.0, 1.0],
+        };
+
+        let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+            label: Some("Light VB"),
+            contents: bytemuck::cast_slice(&[light]),
+            usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
+        });
+
+        let light_bind_group_layout =
+            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+                entries: &[wgpu::BindGroupLayoutEntry {
+                    binding: 0,
+                    visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
+                    ty: wgpu::BindingType::Buffer {
+                        ty: wgpu::BufferBindingType::Uniform,
+                        has_dynamic_offset: false,
+                        min_binding_size: None,
+                    },
+                    count: None,
+                }],
+                label: None,
+            });
+
+        let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+            layout: &light_bind_group_layout,
+            entries: &[wgpu::BindGroupEntry {
+                binding: 0,
+                resource: light_buffer.as_entire_binding(),
+            }],
+            label: None,
+        });
+
+        let depth_texture =
+            texture::Texture::create_depth_texture(&device, &sc_desc, "depth_texture");
+
+        let render_pipeline_layout =
+            device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+                label: Some("Render Pipeline Layout"),
+                bind_group_layouts: &[
+                    &texture_bind_group_layout,
+                    &uniform_bind_group_layout,
+                    &light_bind_group_layout,
+                ],
+                push_constant_ranges: &[],
+            });
+
+        let render_pipeline = create_render_pipeline(
+            &device,
+            &render_pipeline_layout,
+            sc_desc.format,
+            Some(texture::Texture::DEPTH_FORMAT),
+            &[model::ModelVertex::desc(), InstanceRaw::desc()],
+            wgpu::include_spirv!("../../res/shader/shader.vert.spv"),
+            wgpu::include_spirv!("../../res/shader/shader.frag.spv"),
+        );
+
+        let light_render_pipeline = {
+            let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+                label: Some("Light Pipeline Layout"),
+                bind_group_layouts: &[&uniform_bind_group_layout, &light_bind_group_layout],
+                push_constant_ranges: &[],
+            });
+
+            create_render_pipeline(
+                &device,
+                &layout,
+                sc_desc.format,
+                Some(texture::Texture::DEPTH_FORMAT),
+                &[model::ModelVertex::desc()],
+                wgpu::include_spirv!("../../res/shader/light.vert.spv"),
+                wgpu::include_spirv!("../../res/shader/light.frag.spv"),
+            )
+        };
+
+        //-------------------
+
+        let texture_bind_group_layout =
+            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
+                entries: &[
+                    wgpu::BindGroupLayoutEntry {
+                        binding: 0,
+                        visibility: wgpu::ShaderStage::FRAGMENT,
+                        ty: wgpu::BindingType::Texture {
+                            multisampled: false,
+                            view_dimension: wgpu::TextureViewDimension::D2,
+                            sample_type: wgpu::TextureSampleType::Float { filterable: false },
+                        },
+                        count: None,
+                    },
+                    wgpu::BindGroupLayoutEntry {
+                        binding: 1,
+                        visibility: wgpu::ShaderStage::FRAGMENT,
+                        ty: wgpu::BindingType::Sampler {
+                            comparison: false,
+                            filtering: true,
+                        },
+                        count: None,
+                    },
+                ],
+                label: Some("texture_bind_group_layout"),
+            });
+
+        let diffuse_bytes = include_bytes!("../../res/img/absolutely-proprietary.png");
         let diffuse_texture =
-            texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "assets/absolutely-proprietary.png").unwrap();
+            texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "stallman1").unwrap();
 
         let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
             layout: &texture_bind_group_layout,
@@ -227,10 +553,9 @@ impl State {
             label: Some("diffuse_bind_group"),
         });
 
-        let cartoon_bytes = include_bytes!("assets/absolutely-proprietary2.png");
+        let cartoon_bytes = include_bytes!("../../res/img/absolutely-proprietary2.png");
         let cartoon_texture =
-            texture::Texture::from_bytes(&device, &queue, cartoon_bytes, "happy-tree-cartoon.png")
-                .unwrap();
+            texture::Texture::from_bytes(&device, &queue, cartoon_bytes, "stallman2").unwrap();
 
         let cartoon_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
             layout: &texture_bind_group_layout,
@@ -247,9 +572,6 @@ impl State {
             label: Some("cartoon_bind_group"),
         });
 
-        let vs_module = device.create_shader_module(&wgpu::include_spirv!("assets/shader.vert.spv"));
-        let fs_module = device.create_shader_module(&wgpu::include_spirv!("assets/shader.frag.spv"));
-
         let render_pipeline_layout =
             device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
                 label: Some("Render Pipeline Layout"),
@@ -257,39 +579,15 @@ impl State {
                 push_constant_ranges: &[],
             });
 
-        let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
-            label: Some("Render Pipeline"),
-            layout: Some(&render_pipeline_layout),
-            vertex: wgpu::VertexState {
-                module: &vs_module,
-                entry_point: "main",
-                buffers: &[Vertex::desc()],
-            },
-            fragment: Some(wgpu::FragmentState {
-                module: &fs_module,
-                entry_point: "main",
-                targets: &[wgpu::ColorTargetState {
-                    format: sc_desc.format,
-                    alpha_blend: wgpu::BlendState::REPLACE,
-                    color_blend: wgpu::BlendState::REPLACE,
-                    write_mask: wgpu::ColorWrite::ALL,
-                }],
-            }),
-            primitive: wgpu::PrimitiveState {
-                topology: wgpu::PrimitiveTopology::TriangleList,
-                strip_index_format: None,
-                front_face: wgpu::FrontFace::Ccw,
-                cull_mode: wgpu::CullMode::Back,
-                // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
-                polygon_mode: wgpu::PolygonMode::Fill,
-            },
-            depth_stencil: None,
-            multisample: wgpu::MultisampleState {
-                count: 1,
-                mask: !0,
-                alpha_to_coverage_enabled: false,
-            },
-        });
+        let ui_render_pipeline = create_render_pipeline(
+            &device,
+            &render_pipeline_layout,
+            sc_desc.format,
+            Some(texture::Texture::DEPTH_FORMAT),
+            &[model::ModelVertex::desc()],
+            wgpu::include_spirv!("../../res/shader/ui_shader.vert.spv"),
+            wgpu::include_spirv!("../../res/shader/ui_shader.frag.spv"),
+        );
 
         let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
             label: Some("Vertex Buffer"),
@@ -315,49 +613,131 @@ impl State {
             sc_desc,
             swap_chain,
             render_pipeline,
+            obj_model,
+
+            camera,
+            projection,
+            camera_controller,
+
+            uniform_buffer,
+            uniform_bind_group,
+            uniforms,
+            instances,
+            instance_buffer,
+            depth_texture,
+            size,
+            light,
+            light_buffer,
+            light_bind_group,
+            light_render_pipeline,
+
+            ui_render_pipeline,
             vertex_buffer,
             index_buffer,
-            glyph_brush,
-            staging_belt,
             num_indices,
             diffuse_texture,
             diffuse_bind_group,
             cartoon_texture,
             cartoon_bind_group,
-            size,
-            is_space_pressed: false,
+
+            glyph_brush,
+            staging_belt,
+
+            is_space_pressed: true,
+            mouse_pressed: false,
         }
     }
 
     fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
+        self.projection.resize(new_size.width, new_size.height);
         self.size = new_size;
         self.sc_desc.width = new_size.width;
         self.sc_desc.height = new_size.height;
         self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc);
+        self.depth_texture =
+            texture::Texture::create_depth_texture(&self.device, &self.sc_desc, "depth_texture");
     }
 
-    fn input(&mut self, event: &WindowEvent) -> bool {
+    fn input(&mut self, event: &DeviceEvent) -> bool {
         match event {
-            WindowEvent::KeyboardInput {
-                input:
-                    KeyboardInput {
-                        state,
-                        virtual_keycode: Some(VirtualKeyCode::Space),
-                        ..
-                    },
+            DeviceEvent::Key(KeyboardInput {
+                virtual_keycode: Some(key),
+                state,
                 ..
+            }) => self.camera_controller.process_keyboard(*key, *state),
+            DeviceEvent::MouseWheel { delta, .. } => {
+                self.camera_controller.process_scroll(delta);
+                true
+            }
+            DeviceEvent::Button {
+                button: 1, // Left Mouse Button
+                state,
             } => {
-                self.is_space_pressed = *state == ElementState::Pressed;
+                self.mouse_pressed = *state == ElementState::Pressed;
+                true
+            }
+            DeviceEvent::MouseMotion { delta } => {
+                if self.mouse_pressed {
+                    self.camera_controller.process_mouse(delta.0, delta.1);
+                }
                 true
             }
             _ => false,
         }
     }
 
-    fn update(&mut self) {
+    fn update(&mut self, dt: std::time::Duration) {
         if rand::thread_rng().gen_range(0, 5) == 0 {
             self.is_space_pressed = !self.is_space_pressed;
         }
+
+        self.camera_controller.update_camera(&mut self.camera, dt);
+        self.uniforms
+            .update_view_proj(&self.camera, &self.projection);
+        self.queue.write_buffer(
+            &self.uniform_buffer,
+            0,
+            bytemuck::cast_slice(&[self.uniforms]),
+        );
+
+        let time = get_time();
+        const SPACE_BETWEEN: f32 = 3.0;
+        let instances = (0..NUM_INSTANCES_PER_ROW)
+            .flat_map(|z| {
+                (0..NUM_INSTANCES_PER_ROW).map(move |x| {
+                    let x = SPACE_BETWEEN * (x as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
+                    let z = SPACE_BETWEEN * (z as f32 - NUM_INSTANCES_PER_ROW as f32 / 2.0);
+
+                    //println!("{} {} {}", x, z, time);
+                    let y = ((x / 3.0 + time).sin() + (z / 3.0 + time).cos()) * 1.5;
+
+                    let position = cgmath::Vector3 { x, y, z };
+
+                    let rotation = cgmath::Quaternion::from_axis_angle(
+                        cgmath::Vector3::unit_z(),
+                        cgmath::Deg(180.0 + 0.0),
+                    );
+
+                    Instance { position, rotation }
+                })
+            })
+            .collect::<Vec<_>>();
+
+        let instance_data = instances.iter().map(Instance::to_raw).collect::<Vec<_>>();
+        self.queue.write_buffer(
+            &self.instance_buffer,
+            0,
+            bytemuck::cast_slice(&instance_data),
+        );
+
+        // Update the light
+        let old_position: cgmath::Vector3<_> = self.light.position.into();
+        self.light.position =
+            (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0))
+                * old_position)
+                .into();
+        self.queue
+            .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light]));
     }
 
     fn render(&mut self) -> Result<(), wgpu::SwapChainError> {
@@ -385,16 +765,38 @@ impl State {
                         store: true,
                     },
                 }],
-                depth_stencil_attachment: None,
+                depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
+                    attachment: &self.depth_texture.view,
+                    depth_ops: Some(wgpu::Operations {
+                        load: wgpu::LoadOp::Clear(1.0),
+                        store: true,
+                    }),
+                    stencil_ops: None,
+                }),
             });
 
+            render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..));
+            //render_pass.set_pipeline(&self.light_render_pipeline);
+            //render_pass.draw_light_model(
+            //    &self.obj_model,
+            //    &self.uniform_bind_group,
+            //    &self.light_bind_group,
+            //);
+            render_pass.set_pipeline(&self.render_pipeline);
+            render_pass.draw_model_instanced(
+                &self.obj_model,
+                0..self.instances.len() as u32,
+                &self.uniform_bind_group,
+                &self.light_bind_group,
+            );
+
             let bind_group = if self.is_space_pressed {
                 &self.cartoon_bind_group
             } else {
                 &self.diffuse_bind_group
             };
 
-            render_pass.set_pipeline(&self.render_pipeline);
+            render_pass.set_pipeline(&self.ui_render_pipeline);
             render_pass.set_bind_group(0, bind_group, &[]);
             render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
             render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
@@ -411,18 +813,18 @@ impl State {
         };
         draw_text(&play_text, &mut self.glyph_brush);
 
-                self.glyph_brush
-                    .draw_queued(
-                        &self.device,
-                        &mut self.staging_belt,
-                        &mut encoder,
-                        &frame.view,
-                        self.sc_desc.width,
-                        self.sc_desc.height,
-                    )
-                    .unwrap();
+        self.glyph_brush
+            .draw_queued(
+                &self.device,
+                &mut self.staging_belt,
+                &mut encoder,
+                &frame.view,
+                self.sc_desc.width,
+                self.sc_desc.height,
+            )
+            .unwrap();
 
-                self.staging_belt.finish();
+        self.staging_belt.finish();
 
         self.queue.submit(iter::once(encoder.finish()));
 
@@ -437,20 +839,21 @@ fn draw_text(text: &Text, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>) {
         wgpu_glyph::HorizontalAlign::Left
     });
 
-    let section =
-        wgpu_glyph::Section {
-            screen_position: text.position.into(),
-            bounds: text.bounds.into(),
-            layout,
-            ..Default::default()
-        }
-        .add_text(wgpu_glyph::Text::new(&text.text).with_color(text.color).with_scale(
-            if text.focused {
+    let section = wgpu_glyph::Section {
+        screen_position: text.position.into(),
+        bounds: text.bounds.into(),
+        layout,
+        ..Default::default()
+    }
+    .add_text(
+        wgpu_glyph::Text::new(&text.text)
+            .with_color(text.color)
+            .with_scale(if text.focused {
                 text.size + 8.0
             } else {
                 text.size
-            },
-        ));
+            }),
+    );
 
     glyph_brush.queue(section);
 }
@@ -458,43 +861,54 @@ fn draw_text(text: &Text, glyph_brush: &mut wgpu_glyph::GlyphBrush<()>) {
 fn main() {
     env_logger::init();
     let event_loop = EventLoop::new();
-    let window = WindowBuilder::new().build(&event_loop).unwrap();
-
+    let title = env!("CARGO_PKG_NAME");
+    let window = winit::window::WindowBuilder::new()
+        .with_title(title)
+        .build(&event_loop)
+        .unwrap();
     use futures::executor::block_on;
-
-    // Since main can't be async, we're going to need to block
     let mut state = block_on(State::new(&window));
-
+    let mut last_render_time = std::time::Instant::now();
     event_loop.run(move |event, _, control_flow| {
+        *control_flow = ControlFlow::Poll;
         match event {
+            Event::MainEventsCleared => window.request_redraw(),
+            Event::DeviceEvent {
+                ref event,
+                .. // We're not using device_id currently
+            } => {
+                state.input(event);
+            }
             Event::WindowEvent {
                 ref event,
                 window_id,
             } if window_id == window.id() => {
-                if !state.input(event) {
-                    match event {
-                        WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
-                        WindowEvent::KeyboardInput { input, .. } => match input {
-                            KeyboardInput {
-                                state: ElementState::Pressed,
-                                virtual_keycode: Some(VirtualKeyCode::Escape),
-                                ..
-                            } => *control_flow = ControlFlow::Exit,
-                            _ => {}
-                        },
-                        WindowEvent::Resized(physical_size) => {
-                            state.resize(*physical_size);
-                        }
-                        WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
-                            // new_inner_size is &mut so w have to dereference it twice
-                            state.resize(**new_inner_size);
+                match event {
+                    WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
+                    WindowEvent::KeyboardInput { input, .. } => match input {
+                        KeyboardInput {
+                            state: ElementState::Pressed,
+                            virtual_keycode: Some(VirtualKeyCode::Escape),
+                            ..
+                        } => {
+                            *control_flow = ControlFlow::Exit;
                         }
                         _ => {}
+                    },
+                    WindowEvent::Resized(physical_size) => {
+                        state.resize(*physical_size);
                     }
+                    WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
+                        state.resize(**new_inner_size);
+                    }
+                    _ => {}
                 }
             }
             Event::RedrawRequested(_) => {
-                state.update();
+                let now = std::time::Instant::now();
+                let dt = now - last_render_time;
+                last_render_time = now;
+                state.update(dt);
                 match state.render() {
                     Ok(_) => {}
                     // Recreate the swap_chain if lost
@@ -505,13 +919,7 @@ fn main() {
                     Err(e) => eprintln!("{:?}", e),
                 }
             }
-            Event::MainEventsCleared => {
-                // RedrawRequested will only trigger once, unless we manually
-                // request it.
-                window.request_redraw();
-            }
             _ => {}
         }
     });
 }
-

+ 191 - 0
src/gfx/camera.rs

@@ -0,0 +1,191 @@
+use cgmath::*;
+use std::f32::consts::FRAC_PI_2;
+use std::time::Duration;
+use winit::dpi::PhysicalPosition;
+use winit::event::*;
+
+#[rustfmt::skip]
+pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
+    1.0, 0.0, 0.0, 0.0,
+    0.0, 1.0, 0.0, 0.0,
+    0.0, 0.0, 0.5, 0.0,
+    0.0, 0.0, 0.5, 1.0,
+);
+
+#[derive(Debug)]
+pub struct Camera {
+    pub position: Point3<f32>,
+    yaw: Rad<f32>,
+    pitch: Rad<f32>,
+}
+
+impl Camera {
+    pub fn new<V: Into<Point3<f32>>, Y: Into<Rad<f32>>, P: Into<Rad<f32>>>(
+        position: V,
+        yaw: Y,
+        pitch: P,
+    ) -> Self {
+        Self {
+            position: position.into(),
+            yaw: yaw.into(),
+            pitch: pitch.into(),
+        }
+    }
+
+    pub fn calc_matrix(&self) -> Matrix4<f32> {
+        Matrix4::look_at_dir(
+            self.position,
+            Vector3::new(self.yaw.0.cos(), self.pitch.0.sin(), self.yaw.0.sin()).normalize(),
+            Vector3::unit_y(),
+        )
+    }
+}
+
+pub struct Projection {
+    aspect: f32,
+    fovy: Rad<f32>,
+    znear: f32,
+    zfar: f32,
+}
+
+impl Projection {
+    pub fn new<F: Into<Rad<f32>>>(width: u32, height: u32, fovy: F, znear: f32, zfar: f32) -> Self {
+        Self {
+            aspect: width as f32 / height as f32,
+            fovy: fovy.into(),
+            znear,
+            zfar,
+        }
+    }
+
+    pub fn resize(&mut self, width: u32, height: u32) {
+        self.aspect = width as f32 / height as f32;
+    }
+
+    pub fn calc_matrix(&self) -> Matrix4<f32> {
+        OPENGL_TO_WGPU_MATRIX * perspective(self.fovy, self.aspect, self.znear, self.zfar)
+    }
+}
+
+#[derive(Debug)]
+pub struct CameraController {
+    amount_left: f32,
+    amount_right: f32,
+    amount_forward: f32,
+    amount_backward: f32,
+    amount_up: f32,
+    amount_down: f32,
+    rotate_horizontal: f32,
+    rotate_vertical: f32,
+    scroll: f32,
+    speed: f32,
+    sensitivity: f32,
+}
+
+impl CameraController {
+    pub fn new(speed: f32, sensitivity: f32) -> Self {
+        Self {
+            amount_left: 0.0,
+            amount_right: 0.0,
+            amount_forward: 0.0,
+            amount_backward: 0.0,
+            amount_up: 0.0,
+            amount_down: 0.0,
+            rotate_horizontal: 0.0,
+            rotate_vertical: 0.0,
+            scroll: 0.0,
+            speed,
+            sensitivity,
+        }
+    }
+
+    pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool {
+        let amount = if state == ElementState::Pressed {
+            1.0
+        } else {
+            0.0
+        };
+        match key {
+            VirtualKeyCode::W | VirtualKeyCode::Up => {
+                self.amount_forward = amount;
+                true
+            }
+            VirtualKeyCode::S | VirtualKeyCode::Down => {
+                self.amount_backward = amount;
+                true
+            }
+            VirtualKeyCode::A | VirtualKeyCode::Left => {
+                self.amount_left = amount;
+                true
+            }
+            VirtualKeyCode::D | VirtualKeyCode::Right => {
+                self.amount_right = amount;
+                true
+            }
+            VirtualKeyCode::Space => {
+                self.amount_up = amount;
+                true
+            }
+            VirtualKeyCode::LShift => {
+                self.amount_down = amount;
+                true
+            }
+            _ => false,
+        }
+    }
+
+    pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) {
+        self.rotate_horizontal = mouse_dx as f32;
+        self.rotate_vertical = mouse_dy as f32;
+    }
+
+    pub fn process_scroll(&mut self, delta: &MouseScrollDelta) {
+        self.scroll = match delta {
+            // I'm assuming a line is about 100 pixels
+            MouseScrollDelta::LineDelta(_, scroll) => -scroll * 0.5,
+            MouseScrollDelta::PixelDelta(PhysicalPosition { y: scroll, .. }) => -*scroll as f32,
+        };
+    }
+
+    pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) {
+        let dt = dt.as_secs_f32();
+
+        // Move forward/backward and left/right
+        let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos();
+        let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize();
+        let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize();
+        camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt;
+        camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt;
+
+        // Move in/out (aka. "zoom")
+        // Note: this isn't an actual zoom. The camera's position
+        // changes when zooming. I've added this to make it easier
+        // to get closer to an object you want to focus on.
+        let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos();
+        let scrollward =
+            Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize();
+        camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt;
+        self.scroll = 0.0;
+
+        // Move up/down. Since we don't use roll, we can just
+        // modify the y coordinate directly.
+        camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt;
+
+        // Rotate
+        camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt;
+        camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt;
+
+        // If process_mouse isn't called every frame, these values
+        // will not get set to zero, and the camera will rotate
+        // when moving in a non cardinal direction.
+        self.rotate_horizontal = 0.0;
+        self.rotate_vertical = 0.0;
+
+        // Keep the camera's angle from going too high/low.
+        if camera.pitch < -Rad(FRAC_PI_2) {
+            camera.pitch = -Rad(FRAC_PI_2);
+        } else if camera.pitch > Rad(FRAC_PI_2) {
+            camera.pitch = Rad(FRAC_PI_2);
+        }
+    }
+}

+ 3 - 0
src/gfx/mod.rs

@@ -0,0 +1,3 @@
+pub mod camera;
+pub mod model;
+pub mod texture;

+ 317 - 0
src/gfx/model.rs

@@ -0,0 +1,317 @@
+use anyhow::*;
+use std::ops::Range;
+use std::path::Path;
+use wgpu::util::DeviceExt;
+
+use crate::gfx::texture;
+
+pub trait Vertex {
+    fn desc<'a>() -> wgpu::VertexBufferLayout<'a>;
+}
+
+#[repr(C)]
+#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
+pub struct ModelVertex {
+    pub position: [f32; 3],
+    pub tex_coords: [f32; 2],
+    pub normal: [f32; 3],
+}
+
+impl Vertex for ModelVertex {
+    fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
+        use std::mem;
+        wgpu::VertexBufferLayout {
+            array_stride: mem::size_of::<ModelVertex>() as wgpu::BufferAddress,
+            step_mode: wgpu::InputStepMode::Vertex,
+            attributes: &[
+                wgpu::VertexAttribute {
+                    offset: 0,
+                    shader_location: 0,
+                    format: wgpu::VertexFormat::Float3,
+                },
+                wgpu::VertexAttribute {
+                    offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
+                    shader_location: 1,
+                    format: wgpu::VertexFormat::Float2,
+                },
+                wgpu::VertexAttribute {
+                    offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress,
+                    shader_location: 2,
+                    format: wgpu::VertexFormat::Float3,
+                },
+            ],
+        }
+    }
+}
+
+pub struct Material {
+    pub name: String,
+    pub diffuse_texture: texture::Texture,
+    pub bind_group: wgpu::BindGroup,
+}
+
+pub struct Mesh {
+    pub name: String,
+    pub vertex_buffer: wgpu::Buffer,
+    pub index_buffer: wgpu::Buffer,
+    pub num_elements: u32,
+    pub material: usize,
+}
+
+pub struct Model {
+    pub meshes: Vec<Mesh>,
+    pub materials: Vec<Material>,
+}
+
+impl Model {
+    pub fn load<P: AsRef<Path>>(
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        layout: &wgpu::BindGroupLayout,
+        path: P,
+    ) -> Result<Self> {
+        let (obj_models, obj_materials) = tobj::load_obj(path.as_ref(), true)?;
+
+        // We're assuming that the texture files are stored with the obj file
+        let containing_folder = path.as_ref().parent().context("Directory has no parent")?;
+
+        let mut materials = Vec::new();
+        for mat in obj_materials {
+            let diffuse_path = mat.diffuse_texture;
+            let diffuse_texture =
+                texture::Texture::load(device, queue, containing_folder.join(diffuse_path))?;
+
+            let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+                layout,
+                entries: &[
+                    wgpu::BindGroupEntry {
+                        binding: 0,
+                        resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
+                    },
+                    wgpu::BindGroupEntry {
+                        binding: 1,
+                        resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
+                    },
+                ],
+                label: None,
+            });
+
+            materials.push(Material {
+                name: mat.name,
+                diffuse_texture,
+                bind_group,
+            });
+        }
+
+        let mut meshes = Vec::new();
+        for m in obj_models {
+            let mut vertices = Vec::new();
+            for i in 0..m.mesh.positions.len() / 3 {
+                vertices.push(ModelVertex {
+                    position: [
+                        m.mesh.positions[i * 3],
+                        m.mesh.positions[i * 3 + 1],
+                        m.mesh.positions[i * 3 + 2],
+                    ],
+                    tex_coords: [1.0 - m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]],
+                    normal: [
+                        m.mesh.normals[i * 3],
+                        m.mesh.normals[i * 3 + 1],
+                        m.mesh.normals[i * 3 + 2],
+                    ],
+                });
+            }
+
+            let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+                label: Some(&format!("{:?} Vertex Buffer", path.as_ref())),
+                contents: bytemuck::cast_slice(&vertices),
+                usage: wgpu::BufferUsage::VERTEX,
+            });
+            let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+                label: Some(&format!("{:?} Index Buffer", path.as_ref())),
+                contents: bytemuck::cast_slice(&m.mesh.indices),
+                usage: wgpu::BufferUsage::INDEX,
+            });
+
+            meshes.push(Mesh {
+                name: m.name,
+                vertex_buffer,
+                index_buffer,
+                num_elements: m.mesh.indices.len() as u32,
+                material: m.mesh.material_id.unwrap_or(0),
+            });
+        }
+
+        Ok(Self { meshes, materials })
+    }
+}
+
+pub trait DrawModel<'a, 'b>
+where
+    'b: 'a,
+{
+    fn draw_mesh(
+        &mut self,
+        mesh: &'b Mesh,
+        material: &'b Material,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+    fn draw_mesh_instanced(
+        &mut self,
+        mesh: &'b Mesh,
+        material: &'b Material,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+
+    fn draw_model(
+        &mut self,
+        model: &'b Model,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+    fn draw_model_instanced(
+        &mut self,
+        model: &'b Model,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+}
+
+impl<'a, 'b> DrawModel<'a, 'b> for wgpu::RenderPass<'a>
+where
+    'b: 'a,
+{
+    fn draw_mesh(
+        &mut self,
+        mesh: &'b Mesh,
+        material: &'b Material,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.draw_mesh_instanced(mesh, material, 0..1, uniforms, light);
+    }
+
+    fn draw_mesh_instanced(
+        &mut self,
+        mesh: &'b Mesh,
+        material: &'b Material,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
+        self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
+        self.set_bind_group(0, &material.bind_group, &[]);
+        self.set_bind_group(1, &uniforms, &[]);
+        self.set_bind_group(2, &light, &[]);
+        self.draw_indexed(0..mesh.num_elements, 0, instances);
+    }
+
+    fn draw_model(
+        &mut self,
+        model: &'b Model,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.draw_model_instanced(model, 0..1, uniforms, light);
+    }
+
+    fn draw_model_instanced(
+        &mut self,
+        model: &'b Model,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        for mesh in &model.meshes {
+            let material = &model.materials[mesh.material];
+            self.draw_mesh_instanced(mesh, material, instances.clone(), uniforms, light);
+        }
+    }
+}
+
+pub trait DrawLight<'a, 'b>
+where
+    'b: 'a,
+{
+    fn draw_light_mesh(
+        &mut self,
+        mesh: &'b Mesh,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+    fn draw_light_mesh_instanced(
+        &mut self,
+        mesh: &'b Mesh,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) where
+        'b: 'a;
+
+    fn draw_light_model(
+        &mut self,
+        model: &'b Model,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+    fn draw_light_model_instanced(
+        &mut self,
+        model: &'b Model,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    );
+}
+
+impl<'a, 'b> DrawLight<'a, 'b> for wgpu::RenderPass<'a>
+where
+    'b: 'a,
+{
+    fn draw_light_mesh(
+        &mut self,
+        mesh: &'b Mesh,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.draw_light_mesh_instanced(mesh, 0..1, uniforms, light);
+    }
+
+    fn draw_light_mesh_instanced(
+        &mut self,
+        mesh: &'b Mesh,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));
+        self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32);
+        self.set_bind_group(0, uniforms, &[]);
+        self.set_bind_group(1, light, &[]);
+        self.draw_indexed(0..mesh.num_elements, 0, instances);
+    }
+
+    fn draw_light_model(
+        &mut self,
+        model: &'b Model,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        self.draw_light_model_instanced(model, 0..1, uniforms, light);
+    }
+    fn draw_light_model_instanced(
+        &mut self,
+        model: &'b Model,
+        instances: Range<u32>,
+        uniforms: &'b wgpu::BindGroup,
+        light: &'b wgpu::BindGroup,
+    ) {
+        for mesh in &model.meshes {
+            self.draw_light_mesh_instanced(mesh, instances.clone(), uniforms, light);
+        }
+    }
+}

+ 135 - 0
src/gfx/texture.rs

@@ -0,0 +1,135 @@
+use anyhow::*;
+use image::GenericImageView;
+use std::path::Path;
+
+pub struct Texture {
+    pub texture: wgpu::Texture,
+    pub view: wgpu::TextureView,
+    pub sampler: wgpu::Sampler,
+}
+
+impl Texture {
+    pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
+
+    pub fn load<P: AsRef<Path>>(
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        path: P,
+    ) -> Result<Self> {
+        // Needed to appease the borrow checker
+        let path_copy = path.as_ref().to_path_buf();
+        let label = path_copy.to_str();
+
+        let img = image::open(path)?;
+        Self::from_image(device, queue, &img, label)
+    }
+
+    pub fn create_depth_texture(
+        device: &wgpu::Device,
+        sc_desc: &wgpu::SwapChainDescriptor,
+        label: &str,
+    ) -> Self {
+        let size = wgpu::Extent3d {
+            width: sc_desc.width,
+            height: sc_desc.height,
+            depth: 1,
+        };
+        let desc = wgpu::TextureDescriptor {
+            label: Some(label),
+            size,
+            mip_level_count: 1,
+            sample_count: 1,
+            dimension: wgpu::TextureDimension::D2,
+            format: Self::DEPTH_FORMAT,
+            usage: wgpu::TextureUsage::RENDER_ATTACHMENT | wgpu::TextureUsage::SAMPLED,
+        };
+        let texture = device.create_texture(&desc);
+        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
+        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
+            address_mode_u: wgpu::AddressMode::ClampToEdge,
+            address_mode_v: wgpu::AddressMode::ClampToEdge,
+            address_mode_w: wgpu::AddressMode::ClampToEdge,
+            mag_filter: wgpu::FilterMode::Linear,
+            min_filter: wgpu::FilterMode::Linear,
+            mipmap_filter: wgpu::FilterMode::Nearest,
+            compare: Some(wgpu::CompareFunction::LessEqual),
+            lod_min_clamp: -100.0,
+            lod_max_clamp: 100.0,
+            ..Default::default()
+        });
+
+        Self {
+            texture,
+            view,
+            sampler,
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn from_bytes(
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        bytes: &[u8],
+        label: &str,
+    ) -> Result<Self> {
+        let img = image::load_from_memory(bytes)?;
+        Self::from_image(device, queue, &img, Some(label))
+    }
+
+    pub fn from_image(
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        img: &image::DynamicImage,
+        label: Option<&str>,
+    ) -> Result<Self> {
+        let dimensions = img.dimensions();
+        let rgba = img.to_rgba8();
+
+        let size = wgpu::Extent3d {
+            width: dimensions.0,
+            height: dimensions.1,
+            depth: 1,
+        };
+        let texture = device.create_texture(&wgpu::TextureDescriptor {
+            label,
+            size,
+            mip_level_count: 1,
+            sample_count: 1,
+            dimension: wgpu::TextureDimension::D2,
+            format: wgpu::TextureFormat::Rgba8UnormSrgb,
+            usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
+        });
+
+        queue.write_texture(
+            wgpu::TextureCopyView {
+                texture: &texture,
+                mip_level: 0,
+                origin: wgpu::Origin3d::ZERO,
+            },
+            &rgba,
+            wgpu::TextureDataLayout {
+                offset: 0,
+                bytes_per_row: 4 * dimensions.0,
+                rows_per_image: dimensions.1,
+            },
+            size,
+        );
+
+        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
+        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
+            address_mode_u: wgpu::AddressMode::ClampToEdge,
+            address_mode_v: wgpu::AddressMode::ClampToEdge,
+            address_mode_w: wgpu::AddressMode::ClampToEdge,
+            mag_filter: wgpu::FilterMode::Linear,
+            min_filter: wgpu::FilterMode::Nearest,
+            mipmap_filter: wgpu::FilterMode::Nearest,
+            ..Default::default()
+        });
+
+        Ok(Self {
+            texture,
+            view,
+            sampler,
+        })
+    }
+}

+ 0 - 1
src/gui/mod.rs

@@ -1,2 +1 @@
 pub mod texture;
-

+ 0 - 1
src/gui/texture.rs

@@ -75,4 +75,3 @@ impl Texture {
         })
     }
 }
-

+ 1 - 0
src/lib.rs

@@ -6,6 +6,7 @@ pub mod async_serial;
 pub mod bls_extensions;
 pub mod endian;
 pub mod error;
+pub mod gfx;
 pub mod gui;
 pub mod net;
 pub mod serial;

+ 9 - 7
src/net/acceptor.rs

@@ -10,8 +10,8 @@ use crate::system::{StoppableTask, StoppableTaskPtr, Subscriber, SubscriberPtr,
 /// Atomic pointer to Acceptor class.
 pub type AcceptorPtr = Arc<Acceptor>;
 
-/// Handles the acceptance of inbound socket connections. Used to start listening on a local
-/// socket address, to accept incoming connections and to handle network errors.
+/// Handles the acceptance of inbound socket connections. Used to start listening on a local socket
+/// address, to accept incoming connections and to handle network errors.
 pub struct Acceptor {
     channel_subscriber: SubscriberPtr<NetResult<ChannelPtr>>,
     task: StoppableTaskPtr,
@@ -25,7 +25,9 @@ impl Acceptor {
             task: StoppableTask::new(),
         })
     }
-    /// Start accepting inbound socket connections.
+    /// Start accepting inbound socket connections. Creates a listener to start listening on a
+    /// local socket address. Then runs an accept loop in a new thread, erroring if a connection
+    /// problem occurs.
     pub fn start(
         self: Arc<Self>,
         accept_addr: SocketAddr,
@@ -38,18 +40,18 @@ impl Acceptor {
 
         Ok(())
     }
-    
+
     /// Stop accepting inbound socket connections.
     pub async fn stop(&self) {
         // Send stop signal
         self.task.stop().await;
     }
-    
+
     /// Start receiving network messages.
     pub async fn subscribe(self: Arc<Self>) -> Subscription<NetResult<ChannelPtr>> {
         self.channel_subscriber.clone().subscribe().await
     }
-    
+
     /// Start listening on a local socket address.
     fn setup(accept_addr: SocketAddr) -> NetResult<Async<TcpListener>> {
         let listener = match Async::<TcpListener>::bind(accept_addr) {
@@ -100,7 +102,7 @@ impl Acceptor {
             }
         }
     }
-    
+
     /// Single attempt to accept an incoming connection. Stops after one attempt.
     async fn tick_accept(&self, listener: &Async<TcpListener>) -> NetResult<ChannelPtr> {
         let (stream, peer_addr) = match listener.accept().await {

+ 12 - 13
src/net/channel.rs

@@ -31,10 +31,7 @@ pub struct Channel {
 
 impl Channel {
     /// Create a new channel.
-    pub async fn new(
-        stream: Async<TcpStream>,
-        address: SocketAddr,
-    ) -> Arc<Self> {
+    pub async fn new(stream: Async<TcpStream>, address: SocketAddr) -> Arc<Self> {
         let (reader, writer) = stream.split();
         let reader = Mutex::new(reader);
         let writer = Mutex::new(writer);
@@ -52,7 +49,7 @@ impl Channel {
             stopped: AtomicBool::new(false),
         })
     }
-    
+
     /// Start the channel.
     pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
         debug!(target: "net", "Channel::start() [START, address={}]", self.address());
@@ -66,7 +63,7 @@ impl Channel {
         );
         debug!(target: "net", "Channel::start() [END, address={}]", self.address());
     }
-    
+
     /// Stop the channel.
     pub async fn stop(&self) {
         debug!(target: "net", "Channel::stop() [START, address={}]", self.address());
@@ -74,7 +71,9 @@ impl Channel {
         self.stopped.store(false, Ordering::Relaxed);
         self.stop_subscriber.notify(NetError::ChannelStopped).await;
         self.receive_task.stop().await;
-        self.message_subsystem.trigger_error(NetError::ChannelStopped).await;
+        self.message_subsystem
+            .trigger_error(NetError::ChannelStopped)
+            .await;
         debug!(target: "net", "Channel::stop() [END, address={}]", self.address());
     }
 
@@ -93,8 +92,8 @@ impl Channel {
         );
         sub
     }
-    
-    /// Send a message across a channel. 
+
+    /// Send a message across a channel.
     pub async fn send<M: messages::Message>(&self, message: M) -> NetResult<()> {
         debug!(target: "net",
             "Channel::send() [START, command={:?}, address={}]",
@@ -121,7 +120,7 @@ impl Channel {
         );
         result
     }
-    
+
     /// Implements send message functionality.
     async fn send_message<M: messages::Message>(&self, message: M) -> error::Result<()> {
         let mut payload = Vec::new();
@@ -150,12 +149,12 @@ impl Channel {
         );
         sub
     }
-    
+
     /// Return the local socket address.
     pub fn address(&self) -> SocketAddr {
         self.address
     }
-    
+
     /// End of file error. Triggered when unexpected end of file occurs.
     fn is_eof_error(err: &error::Error) -> bool {
         match err {
@@ -185,7 +184,7 @@ impl Channel {
             .add_dispatch::<messages::AddrsMessage>()
             .await;
     }
-    
+
     pub fn get_message_subsystem(&self) -> &MessageSubsystem {
         &self.message_subsystem
     }

+ 1 - 1
src/net/connector.rs

@@ -16,7 +16,7 @@ impl Connector {
     pub fn new(settings: SettingsPtr) -> Self {
         Self { settings }
     }
-    
+
     /// Establish an outbound connection.
     pub async fn connect(&self, hostaddr: SocketAddr) -> NetResult<ChannelPtr> {
         futures::select! {

+ 8 - 4
src/net/hosts.rs

@@ -1,8 +1,8 @@
 use async_std::sync::Mutex;
 use rand::seq::SliceRandom;
+use std::collections::HashSet;
 use std::net::SocketAddr;
 use std::sync::Arc;
-use std::collections::HashSet;
 
 /// Pointer to hosts class.
 pub type HostsPtr = Arc<Hosts>;
@@ -19,11 +19,15 @@ impl Hosts {
             addrs: Mutex::new(Vec::new()),
         })
     }
-    
+
     /// Checks if a host address is in the host list.
     async fn contains(&self, addrs: &Vec<SocketAddr>) -> bool {
         let a_set: HashSet<_> = addrs.iter().copied().collect();
-        self.addrs.lock().await.iter().any(|item| a_set.contains(item))
+        self.addrs
+            .lock()
+            .await
+            .iter()
+            .any(|item| a_set.contains(item))
     }
 
     /// Add a new host to the host list.
@@ -32,7 +36,7 @@ impl Hosts {
             self.addrs.lock().await.extend(addrs)
         }
     }
-    
+
     /// Return a single host address.
     pub async fn load_single(&self) -> Option<SocketAddr> {
         self.addrs

+ 6 - 7
src/net/message_subscriber.rs

@@ -18,7 +18,7 @@ pub type MessageSubscriptionID = u64;
 type MessageResult<M> = NetResult<Arc<M>>;
 
 /// Handles message subscriptions through a subscription ID and a receiver channel.
-/// Inherits from Message Dispatcher. 
+/// Inherits from Message Dispatcher.
 pub struct MessageSubscription<M: Message> {
     id: MessageSubscriptionID,
     recv_queue: async_channel::Receiver<MessageResult<M>>,
@@ -43,7 +43,7 @@ impl<M: Message> MessageSubscription<M> {
 }
 
 #[async_trait]
-/// Generic interface for message dispatcher. 
+/// Generic interface for message dispatcher.
 trait MessageDispatcherInterface: Send + Sync {
     async fn trigger(&self, payload: Vec<u8>);
 
@@ -88,7 +88,7 @@ impl<M: Message> MessageDispatcher<M> {
     async fn unsubscribe(&self, sub_id: MessageSubscriptionID) {
         self.subs.lock().await.remove(&sub_id);
     }
-    
+
     /// Send a message to all subscriber channels. Automatically clear inactive channels.
     async fn trigger_all(&self, message: MessageResult<M>) {
         debug!(
@@ -119,7 +119,7 @@ impl<M: Message> MessageDispatcher<M> {
             self.subs.lock().await.len()
         );
     }
-    
+
     /// Remove inactive channels.
     async fn collect_garbage(&self, ids: Vec<MessageSubscriptionID>) {
         let mut subs = self.subs.lock().await;
@@ -147,7 +147,7 @@ impl<M: Message> MessageDispatcherInterface for MessageDispatcher<M> {
             }
         }
     }
-    
+
     /// Sends a message to all subscriber channels. Clears any inactive channels.
     async fn trigger_error(&self, err: NetError) {
         self.trigger_all(Err(err)).await;
@@ -161,7 +161,7 @@ impl<M: Message> MessageDispatcherInterface for MessageDispatcher<M> {
 
 /// Generic publish/subscribe class that can dispatch any kind of message
 /// to a subscribed list of dispatchers. Dispatchers subscribe to a single message format of any
-/// type. This is a generalized version of the pub/sub model in system::Subscriber. 
+/// type. This is a generalized version of the pub/sub model in system::Subscriber.
 pub struct MessageSubsystem {
     dispatchers: Mutex<HashMap<&'static str, Arc<dyn MessageDispatcherInterface>>>,
 }
@@ -304,4 +304,3 @@ mod tests {
         smol::block_on(_do_message_subscriber_test());
     }
 }
-

+ 1 - 1
src/net/messages.rs

@@ -23,7 +23,7 @@ pub struct PongMessage {
     pub nonce: u32,
 }
 
-/// Requests address of outbound connection. 
+/// Requests address of outbound connection.
 pub struct GetAddrsMessage {}
 
 /// Sends address information to inbound connection. Response to GetAddrs message.

+ 1 - 1
src/net/mod.rs

@@ -2,8 +2,8 @@ pub mod acceptor;
 pub mod channel;
 pub mod connector;
 pub mod error;
-pub mod message_subscriber;
 pub mod hosts;
+pub mod message_subscriber;
 pub mod messages;
 pub mod p2p;
 pub mod protocols;

+ 2 - 2
src/net/p2p.rs

@@ -6,9 +6,9 @@ use std::net::SocketAddr;
 use std::sync::Arc;
 
 use crate::net::error::{NetError, NetResult};
+use crate::net::messages::Message;
 use crate::net::sessions::{InboundSession, OutboundSession, SeedSession};
 use crate::net::{Channel, ChannelPtr, Hosts, HostsPtr, Settings, SettingsPtr};
-use crate::net::messages::Message;
 use crate::system::{Subscriber, SubscriberPtr, Subscription};
 
 /// List of channels that are awaiting connection.
@@ -101,7 +101,7 @@ impl P2p {
         self.channels.lock().await.remove(&channel.address());
     }
 
-    /// Check whether a channel is stored in the list of channels.
+    /// Check whether a channel is stored in the list of connected channels.
     pub async fn exists(&self, addr: &SocketAddr) -> bool {
         self.channels.lock().await.contains_key(addr)
     }

+ 15 - 1
src/net/protocols/protocol_address.rs

@@ -8,6 +8,7 @@ use crate::net::messages;
 use crate::net::protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr};
 use crate::net::{ChannelPtr, HostsPtr};
 
+/// Protocol for address and get-address messages.
 pub struct ProtocolAddress {
     channel: ChannelPtr,
 
@@ -20,13 +21,17 @@ pub struct ProtocolAddress {
 }
 
 impl ProtocolAddress {
+    /// Create a new address protocol. Makes an address and get-address subscription and adds them
+    /// to the address protocol instance.
     pub async fn new(channel: ChannelPtr, hosts: HostsPtr) -> Arc<Self> {
+        // Creates a subscription to address message.
         let addrs_sub = channel
             .clone()
             .subscribe_msg::<messages::AddrsMessage>()
             .await
             .expect("Missing addrs dispatcher!");
 
+        // Creates a subscription to get-address message.
         let get_addrs_sub = channel
             .clone()
             .subscribe_msg::<messages::GetAddrsMessage>()
@@ -42,6 +47,8 @@ impl ProtocolAddress {
         })
     }
 
+    /// Starts the address protocol. Runs receive address and get address protocols on the protocol
+    /// task manager. Then sends get-address message.
     pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
         debug!(target: "net", "ProtocolAddress::start() [START]");
         self.jobsman.clone().start(executor.clone());
@@ -54,12 +61,14 @@ impl ProtocolAddress {
             .spawn(self.clone().handle_receive_get_addrs(), executor)
             .await;
 
-        // Send get_address message
+        // Send get_address message.
         let get_addrs = messages::GetAddrsMessage {};
         let _ = self.channel.clone().send(get_addrs).await;
         debug!(target: "net", "ProtocolAddress::start() [END]");
     }
 
+    /// Handles receiving the address message. Loops to continually recieve address messages on the
+    /// address subsciption. Adds the recieved addresses to the list of hosts.
     async fn handle_receive_addrs(self: Arc<Self>) -> NetResult<()> {
         debug!(target: "net", "ProtocolAddress::handle_receive_addrs() [START]");
         loop {
@@ -77,6 +86,8 @@ impl ProtocolAddress {
         }
     }
 
+    /// Handles receiving the get-address message. Continually recieves get-address messages on the
+    /// get-address subsciption. Then replies with an address message.
     async fn handle_receive_get_addrs(self: Arc<Self>) -> NetResult<()> {
         debug!(target: "net", "ProtocolAddress::handle_receive_get_addrs() [START]");
         loop {
@@ -84,13 +95,16 @@ impl ProtocolAddress {
 
             debug!(target: "net", "ProtocolAddress::handle_receive_get_addrs() received GetAddrs message");
 
+            // Loads the list of hosts.
             let addrs = self.hosts.load_all().await;
             debug!(
                 target: "net",
                 "ProtocolAddress::handle_receive_get_addrs() sending {} addrs",
                 addrs.len()
             );
+            // Creates an address messages containing host address.
             let addrs_msg = messages::AddrsMessage { addrs };
+            // Sends the address message across the channel.
             self.channel.clone().send(addrs_msg).await?;
         }
     }

+ 8 - 2
src/net/protocols/protocol_jobs_manager.rs

@@ -8,8 +8,10 @@ use crate::net::error::NetResult;
 use crate::net::ChannelPtr;
 use crate::system::ExecutorPtr;
 
+/// Pointer to protocol jobs manager.
 pub type ProtocolJobsManagerPtr = Arc<ProtocolJobsManager>;
 
+/// Manages the tasks for the network protocol.
 pub struct ProtocolJobsManager {
     name: &'static str,
     channel: ChannelPtr,
@@ -17,6 +19,7 @@ pub struct ProtocolJobsManager {
 }
 
 impl ProtocolJobsManager {
+    /// Create a new protocol jobs manager.
     pub fn new(name: &'static str, channel: ChannelPtr) -> Arc<Self> {
         Arc::new(Self {
             name,
@@ -25,11 +28,12 @@ impl ProtocolJobsManager {
         })
     }
 
+    /// Runs the task on an executor. Prepares to stop all tasks when the channel is closed.
     pub fn start(self: Arc<Self>, executor: ExecutorPtr<'_>) {
         executor.spawn(self.handle_stop()).detach()
     }
 
-    /// Spawns a new task adding it to the internal queue
+    /// Spawns a new task and adds it to the internal queue.
     pub async fn spawn<'a, F>(&self, future: F, executor: ExecutorPtr<'a>)
     where
         F: Future<Output = NetResult<()>> + Send + 'a,
@@ -37,7 +41,8 @@ impl ProtocolJobsManager {
         self.tasks.lock().await.push(executor.spawn(future))
     }
 
-    /// This is run in start(). When the channel closes, we also stop all the tasks
+    /// Waits for a stop signal, then closes all tasks. Insures that all tasks are stopped when a
+    /// channel closes. Called in start().
     async fn handle_stop(self: Arc<Self>) {
         let stop_sub = self.channel.clone().subscribe_stop().await;
 
@@ -48,6 +53,7 @@ impl ProtocolJobsManager {
         self.close_all_tasks().await
     }
 
+    /// Closes all open tasks. Takes all the tasks from the internal queue and closes them.
     async fn close_all_tasks(self: Arc<Self>) {
         debug!(target: "net",
             "ProtocolJobsManager::close_all_tasks() [START, name={}, addr={}]",

+ 18 - 7
src/net/protocols/protocol_ping.rs

@@ -10,6 +10,7 @@ use crate::net::protocols::{ProtocolJobsManager, ProtocolJobsManagerPtr};
 use crate::net::utility::sleep;
 use crate::net::{ChannelPtr, SettingsPtr};
 
+/// Protocol for ping-pong keep-alive messages.
 pub struct ProtocolPing {
     channel: ChannelPtr,
     settings: SettingsPtr,
@@ -18,6 +19,7 @@ pub struct ProtocolPing {
 }
 
 impl ProtocolPing {
+    /// Create a new ping-pong protocol.
     pub fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc<Self> {
         Arc::new(Self {
             channel: channel.clone(),
@@ -26,6 +28,9 @@ impl ProtocolPing {
         })
     }
 
+    /// Starts ping-pong keep-alive messages exchange. Runs ping-pong in the protocol task manager,
+    /// then queues the reply. run_ping_pong() sends out a ping and waits for pong reply.
+    /// reply_to_ping() waits for ping and replies with a pong.
     pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) {
         debug!(target: "net", "ProtocolPing::start() [START]");
         self.jobsman.clone().start(executor.clone());
@@ -40,8 +45,12 @@ impl ProtocolPing {
         debug!(target: "net", "ProtocolPing::start() [END]");
     }
 
+    /// Runs ping-pong protocol. Creates a subscription to pong, then starts a loop. Loop sleeps
+    /// for the duration of the channel heartbeat, then sends a ping message with a random nonce.
+    /// Loop starts a timer, waits for the pong reply and insures the nonce is the same.
     async fn run_ping_pong(self: Arc<Self>) -> NetResult<()> {
         debug!(target: "net", "ProtocolPing::run_ping_pong() [START]");
+        // Creates a subscription to pong message.
         let pong_sub = self
             .channel
             .clone()
@@ -50,20 +59,20 @@ impl ProtocolPing {
             .expect("Missing pong dispatcher!");
 
         loop {
-            // Wait channel_heartbeat amount of time
+            // Wait channel_heartbeat amount of time.
             sleep(self.settings.channel_heartbeat_seconds).await;
 
-            // Create a random nonce
+            // Create a random nonce.
             let nonce = Self::random_nonce();
 
-            // Send ping message
+            // Send ping message.
             let ping = messages::PingMessage { nonce };
             self.channel.clone().send(ping).await?;
             debug!(target: "net", "ProtocolPing::run_ping_pong() send Ping message");
-            // Start the timer for ping timer
+            // Start the timer for ping timer.
             let start = Instant::now();
 
-            // Wait for pong, check nonce matches
+            // Wait for pong, check nonce matches.
             let pong_msg = pong_sub.receive().await?;
             if pong_msg.nonce != nonce {
                 error!("Wrong nonce for ping reply. Disconnecting from channel.");
@@ -75,8 +84,10 @@ impl ProtocolPing {
         }
     }
 
+    /// Waits for ping, then replies with pong. Copies ping's nonce into the pong reply.
     async fn reply_to_ping(self: Arc<Self>) -> NetResult<()> {
         debug!(target: "net", "ProtocolPing::reply_to_ping() [START]");
+        // Creates a subscription to ping message.
         let ping_sub = self
             .channel
             .clone()
@@ -85,11 +96,11 @@ impl ProtocolPing {
             .expect("Missing ping dispatcher!");
 
         loop {
-            // Wait for ping, reply with pong that has a matching nonce
+            // Wait for ping, reply with pong that has a matching nonce.
             let ping = ping_sub.receive().await?;
             debug!(target: "net", "ProtocolPing::reply_to_ping() received Ping message");
 
-            // Send ping message
+            // Send pong message.
             let pong = messages::PongMessage { nonce: ping.nonce };
             self.channel.clone().send(pong).await?;
             debug!(target: "net", "ProtocolPing::reply_to_ping() sent Pong reply");

+ 11 - 3
src/net/protocols/protocol_seed.rs

@@ -6,6 +6,8 @@ use crate::net::error::NetResult;
 use crate::net::messages;
 use crate::net::{ChannelPtr, HostsPtr, SettingsPtr};
 
+/// Seed server protocol. Seed server is used when connecting to the network for the first time.
+/// Returns a list of IP addresses that nodes can connect to.
 pub struct ProtocolSeed {
     channel: ChannelPtr,
     hosts: HostsPtr,
@@ -13,6 +15,7 @@ pub struct ProtocolSeed {
 }
 
 impl ProtocolSeed {
+    /// Create a new seed protocol.
     pub fn new(channel: ChannelPtr, hosts: HostsPtr, settings: SettingsPtr) -> Arc<Self> {
         Arc::new(Self {
             channel,
@@ -21,8 +24,11 @@ impl ProtocolSeed {
         })
     }
 
+    /// Starts the seed protocol. Creates a subscription to the address message, then sends our
+    /// address to the seed server. Sends a get-address message and receives an address message.
     pub async fn start(self: Arc<Self>, _executor: Arc<Executor<'_>>) -> NetResult<()> {
         debug!(target: "net", "ProtocolSeed::start() [START]");
+        // Create a subscription to address message.
         let addr_sub = self
             .channel
             .clone()
@@ -30,14 +36,14 @@ impl ProtocolSeed {
             .await
             .expect("Missing addrs dispatcher!");
 
-        // Send own address to the seed server
+        // Send own address to the seed server.
         self.send_self_address().await?;
 
-        // Send get address message
+        // Send get address message.
         let get_addr = messages::GetAddrsMessage {};
         self.channel.clone().send(get_addr).await?;
 
-        // Receive addresses
+        // Receive addresses.
         let addrs_msg = addr_sub.receive().await?;
         debug!(target: "net", "ProtocolSeed::start() received {} addrs", addrs_msg.addrs.len());
         self.hosts.store(addrs_msg.addrs.clone()).await;
@@ -46,6 +52,8 @@ impl ProtocolSeed {
         Ok(())
     }
 
+    /// Sends own external address over a channel. Imports own external address from settings, then
+    /// adds that address to an address message and sends it out over the channel.
     pub async fn send_self_address(&self) -> NetResult<()> {
         match self.settings.external_addr {
             Some(addr) => {

+ 9 - 4
src/net/protocols/protocol_version.rs

@@ -9,7 +9,7 @@ use crate::net::messages;
 use crate::net::utility::sleep;
 use crate::net::{ChannelPtr, SettingsPtr};
 
-/// Version information sent between nodes at the start of a connection.
+/// Protocol for version information handshake between nodes at the start of a connection.
 pub struct ProtocolVersion {
     channel: ChannelPtr,
     version_sub: MessageSubscription<messages::VersionMessage>,
@@ -18,14 +18,17 @@ pub struct ProtocolVersion {
 }
 
 impl ProtocolVersion {
-    /// Create a new version instance.
+    /// Create a new version protocol. Makes a version and version acknowledgement subscription,
+    /// then adds them to a version protocol instance.
     pub async fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc<Self> {
+        // Creates a version subscription.
         let version_sub = channel
             .clone()
             .subscribe_msg::<messages::VersionMessage>()
             .await
             .expect("Missing version dispatcher!");
 
+        // Creates a version acknowledgement subscription.
         let verack_sub = channel
             .clone()
             .subscribe_msg::<messages::VerackMessage>()
@@ -39,7 +42,8 @@ impl ProtocolVersion {
             settings,
         })
     }
-    /// Start version information exchange.
+    /// Start version information exchange. Start the timer. Send version info and wait for version
+    /// acknowledgement. Wait for version info and send version acknowledgement.
     pub async fn run(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
         debug!(target: "net", "ProtocolVersion::run() [START]");
         // Start timer
@@ -76,9 +80,10 @@ impl ProtocolVersion {
         debug!(target: "net", "ProtocolVersion::send_version() [END]");
         Ok(())
     }
-    /// Recieve version info and send version acknowledgement.
+    /// Recieve version info, check the message is okay and send version acknowledgement.
     async fn recv_version(self: Arc<Self>) -> NetResult<()> {
         debug!(target: "net", "ProtocolVersion::recv_version() [START]");
+        // Rec
         let _version_msg = self.version_sub.receive().await?;
 
         // Check the message is OK

+ 6 - 2
src/net/sessions/inbound_session.rs

@@ -28,7 +28,8 @@ impl InboundSession {
             accept_task: StoppableTask::new(),
         })
     }
-    /// Start the inbound session.
+    /// Starts the inbound session. Begins by accepting connections and fails if the address is not
+    /// configured. Then runs the channel subscription loop.
     pub fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
         match self.p2p().settings().inbound {
             Some(accept_addr) => {
@@ -51,7 +52,7 @@ impl InboundSession {
 
         Ok(())
     }
-    /// Stop the inbound session.
+    /// Stops the inbound session.
     pub async fn stop(&self) {
         self.acceptor.stop().await;
         self.accept_task.stop().await;
@@ -83,6 +84,8 @@ impl InboundSession {
         }
     }
 
+    /// Registers the channel. First performs a network handshake and starts the channel. Then starts
+    /// sending keep-alive and address messages across the channel.
     async fn setup_channel(
         self: Arc<Self>,
         channel: ChannelPtr,
@@ -97,6 +100,7 @@ impl InboundSession {
         self.attach_protocols(channel, executor).await
     }
 
+    /// Starts sending keep-alive and address messages across the channels.
     async fn attach_protocols(
         self: Arc<Self>,
         channel: ChannelPtr,

+ 14 - 9
src/net/sessions/outbound_session.rs

@@ -24,7 +24,7 @@ impl OutboundSession {
             connect_slots: Mutex::new(Vec::new()),
         })
     }
-    /// Start the outbound session.
+    /// Start the outbound session. Runs the channel connect loop.
     pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
         let slots_count = self.p2p().settings().outbound_connections;
         info!("Starting {} outbound connection slots.", slots_count);
@@ -47,7 +47,7 @@ impl OutboundSession {
         Ok(())
     }
 
-    /// Stop the inbound session.
+    /// Stop the outbound session.
     pub async fn stop(&self) {
         let connect_slots = &*self.connect_slots.lock().await;
 
@@ -57,6 +57,9 @@ impl OutboundSession {
     }
 
     /// Start making outbound connections.
+    /// Creates a connector object, then starts a connect loop. Loads a valid address then tries to
+    /// connect. Once connected, registers the channel, removes it from the list of pending
+    /// channels, and starts sending messages across the channel. Otherwise returns a network error.
     pub async fn channel_connect_loop(
         self: Arc<Self>,
         slot_number: u32,
@@ -99,10 +102,10 @@ impl OutboundSession {
         }
     }
 
-    /// Load a valid address that we can connect to.
-    /// Valid means we aren't connecting (pending state) or connected (open channel)
-    /// in another slot, and it isn't our own inbound address.
-    /// Retry otherwise.
+    /// Loops through host addresses to find a outbound address that we can connect to.
+    /// Checks whether address is valid by making sure it isn't our own inbound address,
+    /// then checks whether it is already connected (exists) or connecting (pending).
+    /// Keeps looping until address is found that passes all checks.
     async fn load_address(&self, slot_number: u32) -> NetResult<SocketAddr> {
         let p2p = self.p2p();
         let hosts = p2p.hosts();
@@ -120,7 +123,7 @@ impl OutboundSession {
             }
             let addr = addr.unwrap();
 
-            if Self::addr_is_inbound(&addr, &inbound_addr) {
+            if Self::is_self_inbound(&addr, &inbound_addr) {
                 continue;
             }
 
@@ -136,8 +139,9 @@ impl OutboundSession {
             return Ok(addr);
         }
     }
-    /// Check whether an inbound address is configured.
-    fn addr_is_inbound(addr: &SocketAddr, inbound_addr: &Option<SocketAddr>) -> bool {
+
+    /// Checks whether an address is our own inbound address to avoid connecting to ourselves.
+    fn is_self_inbound(addr: &SocketAddr, inbound_addr: &Option<SocketAddr>) -> bool {
         match inbound_addr {
             Some(inbound_addr) => inbound_addr == addr,
             // No inbound listening address configured
@@ -145,6 +149,7 @@ impl OutboundSession {
         }
     }
 
+    /// Starts sending keep-alive and address messages across the channels.
     async fn attach_protocols(
         self: Arc<Self>,
         channel: ChannelPtr,

+ 5 - 1
src/net/sessions/seed_session.rs

@@ -21,7 +21,8 @@ impl SeedSession {
         Arc::new(Self { p2p })
     }
 
-    /// Start the seed session.
+    /// Start the seed session. Creates a new task for every seed connection and
+    /// starts the seed on each task.
     pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> NetResult<()> {
         debug!(target: "net", "SeedSession::start() [START]");
         let settings = self.p2p().settings();
@@ -69,6 +70,8 @@ impl SeedSession {
         Ok(())
     }
 
+    /// Connects to a seed socket address. Registers a new channel with a network
+    /// handshake, then starts the keep-alive messages and seed protocol.
     async fn start_seed(
         self: Arc<Self>,
         seed_index: usize,
@@ -108,6 +111,7 @@ impl SeedSession {
         }
     }
 
+    /// Starts keep-alive messages and seed protocol.
     async fn attach_protocols(
         self: Arc<Self>,
         channel: ChannelPtr,

+ 7 - 1
src/net/sessions/session.rs

@@ -8,6 +8,7 @@ use crate::net::p2p::P2pPtr;
 use crate::net::protocols::ProtocolVersion;
 use crate::net::ChannelPtr;
 
+/// Removes channel from the list of connected channels when a stop signal is received.
 async fn remove_sub_on_stop(p2p: P2pPtr, channel: ChannelPtr) {
     debug!(target: "net", "remove_sub_on_stop() [START]");
     // Subscribe to stop events
@@ -24,8 +25,10 @@ async fn remove_sub_on_stop(p2p: P2pPtr, channel: ChannelPtr) {
 }
 
 #[async_trait]
+/// Session trait. Defines methods that are used across sessions. Implements registering the channel
+/// and initializing the channel by performing a network handshake.
 pub trait Session: Sync {
-    /// Register a new channel with the session.
+    /// Registers a new channel with the session. Performs a network handshake and starts the channel.
     async fn register_channel(
         self: Arc<Self>,
         channel: ChannelPtr,
@@ -46,6 +49,8 @@ pub trait Session: Sync {
         Ok(())
     }
 
+    /// Performs network handshake to initialize channel. Adds the channel to the list of connected
+    /// channels, and prepares to remove the channel when a stop signal is received.
     async fn perform_handshake_protocols(
         &self,
         protocol_version: Arc<ProtocolVersion>,
@@ -69,5 +74,6 @@ pub trait Session: Sync {
         Ok(())
     }
 
+    /// Returns a pointer to the p2p network interface.
     fn p2p(&self) -> P2pPtr;
 }

+ 0 - 1
src/net/settings.rs

@@ -35,4 +35,3 @@ impl Default for Settings {
         }
     }
 }
-

+ 11 - 5
src/old/mimc.rs

@@ -11,8 +11,8 @@ use sapvi::bls_extensions::BlsStringConversion;
 use ff::{Field, PrimeField};
 
 // mimc constants
-mod mimc_constants;
-use mimc_constants::mimc_constants;
+//mod mimc_constants;
+//use mimc_constants::mimc_constants;
 
 // We're going to use the BLS12-381 pairing-friendly elliptic curve.
 use bls12_381::{Bls12, Scalar};
@@ -109,7 +109,7 @@ impl<'a, Scalar: PrimeField> Circuit<Scalar> for MiMCDemo<'a, Scalar> {
                 e.add_assign(&self.constants[i]);
                 e.square()
             });
-            
+
             // println!("tmp_value {:?} {:?}", self.constants[i], tmp_value);
 
             let tmp = cs.alloc(
@@ -181,6 +181,7 @@ fn main() {
     //     .collect::<Vec<_>>();
 
     let mut constants = Vec::new();
+    /*
     for const_str in mimc_constants() {
         let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
         assert_eq!(bytes.len(), 32);
@@ -188,6 +189,7 @@ fn main() {
 
         constants.push(constant);
     }
+    */
 
     println!("Creating parameters...");
 
@@ -220,8 +222,12 @@ fn main() {
         // Generate a random preimage and compute the image
         // let xl = Scalar::random(&mut OsRng);
         // let xr = Scalar::random(&mut OsRng);
-        let xl = bls12_381::Scalar::from_string("15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e");
-        let xr = bls12_381::Scalar::from_string("015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891");
+        let xl = bls12_381::Scalar::from_string(
+            "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e",
+        );
+        let xr = bls12_381::Scalar::from_string(
+            "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891",
+        );
         let image = mimc(xl, xr, &constants);
 
         proof_vec.truncate(0);