diff --git a/assets/models/cornell_box.mtl b/assets/models/cornell_box.mtl deleted file mode 100644 index d3a1c7a..0000000 --- a/assets/models/cornell_box.mtl +++ /dev/null @@ -1,24 +0,0 @@ -newmtl white -Ka 0 0 0 -Kd 1 1 1 -Ks 0 0 0 - -newmtl red -Ka 0 0 0 -Kd 1 0 0 -Ks 0 0 0 - -newmtl green -Ka 0 0 0 -Kd 0 1 0 -Ks 0 0 0 - -newmtl blue -Ka 0 0 0 -Kd 0 0 1 -Ks 0 0 0 - -newmtl light -Ka 20 20 20 -Kd 1 1 1 -Ks 0 0 0 diff --git a/assets/models/cornell_box.obj b/assets/models/cornell_box.obj deleted file mode 100644 index 43e021f..0000000 --- a/assets/models/cornell_box.obj +++ /dev/null @@ -1,145 +0,0 @@ -# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project. -# original cornell box data - # comment - -# empty line including some space - - -mtllib cornell_box.mtl - -o floor -usemtl white -v 552.8 0.0 0.0 -v 0.0 0.0 0.0 -v 0.0 0.0 559.2 -v 549.6 0.0 559.2 - -v 130.0 0.0 65.0 -v 82.0 0.0 225.0 -v 240.0 0.0 272.0 -v 290.0 0.0 114.0 - -v 423.0 0.0 247.0 -v 265.0 0.0 296.0 -v 314.0 0.0 456.0 -v 472.0 0.0 406.0 - -f 1 2 3 4 -f 8 7 6 5 -f 12 11 10 9 - -o light -usemtl light -v 343.0 548.0 227.0 -v 343.0 548.0 332.0 -v 213.0 548.0 332.0 -v 213.0 548.0 227.0 -f -4 -3 -2 -1 - -o ceiling -usemtl white -v 556.0 548.8 0.0 -v 556.0 548.8 559.2 -v 0.0 548.8 559.2 -v 0.0 548.8 0.0 -f -4 -3 -2 -1 - -o back_wall -usemtl white -v 549.6 0.0 559.2 -v 0.0 0.0 559.2 -v 0.0 548.8 559.2 -v 556.0 548.8 559.2 -f -4 -3 -2 -1 - -o front_wall -usemtl blue -v 549.6 0.0 0 -v 0.0 0.0 0 -v 0.0 548.8 0 -v 556.0 548.8 0 -#f -1 -2 -3 -4 - -o green_wall -usemtl green -v 0.0 0.0 559.2 -v 0.0 0.0 0.0 -v 0.0 548.8 0.0 -v 0.0 548.8 559.2 -f -4 -3 -2 -1 - -o red_wall -usemtl red -v 552.8 0.0 0.0 -v 549.6 0.0 559.2 -v 556.0 548.8 559.2 -v 556.0 548.8 0.0 -f -4 -3 -2 -1 - -o short_block -usemtl white - -v 130.0 165.0 65.0 -v 82.0 165.0 225.0 -v 240.0 165.0 272.0 -v 290.0 165.0 114.0 -f -4 -3 -2 -1 - -v 290.0 0.0 114.0 -v 290.0 165.0 114.0 -v 240.0 165.0 272.0 -v 240.0 0.0 272.0 -f -4 -3 -2 -1 - -v 130.0 0.0 65.0 -v 130.0 165.0 65.0 -v 290.0 165.0 114.0 -v 290.0 0.0 114.0 -f -4 -3 -2 -1 - -v 82.0 0.0 225.0 -v 82.0 165.0 225.0 -v 130.0 165.0 65.0 -v 130.0 0.0 65.0 -f -4 -3 -2 -1 - -v 240.0 0.0 272.0 -v 240.0 165.0 272.0 -v 82.0 165.0 225.0 -v 82.0 0.0 225.0 -f -4 -3 -2 -1 - -o tall_block -usemtl white - -v 423.0 330.0 247.0 -v 265.0 330.0 296.0 -v 314.0 330.0 456.0 -v 472.0 330.0 406.0 -f -4 -3 -2 -1 - -usemtl white -v 423.0 0.0 247.0 -v 423.0 330.0 247.0 -v 472.0 330.0 406.0 -v 472.0 0.0 406.0 -f -4 -3 -2 -1 - -v 472.0 0.0 406.0 -v 472.0 330.0 406.0 -v 314.0 330.0 456.0 -v 314.0 0.0 456.0 -f -4 -3 -2 -1 - -v 314.0 0.0 456.0 -v 314.0 330.0 456.0 -v 265.0 330.0 296.0 -v 265.0 0.0 296.0 -f -4 -3 -2 -1 - -v 265.0 0.0 296.0 -v 265.0 330.0 296.0 -v 423.0 330.0 247.0 -v 423.0 0.0 247.0 -f -4 -3 -2 -1 - diff --git a/assets/models/tescoPiwo.mtl b/assets/models/tescoPiwo.mtl new file mode 100644 index 0000000..1c58cf2 --- /dev/null +++ b/assets/models/tescoPiwo.mtl @@ -0,0 +1,13 @@ +# Blender 4.2.0 MTL File: 'tescoPiwo.blend' +# www.blender.org + +newmtl Material.001 +Ns 360.000000 +Ka 0.500000 0.500000 0.500000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.500000 +d 1.000000 +illum 3 +map_Kd tescoPiwoTexture.png +map_Bump -bm 1.000000 /home/przmk/Downloads/Downloads/tescoPiwoNormal.png diff --git a/assets/models/tescoPiwo.obj b/assets/models/tescoPiwo.obj new file mode 100644 index 0000000..92a9452 --- /dev/null +++ b/assets/models/tescoPiwo.obj @@ -0,0 +1,1751 @@ +# Blender 4.2.0 +# www.blender.org +mtllib tescoPiwo.mtl +o Piwo +v -0.000000 0.044375 0.230400 +v -0.000000 1.086295 0.230400 +v -0.044949 0.044375 0.225973 +v -0.044949 1.086295 0.225973 +v -0.088170 0.044375 0.212862 +v -0.088170 1.086295 0.212862 +v -0.128003 0.044375 0.191571 +v -0.128003 1.086295 0.191571 +v -0.162917 0.044375 0.162917 +v -0.162917 1.086295 0.162917 +v -0.191571 0.044375 0.128003 +v -0.191571 1.086295 0.128003 +v -0.212862 0.044375 0.088170 +v -0.212862 1.086295 0.088170 +v -0.225973 0.044375 0.044949 +v -0.225973 1.086295 0.044949 +v -0.230400 0.044375 -0.000000 +v -0.230400 1.086295 -0.000000 +v -0.225973 0.044375 -0.044949 +v -0.225973 1.086295 -0.044949 +v -0.212862 0.044375 -0.088170 +v -0.212862 1.086295 -0.088170 +v -0.191571 0.044375 -0.128003 +v -0.191571 1.086295 -0.128003 +v -0.162917 0.044375 -0.162917 +v -0.162917 1.086295 -0.162917 +v -0.128003 0.044375 -0.191571 +v -0.128003 1.086295 -0.191571 +v -0.088170 0.044375 -0.212862 +v -0.088170 1.086295 -0.212862 +v -0.044949 0.044375 -0.225973 +v -0.044949 1.086295 -0.225973 +v 0.000000 0.044375 -0.230400 +v 0.000000 1.086295 -0.230400 +v 0.044949 0.044375 -0.225973 +v 0.044949 1.086295 -0.225973 +v 0.088170 0.044375 -0.212862 +v 0.088170 1.086295 -0.212862 +v 0.128003 0.044375 -0.191571 +v 0.128003 1.086295 -0.191571 +v 0.162917 0.044375 -0.162917 +v 0.162917 1.086295 -0.162917 +v 0.191571 0.044375 -0.128003 +v 0.191571 1.086295 -0.128003 +v 0.212862 0.044375 -0.088170 +v 0.212862 1.086295 -0.088170 +v 0.225973 0.044375 -0.044949 +v 0.225973 1.086295 -0.044949 +v 0.230400 0.044375 -0.000000 +v 0.230400 1.086295 -0.000000 +v 0.225973 0.044375 0.044949 +v 0.225973 1.086295 0.044949 +v 0.212862 0.044375 0.088170 +v 0.212862 1.086295 0.088170 +v 0.191571 0.044375 0.128003 +v 0.191571 1.086295 0.128003 +v 0.162917 0.044375 0.162917 +v 0.162917 1.086295 0.162917 +v 0.128003 0.044375 0.191571 +v 0.128003 1.086295 0.191571 +v 0.088170 0.044375 0.212862 +v 0.088170 1.086295 0.212862 +v 0.044949 0.044375 0.225973 +v 0.044949 1.086295 0.225973 +v -0.038174 1.185086 0.191913 +v -0.000000 1.185086 0.195673 +v -0.074881 1.185086 0.180778 +v -0.108710 1.185086 0.162696 +v -0.138361 1.185086 0.138361 +v -0.162696 1.185086 0.108710 +v -0.180778 1.185086 0.074881 +v -0.191913 1.185086 0.038174 +v -0.195673 1.185086 -0.000000 +v -0.191913 1.185086 -0.038174 +v -0.180778 1.185086 -0.074881 +v -0.162696 1.185086 -0.108710 +v -0.138361 1.185086 -0.138361 +v -0.108710 1.185086 -0.162696 +v -0.074881 1.185086 -0.180778 +v -0.038174 1.185086 -0.191913 +v 0.000000 1.185086 -0.195673 +v 0.038174 1.185086 -0.191913 +v 0.074881 1.185086 -0.180778 +v 0.108710 1.185086 -0.162696 +v 0.138361 1.185086 -0.138361 +v 0.162696 1.185086 -0.108710 +v 0.180778 1.185086 -0.074881 +v 0.191913 1.185086 -0.038174 +v 0.195673 1.185086 -0.000000 +v 0.191913 1.185086 0.038174 +v 0.180778 1.185086 0.074881 +v 0.162696 1.185086 0.108710 +v 0.138361 1.185086 0.138361 +v 0.108710 1.185086 0.162696 +v 0.074881 1.185086 0.180778 +v 0.038174 1.185086 0.191913 +v -0.037345 1.211296 0.187747 +v -0.000000 1.211296 0.191425 +v -0.073255 1.211296 0.176854 +v -0.106350 1.211296 0.159164 +v -0.135358 1.211296 0.135358 +v -0.159164 1.211296 0.106350 +v -0.176854 1.211296 0.073255 +v -0.187747 1.211296 0.037345 +v -0.191425 1.211296 -0.000000 +v -0.187747 1.211296 -0.037345 +v -0.176854 1.211296 -0.073255 +v -0.159164 1.211296 -0.106350 +v -0.135358 1.211296 -0.135358 +v -0.106350 1.211296 -0.159164 +v -0.073255 1.211296 -0.176854 +v -0.037345 1.211296 -0.187747 +v 0.000000 1.211296 -0.191425 +v 0.037345 1.211296 -0.187747 +v 0.073255 1.211296 -0.176854 +v 0.106350 1.211296 -0.159164 +v 0.135358 1.211296 -0.135358 +v 0.159164 1.211296 -0.106350 +v 0.176854 1.211296 -0.073255 +v 0.187747 1.211296 -0.037345 +v 0.191425 1.211296 -0.000000 +v 0.187747 1.211296 0.037345 +v 0.176854 1.211296 0.073255 +v 0.159164 1.211296 0.106350 +v 0.135358 1.211296 0.135358 +v 0.106350 1.211296 0.159164 +v 0.073255 1.211296 0.176854 +v 0.037345 1.211296 0.187747 +v 0.185004 1.204968 0.076631 +v 0.185004 1.191414 0.076631 +v 0.166499 1.191414 0.111251 +v 0.166499 1.204968 0.111251 +v -0.111251 1.204968 -0.166499 +v -0.111251 1.191414 -0.166499 +v -0.076631 1.191414 -0.185004 +v -0.076631 1.204968 -0.185004 +v -0.000000 1.204968 0.200246 +v -0.000000 1.191414 0.200246 +v -0.039066 1.191414 0.196399 +v -0.039066 1.204968 0.196399 +v 0.141596 1.191414 0.141596 +v 0.141596 1.204968 0.141596 +v -0.039066 1.191414 -0.196399 +v -0.039066 1.204968 -0.196399 +v -0.076631 1.191414 0.185004 +v -0.076631 1.204968 0.185004 +v 0.111251 1.191414 0.166499 +v 0.111251 1.204968 0.166499 +v 0.000000 1.191414 -0.200246 +v 0.000000 1.204968 -0.200246 +v -0.111251 1.191414 0.166499 +v -0.111251 1.204968 0.166499 +v 0.076631 1.191414 0.185004 +v 0.076631 1.204968 0.185004 +v 0.039066 1.191414 -0.196399 +v 0.039066 1.204968 -0.196399 +v -0.141596 1.191414 0.141596 +v -0.141596 1.204968 0.141596 +v 0.039066 1.191414 0.196399 +v 0.039066 1.204968 0.196399 +v 0.076631 1.191414 -0.185004 +v 0.076631 1.204968 -0.185004 +v -0.166499 1.191414 0.111251 +v -0.166499 1.204968 0.111251 +v 0.111251 1.191414 -0.166499 +v 0.111251 1.204968 -0.166499 +v -0.185004 1.191414 0.076631 +v -0.185004 1.204968 0.076631 +v 0.141596 1.191414 -0.141596 +v 0.141596 1.204968 -0.141596 +v -0.196399 1.191414 0.039066 +v -0.196399 1.204968 0.039066 +v 0.166499 1.191414 -0.111251 +v 0.166499 1.204968 -0.111251 +v -0.200246 1.191414 -0.000000 +v -0.200246 1.204968 -0.000000 +v 0.185004 1.191414 -0.076631 +v 0.185004 1.204968 -0.076631 +v -0.196399 1.191414 -0.039066 +v -0.196399 1.204968 -0.039066 +v 0.196399 1.191414 -0.039066 +v 0.196399 1.204968 -0.039066 +v -0.185004 1.191414 -0.076631 +v -0.185004 1.204968 -0.076631 +v 0.200246 1.191414 -0.000000 +v 0.200246 1.204968 -0.000000 +v -0.166499 1.191414 -0.111251 +v -0.166499 1.204968 -0.111251 +v 0.196399 1.191414 0.039066 +v 0.196399 1.204968 0.039066 +v -0.141596 1.191414 -0.141596 +v -0.141596 1.204968 -0.141596 +v -0.038174 1.211296 0.191913 +v -0.000000 1.211296 0.195673 +v -0.074881 1.211296 0.180778 +v -0.108710 1.211296 0.162696 +v -0.138361 1.211296 0.138361 +v -0.162696 1.211296 0.108710 +v -0.180778 1.211296 0.074881 +v -0.191913 1.211296 0.038174 +v -0.195673 1.211296 -0.000000 +v -0.191913 1.211296 -0.038174 +v -0.180778 1.211296 -0.074881 +v -0.162696 1.211296 -0.108710 +v -0.138361 1.211296 -0.138361 +v -0.108710 1.211296 -0.162696 +v -0.074881 1.211296 -0.180778 +v -0.038174 1.211296 -0.191913 +v 0.000000 1.211296 -0.195673 +v 0.038174 1.211296 -0.191913 +v 0.074881 1.211296 -0.180778 +v 0.108710 1.211296 -0.162696 +v 0.138361 1.211296 -0.138361 +v 0.162696 1.211296 -0.108710 +v 0.180778 1.211296 -0.074881 +v 0.191913 1.211296 -0.038174 +v 0.195673 1.211296 -0.000000 +v 0.191913 1.211296 0.038174 +v 0.180778 1.211296 0.074881 +v 0.162696 1.211296 0.108710 +v 0.138361 1.211296 0.138361 +v 0.108710 1.211296 0.162696 +v 0.074881 1.211296 0.180778 +v 0.038174 1.211296 0.191913 +v -0.037345 1.182776 0.187747 +v 0.000000 1.182776 0.191425 +v -0.073255 1.182776 0.176854 +v -0.106350 1.182776 0.159164 +v -0.135358 1.182776 0.135358 +v -0.159164 1.182776 0.106350 +v -0.176854 1.182776 0.073255 +v -0.187747 1.182776 0.037345 +v -0.191425 1.182776 -0.000000 +v -0.187747 1.182776 -0.037345 +v -0.176854 1.182776 -0.073255 +v -0.159164 1.182776 -0.106350 +v -0.135358 1.182776 -0.135358 +v -0.106350 1.182776 -0.159164 +v -0.073255 1.182776 -0.176854 +v -0.037345 1.182776 -0.187747 +v 0.000000 1.182776 -0.191425 +v 0.037345 1.182776 -0.187747 +v 0.073255 1.182776 -0.176854 +v 0.106350 1.182776 -0.159164 +v 0.135358 1.182776 -0.135358 +v 0.159164 1.182776 -0.106350 +v 0.176854 1.182776 -0.073255 +v 0.187747 1.182776 -0.037345 +v 0.191425 1.182776 -0.000000 +v 0.187747 1.182776 0.037345 +v 0.176854 1.182776 0.073255 +v 0.159164 1.182776 0.106350 +v 0.135358 1.182776 0.135358 +v 0.106350 1.182776 0.159164 +v 0.073255 1.182776 0.176854 +v 0.037345 1.182776 0.187747 +v -0.000000 0.002513 0.202216 +v -0.039450 0.002513 0.198330 +v -0.077385 0.002513 0.186823 +v -0.112345 0.002513 0.168136 +v -0.142988 0.002513 0.142988 +v -0.168136 0.002513 0.112345 +v -0.186823 0.002513 0.077385 +v -0.198330 0.002513 0.039450 +v -0.202216 0.002513 -0.000000 +v -0.198330 0.002513 -0.039450 +v -0.186823 0.002513 -0.077385 +v -0.168136 0.002513 -0.112345 +v -0.142988 0.002513 -0.142988 +v -0.112345 0.002513 -0.168136 +v -0.077385 0.002513 -0.186823 +v -0.039450 0.002513 -0.198330 +v 0.000000 0.002513 -0.202216 +v 0.039450 0.002513 -0.198330 +v 0.077385 0.002513 -0.186823 +v 0.112345 0.002513 -0.168136 +v 0.142988 0.002513 -0.142988 +v 0.168136 0.002513 -0.112345 +v 0.186823 0.002513 -0.077385 +v 0.198330 0.002513 -0.039450 +v 0.202216 0.002513 -0.000000 +v 0.198330 0.002513 0.039450 +v 0.186823 0.002513 0.077385 +v 0.168136 0.002513 0.112345 +v 0.142988 0.002513 0.142988 +v 0.112345 0.002513 0.168136 +v 0.077385 0.002513 0.186823 +v 0.039450 0.002513 0.198330 +v -0.000000 -0.009869 0.197613 +v -0.038552 -0.009869 0.193816 +v -0.075623 -0.009869 0.182570 +v -0.109788 -0.009869 0.164309 +v -0.139733 -0.009869 0.139733 +v -0.164309 -0.009869 0.109788 +v -0.182570 -0.009869 0.075623 +v -0.193816 -0.009869 0.038552 +v -0.197613 -0.009869 -0.000000 +v -0.193816 -0.009869 -0.038552 +v -0.182570 -0.009869 -0.075623 +v -0.164309 -0.009869 -0.109788 +v -0.139733 -0.009869 -0.139733 +v -0.109788 -0.009869 -0.164309 +v -0.075623 -0.009869 -0.182570 +v -0.038552 -0.009869 -0.193816 +v 0.000000 -0.009869 -0.197613 +v 0.038552 -0.009869 -0.193816 +v 0.075623 -0.009869 -0.182570 +v 0.109788 -0.009869 -0.164309 +v 0.139733 -0.009869 -0.139733 +v 0.164309 -0.009869 -0.109788 +v 0.182570 -0.009869 -0.075623 +v 0.193816 -0.009869 -0.038552 +v 0.197613 -0.009869 -0.000000 +v 0.193816 -0.009869 0.038552 +v 0.182570 -0.009869 0.075623 +v 0.164309 -0.009869 0.109788 +v 0.139733 -0.009869 0.139733 +v 0.109788 -0.009869 0.164309 +v 0.075623 -0.009869 0.182570 +v 0.038552 -0.009869 0.193816 +v 0.188661 -0.006239 -0.078146 +v 0.188661 -0.001118 -0.078146 +v 0.169791 -0.001118 -0.113451 +v 0.169791 -0.006239 -0.113451 +v -0.200282 -0.006239 -0.039839 +v -0.200282 -0.001118 -0.039839 +v -0.204206 -0.001118 -0.000000 +v -0.204206 -0.006239 -0.000000 +v 0.200282 -0.006239 -0.039839 +v 0.200282 -0.001118 -0.039839 +v -0.188661 -0.006239 -0.078146 +v -0.188661 -0.001118 -0.078146 +v 0.204206 -0.006239 -0.000000 +v 0.204206 -0.001118 -0.000000 +v -0.169791 -0.006239 -0.113451 +v -0.169791 -0.001118 -0.113451 +v 0.200282 -0.006239 0.039839 +v 0.200282 -0.001118 0.039839 +v -0.144395 -0.006239 -0.144395 +v -0.144395 -0.001118 -0.144395 +v 0.188661 -0.006239 0.078146 +v 0.188661 -0.001118 0.078146 +v -0.113451 -0.006239 -0.169791 +v -0.113451 -0.001118 -0.169791 +v 0.169791 -0.006239 0.113451 +v 0.169791 -0.001118 0.113451 +v -0.078146 -0.006239 -0.188661 +v -0.078146 -0.001118 -0.188661 +v -0.039839 -0.006239 0.200282 +v -0.039839 -0.001118 0.200282 +v -0.000000 -0.001118 0.204206 +v -0.000000 -0.006239 0.204206 +v 0.144395 -0.006239 0.144395 +v 0.144395 -0.001118 0.144395 +v -0.039839 -0.006239 -0.200282 +v -0.039839 -0.001118 -0.200282 +v -0.078146 -0.006239 0.188661 +v -0.078146 -0.001118 0.188661 +v 0.113451 -0.006239 0.169791 +v 0.113451 -0.001118 0.169791 +v 0.000000 -0.006239 -0.204206 +v 0.000000 -0.001118 -0.204206 +v -0.113451 -0.006239 0.169791 +v -0.113451 -0.001118 0.169791 +v 0.078146 -0.006239 0.188661 +v 0.078146 -0.001118 0.188661 +v 0.039839 -0.006239 -0.200282 +v 0.039839 -0.001118 -0.200282 +v -0.144395 -0.006239 0.144395 +v -0.144395 -0.001118 0.144395 +v 0.039839 -0.006239 0.200282 +v 0.039839 -0.001118 0.200282 +v 0.078146 -0.006239 -0.188661 +v 0.078146 -0.001118 -0.188661 +v -0.169791 -0.006239 0.113451 +v -0.169791 -0.001118 0.113451 +v 0.113451 -0.006239 -0.169791 +v 0.113451 -0.001118 -0.169791 +v -0.188661 -0.006239 0.078146 +v -0.188661 -0.001118 0.078146 +v 0.144395 -0.006239 -0.144395 +v 0.144395 -0.001118 -0.144395 +v -0.200282 -0.006239 0.039839 +v -0.200282 -0.001118 0.039839 +v -0.000000 -0.009869 0.202216 +v -0.039450 -0.009869 0.198330 +v -0.077385 -0.009869 0.186823 +v -0.112345 -0.009869 0.168136 +v -0.142988 -0.009869 0.142988 +v -0.168136 -0.009869 0.112345 +v -0.186823 -0.009869 0.077385 +v -0.198330 -0.009869 0.039450 +v -0.202216 -0.009869 -0.000000 +v -0.198330 -0.009869 -0.039450 +v -0.186823 -0.009869 -0.077385 +v -0.168136 -0.009869 -0.112345 +v -0.142988 -0.009869 -0.142988 +v -0.112345 -0.009869 -0.168136 +v -0.077385 -0.009869 -0.186823 +v -0.039450 -0.009869 -0.198330 +v 0.000000 -0.009869 -0.202216 +v 0.039450 -0.009869 -0.198330 +v 0.077385 -0.009869 -0.186823 +v 0.112345 -0.009869 -0.168136 +v 0.142988 -0.009869 -0.142988 +v 0.168136 -0.009869 -0.112345 +v 0.186823 -0.009869 -0.077385 +v 0.198330 -0.009869 -0.039450 +v 0.202216 -0.009869 -0.000000 +v 0.198330 -0.009869 0.039450 +v 0.186823 -0.009869 0.077385 +v 0.168136 -0.009869 0.112345 +v 0.142988 -0.009869 0.142988 +v 0.112345 -0.009869 0.168136 +v 0.077385 -0.009869 0.186823 +v 0.039450 -0.009869 0.198330 +v -0.000000 0.012240 0.183178 +v -0.035736 0.012240 0.179658 +v -0.070099 0.012240 0.169234 +v -0.101768 0.012240 0.152307 +v -0.129526 0.012240 0.129526 +v -0.152307 0.012240 0.101768 +v -0.169234 0.012240 0.070099 +v -0.179658 0.012240 0.035736 +v -0.183178 0.012240 -0.000000 +v -0.179658 0.012240 -0.035736 +v -0.169234 0.012240 -0.070099 +v -0.152307 0.012240 -0.101768 +v -0.129526 0.012240 -0.129526 +v -0.101768 0.012240 -0.152307 +v -0.070099 0.012240 -0.169234 +v -0.035736 0.012240 -0.179658 +v 0.000000 0.012240 -0.183178 +v 0.035736 0.012240 -0.179658 +v 0.070099 0.012240 -0.169234 +v 0.101768 0.012240 -0.152307 +v 0.129526 0.012240 -0.129526 +v 0.152307 0.012240 -0.101768 +v 0.169234 0.012240 -0.070099 +v 0.179658 0.012240 -0.035736 +v 0.183178 0.012240 -0.000000 +v 0.179658 0.012240 0.035736 +v 0.169234 0.012240 0.070099 +v 0.152307 0.012240 0.101768 +v 0.129526 0.012240 0.129526 +v 0.101768 0.012240 0.152307 +v 0.070099 0.012240 0.169234 +v 0.035736 0.012240 0.179658 +v -0.037345 1.194055 0.187747 +v -0.000000 1.194055 0.191425 +v -0.073255 1.194055 0.176854 +v -0.106350 1.194055 0.159164 +v -0.135358 1.194055 0.135358 +v -0.159164 1.194055 0.106350 +v -0.176854 1.194055 0.073255 +v -0.187747 1.194055 0.037345 +v -0.191425 1.194055 -0.000000 +v -0.187747 1.194055 -0.037345 +v -0.176854 1.194055 -0.073255 +v -0.159164 1.194055 -0.106350 +v -0.135358 1.194055 -0.135358 +v -0.106350 1.194055 -0.159164 +v -0.073255 1.194055 -0.176854 +v -0.037345 1.194055 -0.187747 +v 0.000000 1.194055 -0.191425 +v 0.037345 1.194055 -0.187747 +v 0.073255 1.194055 -0.176854 +v 0.106350 1.194055 -0.159164 +v 0.135358 1.194055 -0.135358 +v 0.159164 1.194055 -0.106350 +v 0.176854 1.194055 -0.073255 +v 0.187747 1.194055 -0.037345 +v 0.191425 1.194055 -0.000000 +v 0.187747 1.194055 0.037345 +v 0.176854 1.194055 0.073255 +v 0.159164 1.194055 0.106350 +v 0.135358 1.194055 0.135358 +v 0.106350 1.194055 0.159164 +v 0.073255 1.194055 0.176854 +v 0.037345 1.194055 0.187747 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 0.1665 0.9860 +vn -0.1924 0.1665 0.9671 +vn -0.1951 -0.0000 0.9808 +vn -0.3773 0.1665 0.9110 +vn -0.3827 -0.0000 0.9239 +vn -0.5478 0.1665 0.8199 +vn -0.5556 -0.0000 0.8315 +vn -0.6972 0.1665 0.6972 +vn -0.7071 -0.0000 0.7071 +vn -0.8199 0.1665 0.5478 +vn -0.8315 -0.0000 0.5556 +vn -0.9110 0.1665 0.3773 +vn -0.9239 -0.0000 0.3827 +vn -0.9671 0.1665 0.1924 +vn -0.9808 -0.0000 0.1951 +vn -0.9860 0.1665 -0.0000 +vn -1.0000 -0.0000 -0.0000 +vn -0.9671 0.1665 -0.1924 +vn -0.9808 -0.0000 -0.1951 +vn -0.9110 0.1665 -0.3773 +vn -0.9239 -0.0000 -0.3827 +vn -0.8199 0.1665 -0.5478 +vn -0.8315 -0.0000 -0.5556 +vn -0.6972 0.1665 -0.6972 +vn -0.7071 -0.0000 -0.7071 +vn -0.5478 0.1665 -0.8199 +vn -0.5556 -0.0000 -0.8315 +vn -0.3773 0.1665 -0.9110 +vn -0.3827 -0.0000 -0.9239 +vn -0.1924 0.1665 -0.9671 +vn -0.1951 -0.0000 -0.9808 +vn -0.0000 0.1665 -0.9860 +vn -0.0000 -0.0000 -1.0000 +vn 0.1924 0.1665 -0.9671 +vn 0.1951 -0.0000 -0.9808 +vn 0.3773 0.1665 -0.9110 +vn 0.3827 -0.0000 -0.9239 +vn 0.5478 0.1665 -0.8199 +vn 0.5556 -0.0000 -0.8315 +vn 0.6972 0.1665 -0.6972 +vn 0.7071 -0.0000 -0.7071 +vn 0.8199 0.1665 -0.5478 +vn 0.8315 -0.0000 -0.5556 +vn 0.9110 0.1665 -0.3773 +vn 0.9239 -0.0000 -0.3827 +vn 0.9671 0.1665 -0.1924 +vn 0.9808 -0.0000 -0.1951 +vn 0.9860 0.1665 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn 0.9671 0.1665 0.1924 +vn 0.9808 -0.0000 0.1951 +vn 0.9110 0.1665 0.3773 +vn 0.9239 -0.0000 0.3827 +vn 0.8199 0.1665 0.5478 +vn 0.8315 -0.0000 0.5556 +vn 0.6972 0.1665 0.6972 +vn 0.7071 -0.0000 0.7071 +vn 0.5478 0.1665 0.8199 +vn 0.5556 -0.0000 0.8315 +vn 0.3773 0.1665 0.9110 +vn 0.3827 -0.0000 0.9239 +vn -0.9253 0.3316 -0.1840 +vn -0.8716 0.3316 -0.3610 +vn 0.1924 0.1665 0.9671 +vn 0.1951 -0.0000 0.9808 +vn -0.7664 -0.5585 0.3174 +vn -0.8136 -0.5585 0.1618 +vn 0.7488 -0.5858 0.3102 +vn 0.7949 -0.5858 0.1581 +vn 0.3610 0.3316 -0.8716 +vn 0.5241 0.3316 -0.7844 +vn 0.7844 0.3316 0.5241 +vn 0.6671 0.3316 0.6671 +vn -0.7844 0.3316 0.5241 +vn -0.8716 0.3316 0.3610 +vn -0.3610 0.3316 -0.8716 +vn -0.1841 0.3316 -0.9253 +vn 0.9253 0.3316 -0.1840 +vn 0.9434 0.3316 -0.0000 +vn -0.1841 0.3316 0.9253 +vn -0.3610 0.3316 0.8716 +vn -0.7844 0.3316 -0.5241 +vn 0.6671 0.3316 -0.6671 +vn 0.5241 0.3316 0.7844 +vn -0.9253 0.3316 0.1840 +vn -0.0000 0.3316 -0.9434 +vn 0.9253 0.3316 0.1840 +vn -0.5241 0.3316 0.7844 +vn -0.6671 0.3316 -0.6671 +vn 0.7844 0.3316 -0.5241 +vn 0.3610 0.3316 0.8716 +vn -0.9434 0.3316 -0.0000 +vn 0.1841 0.3316 -0.9253 +vn 0.8716 0.3316 0.3610 +vn -0.6671 0.3316 0.6671 +vn -0.5241 0.3316 -0.7844 +vn 0.8716 0.3316 -0.3610 +vn 0.1840 0.3316 0.9253 +vn -0.0000 0.3316 0.9434 +vn -0.4503 -0.5858 -0.6739 +vn -0.5731 -0.5858 -0.5731 +vn -0.0000 -0.5858 0.8105 +vn 0.1581 -0.5858 0.7949 +vn -0.4503 0.5858 -0.6739 +vn -0.5731 0.5858 -0.5731 +vn -0.0000 0.5858 0.8105 +vn 0.1581 0.5858 0.7949 +vn 0.4503 -0.5858 0.6739 +vn 0.5731 -0.5858 0.5731 +vn -0.0000 -0.5858 -0.8105 +vn -0.1581 -0.5858 -0.7949 +vn -0.4503 -0.5858 0.6739 +vn -0.3102 -0.5858 0.7488 +vn 0.3102 -0.5858 0.7488 +vn 0.1581 -0.5858 -0.7949 +vn -0.5731 -0.5858 0.5731 +vn 0.3102 -0.5858 -0.7488 +vn -0.6739 -0.5858 0.4503 +vn 0.4503 -0.5858 -0.6739 +vn -0.1581 -0.5858 0.7949 +vn -0.7488 -0.5858 0.3102 +vn 0.5731 -0.5858 -0.5731 +vn -0.7949 -0.5858 0.1581 +vn 0.6739 -0.5858 -0.4503 +vn -0.8105 -0.5858 -0.0000 +vn 0.7488 -0.5858 -0.3101 +vn -0.7949 -0.5858 -0.1581 +vn 0.7949 -0.5858 -0.1581 +vn -0.7488 -0.5858 -0.3101 +vn 0.8105 -0.5858 -0.0000 +vn -0.6739 -0.5858 -0.4503 +vn 0.6739 -0.5858 0.4503 +vn -0.3102 -0.5858 -0.7488 +vn -0.6739 0.5858 -0.4503 +vn 0.7949 0.5858 0.1581 +vn 0.8105 0.5858 -0.0000 +vn -0.7488 0.5858 -0.3102 +vn 0.7949 0.5858 -0.1581 +vn -0.7949 0.5858 -0.1581 +vn 0.7488 0.5858 -0.3102 +vn -0.8105 0.5858 -0.0000 +vn 0.6739 0.5858 -0.4503 +vn -0.7949 0.5858 0.1581 +vn 0.5731 0.5858 -0.5731 +vn -0.7488 0.5858 0.3102 +vn 0.4503 0.5858 -0.6739 +vn -0.6739 0.5858 0.4503 +vn 0.3102 0.5858 -0.7488 +vn -0.5731 0.5858 0.5731 +vn 0.1581 0.5858 -0.7949 +vn 0.3102 0.5858 0.7488 +vn -0.4503 0.5858 0.6739 +vn -0.0000 0.5858 -0.8105 +vn 0.4503 0.5858 0.6739 +vn -0.3102 0.5858 0.7488 +vn -0.1581 0.5858 -0.7949 +vn 0.5731 0.5858 0.5731 +vn -0.1581 0.5858 0.7949 +vn -0.3102 0.5858 -0.7488 +vn 0.6739 0.5858 0.4503 +vn 0.7488 0.5858 0.3102 +vn -0.0000 1.0000 -0.0000 +vn 0.8102 0.4806 -0.3356 +vn 0.8601 0.4806 -0.1711 +vn 0.9510 0.2444 -0.1892 +vn 0.8959 0.2444 -0.3711 +vn -0.1618 -0.5585 -0.8136 +vn -0.0000 -0.5585 -0.8295 +vn 0.8295 -0.5585 -0.0000 +vn 0.8136 -0.5585 0.1618 +vn -0.3174 -0.5585 0.7664 +vn -0.4609 -0.5585 0.6897 +vn -0.6897 -0.5585 -0.4609 +vn -0.5866 -0.5585 -0.5866 +vn 0.5866 -0.5585 -0.5866 +vn 0.6897 -0.5585 -0.4609 +vn 0.4609 -0.5585 0.6897 +vn 0.3174 -0.5585 0.7664 +vn -0.8295 -0.5585 -0.0000 +vn 0.1618 -0.5585 -0.8136 +vn 0.7664 -0.5585 0.3174 +vn -0.5866 -0.5585 0.5866 +vn -0.4609 -0.5585 -0.6897 +vn 0.7664 -0.5585 -0.3174 +vn 0.1618 -0.5585 0.8136 +vn -0.8136 -0.5585 -0.1618 +vn 0.3174 -0.5585 -0.7664 +vn 0.6897 -0.5585 0.4609 +vn -0.6897 -0.5585 0.4609 +vn -0.3174 -0.5585 -0.7664 +vn 0.8136 -0.5585 -0.1618 +vn -0.0000 -0.5585 0.8295 +vn -0.1618 -0.5585 0.8136 +vn -0.7664 -0.5585 -0.3174 +vn 0.4609 -0.5585 -0.6897 +vn 0.5866 -0.5585 0.5866 +vn -0.5921 -0.5467 0.5921 +vn -0.6962 -0.5467 0.4652 +vn -0.8601 0.4806 -0.1711 +vn -0.8102 0.4806 -0.3356 +vn -0.8959 0.2444 -0.3711 +vn -0.9510 0.2444 -0.1892 +vn 0.7291 0.4806 -0.4872 +vn 0.8063 0.2444 -0.5387 +vn -0.8769 0.4806 -0.0000 +vn -0.9697 0.2444 -0.0000 +vn 0.8769 0.4806 -0.0000 +vn 0.9697 0.2444 -0.0000 +vn -0.7291 0.4806 -0.4872 +vn -0.8063 0.2444 -0.5387 +vn 0.8601 0.4806 0.1711 +vn 0.9510 0.2444 0.1892 +vn -0.6201 0.4806 -0.6201 +vn -0.6857 0.2444 -0.6857 +vn 0.8102 0.4806 0.3356 +vn 0.8959 0.2444 0.3711 +vn -0.4872 0.4806 -0.7291 +vn -0.5387 0.2444 -0.8063 +vn 0.7291 0.4806 0.4872 +vn 0.8063 0.2444 0.5387 +vn -0.3356 0.4806 -0.8102 +vn -0.3711 0.2444 -0.8959 +vn -0.1711 0.4806 0.8601 +vn -0.3356 0.4806 0.8102 +vn -0.3711 0.2444 0.8959 +vn -0.1892 0.2444 0.9510 +vn 0.6201 0.4806 0.6201 +vn 0.6857 0.2444 0.6857 +vn -0.1711 0.4806 -0.8601 +vn -0.1892 0.2444 -0.9510 +vn -0.0000 0.4806 0.8769 +vn -0.0000 0.2444 0.9697 +vn 0.4872 0.4806 0.7291 +vn 0.5387 0.2444 0.8063 +vn -0.0000 0.4806 -0.8769 +vn -0.0000 0.2444 -0.9697 +vn -0.4872 0.4806 0.7291 +vn -0.5387 0.2444 0.8063 +vn 0.3356 0.4806 0.8102 +vn 0.3711 0.2444 0.8959 +vn 0.1711 0.4806 -0.8601 +vn 0.1892 0.2444 -0.9510 +vn -0.6201 0.4806 0.6201 +vn -0.6857 0.2444 0.6857 +vn 0.1711 0.4806 0.8601 +vn 0.1892 0.2444 0.9510 +vn 0.3356 0.4806 -0.8102 +vn 0.3711 0.2444 -0.8959 +vn -0.7291 0.4806 0.4872 +vn -0.8063 0.2444 0.5387 +vn 0.6857 -0.2444 0.6857 +vn 0.5387 -0.2444 0.8063 +vn 0.4872 -0.4806 0.7291 +vn 0.6201 -0.4806 0.6201 +vn 0.4872 0.4806 -0.7291 +vn 0.5387 0.2444 -0.8063 +vn -0.8102 0.4806 0.3356 +vn -0.8959 0.2444 0.3711 +vn 0.6201 0.4806 -0.6201 +vn 0.6857 0.2444 -0.6857 +vn -0.8601 0.4806 0.1711 +vn -0.9510 0.2444 0.1892 +vn -0.9510 -0.2444 -0.1892 +vn -0.8959 -0.2444 -0.3711 +vn -0.8102 -0.4806 -0.3356 +vn -0.8601 -0.4806 -0.1711 +vn 0.9510 -0.2444 -0.1892 +vn 0.9697 -0.2444 -0.0000 +vn 0.8769 -0.4806 -0.0000 +vn 0.8601 -0.4806 -0.1711 +vn -0.9510 -0.2444 0.1892 +vn -0.9697 -0.2444 -0.0000 +vn -0.8769 -0.4806 -0.0000 +vn -0.8601 -0.4806 0.1711 +vn 0.6857 -0.2444 -0.6857 +vn 0.8063 -0.2444 -0.5387 +vn 0.7291 -0.4806 -0.4872 +vn 0.6201 -0.4806 -0.6201 +vn -0.8959 -0.2444 0.3711 +vn -0.8102 -0.4806 0.3356 +vn 0.5387 -0.2444 -0.8063 +vn 0.4872 -0.4806 -0.7291 +vn -0.8063 -0.2444 0.5387 +vn -0.7291 -0.4806 0.4872 +vn 0.1892 -0.2444 0.9510 +vn -0.0000 -0.2444 0.9697 +vn -0.0000 -0.4806 0.8769 +vn 0.1711 -0.4806 0.8601 +vn 0.3711 -0.2444 -0.8959 +vn 0.3356 -0.4806 -0.8102 +vn -0.6857 -0.2444 0.6857 +vn -0.6201 -0.4806 0.6201 +vn 0.1892 -0.2444 -0.9510 +vn 0.1711 -0.4806 -0.8601 +vn 0.3711 -0.2444 0.8959 +vn 0.3356 -0.4806 0.8102 +vn -0.5387 -0.2444 0.8063 +vn -0.4872 -0.4806 0.7291 +vn -0.0000 -0.2444 -0.9697 +vn -0.0000 -0.4806 -0.8769 +vn -0.3711 -0.2444 0.8959 +vn -0.3356 -0.4806 0.8102 +vn -0.1892 -0.2444 -0.9510 +vn -0.1711 -0.4806 -0.8601 +vn -0.1892 -0.2444 0.9510 +vn -0.1711 -0.4806 0.8601 +vn -0.3711 -0.2444 -0.8959 +vn -0.3356 -0.4806 -0.8102 +vn 0.8063 -0.2444 0.5387 +vn 0.7291 -0.4806 0.4872 +vn -0.5387 -0.2444 -0.8063 +vn -0.4872 -0.4806 -0.7291 +vn 0.8959 -0.2444 0.3711 +vn 0.8102 -0.4806 0.3356 +vn -0.6857 -0.2444 -0.6857 +vn -0.6201 -0.4806 -0.6201 +vn 0.9510 -0.2444 0.1892 +vn 0.8601 -0.4806 0.1711 +vn -0.8063 -0.2444 -0.5387 +vn -0.7291 -0.4806 -0.4872 +vn 0.8959 -0.2444 -0.3711 +vn 0.8102 -0.4806 -0.3356 +vn -0.0000 -1.0000 -0.0000 +vn 0.8213 -0.5467 -0.1634 +vn 0.8373 -0.5467 -0.0000 +vn -0.7736 -0.5467 0.3204 +vn 0.8213 -0.5467 0.1634 +vn -0.8213 -0.5467 0.1634 +vn 0.7736 -0.5467 0.3204 +vn -0.8373 -0.5467 -0.0000 +vn 0.6962 -0.5467 0.4652 +vn -0.8213 -0.5467 -0.1634 +vn 0.5921 -0.5467 0.5921 +vn -0.7736 -0.5467 -0.3204 +vn 0.4652 -0.5467 0.6962 +vn -0.6962 -0.5467 -0.4652 +vn 0.3204 -0.5467 0.7736 +vn -0.0000 -0.5467 -0.8373 +vn 0.1634 -0.5467 -0.8213 +vn -0.5921 -0.5467 -0.5921 +vn 0.1634 -0.5467 0.8213 +vn 0.3204 -0.5467 -0.7736 +vn -0.4652 -0.5467 -0.6962 +vn -0.0000 -0.5467 0.8373 +vn 0.4652 -0.5467 -0.6962 +vn -0.3204 -0.5467 -0.7736 +vn -0.1634 -0.5467 0.8213 +vn 0.5921 -0.5467 -0.5921 +vn -0.1634 -0.5467 -0.8213 +vn -0.3204 -0.5467 0.7736 +vn 0.6962 -0.5467 -0.4652 +vn -0.4652 -0.5467 0.6962 +vn 0.7736 -0.5467 -0.3204 +vt 0.769149 0.045079 +vt 0.769149 0.696279 +vt 0.745399 0.696279 +vt 0.745399 0.045079 +vt 0.721649 0.696279 +vt 0.721649 0.045079 +vt 0.697899 0.696279 +vt 0.697899 0.045079 +vt 0.674148 0.696279 +vt 0.674148 0.045079 +vt 0.650398 0.696279 +vt 0.650398 0.045079 +vt 0.626649 0.696279 +vt 0.626649 0.045079 +vt 0.602899 0.696279 +vt 0.602899 0.045079 +vt 0.579149 0.696279 +vt 0.579149 0.045079 +vt 0.555399 0.696279 +vt 0.555398 0.045079 +vt 0.531649 0.696279 +vt 0.531649 0.045079 +vt 0.507899 0.696279 +vt 0.507899 0.045079 +vt 0.484149 0.696279 +vt 0.484149 0.045079 +vt 0.460399 0.696279 +vt 0.460399 0.045079 +vt 0.436649 0.696279 +vt 0.436648 0.045079 +vt 0.412899 0.696279 +vt 0.412898 0.045079 +vt 0.389149 0.696279 +vt 0.389149 0.045079 +vt 0.365399 0.696279 +vt 0.365398 0.045079 +vt 0.341649 0.696279 +vt 0.341649 0.045079 +vt 0.317899 0.696279 +vt 0.317899 0.045079 +vt 0.294149 0.696279 +vt 0.294149 0.045079 +vt 0.270399 0.696279 +vt 0.270399 0.045079 +vt 0.246649 0.696279 +vt 0.246649 0.045079 +vt 0.222899 0.696279 +vt 0.222899 0.045079 +vt 0.199148 0.696279 +vt 0.199149 0.045079 +vt 0.175398 0.696279 +vt 0.175399 0.045079 +vt 0.151648 0.696279 +vt 0.151649 0.045079 +vt 0.127898 0.696279 +vt 0.127899 0.045079 +vt 0.104148 0.696279 +vt 0.104149 0.045079 +vt 0.080398 0.696279 +vt 0.080399 0.045079 +vt 0.056648 0.696279 +vt 0.056648 0.045079 +vt 0.555399 0.758023 +vt 0.531649 0.758023 +vt 0.032899 0.696279 +vt 0.032899 0.045079 +vt 0.009149 0.696279 +vt 0.009149 0.045079 +vt 0.602899 0.018915 +vt 0.626649 0.018915 +vt 0.151648 0.758023 +vt 0.175398 0.758023 +vt 0.175398 0.761979 +vt 0.151648 0.761979 +vt 0.341649 0.758023 +vt 0.317899 0.758023 +vt 0.127898 0.758023 +vt 0.104148 0.758023 +vt 0.650398 0.758023 +vt 0.626649 0.758023 +vt 0.436649 0.758023 +vt 0.412899 0.758023 +vt 0.222898 0.758023 +vt 0.199148 0.758023 +vt 0.745399 0.758023 +vt 0.721649 0.758023 +vt 0.507899 0.758023 +vt 0.294149 0.758023 +vt 0.080398 0.758023 +vt 0.602899 0.758023 +vt 0.389149 0.758023 +vt 0.697899 0.758023 +vt 0.484149 0.758023 +vt 0.270399 0.758023 +vt 0.056648 0.758023 +vt 0.579149 0.758023 +vt 0.365399 0.758023 +vt 0.674148 0.758023 +vt 0.460399 0.758023 +vt 0.246649 0.758023 +vt 0.032898 0.758023 +vt 0.769149 0.758023 +vt 0.009149 0.758023 +vt 0.294149 0.774405 +vt 0.317899 0.774405 +vt 0.317899 0.754637 +vt 0.294149 0.754637 +vt 0.484149 0.761979 +vt 0.460399 0.761979 +vt 0.032898 0.761979 +vt 0.009149 0.761979 +vt 0.460399 0.770449 +vt 0.484149 0.770449 +vt 0.484149 0.774405 +vt 0.460399 0.774405 +vt 0.009149 0.770449 +vt 0.032898 0.770449 +vt 0.032898 0.774405 +vt 0.009149 0.774405 +vt 0.104148 0.761979 +vt 0.080398 0.761979 +vt 0.412899 0.761979 +vt 0.389149 0.761979 +vt 0.721649 0.761979 +vt 0.697899 0.761979 +vt 0.056648 0.761979 +vt 0.365399 0.761979 +vt 0.674148 0.761979 +vt 0.341649 0.761979 +vt 0.650398 0.761979 +vt 0.317899 0.761979 +vt 0.769149 0.761979 +vt 0.745399 0.761979 +vt 0.626649 0.761979 +vt 0.294149 0.761979 +vt 0.602899 0.761979 +vt 0.270399 0.761979 +vt 0.579149 0.761979 +vt 0.246649 0.761979 +vt 0.555399 0.761979 +vt 0.222898 0.761979 +vt 0.531649 0.761979 +vt 0.199148 0.761979 +vt 0.507899 0.761979 +vt 0.127898 0.761979 +vt 0.436649 0.761979 +vt 0.507899 0.770449 +vt 0.507899 0.774405 +vt 0.175398 0.770449 +vt 0.199148 0.770449 +vt 0.199148 0.774405 +vt 0.175398 0.774405 +vt 0.531649 0.770449 +vt 0.531649 0.774405 +vt 0.222898 0.770449 +vt 0.222898 0.774405 +vt 0.555399 0.770449 +vt 0.555399 0.774405 +vt 0.246649 0.770449 +vt 0.246649 0.774405 +vt 0.579149 0.770449 +vt 0.579149 0.774405 +vt 0.270399 0.770449 +vt 0.270399 0.774405 +vt 0.602899 0.770449 +vt 0.602899 0.774405 +vt 0.294149 0.770449 +vt 0.626649 0.770449 +vt 0.626649 0.774405 +vt 0.317899 0.770449 +vt 0.650398 0.770449 +vt 0.650398 0.774405 +vt 0.341649 0.770449 +vt 0.341649 0.774405 +vt 0.674148 0.770449 +vt 0.674148 0.774405 +vt 0.365399 0.770449 +vt 0.365399 0.774405 +vt 0.056648 0.770449 +vt 0.056648 0.774405 +vt 0.697899 0.770449 +vt 0.697899 0.774405 +vt 0.389149 0.770449 +vt 0.389149 0.774405 +vt 0.080398 0.770449 +vt 0.080398 0.774405 +vt 0.721649 0.770449 +vt 0.721649 0.774405 +vt 0.412899 0.770449 +vt 0.412899 0.774405 +vt 0.104148 0.770449 +vt 0.104148 0.774405 +vt 0.745399 0.770449 +vt 0.745399 0.774405 +vt 0.436649 0.770449 +vt 0.436649 0.774405 +vt 0.127898 0.770449 +vt 0.127898 0.774405 +vt 0.769149 0.770449 +vt 0.769149 0.774405 +vt 0.151648 0.770449 +vt 0.151648 0.774405 +vt 0.626649 0.754637 +vt 0.602899 0.754637 +vt 0.270399 0.754637 +vt 0.579149 0.754637 +vt 0.246648 0.754637 +vt 0.555399 0.754637 +vt 0.222898 0.754637 +vt 0.531649 0.754637 +vt 0.199148 0.754637 +vt 0.507899 0.754637 +vt 0.175398 0.754637 +vt 0.484149 0.754637 +vt 0.151648 0.754637 +vt 0.460399 0.754637 +vt 0.127898 0.754637 +vt 0.436649 0.754637 +vt 0.769149 0.754637 +vt 0.745399 0.754637 +vt 0.104148 0.754637 +vt 0.412899 0.754637 +vt 0.721649 0.754637 +vt 0.080398 0.754637 +vt 0.389149 0.754637 +vt 0.697899 0.754637 +vt 0.056648 0.754637 +vt 0.365399 0.754637 +vt 0.674148 0.754637 +vt 0.032898 0.754637 +vt 0.341649 0.754637 +vt 0.650398 0.754637 +vt 0.009149 0.754637 +vt 0.246649 0.018915 +vt 0.222899 0.018915 +vt 0.222899 0.016646 +vt 0.246649 0.016646 +vt 0.389149 0.018915 +vt 0.412898 0.018915 +vt 0.175399 0.018915 +vt 0.199149 0.018915 +vt 0.697899 0.018915 +vt 0.721649 0.018915 +vt 0.484148 0.018915 +vt 0.507899 0.018915 +vt 0.270399 0.018915 +vt 0.294149 0.018915 +vt 0.056649 0.018915 +vt 0.080399 0.018915 +vt 0.579149 0.018915 +vt 0.365398 0.018915 +vt 0.151649 0.018915 +vt 0.674148 0.018915 +vt 0.460399 0.018915 +vt 0.032899 0.018915 +vt 0.555398 0.018915 +vt 0.341649 0.018915 +vt 0.127899 0.018915 +vt 0.650398 0.018915 +vt 0.436648 0.018915 +vt 0.745399 0.018915 +vt 0.769149 0.018915 +vt 0.009149 0.018915 +vt 0.531649 0.018915 +vt 0.317899 0.018915 +vt 0.104149 0.018915 +vt 0.294149 0.011176 +vt 0.270399 0.011176 +vt 0.270399 0.024995 +vt 0.294149 0.024995 +vt 0.531649 0.016646 +vt 0.555398 0.016646 +vt 0.270399 0.016646 +vt 0.579149 0.016646 +vt 0.199149 0.016646 +vt 0.507899 0.016646 +vt 0.175399 0.016646 +vt 0.484148 0.016646 +vt 0.151649 0.016646 +vt 0.460399 0.016646 +vt 0.127899 0.016646 +vt 0.436648 0.016646 +vt 0.721649 0.016646 +vt 0.745399 0.016646 +vt 0.104149 0.016646 +vt 0.412898 0.016646 +vt 0.769149 0.016646 +vt 0.080399 0.016646 +vt 0.389149 0.016646 +vt 0.697899 0.016646 +vt 0.056649 0.016646 +vt 0.365398 0.016646 +vt 0.674148 0.016646 +vt 0.032899 0.016646 +vt 0.341649 0.016646 +vt 0.650398 0.016646 +vt 0.104149 0.013445 +vt 0.080399 0.013445 +vt 0.080399 0.011176 +vt 0.104149 0.011176 +vt 0.317899 0.016646 +vt 0.626649 0.016646 +vt 0.294149 0.016646 +vt 0.602899 0.016646 +vt 0.555398 0.013445 +vt 0.531649 0.013445 +vt 0.531649 0.011176 +vt 0.555398 0.011176 +vt 0.222899 0.013445 +vt 0.199149 0.013445 +vt 0.199149 0.011176 +vt 0.222899 0.011176 +vt 0.602899 0.013445 +vt 0.579149 0.013445 +vt 0.579149 0.011176 +vt 0.602899 0.011176 +vt 0.294149 0.013445 +vt 0.270399 0.013445 +vt 0.626649 0.013445 +vt 0.626649 0.011176 +vt 0.317899 0.013445 +vt 0.317899 0.011176 +vt 0.650398 0.013445 +vt 0.650398 0.011176 +vt 0.032899 0.013445 +vt 0.009149 0.013445 +vt 0.009149 0.011176 +vt 0.032899 0.011176 +vt 0.341649 0.013445 +vt 0.341649 0.011176 +vt 0.674148 0.013445 +vt 0.674148 0.011176 +vt 0.365398 0.013445 +vt 0.365398 0.011176 +vt 0.056649 0.013445 +vt 0.056649 0.011176 +vt 0.697899 0.013445 +vt 0.697899 0.011176 +vt 0.389149 0.013445 +vt 0.389149 0.011176 +vt 0.721649 0.013445 +vt 0.721649 0.011176 +vt 0.412898 0.013445 +vt 0.412898 0.011176 +vt 0.009149 0.016646 +vt 0.745399 0.013445 +vt 0.745399 0.011176 +vt 0.436648 0.013445 +vt 0.436648 0.011176 +vt 0.769149 0.013445 +vt 0.769149 0.011176 +vt 0.127899 0.013445 +vt 0.127899 0.011176 +vt 0.460399 0.013445 +vt 0.460399 0.011176 +vt 0.151649 0.013445 +vt 0.151649 0.011176 +vt 0.484148 0.013445 +vt 0.484148 0.011176 +vt 0.175399 0.013445 +vt 0.175399 0.011176 +vt 0.507899 0.013445 +vt 0.507899 0.011176 +vt 0.246649 0.013445 +vt 0.246649 0.011176 +vt 0.317898 0.011176 +vt 0.852947 0.217272 +vt 0.833579 0.209249 +vt 0.816148 0.197602 +vt 0.801324 0.182778 +vt 0.789677 0.165347 +vt 0.781654 0.145979 +vt 0.777564 0.125417 +vt 0.777564 0.104453 +vt 0.781654 0.083892 +vt 0.789677 0.064523 +vt 0.801324 0.047092 +vt 0.816148 0.032268 +vt 0.833579 0.020621 +vt 0.852947 0.012599 +vt 0.873509 0.008509 +vt 0.894473 0.008509 +vt 0.915034 0.012599 +vt 0.934402 0.020621 +vt 0.951834 0.032268 +vt 0.966657 0.047092 +vt 0.978305 0.064523 +vt 0.986327 0.083892 +vt 0.990417 0.104453 +vt 0.990417 0.125417 +vt 0.986327 0.145979 +vt 0.978305 0.165347 +vt 0.966657 0.182778 +vt 0.951834 0.197602 +vt 0.934402 0.209249 +vt 0.915034 0.217272 +vt 0.894473 0.221362 +vt 0.873508 0.221362 +vt 0.579149 0.024995 +vt 0.602899 0.024995 +vt 0.246649 0.024995 +vt 0.555398 0.024995 +vt 0.222899 0.024995 +vt 0.531649 0.024995 +vt 0.199149 0.024995 +vt 0.507899 0.024995 +vt 0.175399 0.024995 +vt 0.484148 0.024995 +vt 0.151649 0.024995 +vt 0.460399 0.024995 +vt 0.127899 0.024995 +vt 0.436648 0.024995 +vt 0.745399 0.024995 +vt 0.769149 0.024995 +vt 0.104149 0.024995 +vt 0.412898 0.024995 +vt 0.721649 0.024995 +vt 0.080399 0.024995 +vt 0.389149 0.024995 +vt 0.697899 0.024995 +vt 0.056649 0.024995 +vt 0.365398 0.024995 +vt 0.674148 0.024995 +vt 0.032899 0.024995 +vt 0.341649 0.024995 +vt 0.650398 0.024995 +vt 0.009149 0.024995 +vt 0.317898 0.024995 +vt 0.626649 0.024995 +vt 0.959679 0.255095 +vt 0.975171 0.270586 +vt 0.987342 0.288802 +vt 0.995726 0.309043 +vt 1.000000 0.330530 +vt 1.000000 0.352438 +vt 0.995726 0.373925 +vt 0.987342 0.394165 +vt 0.975171 0.412381 +vt 0.959679 0.427872 +vt 0.941463 0.440044 +vt 0.921223 0.448428 +vt 0.899736 0.452702 +vt 0.877828 0.452702 +vt 0.856341 0.448428 +vt 0.836101 0.440044 +vt 0.817885 0.427872 +vt 0.802393 0.412381 +vt 0.790222 0.394165 +vt 0.781838 0.373925 +vt 0.777564 0.352438 +vt 0.777564 0.330530 +vt 0.781838 0.309043 +vt 0.790222 0.288802 +vt 0.802393 0.270586 +vt 0.817885 0.255095 +vt 0.836101 0.242924 +vt 0.856341 0.234540 +vt 0.877828 0.230266 +vt 0.899736 0.230266 +vt 0.921223 0.234540 +vt 0.941464 0.242924 +s 1 +usemtl Material.001 +f 1/1/1 2/2/2 4/3/3 3/4/4 +f 3/4/4 4/3/3 6/5/5 5/6/6 +f 5/6/6 6/5/5 8/7/7 7/8/8 +f 7/8/8 8/7/7 10/9/9 9/10/10 +f 9/10/10 10/9/9 12/11/11 11/12/12 +f 11/12/12 12/11/11 14/13/13 13/14/14 +f 13/14/14 14/13/13 16/15/15 15/16/16 +f 15/16/16 16/15/15 18/17/17 17/18/18 +f 17/18/18 18/17/17 20/19/19 19/20/20 +f 19/20/20 20/19/19 22/21/21 21/22/22 +f 21/22/22 22/21/21 24/23/23 23/24/24 +f 23/24/24 24/23/23 26/25/25 25/26/26 +f 25/26/26 26/25/25 28/27/27 27/28/28 +f 27/28/28 28/27/27 30/29/29 29/30/30 +f 29/30/30 30/29/29 32/31/31 31/32/32 +f 31/32/32 32/31/31 34/33/33 33/34/34 +f 33/34/34 34/33/33 36/35/35 35/36/36 +f 35/36/36 36/35/35 38/37/37 37/38/38 +f 37/38/38 38/37/37 40/39/39 39/40/40 +f 39/40/40 40/39/39 42/41/41 41/42/42 +f 41/42/42 42/41/41 44/43/43 43/44/44 +f 43/44/44 44/43/43 46/45/45 45/46/46 +f 45/46/46 46/45/45 48/47/47 47/48/48 +f 47/48/48 48/47/47 50/49/49 49/50/50 +f 49/50/50 50/49/49 52/51/51 51/52/52 +f 51/52/52 52/51/51 54/53/53 53/54/54 +f 53/54/54 54/53/53 56/55/55 55/56/56 +f 55/56/56 56/55/55 58/57/57 57/58/58 +f 57/58/58 58/57/57 60/59/59 59/60/60 +f 59/60/60 60/59/59 62/61/61 61/62/62 +f 22/21/21 20/19/19 74/63/63 75/64/64 +f 61/62/62 62/61/61 64/65/65 63/66/66 +f 63/66/66 64/65/65 2/67/2 1/68/1 +f 13/14/67 15/16/68 264/69/68 263/70/67 +f 91/71/69 90/72/70 189/73/70 130/74/69 +f 40/39/39 38/37/37 83/75/71 84/76/72 +f 58/57/57 56/55/55 92/77/73 93/78/74 +f 14/13/13 12/11/11 70/79/75 71/80/76 +f 32/31/31 30/29/29 79/81/77 80/82/78 +f 50/49/49 48/47/47 88/83/79 89/84/80 +f 6/5/5 4/3/3 65/85/81 67/86/82 +f 24/23/23 22/21/21 75/64/64 76/87/83 +f 42/41/41 40/39/39 84/76/72 85/88/84 +f 60/59/59 58/57/57 93/78/74 94/89/85 +f 16/15/15 14/13/13 71/80/76 72/90/86 +f 34/33/33 32/31/31 80/82/78 81/91/87 +f 52/51/51 50/49/49 89/84/80 90/72/88 +f 8/7/7 6/5/5 67/86/82 68/92/89 +f 26/25/25 24/23/23 76/87/83 77/93/90 +f 44/43/43 42/41/41 85/88/84 86/94/91 +f 62/61/61 60/59/59 94/89/85 95/95/92 +f 18/17/17 16/15/15 72/90/86 73/96/93 +f 36/35/35 34/33/33 81/91/87 82/97/94 +f 54/53/53 52/51/51 90/72/88 91/71/95 +f 10/9/9 8/7/7 68/92/89 69/98/96 +f 28/27/27 26/25/25 77/93/90 78/99/97 +f 46/45/45 44/43/43 86/94/91 87/100/98 +f 64/65/65 62/61/61 95/95/92 96/101/99 +f 20/19/19 18/17/17 73/96/93 74/63/63 +f 38/37/37 36/35/35 82/97/94 83/75/71 +f 56/55/55 54/53/53 91/71/95 92/77/73 +f 12/11/11 10/9/9 69/98/96 70/79/75 +f 30/29/29 28/27/27 78/99/97 79/81/77 +f 48/47/47 46/45/45 87/100/98 88/83/79 +f 4/3/3 2/2/2 66/102/100 65/85/81 +f 2/67/2 64/65/65 96/101/99 66/103/100 +f 117/104/10 116/105/8 244/106/8 245/107/10 +f 78/99/101 77/93/102 191/108/102 134/109/101 +f 66/103/103 96/101/104 159/110/104 138/111/103 +f 133/112/105 192/113/106 205/114/106 206/115/105 +f 137/116/107 160/117/108 224/118/108 194/119/107 +f 94/89/109 93/78/110 141/120/110 147/121/109 +f 81/91/111 80/82/112 143/122/112 149/123/111 +f 68/92/113 67/86/114 145/124/114 151/125/113 +f 95/95/115 94/89/109 147/121/109 153/126/115 +f 82/97/116 81/91/111 149/123/111 155/127/116 +f 69/98/117 68/92/113 151/125/113 157/128/117 +f 96/101/104 95/95/115 153/126/115 159/110/104 +f 83/75/118 82/97/116 155/127/116 161/129/118 +f 70/79/119 69/98/117 157/128/117 163/130/119 +f 84/76/120 83/75/118 161/129/118 165/131/120 +f 65/85/121 66/102/103 138/132/103 139/133/121 +f 71/80/122 70/79/119 163/130/119 167/134/122 +f 85/88/123 84/76/120 165/131/120 169/135/123 +f 72/90/124 71/80/122 167/134/122 171/136/124 +f 86/94/125 85/88/123 169/135/123 173/137/125 +f 73/96/126 72/90/124 171/136/124 175/138/126 +f 87/100/127 86/94/125 173/137/125 177/139/127 +f 74/63/128 73/96/126 175/138/126 179/140/128 +f 88/83/129 87/100/127 177/139/127 181/141/129 +f 75/64/130 74/63/128 179/140/128 183/142/130 +f 89/84/131 88/83/129 181/141/129 185/143/131 +f 76/87/132 75/64/130 183/142/130 187/144/132 +f 90/72/70 89/84/131 185/143/131 189/73/70 +f 77/93/102 76/87/132 187/144/132 191/108/102 +f 92/77/133 91/71/69 130/74/69 131/145/133 +f 79/81/134 78/99/101 134/109/101 135/146/134 +f 80/82/112 79/81/134 135/146/134 143/122/112 +f 93/78/110 92/77/133 131/145/133 141/120/110 +f 192/113/106 188/147/135 204/148/135 205/114/106 +f 190/149/136 186/150/137 217/151/137 218/152/136 +f 188/147/135 184/153/138 203/154/138 204/148/135 +f 186/150/137 182/155/139 216/156/139 217/151/137 +f 184/153/138 180/157/140 202/158/140 203/154/138 +f 182/155/139 178/159/141 215/160/141 216/156/139 +f 180/157/140 176/161/142 201/162/142 202/158/140 +f 178/159/141 174/163/143 214/164/143 215/160/141 +f 176/161/142 172/165/144 200/166/144 201/162/142 +f 174/163/143 170/167/145 213/104/145 214/164/143 +f 172/165/144 168/168/146 199/169/146 200/166/144 +f 170/167/145 166/170/147 212/105/147 213/104/145 +f 168/168/146 164/171/148 198/172/148 199/169/146 +f 166/170/147 162/173/149 211/174/149 212/105/147 +f 67/86/114 65/85/121 139/133/121 145/124/114 +f 164/171/148 158/175/150 197/176/150 198/172/148 +f 162/173/149 156/177/151 210/178/151 211/174/149 +f 160/117/108 154/179/152 223/180/152 224/118/108 +f 158/175/150 152/181/153 196/182/153 197/176/150 +f 156/177/151 150/183/154 209/184/154 210/178/151 +f 154/179/152 148/185/155 222/186/155 223/180/152 +f 152/181/153 146/187/156 195/188/156 196/182/153 +f 150/183/154 144/189/157 208/190/157 209/184/154 +f 148/185/155 142/191/158 221/192/158 222/186/155 +f 146/187/156 140/193/159 193/194/159 195/188/156 +f 144/189/157 136/195/160 207/196/160 208/190/157 +f 142/191/158 132/197/161 220/198/161 221/192/158 +f 140/193/159 137/199/107 194/200/107 193/194/159 +f 136/195/160 133/112/105 206/115/105 207/196/160 +f 132/197/161 129/201/162 219/202/162 220/198/161 +f 192/113/26 133/112/28 134/109/28 191/108/26 +f 190/149/52 129/201/54 130/74/54 189/73/52 +f 188/147/24 192/113/26 191/108/26 187/144/24 +f 186/150/50 190/149/52 189/73/52 185/143/50 +f 184/153/22 188/147/24 187/144/24 183/142/22 +f 182/155/48 186/150/50 185/143/50 181/141/48 +f 180/157/20 184/153/22 183/142/22 179/140/20 +f 178/159/46 182/155/48 181/141/48 177/139/46 +f 176/161/18 180/157/20 179/140/20 175/138/18 +f 174/163/44 178/159/46 177/139/46 173/137/44 +f 172/165/16 176/161/18 175/138/18 171/136/16 +f 170/167/42 174/163/44 173/137/44 169/135/42 +f 168/168/14 172/165/16 171/136/16 167/134/14 +f 166/170/40 170/167/42 169/135/42 165/131/40 +f 164/171/12 168/168/14 167/134/14 163/130/12 +f 162/173/38 166/170/40 165/131/40 161/129/38 +f 160/117/66 137/116/1 138/111/1 159/110/66 +f 158/175/10 164/171/12 163/130/12 157/128/10 +f 156/177/36 162/173/38 161/129/38 155/127/36 +f 154/179/62 160/117/66 159/110/66 153/126/62 +f 152/181/8 158/175/10 157/128/10 151/125/8 +f 150/183/34 156/177/36 155/127/36 149/123/34 +f 148/185/60 154/179/62 153/126/62 147/121/60 +f 146/187/6 152/181/8 151/125/8 145/124/6 +f 144/189/32 150/183/34 149/123/34 143/122/32 +f 142/191/58 148/185/60 147/121/60 141/120/58 +f 140/193/4 146/187/6 145/124/6 139/133/4 +f 136/195/30 144/189/32 143/122/32 135/146/30 +f 132/197/56 142/191/58 141/120/58 131/145/56 +f 137/199/1 140/193/4 139/133/4 138/132/1 +f 133/112/28 136/195/30 135/146/30 134/109/28 +f 129/201/54 132/197/56 131/145/56 130/74/54 +f 129/201/162 190/149/136 218/152/136 219/202/162 +f 98/200/163 97/194/163 193/194/163 194/200/163 +f 97/194/163 99/188/163 195/188/163 193/194/163 +f 99/188/163 100/182/163 196/182/163 195/188/163 +f 100/182/163 101/176/163 197/176/163 196/182/163 +f 101/176/163 102/172/163 198/172/163 197/176/163 +f 102/172/163 103/169/163 199/169/163 198/172/163 +f 103/169/163 104/166/163 200/166/163 199/169/163 +f 104/166/163 105/162/163 201/162/163 200/166/163 +f 105/162/163 106/158/163 202/158/163 201/162/163 +f 106/158/163 107/154/163 203/154/163 202/158/163 +f 107/154/163 108/148/163 204/148/163 203/154/163 +f 108/148/163 109/114/163 205/114/163 204/148/163 +f 109/114/163 110/115/163 206/115/163 205/114/163 +f 110/115/163 111/196/163 207/196/163 206/115/163 +f 111/196/163 112/190/163 208/190/163 207/196/163 +f 112/190/163 113/184/163 209/184/163 208/190/163 +f 113/184/163 114/178/163 210/178/163 209/184/163 +f 114/178/163 115/174/163 211/174/163 210/178/163 +f 115/174/163 116/105/163 212/105/163 211/174/163 +f 116/105/163 117/104/163 213/104/163 212/105/163 +f 117/104/163 118/164/163 214/164/163 213/104/163 +f 118/164/163 119/160/163 215/160/163 214/164/163 +f 119/160/163 120/156/163 216/156/163 215/160/163 +f 120/156/163 121/151/163 217/151/163 216/156/163 +f 121/151/163 122/152/163 218/152/163 217/151/163 +f 122/152/163 123/202/163 219/202/163 218/152/163 +f 123/202/163 124/198/163 220/198/163 219/202/163 +f 124/198/163 125/192/163 221/192/163 220/198/163 +f 125/192/163 126/186/163 222/186/163 221/192/163 +f 126/186/163 127/180/163 223/180/163 222/186/163 +f 127/180/163 128/118/163 224/118/163 223/180/163 +f 128/118/163 98/119/163 194/119/163 224/118/163 +f 245/107/42 244/106/40 468/106/40 469/107/42 +f 104/166/48 103/169/46 231/203/46 232/204/48 +f 118/164/12 117/104/10 245/107/10 246/205/12 +f 105/162/50 104/166/48 232/204/48 233/206/50 +f 119/160/14 118/164/12 246/205/12 247/207/14 +f 106/158/52 105/162/50 233/206/50 234/208/52 +f 120/156/16 119/160/14 247/207/14 248/209/16 +f 107/154/54 106/158/52 234/208/52 235/210/54 +f 121/151/18 120/156/16 248/209/16 249/211/18 +f 108/148/56 107/154/54 235/210/54 236/212/56 +f 122/152/20 121/151/18 249/211/18 250/213/20 +f 109/114/58 108/148/56 236/212/56 237/214/58 +f 123/202/22 122/152/20 250/213/20 251/215/22 +f 110/115/60 109/114/58 237/214/58 238/216/60 +f 124/198/24 123/202/22 251/215/22 252/217/24 +f 111/196/62 110/115/60 238/216/60 239/218/62 +f 97/194/36 98/200/34 226/219/34 225/220/36 +f 125/192/26 124/198/24 252/217/24 253/221/26 +f 112/190/66 111/196/62 239/218/62 240/222/66 +f 99/188/38 97/194/36 225/220/36 227/223/38 +f 126/186/28 125/192/26 253/221/26 254/224/28 +f 113/184/1 112/190/66 240/222/66 241/225/1 +f 100/182/40 99/188/38 227/223/38 228/226/40 +f 127/180/30 126/186/28 254/224/28 255/227/30 +f 114/178/4 113/184/1 241/225/1 242/228/4 +f 101/176/42 100/182/40 228/226/40 229/229/42 +f 128/118/32 127/180/30 255/227/30 256/230/32 +f 115/174/6 114/178/4 242/228/4 243/231/6 +f 102/172/44 101/176/42 229/229/42 230/232/44 +f 98/119/34 128/118/32 256/230/32 226/233/34 +f 116/105/8 115/174/6 243/231/6 244/106/8 +f 103/169/46 102/172/44 230/232/44 231/203/46 +f 279/234/164 280/235/165 330/236/166 322/237/167 +f 31/32/168 33/34/169 273/238/169 272/239/168 +f 49/50/170 51/52/171 282/240/171 281/241/170 +f 5/6/172 7/8/173 260/242/173 259/243/172 +f 23/24/174 25/26/175 269/244/175 268/245/174 +f 41/42/176 43/44/177 278/246/177 277/247/176 +f 59/60/178 61/62/179 287/248/179 286/249/178 +f 15/16/68 17/18/180 265/250/180 264/69/68 +f 33/34/169 35/36/181 274/251/181 273/238/169 +f 51/52/171 53/54/182 283/252/182 282/240/171 +f 7/8/173 9/10/183 261/253/183 260/242/173 +f 25/26/175 27/28/184 270/254/184 269/244/175 +f 43/44/177 45/46/185 279/234/185 278/246/177 +f 61/62/179 63/66/186 288/255/186 287/248/179 +f 17/18/180 19/20/187 266/256/187 265/250/180 +f 35/36/181 37/38/188 275/257/188 274/251/181 +f 53/54/182 55/56/189 284/258/189 283/252/182 +f 9/10/183 11/12/190 262/259/190 261/253/183 +f 27/28/184 29/30/191 271/260/191 270/254/184 +f 45/46/185 47/48/192 280/235/192 279/234/185 +f 1/1/193 3/4/194 258/261/194 257/262/193 +f 63/66/186 1/68/193 257/263/193 288/255/186 +f 19/20/187 21/22/195 267/264/195 266/256/187 +f 37/38/188 39/40/196 276/265/196 275/257/188 +f 55/56/189 57/58/197 285/266/197 284/258/189 +f 11/12/190 13/14/67 263/70/67 262/259/190 +f 29/30/191 31/32/168 272/239/168 271/260/191 +f 47/48/192 49/50/170 281/241/170 280/235/192 +f 3/4/194 5/6/172 259/243/172 258/261/194 +f 21/22/195 23/24/174 268/245/174 267/264/195 +f 39/40/196 41/42/176 277/247/176 276/265/196 +f 57/58/197 59/60/178 286/249/178 285/266/197 +f 309/267/198 310/268/199 438/269/199 437/270/198 +f 266/256/200 267/264/201 332/271/202 326/272/203 +f 278/246/204 279/234/164 322/237/167 323/273/205 +f 265/250/206 266/256/200 326/272/203 327/274/207 +f 280/235/165 281/241/208 334/275/209 330/236/166 +f 267/264/201 268/245/210 336/276/211 332/271/202 +f 281/241/208 282/240/212 338/277/213 334/275/209 +f 268/245/210 269/244/214 340/278/215 336/276/211 +f 282/240/212 283/252/216 342/279/217 338/277/213 +f 269/244/214 270/254/218 344/280/219 340/278/215 +f 283/252/216 284/258/220 346/281/221 342/279/217 +f 270/254/218 271/260/222 348/282/223 344/280/219 +f 258/261/224 259/243/225 358/283/226 350/284/227 +f 284/258/220 285/266/228 354/285/229 346/281/221 +f 271/260/222 272/239/230 356/286/231 348/282/223 +f 257/262/232 258/261/224 350/284/227 351/287/233 +f 285/266/228 286/249/234 360/288/235 354/285/229 +f 272/239/230 273/238/236 362/289/237 356/286/231 +f 259/243/225 260/242/238 364/290/239 358/283/226 +f 286/249/234 287/248/240 366/291/241 360/288/235 +f 273/238/236 274/251/242 368/292/243 362/289/237 +f 260/242/238 261/253/244 370/293/245 364/290/239 +f 287/248/240 288/255/246 372/294/247 366/291/241 +f 274/251/242 275/257/248 374/295/249 368/292/243 +f 261/253/244 262/259/250 376/296/251 370/293/245 +f 353/297/252 359/298/253 414/299/254 413/300/255 +f 275/257/248 276/265/256 378/301/257 374/295/249 +f 262/259/250 263/70/258 380/302/259 376/296/251 +f 276/265/256 277/247/260 382/303/261 378/301/257 +f 263/70/258 264/69/262 384/304/263 380/302/259 +f 325/305/264 331/306/265 395/307/266 394/308/267 +f 329/309/268 333/310/269 409/311/270 408/312/271 +f 383/313/272 328/314/273 393/315/274 392/316/275 +f 381/317/276 324/318/277 406/268/278 405/267/279 +f 379/319/280 383/313/272 392/316/275 391/320/281 +f 377/321/282 381/317/276 405/267/279 404/322/283 +f 375/323/284 379/319/280 391/320/281 390/324/285 +f 371/325/286 352/326/287 385/327/288 416/328/289 +f 373/329/290 377/321/282 404/322/283 403/330/291 +f 369/331/292 375/323/284 390/324/285 389/332/293 +f 367/333/294 373/329/290 403/330/291 402/334/295 +f 365/335/296 371/325/286 416/328/289 415/336/297 +f 363/337/298 369/331/292 389/332/293 388/338/299 +f 361/339/300 367/333/294 402/334/295 401/340/301 +f 359/298/253 365/335/296 415/336/297 414/299/254 +f 357/341/302 363/337/298 388/338/299 387/342/303 +f 355/343/304 361/339/300 401/340/301 400/344/305 +f 288/255/246 257/263/232 351/345/233 372/294/247 +f 349/346/306 357/341/302 387/342/303 386/347/307 +f 347/348/308 355/343/304 400/344/305 399/349/309 +f 352/350/287 349/346/306 386/347/307 385/351/288 +f 345/352/310 353/297/252 413/300/255 412/353/311 +f 343/354/312 347/348/308 399/349/309 398/355/313 +f 341/356/314 345/352/310 412/353/311 411/357/315 +f 339/358/316 343/354/312 398/355/313 397/359/317 +f 337/360/318 341/356/314 411/357/315 410/361/319 +f 335/362/320 339/358/316 397/359/317 396/363/321 +f 333/310/269 337/360/318 410/361/319 409/311/270 +f 331/306/265 335/362/320 396/363/321 395/307/266 +f 264/69/262 265/250/206 327/274/207 384/304/263 +f 277/247/260 278/246/204 323/273/205 382/303/261 +f 328/314/273 325/305/264 394/308/267 393/315/274 +f 324/318/277 321/364/322 407/365/323 406/268/278 +f 328/314/273 383/313/272 384/304/263 327/274/207 +f 324/318/277 381/317/276 382/303/261 323/273/205 +f 383/313/272 379/319/280 380/302/259 384/304/263 +f 381/317/276 377/321/282 378/301/257 382/303/261 +f 379/319/280 375/323/284 376/296/251 380/302/259 +f 377/321/282 373/329/290 374/295/249 378/301/257 +f 352/326/287 371/325/286 372/294/247 351/345/233 +f 375/323/284 369/331/292 370/293/245 376/296/251 +f 373/329/290 367/333/294 368/292/243 374/295/249 +f 371/325/286 365/335/296 366/291/241 372/294/247 +f 369/331/292 363/337/298 364/290/239 370/293/245 +f 367/333/294 361/339/300 362/289/237 368/292/243 +f 365/335/296 359/298/253 360/288/235 366/291/241 +f 363/337/298 357/341/302 358/283/226 364/290/239 +f 361/339/300 355/343/304 356/286/231 362/289/237 +f 359/298/253 353/297/252 354/285/229 360/288/235 +f 357/341/302 349/346/306 350/284/227 358/283/226 +f 355/343/304 347/348/308 348/282/223 356/286/231 +f 353/297/252 345/352/310 346/281/221 354/285/229 +f 349/346/306 352/350/287 351/287/233 350/284/227 +f 347/348/308 343/354/312 344/280/219 348/282/223 +f 345/352/310 341/356/314 342/279/217 346/281/221 +f 343/354/312 339/358/316 340/278/215 344/280/219 +f 341/356/314 337/360/318 338/277/213 342/279/217 +f 339/358/316 335/362/320 336/276/211 340/278/215 +f 337/360/318 333/310/269 334/275/209 338/277/213 +f 335/362/320 331/306/265 332/271/202 336/276/211 +f 333/310/269 329/309/268 330/236/166 334/275/209 +f 331/306/265 325/305/264 326/272/203 332/271/202 +f 329/309/268 321/364/322 322/237/167 330/236/166 +f 325/305/264 328/314/273 327/274/207 326/272/203 +f 321/364/322 324/318/277 323/273/205 322/237/167 +f 321/364/322 329/309/268 408/312/271 407/365/323 +f 290/347/324 289/351/324 385/351/324 386/347/324 +f 291/342/324 290/347/324 386/347/324 387/342/324 +f 292/338/324 291/342/324 387/342/324 388/338/324 +f 293/332/324 292/338/324 388/338/324 389/332/324 +f 294/324/324 293/332/324 389/332/324 390/324/324 +f 295/320/324 294/324/324 390/324/324 391/320/324 +f 296/316/324 295/320/324 391/320/324 392/316/324 +f 297/315/324 296/316/324 392/316/324 393/315/324 +f 298/308/324 297/315/324 393/315/324 394/308/324 +f 299/307/324 298/308/324 394/308/324 395/307/324 +f 300/363/324 299/307/324 395/307/324 396/363/324 +f 301/359/324 300/363/324 396/363/324 397/359/324 +f 302/355/324 301/359/324 397/359/324 398/355/324 +f 303/349/324 302/355/324 398/355/324 399/349/324 +f 304/344/324 303/349/324 399/349/324 400/344/324 +f 305/340/324 304/344/324 400/344/324 401/340/324 +f 306/334/324 305/340/324 401/340/324 402/334/324 +f 307/330/324 306/334/324 402/334/324 403/330/324 +f 308/366/324 307/330/324 403/330/324 404/322/324 +f 309/267/324 308/366/324 404/322/324 405/267/324 +f 310/268/324 309/267/324 405/267/324 406/268/324 +f 311/365/324 310/268/324 406/268/324 407/365/324 +f 312/312/324 311/365/324 407/365/324 408/312/324 +f 313/311/324 312/312/324 408/312/324 409/311/324 +f 314/361/324 313/311/324 409/311/324 410/361/324 +f 315/357/324 314/361/324 410/361/324 411/357/324 +f 316/353/324 315/357/324 411/357/324 412/353/324 +f 317/300/324 316/353/324 412/353/324 413/300/324 +f 318/299/324 317/300/324 413/300/324 414/299/324 +f 319/336/324 318/299/324 414/299/324 415/336/324 +f 320/328/324 319/336/324 415/336/324 416/328/324 +f 289/327/324 320/328/324 416/328/324 385/327/324 +f 417/367/324 418/368/324 419/369/324 420/370/324 421/371/324 422/372/324 423/373/324 424/374/324 425/375/324 426/376/324 427/377/324 428/378/324 429/379/324 430/380/324 431/381/324 432/382/324 433/383/324 434/384/324 435/385/324 436/386/324 437/387/324 438/388/324 439/389/324 440/390/324 441/391/324 442/392/324 443/393/324 444/394/324 445/395/324 446/396/324 447/397/324 448/398/324 +f 296/316/325 297/315/326 425/399/326 424/400/325 +f 310/268/199 311/365/327 439/401/327 438/269/199 +f 297/315/326 298/308/328 426/402/328 425/399/326 +f 311/365/327 312/312/329 440/403/329 439/401/327 +f 298/308/328 299/307/330 427/404/330 426/402/328 +f 312/312/329 313/311/331 441/405/331 440/403/329 +f 299/307/330 300/363/332 428/406/332 427/404/330 +f 313/311/331 314/361/333 442/407/333 441/405/331 +f 300/363/332 301/359/334 429/408/334 428/406/332 +f 314/361/333 315/357/335 443/409/335 442/407/333 +f 301/359/334 302/355/336 430/410/336 429/408/334 +f 315/357/335 316/353/337 444/411/337 443/409/335 +f 302/355/336 303/349/338 431/412/338 430/410/336 +f 289/351/339 290/347/340 418/413/340 417/414/339 +f 316/353/337 317/300/341 445/415/341 444/411/337 +f 303/349/338 304/344/342 432/416/342 431/412/338 +f 290/347/340 291/342/343 419/417/343 418/413/340 +f 317/300/341 318/299/344 446/418/344 445/415/341 +f 304/344/342 305/340/345 433/419/345 432/416/342 +f 291/342/343 292/338/346 420/420/346 419/417/343 +f 318/299/344 319/336/347 447/421/347 446/418/344 +f 305/340/345 306/334/348 434/422/348 433/419/345 +f 292/338/346 293/332/349 421/423/349 420/420/346 +f 319/336/347 320/328/350 448/424/350 447/421/347 +f 306/334/348 307/330/351 435/425/351 434/422/348 +f 293/332/349 294/324/352 422/426/352 421/423/349 +f 320/328/350 289/327/339 417/427/339 448/424/350 +f 307/330/351 308/366/353 436/428/353 435/425/351 +f 294/324/352 295/320/354 423/429/354 422/426/352 +f 308/366/353 309/267/198 437/270/198 436/428/353 +f 295/320/354 296/316/325 424/400/325 423/429/354 +f 449/430/163 450/431/163 480/432/163 479/433/163 478/434/163 477/435/163 476/436/163 475/437/163 474/438/163 473/439/163 472/440/163 471/441/163 470/442/163 469/443/163 468/444/163 467/445/163 466/446/163 465/447/163 464/448/163 463/449/163 462/450/163 461/451/163 460/452/163 459/453/163 458/454/163 457/455/163 456/456/163 455/457/163 454/458/163 453/459/163 452/460/163 451/461/163 +f 232/204/16 231/203/14 455/203/14 456/204/16 +f 246/205/44 245/107/42 469/107/42 470/205/44 +f 233/206/18 232/204/16 456/204/16 457/206/18 +f 247/207/46 246/205/44 470/205/44 471/207/46 +f 234/208/20 233/206/18 457/206/18 458/208/20 +f 248/209/48 247/207/46 471/207/46 472/209/48 +f 235/210/22 234/208/20 458/208/20 459/210/22 +f 249/211/50 248/209/48 472/209/48 473/211/50 +f 236/212/24 235/210/22 459/210/22 460/212/24 +f 250/213/52 249/211/50 473/211/50 474/213/52 +f 237/214/26 236/212/24 460/212/24 461/214/26 +f 251/215/54 250/213/52 474/213/52 475/215/54 +f 238/216/28 237/214/26 461/214/26 462/216/28 +f 252/217/56 251/215/54 475/215/54 476/217/56 +f 239/218/30 238/216/28 462/216/28 463/218/30 +f 225/220/4 226/219/1 450/219/1 449/220/4 +f 253/221/58 252/217/56 476/217/56 477/221/58 +f 240/222/32 239/218/30 463/218/30 464/222/32 +f 227/223/6 225/220/4 449/220/4 451/223/6 +f 254/224/60 253/221/58 477/221/58 478/224/60 +f 241/225/34 240/222/32 464/222/32 465/225/34 +f 228/226/8 227/223/6 451/223/6 452/226/8 +f 255/227/62 254/224/60 478/224/60 479/227/62 +f 242/228/36 241/225/34 465/225/34 466/228/36 +f 229/229/10 228/226/8 452/226/8 453/229/10 +f 256/230/66 255/227/62 479/227/62 480/230/66 +f 243/231/38 242/228/36 466/228/36 467/231/38 +f 230/232/12 229/229/10 453/229/10 454/232/12 +f 226/233/1 256/230/66 480/230/66 450/233/1 +f 244/106/40 243/231/38 467/231/38 468/106/40 +f 231/203/14 230/232/12 454/232/12 455/203/14 diff --git a/assets/textures/tescoPiwoNormal.png b/assets/textures/tescoPiwoNormal.png new file mode 100644 index 0000000..1192b94 Binary files /dev/null and b/assets/textures/tescoPiwoNormal.png differ diff --git a/assets/textures/tescoPiwoTexture.png b/assets/textures/tescoPiwoTexture.png new file mode 100644 index 0000000..fa252f1 Binary files /dev/null and b/assets/textures/tescoPiwoTexture.png differ diff --git a/build.zig b/build.zig index 0a72756..6462702 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const sdl = @import("libs/sdl/build.zig"); -const vkgen = @import("vulkan_zig"); +const sdl = @import("sdl"); +const vkgen = @import("vulkan"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); @@ -15,30 +15,25 @@ pub fn build(b: *std.Build) void { .link_libc = true, }); - // exe.addIncludePath(b.path("include/")); - // --- Dependencies --- // Vulkan - const vkzig_dep = b.dependency("vulkan_zig", .{ + const vkzig_dep = b.dependency("vulkan", .{ .registry = @as([]const u8, b.pathFromRoot("./vk.xml")), }); const vkzig_bindings = vkzig_dep.module("vulkan-zig"); exe.root_module.addImport("vulkan", vkzig_bindings); - const shader_comp = vkgen.ShaderCompileStep.create( - b, - &[_][]const u8{ "glslc", "--target-env=vulkan1.3" }, - "-o", - ); - shader_comp.add("shader_frag", "src/shaders/shader.frag", .{}); - shader_comp.add("shader_vert", "src/shaders/shader.vert", .{}); - exe.root_module.addImport("shaders", shader_comp.getModule()); + // Shaders + compileShader(b, exe, "shader_frag", "shader.frag"); + compileShader(b, exe, "shader_vert", "shader.vert"); + compileShader(b, exe, "second_frag", "second.frag"); + compileShader(b, exe, "second_vert", "second.vert"); // SDL2 - const sdl_sdk = sdl.init(b, null, null); + const sdl_sdk = sdl.init(b, .{}); sdl_sdk.link(exe, .dynamic, sdl.Library.SDL2); - exe.root_module.addImport("sdl2", sdl_sdk.getWrapperModuleVulkan(vkzig_bindings)); + exe.root_module.addImport("sdl", sdl_sdk.getWrapperModuleVulkan(vkzig_bindings)); // zmath const zmath = b.dependency("zmath", .{}); @@ -88,3 +83,16 @@ pub fn build(b: *std.Build) void { const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_exe_unit_tests.step); } + +fn compileShader( + b: *std.Build, + exe: *std.Build.Step.Compile, + comptime name: []const u8, + comptime file_name: []const u8, +) void { + const cmd = b.addSystemCommand(&.{ "glslc", "--target-env=vulkan1.3", "-o" }); + + const spv = cmd.addOutputFileArg(name ++ ".spv"); + cmd.addFileArg(b.path("src/shaders/" ++ file_name)); + exe.root_module.addAnonymousImport(name, .{ .root_source_file = spv }); +} diff --git a/build.zig.zon b/build.zig.zon index bf20cb5..137b837 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,14 +6,15 @@ .dependencies = .{ .zmath = .{ .path = "libs/zmath" }, .zstbi = .{ .path = "libs/zstbi" }, - .vulkan_zig = .{ - .url = "https://github.com/Snektron/vulkan-zig/archive/9f6e6177b1fdb3ed22231d9216a24480e84cfa5e.tar.gz", - .hash = "1220f2961df224f7d35dee774b26194b8b937cc252fa8e4023407776c58521d53e38", - }, - .obj = .{ - .url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz", - .hash = "1220ff46dcbeb40677c0ce8560b954885beec8b699835d9e6686beab72aa9d422c79", + .sdl = .{ .path = "libs/sdl" }, + .vulkan = .{ + .url = "https://github.com/Snektron/vulkan-zig/archive/06dae6c9201863837a92064e2e7814aa71064067.tar.gz", + .hash = "1220edeb3fc7dfc40e6fde705a108edce0a3cc76d165a7c9919d1fb037eccec43372", }, + // .obj = .{ + // .url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz", + // .hash = "1220ff46dcbeb40677c0ce8560b954885beec8b699835d9e6686beab72aa9d422c79", + // }, }, .paths = .{ diff --git a/libs/sdl b/libs/sdl index 9663dc7..172a84e 160000 --- a/libs/sdl +++ b/libs/sdl @@ -1 +1 @@ -Subproject commit 9663dc70c19b13afcb4b9f596c928d7b2838e548 +Subproject commit 172a84e7b5ce7d4891b8b970c68f4532f96aa7e9 diff --git a/libs/zmath/src/zmath.zig b/libs/zmath/src/zmath.zig index e38eebf..782a3d1 100644 --- a/libs/zmath/src/zmath.zig +++ b/libs/zmath/src/zmath.zig @@ -329,7 +329,7 @@ pub inline fn boolx16( // zig fmt: on pub inline fn veclen(comptime T: type) comptime_int { - return @typeInfo(T).Vector.len; + return @typeInfo(T).vector.len; } pub inline fn splat(comptime T: type, value: f32) T { @@ -413,14 +413,14 @@ pub inline fn storeArr4(arr: *[4]f32, v: F32x4) void { } pub inline fn arr3Ptr(ptr: anytype) *const [3]f32 { - comptime assert(@typeInfo(@TypeOf(ptr)) == .Pointer); + comptime assert(@typeInfo(@TypeOf(ptr)) == .pointer); const T = std.meta.Child(@TypeOf(ptr)); comptime assert(T == F32x4); return @as(*const [3]f32, @ptrCast(ptr)); } pub inline fn arrNPtr(ptr: anytype) [*]const f32 { - comptime assert(@typeInfo(@TypeOf(ptr)) == .Pointer); + comptime assert(@typeInfo(@TypeOf(ptr)) == .pointer); const T = std.meta.Child(@TypeOf(ptr)); comptime assert(T == Mat or T == F32x4 or T == F32x8 or T == F32x16); return @as([*]const f32, @ptrCast(ptr)); diff --git a/src/Context.zig b/src/Context.zig new file mode 100644 index 0000000..d90f54c --- /dev/null +++ b/src/Context.zig @@ -0,0 +1,340 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +const vk = @import("vulkan"); +const sdl = @import("sdl"); +const img = @import("zstbi"); + +const validation = @import("validation_layers.zig"); +const Swapchain = @import("Swapchain.zig"); +const QueueUtils = @import("queue_utils.zig"); + +const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name}; + +pub const apis: []const vk.ApiInfo = &.{ + vk.features.version_1_0, + vk.features.version_1_1, + vk.features.version_1_2, + vk.features.version_1_3, + vk.extensions.khr_surface, + vk.extensions.khr_swapchain, + vk.extensions.ext_debug_utils, +}; + +const enable_validation_layers = builtin.mode == .Debug; +const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; + +const BaseDispatch = vk.BaseWrapper(apis); +const InstanceDispatch = vk.InstanceWrapper(apis); +const DeviceDispatch = vk.DeviceWrapper(apis); + +pub const Instance = vk.InstanceProxy(apis); +pub const Device = vk.DeviceProxy(apis); +pub const Queue = vk.QueueProxy(apis); + +// --- + +const Self = @This(); + +allocator: std.mem.Allocator, + +vkb: BaseDispatch, + +window: sdl.Window, + +instance: Instance, +physical_device: vk.PhysicalDevice, +device: Device, + +command_pool: vk.CommandPool, +graphics_queue: Queue, +presentation_queue: Queue, +surface: vk.SurfaceKHR, +swapchain: Swapchain, + +debug_utils: ?vk.DebugUtilsMessengerEXT, + +pub fn init(allocator: std.mem.Allocator, window: sdl.Window) !Self { + var self: Self = undefined; + + self.window = window; + self.allocator = allocator; + self.vkb = try BaseDispatch.load(try sdl.vulkan.getVkGetInstanceProcAddr()); + + img.init(allocator); + + try self.createInstance(); + + if (enable_validation_layers) { + self.debug_utils = try validation.createDebugMessenger(self.instance); + } + + try self.createSurface(); + + try self.getPhysicalDevice(); + try self.createLogicalDevice(); + self.swapchain = try Swapchain.create(allocator, self); + + return self; +} + +pub fn deinit(self: *Self) void { + if (enable_validation_layers) { + self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null); + } + + self.device.destroyDevice(null); + self.instance.destroySurfaceKHR(self.surface, null); + self.instance.destroyInstance(null); + + self.allocator.destroy(self.device.wrapper); + self.allocator.destroy(self.instance.wrapper); + + img.deinit(); +} + +fn createInstance(self: *Self) !void { + if (enable_validation_layers and !self.checkValidationLayersSupport()) { + // TODO Better error + return error.LayerNotPresent; + } + + const extensions = try self.getRequiredExtensions(); + defer self.allocator.free(extensions); + + std.debug.print("[Required instance extensions]\n", .{}); + for (extensions) |ext| { + std.debug.print("\t- {s}\n", .{ext}); + } + + if (!try self.checkInstanceExtensions(&extensions)) { + return error.ExtensionNotPresent; + } + + const app_info = vk.ApplicationInfo{ + .p_application_name = "Vulkan SDL Test", + .application_version = vk.makeApiVersion(0, 0, 1, 0), + .p_engine_name = "Vulkan SDL Test", + .engine_version = vk.makeApiVersion(0, 0, 1, 0), + .api_version = vk.API_VERSION_1_3, + }; + + var instance_create_info: vk.InstanceCreateInfo = .{ + .p_application_info = &app_info, + .enabled_extension_count = @intCast(extensions.len), + .pp_enabled_extension_names = @ptrCast(extensions), + }; + + if (enable_validation_layers) { + const debug_create_info = validation.getDebugUtilsCreateInfo(); + + instance_create_info.enabled_layer_count = @intCast(validation_layers.len); + instance_create_info.pp_enabled_layer_names = &validation_layers; + instance_create_info.p_next = &debug_create_info; + } + + const instance_handle = try self.vkb.createInstance(&instance_create_info, null); + const vki = try self.allocator.create(InstanceDispatch); + errdefer self.allocator.destroy(vki); + vki.* = try InstanceDispatch.load(instance_handle, self.vkb.dispatch.vkGetInstanceProcAddr); + + self.instance = Instance.init(instance_handle, vki); +} + +fn createSurface(self: *Self) !void { + self.surface = try sdl.vulkan.createSurface(self.window, self.instance.handle); +} + +fn getPhysicalDevice(self: *Self) !void { + var pdev_count: u32 = 0; + _ = try self.instance.enumeratePhysicalDevices(&pdev_count, null); + + const pdevs = try self.allocator.alloc(vk.PhysicalDevice, pdev_count); + defer self.allocator.free(pdevs); + + _ = try self.instance.enumeratePhysicalDevices(&pdev_count, pdevs.ptr); + + for (pdevs) |pdev| { + if (self.checkDeviceSuitable(pdev)) { + self.physical_device = pdev; + break; + } + } else { + // TODO Obviously needs to be something else + unreachable; + } +} + +fn createLogicalDevice(self: *Self) !void { + const indices = try QueueUtils.getQueueFamilies(self.*, self.physical_device); + // 1 is the highest priority + const priority = [_]f32{1}; + + const qci = [_]vk.DeviceQueueCreateInfo{ + .{ + .queue_family_index = indices.graphics_family.?, + .queue_count = 1, + .p_queue_priorities = &priority, + }, + .{ + .queue_family_index = indices.presentation_family.?, + .queue_count = 1, + .p_queue_priorities = &priority, + }, + }; + + const queue_count: u32 = if (indices.graphics_family.? == indices.presentation_family.?) + 1 + else + 2; + + // Device features + const device_features: vk.PhysicalDeviceFeatures = .{ + .sampler_anisotropy = vk.TRUE, // Enable anisotropy + }; + + const device_create_info: vk.DeviceCreateInfo = .{ + .queue_create_info_count = queue_count, + .p_queue_create_infos = &qci, + .pp_enabled_extension_names = &device_extensions, + .enabled_extension_count = @intCast(device_extensions.len), + .p_enabled_features = &device_features, + }; + + const device_handle = try self.instance.createDevice(self.physical_device, &device_create_info, null); + + const vkd = try self.allocator.create(DeviceDispatch); + errdefer self.allocator.destroy(vkd); + vkd.* = try DeviceDispatch.load(device_handle, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); + + self.device = Device.init(device_handle, vkd); + + const queues = try QueueUtils.getDeviceQueues(self.*); + + self.graphics_queue = Queue.init(queues[0], self.device.wrapper); + self.presentation_queue = Queue.init(queues[1], self.device.wrapper); +} + +fn createCommandPool(self: *Self) !void { + // Get indices of queue families from device + const queue_family_indices = try QueueUtils.getQueueFamilies(self.*, self.physical_device); + + const pool_create_info: vk.CommandPoolCreateInfo = .{ + // Queue family type that buffers from this command pool will use + .queue_family_index = queue_family_indices.graphics_family.?, + .flags = .{ .reset_command_buffer_bit = true }, + }; + + // Create a graphics queue family command pool + self.graphics_command_pool = try self.device.createCommandPool(&pool_create_info, null); +} + +fn getRequiredExtensions(self: Self) ![][*:0]const u8 { + var ext_count = sdl.vulkan.getInstanceExtensionsCount(self.window); + + if (enable_validation_layers) { + ext_count += 1; + } + + var extensions = try self.allocator.alloc([*:0]const u8, ext_count); + _ = try sdl.vulkan.getInstanceExtensions(self.window, extensions); + + if (enable_validation_layers) { + extensions[extensions.len - 1] = vk.extensions.ext_debug_utils.name; + } + + return extensions; +} + +fn checkInstanceExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool { + var prop_count: u32 = 0; + _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null); + + const props = try self.allocator.alloc(vk.ExtensionProperties, prop_count); + defer self.allocator.free(props); + + _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, props.ptr); + + for (required_extensions.*) |required_extension| { + for (props) |prop| { + if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(required_extension))) { + break; + } + } else { + return false; + } + } + + return true; +} + +fn checkDeviceExtensions(self: Self, pdev: vk.PhysicalDevice) !bool { + var prop_count: u32 = 0; + _ = try self.instance.enumerateDeviceExtensionProperties(pdev, null, &prop_count, null); + + if (prop_count == 0) { + return false; + } + + const props = try self.allocator.alloc(vk.ExtensionProperties, prop_count); + defer self.allocator.free(props); + + _ = try self.instance.enumerateDeviceExtensionProperties(pdev, null, &prop_count, props.ptr); + + for (device_extensions) |device_extension| { + for (props) |prop| { + if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(device_extension))) { + break; + } + } else { + return false; + } + } + + return true; +} + +fn checkDeviceSuitable(self: Self, pdev: vk.PhysicalDevice) bool { + const pdev_properties = self.instance.getPhysicalDeviceProperties(pdev); + + if (pdev_properties.device_type == .cpu) { + return false; + } + + const pdev_features = self.instance.getPhysicalDeviceFeatures(pdev); + const queue_family_indices = QueueUtils.getQueueFamilies(self, pdev) catch return false; + const extension_support = self.checkDeviceExtensions(pdev) catch return false; + + const swapchain_details = Swapchain.getSwapchainDetails( + self.allocator, + self.instance, + pdev, + self.surface, + ) catch return false; + defer self.allocator.free(swapchain_details.formats); + defer self.allocator.free(swapchain_details.presentation_modes); + + const swapchain_valid = swapchain_details.formats.len != 0 and swapchain_details.formats.len != 0; + + return queue_family_indices.isValid() and extension_support and swapchain_valid and pdev_features.sampler_anisotropy == vk.TRUE; +} + +fn checkValidationLayersSupport(self: Self) bool { + var layer_count: u32 = undefined; + _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, null) catch return false; + + const available_layers = self.allocator.alloc(vk.LayerProperties, layer_count) catch unreachable; + defer self.allocator.free(available_layers); + + _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, available_layers.ptr) catch return false; + + for (validation_layers) |validation_layer| { + for (available_layers) |available_layer| { + if (std.mem.eql(u8, std.mem.span(validation_layer), std.mem.sliceTo(&available_layer.layer_name, 0))) { + return true; + } + } + } + + return false; +} diff --git a/src/Material.zig b/src/Material.zig new file mode 100644 index 0000000..f65275f --- /dev/null +++ b/src/Material.zig @@ -0,0 +1,12 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const Context = @import("Context.zig"); + +const Self = @This(); + +allocator: std.mem.Allocator, + +ctx: Context, + +pub fn new(allocator: std.mem.Allocator, ctx: Context) Self {} diff --git a/src/Mesh.zig b/src/Mesh.zig index 74e52d4..68f7f82 100644 --- a/src/Mesh.zig +++ b/src/Mesh.zig @@ -2,16 +2,16 @@ const std = @import("std"); const vk = @import("vulkan"); const zm = @import("zmath"); +const Context = @import("Context.zig"); const Utilities = @import("utilities.zig"); const Vertex = Utilities.Vertex; -const Device = @import("vulkan_renderer.zig").Device; -const Instance = @import("vulkan_renderer.zig").Instance; +const Device = @import("Context.zig").Device; +const Instance = @import("Context.zig").Instance; const Model = @import("vulkan_renderer.zig").Model; const Self = @This(); ubo_model: Model, -tex_id: u32, vertex_count: u32, vertex_buffer: vk.Buffer, @@ -21,32 +21,27 @@ index_count: u32, index_buffer: vk.Buffer, index_buffer_memory: vk.DeviceMemory, -instance: Instance, -physical_device: vk.PhysicalDevice, -device: Device, +ctx: Context, allocator: std.mem.Allocator, -pub fn new( - instance: Instance, - pdev: vk.PhysicalDevice, - device: Device, +pub fn create( + allocator: std.mem.Allocator, + ctx: Context, transfer_queue: vk.Queue, transfer_command_pool: vk.CommandPool, vertices: []const Vertex, indices: []const u32, tex_id: u32, - allocator: std.mem.Allocator, ) !Self { var self: Self = undefined; + self.allocator = allocator; + self.vertex_count = @intCast(vertices.len); self.index_count = @intCast(indices.len); - self.instance = instance; - self.physical_device = pdev; - self.device = device; - self.allocator = allocator; + self.ctx = ctx; try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices); try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices); @@ -57,12 +52,12 @@ pub fn new( return self; } -pub fn destroyBuffers(self: Self) void { - self.device.destroyBuffer(self.vertex_buffer, null); - self.device.freeMemory(self.vertex_buffer_memory, null); +pub fn destroy(self: Self) void { + self.ctx.device.destroyBuffer(self.vertex_buffer, null); + self.ctx.device.freeMemory(self.vertex_buffer_memory, null); - self.device.destroyBuffer(self.index_buffer, null); - self.device.freeMemory(self.index_buffer_memory, null); + self.ctx.device.destroyBuffer(self.index_buffer, null); + self.ctx.device.freeMemory(self.index_buffer_memory, null); } fn createVertexBuffer( @@ -77,14 +72,12 @@ fn createVertexBuffer( // Temporary buffer to "stage" vertex data before transfering to GPU var staging_buffer: vk.Buffer = undefined; var staging_buffer_memory: vk.DeviceMemory = undefined; - defer self.device.destroyBuffer(staging_buffer, null); - defer self.device.freeMemory(staging_buffer_memory, null); + defer self.ctx.device.destroyBuffer(staging_buffer, null); + defer self.ctx.device.freeMemory(staging_buffer_memory, null); // Create buffer and allocate memory to it try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, + self.ctx, buffer_size, .{ .transfer_src_bit = true }, .{ .host_visible_bit = true, .host_coherent_bit = true }, @@ -95,21 +88,19 @@ fn createVertexBuffer( // Map memory to vertex // 1. Create pointer to a point in normal memory // 2. Map the vertex buffer memory to that point - const data = try self.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{}); + const data = try self.ctx.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{}); // 3. Copy memory from vertices vector to the point in memory const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(data)); @memcpy(gpu_vertices, vertices[0..]); // 4. Unmap the vertex buffer memory - self.device.unmapMemory(staging_buffer_memory); + self.ctx.device.unmapMemory(staging_buffer_memory); // --- // Create buffer with TRANSFER_DST_BIT to mark as recipient of transfer data (also VERTEX_BUFFER) // Buffer memory is to be DEVICE_LOCAL_BIT meaning memory is on the GPU and only accessible by it and not CPU (host) try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, + self.ctx, buffer_size, .{ .transfer_dst_bit = true, .vertex_buffer_bit = true }, .{ .device_local_bit = true }, @@ -119,7 +110,7 @@ fn createVertexBuffer( // Copy staging buffer to vertex buffer on GPU try Utilities.copyBuffer( - self.device, + self.ctx, transfer_queue, transfer_command_pool, staging_buffer, @@ -140,13 +131,11 @@ fn createIndexBuffer( // Temporary buffer to "stage" vertex data before transfering to GPU var staging_buffer: vk.Buffer = undefined; var staging_buffer_memory: vk.DeviceMemory = undefined; - defer self.device.destroyBuffer(staging_buffer, null); - defer self.device.freeMemory(staging_buffer_memory, null); + defer self.ctx.device.destroyBuffer(staging_buffer, null); + defer self.ctx.device.freeMemory(staging_buffer_memory, null); try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, + self.ctx, buffer_size, .{ .transfer_src_bit = true }, .{ .host_visible_bit = true, .host_coherent_bit = true }, @@ -155,16 +144,14 @@ fn createIndexBuffer( ); // Map memory to index buffer - const data = try self.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{}); + const data = try self.ctx.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{}); const gpu_vertices: [*]u32 = @ptrCast(@alignCast(data)); @memcpy(gpu_vertices, indices[0..]); - self.device.unmapMemory(staging_buffer_memory); + self.ctx.device.unmapMemory(staging_buffer_memory); // Create buffer for index data on GPU access only try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, + self.ctx, buffer_size, .{ .transfer_dst_bit = true, .index_buffer_bit = true }, .{ .device_local_bit = true }, @@ -174,7 +161,7 @@ fn createIndexBuffer( // Copy from staging buffer to GPU access buffer try Utilities.copyBuffer( - self.device, + self.ctx, transfer_queue, transfer_command_pool, staging_buffer, diff --git a/src/MeshModel.zig b/src/MeshModel.zig index 4e7ca77..80acd0f 100644 --- a/src/MeshModel.zig +++ b/src/MeshModel.zig @@ -4,30 +4,93 @@ const zm = @import("zmath"); const ai = @import("assimp.zig").c; const Mesh = @import("Mesh.zig"); -const Device = @import("vulkan_renderer.zig").Device; -const Instance = @import("vulkan_renderer.zig").Instance; +const Context = @import("Context.zig"); +const Device = Context.Device; +const Instance = @import("Context.zig").Instance; const Vertex = @import("utilities.zig").Vertex; +const StringUtils = @import("string_utils.zig"); +const Texture = @import("Texture.zig"); const Self = @This(); allocator: std.mem.Allocator, mesh_list: std.ArrayList(Mesh), +textures: std.ArrayList(Texture), model: zm.Mat, -pub fn new(allocator: std.mem.Allocator, mesh_list: std.ArrayList(Mesh)) Self { +sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet), + +pub fn new( + allocator: std.mem.Allocator, + ctx: Context, + graphics_command_pool: vk.CommandPool, + texture_sampler: vk.Sampler, + model_file: []const u8, +) Self { + _ = texture_sampler; var new_mesh_model: Self = undefined; new_mesh_model.allocator = allocator; - new_mesh_model.mesh_list = mesh_list; new_mesh_model.model = zm.identity(); + new_mesh_model.sampler_descriptor_sets = try std.ArrayList(vk.DescriptorSet) + .init(allocator); + + const path = try StringUtils.concat("assets/models/", model_file, allocator); + defer allocator.free(path); + + // Import model scene + const scene = ai.aiImportFile( + path.ptr, + ai.aiProcess_Triangulate | ai.aiProcess_FlipUVs | ai.aiProcess_JoinIdenticalVertices, + ); + defer ai.aiReleaseImport(scene); + + // Get array of all materials with 1:1 ID placement + const texture_names = try ai.loadMaterials(allocator, scene); + defer { + for (0..texture_names.items.len) |i| { + if (texture_names.items[i]) |texture_name| { + allocator.free(texture_name); + } + } + texture_names.deinit(); + } + + // Conversion from the material list IDs to our descriptor array IDs + new_mesh_model.textures = try std.ArrayList(Texture).initCapacity(allocator, texture_names.items.len); + + // Loop over texture names and create textures for them + for (texture_names.items) |texture_name| { + if (texture_name != null) { + // Create texture and set value to index of new texture + new_mesh_model.textures.appendAssumeCapacity(try Texture.create(texture_name.?)); + } else { + // If material had no texture, set to 0 to indicate no texture. Texture 0 will be reserver for a default texture + // TODO Put the default texture somewhere else where it's shared + new_mesh_model.textures.appendAssumeCapacity(try Texture.create("giraffe.png")); + } + } + + // Load in all our meshes + new_mesh_model.mesh_list = try loadNode( + allocator, + ctx.instance, + ctx.physical_device, + ctx.device, + ctx.graphics_queue.handle, + graphics_command_pool, + scene.*.mRootNode, + scene, + ); + return new_mesh_model; } pub fn destroy(self: *Self) void { for (0..self.mesh_list.items.len) |i| { - self.mesh_list.items[i].destroyBuffers(); + self.mesh_list.items[i].destroy(); } self.mesh_list.deinit(); } @@ -40,50 +103,6 @@ pub fn getMesh(self: Self, idx: usize) !Mesh { return self.mesh_list.items[idx]; } -pub fn loadMaterials(allocator: std.mem.Allocator, scene: *const ai.aiScene) !std.ArrayList(?[]const u8) { - // Create 1:1 sized list of textures - var texture_list = try std.ArrayList(?[]const u8).initCapacity(allocator, scene.mNumMaterials); - - // Go through each material and copy its texture file name (if it exists) - for (0..scene.mNumMaterials) |i| { - // Get the material - const material = scene.mMaterials[i]; - - // Initialise the texture to empty string (will be replaced if the texture exists) - // try texture_list.append(""); - - // Check for diffuse texture (standard detail texture) - if (ai.aiGetMaterialTextureCount(material, ai.aiTextureType_DIFFUSE) != 0) { - // Get the path of the texture file - var path: ai.aiString = undefined; - if (ai.aiGetMaterialTexture( - material, - ai.aiTextureType_DIFFUSE, - 0, - &path, - null, - null, - null, - null, - null, - null, - ) == ai.AI_SUCCESS) { - // Cut of any directory information already present - var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/"); - if (it.next()) |filename| { - texture_list.appendAssumeCapacity(try allocator.dupe(u8, filename)); - } - } else { - texture_list.appendAssumeCapacity(null); - } - } else { - texture_list.appendAssumeCapacity(null); - } - } - - return texture_list; -} - pub fn loadNode( allocator: std.mem.Allocator, instance: Instance, @@ -93,7 +112,6 @@ pub fn loadNode( transfer_command_pool: vk.CommandPool, node: *const ai.aiNode, scene: *const ai.aiScene, - mat_to_tex: []u32, ) !std.ArrayList(Mesh) { var mesh_list = std.ArrayList(Mesh).init(allocator); @@ -108,7 +126,6 @@ pub fn loadNode( transfer_queue, transfer_command_pool, scene.mMeshes[node.mMeshes[i]], - mat_to_tex, )); } @@ -123,7 +140,6 @@ pub fn loadNode( transfer_command_pool, node.mChildren[i], scene, - mat_to_tex, ); defer new_list.deinit(); @@ -141,7 +157,6 @@ pub fn loadMesh( transfer_queue: vk.Queue, transfer_command_pool: vk.CommandPool, mesh: *const ai.aiMesh, - mat_to_tex: []u32, ) !Mesh { var vertices = try std.ArrayList(Vertex).initCapacity(allocator, mesh.mNumVertices); var indices = std.ArrayList(u32).init(allocator); @@ -180,7 +195,8 @@ pub fn loadMesh( } } - return try Mesh.new( + return try Mesh.create( + allocator, instance, pdev, device, @@ -188,7 +204,6 @@ pub fn loadMesh( transfer_command_pool, vertices.items, indices.items, - mat_to_tex[mesh.mMaterialIndex], - allocator, + mesh.mMaterialIndex, ); } diff --git a/src/ResourceManager.zig b/src/ResourceManager.zig new file mode 100644 index 0000000..88badf3 --- /dev/null +++ b/src/ResourceManager.zig @@ -0,0 +1,55 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const Context = @import("Context.zig"); +const Mesh = @import("Mesh.zig"); +const Material = @import("Material.zig"); + +const Self = @This(); + +allocator: std.mem.Allocator, + +ctx: Context, + +sampler_descriptor_pool: vk.DescriptorPool, +sampler_descriptor_set_layout: vk.DescriptorSetLayout, + +mesh_cache: std.AutoArrayHashMap([]const u8, Mesh), +material_cache: std.AutoArrayHashMap([]const u8, Material), + +pub fn new(allocator: std.mem.Allocator, ctx: Context) Self { + var self: Self = undefined; + + self.allocator = allocator; + self.ctx = ctx; + + self.mesh_cache = std.AutoArrayHashMap([]const u8, Mesh).init(allocator); + self.material_cache = std.AutoArrayHashMap([]const u8, Material).init(allocator); + + return self; +} + +pub fn deinit(self: *Self) void { + // TODO Release resources properly + self.mesh_cache.deinit(); + self.material_cache.deinit(); +} + +pub fn getMesh(self: *Self, file_name: []const u8) !Mesh { + if (self.mesh_cache.get(file_name)) |mesh| { + return mesh; + } + + // TODO Create mesh + // load mesh + + return undefined; +} + +fn allocateDescriptorSet(self: *Self) !void { + // TODO +} + +fn createDescriptorSetLayout(self: *Self) !void { + // TODO +} diff --git a/src/Swapchain.zig b/src/Swapchain.zig new file mode 100644 index 0000000..7339a8c --- /dev/null +++ b/src/Swapchain.zig @@ -0,0 +1,209 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const sdl = @import("sdl"); + +const Context = @import("Context.zig"); +const Instance = Context.Instance; +const QueueUtils = @import("queue_utils.zig"); +const Utilities = @import("utilities.zig"); +const Image = @import("image.zig"); + +pub const SwapchainDetails = struct { + surface_capabilities: vk.SurfaceCapabilitiesKHR, + formats: []vk.SurfaceFormatKHR, + presentation_modes: []vk.PresentModeKHR, +}; + +pub const SwapchainImage = struct { + image: vk.Image, + image_view: vk.ImageView, +}; + +const Self = @This(); + +allocator: std.mem.Allocator, + +ctx: Context, + +handle: vk.SwapchainKHR, + +swapchain_images: []SwapchainImage, +swapchain_framebuffers: []vk.Framebuffer, + +swapchain_image_format: vk.Format, +extent: vk.Extent2D, + +pub fn create(allocator: std.mem.Allocator, context: Context) !Self { + var self: Self = undefined; + + self.allocator = allocator; + self.ctx = context; + + const swapchain_details = try getSwapchainDetails(allocator, context.instance, context.physical_device, context.surface); + defer self.allocator.free(swapchain_details.formats); + defer self.allocator.free(swapchain_details.presentation_modes); + + // 1. Choose best surface format + const surface_format = chooseBestSurfaceFormat(swapchain_details.formats); + // 2. Choose best presentation mode + const present_mode = chooseBestPresentationMode(swapchain_details.presentation_modes); + // 3. Choose swapchain image resolution + const extent = chooseSwapExtent(&self.ctx.window, swapchain_details.surface_capabilities); + + // How many images are in the swapchain? Get 1 more than the minimum to allow triple buffering + var image_count: u32 = swapchain_details.surface_capabilities.min_image_count + 1; + const max_image_count = swapchain_details.surface_capabilities.max_image_count; + + // Clamp down if higher + // If 0, it means it's limitless + if (max_image_count != 0 and image_count > max_image_count) { + image_count = max_image_count; + } + + var swapchain_create_info: vk.SwapchainCreateInfoKHR = .{ + .image_format = surface_format.format, + .image_color_space = surface_format.color_space, + .present_mode = present_mode, + .image_extent = extent, + .min_image_count = image_count, + .image_array_layers = 1, // Number of layers for each image + .image_usage = .{ .color_attachment_bit = true }, // What attachment will images be used as + .pre_transform = swapchain_details.surface_capabilities.current_transform, // Transform to perform on swapchain images + .composite_alpha = .{ .opaque_bit_khr = true }, // How to handle blending images with external graphics (e.g.: other windows) + .clipped = vk.TRUE, // Whether to clip parts of images not in view (e.g.: behind another window, off-screen, etc...) + .old_swapchain = .null_handle, // Links old one to quickly share responsibilities in case it's been destroyed and replaced + .surface = context.surface, + .image_sharing_mode = .exclusive, + }; + + // Get queue family indices + const family_indices = try QueueUtils.getQueueFamilies(self.ctx, self.ctx.physical_device); + + // If graphic and presentation families are different, then swapchain must let images be shared between families + + if (family_indices.graphics_family.? != family_indices.presentation_family.?) { + const qfi = [_]u32{ + family_indices.graphics_family.?, + family_indices.presentation_family.?, + }; + + swapchain_create_info.image_sharing_mode = .concurrent; + swapchain_create_info.queue_family_index_count = @intCast(qfi.len); // Number of queues to share images between + swapchain_create_info.p_queue_family_indices = &qfi; + } + + self.handle = try self.ctx.device.createSwapchainKHR(&swapchain_create_info, null); + self.swapchain_image_format = surface_format.format; + self.extent = extent; + + // Swapchain images + var swapchain_image_count: u32 = 0; + _ = try self.ctx.device.getSwapchainImagesKHR(self.handle, &swapchain_image_count, null); + + const images = try self.allocator.alloc(vk.Image, swapchain_image_count); + defer self.allocator.free(images); + + _ = try self.ctx.device.getSwapchainImagesKHR(self.handle, &swapchain_image_count, images.ptr); + + self.swapchain_images = try self.allocator.alloc(SwapchainImage, swapchain_image_count); + + for (images, 0..) |image, i| { + self.swapchain_images[i] = .{ + .image = image, + .image_view = try Image.createImageView(self.ctx, image, self.swapchain_image_format, .{ .color_bit = true }), + }; + } + + return self; +} + +pub fn destroy(self: *Self) void { + for (self.swapchain_framebuffers) |framebuffer| { + self.ctx.device.destroyFramebuffer(framebuffer, null); + } + self.allocator.free(self.swapchain_framebuffers); + + for (self.swapchain_images) |swapchain_image| { + self.ctx.device.destroyImageView(swapchain_image.image_view, null); + } + self.allocator.free(self.swapchain_images); + + self.ctx.device.destroySwapchainKHR(self.handle, null); +} + +pub fn getSwapchainDetails(allocator: std.mem.Allocator, instance: Instance, pdev: vk.PhysicalDevice, surface: vk.SurfaceKHR) !SwapchainDetails { + // Capabilities + const surface_capabilities = try instance.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, surface); + + // Formats + var format_count: u32 = 0; + _ = try instance.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &format_count, null); + + const formats = try allocator.alloc(vk.SurfaceFormatKHR, format_count); + _ = try instance.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &format_count, formats.ptr); + + // Presentation modes + var present_mode_count: u32 = 0; + _ = try instance.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &present_mode_count, null); + + const presentation_modes = try allocator.alloc(vk.PresentModeKHR, format_count); + _ = try instance.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &present_mode_count, presentation_modes.ptr); + + return .{ + .surface_capabilities = surface_capabilities, + .formats = formats, + .presentation_modes = presentation_modes, + }; +} + +// Format: VK_FORMAT_R8G8B8A8_UNORM (VK_FORMAT_B8G8R8A8_UNORM as backup) +// Color space: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR +fn chooseBestSurfaceFormat(formats: []vk.SurfaceFormatKHR) vk.SurfaceFormatKHR { + // If only one format available and is undefined, then this means all formats are available + if (formats.len == 1 and formats[0].format == vk.Format.undefined) { + return .{ + .format = vk.Format.r8g8b8a8_srgb, + .color_space = vk.ColorSpaceKHR.srgb_nonlinear_khr, + }; + } + + for (formats) |format| { + if ((format.format == vk.Format.r8g8b8a8_srgb or format.format == vk.Format.b8g8r8a8_srgb) and format.color_space == vk.ColorSpaceKHR.srgb_nonlinear_khr) { + return format; + } + } + + return formats[0]; +} + +fn chooseBestPresentationMode(presentation_modes: []vk.PresentModeKHR) vk.PresentModeKHR { + for (presentation_modes) |presentation_mode| { + if (presentation_mode == vk.PresentModeKHR.mailbox_khr) { + return presentation_mode; + } + } + + // Use FIFO as Vulkan spec says it must be present + return vk.PresentModeKHR.fifo_khr; +} + +fn chooseSwapExtent(window: *sdl.Window, surface_capabilities: vk.SurfaceCapabilitiesKHR) vk.Extent2D { + // If the current extent is at max value, the extent can vary. Otherwise it's the size of the window + if (surface_capabilities.current_extent.width != std.math.maxInt(u32)) { + return surface_capabilities.current_extent; + } + + // If value can very, need to set the extent manually + const framebuffer_size = sdl.vulkan.getDrawableSize(window); + + var extent: vk.Extent2D = .{ + .width = @intCast(framebuffer_size.width), + .height = @intCast(framebuffer_size.height), + }; + + // Surface also defines max and min, so make sure it's within boundaries by clamping values + extent.width = @max(surface_capabilities.min_image_extent.width, @min(surface_capabilities.max_image_extent.width, extent.width)); + extent.height = @max(surface_capabilities.min_image_extent.height, @min(surface_capabilities.max_image_extent.height, extent.height)); + + return extent; +} diff --git a/src/Texture.zig b/src/Texture.zig new file mode 100644 index 0000000..cadc83d --- /dev/null +++ b/src/Texture.zig @@ -0,0 +1,200 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const img = @import("zstbi"); + +const Context = @import("Context.zig"); +const Image = @import("image.zig"); +const Utilities = @import("utilities.zig"); + +const Self = @This(); + +allocator: std.mem.Allocator, + +ctx: Context, + +idx: u32, +texture_image: vk.Image, +texture_image_memory: vk.DeviceMemory, +texture_image_view: vk.ImageView, + +sampler_descriptor_set: vk.DescriptorSet, + +image_file: img.Image, + +pub fn create( + file_name: []const u8, + ctx: Context, + graphics_command_pool: vk.CommandPool, + texture_sampler: vk.Sampler, + sampler_set_layout: vk.DescriptorSetLayout, + sampler_descriptor_pool: vk.DescriptorPool, +) Self { + var self: Self = undefined; + + self.ctx = ctx; + + // Create texture image and get its location in the array + const texture_image_loc = try self.createTextureImage(file_name, graphics_command_pool); + + // Create image view + self.texture_image_view = try Image.createImageView( + ctx, + self.texture_images.items[texture_image_loc], + .r8g8b8a8_srgb, + .{ .color_bit = true }, + ); + + // Create texture descriptor + try self.createTextureDescriptor( + texture_sampler, + sampler_set_layout, + sampler_descriptor_pool, + ); + + // Return location of set with texture + return self; +} + +pub fn destroy(self: *Self) void { + _ = self; +} + +fn createTextureImage( + self: *Self, + file_name: []const u8, + graphics_command_pool: vk.CommandPool, +) !u32 { + // Load image file + var width: u32 = undefined; + var height: u32 = undefined; + var image_size: vk.DeviceSize = undefined; + const image = try self.loadTextureFile(file_name, &width, &height, &image_size); + + // Create staging buffer to hold loaded data, ready to copy to device + var image_staging_buffer: vk.Buffer = undefined; + var image_staging_buffer_memory: vk.DeviceMemory = undefined; + defer self.ctx.device.destroyBuffer(image_staging_buffer, null); + defer self.ctx.device.freeMemory(image_staging_buffer_memory, null); + + try Utilities.createBuffer( + self.ctx.physical_device, + self.ctx.instance, + self.ctx.device, + image_size, + .{ .transfer_src_bit = true }, + .{ .host_visible_bit = true, .host_coherent_bit = true }, + &image_staging_buffer, + &image_staging_buffer_memory, + ); + + // Copy data to staging buffer + const data = try self.ctx.device.mapMemory(image_staging_buffer_memory, 0, image_size, .{}); + const image_data: [*]u8 = @ptrCast(@alignCast(data)); + + @memcpy(image_data, image[0..]); + self.ctx.device.unmapMemory(image_staging_buffer_memory); + + // Create image to hold final texture + var tex_image_memory: vk.DeviceMemory = undefined; + const tex_image = try Image.createImage( + self.ctx, + width, + height, + .r8g8b8a8_srgb, + .optimal, + .{ .transfer_dst_bit = true, .sampled_bit = true }, + .{ .device_local_bit = true }, + &tex_image_memory, + ); + + // Transition image to be DST for copy operation + try Utilities.transitionImageLayout( + self.ctx.device, + self.ctx.graphics_queue.handle, + graphics_command_pool, + tex_image, + .undefined, + .transfer_dst_optimal, + ); + + // Copy data to image + try Utilities.copyImageBuffer( + self.ctx.device, + self.ctx.graphics_queue.handle, + graphics_command_pool, + image_staging_buffer, + tex_image, + width, + height, + ); + + // Transition image to be shader readable for shader usage + try Utilities.transitionImageLayout( + self.ctx.device, + self.ctx.graphics_queue.handle, + graphics_command_pool, + tex_image, + .transfer_dst_optimal, + .shader_read_only_optimal, + ); + + self.texture_image = tex_image; + self.texture_image_memory = tex_image_memory; + + // Return index of new texture image + return @intCast(self.texture_images.items.len - 1); +} + +fn createTextureDescriptor( + self: *Self, + texture_sampler: vk.Sampler, + sampler_set_layout: vk.DescriptorSetLayout, + sampler_descriptor_pool: vk.DescriptorPool, +) !u32 { + // Descriptor set allocation info + const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ + .descriptor_pool = sampler_descriptor_pool, + .descriptor_set_count = 1, + .p_set_layouts = @ptrCast(&sampler_set_layout), + }; + + // Allocate descriptor sets + try self.ctx.device.allocateDescriptorSets(&set_alloc_info, @ptrCast(&self.sampler_descriptor_set)); + + const image_info: vk.DescriptorImageInfo = .{ + .image_layout = .shader_read_only_optimal, // Image layout when in use + .image_view = self.texture_image_view, // Image to bind to set + .sampler = texture_sampler, // Sampler to use for set + }; + + // Descriptor write info + const descriptor_write: vk.WriteDescriptorSet = .{ + .dst_set = self.sampler_descriptor_set, + .dst_binding = 0, + .dst_array_element = 0, + .descriptor_type = .combined_image_sampler, + .descriptor_count = 1, + .p_image_info = @ptrCast(&image_info), + .p_buffer_info = undefined, + .p_texel_buffer_view = undefined, + }; + + // Update the new descriptor set + self.ctx.device.updateDescriptorSets(1, @ptrCast(&descriptor_write), 0, null); +} + +fn loadTextureFile(self: *Self, file_name: []const u8, width: *u32, height: *u32, image_size: *vk.DeviceSize) !void { + const path_concat = [2][]const u8{ "./assets/textures/", file_name }; + const path = try std.mem.concatWithSentinel(self.allocator, u8, &path_concat, 0); + defer self.allocator.free(path); + + const image = try img.Image.loadFromFile(path, 0); + + width.* = image.width; + height.* = image.height; + + // Calculate image size using given and known data + image_size.* = width.* * height.* * 4; + + self.image_file = image; +} diff --git a/src/assimp.zig b/src/assimp.zig index 5d17599..76e06f2 100644 --- a/src/assimp.zig +++ b/src/assimp.zig @@ -1,9 +1,53 @@ +const std = @import("std"); + pub const c = @cImport({ @cInclude("assimp/cimport.h"); @cInclude("assimp/scene.h"); @cInclude("assimp/postprocess.h"); }); -// pub fn importFile(path: [:0]const u8, flags: c_uint) *const c.aiScene { -// return c.aiImportFile(path.ptr, flags); -// } +/// Load the texture material names in a scene. +/// Don't forget to free each element after use. +pub fn loadMaterials(allocator: std.mem.Allocator, scene: *const c.aiScene) !std.ArrayList(?[]const u8) { + // Create 1:1 sized list of textures + var texture_list = try std.ArrayList(?[]const u8).initCapacity(allocator, scene.mNumMaterials); + + // Go through each material and copy its texture file name (if it exists) + for (0..scene.mNumMaterials) |i| { + // Get the material + const material = scene.mMaterials[i]; + + // Initialise the texture to empty string (will be replaced if the texture exists) + // try texture_list.append(""); + + // Check for diffuse texture (standard detail texture) + if (c.aiGetMaterialTextureCount(material, c.aiTextureType_DIFFUSE) != 0) { + // Get the path of the texture file + var path: c.aiString = undefined; + if (c.aiGetMaterialTexture( + material, + c.aiTextureType_DIFFUSE, + 0, + &path, + null, + null, + null, + null, + null, + null, + ) == c.AI_SUCCESS) { + // Cut of any directory information already present + var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/"); + if (it.next()) |filename| { + texture_list.appendAssumeCapacity(try allocator.dupe(u8, filename)); + } + } else { + texture_list.appendAssumeCapacity(null); + } + } else { + texture_list.appendAssumeCapacity(null); + } + } + + return texture_list; +} diff --git a/src/image.zig b/src/image.zig new file mode 100644 index 0000000..168ad46 --- /dev/null +++ b/src/image.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const Context = @import("Context.zig"); +const Utilities = @import("utilities.zig"); + +pub fn createImage( + ctx: Context, + width: u32, + height: u32, + format: vk.Format, + tiling: vk.ImageTiling, + use_flags: vk.ImageUsageFlags, + prop_flags: vk.MemoryPropertyFlags, + image_memory: *vk.DeviceMemory, +) !vk.Image { + // -- Create Image -- + const image_create_info: vk.ImageCreateInfo = .{ + .image_type = .@"2d", // Type of image (1D, 2D or 3D) + .extent = .{ + .width = width, // Width of image extent + .height = height, // Height of image extent + .depth = 1, // Depth of image (just 1, no 3D aspecct) + }, + .mip_levels = 1, // Number of mipmap levels + .array_layers = 1, // Number of level in image array + .format = format, // Format type of image + .tiling = tiling, // How image data should be tiled (arranged for optimal reading) + .initial_layout = .undefined, // Layout of image data on creation + .usage = use_flags, // Bit flags defining what image will be used for + .samples = .{ .@"1_bit" = true }, // Number of samples for multi-sampling + .sharing_mode = .exclusive, // Whether image can be shared between queues + }; + + const image = try ctx.device.createImage(&image_create_info, null); + + // -- Create memory for image -- + // Get memory requirements for a type of image + const memory_requirements = ctx.device.getImageMemoryRequirements(image); + + // Allocate memory using image requirements and user-defined properties + const memory_alloc_info: vk.MemoryAllocateInfo = .{ + .allocation_size = memory_requirements.size, + .memory_type_index = Utilities.findMemoryTypeIndex(ctx.physical_device, ctx.instance, memory_requirements.memory_type_bits, prop_flags), + }; + + image_memory.* = try ctx.device.allocateMemory(&memory_alloc_info, null); + + // Connect memory to image + try ctx.device.bindImageMemory(image, image_memory.*, 0); + + return image; +} + +pub fn createImageView( + ctx: Context, + image: vk.Image, + format: vk.Format, + aspect_flags: vk.ImageAspectFlags, +) !vk.ImageView { + const image_view_create_info: vk.ImageViewCreateInfo = .{ + .image = image, + .format = format, + .view_type = .@"2d", + .components = .{ + // Used for remapping rgba values to other rgba values + .r = .identity, + .g = .identity, + .b = .identity, + .a = .identity, + }, + .subresource_range = .{ + .aspect_mask = aspect_flags, // Which aspect of image to view (e.g.: colour, depth, stencil, etc...) + .base_mip_level = 0, // Start mipmap level to view from + .level_count = 1, // Number of mipmap levels to view + .base_array_layer = 0, // Start array level to view from + .layer_count = 1, // Number of array levels to view + }, + }; + + return try ctx.device.createImageView(&image_view_create_info, null); +} diff --git a/src/main.zig b/src/main.zig index 5937000..5475116 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const sdl = @import("sdl2"); +const sdl = @import("sdl"); const zm = @import("zmath"); const VulkanRenderer = @import("vulkan_renderer.zig").VulkanRenderer; @@ -62,7 +62,7 @@ pub fn main() !void { defer _ = gpa.deinit(); const allocator = gpa.allocator(); - var vulkan_renderer = try VulkanRenderer.init(window, allocator); + var vulkan_renderer = try VulkanRenderer.init(allocator, window); defer vulkan_renderer.deinit(); var delta = Delta.new(); @@ -71,7 +71,7 @@ pub fn main() !void { var angle: f32 = 0.0; const move_speed: f32 = 1000; - const model_handle = try vulkan_renderer.createMeshModel("teapot.obj"); + const model_handle = try vulkan_renderer.createMeshModel("tescoPiwo.obj"); mainLoop: while (true) { while (sdl.pollEvent()) |ev| { diff --git a/src/queue_utils.zig b/src/queue_utils.zig new file mode 100644 index 0000000..c3dd0ed --- /dev/null +++ b/src/queue_utils.zig @@ -0,0 +1,53 @@ +const std = @import("std"); + +const vk = @import("vulkan"); + +const Context = @import("Context.zig"); +const Instance = Context.Instance; +const Device = Context.Device; + +pub const QueueFamilyIndices = struct { + graphics_family: ?u32 = null, + presentation_family: ?u32 = null, + + pub fn isValid(self: QueueFamilyIndices) bool { + return self.graphics_family != null and self.presentation_family != null; + } +}; + +pub fn getQueueFamilies(ctx: Context, pdev: vk.PhysicalDevice) !QueueFamilyIndices { + var indices: QueueFamilyIndices = .{ .graphics_family = null }; + + var queue_family_count: u32 = 0; + ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, null); + + const queue_family_list = try ctx.allocator.alloc(vk.QueueFamilyProperties, queue_family_count); + defer ctx.allocator.free(queue_family_list); + + ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, queue_family_list.ptr); + + for (queue_family_list, 0..) |queue_family, i| { + if (queue_family.queue_count > 0 and queue_family.queue_flags.graphics_bit) { + indices.graphics_family = @intCast(i); + } + + const presentation_support = try ctx.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), ctx.surface); + if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) { + indices.presentation_family = @intCast(i); + } + + if (indices.isValid()) { + return indices; + } + } + + unreachable; +} + +pub fn getDeviceQueues(ctx: Context) ![2]vk.Queue { + const indices = try getQueueFamilies(ctx, ctx.physical_device); + + const graphics_queue = ctx.device.getDeviceQueue(indices.graphics_family.?, 0); + const presentation_queue = ctx.device.getDeviceQueue(indices.presentation_family.?, 0); + return .{ graphics_queue, presentation_queue }; +} diff --git a/src/shaders/second.frag b/src/shaders/second.frag new file mode 100644 index 0000000..7c98a5c --- /dev/null +++ b/src/shaders/second.frag @@ -0,0 +1,22 @@ +#version 450 + +// Colour output from subpass 1 +layout(input_attachment_index = 0, binding = 0) uniform subpassInput inputColour; +// Depth output from subpass 1 +layout(input_attachment_index = 1, binding = 1) uniform subpassInput inputDepth; + +layout(location = 0) out vec4 colour; + +void main() { + int xHalf = 800 / 2; + if (gl_FragCoord.x > xHalf) { + float lowerBound = 0.98; + float upperBound = 1; + + float depth = subpassLoad(inputDepth).r; + float depthColourScaled = 1.0f - ((depth - lowerBound) / (upperBound - lowerBound)); + colour = vec4(subpassLoad(inputColour).rgb * depthColourScaled, 1.0f); + } else { + colour = subpassLoad(inputColour).rgba; + } +} diff --git a/src/shaders/second.vert b/src/shaders/second.vert new file mode 100644 index 0000000..e9b3199 --- /dev/null +++ b/src/shaders/second.vert @@ -0,0 +1,12 @@ +#version 450 + +// Array for triangle that fills screen +vec2 positions[3] = vec2[]( + vec2(3.0, -1.0), + vec2(-1.0, -1.0), + vec2(-1.0, 3.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); +} diff --git a/src/utilities.zig b/src/utilities.zig index 94eed98..6773a0e 100644 --- a/src/utilities.zig +++ b/src/utilities.zig @@ -1,12 +1,11 @@ const std = @import("std"); const vk = @import("vulkan"); -const Instance = @import("vulkan_renderer.zig").Instance; -const Device = @import("vulkan_renderer.zig").Device; +const Context = @import("Context.zig"); +const Instance = @import("Context.zig").Instance; +const Device = @import("Context.zig").Device; const CommandBuffer = @import("vulkan_renderer.zig").CommandBuffer; -pub const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name}; - pub const Vector3 = @Vector(3, f32); pub const Vector2 = @Vector(2, f32); @@ -17,29 +16,9 @@ pub const Vertex = struct { tex: Vector2, // Texture coords (u, v) }; -pub const QueueFamilyIndices = struct { - graphics_family: ?u32 = null, - presentation_family: ?u32 = null, - - pub fn isValid(self: QueueFamilyIndices) bool { - return self.graphics_family != null and self.presentation_family != null; - } -}; - -pub const SwapchainDetails = struct { - surface_capabilities: vk.SurfaceCapabilitiesKHR, - formats: []vk.SurfaceFormatKHR, - presentation_modes: []vk.PresentModeKHR, -}; - -pub const SwapchainImage = struct { - image: vk.Image, - image_view: vk.ImageView, -}; - -pub fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 { +pub fn findMemoryTypeIndex(ctx: Context, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 { // Get properties of physical device memory - const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev); + const memory_properties = ctx.instance.getPhysicalDeviceMemoryProperties(ctx.physical_device); const mem_type_count = memory_properties.memory_type_count; for (memory_properties.memory_types[0..mem_type_count], 0..mem_type_count) |mem_type, i| { @@ -54,9 +33,7 @@ pub fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_ } pub fn createBuffer( - pdev: vk.PhysicalDevice, - instance: Instance, - device: Device, + ctx: Context, buffer_size: vk.DeviceSize, buffer_usage: vk.BufferUsageFlags, buffer_properties: vk.MemoryPropertyFlags, @@ -72,17 +49,16 @@ pub fn createBuffer( .sharing_mode = .exclusive, // Similar to swapchain images, can share vertex buffers }; - buffer.* = try device.createBuffer(&buffer_create_info, null); + buffer.* = try ctx.device.createBuffer(&buffer_create_info, null); // Get buffer memory requirements - const mem_requirements = device.getBufferMemoryRequirements(buffer.*); + const mem_requirements = ctx.device.getBufferMemoryRequirements(buffer.*); // Allocate memory to buffer const allocate_info: vk.MemoryAllocateInfo = .{ .allocation_size = mem_requirements.size, .memory_type_index = findMemoryTypeIndex( - pdev, - instance, + ctx, mem_requirements.memory_type_bits, // Index of memory type of physical device that has required bit flags // Host visible: CPU can interact with memory // Host coherent: Allows placement of data straight into buffer after mapping (otherwise would have to specify manually) @@ -91,10 +67,10 @@ pub fn createBuffer( }; // Allocate memory to vkDeviceMemory - buffer_memory.* = try device.allocateMemory(&allocate_info, null); + buffer_memory.* = try ctx.device.allocateMemory(&allocate_info, null); // Allocate memory to given vertex buffer - try device.bindBufferMemory(buffer.*, buffer_memory.*, 0); + try ctx.device.bindBufferMemory(buffer.*, buffer_memory.*, 0); } fn beginCommandBuffer(device: Device, command_pool: vk.CommandPool) !CommandBuffer { diff --git a/src/validation_layers.zig b/src/validation_layers.zig new file mode 100644 index 0000000..69ee9c6 --- /dev/null +++ b/src/validation_layers.zig @@ -0,0 +1,61 @@ +const std = @import("std"); + +const vk = @import("vulkan"); +const Instance = @import("Context.zig").Instance; + +// Validation layers stuff +pub fn createDebugMessenger(instance: Instance) !vk.DebugUtilsMessengerEXT { + const debug_create_info = getDebugUtilsCreateInfo(); + + return try instance.createDebugUtilsMessengerEXT(&debug_create_info, null); +} + +pub fn getDebugUtilsCreateInfo() vk.DebugUtilsMessengerCreateInfoEXT { + return vk.DebugUtilsMessengerCreateInfoEXT{ + .message_severity = .{ .verbose_bit_ext = true, .warning_bit_ext = true, .error_bit_ext = true }, + .message_type = .{ .general_bit_ext = true, .validation_bit_ext = true, .performance_bit_ext = true }, + .pfn_user_callback = debugCallback, + }; +} + +fn debugCallback( + message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, + message_types: vk.DebugUtilsMessageTypeFlagsEXT, + p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, + p_user_data: ?*anyopaque, +) callconv(vk.vulkan_call_conv) vk.Bool32 { + _ = p_user_data; + const severity = getMessageSeverityLabel(message_severity); + const message_type = getMessageTypeLabel(message_types); + + std.debug.print("[{s}] ({s}): {s}\n=====\n", .{ severity, message_type, p_callback_data.?.p_message.? }); + return vk.TRUE; +} + +inline fn getMessageSeverityLabel(message_severity: vk.DebugUtilsMessageSeverityFlagsEXT) []const u8 { + if (message_severity.verbose_bit_ext) { + return "VERBOSE"; + } else if (message_severity.info_bit_ext) { + return "INFO"; + } else if (message_severity.warning_bit_ext) { + return "WARNING"; + } else if (message_severity.error_bit_ext) { + return "ERROR"; + } else { + unreachable; + } +} + +inline fn getMessageTypeLabel(message_types: vk.DebugUtilsMessageTypeFlagsEXT) []const u8 { + if (message_types.general_bit_ext) { + return "general"; + } else if (message_types.validation_bit_ext) { + return "validation"; + } else if (message_types.performance_bit_ext) { + return "performance"; + } else if (message_types.device_address_binding_bit_ext) { + return "device_address_binding"; + } else { + return "unknown"; + } +} diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index f58728a..58c793e 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -1,47 +1,30 @@ const std = @import("std"); -const sdl = @import("sdl2"); +const sdl = @import("sdl"); const vk = @import("vulkan"); const builtin = @import("builtin"); -const shaders = @import("shaders"); const zm = @import("zmath"); const img = @import("zstbi"); const ai = @import("assimp.zig").c; +const QueueUtils = @import("queue_utils.zig"); const StringUtils = @import("string_utils.zig"); const Utilities = @import("utilities.zig"); -const QueueFamilyIndices = Utilities.QueueFamilyIndices; -const SwapchainDetails = Utilities.SwapchainDetails; -const SwapchainImage = Utilities.SwapchainImage; const Vertex = Utilities.Vertex; const Vector3 = Utilities.Vector3; +const Context = @import("Context.zig"); +const Instance = Context.Instance; +const Swapchain = @import("Swapchain.zig"); +const Texture = @import("Texture.zig"); +const Image = @import("image.zig"); + const Mesh = @import("Mesh.zig"); const MeshModel = @import("MeshModel.zig"); -const enable_validation_layers = builtin.mode == .Debug; -const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; - const MAX_FRAME_DRAWS: u32 = 2; const MAX_OBJECTS: u32 = 20; -const apis: []const vk.ApiInfo = &.{ - vk.features.version_1_0, - vk.features.version_1_1, - vk.features.version_1_2, - vk.features.version_1_3, - vk.extensions.khr_surface, - vk.extensions.khr_swapchain, - vk.extensions.ext_debug_utils, -}; - -const BaseDispatch = vk.BaseWrapper(apis); -const InstanceDispatch = vk.InstanceWrapper(apis); -const DeviceDispatch = vk.DeviceWrapper(apis); - -pub const Instance = vk.InstanceProxy(apis); -pub const Device = vk.DeviceProxy(apis); -pub const Queue = vk.QueueProxy(apis); -pub const CommandBuffer = vk.CommandBufferProxy(apis); +pub const CommandBuffer = vk.CommandBufferProxy(Context.apis); const UboViewProjection = struct { projection: zm.Mat align(16), @@ -57,95 +40,74 @@ pub const VulkanRenderer = struct { allocator: std.mem.Allocator, - vkb: BaseDispatch, - - window: sdl.Window, - current_frame: u32 = 0, + ctx: Context, + // Scene settings ubo_view_projection: UboViewProjection, // Main - instance: Instance, - physical_device: vk.PhysicalDevice, - device: Device, - graphics_queue: Queue, - presentation_queue: Queue, - surface: vk.SurfaceKHR, - swapchain: vk.SwapchainKHR, viewport: vk.Viewport, scissor: vk.Rect2D, texture_sampler: vk.Sampler, - swapchain_images: []SwapchainImage, - swapchain_framebuffers: []vk.Framebuffer, - command_buffers: []CommandBuffer, + depth_buffer_image: []vk.Image, + depth_buffer_image_memory: []vk.DeviceMemory, + depth_buffer_image_view: []vk.ImageView, - depth_buffer_image: vk.Image, - depth_buffer_image_memory: vk.DeviceMemory, - depth_buffer_image_view: vk.ImageView, + colour_buffer_image: []vk.Image, + colour_buffer_image_memory: []vk.DeviceMemory, + colour_buffer_image_view: []vk.ImageView, // Descriptors descriptor_set_layout: vk.DescriptorSetLayout, sampler_set_layout: vk.DescriptorSetLayout, + input_set_layout: vk.DescriptorSetLayout, push_constant_range: vk.PushConstantRange, descriptor_pool: vk.DescriptorPool, sampler_descriptor_pool: vk.DescriptorPool, + input_descriptor_pool: vk.DescriptorPool, descriptor_sets: []vk.DescriptorSet, - sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet), + // sampler_descriptor_sets: std.ArrayList(vk.DescriptorSet), + input_descriptor_sets: []vk.DescriptorSet, vp_uniform_buffer: []vk.Buffer, vp_uniform_buffer_memory: []vk.DeviceMemory, + // TODO + command_buffers: []CommandBuffer, + // Assets - image_files: std.ArrayList(img.Image), - texture_images: std.ArrayList(vk.Image), - texture_image_memory: std.ArrayList(vk.DeviceMemory), - texture_image_views: std.ArrayList(vk.ImageView), + textures: std.ArrayList(Texture), model_list: std.ArrayList(MeshModel), // Pipeline graphics_pipeline: vk.Pipeline, pipeline_layout: vk.PipelineLayout, + + second_pipeline: vk.Pipeline, + second_pipeline_layout: vk.PipelineLayout, + render_pass: vk.RenderPass, - // Pools - graphics_command_pool: vk.CommandPool, - // Utilities - swapchain_image_format: vk.Format, depth_format: vk.Format, - extent: vk.Extent2D, // Synchronisation image_available: [MAX_FRAME_DRAWS]vk.Semaphore, render_finished: [MAX_FRAME_DRAWS]vk.Semaphore, draw_fences: [MAX_FRAME_DRAWS]vk.Fence, - debug_utils: ?vk.DebugUtilsMessengerEXT, - - pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self { + pub fn init(allocator: std.mem.Allocator, window: sdl.Window) !Self { var self: Self = undefined; - self.window = window; - self.current_frame = 0; self.allocator = allocator; - self.vkb = try BaseDispatch.load(try sdl.vulkan.getVkGetInstanceProcAddr()); + self.ctx = try Context.init(allocator, window); + self.current_frame = 0; - img.init(allocator); - - try self.createInstance(); - try self.createSurface(); - - if (enable_validation_layers) { - self.debug_utils = try createDebugMessenger(self.instance); - } - - try self.getPhysicalDevice(); - try self.createLogicalDevice(); - try self.createSwapchain(); + try self.createColourBufferImage(); try self.createDepthBufferImage(); try self.createRenderPass(); try self.createDescriptorSetLayout(); @@ -154,22 +116,21 @@ pub const VulkanRenderer = struct { try self.createFramebuffers(); try self.createCommandPool(); + self.sampler_descriptor_sets = try std.ArrayList(vk.DescriptorSet).initCapacity(self.allocator, self.ctx.swapchain.swapchain_images.len); + try self.createCommandBuffers(); try self.createTextureSampler(); try self.createUniformBuffers(); try self.createDescriptorPool(); try self.createDescriptorSets(); - + try self.createInputDescriptorSets(); try self.createSynchronisation(); self.image_files = std.ArrayList(img.Image).init(self.allocator); - self.texture_images = std.ArrayList(vk.Image).init(self.allocator); - self.texture_image_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator); - self.texture_image_views = std.ArrayList(vk.ImageView).init(self.allocator); + self.textures = std.ArrayList(Texture).init(self.allocator); self.model_list = std.ArrayList(MeshModel).init(allocator); - self.sampler_descriptor_sets = std.ArrayList(vk.DescriptorSet).init(self.allocator); - const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height)); + const aspect: f32 = @as(f32, @floatFromInt(self.ctx.swapchain.extent.width)) / @as(f32, @floatFromInt(self.ctx.swapchain.extent.height)); self.ubo_view_projection.projection = zm.perspectiveFovRh( std.math.degreesToRadians(45.0), aspect, @@ -202,19 +163,19 @@ pub const VulkanRenderer = struct { pub fn draw(self: *Self) !void { // Wait for given fence to signal (open) from last draw before continuing - _ = try self.device.waitForFences( + _ = try self.ctx.device.waitForFences( 1, @ptrCast(&self.draw_fences[self.current_frame]), vk.TRUE, std.math.maxInt(u64), ); // Manually reset (close) fences - try self.device.resetFences(1, @ptrCast(&self.draw_fences[self.current_frame])); + try self.ctx.device.resetFences(1, @ptrCast(&self.draw_fences[self.current_frame])); // -- Get next image // Get index of next image to be drawn to, and signal semaphore when ready to be drawn to - const image_index_result = try self.device.acquireNextImageKHR( - self.swapchain, + const image_index_result = try self.ctx.device.acquireNextImageKHR( + self.ctx.swapchain.handle, std.math.maxInt(u64), self.image_available[self.current_frame], .null_handle, @@ -238,30 +199,26 @@ pub const VulkanRenderer = struct { }; // Submit command buffer to queue - try self.device.queueSubmit(self.graphics_queue.handle, 1, @ptrCast(&submit_info), self.draw_fences[self.current_frame]); + try self.ctx.device.queueSubmit(self.ctx.graphics_queue.handle, 1, @ptrCast(&submit_info), self.draw_fences[self.current_frame]); // -- Present rendered image to screen const present_info: vk.PresentInfoKHR = .{ .wait_semaphore_count = 1, // Number of semaphores to wait on .p_wait_semaphores = @ptrCast(&self.render_finished[self.current_frame]), // Semaphores to wait on .swapchain_count = 1, // Number of swapchains to present to - .p_swapchains = @ptrCast(&self.swapchain), // Swapchains to present images to + .p_swapchains = @ptrCast(&self.ctx.swapchain.handle), // Swapchains to present images to .p_image_indices = @ptrCast(&image_index_result.image_index), // Index of images in swapchains to present }; // Present image - _ = try self.device.queuePresentKHR(self.presentation_queue.handle, &present_info); + _ = try self.ctx.device.queuePresentKHR(self.ctx.presentation_queue.handle, &present_info); // Get next frame (use % to keep the current frame below MAX_FRAME_DRAWS) self.current_frame = (self.current_frame + 1) % MAX_FRAME_DRAWS; } pub fn deinit(self: *Self) void { - self.device.deviceWaitIdle() catch undefined; - - if (enable_validation_layers) { - self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null); - } + self.ctx.device.deviceWaitIdle() catch undefined; for (0..self.model_list.items.len) |i| { self.model_list.items[i].destroy(); @@ -273,271 +230,106 @@ pub const VulkanRenderer = struct { } self.image_files.deinit(); - self.device.destroySampler(self.texture_sampler, null); + self.ctx.device.destroySampler(self.texture_sampler, null); for ( self.texture_images.items, self.texture_image_memory.items, self.texture_image_views.items, ) |tex_image, tex_image_memory, tex_image_view| { - self.device.destroyImage(tex_image, null); - self.device.freeMemory(tex_image_memory, null); - self.device.destroyImageView(tex_image_view, null); + self.ctx.device.destroyImage(tex_image, null); + self.ctx.device.freeMemory(tex_image_memory, null); + self.ctx.device.destroyImageView(tex_image_view, null); } self.texture_images.deinit(); self.texture_image_memory.deinit(); self.texture_image_views.deinit(); - self.device.destroyImageView(self.depth_buffer_image_view, null); - self.device.destroyImage(self.depth_buffer_image, null); - self.device.freeMemory(self.depth_buffer_image_memory, null); + for (0..self.depth_buffer_image.len) |i| { + self.ctx.device.destroyImageView(self.depth_buffer_image_view[i], null); + self.ctx.device.destroyImage(self.depth_buffer_image[i], null); + self.ctx.device.freeMemory(self.depth_buffer_image_memory[i], null); + } - self.device.destroyDescriptorPool(self.descriptor_pool, null); - self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null); - self.device.destroyDescriptorPool(self.sampler_descriptor_pool, null); - self.device.destroyDescriptorSetLayout(self.sampler_set_layout, null); + self.allocator.free(self.depth_buffer_image); + self.allocator.free(self.depth_buffer_image_memory); + self.allocator.free(self.depth_buffer_image_view); + + for (0..self.colour_buffer_image.len) |i| { + self.ctx.device.destroyImageView(self.colour_buffer_image_view[i], null); + self.ctx.device.destroyImage(self.colour_buffer_image[i], null); + self.ctx.device.freeMemory(self.colour_buffer_image_memory[i], null); + } + + self.allocator.free(self.colour_buffer_image); + self.allocator.free(self.colour_buffer_image_memory); + self.allocator.free(self.colour_buffer_image_view); + + self.ctx.device.destroyDescriptorPool(self.input_descriptor_pool, null); + self.ctx.device.destroyDescriptorPool(self.descriptor_pool, null); + self.ctx.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null); + self.ctx.device.destroyDescriptorPool(self.sampler_descriptor_pool, null); + self.ctx.device.destroyDescriptorSetLayout(self.sampler_set_layout, null); + self.ctx.device.destroyDescriptorSetLayout(self.input_set_layout, null); self.sampler_descriptor_sets.deinit(); + self.allocator.free(self.input_descriptor_sets); - for (0..self.swapchain_images.len) |i| { - self.device.destroyBuffer(self.vp_uniform_buffer[i], null); - self.device.freeMemory(self.vp_uniform_buffer_memory[i], null); + for (0..self.ctx.swapchain.swapchain_images.len) |i| { + self.ctx.device.destroyBuffer(self.vp_uniform_buffer[i], null); + self.ctx.device.freeMemory(self.vp_uniform_buffer_memory[i], null); } self.allocator.free(self.vp_uniform_buffer); self.allocator.free(self.vp_uniform_buffer_memory); self.allocator.free(self.descriptor_sets); for (0..MAX_FRAME_DRAWS) |i| { - self.device.destroySemaphore(self.render_finished[i], null); - self.device.destroySemaphore(self.image_available[i], null); - self.device.destroyFence(self.draw_fences[i], null); + self.ctx.device.destroySemaphore(self.render_finished[i], null); + self.ctx.device.destroySemaphore(self.image_available[i], null); + self.ctx.device.destroyFence(self.draw_fences[i], null); } self.allocator.free(self.command_buffers); - self.device.destroyCommandPool(self.graphics_command_pool, null); + self.ctx.device.destroyCommandPool(self.graphics_command_pool, null); - for (self.swapchain_framebuffers) |framebuffer| { - self.device.destroyFramebuffer(framebuffer, null); - } + self.ctx.device.destroyPipeline(self.second_pipeline, null); + self.ctx.device.destroyPipelineLayout(self.second_pipeline_layout, null); + self.ctx.device.destroyPipeline(self.graphics_pipeline, null); + self.ctx.device.destroyPipelineLayout(self.pipeline_layout, null); + self.ctx.device.destroyRenderPass(self.render_pass, null); - self.allocator.free(self.swapchain_framebuffers); + self.ctx.swapchain.deinit(); - self.device.destroyPipeline(self.graphics_pipeline, null); - self.device.destroyPipelineLayout(self.pipeline_layout, null); - self.device.destroyRenderPass(self.render_pass, null); - - for (self.swapchain_images) |swapchain_image| { - self.device.destroyImageView(swapchain_image.image_view, null); - } - - self.allocator.free(self.swapchain_images); - self.device.destroySwapchainKHR(self.swapchain, null); - self.device.destroyDevice(null); - self.instance.destroySurfaceKHR(self.surface, null); - self.instance.destroyInstance(null); - - self.allocator.destroy(self.device.wrapper); - self.allocator.destroy(self.instance.wrapper); - - img.deinit(); - } - - fn createInstance(self: *Self) !void { - if (enable_validation_layers and !self.checkValidationLayersSupport()) { - // TODO Better error - return error.LayerNotPresent; - } - - const extensions = try self.getRequiredExtensions(); - defer self.allocator.free(extensions); - - std.debug.print("[Required instance extensions]\n", .{}); - for (extensions) |ext| { - std.debug.print("\t- {s}\n", .{ext}); - } - - if (!try self.checkInstanceExtensions(&extensions)) { - return error.ExtensionNotPresent; - } - - const app_info = vk.ApplicationInfo{ - .p_application_name = "Vulkan SDL Test", - .application_version = vk.makeApiVersion(0, 0, 1, 0), - .p_engine_name = "Vulkan SDL Test", - .engine_version = vk.makeApiVersion(0, 0, 1, 0), - .api_version = vk.API_VERSION_1_3, - }; - - var instance_create_info: vk.InstanceCreateInfo = .{ - .p_application_info = &app_info, - .enabled_extension_count = @intCast(extensions.len), - .pp_enabled_extension_names = @ptrCast(extensions), - }; - - if (enable_validation_layers) { - const debug_create_info = getDebugUtilsCreateInfo(); - - instance_create_info.enabled_layer_count = @intCast(validation_layers.len); - instance_create_info.pp_enabled_layer_names = &validation_layers; - instance_create_info.p_next = &debug_create_info; - } - - const instance_handle = try self.vkb.createInstance(&instance_create_info, null); - const vki = try self.allocator.create(InstanceDispatch); - errdefer self.allocator.destroy(vki); - vki.* = try InstanceDispatch.load(instance_handle, self.vkb.dispatch.vkGetInstanceProcAddr); - - self.instance = Instance.init(instance_handle, vki); - } - - fn createSurface(self: *Self) !void { - self.surface = try sdl.vulkan.createSurface(self.window, self.instance.handle); - } - - fn createLogicalDevice(self: *Self) !void { - const indices = try self.getQueueFamilies(self.physical_device); - // 1 is the highest priority - const priority = [_]f32{1}; - - const qci = [_]vk.DeviceQueueCreateInfo{ - .{ - .queue_family_index = indices.graphics_family.?, - .queue_count = 1, - .p_queue_priorities = &priority, - }, - .{ - .queue_family_index = indices.presentation_family.?, - .queue_count = 1, - .p_queue_priorities = &priority, - }, - }; - - const queue_count: u32 = if (indices.graphics_family.? == indices.presentation_family.?) - 1 - else - 2; - - // Device features - const device_features: vk.PhysicalDeviceFeatures = .{ - .sampler_anisotropy = vk.TRUE, // Enable anisotropy - }; - - const device_create_info: vk.DeviceCreateInfo = .{ - .queue_create_info_count = queue_count, - .p_queue_create_infos = &qci, - .pp_enabled_extension_names = &Utilities.device_extensions, - .enabled_extension_count = @intCast(Utilities.device_extensions.len), - .p_enabled_features = &device_features, - }; - - const device_handle = try self.instance.createDevice(self.physical_device, &device_create_info, null); - - const vkd = try self.allocator.create(DeviceDispatch); - errdefer self.allocator.destroy(vkd); - vkd.* = try DeviceDispatch.load(device_handle, self.instance.wrapper.dispatch.vkGetDeviceProcAddr); - - self.device = Device.init(device_handle, vkd); - - const queues = try self.getDeviceQueues(); - - self.graphics_queue = Queue.init(queues[0], self.device.wrapper); - self.presentation_queue = Queue.init(queues[1], self.device.wrapper); - } - - fn createSwapchain(self: *Self) !void { - const swapchain_details = try self.getSwapchainDetails(self.physical_device); - defer self.allocator.free(swapchain_details.formats); - defer self.allocator.free(swapchain_details.presentation_modes); - - // 1. Choose best surface format - const surface_format = chooseBestSurfaceFormat(swapchain_details.formats); - // 2. Choose best presentation mode - const present_mode = chooseBestPresentationMode(swapchain_details.presentation_modes); - // 3. Choose swapchain image resolution - const extent = chooseSwapExtent(&self.window, swapchain_details.surface_capabilities); - - // How many images are in the swapchain? Get 1 more than the minimum to allow triple buffering - var image_count: u32 = swapchain_details.surface_capabilities.min_image_count + 1; - const max_image_count = swapchain_details.surface_capabilities.max_image_count; - - // Clamp down if higher - // If 0, it means it's limitless - if (max_image_count != 0 and image_count > max_image_count) { - image_count = max_image_count; - } - - var swapchain_create_info: vk.SwapchainCreateInfoKHR = .{ - .image_format = surface_format.format, - .image_color_space = surface_format.color_space, - .present_mode = present_mode, - .image_extent = extent, - .min_image_count = image_count, - .image_array_layers = 1, // Number of layers for each image - .image_usage = .{ .color_attachment_bit = true }, // What attachment will images be used as - .pre_transform = swapchain_details.surface_capabilities.current_transform, // Transform to perform on swapchain images - .composite_alpha = .{ .opaque_bit_khr = true }, // How to handle blending images with external graphics (e.g.: other windows) - .clipped = vk.TRUE, // Whether to clip parts of images not in view (e.g.: behind another window, off-screen, etc...) - .old_swapchain = .null_handle, // Links old one to quickly share responsibilities in case it's been destroyed and replaced - .surface = self.surface, - .image_sharing_mode = .exclusive, - }; - - // Get queue family indices - const family_indices = try self.getQueueFamilies(self.physical_device); - - // If graphic and presentation families are different, then swapchain must let images be shared between families - - if (family_indices.graphics_family.? != family_indices.presentation_family.?) { - const qfi = [_]u32{ - family_indices.graphics_family.?, - family_indices.presentation_family.?, - }; - - swapchain_create_info.image_sharing_mode = .concurrent; - swapchain_create_info.queue_family_index_count = @intCast(qfi.len); // Number of queues to share images between - swapchain_create_info.p_queue_family_indices = &qfi; - } - - self.swapchain = try self.device.createSwapchainKHR(&swapchain_create_info, null); - self.swapchain_image_format = surface_format.format; - self.extent = extent; - - // Swapchain images - var swapchain_image_count: u32 = 0; - _ = try self.device.getSwapchainImagesKHR(self.swapchain, &swapchain_image_count, null); - - const images = try self.allocator.alloc(vk.Image, swapchain_image_count); - defer self.allocator.free(images); - - _ = try self.device.getSwapchainImagesKHR(self.swapchain, &swapchain_image_count, images.ptr); - - self.swapchain_images = try self.allocator.alloc(SwapchainImage, swapchain_image_count); - - for (images, 0..) |image, i| { - self.swapchain_images[i] = .{ - .image = image, - .image_view = try self.createImageView(image, self.swapchain_image_format, .{ .color_bit = true }), - }; - } + self.ctx.deinit(); } fn createRenderPass(self: *Self) !void { // -- Attachments -- - // Colour attachment of the render pass + + var subpasses: [2]vk.SubpassDescription = undefined; + + // Subpass 1 attachments and references (input attachments) + + // Colour attachment (input) + const colour_format = chooseSupportedFormat( + self.ctx.physical_device, + self.ctx.instance, + &[_]vk.Format{.r8g8b8a8_srgb}, + .optimal, + .{ .color_attachment_bit = true }, + ); const colour_attachment: vk.AttachmentDescription = .{ - .format = self.swapchain_image_format, // Format to use for attachment - .samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling - .load_op = .clear, // Describes what to do with attachment before rendering - .store_op = .store, // Describes what to do with attachment after rendering - .stencil_load_op = .dont_care, // Describes what to do with stencil before rendering - .stencil_store_op = .dont_care, // Describes what to do with stencil after rendering - // Framebuffer data will be stored as an image, but images can be given different data layouts - // to give optimal use for certain operations - .initial_layout = vk.ImageLayout.undefined, // Image data layout before render pass starts - .final_layout = vk.ImageLayout.present_src_khr, // Image data layout after render pass (to change to) + .format = colour_format.?, + .samples = .{ .@"1_bit" = true }, + .load_op = .clear, + .store_op = .dont_care, + .stencil_load_op = .dont_care, + .stencil_store_op = .dont_care, + .initial_layout = .undefined, + .final_layout = .color_attachment_optimal, }; - // Depth attachment of render pass + // Depth attachment (input) const depth_attachment: vk.AttachmentDescription = .{ .format = self.depth_format, .samples = .{ .@"1_bit" = true }, @@ -549,30 +341,73 @@ pub const VulkanRenderer = struct { .final_layout = .depth_stencil_attachment_optimal, }; - // -- References -- - // Attachment reference uses an attachment index that refers to index in the attachment list passed to render pass create info + // Colour attachment (input) reference const colour_attachment_reference: vk.AttachmentReference = .{ - .attachment = 0, - .layout = vk.ImageLayout.color_attachment_optimal, - }; - - const depth_attachment_reference: vk.AttachmentReference = .{ .attachment = 1, - .layout = vk.ImageLayout.depth_stencil_attachment_optimal, + .layout = .color_attachment_optimal, }; - // Information about a particular subpass the render pass is using - const subpass: vk.SubpassDescription = .{ + // Depth attachment (input) reference + const depth_attachment_reference: vk.AttachmentReference = .{ + .attachment = 2, + .layout = .depth_stencil_attachment_optimal, + }; + + subpasses[0] = .{ .pipeline_bind_point = .graphics, // Pipeline type subpass is to be bound to .color_attachment_count = 1, .p_color_attachments = @ptrCast(&colour_attachment_reference), .p_depth_stencil_attachment = &depth_attachment_reference, }; + // Subpass 2 attachments and references + + // Colour attachment of the render pass + const swapchain_colour_attachment: vk.AttachmentDescription = .{ + .format = self.ctx.swapchain.swapchain_image_format, // Format to use for attachment + .samples = .{ .@"1_bit" = true }, // Number of samples to write for multisampling + .load_op = .clear, // Describes what to do with attachment before rendering + .store_op = .store, // Describes what to do with attachment after rendering + .stencil_load_op = .dont_care, // Describes what to do with stencil before rendering + .stencil_store_op = .dont_care, // Describes what to do with stencil after rendering + // Framebuffer data will be stored as an image, but images can be given different data layouts + // to give optimal use for certain operations + .initial_layout = vk.ImageLayout.undefined, // Image data layout before render pass starts + .final_layout = vk.ImageLayout.present_src_khr, // Image data layout after render pass (to change to) + }; + + // Attachment reference uses an attachment index that refers to index in the attachment list passed to render pass create info + const swapchain_colour_attachment_reference: vk.AttachmentReference = .{ + .attachment = 0, + .layout = vk.ImageLayout.color_attachment_optimal, + }; + + // References to attachments that subpass will take input from + const input_references = [_]vk.AttachmentReference{ + .{ + .attachment = 1, // Colour attachment + .layout = .shader_read_only_optimal, + }, + .{ + .attachment = 2, // Depth attachment + .layout = .shader_read_only_optimal, + }, + }; + + subpasses[1] = .{ + .pipeline_bind_point = .graphics, + .color_attachment_count = 1, + .p_color_attachments = @ptrCast(&swapchain_colour_attachment_reference), + .input_attachment_count = @intCast(input_references.len), + .p_input_attachments = &input_references, + }; + + // -- Subpass dependencies + // Need to determine when layout transitions occur using subpass dependencies - const subpass_dependencies = [2]vk.SubpassDependency{ + const subpass_dependencies = [_]vk.SubpassDependency{ // Conversion from VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - vk.SubpassDependency{ + .{ // Transition must happen after... .src_subpass = vk.SUBPASS_EXTERNAL, // Subpass index (VK_SUBPASS_EXTERNAL = outside of renderpass) .src_stage_mask = .{ .bottom_of_pipe_bit = true }, // Pipeline stage @@ -582,8 +417,17 @@ pub const VulkanRenderer = struct { .dst_stage_mask = .{ .color_attachment_output_bit = true }, .dst_access_mask = .{ .color_attachment_read_bit = true, .color_attachment_write_bit = true }, }, + // Subpass 1 layout (colour/depth) to subpass 2 layout (shader read) + .{ + .src_subpass = 0, + .src_stage_mask = .{ .color_attachment_output_bit = true }, + .src_access_mask = .{ .color_attachment_write_bit = true }, + .dst_subpass = 1, + .dst_stage_mask = .{ .fragment_shader_bit = true }, + .dst_access_mask = .{ .shader_read_bit = true }, + }, // Conversion from VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR - vk.SubpassDependency{ + .{ // Transition must happen after... .src_subpass = 0, .src_stage_mask = .{ .color_attachment_output_bit = true }, @@ -596,18 +440,18 @@ pub const VulkanRenderer = struct { }; // Order matters - const render_pass_attachments = [_]vk.AttachmentDescription{ colour_attachment, depth_attachment }; + const render_pass_attachments = [_]vk.AttachmentDescription{ swapchain_colour_attachment, colour_attachment, depth_attachment }; const render_pass_create_info: vk.RenderPassCreateInfo = .{ .attachment_count = @intCast(render_pass_attachments.len), .p_attachments = &render_pass_attachments, - .subpass_count = 1, - .p_subpasses = @ptrCast(&subpass), + .subpass_count = @intCast(subpasses.len), + .p_subpasses = &subpasses, .dependency_count = @intCast(subpass_dependencies.len), .p_dependencies = &subpass_dependencies, }; - self.render_pass = try self.device.createRenderPass(&render_pass_create_info, null); + self.render_pass = try self.ctx.device.createRenderPass(&render_pass_create_info, null); } fn createDescriptorSetLayout(self: *Self) !void { @@ -631,7 +475,7 @@ pub const VulkanRenderer = struct { }; // Create descriptor set layout - self.descriptor_set_layout = try self.device.createDescriptorSetLayout(&layout_create_info, null); + self.descriptor_set_layout = try self.ctx.device.createDescriptorSetLayout(&layout_create_info, null); // -- Texture sampler descriptor set layout -- @@ -650,7 +494,35 @@ pub const VulkanRenderer = struct { .p_bindings = @ptrCast(&sampler_layout_binding), }; - self.sampler_set_layout = try self.device.createDescriptorSetLayout(&texture_layout_info, null); + self.sampler_set_layout = try self.ctx.device.createDescriptorSetLayout(&texture_layout_info, null); + + // -- Create input attachment image descriptor set layout + // Colour input binding + const colour_input_layout_binding: vk.DescriptorSetLayoutBinding = .{ + .binding = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .stage_flags = .{ .fragment_bit = true }, + }; + + // Depth input binding + const depth_input_layout_binding: vk.DescriptorSetLayoutBinding = .{ + .binding = 1, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .stage_flags = .{ .fragment_bit = true }, + }; + + // Array of input attachment bindings + const input_bindings = [_]vk.DescriptorSetLayoutBinding{ colour_input_layout_binding, depth_input_layout_binding }; + + // Create a descriptor set layout for input attachments + const input_layout_create_info: vk.DescriptorSetLayoutCreateInfo = .{ + .binding_count = @intCast(input_bindings.len), + .p_bindings = &input_bindings, + }; + + self.input_set_layout = try self.ctx.device.createDescriptorSetLayout(&input_layout_create_info, null); } fn createPushConstantRange(self: *Self) !void { @@ -662,57 +534,103 @@ pub const VulkanRenderer = struct { }; } + fn createColourBufferImage(self: *Self) !void { + self.colour_buffer_image = try self.allocator.alloc(vk.Image, self.ctx.swapchain.swapchain_images.len); + self.colour_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.ctx.swapchain.swapchain_images.len); + self.colour_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.ctx.swapchain.swapchain_images.len); + + // Get supported format for colour attachment + const colour_format = chooseSupportedFormat( + self.ctx.physical_device, + self.ctx.instance, + &[_]vk.Format{.r8g8b8a8_srgb}, + .optimal, + .{ .color_attachment_bit = true }, + ) orelse return error.FormatNotSupported; + + // Create colour buffers + for (0..self.colour_buffer_image.len) |i| { + self.colour_buffer_image[i] = try Image.createImage( + self.ctx, + self.ctx.swapchain.extent.width, + self.ctx.swapchain.extent.height, + colour_format, + .optimal, + .{ .color_attachment_bit = true, .input_attachment_bit = true }, + .{ .device_local_bit = true }, + &self.colour_buffer_image_memory[i], + ); + + self.colour_buffer_image_view[i] = try Image.createImageView( + self.ctx, + self.colour_buffer_image[i], + colour_format, + .{ .color_bit = true }, + ); + } + } + fn createDepthBufferImage(self: *Self) !void { + self.depth_buffer_image = try self.allocator.alloc(vk.Image, self.ctx.swapchain.swapchain_images.len); + self.depth_buffer_image_memory = try self.allocator.alloc(vk.DeviceMemory, self.ctx.swapchain.swapchain_images.len); + self.depth_buffer_image_view = try self.allocator.alloc(vk.ImageView, self.ctx.swapchain.swapchain_images.len); + // Get supported depth buffer format const formats = [_]vk.Format{ .d32_sfloat_s8_uint, .d32_sfloat, .d24_unorm_s8_uint }; self.depth_format = chooseSupportedFormat( - self.physical_device, - self.instance, + self.ctx.physical_device, + self.ctx.instance, &formats, .optimal, .{ .depth_stencil_attachment_bit = true }, ) orelse return error.UnsupportedDepthBufferFormat; - // Create depth buffer image - self.depth_buffer_image = try self.createImage( - self.extent.width, - self.extent.height, - self.depth_format, - .optimal, - .{ .depth_stencil_attachment_bit = true }, - .{ .device_local_bit = true }, - &self.depth_buffer_image_memory, - ); + for (0..self.depth_buffer_image.len) |i| { + // Create depth buffer image + self.depth_buffer_image[i] = try Image.createImage( + self.ctx, + self.ctx.swapchain.extent.width, + self.ctx.swapchain.extent.height, + self.depth_format, + .optimal, + .{ .depth_stencil_attachment_bit = true, .input_attachment_bit = true }, + .{ .device_local_bit = true }, + &self.depth_buffer_image_memory[i], + ); - // Create depth buffer image view - self.depth_buffer_image_view = try self.createImageView(self.depth_buffer_image, self.depth_format, .{ .depth_bit = true }); + // Create depth buffer image view + self.depth_buffer_image_view[i] = try Image.createImageView(self.ctx, self.depth_buffer_image[i], self.depth_format, .{ .depth_bit = true }); + } } fn createGraphicsPipeline(self: *Self) !void { - // Create shader modules - const vert = try self.device.createShaderModule(&.{ - .code_size = shaders.shader_vert.len, - .p_code = @ptrCast(&shaders.shader_vert), - }, null); - defer self.device.destroyShaderModule(vert, null); + const v_shader align(@alignOf(u32)) = @embedFile("shader_vert").*; + const f_shader align(@alignOf(u32)) = @embedFile("shader_frag").*; - const frag = try self.device.createShaderModule(&.{ - .code_size = shaders.shader_frag.len, - .p_code = @ptrCast(&shaders.shader_frag), + // Create shader modules + const vert = try self.ctx.device.createShaderModule(&.{ + .code_size = v_shader.len, + .p_code = @ptrCast(&v_shader), }, null); - defer self.device.destroyShaderModule(frag, null); + defer self.ctx.device.destroyShaderModule(vert, null); + + const frag = try self.ctx.device.createShaderModule(&.{ + .code_size = f_shader.len, + .p_code = @ptrCast(&f_shader), + }, null); + defer self.ctx.device.destroyShaderModule(frag, null); // -- Shader stage creation information -- // Vertex stage creation information - const vertex_shader_create_info: vk.PipelineShaderStageCreateInfo = .{ + var vertex_shader_create_info: vk.PipelineShaderStageCreateInfo = .{ .stage = .{ .vertex_bit = true }, .module = vert, .p_name = "main", }; // Fragment stage creation information - const fragment_shader_create_info: vk.PipelineShaderStageCreateInfo = .{ + var fragment_shader_create_info: vk.PipelineShaderStageCreateInfo = .{ .stage = .{ .fragment_bit = true }, .module = frag, .p_name = "main", @@ -758,7 +676,7 @@ pub const VulkanRenderer = struct { }; // -- Vertex input -- - const vertex_input_create_info: vk.PipelineVertexInputStateCreateInfo = .{ + var vertex_input_create_info: vk.PipelineVertexInputStateCreateInfo = .{ .vertex_binding_description_count = 1, .p_vertex_binding_descriptions = @ptrCast(&binding_description), // List of vertex binding descriptions (data spacing, stride info) .vertex_attribute_description_count = @intCast(attribute_descriptions.len), @@ -775,15 +693,15 @@ pub const VulkanRenderer = struct { self.viewport = .{ .x = 0.0, .y = 0.0, - .width = @floatFromInt(self.extent.width), - .height = @floatFromInt(self.extent.height), + .width = @floatFromInt(self.ctx.swapchain.extent.width), + .height = @floatFromInt(self.ctx.swapchain.extent.height), .min_depth = 0.0, .max_depth = 1.0, }; self.scissor = .{ .offset = .{ .x = 0, .y = 0 }, - .extent = self.extent, + .extent = self.ctx.swapchain.extent, }; const viewport_state_create_info: vk.PipelineViewportStateCreateInfo = .{ @@ -861,10 +779,10 @@ pub const VulkanRenderer = struct { .p_push_constant_ranges = @ptrCast(&self.push_constant_range), }; - self.pipeline_layout = try self.device.createPipelineLayout(&pipeline_layout_create_info, null); + self.pipeline_layout = try self.ctx.device.createPipelineLayout(&pipeline_layout_create_info, null); // -- Depth stencil testing -- - const depth_stencil_create_info: vk.PipelineDepthStencilStateCreateInfo = .{ + var depth_stencil_create_info: vk.PipelineDepthStencilStateCreateInfo = .{ .depth_test_enable = vk.TRUE, // Enable checking depth to determine fragment write .depth_write_enable = vk.TRUE, // Enable writing to depth buffer to replace all values .depth_compare_op = .less, // Comparison operation that allows an overwrite (is in front) @@ -877,7 +795,7 @@ pub const VulkanRenderer = struct { }; // -- Graphics pipeline creation -- - const pipeline_create_info: vk.GraphicsPipelineCreateInfo = .{ + var pipeline_create_info: vk.GraphicsPipelineCreateInfo = .{ .stage_count = @intCast(shader_create_infos.len), // Number of shader stages .p_stages = &shader_create_infos, // List of shader stages .p_vertex_input_state = &vertex_input_create_info, @@ -896,53 +814,97 @@ pub const VulkanRenderer = struct { .base_pipeline_index = -1, // Or index of pipeline being created to derive from (in case creating multiple at once) }; - _ = try self.device.createGraphicsPipelines( + _ = try self.ctx.device.createGraphicsPipelines( .null_handle, 1, @ptrCast(&pipeline_create_info), null, @ptrCast(&self.graphics_pipeline), ); + + // -- Create second pass pipeline + // Second pass shaders + const v_second align(@alignOf(u32)) = @embedFile("second_vert").*; + const f_second align(@alignOf(u32)) = @embedFile("second_frag").*; + + const second_vert_shader_module = try self.ctx.device.createShaderModule(&.{ + .code_size = v_second.len, + .p_code = @ptrCast(&v_second), + }, null); + defer self.ctx.device.destroyShaderModule(second_vert_shader_module, null); + + const second_frag_shader_module = try self.ctx.device.createShaderModule(&.{ + .code_size = f_second.len, + .p_code = @ptrCast(&f_second), + }, null); + defer self.ctx.device.destroyShaderModule(second_frag_shader_module, null); + + // Set new shaders + vertex_shader_create_info.module = second_vert_shader_module; + fragment_shader_create_info.module = second_frag_shader_module; + + const second_shader_stages = [_]vk.PipelineShaderStageCreateInfo{ vertex_shader_create_info, fragment_shader_create_info }; + + // No vertex data for second pass + vertex_input_create_info.vertex_binding_description_count = 0; + vertex_input_create_info.p_vertex_binding_descriptions = null; + vertex_input_create_info.vertex_attribute_description_count = 0; + vertex_input_create_info.p_vertex_attribute_descriptions = null; + + // Don't want to write to depth buffer + depth_stencil_create_info.depth_write_enable = vk.FALSE; + + // Create new pipeline layout + const second_pipeline_layout_create_info: vk.PipelineLayoutCreateInfo = .{ + .set_layout_count = 1, + .p_set_layouts = @ptrCast(&self.input_set_layout), + }; + + self.second_pipeline_layout = try self.ctx.device.createPipelineLayout(&second_pipeline_layout_create_info, null); + + pipeline_create_info.stage_count = @intCast(second_shader_stages.len); + pipeline_create_info.p_stages = &second_shader_stages; + pipeline_create_info.layout = self.second_pipeline_layout; + pipeline_create_info.subpass = 1; + + // Create second pipeline + _ = try self.ctx.device.createGraphicsPipelines( + .null_handle, + 1, + @ptrCast(&pipeline_create_info), + null, + @ptrCast(&self.second_pipeline), + ); } fn createFramebuffers(self: *Self) !void { - self.swapchain_framebuffers = try self.allocator.alloc(vk.Framebuffer, self.swapchain_images.len); + self.ctx.swapchain.swapchain_framebuffers = try self.allocator.alloc(vk.Framebuffer, self.ctx.swapchain.swapchain_images.len); // Create a frammebuffer for each swapchain image - for (self.swapchain_images, 0..) |swapchain_image, i| { + for (self.ctx.swapchain.swapchain_images, 0..) |swapchain_image, i| { // Order matters - const attachments = [_]vk.ImageView{ swapchain_image.image_view, self.depth_buffer_image_view }; + const attachments = [_]vk.ImageView{ + swapchain_image.image_view, + self.colour_buffer_image_view[i], + self.depth_buffer_image_view[i], + }; const framebuffer_create_info: vk.FramebufferCreateInfo = .{ .render_pass = self.render_pass, // Render pass layout the frambuffer will be used with .attachment_count = @intCast(attachments.len), .p_attachments = &attachments, // List of attachments (1:1 with render pass) - .width = self.extent.width, // Framebuffer width - .height = self.extent.height, // Framebuffer height + .width = self.ctx.swapchain.extent.width, // Framebuffer width + .height = self.ctx.swapchain.extent.height, // Framebuffer height .layers = 1, // Framebuffer layers }; - self.swapchain_framebuffers[i] = try self.device.createFramebuffer(&framebuffer_create_info, null); + self.ctx.swapchain.swapchain_framebuffers[i] = try self.ctx.device.createFramebuffer(&framebuffer_create_info, null); } } - fn createCommandPool(self: *Self) !void { - // Get indices of queue families from device - const queue_family_indices = try self.getQueueFamilies(self.physical_device); - - const pool_create_info: vk.CommandPoolCreateInfo = .{ - // Queue family type that buffers from this command pool will use - .queue_family_index = queue_family_indices.graphics_family.?, - .flags = .{ .reset_command_buffer_bit = true }, - }; - - // Create a graphics queue family command pool - self.graphics_command_pool = try self.device.createCommandPool(&pool_create_info, null); - } - fn createCommandBuffers(self: *Self) !void { // Allocate one command buffer for each framebuffer - const command_buffer_handles = try self.allocator.alloc(vk.CommandBuffer, self.swapchain_framebuffers.len); + const command_buffer_handles = try self.allocator.alloc(vk.CommandBuffer, self.ctx.swapchain.swapchain_framebuffers.len); defer self.allocator.free(command_buffer_handles); self.command_buffers = try self.allocator.alloc(CommandBuffer, command_buffer_handles.len); @@ -953,9 +915,9 @@ pub const VulkanRenderer = struct { }; // Allocate command buffers and place handles in array of buffers - try self.device.allocateCommandBuffers(&command_buffer_allocate_info, command_buffer_handles.ptr); + try self.ctx.device.allocateCommandBuffers(&command_buffer_allocate_info, command_buffer_handles.ptr); for (command_buffer_handles, 0..) |command_buffer_handle, i| { - self.command_buffers[i] = CommandBuffer.init(command_buffer_handle, self.device.wrapper); + self.command_buffers[i] = CommandBuffer.init(command_buffer_handle, self.ctx.device.wrapper); } } @@ -965,9 +927,9 @@ pub const VulkanRenderer = struct { // Semaphore creation information for (0..MAX_FRAME_DRAWS) |i| { - self.image_available[i] = try self.device.createSemaphore(&.{}, null); - self.render_finished[i] = try self.device.createSemaphore(&.{}, null); - self.draw_fences[i] = try self.device.createFence(&fence_create_info, null); + self.image_available[i] = try self.ctx.device.createSemaphore(&.{}, null); + self.render_finished[i] = try self.ctx.device.createSemaphore(&.{}, null); + self.draw_fences[i] = try self.ctx.device.createFence(&fence_create_info, null); } } @@ -991,7 +953,7 @@ pub const VulkanRenderer = struct { .compare_op = .never, }; - self.texture_sampler = try self.device.createSampler(&sampler_create_info, null); + self.texture_sampler = try self.ctx.device.createSampler(&sampler_create_info, null); } fn createUniformBuffers(self: *Self) !void { @@ -999,15 +961,15 @@ pub const VulkanRenderer = struct { const vp_buffer_size: vk.DeviceSize = @sizeOf(UboViewProjection); // One uniform buffer for each image (and by extension, command buffer) - self.vp_uniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain_images.len); - self.vp_uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len); + self.vp_uniform_buffer = try self.allocator.alloc(vk.Buffer, self.ctx.swapchain.swapchain_images.len); + self.vp_uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.ctx.swapchain.swapchain_images.len); // Create the uniform buffers for (0..self.vp_uniform_buffer.len) |i| { try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, + self.ctx.physical_device, + self.ctx.instance, + self.ctx.device, vp_buffer_size, .{ .uniform_buffer_bit = true }, .{ .host_visible_bit = true, .host_coherent_bit = true }, @@ -1032,13 +994,13 @@ pub const VulkanRenderer = struct { // Data to create descriptor pool const pool_create_info: vk.DescriptorPoolCreateInfo = .{ - .max_sets = @intCast(self.swapchain_images.len), // Maximum number of descriptor sets that can be created from pool + .max_sets = @intCast(self.ctx.swapchain.swapchain_images.len), // Maximum number of descriptor sets that can be created from pool .pool_size_count = @intCast(descriptor_pool_sizes.len), // Amount of pool sizes being passed .p_pool_sizes = &descriptor_pool_sizes, // Pool sizes to create pool with }; // Create descriptor pool - self.descriptor_pool = try self.device.createDescriptorPool(&pool_create_info, null); + self.descriptor_pool = try self.ctx.device.createDescriptorPool(&pool_create_info, null); // -- Create sampler descriptor pool -- @@ -1055,14 +1017,38 @@ pub const VulkanRenderer = struct { .p_pool_sizes = @ptrCast(&sampler_pool_size), }; - self.sampler_descriptor_pool = try self.device.createDescriptorPool(&sampler_pool_create_info, null); + self.sampler_descriptor_pool = try self.ctx.device.createDescriptorPool(&sampler_pool_create_info, null); + + // -- Create input attachment descriptor pool + // Colour attachment pool size + const colour_input_pool_size: vk.DescriptorPoolSize = .{ + .type = .input_attachment, + .descriptor_count = @intCast(self.colour_buffer_image_view.len), + }; + + // Depth attachment pool size + const depth_input_pool_size: vk.DescriptorPoolSize = .{ + .type = .input_attachment, + .descriptor_count = @intCast(self.depth_buffer_image_view.len), + }; + + const input_pool_sizes = [_]vk.DescriptorPoolSize{ colour_input_pool_size, depth_input_pool_size }; + + // Create input attachment pool + const input_pool_create_info: vk.DescriptorPoolCreateInfo = .{ + .max_sets = @intCast(self.ctx.swapchain.swapchain_images.len), + .pool_size_count = @intCast(input_pool_sizes.len), + .p_pool_sizes = &input_pool_sizes, + }; + + self.input_descriptor_pool = try self.ctx.device.createDescriptorPool(&input_pool_create_info, null); } fn createDescriptorSets(self: *Self) !void { // One descriptor set for every buffer - self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain_images.len); + self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.ctx.swapchain.swapchain_images.len); - var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain_images.len); + var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.ctx.swapchain.swapchain_images.len); defer self.allocator.free(set_layouts); for (0..set_layouts.len) |i| { set_layouts[i] = self.descriptor_set_layout; @@ -1071,15 +1057,15 @@ pub const VulkanRenderer = struct { // Descriptor set allocation info const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ .descriptor_pool = self.descriptor_pool, // Pool to allocate descriptor set from - .descriptor_set_count = @intCast(self.swapchain_images.len), // Number of sets to allocate + .descriptor_set_count = @intCast(self.ctx.swapchain.swapchain_images.len), // Number of sets to allocate .p_set_layouts = set_layouts.ptr, // Layouts to use to allocate sets (1:1 relationship) }; // Allocate descriptor sets (multiple) - try self.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr); + try self.ctx.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr); // Update all of descriptor set buffer bindings - for (0..self.swapchain_images.len) |i| { + for (0..self.ctx.swapchain.swapchain_images.len) |i| { // -- View projection descriptor // Buffer info and data offset info const vp_buffer_info: vk.DescriptorBufferInfo = .{ @@ -1104,13 +1090,81 @@ pub const VulkanRenderer = struct { const set_writes = [_]vk.WriteDescriptorSet{vp_set_write}; // Update the descriptor sets with new buffer/binding info - self.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null); + self.ctx.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null); + } + } + + fn createInputDescriptorSets(self: *Self) !void { + self.input_descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.ctx.swapchain.swapchain_images.len); + + // Fill array of layouts ready for set creation + var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.ctx.swapchain.swapchain_images.len); + defer self.allocator.free(set_layouts); + for (0..set_layouts.len) |i| { + set_layouts[i] = self.input_set_layout; + } + + // Input attachment descriptor set allocation info + const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ + .descriptor_pool = self.input_descriptor_pool, + .descriptor_set_count = @intCast(self.ctx.swapchain.swapchain_images.len), + .p_set_layouts = set_layouts.ptr, + }; + + // Allocate descriptor sets + try self.ctx.device.allocateDescriptorSets(&set_alloc_info, self.input_descriptor_sets.ptr); + + // Update each descriptor set with input attachment + for (0..self.ctx.swapchain.swapchain_images.len) |i| { + // Colour attachment descriptor + const colour_attachment_descriptor: vk.DescriptorImageInfo = .{ + .image_layout = .shader_read_only_optimal, + .image_view = self.colour_buffer_image_view[i], + .sampler = .null_handle, + }; + + // Colour attachment descriptor write + const colour_write: vk.WriteDescriptorSet = .{ + .dst_set = self.input_descriptor_sets[i], + .dst_binding = 0, + .dst_array_element = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .p_image_info = @ptrCast(&colour_attachment_descriptor), + .p_buffer_info = undefined, + .p_texel_buffer_view = undefined, + }; + + // Depth attachment descriptor + const depth_attachment_descriptor: vk.DescriptorImageInfo = .{ + .image_layout = .shader_read_only_optimal, + .image_view = self.depth_buffer_image_view[i], + .sampler = .null_handle, + }; + + // Depth attachment descriptor write + const depth_write: vk.WriteDescriptorSet = .{ + .dst_set = self.input_descriptor_sets[i], + .dst_binding = 1, + .dst_array_element = 0, + .descriptor_type = .input_attachment, + .descriptor_count = 1, + .p_image_info = @ptrCast(&depth_attachment_descriptor), + .p_buffer_info = undefined, + .p_texel_buffer_view = undefined, + }; + + // List of input descriptor set writes + const set_writes = [_]vk.WriteDescriptorSet{ colour_write, depth_write }; + + // Update descriptor sets + self.ctx.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null); } } fn updateUniformBuffers(self: *Self, image_index: u32) !void { // Copy VP data - const data = try self.device.mapMemory( + const data = try self.ctx.device.mapMemory( self.vp_uniform_buffer_memory[image_index], 0, @sizeOf(UboViewProjection), @@ -1119,7 +1173,7 @@ pub const VulkanRenderer = struct { const vp_data: *UboViewProjection = @ptrCast(@alignCast(data)); vp_data.* = self.ubo_view_projection; - self.device.unmapMemory(self.vp_uniform_buffer_memory[image_index]); + self.ctx.device.unmapMemory(self.vp_uniform_buffer_memory[image_index]); } fn recordCommands(self: *Self, current_image: u32) !void { @@ -1130,7 +1184,8 @@ pub const VulkanRenderer = struct { }; const clear_values = [_]vk.ClearValue{ - .{ .color = .{ .float_32 = [4]f32{ 0.6, 0.65, 0.4, 1.0 } } }, + .{ .color = .{ .float_32 = .{ 0.0, 0.0, 0.0, 0.0 } } }, + .{ .color = .{ .float_32 = .{ 0.6, 0.65, 0.4, 1.0 } } }, .{ .depth_stencil = .{ .depth = 1.0, .stencil = 1 } }, }; @@ -1139,11 +1194,11 @@ pub const VulkanRenderer = struct { .render_pass = self.render_pass, // Render pass to begin .render_area = .{ .offset = .{ .x = 0, .y = 0 }, // Start point of render pass in pixels - .extent = self.extent, // Size of region to run render pass on (starting at offset) + .extent = self.ctx.swapchain.extent, // Size of region to run render pass on (starting at offset) }, .p_clear_values = &clear_values, // List of clear values .clear_value_count = @intCast(clear_values.len), - .framebuffer = self.swapchain_framebuffers[current_image], + .framebuffer = self.ctx.swapchain.swapchain_framebuffers[current_image], }; const command_buffer = self.command_buffers[current_image]; @@ -1204,6 +1259,21 @@ pub const VulkanRenderer = struct { } } + // Start second subpass + command_buffer.nextSubpass(.@"inline"); + + command_buffer.bindPipeline(.graphics, self.second_pipeline); + command_buffer.bindDescriptorSets( + .graphics, + self.second_pipeline_layout, + 0, + 1, + @ptrCast(&self.input_descriptor_sets[current_image]), + 0, + null, + ); + command_buffer.draw(3, 1, 0, 0); + // End render pass command_buffer.endRenderPass(); } @@ -1212,535 +1282,18 @@ pub const VulkanRenderer = struct { try command_buffer.endCommandBuffer(); } - fn getPhysicalDevice(self: *Self) !void { - var pdev_count: u32 = 0; - _ = try self.instance.enumeratePhysicalDevices(&pdev_count, null); - - const pdevs = try self.allocator.alloc(vk.PhysicalDevice, pdev_count); - defer self.allocator.free(pdevs); - - _ = try self.instance.enumeratePhysicalDevices(&pdev_count, pdevs.ptr); - - for (pdevs) |pdev| { - if (self.checkDeviceSuitable(pdev)) { - self.physical_device = pdev; - break; - } - } else { - // TODO Obviously needs to be something else - unreachable; - } - } - - fn getRequiredExtensions(self: Self) ![][*:0]const u8 { - var ext_count = sdl.vulkan.getInstanceExtensionsCount(self.window); - - if (enable_validation_layers) { - ext_count += 1; - } - - var extensions = try self.allocator.alloc([*:0]const u8, ext_count); - _ = try sdl.vulkan.getInstanceExtensions(self.window, extensions); - - if (enable_validation_layers) { - extensions[extensions.len - 1] = vk.extensions.ext_debug_utils.name; - } - - return extensions; - } - - fn getQueueFamilies(self: Self, pdev: vk.PhysicalDevice) !QueueFamilyIndices { - var indices: QueueFamilyIndices = .{ .graphics_family = null }; - - var queue_family_count: u32 = 0; - self.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, null); - - const queue_family_list = try self.allocator.alloc(vk.QueueFamilyProperties, queue_family_count); - defer self.allocator.free(queue_family_list); - - self.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, queue_family_list.ptr); - - for (queue_family_list, 0..) |queue_family, i| { - if (queue_family.queue_count > 0 and queue_family.queue_flags.graphics_bit) { - indices.graphics_family = @intCast(i); - } - - const presentation_support = try self.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), self.surface); - if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) { - indices.presentation_family = @intCast(i); - } - - if (indices.isValid()) { - return indices; - } - } - - unreachable; - } - - fn getDeviceQueues(self: Self) ![2]vk.Queue { - const indices = try self.getQueueFamilies(self.physical_device); - - const graphics_queue = self.device.getDeviceQueue(indices.graphics_family.?, 0); - const presentation_queue = self.device.getDeviceQueue(indices.presentation_family.?, 0); - return .{ graphics_queue, presentation_queue }; - } - - fn checkInstanceExtensions(self: Self, required_extensions: *const [][*:0]const u8) !bool { - var prop_count: u32 = 0; - _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, null); - - const props = try self.allocator.alloc(vk.ExtensionProperties, prop_count); - defer self.allocator.free(props); - - _ = try self.vkb.enumerateInstanceExtensionProperties(null, &prop_count, props.ptr); - - for (required_extensions.*) |required_extension| { - for (props) |prop| { - if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(required_extension))) { - break; - } - } else { - return false; - } - } - - return true; - } - - fn checkDeviceExtensions(self: Self, pdev: vk.PhysicalDevice) !bool { - var prop_count: u32 = 0; - _ = try self.instance.enumerateDeviceExtensionProperties(pdev, null, &prop_count, null); - - if (prop_count == 0) { - return false; - } - - const props = try self.allocator.alloc(vk.ExtensionProperties, prop_count); - defer self.allocator.free(props); - - _ = try self.instance.enumerateDeviceExtensionProperties(pdev, null, &prop_count, props.ptr); - - for (Utilities.device_extensions) |device_extension| { - for (props) |prop| { - if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(device_extension))) { - break; - } - } else { - return false; - } - } - - return true; - } - - fn checkDeviceSuitable(self: Self, pdev: vk.PhysicalDevice) bool { - const pdev_properties = self.instance.getPhysicalDeviceProperties(pdev); - - if (pdev_properties.device_type == .cpu) { - return false; - } - - const pdev_features = self.instance.getPhysicalDeviceFeatures(pdev); - const queue_family_indices = self.getQueueFamilies(pdev) catch return false; - const extension_support = self.checkDeviceExtensions(pdev) catch return false; - - const swapchain_details = self.getSwapchainDetails(pdev) catch return false; - defer self.allocator.free(swapchain_details.formats); - defer self.allocator.free(swapchain_details.presentation_modes); - - const swapchain_valid = swapchain_details.formats.len != 0 and swapchain_details.formats.len != 0; - - return queue_family_indices.isValid() and extension_support and swapchain_valid and pdev_features.sampler_anisotropy == vk.TRUE; - } - - fn checkValidationLayersSupport(self: Self) bool { - var layer_count: u32 = undefined; - _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, null) catch return false; - - const available_layers = self.allocator.alloc(vk.LayerProperties, layer_count) catch unreachable; - defer self.allocator.free(available_layers); - - _ = self.vkb.enumerateInstanceLayerProperties(&layer_count, available_layers.ptr) catch return false; - - for (validation_layers) |validation_layer| { - for (available_layers) |available_layer| { - if (std.mem.eql(u8, std.mem.span(validation_layer), std.mem.sliceTo(&available_layer.layer_name, 0))) { - return true; - } - } - } - - return false; - } - - fn getSwapchainDetails(self: Self, pdev: vk.PhysicalDevice) !SwapchainDetails { - // Capabilities - const surface_capabilities = try self.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(pdev, self.surface); - - // Formats - var format_count: u32 = 0; - _ = try self.instance.getPhysicalDeviceSurfaceFormatsKHR(pdev, self.surface, &format_count, null); - - const formats = try self.allocator.alloc(vk.SurfaceFormatKHR, format_count); - _ = try self.instance.getPhysicalDeviceSurfaceFormatsKHR(pdev, self.surface, &format_count, formats.ptr); - - // Presentation modes - var present_mode_count: u32 = 0; - _ = try self.instance.getPhysicalDeviceSurfacePresentModesKHR(pdev, self.surface, &present_mode_count, null); - - const presentation_modes = try self.allocator.alloc(vk.PresentModeKHR, format_count); - _ = try self.instance.getPhysicalDeviceSurfacePresentModesKHR(pdev, self.surface, &present_mode_count, presentation_modes.ptr); - - return .{ - .surface_capabilities = surface_capabilities, - .formats = formats, - .presentation_modes = presentation_modes, - }; - } - - fn createImage( - self: *Self, - width: u32, - height: u32, - format: vk.Format, - tiling: vk.ImageTiling, - use_flags: vk.ImageUsageFlags, - prop_flags: vk.MemoryPropertyFlags, - image_memory: *vk.DeviceMemory, - ) !vk.Image { - // -- Create Image -- - const image_create_info: vk.ImageCreateInfo = .{ - .image_type = .@"2d", // Type of image (1D, 2D or 3D) - .extent = .{ - .width = width, // Width of image extent - .height = height, // Height of image extent - .depth = 1, // Depth of image (just 1, no 3D aspecct) - }, - .mip_levels = 1, // Number of mipmap levels - .array_layers = 1, // Number of level in image array - .format = format, // Format type of image - .tiling = tiling, // How image data should be tiled (arranged for optimal reading) - .initial_layout = .undefined, // Layout of image data on creation - .usage = use_flags, // Bit flags defining what image will be used for - .samples = .{ .@"1_bit" = true }, // Number of samples for multi-sampling - .sharing_mode = .exclusive, // Whether image can be shared between queues - }; - - const image = try self.device.createImage(&image_create_info, null); - - // -- Create memory for image -- - // Get memory requirements for a type of image - const memory_requirements = self.device.getImageMemoryRequirements(image); - - // Allocate memory using image requirements and user-defined properties - const memory_alloc_info: vk.MemoryAllocateInfo = .{ - .allocation_size = memory_requirements.size, - .memory_type_index = Utilities.findMemoryTypeIndex(self.physical_device, self.instance, memory_requirements.memory_type_bits, prop_flags), - }; - - image_memory.* = try self.device.allocateMemory(&memory_alloc_info, null); - - // Connect memory to image - try self.device.bindImageMemory(image, image_memory.*, 0); - - return image; - } - - fn createImageView(self: Self, image: vk.Image, format: vk.Format, aspect_flags: vk.ImageAspectFlags) !vk.ImageView { - const image_view_create_info: vk.ImageViewCreateInfo = .{ - .image = image, - .format = format, - .view_type = .@"2d", - .components = .{ - // Used for remapping rgba values to other rgba values - .r = .identity, - .g = .identity, - .b = .identity, - .a = .identity, - }, - .subresource_range = .{ - .aspect_mask = aspect_flags, // Which aspect of image to view (e.g.: colour, depth, stencil, etc...) - .base_mip_level = 0, // Start mipmap level to view from - .level_count = 1, // Number of mipmap levels to view - .base_array_layer = 0, // Start array level to view from - .layer_count = 1, // Number of array levels to view - }, - }; - - return try self.device.createImageView(&image_view_create_info, null); - } - - fn createTextureImage(self: *Self, file_name: []const u8) !u32 { - // Load image file - var width: u32 = undefined; - var height: u32 = undefined; - var image_size: vk.DeviceSize = undefined; - const image = try self.loadTextureFile(file_name, &width, &height, &image_size); - - // Create staging buffer to hold loaded data, ready to copy to device - var image_staging_buffer: vk.Buffer = undefined; - var image_staging_buffer_memory: vk.DeviceMemory = undefined; - defer self.device.destroyBuffer(image_staging_buffer, null); - defer self.device.freeMemory(image_staging_buffer_memory, null); - - try Utilities.createBuffer( - self.physical_device, - self.instance, - self.device, - image_size, - .{ .transfer_src_bit = true }, - .{ .host_visible_bit = true, .host_coherent_bit = true }, - &image_staging_buffer, - &image_staging_buffer_memory, - ); - - // Copy data to staging buffer - const data = try self.device.mapMemory(image_staging_buffer_memory, 0, image_size, .{}); - const image_data: [*]u8 = @ptrCast(@alignCast(data)); - - @memcpy(image_data, image[0..]); - self.device.unmapMemory(image_staging_buffer_memory); - - // Create image to hold final texture - var tex_image_memory: vk.DeviceMemory = undefined; - const tex_image: vk.Image = try self.createImage( - width, - height, - .r8g8b8a8_srgb, - .optimal, - .{ .transfer_dst_bit = true, .sampled_bit = true }, - .{ .device_local_bit = true }, - &tex_image_memory, - ); - - // Transition image to be DST for copy operation - try Utilities.transitionImageLayout( - self.device, - self.graphics_queue.handle, - self.graphics_command_pool, - tex_image, - .undefined, - .transfer_dst_optimal, - ); - - // Copy data to image - try Utilities.copyImageBuffer( - self.device, - self.graphics_queue.handle, - self.graphics_command_pool, - image_staging_buffer, - tex_image, - width, - height, - ); - - // Transition image to be shader readable for shader usage - try Utilities.transitionImageLayout( - self.device, - self.graphics_queue.handle, - self.graphics_command_pool, - tex_image, - .transfer_dst_optimal, - .shader_read_only_optimal, - ); - - // Add texture data to array for reference - try self.texture_images.append(tex_image); - try self.texture_image_memory.append(tex_image_memory); - - // Return index of new texture image - return @intCast(self.texture_images.items.len - 1); - } - - fn createTexture(self: *Self, file_name: []const u8) !u32 { - // Create texture image and get its location in the array - const texture_image_loc = try self.createTextureImage(file_name); - - // Create image view and add to list - const image_view = try self.createImageView( - self.texture_images.items[texture_image_loc], - .r8g8b8a8_srgb, - .{ .color_bit = true }, - ); - - try self.texture_image_views.append(image_view); - - // Create texture descriptor - const descriptor_loc = try self.createTextureDescriptor(image_view); - - // Return location of set with texture - return descriptor_loc; - } - pub fn createMeshModel(self: *Self, model_file: []const u8) !usize { - const path = try StringUtils.concat("assets/models/", model_file, self.allocator); - defer self.allocator.free(path); - - // Import model scene - const scene = ai.aiImportFile( - path.ptr, - ai.aiProcess_Triangulate | ai.aiProcess_FlipUVs | ai.aiProcess_JoinIdenticalVertices, - ); - defer ai.aiReleaseImport(scene); - - // Get array of all materials with 1:1 ID placement - const texture_names = try MeshModel.loadMaterials(self.allocator, scene); - defer { - for (0..texture_names.items.len) |i| { - if (texture_names.items[i]) |texture_name| { - self.allocator.free(texture_name); - } - } - texture_names.deinit(); - } - - // Conversion from the material list IDs to our descriptor array IDs - var mat_to_tex = try std.ArrayList(u32).initCapacity(self.allocator, texture_names.items.len); - defer mat_to_tex.deinit(); - - // Loop over texture names and create textures for them - for (texture_names.items) |texture_name| { - if (texture_name != null) { - // Create texture and set value to index of new texture - mat_to_tex.appendAssumeCapacity(try self.createTexture(texture_name.?)); - } else { - - // If material had no texture, set to 0 to indicate no texture. Texture 0 will be reserver for a default texture - mat_to_tex.appendAssumeCapacity(0); - } - } - - // Load in all our meshes - const model_meshes = try MeshModel.loadNode( + // Pass tex smapler + MeshModel.new( self.allocator, - self.instance, - self.physical_device, - self.device, - self.graphics_queue.handle, + self.ctx, self.graphics_command_pool, - scene.*.mRootNode, - scene, - mat_to_tex.items, + self.texture_sampler, + model_file, ); - - // Create a mesh model and add to our list - const mesh_model = MeshModel.new(self.allocator, model_meshes); - try self.model_list.append(mesh_model); - - return self.model_list.items.len - 1; - } - - fn createTextureDescriptor(self: *Self, texture_image: vk.ImageView) !u32 { - var descriptor_set: vk.DescriptorSet = undefined; - - // Descriptor set allocation info - const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ - .descriptor_pool = self.sampler_descriptor_pool, - .descriptor_set_count = 1, - .p_set_layouts = @ptrCast(&self.sampler_set_layout), - }; - - // Allocate descriptor sets - try self.device.allocateDescriptorSets(&set_alloc_info, @ptrCast(&descriptor_set)); - - const image_info: vk.DescriptorImageInfo = .{ - .image_layout = .shader_read_only_optimal, // Image layout when in use - .image_view = texture_image, // Image to bind to set - .sampler = self.texture_sampler, // Sampler to use for set - }; - - // Descriptor write info - const descriptor_write: vk.WriteDescriptorSet = .{ - .dst_set = descriptor_set, - .dst_binding = 0, - .dst_array_element = 0, - .descriptor_type = .combined_image_sampler, - .descriptor_count = 1, - .p_image_info = @ptrCast(&image_info), - .p_buffer_info = undefined, - .p_texel_buffer_view = undefined, - }; - - // Update the new descriptor set - self.device.updateDescriptorSets(1, @ptrCast(&descriptor_write), 0, null); - - try self.sampler_descriptor_sets.append(descriptor_set); - - // Return descriptor set location - return @intCast(self.sampler_descriptor_sets.items.len - 1); - } - - fn loadTextureFile(self: *Self, file_name: []const u8, width: *u32, height: *u32, image_size: *vk.DeviceSize) ![]const u8 { - const path_concat = [2][]const u8{ "./assets/textures/", file_name }; - const path = try std.mem.concatWithSentinel(self.allocator, u8, &path_concat, 0); - defer self.allocator.free(path); - - const image = try img.Image.loadFromFile(path, 0); - try self.image_files.append(image); - - width.* = image.width; - height.* = image.height; - - // Calculate image size using given and known data - image_size.* = width.* * height.* * 4; - - return image.data; } }; -// Format: VK_FORMAT_R8G8B8A8_UNORM (VK_FORMAT_B8G8R8A8_UNORM as backup) -// Color space: VK_COLOR_SPACE_SRGB_NONLINEAR_KHR -fn chooseBestSurfaceFormat(formats: []vk.SurfaceFormatKHR) vk.SurfaceFormatKHR { - // If only one format available and is undefined, then this means all formats are available - if (formats.len == 1 and formats[0].format == vk.Format.undefined) { - return .{ - .format = vk.Format.r8g8b8a8_srgb, - .color_space = vk.ColorSpaceKHR.srgb_nonlinear_khr, - }; - } - - for (formats) |format| { - if ((format.format == vk.Format.r8g8b8a8_srgb or format.format == vk.Format.b8g8r8a8_srgb) and format.color_space == vk.ColorSpaceKHR.srgb_nonlinear_khr) { - return format; - } - } - - return formats[0]; -} - -fn chooseBestPresentationMode(presentation_modes: []vk.PresentModeKHR) vk.PresentModeKHR { - for (presentation_modes) |presentation_mode| { - if (presentation_mode == vk.PresentModeKHR.mailbox_khr) { - return presentation_mode; - } - } - - // Use FIFO as Vulkan spec says it must be present - return vk.PresentModeKHR.fifo_khr; -} - -fn chooseSwapExtent(window: *sdl.Window, surface_capabilities: vk.SurfaceCapabilitiesKHR) vk.Extent2D { - // If the current extent is at max value, the extent can vary. Otherwise it's the size of the window - if (surface_capabilities.current_extent.width != std.math.maxInt(u32)) { - return surface_capabilities.current_extent; - } - - // If value can very, need to set the extent manually - const framebuffer_size = sdl.vulkan.getDrawableSize(window); - - var extent: vk.Extent2D = .{ - .width = @intCast(framebuffer_size.width), - .height = @intCast(framebuffer_size.height), - }; - - // Surface also defines max and min, so make sure it's within boundaries by clamping values - extent.width = @max(surface_capabilities.min_image_extent.width, @min(surface_capabilities.max_image_extent.width, extent.width)); - extent.height = @max(surface_capabilities.min_image_extent.height, @min(surface_capabilities.max_image_extent.height, extent.height)); - - return extent; -} - fn chooseSupportedFormat( pdev: vk.PhysicalDevice, instance: Instance, @@ -1764,60 +1317,3 @@ fn chooseSupportedFormat( return null; } - -// Validation layers stuff -fn createDebugMessenger(instance: Instance) !vk.DebugUtilsMessengerEXT { - const debug_create_info = getDebugUtilsCreateInfo(); - - return try instance.createDebugUtilsMessengerEXT(&debug_create_info, null); -} - -fn getDebugUtilsCreateInfo() vk.DebugUtilsMessengerCreateInfoEXT { - return vk.DebugUtilsMessengerCreateInfoEXT{ - .message_severity = .{ .verbose_bit_ext = true, .warning_bit_ext = true, .error_bit_ext = true }, - .message_type = .{ .general_bit_ext = true, .validation_bit_ext = true, .performance_bit_ext = true }, - .pfn_user_callback = debugCallback, - }; -} - -fn debugCallback( - message_severity: vk.DebugUtilsMessageSeverityFlagsEXT, - message_types: vk.DebugUtilsMessageTypeFlagsEXT, - p_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, - p_user_data: ?*anyopaque, -) callconv(vk.vulkan_call_conv) vk.Bool32 { - _ = p_user_data; - const severity = getMessageSeverityLabel(message_severity); - const message_type = getMessageTypeLabel(message_types); - - std.debug.print("[{s}] ({s}): {s}\n=====\n", .{ severity, message_type, p_callback_data.?.p_message.? }); - return vk.TRUE; -} - -inline fn getMessageSeverityLabel(message_severity: vk.DebugUtilsMessageSeverityFlagsEXT) []const u8 { - if (message_severity.verbose_bit_ext) { - return "VERBOSE"; - } else if (message_severity.info_bit_ext) { - return "INFO"; - } else if (message_severity.warning_bit_ext) { - return "WARNING"; - } else if (message_severity.error_bit_ext) { - return "ERROR"; - } else { - unreachable; - } -} - -inline fn getMessageTypeLabel(message_types: vk.DebugUtilsMessageTypeFlagsEXT) []const u8 { - if (message_types.general_bit_ext) { - return "general"; - } else if (message_types.validation_bit_ext) { - return "validation"; - } else if (message_types.performance_bit_ext) { - return "performance"; - } else if (message_types.device_address_binding_bit_ext) { - return "device_address_binding"; - } else { - return "unknown"; - } -}